Page cover

Analyze - sub_1400816E0

Leaving off from the previous page ( Analyzing Important Sections ), we were just starting to analyze the subroutine sub_1400816E0 as named by IDA.

Analyzing the routine

Analyzing the top half entirely is a difficult task in of itself and requires a lot of analysis. So lets take the most important part (which is the first and biggest conditional determining the major steps to the function) and analyze it.

This screenshot demonstrates two important things.

  • 1: The call to the local routine -> This is a function or comparison that seems to entirely depend on if the function is going to go nowhere or continue to do something. So we can imagine, both forms are worth exploring (both conditional routes, sorry).

  • 2: The POST keyword -> This keyword kind of confirms a little bit what we have up top about that local jump. This function may actually be checking if the request method for the API endpoint was a POST request. This is good to keep in mind and document.

Checking The Local Jump

Lets analyze the local jump by double clicking on loc_1400821E2 and see where it takes us. The image below showcases the result location.

So it is clear that if this jump is made, the function is cleaned up. So we can now call the local jump to Local_Suicide which means the functions just going to kill itself when it jumps to that.

When we analyze just below the POST request condition (when its true) we see a small load into a character sequence which is defined by ASCII string constant (ASC) seen as asc_14013C410 which helps us identify the way data may be parsed. To verify this- lets go back a little bit.

Tracing back our steps

Lets actually analyze the request. Follow the steps below to verify how our POST data is being sent to the server socket.

Step 1 - Open the browser and navigate to the server

Assuming you did everything right and the application is running and you verified the server is up- you should see this.

Step 2 - Open up Inspect element and go to the network tab in chrome dev tools

If you did open up inspect element, send a request to the server and see how it was done and inspect the results. When you send the request you should be able to see the following.

In the results- we have the following

  • Headers: Helpful for knowing how to craft our own (if there is anything specific we need) (knowing how to send)

Cool so nothing special. Just that we verified the server is looking for HTTP post at this endpoint.

  • Request payload : Helpful for crafting our own later on (knowing what to send)

Alas! We have verified some information here- our program is probably going to be taking the text data by reading the content inside of the brackets and also parsing it (most likely using libraries like Nlohman JSON or standard text parsing libraries even APIs)

Going back

Now that we have actually verified our program is probably parsing data based on what is inside of the brackets, we can move on with analyzing the function to see if we come across anything wild or out in the open.

Eventually, you may notice the same content that is in the screenshot below.

The two reasons this is important to us are as follows:

  • 1: The same data operations for loading values and pushing them to a function that happens all in the same exact stage.

  • 2: The same functions being called in the same order every time with similar data

These two coordination's call for investigation on subroutine sub_140087380! Lets analyze!

Damn okay! That was actually pretty fast. So as we imagined, or probably guessed- we are in the area or part of the function that decodes the json values from the incomming POST request that was being parsed and checked out prior to this being executed.

Break - What now?

Since we have gotten far, lets take a break to breathe, analyze our results, then continue forward.

Noting what we have

Right now, we are understanding that our server works like this

  • Step 1 -> Listen for requests

  • Step 2 -> Check the path and based on the path execute a function

  • Step 3 -> Said function being called checks the request for that path

  • Step 4 -> If the endpoint is /api/v2/login and the request is POST then parse

  • Step 5 -> During parse, using nlohmann JSON calls to store and deserialize data properly

So far, that is all we have. Now...

What do we expect?

Well, since our program is utilizing AdminIDs, we can imagine a few things.

  • 1: The program is going to take the AdminID and internally verify it with a encrypted key we do not see or something that is generated (maybe using a custom seed and algorithm and implementation)

  • 2: The program is going to be executing cryptographic operations on the key (e.g: base64 encoding it or even hashing it to compare it to one in an online or local database that the software setup or had shipped)

  • 3: We are going to be sorting through weeds. Because of the way C++ programs work, especially when using the Windows API- you will have to use MANY different data conversion functions which can make it an absolute mess to sort through (due to compiler optimization stuffing it all into one function if need be.) With that, we can expect a gradual amount of noise to sort through.

