Affinis - Subdomain Discovery Through RNN (Recurrent Neural Network)

Credits: James Barnett

Affinis - Subdomain Discovery Through RNN (Recurrent Neural Network)

Project Repository: JetP1ane/Affinis (github.com)

It is said all too often, but Reconnaissance is such a critical part of a successful penetration test, especially when it comes to subdomain discovery. We never want to miss those vulnerable assets that the client may fail to disclose or just frankly doesn’t know about like stale assets. There are hundreds of tools available to assist with the Recon process, but I wanted to contribute something that would help narrow those chances of missing something during this process. So, I started looking into Neural Networks with the hope that this technology may be applicable to helping to solve this issue, or at least to help minimize it.

The way I wanted to leverage neural networks for this solution was to feed it a list of subdomains discovered from traditional methods and have it generate new subdomains based on that input data. Instead of continuing to try and brute-force subdomains with pre-made lists, I wanted the neural network to make a more educated decision on what those next guesses should be based on already known samples. My research eventually led me to RNN (Recurrent Neural Networks) in conjunction with NLP (Natural Language Processing).

RNN’s & NLP

RNN’s (Recurrent Neural Networks) excel at solving sequence-based problems and utilize a ‘memory’ to learn from previous iterations. NLP (Natural Language Processing) is the computer science sub-field used for machine text classification and text generation, just like those auto-filled words in your Google search or Siri on your iPhone. RNN’s help to solve NLP related problems due to its ability to store and recall information from a data stream. The RNN is essentially emulating a human brain and learning speech patterns based on the textual data it is fed. As it interprets this data, it is learning the structure and style of the language and can then generate predictive text based on that input. I wanted this to function as a subdomain name generator, so this seemed like the perfect solution. RNN

I highly recommend reading more into the relationship between RNN’s and NLP, but I want to get back to my main point. I wanted to implement a programmatic solution utilizing RNN’s, more specifically the LSTM algorithm, to solve my subdomain name generator problem.

Affinis - POC

Python and the Keras API became the tools of choice based on my reading from this documentation. Affinis takes a list of subdomains generated from passive and active tools and formulates its own list of potential subdomains that the target may be using based off the ones that it already knows about. It makes a very educated prediction on what style and structure the target may be using to name their subdomains. It is by no means perfect and may not be of any use in certain situations, but I have been fortunate to have success with it on real engagements. It has found obscure subdomains for me that were never found with traditional passive and active subdomain discovery tooling. Affinis in action

I believe neural networks can provide tremendous value to the infosec industry in solving a plethora of problems. I will be continuing to evolve this solution and it will be eventually integrated into a larger automated reconnaissance framework, but for now it exists as a standalone Python app. I hope it provides value to some and I’m always open to hear feedback and improvement suggestions.

Project Repository: JetP1ane/Affinis (github.com)

CookieMonsteRCE

Credits: James Barnett and Jeff Green

CookieMonsteRCE - XSS to RCE Exploitation in Zena 4.2.1

It can often be overlooked just how impactful medium or low severity vulnerabilities truly are. They lack the persuasive punch that High and Critical severity vulnerabilities carry and this often leads to them being ignored or dismissed. Given the right circumstances, these vulnerabilities can wreak havoc, especially when chained together. This is our story of how even a simple vulnerability like stored XSS, can lead to a worst-case scenario such as RCE (Remote Code Execution) on the hosting server and lateral movement through the network.

Zena Intro

Zeke and Zena are two enterprise IT orchestration tools by ASG Technologies (a Rocket Software Company) that we conducted our research on. Our research focused primarily on Zena, but Zeke played a part by contributing a very important vulnerability to this exploit chain that we later developed. Both of these applications allow you to run agents on endpoints that listen to a scheduler/controller for commands. From the scheduler, jobs can be created that are pushed to these agent endpoints. These jobs can entail running a script, program, or even executing direct system shell commands. You can already see the power that this application has and if someone was able to abuse this functionality, the situation could be dire for an organization.

Research

Our journey started when we were tasked with testing this software for any potential business logic manipulation vectors that could allow this application to be used maliciously. We quickly discovered that this application had other glaring security issues that required our immediate attention.

Cleartext Storage of Sensitive Information in a Cookie

We had initially logged into the Zeke application and about to transition over to testing the Zena application when we noticed something peculiar in the Cookie storage: PlainText Cookie Credentials After successfully logging into Zeke, the plaintext username and password are stored as cookies. These cookies lack samesite and httponly security protections and we found we were able to access these values from the Zena application running on the same IP/Domain. Since administrators are likely bouncing between the Zeke and Zena applications, this was very interesting. This is not necessarily a huge red flag, but it did pique our interests to keep digging deeper.

Stored XSS

The prior discovery prompted us to start testing some user input fields within the application to see if input was being properly sanitized and if there were any XSS vulnerabilities laying around. Finding an XSS vulnerability would allow us to take advantage of that credential cookie storage.

We began by looking at the webconfig page for the Zena application, which is where our first XSS vuln was uncovered. On the webconfig page, we were presented with a login page requiring only a password. A quick Google search told us this had a “very complex” default password according to the online ASG documentation. Default Cred Once logged in, we were presented with a database connection configuration menu that was full of input fields. So, being offsec people, we start dropping XSS payloads into these input fields hoping something sticks and detonates. There were some filters in place, but after some HTML tag escaping, we successfully found our first XSS vulnerability; stored XSS. stored xss - auth Now we were cooking with fire! Something told us this wouldn’t be the only stored XSS vulnerability and we decided to push deeper and try to find a purely unauthenticated XSS vuln within the site.

This was rather quickly found when inspecting the logging mechanism integrated into Zena. Zena was logging the username field from both successful or failed login attempts and incorrectly sanitizing that input before storing it in the log. This meant that anyone navigating to an injected log in the Zena application logs would trigger the exploit…

