Arman Ridho MaulanaArman Ridho
  • Home
  • About
  • Skills
  • Experience
  • Projects
  • Certifications
  • Blog
  • Contact
Download CV
Back to Blog
August 30, 2026ssrfred-teamweb-securitypentest

Server-Side Request Forgery: When the Server Becomes Your Unwitting Courier

Gue cerita soal pengalaman nemuin celah SSRF di fitur generator laporan klien, gimana server mereka sendiri gue suruh ambil data dari dalam jaringan internal, sampai kepoin metadata cloud yang seharusnya gak boleh kemana-mana.

Beberapa bulan lalu gue dapet tugas buat ngelakuin penetration test di sebuah aplikasi web punya klien. Aplikasinya lumayan standar: portal buat karyawan internal yang bisa bikin laporan otomatis dari data yang mereka input. Di salah satu fiturnya ada tombol "Generate laporan dari website", di mana user tinggal masukin URL, terus sistem bakal nge-fetch halaman itu, ambil teksnya, terus jadiin PDF. Pas gue liat fitur itu, insting red team gue langsung berbunyi: kalau server yang disuruh fetch URL secara sepihak, berarti server itu sendiri yang bakal jadi kurir buat gue. Dan dari situlah cerita soal Server-Side Request Forgery ini mulai.

Gue nulis catatan ini bukan buat pamer "gue berhasil nge-hack", tapi buat bagi perspektif gimana sebuah fitur yang kelihatannya sangat polos bisa jadi jalan tol menuju dalem jaringan klien. SSRF itu menarik karena dia nggak butuh gue duduk di dalam jaringan mereka. Gue cuma butuh aplikasi mereka yang dengan senang hati mau ngeakses apa pun yang gue suruh, atas nama server mereka sendiri.

Server-Side Request Forgery hero infographic

Awalnya Cuma Mau Bikin Laporan Otomatis

Fitur generator laporan itu dibikin biar enak dipakai. Bayangin kamu kerja di tim HR, terus mau bikin ringkasan dari artikel berita buat dilewatkan ke manajemen. Kamu paste URL beritanya, klik tombol, dua detik kemudian keluar PDF rapi. Dari sisi user, ini produktivitas. Dari sisi security engineer yang lagi ngopi dan baca kode, ini bom waktu yang dikasih label "fitur".

Cara kerjanya kira-kira gini: di backend, ada kode yang mengambil input URL dari form, terus langsung memanggil fungsi fetch atau HttpClient ke URL tersebut. Di banyak bahasa, ini cuma satu baris: http.Get(userURL). Nggak ada validasi, nggak ada allowlist, nggak ada batasan soal ke mana request itu boleh pergi. Si developer mikirnya, "lah ini kan buat ambil berita, pasti user masukin URL publik." Padahal di dunia nyata, user adalah orang asing di internet yang punya banyak waktu luang dan niat kurang baik.

Pas gue tes, gue gak langsung serang hal gila-gilaan. Gue mulai pelan. Gue masukin URL milik gue sendiri yang nyatet semua request yang masuk. Dan bener, server klien nge-fetch URL gue. Di log gue, kelihatan IP publik kantor mereka, user-agent berupa bahasa pemrograman dan library yang dipakai, plus header internal. Dari sini gue udah tau: aplikasi ini percaya 100 persen sama input user buat menentukan tujuan request.

SSRF Itu Sebenarnya Apa Sih

Sebelum lanjut ke bagian seru, gue mau jelasin dulu secara manusiawi apa itu SSRF. Bayangin kamu suruh satpam kantor ambil paket di alamat yang kamu tul sendiri. Satpam itu punya badge masuk ke semua ruangan, termasuk ruang server dan brankas. Kalau kamu nurutin aturan, kamu cuma bakal nyuruh dia ambil paket di toko sebelah. Tapi kalau sistemnya gak ngecek alamat, kamu bisa tul "ambilin file di ruang server belakang" atau "bukain brankas". Si satpam bakal nurut karena dia disuruh ambil apa pun, dan dia punya akses ke mana-mana.

