1 00:00:00,000 --> 00:00:20,840 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. 2 00:00:20,840 --> 00:00:38,780 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. 3 00:00:39,560 --> 00:00:46,940 I'm especially interested in low-level and vulnerability research, and I'm also a technology and science enthusiast. 4 00:00:48,700 --> 00:00:50,820 Okay. So, in this session, we're going to talk about how security vulnerabilities in global transportation can cost you. 5 00:00:50,820 --> 00:01:06,520 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. 6 00:01:07,670 --> 00:01:15,620 Then, we will focus on Movit, a mass operator that provides a mobile solution for public transport. 7 00:01:16,460 --> 00:01:20,800 We will delve into the APIs of this application, and we'll focus on Movit. 8 00:01:20,820 --> 00:01:25,340 To find some vulnerabilities that led me to the perfect crime. 9 00:01:25,840 --> 00:01:26,960 So, let's kick it off. 10 00:01:28,460 --> 00:01:31,640 So, I guess all of you have ever used public transportation. 11 00:01:32,220 --> 00:01:33,760 So, give me hands. I want hands. 12 00:01:33,920 --> 00:01:38,840 Please raise your hand if you have ever used mobile solution in order to pay. 13 00:01:40,380 --> 00:01:42,020 Okay. I can see a few hands. 14 00:01:42,220 --> 00:01:46,440 Cool. So, I encourage all the people that raised their hands to stay tuned to this session. 15 00:01:47,220 --> 00:01:50,720 And all the people that didn't raise their hands, also stay tuned. 16 00:01:50,820 --> 00:01:53,180 Because it will be fun and profit. 17 00:01:54,620 --> 00:02:04,700 Okay. So, recently, mobile payment solutions have become increasingly popular, allowing passengers to pay for their rides using their smartphones. 18 00:02:05,960 --> 00:02:11,480 This trend is likely to continue, so let's discuss some terms used in this field. 19 00:02:12,150 --> 00:02:14,980 So, let's explain what is mass, actually. 20 00:02:16,420 --> 00:02:19,900 So, mass is actually SaaS. 21 00:02:20,820 --> 00:02:26,920 In the mobility field, it's actually an application that provides plan and pay for transportation. 22 00:02:27,780 --> 00:02:34,640 The mass operator is actually the company that develops the application that provides those features. 23 00:02:35,700 --> 00:02:42,580 We can see the logos below, like Bird and Movit, and later on, on this talk, we will focus more on Movit. 24 00:02:44,980 --> 00:02:48,540 But a disclosure before we delve into the session. 25 00:02:48,840 --> 00:02:50,800 All the findings and explanations are in the description. 26 00:02:50,800 --> 00:02:57,980 All the findings and explanations are based on the transportation in Israel, but are not limited to other countries, like the U.S. 27 00:02:58,180 --> 00:03:06,240 And, also, I focused on the train services, but the techniques apply to other transport services as well. 28 00:03:06,800 --> 00:03:12,100 And one more thing to note is that all my research is done in an ethical way. 29 00:03:12,580 --> 00:03:17,660 So now, it's time to understand the mobile solution in public transport. 30 00:03:19,460 --> 00:03:20,780 So, I'll actually continue. 31 00:03:20,780 --> 00:03:26,400 mobile solution work as far as the trend services is concerned I want to 32 00:03:26,400 --> 00:03:32,400 introduce Mike Mike wants to take a train ride and use his new mobile 33 00:03:32,400 --> 00:03:39,820 solution his mass operator application that he just downloaded so my get close 34 00:03:39,820 --> 00:03:46,520 enough to the station and open up the favorite mass operator with his mass 35 00:03:46,520 --> 00:03:52,740 operator Mike an order an entrance ticket and this ticket is actually a 36 00:03:52,740 --> 00:03:59,160 cure code that the gates can and validate and if the ticket is valid the 37 00:03:59,160 --> 00:04:05,020 gate will open the doors now Mike can enjoys right and when Mike reached his 38 00:04:05,020 --> 00:04:11,040 destination Mike again open up the application and order an exit ticket and 39 00:04:11,040 --> 00:04:16,360 complete the train ride but one more thing to note is 40 00:04:16,360 --> 00:04:16,500 now Mike will not be able to see his local destination unless he wants to 41 00:04:16,500 --> 00:04:22,100 that the fare is calculated when we end the ride because only at the destination 42 00:04:22,100 --> 00:04:27,900 the mass operator know how much to charge us and all the billings are 43 00:04:27,900 --> 00:04:34,460 accumulated and will be charged on monthly basis so the mobile solution 44 00:04:34,460 --> 00:04:39,960 provides the payment interface between the train services and the user in the 45 00:04:39,960 --> 00:04:47,220 form of the QR code and I thought to myself what the ticket contain maybe the 46 00:04:47,220 --> 00:04:51,100 ticket is encrypted maybe not but I decided to give it a shot and 47 00:04:51,100 --> 00:04:57,240 investigate the ticket format cool so now we understand how to use the 48 00:04:57,240 --> 00:05:02,400 provided mobile solution in order to get around let's deep dive into the format 49 00:05:02,400 --> 00:05:08,960 of the ticket so here's an example of train ticket you can see a long number 50 00:05:08,960 --> 00:05:09,940 below the QR code 51 00:05:09,940 --> 00:05:17,180 which is the row ticket number it seems that the QR code is not encrypted and I 52 00:05:17,180 --> 00:05:21,980 wondered if it's possible to change this value and trick the gates into 53 00:05:21,980 --> 00:05:28,800 accepting a fake ticket and ultimately this is a way to avoid paying right but 54 00:05:28,800 --> 00:05:35,000 what is this format of random looking G digits to make sense of it I need to 55 00:05:35,000 --> 00:05:38,380 gather more ticket samples and analyze their patterns 56 00:05:38,630 --> 00:05:39,920 you can see that the ticket number is not encrypted but it's not encrypted 57 00:05:39,940 --> 00:05:45,300 so I collected a few train tickets and notice repeating patering in the form of 58 00:05:45,300 --> 00:05:49,080 the ending 201 in each of the tickets 59 00:05:50,360 --> 00:05:56,200 they suggest a format that can be figured out by more analysis but it's 60 00:05:56,200 --> 00:06:00,040 still difficult for me to identify a specific format that I can fully 61 00:06:00,040 --> 00:06:08,260 understand so when I search on Google I found an API that gave me a JSON file 62 00:06:08,260 --> 00:06:09,920 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 63 00:06:09,920 --> 00:06:17,720 information. In that file, one of the details mentioned was the operator. This JSON member 64 00:06:17,720 --> 00:06:25,020 represents the ID of the mass operator. So it turns out that the repeated number 201 65 00:06:25,580 --> 00:06:33,520 at the end of each ticket that I collected represented the ID for Movit Pango, which 66 00:06:33,520 --> 00:06:41,720 is the one that I used. And I also found other operator mentions in the JSON, including 67 00:06:41,720 --> 00:06:50,480 one called IDF. And it's interesting to know that IDF operator allows soldiers in Israel 68 00:06:50,480 --> 00:06:57,740 to ride for free. But I'm still not familiar with the remaining part of the ticket, and 69 00:06:57,740 --> 00:07:00,140 I don't have any leads to help me understand it. 70 00:07:01,820 --> 00:07:03,380 Well, now what? 71 00:07:04,560 --> 00:07:10,460 At that point in time, I understood that breaking down the whole format of the ticket 72 00:07:10,460 --> 00:07:17,880 is too difficult. And I decided to take my core knowledge at that point in time and conduct 73 00:07:17,880 --> 00:07:26,100 an experiment on the train station physical gates. So what would happen if I will order 74 00:07:26,100 --> 00:07:33,140 a ticket and just in time modify the ending operator ID to be different operator ID? 75 00:07:33,140 --> 00:07:40,800 In this example, I will change Movit Pango operator to be the IDF one. And my expectation 76 00:07:40,800 --> 00:07:47,220 was that the gates would see this ticket as a valid ticket as I just modified the operator 77 00:07:47,220 --> 00:07:55,860 ID to another known operator ID. But long story short, the experiment failed. So in 78 00:07:55,860 --> 00:08:00,440 summary, I had some knowledge about the ticket format, but it was not enough to do anything 79 00:08:00,440 --> 00:08:00,960 interesting. 80 00:08:01,900 --> 00:08:08,400 And I realized that this approach may not be effective because the gates still validate 81 00:08:08,400 --> 00:08:11,780 the ticket, even if I make small changes to it. 82 00:08:13,580 --> 00:08:21,220 So I decided to take the focus from the ticket to focus on the gates. And the focus change 83 00:08:21,220 --> 00:08:27,100 from the ticket to the gates led me to find a logical vulnerability that allowed me to 84 00:08:27,100 --> 00:08:30,060 take a ride without being charged. Let's see. 85 00:08:30,960 --> 00:08:37,460 So a quick reminder. There are two tickets during a train ride. The enter ticket, which 86 00:08:37,460 --> 00:08:42,400 we order before entering the station, and the exit ticket before exiting the station. 87 00:08:44,240 --> 00:08:49,840 Diffing the entrance and exit tickets revealed that these two tickets are actually the same 88 00:08:49,840 --> 00:08:50,180 ticket. 89 00:08:51,900 --> 00:08:59,060 Okay. So if the entrance and the exit ticket are the same, why not to use a cancel ticket 90 00:08:59,500 --> 00:09:00,940 in order to take a train ride? 91 00:09:00,960 --> 00:09:08,560 Let me explain exactly how. So Mike gets close enough to the station and then orders 92 00:09:08,560 --> 00:09:17,180 an entrance ticket. But this time, Mike immediately cancels his ticket. And the question is, will 93 00:09:17,180 --> 00:09:19,000 the gates validate this ticket? 94 00:09:20,760 --> 00:09:27,780 So it turns out that the gates accepted the canceled ticket. Perfect. Now we know that 95 00:09:27,780 --> 00:09:30,940 there is no real-time communication between the gates and the exit ticket. So the gates 96 00:09:30,960 --> 00:09:31,880 and the mass operator. 97 00:09:33,360 --> 00:09:40,560 Now Mike can enjoy his ride, and now is the moment of truth. Mike reaches his destination. 98 00:09:41,080 --> 00:09:43,560 Will the canceled ticket open the doors gate? 99 00:09:44,500 --> 00:09:51,660 So yes, Mike completed a full ride with a canceled ticket. This means that Mike will 100 00:09:51,660 --> 00:09:53,580 not pay on the ride, right? 101 00:09:54,800 --> 00:09:57,380 So nope. Mike will pay. 102 00:09:57,520 --> 00:10:00,420 A week after his ride, the mass operator 103 00:10:00,960 --> 00:10:08,280 found that there is a ride that's not being charged. How they knew that? After all, Mike 104 00:10:08,280 --> 00:10:09,360 canceled his ticket. 105 00:10:11,720 --> 00:10:18,920 So what likely happened is that when Mike entered the station, a record was saved in 106 00:10:18,920 --> 00:10:27,700 the train logs. And similarly, a record will be saved for the exit. These two logs together 107 00:10:27,700 --> 00:10:29,720 represent a complete ride. 108 00:10:29,720 --> 00:10:35,400 Even though the ticket was canceled, the mass operator can still calculate the fare 109 00:10:35,400 --> 00:10:36,340 for the full ride. 110 00:10:38,020 --> 00:10:44,480 So I had to trick somehow the gates. And the idea that came to my mind is to make a 111 00:10:44,480 --> 00:10:47,380 hole in the logs. And I will explain how. 112 00:10:49,460 --> 00:10:55,360 The process is similar to the previous process. But this time, when Mike reaches destination 113 00:10:55,820 --> 00:10:59,700 with the canceled ticket, Mike orders again a ticket. 114 00:10:59,700 --> 00:11:02,460 And then immediately cancels it. 115 00:11:03,280 --> 00:11:09,060 The second ticket will open the gate. And in this process, there is no full ride that 116 00:11:09,060 --> 00:11:11,940 the mass operators see that Mike did. 117 00:11:12,980 --> 00:11:14,700 So this has actually worked. 118 00:11:16,160 --> 00:11:22,960 And to summarize all, we gained knowledge of how mobile solution works. And I showed 119 00:11:22,960 --> 00:11:29,120 a way to trick the train station gates in order to avoid paying. So far, so good. But 120 00:11:29,120 --> 00:11:29,860 that's not all. 121 00:11:30,940 --> 00:11:38,560 I decided to take a specific mass operator and find security issues there. The goal is 122 00:11:38,560 --> 00:11:42,240 to make freerides and maybe even more. 123 00:11:44,000 --> 00:11:50,260 So in the second half of this session, I will shift my focus to move it. And present 124 00:11:50,260 --> 00:11:57,960 three vulnerabilities that I have discovered. And additionally, there will be a bonus demonstration 125 00:11:57,960 --> 00:12:05,240 towards the end. But first let me introduce Moovit. So Moovit is a worldwide 126 00:12:05,240 --> 00:12:12,780 mass operator that has been acquired by Intel at 900 million dollars. Moovit has 127 00:12:12,780 --> 00:12:19,240 more than 1.4 billion users around the world and they operate in more than 128 00:12:19,240 --> 00:12:27,760 100 countries and 5,000 cities. Moovit has integration with these big 129 00:12:27,760 --> 00:12:33,340 transit providers. It means that we could control an account with one of 130 00:12:33,340 --> 00:12:40,240 these providers linked to the account. And the application is primarily used 131 00:12:40,240 --> 00:12:47,320 for navigation and finding routes but also used for paying for rides. By 132 00:12:47,320 --> 00:12:52,040 clicking the Join Now button and completing the registration process, users 133 00:12:52,040 --> 00:12:57,680 can use their Moovit application to pay for rides including the train 134 00:12:57,680 --> 00:13:03,980 as we discussed earlier. So let's see what it looks like. So the account 135 00:13:03,980 --> 00:13:08,220 registration process begins with downloading the app and joining the 136 00:13:08,220 --> 00:13:14,280 payment service. As part of the payment service registration, users are prompted 137 00:13:14,280 --> 00:13:20,240 to provide their phone number and to validate that the provided phone number 138 00:13:20,240 --> 00:13:25,820 belongs to the users and the phone number is owned by the user Moovit 139 00:13:25,820 --> 00:13:27,660 servers generate a random registration. 140 00:13:27,680 --> 00:13:34,900 OTP and send it to the provided phone number. If the user responds with the 141 00:13:34,900 --> 00:13:42,600 correct OTP, Moovit will register a new account and this account is affiliated 142 00:13:42,600 --> 00:13:48,680 with the provided phone number. The account holds other details of the user 143 00:13:48,680 --> 00:13:56,360 such as their credit card and their personal information. Also, Moovit offers 144 00:13:56,360 --> 00:14:02,540 a feature that enables users to switch their account between devices. The 145 00:14:02,540 --> 00:14:07,840 process of switching devices is quite seamless as it follows the same steps as 146 00:14:07,840 --> 00:14:13,920 registering a new account. So, for example, if the user takes his SIM card 147 00:14:13,920 --> 00:14:19,780 and places it in another device, the new device holds the phone number of the old 148 00:14:19,780 --> 00:14:24,400 device that already has an account registered. But there is no account 149 00:14:24,400 --> 00:14:26,160 connected to the new device, right? 150 00:14:27,740 --> 00:14:33,900 So if the new device is trying to join the service, Moovit server will see that 151 00:14:33,900 --> 00:14:41,320 there is an existing account in their affiliations. By authorizing the generated 152 00:14:41,320 --> 00:14:47,300 OTP, it will cause the account previously connected to the old device to disconnect 153 00:14:47,860 --> 00:14:55,500 and transfer to the newly registered device. So I wondered if I would be able 154 00:14:55,500 --> 00:14:56,340 to find some 155 00:14:56,360 --> 00:15:02,840 basic insecurities in the API. And I decided to look at the API request between the server 156 00:15:02,840 --> 00:15:09,720 and the mobile application. But all the traffic between the server and the application is 157 00:15:09,720 --> 00:15:18,260 encrypted using SSL, making it impossible to intercept. But I managed to bypass the 158 00:15:18,260 --> 00:15:25,620 SSL certificate using a free descript. This allowed me to serve my own certificate and 159 00:15:25,620 --> 00:15:34,360 ultimately intercept all API requests between the server and the device. And my goal was to understand the 160 00:15:34,360 --> 00:15:42,980 API communication between the device and the server. So let's see. When the application is first opened, a 161 00:15:42,980 --> 00:15:49,200 create user API request is sent to the server. The name of the API may sound 162 00:15:49,200 --> 00:15:55,200 straightforward, but I realize it's actually badly named. Let me explain why. 163 00:15:55,620 --> 00:16:02,160 When the API request is sent, the server responds with a long identifier, called 164 00:16:02,160 --> 00:16:09,000 user key. Through my research, I found that this identifier is actually assigned to the device, 165 00:16:09,060 --> 00:16:16,820 and not to the user. And later on, we will discuss this user key identifier more in detail. 166 00:16:17,340 --> 00:16:22,680 For now, just remember, it is associated with the device, and not to the user. 167 00:16:25,620 --> 00:16:30,940 I explained earlier the account registration process, and that the server holds additional 168 00:16:30,940 --> 00:16:34,040 details on the user like his credit card. 169 00:16:34,640 --> 00:16:38,720 And I want to add one more detail, the user key. 170 00:16:38,980 --> 00:16:43,260 The server also identifies accounts by its user key. 171 00:16:44,020 --> 00:16:50,300 But it's important to know that not all the user keys have affiliated accounts, but all 172 00:16:50,300 --> 00:16:52,860 the accounts have affiliated user keys. 173 00:16:54,440 --> 00:16:59,020 Okay, so let's assume there is a device with user key number one. 174 00:16:59,720 --> 00:17:04,500 And for example, this account is linked with phone number one. 175 00:17:05,320 --> 00:17:09,800 Our goal is to hijack this account using the account switching feature. 176 00:17:11,460 --> 00:17:17,840 First, the attacker make a create user API request to obtain user key legitimately. 177 00:17:18,780 --> 00:17:22,360 For example, in this, we get user key number two. 178 00:17:23,520 --> 00:17:29,640 After obtaining the user key, the attacker attempts to join the payment service by pretending 179 00:17:29,640 --> 00:17:36,040 to be the other device, and specifically the phone device with user key number one. 180 00:17:37,140 --> 00:17:43,420 But to complete the registration, the attacker needs to provide the OTP generated by move 181 00:17:43,420 --> 00:17:49,040 it right, and since the attacker doesn't have access to the phone device, they cannot 182 00:17:49,040 --> 00:17:49,820 guess the OTP. 183 00:17:52,660 --> 00:17:55,560 The OTP is actually four digits long. 184 00:17:56,100 --> 00:18:00,800 And this is immediately raised the idea of brute forcing this OTP. 185 00:18:01,060 --> 00:18:06,860 And I know that there is a small chance that it will work, but I decided to give it a shot. 186 00:18:08,060 --> 00:18:12,680 And for my surprise, the brute force attack against the OTP actually worked. 187 00:18:13,020 --> 00:18:18,920 And I could literally go over all the OTP options from zero to 9,099. 188 00:18:19,960 --> 00:18:23,580 And in the worst case, the brute force took me only five minutes. 189 00:18:24,060 --> 00:18:25,060 So let's see. 190 00:18:26,260 --> 00:18:32,560 So we can see the device, the emulator that I connected with my account. 191 00:18:32,940 --> 00:18:38,400 And now I'm executing the brute force script, providing my phone number. 192 00:18:39,320 --> 00:18:44,660 And now the script are trying to guess all the OTP options, as you can see. 193 00:18:46,860 --> 00:18:49,020 And we got the OTP. 194 00:18:49,240 --> 00:18:49,800 Okay. 195 00:18:49,820 --> 00:18:54,020 2014, which immediately disconnected me from the device. 196 00:18:54,460 --> 00:18:55,560 We can see. 197 00:18:56,020 --> 00:19:01,340 And I order a train ticket on behalf of my account. 198 00:19:01,620 --> 00:19:05,300 And now we will see that someone purchased the ticket. 199 00:19:05,520 --> 00:19:07,220 And this was not me. 200 00:19:10,800 --> 00:19:11,480 Cool. 201 00:19:11,580 --> 00:19:16,340 So after the brute force attack, the attacker takes control of the account. 202 00:19:16,680 --> 00:19:19,800 This allows the attacker to complete the OTP. 203 00:19:19,820 --> 00:19:24,600 This allows the attacker to completely impersonate the account and use its credit card to order 204 00:19:24,600 --> 00:19:25,080 tickets. 205 00:19:26,530 --> 00:19:31,180 And furthermore, the attacker gains access to account's personal information. 206 00:19:32,760 --> 00:19:39,360 Also the server will change its affiliation and link the attacker user key to the account 207 00:19:39,360 --> 00:19:41,800 represented by the victim phone number. 208 00:19:44,180 --> 00:19:47,580 So this attack has its pros and its cons. 209 00:19:47,900 --> 00:19:49,440 And on the positive side. 210 00:19:49,440 --> 00:19:52,740 It targets a specific phone number, which can be useful. 211 00:19:53,220 --> 00:19:54,940 But it also has limitation. 212 00:19:55,640 --> 00:20:01,740 It cannot be widely spread, takes time due to the brute force and causes the account 213 00:20:01,740 --> 00:20:02,440 to be disconnected. 214 00:20:05,080 --> 00:20:11,060 The brute force attack is possible approach, but its effectiveness is limited due to the 215 00:20:11,060 --> 00:20:14,120 requirement of having the phone number linked to the account. 216 00:20:14,640 --> 00:20:19,420 So I decided to transform the problem of getting phone number linked to the account into a 217 00:20:19,440 --> 00:20:26,100 user key format to understand the user key format with the goal of enumerating existing 218 00:20:26,620 --> 00:20:26,920 accounts. 219 00:20:28,520 --> 00:20:34,240 So in the next few slides, I will delve into the user key format and I will showcase the 220 00:20:34,240 --> 00:20:36,280 second vulnerability that I found. 221 00:20:36,980 --> 00:20:42,620 So as I mentioned earlier, when the application is open for the first time, a create user 222 00:20:42,620 --> 00:20:44,860 API is sent to the Movit servers. 223 00:20:45,580 --> 00:20:48,160 The server responds with the user key. 224 00:20:48,300 --> 00:20:49,420 And we can see that the user key is not the user key. 225 00:20:49,420 --> 00:20:51,960 You can see the above value is an example for a user key. 226 00:20:52,100 --> 00:20:54,400 It looks like a type of UUID or something. 227 00:20:55,840 --> 00:21:01,280 And if I make the API request multiple times, I can gather a lot of user key samples. 228 00:21:01,720 --> 00:21:06,580 And by analyzing these samples, I will be able to understand the format better. 229 00:21:07,420 --> 00:21:11,660 So I created around 25,000 user keys. 230 00:21:12,360 --> 00:21:16,740 And the keys seem pretty similar as they all started with E4. 231 00:21:17,880 --> 00:21:23,740 And in a brief look, there is a value within the user key, which repeated in each of the 232 00:21:23,740 --> 00:21:23,960 keys. 233 00:21:24,940 --> 00:21:26,980 Maybe this is a known value. 234 00:21:27,400 --> 00:21:29,060 So I searched this on Google. 235 00:21:30,760 --> 00:21:37,660 And I found this Oracle DB function that generates unique identifier with similar value. 236 00:21:38,360 --> 00:21:42,520 In fact, this identifier is not really randomized well. 237 00:21:43,720 --> 00:21:45,740 The function that generates. 238 00:21:46,740 --> 00:21:50,000 These keys doesn't generate a real pseudorandom identifier. 239 00:21:50,600 --> 00:21:51,920 And I will explain why. 240 00:21:52,180 --> 00:21:56,120 And how I managed to identify other devices. 241 00:21:56,980 --> 00:22:04,080 So the documentation on this function shows that this identifier consists of OS identifier, 242 00:22:04,720 --> 00:22:09,220 OS or credit identifier, and a non-repeating value. 243 00:22:09,900 --> 00:22:15,480 And probably the OS identifier is constant value that appears in each of the keys. 244 00:22:15,660 --> 00:22:15,920 So. 245 00:22:15,920 --> 00:22:16,720 Okay. 246 00:22:16,740 --> 00:22:21,100 So let's try to confirm this on each of the user keys that I've collected. 247 00:22:22,960 --> 00:22:27,120 So in a second look, we can see that the user keys are not randomized well. 248 00:22:27,660 --> 00:22:31,160 But there are two parts of the user key that seems pretty random. 249 00:22:33,040 --> 00:22:39,320 But I noticed that the last four bytes of the user key repeat in some user keys. 250 00:22:40,660 --> 00:22:46,720 Additionally, when this repetition happens, there are also four middle bytes that are 251 00:22:46,720 --> 00:22:47,580 that remain the same. 252 00:22:48,560 --> 00:22:54,160 And moreover, these two numbers are the only ones that seems well randomized. 253 00:22:54,600 --> 00:22:59,560 So when this repetition happened, the user keys became almost identical. 254 00:23:00,900 --> 00:23:05,720 Suggesting a relationship between the last four bytes and the middle four bytes. 255 00:23:08,140 --> 00:23:14,040 But brute forcing these two numbers is very difficult due to the large number of combination, 256 00:23:14,360 --> 00:23:14,560 right? 257 00:23:15,400 --> 00:23:16,080 So. 258 00:23:16,080 --> 00:23:18,300 So brute force is not a possible approach in here. 259 00:23:18,600 --> 00:23:19,660 What we can do? 260 00:23:20,660 --> 00:23:25,580 So I sorted all the keys and got so many keys with these matching values. 261 00:23:26,660 --> 00:23:33,860 These keys are almost identical except of the red square, which turned to be sequential. 262 00:23:35,340 --> 00:23:37,420 But I noticed something interesting. 263 00:23:37,800 --> 00:23:45,000 Some of the keys follow a sequence, but there are a few missings, for example, between a0 264 00:23:45,000 --> 00:23:46,060 and a7. 265 00:23:46,060 --> 00:23:47,840 There are six missing keys. 266 00:23:48,480 --> 00:23:54,100 And after looking into it, I realized that those missing keys have already been taken 267 00:23:54,100 --> 00:23:55,200 by other users. 268 00:23:55,760 --> 00:23:56,820 So bingo. 269 00:23:57,160 --> 00:24:03,740 If we will look for those gaps, we could fill those gaps with user keys of other devices, 270 00:24:03,860 --> 00:24:04,020 right? 271 00:24:05,240 --> 00:24:12,520 So we will fill the gaps between a0 to a7, and we know all these missing are actually 272 00:24:12,520 --> 00:24:14,140 belong to other devices. 273 00:24:14,800 --> 00:24:15,480 But. 274 00:24:16,060 --> 00:24:18,460 But what we can do with devices' user key? 275 00:24:20,000 --> 00:24:25,940 So I was looking for an API request to get some more details by providing user key. 276 00:24:26,940 --> 00:24:30,820 And luckily I found the perfect API for this. 277 00:24:32,000 --> 00:24:38,740 To retrieve the users' information, I can use the user profile API by passing the user 278 00:24:38,740 --> 00:24:39,760 key as an argument. 279 00:24:40,440 --> 00:24:46,040 And when I make the request, the server will respond with the details related to the user. 280 00:24:46,040 --> 00:24:54,160 to the user keys. And guess what? If there is an account associated with the user key, 281 00:24:54,320 --> 00:25:01,660 the response will include the account phone number. And if we have a phone number, we 282 00:25:01,660 --> 00:25:08,260 can do brute force, right? So I filmed a demonstration of catching user keys of newly registered 283 00:25:08,260 --> 00:25:14,900 devices and their phone numbers. And I attempted to test if downloading and registering the 284 00:25:14,900 --> 00:25:24,900 payment service would be detected. So let's see. We can see that this is immediately catching 285 00:25:24,900 --> 00:25:34,000 a new, really, customers of movies and their phone numbers. And we will wait to see if 286 00:25:34,000 --> 00:25:39,640 I can catch myself. All these are actually real users. 287 00:25:46,680 --> 00:25:52,800 So as we can see, we caught myself, and this is my phone number, and I actually can attack 288 00:25:52,800 --> 00:26:00,760 myself. So I leave the script to run for two hours, and a few moments later, the script 289 00:26:00,760 --> 00:26:08,880 caught so many accounts, even worldwide accounts. And for each account, I can link a phone number 290 00:26:08,880 --> 00:26:14,880 that belongs to the user. And from now on, we can practically catch the user keys of 291 00:26:14,900 --> 00:26:22,520 all the newly registered customers of Moovit. So we have a lot of phone numbers of accounts 292 00:26:22,520 --> 00:26:28,180 that can be attacked with the brute force. And now we have made the brute force attack 293 00:26:28,180 --> 00:26:34,440 more powerful. We don't need the phone number anymore. Instead, we can go through all the 294 00:26:34,440 --> 00:26:39,640 newly registered customers and attack them. But it still disconnects the account from 295 00:26:39,640 --> 00:26:43,220 the device. And I wanted to improve that also. 296 00:26:44,900 --> 00:26:50,460 So we have a list of user keys and their phone numbers. We want to be able to impersonate 297 00:26:50,460 --> 00:26:56,540 the user without disconnecting them from the device. To do this, we need to understand 298 00:26:56,540 --> 00:27:03,540 how the API request looks from the user's account perspective. So let's see. In the 299 00:27:03,540 --> 00:27:11,460 next slide, we will learn how ticket purchasing works in relation to API requests. We discussed 300 00:27:11,460 --> 00:27:14,620 the brute force attack, which involves hijacking accounts. 301 00:27:15,260 --> 00:27:17,760 We'll learn how to use a brute force attack, which involves hijacking accounts. We'll learn 302 00:27:17,760 --> 00:27:19,260 how to use the brute force attack, which involves hijacking accounts. And we'll learn how 303 00:27:19,260 --> 00:27:27,740 Now, I would like to explore the internals of the API involved. So just a reminder about 304 00:27:27,740 --> 00:27:33,820 the create user API. When the application is first opened, a user key is generated for 305 00:27:33,820 --> 00:27:43,020 the device and requested through this API request. But that's not all. After this API request, 306 00:27:43,280 --> 00:27:44,700 there is something important to know. 307 00:27:45,540 --> 00:27:50,900 We have learned that Moovit stores account information like personal details and credit 308 00:27:50,900 --> 00:27:58,220 card data along to the user key. But there is one more essential requirement we missed. 309 00:27:58,380 --> 00:28:06,440 The access token. Without it, communicating with the servers is impossible. The access 310 00:28:06,440 --> 00:28:13,380 token is generated immediately after the device receives its user key. By sending registered 311 00:28:13,380 --> 00:28:14,880 API requests, the servers receive this user key. Then it sends the remaining access token. 312 00:28:14,900 --> 00:28:22,400 will respond with a temporary token and with this token we can request a verification from 313 00:28:22,400 --> 00:28:30,100 a third party providing the token along with the user key and in exchange google will respond with 314 00:28:30,100 --> 00:28:39,300 the access token so after setting up the access token the application has user key and an access 315 00:28:39,300 --> 00:28:47,140 token allowing us to request more apis for instance without the access token we cannot register for 316 00:28:47,140 --> 00:28:53,480 the payment service which also means that we won't be able to use the api for purchasing new tickets 317 00:28:54,320 --> 00:28:59,360 so now we understand that these two requirements are essential to the api communication 318 00:29:00,360 --> 00:29:07,060 let's go back to the problem the issue is that we have the user key of an existing account 319 00:29:07,740 --> 00:29:09,240 but we don't have 320 00:29:09,300 --> 00:29:16,340 the access token this means that we cannot make api requests on behalf of the account 321 00:29:16,340 --> 00:29:24,360 like ordering a train ticket so in this situation if we use the brute force attack that i explained 322 00:29:24,360 --> 00:29:31,960 earlier the account will be disconnected from the device and associated to other device but we want 323 00:29:31,960 --> 00:29:37,420 to fully impersonate the account without disconnecting it so let's see what we can do 324 00:29:38,240 --> 00:29:39,280 the access token 325 00:29:39,300 --> 00:29:46,260 is actually a jwt as we can see can we forge this token by modifying the payload 326 00:29:47,820 --> 00:29:52,500 so this approach is not possible due to the way jwt works 327 00:29:55,140 --> 00:30:02,880 so what can so we cannot forge jwt do we have another way to get the token so through 328 00:30:02,880 --> 00:30:09,140 this research i've learned that sometimes the simple things will work so i went back to the 329 00:30:09,140 --> 00:30:18,060 creation of the jwt token and we'll we already have a user key of a different account maybe you 330 00:30:18,060 --> 00:30:24,400 can request another token for this user key even though there is an already active token 331 00:30:25,320 --> 00:30:32,660 to do that we need to send register and then verify custom token request so let's see what we 332 00:30:32,660 --> 00:30:37,740 got so that's actually worked there is no validation on the 333 00:30:39,140 --> 00:30:45,220 we could request as much as tokens as we want even though there is an active 334 00:30:45,220 --> 00:30:52,600 token now we can fully impersonate accounts without disconnecting them it's 335 00:30:52,600 --> 00:30:57,780 like it's crazy we actually have the ability to perform all the operation on 336 00:30:57,780 --> 00:31:04,980 behalf of different accounts including ordering tickets additionally we can 337 00:31:04,980 --> 00:31:10,220 access all of their personal information now we have made the 338 00:31:10,220 --> 00:31:15,740 perfect attack without disconnecting the account this attack is quick and doesn't 339 00:31:15,740 --> 00:31:20,700 require a phone number with the information collected through our script 340 00:31:20,700 --> 00:31:26,240 we have the ability to access each of this account and by doing so we can 341 00:31:26,240 --> 00:31:33,780 retrieve their personal information so let's see what we did so I conduct a 342 00:31:33,780 --> 00:31:34,780 proof-of-concept 343 00:31:34,980 --> 00:31:39,520 in which I took each of the user keys and use them to create a database 344 00:31:39,520 --> 00:31:45,180 containing various personal information such their ID email address and so on 345 00:31:47,220 --> 00:31:51,980 using the database I developed a user interface for demonstration purposes 346 00:31:51,980 --> 00:31:59,280 which I then tested on the train station but before the demo isn't a fun fact one 347 00:31:59,280 --> 00:32:03,760 of the code accounts belong to one of the developers that move it they 348 00:32:03,760 --> 00:32:04,960 actually back and develop it 349 00:32:04,980 --> 00:32:06,600 for the time being ما 350 00:32:06,600 --> 00:32:12,220 through a video made for the email address a different user platform 351 00:32:12,220 --> 00:32:16,960 this is the demo this is me in a train station and you can see on the left 352 00:32:16,960 --> 00:32:21,540 side the user interface that I have developed and now I'm selecting the 353 00:32:21,540 --> 00:32:27,900 source station and the account that I want to pay on my ride and in 354 00:32:27,900 --> 00:32:34,900 exchange I'm getting a ticket which someone else paid me and I'm easily 355 00:32:34,900 --> 00:32:38,700 passing the gates thank you 356 00:32:44,580 --> 00:32:50,960 okay so the takeaways even big companies can fall victim to simple attacks showing 357 00:32:50,960 --> 00:32:56,880 the need for increased awareness and attention to basic security measures and 358 00:32:56,880 --> 00:33:04,800 also I want to understand the research perspective turning challenges into a 359 00:33:04,800 --> 00:33:12,600 opportunities and using limitations for positive results we conduct we connected 360 00:33:12,600 --> 00:33:18,380 with move it and responsibly disclose all the vulnerabilities and all of them 361 00:33:18,380 --> 00:33:24,900 have been fixed and no customer action is required also all the scripts that I 362 00:33:24,900 --> 00:33:30,900 use throughout this research push push to this github repository and you are 363 00:33:30,900 --> 00:33:34,480 more than welcome to take a look and I want 364 00:33:34,480 --> 00:33:34,720 to 365 00:33:34,800 --> 00:33:40,700 thank more corn for helping me a lot throughout this research thank you and I 366 00:33:40,700 --> 00:33:42,840 want to thank you for joining thank you