<?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://aadhilanwar.dev/feed.xml" rel="self" type="application/atom+xml" /><link href="https://aadhilanwar.dev/" rel="alternate" type="text/html" /><updated>2026-04-24T22:16:15+00:00</updated><id>https://aadhilanwar.dev/feed.xml</id><title type="html">Aadhil Anwar</title><subtitle>Security engineer specializing in network security, vulnerability research, and API exploitation. Currently at GoDaddy working on infrastructure security, access control architecture, and cloud security on AWS.</subtitle><author><name>Aadhil Anwar</name></author><entry><title type="html">Buying Rekhta Tickets Worth INR 1499 for Free</title><link href="https://aadhilanwar.dev/blog/hacking-rekhta-tickets-for-free/" rel="alternate" type="text/html" title="Buying Rekhta Tickets Worth INR 1499 for Free" /><published>2025-04-07T00:00:00+00:00</published><updated>2025-04-07T00:00:00+00:00</updated><id>https://aadhilanwar.dev/blog/hacking-rekhta-tickets-for-free</id><content type="html" xml:base="https://aadhilanwar.dev/blog/hacking-rekhta-tickets-for-free/"><![CDATA[<h2 id="the-setup">The Setup</h2>

<p>I was sitting in yet another painful DevOps class - the kind where phrases like “pipelines” and “infrastructure” get thrown around so aggressively that your brain starts to dissociate. I needed something, <em>anything</em>, to keep myself from falling asleep.</p>

<p>That’s when I stumbled upon <strong>Jashn-e-Rekhta</strong> - a massive 3-day Urdu/Hindi literary festival featuring names like Kailash Kher and Javed Akhtar. The kind of event you hear about and immediately know you <em>have</em> to be there.</p>

<p>The problem? Concert passes were priced at <strong>INR 1499</strong>. And as a student running on hostel food and borrowed Wi-Fi, that wasn’t happening. But the security engineer in me had a different question: <em>how well does their payment system actually work?</em></p>

<h2 id="reconnaissance">Reconnaissance</h2>

<p>I fired up <strong>Burp Suite</strong>, configured my browser’s proxy, and started mapping the application. The first thing I always do when testing an e-commerce or ticketing flow is trace the entire purchase lifecycle - from item selection to payment confirmation. You’d be surprised how many applications have their most critical logic flaws sitting right in the checkout pipeline.</p>

<p>The Rekhta ticketing site had a fairly standard flow:</p>

<ol>
  <li>Select your ticket tier</li>
  <li>Fill in personal details (name, phone, email)</li>
  <li>Hit “Pay” - which triggers a payment gateway</li>
</ol>

<p>I watched the HTTP traffic as I walked through the flow. Most of the requests were unremarkable - static assets, session tokens, the usual noise. But one request caught my attention.</p>

<h2 id="the-vulnerability">The Vulnerability</h2>

<p>When you clicked the payment button, the frontend fired a <strong>POST request</strong> to an endpoint:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>POST /api/createorder
</code></pre></div></div>

<p>The request body looked something like this:</p>

<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w">
  </span><span class="nl">"name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Aadhil Anwar"</span><span class="p">,</span><span class="w">
  </span><span class="nl">"phone"</span><span class="p">:</span><span class="w"> </span><span class="s2">"+91XXXXXXXXXX"</span><span class="p">,</span><span class="w">
  </span><span class="nl">"email"</span><span class="p">:</span><span class="w"> </span><span class="s2">"xxxxx@gmail.com"</span><span class="p">,</span><span class="w">
  </span><span class="nl">"ticketType"</span><span class="p">:</span><span class="w"> </span><span class="s2">"concert"</span><span class="p">,</span><span class="w">
  </span><span class="nl">"amount"</span><span class="p">:</span><span class="w"> </span><span class="mi">1499</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>

<p>That <code class="language-plaintext highlighter-rouge">amount</code> field. Sitting right there in the request body. Client-controlled. Unsigned. Unvalidated.</p>

