Skip to main content

Lab 13 - CTF

Task: Hidden in Plain Sight

The hidden-in-plain-sight-1/support/link binary provides everything you need. Find a way to use it.

TIP: If you want a main function to be done right, you gotta do it yourself.

If you are having trouble solving this exercise, check this.

Task: Hidden in Plain Sight 2

Analyze the hidden-in-plain-sight-2/support/link2 binary. Executing it is no longer a mystery, but it will be a bit more challenging to reach the flag.

TIP: Not all functions are private.

In case you get stuck, feel free to take a look at this!

Task: Look at Him Go

The look-at-him-go/support/dynamic binary is executable this time and its sole purpose is to obtain the flag and place it somewhere in memory. No tricks here.

TIP: GDB is your friend.

If you're unable to progress in this exercise, reference the GDB lab and this.

Task: Playing God

The playing-god/support/dynamic2 binary asks you to guess a number between 1 and 100000. Find a better way to discover it.

To help you solve this exercise, like in the previous one, make sure to keep an eye on the registers!

Task: Indirect Business

The indirect-business/support/buff-ovf binary contains a classic vulnerability. Use the input to alter the data in your favor.

If you experience a neural buffer overflow, take a look at the relevant lab and at online examples.

If that still doesn't work, keep in mind that the great cybersecurity expert named Sun Tzu was a big proponent of bruteforce attacks.

Task: RIP My Buffers Off

The rip-my-buffers-off/support/buff-ovf2 binary does not use the get_flag() function, but it offers an opportunity to call it.

TIP: Where can a function address be overwritten?

This example, albeit also linked in the previous exercise, is still a great resource to help you solve this exercise.

Task: Feeling Chained

Follow the sequence of operations in the functions of the binary at feeling-chained/support/buff-ovf3. Identify the necessary ones and... you already know how to call them.

If you cannot find your way through this exercise, look for variables that you need to overwrite with specific values in order to finish the exploit, and think of their positioning on the stack. The previously mentioned online example is still highly relevant.

Task: ROP

rop/support/rop is a 64-bit binary with a simple buffer overflow. However, it has NX enabled, so normal shellcode will not work. Find a way to create a working exploit.

TIP: On x86_64, function arguments are no longer found on the stack but in registers.

If you're having trouble with this exercise, you may use this. Keep in mind that peda's functionality may be a bit different from that of the provided setup, but you should have this. In pwndbg, you can use something like rop --grep "pop rsi".

CTF

In this laboratory, you will have to apply most of the concepts presented throughout this course under the format of Capture-The-Flag tasks. These tasks will test your understanding and mastery of specific static and dynamic analysis methods and tools, the compilation process, assembly language - syntax, registers, memory handling, functions, - as well as your ability to identify and exploit simple buffer overflow vulnerabilities.

Return Oriented Programming

For the bonus exercise, you will have to use Return Oriented Programming (ROP). This is a technique in which, if we have the ability to overwrite the return address, we execute gadgets. These gadgets are simply portions of the existing code that end with a ret instruction.

Examples of gadgets include:

pop rdi ; mov rdx, rax ; mov r12, rax ; jmp 0xd178
pop rdi ; pop rbp ; ret
pop rdi ; ret
pop rsi ; pop rdi ; jmp 0xbd5f

Notice that each gadget must end in a control-flow instruction, such as a ret or a jmp. The reason is so that they can be chained together. We usually write payloads that contain the addresses of these snippets. Then we trigger the ROP attack by placing this payload to overwrite a code pointer with the first address in the payload (such as overwriting the return address with this address).

Follow the example below to get a better picture:

ROP Anatomy

The image above aims to execute pop rdx; pop rbx; ret. Let's assume a function's return address is overwritten with that of the gadget, gadget_addr. The following things are going to happen:

  1. The function's ret will be executed and the rip will move to the first instruction of the gadget: pop rdx; the rsp will move towards the number 3 on the stack.

  2. pop rdx is executed, so the number pointed by rsp is popped into rdx, which is 3; rsp increases and now points to 4.

  3. Similarly, pop rbx will pop the number 4 into rbx; now rsp points to the new return address.

  4. The gadget's ret is executed, thus allowing us to execute new code: either a separate function, or a new gadget.

To determine the address of a gadget in a binary, there is the tool ROPgadget. Alternatively, in pwndbg, you can use a command like rop --grep "pop rsi".