Memory Errors
level 1.0
Overflow a buffer on the stack to set the right conditions to obtain the flag!
From the information that we have been provided and by looking at the stack, we can make a few modifications that can help us better understand the challenge.
+---------------------------------+-------------------------+--------------------+
| Stack location | Data (bytes) | Data (LE int) |
+---------------------------------+-------------------------+--------------------+
esp ------> | 0x00007fff5e6805e0 (rsp+0x0000) | f0 05 68 5e ff 7f 00 00 | 0x00007fff5e6805f0 |
| 0x00007fff5e6805e8 (rsp+0x0008) | e8 17 68 5e ff 7f 00 00 | 0x00007fff5e6817e8 |
| 0x00007fff5e6805f0 (rsp+0x0010) | d8 17 68 5e ff 7f 00 00 | 0x00007fff5e6817d8 |
| 0x00007fff5e6805f8 (rsp+0x0018) | 00 4a 23 d3 01 00 00 00 | 0x00000001d3234a00 |
| 0x00007fff5e680600 (rsp+0x0020) | 01 00 00 00 00 00 00 00 | 0x0000000000000001 |
| 0x00007fff5e680608 (rsp+0x0028) | 00 00 00 00 00 00 00 00 | 0x0000000000000000 |
| 0x00007fff5e680610 (rsp+0x0030) | 20 06 68 5e ff 7f 00 00 | 0x00007fff5e680620 | <------ *buff
| 0x00007fff5e680618 (rsp+0x0038) | 94 06 68 5e ff 7f 00 00 | 0x00007fff5e680694 | <------ *win
| 0x00007fff5e680620 (rsp+0x0040) | 00 00 00 00 00 00 00 00 | 0x0000000000000000 | \
| 0x00007fff5e680628 (rsp+0x0048) | 00 00 00 00 00 00 00 00 | 0x0000000000000000 | \
| 0x00007fff5e680630 (rsp+0x0050) | 00 00 00 00 00 00 00 00 | 0x0000000000000000 | |
| 0x00007fff5e680638 (rsp+0x0058) | 00 00 00 00 00 00 00 00 | 0x0000000000000000 | |
| 0x00007fff5e680640 (rsp+0x0060) | 00 00 00 00 00 00 00 00 | 0x0000000000000000 | |
| 0x00007fff5e680648 (rsp+0x0068) | 00 00 00 00 00 00 00 00 | 0x0000000000000000 | |
| 0x00007fff5e680650 (rsp+0x0070) | 00 00 00 00 00 00 00 00 | 0x0000000000000000 | |---- buffer
| 0x00007fff5e680658 (rsp+0x0078) | 00 00 00 00 00 00 00 00 | 0x0000000000000000 | |
| 0x00007fff5e680660 (rsp+0x0080) | 00 00 00 00 00 00 00 00 | 0x0000000000000000 | |
| 0x00007fff5e680668 (rsp+0x0088) | 00 00 00 00 00 00 00 00 | 0x0000000000000000 | |
| 0x00007fff5e680670 (rsp+0x0090) | 00 00 00 00 00 00 00 00 | 0x0000000000000000 | |
| 0x00007fff5e680678 (rsp+0x0098) | 00 00 00 00 00 00 00 00 | 0x0000000000000000 | |
| 0x00007fff5e680680 (rsp+0x00a0) | 00 00 00 00 00 00 00 00 | 0x0000000000000000 | /
| 0x00007fff5e680688 (rsp+0x00a8) | 00 00 00 00 00 00 00 00 | 0x0000000000000000 | /
| 0x00007fff5e680690 (rsp+0x00b0) | 00 00 00 00 00 00 00 00 | 0x0000000000000000 | <------ win
| 0x00007fff5e680698 (rsp+0x00b8) | 00 4a 23 d3 24 fd 59 d9 | 0xd959fd24d3234a00 |
ebp ------> | 0x00007fff5e6806a0 (rsp+0x00c0) | e0 16 68 5e ff 7f 00 00 | 0x00007fff5e6816e0 | <------ saved ebp of previous frame
| 0x00007fff5e6806a8 (rsp+0x00c8) | e8 3d 60 8c 02 56 00 00 | 0x000056028c603de8 | <------ return address
+---------------------------------+-------------------------+--------------------+In this case, the pointer to the buffer is stored at (rsp+0x0030) and the pointer to the win variable is located at (rsp+0x0038). These are not to be confused with the actual location of the buffer or the win variable.
The actual win variable is located right after the buffer, at (rsp+0x00b4).
In order to overwrite the variable, we have to first overflow the buffer, whose size is 115 bytes.
So the buffer and win variable, are located as follows:
So as soon as the buffer ends, we have a single NULL byte, possibly a padding byte. And then we have our win variable which is 4 bytes long.
This means that we need to provide a payload of (115 + 1 + 4) bytes.
We are going to use pwntools in order to craft our payload.
As we can see we have successfully overwritten the win function.
level 1.1
Overflow a buffer on the stack to set the right conditions to obtain the flag!
This time we are not given any information by the program.
In order to create a payload we need to know three things:
You could use IDA or Ghidra, for this task, but we will use good old gdb.
Once we are prompted to enter our payload we can press CTRL C and then enter our payload.
The program has now read our payload.
The read syscall takes the following arguments:
Let's check the value of $rsi.
Now we know that the buffer starts at 0x7ffc615eeba0.
Let's disassemble the program:
This block of code decides whether we get the flag or not.
We can see that the cmp instruction is comparing whether the value stored in $eax has been changed.
And from the two lines above, we learn that the value in $eax is moved from dereferenced [rbp-0x58].
Let's check the value of [rbp-0x58]:
The location of the win variable is 0x7ffc615eec14.
So we have all the information we need:
Let's find the distance between the buffer and win variable in order to get the length of our payload padding.
We are all set to craft our payload.
level 2.0
Overflow a buffer on the stack to set trickier conditions to obtain the flag!
The buffer is 87 bytes long, which means that it only covers 7 bytes out of the word at (rsp+0x0090).
The buffer ends, we have a null byte and then we have our win variable.
We have to change the value of the win variable to 0x2dbba028.
Let's build our payload.
We successfully overwrote the variable.
level 2.1
Overflow a buffer on the stack to set trickier conditions to obtain the flag!
This time we are not given any information by the program.
In order to create a payload we need to know three things:
Let's open the program in gdb.
Once we are prompted to enter our payload we can press CTRL C and then enter our payload.
The program has now read our payload.
The read syscall takes the following arguments:
We can see that the second argument is the location to which input is read, and it is stored in $rsi.
Now we know that the buffer starts at 0x7ffc615eeba0.
Let's disassemble the program:
This block of code decides whether we get the flag or not.
We can see that the cmp instruction is comparing 0x47ba9894 with the value stored in $eax.
And from the two lines above, we learn that the value in $eax is moved from dereferenced [rbp-0x88].
Let's check the value of [rbp-0x88]:
The location of the win variable is 0x7ffc615eec14.
So we have all the information we need:
Let's find the distance between the buffer and win variable in order to get the length of our payload padding.
We are all set to craft our payload.
level 3.0
Overflow a buffer and smash the stack to obtain the flag!
This time there's no pointer to the buffer or to the win variable as there is no win variable in the first place.
In order to execute the win function, we have to overwrite the return address with the address of the win function.
Let's open the program in gdb.
As we can see the location of the win function is 0x000000000040236c.
Let's craft our payload.
level 3.1
Overflow a buffer and smash the stack to obtain the flag!
In order to create a payload we need to know three things:
Once we are prompted to enter our payload we can press
CTRL Cand then enter our payload.
The program has now read our payload.
The read syscall takes the following arguments:
We can see that the second argument is the location to which input is read, and it is stored in $rsi.
In this challenge, we have no win variable to overwrite.
The way we can divert flow of the program is by overwriting the return address.
We know that the base pointer $rbp points to the saved base pointer of the caller function.
Let's check this:
The base pointer $rbp has the value 0x7fff0c8f8e90 and it points to 0x7fff0c8f9ec0 which is the $rbp of the caller function.
And the return address is stored right before the caller functions base pointer. In our case at $rbp + 8.
As we can see the return address is <main+238> and it is located at 0x7fff0c8f8e98.
We want to replace this value with the address of the win function.
As we can see the win function starts at 0x0000000000402184.
We now have the information we need:
Let's calculate the padding required.
We can now create our payload.
level 4.0
Overflow a buffer and smash the stack to obtain the flag, but this time bypass a check designed to prevent you from doing so!
Our stack frame looks something like this:
Again, we have to overwrite the return address in order to divert control flow.
Let's find the address of the win function.
The program does not want us to overflow the buffer, so it tries to ensure that the payload size we set is lower than the buffer size.
However we can use the concept of two's compliment to our advantage.
The two's-compliment of -1 is 0xffffffff. If we enter the payload size to be -1, the program will interpret it as an unsigned 4294967295 instead of a signed -1.
And thus, we can pass the check.
Let's craft our payload:
level 4.1
Overflow a buffer and smash the stack to obtain the flag, but this time bypass a check designed to prevent you from doing so!
In order to create a payload we need to know three things:
Once we are prompted to enter our payload we can press CTRL C and then enter our payload.
The program has now read our payload.
The read syscall takes the following arguments:
We can see that the second argument is the location to which input is read, and it is stored in $rsi.
In this challenge, we have no win variable to overwrite.
The way we can divert flow of the program is by overwriting the return address.
We know that the base pointer $rbp points to the saved base pointer of the caller function.
Let's check this:
The base pointer $rbp has the value 0x7fff0c8f8e90 and it points to 0x7fff0c8f9ec0 which is the $rbp of the caller function.
And the return address is stored right before the caller functions base pointer. In our case at $rbp + 8.
As we can see the return address is main+238 and it is located at 0x7ffd98ad73d8.
We want to replace this value with the address of the win function.
As we can see the win function starts at 0x0000000000401958.
We now have the information we need:
Let's calculate the padding required.
We can now create our payload.
level 6.0
Overflow a buffer and smash the stack to obtain the flag, but this time bypass another check designed to prevent you from doing so!
In this level, the win_authed function checks if it's argument is 0x1337. If it isn't, we don't get the flag.
For now, instead of trying to pass it, we will just skip over this check.
Let's look at the win_authed function in gdb.
We can see that the instruction at 0x00000000004016d3 is performing the check and the next instruction is making the jump.
In order to skip the check, we have to set the return address to 0x00000000004016e0.
Before we do that we need to know the distance between the start of the buffer and location of return address.
As we can see the distance is 56 bytes. This means we need 56 bytes of padding in order to overwrite the return address.
level 6.1
Overflow a buffer and smash the stack to obtain the flag, but this time bypass another check designed to prevent you from doing so!
In order to create a payload we need to know three things:
Once we are prompted to enter our payload we can press CTRL C and then enter our payload.
The program has now read our payload.
The read syscall takes the following arguments:
We can see that the second argument is the location to which input is read, and it is stored in $rsi.
In this challenge, we have no win variable to overwrite.
The way we can divert flow of the program is by overwriting the return address.
We know that the base pointer $rbp points to the saved base pointer of the caller function.
Let's check this:
The base pointer $rbp has the value 0x7ffdf99af610 and it points to 0x7ffdf99b0640 which is the $rbp of the caller function.
And the return address is stored right before the caller functions base pointer. In our case at $rbp + 8.
As we can see the return address is main+238 and it is located at 0x7ffdf99af618.
We want to replace this value with the address in the win_authed function such that it skips the check.
As we can see the win function starts at 0x000000000040168a. However the address we want to overwrite the return address with is 0x00000000004016a6.
We now have the information we need:
Let's calculate the padding required.
We can now create our payload.
Last updated
Was this helpful?