This could be exploited by just injecting the payload into the username field on an unsuccessful login attempt: unauth stored xss When a user in the application navigates to the log, the exploit is triggered. This is a ticking timebomb and an attacker could expedite this execution with some social engineering to coerce an admin to navigate to the logs thus triggering the waiting payload. unauth xss trigger To make matters even worse, there was no character limit to what our stored XSS payload could be. This meant that we could inject a rather large and sophisticated payload.

Putting it All Together - Unleashing the CookieMonsteRCE

Okay, so you have an unauthenticated XSS vulnerability, who friggin cares? Right, well this is where things get interesting. We now have cleartext credentials being stored in cookies that are accessible across applications, authenticated and unauthenticated stored XSS vulnerabilities, and two determined researchers who wanna pop dem shells.

Zena’s backend is essentially a RESTful API and thanks to their swagger documentation, we were able to educate ourselves on its capabilities. Zena uses what are called Defintions to define jobs that the agent endpoints will perform. These Definitions can be created and executed via the RESTful API as long as you pass valid and authorized credentials in the request headers. So, what can these Definitions do? Just about everything. A Definition task can be configured to run a local script, program, or just execute arbitrary shell commands: definition

Weaponization

Knowing that we have cleartext credentials stored as cookies, a stored XSS vulnerability, and now a full fledged RESTful API backend, we had a solid plan on how to achieve the ultimate goal of RCE. We decided to build a POC that would take advantage of the credential cookie storage, the authenticated stored XSS, and the RESTful backend. The payload would perform RCE on not only the hosting server, but any agent endpoints on the network. This would be accomplished by a stored XSS payload stealing the cookie credentials, building Definition tasks using the API that would execute arbitrary commands on the agent endpoints, and then immediately executing the created Definition task.

This POC involves a few steps:

  • First, the stored XSS payload must be delivered through the webconfig page
  • Second, the payload must be triggered by some privileged user/administrator navigating to the webconfig page
  • Third, the payload is executed and subsequent REST API calls are made using the stolen credentials. These API calls build a Definition task with an arbitrary system command.
  • Fourth, the newly created task is executed and RCE is achieved

We built the POC using a Python script that would inject our large JavaScript XSS payload into the webconfig page. After some tinkering, the POC was successful and we had RCE on our test server that was registered as a Zena agent. The POC successfully injected our XSS payload into the WebConfig page. Upon triggering, it then stole the cleartext credentials, used them to authenticate to the Zena API and register a Task for an agent that instructed the agent to execute our local shell command. This POC accepts custom commands, so you can specify what that local execution will be.

POC: https://github.com/JetP1ane/Zena

Conclusion

CVE Vulnerability Details:

These vulnerabilities have been remediated by Rocket Software and a new patch is available:

Our lesson learned was to never underestimate the impact a lower severity vulnerability might have. A highly motivated threat actor is likely to find a way to conjure up something nasty given enough time.

Somewhere I Belong Part 3

Credits: HopScotch

The theory and practice of social engineering

Part 3: A Breath of Fresh Air

Physical penetration testing is breath of fresh air in the red teaming space as a way to get out of our normal desk space and let us really play the part of a spy. They are my favorite form of test and I hope everyone reading will get a chance one day to do their own physical pentest. This post will be a short story of a physical pentest I performed the other day with some lessons learned sprinked through. The client’s name will not be revealed due to NDA and certain steps may be only discussed at a high level.

The Setup

My client requested myself and one other tester fly to their headquarters and perform as much social engineering and physical pentesting as we can. They had a conference going on at the same time at a hotel close by and performing social engineering there was in scope as well as long as we did not interrupt any on going presentations. We had 2.5 days to perform our tasks and presented and went home on the final day.

Some key areas the client wanted focus on was:

  • Badge replication and cloning
  • Rogue Access Points/Evil Twins
  • Tailgating
  • Phishing/Smishing

This was a large order for little time as we were only authorized for 45 hours worth a labor. We performed OSINT on the client to see if there was any low hanging fruit, good pretext for phishing/smishing and we discovered their Citrix site with a domain similar to login.ClientName.com. Setup began one week before travel and was performed in AWS EC2/Route 53. We stood up a new EC2 instance and purchased a domain similiar to “loginClientName.com”, notice the “.” before login and clientName is missing. We then used Evilginx2 as a psuedo phishing page as it allowed us to capture session cookies as well as credentials and saved us the work of having to mirror the Citrix login page in HTML/CSS. After the custom phishlet was made, we used a free QR code site to create malicious QR codes for Quishing. These were printed as stickers to mark around HQ and the conference. After discussion with my partner, we agreed a fake raffle would be the best way to collect emails and phone numbers for other social engineering attacks.

This leads to lesson 1, come into your engagement prepared so the on keyboard team can perform work the second a user takes the bait. Time was short during the engagement so this prep was crucial.

Day 0.5

We arrived at our hotel. My teammate arrived approximately 2 hours before me and fried our Proxmark, a tool to copy RFID signals, which left us unable to clone any sort of badge. While repairs were being attempted to it, I decided to war drive their campus, or walk around with my phone out and see what their WiFi was, and discovered all of their WiFi was WPA2 with EAP except their guest network which was open. After recording their ESSIDs and type, I grabbed a burger at a local restaurant and attempted to grab a few photos of employee badges to fake but all my attempts were unsuccessful. I went back to the hotel and began setting up a Wifi Pinapple Mark vii. We set their ComPanyGuest network up as a Evil Twin as an Open Network and attempted to setup an Evil Twin Network that would perform an EAP Replay to their main network or attempt to crack their RADIUS credential as most companies use Active Directory as a RADIUS auth server. We attempted to get some more badge photos and failed but have a general idea of design. I went back to the hotel and created a template of the badge and just had to fill in some small text at the bottom.

Lesson 2 is expect for all of your equipment to break. Our Proxmark had set us way back in our testing timeline back and badge photos had gone awful this day which caused a busy day 1 that I will go over now.

Day 1.

