<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Usama helps you secure your APIs & apps]]></title><description><![CDATA[I write about web & api security here. Follow me to receive new articles about security.]]></description><link>https://blog.usamav.dev</link><generator>RSS for Node</generator><lastBuildDate>Mon, 13 Apr 2026 14:30:01 GMT</lastBuildDate><atom:link href="https://blog.usamav.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[XSS Vulnerability: A Quick Guide for Entry-Level Developers]]></title><description><![CDATA[XSS aka Cross Site Scripting is one of the strong enemies of developers. It ruins the whole app. Let me explain:
What’s XSS btw?
Imagine you have a magical input box on your website where users can leave comments. You as a developer expect a comment ...]]></description><link>https://blog.usamav.dev/xss-vulnerability-a-quick-guide-for-entry-level-developers</link><guid isPermaLink="true">https://blog.usamav.dev/xss-vulnerability-a-quick-guide-for-entry-level-developers</guid><category><![CDATA[XSS]]></category><category><![CDATA[Security]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[websecurity]]></category><category><![CDATA[penetration testing]]></category><dc:creator><![CDATA[Usama Varikkottil]]></dc:creator><pubDate>Mon, 26 Jun 2023 10:35:02 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1687775511349/b27dfe1e-d366-408e-8263-12cc8f1e2a54.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>XSS aka Cross Site Scripting is one of the strong enemies of developers. It ruins the whole app. Let me explain:</p>
<h1 id="heading-whats-xss-btw">What’s XSS btw?</h1>
<p>Imagine you have a magical input box on your website where users can leave comments. You as a developer expect a comment like this from your users:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1687772733391/5ee2a019-bf1f-4d98-8e55-88f1454cf2aa.png" alt class="image--center mx-auto" /></p>
<p><strong>But, uh-oh, someone leaves a comment like this:</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1687772828824/36a6a2e8-6217-40b9-a93e-3b030c3d305b.png" alt class="image--center mx-auto" /></p>
<p>XSS can make your website do funny and dangerous things. Look what happens when the bad code is executed:</p>
<p><strong>Bad code:</strong></p>
<pre><code class="lang-javascript">&lt;script&gt;
alert(<span class="hljs-string">"Uh-oh, XSS!"</span>)
&lt;/script&gt;
</code></pre>
<p>The output of the bad code when it is entered as a comment:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1687772947993/31052fbd-94e1-4c9d-af54-dbecc7dbb1c7.png" alt class="image--center mx-auto" /></p>
<p>Suddenly, a pop-up appears to the people while viewing comments! That's the trick of XSS - it can run any code it wants!</p>
<h1 id="heading-the-trouble-with-xss">The Trouble with XSS</h1>
<p>XSS can cause real trouble. An attacker could steal passwords or trick users into doing things they didn't mean to. It happens when bad hackers inject malicious code into your site, and innocent users execute it without being aware of it.</p>
<h2 id="heading-by-exploiting-xss-bad-guys-can">By exploiting XSS, bad guys can:</h2>
<ul>
<li><p>Hijack user accounts.</p>
</li>
<li><p>Steal sensitive user data.</p>
</li>
<li><p>Deface the website.</p>
</li>
<li><p>Redirect users to malicious sites.</p>
</li>
<li><p>Manipulate website content.</p>
</li>
</ul>
<p>Well done! you are an XSS king now. Haha, just kidding. You got a basic idea about XSS.</p>
<h1 id="heading-how-xss-attacks-happen">How XSS Attacks Happen:</h1>
<h3 id="heading-the-attackers-perspective">The Attacker's Perspective:</h3>
<p>Let's meet Mallory, a baaad hacker. Mallory loves exploiting XSS vulnerabilities and hacking victims.</p>
<p>Mallory visits websites. Finds weak spots. Injects malicious code to make things worse. Imagine Mallory as a clever attacker who earns by cheating people. He always looks for a way to pull off the ultimate trick.</p>
<h3 id="heading-the-victims-perspective">The Victim's Perspective:</h3>
<p>Now, let's introduce Alice, our victim user. Alice innocently visits the website. Alice doesn't know that a malicious code is lurking in the shadows.</p>
<p>Things get worse when Allice interacts with the website. And she becomes a victim of an XSS attack. Poor Alice, she had no idea what she was getting herself into!</p>
<p>All blame should be put on the developers for opening a door for the attacker Mallory.</p>
<h1 id="heading-summary">Summary</h1>
<p>So, in short, XSS is a JavaScript code injection on web applications. Attackers use vulnerable web apps to inject malicious javascript code or a script.</p>
<p>If the attackers could successfully input javascript code AND execute it on your application, then it means, your app is vulnerable to XSS.</p>
<p><strong>Love this blog post? I created a comprehensive XSS prevention guide for developers. Grab it by joining my newsletter or DM me “XSS101” on</strong> <a target="_blank" href="https://www.linkedin.com/in/usama-varikkottil/"><strong>LinkedIn here</strong></a><strong>.</strong></p>
]]></content:encoded></item><item><title><![CDATA[How to fix XSS vulnerabilities in Node.js and expressJS]]></title><description><![CDATA[What is XSS?
Simply we can say that XSS (Cross-site scripting) is a JavaScript code injection on web applications. Attackers use vulnerable web apps to inject malicious javascript code or a script. There are several types of XSS attacks.
The risks of...]]></description><link>https://blog.usamav.dev/how-to-fix-xss-vulnerabilities-in-nodejs-and-expressjs</link><guid isPermaLink="true">https://blog.usamav.dev/how-to-fix-xss-vulnerabilities-in-nodejs-and-expressjs</guid><category><![CDATA[Node.js]]></category><category><![CDATA[Security]]></category><category><![CDATA[Express]]></category><category><![CDATA[Express.js]]></category><category><![CDATA[hacking]]></category><dc:creator><![CDATA[Usama Varikkottil]]></dc:creator><pubDate>Thu, 27 Jan 2022 16:11:06 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1680848556383/e52d8960-e7e2-45f9-8550-89b6bcacef38.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-what-is-xss">What is XSS?</h1>
<p>Simply we can say that XSS (Cross-site scripting) is a JavaScript code injection on web applications. Attackers use vulnerable web apps to inject malicious javascript code or a script. There are several types of XSS attacks.</p>
<h1 id="heading-the-risks-of-having-an-xss-vulnerability">The risks of having an XSS vulnerability</h1>
<p>The malicious script can access any cookies, session tokens, or other sensitive information kept by the browser and used with that app. These scripts can even rewrite the content of the web page.</p>
<h1 id="heading-the-impact-an-xss-vulnerability-can-make-on-a-business">The impact an XSS vulnerability can make on a business</h1>
<p>In a worst-case scenario, an attacker could take over the whole web application. It results in leaking all of your user's data, gaining access to all the user accounts, and accessing the restricted areas of your web app, such as the admin panel.</p>
<h1 id="heading-how-to-fix-the-xss-vulnerabilities">How to fix the XSS vulnerabilities?</h1>
<p>Proper sanitization of the user inputs is one of the best methods to fix an XSS vulnerability. Below are the methods to prevent an XSS attack.</p>
<ol>
<li><p>Proper sanitization of inputs</p>
</li>
<li><p>Encoding the output data</p>
</li>
<li><p>Using proper response headers</p>
</li>
<li><p>Content security policy header</p>
</li>
</ol>
<h1 id="heading-how-to-prevent-xss-in-nodejs">How to prevent XSS in Node.js?</h1>
<p>There are several node packages available to prevent XSS through proper sanitization. We are using only the best ones available out there.</p>
<h2 id="heading-1-input-sanitization-using-the-validator-library">1. Input sanitization using the <code>validator</code> library.</h2>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> validator = <span class="hljs-built_in">require</span>(<span class="hljs-string">'validator'</span>);

