注意:实验阶段的切勿使用个人账号进行刷数据,以免被视为作弊。
截获请求负载信息
运动世界的跑步规则,大家应该都很熟悉了,在选择目标距离后,在地图上回“随机”给出多个待检测点,而在这些点中,你必须要经过几个,路线随意,这样才完成了跑步评测的第一步。而在跑步结束后,软件还会计算你的跑步平均速度,如果偏差太大(过快或过慢)也不会记录成为有效成绩。
分别对设置目标距离、产生随机点、上传数据三个请求进行了抓包,其结果如下:
设置目标点 及 产生随机点
POST http://gxapp.iydsj.com/api/v2/campus/901/get/1/distance/3
Host: gxapp.iydsj.com
uid: 47881
Accept: */*
Authorization: Basic MTRwXBd3MjU1MzU6MTk5NzAyLjZXWGz=
Proxy-Connection: keep-alive
osType: 1
appVersion: 1.2.0
Accept-Language: zh-Hans-CN;q=1
Accept-Encoding: gzip, deflate
Content-Type: application/json
DeviceId: FC139628-F5F6-423A-ADBF-C8E310FCB713
CustomDeviceId: FC139628-F5F6-423A-ADBF-C8E310FCB713_iOS_sportsWorld_campus
Content-Length: 45
User-Agent: SWCampus/1.2.0 (iPhone; iOS 9.3.4; Scale/3.00)
Connection: keep-alive
json: {"longitude":103.991842,"latitude":30.766178}
数据上传
POST http://gxapp.iydsj.com/api/v2/users/47881/running_records/add
Host: gxapp.iydsj.com
uid: 47881
Accept: */*
Authorization: Basic MTRwXBd3MjU1MzU6MTk5NzAyLjZXWGz=
Proxy-Connection: keep-alive
osType: 1
appVersion: 1.2.0
Accept-Language: zh-Hans-CN;q=1
Accept-Encoding: gzip, deflate
Content-Type: application/json
DeviceId: FC139628-F5F6-423A-ADBF-C8E310FCB713
CustomDeviceId: FC139628-F5F6-423A-ADBF-C8E310FCB713_iOS_sportsWorld_campus
Content-Length: 89183
User-Agent: SWCampus/1.2.0 (iPhone; iOS 9.3.4; Scale/3.00)
Connection: keep-alive
json: {"totalDis":3.24,"sportType":1,"speed":12,"fivePointJson":"{"useZip" : false, "fivePointJson" : "[{"flag":"1476258220000","isPass":true,"lat":"30.772452","lon":"103.988141","isFixed":"0"},
{"flag":"1476258220000","isPass":true,"lat":"30.769404","lon":"103.991393","isFixed":"0"},{"flag": ...
// 数据量过大,部分显示
从格式上来看,很容易就能猜到这是个 Base64 转码方式。于是使用 Base64 解码方式将其转回,发现了具有如下规则:
Basic [username]:[passward]
进行跑步数据的处理及分析
展示一个接近完整的跑步数据:
{
"totalDis":3.24,
"sportType":1,
"speed":12,
"fivePointJson":
"{
"useZip" : false,
"fivePointJson" :
"[{
"flag":"1476258220000",
"isPass":true,
"lat":"30.772452",
"lon":"103.988141",
"isFixed":"0"
},
{
"flag":"1476258220000",
"isPass":true,
"lat":"30.769404",
"lon":"103.991393",
"isFixed":"0"
},
{
"flag":"1476258220000",
"isPass":true,
"lat":"30.768566",
"lon":"103.989982",
"isFixed":"0"
},
{
"flag":"1476258220000",
"isPass":false,
"lat":"30.774981",
"lon":"104.000061",
"isFixed":"0"
},
{
"flag":"1476258220000",
"isPass":true,
"lat":"30.775152",
"lon":"103.990113",
"isFixed":"1"
}]"}",
"selDistance":3,
"unCompleteReason":4,
"allLocJson":
"{
"useZip" : false,
"allLocJson" :
"[{
"speed":"0",
"id":"1",
"pointid":"1",
"radius":"65.000000",
"gaintime":"1476258220000",
"createtime":"",
"modifytime":"",
"type":"5",
"totaldis":"0",
"lat":"30.766170",
"flag":"1476258220000",
"avgspeed":"0",
"totaltime":"2.000000",
"lng":"103.991934",
"locationtype":"0"
},
....,
{
"speed":"0",
"id":"294",
"pointid":"294",
"radius":"10.000000",
"gaintime":"1476260686000",
"createtime":"",
"modifytime":"",
"type":"6",
"totaldis":"3241",
"lat":"30.766135",
"flag":"1476258220000",
"avgspeed":"0",
"totaltime":"2159.000000",
"lng":"103.992010",
"locationtype":"0"
}]
"}",
"complete":true,
"startTime":1476258220000,
"stopTime":1476260686000,
"totalTime":2466
}
这里仍然省略了大量的跑步打点数据,因为实在是太多。根据 json 数据每个属性的名字,我们能猜出个大概。而且在最外层数据中,我们发现 :totalDis
、speed
、 fivePointJson
、 complete
、 startTime
、 stopTime
、 totalTime
这几个属性,对于所有的数据处理,都是在 client 端进行的,而后台的服务器仅仅提供了数据库的记录作用。
经过几组数据的测试,我们发现在 server 端,仅仅对当次提交的 speed
数据进行判断,而 speed
数据居然没有经过 totalTime
和 totalDis
的验证,而后两者仅仅是用来在 client 端起显示作用。
而对于 startTime
和 stopTime
两个属性,自然就能猜测到这是系统默认生成的当前时间的时间戳,从末尾的三个0就可以暴露出它设置成为毫秒级别。
我们再来看 fivePointJson
这个属性的结构:
"flag":"1476258220000",
"isPass":true,
"lat":"30.775152",
"lon":"103.990113",
"isFixed":"1"
flag
自然也是时间戳,并且可以惊讶的发现他与 startTime
相同。而是否通过,仅仅使用了 isPass
这个布尔值来记录。实在是令人无语,于是我将数据保存下来,进行一次虚假提交,不出意外增加了一次新的记录。
但是知道了这些,我们还是无法解决一个重要的问题,即跑步路径坐标。并且在我的提交尝试中,如果跑步路径的 json 格式提交错误,就会造成在 client 端无法显示跑步路线的问题。由于这个 app 使用了百度地图第三方sdk,所以我的第一想法是通过百度地图路径规划功能,从一条路径中取点进行构造 route。可是在构造的时候会遇到很多问题,比如取点的距离与跑步速度不统一等。
而在 app 中会有一个 约跑功能 ,我们可以看见他人的跑步路线。因此我们打算采取偷梁换柱的方式,将他人跑步数据进行抓取,进而修改成自己此时的信息及时间戳即可。
约跑请求
{
"error":10000,
"message":"成功",
"data":
{
"roomInfoModel":
{
"beginTime":"2016-10-21 20:17:13",
"endTime":"2016-10-21 20:44:42",
"distance":3.0,
"locDesc":"人体机能实验室",
"finishNum":2
},
"roomersModelList":
[{
"finished":true,
"uid":57446,
"unid":901,
"icon":
"http://imgs.gxapp.iydsj.com/imgs/d30a0bff-1b20-4504-91b9-49ae65ada0a6.jpeg",
"sex":1,
"name":"杨xx",
"endTime":"2016-10-21 20:44:42",
"points":"{...}"
},
{
"finished":true,
"uid":57276,
"unid":901,
"icon":"http://imgs.gxapp.iydsj.com/imgs/null",
"sex":0,
"name":"李x",
"endTime":"2016-10-21 20:44:42",
"points":"{...}"
},...
]
}
}
为了保护隐私,我没有展示完整姓名。从获取到的数据中,我们发现 points
的格式与我们想要的跑步路线是完全一致的。因此我们对其进行数据解析,并处理时间戳生成我们所需要的数据。进而再将处理过后的数据进行整合,通过上传数据接口对个人用户进行认证,制造一条近乎完美的跑步数据出来。
信息泄露问题
我大概可以猜测一下,每个需要跑步的学校都会收到比以往多的多的垃圾短信。因为在约跑记录网络接口中,可以能够获取到每个用户的真实姓名、性别、头像,这是极其严重的个人信息泄露!
在斥责 app 制作公司的同时,也提醒广大童鞋多加注意个人隐私的保护,提高个人信息的安全意识,在有法却无严厉监管的环境下我们只有自我提高。(这实属无奈之举)