2fa Can Be Hacked

1 view
Skip to first unread message

Kellye Tunks

unread,
Aug 5, 2024, 8:39:11 AM8/5/24
to onintuhi
Twoyears ago, something very strange happened to me while working from my home network. I was exploiting a blind XXE vulnerability that required an external HTTP server to smuggle out files, so I spun up an AWS box and ran a simple Python webserver to receive the traffic from the vulnerable server:

Perfect, this meant that I was able to receive network traffic on the box. Everything seemed good to go, but right as I switched back to exploiting the vulnerability, something very unexpected appeared in my log file:


The same unknown IP address had intercepted and replayed both HTTP requests from my computer and iPhone. Somehow, someone was intercepting and replaying the web traffic from likely every single device on my home network.


The only real option left was that my modem had been hacked, but who was the attacker? I queried the owner of the IP address and found that it belonged to DigitalOcean. Strange. That definitely didn't belong to my ISP.


To kick off an investigation, I sent the IP address to some friends who worked for threat intelligence companies. They sent me a link to the VirusTotal listing for the IP address which detailed all of the domains which resolved to the IP address over the past few years.


Out of the last 5 domains that were tied to the IP address, 3 were phishing websites, and 2 were what appeared to be mail servers. The following domains all at one point in time resolved to the DigitalOcean IP address:


Two of the domains associated with the 159.65.76.209 IP address were isglatam.online and isglatam.tk. These were both at one point in time phishing websites for isglatam.com, a South American cybersecurity company.


After visiting the real ISG Latam website, we learned that they are based out of Paraguay and partnered with Crowdstrike, AppGate, Acunetix, DarkTrace, and ForcePoint. From a 10 minute read of everything, it appeared that the people who were intercepting my traffic had tried to phish ISG Latam using the same IP address.


Now this was odd. The IP address, just one year prior, was being used to host phishing infrastructure that targeted a South American cybersecurity company. Assuming that they have been in control of this IP address for 3 years, it would mean that they have used it for at least 2 different phishing campaigns and what appeared to be a C&C server for router malware?


The signature of the attacker was super interesting, because they were doing a lot of different malicious activities from the same box and apparently had not gotten suspended in over 3 years. It was really hard to piece together their intent with the Adidas, ISG Latam, and modem hacking thing all coming from the same IP address. There was a chance that the IP had rotated between different owners over the years, but it didn't seem likely as the gaps in between everything were long and it was unlikely that it was immediately reassigned to another malicious party.


The first thing that caught their attention (having worked on more malware analysis a lot more than I had) was the format of the two mail server domains (limit742921.tokyo and jingoism44769.xyz). They pulled the IP address of the mx1 subdomain for limit742921.tokyo and then ran a reverse IP search on all domains that had at one point in time pointed to that same IP address. There were over 1,000 domains that all followed the exact same pattern...


Due to the mass-number of domains and algorithmic structure of the registered address, this appeared to be a domain generation algorithm used by malware operators to rotate the resolving address for the C&C server for the purpose of obfuscation. There was a good chance that the IP address replaying my traffic was a C&C server, and the two domains which I thought were mail servers were actually algorithmically generated pointers to the C&C server.


To theorycraft a little bit, if I were a hacker who wanted to compromise my modem I'd likely target whatever infrastructure powered the support tools that the agents were using. There was probably some internal website for device management that support agents used, backed by an API that could execute arbitrary commands and change/view administrative settings of customer devices. If I could find some way to access this functionality, it might shed light on how I might have been originally hacked and patch out at least one method for someone to compromise my modem.


Without actually having a Cox business account myself, I opened the login page for the portal and grabbed a copy of the main.36624ed36fb0ff5b.js file that powered the core functionality of the app. After beautifying it, I parsed out all of the routes and scrolled through them:


There were over 100 different API calls that all had the same base path of /api/cbma/. Since this route seemed to be power most device-related functionality, I thought it was worth investigating if the /api/cbma/ endpoint happened to be a reverse proxy to another host. I tested this by sending the following requests:


From sending the above HTTP requests, we learn that the api/cbma endpoint is an explicit route that is likely a reverse proxy to another host due to the differing behavior around the HTTP response. When we request anything besides api/cbma, it responds with a 302 redirect instead of the 500 internal server error triggered from api/cbma.


Since the API itself had all of the interesting device management functionality, it made sense to focus on everything behind the api/cbma route and see if there was any low hanging fruit like exposed actuators, API documentation, or any directory traversal vulnerabilities that would allow us to escalate permissions.


The HTTP request contained a bunch of different authorization headers including what looked to be a general-use API key that was shared between users. The clientid and Cb_session keys looked very custom and indicated there were multiple roles and permissions used in the application.


It seemed that requests to load static resources for the page (.png, .js, .css) were all being routed through the base URI instead of the reverse proxy API host. What this meant was there was probably a proxy rule for static assets, so I changed the extension to test this:


Perfect, the swagger routes had loaded. I used the same trick to load all the swagger docs on all of the other API endpoints. In total, there were about 700 different API calls with each API having the following number of calls:


After the intruder scan of all of the API endpoints completed, I scrolled through to see if any had any interesting responses. The following "profilesearch" endpoint had an interesting HTTP response which appeared to be returning a blank JSON object from what looked to be an empty search:


I did a sanity check and confirmed that nothing had changed between the request in intruder and my repeater request. I replayed the request one more time, but surprisingly this time it gave me the original 200 OK and the JSON response from intruder! What was going on? It seemed to be intermittently giving me authorization errors or saying that the request had been successful.


We had confirmed that we could bypass authorization for the API endpoints by simply replaying the HTTP request multiple times, and there were over 700 other API requests that we could hit. It was time to see what the real impact was.


I looked back at the results of the intruder scan, now knowing that I could bypass authorization by simply replaying a request. In order to figure out if this vulnerability could've been used to hack my modem, I needed to know if this API had access to the residential network at an access control level. Cox offered both residential and business services, but under the hood, I was guessing that the underlying API had access to both.


This was a GET request to retrieve a modem IP address that required a macAddress parameter. I logged into Cox, retrieved my own MAC address, then sent the HTTP request over-and-over until it returned 200 OK:


It worked! We were accessing our own device through the Cox Business website API! This meant that whatever was running on this could actually be used to talk to the devices. Cox provided service to millions of customers, and this API seemingly allowed me to directly communicate via MAC address with anyone's device.


The next question I had was whether or not we could retrieve the MAC addresses of the hardware connected to someone's account via searching their account ID (which we had retrieved previously through the customer query endpoint). I found the accountequipment/services/accountequipment/v1/equipments endpoint in my swagger list and threw it in my Burp Repeater with my own account ID. It returned the following information:


To test if this could be abused to access and modify business customer accounts, I found an API request which could query customers via email. I sent the following HTTP request and saw the following response:


At this point, I'd demonstrated that it was possible to (1) search a customer and retrieve their business account PII using only their name, then (2) retrieve the MAC addresses of the connected hardware on their account, then (3) run commands against the MAC address via the API. It was time to find some API endpoints that actually wrote to the device to simulate an attacker attempting to get code execution.


Looking through the swagger docs, it seemed that every hardware modification requests (e.g. update device password) required a parameter called encryptedValue. If I could find a way to generate this value, then I could demonstrate write access to modems which would lead to remote code execution.


Now that I had a breakpoint set and I was in the correct context for the function I could simply paste the function into my console and run whatever I wanted. To validate that it worked, I copied the encrypted value of the PIN code that was sent in the POST request and passed it to the decrypt function.


Perfect! It worked as expected. The only issue now was getting the encrypted value of a device. I asked around for a while until I found a friend who owned a MSP a few states away who used Cox Business. They gave me a login to their account and I saw what appeared to be an encryptedValue parameter in one of the HTTP responses after authenticating into their account. I copied this value and passed it to the decrypt function once again:

3a8082e126
Reply all
Reply to author
Forward
0 new messages