Reversing and Exploiting with Free Tools: Part 4

In part three, we learned how to analyze the first two exercises (stacks), using the three interactive disassemblers, IDA FREE, RADARE, and GHIDRA.

In this next part, we will continue our analysis with stack three and stack four. However, before that we need to introduce the new concept of invalid or bad chars.

What is a Bad Char?

Bad chars, also called invalid characters, are characters received and filtered by the target program that serve as delimiters. Through the internal algorithms of the program, bad characters eliminate functional characters or replaces them with other values, making our shellcode useless.

The search for badchars is a crucial part in the methodology of developing exploits, since, if they are not located and avoided during the generation of the payload, they make it useless because it would not be interpreted correctly in the target system.

When we send data to a program, it processes it. For the duration of this operation, until it arrives at the point of exploitation, the program checks, filters, substitutes, or blocks certain characters. This prevents us from using them in our payload. Obviously, this complicates the exploitation as it will need to be determined quickly at the moment of creating the exploit.

There are many ways to check if in the exploitation of a program, it produces invalid characters. For example, you could analyze the program from where data is entered to the point of exploitation and see what it does with this data. This method is the most accurate but can be extremely tedious if the program performs multiple checks, copies, and manipulations of the entered data.

Another option is to pass a string containing all the possible characters and check what happens to it. After several attempts, we’ll generate a string that passes completely and is fully copied to the destination buffer by removing the invalid characters.

Normally, in a first attempt, we avoid passing the most common invalid characters: 0xA, 0xD, 0x0 and 0xFF. If the rest pass well and arrive at the zone of exploitation without problems, then these four can be added one by one to see if there are any problems with them.

In the case of a buffer overflow, we could pass the string of test characters and see if it is copied to the buffer and if all the ones sent.

The following section demonstrates a sample code in python 3 that sets up a payload to test the invalid characters.

BASIC SCRIPT TO TEST BAD CHARS

Image
BASIC SCRIPT TO TEST BAD CHARS

Text

We can see that certain invalid characters are excluded. We can add or remove more depending on the tests we are doing.

There is a modification to the stack 1 script to test the invalid characters. Those that we find will be valid for the exercises since they all process data in the same way. They enter by means of the function gets, which then copies them to the destination buffer buf.

ADAPTING BASIC SCRIPT TO TEST BAD CHARS IN STACK 1

Image
ADAPTING BASIC SCRIPT TO TEST BAD CHARS IN STACK 1

Text

We’ll execute this script by attaching it to x64dbg when the message box pops up and going until the gets() function. After this execution, we’ll check if it copies all the characters to buf, which is the destination buffer that is going to be overflowed.

Image
attaching it to x64dbg

Text
Image
attaching it to x64dbg

Text

If we put a breakpoint in the gets()and accept the message box, it will stop there.

Image
accept the message box

Text

\ EDX contains the address of buf. Select the EDX register and choose FOLLOW IN DUMP to see in the dump the area where it will copy the bytes that we will send.

Press f8 to execute the gets().

Image
Press f8 to execute the gets()

Text

The string is cut at 0x1a character, so let's add it to the list of invalid characters and try again.

Image
cut at 0x1a character

Text

Repeat the process: launch it, attach the program, and press f8 to retry the step above and execute the gets().

Image
Repeat the process launch it

Text

We can already see that it entered from 0x1 to 0xfe, which means that avoiding the five characters that we put in the list of invalids will pass our payload.

Now we can remove the initial invalid characters one by one. Let's start with 0x0.

Image
 initial invalid characters

Text

Now, let’s try executing the gets () again.

Image
executing the gets () again

Text

We can see that 0x0 is not an invalid character since it entered and didn't cut the payload.  Let's continue with the others.

We remove the 0xa.

Image
remove the 0xa

Text
Image
remove the 0xa

Text

We see that 0xa is an invalid character since it cuts the payload and does not enter complete. We should add it again and remove the 0xd.

Image
cuts the payload

Text
Image
cuts the payload

Text

Now we see that 0xd is not an invalid character as it did not cut the payload. Only 0xff is left to try.

Image
0xd is not an invalid character

Text

To enter the character 0xFF in the loop, it must loop up to range(256) to ensure that 255 (0xFF) is included.

Image
character 0xFF in the loop

Text

Since we have entered the whole string and individually tested all the characters, the invalids for the stacks are 0x1a and 0xa. The rest can be sent without problems.

That's why in stack 3, which has a zero in the cookie, one needs to investigate if the zero is an invalid character. Since it is not, we can send it in the payload. This means the script will be like stack 1 and 2, except for the value change so that it compares with the cookie.

STACK 3 SOLUTION

Image
STACK 3 SOLUTION

Text

We must pass "05\x00\x02\x01" to compare with the cookie. There are no invalid characters so there is no problem.

Image
pass "05\x00\x02\x01"

Text
Image
pass "05\x00\x02\x01"

Text

Next, we can print the invalid characters. Using the same analysis that we did for stack 1 and 2, we can solve number 3 without problems.

Whenever we must perform an exploit, it helps to take the time to detect invalid characters, as it will ensure \that our payload will not be affected by them.

STACK 4 SOLUTION

The stack 4 case is different as there is an invalid character in the cookie.

Image
 stack 4 case

Text

We can see that we need to pass over this to step on the cookie.

payload = b"A" * 80 + b"\x00\x0a\x0d\x00"

Our payload contains an invalid character. This means we cannot pass the value we need to step on the cookie, which will complete the exercise and print “YOU WIN”.

We will look into the solutions in the upcoming part five.

If you want to try this exercise, you must continue to step below the cookie and try to step on the return address, forcefully returning to the address where the program calls the printf with the message “YOU WIN." Otherwise, look for some way to achieve the printout that we want.

Of course, it is quite possible the program will break when you do that, so there are only two valid solutions:

  1. Print “YOU WIN” and breaking the program, which is the simpler option.
  2. Print “YOU WIN” and to avoid breaking the program, which is obviously much more difficult.

 

Let's see who attempts to do it either way—or both!

Get the "Penetration Testing Toolkit"

CTA Text

This toolkit is designed to guide you through all the steps of managing an effective penetration testing program including: A detailed explanation of the six critical stages of pen testing, Maximizing defense tactics with purple teaming, Reinforcing broader security strategies using pen testing results and Deploying phishing simulations to prevent social engineering attacks.

DOWNLOAD NOW