e乐充app数据包加解密和签名算法

将APP的流量代理出来,抓包发现虽然走的是https,但没有验证证书,burpsuite可以抓到请求的内容,不过请求和响应的内容都加密了。逆向apk,发现用AES加密之后base64编码了一下,签名是拼接参数算md5。简单用python模拟了这个加解密的过程。敏感信息已打码。

分析充值的逻辑,发现手机只是充当了一个代理的作用,将卡片和充值服务器连接起来,与卡交互的流量是加密的。北京的公交卡采用的是NXP MIFARE DESFire的卡,用DES/3DES加密,无法获取到密钥破解卡片。

充值的订单与一卡通的卡号绑定,无法给其他的卡片充值,所以无法通过遍历未完成订单的方法来给自己充值。

尝试在写入一部分数据后移走卡片,此时查询卡片余额已经充值成功,订单仍然处于未完成的状态,但是此时已经无法退款,只能选择继续完成写卡。

到此为止没有其他的利用思路了,只能老老实实花钱充卡了。。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#coding = utf-8
import base64
from hashlib import md5
from urllib import unquote,quote
from Crypto.Cipher import AES
import urlparse
import requests
BS = 16
key = 'effb457b-f4a8-4a99-8a7d-539dbe8f05e9'[:BS]
pad = lambda s: s + (BS - len(s) % BS) * chr(BS - len(s) % BS)
unpad = lambda s : s[:-ord(s[len(s)-1:])]
class AESCipher:
def __init__(self):
self.key = "effb457b-f4a8-4a99-8a7d-539dbe8f05e9"[:BS]
def encrypt(self, raw):
raw = pad(raw)
iv = "0102030405060708"
cipher = AES.new(self.key, AES.MODE_CBC, iv)
return base64.b64encode(cipher.encrypt(raw))
def decrypt(self, enc):
enc = base64.urlsafe_b64decode(enc.replace('\n', '').encode('utf-8'))
iv = "0102030405060708"
cipher = AES.new(self.key, AES.MODE_CBC, iv)
return unpad(cipher.decrypt(enc))
def sign(msgType, data):
return md5('msgType=%s&data=%s&key=116107e6-b71f-42da-898a-06b99f48a07d'%(msgType, data)).hexdigest().upper()
def req(msgType, data):
data = AESCipher().encrypt(data)
sig = sign(msgType, data)
return 'msgType=%s&data=%s&sign=%s&client=NFC&token=xxxxx&cardNo=xxxxx&ver=003&headmodel=xxx&phoneType=NFC&pda=xxx&headimei=xxx&clientVer=2.0.14&citycode=1&cardAttr='%(msgType, quote(data), sig)
# 加密签名并请求
msgType = '0256'
data = '{"orderCode":"WXNFC-xxx","type":"","apdu":"","nowBalance":"","oldBalance":"","refundType":""}'
headers = {'USER-AGENT': 'Android 6.0.1', 'Content-Type': 'application/x-www-form-urlencoded'}
res_body = requests.post('http://www.hzt360.com/phoneManager', data=req(msgType, data), headers=headers).text
#print res_body
# 解密
print AESCipher().decrypt(urlparse.parse_qs(res_body)['data'][0].replace(' ', '+'))
分享到 评论