<span class="hljs-keyword">let</span> string = <span class="hljs-string">"\"&gt;&lt;script&gt;alert(1234);&lt;/script&gt;"</span>
<span class="hljs-keyword">let</span> sanitized_string = validator.escape(string);
<span class="hljs-built_in">console</span>.log(<span class="hljs-string">" \n The input string is: "</span>, string);
<span class="hljs-built_in">console</span>.log(<span class="hljs-string">"The sanitized string is: "</span>,sanitized_string)
</code></pre>
<h4 id="heading-console-output-of-the-above-code">Console output of the above code:</h4>
<pre><code class="lang-http"><span class="hljs-attribute">The input string is</span>:  "&gt;&lt;script&gt;alert(1234);&lt;/script&gt;
<span class="hljs-attribute">The sanitized string is</span>:  &amp;quot;&amp;gt;&amp;lt;script&amp;gt;alert(1234);&amp;lt;&amp;#x2F;script&amp;gt;
</code></pre>
<p><code>validator.escape()</code> replaces <code>&lt;</code>, <code>&gt;</code>, <code>&amp;</code>, <code>'</code>, <code>"</code> and <code>/</code> with HTML entities.</p>
<p>Other than escaping these characters, a lot of sanitization and validation functions are available in the package <code>validator</code>. Check it out here: <a target="_blank" href="https://www.npmjs.com/package/validator">validator npm package</a></p>
<h2 id="heading-2-input-sanitization-using-xss-module">2. Input sanitization using <code>xss</code> module</h2>
<p><code>xss</code> is an npm module used to filter input from users to prevent XSS attacks.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">let</span> xss = <span class="hljs-built_in">require</span>(<span class="hljs-string">"xss"</span>);
<span class="hljs-keyword">let</span> string = <span class="hljs-string">"&lt;script&gt;alert(1234);&lt;/script&gt;"</span>
<span class="hljs-keyword">let</span> sanitized_string = xss(string);
<span class="hljs-built_in">console</span>.log(<span class="hljs-string">" \n The input string is: "</span>, string);
<span class="hljs-built_in">console</span>.log(<span class="hljs-string">"The sanitized string is: "</span>,sanitized_string)
</code></pre>
<h4 id="heading-console-output-of-the-above-code-1">Console output of the above code:</h4>
<pre><code class="lang-http"><span class="hljs-attribute">The input string is</span>:  &lt;script&gt;alert(1234);&lt;/script&gt;
<span class="hljs-attribute">The sanitized string is</span>:  &amp;lt;script&amp;gt;alert(1234);&amp;lt;/script&amp;gt;
</code></pre>
<p>The <code>xss</code> module is specifically developed for preventing XSS vulnerabilities. You can learn more about it here: <a target="_blank" href="https://www.npmjs.com/package/xss">npmjs.com/package/xss</a></p>
<h1 id="heading-how-to-prevent-xss-in-expressjs">How to prevent XSS in ExpressJS?</h1>
<blockquote>
<p><code>express-validator</code> is a set of express.js middlewares that wraps <code>validator.js</code> validator and sanitizer functions.</p>
</blockquote>
<h2 id="heading-input-sanitization-using-express-validator">Input sanitization using <code>Express-validator</code></h2>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> express = <span class="hljs-built_in">require</span>(<span class="hljs-string">'express'</span>);
<span class="hljs-keyword">const</span> { body } = <span class="hljs-built_in">require</span>(<span class="hljs-string">'express-validator'</span>);

<span class="hljs-keyword">const</span> app = express();
app.use(express.json());

app.post(
  <span class="hljs-string">'/comment'</span>,
  body(<span class="hljs-string">'text'</span>).escape(), 
  <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
    res.send(<span class="hljs-string">"The sanitized text is: "</span> + req.body.text);
  },
);

app.listen(<span class="hljs-number">5000</span>, <span class="hljs-function">()=&gt;</span>{
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"server is listening on port 5000"</span>)
})
</code></pre>
<p>We can send a <code>POST</code> request to the <code>/comment</code> route, as given below:</p>
<pre><code class="lang-http"><span class="hljs-keyword">POST</span> <span class="hljs-string">/comment</span> HTTP/1.1
<span class="hljs-attribute">Host</span>: localhost:5000
<span class="hljs-attribute">Content-Type</span>: application/json
<span class="hljs-attribute">Content-Length</span>: 42

