Post

Phishing Page Obfuscation. Infrastructure Madness.

Introduction

Sometimes, I like to snoop a little on known phishing sites to see how it operates, how it’s structured… maybe if there are any credentials stored in cleartext that you can snag due to a poorly locked down .htaccess or lack thereof - something about stumbling upon an open directory listing feels satisfying! The inner-workings of this phishing campaign is one that I haven’t seen before and definitely challenged me.

An alert regarding a suspicious email had come our teams way, possible phishing site. Upon initial review, sure enough there was a URL that brings you to a compromised SharePoint site, which redirects to a OneNote. Therein, there is a link to download a PDF which in turn brings you to a landing page asking that you login with your email provider of choice to obtain the PDF document; pretty typical.

Inspecting

Hello, 213232.h4y5trfd[.]repl[.]co, a bit odd to ask for third-party credentials.

I wanted to peek at the HTML to inspect the <form> parameters to see where credentials being placed into the relevant fields would end up going via POST actions. Sometimes, it can lead you to open directory listings where you can peek around for credentials being dumped into a flat file. From there you can take a peek to see if any email addresses attributed to your organizations domain shows up, ya know, doing the right thing! I was greeted with an odd modal, likely an alert() JS function.

phishlanding

Not a big deal because we can leverage Chrome’s Development Tools, just select “View Source” from the “View” menu to inspect the page, or use curl. Which reveals some content encoded in Base64. What I thought was another hurdle to just jump over turned out to be not so simple.

Turns out, we find a very long Base64 encoded string that is within a Javascript atob() function that is subsequently nestled cosily in an eval() function, sandwiched between some <script> tags… yummy.

1
<script>eval(atob('dmFyIHM9Ij1cImVwZHV6cWYhaXVubT8OCz...='))</script>

With Javascript, the atob() method will decode a Base64 encoded string while eval() will effectively “execute” what will be decoded by eval() which, as we’ll see below, is a combination of heavily obfuscated Javascript and HTML to be renderer by a browser.

yodawg Yo dawg, heard you like Base64. So we Base64’d your Base64!

Turns out, the payload that is Base64 encoded is double-encoded, so I decoded and then decoded again and ran it through a beautifier. To which, we’re met with some heavily obfuscated JavaScript. Also turns out the Base64 payload was a mile long due to insane amounts of padding. While I don’t know with 100% certainty, I’m sure with enough persistence there’s a way to reverse this, and I’ll add it to the retrospective as an item for me to pickup and learn.

obfusc

This insanely long string is being held in a variable called s as seen above. At the very end of the code, there’s a section that performs some magic by getting the total string length, passing it through String.fromCharCode(), dumping the output into a new variable m as the deobfuscated code to be rendered via document.write()

1
2
3
4
5
6
7
8
var m = "";

var i = 0;
for (; i < s.length; i++) {

    m = m + String.fromCharCode(s.charCodeAt(i) - 1);
}
document.write(m);

What’s going on in there?

I wanted to see how the application functions when providing it some bogus credentials and submitting the data, so I fired up Burpsuite and interacted with the page for a bit. The robots.txt is wack, disallowing user-agent strings that exist in nearly every galaxy; 1,571 lines of disallows.

When submitting a bogus email address and password for a totally valid Office 365 account, I saw an interesting POST request in Burp.

burp Where are you going?!

When sending a request to that URI without any data:

error

Unlike a typical quick-and-dirty phishing page that would take input and write it to a flat file on the same server, the data is being sent in a HTTP POST from the phishing landing page, to /jg1/next.php on tamacha.dyndns[.]dk - which, interestingly enough, has an open directory listing over there!

indexof

In the directory listing, we can see the jg1 directory referenced in the HTTP POST from Burp - unfortunately, no credentials are stored in the clear. In fact, no credentials are stored in any of the directories available to us. Many of the directories contain a next.php file as we saw referenced in Burp, along with other PHP files that either redirect to legitimate login pages or to cloned login pages to collect credentials and other PII for other campaigns for sites such as Xfinity and OurTime.

We can also likely assume by the timestamp for the cgi-bin directory that this was setup very recently - at least one day after the server was spun up, as we’ll see in the SSL certificate information below.

Infrastructure

My theory was that within the PHP code of next.php (which are found in almost all of the folders in the directory listing, likely related to other phishing campaigns) is a hook into a local MySQL instance. Where HTTP POST data being sent to that URI, as observed in Burp, is subsequently being written to a local MySQL instance on the server, so our dreams of actually validating compromised entities are pretty much crushed. Let’s keep going anyway!

For smiles and grins, I plugged the IP address of the box into Shodan to see if it has been indexed yet.

shodan

To which, the probability of that theory is high. The infrastructure is being hosted in DigitalOcean at 204.48.29[.]124 and per the date within the self-signed SSL certificate details of the cPanel instance on the server was on 9/21/2020:

openssl Is that some DigitalOcean?

Also, given the CN in the certificate being cpanel-whm-centos-s-2vcpu-2gb-nyc1-04 we could probably now agree that it’s a cPanel & WHM server spun up via DigitalOcean’s one-click Droplet deployment.

Given the credentials being (presumably) committed to the local MySQL instance from data being sent via HTTP POST to next.php, it’s likely that it’s only capable of handling POST so I figured it would be pointless to try and perform any type of SQLi or fuzzing to see if data could be pulled. Anything is possible, but just outside of my scope right now.

I Wanted to do a Diagram, because it’s cool!

As this section’s title suggests, I need to put an “attack flow” diagram in here to illustrate how this was working under the hood, with its multi-tiered credential stealing infrastructure… or something.

diag

This post is licensed under CC BY 4.0 by the author.