-
Notifications
You must be signed in to change notification settings - Fork 0
PWN
If you want to get started on PWN it is heavily recommended that you first understand the basics of REV
Pwning is the art of exploiting an already running system.
Generally there is a binary running on a server hosted by the CTF.
They give the URL and port for us to open a connection.
We can then interact with that server.
Importantly we want to craft a malicious input that we can send which somehow redirects code execution on the server.
Often times we want to "pop a shell" which means we cause the server program to turn itself into bash.
This is outside the scope of the paragraph but that often entails sending an input that causes the program to run execve('/bin/sh')
.
We can then use that sell to do whatever we want in the server. Often this is just reading the filesystem which has a flag file. Do not worry about the challenge owner's server! If set up properly all instances all containerized.
However we don't want to find the exploit using the server. We usually want to download the challenge, exploit it locally, and then use the same solution on the remote.
Useful Commands
-
checksec <file>
(can also do inpwndbg
) ropper -f <file>
ropper -f <file> --search <regex>
-
buffer overflow 0
on picoCTF: https://play.picoctf.org/practice/challenge/257 - Others on our CTFd
There may be several types of files uploaded:
This is a great way to find the vulnerability without having to open up Ghidra or disassemble inside of GDB. One of the first things you should do is analyze the usage of libc functions. For example:
- Is
gets
called? This function is fundamentally unsafe. It lets the user read as many characters as they want into a specified buffer. This is classified as an overflow issue, meaning we can write to memory that we are not supposed to - Is
fgets
called with a size that is greater than the buffer it writes to? If so it is similar to usinggets
- Is
printf
called with direct user input? It turns out this is REALLY unsafe and gives us an arbitrary write primitive. What that means is we can write any value to any address we want to in the program.
Even if there is source code you should still open the binary in a static reversing tool such as Ghidra or IDA. It turns out compilers take some liberties when transferring the source code into assembly. You should also poke around and identify:
- What assembly architecture is used? (x86, ARM, etc.)
- What type of libraries are linked?
- What strings are there?
- Identify functions that do critical things and identify small helper functions
Usually the Dockerfile is not actually part of the challenge. It just allows you to recreate the environment in which the server is running the binary. For example, often times knowing what version of libc is used is an integral part in solving the challenge. The Dockerfile allows you to build the challenge locally and then have access to that version. Often times I actually install all the tools inside the Docker container and then work there so everything works "first try" on the remote.
Sometimes the challenge author just provide the libc directly. We can then place it in the same folder as the binary and if done right it will use that libc. This is a bit simpler than Docker.
The binary or executable. This is what is actually run on the server and what we are exploiting. As mentioned before this should be opened in static reversing tools first. You can also run it a few times and provide some input to get a sense of what the program is doing.
A must do is running checksec
on this binary. There are four major mitigations that processes have on Linux:
- PIE: Position Independent code means that this binary has ASLR turned on. In other words the segments will be at random addresses. For example the
main
function could be at0x40000
in one launch and0x60000
in another. Often times this means we need to first leak information before launching our actual attack. - NX: Non-executable bit. This means that code segments which don't have code cannot be executed. This is used to mitigate shellcode. For example placing assembly on the stack and then executing it. Often times this is a sign you need to use ROP chaining or a one gadget.
- Stack Canary: Before the stack frame end there will be a unique value that is randomly generated at the launch of the program. It will be checked before the function executes its
leave
andret
instructions. So if you had a overflow but had to write over this the program would know and exit right away. You can either leak it it or get a more granular write primitive to skip over it. - RELRO: This means the PLT (Procedural Linkage Table) and GOT (Global Offset Table) have additional security measures. Specifically the GOT is read only. When you call a function to a linked library the code first goes to the GOT and looks up a value. One form of attacking is overwriting that table with a malicious address. This attempts to mitigate such behavior.
These settings HIGHLY affect how you craft your solution.
- Very good introduction by Georgia Tech
- Structured and more Comprehensive Courses
- Test Yourself