Nah, dalam SSRF, "satpam" itu adalah server aplikasi korban. Dia punya akses ke jaringan internal, ke layanan lokal, ke metadata cloud, dan ke berbagai hal yang seharusnya gak kemana-mana. "Alamat yang kamu tul" itu adalah URL yang gue masukin. Kalau aplikasi gak nge-filter ke mana request boleh dikirim, gue bisa suruh server korban nyerang dirinya sendiri, atau nyerang mesin lain di dalam jaringan yang gak kelihatan dari luar.

Bedanya sama CSRF atau XSS: SSRF itu server yang jadi korban utamanya, bukan browser user. Gue gak butuh kamu klik link jahat. Gue cuma butuh satu endpoint yang mau fetch URL atas perintah gue. Itu aja. Tenang aja, gue gak bakal kasih payload jadi-jadian yang bisa langsung dicopas buat ngerusak, tapi gue bakal cerita polanya biar kamu paham kenapa ini berbahaya.

Gimana Gue Nemu Lubangnya

Balik ke fitur generator laporan. Setelah yakin server mau fetch URL gue, gue mulai ganti targetnya pelan-pelan. Gue coba suruh dia akses localhost di berbagai port. Pertama gue tes http://127.0.0.1:80 dan liat apakah responsnya beda dibanding URL publik. Bedanya kelihatan: dia balikin konten dari web server lokal mereka. Artinya request gue dieksekusi dari dalam, bukan dari luar.

Terus gue naikin levelnya. Gue suruh dia akses http://127.0.0.1:8080, http://127.0.0.1:3306, dan port-port umum lainnya. Port 3306 itu MySQL. Walaupun gue gak bisa langsung masuk ke database lewat fetch HTTP biasa, respons error-nya ngasih tahu gue kalau ada layanan MySQL jalan di situ. Dalam bahasa pentest, ini namanya internal port scanning: gue memetakan layanan apa aja yang jalan di dalam jaringan, cuma dari satu fitur web yang polos.

Yang bikin gue tersenyum sendiri ialah saat gue sadar aplikasi ini jalan di atas cloud. Dan kalau jalan di cloud, ada satu alamat yang hampir selalu ada: 169.254.169.254. Itu alamat metadata instance. Di layanan cloud mayoritas, alamat itu adalah "ruang brankas" yang bisa dibaca sama instance buat dapetin credential sementara, token akses, dan info konfigurasi. Kalau aplikasi diizinin akses ke sana (dan secara default, dia biasanya diizinin), maka siapa pun yang bisa suruh server fetch alamat itu bakal dapet kunci sementara ke cloud account klien.

Pas Gue Suruh Server Ambil URL Intern

Gue masukin http://169.254.169.254/latest/meta-data/ ke form. Dan dia balikin daftar direktori. Jantung gue kecipratan kopi. Ini bukan "kebocoran kecil", ini pintu depan ke ruang kontrol cloud mereka. Di situ ada path ke IAM credential, ke user data yang kadang isinya script bootstrap lengkap dengan password, sampai ke info tentang siapa pemilik instance.

Di beberapa cloud, versi lama dari metadata endpoint ini ngasih credential langsung tanpa tanya. Gue tinggal fetch http://169.254.169.254/latest/meta-data/iam/security-credentials/ dan dapat temporary access key, secret, sama session token. Dengan tiga hal itu, gue bisa pakai CLI cloud dari laptop gue sendiri dan bertindak seolah-olah gue adalah aplikasi klien yang sah. Aksesnya terbatas sama permission role tersebut, tapi dalam banyak kasus nyata, role itu kebanyakan dikasih akses lebih dari yang seharusnya. Orang buat cloud sering kali kasih akses "admin aja biar cepet", dan itu yang jadi bumerang.

Gue catat temuan ini dengan hati-hati. Gue gak pake credential itu buat apa-apa selain membuktikan dia bisa dibaca. Dalam pentest yang bener, batasnya ya sampai situ: tunjukin lubangnya, jangan manfaatin buat ngerusak. Tapi bayangin kalau yang nemuin ini bukan gue, melainkan orang yang beneran punya niat. Dalam hitungan menit mereka bisa punya akses ke bucket penyimpanan, ke database, atau ke layanan lain di dalam akun yang sama.

