<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>API Testing on an's security blog</title><link>https://panman4040.github.io/training/portswigger/api_testing/</link><description>Recent content in API Testing on an's security blog</description><generator>Hugo</generator><language>en</language><lastBuildDate>Wed, 15 Jul 2026 08:36:00 +0700</lastBuildDate><atom:link href="https://panman4040.github.io/training/portswigger/api_testing/index.xml" rel="self" type="application/rss+xml"/><item><title>Exploiting server-side parameter pollution in a REST URL | &lt;span style="color:#9b59b6">Expert&lt;/span></title><link>https://panman4040.github.io/training/portswigger/api_testing/at_expert1/</link><pubDate>Tue, 14 Jul 2026 10:53:16 +0800</pubDate><guid>https://panman4040.github.io/training/portswigger/api_testing/at_expert1/</guid><description>&lt;p>Similar to &lt;a href="https://panman4040.github.io/training/portswigger/api_testing/at_practitioner3/">this problem&lt;/a>, our goal is to log in as &lt;code>administrator&lt;/code> and delete &lt;code>carlos&lt;/code>. Since we don&amp;rsquo;t have the credentials, we have to look for an API exploitation elsewhere. And the safest bet is the Reset Password functionality in the login page.&lt;/p>
&lt;p>&lt;img src="https://panman4040.github.io/images/viber_image_2026-07-13_15-45-36-670.png" alt="">&lt;/p>
&lt;p>Let&amp;rsquo;s try sending a password reset request to see what it looks like:
&lt;img src="https://panman4040.github.io/images/viber_image_2026-07-13_15-51-51-310.png" alt="">&lt;/p>
&lt;p>There is no explicit client-side API call, only a POST request to the very much visible &lt;code>/forgot-password&lt;/code> endpoint. This probably means there is an internal API call happening server-side, but just to be sure it&amp;rsquo;s safe to try enumerating all the common API endpoints in Intruder to check for any hidden attack surfaces:
&lt;img src="https://panman4040.github.io/images/viber_image_2026-07-13_16-26-31-322.png" alt="">&lt;/p></description></item><item><title>Exploiting server-side parameter pollution in a query string | &lt;span style="color:#3498db">Practitioner&lt;/span></title><link>https://panman4040.github.io/training/portswigger/api_testing/at_practitioner3/</link><pubDate>Thu, 09 Jul 2026 15:06:16 +0800</pubDate><guid>https://panman4040.github.io/training/portswigger/api_testing/at_practitioner3/</guid><description>&lt;p>Our goal is to log in as &lt;code>administrator&lt;/code> and delete the user &lt;code>carlos&lt;/code>, but the problem is that we don&amp;rsquo;t know the password. Thankfully, there&amp;rsquo;s this convenient Forgot Password feature for us to poke into. Let&amp;rsquo;s try sending a normal password reset to &lt;code>administrator&lt;/code> to see what happens:
&lt;img src="https://panman4040.github.io/images/viber_image_2026-07-09_14-03-11-479.png" alt="">
The server responds with a redacted email, that&amp;rsquo;s fair because nobody wants their PII leaked right? Let&amp;rsquo;s try adding a new nonsense param and truncate the end bit, what if something unexpected happens?
&lt;img src="https://panman4040.github.io/images/viber_image_2026-07-09_14-50-54-305.png" alt="">
Weird. The server still processes the request as normal. No change to the response length, nor the response time. Adding more nonsense params does not work either. How about sending &lt;code>username&lt;/code> only &lt;em>then&lt;/em> truncate the query string?
&lt;img src="https://panman4040.github.io/images/viber_image_2026-07-09_14-04-46-228.png" alt="">
It looks like truncating works! And the server demands a hidden field on top of &lt;code>username&lt;/code> for a hidden API request (maybe?). But we don&amp;rsquo;t know what the hidden field name is, and based on our attempt of adding &lt;code>&amp;amp;foo=bar#&lt;/code> above we know that the server doesn&amp;rsquo;t care about custom fields. Or does it?&lt;/p></description></item><item><title>Exploiting a mass assignment vulnerability | &lt;span style="color:#3498db">Practitioner&lt;/span></title><link>https://panman4040.github.io/training/portswigger/api_testing/at_practitioner2/</link><pubDate>Thu, 09 Jul 2026 13:23:16 +0800</pubDate><guid>https://panman4040.github.io/training/portswigger/api_testing/at_practitioner2/</guid><description>&lt;p>Our task is to buy that leet jacket, but our coffer runs dry. Just like &lt;a href="https://panman4040.github.io/training/portswigger/api_testing/at_practitioner1/">last lab&lt;/a>, we have to either raise our balance or make the jacket free.&lt;/p>
&lt;p>While crawling through the page, I tried sending a request to &lt;code>/api&lt;/code>, literally. To my surprise, there actually is a hidden documentation lying around:
&lt;img src="https://panman4040.github.io/images/viber_image_2026-07-09_11-03-23-248.png" alt="">
The GET request to &lt;code>/checkout&lt;/code> seems to request the metadata for our purchase, with these attributes lying around. While the POST request is performing that purchase. So after adding the leet jacket to our cart, let&amp;rsquo;s perform the GET request to see the response:
&lt;img src="https://panman4040.github.io/images/viber_image_2026-07-09_11-08-11-613.png" alt="">
The server returns a JSON object with very clear attributes. One thing to note though is that the &lt;code>chosen_discount&lt;/code> attribute is left conveniently there for us, while no explicit option for discount is present on the page (perhaps it&amp;rsquo;s for a later sales period?). Let&amp;rsquo;s try sending the discount attribute along with our purchase in a POST request to &lt;code>/checkout&lt;/code>, with say 100% discount rate? Let&amp;rsquo;s try this out:
&lt;img src="https://panman4040.github.io/images/viber_image_2026-07-09_11-08-38-249.png" alt="">
Looks like the request has gone through, and we got ourselves a slick jacket free of charge. Nice.
&lt;img src="https://panman4040.github.io/images/viber_image_2026-07-09_11-08-56-955.png" alt="">&lt;/p></description></item><item><title>Finding and exploiting an unused API endpoint | &lt;span style="color:#3498db">Practitioner&lt;/span></title><link>https://panman4040.github.io/training/portswigger/api_testing/at_practitioner1/</link><pubDate>Thu, 09 Jul 2026 10:32:16 +0800</pubDate><guid>https://panman4040.github.io/training/portswigger/api_testing/at_practitioner1/</guid><description>&lt;p>Our task is to purchase the hackerleet hoodie, but we are also broke af. Upon attempting to purchase the thing without septims, we are hit with an expected denial:
&lt;img src="https://panman4040.github.io/images/viber_image_2026-07-09_10-12-01-715.png" alt="">&lt;/p>
&lt;p>One may think to try illicitly manipulate our store balance, but there is no JS or API call present that queries for an user&amp;rsquo;s current balance. So that&amp;rsquo;s bust.&lt;/p>
&lt;p>However, notice how whenever we fetch a GET request to a store item, an API request to &lt;code>/products/./price&lt;/code> is called:
&lt;img src="https://panman4040.github.io/images/viber_image_2026-07-09_10-11-59-974.png" alt="">
Obviously, if we are not able to increase our coffers, we should make the shopitem free right? Since the response body is a JSON object, it&amp;rsquo;s expected that the request body to change the price should be a JSON object too. Let&amp;rsquo;s try sending a POST request to change the price to zero:
&lt;img src="https://panman4040.github.io/images/viber_image_2026-07-09_10-20-03-319.png" alt="">
Too bad that we are hit with a 405, but there is one convenient header they so kindly left for us. The only allowed methods are &lt;code>GET&lt;/code>, which we&amp;rsquo;ve just covered, and &lt;code>PATCH&lt;/code>. Since we cannot create a new resource with &lt;code>POST&lt;/code>, let&amp;rsquo;s try &lt;strong>updating&lt;/strong> the resource with &lt;code>PATCH&lt;/code> instead:
&lt;img src="https://panman4040.github.io/images/viber_image_2026-07-09_10-24-19-920.png" alt="">
Looks like that didn&amp;rsquo;t work. It&amp;rsquo;s sad to say but I&amp;rsquo;ve spent an embarassingly long amount of time trying to figure out what went wrong here, but in reality it&amp;rsquo;s just that the &lt;code>price&lt;/code> is a &lt;strong>string&lt;/strong>, and the backend demands an &lt;strong>integer&lt;/strong>:
&lt;img src="https://panman4040.github.io/images/viber_image_2026-07-09_10-31-16-323.png" alt="">
So after setting the price of leet to free, we are able to buy it no problemo:
&lt;img src="https://panman4040.github.io/images/viber_image_2026-07-09_10-31-40-054.png" alt="">
&lt;img src="https://panman4040.github.io/images/viber_image_2026-07-09_10-31-50-972.png" alt="">&lt;/p></description></item><item><title>Exploiting an API endpoint using documentation | &lt;span style="color:#2ecc71">Apprentice&lt;/span></title><link>https://panman4040.github.io/training/portswigger/api_testing/at_apprentice1/</link><pubDate>Thu, 09 Jul 2026 09:32:16 +0800</pubDate><guid>https://panman4040.github.io/training/portswigger/api_testing/at_apprentice1/</guid><description>&lt;p>When we want to test for APIs, we first need to find out as much information about the API as possible. To do that, we must identify API endpoints. This can be done through reading developer&amp;rsquo;s API doc or fuzzing the paths using Intruder.&lt;/p>
&lt;p>In this lab, no doc is provided meaning we have to stick with the latter method. Funnily enough, the documentation endpoint is literally &lt;code>/api/&lt;/code>, that&amp;rsquo;s it:
&lt;img src="https://panman4040.github.io/images/viber_image_2026-07-09_09-20-28-695.png" alt="">&lt;/p></description></item></channel></rss>