【HUST】Network Attack and Defense Practice|6_Internet of Things Device Firmware Security Experiment|Experiment 3 FreeRTOS-MPU Protection Bypass

Written at the top: Be sure to task3.sctlink the file to the project first, the specific operation will be written later, and I explained the meaning of the sct file in the additional content.

It is finally possible to say goodbye to this practice. Can you add a sentence " the task load is relatively large, it is recommended to reduce the task load " in your experience ?

Experiment 3 FreeRTOS-MPU protection bypass

Experimental requirements

MPU presets:

insert image description here

a) Write C code to realize privilege escalation code and specified function lookup based on FreeRTOS-MPU v10.4
b) Use overflow vulnerability to realize system privilege escalation and Flag function printing in FreeRTOS MPU V10.4

Subtask 1

First of all, similar to the previous experiment, look at .cthe structure of the file.

mainFunction:
① Define an unsigned integer variable id, and assign it to the last 4 digits of the student number;
② Call prvSetupHardware(), hardware initialization;
③ Call StartFreeRTOS(id, vTask3);
④ Use to for(;;)keep the program from exiting.

vTask3content, only for(;;).

The role of header files and lib files is similar to the previous experiment.

Therefore, all mission requirements are concentrated in StartFreeRTOSit, and we need to conduct further reverse analysis.

Reverse analysis of StartFreeRTOS

IDA Pro opens and decompiles StartFreeRTOSas follows:

insert image description here

As you can see, the function roughly has the following operations:

byte_7714Copy the content pointed to by the address to the task parameter xTask3Parameters; ② Set the function pointer of
the task parameter to ; ③ val *= id; ④ Call , create a constrained task combined with the task parameter ; ⑤ Call to start the task sequence.xTask3ParametersvTask3

xTaskCreateRetrictedxTask3Parameters
vTaskStartScheduler()

What we have to do is vTask3call the privilege escalation function in , and then call the function that prints the flag.

The function to print the flag is easy to find. You can find it directly in the string window of IDA Pro. After finding it, double-click to open it, and then check the reference:

insert image description here

In short, we can find a vTaskRemovefunction called , which is a parameterless function and can print flag.

To find the privilege escalation function, I didn't know how to find it at first.
Until I read the PPT explained in the experiment, I saw the following picture:
insert image description here

It can be seen that if a common task needs to use the kernel API, it cannot be used directly, but must be added MPU_. This function is added, which includes the privilege escalation operation. Moreover, the privilege escalation operation should be to use SVCinterrupts.

Therefore, we might as well open a random function in IDA Pro to MPU_reverse engineer and find the privilege escalation operation. I take as MPU_vTaskDeletean example. The analysis in IDA Pro is as follows:

insert image description here

What I framed in the picture above is the privilege escalation operation. TaskIt can be seen that it is to do some push operations to enter the function first, and then pass in the privilege escalation function R4. If R4it is not 0, it will jump to the privilege escalation function (if it is 0, then it is a privileged level). Then execute the kernel API normally xTaskDelete.

Obviously, the privilege escalation function is xPortRaisePrivilege, and it uses registers R4to pass parameters, so it is also a parameterless function.

vTask3Do not rush to fill in the address, because this address will change after the content is modified . Pretend to have found the address first, and vTask3use the address to call these functions in , so that after finding it, you only need to modify it to the corresponding address. Add the code as follows:

Note that the addresses randomly filled in must not be all zeros or the same. It is better to fill in a bit similarly , otherwise the address will change after the second revision.

void (*pPrivilege)();
void (*pFunc)();
pPrivilege=(void(*)())0x00001051;
pFunc=(void(*)())0x000029AD;
pPrivilege();
pFunc();

After Rebuild, go to IDA Pro to find the function address. When using the address to call the function, you need to add one.

It should be noted that when the function address has been added correctly, but there is no log.txtlink in it vTask3, it is likely that there is a problem with the configuration of the project, such as the distribution of memory addresses. The problem is as log.txtfollows:

insert image description here

At this time, you must import the one sent by the teacher task3.srt. The import method is as follows:

insert image description here

After the import is complete, rebuild the project and re-analyze the address. (I re-screened the picture after importing)

For the specific function of sct, see additional content 1 below .

Print Flag function name and address

Name: vTaskRemove;
Address: 0x000005F4.

The content is shown in the figure below:

insert image description here

Function name and address for privilege escalation

Name: xPortRaisePrivilege;
Address: 0x00008EDC.

The content is shown in the figure below:

insert image description here

filled code

Note that you need to add 1 to the address found above before calling. Fill in the code as shown below:

insert image description here

Screenshot of simulation run

The result of running and printing the flag is as follows:

insert image description here

log.txt is as follows:

insert image description here

The reason why I want to log.txttake a screenshot is because in the previous analysis, we can see that xPortRaisePrivilegethe task of function escalation is R4the register, and we simply called the function without R4processing the register. But it worked.
If you check log.txt, you will find that there is no obvious processing content for the R4 register. The last assignment is the pop of prvSVCHandler. I guess that it is possible to svc 2escalate privileges only by executing interrupts. The specific situation is not yet clear, but it has no impact on this experiment.

Later, when I wrote the flag5 report, I realized that when R4 is 0, the task should be elevated; or, regardless of the value of R4, the task will be elevated.