Saat Metadata Cloud Jadi Korban

Bagian metadata cloud ini penting banget buat gue ceritain karena ini salah satu dampak SSRF yang paling sering diremehin. Banyak tim engineering mikir, "lah server kan di cloud, pasti aman, ada firewall." Padahal firewall melindungi dari luar. SSRF itu serangan dari dalam, lewat aplikasi yang emang diizinin jalan di dalam.

Ada detail teknis yang bikin ini makin licik: alamat 169.254.169.254 itu alamat link-local, artiinya cuma bisa diakses dari dalam instance itu sendiri. Dari laptop gue di luar, gue gak bakal bisa nyentuh dia. Tapi karena aplikasi klien jalan di dalam instance tersebut, dan aplikasi itu mau fetch URL atas perintah gue, maka "dari dalam"-nya jadi terwakilkan oleh server mereka. Gue gak nembus firewall; gue numpang lewat pintu yang udah kebuka buat satpam kantor tadi.

Poin penting buat kamu yang lagi bangun sistem: jangan pernah biarin aplikasi punya akses bebas ke alamat metadata, ke IP privat, atau ke localhost tanpa filter. Banyak insiden besar di industri mulai dari satu fitur fetch URL yang gak diawasi. Gue sering liat tim dev kaget pas diajarin ini, karena emang gak ada yang ngajarin di tutorial bikin CRUD pertama mereka.

Mainan Bypass: Kadang Server Nge-blokir, Kadang Gak

Tentu aja gak semua aplikasi se-polos punya klien tadi. Banyak yang udah pasang filter: mereka nolak kalau URL mengandung 127.0.0.1, localhost, atau 169.254.x.x. Tapi di sisi red team, bagian paling asyik justru pas nemuin tembok: gue mulai cari celah buat muterinya.

Cara pertama yang gue suka: pakai representasi IP selain bentuk desimal titik. 127.0.0.1 bisa ditulis 2130706433 dalam bentuk integer desimal, atau 0x7f000001 dalam heksadesimal, atau 0177.0.0.1 dalam oktal. Beberapa filter cuma ngecek string "127.0.0.1" secara harfiah, jadi bentuk lain lolos. Ini bukan sihir, cuma keteledoran di logika validasi.

Cara kedua: DNS yang gue kontrol. Gue bisa bikin subdomain di domain gue yang mengarah ke 127.0.0.1, misalnya internal.gue.dev resolve ke 127.0.0.1. Aplikasi baca URL-nya sebagai domain biasa, nge-resolve ke 127.0.0.1, terus fetch localhost. Filter yang cuma ngecek awalan "http://127" gak nyangka domain bakal jadi localhost.

Cara ketiga yang lebih canggih: DNS rebinding. Ini teknik di mana domain gue balikin IP publik pas pertama kali di-resolve (biar lolos allowlist), terus pas aplikasi benar-benar fetch, DNS gue balikin IP internal. Butuh timing yang pas, tapi kalau berhasil, filter allowlist jadi sia-sia karena IP tujuan berubah setelah pengecekan.

Cara keempat: redirect. Kadang aplikasi cuma ngecek URL awal, tapi kalo server gue balikin HTTP redirect ke http://169.254.169.254/..., aplikasi banyak yang nurutin redirect tanpa ngecek ulang tujuan akhirnya. Jadi gue masukin URL publik gue, filter senang, terus gue redirect ke dalam, aplikasi tetep nurut.

Gue cerita ini bukan buat ngajarin nge-hack, tapi biar kamu yang di sisi biru paham: filter berbasis string itu rapuh. Validasi yang bener harus resolve dulu IP tujuannya, terus nolak semua IP privat, loopback, link-local, dan IPv6 yang setara, baru boleh lanjut. Dan jangan nurutin redirect ke sembarang tempat.