After a quick breakfast, my teammate and I split up to perform our tasks. I set up our Evil Twin/ Rogue Access Points at the nearby conference hoping to snag a connection via a Peferred Network List(PNL) connection which is essentially a phone recognizing a WiFi name and automatically trying to connect to it. It was surprisingly easy to set up under a desk as nobody was out in the lobby watching and the hotel staff did not seem to care I was plugging things in. From my teammates perspective, he had to go and print out our raffle poster and pick up supplies for our fake raffle to set up but due to supply chain issues, Fedex required a 3 day notice for printing poster board so we went with a garbage looking piece of paper and notebook next to a fishbowl or as we called it a “phish bowl”. I got a few good guest network connections but due to TLS, I couldn’t get anything important. My suspicion with Active Directory was correct as we got some hashes being sent that I sent off to our on keyboard team so they can run it through our cracking rig. The credentials were cracked in under 5 minutes. I had managed to get us a picture of a badge but it was clipped to a gentleman’s belt as he was in a bathroom stall and another on a woman’s dress. I was getting very sloppy with stealthy photos and was getting some glares by folks so we left the conference area for lunch and to stalk their HQ. We managed to get another clearer picture in the HQ elevator and tailgated into the building. I helped myself to a bottle of water in their kitchen and we left. My teammate went back to the hotel to print badges for us while I went to collect the phish bowl and it was gone. After looking around I overheard the event coordinator talking to someone about it being suspicious and heard they moved it inside a hotel room inside a box so I went to steal it. No one seemed to say anything as the conference hotel staff didn’t seem to care at all. We had collected approximately 38 names, emails, and cell phone numbers before it was moved. We sent the information to our on keyboard team to send out the evilginx2 phishing link using Amazon SMS and AWS Simple Email Service. The day was over and we grabbed the pineapple and went to dinner. This was my first down time all trip so I started working on the presentation.

Lesson 3 is to act natural and act like you belong. My teammate and I were in a lot of spaces we should not have been today but since we were not acting suspicous and were dressed similarly to everyone else, we didn’t arise suspicion at all. This let us tailgate in a building and do a lot more than we should have been able to do at the conference setting up equipment and the phish bowl even though the phish bowl was burned in the second half of the afternoon.

Day 2

A replacment Proxmark had finally come in that morning after breakfast so it was finally time to badge clone. After a very nice breakfast, we spent the remainder of the afternoon trying to get a valid badge read. This was a lot harder than it should have been as we only had about a foot to a foot and a half of distance for the read. We rode the HQ elevator for about an hour without a good hit and I bumped into a lot of people at the conference trying to get a valid read. I even tried the bathroom stall approach again where I attempted to catch someone with their pants down literally. I got uncomfortably close to a guy washing his hands and almost got into a physical altercation but talked my way out of it. I eventually got a valid read on an escalator while my teammate distributed the QR code stickers inside of conference rooms during a break and at HQ. He went to work on creating us badges while I managed the Evilginx2 console. We finished the test with 23 credentials harvested through either Smishing/ phishing, or Quishing with a valid session cookie, username, and password. We grabbed some lunch and took a stroll with our fake badges in their main HQ and surprised the CISO at her office. She was happy and freaked out to see us and complimented our badge accuracy. We wrapped up by finishing and rehursing the day 3 presentation.

Lesson 4, don’t get within a foot of a guy while he washes his hands in a restroom, he will try to fight you. Okay, the serious lesson is don’t be afraid to get on top of people. A simple “excuse me” goes a long way with getting uncomfortably close. Elevators, escalators, and bathrooms make prime areas for badge cloning as well as hallway entrances or exits.

Day 3

We woke up, checked out of the hotel and went over to the conference to give the final talk of the day. The video of us badging into their HQ made everyone gasp and scared which really helped drive the message across. The presentation went amazing and my teammate was pretty happy with the end product.
We went home with the client praising us and secured a retest the following year.

Tips and take aways for phyiscal pentesting

  • Think on your feet. Knowing what to say or defusing a situation is the difference between a success and a failure
  • Be prepared. Having some background on an event or company is huge when building trust. During the prep OSINT, we had found a bunch of products we lied about being on the team for. We had no time to set up when we got there. Setup time was pivotal to the test.
  • What can break, will break. I thought we were doomed to fail once our ProxMark shorted on Day 0. We were looking everywhere for a replacement and had considered running Kali Nethunter on my phone if it was feasible. We managed to diagnose what part broke and ordered just that part which made badge cloning possible on Day 2.
  • Know how to dress, while a clipboard and and vest will get you far, the average employee look is a staple in a big crowd like the conference setting and sitting idly by in HQ.
  • Have fun and don’t be nervous. I like to pretend I am on an Impractical Jokers episode when I get nervous. Keep in the back of your head you are there doing what the company paid you to do and that randomly employee being nervous will forget all about it in a month.

This has been a walkthrough in an out there physical pentest. I hope everyone learned something valuable and keep on studying.

Somewhere I Belong Part 2

Credits: Jeff Green and James Barnett

The theory and practice of social engineering

Part 2: Walking in like the place owns us!

When Life hands you security guards, make doors open.

Assuming that it is abnormal for 2 random IT workers to show up at 1:00 am, you can still find ways to fit into your targets mind. Act like the place owns you! You are working at 1:00 am, you are probably tired or annoyed. Your boss is on the phone with you asking why it is taking so long. Your badge has never done that before. Shrug. You do not ask to be let in, your day sucks and you would love to be able to just stumble home for the night and finish tomorrow.

There are subtle differences in our communication patterns based on our level of comfort. Relaxed does not always mean you belong. Comfort is a complex thing, if we feel really comfortable with someone we may something uncomfortable that we would never say to someone we were uncomfortable with in the first place. We may be more short tempered with those we love or are used to.

We need to fit into the mind like a piece of a jigsaw puzzle. Circle goes in circle hole.

Story Time

Changes and redactions have been made in this story to protect those involved.

