the home site for me: also iteration 3 or 4 of my site
1+++
2title = "Hilton Tomfoolery"
3date = 2024-10-13
4slug = "hilton-tomfoolery"
5description = "Playing around with mitmproxy and the Hilton Honors app as well as a flipper zero"
6
7[taxonomies]
8tags = ["reverse engineering", "hilton"]
9+++
10
11I'm at a Hilton at the time of writing this, and I'm decently bored. Currently, I'm downloading the latest version of RogueMaster (0.420.0) to my flipper, as it is currently crashing every time I open the NFC app. My dad tried out the app unlock feature in the Hilton app for the first time today, which, as most new tech things, made me quite curious how it worked and whether I could break it. Based on playing with it, there seems to be a proximity reading (over Bluetooth? Perhaps a BLE beacon?) to detect if you are by your door but for a period of time (~20 sec) after getting that signal it allows you to unlock the door from across the room which I'm guessing means that it controls the locks via a central server. The current plan is to install the root cert (of mitmproxy) on my iPhone and then try and intercept those API calls and see if we can manipulate them in any interesting ways. I'm also planning on live blogging this, which I've never tried before. (I also wrote this whole article in vim ^_^)
12
13<!-- more -->
14
15## Connecting to Mitmproxy
16
17I'm connecting over WireGuard, so I fired up mitmproxy with `mitmweb --mode wireguard` on my laptop. Connecting via WireGuard theoretically is pretty simple; all I need to do is to scan a qr code and connect. Unfortunately, the hotel Wi-Fi seems to be oddly segmented, and I can't access the WireGuard server or ping my laptop from my phone. I'm going to try firing up a hot spot on my dad's phone and see if that allows me to talk to my phone.
18
19{caption="You have to dig through several menus to trust it"}
20
21I messed with getting my laptop to connect to my dad's phone, but it kept refusing for some reason. My next idea is to ngrok the WireGuard tunnel, which ended up failing because ngrok doesn't support UDP. Finally, after an embarrassingly long time, I realized that I could simply use `ngrok tcp 8080` and the HTTP proxy server built into mitmproxy instead. After installing the root certificate and trusting it in the iPhone settings, we were good to go!
22
23## Digging around in the Hilton Honors app
24
25First I had to download the app, which required disabling the proxy as iOS seems to ignore certificate trust settings for the app store. Enrollment happened via the `https://m.hilton.io/graphql/customer?operationName=createGuest&type=enroll` endpoint and was as follows:
26
27> POST
28```json
29{
30 "query": "...",
31 "variables": {
32 "input": {
33 "email": {
34 "emailAddress": "xxxx-xxxx-xxxx@duck.com"
35 },
36 "preferredLanguage": "EN",
37 "enrollSourceCode": "IOSEW",
38 "phone": {
39 "phoneNumber": "xxxxxxxxxx",
40 "phoneType": "home"
41 },
42 "subscriptions": {
43 "hhonorsSubscriptions": [],
44 "optOuts": {
45 "survey": false,
46 "marketing": false
47 }
48 },
49 "name": {
50 "firstName": "Kieran",
51 "lastName": "Klukas"
52 },
53 "address": {
54 "city": "Washington",
55 "addressType": "home",
56 "addressLine2": null,
57 "postalCode": "20003",
58 "state": "DC",
59 "addressLine1": "1600 Pennsylvania Ave SE Apartments",
60 "country": "US"
61 },
62 "privacyRequested": false,
63 "password": "xxxxxxxxxxxxxxxxxxxxxxxxxxx"
64 },
65 "language": "en_US"
66 },
67 "operationName": "createGuest"
68}
69```
70```bash
71---
72mutation createGuest($input: EnrollInput!, $language: String!) {
73 createGuest(language: $language, input: $input) {
74 data {
75 guestId
76 hhonorsNumber
77 }
78 error {
79 code
80 context
81 message
82 notifications {
83 code
84 fields
85 message
86 }
87 }
88 }
89}
90```
91<br/>
92
93> response
94
95```json
96{
97 "data": {
98 "createGuest": {
99 "data": {
100 "guestId": 1726240000,
101 "hhonorsNumber": "225782xxxx"
102 },
103 "error": null
104 }
105 },
106 "extensions": {
107 "logSearch": "mdc.client_message_id=51da35305bde9b71e7faa2993ebc2a619e50c598-iap71t195vk6jur6eyd83hy9g21w4bzam"
108 }
109}
110```
111<br/>
112
113> headers
114
115```json
116{
117 "access_token": "DX.eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkEyNTZHQ00iLCJwaWQiOiJtb2JpbGUiLCJraWQiOiJWTktOaU9WLTZ4c2cyOXQ2dEJUMmR5Nnl1TEJPUG8tb2FycDFpZzZnVWdZIn0.Yfxkp8Jnrwttmrp_QcMTp6HwW2yBzEIROsAjheNVd3LgIWBQVfw5UDstAd7qA3MKZffoKSf7SbkopJhWIr-vreOYQ2BZEf2a9DYm4p-tD9jXEMsuVY9offYqjRzyeWwcjLyWq9ubnUBpQuCHMNUO1025BZkNV3NYG3_LZfJlNc77aMawrfS52zi5I5hSL0zAs3K7kxYuReJEC-RzASt-coPHEmdkmDp1TLqujqe8Opy6z4DC8xFDFkO09J-tN6RwolJ6jtssr0vnFyCv9zw_lbAQppB0jbWZqxiEmNk_krC4laOsChe3bUJc8ECeKltvqgVnSAKAhz-zBfy9EbFeew.Wki3N1rclvnjMfA4.dtWVnkpMJZixW86Q9hiiBY30_Oa1NHPLM_SuuAjtTrY-QZilp5tgu7COJtiVYI51_j6nIOHdX2oI0EoiHaPhzC4YizFxNbZsUfpR0W6wPVWj3LpdTr23GMhoOga5UTFCbaehb5XCsWr9PLfnLc2tSGyi4wZOSGrSidQUCDQ6UssUTxt6vvlp5y623EbvkMEi-ok6IXqUnYgsztcz_i14GKRHdRmJZFACJj3X0zQLarN4b19KEwvqIXfIrpPWpr1f74ozamM6CUEQhqoF61cucKCxKf0hU7kAyMduo4l3OfEkghQUfrlfA1D7eoInyPcOb8a3_LjQhGXwh1XVoElXUriuP7yEOfyksv59_pKCWajzJuyWdEl164OZXAFmMkdQ89flDO3_nRZUliMXapnWkU3WDBGD_gQ49sYbxlAh95l0HiJeKZwf2g4DTlEb6ccauRAbUzD2Fopoe2ldMXL-wBkVg2Grx8SfaCnOCiyfGq2HloJMf-8YRz-tWQoTXFEM30KdJCWY70sUTY9LeWVQrz4dnpZlRk29KyNi20YsdQRK3y9_ZFL0qs4IJwhddtrhzQVKz6oaxDPgQxy2vK1DErers-8-oJ3WgDho9l9D7Z7U9C1spjf1IIBG5hvdtCiExqh78fFsizcvkG9oeHB09Z1oGU3jL_cUFKrrUp9ZXnOKlwU1BjFPrOjVVZi97-rVN3IjvlRjJCBfFCf2CxlbZcib_CWSiD0vtFsloClkmSho2ynnbLQG341SibvaO4TKygttS-NsluDjBtpuJydlNjDAXO6ZvWRiFWcHDrDqiBeo897yUM40kHYFXBpjhbiIDcCnAJu6GDozbacnGsEGOJlauASm3t8TFn1lPd_kQgd3Uy2fDtTCKxxSaXA4RvHwUbBgYWU4SMA7UPYn_RygkxUZ0UL4ZHfN1-bDpkQ16DLm0Q.hh53MImM9BA7Ujib61RUOg",
118 "exp": 1728879203,
119 "expires_in": 3600,
120 "iat": 1728875603,
121 "scope": "am_application_scope default",
122 "token_type": "Bearer"
123}
124```
125
126At this point I went to bed as it was about 23:30, but I set my alarm for 5:30 (if you know me I never get up before 8:00, so this is rare) and actually managed to wake-up on time. It's always quite curious how excitement and a new place can cause you to wake-up earlier. Unfortunately, while I was sleeping my laptop died which caused me to lose the rest of the signup data. I'm going to invite myself to get the room key and see what API requests that triggers, and then try actually unlocking the door.
127
128# Invitation
129
130> Hi Kieran,
131> I’m sharing my Digital Key so you can use your phone as a room key.
132> If you already have the Hilton Honors app make sure you are on the latest version and click this https://hiltonhonors3.hilton.com/rs/hilton-honors-mobile-app?shareId=b4d6140d311e4c4c935dd653ca00af65 to accept the Digital Key.
133> If you don’t have the Hilton Honors app, download it using the link above and return to this message to accept within 8 hours to get your key.
134> See you soon,
135> xxxx xxxx
136
137I shared the key which asked for a name and then opened the iOS share sheet and I choose to send by text (it sent the above message). I went back to my phone, clicked the link and low and behold we got a hit! `https://hms.hiltonapi.com/hms/v1/digitalkey/invitation/accept`:
138
139> POST
140```json
141{
142 "shareId": "b4d6140d311e4c4c935dd653ca00af65"
143}
144```
145
146<br/>
147
148> response
149```json
150{
151 "arrivalDateTime": "2024-10-13T15:00-04:00",
152 "confirmationNumber": "5448xxxx",
153 "ctyhocn": "GCYPAHX",
154 "departureDateTime": "2024-10-14T11:00-04:00",
155 "hotelName": "Hampton Inn & Suites Grove City",
156 "stayId": "296088xxxx"
157}
158```
159
160Another interesting request was to `https://m.hilton.io/graphql/customer?operationName=hotel_brand&type=hotelDetails_GCYPAHX`
161
162> POST
163```json
164{
165 "variables": {
166 "ctyhocn": "GCYPAHX",
167 "language": "en-US"
168 },
169 "operationName": "hotel_brand",
170 "query": "..."
171}
172```
173```bash
174---
175query hotel_brand($language: String!, $ctyhocn: String!) {
176 hotel(language: $language, ctyhocn: $ctyhocn) {
177 address {
178 addressFmt
179 addressLine1
180 addressLine2
181 city
182 country
183 countryName
184 postalCode
185 state
186 }
187 alerts {
188 description
189 type
190 }
191 amenities {
192 id
193 name
194 }
195 attributes {
196 numberOfRestaurants
197 }
198 brand {
199 isPartnerBrand
200 }
201 brandCode
202 campus {
203 type
204 }
205 chainCode
206 checkin {
207 checkinTimeFmt
208 checkinTime
209 checkoutTimeFmt
210 checkoutTime
211 digitalKey
212 }
213 config {
214 checkout {
215 allowDCO
216 }
217 connectedRoom {
218 crEnabled
219 crFullyEnabled
220 emsEnabled
221 }
222 messaging {
223 kipsuEnabled
224 messagingTileEnabled
225 gatewayRoutingEnabled
226 }
227 adjoiningRooms {
228 active
229 }
230 }
231 coordinate {
232 latitude
233 longitude
234 }
235 crsData {
236 adultAge
237 ageBasedPricing
238 acceptedCreditCards
239 }
240 ctyhocn
241 currencyCode
242 display {
243 treatments
244 }
245 gmtHours
246 internetAddress
247 name
248 phoneNumber
249 policyOptions {
250 label
251 value
252 options {
253 label
254 value
255 }
256 }
257 facilityOverview {
258 shortDesc
259 }
260 images {
261 master {
262 altText
263 url(height: 430, width: 612)
264 }
265 gallery {
266 image(variant: searchPropertyImageThumbnail) {
267 altText
268 url(height: 430, width: 612)
269 }
270 masterImage
271 }
272 carousel {
273 altText
274 url(height: 430, width: 612)
275 }
276 }
277 }
278}
279```
280
281<br/>
282
283> response
284```json
285{
286 "data": {
287 "hotel": {
288 "address": {
289 "addressFmt": "4 Holiday Blvd., Mercer, Pennsylvania, 16137, USA",
290 "addressLine1": "4 Holiday Blvd.",
291 "addressLine2": null,
292 "city": "Mercer",
293 "country": "US",
294 "countryName": "USA",
295 "postalCode": "16137",
296 "state": "PA"
297 },
298 "alerts": [
299 {
300 "description": "The hotel will be undergoing exterior renovations September 03, 2024 - December 31, 2024. The interior and guestrooms will be unaffected. Thank you for your patience and understanding.",
301 "type": "alert"
302 }
303 ],
304 "amenities": [
305 {
306 "id": "adjoiningRooms",
307 "name": "Connecting Rooms"
308 },
309 {
310 "id": "freeBreakfast",
311 "name": "Free hot breakfast"
312 },
313 {
314 "id": "freeParking",
315 "name": "Free parking"
316 },
317 {
318 "id": "freeWifi",
319 "name": "Free WiFi"
320 },
321 {
322 "id": "nonSmoking",
323 "name": "Non-smoking rooms"
324 },
325 {
326 "id": "digitalKey",
327 "name": "Digital Key"
328 },
329 {
330 "id": "evCharging",
331 "name": "EV charging"
332 },
333 {
334 "id": "indoorPool",
335 "name": "Indoor pool"
336 },
337 {
338 "id": "fitnessCenter",
339 "name": "Fitness center"
340 },
341 {
342 "id": "petsAllowed",
343 "name": "Pet-friendly rooms"
344 },
345 {
346 "id": "meetingRooms",
347 "name": "Meeting rooms"
348 }
349 ],
350 "attributes": {
351 "numberOfRestaurants": 0
352 },
353 "brand": {
354 "isPartnerBrand": false
355 },
356 "brandCode": "HP",
357 "campus": {
358 "type": "enhanced"
359 },
360 "chainCode": "HH",
361 "checkin": {
362 "checkinTime": "15:00",
363 "checkinTimeFmt": "3:00 PM",
364 "checkoutTime": "11:00",
365 "checkoutTimeFmt": "11:00 AM",
366 "digitalKey": true
367 },
368 "config": {
369 "adjoiningRooms": {
370 "active": true
371 },
372 "checkout": {
373 "allowDCO": true
374 },
375 "connectedRoom": null,
376 "messaging": {
377 "gatewayRoutingEnabled": true,
378 "kipsuEnabled": true,
379 "messagingTileEnabled": true
380 }
381 },
382 "coordinate": {
383 "latitude": 41.142354,
384 "longitude": -80.164956
385 },
386 "crsData": {
387 "acceptedCreditCards": [
388 "CU",
389 "VI",
390 "MC",
391 "AX",
392 "DS",
393 "DC",
394 "CB"
395 ],
396 "adultAge": null,
397 "ageBasedPricing": null
398 },
399 "ctyhocn": "GCYPAHX",
400 "currencyCode": "USD",
401 "display": {
402 "treatments": []
403 },
404 "facilityOverview": {
405 "shortDesc": "We're off I-79, 10 minutes from Grove City. Grove City Premium Outlets and Wendell August Forge, America's oldest and largest working forge, are less than a mile away. Both Grove City College and Slippery Rock University are within 20 minutes of us. Enjoy free hot breakfast, free WiFi, and our indoor pool and hot tub."
406 },
407 "gmtHours": -4,
408 "images": {
409 "carousel": [
410 {
411 "altText": "Outdoor Patio",
412 "url": "https://www.hilton.com/im/en/GCYPAHX/2888809/gcypahx-patio.jpg?impolicy=resize&rh=430&rw=612"
413 },
414 {
415 "altText": "Double Queen",
416 "url": "https://www.hilton.com/im/en/GCYPAHX/4248848/hampton-grove-city-standard-queen-1-preview.jpg?impolicy=resize&rh=430&rw=612"
417 },
418 {
419 "altText": "King Standard",
420 "url": "https://www.hilton.com/im/en/GCYPAHX/4248016/hampton-grove-city-king-standard-1.jpg?impolicy=resize&rh=430&rw=612"
421 },
422 {
423 "altText": "Lobby and Dining Area",
424 "url": "https://www.hilton.com/im/en/GCYPAHX/2887422/lobby-1.jpg?impolicy=resize&rh=430&rw=612"
425 },
426 {
427 "altText": "Lobby",
428 "url": "https://www.hilton.com/im/en/GCYPAHX/2887224/lobby-2.jpg?impolicy=resize&rh=430&rw=612"
429 },
430 {
431 "altText": "Breakfast Buffet",
432 "url": "https://www.hilton.com/im/en/GCYPAHX/2880542/breakfast-1.jpg?impolicy=resize&rh=430&rw=612"
433 },
434 {
435 "altText": "Indoor Pool",
436 "url": "https://www.hilton.com/im/en/GCYPAHX/4258295/hampton-new-pics-2008-035.jpg?impolicy=resize&rh=430&rw=612"
437 },
438 {
439 "altText": "Fitness Center",
440 "url": "https://www.hilton.com/im/en/GCYPAHX/2883297/fitness.jpg?impolicy=resize&rh=430&rw=612"
441 },
442 {
443 "altText": "Boardroom",
444 "url": "https://www.hilton.com/im/en/GCYPAHX/2879933/board-room.jpg?impolicy=resize&rh=430&rw=612"
445 },
446 {
447 "altText": "Meeting Room",
448 "url": "https://www.hilton.com/im/en/GCYPAHX/2888194/meeting.jpg?impolicy=resize&rh=430&rw=612"
449 },
450 {
451 "altText": "Hotel Exterior at Night",
452 "url": "https://www.hilton.com/im/en/GCYPAHX/4251655/exterior-night.jpg?impolicy=resize&rh=430&rw=612"
453 },
454 {
455 "altText": "Business Center",
456 "url": "https://www.hilton.com/im/en/GCYPAHX/2881016/business-center.jpg?impolicy=resize&rh=430&rw=612"
457 }
458 ],
459 "gallery": [
460 {
461 "image": {
462 "altText": "Outdoor Patio",
463 "url": "https://www.hilton.com/im/en/GCYPAHX/2888809/gcypahx-patio.jpg?impolicy=resize&rh=430&rw=612"
464 },
465 "masterImage": true
466 },
467 {
468 "image": {
469 "altText": "Double Queen",
470 "url": "https://www.hilton.com/im/en/GCYPAHX/4248848/hampton-grove-city-standard-queen-1-preview.jpg?impolicy=resize&rh=430&rw=612"
471 },
472 "masterImage": false
473 },
474 {
475 "image": {
476 "altText": "King Standard",
477 "url": "https://www.hilton.com/im/en/GCYPAHX/4248016/hampton-grove-city-king-standard-1.jpg?impolicy=resize&rh=430&rw=612"
478 },
479 "masterImage": false
480 },
481 {
482 "image": {
483 "altText": "Lobby and Dining Area",
484 "url": "https://www.hilton.com/im/en/GCYPAHX/2887422/lobby-1.jpg?impolicy=resize&rh=430&rw=612"
485 },
486 "masterImage": false
487 },
488 {
489 "image": {
490 "altText": "Lobby",
491 "url": "https://www.hilton.com/im/en/GCYPAHX/2887224/lobby-2.jpg?impolicy=resize&rh=430&rw=612"
492 },
493 "masterImage": false
494 },
495 {
496 "image": {
497 "altText": "Breakfast Buffet",
498 "url": "https://www.hilton.com/im/en/GCYPAHX/2880542/breakfast-1.jpg?impolicy=resize&rh=430&rw=612"
499 },
500 "masterImage": false
501 },
502 {
503 "image": {
504 "altText": "Indoor Pool",
505 "url": "https://www.hilton.com/im/en/GCYPAHX/4258295/hampton-new-pics-2008-035.jpg?impolicy=resize&rh=430&rw=612"
506 },
507 "masterImage": false
508 },
509 {
510 "image": {
511 "altText": "Fitness Center",
512 "url": "https://www.hilton.com/im/en/GCYPAHX/2883297/fitness.jpg?impolicy=resize&rh=430&rw=612"
513 },
514 "masterImage": false
515 },
516 {
517 "image": {
518 "altText": "Boardroom",
519 "url": "https://www.hilton.com/im/en/GCYPAHX/2879933/board-room.jpg?impolicy=resize&rh=430&rw=612"
520 },
521 "masterImage": false
522 },
523 {
524 "image": {
525 "altText": "Meeting Room",
526 "url": "https://www.hilton.com/im/en/GCYPAHX/2888194/meeting.jpg?impolicy=resize&rh=430&rw=612"
527 },
528 "masterImage": false
529 },
530 {
531 "image": {
532 "altText": "Hotel Exterior at Night",
533 "url": "https://www.hilton.com/im/en/GCYPAHX/4251655/exterior-night.jpg?impolicy=resize&rh=430&rw=612"
534 },
535 "masterImage": false
536 },
537 {
538 "image": {
539 "altText": "Business Center",
540 "url": "https://www.hilton.com/im/en/GCYPAHX/2881016/business-center.jpg?impolicy=resize&rh=430&rw=612"
541 },
542 "masterImage": false
543 },
544 {
545 "image": {
546 "altText": "Indoor Pool / Whirlpool",
547 "url": "https://www.hilton.com/im/en/GCYPAHX/2885342/pool.jpg?impolicy=resize&rh=430&rw=612"
548 },
549 "masterImage": false
550 },
551 {
552 "image": {
553 "altText": "Double Queen Studio",
554 "url": "https://www.hilton.com/im/en/GCYPAHX/4250170/hampton-new-pics-2008-020.jpg?impolicy=resize&rh=430&rw=612"
555 },
556 "masterImage": false
557 },
558 {
559 "image": {
560 "altText": "Whirlpool Suite",
561 "url": "https://www.hilton.com/im/en/GCYPAHX/4251204/whirlpool-king-suite-one-2-2-.jpg?impolicy=resize&rh=430&rw=612"
562 },
563 "masterImage": false
564 },
565 {
566 "image": {
567 "altText": "Breakfast Area",
568 "url": "https://www.hilton.com/im/en/GCYPAHX/2880342/breakfast-2.tif?impolicy=resize&rh=430&rw=612"
569 },
570 "masterImage": false
571 },
572 {
573 "image": {
574 "altText": "Suite Shop",
575 "url": "https://www.hilton.com/im/en/GCYPAHX/2890823/gift-shop.jpg?impolicy=resize&rh=430&rw=612"
576 },
577 "masterImage": false
578 },
579 {
580 "image": {
581 "altText": "Hotel Exterior",
582 "url": "https://www.hilton.com/im/en/GCYPAHX/390670/gcypahx-hampton-exterior-night-1.jpg?impolicy=resize&rh=430&rw=612"
583 },
584 "masterImage": false
585 },
586 {
587 "image": {
588 "altText": "Hotel Exterior",
589 "url": "https://www.hilton.com/im/en/GCYPAHX/4255766/hampton-new-pics-2008-012.jpg?impolicy=resize&rh=430&rw=612"
590 },
591 "masterImage": false
592 },
593 {
594 "image": {
595 "altText": "Double Queen Suite",
596 "url": "https://www.hilton.com/im/en/GCYPAHX/4251117/double-queen-standard-2-.jpg?impolicy=resize&rh=430&rw=612"
597 },
598 "masterImage": false
599 }
600 ],
601 "master": {
602 "altText": "Outdoor Patio",
603 "url": "https://www.hilton.com/im/en/GCYPAHX/2888809/gcypahx-patio.jpg?impolicy=resize&rh=430&rw=612"
604 }
605 },
606 "internetAddress": "https://www.hilton.com/en/hotels/gcypahx-hampton-suites-grove-city/",
607 "name": "Hampton Inn & Suites Grove City",
608 "phoneNumber": "+1 724-748-5744",
609 "policyOptions": [
610 {
611 "label": "Cancellation",
612 "options": [
613 {
614 "label": "Description",
615 "value": "Cancellation policies may vary depending on the rate or dates of your reservation. Please refer to your reservation confirmation to verify your cancellation policy. If you need further assistance, call the hotel directly or contact <a href=https://help.hilton.com/s/>customer service</a>. Alternatively, you can <a href=https://www.hilton.com/en/book/reservation/find/>cancel your reservation online</a>."
616 }
617 ],
618 "value": null
619 },
620 {
621 "label": "Check-in/Check-out",
622 "options": [
623 {
624 "label": "Checkin Time",
625 "value": "3:00 PM"
626 },
627 {
628 "label": "Checkout Time",
629 "value": "11:00 AM"
630 },
631 {
632 "label": "Early Departure Fee",
633 "value": null
634 },
635 {
636 "label": "Late Checkout Fee",
637 "value": null
638 },
639 {
640 "label": "Minimum Age To Register",
641 "value": "21"
642 }
643 ],
644 "value": null
645 },
646 {
647 "label": "Wi-Fi",
648 "options": [
649 {
650 "label": "Description",
651 "value": "Standard In-Room and Lobby Wi-Fi - All guests get free standard Wi-Fi in-room and in the lobby."
652 }
653 ],
654 "value": null
655 },
656 {
657 "label": "Parking",
658 "options": [
659 {
660 "label": "Covered",
661 "value": "Not Available"
662 },
663 {
664 "label": "In Out Privileges",
665 "value": "Not Available"
666 },
667 {
668 "label": "Other Parking Information",
669 "value": "Parking Lot"
670 },
671 {
672 "label": "Secured",
673 "value": "Not Available"
674 },
675 {
676 "label": "Self Parking",
677 "value": "$0.00 Complimentary"
678 },
679 {
680 "label": "Valet Parking",
681 "value": "Not Available"
682 }
683 ],
684 "value": null
685 },
686 {
687 "label": "Payment",
688 "options": [
689 {
690 "label": "Hotel Currency",
691 "value": "US Dollar"
692 },
693 {
694 "label": "Accepted Payment Options",
695 "value": "American Express, Carte Blanche, China Union Pay, Diner's Club, Discover, MasterCard, Visa"
696 }
697 ],
698 "value": null
699 },
700 {
701 "label": "Pets",
702 "options": [
703 {
704 "label": "Deposit",
705 "value": "$50.00 Non-Refundable"
706 },
707 {
708 "label": "Kennel Message",
709 "value": null
710 },
711 {
712 "label": "Maximum Size",
713 "value": null
714 },
715 {
716 "label": "Maximum Weight",
717 "value": null
718 },
719 {
720 "label": "Other Pet Services",
721 "value": "$50(1-4n),$75(5+n) 2petsMax,dog/cat only"
722 },
723 {
724 "label": "Pets Allowed",
725 "value": "Yes"
726 },
727 {
728 "label": "Service Animals Allowed",
729 "value": "Yes"
730 }
731 ],
732 "value": null
733 },
734 {
735 "label": "Smoking",
736 "options": [
737 {
738 "label": "Indicator",
739 "value": "Non-Smoking"
740 },
741 {
742 "label": "Description",
743 "value": null
744 }
745 ],
746 "value": null
747 }
748 ]
749 }
750 },
751 "extensions": {
752 "logSearch": "mdc.client_message_id=51da35305bde9b71e7faa2993ebc2a619e50c598-uauhdwbaydoqbvy3uvuzai20c4takt22"
753 }
754}
755```
756
757It appears that Hilton relies very heavily on GraphQL, which is interesting. I would be interested in playing with those APIs more. For now, though, onto unlocking stuff!
758
759## Locks
760
761{caption="What it looks like in the app"}
762
763When using the unlock button, it made a request to this URL: `https://smetric.hilton.com/b/ss/hiltonglobalprod/10/IOSN030200030900/s65425920` with a payload of a URL encoded form.
764
765> POST
766```yaml
767ndh: 1
768cid.:
769card_no.:
770as: 0
771id: 2257829743
772.card_no:
773hhid.:
774as: 1
775id: 2257829743
776.hhid:
777.cid:
778aamb: j8Odv6LonN4r3an7LhD3WZrU1bUpAkFkkiY1ncBR96t2PTI
779aamlh: 7
780c.:
781a.:
782AppID: HHonors 2024.10.1 (1)
783CarrierName: --
784DeviceName: iPhone14,4
785OSVersion: iOS 18.1
786Resolution: 1125x2436
787RunMode: Application
788TimeSinceLaunch: 24560
789action: digital key:key:unlock_btn
790.a:
791hm.:
792app.:
793name: HHonors iOS Mobile
794.app:
795digitalkeyflag: Yes
796event.:
797element.:
798click: digital key:key:unlock_btn
799.element:
800key.:
801unlock.:
802initiate: 1
803.unlock:
804.key:
805.event:
806flag.:
807appsettings: N|N|NA|N|Y|Y|Y|Y|Y|NA|UsingApp|N|
808orientation: L
809stay.:
810level.:
811status: In-Stay
812.level:
813.stay:
814timeCaptureAEP: 2024-10-14T09:59:44.676Z
815timeCaptureEpoch: 1728899984
816timeCaptureISO: 2024-10-14T05:59:44-0400
817.flag:
818hotel.:
819brand: HP
820propertycode: GCYPAHX
821.hotel:
822key.:
823gnr: 79125065
824locktype: guest
825lsn: 92044507
826shared.:
827flag: Yes
828.shared:
829.key:
830page.:
831name:
832previous: App:EN:Honors:Digital Key:Key
833.page:
834purchase.:
835booking.:
836dates: 10132024:10142024:1
837.booking:
838bookingid: 54486330
839.purchase:
840site.:
841type: PA
842.site:
843user.:
844aam.:
845segments: 15218869,26458327,19493122,21537957,22516131,17952857,23583601,17952894,19484989,21539153,22889861,21539313,26458383,21881915,15217574
846.aam:
847language: en
848login.:
849status: Logged-in
850.login:
851memberId: 2257829743
852stayid: 2960880196
853tierpoints: Member
854.user:
855.hm:
856.c:
857ce: UTF-8
858cp: foreground
859d.ptfm: ios
860mid: 61621496110939688115558742623055817571
861pageName: HHonors 2024.10.1 (1)
862pe: lnk_o
863pev2: AMACTION:digital key:key:unlock_btn
864products: ;GCYPAHX;;;;
865t: 00/00/0000 00:00:00 0 240
866ts: 1728899984
867```
868
869<br/>
870
871> response
872```json
873 {
874 "stuff":[ {
875 "cn":"TMS","cv":"web=17836315,Web-app=15217574,Web-app=17952857,Web-app=17952894,web-app=19493122,web-app=19484989,web-app=21539153,web-app=21539313,web-app=21881915,web-app=22516131,web-app=22889861,web-app=23583601,web-app=15218869,web-app=26458327,web-app=26458383,web-app=21537957","ttl":30,"dmn":""
876 }
877 , {
878 "cn":"fltk","cv":"segID=15218869","ttl":30,"dmn":""
879 }
880 ],"uuid":"61645808922583835885560882535048239660","dcs_region":7,"tid":"RufgJCfxTjg="
881}
882```
883
884About a second afterward, I get a second request to `https://smetric.hilton.com/b/ss/hiltonglobalprod/10/IOSN030200030900/s88785229` with similar form data. Diff shown below.
885
886> POST.diff
887```diff
88823c23
889< action: digital key:key:unlock_btn
890---
891> action: digital key:key:unlock:unlock_success
89231,33d30
893< element.:
894< click: digital key:key:unlock_btn
895< .element:
89636c33
897< initiate: 1
898---
899> success: 1
90048,50c45,47
901< timeCaptureAEP: 2024-10-14T09:59:44.676Z
902< timeCaptureEpoch: 1728899984
903< timeCaptureISO: 2024-10-14T05:59:44-0400
904---
905> timeCaptureAEP: 2024-10-14T09:59:45.537Z
906> timeCaptureEpoch: 1728899985
907> timeCaptureISO: 2024-10-14T05:59:45-0400
90879c76
909< segments: 15218869,26458327,19493122,21537957,22516131,17952857,23583601,17952894,19484989,21539153,22889861,21539313,26458383,21881915,15217574
910---
911> segments: 21537957,22889861,23583601,15218869,17952857,21881915,21539313,22516131,19484989,26458383,19493122,17952894,15217574,21539153,26458327
91297c94
913< pev2: AMACTION:digital key:key:unlock_btn
914---
915> pev2: AMACTION:digital key:key:unlock:unlock_success
916100c97,99
917< ts: 1728899984
918---
919> ts: 1728899985
920>
921> *:8080mitmproxy 10.4.2
922```
923<br/>
924
925> response.diff
926```diff
927< ],"uuid":"61645808922583835885560882535048239660","dcs_region":7,"tid":"RufgJCfxTjg="
928---
929> ],"uuid":"61645808922583835885560882535048239660","dcs_region":7,"tid":"69dMPcWjQD4="
930```
931
932Replaying either of the requests does nothing except give a new `tid` value but doesn't unlock the door. The `sxxxxxxx` part of the request URL also changes on every new request and doesn't seem to match any discernible pattern. The `IOSN030200030900` part never changes, however. My guess is that that part is a hotel reference ID. From doing some ducking around online, I couldn't find any references to the `smetric.hilton.com` domain, but it was blocked by uBlock Origin as part of the [EasyPrivacy](https://easylist.to/#easyprivacy) block list. The app also seems to issue requests to this URL.
933
934## Wrap up
935
936{{ img(id="https://hc-cdn.hel1.your-objectstorage.com/s/v3/4e9bfb28c266eb29cea1568cedd3573be2ba1f97_1bluetooth-scan.png" alt="screenshot of bluetooth scan" caption="The bluetooth scan of (what i believe is) the lift") }}
937
938I tried running a Bluetooth scan to see if I could find the locks, but nothing popped out as being a likely culprit. I did however find an interesting set of 3 Bluetooth devices named "clearsky smart fleet" which upon research seems to be scissor lifts / construction equipment made by a company called [JLG](https://smartfleet.jlg.com/) which is quite interesting. That would make sense, however, as I saw several scissor lifts outside the hotel on my way in.
939
940{{ img(id="https://hc-cdn.hel1.your-objectstorage.com/s/v3/993ad810e42289ad3aaefa4093ede271a4ee1d12_0img_2781.jpg" alt="image of JLG lift" caption="The same (probably) JLG lift in the wild!") }}
941
942By the time I'm writing this it's 6:41, and I need to eat breakfast, so I'll probably finish this post in the car this afternoon. Overall this was a fascinating experiment and while I sadly did fail at unlocking doors from my laptop I do feel more confident with reverse engineering app requests now! The next step would probably be to grab the app bundle and try to decompile it looking for the URLs we saw, but I don't have a mac on me, and I've never done that before. Next post?
943
944Taking inspiration from the [LOW←TECH MAGAZINE](https://solar.lowtechmagazine.com/) I will be taking any questions / comments about this article via email and then posting them here to my site! If you have a question or comment, feel free to email me at [me@dunkirk.sh](mailto://me@dunkirk.sh). Now to go eat breakfast :)
945
946{caption="A delicious waffle, mildy warm bacon, and under seasoned potatoes."}