<span class="json">{
<span class="hljs-attr">"text"</span>:<span class="hljs-string">"&lt;script&gt;alert(1337);&lt;/script&gt;"</span>
}</span>
</code></pre>
<h4 id="heading-the-response-to-the-above-request">The response to the above request:</h4>
<pre><code class="lang-http"><span class="hljs-attribute">The sanitized text is</span>: &amp;lt;script&amp;gt;alert(1337);&amp;lt;&amp;#x2F;script&amp;gt;
</code></pre>
<p>You can learn more about <code>express-validator</code> here: <a target="_blank" href="https://www.npmjs.com/package/express-validator">npmjs.com/package/express-validator</a></p>
<h1 id="heading-conclusion">Conclusion</h1>
<p>We have covered only the sanitization method to prevent XSS. As we have seen earlier, there are some more methods for reducing the impact of an XSS attack. I will update this blog post by adding those XSS prevention methods as well.</p>
<h1 id="heading-need-to-find-andamp-fix-xss-issues-on-your-app"><mark>Need to find &amp; fix XSS issues on your app?</mark></h1>
<p>Feel free to contact me on Linkedin: <a target="_blank" href="https://www.linkedin.com/in/usama-varikkottil/">https://www.linkedin.com/in/usama-varikkottil/</a></p>
]]></content:encoded></item><item><title><![CDATA[How to exploit a basic SSRF vulnerability?]]></title><description><![CDATA[The challenge in this writeup is from Portswigger's web security academy lab. You can access it here  for Free.
The challenge

We need to access the admin panel and delete the user called Carlos. We can only access the admin panel from the internal n...]]></description><link>https://blog.usamav.dev/how-to-exploit-a-basic-ssrf-vulnerability</link><guid isPermaLink="true">https://blog.usamav.dev/how-to-exploit-a-basic-ssrf-vulnerability</guid><category><![CDATA[Security]]></category><category><![CDATA[#cybersecurity]]></category><category><![CDATA[CyberSec]]></category><category><![CDATA[hacking]]></category><category><![CDATA[hack]]></category><dc:creator><![CDATA[Usama Varikkottil]]></dc:creator><pubDate>Sun, 09 Jan 2022 14:21:58 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1641709390900/enw5i9fT5O.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>The challenge in this writeup is from Portswigger's web security academy lab. You can access it <a target="_blank" href="https://portswigger.net/web-security/ssrf/lab-basic-ssrf-against-localhost">here </a> for <strong>Free</strong>.</p>
<h2 id="heading-the-challenge">The challenge</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1641709390900/enw5i9fT5O.png" alt="image.png" />
We need to access the admin panel and delete the user called <code>Carlos</code>. We can only access the admin panel from the internal network.</p>
<h2 id="heading-the-details-we-have">The details we have</h2>
<p>They have given us the details about the SSRF vulnerable endpoint. <code>Stock check</code> is the feature where SSRF vulnerability is present. Also, the admin interface URL is given. </p>
<h2 id="heading-exploring-the-app">Exploring the app</h2>
<p>The landing page of the lab. </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1641704070573/sqSQDoLRy.png" alt="image.png" /></p>
<p>On viewing any of the product details we could see an option to check stock.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1641704165581/1GVQRN4YI.png" alt="image.png" /></p>
<p>The below request is being sent to the server whenever we check the stock.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1641704272328/cwb0X3erG.png" alt="image.png" /></p>
<h3 id="heading-the-first-door-to-the-solution">The first door to the solution</h3>
<p>Let's change the stock URL with the URL given on the challenge home page.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1641704449040/JPRfbldiF.png" alt="image.png" /></p>
<p>When we send the above request, we get the admin interface in the place of stock details.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1641704583362/MFhK4-gtZ.png" alt="image.png" /></p>
<h3 id="heading-the-final-task">The Final task</h3>
<p>The primary task we have to complete is to delete the user named <code>Carlos</code>.</p>
<p>There is a delete button near the username <code>Carlos</code>. If we click the button, a <code>GET</code> request is sent to the server from  <strong><em>our browser</em></strong>. </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1641707968487/DYCRAoO5j.png" alt="image.png" /></p>
<p>However, the response is permission denied. What went wrong???
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1641708022260/yRi3EenqA.png" alt="image.png" /></p>
<p>The server will only accept all admin-requests only if it is coming from the internal network. Otherwise, it will reject the request.</p>
<p>So, just as we accessed the admin panel earlier, we should send the user-deletion request.</p>
<h4 id="heading-what-can-we-do-to-delete-the-user-carlos">What can we do to delete the user <code>Carlos</code>?</h4>
<p>Let's exploit the SSRF vulnerability present in the stock check feature, and send the user deletion request via exploiting the SSRF, which will hopefully delete the user <code>Carlos</code>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1641708675029/UGZ2-uXpf.png" alt="image.png" /></p>
<h3 id="heading-revisits-the-admin-page">Revisits the <code>admin</code> page</h3>
<p>Now if we go again to the <code>admin</code> page through the <code>stock check</code> endpoint, we could see only one user there. The user <code>Carlos</code> has successfully deleted.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1641708845420/pCwznOQF2.png" alt="image.png" /></p>
<p>We solved an easy lab <strong> Basic SSRF against the local server </strong> from Portswigger's Web security Academy.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1641708962792/IReFpNWpS.png" alt="image.png" /></p>
<h2 id="heading-references">References</h2>
<ul>
<li><a target="_blank" href="https://portswigger.net/web-security/ssrf/lab-basic-ssrf-against-localhost">Lab: Basic SSRF against the local server</a></li>
<li><a target="_blank" href="https://portswigger.net/web-security/ssrf">Learn more about SSRF vulnerability</a></li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Top 7 methods to find account takeover bugs in 2023]]></title><description><![CDATA[Making some weird API requests resulted in full user account takeovers, which paid me the highest reward of two bug bounty programs. Account takeovers are critical security vulnerabilities. Making strange API requests can sometimes lead to critical a...]]></description><link>https://blog.usamav.dev/account-takeover-bugs</link><guid isPermaLink="true">https://blog.usamav.dev/account-takeover-bugs</guid><category><![CDATA[Security]]></category><category><![CDATA[hacking]]></category><category><![CDATA[bugbounty]]></category><category><![CDATA[#cybersecurity]]></category><category><![CDATA[cybersecurity]]></category><dc:creator><![CDATA[Usama Varikkottil]]></dc:creator><pubDate>Sun, 29 Aug 2021 13:48:32 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/MdXBFRSEnhQ/upload/17cb9c8fb37e2ca7977ff48db09c6c66.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Making some weird API requests resulted in full user account takeovers, which paid me the highest reward of two bug bounty programs. Account takeovers are critical security vulnerabilities. Making strange API requests can sometimes lead to critical account takeover bugs. I discovered 2 such vulnerabilities while performing security tests on apps. Let's talk about those 2 specific bugs today.</p>
<h2 id="heading-the-first-target">The first target🎯</h2>
<p>It is a productivity application with 2+ million users. They have a Responsible Disclosure Policy, where they offered $2500 for critical security issues.</p>
<h4 id="heading-the-target-web-application-has-some-features-including-but-not-limited-to">The target web application has some features including, but not limited to:</h4>
<ul>
<li><p>Create user accounts and log in to the account.</p>
</li>
<li><p>The users can create workspaces.</p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1622197884628/aoQcb5sFL.png" alt="image.png" /></p>
</li>
<li><p>The admin users in the workspaces can invite new team members to the workspaces.</p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1622198289821/8NEmCbapO.png" alt="image.png" /></p>
</li>
<li><p>One user can be a member of multiple workspaces.</p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1622198571942/-n-cNcOOo.png" alt="image.png" /></p>
</li>
</ul>
<hr />
<h2 id="heading-finding-the-first-two-bugs">Finding the first two bugs</h2>
<p>I was exploring the target web application features and got 2 minor security issues in 7 days. Even though they offer a $100 bounty for similar minor issues, I didn't report those two issues because I was not happy with those findings. This doesn't mean that I won't report minor issues, I will report those issues anyway, but once after I cannot make it to high impact.</p>
<h4 id="heading-the-two-minor-issues-i-found-were">The two minor issues I found were:</h4>
<ol>
<li><p>No expiration of the old password reset link after requesting a new password reset link.</p>
</li>
<li><p>Response manipulation during the user account deletion process.</p>
</li>
</ol>
<p>To delete a user account, the user has to enter his current password for verification. I could bypass it simply by changing a <code>false</code> value into <code>true</code>. This resulted in the user account deletion without entering the correct password.</p>
<p>I needed to make the response manipulation vulnerability worth reporting by increasing the impact. So I started experimenting with the features related to team members (workspace), by thinking response manipulation could be used again somewhere in the application to get some cool privilege escalation bugs.</p>
<p>Sadly, there were no such requests that needed a response for validation, not even 2FA. So I started testing for IDORs on the web application.</p>
<h3 id="heading-multiple-user-accounts-for-testing-idor">Multiple user accounts for testing IDOR</h3>
<p>I registered 2 user accounts with 2 different emails: <a target="_blank" href="mailto:adimon@just4fun.me"><code>adimon@just4fun.me</code></a> for the admin and <a target="_blank" href="mailto:attacker@appzily.com"><code>attacker@appzily.com</code></a> for the attacker. On creating a new user account, a default workspace automatically gets created inside the user account. The name of the default workspace always starts with the user's first name.</p>
<p>Let's call the victim user "Adimon" and the attacker user "Attacker".</p>
<blockquote>
<p>We can use the <code>Chrome profile</code> feature to keep all our info separate, such as cookies and sessions. We can log in to the Attacker's account and the victim's account in Chrome itself. We don't have to open different browsers for keeping different sessions separately.</p>
</blockquote>
<p>By analyzing the <code>HTTP</code> requests and responses, I got the following information about the accounts I created while playing with the application.</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td></td><td>attacker</td><td>admin</td></tr>
</thead>
<tbody>
<tr>
<td><code>email</code></td><td><a target="_blank" href="mailto:attacker@appzily.com">attacker@appzily.com</a></td><td><a target="_blank" href="mailto:adimon@just4fun.me">adimon@just4fun.me</a></td></tr>
<tr>
<td><code>userId</code></td><td>60b64f71adf0d3543cfd8225</td><td>60c30f168747147d9acd89aa</td></tr>
<tr>
<td><code>workspace IDs</code></td><td>60b64f71adf0d3543cfd8229, 60c30f178747147d9acd89ba</td><td>60c30f178747147d9acd89ba</td></tr>
<tr>
<td><code>Owned workspace IDs</code></td><td>60b64f71adf0d3543cfd8229</td><td>60c30f178747147d9acd89ba</td></tr>
</tbody>
</table>
</div><blockquote>
<p>Usually, I use temporary email services like <a target="_blank" href="http://temp-mail.io">temp-mail.io</a> or <a target="_blank" href="http://mail.tm">mail.tm</a> for using multiple emails during pentesting. Because I don't want to mess up my Gmail account.</p>
</blockquote>
<h3 id="heading-privilege-escalation-bugs-inside-a-workspace">Privilege escalation bugs inside a workspace</h3>
<p>From Adimon's account, I invited the attacker to Adimon's workspace. The invitation request has shown below.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1625101412363/PVSNBASUr.png" alt="image.png" /></p>
<h2 id="heading-simplified-request">Simplified request</h2>
<p>There are 3 major parts in every request for this target API.</p>
<h3 id="heading-1-auth-token">1. Auth token.</h3>
<p>Auth tokens are different for different users. Adimon will have an auth token, and the attacker will have another auth token. An API request made from Adimon's account should be included Adimon's auth token.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1626796353347/SVafrck2r.png" alt="image.png" /></p>
<p><em>The token may or may not expire at a certain timeframe, but we don't have to worry about it for now.</em></p>
<h4 id="heading-how-do-we-obtain-a-request-from-adimon-and-send-it-as-the-attacker">How do we obtain a request from Adimon and send it as the attacker?</h4>
<p>Good question😃. We can do that by replacing Adimon's auth token with the attacker's auth token.</p>
<h3 id="heading-2-api-route">2. API route</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1626796965789/Hz_LYXhX0.png" alt="image.png" /></p>
<p>There will be separate API routes for different functions of the application. API requests related to workspace comes under <code>/workspace</code> route. The above screenshot shows an API request made when inviting a user to Adimon's workspace. Therefore, the ID in the request is Adimon's workspace ID.</p>
<h3 id="heading-3-request-data">3. Request data.</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1626797225114/VfXeFIU_0.png" alt="image.png" /></p>
<p>We are working with a workspace invitation request above, so the relevant data would be about whom to be invited. If the request was related to a photo upload, then the request data would be details about the uploading photo.</p>
<p>The workspace admins invite new users by email, so the request data contains the emails to be invited into the workspace.</p>
<pre><code class="lang-http"><span class="hljs-keyword">POST</span> <span class="hljs-string">/workspaces/&lt;Adimon's_workspace_ID&gt;/users?sendEmail=true</span> HTTP/1.1
<span class="hljs-attribute">Host</span>: global.api.host.com
<span class="hljs-attribute">Connection</span>: close
<span class="hljs-attribute">Content-Type</span>: application/json
<span class="hljs-attribute">X-Auth-Token</span>: &lt;Adimon's Auth token&gt;