The inspiration for this blog post series came from a Covert Entry Red Team Engagement my partner and I were on. I will start with a little story about some work we did and follow up with what I learned from the experience. The dialogue is remembered as best I can as it was not all recorded and some things are changed to protect identities. We had done our osint, completed our physical recon, and already compromised 2 of our 4 targets. Our third was the big prize. High Security Badge Access, constant guard presence, great side and rear door security made it appear to be a really hard target. We came up with all sorts of wild schemes and at some point while we were sitting in the car together we realized we were thinking about it all wrong. I forget who, but one of us said, “We just need to walk in the front door like we own the place, what are they gonna do? …Nothing I bet.”

I thought I had the front door opened from something I had done previously.We pulled into the parking lot after midnight and walked up to the door. I was on the phone talking excitedly to my boss who was helping me stay in character, stressed out and tired. Maybe even a little bored. I scanned my badge( a drivers license in a stolen company lanyard) on the main door and reached for the handle. Nothing. Later I realized from some pictures I took I had messed up on that door by accident. Huge mistake. I tried again? ( Knowing at this point the game was up but wanting to try my hand at one more little thing) The security guard got up and walked to the door looking at us. I gesticulated and talked into the phone shrugging dejectedly. We turned and started to walk away and then the guard shouted, “ Hey, do you work here?” I turned around. “Yeah, I am on the phone with my boss now. I have to change some hard drives in the server racks asap. I have no idea why this dumb card is messed up. Makes no sense” She asked. “ You work for COMPANYNAME?” My partner speaks up. “ yeah, we are just finishing up for the day. One more job.” “Ok, come on in.” The guard trudged back to the desk after saving the day for some hapless IT workers. We walked up the stairs and into the hallway and saw through the glass doors, a miracle . We had reached the promised land! The rush was unbelievable as we slapped red stickers on the servers. I grabbed a picture of the NOC analyst on duty as we walked around the data center like the place owned us and we had better get our work done asap.

-Start StreamofConsciousness -U SecurityGuard -D HighCommand -P Hunter02
Someone parked their car in the front spot. Must be someone who thinks they are important. He is getting out. lanyard with badge. Dang I just lost my game of candycrush.
He swiped his badge and pulled on the door. Wow he looks confused. On the phone. looks stressed and annoyed. I guess I will go find out whats going on.
---Do you work here?---
---Yeah, no idea why my dang badge didnt work. Never had that problem before.---
---Do you work here?---
---Yeah, I am with IT, gotta change some hard drives asap. Sorry, boss on the phone.---
---Oh, ok, come on in---
Man they are loud people. All right. Imma crush this candycrush game now.
-End StreamofConsciousness SecurityGuard HighCommand

Theory

You are always welcome at your home. How do you know you are welcome? You just do. How do they know you are welcome? If your behaviors are a pattern that they can understand in all of the particular situations you find yourself in. Does your personality fit the time? Are you tired, bored, annoyed? Well I would hope so! It is midnight and they are used to seeing someone annoyed at having to do things at midnight. If you were happy maybe they would be a little suspicious of you. Who knows for sure. Look at your target. Are they bored? Are they annoyed? Mirroring behaviors and communication works sometimes, if all else fails.

Be consistent and have a story that is malleable. Dropping some WiFi pineapples when a guard walks up on you? No your not, your hanging wireless APs for the new faster better WiFi system.
Had to be late because disruption to the internet. So annoying. Yeah… I picked the short straw again. No, no… we are not with Wireless AP We are IT and we are hanging up wireless internet access points…

Don’t walk in like you own the place, walk in like the place owns you.

Good Luck Red Teams!

Detecting Time-based SQLI

Credits: Patrick Smith

Purpose

This post details real-world analysis of an incident response where the logging gods were not on my side (thanks redacted client) and how I was able to use an incovential way to detect time-based SQL injection exploitation through commonly available logging mechanisms that may be overlooked.

Background

My company was contracted to assist in a CSIR (Cybersecurity Incident Response) effort. At the tme of first contract, the initial means of compromise were unknown.

The objectives were simple:

  1. Discover the initial means of compromise
  2. Evaluate what information was potentially acccessed by the threat
  3. Mitigate the current attack and provide future guidance

Story

This post will cover objective one. After discovering a malicious binary dropped by the threat(s), it was analyzed for any sort of C2 callbacks. This provided an IP address. Naturally, the first thing I did was used Crowdstrike to search for all machines that have made any of outbound newtwork connections to the known IP address, which can be used as an IOC (indicator of compromise) for other machines on the network. While it’s normal for externally facing hosts to be receiving a ton of unknown inbound connections, connections being built OUTBOUND to unknown IPs are a hugeee red flag.

An application server, which was serving a publicly-facing web applications, happened to be calling back to this IP address. External web applications are very prone to being attacked, so this was a good place to start. Whenever I find a malicious IP address, I always note down the ISP (hosting provider), the country, and the range. I try to build a database of signatures on the threat(s). By doing this, I can make subsequent searches or just keep my eye out for other “sketchy” IP addresses that may be related to the threat(s). When checking inbound connections to all of the known hosts on the client’s network from the known-malicious IP address, the application server had significantly more than any others, and it was all port 443 (HTTPS/the webserver). Unfortunately, this client did not have logs/the ability to view the entirety of the conents of the HTTPS traffic, such as TLS inspection, so a big challenge was trying to figure out what the attacker(s) were doing with this webserver.

I went straight to the webserver logs, in this case the webserver was IIS. When it comes to webserver logs, there are a two primary types:

  1. Access logs
    • Logs every HTTP request to the webserver, but not the entire HTTP request (it wont contain all of the HTTP headers or the body of requests)
  2. Error logs
    • Usually not very helpful for the goal here.

IIS Access log analysis

By default,IIS access logs are configured to use the W3C file format which includes the following fields related to logged HTTP requests:

  • Time & date the HTTP request was sent
  • Client IP address
  • HTTP method (GET, POST, etc.)
  • URI components (query strings, paths, etc.)
  • Bytes Received
  • Response time (how long the webserver took to return the complete HTTP response)