<p>This is what’s known as a <strong>parameter tampering</strong> vulnerability - specifically, a <strong>price manipulation</strong> flaw. The architecture assumed that whatever the frontend sent was gospel truth. There was no server-side validation cross-referencing the <code class="language-plaintext highlighter-rouge">amount</code> against the actual ticket price in the database. The backend was blindly trusting the client.</p>

<p>Now, any developer reading this might think: <em>“Surely the payment gateway would catch this?”</em> Here’s the thing - payment gateways like Razorpay process whatever amount they receive in the order creation call. They don’t know or care what the “correct” price is. That’s the merchant’s responsibility. If the merchant’s backend says “create an order for INR 2,” Razorpay creates an order for INR 2. The trust boundary was broken at the application layer, not the gateway layer.</p>

<h2 id="the-exploit">The Exploit</h2>

<p>I intercepted the request in Burp Suite’s <strong>Intercept</strong> tab, modified the <code class="language-plaintext highlighter-rouge">amount</code> parameter:</p>

<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w">
  </span><span class="nl">"name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Aadhil Anwar"</span><span class="p">,</span><span class="w">
  </span><span class="nl">"phone"</span><span class="p">:</span><span class="w"> </span><span class="s2">"+91XXXXXXXXXX"</span><span class="p">,</span><span class="w">
  </span><span class="nl">"email"</span><span class="p">:</span><span class="w"> </span><span class="s2">"xxxxx@gmail.com"</span><span class="p">,</span><span class="w">
  </span><span class="nl">"ticketType"</span><span class="p">:</span><span class="w"> </span><span class="s2">"concert"</span><span class="p">,</span><span class="w">
  </span><span class="nl">"amount"</span><span class="p">:</span><span class="w"> </span><span class="mi">2</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>

<p>Forwarded the request. The server accepted it without flinching and returned a valid Razorpay order object with <code class="language-plaintext highlighter-rouge">amount: 200</code> (Razorpay uses paise, so INR 2 = 200 paise). A UPI payment request for <strong>INR 2</strong> popped up on my phone.</p>

<p>I paid it.</p>

<p><strong>And just like that - I had a confirmed ticket to Jashn-e-Rekhta.</strong></p>

<p>The payment confirmation email came through within seconds. The pass was delivered to my WhatsApp and email. A fully valid concert ticket, for the price of a candy bar.</p>

<p><img src="/images/blog/rekhta-payment-confirmation.png" alt="Payment confirmation showing INR 2 paid successfully" /></p>

<p><img src="/images/blog/rekhta-ticket-success.png" alt="Jashn-e-Rekhta payment successful page with pass confirmation" /></p>

<h2 id="why-this-matters">Why This Matters</h2>

<p>This isn’t just a “fun hack.” This is a textbook case of a broken trust boundary between the client and the server.</p>

<p><strong>The root cause:</strong> The backend used the <code class="language-plaintext highlighter-rouge">amount</code> value from the frontend request to create the payment order, instead of looking up the actual ticket price from its own database. The server essentially said, <em>“Whatever the user says they owe, that’s what they owe.”</em></p>

<p>In a properly designed system, the flow should look like this:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Frontend sends: { ticketType: "concert" }
Backend looks up: concert → INR 1499
Backend creates order: amount = 1499 (from DB, not from client)
</code></pre></div></div>

<p>The client should never have authority over pricing. The only thing the frontend should send is a <strong>ticket identifier</strong> - the backend should resolve everything else. The <code class="language-plaintext highlighter-rouge">amount</code> field in the request body should have never existed.</p>

<p><strong>The impact</strong> was significant - any attacker could purchase tickets at any arbitrary price (including INR 0 if the gateway allowed it), effectively bypassing the entire payment system. For a festival of this scale, the potential revenue loss could have been massive.</p>

<h2 id="the-fix">The Fix</h2>

<p>A proper remediation for this class of vulnerability involves:</p>

<ol>
  <li><strong>Server-side price resolution</strong> - the backend should map ticket types to prices using its own data store, never accepting price from the client</li>
  <li><strong>Order integrity verification</strong> - before processing payment confirmation, verify the paid amount matches the expected amount</li>
  <li><strong>Signed payloads</strong> - use HMAC signatures on order parameters so tampering is detectable</li>
  <li><strong>Post-payment reconciliation</strong> - compare the amount received (from payment gateway webhook) against the expected amount before issuing the ticket</li>
