日高校体育(2.8.4)
Table of Contents
高校体育爪巴
起因
从这个学期开始,我们学校刷锻就要用上臭名昭著,隔壁交大大师用了都说好的 高校体育 辣!
不会真的有人想照着这个跑步吧,不会吧不会吧不会吧?
(专家提示:在适当的时候保持大量运动有助于健康生活和下半辈子的幸福。)
流量劫持
有网络通信就要尝试抓包:
- 一定要用新版本的工具(Burpsuite 或 Fiddler)。
- Android >=(?) 7 时系统不会信任用户安装的 CA 证书,需要把 CA 证书安装到系统证书下。
- 对于上一条,执行
openssl x509 -inform PEM -subject_hash_old -in ******.pem | head -1
得到 hash 值(类似于8efb32d4
);重命名证书为<hash>.0
,拷贝到/system/etc/security/cacerts/
并chmod 644
但是这几把东西上了 SSL Pinning
使用 OKHttp
(这是结论,忽略了发现过程)
在电脑上做准备:
首先你要有个 Python 3 和对应的 pip
pip install Frida
pip install objection
pip install frida-tools
使用 frida-server
(无论是 Magisk 方式还是直接把可执行文件拷贝进去):
./frida-server [-l 0.0.0.0] # 方括号内为使用网络时的监听地址
使用线缆连接时此时应能通过 frida-pa -U
查看进程。网络的话请参阅 frida
的文档。
使用 objection -g com.example.gita.gxty explore
尝试进行注入。网络的话请使用 -h
和 -p
来指定主机名和端口。
如果成功的话,直接进行一个 android sslpinning disable
的执行来禁用 SSL Pinning
。
协议(?)分析
签名
最终发送的内容主题会包括 data
和 sign
两部分。
data
是一个最小化的 JSON 格式字符串(没有换行,没有段间空格)。
import json
def dump_dict(incoming_dict: dict) -> str:
return json.dumps(incoming_dict, separators=(',', ':'))
sign
是一个 MD5 算法的信息摘要。构造过程为
md5(`前缀` + "data" + `你实际传输的 JSON 字符串`)
import hashlib
MD5_PREFIX = ******
def sign_request(raw_payload: str) -> str:
md5 = hashlib.md5()
str_to_digest = f"{MD5_PREFIX}data{raw_payload}"
md5.update((str_to_digest).encode('ascii'))
return md5.hexdigest()
这里 raw_payload
就是你实际发送的 data
。
在实际观测过程中,GET
方法不会指定 Content-Type
头; POST
方法指定 Content-Type
: application/x-www-form-urlencoded
def send_payload_get(self, endpoint: str, payload_dict: dict) -> dict:
payload_json_str, sign = self.generate_signed_payload(payload_dict)
r = requests.get(self.api_base_endpoint + endpoint,
params=(("sign", sign), ("data", payload_json_str)),
headers=self.real_headers)
return json.loads(r.text)
def send_payload_post(self, endpoint: str, payload_dict: dict) -> dict:
payload_json_str, sign = self.generate_signed_payload(payload_dict)
urlencoded_body_dict = {
'sign': sign,
'data': payload_json_str
}
r = requests.post(self.api_base_endpoint + endpoint,
data=urlencoded_body_dict,
headers=self.real_headers)
return json.loads(r.text)
身份验证
- 返回中不相关的部分会被省略。
登录
/api/reg/login
POST
{"info":"<uuid>","mobile":"<mobile>","password":"<password>","type":"<device_type>"}
Response:
{"code":"200","msg":"登录成功","data":{"userid":"<userid>","utoken":"<utoken>"}}
使用身份验证:
加入如下 HTTP 头:
"headers": {
"BDA9F42E0C8A294ECDF5CC72AAE6A701": "1,0,0,0,0,0",
"uuid": "<uuid>",
"ntoken": "",
"utoken": "<utoken>",
"Cookie": "PHPSESSID=<php_sessionid>",
"User-Agent": "okhttp-okgo/jeasonlzy",
"xxversionxx": "20180601",
"versionName": "2.8.4",
"versionCode": "440",
"platform": "android"
}