Dari Sekadar Baca File Sampai Jadi Pintu Belakang

Selain mbandel di metadata cloud, SSRF juga sering dipakai buat bacai file lewat skema URL tertentu. Di beberapa lingkungan, gue bisa pakai file:///etc/passwd atau file:///var/run/secrets/kubernetes.io/... buat bacai file langsung dari disk server. Di Kubernetes, misalnya, token akses service account disimpen di path tertentu yang bisa dibaca lewat file scheme kalau aplikasi pemroses URL-nya longgar.

Gue pernah nemuin kasus di mana SSRF kecil berujung jadi akses ke layanan manajemen internal yang gak punya autentikasi sama sekali, karena si arsitek mikir, "lah ini kan di jaringan dalem, siapa yang nyampe?" Ternyata jawabannya: server aplikasi mereka sendiri, yang bisa gue suruh lewat fitur web publik. Jadi "di jaringan dalem" bukan jaminan apa-apa kalau ada satu fitur yang mau jadi kurir buat orang luar.

Dampaknya bisa bermacam-macam: baca data sensitif, muterin autentikasi internal, lanjut ke remote code execution kalau ada layanan internal yang nerima input berbahaya, sampai keluarnya data ke publik. Gue selalu ingetin klien: satu endpoint fetch URL yang kelihatannya remeh bisa jadi rantai awal dari insiden yang jauh lebih gede.

Sisi Lain: Gimana Seharusnya Ini Di-tutup

Sebagai orang yang suka ngoprek celah, gue juga punya kewajiban buat ngasih solusi, bukan cuma lapor. Untuk SSRF, penutupnya gak bisa cuma satu lapis. Gue selalu rekomendasiin pendekatan bertingkat.

Pertama, batasi tujuan request sedari awal. Kalau fitur emang cuma butuh ambil dari beberapa sumber resmi, taruhlah daftar domain itu di allowlist dan cuma izinin yang ada di situ. Jangan izinin IP mentah, jangan izinin localhost, jangan izinin metadata. Allowlist jauh lebih aman daripada denylist karena kamu yang nentuin yang boleh, bukan cuma nolak yang kepikiran.

Kedua, validasi di level jaringan. Pisahkan instance aplikasi dari layanan sensitif pakai network policy atau security group. Di cloud, matiin akses ke 169.254.169.254 dari instance aplikasi lewat aturan firewall lokal atau metadata service dengan IMDSv2 yang wajibin token sesi. IMDSv2 itu penambalan dari penyedia cloud supaya metadata gak bisa dibaca cuma dengan GET polos; dia butuh langkah permintaan token dulu. Kalau aplikasimu gak dirancang ambil token itu, maka SSRF pun gak bakal dapet credential. Ini satu perubahan kecil yang nyelamatin banyak orang.

Ketiga, jangan nurutin redirect sembarangan dan matiin skema selain HTTP/HTTPS. Kalau pemroses URL kamu mau nerima file://, gopher://, atau dict://, kamu buka pintu ke teknik yang jauh lebih berbahaya dari sekadar fetch web. Batasi protokol yang diizinin.

Keempat, tambahin autentikasi di semua layanan internal. Jangan pernah anggap "di dalem aman". Setiap layanan internal harus tetep butuh credential, biar kalau ada yang berhasil nyusup lewat SSRF, mereka tetep ketemu tembok login, bukan langsung masuk ruang kontrol.

Kelima, observasi. Pasang deteksi di sisi jaringan buat request aneh ke 169.254.169.254 atau ke rentang IP privat dari aplikasi publik. Di SOC, pola "server publik tiba-tiba nanya metadata cloud" itu harusnya bunyi alarm, bukan dianggap traffic biasa.

Yang Gue Pelajarin Setelah Semalam Itu

Pulang dari project itu, ada beberapa hal yang gue simpen buat diri sendiri. Pertama, fitur yang paling "membantu user" sering kali adalah fitur yang paling berisiko. Generator laporan, previewer link, fetcher thumbnail, webhook tester, semua itu punya satu kesamaan: mereka disuruh aplikasi buat akses URL atas nama server. Setiap kali gue liat fitur kayak gitu, gue langsung curiga. Bukan karena gue sinis, tapi karena pengalaman nunjukin itulah jalan masuknya.

