案例-中大网校登录-RSA加密解密
地址: https://ks.wangxiao.cn/
Preserve log一定要先勾上

有内容挡住我们了,需要把挡着的内容去掉:

进入Elements


再选中左边内容

可以看到左边内容和右边代码是一一对应的。直接把右边代码删掉即可。

删掉后,就可以看到没有了

之后就可以抓包了:

再来解决一下验证码的问题:

点击验证码(这种图片类的,一点就会切换了):

然后看到发送请求了:

看一下第一个请求:


猜测第二个请求貌似没什么用:

看看第二个请求的cookie(看看这个请求有没有改变cookie)

再点一下:

然后再看看cookie,发现:两个值是一样的。这个cookie不会因为不同的验证码请求而不一样。所以第二个请求和验证码无关。

所以看这个请求:

注意这个验证码的请求上的URL是没有参数的。

但是可以看到URL和cookie是一伙的。也就是说cookie和验证码是有关联的。
接下来需要用session来处理整个请求过程。
打开无痕模式:


看到进入网页的第一个请求就是:

看到这里面有一个初始的session:

一开始应该有一个cookie的加载过程. 一个session对应就是类比成一个客户端. 相当于一个浏览器
# 用来加载第一个cookie
session.get("https://user.wangxiao.cn/login?url=http%3A%2F%2Fks.wangxiao.cn%2F")
下面的代码获取验证码的图片:
import requests
import base64
session.headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36"
}
# 用来加载第一个cookie
session.get("https://user.wangxiao.cn/login?url=http%3A%2F%2Fks.wangxiao.cn%2F")
# 获取验证码..
img_url = "https://user.wangxiao.cn/apis//common/getImageCaptcha"
img_resp = session.post(img_url, headers={
"Content-Type": "application/json;charset=UTF-8", # 服务器检测这个东西..
"Referer": "https://user.wangxiao.cn/login?url=http%3A%2F%2Fks.wangxiao.cn%2F"
})
img_base64 = img_resp.json()['data'].split(",")[-1]
# print(img_base64)
with open("tu.png", mode="wb") as f:
f.write(base64.b64decode(img_base64))
用图鉴来处理识别验证码:
def base64_api(img_base64):
data = {"username": "q6035945", "password": "q6035945", "typeid": 1003, "image": img_base64}
result = json.loads(requests.post("http://api.ttshitu.com/predict", json=data).text)
if result['success']:
return result["data"]["result"]
else:
return result["message"]
return ""
看看下面的请求中,每个请求后面都会有一个 r.png? 的请求,

注意看协议都不一样:

看他的参数, r.png? 这个请求是用来跟踪记录日志的,用来记录用户操作行为的,一般这种都不是网站自己做的,一般都是第三方的。所以这个记录日志的跟咱们要做的事情不相干,不用管他。

所以我们要重点关注以下三个请求,而getImageCaptcha 我们前面已经搞定了。接下来看看另外两个。

下面这个请求也没有任何参数

看返回的数据:

看看我们需要输入的登录参数

再看另外的请求,有传参数和上图的对应,可以看到下面密码的参数是有加密的,所以我们接下来需要找到加密密码的地方。

在启动器中,上面两个是jquery的代码,我们直接跳过,看到下面的 utils.min.js 代码,点进去:

然后设置断点,这是找加密函数的一种方案。。。

找加密函数的另外一种方案:
我们找URL,找到 passwordLogin 关键字

可以全局搜索 passwordLogin

点进来就可以看到:

并在password那一行处打断点:

可以看到断点出的值分别为:
pwd 是前面输入的密码。

而 ress.data 是一个未知的值

进去函数里面:

看到下面的 JSencrypt ,JSEncrypt 是 js的一个第三方加密库. 专门用来做rsa加密,并且加密方式用的是 PKCS padding,对于逆向来说,既可以用JS来解密,也可以用Python来写。
同时看到publicKey字眼,显然就是RSA。

再回到 ress.data,他是箭头函数的参数

选中箭头函数,也就是下面的内容

注意一直要到下面的地方,才是结束:

上面是一个函数,那这个函数如果我们知道是在哪里调用的,就可以知道 ress.data 在哪里了。
看到下图的Call Stack,点击它后面的success,就是success调用的 ress:

点进去之后,看到这里是 success,发送请求成功后才会调用这里。
请求了某个URL,返回值传递给了刚刚断点的那个位置。
所以知道这个URL是啥,就知道后面该怎么做了。
这个URL所返回的东西,传递给了断点的位置。

鼠标划到url,可以看到:

就是我们抓包时,看到的gettime

自此,整个逻辑就清楚了。下面再来走一遍:
第一个请求:


第二个请求:密码加密:

去看断点的位置:

以后看到pwd 后面的 '' 这种,需要验证一下是否是空字符串。复制到console打印或者看一下长度。

这里,把密码和ress.data拼接起来,然后进行加密。ress.data 就是下面的 data

之后就是登录了。登录成功之后,才能访问网站内容(题库),如果没登陆去看题库,就会跳到下图页面:

明明已经登陆了,但是后续请求数据的时候,拿不到数据。
cookie的信息不全. 从头到尾用的是session发的请求。
如果服务器返回的cookie都是在响应头中的set-cookie中. 那么不会出这个问题,间接的说明, cookie的设置有一些是在js中完成的。
找到js中, 登陆成功了之后, 做了些什么?发现js中有对cookie的写入代码. 我们只需要照葫芦画瓢即可。
也就是得登录后,cookie才会有登录的信息,才能访问题库。
session只能帮我们处理响应头的cookie。不能处理js动态加载的cookie。需要手动去维护cookie的信息。
怎么维护这些cookie信息呢,我们需要抓包观察。
在登录之前,设置断点:

