起因
这段时间每天都要下楼做核酸,而做核酸需要查验两码。
由于我13天前有一个外地的行程轨迹(非疫情严重地区),所以今天在做核酸检测的时候,遇到了一点点小麻烦。
好奇心驱使,就想看看这个行程卡的查询到底是怎么去实现的,并且对行程卡api进行了一些简单的安全测试,以希望能够帮助提高行程卡的安全性。
摸索了一下,大概有两种方式查询行程卡:
- 需要输入手机号码,获取验证码短信
- 支付宝直接授权当前手机号码
第一种方式:短信验证码
环境:PC端浏览器,burpsuite抓包
网址:https://xc.caict.ac.cn/#/login(中国信通院的域名)
流程:输入手机号,点击“获取二维码”。
此时,浏览器会向/dYvFMYL8/h8A2xuUsHKoMz
发一个POST请求包
手机号是随便从一个接码平台上找的,可惜接码平台接不了行程卡的短信。。。
请求包里有4个字段,虽然都被混淆了,但还是可以一眼看出前2个字段的含义。
- p090983d:手机号码
- s324234m:当前时间
后面两个字段一看就是hex编码的数据,解码一下可知,原始数据为16字节
F12看js代码,搜字符串"h8A2xuUsHKoMz",找到相关代码:
- q435434f:客户端随机生成的16字节uuid,作为queryID唯一标识此次请求
最后一个字段s234234s,是由代码_0xfc3b9f()('MOFXTCJq8bOhlSi' + _0x3759ef)
生成。其中变量_0x3759ef
就是s324234m字段,也就是当前时间Date
的字符串表示。这里在前面又补了一段随机字符串MOFXTCJq8bOhlSi
,并把补完的字符串作为参数传入_0xfc3b9f()
函数中。追了一下_0xfc3b9f()
,混淆太多了,看不出来。16字节,盲猜一下是md5,本地测了一下,果然!
- s234234s:
md5("MOFXTCJq8bOhlSi" + s324234m).hexdigest()
,用作签名校验
测了一下这个接口:
- 4个字段缺一不可
- 从报错信息中看出来后端是Java写的,com.fasterxml.jackson.core(没什么比较猛的现成Nday)
- s324234m(Date)字段跟当前时间相差不能超过15min
- 可以对这个请求包原封不动地重放
- 如果验证码还未使用,则服务端会返回“您的验证码仍在有效期内”
- 如果验证码被使用过,则服务器会重新给手机发短信验证码(感觉这是个小问题,影响不大)
- 理论上,由于在发短信前没有一层人工验证码的check,所以非法分子其实是可以利用这个api接口来“短信轰炸”的(尚未测试高频率访问是否会被禁ip)
用户收到短信验证码后,就可以点“查询”按钮对行程信息进行查询。
浏览器会向/PMfdZtmQM6PIu/jKDFMlURRsN6D9发请求包。
此处短信验证码随便填的“123456”。
请求包中有5个字段,稍微看看js代码也能看出来每个字段的具体含义
- p234324:手机号
- q363209:随机的16字节uuid,作为queryID唯一标识此次请求(与请求短信验证码的相同)
- y892342:6位数字 短信验证码
- c098465:当前url的key(默认为空字符串“”)
- s456hr8:
md5("OcpqZSOIZOxr0" + p234324).hexdigest()
短信验证码会作为身份认证的凭据,如果不正确,就会返回“非法访问”。
如果短信验证码正确,则会返回一段base64编码的图片数据。随后,浏览器会渲染出图片,呈现出此手机号近14天内行程信息。
测了一下这个接口:
-
想查别人的行程卡信息,必须要知道其他人的短信验证码,在请求里提供y892342字段才行
-
验证码只能用一次,重放会返回“验证码错误”
-
自娱自乐改响应包是可以的
- 把响应包里的message图片数据改成另外一个图片数据,可以把途径地改成其他的,绕过“某些检测”
- 改color字段,有3种:“green”、“yellow”、“red”,可以把自己的行程卡改成其他颜色的码:)
第二种方式:直接授权
环境:手机支付宝, HTTP Catcher(网球)抓包
打开行程卡,支付宝会自动授权本机手机号,然后直接点击“查询”就能查询。
用网球抓包,可以抓到2条访问xcweb01.caict.ac.cn
(信通院)的流量。
首先访问/alipay/getPhoneByAuthSec
,会带4个请求参数(已对authCode、secret字段做了脱敏处理):
|
|
第一个请求是用来获取手机号的,响应包中会返回手机号(已对phone字段做了脱敏处理):
|
|
然后再带着加密的手机号去访问/alipay/queryAdressQuicklyNewSec
,访问的queryId保持不变,secret和authCode则会重新生成。(已对phone、secret、authCode字段做了脱敏处理)
|
|
服务器响应包中的message即携带有相关的行程信息(已对phone、message做了脱敏处理)
|
|
测试发现:
- 两次请求的secret字段为hex编码的数据,原始数据长度为16字节(猜测为密钥key?或者hash的salt?)
- 两次请求的authCode字段看似是hex编码的数据,但是末尾都是HX44、MX44,怀疑为一种自定义的校验码
- 试了好几次,第二次请求里面的phone字段和响应的message字段每次都不会变
- phone字段是base64编码的数据,解码后得到16字节的数据,怀疑为
- block_cipher_enc(key, phone)
- hash(salt + phone)
- message字段也有可能是这样的?
支付宝小程序,不像浏览器可以直接看到js源码,所以对于这些字段到底是什么含义不太能搞懂。也盲测了很多,都不太对,感觉还是要看源码才行。
搜了一下小程序逆向,网上的方案是:安卓手机root,adb连进去,去找到对应的tar文件,然后拖出来解压。
设备受限,无法下一步,就不深挖了。。
不过还是可以自娱自乐地改一下行程信息。
例如:用朋友的手机号(正常的行程信息)去查询,抓第二次响应包,记录一下里面的message字段。然后网球里面有改包功能,把/alipay/queryAdressQuicklyNewSec
响应包里的message字段固定改成想要的取值,就能实现修改行程信息的目的。
以上纯属娱乐行为,请勿用做非法行为。