*Important reminder: IIS access logs do NOT log certain aspects of HTTP requests, such as the bodies of HTTP requests, this means discovering attacks that distribute payloads via the body of HTTP requests and HTTP headers can be challenging and often yield inconclusive results without definitive empirical evidence. *

For this scenario, two IP addresses will be mentioned. They will be referred to as Attacker-IP-A and Attacker-IP-B, both belonging to the attacker.

The suspect IP address began making connections to the web application on 2/8. The following files were requested:

193 requests: /login.aspx 2 requests: /WebResource.axd 1 request: /Scripts/WebForms/MsAjax/MicrosoftAjaxWebForms.js 1 request: /Style/buttons.css 1 request: /Scripts/WebForms/MsAjax/MicrosoftAjax.js 1 request: /favicon.ico

Identifying Anomolous HTTP Traffic

The request breakdown shows nearly all of the traffic going directly to the login.aspx page which is very uncommon behavior for normal users and even automated scanners. Normal behavior would return many more HTTP GET requests as the user browses the website and the browser loads static assets. Of all of these requests, 193 were HTTP POST, and only 6 were HTTP GET. This is extremely irregular behavior. For a vulnerability to be exploited, there is typically preliminary exploration of the website and other fuzzing, however, these requests are directly targeting /login.aspx, signifying the original reconassiance and fuzzing was likely performed from different IP addresses.

The first HTTP request received from is an HTTP POST request to /login.aspx. This is another irregularity and indication of programmatic exploitation as normal users would need to usually visit the website, for example, https://website.com/, then manually traverse to https://website.com/login.aspx by clicking around. This activity will create HTTP GET requests in the process; because this is not consistent with what is being seen within the logs, this strengthens the narrative that other IP addresses are being used.

Example log entry:

2022-02-08 06:34:24 <redacted internal IP> POST /login.aspx - 443 - <Attacker-IP-A> Mozilla/5.0+(Macintosh;+U;+PPC+Mac+OS+X;+en-us)+AppleWebKit/125.5.5+(KHTML,+like+Gecko)+      Safari/125.11 - 302 0 0 242

Further analysis of the traffic from revealed an extremely odd consistent behavior of consecutive very long response times of 15,000 milliseconds (15 seconds). For perspective, normal response times were noted to be within the range of 200-500 milliseconds.

Important note: The last field of the logs (f.e 15249 on the first entry) is the amount of time it took the webserver to serve the HTTP response.

Format reminder:

[Time] [Source IP] [HTTP method] [URL] [Source port] [User-Agent] [Referer] [HTTP Status Code] [sc-substatus] [sc-win32-status] [HTTP Response Time Taken]

IIS access log entries:

 03:24:23 <redacted internal IP> POST /login.aspx - 443 - <Attacker-IP-A> Mozilla/5.0+(Windows;+U;+Windows+NT+6.1;+en-US)+AppleWebKit/534.13+(KHTML,+      like+Gecko)+Chrome/9.0.597.0+Safari/534.13 - 200 0 0 15249
 03:24:39 <redacted internal IP> POST /login.aspx - 443 - <Attacker-IP-A> Mozilla/5.0+(Windows;+U;+Windows+NT+6.1;+en-US)+AppleWebKit/534.13+(KHTML,+      like+Gecko)+Chrome/9.0.597.0+Safari/534.13 - 200 0 0 15246
 03:24:55 <redacted internal IP> POST /login.aspx - 443 - <Attacker-IP-A> Mozilla/5.0+(Windows;+U;+Windows+NT+6.1;+en-US)+AppleWebKit/534.13+(KHTML,+      like+Gecko)+Chrome/9.0.597.0+Safari/534.13 - 200 0 0 15249
 03:25:11 <redacted internal IP> POST /login.aspx - 443 - <Attacker-IP-A> Mozilla/5.0+(Windows;+U;+Windows+NT+6.1;+en-US)+AppleWebKit/534.13+(KHTML,+      like+Gecko)+Chrome/9.0.597.0+Safari/534.13 - 200 0 0 15242
 03:25:11 <redacted internal IP> POST /login.aspx - 443 - <Attacker-IP-A> Mozilla/5.0+(Windows;+U;+Windows+NT+6.1;+en-US)+AppleWebKit/534.13+(KHTML,+      like+Gecko)+Chrome/9.0.597.0+Safari/534.13 - 302 0 0 242
 03:25:27 <redacted internal IP> POST /login.aspx - 443 - <Attacker-IP-A> Mozilla/5.0+(Windows;+U;+Windows+NT+6.1;+en-US)+AppleWebKit/534.13+(KHTML,+      like+Gecko)+Chrome/9.0.597.0+Safari/534.13 - 200 0 0 15245
 03:25:43 <redacted internal IP> POST /login.aspx - 443 - <Attacker-IP-A> Mozilla/5.0+(Windows;+U;+Windows+NT+6.1;+en-US)+AppleWebKit/534.13+(KHTML,+      like+Gecko)+Chrome/9.0.597.0+Safari/534.13 - 200 0 0 15245
 03:25:58 <redacted internal IP> POST /login.aspx - 443 - <Attacker-IP-A> Mozilla/5.0+(Windows;+U;+Windows+NT+6.1;+en-US)+AppleWebKit/534.13+(KHTML,+      like+Gecko)+Chrome/9.0.597.0+Safari/534.13 - 200 0 0 15243
 03:26:14 <redacted internal IP> POST /login.aspx - 443 - <Attacker-IP-A> Mozilla/5.0+(Windows;+U;+Windows+NT+6.1;+en-US)+AppleWebKit/534.13+(KHTML,+      like+Gecko)+Chrome/9.0.597.0+Safari/534.13 - 200 0 0 15244
 03:26:29 <redacted internal IP> POST /login.aspx - 443 - <Attacker-IP-A> Mozilla/5.0+(Windows;+U;+Windows+NT+6.1;+en-US)+AppleWebKit/534.13+(KHTML,+      like+Gecko)+Chrome/9.0.597.0+Safari/534.13 - 200 0 0 15247
 03:26:45 <redacted internal IP> POST /login.aspx - 443 - <Attacker-IP-A> Mozilla/5.0+(Windows;+U;+Windows+NT+6.1;+en-US)+AppleWebKit/534.13+(KHTML,+      like+Gecko)+Chrome/9.0.597.0+Safari/534.13 - 200 0 0 15246
 03:27:00 <redacted internal IP> POST /login.aspx - 443 - <Attacker-IP-A> Mozilla/5.0+(Windows;+U;+Windows+NT+6.1;+en-US)+AppleWebKit/534.13+(KHTML,+      like+Gecko)+Chrome/9.0.597.0+Safari/534.13 - 200 0 0 15242
 03:27:16 <redacted internal IP> POST /login.aspx - 443 - <Attacker-IP-A> Mozilla/5.0+(Windows;+U;+Windows+NT+6.1;+en-US)+AppleWebKit/534.13+(KHTML,+      like+Gecko)+Chrome/9.0.597.0+Safari/534.13 - 200 0 0 15248
 03:27:31 <redacted internal IP> POST /login.aspx - 443 - <Attacker-IP-A> Mozilla/5.0+(Windows;+U;+Windows+NT+6.1;+en-US)+AppleWebKit/534.13+(KHTML,+      like+Gecko)+Chrome/9.0.597.0+Safari/534.13 - 200 0 0 15246
 03:27:47 <redacted internal IP> POST /login.aspx - 443 - <Attacker-IP-A> Mozilla/5.0+(Windows;+U;+Windows+NT+6.1;+en-US)+AppleWebKit/534.13+(KHTML,+      like+Gecko)+Chrome/9.0.597.0+Safari/534.13 - 200 0 0 15242
 03:28:02 <redacted internal IP> POST /login.aspx - 443 - <Attacker-IP-A> Mozilla/5.0+(Windows;+U;+Windows+NT+6.1;+en-US)+AppleWebKit/534.13+(KHTML,+      like+Gecko)+Chrome/9.0.597.0+Safari/534.13 - 200 0 0 15246
 

