
ForeignDesign
- Tôi mở file jar bằng JD-GUI để xem code java.
- Sau khi xem qua hàm main thì tôi có thể tóm tắt logic chương trình như này.
public static native void initialize();private static native void sc(char paramChar, int paramInt);
public static int s2(char c, int i) { int base = c + i % 7 * 2; if (i % 2 == 0) { base ^= 0x2C; } else { base ^= 0x13; } return base + (i & 0x1);}
public static void ck(String ws) { if (ws.length() == ll.length + lll.length) { for (int i = 0; i < ws.length(); i++) { int idx = (i * 5 + 3) % ws.length(); char ch = ws.charAt(idx); sc(ch, i); } System.out.println("Correct!"); } else { System.out.println("Incorrect!"); }}- Đơn giản hàm
s2chỉ là hàm mã hóa đơn giản, cònckchỉ là 1 hàm check. - Cái chúng ta chưa biết ở đây là hàm
initializevàsc, nó được lấy từ trong filenativera. - Tôi unzip file jar ra để xem file
nativecó gì bên trong. - Tôi tiến hành mở file
nativebằng IDA để xem code. - Sau khi đọc hiểu code và tóm tắt nó ta có:
- Hàm
initializeđơn giản là gán giá trị cho ll và lll, sau đó lấy dữ liệu nhập vào và gọi hàmckvới giá trị nhập vào. - Hàm
scsẽ duyệt từng ký tự của input nhập vào, nếu ký tự đấy ở vị trí lẻ (i & 1 != 0) thì sẽ gọi hàms2, còn không thì gọisub_13A0như hình bên dưới.
- Hàm

- Vì dữ liệu nhập vào sẽ được so sánh với từng giá trị trong ll rồi đến lll, nên ta sẽ gộp ll và lll vào và đặt tên là mảng check.
- Tôi viết 1 mã python để bruteforce các ký tự nhập vào để kiểm tra với mảng check, nếu với ký tự đó kiểm tra đúng thì ký tự đó là của flag.
check = [ 0x20, 0x5C, 0x04, 0x68, 0x6A, 0x4C, 0x60, 0x71, 0x2A, 0x41, 0x16, 0x2B, 0xCB, 0x54, 0xDC, 0x62, 0xD2, 0x47, 0x1D, 0x7B, 0x14, 0x7D, 0xC7, 0x4C, 0xE6, 0x75, 0xF3, 0x54, 0x36, 0x67, 0xC5, 0x68, 0xFB, 0x53, 0xFD, 0x80, 0x9F]
def s2(c, i): base = ord(c) + (i % 7) * 2 if (i % 2 == 0): base ^= 0x2C else: base ^= 0x13 return base + (i & 0x1)
def sub_13A0(c, i): return ((ord(c) ^ (i + 19)) + 3 * i) ^ 0x5A
def sc(c, i): if (i & 1): return s2(c, i) else: return sub_13A0(c, i)
len_flag = 37flag = [""] * len_flag
for i in range(len_flag): for c in range(32, 127): if sc(chr(c), i) == check[i]: flag[(i * 5 + 3) % len_flag] = chr(c) break
print(''.join(flag))- Và tôi đã có được flag.
Flag
scriptCTF{nO_MOr3_n471v3_tr4N5l471on}Plastic Shield
- Tôi mở file bằng IDA để xem mã code.

- Nói qua về logic thì chỉ là cho người dùng nhập vào sau đó lấy tính lại độ dài bằng cách chia cho 100 và nhân 60,
v15 = 60 * v16 / 100;. - Sau đó, biến
v9chỉ lấy ra một ký tự từ đoạn nhập vào, từ đó ta biết được chương trình chỉ sử dụng 1 ký tự nhập vào để làm key giải mã. - Tôi viết ra một đoạn script python bruteforce từng ký tự để giải mã flag.
from pwn import *
exe = ELF("./plastic-shield", checksec = False)
flag = ""for i in range(33, 127): p = process([exe.path]) p.sendline(chr(i).encode()) flag = p.recvline().decode(errors="ignore").strip() if "scriptCTF" in flag: flag = flag.split(": ")[-1] p.close() break p.close()
print(flag)- Và tôi đã có được flag.
Flag
scriptCTF{20_cau541i71e5_d3f3n5es_d0wn}Plastic Shield 2
- Tôi mở file bằng IDA để xem mã code.

- Sau khi xem qua hàm main thì tôi thấy ở hàm for có một chút vấn đề.
for ( i = 0LL; i <= 63; ++i ) sprintf(&v8[2 * i + 32], "%02x", (unsigned __int8)v10[i]);v9[3] = 0;- Vòng for chạy 64 lần, tức là sẽ ghi đến vị trí (2 * 64 + 32) = 160, mà ở đây mảng v8 chỉ được khai báo 157 phần tử, tức là v8 sẽ tràn 3 ký tự cuối của mã hex sang v9.
- Vậy nên ta chỉ cần bruteforce 3 ký tự đó (000 -> fff, 16 ^ 3 = 4096), với 4096 thì bruteforce là khả thi.
- Tôi tiến hành viết mã python để giải flag.
from binascii import unhexlifyfrom Crypto.Cipher import AESimport stringimport re
ciphertext = unhexlify("e2ea0d318af80079fb56db5674ca8c274c5fd0e92019acd01e89171bb889f6b1")
for i in range(4096): hex_string = f"{i:03x}"
byte0 = int(hex_string[:2], 16) byte1 = (int(hex_string[2], 16) << 4) & 0xFF key = bytes([byte0, byte1] + [0] * 14)
cipher = AES.new(key, AES.MODE_CBC, key) decrypted = cipher.decrypt(ciphertext)
padding_length = decrypted[-1] if padding_length <= 16: expected_padding = bytes([padding_length]) * padding_length if decrypted[-padding_length:] == expected_padding: plaintext = decrypted[:-padding_length]
try: text = plaintext.decode('utf-8') is_printable = all(ch in string.printable for ch in text) has_flag = re.search(r'scriptCTF\{', text)
if is_printable and has_flag: print(text) break except: continue- Sau khi chạy thì tôi đã có được flag
Flag
scriptCTF{00p513_n07_4641n!}