0x01 抓包
这个软件对连接数进行了限制,要输入授权码进行网络验证。
通过抓包,分析软件提交的数据,serialNumberKey后面跟着一大串字符,看起来很像base64编码,猜测加密后使用了自定义的base64编码。
0x02 调试分析
2.1 发送流程
软件使用了OpenSSL加密库,通过查看那些地方使用了加解密的函数,即可快速定位到发送密文和接受处理的地方,然后就是调试下整个流程。
首先把获取到的mac,序列号及其本地时间组成一个json,加密后添加到serialNumberKey再发送出去。
来看下加密使用的算法,设置对应的秘钥QN01R3M7WPKKORBK
调用OpenSSL里面的库函数进行加密,加密算法为aes_128_ecb,注意IV为16个字节的0,pad方式为PKCS7
将加密后的二进制数据进行编码,编码方式为base64的变形
所谓变形就是使用的编码字符串不同,但是具体算法还是一样的,第一行是软件使用的字符串,第二行是标准base64采用的字符串序列,这就解释了编码后的字符串出现了'@ ! -'的原因。
[JavaScript] 纯文本查看 复制代码 pri_base64_str="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789@!-"
base64_str="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="
2.2接收流程
通过分析代码可以知道,返回内容应该是个json,code的值应该是1,才能进行下一步处理
从encodeStr提取出字符串进行解密
先把字符串进行base64解码转为二进制数据,在进行解密
解密的秘钥是发送的时候的time字段的值,解密算法和发送的加密算法是相同的
解密之后还是一个json,接下来就是json解析,connectNum是最大的连接数,他转化成数字之后对一个全局变量进行赋值,如果想破解的话可以改掉这个全局变量的初值(把5改成其他的)
endTime是到期时间,当为forever的时候是用不过期
最后应该构造一个类似{"connectNum": "50", "endTime": "forever"}的json获取对应的时间进行加密------>>>>>{"code":1,"encodeStr":"Eq/GisQkh7zt8iRo7EgFGKiYEmQh1tAPxien5zjDKPjNcUOFuqrU1YnRzzFU8lXC"}
0x03 编写加解密程序
通过分析加解密算法即可编写出对应的程序
[Python] 纯文本查看 复制代码 import base64
import binascii
import sys
import crypto
import json
import requests
sys.modules['Crypto']=crypto
from crypto.Cipher import AES
class validserno_payload(object):
def __init__(self,mac,serialNo,time):
self.mac= mac
self.serialNo = serialNo
self.time=time
class validrep_payload(object):
def __init__(self,connectNum,endTime):
self.connectNum= connectNum
self.endTime = endTime
class lb_crypto():
def __init__(self,key,iv):
self.key=key
self.iv=iv
self.blk_size=16
def lb_encrypt(self,str,pri):
in_len=len(str)
add=self.blk_size-(in_len%self.blk_size)
str=str+add*chr(add) #处理pad
cryptor = AES.new(self.key, AES.MODE_ECB,self.iv)
enc_text = cryptor.encrypt(str)
print binascii.hexlify(enc_text)
base64_str=base64.b64encode(enc_text)
if not pri:
return base64_str
encode_str=base64_str.replace('+','@').replace('/','!').replace('=','-')
return encode_str
def lb_decrypt(self,encode_str):
base64_str=encode_str.replace('@','+').replace('!','/').replace('-','=')
decode_str=base64.b64decode(base64_str)
cryptor = AES.new(self.key, AES.MODE_ECB,self.iv)
plain_text = cryptor.decrypt(decode_str)
str_len=len(plain_text)
pad=ord(plain_text[-1])
return plain_text[0:str_len-pad]
payload=validrep_payload("50","forever")
lc=lb_crypto('2017050512453200','\0'*16) #时间需要动态获取
print json.dumps(payload.__dict__)
rep_data="encodeStr="+lc.lb_encrypt(json.dumps(payload.__dict__),False)
print rep_data
0x04 验证结果
为了验证分析结果,可修改http返回内容,看是否达到预期目的。
noname.txt内容如下
注意解密时候是根据时间来动态解密的,要想解密正确应该在解密的时候patch时间值秘钥,验证结果如下:
|