The 15,000 millisecond response time was used as marker for possible exploitation attempts. I reviewed neighoring HTTP requests for similar behaviors, expecting a rotation in IP addresses. The following entries were discovered (spoiler: the same anomolous behavior):

   07:33:16 <redacted internal IP> POST /login.aspx - 443 - <Attacker-IP-B> Mozilla/5.0+(Windows;+U;+Windows+NT+5.0;+en-US)+AppleWebKit/532.0+(KHTML,+like+Gecko)+           Chrome/3.0.198+Safari/532.0 - 200 0 0 15256
  [NORMAL TRAFFIC] 07:33:27 <redacted internal IP> GET /keepalive.ashx - 443 - 73.211.202.213 Mozilla/5.0+(Windows+NT+10.0;+Win64;+x64)+AppleWebKit/537.36+(KHTML,+like+Gecko)+Chrome/        97.0.4692.99+Safari/537.36 https://website.com/quote.aspx?quoteid=2202013 302 0 0 50
  [NORMAL TRAFFIC] 07:33:27 <redacted internal IP> GET /keepalive.ashx - 443 - 73.211.202.213 Mozilla/5.0+(Windows+NT+10.0;+Win64;+x64)+AppleWebKit/537.36+(KHTML,+like+Gecko)+Chrome/        97.0.4692.99+Safari/537.36 https://website.com/frmQuoteSearch.aspx 302 0 0 52
 
   07:33:27 <redacted internal IP> GET /~login.aspx - 443 - 73.211.202.213 Mozilla/5.0+(Windows+NT+10.0;+Win64;+x64)+AppleWebKit/537.36+(KHTML,+like+Gecko)+Chrome/        97.0.4692.99+Safari/537.36 https://website.com/quote.aspx?quoteid=2202013 404 0 0 52
   07:33:27 <redacted internal IP> GET /keepalive.ashx - 443 - 73.211.202.213 Mozilla/5.0+(Windows+NT+10.0;+Win64;+x64)+AppleWebKit/537.36+(KHTML,+like+Gecko)+Chrome/        97.0.4692.99+Safari/537.36 https://website.com/quote.aspx?quoteid=2202013 302 0 0 54
   07:33:27 <redacted internal IP> GET /~login.aspx - 443 - 73.211.202.213 Mozilla/5.0+(Windows+NT+10.0;+Win64;+x64)+AppleWebKit/537.36+(KHTML,+like+Gecko)+Chrome/        97.0.4692.99+Safari/537.36 https://website.com/frmQuoteSearch.aspx 404 0 0 50
   07:33:27 <redacted internal IP> GET /~login.aspx - 443 - 73.211.202.213 Mozilla/5.0+(Windows+NT+10.0;+Win64;+x64)+AppleWebKit/537.36+(KHTML,+like+Gecko)+Chrome/        97.0.4692.99+Safari/537.36 https://website.com/quote.aspx?quoteid=2202013 404 0 0 61
   07:33:27 <redacted internal IP> GET /keepalive.ashx - 443 - 73.211.202.213 Mozilla/5.0+(Windows+NT+10.0;+Win64;+x64)+AppleWebKit/537.36+(KHTML,+like+Gecko)+Chrome/        97.0.4692.99+Safari/537.36 https://website.com/quote.aspx?quoteid=2202061 302 0 0 91
   07:33:27 <redacted internal IP> GET /~login.aspx - 443 - 73.211.202.213 Mozilla/5.0+(Windows+NT+10.0;+Win64;+x64)+AppleWebKit/537.36+(KHTML,+like+Gecko)+Chrome/        97.0.4692.99+Safari/537.36 https://website.com/quote.aspx?quoteid=2202061 404 0 0 51
  