Going through this list is pretty easy- we can choose to eliminate based on the easiest one. In this case, option 2 or possibility 2 is more likely considering it is an AdminID and we might be comparing encoded values or something!

Lateral Movement

In order to move and eliminate this option- we need to search for any use of WinCrypt (Windows API for encrypted related operations) which may indicate for a cryptographic operation, analyze that function and the data being pushed to it, then check if its the same data that we are expecting.

For more information on WinCrypt API symbols, go to this documentation. But also note that anything with Crypt in the name should give you the hint its related to a cryptographic operation.

Resuming - Eliminating The List

In order to eliminate this option, we can just analyze the entire function for anything that uses Crypt indicating it is an import from the WinCrypt library. From our previous location, we scroll down in the function and we eventually meet the brick of code shown below.

Lets go through this color by color.

  • Magenta: This is the most crucial and confusing part for us at the same time. Notice how there is multiple interdrawn sections? Well, this section pretty much breaks down into the function call to CryptBinaryToStringW, the function arguments and one argument that sticks out as a large hex value. This value is - '0x40000001'

  • Green: This is just indicating that we were in fact correct on our choice, this choice actually was the one that we needed to look for! As expected, we are taking the data and eventually pushing it to CryptBinaryToStringW which will encode the string.

  • Blue: Blue is just pointing out sections of interest- we see one repetition and possibly a error handling function which outputs an error message based on 'caption' being used.

  • Yellow: Ah yes! This is the value that was confusing. Don't worry- lets think this through step by step.

Analyzing CryptBinaryToStringW

To do this, lets refer to the official Microsoft documentation shown here- which shows the following syntax of the function.

Inn this function, one of the arguments are pretty important here in identifying what is happening to the data. If we look at the 'dwFlags' definition in the Microsoft documentation, we get the note below.

[in] dwFlags

Specifies the format of the resulting formatted string. This parameter can be one of the following values.

These values are in the screenshot of the tables below.

This means that basically, when specifying flags for the function, they can use the pipe or pipe eq with other flags like CRYPT_STRING_NOCRLF and CRYPT_STRING_NOCR. Awesome! So now what? Well, we need to choose the two best values that fits our scenario.

Assuming our values

In the 'dwFlags' position was the value - 0x40000001 So we can imagine, that ideally- the value indicates the use of flags CRYPT_STRING_NOCRLF which holds 0x40000000 and CRYPT_STRING_BASE64 with value 0x00000001

To check this we can actually take the two values in a Python terminal and see that the value we get using the following line.

0x00000001 | 0x4000000

This gives us

But wait- that is not the value we expected... whats going on here?

Recall back to the page that talks about IEEE-754 and how compilers use that. This was a good hint and lead!

If you did not follow the hint above, then basically, due to the way numbers and data works in a computer- we use specific standards to convert and store original values, especially large hexadecimal values and floating point values. In this case, our decimal value needs to be verified by applying a formula known as the IEEE-754 standard with a script like the one below.

If you followed the code example below, then you would know that this value 0x40000001 is the exact value we were looking for. So by now, we understand that our key is actually being base64 encoded and will be checked.

The issue with Windows APIs

Many people, especially when setting up buffers on the Windows API, believe that the WinAPI was designed enough to build-in safeguarding mechanisms into the API calls themselves. However, as saddened as you may be to hear, this is not always true.

In many cases, compiling functions like CryptBinaryToStringW with standard buffers can easily be susceptible to BOFs and I have seen it soooo many times before in the past. Mainly because, even if the compiler sees a buffer overrun, and warns you- developers might turn these warnings off as it is not a super high security issue to the compiler.

Alas: analyzing functions like CryptBinaryToStringW can be extremely important especially when auditing for mistakes with buffers.

To continue on, you should...

Before we continue on, and you read some of the other pages- it may be important to stop now and analyze all functions that could be heap-based since we are looking for a heap BOF. This includes free() calls as we will be using this information later.

If you are having problems with this, see the linked page below.

Analyzing Free

and

Tracing malloc

Once done- go to the next page linked below to analyze where the vulnerability is happening.

Analyzing this API call and setup further

Last updated