Search This Blog

Friday, February 25, 2022

Executable Stack | 247CTF write-up [PWNED!!!]

 


In this walkthrough I go over the challenge I completed on 247CTF, a platform which offers hackers a chance to sharpen their hacking skills ranging from challenges such as Web Exploitation, Cryptography & Pwn challenges. The challenge I completed is from the pwn category, called "executable stack". Below is the challenge description. Reading this while playing CTFs help with regards to mentally browsing through how to take on the challenge and what route to go through.


Completing this challenge requires you to exploit a binary on a remote host. So in order to analyze this binary, the challenge supplies us with the same binary hosted on the remote host so we can inspect the binary, identify the vulnerability, craft the exploit and see if we get a shell for testing.

Information Gathering




Usually, for CTF challenges, binaries are usually compiled with security protections. For this challenge, NX is disabled. In a low-level security, if NX was enabled, that would prevent any code to be executed on the stack. But for this challenge, it is disabled, thus concluding that we might be able to execute code on the stack. This feature could possibly come in handy in exploiting this binary. I will go through other protections such as PIE (Also known as ASLR [Address Stack Layout Randomization]), RELRO and RWX in another blog post.

We now know the protections on this binary. We can now go further in executing the binary to see what it does exactly to get a better understanding of its general functions. 


When I run the binary, it shows me this simple text telling us there are no flag functions. It also goes ahead on informing me that "you can make your own". After this the binary expects some sort of user input. When I input "test", the binary exits without any errors. This immediately tells me that this is a buffer overflow attack. 

Buffer Overflow: Brief Overview

The buffer overflow vulnerability is when user input surpasses the number of bytes allocated for that specific input itself. If a program required your name and assigned a buffer of 10 bytes to the buffer 'name', if an attacker inserts a name or even random text that surpasses that buffer, the attacker can essentially access other parts of memory and insert arbitrary code and execute malicious code and redirect program execution. Since I'm the attacker, that's exactly what I am going to do to solve the challenge. 

For further investigation, we will use GDB, a debugger which will strip the binary so that we can see the low-level functions that are executed under the hood. We will specifically look at the "main" function as this function is typically the most common function that are run by C programs. Since this challenge does not have the PIE security feature enabled, this allows us to see the functions. If It was enabled, that would make the challenge much more harder to complete. Just a side note.



Above is the assembly code of the binary which is executed by the CPU, thus making it a very low-level language to understand. Hackers in the real world deal with this frequently to debug software and hunt for various vulnerabilities in order to exploit them. Above we see many function calls such as <puts@plt> and <chall>. What is interesting is that the main function calls the function <chall>. We might want to look into that. 


Looking into the <chall> function, we see that the function prepares memory for a buffer and <gets@plt> gets called, which is the same as the gets() function which essentially does not check how many bytes are inserted in it, thus making it vulnerable to buffer overflows. In order for us to successfully exploit this, we need to essentially overwrite EIP, which is the Instruction Pointer, a register in memory (like EAX, EBX, ECX, ESP etc.). Before we get into that, we need to insert more data into the binary so we ca cause it to crash. 

To do this, I will generate a cyclic pattern of 200 bytes, which will be used to test and see if we get a Segmentation Fault, which in more technical terms means the program has crashed.



The command above creates the cyclic pattern and redirects the output into a file called payload. After we do this we go back into GDB and insert this payload file into the binary to see if we cause a buffer overflow.


Segmentation Fault! Exactly what we wanted. Looking at the registers, we see the EIP, specifically being overwritten with 0x6261616b which is equivalent to 'kaab'. With this data we need to go on and calculate the exact offset of where the EIP was overwritten. Since the cyclic pattern generated to 200 bytes, we need to know exactly how many bytes it took to overwrite the EIP. 


Using python and the pwn module, which essentially a CTF framework to make binary exploitation easier, we find that it took exactly 140 bytes to overwrite EIP. From this point onward, we can go on to start crafting the payload. EIP is important because it essentially points to the next memory address where the next block of code will be executed. In this case, 0x6261616b is an invalid memory address. It is the hexademical representation of 'kaab' that we saw in the output of the Segmentation Fault. At this point onward, we can redirect the execution flow of the binary to what we want. 

Addtionally, looking at the functions, we should also get the JMP_ESP memory address as the code for us to get a shell on the remote target is located in the stack. Upon all the analysis and debugging of the binary, I have already written the final exploit which will essentially "hack" into the binary in the remote target via the buffer overflow vulnerability so we can capture the flag and complete the flag.

Final Exploit



Above is the final exploit. It imports the everything in the pwn module firstly, defines the target which are 'XXXXX.247ctf.com' and the TCP port 50339. Next it crafts the shellcode (/bin/bash shellcode) and stores it in the shellcode variable. The payload (in bytes) will create 140 'A's and appends the memory address of JMP_ESP(0x080484b3). After this it appends the shellcode crafted by the pwn module, stored in the shellcode variable. It then sends the payload to the remote target. Once the payload exploits the buffer overflow vulnerability, we can interact with it (using the target.interactive()). Now we run the exploit.


Upon running the exploit, WE GET A SHELL! We can now get the flag an submit. Challenge Completed!

FLAG: 247CTF{27886b9a498ed93685af9db0b1e304ec}

Wrapping Up

This challenge was a really basic introduction to binary exploitation and exploit development. I look forward to writing more walkthroughs like this and documenting my thought process on challenges like these.  Binary exploitation challenges get a lot more complex and complex, challenging hackers in their knowledge on how to bypass various protections. I look forward to documenting it all for you all to hjhave a look at how its done. Thanks for reading !


No comments:

Post a Comment