Suspected IP: 07:33:29 <redacted internal IP> POST /login.aspx - 443 - <Attacker-IP-A> Mozilla/5.0+(Windows+NT+10.0;+Win64;+x64;+rv:96.0)+Gecko/20100101+Firefox/96.0 https://         website.com/login.aspx 200 0 0 15103

A second IP address <Attacker-IP-B> was discovered to be making the same HTTP POST requests to the same login.aspx page with the same 15,000 millisecond response times, within 20 seconds of each other. This is further signal of other IP addresses being used. Inspection of traffic of <Attacker-IP-B> both in Splunk and IIS access logs shows significantly more HTTP traffic and connections predating the usage of <Attacker-IP-A>.

The IP address made the following HTTP requests:

22,298 requests: /login.aspx 
0 requests: /WebResource.axd
0 request: /Scripts/WebForms/MsAjax/MicrosoftAjaxWebForms.js 
0 request: /Style/buttons.css 
0 request: /Scripts/WebForms/MsAjax/MicrosoftAjax.js 
0 request: /favicon.ico requests 1 times

Every request from was an HTTP POST to /login.aspx. This behavior is extremely similar to what has been observed with , and even more irregular with no HTTP GET requests. A total of 4,570 HTTP requests from took over 5,000 milliseconds for the webserver to process and return a response.

Example:

 11:15:57 <redacted internal IP> POST /login.aspx - 443 - <Attacker-IP-B> Mozilla/5.0+(X11;+U;+Linux+x86_64;+en-US;+rv:1.9.2.9)+Gecko/20100915+Gentoo+Firefox/3.6.         9 - 200 0 0 15257
 44580
 11:16:13 <redacted internal IP> POST /login.aspx - 443 - <Attacker-IP-B> Mozilla/5.0+(X11;+U;+Linux+x86_64;+en-US;+rv:1.9.2.9)+Gecko/20100915+Gentoo+Firefox/3.6.         9 - 200 0 0 15257
 44582
 11:16:28 <redacted internal IP> POST /login.aspx - 443 - <Attacker-IP-B> Mozilla/5.0+(X11;+U;+Linux+x86_64;+en-US;+rv:1.9.2.9)+Gecko/20100915+Gentoo+Firefox/3.6.         9 - 200 0 0 15257
 44584
 11:16:44 <redacted internal IP> POST /login.aspx - 443 - <Attacker-IP-B> Mozilla/5.0+(X11;+U;+Linux+x86_64;+en-US;+rv:1.9.2.9)+Gecko/20100915+Gentoo+Firefox/3.6.         9 - 200 0 0 15264
 44586
 11:16:59 <redacted internal IP> POST /login.aspx - 443 - <Attacker-IP-B> Mozilla/5.0+(X11;+U;+Linux+x86_64;+en-US;+rv:1.9.2.9)+Gecko/20100915+Gentoo+Firefox/3.6.         9 - 200 0 0 15253
 44588
 11:17:15 <redacted internal IP> POST /login.aspx - 443 - <Attacker-IP-B> Mozilla/5.0+(X11;+U;+Linux+x86_64;+en-US;+rv:1.9.2.9)+Gecko/20100915+Gentoo+Firefox/3.6.         9 - 200 0 0 15257
 44590
 11:17:30 <redacted internal IP> POST /login.aspx - 443 - <Attacker-IP-B> Mozilla/5.0+(X11;+U;+Linux+x86_64;+en-US;+rv:1.9.2.9)+Gecko/20100915+Gentoo+Firefox/3.6.         9 - 200 0 0 15257
 44592
 11:17:46 <redacted internal IP> POST /login.aspx - 443 - <Attacker-IP-B> Mozilla/5.0+(X11;+U;+Linux+x86_64;+en-US;+rv:1.9.2.9)+Gecko/20100915+Gentoo+Firefox/3.6.         9 - 200 0 0 15259
 44594
 11:18:01 <redacted internal IP> POST /login.aspx - 443 - <Attacker-IP-B> Mozilla/5.0+(X11;+U;+Linux+x86_64;+en-US;+rv:1.9.2.9)+Gecko/20100915+Gentoo+Firefox/3.6.         9 - 200 0 0 15264

Identifying the issue

At this point, anomolous traffic has been identified, but what is causing it? How and why would an attacker influence HTTP response times? The answer: time-based SQL injection.

Time-based SQL Injection is an inferential SQL Injection technique that relies on sending an SQL query to the database which forces the database to wait for a specified amount of time before responding, in the case of SQL server, that is typically WAIT FOR DELAY. The response time will indicate to the attacker whether the result of the query is TRUE or FALSE. Essentially, an injected query, in English would read: If the first character of the password of the user 'patrick' is 'a', then sleep for 10 seconds. If the first character is indeed ‘a’, the sleep command is executed, and the HTTP response will be delayed for 10 seconds, which can easily be measured by an attacker.

Given the abnormal attention to /login.aspx, I began to audit this page for signs of vulnerability. The client provided source code to the relevant web applications and through code review of the application, I was able to identify the SQL injection vulnerability then confirmed it to exist with live dynamic testing.

