JUN0.DEV
JUN0.DEV

AttackLab - Buffer Overflow Writeup

Published on
  • avatarJunyoung Yang
GitHubNeibce/SysSoft-LABS-2024System Software(059) LAB 과제 풀이
  • The Attack Lab: Understanding Buffer Overflow Bugs
  • Solving the given binary through disassembly, GDB debugging, and buffer overflow bugs
  • Writeup

1. Phase 1

image

From the getbuf function, I could see that 0x28 bytes were allocated on the stack. To trigger touch1 through a buffer overflow, I needed to fill 0x28 bytes and then write the address of touch1.

image

The address of touch1 was 0x401859, so the answer was:
image

The address at the bottom was written in little-endian format.

2. Phase 2

From the source code provided in the writeup, I could see that the phase passed when the first argument val matched the cookie.
image

Since val is the value stored in rdi when touch2 is executed, I had to put the cookie value into rdi before calling touch2.
image

I wrote the assembly code and converted it into byte form with gcc and objdump.
image

To find where the string read by Gets was stored, I set a breakpoint right after the Gets call and checked rsp.
image image

The final answer was as follows. The first line puts the cookie value into rdi. The following lines are padding for the buffer overflow. The second-to-last line is the starting address of the string read by Gets, so the injected instruction on the first line can be executed. The final line is the address of touch2.
image image

3. Phase 3

image

This phase could be solved in almost the same way as Phase 2.

From the C code provided in the writeup, I found that the cookie value was converted into a hexadecimal string and compared. Therefore, I had to execute touch3("53374143").

I reused the answer from Phase 2, changed the final touch2 address to the touch3 address, and added the cookie string "53374143" at the bottom. I placed the cookie string at the bottom because the writeup warned that calls to hexmatch and strncmp could push values onto the stack and overwrite earlier contents.

Since rdi had to contain the address of the cookie string, I calculated it as 0x556353a8 + 0x38. Then I used gcc and objdump again to add the instruction for putting that address into rdi on the first line, and the phase passed.

image image

4. Phase 4

This phase had the same goal as Phase 2, so I knew that I had to put the cookie value into rdi. Unlike Phase 2, code could not be executed from the stack, so the best approach seemed to be placing the cookie value on the stack and popping it into a register. I looked for a popq %rdi gadget with objdump, but could not find one. I only found popq %rax at 0x401a49.
image

I then searched for movq %rax, %rdi and found it at 0x401a54, so I decided to use popq %rax followed by that mov gadget.
image

image
The first five lines are padding for the buffer overflow. The sixth line is the address of the popq gadget found earlier. Since the cookie value had to be popped, I placed the cookie value on the next line. After that, I wrote the address of the movq gadget and finally the address of touch2 from Phase 2. This passed the phase.

5. Phase 5

Like Phase 3, this phase required executing touch3, so I had to put the address of the "53374143" string into rdi. Unlike Phase 3, I could not know the stack address before execution. I thought I could solve it by reading rsp, adding the offset to the string, and storing the result in rdi.

I searched for gadgets between start_farm and end_farm that moved rsp, and only found movq %rsp, %rax at 0x401b11. So I moved rsp into rax, then used the movq %rax, %rdi gadget to move it into rdi. The path was rsp -> rax -> rdi.
image (0x401b11 movq %rsp, %rax)
image (0x401a54 movq %rax, %rdi)

After that, I needed to add the distance from the current rsp value to the cookie string placed at the end. I found a function named add_xy inside the farm region, which took two parameters and returned their sum.
image

I could pass the saved rsp value and the distance to the cookie string into add_xy. Since rsp had already been moved into rdi, I only needed to put the distance into rsi. I tried to put the value into rsi with a pop instruction, but only pop %rax existed at 0x401a49. So after popping into rax, I moved the value through eax -> edx -> ecx -> esi. I could not find a direct move from eax to esi, so I had to go through the intermediate registers. I first used a temporary distance and calculated later that the actual distance was 72(0x48).
image (0x401a49 pop %rax)
image (0x401ab4 movl %eax, %edx)
image (0x401a72 movl %edx, %ecx)
image (0x401a78 movl %ecx, %esi)

Finally, I executed add_xy, moved the return value in rax to rdi using the 0x401a54 movq %rax, %rdi gadget, and then executed touch3. That passed the phase.
image