<?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 The Mobile Security Guys on Medium]]></title>
        <description><![CDATA[Stories by The Mobile Security Guys on Medium]]></description>
        <link>https://medium.com/@mobsecguys?source=rss-509720bbaed3------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/2*edgS_gbR2ll4VxzEgbVBqA.png</url>
            <title>Stories by The Mobile Security Guys on Medium</title>
            <link>https://medium.com/@mobsecguys?source=rss-509720bbaed3------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sun, 15 Nov 2026 04:56:01 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@mobsecguys/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[Unlocking the Treasure Trove: Enhancing OSINT through Mobile App Hacking]]></title>
            <link>https://mobsecguys.medium.com/unlocking-the-treasure-trove-enhancing-osint-through-mobile-app-hacking-a8b4f180e636?source=rss-509720bbaed3------2</link>
            <guid isPermaLink="false">https://medium.com/p/a8b4f180e636</guid>
            <category><![CDATA[osint]]></category>
            <category><![CDATA[mobile]]></category>
            <category><![CDATA[hacking]]></category>
            <category><![CDATA[mobile-apps]]></category>
            <dc:creator><![CDATA[The Mobile Security Guys]]></dc:creator>
            <pubDate>Wed, 19 Jun 2024 10:26:15 GMT</pubDate>
            <atom:updated>2024-06-19T10:26:15.600Z</atom:updated>
            <content:encoded><![CDATA[<p>Open Source Intelligence (OSINT) has become an invaluable tool for various fields including cybersecurity, journalism, and law enforcement. Mobile devices, with their ubiquitous presence and rich data stores, represent a treasure trove of information for OSINT practitioners. However, extracting this data effectively often requires more than just conventional methods. Mobile app hacking can significantly enhance the depth and breadth of OSINT data extraction. This blog post explores how mobile app hacking techniques can be leveraged to improve mobile OSINT data extraction.</p><p><strong>The Quest for Data: Mobile OSINT</strong></p><p>Outside of my professional work, I engage in Mobile Open Source Intelligence (OSINT). This involves gathering intelligence from publicly available sources using mobile devices. Unlike traditional OSINT, my focus is on extracting valuable data from specific, data-rich applications, often employing a hint of hacking for the best results.</p><p><strong>The Role of Mobile Apps in OSINT</strong></p><p>Mobile apps often have access to a wealth of data, including user profiles, geolocation information, communication logs, and more. Many apps also interact with online services and APIs, which can further enrich the available data. However, much of this information is not readily accessible due to security mechanisms and data protection policies.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*fdPBQRgc0emp7pi2" /><figcaption>It’s like finding a locked treasure chest in your attic — you know there’s something valuable inside, but you just can’t get to it.</figcaption></figure><p><strong>Mums the word: A Case Study in App Vulnerability</strong></p><p>Several years ago, whilst we had our first child, I encountered an app named MUSH, designed for new mothers to connect and share experiences. Upon my wife’s request to check its security, I discovered that the app stored extensive data on users without proper security measures. This included enough personal information to commit identity fraud.</p><blockquote>My findings led to the app being significantly redeveloped, showcasing the critical need for secure app development.</blockquote><figure><img alt="" src="https://cdn-images-1.medium.com/max/453/1*lJjOsufnkMGPe3wanL6crA.png" /><figcaption>The MUSH application was my first foray into mobile OSINT</figcaption></figure><p><strong>How Mobile App Hacking Enhances OSINT</strong></p><p>Mobile app hacking involves exploiting vulnerabilities in mobile applications to gain unauthorised access to data. This can uncover hidden data sources and provide deeper insights.</p><p><strong>Hacking Tools and Techniques</strong></p><p>To break into these “secure” apps, we start with a checklist of essential tools:</p><p><strong>Reverse Engineering Tools</strong>: APK tool, JD GUI, Hopper disassembler for iOS binaries.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/225/1*EkvBlKlznZmP3d6IIX4_Cg.png" /></figure><p><strong>Network Tools</strong>: Burp Suite for examining app communications.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Hllggq1QnAKKUUZGmIAT0w.jpeg" /><figcaption>See our series on APIs:<a href="https://mobsecguys.medium.com/a-view-on-apis-from-a-security-professional-part-1-4d45cbb74b7b"> Medium</a></figcaption></figure><p><strong>Exploitation Tools</strong>: Postman, Fiddler for interacting with APIs.</p><p><strong>Injection</strong>: Using Frida can be invaluable when manipulating apps at runtime</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/356/1*OxDSVHUVswBuMsOFq3S0FA.png" /><figcaption>See our blog series on Frida: <a href="https://mobsecguys.medium.com/exploring-native-functions-with-frida-on-android-part-1-bf93f0bfa1d3">Medium</a></figcaption></figure><p><strong>Rooting/Jailbreaking</strong>: To access the most secure parts of the device.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/695/1*LTK8pkiwtukRwFQxvmMmrQ.png" /><figcaption>See our write up on the complexities of jailbreaking with palerain blog: <a href="https://mobsecguys.medium.com/ios-15-6-palera1n-ssh-via-lan-cae055579969">Medium</a></figcaption></figure><p><strong>Accessing Hidden Data</strong>:</p><ul><li>Many apps store data locally on the device, which may not be visible through the app’s user interface. By reverse engineering the app, OSINT practitioners can uncover this hidden data.</li><li>Example: Extracting cached files, local databases, and logs from apps.</li></ul><p><strong>Intercepting Network Traffic</strong>:</p><ul><li>By intercepting the network traffic between a mobile app and its backend servers, valuable data transmitted over the network can be captured and analysed.</li><li>Example: Using tools like Burp Suite to capture HTTP/HTTPS traffic and extract API endpoints, user data, and more. It’s like eavesdropping on a conversation — just, you know, legally and ethically.</li></ul><p><strong>Bypassing Security Mechanisms</strong>:</p><ul><li>Many mobile apps implement security features like encryption, obfuscation, and authentication to protect data. Hacking techniques can bypass these mechanisms to access protected data.</li><li>Example: Decrypting encrypted data stored in local files or intercepting decrypted data in memory.</li></ul><p><strong>Gathering Metadata</strong>:</p><ul><li>Metadata from mobile apps can provide contextual information such as app usage patterns, version history, and permissions, which can be valuable for OSINT analysis.</li><li>Example: Extracting metadata to analyse app permissions and infer potential data access capabilities.</li></ul><p><strong>Leaky Apps: Unveiling Data Vulnerabilities</strong></p><blockquote>In my investigations, I have found several apps leaking critical user data.</blockquote><p>These vulnerabilities included:</p><ul><li><strong>Geolocations</strong>: Tracking user movements and sign-up locations.</li><li><strong>Profile Images</strong>: Downloadable caches of user images.</li><li><strong>User IDs</strong>: Leaked identifiers across apps.</li><li><strong>Voice Notes</strong>: Cached and easily accessible voice messages.</li><li><strong>User Preferences</strong>: Detailed likes and interests.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1011/1*QSWSOi63l3sOtAGzAU0ycg.png" /><figcaption>Examples of user data extracted across multiple applications.</figcaption></figure><p>This data can be exploited to construct comprehensive user profiles, making individuals vulnerable to targeted attacks.</p><p><strong>Putting the Puzzle Together</strong></p><p>Using standard OSINT tools combined with the hacked data, we can build comprehensive profiles. This includes personal details, social connections, employment information, and geospatial analysis of movements. Such data is invaluable for crafting targeted social engineering attacks and phishing campaigns.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*5mC-cfuHRY96khvXATaSAQ.png" /><figcaption>Using the tools on this tick list we can use our extracted data to great effect.</figcaption></figure><p><strong>Conclusions:</strong></p><p>By combining traditional OSINT techniques with hacking, we can uncover significant vulnerabilities, underscoring the importance of robust security in protecting user data.</p><p>My explorations highlight the critical need for stringent security measures in mobile apps, indeed it’s imperative security is embedded within the development cycle of applications.</p><p>As people are increasingly required to share personal data, developers must prioritise secure coding practices and regular security testing. For users, a cautious approach to app permissions and data sharing is essential.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=a8b4f180e636" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[iOS 15.6  palera1n —  SSH via LAN]]></title>
            <link>https://mobsecguys.medium.com/ios-15-6-palera1n-ssh-via-lan-cae055579969?source=rss-509720bbaed3------2</link>
            <guid isPermaLink="false">https://medium.com/p/cae055579969</guid>
            <category><![CDATA[security]]></category>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[jailbreak]]></category>
            <dc:creator><![CDATA[The Mobile Security Guys]]></dc:creator>
            <pubDate>Tue, 18 Jul 2023 14:29:23 GMT</pubDate>
            <atom:updated>2023-07-21T15:50:44.038Z</atom:updated>
            <content:encoded><![CDATA[<h3>iOS 15.6 palera1n — SSH via LAN</h3><p>As mobile app security testers we use modified and jailbroken devices to do a lot of our testing; it allows us access to the filesystem, let’s us install tweaks for security mechanisms like SSL pinning and jailbreak detection, and allows use of <a href="https://frida.re/docs/ios/">Frida</a>.<br>However, what do we do when we are tasked to security test an application which targets iOS 15 or above and all our current devices are jailbroken on iOS 14 — firstly, panic…</p><p>…secondly, figure out a new implementation.</p><h3>There are not a lot of options to jailbreak for iOS 15 and above, however there is one, palera1n</h3><blockquote>palera1n is a developer-oriented jailbreak for checkm8 devices (A8-A11) on iOS 15.0–16.5.1 — <a href="https://palera.in/">https://palera.in/</a></blockquote><p>The term here, ‘developer orientated’ is an interesting one, to me it conjurers up images of someone who understands almost everything they are doing, sat in a Terminal amending the open source code to get it working on their device. In general palera1n is very versatile and semi works out of the box for the devices it supports; the recent re-write to full C code has also made it more robust, streamlined and reliable, always a good thing when the downside is a bricked device.</p><p>There are numerous guides on how to install palera1n, and although we will cover that briefly, the main topic will be utilising SSH over the LAN on palera1n devices, because, out the box, this jailbreak is locked down to only allow USB. So here chronicles the steps to regain full SSH access to the device.</p><h3>Installation*</h3><p><em>*note, this process is on macOS</em></p><p>As mentioned, the method is now fairly seamless, open a Terminal and grab the install script.<br>sudo /bin/sh -c &quot;$(curl -fsSL https://static.palera.in/scripts/install.sh)&quot;</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/804/1*Rs2EdfkM-4OCaqD2eLFgXg.png" /></figure><p>Once installed, run the command, and follow the on-screen instructions:<br>palera1n</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/800/1*9lnYlRNA9m6svBHYELtGvg.png" /></figure><p>Once completed and the idevice has rebooted, open the new palera1n app, you’ll be asked to set a password for any terminal commands and install Sileo, Zebra or both. Unfortunately it seems that the now teenage Cydia has finally died a death, but Sileo is rather good.</p><h3>SSH fun</h3><p>The only other issue is that although palera1n installs OpenSSH dependencies out of the box, it modifies the port to 44 (instead of the default 22) and doesn’t allow SSH over LAN.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/417/1*_nNv5dA6ItFMEmwdKwLBng.png" /></figure><p>Fair enough, we’ll get access via iproxy over USB (forwarding port 44 to 2222) and take a look at things. Of course the default SSH password is still the one we all know and love, alpine.</p><p>iproxy 2222 44 -u [device_uuid] &amp;<br>ssh root@127.0.0.1 -p 2222</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/670/1*6l8uNF3hYibkDcXQ2IbNsQ.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/647/1*3s1VuuWfhBxIWPiqx9NzFA.png" /></figure><p>Great, so we’re in. When trying to SSH over the LAN before, the standard rsa authorized keys error popped up, but also that <em>PasswordAuthentication</em> had been disabled. Fine, we’ll turn it back on, except, due to the way palera1n works in its rootless mode, <em>/etc/ssh/sshd_config</em> doesn’t exist.</p><blockquote>Wait, what?</blockquote><h4>Rootful and rootless</h4><p>Generally, all jailbreaks up to this stage, and a few years prior have been rootful, they mount the / root filesystem as read/write and allow changes and modifications to this, and you have access to standard items like <em>/etc</em>, and <em>/usr/bin</em>.</p><p>This is in comparison to rootless, whereby access to the root user account is still achievable as seen, but everything is created virtually and stored within user folders, <em>/var</em> and <em>/private/preboot. </em>Nothing can be written to the main / root filesystem.</p><blockquote>For those who work on both platforms, think of it like Android’s system and systemless rooting variations —<a href="https://magiskroot.net/install-download-magisk-manager-latest/"> Magisk</a></blockquote><p>As this is still a fairly new concept, it’s taking tweak and jailbreak developers sometime to catch up; many tweaks don’t work with rootless jailbreaking and thus can leave you missing your favourite toolset… but it is improving, and rootless, like Android’s systemless, is definitely the way forward.</p><p>So now we now what we’re looking for, and where to find it:<br>find / -name sshd_config -print</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/804/1*YPN2OVfiTjf5KZyR4IQWLA.png" /></figure><p>Once we have found it, simply use vim, to edit the file, and delete the commented out line, replacing it with the opposite, and saving.<br>PasswordAuthentication yes</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/515/1*ADHEJqfrNnpw_wKMZsWQvA.png" /></figure><p>We should now be able to SSH in via LAN using password based auth, much like checkra1n did before, allowing easier access to the device for testing.</p><blockquote>Hold the phone</blockquote><p>Not quite, after any jailbreak always change the default passwords, especially if doing the above and opening up SSH to the LAN, but trying to run <em>passwd </em>was met with the Killed error, and <em>sudo </em>didn’t exist at all, but, we already know exactly where these will be.<br>find / -name sudo -print</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/806/1*wGPwcoFIcse1Th14gExeWQ.png" /></figure><p>Then add it to the device path:<br>export PATH=&quot;/private/preboot/[digit_string]/jb-xxxxxx/procursus/usr/bin:$PATH&quot;</p><p>With this in the path and access to more standard Linux binaries, sudo and passwd should now allow you to change default passwords and run as root.</p><h3>Shells</h3><p>When the device connects via iproxy and USB, it always drops into the basic shell, and has reset the $PATH variable AND passwords, due to rootless using standard sh located in <em>/cores/binpack/bin/sh.<br>Any password changes done to the user accounts via LAN SSH are permanent and stay changed after exit, ensuring the device security.</em></p><p>It is possible to drop into zsh by simply running /<em>var/jb/usr/bin/zsh</em> from the sh prompt giving you access to a proper terminal.</p><p>By creating a .<em>profile </em>file in <em>/private/var/root </em>with the string for the zsh<em> (</em>/<em>var/jb/usr/bin/zsh) </em>the sh spawned on USB connection will automatically run zsh, dropping you directly into it allowing access to other binaries from coreutils. <em>Thanks autom8on</em></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*gP89SKDkNsORquYPgFmFSw.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/574/1*ZieIzG2drDLKRArGhjSejA.png" /></figure><blockquote>Despite palera1n changing the port to SSH via USB, that standard port 22 over LAN works fine once enabled.</blockquote><figure><img alt="" src="https://cdn-images-1.medium.com/max/447/1*dCEH8RvYnmI224nFhSt0fw.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/676/1*33NiPYmn9qGZi3jl-uitEw.png" /></figure><p>Job done.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=cae055579969" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Tales of API Woes From a Security Professional Part 2]]></title>
            <link>https://medium.com/swlh/a-view-on-apis-from-a-security-professional-part-2-65a3137862f4?source=rss-509720bbaed3------2</link>
            <guid isPermaLink="false">https://medium.com/p/65a3137862f4</guid>
            <category><![CDATA[security]]></category>
            <category><![CDATA[hacking]]></category>
            <category><![CDATA[api]]></category>
            <category><![CDATA[mobile]]></category>
            <category><![CDATA[cybersecurity]]></category>
            <dc:creator><![CDATA[The Mobile Security Guys]]></dc:creator>
            <pubDate>Fri, 11 Sep 2020 11:45:47 GMT</pubDate>
            <atom:updated>2020-09-14T21:23:23.431Z</atom:updated>
            <content:encoded><![CDATA[<h4>Looking at mobile app API examples and the shortcomings of their security posture.</h4><blockquote>This is part 2 of our views on APIs. If you haven’t read part 1 then why are you still here? Go take a look :)</blockquote><p><a href="https://medium.com/@mobsecguys/a-view-on-apis-from-a-security-professional-part-1-4d45cbb74b7b">A View on  APIs From a Security Professional Part 1</a></p><h3>Leaking all app data</h3><p>APIs generally have access to loads of user data; they are the middleman to the transactions between the client interface and the back-end databases. Things like search functionality or filtering will be done on data that the API receives from a back-end database query, however this should be done server side, not locally on the client with stored or received data as this risks exposing a lot of information.</p><h4>Using Client-side Filtering</h4><p>With this application, there was a call to <em>api.example.com/call/data</em> as a GET request, the response from the server was the entire listing of companies, emails, usernames, user IDs and real names held by the business; perfect for direct social engineering attacks. This data was then locally stored in a file to be used in the search bar to narrow down results based on pattern matching.</p><blockquote>The entire data set was stored locally on the device as a cached file.</blockquote><p>As this was a locally cached file, it meant that the data had to be updated frequently, cue numerous GET requests to this <em>/call/data</em> API call over the course of the user journey, all in clear text and without certificate pinning; a major issue.</p><p>The idea here is any search term required by the user should be sent as a parameter, the server does the heavy lifting and returns only the specific data required, not everything.</p><ul><li>App sends search term as a parameter in either a GET or POST to the back-end to perform the lookup.</li><li>The Database performs the searching/filtering on the dataset using a query based on the parameter received by the app, and passes the filtered data back to the Server.</li><li>The Server then returns this filtered data back to the app which is relevant to the specifics that were requested.</li></ul><p>Admittedly there are some overhead problems to overcome, especially when scaling this up widely, however fundamentally only the data that is specifically searched for would be obtained by the user and not the entirety of the database.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/928/1*MPwfNnloVort03gCFArXGA.png" /></figure><h4>Server Leaks App Data via Response</h4><p>This next application was seemingly fairly robust; the app itself was quite limited so made attack points difficult to obtain, however there were two instances found where the server response back to the application included the details of the entire user base on the platform. The first involved the use of the <em>Cache.db</em> file on iOS devices.</p><p>The idea of the <em>Cache.db</em> file is that it caches all outgoing requests and incoming responses for the application when used with <em>NSURLSession/NSMutableURLRequest</em> functions, this helps speed up loading times if the same request is repeatedly used, much like the cache for your desktop browser. The downside to this is that if the API shares too much, as in this example, and sends back everything for client-side use, then it is all cached. This file is stored in the app private Library directory, so cannot be browsed on standard stock devices.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*gbDzWQmLQWOSlRrcmfE0nQ.png" /></figure><p>The same API request URLs that were found cached were also found hardcoded in the applications codebase; which after breaking the SSL pinning and utilising an inline proxy tool allowed us to manually call these to obtain the correct headers.</p><p>With the correct headers we could then call <em>/appApi/get_friends/</em> which resulted in a 200 OK response and the full user base details of the application; just like the cache file but no jailbroken device required to access the data this time. Yes it is hashed, but due to the nature of the parameter names, <em>phone_hash</em>, and matching known hashed data with known plaintext, it was simple enough to script a brute force PoC to obtain certain information in plaintext, included names and mobile numbers; enough for further social engineering or smishing.</p><blockquote>Scripting a simple PoC allowed us to brute force hashes to obtain plaintext.</blockquote><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*VQdjYuuqmLpfcE71Od6lXg.png" /></figure><h4>And…?</h4><p>In both of these scenarios there was a massive leakage of personal user information, knowing a name, company and application builds information for the attack; knowing either the email address or a mobile number creates the attack vector. As seen here, if the entirety of the dataset is sent back to the client we risk putting a lot of our information, and potentially sensitive user information at risk as this can be intercepted, or obtained from the device itself from cached files.</p><p>The user should only be sent data that the specific user role is allowed to view based on a set of permissions and restrictions. The entire response to a call should never to sent to the client, especially not one containing so much sensitive information.</p><h3>Enumeration of Data via API Behaviour</h3><p>An enumeration attack is the act of abusing the intended behaviour of the system to obtain something that you didn’t previously have, in this case user data. In this context it involves trying different inputs into certain areas to notice subtle differences in how the app or API responds to valid and invalid data. Once we find the particular nuance to identify the difference between the two, we can increment our starting value to enumerate as much data as possible to gain an awareness of what is stored. We’ll explain this a bit more with some examples.</p><blockquote>Enumeration involves abusing the system to locate small nuances in the result to confirm or deny the presence of certain data.</blockquote><p>The easiest example here is a login form taking an email and a password. The credentials are then checked against the user table in the database and results with either ‘i<em>ncorrect email</em>’ if the user doesn’t exist or ‘<em>incorrect password</em>’ if the user does exist but the password is wrong. Although both tell us we are wrong, they imply totally different things and allow us to make assumptions about the presence of data.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*D7Gn3iYpCh1j_x6T73DEhg.png" /></figure><h4>GET a Forgotten Password</h4><p>This issue demonstrates enumeration of users based off their email address using subtle differences in the GET request URL. The idea here was to build up a list of valid users from email addresses. The authentication mechanism here wasn’t as option as responses to both valid and invalid email addresses, and an incorrect password, the error message was always ‘<em>Login failed. Incorrect email or password</em>’, so this didn’t help or provide any indication to which was wrong.</p><p>However, targeting the Forgotten Password form <em>/pass.html</em>, was more interesting. Entering both a valid and an invalid email gave a stock generic error message about password reset being sent.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*cZIxFA-u2BkojGE2MIYhwg.png" /></figure><p>However, the subtle difference here was in the GET request. When entering an email address of a user who did not exist the URL changed to append: <em>pass.html?sent=n</em></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*FJKZh2J-M90V6NDzsYQVsA.png" /><figcaption>The URL suggests that the reset password email has not been sent as the user doesn’t exist.</figcaption></figure><p>When the email of a user who did exist in the system was entered, this changed to echo out the email and show that the password reset email has been sent; a different string was appended, <em>pass.html?email=bob.hope@test.com&amp;sent=y</em></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*6oC0ruMxp9GFZlgsC_GQOw.png" /><figcaption>URL changed to reflect that this email is of a registered user.</figcaption></figure><blockquote>By abusing the change in the URL, it was possible to build up a list of valid users registered on the platform.</blockquote><p>Using this difference in how the app and API responded to the browser meant it was possible to identify which email address related to a valid user, and from this we can expand the number of attempts to obtain a longer list; this list could then be used for social engineering or phishing for a full credential set. Although browser based enumeration is becoming harder to find, little differences like this are still able to be found and something developers generally overlook, or don’t realise it could be used against them.</p><h4>Response Status Messages</h4><p>Another way to find enumeration is via an inline proxy tool and the responses that are seen via certain API requests. The differences could be a number of different things here such as HTTP status codes, API error messages or custom status messages, but trying different inputs to notice these variances starts to build an image of the behind the scenes working to help figure out what the back-end is expecting.</p><p>The following example shows a few different requests, all to the same API call but with different inputs to test. The format and length of the ID is unknown, and the responses received from the back-end greatly aid in the blind trial and error.</p><p>In the first request we can see that a customer ID of <em>AAAAAAA* </em>is invalid and the response, despite being 200 OK, provide a negative status for that input. Compared with the request of <em>1111111</em>*, provides us with a completely different status code. Based on these two different status codes we are now aware of the correct value, and length for customer ID’s; we can continue this attack using brute force enumeration to locate further customer accounts with automated scanning and increasing the value with a step of 1.</p><blockquote>* To get to this stage progressive requests were sent with 4, 5, 6 and 7 characters until the status code changed from input_error to OK.</blockquote><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*KLQ73979MJHvL9RWvTuigg.png" /><figcaption>A customer ID of AAAAAAA is not the input the server was expecting, and provides a negative status code.</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*FnwQTnqyQoqEEK0SoONfrg.png" /><figcaption>1111111 is a valid customer ID and the response is OK along with other details.</figcaption></figure><p>Now we have a valid customer ID, we can progress deeper into the app to investigate the authentication mechanism to perhaps enumerate valid usernames. Once again, we would be looking for subtle differences in the response from the back-end server to aid in our progression through the API.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*O3Cx7JBL9Vu6dEElF1tfVA.png" /><figcaption>A request for login showing the API status as no data, therefore the user doesn’t exist.</figcaption></figure><h4>And…?</h4><p>These examples have provided an insight into a couple of the numerous methods that enumeration can be done via APIs. Two totally different techniques were able to be used to an attacker’s advantage to gain knowledge of the users, these techniques were likely not even thought about by the developers. Enumeration isn’t just limited to customer IDs, emails or usernames, it could be any item of data that would be useful for an attacker to have.</p><p>APIs are now all around us for the majority of today’s technology. However, out of sight, out of mind won’t work here as whether its a security professional, or a mischievous user, these differences in how requests are handled leaves the door ajar.</p><p>Responses from APIs should be generic and not provide any positive or negative outcomes based on any set of data. Custom error codes could also be designated for certain responses which are then documented internally for troubleshooting. The typical end user will never see the API, or any of these return codes, so using certain words or language that allows the inference of how the server reacts can be a great early foothold into your system for those curious enough to be looking.</p><p>Securing the API and ensuring security is embedded into its development is just as important as implementing a secure web or mobile app. Forgetting to do so, or not understanding the ramifications of not having a secure API may lead to trouble further down the line.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=65a3137862f4" width="1" height="1" alt=""><hr><p><a href="https://medium.com/swlh/a-view-on-apis-from-a-security-professional-part-2-65a3137862f4">Tales of API Woes From a Security Professional Part 2</a> was originally published in <a href="https://medium.com/swlh">The Startup</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Tales of API Woes From a Security Professional Part 1]]></title>
            <link>https://mobsecguys.medium.com/a-view-on-apis-from-a-security-professional-part-1-4d45cbb74b7b?source=rss-509720bbaed3------2</link>
            <guid isPermaLink="false">https://medium.com/p/4d45cbb74b7b</guid>
            <category><![CDATA[api]]></category>
            <category><![CDATA[hacking]]></category>
            <category><![CDATA[mobile]]></category>
            <category><![CDATA[cybersecurity]]></category>
            <category><![CDATA[security]]></category>
            <dc:creator><![CDATA[The Mobile Security Guys]]></dc:creator>
            <pubDate>Fri, 11 Sep 2020 08:43:28 GMT</pubDate>
            <atom:updated>2021-02-10T11:39:33.456Z</atom:updated>
            <content:encoded><![CDATA[<h4>APIs need securing properly, not just via obscurity.</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*InKdXOqZALQhlveo" /><figcaption>Photo by <a href="https://unsplash.com/@markusspiske?utm_source=medium&amp;utm_medium=referral">Markus Spiske</a> on <a href="https://unsplash.com/?utm_source=medium&amp;utm_medium=referral">Unsplash</a></figcaption></figure><p>Application programming interfaces, or APIs, are a large part of today’s world; they are a set of software functions that define the way that multiple applications communicate with each other. Whenever you use an Internet aware software application whether this is a software package, web app, or mobile app it will send data to a back-end server via a request. The server then acts on this information, interpreting it, taking some action and sending it back to the client as a response; this is received via the application and translated into a format readable by humans.</p><blockquote>Some APIs are so large that they are more like complete products of their own, not just an intermediary.</blockquote><p>With the increase in mobile applications and the need for these apps to talk to back-end servers, APIs have started to transform into entire products themselves rather than just a connection link between two end devices. This increase in both the additional complexity and the number of APIs around means that some of these are rushed into production too quickly, introducing various security issues.</p><p>Whether insecure APIs are a product of management pressure, or developers not understanding security boundaries; insecure APIs can greatly impact the security of the application. Perhaps some of these issues are created due to reliance on security through obscurity, general users will never see API communications, so why bother protecting them.</p><blockquote>Average users will never see the API, but this doesn’t mean they don’t need to be secure.</blockquote><p>This post explores several of these API shortcomings and the repercussions that a lack of security design during the API SDLC provides. All of the examples were found on real engagements within the past 12 months so this is still a modern day issue! Hosts have been redacted or changed.</p><h3>Not performing user checks</h3><p>One of the biggest mistakes often found in API testing is the lack of distinction between users. There is either no separation between users and what they have access to, or if there is, that validation is not implemented robustly enough and can be easily bypassed by changing the request URL or the parameters. This may allow users to perform actions such as modifying user details, or submitting new orders as if they were someone else.</p><h4>My Password is Your Password</h4><p>In this example we will be looking at a URL obtained from intercepting the traffic from an app. It was found that that there was no user validation between the authenticated user and the target user whose password was being changed. The URL to change our own password was the following:</p><pre>json/user/update_password</pre><p>Immediately the attack vector is semi-obvious, attempt to change ‘<em>user</em>’ to our own username (<em>un000123</em>) to see if it is still a valid request; if so we can try to target another user (<em>un000132</em>).</p><pre>json/un000123/update_password</pre><pre>json/un000132/update_password</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*eicii7CBYuDEDyt4qh3hUA.png" /><figcaption>A valid request to update our own user password — un000123</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*cTpRoS3ZhnFvGj3wuSpF2w.png" /><figcaption>A valid request to update the target user’s password — un000132</figcaption></figure><blockquote>This simple lack of separation allowed a complete takeover and control of any other user’s account on the entire platform — game over.</blockquote><p>In both cases, us and the target, the API provides a 200 OK response and successfully updates the password on the back-end. This allows us complete control over our target’s user account. This is critical enough, but looking closer there are also a couple of other issues as well.</p><blockquote>The Cookie in the request is blank, so this action was able to be carried out by both an authenticated and an unauthenticated user as long as they had knowledge of the API call.</blockquote><blockquote>There is no server-side check for the current user password, the server checks that <strong>newPassword=confirmNewPassword</strong>, and that’s all.</blockquote><h4>And…?</h4><p>The issue here is that there was no validation of the users on what they could access. There was firstly no check to ensure anyone was even authenticated to the platform before being allowed to perform API calls, and secondly there were no access controls or separation mechanisms to ensure that users could not access or manipulate other accounts. There should be robust checks performed to ensure that the user who is authenticated can only access and modify their own details, straying outside your sandbox should be met with server errors.</p><p><a href="https://medium.com/swlh/a-view-on-apis-from-a-security-professional-part-2-65a3137862f4">Tales of API Woes From a Security Professional Part 2</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=4d45cbb74b7b" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Exploiting App PIN Mechanisms on Android]]></title>
            <link>https://levelup.gitconnected.com/exploiting-custom-protection-mechanisms-in-apps-5983ecd936f6?source=rss-509720bbaed3------2</link>
            <guid isPermaLink="false">https://medium.com/p/5983ecd936f6</guid>
            <category><![CDATA[security]]></category>
            <category><![CDATA[android]]></category>
            <category><![CDATA[mobile]]></category>
            <category><![CDATA[hacking]]></category>
            <category><![CDATA[cybersecurity]]></category>
            <dc:creator><![CDATA[The Mobile Security Guys]]></dc:creator>
            <pubDate>Fri, 03 Jul 2020 11:10:23 GMT</pubDate>
            <atom:updated>2020-07-25T07:19:29.465Z</atom:updated>
            <content:encoded><![CDATA[<h4>Locating and exploiting custom application protection methods.</h4><p>Mobile applications are part of our daily lives, from banking, messaging, health, financial to social networking; but what do most of this type of app have in common?</p><p>They all hold some sort of private user data.</p><p>Whether that data is account numbers, private messages, credit card statements, or the location where you last checked yourself in… that nice cafe round the corner from your house. Our devices store an awful lot of information that would aid someone in potentially stealing an identity.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*uDmwQ7GGiPLGpoXN" /><figcaption>Photo by <a href="https://unsplash.com/@morningbrew?utm_source=medium&amp;utm_medium=referral">Morning Brew</a> on <a href="https://unsplash.com/?utm_source=medium&amp;utm_medium=referral">Unsplash</a></figcaption></figure><blockquote>We rely on the app developers to adequately protect the data we put into their apps.</blockquote><p>If we, as users, decide we want to use an app, we have to rely on the developers to create a secure app and protect our stored data; that is the implicit trust we place onto them. We have usernames, passwords, biometrics, but what about the custom security features that are added into applications in an attempt to safeguard this private information away from malicious intent; protections such as PINs?</p><p>In this post, we will take a look at an app that has a custom PIN entry mechanism as a separate line of defence should anyone else have physical access to the device or know the lock screen password. This would be a secondary authentication mechanism in an attempt to balance usability and security, so the user doesn’t have to login to the app every time they use it.</p><p>We’re not talking about how the PIN is stored or the encryption surrounding it. We‘re interested in looking at the actual logic and internal workings of the PIN implementation and the underlying weaknesses.</p><h3>One PIN to Rule Them All</h3><h4>Code</h4><p>In this first example, we will show how it is possible to patch the application so that it allows any PIN to work, regardless of the original PIN created by the user.</p><p>On looking at the Java code, we see a method called <em>onPINSubmit</em>(), we can see this returns void so nothing is passed back to the calling method. All the PIN function is handled here.</p><p>In order to bypass this authentication, we need to ensure we always trigger the appropriate IF conditions.</p><ol><li>A PIN has previously been setup, and therefore exists.</li><li>The submitted PIN string is not empty.</li><li>Comparing the stored PIN with the one just submitted.</li></ol><p>If the PIN is valid, the IF is passed and the code continues running on lines 153 onwards.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*vuYqVBjafKOw_yUciSmNYw.png" /></figure><p>While looking at the smali we can clearly see these IF conditions and the result of the check being passed into the variable, v0, and jumping to cond_2 depending on the value, lines 477, 485 and 493. These statements match the three bullet points above, so the line 493 does the actual comparison of the two PIN strings which is the last check.</p><p>This comparison is done with the statement, <strong>if-eqz v0, :cond_2</strong>, whereby it jumps to <strong>cond_2</strong>, <strong>if</strong> the value of <strong>v0</strong> is <strong>eq</strong>ual to <strong>z</strong>ero. Equal to zero meaning that if the strings do not match the result would be 0/False. If the PIN strings matched, the result would be 1/True and jump to <strong>cond_2</strong> would not be taken.</p><p>The result of the previous conditions, <em>isEmpty</em>, uses the opposite, <strong>if-nez v0, :cond_2,</strong> and therefore would jump if the result was 1/True.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*LPWQhtqy-bfjsvIKhm-vbw.png" /><figcaption>Three conditions that make up the conditional comparison of the stored and entered PIN.</figcaption></figure><h4>Patching</h4><p>It is then clear to see that we do not want to jump to <strong>cond_2 </strong>and the last check on line 493 is the most critical, as this is the last condition which changes the value of v0. If we modified the code above this, v0 would be overwritten with another value once the check finished.</p><blockquote>By noticing the return values of the methods are Boolean, we can start to build our PIN bypass.</blockquote><p>We can also see that the return values of <em>isEmpty </em>and <em>equals </em>methods are all Boolean values which provides our way of patching this check.</p><p>Firstly we could modify the line which accepts the value from the <em>equals</em> check of the strings, rather than moving the result of the actual check we could hardcode a constant of 1 into v0.</p><pre>move-result v0  --&gt;  const/4 v0, 0x1</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*mviMqMGR8IDnuh_YfUNoiQ.png" /><figcaption>Hardcoding a value of 1 to ensure the check returns True</figcaption></figure><p>A second patch could be simply reversing the logic of the smali conditional statement so that it jumps to cond_2 on a valid PIN, not an invalid one.<br>This however may trigger the user to notice something is amiss when they attempt to use the app and insert their correct PIN and it doesn’t work. Meaning option 1 would be preferable in this instance.</p><pre>if-eqz v0, :cond_2  --&gt;  if-nez v0, :cond_2</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*5DKvJkQkU2DoBs9v4M104w.png" /><figcaption>Reversing the conditional check to return True when an incorrect PIN is entered. This would however also return False when the real PIN was input</figcaption></figure><h3>Unlimited PIN Retries</h3><h4>Code</h4><p>The PIN authentication mechanism also had another protection; this extra piece of security was a count of the incorrect PIN attempts. After 3 incorrect tries, the app would logout and force the user to re-authenticate fully with a valid username and password.</p><p>In the same class as the PIN check above, a return void method named <em>checkPINRetryCount</em>() was found. This is a very simple code block that checked if the wrong attempt variable, incremented in <em>onPINSubmit</em>() method, equals 3.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/598/1*5sPJZDZvts4p0QAqREsHjw.png" /></figure><p>If we look at the smali code we can immediately see the logic flaw involved in this check. The retry counter limit is hardcoded to the constant decimal value 0x3, and then the comparison is done on line 281, <strong>if-ne v0, v1, :cond_0</strong>.</p><ul><li>If <strong>v0</strong> does not equal <strong>v1</strong>, then jump to <strong>cond_0.</strong></li><li>:cond_0 will <strong>return-void</strong>.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/836/1*SC96izw_db6hgFFjg1ArkQ.png" /><figcaption>Hardcoded incorrect try value and the comparison check</figcaption></figure><h4>Patching</h4><p>As with the previous example, there are multiple ways that this check can be bypassed due to the simplicity of the mechanism.</p><p>We have the following options:</p><ul><li>Adding a new code statement to return void as soon as the method is invoked, before the actual comparison check is performed.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/861/1*wS2D9VR1rGfrI1kxJAnw1w.png" /><figcaption>Bypassing of the check by returning void before the comparison is equated.</figcaption></figure><ul><li>It is also possible to change the hardcoded limit value on line 279. Significantly increasing it in from 3 to 999 to allow considerably more attempts.</li></ul><blockquote>Note in this case we had to replace the <strong>const/4</strong> with <strong>const/16</strong> because we need more bits to represent an integer with the value of 999.</blockquote><figure><img alt="" src="https://cdn-images-1.medium.com/max/813/1*QRbDsCejx8-M1VyujLkpog.png" /><figcaption>Modifying the retry value to allow 999 attempts instead of the original 3.</figcaption></figure><ul><li>Replacing the comparison instruction with its opposite equivalent, <strong>if-eq</strong>, but also changing the registers used for the comparison in order to always return True.<br>The modified code would now compare, v1== v1, or 0x3 == 0x3, and always be True to jump to cond_0, the return-void statement.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/803/1*CIZDeClWdmw8zAiw4mvQjg.png" /><figcaption>Reversing the conditional check comparison statement to always return True.</figcaption></figure><p>We’ve looked at a couple of examples of custom implementations of an extra security mechanism in the form of PIN entry. While the idea of these extra protections seems like a great idea from a user and development point of view, by not ensuring security is part of the development lifecycle it is possible to introduce very basic flaws in the flow of the code that can be leveraged by any attacker.</p><p>While these are only simple examples, they represent a very real problem to homebrew solutions to security. Any homebrew implementation should maintain a lot more security focus than the rest of the application which may use well embedded open source libraries, or vendor backed APIs.</p><p>The attack vector here is a very real threat, as we’ve seen the hardest part would not be bypassing the defences, but socially engineering the users to install the modified app and obtain physical access to gain the information from the device.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=5983ecd936f6" width="1" height="1" alt=""><hr><p><a href="https://levelup.gitconnected.com/exploiting-custom-protection-mechanisms-in-apps-5983ecd936f6">Exploiting App PIN Mechanisms on Android</a> was originally published in <a href="https://levelup.gitconnected.com/">Level Up Coding</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Bypassing SSL Pinning on Android]]></title>
            <link>https://levelup.gitconnected.com/bypassing-ssl-pinning-on-android-3c82f5c51d86?source=rss-509720bbaed3------2</link>
            <guid isPermaLink="false">https://medium.com/p/3c82f5c51d86</guid>
            <category><![CDATA[mobile]]></category>
            <category><![CDATA[hacking]]></category>
            <category><![CDATA[cybersecurity]]></category>
            <category><![CDATA[android]]></category>
            <category><![CDATA[security]]></category>
            <dc:creator><![CDATA[The Mobile Security Guys]]></dc:creator>
            <pubDate>Wed, 24 Jun 2020 08:11:01 GMT</pubDate>
            <atom:updated>2020-06-26T22:28:44.834Z</atom:updated>
            <content:encoded><![CDATA[<h4>Circumventing certificate pinning on Android with smali patches.</h4><p>Almost all mobile applications communicate with a backend server, whether this is transmitting app data, backups, analytics; there is some sort of back and forth of data over wireless communication channels in mobile devices.</p><p>Most developers know that they need to use HTTPS, it is 2020 after all, but in mobile applications, this doesn’t go far enough. If you don’t check the server you’re communicating with is the one you’re expecting then how do you trust that the communication is secure and not being intercepted?</p><blockquote>If you don’t verify the server is the legitimate one, how do you know user communication is secure?</blockquote><h3>Problem and Solution</h3><p>The problem is Man in the Middle (MitM) attacks, which as the name suggests refers to some sort of malicious actor sitting in the middle of communications between the client (user/app) and the server. In this position it is possible to intercept, read and modify the traffic to and from the two end devices affecting the users confidentiality, and the integrity of the data. There are numerous ways that MitM can occur, this is not just limited to smart devices, however in the context of mobile one of the biggest threats are fake Android certificates or iOS device profiles.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*lLx9qp0i1jGZ-B7S" /><figcaption>Photo by <a href="https://unsplash.com/@tvick?utm_source=medium&amp;utm_medium=referral">Taylor Vick</a> on <a href="https://unsplash.com/?utm_source=medium&amp;utm_medium=referral">Unsplash</a></figcaption></figure><p>Luckily there is a solution to this problem, Certificate Pinning, or Public Key Pinning as its also commonly known. Pinning is where the app developers specify particular certificates to verify the legitimacy of the servers the app is connecting with to ensure they are trusted.</p><blockquote>We can trust backend servers with the use of Certificate/Public Key Pinning to provide validation.</blockquote><p>This method actually ‘pins’ either the certificate, or the a hash of the public key into the application and uses this to determine the trust of the server that it is connecting to, the server of course holding the private key of the PKI key pair. <br>However, we’re security professionals, while its great to understand the theory of these concepts, we want to understand how we can break these security protections in order to access the underlying API calls. If we can break the certificate pinning, generally it’s possible to gain further footholds into the backend system to obtain a myriad of user data, not just the data of one single user.</p><p>We’re going to take a look at two examples of implementations of certificate pinning that have left flaws in the codebase which can be leveraged by malicious users to intercept this communication and access these behind the scenes API calls.</p><h3>Pinning Bypasses</h3><p>We should note that SSL pinning presents a difficult challenge to bypass; there are multiple different ways an app can implement it, from standard Java APIs to entire libraries built around it. Once you identify how the app implements the pinning, the smali patch can be quite different, either easier or more sophisticated in certain circumstances. We will illustrate and discuss this in our examples.</p><h3>Empty Trust Chain</h3><h4>Java</h4><p>In our first scenario the app was partially obfuscated and used the standard Java SSL pinning. This usually means the app implements a method named “<em>checkServerTrusted</em>()” to validate the backend and possibly “<em>checkClientTrusted</em>()” if client validation is also required by using a custom Trust Manager.</p><pre>public void checkServerTrusted(X509Certificate[] cert, String str)</pre><p>Essentially the method authenticates the server side of the connection. The app provides the certificate as input, usually hardcoded somewhere in the app, and the implementation builds the certificate chain to the server and if trusted, returns a positive value, or in the case of a negative value, throws an Exception.</p><p>The below method takes an array of X509 certificates ‘<em>x509CertificateArr</em>’, which are then iterated through with the Issuer and Subject names extracted and appended to a certificate chain String then validated and in case of “Pinning not found” an Exception is thrown.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/890/1*kZJyO-20Mt1u-xFZX1FTHw.png" /><figcaption>checkServerTrusted() Java pinning code</figcaption></figure><h4>Smali</h4><p>In the smali breakdown of this code block we can see the lower level representation, there are some similarities but also some nuances to take note of.</p><p>The method declaration contains standard smali, however we have:</p><ul><li>‘<em>[</em>‘ to signify an array for the input argument.</li><li>‘<em>L</em>’ to show that the following item is an instance or class, in this case, X509Certificate.</li><li>‘<em>;</em>’ separates arguments</li><li>a String instance, again signified with an ‘<em>L</em>’</li><li>The method then returns void.</li></ul><p>In this case, we can simply move the ‘return void’ statement to before the SSL pinning and String construction is even done. This means the certificate chain is never built, nor verified; however this also demonstrates another issue in play and problem with the logic. There is no error checking to verify that the trust chain was valid or even not null, it blindly accepts the return call and carries on communicating.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*u6mTH7vNZgfrvu0Y4zo6hw.png" /><figcaption>SSL pinning bypass with the smali statement added on line 513.</figcaption></figure><h3>Modification of Stored Certificates</h3><h4>Java</h4><p>This next scenario covers a more complex implementation, but again, one that is flawed in the way it creates the certificate chain and introduces vulnerabilities against the SSL pinning.</p><p>The SSL pinning was found to use a class implementing a method named <em>init()</em>.</p><ol><li>The first step of the method consists of invoking another method named <em>getCertificates</em>(), which is shown just few lines below; line 140</li></ol><p>2. The method <em>getCertificates</em>(), reads CA certificates that are stored as raw resources and returns them in a Java list of type certificate, <em>List&lt;Certificate&gt;</em></p><p>3. Back in <em>init</em>(), instantiate a Java <em>Keystore </em>and add each certificate in the list; lines 95–105</p><p>4. Once this <em>Keystore </em>is built, it is given to a Java <em>TrustManager </em>that will use it to initiate the SSL negotiation with Java SSL <em>init</em>() method; lines 105–107</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*CVhITNM1dwhPLeRx5-LydA.png" /><figcaption>Java code for the init() method and the getCertificates() method</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*I-59P6YSsvRC6b8k3RIZTw.png" /><figcaption>The return value for getCertificates()</figcaption></figure><blockquote>The method implicitly trusts what it’s provided with whether a real certificate, or our custom fake CA.</blockquote><p>From a security point of view this <em>init</em>() method is vulnerable because it entirely trusts the certificates that it is provided with, but doesn’t actually validate what these certificates are for when it is return by the method <em>getCertificates</em>(). Therefore, <em>getCertificates</em>() may return a null value, an empty list or, as we are about to show, our custom CA for the proxy tool.</p><h4>Smali</h4><p>In the first portion of the method <em>getCertificates</em>() we can observe the method call returning a List object, <em>Ljava/util/List</em>; creating a CertificateFactory called <strong>cf</strong> on lines 354–358, then creating and instantiating the <em>ArrayList </em>at lines 362–367.</p><ul><li>What is also important to note here is that the list of Certificates, named <strong>certificates</strong>, is stored in variable <strong>v2</strong>, line 367.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Xq7bCwQaHzkKWv3eBwqBew.png" /><figcaption>getCertificates() smali code</figcaption></figure><p>Further down the code we can start to notice a pattern as to what the code is doing.</p><ol><li>Put a resource ID into a local variable.</li><li>Make a call to <em>openRawResource</em>() with this ID; a reference to the certificate.</li><li>Read using <em>InputStream()</em></li><li>Append to the <strong>certificates</strong> List.</li><li>Close the <em>InputStream()</em></li></ol><p>This same pattern is repeated for each certificate and at the end of the method, the List stored in <strong>v2</strong> is returned.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*QS444EFMgG-hPmc1Npt4GA.png" /><figcaption>Return value of getCertificates() method. v2 is the List of certificates generated</figcaption></figure><p>So this app is taking external input based off a resource ID from the resources folder and building a list of valid “trusted” certificates. What if we were to replace one of these certificates with our attacker controlled certificate?</p><blockquote>We can replace the contents of this ‘trusted’ certificate with our own fake CA.</blockquote><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*zUVQwokmsBNqZuf4rvvqXA.png" /><figcaption>The certificate being opened from the raw resources and read into the app.</figcaption></figure><p>Using the resource ID value that is stored as a constant we can find out what raw file it relates to using a simple command line. Once we have found the resource name, we can locate the raw resource and replace this certificate text with our own.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/330/1*hVLcKixXQH6MSb9X0pZ8QQ.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/690/1*4VcvORtOzkbzEyY9E9tLgw.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/470/1*9X4N-x4iaXEcE9PSdflX4A.png" /></figure><blockquote>What is important to note here is that the certificate might be called .cer but actually be a Base64 encoded DER, also known as PEM; and not the raw binary form of a certificate, (DER or CER).</blockquote><p>In order to convert between raw binary certificates, <em>cer </em>and <em>der</em>, to Base64 encoded certificates, <em>crt </em>or <em>pem</em>, we can use OpenSSL. Once it’s in the correct format, we can overwrite the existing certificate.</p><pre>openssl x509 -in proxyCert.der -inform DER -out proxyCertConvert.pem</pre><p>As we have a real reference to our certificate and real code, all we need to do is to adjust the original logic of the smali. We only care about our certificate being loaded and we can ignore the rest.</p><ul><li>Our certificate has already been opened and read into the <em>InputStream </em><strong>v0 </strong>- line 389</li><li>Generate the certificate using the <em>CertificateFactory </em>method <em>generateCertificate</em>(), and move this into <strong>v5 </strong>- line 390–392</li><li>Add our generated cert<strong>, v5</strong>, to our <strong>certificates </strong>List, <strong>v2 </strong>-line 395</li><li>Close the original <em>InputStream </em>- line 398</li><li>Return the certificates List back to the calling method - line 400.<br>The rest of the smali code continues past this, however as we’ve already returned our <strong>certificates </strong>List object it becomes unreachable code.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*tnc3ciJzgyTStvUCOX7lQw.png" /><figcaption>Returning the list of certificates after only the fake one has been added, ignoring the rest.</figcaption></figure><p>The application will only read in the certificate with our modified content inside it before being returned; the filename remains the same, we merely swapped out the text. As its implicitly trusted, the app continues its communication as normal whilst passing everything through our proxy tool due to accepting our CA.</p><p>We have detailed two examples of how to bypass different implementations of Certificate Pinning, both with errors in how the protection was implemented, but shows how the smallest of flaws could be used by an attacker to push further into the system and investigate the API calls.</p><p>The first example demonstrated a method where the trust chain was implicitly trusted with no further verification other than what the method was passed. There was no error handling or checking what was returned allowing a void return call.</p><p>The second used stored application certificates within the app package, which as the mobile application is on the malicious user’s personal device is never a good idea; because as demonstrated, these can be replaced with something completely different to take advantage of code weaknesses.</p><p>Certificate pinning if used correctly can be an extensive way to protect the backend servers as well as the communication passed in client-server requests and responses. However, it should not be relied upon fully nor used as a reason to accept insecure development practises on the API, but used as part of a layered approach to mobile app network security.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=3c82f5c51d86" width="1" height="1" alt=""><hr><p><a href="https://levelup.gitconnected.com/bypassing-ssl-pinning-on-android-3c82f5c51d86">Bypassing SSL Pinning on Android</a> was originally published in <a href="https://levelup.gitconnected.com/">Level Up Coding</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Defeating Android Root Detection with Smali Patching]]></title>
            <link>https://medium.com/swlh/defeating-android-root-detection-with-smali-patching-46c082c27a81?source=rss-509720bbaed3------2</link>
            <guid isPermaLink="false">https://medium.com/p/46c082c27a81</guid>
            <category><![CDATA[security]]></category>
            <category><![CDATA[mobile]]></category>
            <category><![CDATA[android]]></category>
            <category><![CDATA[hacking]]></category>
            <category><![CDATA[cybersecurity]]></category>
            <dc:creator><![CDATA[The Mobile Security Guys]]></dc:creator>
            <pubDate>Tue, 16 Jun 2020 07:56:01 GMT</pubDate>
            <atom:updated>2020-06-18T16:29:44.870Z</atom:updated>
            <content:encoded><![CDATA[<h4>Binary patching Android applications to bypass security mechanisms.</h4><p>Root detection in Android apps has always been a cat and mouse game. Developers come up with new checks, or a new library comes out; the attackers then bypass these checks or hide root from the filesystem. Despite all the work that goes into coming up with new techniques for either side, root detection remains one of the first hurdles of a defence in depth solution for mobile applications; and as security researchers, one we see all the time.</p><h3>Rooting</h3><p>This post isn’t meant to educate about rooting or the act of obtaining root, but it is useful to understand the concepts surrounding it. To root a device means to gain access to the super user account on the operating system, in Android, which is based on Linux, this user is called ‘<em>root</em>’.</p><blockquote>Rooting is the act of opening up the system, to break the operating system “chains”.</blockquote><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*NRWCw1baJOKzEMb1" /><figcaption>Photo by <a href="https://unsplash.com/@jsalvino?utm_source=medium&amp;utm_medium=referral">John Salvino</a> on <a href="https://unsplash.com/?utm_source=medium&amp;utm_medium=referral">Unsplash</a></figcaption></figure><p>Being the super user, this account can do anything, view, edit, modify anything; but in the modern age when smartphones likely have more personal data than our other devices, being able to view any file is not always a good thing from a privacy perspective. To break out of the operating system ‘chains’ the device requires certain modifications, either through vendor approved unlocking, or device exploitation.</p><p>This is where root detection comes in. Developers add techniques into their app code to check whether this root user is accessible, whether the device has been modified, or if its possible to view files that are usually restricted and then take certain actions based on the result of these checks.</p><p>However, the downfall to this is that most of these checks are done badly, perhaps the strings are hardcoded, the result relies on a single Boolean return value, or incorrect logic means the checks don’t even run at all. By identifying and manipulating these flaws in the logic, we can tamper with this detection allowing apps to run as expected on our modified devices.</p><blockquote>By leveraging development flaws, we can bypass these checks and allow apps to run on modified devices</blockquote><p>We’re going to take a look at two examples of flawed implementations as well as explaining the smali patches involved to avoid having root detected.</p><h3>Return Values</h3><p>Its understandable that you need a return value to return the result of the checks, however this value can become a single point of failure if it’s badly implemented. Nesting if statements and then returning a single Boolean return makes for a very quick patch to easily bypass a multitude of different protections. However they’re not always simple, is it return void, return false, return the value of an object; and this is where understanding the syntax and having knowledge of smali really helps.</p><p>In this first example we’ll look at these return statements in an app that is unobfuscated and uses a very common root detection method, checking for the presence of root utilities with hardcoded names. The lack of code obfuscation on class and method names make finding the root detection code easy.</p><h4>Java</h4><p>In this first root detection mechanism, it is clear what the app attempts to achieve and what the root detection does.</p><p>Two specific root checks are implemented:</p><ul><li><em>checkRootMethod1</em>() searches for strings representing files that maybe present on a rooted device, such as “Superuser.apk”, “sbin/su” etc</li><li><em>checkRootMethod2</em>() attempts to execute the command “su” by means of the Java getRuntime() method.</li><li>These 2 methods are called inside other methods above, which are named <em>testIsRooted</em>() and <em>isRooted</em>()</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*gUUCd_UToUoZkQySbAx_ZQ.png" /><figcaption>Decompiled Java code for the root detection methods.</figcaption></figure><p>What is important to notice here is that these methods do not change any part of the underlying app structure, they are called and merely return the values based on the results. <br>We have two options for this patch to achieve the same outcome.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/381/1*C5aGADHxF4dooXMf99NJNg.png" /><figcaption>Return values for the detection methods.</figcaption></figure><ul><li>Both <em>checkRootMethod1</em>() and <em>checkRootMethod2</em>() return a Boolean. We could amend this to only return False.</li><li>Patch the calling methods, <em>isRooted</em>() to return False and <em>testIsRooted</em>() void before it calls the real methods.</li></ul><h4>Smali</h4><p>Due to the low level that smali works at, it is usually best to modify at the highest point of the calling functions causing the least changes to the codebase. Making changes to specific methods may require more complex patches.</p><p>Let us now look at the <em>checkRootMethod1</em>() to get an idea of some of the syntax used.</p><blockquote>It is generally better to perform the most ‘lazy’ approach, causing minimal changes where possible.</blockquote><figure><img alt="" src="https://cdn-images-1.medium.com/max/794/1*k-F3xUEImw4F1U8lU2lCcw.png" /></figure><p>The smali for the first root detection method is shown.</p><ul><li>Method code can be identified with the key word <strong>.method</strong>,<strong> </strong>and return type character; in this instance a Boolean (Z).</li><li>We see the way the code creates String objects using local variables, <strong>v0…v8</strong>. Then creates a new String array with this range. <strong>{v0 .. v8}, [Ljava/lang/String;</strong></li><li>The array length is calculated, initialisation of other variables and a check, <strong>if v3 &gt; v1, cond_1</strong></li><li>On line 67–71, we create a new File class, signified with <strong>L </strong>prefix; and check if the hardcoded file paths exists.</li><li>If the path exists, put the value 0x1 (True) into the v0 local variable, line 77.</li><li>We then return the value of v0 to the calling method.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/384/1*aQPJ3d5j-SEJOHZWd8AFrQ.png" /></figure><p>It is worth showing both return calls here; only if the file path exists will line 77–79 be executed as it follows the flow of code.</p><p>If no path exists, <strong>if v4 == 0</strong>, line 75, branch the code to <strong>cond_0</strong>, add 0x1 to v3 and follow the<strong> goto_0 </strong>back to line 62.</p><pre>###line 62<br>:goto_0<br>if-ge v3, v1, :cond_1</pre><p>The variable v1 (paths left in array - 0) is now less than v3 (0x1) and thus the code jumps to <strong>cond_1</strong>, whereby <strong>return v2 </strong>is run. v2 is 0 (False) as previously initialised on line 57 with 0x0.</p><blockquote>Note: const/4 [r] [v] puts the numerical value (v) into the specific register (r) as we have seen. The /4 stands for 4 bits and thus the value (v) has a maximum value of 0x15, 0b1111.<br>const/8 (255) and const/16 (65535) can also be used.</blockquote><h4>Patching</h4><p>Now we have covered some of the syntax and opcodes used, let us now consider the actual methods that we are going to patch. Despite the complexities involved in learning this new language, the patches in this first example are very straight forward.<br>The first part of the patch involves bypassing the method which calls the actual root detection code.</p><p>We can see by the (V) type that this method returns void, this is also evident in the <strong>return-void</strong> statement on line 184.<br>Simply moving this statement to before the root check methods are called, from line 184 to line 179 bypasses this function completely.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/827/1*NkVqXOJVPPSlA2yzKyxqXQ.png" /><figcaption>Original smali code for root detection.</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/821/1*lWMRbK7B3EXNmJm4N_pyeA.png" /><figcaption>Modified smali code with moved return-void statement.</figcaption></figure><p>We now need to target the second method, <em>isRooted</em>(), as seen in the method call, this returns a Boolean (Z).<br>This time rather than moving lines, we can add in our own code to perform the desired behaviour. We want to ensure we return 0x0 or False before the actual detection is called.</p><p>In this instance, we can manually write some new code to put a 0 into a local variable, and instantly return this before any other code is run. This can be seen on lines 143–145 in the second image.</p><pre>const/4 v0, 0x0<br>return v0</pre><pre>### original code continues</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/824/1*4wuABrSIz2BEhEoclojsAg.png" /><figcaption>Original smali for the isRooted()</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/829/1*ud3HbXFb5j0cL1moDO3QpQ.png" /><figcaption>Modified code to return False in v0</figcaption></figure><p>Before we move onto the next example we should point out, in case it wasn’t already obvious. None of the original smali code has been modified or overwritten, we have simply moved or added statements to alter the way the application flows.</p><h3>Code Modification</h3><p>When we say code modification we don’t mean we plan to write swathes of complex smali ourself, we simply modify the code to suit our requirements; remember, the lazy approach is the best one.</p><blockquote>Read, interpret and modify… The lazy approach is best.</blockquote><p>In this next example the application is heavily obfuscated, it involves numerous checks both in Java and native C and doesn’t return just a single Boolean value at the end; however the methodology is generally the same, read, interpret and modify.</p><p>When dealing with obfuscated apps, usually the very first steps consist of identifying where the root check is performed, where the root check is implemented, and where it is actually called from. Usually we have 2 options to accomplish this:</p><ol><li>We could search for strings such as “/su” and root package manager apps like “magisk” and then follow the flow. Generally quite time consuming and could lead to rabbit holes.</li><li>A more general approach, consists of running the app and then <em>tracing back </em>any error messages that are shown when the detection check fails. For root detection this is generally on launch.</li></ol><p>When we say “<em>tracing back</em>”, it relies on an associated positive or negative outcome to a specific check. For example, in a positive outcome the app would continue loading and the user would be able to use the app as normal. A negative outcome we may expect an error message, either by displaying the user a pop-up window or a toast, then the app closing. If we are lucky and this error message is visible, we can trace back this pop-up by searching for the string displayed; usually this links to a resource having a similar name defined in a xml file with an associated ID. Using the ID tag we can search for this in the smali code to identify where it is used and the workflow to obtain these actions.</p><h4>Java</h4><p>Let us now examine this second example with the obfuscated app implementing a more sophisticated root check. After having decompiled the app, we search for the string “su” and “magisk” and we manage to find both in a large method named <strong>a()</strong> which is located in the obfuscated class: <strong><em>m.f.a.c.i</em></strong></p><figure><img alt="Java method code incorrectly decompiled, showing smali rather than readable Java." src="https://cdn-images-1.medium.com/max/703/1*5nPnoDTMkUISjKPXZGC-2w.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/427/1*cfTTvp3hZNgNrLjoNv7RQA.png" /></figure><p>Despite the fact the method within this class file failed to decompile correctly we can still ascertain that the method returns a String and takes 2 Strings as input arguments. We also notice that although unclear at current, the String ‘<em>su</em>’ and ‘<em>magisk</em>’ have been hardcoded; this can also be seen when we examine the smali, however there seem to be numerous returns from multiple methods and return values of different values so we have to take a different approach compared to the previous example.</p><h4>Smali</h4><p>Despite not fully understanding the code from the Java point of view we can make some assumptions based on the smali opcodes.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/923/1*j_lxi2c7BtLGP5z8B5_E0A.png" /></figure><ul><li>Already noted are the hardcoded strings in <strong>const-string vx, “str”</strong></li><li>Use of <strong>invoke-virtual</strong>, signifies that the method call is not private, static or final. They are generally used for native library loading.</li><li>The <strong>{}</strong> from invoke-virtual specify the arguments that are given to the method.</li><li>Based on the names where the actual <em>checkForRoot</em>() method is called, we know it is definitely using a native library — <em>RootBeerNative</em></li></ul><p>Based on the above code snippets, and the bad decompilation of the Java, it is not totally understandable what the code does at this point. However we have found these hardcoded strings which relate to rooting tools or binaries so can guess that the code is searching for these at some stage.</p><p>What if we just modify these strings to something else? Something that doesn’t exist and so they will always return False?</p><p>The modification of these two strings was the only necessary adjustments to defeat this detection and use the app as normal. You could be fooled into thinking “that was easy”, however, to get to the stage to find that it was these two strings that were being used was the biggest effort, tracing back, reading over the smali to understand the methods and return values all takes time.</p><blockquote>Just by changing two string values the root detection was defeated, but its not always that simple.</blockquote><figure><img alt="" src="https://cdn-images-1.medium.com/max/494/1*JEN54bbcfvdyXm0__dGo7A.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/395/1*Y9bIGyXdwZB1xiYT1SgBYA.png" /><figcaption>Modification to the hardcoded strings, su to AA and magisk to BB defeated the protections.</figcaption></figure><p>In this post we have covered two different ways to defeat root detection by patching the smali code. We looked at modifying the return values to manipulate the behaviour without modifying the original code; and we looked at a method whereby through small changes we can trick the app into looking for a file that we know doesn’t exist and therefore making the check fail.</p><p>Root detection remains the first step of a defence in depth measure but it needs to be implemented correctly. It needs to have multiple steps and multiple different checks in order to avoid a single point of failure. Using server side verification with tools such as Google SafetyNet Attestation API¹ is a good way to move checks away from the client; however the cat is always chasing the mouse, and even SafetyNet can be bypassed with certain tools.</p><p>¹ SafetyNet Attestation — <a href="https://developer.android.com/training/safetynet/attestation">https://developer.android.com/training/safetynet/attestation</a></p><p><a href="https://medium.com/@mobsecguys/smali-assembler-for-dalvik-e37c8eed22f9">Smali: Assembler for Dalvik</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=46c082c27a81" width="1" height="1" alt=""><hr><p><a href="https://medium.com/swlh/defeating-android-root-detection-with-smali-patching-46c082c27a81">Defeating Android Root Detection with Smali Patching</a> was originally published in <a href="https://medium.com/swlh">The Startup</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Smali: Assembler for Android’s VM]]></title>
            <link>https://mobsecguys.medium.com/smali-assembler-for-dalvik-e37c8eed22f9?source=rss-509720bbaed3------2</link>
            <guid isPermaLink="false">https://medium.com/p/e37c8eed22f9</guid>
            <category><![CDATA[mobile]]></category>
            <category><![CDATA[security]]></category>
            <category><![CDATA[penetration-testing]]></category>
            <category><![CDATA[cybersecurity]]></category>
            <category><![CDATA[android]]></category>
            <dc:creator><![CDATA[The Mobile Security Guys]]></dc:creator>
            <pubDate>Tue, 09 Jun 2020 09:16:00 GMT</pubDate>
            <atom:updated>2020-06-11T14:02:03.606Z</atom:updated>
            <content:encoded><![CDATA[<h4>Assembly language for the dex format, used by Android’s Dalvik virtual machine.</h4><p>When testing Android mobile apps, quite often you can find yourself in a situation where you face a security mechanism that you wish to bypass, either because the app won’t run (e.g root detection) or there is something else you want to investigate more (e.g SSL pinning).</p><p>Usually a tester has 2 options to bypass these mechanisms:</p><ol><li>Bypassing these checks at runtime when executing the app using tools such as Frida; attach the tool to the app process to inject code to manipulate the behaviour. <br>Although fast and usually easier: you need to attach to the app process every time you run the app.</li><li>Otherwise, another more powerful approach while at the same time slightly more complex, consists in modifying the app binary for the specific checks we wish to bypass. In the Android security community this process is referred to as smali code patching.</li></ol><blockquote>By patching the underlying binary code, we can bypass app protections and manipulate its behaviour.</blockquote><h3>Smali</h3><p>From the official git¹, “<em>smali/baksmali is an assembler/disassembler for the </em><strong><em>dex</em></strong><em> format used by </em><strong><em>dalvik</em></strong><em>, Android’s Java VM implementation</em>”.</p><p>The smali code, which is what we wish to modify, can be thought of as an equivalent of assembly code of a C program.</p><p>Having said this, in order to fully understand what smali code is and how it works, it is worth taking a look at the compilation process of an Android app written in Java and where dalvik and dex fit into this.</p><blockquote>Android apps are usually written in Java and compiled to Dalvik bytecode. Dalvik bytecode is created by first compiling the Java code to .class files, then converting the JVM bytecode to the Dalvik .dex format with the dx tool.<br> <br>Extracted from the OWAP Mobile Security Testing Guide²</blockquote><figure><img alt="Java compilation process vs Android compilation process with the extra step for the dex compiler." src="https://cdn-images-1.medium.com/max/476/0*Isgo8FvmdVzeYC25" /><figcaption>Java compilation process vs Android compilation process</figcaption></figure><p>In this comparison, it can be observed that in Android systems we have an extra compilation step rather than the usual Java program. The Java bytecode is compiled into Dalvik bytecode which is then executed by the Android environment; which in modern devices is Android RunTime (ART). ART is the modern day replacement for the Dalvik VM however still runs the .dex file format.</p><p>With this in mind, what smali/backsmali tools do is to reverse the compilation of this bytecode in this .dex format. This is exactly what tools such as apktool³ do; it uses smali/backsmali internally when decompiling an APK file.</p><blockquote>There are still challenges that remain despite smali being a hybrid language; using opcodes as well as semi-readable code.</blockquote><p>Despite all this, smali patching presents a couple of challenges:</p><ul><li>Although smali code does not look exactly like assembly (in terms of syntax), at the same time it does not look like readable code. It is a hybrid mix of the two which the tester must understand.</li><li>Considering the complexity and how low level smali code is, quite often it is easy to modify something that breaks the logic of the app, making the app unusable or unstable.</li></ul><h3>Patching Smali</h3><p>Having introduced and explained the basics of what smali code is, and the reason for modifying it, we’ll begin to talk over some of its structure and syntax, however we will not discuss all opcodes⁴</p><p>Before we start exploring the syntax and patching we first need to <strong>decompile</strong> the target apk. This can be done using apktool to reverse the application, the code and resources; the smali code files can then be found in <em>myAppDirSrc\smali.</em></p><pre>java -jar apktool.jar <strong>d</strong> <em>MyAppName</em>.apk -o <em>myAppDirSrc</em></pre><p>Once we’ve done the smali patches, we need to recompile our code to <strong>build </strong>it from .dex files back into an .apk.</p><pre>java -jar apktool.jar <strong>b</strong> <em>myAppDirSrc</em> -o <em>MyNewAppName</em>.apk</pre><p>However to ensure the modified app installs on a device, it also needs to be signed with a developer signature.</p><pre>keytool -genkey -v -keystore <em>myKey</em>.jks -keyalg RSA -keysize 2048 -validity 10000 -alias <em>myAlias</em></pre><pre>zipalign -v -p 4 <em>MyNewAppName</em>.apk <em>MyNewAppNameAligned</em>.apk</pre><pre>apksigner sign — ks <em>myKey</em>.jks — out <em>MyNewAppNameSigned</em>.apk <em>MyNewAppNameAligned</em>.apk</pre><p>We will look at some examples of Java and the associated smali code to identify where the similarities lie between the two. It is important to be aware of the syntax when working on smali patches in order understand the workflow of the application.</p><h4>Registers and opcodes</h4><pre>.locals x   #local variables<br>.field public a:Ljava/lang/String;   # instance fields<br>.method public constructor &lt;init&gt;(Ljava/lang/String;)V   #methods</pre><pre>v0   #local variable 0<br>v1   #local variable 1<br>...</pre><pre>p0   #parameter 0 (Java &#39;this&#39; context)<br>p1   #parameter 1<br>...</pre><pre>const/4 v0, 0x1   #constant value, putting decimal 1 into v0<br>if-eqz v0   #if v0 is <em>equal </em>to zero<br>if-nez v0   #if v0 is <em>not equal </em>to zero</pre><pre>move-result v1   #store previous result into v1<br>return v1   #return value of v1 back to calling method<br>return void   #return a void value back to calling method</pre><pre>invoke-direct  #invokes non static method, e.g private/constructor<br>invoke-static  #invoke a static method<br>invoke-virtual #invoke non private/static/final, e.g native libs</pre><h4>Types</h4><p>Single characters are used to define various Java types when used in method calls and return values.</p><pre>V - void<br>Z - Boolean<br>B - byte<br>S - short<br>C - char<br>F - float<br>I - int<br>J - long<br>D - double<br>[ - array<br>L - class definition</pre><h4>Sample Syntax</h4><ul><li>method declaration of <em>myMethod </em>with a void return type</li></ul><pre><strong>Java</strong><br>private static void myMethod()</pre><pre><strong>smali</strong><br>.method private static myMethod()V</pre><ul><li>method declaration of <em>myArgMethod </em>with a Boolean return type and a Float argument</li></ul><pre><strong>Java</strong><br>private Boolean myArgMethod(float floatnum)</pre><pre><strong>smali</strong><br>.method private myArgMethod(F)Z –</pre><ul><li>method declaration of <em>myStrMethod </em>with a Boolean return type and a Byte and String argument</li></ul><pre><strong>Java</strong><br>public Boolean myStrMethod(byte mybyte, String str)</pre><pre><strong>smali</strong><br>.method public myStrMethod(B;<em> Ljava/lang/String</em>)Z –</pre><p>We covered a brief intro into some of the vast subject that denotes the smali language; however with only understanding the basics we can start to pull apart the app structure, understand input parameters and return types, and try to modify certain behaviours to manipulate the underlying logic.</p><p>¹ smali — <a href="https://github.com/JesusFreke/smali/wiki">https://github.com/JesusFreke/smali/wiki</a><br>² OWASP MSTG — <a href="https://mobile-security.gitbook.io/mobile-security-testing-guide/android-testing-guide/0x05a-platform-overview#android-security-architecture">https://owasp.org/www-project-mobile-security-testing-guide/</a><br>³ Apktool — <a href="https://github.com/iBotPeaches/Apktool">https://github.com/iBotPeaches/Apktool</a><br>⁴ Dalvik opcodes — 1. <a href="http://pallergabor.uw.hu/androidblog/dalvik_opcodes.html">http://pallergabor.uw.hu/androidblog/dalvik_opcodes.html</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=e37c8eed22f9" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Exploring Native Functions with Frida on Android — part 4]]></title>
            <link>https://medium.com/swlh/exploring-native-functions-with-frida-on-android-part-4-22db2c247e29?source=rss-509720bbaed3------2</link>
            <guid isPermaLink="false">https://medium.com/p/22db2c247e29</guid>
            <category><![CDATA[security]]></category>
            <category><![CDATA[mobile-security]]></category>
            <category><![CDATA[android-ndk]]></category>
            <category><![CDATA[pentesting]]></category>
            <category><![CDATA[android-development]]></category>
            <dc:creator><![CDATA[The Mobile Security Guys]]></dc:creator>
            <pubDate>Tue, 02 Jun 2020 08:01:00 GMT</pubDate>
            <atom:updated>2020-06-03T19:23:37.789Z</atom:updated>
            <content:encoded><![CDATA[<h3>Exploring Native Functions with Frida on Android — part 4</h3><h4>Modifying the input arguments and return values of native functions.</h4><p>We’ve observed how modules from both app execution and the app lifecycle are loaded within the app, but why would this need to be done on a pentest? What can we actually do with all the scripts?</p><p>The aim of this final post is to solve the third consideration; to push the scripts even further to manipulate the input arguments and return values of native functions to be able to modify the true workflow of the app and its designed behaviour.</p><h4>The Target</h4><p>Let us describe our scenario, and our goal. We are targetting the OpenSSL function named <em>SSL_CTX_set_cipher_list()</em> which essentially is used to specify the default ciphers to be used during the SSL negotiation.</p><p>Considering this final example is the most complex one shown and described, reference to the actual code of the OpenSSL function are used. This code is available at: <a href="https://www.openssl.org/source/old/1.0.2/">https://www.openssl.org/source/old/1.0.2/</a></p><p>So why this function?</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*0FnQEzFIMu0O5DwkXs53fw.png" /></figure><p>1. It takes 2 input arguments representing pointers, an <em>SSL_CTX struct</em> (similar to Java object representing SSL context) and <em>char </em>(array of characters representing a string)</p><p>2. It returns an int value that can be either 0 or 1; the same as a true/false Boolean in Java. In this case returning 0 would mean false, therefore the function returns with an error, otherwise it will return 1.</p><p>3. If the circumstances were correct, manipulating this function could be misused to lead to a FREAK¹ attack to downgrade the cipher to force weaker encryption, and represents an interesting case study to test vulnerable backends.</p><h4>Replacing Arguments of the Function</h4><p>Having studied and understood what the target function does, the idea with our script will be to attempt to force a downgrade of the default ciphers used inside the app. This is accomplished by modifying the second function argument (args[1]), the char array representing a string with following string: “<em>ALL:EXP</em>” to represent all ciphers including weak ones.</p><p>To accomplish this, we will make use of <em>NativeFunction². </em>Simply put, <em>NativeFunction</em> lets us call a specified function inside the target process. <br>It requires us to provide the memory address of the desired function as its first argument, which can be achieved using <em>NativePointer³</em>, <em>(ptr </em>for brevity), then we need to follow the target functions signature in terms of return and argument types, respectively arguments 2 and 3, in this case we know the function returns an <em>int </em>and it takes inputs as <em>pointer.</em></p><p>Target function signature:</p><pre>int <strong>&lt;&lt;return value&gt;&gt;</strong> SSL_CTX_set_cipher_list(SSL_CTX *ctx <strong>&lt;&lt;arg1&gt;&gt;</strong>, const char *str <strong>&lt;&lt;arg2&gt;&gt;</strong>)                    </pre><p>Therefore, we can use the following instantiation in our script:</p><pre>var mySet_cipher_list = new NativeFunction(ptr(myExportAddr), &#39;int’, [‘pointer’,’pointer’]);</pre><p>At this stage we just need to call our function variable:</p><p><em>onEnter </em>is passed the target arguments internally, so this is just called simply with <em>function(args).<br></em>We also need to call our function inside <em>onEnter</em> so we can be sure it is called every time. Printing out the value returned by our function allows us to test it actually worked.</p><pre>onEnter: function(args)<br>   var ret = mySet_cipher_list(args[0],str);<br>   console.log(&quot;return value &quot; + ret);<br>   console.log(&quot;decoded args[1] &quot; + Memory.readCString(args[1]));</pre><h4>Replacing Return Values of the Function</h4><p>Having explained and illustrated how to replace arguments of a function, we can utilise the same techniques to modify return values. In this case of theorising the FREAK attack it is not required as we weren’t interested in what was returned, but what was being input.</p><p>However, let us contemplate a case where hooking a native function performs a check and returns a Boolean value indicating whether the check has passed (return 1) or not (return 0), and on failure the app would perhaps stop functioning or show an error.</p><figure><img alt="Root detection strings checking for Magisk stored in a .so file" src="https://cdn-images-1.medium.com/max/476/1*aDz_ru7CgtuGP4HTBU7YDw.png" /></figure><p>A good example of this would be native backed root detection, whereby the checks to be made; checking for ‘su’ or ‘superuser’, checking for known root package names or applications are stored as strings within a .so file.</p><blockquote>We can use this technique to bypass root detection checks which return a Boolean.</blockquote><p>To accomplish this, we need to add some code inside the <em>onLeave </em>callback:</p><p>Just like the <em>args </em>value passed to <em>onEnter</em>, the <em>retval </em>passed to <em>onLeave </em>is done internally by Frida.<br>As we are working with integers, we use the <em>.replace(intVal)</em> to actually replace the returned value, in this case, with 0. A couple of log statements will test that our original value has in fact been modified.</p><pre>onLeave: function(retval)<br>   console.log(&quot;supposed val &quot; + retval);<br>   retval.replace(0);<br>   console.log(&quot;new val &quot; + retval);</pre><p>The full script against an app using the OpenSSL library is provided below along with the output generated from it. At the end of the output both the original return value, referred as “supposed”, and after we have modified it, “replaced”, can be observed.</p><p>It is worth noting that printing the args using <em>JSON.stringify()</em> will print the actual pointer value of the memory address; however using the Memory API allows us to examine the actual content. <br>Similarly, the script output has occurred multiple times, this is due to not only the actual function, <em>SSL_CTX_set_cipher_list</em> being called multiple times by the app, but also due to our modification making it retry until successful.</p><figure><img alt="Script for locating a specific function within a module and modifying the input arguments, and output return values" src="https://cdn-images-1.medium.com/max/1024/1*qH3_C3HrdHxyo3Yk3ziInw.png" /><figcaption>Completed script for locating a specific function within a module and modifying the input arguments, and output return values.</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*EWC5ggyPjrXHBZGvFd-ANA.png" /><figcaption>Output from the script, showing the callbacks of the function and the values.</figcaption></figure><blockquote>We can only “touch, tamper and modify” our C functions rather than creating entire new ones like in Java.</blockquote><p>A final consideration of this technique that should be kept in mind when hooking a C function, we cannot use the same approach one may use when hooking a standard Java function. <br>We cannot hook the function like a Java method and do whatever we want, for example implementing a new <em>TrustManager</em>. When hooking C functions, we can only “touch, tamper, modify” what <em>goes into</em> the function before it is executed and what <em>comes out</em> of it after the function is executed. Therefore, we need to adapt our approaches to keep this logic in mind when examining these native libraries and manipulating them in a real world setting.</p><p>¹ FREAK attack —<a href="https://censys.io/blog/freak"> https://censys.io/blog/freak</a><br>² Frida NativeFunction — <a href="https://frida.re/docs/javascript-api/#nativefunction">https://frida.re/docs/javascript-api/#nativefunction</a><br>³ Frida NativePointer — <a href="https://frida.re/docs/javascript-api/#nativepointer">https://frida.re/docs/javascript-api/#nativepointer</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=22db2c247e29" width="1" height="1" alt=""><hr><p><a href="https://medium.com/swlh/exploring-native-functions-with-frida-on-android-part-4-22db2c247e29">Exploring Native Functions with Frida on Android — part 4</a> was originally published in <a href="https://medium.com/swlh">The Startup</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Exploring Native Functions with Frida on Android — part 3]]></title>
            <link>https://medium.com/swlh/exploring-native-functions-with-frida-on-android-part-3-45422ae18caa?source=rss-509720bbaed3------2</link>
            <guid isPermaLink="false">https://medium.com/p/45422ae18caa</guid>
            <category><![CDATA[security]]></category>
            <category><![CDATA[mobile-security]]></category>
            <category><![CDATA[pentesting]]></category>
            <category><![CDATA[android]]></category>
            <category><![CDATA[mobile-development]]></category>
            <dc:creator><![CDATA[The Mobile Security Guys]]></dc:creator>
            <pubDate>Wed, 27 May 2020 15:22:16 GMT</pubDate>
            <atom:updated>2020-06-02T10:18:35.920Z</atom:updated>
            <content:encoded><![CDATA[<h3>Exploring Native Functions with Frida on Android — part 3</h3><h4>Using Frida to explore libraries during runtime</h4><p>In <a href="https://medium.com/@mobsecguys/exploring-native-functions-with-frida-on-android-part-2-98b97e89eb3d">part 2</a> we moved into a dynamic approach at investigating native libraries using frida-trace and frida CLI. We leveraged the power of the API to construct our own scripts to get useful information from these native functions; however we were left with two considerations.</p><blockquote>The script can only enumerate the modules loaded at its execution — not during the app lifecycle.</blockquote><blockquote>Using the memory base address and the size of library, monitor the memory to extract useful values.</blockquote><p>We will be further exploring the Frida API; and using code examples, try to solve these issues.</p><h4>Exploring Runtime Lifecycle Libraries</h4><p>The first point can be resolved using the Interceptor API, which, as the name suggests lets us intercept a target function. We are interested in any library that is opened at any time during the app lifecycle in order to enumerate its exports, as opposed to just at app execution. This is due to certain libraries not being called until a later stage when certain functionality is triggered by the user.</p><blockquote>By using <em>Interceptor.attach()</em> it is possible to intercept calls of a desired target function while the app is running.</blockquote><p>It is also possible to associate callbacks (functions to do something when the target function is intercepted) specified with the keyword <em>onEnter</em> and <em>onLeave</em>, respectively for when the target function is called but not executed, and when the target function is executed.</p><p>The only required input of this API is a pointer specifying the current memory address of the desired target function. Therefore, either we provide the actual address if it is known, or we use <em>Module.findExportbyName() </em>inline, which will return a pointer to the function given as input<em>, </em>in this case<em> ‘open’</em> from the system <em>libc</em> library or null.</p><figure><img alt="A script to list out libraries at runtime, compared to app execution." src="https://cdn-images-1.medium.com/max/584/1*O9GvDuj6Km5G1g113Qa8RA.png" /><figcaption>Using Interceptor to list out runtime libraries</figcaption></figure><p>It is worth noting again that, when using <em>Module.findExportbyName()</em> it should be given an explicit library name as input, using ‘null’ only when the library is unknown or the desire is to scan all modules.</p><p>Let us now discuss the function <em>explorerOpenedLibs()</em>.</p><ul><li>It first intercepts any function found with the name “open” (a proper C function not a JNI one).</li><li>As a string we read the first input given to open() represented by <em>args[0],</em> which represents the file-path to be opened.</li><li>Checking if this file-path string contains “.so”, we can determine that it is a native library and we can extract its name by using the JavaScript function .split().</li><li>At this point we use another API, <em>Process.findModulebyName()</em>, which will return the module specified by its name if it is found, otherwise it will return null.</li><li>If a match is found, we then print out its exports using the <a href="https://medium.com/@mobsecguys/exploring-native-functions-with-frida-on-android-part-2-98b97e89eb3d">same code from previous scripts</a>.</li></ul><h4>Explicit Library Loading</h4><p>Let us take another scenario, for instance, when we know the specific module we wish to target and the function to be called, yet neither during app execution or runtime the function is ever called.<br>In such circumstances it is possible to manually load a specific library and target a certain call explicitly.</p><p>Let us revisit our app, <em>myBank</em>, with the fork of the OpenSSL native library, <em>openssl_mybank</em>.<br>It is important to note that, in order to avoid any errors, all the related libraries need to be loaded as well. In our scenario the <em>myBank </em>OpenSSL library also requires another library, <em>crypto_mybank</em>.</p><figure><img alt="Script used to explicitly load a library manually rather than via the app" src="https://cdn-images-1.medium.com/max/1024/1*FF2Ic0knmP7I750cImVz7A.png" /><figcaption>Explicitly loading a library manually rather than via the app</figcaption></figure><p>The JavaScript function <em>loadMyBankLibSSL()</em> loads the specific library by using <em>Module.load(), </em>using the absolute path to the library and prints out its respective information. This is done for both libraries that are required.<br>Then we use the <em>Module.findExportByName()</em> to find the pointer to the memory address of the particular function we are interested in, in our example, <em>X509_verify_cert</em>.</p><figure><img alt="Module and export info for the loaded libraries." src="https://cdn-images-1.medium.com/max/1024/1*Bgv7CItQ3OJpX-Pmhy78jA.png" /></figure><p>An output generated by a variant of this script shows the output of the libraries being loaded, the base addresses of these, as well as the export address of the function we are interested in. This goes to show this function actually exists, otherwise it would have been ‘null’.</p><h4>Hooking Native OpenSSL Functions</h4><p>Using all the techniques we have looked at we now have enough knowledge to build a script to combine all these functions together and start using callbacks to provide useful values.</p><blockquote>Using callbacks, we can inspect function arguments - onEnter, or any returned values - onLeave.</blockquote><p>The complete function script <em>hookOpenSSLVerifyCert() </em>is shown below;</p><ul><li>First check if the library we are interested in is ever opened by specifying the full absolute file path (<em>var str</em>).</li><li>Retrieve the module (<em>var module</em>)</li><li>Print out some information from it and attempt to retrieve the address of the function <em>X509_verify_cert() </em>that we are interested in (<em>var myExportAddr</em>).</li><li>If the function is found, therefore the returned value is not null, pass this address as input to <em>Interceptor.attach()</em></li><li>Implement the callbacks for <em>onEnter</em> and <em>onLeave</em> that will be executed when and if the function is ever used by the running app.</li><li>Inside these callbacks, print out the value for the first argument of the function args[0], using JSON or Memory, as well as the returned value.</li></ul><p>Finally, the output generated by<em> </em>our script<em> </em>allows us to observe different values for our defined callbacks<em>, onEnter </em>and <em>onLeave</em>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*qm6YU1hlk0mPXv0IWsI4vw.png" /><figcaption>Complete script to view module exports and associated arguments and return values</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*FtWgguh1VQLvFdfeY_Upyw.png" /></figure><p>The detail in this post allowed us to find a way around a shortcoming of frida-trace, or standard Frida CLI. The use of Interceptor means we can get ahead of the game and trace modules even if they’ve not yet been called by the running app; while the use of callbacks lets us determine how a specific native function is behaving on its return and how this could affect further behaviour of the app.</p><p>In the final post of the series, we will look at how we can modify these callback values and defeat certain protections that have been put in place via native code as a deterrent to attackers.</p><p><a href="https://medium.com/@mobsecguys/exploring-native-functions-with-frida-on-android-part-4-22db2c247e29">Exploring Native Functions with Frida on Android — part 4</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=45422ae18caa" width="1" height="1" alt=""><hr><p><a href="https://medium.com/swlh/exploring-native-functions-with-frida-on-android-part-3-45422ae18caa">Exploring Native Functions with Frida on Android — part 3</a> was originally published in <a href="https://medium.com/swlh">The Startup</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
    </channel>
</rss>