iOS detect mock locations
Asked Answered
P

6

17

Currently I'm working on an App which geolocation capabilities are its most important feature. Actually we're very concerned about getting GPS values mocked up. I've read a lot of comments regarding mocking locations on both iOS and Android and most of them tend to explain an unjailbroken iOS device can't mock locations, but the truth is I've created another project, with a GPX file to mock up location on that project and when executed, the entire system believes I'm in another city. All my locationManager callbacks tell me I'm on the mocked location with the proper timestamp, faking the entire information like it was real. That breaks entirely the purpose of our App, as the user can fake where has been.

Is there any way to detect this behaviour and prevent it? I'm assuming a closed target, the attacker must be a developer in order to this exploit to work, but alas, it's still there

Purificator answered 24/3, 2015 at 12:15 Comment(4)
Won't they need a developer account and your code?Wiltonwiltsey
Well... yes and no. You need a developer account, but there's no need of the code of your App. You could just simply create an App which simulates location (via GPX or even with XCode's fixed locations) and all your device is tricked to believe you're on that location (i.e took a picture this morning mocking the location to San Francisco, uploaded to Facebook, and both picture metadata and Facebook believed I was on San Francisco, not to mention my App :( )Purificator
My point is the location from my App CAN be tricked without the code. That's why I care ... As I said before. When you mock the location for another app ALL APPS ARE TRICKED TO BELIEVE YOU'RE ON THAT LOCATIONPurificator
You don't need a dev account or the code. You can trick the location using an external BT or wired GPS which can easily fake the location.Diphtheria
M
9

Question: Is there any way to detect this behaviour and prevent it?

There actually are 2 separate questions: (1) how to detect, and (2) how to prevent it?

Answer for (1): The simulated location behaviour is quite different from the real one at call back locationManager:didUpdateLocations:

[simulated locations] callback returns almost immediately after calling startUpdatingLocation, and then repeatedly called every exactly one second. Also the locations are all the same if we choose a fixed location. Here is an example:

location: <+51.50998000,-0.13370000> +/- 5.00m (speed -1.00 mps / course -1.00) @ 30.03.15 14:12:48 Час: Індокитай
location: <+51.50998000,-0.13370000> +/- 5.00m (speed -1.00 mps / course -1.00) @ 30.03.15 14:12:49 Час: Індокитай
location: <+51.50998000,-0.13370000> +/- 5.00m (speed -1.00 mps / course -1.00) @ 30.03.15 14:12:50 Час: Індокитай
location: <+51.50998000,-0.13370000> +/- 5.00m (speed -1.00 mps / course -1.00) @ 30.03.15 14:12:51 Час: Індокитай
location: <+51.50998000,-0.13370000> +/- 5.00m (speed -1.00 mps / course -1.00) @ 30.03.15 14:12:52 Час: Індокитай
location: <+51.50998000,-0.13370000> +/- 5.00m (speed -1.00 mps / course -1.00) @ 30.03.15 14:12:53 Час: Індокитай
location: <+51.50998000,-0.13370000> +/- 5.00m (speed -1.00 mps / course -1.00) @ 30.03.15 14:12:54 Час: Індокитай

[real locations] It takes a few seconds (if first run) to call back and then randomly re-call. Also you can see the when significant changes among those locations even if you don't move at all. Here is an example:

location: <+10.77219361,+106.70597441> +/- 67.39m (speed -1.00 mps / course -1.00) @ 30.03.15 14:16:26 Час: Індокитай
location: <+10.77213011,+106.70591088> +/- 65.00m (speed -1.00 mps / course -1.00) @ 30.03.15 14:16:31 Час: Індокитай
location: <+10.77219507,+106.70587790> +/- 65.00m (speed -1.00 mps / course -1.00) @ 30.03.15 14:16:38 Час: Індокитай
location: <+10.77214753,+106.70587741> +/- 65.00m (speed -1.00 mps / course -1.00) @ 30.03.15 14:16:49 Час: Індокитай

Answer for (2): To prevent, I just work around for now, we need to look up at least 3 locations to decide it's simulated or real location.

Remind, it's just temporary solution to detect simulated locations. In the future, Apple may change the behaviour.

By the way, I've also tried to disallow simulate location on xCode at scheme: enter image description here Unfortunately, it still allows simulated locations.

Some more issues you may know here. Hope it help.