断在这之后,点击下图按钮,一步步往后走:

这是我们登录之后的信息,我们看看它做了啥,然后我们就跟着做啥

进去 keepOurCookie12 ,点进去

点进去之后,看到下面的 $.cookie(e,n,o) 这是jquery 设置cookie的一个固定用法,e是 key,n是value,而o是其他参数不用管。

所以回到这里,我们根据key和value直接怼就可以:session.cookies[key] = vaule 这样怼进去
注意下图有一个判断释放是自动登录,很明显我们的不是,所以走else 的内容:

把这几个怼进去:

需要处理这个 res.data

再看看 syncLogin() 函数:

下图这些都要怼进去:

完整代码如下:
import requests
import base64
import json
from Crypto.Cipher import PKCS1_v1_5
from Crypto.PublicKey import RSA
def base64_api(img_base64):
data = {"username": "q6035945", "password": "q6035945", "typeid": 1003, "image": img_base64}
result = json.loads(requests.post("http://api.ttshitu.com/predict", json=data).text)
if result['success']:
return result["data"]["result"]
else:
return result["message"]
return ""
session = requests.session()
def login():
session.headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36"
}
# 一开始应该有一个cookie的加载过程. 一个session对应就是类比成一个客户端. 相当于一个浏览器
# 用来加载第一个cookie
session.get("https://user.wangxiao.cn/login?url=http%3A%2F%2Fks.wangxiao.cn%2F")
# 获取验证码..
img_url = "https://user.wangxiao.cn/apis//common/getImageCaptcha"
img_resp = session.post(img_url, headers={
"Content-Type": "application/json;charset=UTF-8", # 服务器检测这个东西..
"Referer": "https://user.wangxiao.cn/login?url=http%3A%2F%2Fks.wangxiao.cn%2F"
})
img_base64 = img_resp.json()['data'].split(",")[-1]
# print(img_base64)
with open("tu.png", mode="wb") as f:
f.write(base64.b64decode(img_base64))
# 识别验证码
verify_code = base64_api(img_base64)
# 1. 请求getTime获取到 data(时间戳)
# 2. 对密码进行rsa加密. 加密的内容(明文密码+data(时间戳))
# 3. 发送请求到login.
rsa_pub_key_base64 = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDA5Zq6ZdH/RMSvC8WKhp5gj6Ue4Lqjo0Q2PnyGbSkTlYku0HtVzbh3S9F9oHbxeO55E8tEEQ5wj/+52VMLavcuwkDypG66N6c1z0Fo2HgxV3e0tqt1wyNtmbwg7ruIYmFM+dErIpTiLRDvOy+0vgPcBVDfSUHwUSgUtIkyC47UNQIDAQAB"
ress = session.post("https://user.wangxiao.cn/apis//common/getTime", headers={
"Content-Type": "application/json;charset=UTF-8", # 服务器检测这个东西..
"Referer": "https://user.wangxiao.cn/login?url=http%3A%2F%2Fks.wangxiao.cn%2F"
})
password = "q6035945"
# 加密的内容(明文密码+data(时间戳))
password_ming = password + ress.json()['data']
# rsa加密 把页面上的base64的公钥处理成字节. 直接处理.
pub_key = RSA.importKey(base64.b64decode(rsa_pub_key_base64))
rsa = PKCS1_v1_5.new(pub_key)
mi_password = rsa.encrypt(password_ming.encode("utf-8"))
mi_password_base64 = base64.b64encode(mi_password).decode()
# print(mi_password_base64)
data = {
"userName": "18614075987",
"password": mi_password_base64,
"imageCaptchaCode": verify_code,
}
login_resp = session.post(url="https://user.wangxiao.cn/apis//login/passwordLogin",
data=json.dumps(data, separators=(',', ':')),
headers={
"Content-Type": "application/json;charset=UTF-8", # 服务器检测这个东西..
"Referer": "https://user.wangxiao.cn/login?url=http%3A%2F%2Fks.wangxiao.cn%2F"
})
login_info = login_resp.json()
# session只能帮我们处理响应头的cookie. 不能处理js动态加载的cookie
# 需要手动去维护cookie的信息
session.cookies['autoLogin'] = None
session.cookies['userInfo'] = json.dumps(login_info['data'], separators=(',', ':'))
session.cookies['token'] = login_info['data']['token']
login_data = login_info['data']
session.cookies['UserCookieName'] = login_data['userName']
session.cookies['OldUsername2'] = login_data['userNameCookies']
session.cookies['OldUsername'] = login_data['userNameCookies']
session.cookies['OldPassword'] = login_data['passwordCookies']
session.cookies['UserCookieName_'] = login_data['userName']
session.cookies['OldUsername2_'] = login_data['userNameCookies']
session.cookies['OldUsername_'] = login_data['userNameCookies']
session.cookies['OldPassword_'] = login_data['passwordCookies']
session.cookies[login_data['userName'] + "_exam"] = login_data['sign']
def get_info():
for i in range(3):
# 测试, 登陆状态是否可用. <- 跑的多的.
resp = session.post(url="http://ks.wangxiao.cn/practice/listQuestions",
data=json.dumps({
"examPointType":"",
"practiceType":"2",
"questionType":"",
"sign":"jz1",
"subsign":"8cc80ffb9a4a5c114953",
"top":"30",
}, separators=(',', ':'))
,headers={
"Content-Type": "application/json;charset=UTF-8",
})
# 如果登陆状态可以的话. 可以获取到题目内容
if resp.text.startswith("{"):
return resp.json()
else:
# 登陆失败. 或者登陆信息失效. 登陆过期
login()
dta = get_info()
print(dta)
浙公网安备 33010602011771号