Thank you. So, hey everyone. So, do you want to have some fun? All right. So, okay. Hello, everyone. Welcome to my talk, The Price of Convenience, How Security Vulnerabilities in Global Transportation Payment System Can Cost You. Thank you. My name is Omer Atiyas, and I'm 23 years old. I've been working at SafeBridge as a security researcher for the last two years, and previously I started my career at the age of 17 while working at Rafael Advanced Defense Systems. I'm especially interested in low-level and vulnerability research, and I'm also a technology and science enthusiast. Okay. So, in this session, we're going to talk about how security vulnerabilities in global transportation can cost you. So, in this session, we walk through the smart payment solution of public transportation, and we specifically look at the solution in train services and learn how we can trick the train station gates in order to avoid paying. Then, we will focus on Movit, a mass operator that provides a mobile solution for public transport. We will delve into the APIs of this application, and we'll focus on Movit. To find some vulnerabilities that led me to the perfect crime. So, let's kick it off. So, I guess all of you have ever used public transportation. So, give me hands. I want hands. Please raise your hand if you have ever used mobile solution in order to pay. Okay. I can see a few hands. Cool. So, I encourage all the people that raised their hands to stay tuned to this session. And all the people that didn't raise their hands, also stay tuned. Because it will be fun and profit. Okay. So, recently, mobile payment solutions have become increasingly popular, allowing passengers to pay for their rides using their smartphones. This trend is likely to continue, so let's discuss some terms used in this field. So, let's explain what is mass, actually. So, mass is actually SaaS. In the mobility field, it's actually an application that provides plan and pay for transportation. The mass operator is actually the company that develops the application that provides those features. We can see the logos below, like Bird and Movit, and later on, on this talk, we will focus more on Movit. But a disclosure before we delve into the session. All the findings and explanations are in the description. All the findings and explanations are based on the transportation in Israel, but are not limited to other countries, like the U.S. And, also, I focused on the train services, but the techniques apply to other transport services as well. And one more thing to note is that all my research is done in an ethical way. So now, it's time to understand the mobile solution in public transport. So, I'll actually continue. mobile solution work as far as the trend services is concerned I want to introduce Mike Mike wants to take a train ride and use his new mobile solution his mass operator application that he just downloaded so my get close enough to the station and open up the favorite mass operator with his mass operator Mike an order an entrance ticket and this ticket is actually a cure code that the gates can and validate and if the ticket is valid the gate will open the doors now Mike can enjoys right and when Mike reached his destination Mike again open up the application and order an exit ticket and complete the train ride but one more thing to note is now Mike will not be able to see his local destination unless he wants to that the fare is calculated when we end the ride because only at the destination the mass operator know how much to charge us and all the billings are accumulated and will be charged on monthly basis so the mobile solution provides the payment interface between the train services and the user in the form of the QR code and I thought to myself what the ticket contain maybe the ticket is encrypted maybe not but I decided to give it a shot and investigate the ticket format cool so now we understand how to use the provided mobile solution in order to get around let's deep dive into the format of the ticket so here's an example of train ticket you can see a long number below the QR code which is the row ticket number it seems that the QR code is not encrypted and I wondered if it's possible to change this value and trick the gates into accepting a fake ticket and ultimately this is a way to avoid paying right but what is this format of random looking G digits to make sense of it I need to gather more ticket samples and analyze their patterns you can see that the ticket number is not encrypted but it's not encrypted so I collected a few train tickets and notice repeating patering in the form of the ending 201 in each of the tickets they suggest a format that can be figured out by more analysis but it's still difficult for me to identify a specific format that I can fully understand so when I search on Google I found an API that gave me a JSON file with lots of additional trial and error not to be found on Google I found an API that gave me a json file with lots of information. In that file, one of the details mentioned was the operator. This JSON member represents the ID of the mass operator. So it turns out that the repeated number 201 at the end of each ticket that I collected represented the ID for Movit Pango, which is the one that I used. And I also found other operator mentions in the JSON, including one called IDF. And it's interesting to know that IDF operator allows soldiers in Israel to ride for free. But I'm still not familiar with the remaining part of the ticket, and I don't have any leads to help me understand it. Well, now what? At that point in time, I understood that breaking down the whole format of the ticket is too difficult. And I decided to take my core knowledge at that point in time and conduct an experiment on the train station physical gates. So what would happen if I will order a ticket and just in time modify the ending operator ID to be different operator ID? In this example, I will change Movit Pango operator to be the IDF one. And my expectation was that the gates would see this ticket as a valid ticket as I just modified the operator ID to another known operator ID. But long story short, the experiment failed. So in summary, I had some knowledge about the ticket format, but it was not enough to do anything interesting. And I realized that this approach may not be effective because the gates still validate the ticket, even if I make small changes to it. So I decided to take the focus from the ticket to focus on the gates. And the focus change from the ticket to the gates led me to find a logical vulnerability that allowed me to take a ride without being charged. Let's see. So a quick reminder. There are two tickets during a train ride. The enter ticket, which we order before entering the station, and the exit ticket before exiting the station. Diffing the entrance and exit tickets revealed that these two tickets are actually the same ticket. Okay. So if the entrance and the exit ticket are the same, why not to use a cancel ticket in order to take a train ride? Let me explain exactly how. So Mike gets close enough to the station and then orders an entrance ticket. But this time, Mike immediately cancels his ticket. And the question is, will the gates validate this ticket? So it turns out that the gates accepted the canceled ticket. Perfect. Now we know that there is no real-time communication between the gates and the exit ticket. So the gates and the mass operator. Now Mike can enjoy his ride, and now is the moment of truth. Mike reaches his destination. Will the canceled ticket open the doors gate? So yes, Mike completed a full ride with a canceled ticket. This means that Mike will not pay on the ride, right? So nope. Mike will pay. A week after his ride, the mass operator found that there is a ride that's not being charged. How they knew that? After all, Mike canceled his ticket. So what likely happened is that when Mike entered the station, a record was saved in the train logs. And similarly, a record will be saved for the exit. These two logs together represent a complete ride. Even though the ticket was canceled, the mass operator can still calculate the fare for the full ride. So I had to trick somehow the gates. And the idea that came to my mind is to make a hole in the logs. And I will explain how. The process is similar to the previous process. But this time, when Mike reaches destination with the canceled ticket, Mike orders again a ticket. And then immediately cancels it. The second ticket will open the gate. And in this process, there is no full ride that the mass operators see that Mike did. So this has actually worked. And to summarize all, we gained knowledge of how mobile solution works. And I showed a way to trick the train station gates in order to avoid paying. So far, so good. But that's not all. I decided to take a specific mass operator and find security issues there. The goal is to make freerides and maybe even more. So in the second half of this session, I will shift my focus to move it. And present three vulnerabilities that I have discovered. And additionally, there will be a bonus demonstration towards the end. But first let me introduce Moovit. So Moovit is a worldwide mass operator that has been acquired by Intel at 900 million dollars. Moovit has more than 1.4 billion users around the world and they operate in more than 100 countries and 5,000 cities. Moovit has integration with these big transit providers. It means that we could control an account with one of these providers linked to the account. And the application is primarily used for navigation and finding routes but also used for paying for rides. By clicking the Join Now button and completing the registration process, users can use their Moovit application to pay for rides including the train as we discussed earlier. So let's see what it looks like. So the account registration process begins with downloading the app and joining the payment service. As part of the payment service registration, users are prompted to provide their phone number and to validate that the provided phone number belongs to the users and the phone number is owned by the user Moovit servers generate a random registration. OTP and send it to the provided phone number. If the user responds with the correct OTP, Moovit will register a new account and this account is affiliated with the provided phone number. The account holds other details of the user such as their credit card and their personal information. Also, Moovit offers a feature that enables users to switch their account between devices. The process of switching devices is quite seamless as it follows the same steps as registering a new account. So, for example, if the user takes his SIM card and places it in another device, the new device holds the phone number of the old device that already has an account registered. But there is no account connected to the new device, right? So if the new device is trying to join the service, Moovit server will see that there is an existing account in their affiliations. By authorizing the generated OTP, it will cause the account previously connected to the old device to disconnect and transfer to the newly registered device. So I wondered if I would be able to find some basic insecurities in the API. And I decided to look at the API request between the server and the mobile application. But all the traffic between the server and the application is encrypted using SSL, making it impossible to intercept. But I managed to bypass the SSL certificate using a free descript. This allowed me to serve my own certificate and ultimately intercept all API requests between the server and the device. And my goal was to understand the API communication between the device and the server. So let's see. When the application is first opened, a create user API request is sent to the server. The name of the API may sound straightforward, but I realize it's actually badly named. Let me explain why. When the API request is sent, the server responds with a long identifier, called user key. Through my research, I found that this identifier is actually assigned to the device, and not to the user. And later on, we will discuss this user key identifier more in detail. For now, just remember, it is associated with the device, and not to the user. I explained earlier the account registration process, and that the server holds additional details on the user like his credit card. And I want to add one more detail, the user key. The server also identifies accounts by its user key. But it's important to know that not all the user keys have affiliated accounts, but all the accounts have affiliated user keys. Okay, so let's assume there is a device with user key number one. And for example, this account is linked with phone number one. Our goal is to hijack this account using the account switching feature. First, the attacker make a create user API request to obtain user key legitimately. For example, in this, we get user key number two. After obtaining the user key, the attacker attempts to join the payment service by pretending to be the other device, and specifically the phone device with user key number one. But to complete the registration, the attacker needs to provide the OTP generated by move it right, and since the attacker doesn't have access to the phone device, they cannot guess the OTP. The OTP is actually four digits long. And this is immediately raised the idea of brute forcing this OTP. And I know that there is a small chance that it will work, but I decided to give it a shot. And for my surprise, the brute force attack against the OTP actually worked. And I could literally go over all the OTP options from zero to 9,099. And in the worst case, the brute force took me only five minutes. So let's see. So we can see the device, the emulator that I connected with my account. And now I'm executing the brute force script, providing my phone number. And now the script are trying to guess all the OTP options, as you can see. And we got the OTP. Okay. 2014, which immediately disconnected me from the device. We can see. And I order a train ticket on behalf of my account. And now we will see that someone purchased the ticket. And this was not me. Cool. So after the brute force attack, the attacker takes control of the account. This allows the attacker to complete the OTP. This allows the attacker to completely impersonate the account and use its credit card to order tickets. And furthermore, the attacker gains access to account's personal information. Also the server will change its affiliation and link the attacker user key to the account represented by the victim phone number. So this attack has its pros and its cons. And on the positive side. It targets a specific phone number, which can be useful. But it also has limitation. It cannot be widely spread, takes time due to the brute force and causes the account to be disconnected. The brute force attack is possible approach, but its effectiveness is limited due to the requirement of having the phone number linked to the account. So I decided to transform the problem of getting phone number linked to the account into a user key format to understand the user key format with the goal of enumerating existing accounts. So in the next few slides, I will delve into the user key format and I will showcase the second vulnerability that I found. So as I mentioned earlier, when the application is open for the first time, a create user API is sent to the Movit servers. The server responds with the user key. And we can see that the user key is not the user key. You can see the above value is an example for a user key. It looks like a type of UUID or something. And if I make the API request multiple times, I can gather a lot of user key samples. And by analyzing these samples, I will be able to understand the format better. So I created around 25,000 user keys. And the keys seem pretty similar as they all started with E4. And in a brief look, there is a value within the user key, which repeated in each of the keys. Maybe this is a known value. So I searched this on Google. And I found this Oracle DB function that generates unique identifier with similar value. In fact, this identifier is not really randomized well. The function that generates. These keys doesn't generate a real pseudorandom identifier. And I will explain why. And how I managed to identify other devices. So the documentation on this function shows that this identifier consists of OS identifier, OS or credit identifier, and a non-repeating value. And probably the OS identifier is constant value that appears in each of the keys. So. Okay. So let's try to confirm this on each of the user keys that I've collected. So in a second look, we can see that the user keys are not randomized well. But there are two parts of the user key that seems pretty random. But I noticed that the last four bytes of the user key repeat in some user keys. Additionally, when this repetition happens, there are also four middle bytes that are that remain the same. And moreover, these two numbers are the only ones that seems well randomized. So when this repetition happened, the user keys became almost identical. Suggesting a relationship between the last four bytes and the middle four bytes. But brute forcing these two numbers is very difficult due to the large number of combination, right? So. So brute force is not a possible approach in here. What we can do? So I sorted all the keys and got so many keys with these matching values. These keys are almost identical except of the red square, which turned to be sequential. But I noticed something interesting. Some of the keys follow a sequence, but there are a few missings, for example, between a0 and a7. There are six missing keys. And after looking into it, I realized that those missing keys have already been taken by other users. So bingo. If we will look for those gaps, we could fill those gaps with user keys of other devices, right? So we will fill the gaps between a0 to a7, and we know all these missing are actually belong to other devices. But. But what we can do with devices' user key? So I was looking for an API request to get some more details by providing user key. And luckily I found the perfect API for this. To retrieve the users' information, I can use the user profile API by passing the user key as an argument. And when I make the request, the server will respond with the details related to the user. to the user keys. And guess what? If there is an account associated with the user key, the response will include the account phone number. And if we have a phone number, we can do brute force, right? So I filmed a demonstration of catching user keys of newly registered devices and their phone numbers. And I attempted to test if downloading and registering the payment service would be detected. So let's see. We can see that this is immediately catching a new, really, customers of movies and their phone numbers. And we will wait to see if I can catch myself. All these are actually real users. So as we can see, we caught myself, and this is my phone number, and I actually can attack myself. So I leave the script to run for two hours, and a few moments later, the script caught so many accounts, even worldwide accounts. And for each account, I can link a phone number that belongs to the user. And from now on, we can practically catch the user keys of all the newly registered customers of Moovit. So we have a lot of phone numbers of accounts that can be attacked with the brute force. And now we have made the brute force attack more powerful. We don't need the phone number anymore. Instead, we can go through all the newly registered customers and attack them. But it still disconnects the account from the device. And I wanted to improve that also. So we have a list of user keys and their phone numbers. We want to be able to impersonate the user without disconnecting them from the device. To do this, we need to understand how the API request looks from the user's account perspective. So let's see. In the next slide, we will learn how ticket purchasing works in relation to API requests. We discussed the brute force attack, which involves hijacking accounts. We'll learn how to use a brute force attack, which involves hijacking accounts. We'll learn how to use the brute force attack, which involves hijacking accounts. And we'll learn how Now, I would like to explore the internals of the API involved. So just a reminder about the create user API. When the application is first opened, a user key is generated for the device and requested through this API request. But that's not all. After this API request, there is something important to know. We have learned that Moovit stores account information like personal details and credit card data along to the user key. But there is one more essential requirement we missed. The access token. Without it, communicating with the servers is impossible. The access token is generated immediately after the device receives its user key. By sending registered API requests, the servers receive this user key. Then it sends the remaining access token. will respond with a temporary token and with this token we can request a verification from a third party providing the token along with the user key and in exchange google will respond with the access token so after setting up the access token the application has user key and an access token allowing us to request more apis for instance without the access token we cannot register for the payment service which also means that we won't be able to use the api for purchasing new tickets so now we understand that these two requirements are essential to the api communication let's go back to the problem the issue is that we have the user key of an existing account but we don't have the access token this means that we cannot make api requests on behalf of the account like ordering a train ticket so in this situation if we use the brute force attack that i explained earlier the account will be disconnected from the device and associated to other device but we want to fully impersonate the account without disconnecting it so let's see what we can do the access token is actually a jwt as we can see can we forge this token by modifying the payload so this approach is not possible due to the way jwt works so what can so we cannot forge jwt do we have another way to get the token so through this research i've learned that sometimes the simple things will work so i went back to the creation of the jwt token and we'll we already have a user key of a different account maybe you can request another token for this user key even though there is an already active token to do that we need to send register and then verify custom token request so let's see what we got so that's actually worked there is no validation on the we could request as much as tokens as we want even though there is an active token now we can fully impersonate accounts without disconnecting them it's like it's crazy we actually have the ability to perform all the operation on behalf of different accounts including ordering tickets additionally we can access all of their personal information now we have made the perfect attack without disconnecting the account this attack is quick and doesn't require a phone number with the information collected through our script we have the ability to access each of this account and by doing so we can retrieve their personal information so let's see what we did so I conduct a proof-of-concept in which I took each of the user keys and use them to create a database containing various personal information such their ID email address and so on using the database I developed a user interface for demonstration purposes which I then tested on the train station but before the demo isn't a fun fact one of the code accounts belong to one of the developers that move it they actually back and develop it for the time being ما through a video made for the email address a different user platform this is the demo this is me in a train station and you can see on the left side the user interface that I have developed and now I'm selecting the source station and the account that I want to pay on my ride and in exchange I'm getting a ticket which someone else paid me and I'm easily passing the gates thank you okay so the takeaways even big companies can fall victim to simple attacks showing the need for increased awareness and attention to basic security measures and also I want to understand the research perspective turning challenges into a opportunities and using limitations for positive results we conduct we connected with move it and responsibly disclose all the vulnerabilities and all of them have been fixed and no customer action is required also all the scripts that I use throughout this research push push to this github repository and you are more than welcome to take a look and I want to thank more corn for helping me a lot throughout this research thank you and I want to thank you for joining thank you