|
| 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