Mag answered 30/3, 2015 at 8:9 Comment(4)
Note that the simulated location will be received every second only if it is simulated through user-added gpx file. If what is being used is the default xcode locations (London, johannesburg, ...etc), it will be received only one time.Madson
regarding answer (2), what if the attacker simulates 3 fake locations? (1) fake location (2) real location (3) different fake location from the firstMadson
what if the attacker simulates 3 fake locations? ==> No, they can not do or very difficult to do that because all 3 locations are returned continuously for 1 geolocation request. Even they do that, they have to re-run the app 3 separated single times that is not the case I mentioned.Mag
"Note that the simulated location will be received every second only if it is simulated through user-added gpx file" ==> Agree! So, we need another pattern to detect the simulated location. Do you have any suggestion ?Mag
M
12

To elaborate on @KennyHo answer, I found out that there is another difference between real and simulated locations feedback.

A simulated location, as I noticed, always returns this combination of values for these location properties/options:

horizontalAccuracy: 5
verticalAccuracy: -1
altitude: 0.000000
speed: -1

while a real location would give different combincation 99% of the time such as

horizontalAccuracy: 5
verticalAccuracy: 10
altitude: +/- 0.4243232
speed: -1

Note that it is possible for a simulated location to have a different combination than the above one but only if the user uses xcode Automation target test. However the user can only simulate a location to a signed app with a development identity (must own the app). This means nobody, except you, can fake a location with different altitude or verticalAccuracy to trick your app in xcode.

Madson answered 18/8, 2016 at 18:50 Comment(3)
I have to run more test with those params, this seems good but on inner locations I could manage to reproduce some of these params on real measurements.Purificator
as of Xcode 9.3, above simulated location values are still true.Radiate
You can create a dummy app and simulate the location using Xcode. It changes the location for your device. So the simulated location will work with any app (including apps from Appstore.)Inaptitude
E
10

Since iOS15 arrived apple introduced two new properties in CLLocation:

    /*
     * isSimulatedBySoftware
     *
     * Discussion:
     *  Set to YES if this location was detected as being generated by a software simulator, such as Xcode
     */
    open var isSimulatedBySoftware: Bool { get }

    
    /*
     * isProducedByAccessory
     *
     * Discussion:
     *  Set to YES if this location was generated from an external accessory, such as CarPlay or an MFi accessory
     */
    open var isProducedByAccessory: Bool { get }

These two properties are located in:

/*
 *  sourceInformation
 *
 *  Discussion:
 *    Contains information about the source of this location.
 */
@available(iOS 15.0, *)
open var sourceInformation: CLLocationSourceInformation? { get }

I've tested this with virtual location generators like third party apps and xcode and isSimulatedBySoftware was true in every cases. I will order an external GPS device to make sure that the other is working too (hopefully :D) and will update my answer then.

Elias answered 20/1, 2022 at 9:8 Comment(2)
Interesting! Will both isSimulatedBySoftware and isProducedByAccessory be false when the internal GPS sensor (via CLLocationManager on-device) produce the CLLocation?Kidd
Any code example ?Inaptitude
M
9

Question: Is there any way to detect this behaviour and prevent it?

There actually are 2 separate questions: (1) how to detect, and (2) how to prevent it?

Answer for (1): The simulated location behaviour is quite different from the real one at call back locationManager:didUpdateLocations:

[simulated locations] callback returns almost immediately after calling startUpdatingLocation, and then repeatedly called every exactly one second. Also the locations are all the same if we choose a fixed location. Here is an example:

location: <+51.50998000,-0.13370000> +/- 5.00m (speed -1.00 mps / course -1.00) @ 30.03.15 14:12:48 Час: Індокитай
location: <+51.50998000,-0.13370000> +/- 5.00m (speed -1.00 mps / course -1.00) @ 30.03.15 14:12:49 Час: Індокитай
location: <+51.50998000,-0.13370000> +/- 5.00m (speed -1.00 mps / course -1.00) @ 30.03.15 14:12:50 Час: Індокитай
location: <+51.50998000,-0.13370000> +/- 5.00m (speed -1.00 mps / course -1.00) @ 30.03.15 14:12:51 Час: Індокитай
location: <+51.50998000,-0.13370000> +/- 5.00m (speed -1.00 mps / course -1.00) @ 30.03.15 14:12:52 Час: Індокитай
location: <+51.50998000,-0.13370000> +/- 5.00m (speed -1.00 mps / course -1.00) @ 30.03.15 14:12:53 Час: Індокитай
location: <+51.50998000,-0.13370000> +/- 5.00m (speed -1.00 mps / course -1.00) @ 30.03.15 14:12:54 Час: Індокитай

