# Reverse ## Flag Hunters Đề bài: * Chương trình duyệt qua từng dòng của đoạn văn bản từ trên xuống dưới để in ra màn hình, trong đó có một đoạn đã được chèn flag. * Nhưng vì nó bắt đầu chạy ở một điểm dưới flag nên flag sẽ không được in ra. * Được phép nhập input ở chỗ ```CROWD``` chỉ một lần duy nhất, sau đó chương trình sẽ đi làm một vài hành động replace các vị trí đặc biệt được đánh dấu bởi các lệnh RETURN. * Khi gặp RETURN x thì sẽ nhảy về dòng x để chạy tiếp Solution: * Đọc kĩ đoạn ```.split(';')``` nó có tách các phần trên dòng mà ngăn cách bởi dấu ```;``` và duyệt từng cái. Vậy chỉ cần thêm vào sau dấu ```;``` một lệnh RETURN thì có thể nhảy đến bất kì vị trí nào. * payload: ```;RETURN 0``` ![image](https://hackmd.io/_uploads/SyusS6noke.png) picoCTF{70637h3r_f0r3v3r_a3d964ee} ## Tap into Hash Hàm encrypt chèn token gì đó vào giữa, hash bằng sha256, sau đó qua một vài đoạn xor để tạo ra cipher. Viết thêm hàm decrypt vào sources gốc để làm ngược lại như sau: ``` py def decrypt(ciphertext, key): block_size = 16 key_hash = hashlib.sha256(key).digest() plaintext_padded = b"" for i in range(0, len(ciphertext), block_size): block = ciphertext[i:i + block_size] decrypted_block = xor_bytes(block, key_hash) plaintext_padded += decrypted_block plaintext = unpad(plaintext_padded) return plaintext def unpad(data): padding_length = data[-1] return data[:-padding_length].decode('utf-8') key = b'\x8e\xdc\x08\xb8S\xee6\x0c\xf5\xfd\xceP\x15\xbf\xf6\xe2\x90\xf3\xd7F?,!\x1c\xb0D\x0cO\xcc\x04q\xb8' encrypted_blockchain = b"\xb4\xc8\xbd\xec@A\xbd-\x1d\xfd\x16\xe1\xe3sW\x18\xb1\x99\xea\xb8\x15\x10\xe8{\x19\xacE\xb3\xb4w\nH\xe7\x9d\xea\xe9EC\xb9(N\xa8\x14\xe1\xb7t]\x1c\xb7\xc8\xb9\xbaAF\xea}L\xadF\xb4\xb1&\n\x19\xac\xcc\xbc\xedGI\xef~\x16\xab\x10\xb6\xb7'\x0cN\xe0\xca\xee\xba\x15D\xbcz\x17\xfa\x17\xe3\xe0sY\x14\xe5\xca\xb5\xecAB\xea{\x1e\xffD\xe4\xb0%\x0cO\xb0\xc9\xee\xefC\x12\xeb|N\xff\x16\xe8\xb4'[\x15\xe0\xd1\xbc\xec\x10F\xe8q\x17\xa8\x10\xe1\xedu\\N\xb6\xc5\xef\xba\x10@\xe8y\x1a\xadC\xe3\xb0p\nO\xb0\xce\xfc\xb5\x15\x1e\xcd\x1di\xb5B\xbc\xba \x05s\xb2\xaf\xde\xb4 \x18\xdc+{\xffQ\xb3\x8d\x1c6y\xeb\xb1\xbc\xaeBH\xed\x01p\xbfc\xaa\xb8\t4V\xc3\xb7\xd3\xe8G\x12\xbfy\x1c\xfd\x11\xad\xe4r\\\x1f\xb5\xc8\xbf\xeeCC\xefy\x18\xadC\xb1\xe3uXM\xe7\xc4\xe9\xeb\x17\x12\xeb{\x1b\xf7\x15\xb6\xf8s^\x1c\xe7\xca\xba\xe5\x10A\xb8-\x18\xffA\xe4\xe7u]J\xb1\xcf\xb9\xef\x12C\xbd+L\xfd\x19\xe6\xed'XN\xe0\xcf\xe9\xef\x17@\xbczI\xa8\x18\xb1\xe1vV\x1d\xe5\xcb\xbf\xec\x12\x15\xec|L\xabD\xb4\xb0n^\x1c\xb8\x98\xea\xea\x10A\xec/\x1c\xfa\x17\xb6\xecp\x08J\xb9\xc4\xed\xeb\x10\x17\xb6+\x1c\xf6\x11\xe5\xe0s\x0bI\xe3\xca\xb9\xbaGH\xb6}\x18\xf7A\xe0\xe5{X\x1f\xb4\x99\xe9\xbe@H\xbf*I\xfd\x14\xb6\xe7 l." decrypted_blockchain = decrypt(encrypted_blockchain, key) print("Decrypted Blockchain:", decrypted_blockchain) ``` picoCTF{block_3SRhViRbT1qcX_XUjM0r49cH_qCzmJZzBK_41c10331} ## scramble nc verbal-sleep.picoctf.net 60759 > output.txt Vì mỗi phần tử của flag được lưu dưới dạng hex có 4 kí tự, vậy ta có thể tạo một bộ các phần tử có 4 kí tự để mô phỏng lại quá trình scramble. Vì chưa biết trước độ dài nên ta sẽ brute forces cho đến khi độ dài của scramble khớp với output. Sau đó chỉ cần lấy các vị trí theo thứ tự để khôi phục flag. ``` py def scramble(L): A = L i = 2 while (i < len(A)): A[i-2] += A.pop(i-1) A[i-1].append(A[:i-2]) i += 1 return L def get_flag(n): # flag = open('flag.txt', 'r').read() flag = [] for i in range(n): c = str(i) while len(c) < 4: c = '0' + c flag.append(c) hex_flag = [] for c in flag: hex_flag.append([c]) return hex_flag with open("output.txt", "r") as f: res = f.read() n = 10 while 1: testflag = get_flag(n) # print(testflag) cypher = scramble(testflag) # print(cypher) if abs(len(str(cypher)) - len(res)) <= 2: break n += 1 print(cypher) cypher = str(cypher) for i in range(n): c = str(i) while len(c) < 4: c = '0' + c pos = cypher.find(c) print(chr(int(res[pos:pos+4], 16)), end = '') ``` picoCTF{python_is_weirde2a45ca5} ## Chronohack Brute forces seed time 10s ```py from pwn import * import time import random p = remote('verbal-sleep.picoctf.net', 62819) p.recv() def get_random(length, timestamp): alphabet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" random.seed(timestamp) # seeding with current time s = "" for i in range(length): s += random.choice(alphabet) return s timestamp = int(time.time() * 1000) for offset in range(-10, 10): token = get_random(20, timestamp + offset) print(token) p.sendline(token) response = p.recv().decode() if "Congratulations" in response: print(response) break p.close() ``` picoCTF{UseSecure#$_Random@j3n3r@T0rs8a8d9ae0} ## perplexed Hàm checkflag tìm thấy trong IDA như sau: ```C __int64 __fastcall check(const char *a1) { __int64 v2; // rbx __int64 v3; // [rsp+10h] [rbp-50h] _QWORD v4[3]; // [rsp+18h] [rbp-48h] int v5; // [rsp+34h] [rbp-2Ch] int v6; // [rsp+38h] [rbp-28h] int v7; // [rsp+3Ch] [rbp-24h] int j; // [rsp+40h] [rbp-20h] unsigned int i; // [rsp+44h] [rbp-1Ch] int v10; // [rsp+48h] [rbp-18h] int v11; // [rsp+4Ch] [rbp-14h] if ( strlen(a1) != 27 ) return 1LL; v3 = 0x617B2375F81EA7E1LL; v4[0] = 0xD269DF5B5AFC9DB9LL; *(_QWORD *)((char *)v4 + 7) = 0xF467EDF4ED1BFED2LL; v11 = 0; v10 = 0; v7 = 0; for ( i = 0; i <= 0x16; ++i ) { for ( j = 0; j <= 7; ++j ) { if ( !v10 ) v10 = 1; v6 = 1 << (7 - j); v5 = 1 << (7 - v10); if ( (v6 & *((char *)&v4[-1] + (int)i)) > 0 != (v5 & a1[v11]) > 0 ) return 1LL; if ( ++v10 == 8 ) { v10 = 0; ++v11; } v2 = v11; if ( v2 == strlen(a1) ) return 0LL; } } return 0LL; } ``` Hàm này đang check từng bit thứ j của flag[i] được tính qua dữ liệu ban đầu ở mảng v4, (bao gồm cả đoạn v3 kề trước). Có thể lấy dữ liệu đó từ hex view của IDA và tiến thành gán lại cho flag theo đúng thứ tự đó. ```py s = 'E1 A7 1E F8 75 23 7B 61 B9 9D FC 5A 5B DF 69 D2 FE 1B ED F4 ED 67 F4 00 00 00 00' s = bytes.fromhex(s) print(len(s)) print(s) flag = [0 for i in range(27)] k = 0 x = 0 for i in range(len(s)): for j in range(8): if k == 0: k = 1 m1 = 1 << (7 - j) m2 = 1 << (7 - k) if (m1 & s[i]) > 0: flag[x] |= m2 # if ((m1 & s[i]) > 0) != ((m2 & flag[x]) > 0) : # print("wrong") k += 1 if k == 8: k = 0 x += 1 if x == len(s): # print(flag) for i in flag: print(chr(i), end = '') exit(0) ``` picoCTF{0n3_bi7_4t_a_7im3} ## Binary Instrumentation 1 Đây là dạng bài mà các hàm ẩn được sinh ra trong quá trình chạy chương trình nên IDA không thể tìm thấy từ ban đầu, phải tiền hành debug: Hàm quan trọng đầu tiên ở đây ![image](https://hackmd.io/_uploads/BkjmkgJhJe.png) Follow theo thì thấy nó đang gen ra các địa chỉ kiểu debug*:* ucrtbase.dll:*, ... Đến đoạn này thì bắt đầu đứng hình ![image](https://hackmd.io/_uploads/S1sGggyh1e.png) Đặt break point ở đó để nhảy vào xem thì thấy nó đã bắt đầu nhảy và đoạn hàm ban đầu bị ẩn đó ![image](https://hackmd.io/_uploads/ByKDlxynJx.png) Cứ tiếp tục follow theo, đoạn nào bị đứng thì đặt break point để nhảy vào ![image](https://hackmd.io/_uploads/rJDUbeJhke.png) ![image](https://hackmd.io/_uploads/rkgdbey21g.png) ![image](https://hackmd.io/_uploads/r19TWgJ2Jx.png) ![image](https://hackmd.io/_uploads/rkD0Ze131e.png) Vậy ta đã thấy được đoạn nó gọi hàm sleep, vậy chỉ cần SetIP để nhảy qua đoạn đó. ![image](https://hackmd.io/_uploads/HyrQfey3yl.png) Flag đã được in ra dưới dạng base 64. ![image](https://hackmd.io/_uploads/HkG9Qp2jkx.png) The flag is: cGljb0NURnt3NGtlX20zX3VwX3cxdGhfZnIxZGFfZjI3YWNjMzh9 base64: picoCTF{w4ke_m3_up_w1th_fr1da_f27acc38} ## Binary Instrumentation 2 Tương tự như phần 1 Vẫn là Debug chay: ![image](https://hackmd.io/_uploads/Byk4mg12yg.png) ... Sau khi follow hết quá trình thì vẫn chưa thầy flag được in ra ở đâu cả mà chương trình đã gọi hàm kernel32_ExitProcess luôn Dự đoán là có thể cách làm này đã bị chương trình chặn lại bằng một đoạn Antidebug nào đó, thay vì tìm ra tất cả để bypass thì mình có một ý tưởng là dừng lại khi nó đã gen ra hết các hàm ẩn và dump code để đọc, nhưng cũng khá nhiều thứ... ![image](https://hackmd.io/_uploads/ryhUUgy2Jl.png) ![image](https://hackmd.io/_uploads/rkhhYgk3ke.png) Một ý tưởng nữa là nếu như flag đã được gen ra thì có thể sẽ tìm thấy ở search strings. Dừng lại ngay trước khi nhảy vào hàm ẩn và đã tìm thấy flag base64 :v: ![image](https://hackmd.io/_uploads/r1mQSl1nJx.png) ![image](https://hackmd.io/_uploads/B13g-p3i1g.png) debug043:0000000140002270 00000041 C cGljb0NURntmcjFkYV9mMHJfYjFuX2luNXRydW0zbnQ0dGlvbiFfYjIxYWVmMzl9 base64: picoCTF{fr1da_f0r_b1n_in5trum3nt4tion!_b21aef39}