<span class="json">{<span class="hljs-attr">"emails"</span>: [<span class="hljs-string">"attacker@appzily.com"</span>], <span class="hljs-attr">"captchaValue"</span>: <span class="hljs-string">"_"</span>}</span>
</code></pre>
<p>As per the target application, only the workspace admin can:</p>
<ul>
<li><p>invite new users to the team</p>
</li>
<li><p>edit the privileges of the invited users</p>
</li>
<li><p>delete the user from the team</p>
</li>
<li><p>and so on.</p>
</li>
</ul>
<h4 id="heading-how-can-we-test-and-exploit-the-application">How can we test and exploit the application?</h4>
<p>Good question😃. We need to go through each request individually to test for some vulnerabilities like IDOR. In Adimon's workspace, check if the attacker has the same permissions as Adimon.</p>
<p>Using the attacker's Auth token, I tried sending requests to edit, invite, and delete a user from Adimon's workspace. Unfortunately, every request failed by showing a <code>403 Forbidden</code> error.</p>
<p><em>The following screenshot shows a sample request made using the attacker's auth token, to invite a random user into Adimon's workspace.</em></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1625334317513/slnrM_lUIk.png" alt="image.png" /></p>
<pre><code class="lang-http"><span class="hljs-keyword">POST</span> <span class="hljs-string">/workspaces/60c30f178747147d9acd89ba/users?sendEmail=true</span> HTTP/1.1
<span class="hljs-attribute">Host</span>: global.api.host.com
<span class="hljs-attribute">Content-Type</span>: application/json
<span class="hljs-attribute">X-Auth-Token</span>: eyJ0eXAiOiJKV1QiLCJhbGciOiJS...&lt;Attacker's AUTH Token&gt;

<span class="json">
{<span class="hljs-attr">"emails"</span>:[<span class="hljs-string">"random@gmail.com"</span>],<span class="hljs-attr">"captchaValue"</span>:<span class="hljs-string">"_"</span>}</span>
</code></pre>
<h2 id="heading-a-method-to-bypass-the-403-forbidden-error">A method to bypass the <code>403 Forbidden</code> error</h2>
<p>I read a lot of #bugbounty tips from Twitter about bypassing 403 Forbidden errors that help us during API hacking. I started testing them one by one.</p>
<h3 id="heading-1-wrap-id-with-an-array">1: Wrap ID with an array</h3>
<h4 id="heading-send-an-array-of-workspace-ids-failed">Send an array of workspace IDs. <code>Failed</code></h4>
<pre><code class="lang-http"><span class="hljs-keyword">POST</span> <span class="hljs-string">/workspaces/[60c30f178747147d9acd89ba]/users?sendEmail=true</span> HTTP/1.1
<span class="hljs-attribute">Host</span>: global.api.host.com
<span class="hljs-attribute">Content-Type</span>: application/json
<span class="hljs-attribute">X-Auth-Token</span>: eyJ0eXAiOiJKV1QiLCJhbGciOiJS...&lt;Attacker's AUTH Token&gt;

<span class="json">{<span class="hljs-attr">"emails"</span>:[<span class="hljs-string">"random@gmail.com"</span>],<span class="hljs-attr">"captchaValue"</span>:<span class="hljs-string">"_"</span>}</span>
</code></pre>
<h4 id="heading-an-array-of-emails-failed">An array of Emails. <code>Failed</code></h4>
<p>The email is sent as an array by default, so let's try changing it to a nested array.</p>
<pre><code class="lang-http"><span class="hljs-keyword">POST</span> <span class="hljs-string">/workspaces/60c30f178747147d9acd89ba/users?sendEmail=true</span> HTTP/1.1
<span class="hljs-attribute">Host</span>: global.api.host.com
<span class="hljs-attribute">Content-Type</span>: application/json
<span class="hljs-attribute">X-Auth-Token</span>: eyJ0eXAiOiJKV1QiLCJhbGciOiJS...&lt;Attacker's AUTH Token&gt;

