|  | 
|  | 1 | +# Labyrinth (easy) | 
|  | 2 | +This challenge involves exploiting a simple buffer overflow and then redirecting execution to a different function. | 
|  | 3 | + | 
|  | 4 | +First we check the protections the binary has, using `checksec` | 
|  | 5 | +``` | 
|  | 6 | + Arch: amd64-64-little | 
|  | 7 | + RELRO: Full RELRO | 
|  | 8 | + Stack: No canary found | 
|  | 9 | + NX: NX enabled | 
|  | 10 | + PIE: No PIE (0x400000) | 
|  | 11 | + RUNPATH: b'./glibc/' | 
|  | 12 | +``` | 
|  | 13 | + | 
|  | 14 | +Pretty much nothing, there's no canary and no ASLR. | 
|  | 15 | + | 
|  | 16 | +Loading the binary into Ghidra, I analyzed the `main` function. | 
|  | 17 | + | 
|  | 18 | +```c | 
|  | 19 | +undefined8 main(void) | 
|  | 20 | + | 
|  | 21 | +{ | 
|  | 22 | + int iVar1; | 
|  | 23 | + undefined8 local_38; | 
|  | 24 | + undefined8 local_30; | 
|  | 25 | + undefined8 local_28; | 
|  | 26 | + undefined8 local_20; | 
|  | 27 | + char *local_18; | 
|  | 28 | + ulong local_10; | 
|  | 29 | +  | 
|  | 30 | + setup(); | 
|  | 31 | + banner(); | 
|  | 32 | + local_38 = 0; | 
|  | 33 | + local_30 = 0; | 
|  | 34 | + local_28 = 0; | 
|  | 35 | + local_20 = 0; | 
|  | 36 | + fwrite("\nSelect door: \n\n",1,0x10,stdout); | 
|  | 37 | + for (local_10 = 1; local_10 < 0x65; local_10 = local_10 + 1) { | 
|  | 38 | + if (local_10 < 10) { | 
|  | 39 | + fprintf(stdout,"Door: 00%d ",local_10); | 
|  | 40 | + } | 
|  | 41 | + else if (local_10 < 100) { | 
|  | 42 | + fprintf(stdout,"Door: 0%d ",local_10); | 
|  | 43 | + } | 
|  | 44 | + else { | 
|  | 45 | + fprintf(stdout,"Door: %d ",local_10); | 
|  | 46 | + } | 
|  | 47 | + if ((local_10 % 10 == 0) && (local_10 != 0)) { | 
|  | 48 | + putchar(10); | 
|  | 49 | + } | 
|  | 50 | + } | 
|  | 51 | + fwrite(&DAT_0040248f,1,4,stdout); | 
|  | 52 | + local_18 = (char *)malloc(0x10); | 
|  | 53 | + fgets(local_18,5,stdin); | 
|  | 54 | + iVar1 = strncmp(local_18,"69",2); | 
|  | 55 | + if (iVar1 != 0) { | 
|  | 56 | + iVar1 = strncmp(local_18,"069",3); | 
|  | 57 | + if (iVar1 != 0) goto LAB_004015da; | 
|  | 58 | + } | 
|  | 59 | + fwrite("\nYou are heading to open the door but you suddenly see something on the wall:\n\n\"Fly li ke a bird and be free!\"\n\nWould you like to change the door you chose?\n\n>> " | 
|  | 60 | + ,1,0xa0,stdout); | 
|  | 61 | + fgets((char *)&local_38,0x44,stdin); | 
|  | 62 | +LAB_004015da: | 
|  | 63 | + fprintf(stdout,"\n%s[-] YOU FAILED TO ESCAPE!\n\n",&DAT_00402541); | 
|  | 64 | + return 0; | 
|  | 65 | +} | 
|  | 66 | +``` | 
|  | 67 | +
 | 
|  | 68 | +First, 69 should be provided as a door number, in order to get into the vulnerable path of execution. | 
|  | 69 | +
 | 
|  | 70 | +Then `fgets` will read 0x44 bytes into `local_38`. We see at the top of the function that is has 6 variables on the stack starting from `local_38`, each is 8 bytes large. | 
|  | 71 | +
 | 
|  | 72 | +Then we can overwrite the RBP of the calling function and then the **return address**. | 
|  | 73 | +
 | 
|  | 74 | +Browsing the list of functions in Ghidra, I found the `escape_strategy` function, which gives us the flag. | 
|  | 75 | +
 | 
|  | 76 | +As a final trick, stack alignment was an issue, therefore a ROP gadgets needed to be added to the payload, in order to align the stack pointer to 16 bytes again. | 
|  | 77 | +To fix alignment a simple `ret` ROP gadget can be placed. This will just pop the element from the stack and set the program counter to it. | 
|  | 78 | +
 | 
|  | 79 | +To find the ROP gadget I will use the `pwntools` functions. | 
|  | 80 | +
 | 
|  | 81 | +So our payload that gets put on the stack will be: | 
|  | 82 | +``` | 
|  | 83 | +[48 - padding] + [8 - RBP overwrite] + [8 - ret gadget] + [8 - win function address] | 
|  | 84 | +``` | 
|  | 85 | +
 | 
|  | 86 | +Running `solve.py` will give us the flag. | 
0 commit comments