Additional content 1: The role of sct files

The left side of the picture below is the sct file sent by the teacher, and the right side of the picture below is the sct file automatically generated by the software.

insert image description here

The sct file is also a memory-mapped layout file.
In general, when compiling, all the functions (as shown in the figure above .ANY (+R0)) are sorted into the memory according to the function name, and there is no access control such as privileged access or user access.
After we set the MPU, the compilation will not be affected. Therefore, the unprivileged function may be placed in the area of ​​the privileged function in the MPU specified by us. The unprivileged function is stored in the address range of the privileged function, and the MPU will not allow execution.

The sct file modified by the teacher rearranges the position of the API, puts the privileged function privileged_functionsin the first paragraph (that is, the position in the MPU that only allows privileged execution ER_IROM1), and puts the others ER_IROM2. And put the privileged data privileged_datain the segment that only allows privileges to be read and written in the MPU RW_IRAM1, and put the others RW_IRAM2.

In this way, the memory map will be consistent with the MPU settings.

Subtask 2

Reverse analysis of StartFreeRTOS

The reverse analysis function address of this task is similar to the previous task, so I won’t repeat it here.

Print Flag function name and address

Name: vTaskDelayBackup;
Address: 0x00001C7C.

The content is as follows:

insert image description here

Function name and address for privilege escalation

Name: xPortRaisePrivilege;
Address: 0x000086E2.

The content is as follows:

insert image description here

Analysis process

The function of this file mainis super long, but very simple, as shown in the following figure:

insert image description here

For the time being, it can only be seen that the length of the last input string InputBufferis at most 0x63.

Then click StartFreeRTOS:

insert image description here

It just runs the constrained vTask3tasks and does nothing else.

Since this is passed in by parameters, it cannot be opened directly, so return to the previous level first, and then click to open vTask3the task:

insert image description here

vTask3Called Function(), according to experience, this is the problematic code.

Find buffers that are overflowing

Click to open Function:

insert image description here

It was found that the parameters were passed in, and more importantly, the sum Functionappeared , and the value was assigned to , and the size was only 12, indicating that it might be an overflow buffer.lengthInputBufferHelperBufferHelperBufferHelperBuffer

Show Functionthe function in assembly as follows:

insert image description here

Explanation of PUSH and POP: The stack of the ARM architecture is a descending stack, from right to left when PUSH, and from left to right when POP.

After looking at the assembly, you will find that, strictly speaking, there is no overflow buffer at all. FunctionFunction, it first pushregisters 4 registers, and then uses them at the very beginning of the function mov buffer, spto directly change the top pointer sp of the stack, and then immediately InputBufferfills them with the contents one by one buffer(the variable name is parsed into in my IDA HelpBuffer). At the end pop, popisn't the content of the content just HelpBuffer[0], HelpBuffer[1], and HelpBuffer[2]so on?
Overwriting the value of the register is Functionthe purpose and bufferthe function of setting. It just wants to write to the stack and write to the register.
Since the purpose of every bit of this buffer is to write data to registers or stacks that should not be written , it has no part related to normal function at all. It’s like drawing with a piece of paper. The normal operation is drawn on the paper, but if you paint too much, it will overflow to the table. This piece of paper is called overflow buffer; and this code doesn’t even have paper.

In summary, I don't think this is a typical buffer overflow code. If you have to say that there is an overflow buffer, it is deliberately constructed HelpBuffer, and the length of the overflow buffer is 0, which has no normal function .

Stack diagram

Click on the bp of Function to see the stack frame in IDA Pro.

insert image description here

That doesn't explain very well what's on the stack, though. I redraw the stack schematic.

The stack diagram before and after execution mov buffer, spis as follows:

insert image description here

LR (Function) needs to be overwritten with a privilege escalation function, and after calling the privilege escalation function, it is also necessary to call a function that prints the flag, so it is necessary to construct a stack structure that overflows the return address of the privilege escalation call. The fully constructed stack diagram will be drawn in the follow-up "Overflow Privilege Escalation" .

overflow privilege escalation

Overflow privilege escalation call xPortRaisePrivilege, the address is 0x000086E2. The first line of the function is PUSH {xRunningPrivileged,LR}. If this sentence is executed, it will change the stack frame structure we have constructed, and it will also cause the return address to not be overwritten, so we need to skip this sentence and 0x000086E4start from the address. Plus the base address is 1, so LR(Function)it needs to be overwritten 0x000086E5.

After successfully entering and executing the privilege escalation function, continue to execute the function of printing the flag. It is executed when returning POP {xRunningPrivileged,LR}, so 8 HelpBufferbytes need to be constructed. The complete stack diagram is as follows:

insert image description here

Override the parsing process of the return address

The return value in Functionis overwritten with xPortRaisePrivilegethe address of the second line plus 1, that is 0x000086E5, when it returns, it will xPortRaisePrivilegestart executing from the second line of code and complete the privilege escalation;

The return value in xPortRaisePrivilegeis overwritten as vTaskDelayBackupthe address plus 1, that is , so it will execute from the first line of code 0x00001C7Cwhen it returns , and complete the flag printing.vTaskDelayBackup

Screenshot of simulation run

insert image description here

Flowers are over! ! !

Guess you like

Origin blog.csdn.net/qq_46106285/article/details/125464654