<span class="json">
{<span class="hljs-attr">"emails"</span>:[[<span class="hljs-string">"random@gmail.com"</span>]],<span class="hljs-attr">"captchaValue"</span>:<span class="hljs-string">"_"</span>}</span>
</code></pre>
<h3 id="heading-2-wrap-id-with-a-json-object-failed">2: Wrap ID with a JSON object <code>Failed</code></h3>
<pre><code class="lang-http"><span class="hljs-keyword">POST</span> <span class="hljs-string">/workspaces/{"id":"60c30f178747147d9acd89ba"}/users?sendEmail=true</span> HTTP/1.1
<span class="hljs-attribute">Host</span>: global.api.host.com
<span class="hljs-attribute">Content-Type</span>: application/json
<span class="hljs-attribute">X-Auth-Token</span>: eyJ0eXAiOiJKV1QiLCJhbGciOiJS...&lt;Attacker's AUTH Token&gt;

<span class="json">
{<span class="hljs-attr">"emails"</span>:[<span class="hljs-string">"random@gmail.com"</span>],<span class="hljs-attr">"captchaValue"</span>:<span class="hljs-string">"_"</span>}</span>
</code></pre>
<h4 id="heading-send-the-email-as-a-json-object">Send the email as a JSON object</h4>
<pre><code class="lang-http"><span class="hljs-keyword">POST</span> <span class="hljs-string">/workspaces/60c30f178747147d9acd89ba/users?sendEmail=true</span> HTTP/1.1
<span class="hljs-attribute">Host</span>: global.api.host.com
<span class="hljs-attribute">Content-Type</span>: application/json
<span class="hljs-attribute">X-Auth-Token</span>: eyJ0eXAiOiJKV1QiLCJhbGciOiJS...&lt;Attacker's AUTH Token&gt;

