Exercise 3.38 of "deep understanding of computer systems" requires a buffer overflow attack on a provided program. Here is the process of solving your own problems. ThisProgramWithout modification, it cannot be compiled on the Windows platform. So the following exercises are based on Ubuntu 11.04 + GCC 4.5.2
The requirement is: let the program that has always output 1 Output-559038737 (deadbeef ).
The goal is to overflow the getbuf function and get the execution right of the getbuf function.CodeThen, we still need to let this function return to the place where it should have been returned. View the assembly code of test.
08048597 <Test>:
8048597: 55 push % EBP
8048598: 89 E5 mov % ESP, % EBP
804859a: 83 EC 28 sub $0x28, % ESP
804859d: B8 E0 86 04 08 mov $0x80486e0, % eax
80485a2: 89 04 24 mov % eax, (% ESP)
80485a5: E8 12 Fe FF call 80483bc <printf @ PLT>
80485aa: E8 B4 FF call 8048563 <getbuf>
80485af: 89 45 F4 mov % eax,-0xc (% EBP)
80485b2: B8 F1 86 04 08 mov $0x80486f1, % eax
80485b7: 8B 55 F4 mov-0xc (% EBP), % edX
80485ba: 89 54 24 04 mov % edX, 0x4 (% ESP)
80485be: 89 04 24 mov % eax, (% ESP)
80485c1: E8 F6 fd ff call 80483bc <printf @ PLT>
80485c6: C9 leave
80485c7: C3 RET
The yellow highlighted address is the address that should be returned when getbuf returns. Of course, it can also be returned to other places.
Let's verify, run the program, and add a breakpoint to the getbuf function. The value of % EBP is 0xbfffefa8. We are in front of the memory, that is, 0xbfffefac, the returned address of getbuf is 080485af. The bottom of the stack stored in front of it should also be noted down, which is 0xbfffefd8. These two are used when we build the return point.
Let's take a look at the getbuf function.
Int getbuf ()
{
Char Buf [12];
Getxs (BUF );
Return 1;
}
I applied for 12 bytes of memory, so the first 12 bytes can be anything. However, this does not mean that the memory should not be overwritten at the beginning of the 13 characters. It also overwrites the return address of the getxs function. The overwrite address is calculated. Let's look at the decompiled code.
08048563 <getbuf>:
8048563: 55 push % EBP
8048564: 89 E5 mov % ESP, % EBP
8048566: 83 EC 28 sub $0x28, % ESP
8048569: 65 A1 14 00 00 00 mov % GS: 0x14, % eax
804856f: 89 45 F4 mov % eax,-0xc (% EBP)
8048572: 31 C0 XOR % eax, % eax
8048574: 8d 45 E8 lea-0x18 (% EBP), % eax
8048577: 89 04 24 mov % eax, (% ESP)
804857a: E8 15 FF call 8048494 <getxs>
804857f: B8 01 00 00 00 mov $0x1, % eax
8048584: 8B 55 F4 mov-0xc (% EBP), % edX
8048587: 65 33 15 14 00 00 00 XOR % GS: 0x14, % edX
804858e: 74 05 je 8048595 <getbuf + 0x32>
8048590: E8 37 Fe FF call 80483cc <__stack_chk_fail @ PLT>
8048595: C9 leave
8048596: C3 RET
Currently, the value of % EBP is 0xbfffefa8. Before calling getxs, Lea-0x18 (% EBP) and % eax are allocated with the starting address 0xbffef90, this is the Buf address. This address is before the current % ESP, so getxt overflows this Buf and cannot be changed to the return address of getxt itself. You can only rewrite the return address of getbuf. The address of this address is at 0xbfffefac, so we need to rewrite the data in this area. Therefore, the memory area we want to change is from 0xbfffef90 ~ 0xbfffefaf memory of 32 bytes. Of course, you can change all the subsequent memory so that you can do what you want, but now we want to complete this question. So what we need to do later is to do it.
So we hope that the program can return to 0xbfffef90 and execute our own code. The code to be executed is also very simple, just one line
Movl $0 xdeadbeef, % eax
This Code already has similar code in the above example. So we can know that the binary representation of this Code is:
B8 EF be Ad de
My environment is Ubuntu, so I use the small-end method. Then you can return the result. The Returned Code also exists. Yes
C9 C3
The returned address should be the original return address of getbuf: 0x080485af. However, leave and call both cause % ESP changes. One idea is that we can directly return without leave. In this way, the current (when getbuf is called) % EBP points to the correct return address. However, the address 0xbfffefd8 pointed to by % EBP is far away. There is too much to input.
So let's change your mind. No more ret, just use JMP! If we directly use JMP, we can directly jump to the line for preparing parameters for print (0x080485be. Hey. The code is.
FF 25 be 85 04 08
So the first 11 bytes are
B8 EF be Ad de FF 25 be 85 04 08
32-11-8 = 13 bytes in the middle.
Then D8 ef ff bf 90 EF FF BF
B8 EF be Ad de FF 25 be 85 04 08 00 00 00 00 00 00 00 00 00 00 00 00 00 00 D8 ef ff bf 90 EF FF BF
Okay. Let's give it a try and we can see that it failed. In a single step, _ stack_chk_fail is found. The current compiler. Alas, let's find something for us. I temporarily manually changed the value of % EIP to skip this step and continue.
When the RET statement is run, an error box is displayed.
For this SIGSEGV, the explanation is:
SIGSEGV --- segment fault. The possible cases of your encountering this error are:
1. Buffer overflow --- usually caused by a pointer reference out of range.
2. Stack Overflow --- please keep in mind that the default stack size is 8192 K.
3. Illegal File Access --- file operations are forbidden on our judge system.
For a moment, the value of % ESP is 0 xbfffefac, and we want to jump to 0xbfffef90. This address is outside the top of the stack. Maybe it's the reason for Stack Overflow?
Then try again and put the code to be run back. The first 11 are also random.
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 D8 ef ff bf B0 ef ff bf B8 EF be Ad de FF 25 be 85 04 08
The results are the same and the error does not seem to be the problem. So I got angry and changed the value of % EIP to 0xbeffefb0 to bypass ret. Then run the same error. At this time, I began to suspect that this is not a problem with the attack code, but that the operating system itself is not allowed to run the code on the data page. This is another time. At that time, the OS was gentle?
Then, Google found that some people encountered the same problem. I also saw a disgusting practice. The getbuff function is directly returned to the print function. In fact, this method does not make much sense for attacks. In this way, only the code in the program can be called, but only a parameter is provided for it. You have not run your own code.
It seems that only security mechanisms can be bypassed. However, today is too late. I will try again tomorrow to study whether this security mechanism can be bypassed.
Update:
Today I found the final exception explanation. The conclusion is that this mentally retarded buff overflow attack is no longer effective in modern operating systems.
There are also various solutions discussed by a group of people.