imaginaryctf - gdbjail 1 and 2
These challenges are part of the misc
category of Imaginary CTF 2024. The idea is that you netcat into a Python script which has restrictions on user input and passes valid input to gdb
through the gdb
python library.
gdbjail1
Overview
The binary being debugged is /bin/cat
and a breakpoint is placed at the read
function from libc
(wrapper for the read
syscall). The only allowed gdb commands are break
, continue
, and set
:
break
-> placing different types of breakpointscontinue
-> continues execution until the next breakpointset
-> used for setting memory, registers, and gdb vars
Blocked paths
I was looking for ways to execute shell commands. gdb
does have a way to achieve this using (!
) however it must be at the beginning of the line (e.g. !cat flag.txt
) which we cannot do here.
"set"ting shellcode
Reading the documentation about set and this StackOverflow question we can do the following:
Game plan: write our shellcode in a writable location in memory and point rip
to it then continue execution. Since gdb disables ASLR by default (the binary and all libraries are loaded in the same location each run), the memory mappings will stay the same across runs. I ran the docker container without the jail to get the same version of cat and chose a random executable memory location to place the shellcode.
Code
I used Claude to write code for generating the gdb instructions for me (you can tell by the inhuman number of comments across the code).
This in my opinion is a good use of LLMs, we are not asking it to "solve" the problem or "escape a gdb jail". Instead, we (the humans) do the critical thinking and chaining of ideas to figure out a blueprint for a solution then ask the LLM to do the tedious work of writing the code given a concrete specification. Anyway here's the code:
This generates the following:
You run it and you get: ictf{n0_m0re_debugger_a2cd3018}
. Amazing, first challenge done ✅
gdbjail2
In the sequel, two things change:
tougher jail constraints
requirement to get command execution
The full code for this jail is the following:
Added difficulty
Tougher jail constraints
First, the following blacklist is added to the Python script, disallowing any command which features any of the following strings:
This means that setting rip is no longer feasible (we need to work in the current place) and also setting memory is harder since the syntax contains curly braces and square brackets.
Must get command execution
The "cat" function as part of the shellcraft module from pwntools does not actually use the cat binary. It uses syscalls to read the exact file name. As such, using wildcards would fail since it would be looking for the literal *
symbol. Therefore, we need to be able to execute arbitrary commands so we can reach the flag file.
The plan
Command execution = libc.system
especially since there is no ASLR. By running the container locally I get the address of libc
(and libc
itself through a volume). Now we have system
but how do we even call it? And how do we move rip if the letter 'p' is blocked?
Where to place the shellcode
Since we know where the breakpoint is and hence where rip is, we can just place the shellcode there. The exact address is found through the container.
"set"ting memory
Trying different payloads I found that I can set each individual byte without using any braces or brackets. However, 0x
is disabled but that's not a big issue since we can omit it and write the decimal equivalent (looks weird seeing an address in decimal but works).
Putting it all together
Combining everything we have so far we get the following code:
And we get the flag ictf{i_l0ve_syscalls_eebc5336}
✅
Last updated