<span class="json">
{<span class="hljs-attr">"emails"</span>:[{<span class="hljs-attr">"email"</span>: <span class="hljs-string">"random@gmail.com"</span>}],<span class="hljs-attr">"captchaValue"</span>:<span class="hljs-string">"_"</span>}</span>
</code></pre>
<h3 id="heading-3-change-the-request-method-failed">3: Change the request method <code>Failed</code></h3>
<p>I tried changing every <code>POST</code> request to <code>DELETE</code>, <code>PUT</code>, and <code>PATCH</code>. But it failed by showing a <code>405 method not allowed</code> error.</p>
<pre><code class="lang-http"><span class="hljs-keyword">PUT</span> <span class="hljs-string">/workspaces/&lt;workspace_ID&gt;/users?sendEmail=true</span> HTTP/1.1
...
...
</code></pre>
<pre><code class="lang-http"><span class="hljs-keyword">PATCH</span> <span class="hljs-string">/workspaces/&lt;workspace_ID&gt;/users?sendEmail=true</span> HTTP/1.1
...
...
</code></pre>
<pre><code class="lang-http"><span class="hljs-keyword">DELETE</span> <span class="hljs-string">/workspaces/&lt;workspace_ID&gt;/users?sendEmail=true</span> HTTP/1.1
...
...
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1628417168241/SX686uPt8.png" alt="image.png" /></p>
<h3 id="heading-4-addchange-the-api-version-in-the-route-failed">4: Add/Change the API version in the route <code>Failed</code></h3>
<p>We need to check if older versions of API exist by adding <code>/v1/</code>, <code>/v2/</code>, or <code>/v3/</code> to the route. I tested all API versions since there were no version numbers sent in this API request by default.</p>
<pre><code class="lang-http"><span class="hljs-keyword">POST</span> <span class="hljs-string">/v1/workspaces/&lt;workspace_ID&gt;/users?sendEmail=true</span> HTTP/1.1
...
...
</code></pre>
<pre><code class="lang-http"><span class="hljs-keyword">POST</span> <span class="hljs-string">/v2/workspaces/&lt;workspace_ID&gt;/users?sendEmail=true</span> HTTP/1.1
...
...
</code></pre>
<p>I got nothing except the server's <code>404 Not Found</code> error response while playing with API versions.</p>
<h3 id="heading-5-ids-as-a-wildcard-character-failed">5: IDs as a wildcard character <code>Failed</code></h3>
<p>Sometimes replacing the IDs, emails, or usernames with a wildcard character would cause some strange responses from the server. For example, <code>*</code> means "All", so replacing an ID with a <code>*</code> character in a request would mean doing the same thing for all the IDs in the database instead of just one.</p>
<p>As in the example request given below, I tried to replace the workspace ID with a <code>*</code> character to check if I can invite a new user into every workspace out there in the target application. Unfortunately, the only response I'm getting from the server was a <code>404 Not Found</code> error.</p>
<pre><code class="lang-http"><span class="hljs-keyword">POST</span> <span class="hljs-string">/workspaces/*/users?sendEmail=true</span> HTTP/1.1
<span class="hljs-attribute">Host</span>: global.api.host.com
<span class="hljs-attribute">Content-Type</span>: application/json
<span class="hljs-attribute">X-Auth-Token</span>: ....

<span class="json">
{<span class="hljs-attr">"emails"</span>:[<span class="hljs-string">"myEmail@gmail.com"</span>],<span class="hljs-attr">"captchaValue"</span>:<span class="hljs-string">"_"</span>}</span>
</code></pre>
<h3 id="heading-6-add-url-encoded-null-characters-failed">6: Add URL encoded null characters: <code>Failed</code></h3>
<pre><code class="lang-http"><span class="hljs-keyword">POST</span> <span class="hljs-string">/workspaces/60c30f178747147d9acd89ba%00/users?sendEmail=true</span> HTTP/1.1
<span class="hljs-attribute">Host</span>: global.api.host.com
<span class="hljs-attribute">Content-Type</span>: application/json
<span class="hljs-attribute">X-Auth-Token</span>: eyJ0eXAiOiJKV1QiLCJhbGciOiJS...&lt;Attacker's AUTH Token&gt;

<span class="json">
{<span class="hljs-attr">"emails"</span>:[<span class="hljs-string">"random@gmail.com"</span>],<span class="hljs-attr">"captchaValue"</span>:<span class="hljs-string">"_"</span>}</span>
</code></pre>
<p>We get some weird responses sometimes from the server by adding null characters in the requests. Try adding <code>%00</code> in the URL, request data, header, etc. However, this API and server handled every null character carefully.</p>
<hr />
<p>I don't even remember what other things I tested on this API, but I'm sure that I spent a few days just playing on the API with the goal of finding something interesting.</p>
<p>I wanted to test more on this API, but there were no tricks left in my brain at that moment. I knew there are a lot of <code>bug bounty tips</code> shared on Twitter. And the collections of such <code>bug bounty tips</code> are shared on the web.</p>
<p>I made a quick google search for "API bug bounty tips". And I came across a GitHub repository of API security checklists. <a target="_blank" href="https://gowsundar.gitbook.io/book-of-bugbounty-tips/api">Book-of-bugbounty-tips/api</a> (Not 100% sure if this is the repository I landed at.).</p>
<p>After some tests and failures, I tried testing with an <code>../</code> in the API route. The attacker's workspace ID is <code>60b64f71adf0d3543cfd8229</code> and Adimon's workspace ID is <code>60c30f178747147d9acd89ba</code>.</p>
<pre><code class="lang-http"><span class="hljs-keyword">POST</span> <span class="hljs-string">/workspaces/60b64f71adf0d3543cfd8229/../60c30f178747147d9acd89ba/users?sendEmail=true</span> HTTP/1.1
<span class="hljs-attribute">Host</span>: global.api.host.com
<span class="hljs-attribute">Content-Type</span>: application/json
<span class="hljs-attribute">X-Auth-Token</span>: eyJ0eXAiOiJKV1QiLCJhbGciOiJS...&lt;Attacker's AUTH Token&gt;

<span class="json">
{<span class="hljs-attr">"emails"</span>:[<span class="hljs-string">"random@gmail.com"</span>],<span class="hljs-attr">"captchaValue"</span>:<span class="hljs-string">"_"</span>}</span>
</code></pre>
<p>And to my surprise, it was successful😇. I could invite new users to the Adimon workspace by sending a request like the above using the attacker's auth token.</p>
<h4 id="heading-whats-the-next-step">What's the next step?</h4>
<p>Increasing the impact of the vulnerability is the next step. It would be a good deal if we could somehow take over user accounts by exploiting this vulnerability.</p>
<h3 id="heading-password-change">Password change</h3>
<p>I tried changing Adimon's password from the attacker's account by exploiting the above vulnerability. Sadly, it failed since Adimon's old password is required to change the password of Adimon.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1629396381676/juXTUsPDX.png" alt="image.png" /></p>
<p>Okay, next which is the feature to achieve an account takeover by exploiting the vulnerability? Yeah, email changing.</p>
<h3 id="heading-changing-email-of-a-user">Changing email of a user</h3>
<p>Let's try changing Adimon's email using the attacker's auth token in the request. If we get a successful response, we could send the <code>forgot password</code> request later, and the reset email would receive into the updated email address.</p>
<p>A normal email change request looks like this:</p>
<pre><code class="lang-http"><span class="hljs-keyword">PUT</span> <span class="hljs-string">/users/60b64f71adf0d3543cfd8225/email</span> HTTP/1.1
<span class="hljs-attribute">Host</span>: global.api.host.com
<span class="hljs-attribute">Content-Type</span>: application/json
<span class="hljs-attribute">X-Auth-Token</span>: eyJ0eXAiOiJKV1QiLCJhbGciOiJS...&lt;Attacker's AUTH Token&gt;

<span class="json">
{<span class="hljs-attr">"email"</span>:<span class="hljs-string">"attacker-mon@gmail.com"</span>}</span>
</code></pre>
<p><code>60b64f71adf0d3543cfd8225</code> is the userID of the attacker. I sent the below request to change Adimon's email using the attacker's AUTH token. Adimon's userId is <code>60c30f168747147d9acd89aa</code>.</p>
<pre><code class="lang-http"><span class="hljs-keyword">PUT</span> <span class="hljs-string">/users/60b64f71adf0d3543cfd8225/../60c30f168747147d9acd89aa/email</span> HTTP/1.1
<span class="hljs-attribute">Host</span>: global.api.host.com
<span class="hljs-attribute">Content-Type</span>: application/json
<span class="hljs-attribute">X-Auth-Token</span>: eyJ0eXAiOiJKV1QiLCJhbGciOiJS...&lt;Attacker's AUTH Token&gt;

<span class="json">
{<span class="hljs-attr">"email"</span>:<span class="hljs-string">"attacker-mon@gmail.com"</span>}</span>
</code></pre>
<p>The request was successful. And it responded with a <code>200 OK</code> response. Cool... But the email change has not been completed yet, because a verification link needs to click in order to complete the email change process.</p>
<p>There are two possibilities here: The email change verification link would receive into</p>
<ol>
<li><p>the current email.</p>
</li>
<li><p>The newly requested email.</p>
</li>
</ol>
<p>For my luck, it delivered the verification link to the newly requested email. That means, to the attacker's email. In our case, the current email is Adimon's email and the newly requested email is the attacker's email. Taking over Adimon's account from the attacker's account has been done successfully. If an attacker has the <code>userId</code> of the victim, he can successfully take over the victim's account.</p>
<h3 id="heading-solving-the-last-problem">Solving the last problem</h3>
<p>There is one more thing we need to find: The <code>userId</code>. We have successfully found an IDOR vulnerability. But in order to exploit the attack, we need to find <code>userId</code> of the victim user(Adimon in our case).</p>
<h4 id="heading-how-do-we-obtain-the-userid">How do we obtain the <code>userId</code>?</h4>
<p>There is a feature to invite users to the workspace using their email.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1622198289821/8NEmCbapO.png" alt="image.png" /></p>
<p>From the attacker's account, I invited Adimon into the attacker's workspace. After sending the invitation request, the response to that request contained <code>userId</code> of the invited email.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1629646426865/8k1xgV63q.png" alt="image.png" /></p>
<p>Only the user email is needed to get the <code>userId</code>, if there is a user account with the entered email, then the response contains that user's <code>userId</code>.</p>
<p>The complete attack looks like this:</p>
<ol>
<li><p>The attacker invites Adimon to his workspace, by entering the email address <a target="_blank" href="mailto:adimon@just4fun.me"><code>adimon@just4fun.me</code></a>.</p>
</li>
<li><p>Get Adimon's <code>userId</code> from the #1 response.</p>
</li>
<li><p>The attacker changes the email of Adimon into the attacker's email by exploiting IDOR vulnerability.</p>
</li>
<li><p>Make a forgot password request.</p>
</li>
</ol>
<h4 id="heading-bug-report">Bug report</h4>
<p>I made a report and sent it to the company.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1630160892894/-W_cwpqeA.png" alt="image.png" /></p>
<h3 id="heading-the-total-bounty-amount">The total bounty amount</h3>
<blockquote>
<p>Did you know that you can like this post 10 times, if you do, that will make my day! If you don't, it's okay too...</p>
</blockquote>
<p>5 days later after sending the report, I got an email from the team regarding the bounty amount of $2500.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1622305312952/NU872ALCx.png" alt="image.png" /></p>
<h3 id="heading-the-role-of-luck-in-bug-bounty-hunting">The role of luck in bug bounty hunting</h3>
<p>Imagine if they delivered the verification link of the email change request to the current email instead of the new email. I would not find Account takeover vulnerability then. I was lucky enough to receive the verification email to the newly requested email. Luck will come automatically if we work consistently. We can increase the chances of luck by putting in more effort.</p>
<h3 id="heading-reported-1-minor-issue">Reported 1 minor issue</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1629826147933/ju5vRj6o9.png" alt="image.png" /></p>
<p>I mentioned about 2 minor issues I got while hunting the target. I reported the second issue. Unfortunately, it was a duplicate finding.</p>
<h3 id="heading-where-the-heck-is-the-second-account-takeover">Where the heck is the second account takeover?</h3>
<p>I planned to cover details about both the account takeover vulnerabilities in this blog post. But seriously dude, writing a write-up is very challenging and hard. I will publish the other account takeover vulnerability as a new blog post on another day.</p>
<h3 id="heading-struggling-to-get-your-first-bounty">Struggling to get your first bounty?</h3>
<p>If you are still struggling to find your first bug, I get you, dude. It is indeed tough. But it's possible.</p>
<p>If you want this company's details, message "ATOblog" to my <a target="_blank" href="https://www.linkedin.com/in/usama-varikkottil/">LinkedIn here</a>, and I will be happy to share this program's details with you.</p>
<h3 id="heading-references">References</h3>
<ul>
<li><p><a target="_blank" href="https://gowsundar.gitbook.io/book-of-bugbounty-tips/api">https://gowsundar.gitbook.io/book-of-bugbounty-tips/api</a></p>
</li>
<li><p><a target="_blank" href="https://github.com/arainho/awesome-api-security">https://github.com/arainho/awesome-api-security</a></p>
</li>
<li><p><a target="_blank" href="https://github.com/inonshk/31-days-of-API-Security-Tips">https://github.com/inonshk/31-days-of-API-Security-Tips</a></p>
</li>
<li><p><a target="_blank" href="https://github.com/HolyBugx/HolyTips/blob/main/Checklist/API%20Security.pdf">https://github.com/HolyBugx/HolyTips/blob/main/Checklist/API%20Security.pdf</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[How I got $400 for my first SSRF bug?]]></title><description><![CDATA[A story about my first SSRF finding on a bug bounty target web app, where I further exploited the SSRF bug into reading internal server files, which leads to AWS instance secret leakage. There were no filtering or firewalls on my target. So let's jum...]]></description><link>https://blog.usamav.dev/how-i-got-400-usd-for-my-first-ssrf-bug</link><guid isPermaLink="true">https://blog.usamav.dev/how-i-got-400-usd-for-my-first-ssrf-bug</guid><category><![CDATA[Security]]></category><category><![CDATA[webdev]]></category><category><![CDATA[hacking]]></category><category><![CDATA[hack]]></category><dc:creator><![CDATA[Usama Varikkottil]]></dc:creator><pubDate>Sat, 01 May 2021 19:03:20 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1619895368945/edp26jxVy.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>A story about my first SSRF finding on a bug bounty target web app, where I further exploited the SSRF bug into reading internal server files, which leads to AWS instance secret leakage. There were no filtering or firewalls on my target. So let's jump straight into the bug exploitation.</p>
<p>The target was a productivity app. There was a feature to create and manage projects in it. After spending almost 8+ hours exploring <a class="post-section-overview" href="#">app.target.com</a> features, I came to notice a button that prints the projects created on my account. </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1618731184323/ME5EiUYyZ.png" alt="Untitled.png" /></p>
<p>When I clicked the button, a PDF was generated with my project in it. Okay, enough for opening up Burpsuite, it seems interesting to dive deep into it. And I intercepted the HTTP request that is going to the server when I click on the <code>Print</code> button. And it was very interesting.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1618737098087/ewQ3FKOB_.png" alt="Untitled 1.png" /></p>
<p>There was an <code>html</code> parameter, which contains a whole bunch of HTML codes, which the PDF generates from it. </p>
<p>I tried sending the request by entering some random HTML codes as the <code>html</code> parameter value, and it generated the PDFs successfully. </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1618732236151/MzppRnQK6W.png" alt="Untitled 2.png" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1618737158606/f5TWromwc.png" alt="Untitled 3.png" /></p>
<p>Alright, now let's try sending some <code>iframe</code> tags as the <code>html</code> parameter's value. I tried embedding my personal website using the <code>&lt;iframe&gt;</code> tag.</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">iframe</span> <span class="hljs-attr">src</span>=<span class="hljs-string">https://www.usamav.dev</span> <span class="hljs-attr">width</span>=<span class="hljs-string">100%</span> <span class="hljs-attr">height</span>=<span class="hljs-string">100%</span>&gt;</span>
</code></pre>
<p>The generated pdf contained my personal website embedded in it. Cool...</p>
<p>The next step is to access the internal files using <code>&lt;iframe&gt;</code> tags. First, let's start with <code>/etc/passwd</code>.</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">iframe</span> <span class="hljs-attr">src</span>=<span class="hljs-string">file:///etc/passwd</span> <span class="hljs-attr">width</span>=<span class="hljs-string">100%</span> <span class="hljs-attr">height</span>=<span class="hljs-string">100%</span>&gt;</span>
</code></pre>
<p>This generated a pdf with the following content.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1618737186476/a2EK1xZsl-.png" alt="Untitled 4.png" /></p>
<p>The target was running on an AWS EC2 server. So it's time to access AWS EC2 server meta-data. As per <a target="_blank" href="https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instancedata-data-retrieval.html">AWS documentation</a>, </p>
<blockquote>
<p>"To view all categories of instance metadata from within a running instance, use the following URI. <a target="_blank" href="http://169.254.169.254/latest/meta-data/">http://169.254.169.254/latest/meta-data/</a>. The IP address 169.254.169.254 is a link-local address and is valid only from the instance."</p>
</blockquote>
<p>We can try embedding the above URI in the PDF using the <code>&lt;iframe&gt;</code> tag to access the meta-data.</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">iframe</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"http://169.254.169.254/latest/meta-data"</span>+<span class="hljs-attr">width</span>=<span class="hljs-string">"100%"</span>+<span class="hljs-attr">height</span>=<span class="hljs-string">"100%"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">iframe</span>&gt;</span>
</code></pre>
<p>This was also successful. I immediately got the pdf with the meta-data in it.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1618737208263/ttwN3L5K8.png" alt="Untitled 5.png" /></p>
<p>I was able to access some confidential data such as secret_key, private access key, internal server files, mac address, user details, instance details, etc.</p>
<p>The whole process took a little while than I expected. Because whenever I sent a request with the HTML codes to the server, I get a unique code for that PDF, to access the generated PDF, I needed to copy that unique code and paste it on another endpoint on that API. So to automate this boring task, I made a quick python script to automate the PDF generation. </p>
<p>And finally, I spend almost 1 day alone writing a bug report and sent it to the responsible security team. Within a few hours, they responded to my report. I also sent the python script along with the report. I was so excited as this is my first ever SSRF finding on a real-world target. </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1618737233606/yM4e2urdB.png" alt="Untitled 6.png" /></p>
<p>Although, the bug was not a critical finding as I expected.
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1619723399611/5LS2X_9zn.png" alt="image.png" /></p>
<p>And finally, I received the bounty amount of $400 on 22nd April 2021.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1619724049130/ntk5LysHy.png" alt="image.png" /></p>
<hr />
<p>As you have read till here, you would've noticed that this bug is such an easy-to-exploit bug. No firewall, no fancy bypassing techniques, not so complicated, just a straightforward bug.</p>
<p>However, writeups of easy findings motivate me oftentimes. Every time I read similar writeups of some kind of easy bugs, I feel like I have enough skill to start hunting a target application. Usually, those writeups help me to escape from the tutorial hell and push me to start doing the work.</p>
<p>I hope this write-up will also motivate someone to hunt your target for bugs. You can always reach out to me on Twitter at <a target="_blank" href="https://twitter.com/usama_dev">@usama_dev</a></p>
<p>Good luck... and Thanks for reading till here...</p>
]]></content:encoded></item><item><title><![CDATA[Difference Between var, let, and const in Javascript]]></title><description><![CDATA[var and let
These are two keywords used to declare variables in Javascript. Even though most beginners know these two keywords exist, we struggle with finding the difference between them. So let's look at the difference between these keywords.
Declar...]]></description><link>https://blog.usamav.dev/difference-between-var-let-and-const-in-javascript</link><guid isPermaLink="true">https://blog.usamav.dev/difference-between-var-let-and-const-in-javascript</guid><category><![CDATA[JavaScript]]></category><category><![CDATA[React]]></category><category><![CDATA[javascript modules]]></category><category><![CDATA[webdev]]></category><category><![CDATA[Beginner Developers]]></category><dc:creator><![CDATA[Usama Varikkottil]]></dc:creator><pubDate>Sun, 11 Oct 2020 06:30:12 GMT</pubDate><content:encoded><![CDATA[<h3 id="var-and-let">var and let</h3>
<p>These are two keywords used to declare variables in Javascript. Even though most beginners know these two keywords exist, we struggle with finding the difference between them. So let's look at the difference between these keywords.</p>
<h5 id="declaring-variables-example">Declaring variables Example</h5>
<pre><code class="lang-javascript"><span class="hljs-keyword">var</span> humanOne = <span class="hljs-string">"usama"</span>;
<span class="hljs-keyword">let</span> humanTwo = <span class="hljs-string">"jaba"</span>;

<span class="hljs-built_in">console</span>.log(humanOne); <span class="hljs-comment">//Output: usama</span>
<span class="hljs-built_in">console</span>.log(humanTwo); <span class="hljs-comment">//Output: jaba</span>
</code></pre>
<h4 id="declaring-variables-in-for-loop-let-and-var">Declaring variables in for loop (<code>let</code> and <code>var</code>)</h4>
<pre><code class="lang-javascript"><span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i=<span class="hljs-number">0</span>; i&lt;<span class="hljs-number">10</span>; i++){
    <span class="hljs-built_in">console</span>.log(i);<span class="hljs-comment">//Ouput will contain numbers from 0 to 9</span>
}
<span class="hljs-built_in">console</span>.log(i);<span class="hljs-comment">// This will throw an error.</span>
</code></pre>
<p>In the above example, the <code>console.log</code> inside the <code>for</code> loop block will print numbers from zero to nine on the console. However, the last <code>console.log</code> code outside <code>for</code> loop block will throw an error, Since the variables declared using <code>let</code> keyword is only accessible in the block where it is declared. In this case, the variable <code>i</code> is only accessible inside the <code>for</code> loop block.</p>
<h5 id="now-lets-change-the-let-with-var-on-the-above-code">Now let's change the <code>let</code> with <code>var</code> on the above code.</h5>
<pre><code class="lang-javascript"><span class="hljs-keyword">for</span> (<span class="hljs-keyword">var</span> i=<span class="hljs-number">0</span>; i&lt;<span class="hljs-number">10</span>; i++){
    <span class="hljs-built_in">console</span>.log(i);<span class="hljs-comment">//Ouput will contain numbers from 0 to 9</span>
}
<span class="hljs-built_in">console</span>.log(i);<span class="hljs-comment">// Output: 10</span>
</code></pre>
<p>In the above example, <code>i</code> is accessible outside the <code>for</code> loop block. Because we are using the keyword <code>var</code> to declare a variable <code>i</code>. Here the first <code>console.log</code> code will print the numbers from 0 to 9. And after printing the number 9, the value of the <code>i</code> becomes 10. Then the condition for <code>for</code> loop fails and it will jump out from the <code>for</code> loop. Thus execute the last line of code <code>console.log(i)</code>. Which will then print the number 10 on the console.</p>
<h4 id="the-scope-of-the-var-variable-in-a-function">The Scope of the <code>var</code> variable in a function</h4>
<p>The variable declared using the <code>var</code> keyword inside a function is accessible throughout that function, but not outside the function. Look at the below example.</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">count</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">var</span> i = <span class="hljs-number">0</span>; i &lt; <span class="hljs-number">10</span>; i++) {
        <span class="hljs-built_in">console</span>.log(i); <span class="hljs-comment">// Output: print numbers from 0 to 9</span>
    }
    <span class="hljs-built_in">console</span>.log(i); <span class="hljs-comment">// Output: 10</span>
}

count(); <span class="hljs-comment">// calling function</span>
<span class="hljs-built_in">console</span>.log(i); <span class="hljs-comment">//Output: Uncaught ReferenceError: i is not defined</span>
</code></pre>
<p>The last line of the above code will throw an error since <code>var</code> variables are only accessible inside the function where it is declared.</p>
<h4 id="notes">Notes:</h4>
<ul>
<li><code>var</code> is there in javascript from the beginning, but <code>let</code> and <code>const</code> are introduced recently in es6.</li>
<li><code>var</code> is function-scoped, while <code>let</code> and <code>const</code> are block-scoped.</li>
<li>Global variables declared using the <code>var</code> keyword would automatically get attached to the browser <code>window</code> object. Whereas <code>let</code> prevents it.</li>
<li>Variable defined with <code>var</code> gets hoisted at the top of it's function. Variable defined using <code>let</code> and <code>const</code> doesn't gets hoisted.</li>
<li><p>We can redeclare <code>var</code> variables as many times as we want, while <code>let</code> cannot be redeclared.</p>
<pre><code class="lang-javascript">  <span class="hljs-keyword">var</span> humanOne = <span class="hljs-string">"usama"</span>;
  <span class="hljs-keyword">var</span> humanOne = <span class="hljs-string">"new Usama"</span>; <span class="hljs-comment">// This is OK</span>

  <span class="hljs-keyword">let</span> humanTwo = <span class="hljs-string">"jaba"</span>;
  <span class="hljs-keyword">let</span> humanTwo = <span class="hljs-string">"new Jaba"</span>; <span class="hljs-comment">// Throws an error.</span>
</code></pre>
</li>
<li><p>We can re-assign a new value to <code>var</code> and <code>let</code> variables. But a new value cannot be re-assigned to the <code>const</code> variable.</p>
<pre><code class="lang-javascript">  <span class="hljs-keyword">let</span> personOne = <span class="hljs-string">"usama"</span>;
  personOne = <span class="hljs-string">"new Usama"</span>;
  <span class="hljs-built_in">console</span>.log(personOne); <span class="hljs-comment">// Output: new Usama</span>

  <span class="hljs-keyword">const</span> personTwo = <span class="hljs-string">"jaba"</span>;
  personTwo = <span class="hljs-string">"new jaba"</span>; <span class="hljs-comment">//Uncaught TypeError: Assignment to constant variable.</span>
  <span class="hljs-built_in">console</span>.log(personTwo);
</code></pre>
<ul>
<li><p>However, <code>const</code> does allow us to change the properties of an object.</p>
<pre><code class="lang-javascript">  <span class="hljs-keyword">const</span> Usama = {
      <span class="hljs-attr">name</span>: <span class="hljs-string">"usama v"</span>,
      <span class="hljs-attr">age</span>: <span class="hljs-number">20</span>
  }

  Usama.age = <span class="hljs-number">19</span>;
  <span class="hljs-built_in">console</span>.log(Usama); <span class="hljs-comment">// Output: {name: "usama v", age: 19}</span>
</code></pre>
</li>
</ul>
</li>
<li><p>Use <code>const</code> and <code>let</code> almost every single time when you declare variables unless you have a very specific case using <code>var</code>.</p>
</li>
</ul>
<h4 id="for-more-information-watch-these-videos">For more information watch these videos</h4>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://youtu.be/9WIJQDvt4Us">https://youtu.be/9WIJQDvt4Us</a></div>
<hr />
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://youtu.be/XgSjoHgy3Rk">https://youtu.be/XgSjoHgy3Rk</a></div>
]]></content:encoded></item></channel></rss>