 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. Our security vulnerabilities in global transportation payment system can cost you. My name is Omer Atias 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 Raphael 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 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 ping. Then we will focus on moving a mass operator that provide a mobile solution for public transport. We will delve into the APIs of this application and we'll 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 a hand. I want to ask, please raise your hand if you have ever used mobile 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 solution have become increasingly popular, allowing passengers to pay for their rides using their smart phones. 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 SAS, but in the mobility field. It's actually application that provide plan and pay for transportation. The mass operator is actually the company that develops the application that provide those features. We can see the logos below like bird and movie and later on on this talk we will focus more on movie. But a disclosure before we delve into the session, all the findings and explanation 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 done in an ethical way. So, now it's time to understand the mobile solution in public transport. So, how actually mobile solution work as far as the train 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. And Mike got close enough to the station and open up the favorite mass operator. With his mass operator, Mike can order an entrance ticket. And this ticket is actually a cure code that the gates can invalidate. And if the ticket is valid, the gate will open the doors. Now Mike can enjoy his ride and when Mike reached his destination, Mike again opened up the application and ordered an exit ticket and complete the train ride. But one more thing to note is that the fare is calculated when we hand the ride because only the destination, the mass operator, know how much to charge us. And all the buildings are accumulated and will be charged on a monthly basis. So, the mobile solution provides the payment interface between the train services and the user in the form of the cure code. And I thought to myself, what the ticket contained? 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 dive into the format of the ticket. So, here's an example of train ticket. You can see a long number below the cure code, which is the row ticket number. It seems that the cure 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 digits? To make sense of it, I need to gather more ticket samples and analyze their patterns. So, I collected a few train tickets and noticed a repeating pattern in the form of the ending 201 in each of the tickets. This suggests 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 searched 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 ordered before entering the station, and the exit ticket before exiting the station. Defeating the entrance and exit tickets revealed that these two tickets are actually the same ticket. Okay, so, if the entrance and 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 order 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 cancel ticket. Perfect. Now we know that there is no real-time communication between the gates and the mass operator. Now Mike can enjoy his ride and now it's the moment of truth. Mike reached his destination. Will the cancel ticket open the doors gate? So, yes, Mike completed a full ride with a cancel ticket. This means that Mike will not pay on the ride, right? So, no, Mike will pay. A week after his ride, the mass operator found that there is a ride that 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 some of 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 cancel ticket, Mike ordered again entrance ticket and then immediately canceled 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 is 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 a free ride 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 toward the end. But first, let me introduce move it. So, move it is a worldwide mass operator that has been acquired by Intel at 900 million dollars. Move it as more than 1.4 billion users around the world. And they operate in more than 100 countries and 5,000 cities. Move it as 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 out button and completing the registration process, users can use their move it application to pay for rides, including the train as we discussed earlier. So, let's see what this looks like. So, the account registration process begin 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, move it service, generate a random OTP, and send it to the provided phone number. If the user responds with the correct OTP, move it will register a new account. And this account is affiliated with the provided phone number. The account holds other details of the users such as their credit card and their personal information. Also, move it 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 placed it in another device, the new device all the phone number of the old device that already have an account registered. But there is no account connected to the new device, right? So, if the new device trying to join the service, move it server will see that there is an existing account in their affiliations. By authorizing the generated OTP 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 request 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, I 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. And 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's associated with the device and not with the user. So, 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 account by his 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 get 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 be 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 2014, which immediately disconnected me from the device. We can see. And I ordered a trend 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 completely impersonate the account and use its credit card to order tickets. And furthermore, the attacker gains access to accounts 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 attack 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 an account 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 Movid server. The server responds with the user key and we can see the above value is an example for user key. It looks like a type of idea 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 key seems 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 ORACLDB 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 manage to identify other devices. So the documentation on this function shows that this identifier consists of OS identifier, process or thread identifier and non-repeating value. And probably the OS identifier is constant value that appears in each of the keys. So let's try to confirm this on each of the user keys that I have 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 remain the same. And moreover, these two numbers are the only ones that seems well randomized. So when this repetition happens, the user keys become 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 combinations, right? So brute force is not a possible approach in here. What we can do? So I started 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 and A7, and we know all these missing are actually belong to other devices. But what we can do with devices' user keys? 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 user's 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 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 phone number, we can do brute force, right? So I filmed the 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 belongs to the user. And from now on, we can practically obtain all the newly registered customers of movies. 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 account by trying out all possible OTP options. 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 movie store 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 request, the server 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 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 their access token. This means that we cannot make API request on behalf of the account, like ordering a trend 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 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 access token. And we already have a user key of a different account. Maybe we 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 access token creation request. 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 these accounts. 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 used them to create a database containing various personal information, such their ID, email address, and so on. Using this database, I developed a user interface for demonstration purposes, which I then tested on the train station. But before the demo, here's a fun fact. One of the code accounts belonged to one of the developers that moved it. They actually backend the developer. It's nice to see that he believes in the product. So let's see the demo. This is me in the 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 takeaway is, 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 opportunities and using limitations for positive results. We connected with Movit 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 used throughout this research pushed to this GitHub repository. And you are more than welcome to take a look. And I want to thank for helping me a lot throughout this research. Thank you. And I want to thank you for joining. Thank you.