RNRF 2021. 11. 3. 01:08

34. Developing an intuition for binary exploitation - bin.0x20

: We are already trying to understand how to exploit the program.
-> Various examples were covered in previous videos, including memory corruption, default buffer overflow, heap exploitation and format string.
-> And many would think it's already quite complicated.
-> But put it in the context of history and we are still 16 years from now.
-> The last example we looked at at "exploit-exercises.com" introduced the latest technology.
-> As "2001" it can be applied directly to cheap, low-cost embedded devices such as "IoT," but it is very important to lay the foundation.
-> But it's a good idea to put in more of what we've learned before we start talking about all these modern exploits.
-> Abusing the binary, about feelings or hunches should learn.

: Let's try to create a mental model of exploitation.
-> But first, let me introduce some constraints. Otherwise, it is too abstract.
-> Let's focus on programs that we've interacted with before.
-> First, it means Intel architecture and Linux.
-> We want the program to be implemented in "CPU".
-> This is why the program includes an assembler code (machine code).
-> Machine code is the same as other data on the computer
-> It's basically a bit. "0" and "1".
-> In many cases we combine it in bytes.
-> And "CPU" can interpret byte as a command. Alternatively, several bytes may be interpreted as a command.
-> And the "CPU" digital hardware has special value.
-> "01 D8 -> add eax, ebx -> eax = eax + ebx"
-> For example, add values stored in both registers and place the results in the first register.
-> The register is the same as the small memory cell of the "CPU" and fully performs other purposes.
-> In addition, different architectures may have different registers for different purposes.
-> However, Intel has general purpose registers such as "eax" and "ebx".
-> Programmers are free to use whatever they want.
-> However, there is also a special register, such as the command pointer "EIP".
-> The address simply contains an address, and the next address refers to memory.
-> There is also a stack pointer "ESP" that points to the top of the stack.
-> Along with the stack pointer, there is also the default pointer "EBP" that defines the stack frame.
-> Perhaps, for beginners, it is already complicated.
-> There's code, there's data, there's stacks, there's heap. And there is a function that can be called.
-> Somehow there is a return pointer in the stack that can be overwritten with a buffer.
-> There are many terms that we use.
-> But it's a lot less complex as it may sound.
-> Because there are only two parts that are inherently important.
-> Bits that can be "1" or "0" memory space.
-> In general we group byte or word.
-> And there's a "CPU" that's well defined for the deterministic behavior that works on it.
-> It's really simpler than I thought.
-> The devil is in actual detail but essentially starts at the defined address when the "CPU" is turned on.
-> This may be "0" but may be defined as something else.
-> Some "RAMs" request memory content, view the values stored in the address, and perform the operation according to everything that the value indicates.
-> Now you can't write your own code when you try to run a program.
-> Let's restart "RAM" at address "0".
-> When an infinite loop occurs in a program, the entire system stops working.
-> But when you program an arduino, a little microcontroller, that's basically what you do.
-> But this is why some people have developed something like the "Linux" kernel.
-> You don't kill the whole system even if you abstract the hardware yourself and the program is annoying.
-> This is why the program is not just an assembly code, but rather a very complex file format.
-> It includes "ELF" files, raw code as well as many other information.
-> When you run this program, the "Linux" system actually opens the "ELF" file, interprets all required metadata and sets up an execution environment.
-> Then move to the beginning of the actual code.
: How is the execution environment?
-> You have to understand it because you want to use the program in that environment.
-> And in a way, it's actually very simple.
-> Now the devil is in real detail, but it will be understood.
-> Suppose "CPU" is about to execute the first command. (Ex. $./my-program “argument”)
-> This means that the kernel and hardware have already set everything up.
-> And what it looks like.
-> You have a big memory.
-> range from "0" to "ffffffffff."
-> In fact, it is called virtual memory because it does not have a lot of memory.
-> This seems to own all the memory, but the hardware makes you think you have it.
-> But at least "cpu" is now a huge program in memory.
-> Let's take a look at how this memory is separated from the actual program. (Ex. gdb ./stack0)
-> For example, programs are mapped from this starting address to the end address.
-> We're mapped because we're not actually at this address, but we're there if we want to.
-> Read the value of the address from the assembly code.
-> Ignore the basic physical reality and admit and know that there is this huge range.
-> In other words, you need to know the memory that you can work on.
-> There's actually a stack here, too.
-> It also defines what starts and ends at this address.
-> Thus, a stack is not actually big or shrinking, it is just a computer theory model.
-> But how is a stack actually defined?
-> "CPU" has a stack register, "ESP," and its area is located there.
-> Therefore, stack pointers can be pointed elsewhere. Like a code.
-> The stack pointer is not really special and is just a register containing an address.
-> In other words, may include the address.
-> In fact, what makes "ESP" special is that it performs wonderful tasks based on guidelines.
-> For example, the "pop eax" command will look at what values are stored in that location.
-> The place where "ESP" points is usually a stack, but it does not necessarily need to be.
-> Then write the value for that position to the "eax" register.
-> And it can be abused in Explorer.
-> For example, if you find a bug that can set the stack pointer to something else, you can create a fake stack in "heap" and point to "ESP."
-> This is also called stack pivot.
: Let's not lose the mental image of the stack we learned from computer science.
-> And you have to think about what it really is.
-> It is only the memory that the "ESP" register points to.
-> The command also generates interesting effects based on the corresponding register.
-> In the same sense, command pointers are not special.
-> Generally point to the code, but not necessarily.
-> If you can somehow control "EIP," you can point to other memory.
-> For example, there is a stack that was used by the previous exploit.
-> This is because the data, which is actually a valid assembly code, was placed in the stack.
-> You can know it as a shell code
-> "CPU" is irrelevant.
-> The "EIP" register points to some memory and the "CPU" performs the value happily.
-> And that's only half.
-> As you know, in modern systems the stack can no longer be run, so "CPU" pays some attention, but in reality it is not.
-> This means that certain areas of this memory may have different privileges.
-> Certain areas have the executable flag which means the CPU allows EIP to point there and is happy to interpret the values as instructions, but other areas like the stack don't have it.
-> And "CPU" refuses to interpret it as a command.
-> Now, if we take a closer look at what kind of data all the other data contains, we can come up with creative ways to abuse memory areas.
-> A typical stack structure is an example.
-> When the "CPU" executes a callout command, it places the current command pointer value at the address that the stack pointer points to.
-> Place on top of stack.
-> Then, when the function returns, it sets the location to which the stack pointer points and the command pointer.
-> Thus, modifying this value in the stack allows you to control it with some "EIP".
-> The function is set when it is returned, so you can decide what to run.
-> That's the classic buffer overflow.
: Another interesting data structure is the global offset table, which is basically just an area in memory containing pointers to functions, if you overwrite an entry there, you can also control what will be executed if a function is called that references an address from this table.
-> Often this value cannot be overwritten directly, but it may be possible with creativity.
-> For example, consider two objects in "heap."
-> The user object and the name object and the user object have pointers to the name object.
-> To change the name of this user, the code must follow the pointer and write a new name at that location.
-> That is, if the pointer can be overwritten, you can control where the name will be written.
-> So we could overwrite the name pointer with an address on the stack, and when we the new name for the user, we will actually overwrite the stored instruction pointer on the stack.
: Do you see what we're trying to get?
-> There is a memory that contains data.
-> Some limitations apply, as if certain memory areas are not writable and some are unworkable.
-> And there's a very stupid "CPU" that does everything that "EIP" points to.
-> And there's a program in memory that runs "CPU."
-> And this code uses the memory to do whatever it is supposed to do.
-> And it trusts in a certain integrity of the data in memory.
-> However, with a bug, you can change the value of the memory.
-> Even the impossibility of modification can be surprising.
-> And what can happen is limited by creativity and imagination.
-> One changed byte here in memory, might cause a certain piece of code to write to an location, which overwrites a function pointer of an object, which another part of the wanted to use, and suddenly executes something very different.
-> "stack buffer overflow, heap fengshui, ROP and use-after-free" are all original ways of securing data to memory.
-> The program executed by the "CPU" responds.

: This episode may not contain real useful information.
-> But if someone doesn't understand the program well, I think it's right to talk about it.
-> That abuse this way.
-> But I hope you can see value in the way you think about it.
-> There may be some fear because it seems too complicated.