intmain() { init(); bool end = false; while (!end) { int choice; printf("1. Take a fortune\n" "2. Share a story\n" "3. Exit\n" "> "); scanf("%d%*c", &choice); switch (choice) { case1: system("fortune"); break; case2: { int size; printf("Size: "); scanf("%d%*c", &size); char buf[size % MAX_SIZE]; #VULN printf("Text: "); read(0, buf, size); write(1, buf, size); } break; case3: { end = true; } break; default: printf("Invalid choice\n"); } } }
Summary
Make buf size the same or bigger then MAX_SIZE to leak stack and make it buffer overflow. Than use stack leak with fill buffer null byte to fix pivoting stack return.
Solution
Given a statically linked binary chall using musl libc and all live protection with Partial Relro.
It can be seen that there are 3 options containing:
The first option is to run the system("fortune") //Not Important
The second option is to declare a variable with size % MAX_SIZE, then read as much size and write to stdout as much size as (just like regular print)
The third option exits the menu to be used for RIP control
So in option 2 if you provide an input of MAX_SIZE which becomes 0, when reading as many as 300 becomes a buffer overflow. For the leak address, you can declare a variable size MAX_SIZE so that it becomes a char buf[0] and after that is the content of the stack address that can be used as a leak. Next, set the breakpoint after the exit option and analyze what was done.
It can be seen that when choosing the exit option, the instructions to be carried out Set eax = 0 esp - &[ebp-0xc] pop ecx (Important where to control the return later) pop ebx pop esi pop ebp esp - &[ecx - 4] To operate an eip, a true esp is required. esp will change depending on the content of the first ebp and ecx. To make it easier, i padded until pop ecx and set: ebp - 0xc = 0 ecx - 4 = stack leak The padding offset \x00 is at 44 for pop ecx and the rest I spam ret2system to get the shell because in the binary there is a system function and the /bin/sh string.