[real locations] It takes a few seconds (if first run) to call back and then randomly re-call. Also you can see the when significant changes among those locations even if you don't move at all. Here is an example:

location: <+10.77219361,+106.70597441> +/- 67.39m (speed -1.00 mps / course -1.00) @ 30.03.15 14:16:26 Час: Індокитай
location: <+10.77213011,+106.70591088> +/- 65.00m (speed -1.00 mps / course -1.00) @ 30.03.15 14:16:31 Час: Індокитай
location: <+10.77219507,+106.70587790> +/- 65.00m (speed -1.00 mps / course -1.00) @ 30.03.15 14:16:38 Час: Індокитай
location: <+10.77214753,+106.70587741> +/- 65.00m (speed -1.00 mps / course -1.00) @ 30.03.15 14:16:49 Час: Індокитай

Answer for (2): To prevent, I just work around for now, we need to look up at least 3 locations to decide it's simulated or real location.

Remind, it's just temporary solution to detect simulated locations. In the future, Apple may change the behaviour.

By the way, I've also tried to disallow simulate location on xCode at scheme: enter image description here Unfortunately, it still allows simulated locations.

Some more issues you may know here. Hope it help.

Mag answered 30/3, 2015 at 8:9 Comment(4)
Note that the simulated location will be received every second only if it is simulated through user-added gpx file. If what is being used is the default xcode locations (London, johannesburg, ...etc), it will be received only one time.Madson
regarding answer (2), what if the attacker simulates 3 fake locations? (1) fake location (2) real location (3) different fake location from the firstMadson
what if the attacker simulates 3 fake locations? ==> No, they can not do or very difficult to do that because all 3 locations are returned continuously for 1 geolocation request. Even they do that, they have to re-run the app 3 separated single times that is not the case I mentioned.Mag
"Note that the simulated location will be received every second only if it is simulated through user-added gpx file" ==> Agree! So, we need another pattern to detect the simulated location. Do you have any suggestion ?Mag
D
3

[edited] -- Since iOS 15 there are ways to detect that GPS data is coming from external accessories (serial or Bluetooth), so my original answer is no longer correct. There are ways to detect GPS spoofing using the isSimulatedBySoftware and isProducedByAccessory properties in sourceInformation as mentioned by several other answers.

OLD: I don't believe it's possible to detect location simulators.

An easier way to fake location is to use an external bluetooth or serial connection to a GPS simulator that outputs NMEA sentences. You don't need a developer account although you do need an Android phone to run the simulator.

The iPhone will auto detect an external GPS and CLLocationManager will use the external GPS sources in place of own internal GPS. It's really handy for lab testing of mapping and navigation apps.

Diphtheria answered 25/3, 2015 at 5:29 Comment(1)
You mean we can use an android device to simulate an external GPS device? How do I emit the NMEA sequences?Halloween
D
3

I also faced the issue of detecting mock location on iOS devices. One of the testing users was able to fake its location by using a simulation software. However, I discovered a solution by utilizing the "isSimulatedBySoftware" and "isProducedByAccessory" properties.

The following code worked for me:

let locationManager = CLLocationManager()
        if #available(iOS 15.0, *) {
            // use UICollectionViewCompositionalLayout
            let isLocationSimulated = locationManager.location?.sourceInformation?.isSimulatedBySoftware ?? false
            let isProducedByAccess = locationManager.location?.sourceInformation?.isProducedByAccessory ?? false
            
            let info = CLLocationSourceInformation(softwareSimulationState: isLocationSimulated, andExternalAccessoryState: isProducedByAccess)
            
            if info.isSimulatedBySoftware == true || info.isProducedByAccessory == true{
                result(true)
            } else {
                result(false)
            }
        }
        else{
            result(false)
        }

Additionally, I have created a package/plugin for Flutter developers that can detect fake location. The package is available on https://pub.dev/packages/detect_fake_location.

Disturbance answered 9/4, 2023 at 21:48 Comment(0)
C
2

It is also possible to spoof iPhones with a software-defined radio and gps-sdr-sim from GitHub. You use gps-sdr-sim to generate I/Q files that contain GPS signals and use the SDR to transmit those samples over-the-air. This type of spoofing is much harder to detect.

Cherycherye answered 17/8, 2020 at 18:20 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.