Time App IP HTTP method URL Source port Source IP User-Agent Referer HTTP Status Code HTTP Response Time Taken      
03:24:23 intip POST /login.aspx 443 Attacker-IP-A Mozilla/5.0+(Windows;+U;+Windows+NT+6.1;+en-US)+AppleWebKit/534.13+(KHTML,+like+Gecko)+Chrome/9.0.597.0+Safari/534.13 - 200 0 15249      
03:24:39 intip POST /login.aspx 443 Attacker-IP-A Mozilla/5.0+(Windows;+U;+Windows+NT+6.1;+en-US)+AppleWebKit/534.13+(KHTML,+like+Gecko)+Chrome/9.0.597.0+Safari/534.13 - 200 0 15246      
03:24:55 POST /login.aspx 443 Attacker-IP-A Mozilla/5.0+(Windows;+U;+Windows+NT+6.1;+en-US)+AppleWebKit/534.13+(KHTML,+like+Gecko)+Chrome/9.0.597.0+Safari/534.13 - 200 0 15249      
03:25:11 <intip POST /login.aspx 443 Attacker-IP-A Mozilla/5.0+(Windows;+U;+Windows+NT+6.1;+en-US)+AppleWebKit/534.13+(KHTML,+like+Gecko)+Chrome/9.0.597.0+Safari/534.13 - 200 0 15242      
03:25:11 <intip POST /login.aspx 443 Attacker-IP-A Mozilla/5.0+(Windows;+U;+Windows+NT+6.1;+en-US)+AppleWebKit/534.13+(KHTML,+like+Gecko)+Chrome/9.0.597.0+Safari/534.13 302 242          
03:25:27 <intip POST /login.aspx - 443 - Mozilla/5.0+(Windows;+U;+Windows+NT+6.1;+en-US)+AppleWebKit/534.13+(KHTML,+like+Gecko)+Chrome/9.0.597.0+Safari/534.13 - 200 0 0 15245
03:25:43 <intip POST /login.aspx - 443 - Mozilla/5.0+(Windows;+U;+Windows+NT+6.1;+en-US)+AppleWebKit/534.13+(KHTML,+ike+Gecko)+Chrome/9.0.597.0+Safari/534.13 - 200 0 0 15245
03:25:58 <intip POST /login.aspx - 443 - Mozilla/5.0+(Windows;+U;+Windows+NT+6.1;+en-US)+AppleWebKit/534.13+(KHTML,+like+Gecko)+Chrome/9.0.597.0+Safari/534.13 - 200 0 0 15243
03:26:14 <intip POST /login.aspx - 443 - Mozilla/5.0+(Windows;+U;+Windows+NT+6.1;+en-US)+AppleWebKit/534.13+(KHTML,+like+Gecko)+Chrome/9.0.597.0+Safari/534.13 - 200 0 0 15244
03:26:29 <intip POST /login.aspx - 443 - Mozilla/5.0+(Windows;+U;+Windows+NT+6.1;+en-US)+AppleWebKit/534.13+(KHTML,+like+Gecko)+Chrome/9.0.597.0+Safari/534.13 - 200 0 0 15247
03:26:45 <intip POST /login.aspx - 443 - Mozilla/5.0+(Windows;+U;+Windows+NT+6.1;+en-US)+AppleWebKit/534.13+(KHTML,+like+Gecko)+Chrome/9.0.597.0+Safari/534.13 - 200 0 0 15246
03:27:00 <intip POST /login.aspx - 443 - Mozilla/5.0+(Windows;+U;+Windows+NT+6.1;+en-US)+AppleWebKit/534.13+(KHTML,+like+Gecko)+Chrome/9.0.597.0+Safari/534.13 - 200 0 0 15242
03:27:16 <intip POST /login.aspx - 443 - Mozilla/5.0+(Windows;+U;+Windows+NT+6.1;+en-US)+AppleWebKit/534.13+(KHTML,+like+Gecko)+Chrome/9.0.597.0+Safari/534.13 - 200 0 0 15248
03:27:31 <intip POST /login.aspx - 443 - Mozilla/5.0+(Windows;+U;+Windows+NT+6.1;+en-US)+AppleWebKit/534.13+(KHTML,+like+Gecko)+Chrome/9.0.597.0+Safari/534.13 - 200 0 0 15246
03:27:47 <intip POST /login.aspx - 443 - Mozilla/5.0+(Windows;+U;+Windows+NT+6.1;+en-US)+AppleWebKit/534.13+(KHTML,+like+Gecko)+Chrome/9.0.597.0+Safari/534.13 - 200 0 0 15242
03:28:02 <intip POST /login.aspx - 443 - Mozilla/5.0+(Windows;+U;+Windows+NT+6.1;+en-US)+AppleWebKit/534.13+(KHTML,+like+Gecko)+Chrome/9.0.597.0+Safari/534.13 - 200 0 0 15246

In conclusion…

Moral of the story: reviewing the response times to HTTP requests can aid in the successful exploitation of time-based SQL injections.

Tips & tricks

  • Build a base of what normal HTTP traffic looks like – What time do your users typically visit? – What countries are they from? – What devices do they use? – What is a normal amount of HTTP requests for a single browsing session

  • Check the initial HTTP request – Most users will visit the root first, for example, https://website.com/, then go about their business. If you have a page that would require a little bit of intentional searching to find, such as fileupload.aspx, and the first request of the suspected IP address is directly to fileupload.aspx, that’s a bit weird. How did they know this page exists if they haven’t browsed the site like a normal would? This may be a sign the attacker is using multiple IP addresses, and performed asset enumertion from a different IP address. In this case, check neighoring connections.

  • Check the HTTP referrer header

It’s hilarious what you can find here. I used to run a blog that would be DDoS’d occasionally, typically by people using web stressers or “booters”. It would be hilarious to see somebody would hit the “attack” button on ragebooter.net, then browse straight to my website from there, revealing https://ragebooter.net in the referrer header.

  • Check the HTTP response times

If you’re seeing a constant stream of very odd response times, this likely isn’t natural. If your webapp is normally averaging 10,000 MS response times, you have other problems to worry about.

  • Check the user-agents

User-agents will contain information related to the client that built the HTTP request. This is usually stuff like operating system, browser name, or anything related to the underlying technology used. For example, building HTTP requests with cURL will contain “cURL” in the user-agent of the HTTP requests it sends, unless you specify a different agent to use, or none at all. The same applies for programming libraries, such as Python’s Requests.

If you’re seeing a single IP address using a bunch of different user-agents in a short timeframe (like an hour..), this is often an attacker trying to evade detection, but usually overcompensating. I can’t imagine too many scenarios where a legitimate user would change user-agents 15 times in an hour, unless they’re using 10 different versions of Firefox and have 5 different computers and phones.