Kedua, validasi berbasis daftar tolak itu ilusi keamanan. Orang nulis denylist 127.0.0.1, localhost, 0.0.0.0 terus ngerasa aman, padahal masih ada belasan cara nulis ulang alamat yang sama. Keamanan beneran datang dari "yang gak diizinin secara eksplisit, ditolak".

Ketiga, cloud itu nyaman tapi butuh disiplin. IMDSv2, network policy, least-privilege IAM, itu semua gratis secara konsep tapi sering kelewat karena orang buru-buru deploy. SSRF ke metadata cloud udah jadi penyebab dari terlalu banyak kebocoran besar di industri, dan hampir semuanya bisa dihindari cuma dengan nyalain IMDSv2 dan kasih aplikasi akses minimal.

Keempat, red team dan blue team sebenernya ngejar hal yang sama: sistem yang gak gampang jadi korban. Gue di sisi merah cuma nunjukin di mana satpamnya kemurahan hati. Tim biru yang harus ngasih dia batas. Diskusi antara dua sisi ini yang bikin gue betah di dunia security, karena gak ada akhirnya, selalu ada cara baru buat muterin dan cara baru buat ngeblokir.

Terakhir, buat kamu yang lagi belajar dan takut "apakah gue cukup pinter buat ngerti security": gue mulai dari baca dokumentasi fitur biasa dan nanya "kalau gue masukin ini, apa yang terjadi?" SSRF gak butuh kamu jago cryptography atau ngerti assembly. Dia butuh kamu paham gimana aplikasi bergerak di jaringan dan berani eksplorasi satu langkah lebih jauh dari yang tertulis di tutorial. Rasa penasaran yang teratur itu senjata utamanya.

Jadi kalau suatu hari kamu bikin fitur yang mau fetch URL atas nama server, berhenti sebentar. Tanya ke diri sendiri: ke mana aja dia boleh pergi, siapa yang boleh nyuruh dia, dan apa yang terjadi kalau yang nyuruh itu orang asing. Satpam kantormu mungkin baik dan nurut, tapi dia harus tau mana ruangan yang gak boleh dia bukain buat sembarang orang.

Related Posts

Aug 17, 202610 min read

SQL Injection: From a Broken Login Form to a Full Database Dump

Cerita gue waktu pertama kali nemu celah SQL injection di form login, gimana gue manfaatin kelemahan query database buat ngeluarin data yang seharusnya tertutup rapat, plus pelajaran buat nulis kode yang nggak gampang diretas.

sql-injection·web-security·red-team·penetration-testing
Read article
Aug 14, 202612 min read

OSINT Recon: Mapping the Target Before the First Exploit

Sebelum exploit apa pun dikirim, red teamer yang baik sudah tahu peta targetnya dari informasi publik. Artikel ini bercerita tentang bagaimana OSINT dan passive recon — dari Google dorking, Shodan, hingga Wayback Machine — berhasil membuka jalan masuk ke engagement yang tampaknya mustahil ditembus.

osint·recon·red-team·pentest
Read article
Aug 23, 202612 min read

Web Application Firewall: What I Learned After Mine Got Bypassed

Gue pikir pasang WAF itu cukup buat amanin website, ternyata baru setengah jalan. Artikel ini cerita perjalanan gue belajar dari WAF yang berhasil di-bypass: soal tuning rules, baca log, teknik bypass, dan kenapa WAF cuma satu lapisan dari pertahanan yang jauh lebih besar.

waf·blue-team·web-security·hardening
Read article
A
Arman Ridho

Cybersecurity & IT infrastructure professional building secure, reliable systems in Jakarta.

Navigate
  • Home
  • About
  • Skills
  • Projects
  • Contact
Explore
  • Experience
  • Certifications
  • Blog
  • Download CV
© 2026 Arman Ridho Maulana. All rights reserved.Built with Next.js & Gravity UI