</ol>

<h2 id="did-i-go-to-the-concert">Did I Go to the Concert?</h2>

<p>No. I didn’t.</p>

<p>Let’s just say the thrill of the hack was enough for me.</p>

<hr />

<p><em>This vulnerability was responsibly reported to the Rekhta team and has been patched. No tickets were used, no financial damage was caused. Always hack responsibly.</em></p>]]></content><author><name>Aadhil Anwar</name></author><category term="security" /><category term="bug-bounty" /><category term="web-security" /><category term="parameter-tampering" /><summary type="html"><![CDATA[How I found a critical parameter tampering vulnerability in Jashn-e-Rekhta's payment flow - where the backend blindly trusted the frontend.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://aadhilanwar.dev/images/og-default.png" /><media:content medium="image" url="https://aadhilanwar.dev/images/og-default.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">I Reverse-Engineered a Live Phishing Operation Targeting My University</title><link href="https://aadhilanwar.dev/blog/hacking-the-hacker-university-phishing/" rel="alternate" type="text/html" title="I Reverse-Engineered a Live Phishing Operation Targeting My University" /><published>2025-03-25T00:00:00+00:00</published><updated>2025-03-25T00:00:00+00:00</updated><id>https://aadhilanwar.dev/blog/hacking-the-hacker-university-phishing</id><content type="html" xml:base="https://aadhilanwar.dev/blog/hacking-the-hacker-university-phishing/"><![CDATA[<h2 id="the-email">The Email</h2>

<p>I was going through my student inbox at LPU when an email marked <strong>Urgent</strong> caught my eye. Sent from what appeared to be a legitimate LPU email address, warning that inactive accounts would be “permanently closed” and urging immediate login through a link.</p>

<p><img src="/images/blog/phishing-email.png" alt="Phishing email sent from a compromised LPU account" /></p>

<p>Standard phishing playbook. But the sender wasn’t a random Gmail or spoofed domain. <strong>It was sent from an actual LPU email address</strong> - an account that had already been compromised and was being weaponized to phish others from inside the trust boundary. LPU email addresses pass SPF, DKIM, and DMARC. They don’t get flagged. Students trust them by default.</p>

<h2 id="the-phish">The Phish</h2>

<p>Pulled the email headers, extracted the link. A near-pixel-perfect clone of the Microsoft Outlook login portal.</p>

<p><img src="/images/blog/phishing-login-page.png" alt="Fake Outlook login page - French localization" /></p>

<p>One mistake: <strong>the page was in French</strong>. “Se connecter,” “Suivant,” “Besoin d’aide?” - the kit wasn’t localized for the target.</p>

<p>The form’s <code class="language-plaintext highlighter-rouge">action</code> didn’t POST to Microsoft. It posted to an attacker-controlled backend.</p>

<h2 id="the-c2">The C2</h2>

<p>Traced the exfiltration flow. Credentials were being piped into a <strong>Telegram bot</strong>. The bot token and chat ID were embedded in the page’s JavaScript. Plaintext. No obfuscation.</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">var</span> <span class="nx">token</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">7XXXXXXXXX:AAHXXXXXXXXXXXXXXXXXXXXXXXXXXXXX</span><span class="dl">"</span><span class="p">;</span>
<span class="kd">var</span> <span class="nx">chat_id</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">XXXXXXXXXX</span><span class="dl">"</span><span class="p">;</span>
</code></pre></div></div>

<p>Queried the bot’s message history via Telegram Bot API:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>https://api.telegram.org/bot&lt;token&gt;/getUpdates
</code></pre></div></div>

<p>Full database of stolen credentials came back.</p>

<p><img src="/images/blog/phishing-c2-data.png" alt="Telegram C2 bot receiving stolen credentials in real time" /></p>

<ul>
  <li><strong>Hundreds of compromised LPU accounts</strong> - students and staff</li>
  <li>Login attempts from multiple geographic locations</li>
  <li>Compromised accounts already being used to send more phishing emails - self-propagating chain</li>
  <li>Credentials from <strong>far beyond LPU</strong> sitting in the same C2 channel - the <strong>French Ministry of National Education</strong> (education.gouv.fr), major French electronics retailers, other <code class="language-plaintext highlighter-rouge">.edu</code> institutions, and multiple South Asian universities</li>
</ul>

<p>The forwarding metadata tagged an account named <strong>“adamo”</strong>. The French login page, the French government and retail credentials in the same bot, the sheer spread of targets - this wasn’t just an attack on LPU. It was a multi-target, multi-country operation, and LPU was one node in a much larger campaign.</p>

<h2 id="the-attack-chain">The Attack Chain</h2>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>1. Attacker compromises initial LPU email account
2. Uses it to phish all contacts from a trusted address
3. Victim enters credentials on cloned Outlook page
4. Credentials exfiltrated to Telegram bot in real time
5. New credentials used to compromise more accounts
6. Self-propagating loop
</code></pre></div></div>

<h2 id="the-response">The Response</h2>

<p>I reported the findings to every affected domain I could identify from the C2 data - the French ministry, the retailers, the other universities. Most responded and acted on it.</p>

<p>LPU’s dean’s response: <em>“It’s just student data, not staff data.”</em></p>

<p>Didn’t hear the full issue out. Hundreds of compromised accounts, an active self-propagating chain, credentials from French government ministries and retailers in the same C2 - and the man said “just student data.”</p>

<p>I’m sure the attacker appreciated the extra time.</p>]]></content><author><name>Aadhil Anwar</name></author><category term="security" /><category term="phishing" /><category term="incident-response" /><category term="threat-hunting" /><summary type="html"><![CDATA[A credential harvesting campaign hit LPU from the inside. I traced the kill chain, broke into the attacker's Telegram C2, and found hundreds of compromised accounts.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://aadhilanwar.dev/images/og-default.png" /><media:content medium="image" url="https://aadhilanwar.dev/images/og-default.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">How I Found a Secret Backdoor to a University’s News Feed</title><link href="https://aadhilanwar.dev/blog/university-news-backdoor/" rel="alternate" type="text/html" title="How I Found a Secret Backdoor to a University’s News Feed" /><published>2025-01-07T00:00:00+00:00</published><updated>2025-01-07T00:00:00+00:00</updated><id>https://aadhilanwar.dev/blog/university-news-backdoor</id><content type="html" xml:base="https://aadhilanwar.dev/blog/university-news-backdoor/"><![CDATA[<h2 id="the-find">The Find</h2>

<p>I was running subdomain enumeration against a university’s root domain when one result stood out:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>services.university.edu  [200] [ASP.NET Application]
</code></pre></div></div>

<p>A bare ASP.NET default page sitting in production. No branding, no login. Just the framework welcome screen - which already tells you the stack, signals a forgotten deployment, and screams “dig deeper.”</p>

<p><img src="/images/blog/university-api-docs.png" alt="Default ASP.NET application page exposed on the subdomain" /></p>

<p><em>Hostnames and endpoints in this post have been changed.</em></p>

<p>I hit it with a targeted wordlist for ASP.NET-specific paths - <code class="language-plaintext highlighter-rouge">/swagger</code>, <code class="language-plaintext highlighter-rouge">/api</code>, <code class="language-plaintext highlighter-rouge">/Help</code>, <code class="language-plaintext highlighter-rouge">/odata</code> - and <code class="language-plaintext highlighter-rouge">/Help</code> came back <code class="language-plaintext highlighter-rouge">200</code>.</p>

<p>It was a <strong>fully exposed API documentation page</strong> auto-generated by ASP.NET’s Web API Help Page. Every endpoint, every HTTP method, every parameter - all laid out in production.</p>

<p>Most endpoints had proper auth. But a cluster under <code class="language-plaintext highlighter-rouge">/api/Media/</code> didn’t:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>GET    /api/Media/GetPressRelease
GET    /api/Media/GetPressRelease/{id}
POST   /api/Media/AddPressRelease
PUT    /api/Media/UpdatePressRelease/{id}
DELETE /api/Media/DeletePressReleaseById/{id}
</code></pre></div></div>

<p>Full CRUD on the university’s official press releases. The content that goes on the homepage, gets picked up by media, gets shared across channels.</p>

<h2 id="the-exploit">The Exploit</h2>

<p>First, I pulled existing press releases:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>curl <span class="nt">-s</span> https://services.university.edu/api/Media/GetPressRelease | jq <span class="s1">'.[0]'</span>
</code></pre></div></div>

<p>No auth token. No API key. No session. Raw response with live data and internal IDs.</p>

<p>Then I sent a <code class="language-plaintext highlighter-rouge">DELETE</code> with one of those IDs:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>GET https://services.university.edu/api/Media/DeletePressReleaseById/5219
</code></pre></div></div>

<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">[</span><span class="w">
  </span><span class="p">{</span><span class="w">
    </span><span class="nl">"$id"</span><span class="p">:</span><span class="w"> </span><span class="s2">"1"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"Status"</span><span class="p">:</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w">
    </span><span class="nl">"Message"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Delete Successfully !"</span><span class="w">
  </span><span class="p">}</span><span class="w">
</span><span class="p">]</span><span class="w">
</span></code></pre></div></div>

<p><img src="/images/blog/university-delete-response.png" alt="Postman showing successful unauthenticated delete of press release ID 5219" /></p>

<p>I figured it was a false positive - maybe the API just returns success regardless. So I sent a follow-up <code class="language-plaintext highlighter-rouge">GET</code> for the same ID.</p>

<p><code class="language-plaintext highlighter-rouge">404 Not Found.</code></p>

<p>Checked the university’s actual website. The news item was gone from the public feed.</p>

<p><strong>One unauthenticated HTTP request deleted an official university press release from production.</strong></p>

<p>The <code class="language-plaintext highlighter-rouge">POST</code> and <code class="language-plaintext highlighter-rouge">PUT</code> endpoints were equally exposed. I verified by creating a test entry (immediately removed it). Zero authentication on any write operation.</p>

<h2 id="the-impact">The Impact</h2>

<p>Any person on the internet could:</p>

<ul>
  <li><strong>Create</strong> fake press releases - “Final exams cancelled,” “Tuition fees refunded,” politically motivated statements</li>
  <li><strong>Modify</strong> existing ones - alter facts, inject misinformation, change quotes</li>
  <li><strong>Delete</strong> real announcements - suppress official communications</li>
</ul>

<p>For an institution with thousands of students, faculty, and media monitoring its channels, this is full compromise of the communication pipeline. The attack surface is a single curl command. Automating mass manipulation of the entire news feed would take minutes.</p>

<h2 id="root-cause">Root Cause</h2>

<p>Multiple failures stacking:</p>

<p><strong>Broken Access Control (OWASP A01:2021)</strong> - Write endpoints had zero auth checks. The server processed any request from any origin.</p>

<p><strong>API Documentation in Production</strong> - The <code class="language-plaintext highlighter-rouge">/Help</code> endpoint gave attackers a full map of every endpoint and parameter. Blind enumeration turned into targeted exploitation.</p>

<p><strong>No Network Segmentation</strong> - An internal CMS backend service was directly reachable from the public internet with no API gateway, no IP whitelist, no VPN.</p>

<p><strong>Forgotten Infrastructure</strong> - The default ASP.NET landing page says it all. This was deployed, wired to the production database, and abandoned. Nobody was watching.</p>

<h2 id="cvss-96-critical">CVSS 9.6 (Critical)</h2>

<p>Network-accessible, no authentication, full integrity impact on a public-facing communication channel. Availability impact is maximum - an attacker can wipe the entire news archive.</p>

<p>Reported and patched.</p>]]></content><author><name>Aadhil Anwar</name></author><category term="security" /><category term="bug-bounty" /><category term="broken-access-control" /><category term="API-security" /><summary type="html"><![CDATA[A broken access control vulnerability in a university's API let anyone create, edit, or delete official press releases. No auth required. CVSS 9.6.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://aadhilanwar.dev/images/og-default.png" /><media:content medium="image" url="https://aadhilanwar.dev/images/og-default.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry></feed>