本帖最后由 buluo533 于 2025-7-5 19:34 编辑
在学习路上一直伴我逆向成长的某网(本来是个假滑块,最近更新了),现在变成真假双滑块了{:1_923:},都属于入门级的案例
食用地址(过期的链接都会弹出,不一定是这个,因为链接是动态更新的):
aHR0cHM6Ly9rbnMuY25raS5uZXQvdmVyaWZ5L2hvbWU/Y2FwdGNoYVR5cGU9YmxvY2tQdXp6bGUmaWRlbnQ9YmMzOTdjJmNhcHRjaGFJZD1lNGVkYzI0NS03NWYzLTRlNmMtYmUwYS0zMjYxNDI4MGYzMDQmcmV0dXJuVXJsPWlFQ0JEbmhyNzE2UWQ2cGJiN0VsMTBuZ3VQNVNibTlVUXhwenNZeFNBTS1KdVJlSUphalh0SHRBX0VkZXg0cWhpcnJIN0ZDUkNvb3ZaQXBrakFNbkxCRjZRMUEzNXk5WVNfUHBEVzZJeG11VWppTzJMeUFKUDJwY1VKMXhuSU1KSVBYOHhZZXVLSndmR3ZUQm1lM0VSWm01MF9IQm5STjhLVUx2ZW5wLTNCZ0pSVXJyN05BQ0pDNVl3azVqdXhILW1CVXVaQVBQMVVDTGRTQl9mN3V3ckxTd1JUQ3lmRnlSbGpjVEFYRXEzUHFQSVlmeWh5bjQ1V2tMWjJremloRWptWk5mUnJGUTk0RGhuX2k2c0oxTndEdlNXWE9iRWNRdE9sWDBkY3M2NlllRnpkeUhQbXpBa29lcVdIVmRhS3lIN3RiZmsySTJJRnNEdmZiWXJ3YnJLT2hlWjh3THlxWnNucFZkRGs2N1hqc1poOWphSHZoOE5nNXUzU1JOZjVCcw==
一、流程分析
比较简单的一个流程,直接看一下具体的返回参数信息,怎么去获取和使用的
可以明显地看到两个图片地址写着base64,说明要用base64进行编码处理后存储。剩下的就是token和secretKey,多次请求查看具体哪些内容是动态变化的,可以看到前置请求时固定的,只有一个ts时间戳在变化的
token和secretKey也是动态返回的内容
很熟悉的有一个值就是token,剩下的有点不是很熟悉,感觉前两个是定值,我们直接跟栈来看看情况,刷新下断点
跟栈到这里就会发现很明显的参数,偷懒的也可以直接搜:keai这样我们来做参数逆向和python还原
二、加密参数分析与还原
经过分析我们知道需要处理的参数,先简单处理一下前置请求的内容
import requests
import time
import base64
import ddddocr
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.primitives import padding
from cryptography.hazmat.backends import default_backend
def main():
cookies = {
}
headers = {
}
json_data = {
'captchaType': 'blockPuzzle',
'clientUid': 'a91a6829f4537dd20eb15da3781158f2',
'ident': 'bc397c',
'captchaId': 'e4edc245-75f3-4e6c-be0a-32614280f304',
'ts': time.time() * 1000,
}
response = requests.post('脱敏处理', cookies=cookies, headers=headers,
json=json_data).json()
res = response['data']
secretKey = res['secretKey']
token = res['token']
jigsawImageBase64 = res['jigsawImageBase64']
originalImageBase64 = res['originalImageBase64']
gap_pic = base64.b64decode(jigsawImageBase64)
bg_pic = base64.b64decode(originalImageBase64)
with open('gap.jpg', 'wb') as f:
f.write(gap_pic)
with open('bg.jpg', 'wb') as f:
f.write(bg_pic)
det = ddddocr.DdddOcr(det=False, ocr=True, show_ad=False)
with open('gap.jpg', 'rb') as f:
target_bytes = f.read()
with open('bg.jpg', 'rb') as f:
background_bytes = f.read()
rest = det.slide_match(target_bytes, background_bytes, simple_target=True)
value = rest['target'][0]
print(rest)
print('识别到距离', value)
这样我们搞定了前置请求,获取到需要的内容,存储到了图片,用ddddocr获取滑块的距离
有了这些前提,我们来搞定后面的加密参数,先看看哪些内容是固定的,哪些是变化的
还是挺明显的,都是在this里面,可以肯定的是pointjson是通过函数f实现的加密
var e = parseInt((this.moveBlockLeft || "").replace("px", ""));
e = 310 * e / parseInt(this.setSize.imgWidth);
这里的e应该是一个简单的滑动距离做了取整的处理,接下来就是用f进行加密,同时传入了两个参数,一个是序列化后的x和y,然后是动态的密钥,是前置接口的返回值
很熟悉的一个加密,aes,ecb,都是熟悉的词汇(有不熟悉小伙伴可以看看密码学文章,前几篇帖子中都有直达链接,可以读一下),非常标准的加密,我们先用固定值测试一下结果。
def aesEncrypt(plaintext, aes_key):
if isinstance(plaintext, str):
plaintext = plaintext.encode('utf-8')
if isinstance(aes_key, str):
aes_key = aes_key.encode('utf-8')
cipher = Cipher(algorithms.AES(aes_key), modes.ECB(), backend=default_backend())
encryptor = cipher.encryptor()
padder = padding.PKCS7(128).padder()
padded_data = padder.update(plaintext) + padder.finalize()
ciphertext = encryptor.update(padded_data) + encryptor.finalize()
return base64.b64encode(ciphertext).decode('utf-8')
function f (t, e="XwKsGlMcdPMEhR1B") {
var n = l().enc.Utf8.parse(e)
, r = l().enc.Utf8.parse(t)
, i = l().AES.encrypt(r, n, {
mode: l().mode.ECB,
padding: l().pad.Pkcs7
});
return i.toString()
}
、
非常完美,搞定了这个加密参数,接下来看看其他的,还是多抓包分析看看哪些是不变的,要注意的是 returnUrl参数,我们搜索一下,因为他在this里面,不熟悉的大佬可以补补js基础
在这里看看下一个断点,重新刷新,他的操作大概就是先获取网站的链接,然后再通过k函数处理后赋值给e,进去看看k是怎么个事儿
很明显是一个分割重组的过程,很多参数就是来自于这里,说明这个也是动态变化的,只是相对于我们这次分析是静态的内容,可以简单复现一下
def k(t):
e = []
n = 0
r = {}
i = t.find("?")
t = t[i + 1:]
e = t.split("&")
n = len(e)
for o in range(n):
parts = e[o].split("=", 1)
if len(parts) > 1:
r[parts[0]] = parts[1]
else:
r[parts[0]] = ''
return r
这样我们就是实现了完整的第一次真实滑块的任务,完善一下代码内容:
def check(token, point_json):
json_data = {
'captchaType': 'blockPuzzle',
'pointJson': point_json,
'token': token,
'ident': 'bc397c',
'returnUrl': '自行修改'
}
response = requests.post('脱敏处理', cookies=cookies, headers=headers,
json=json_data).text
三、二次滑块分析与绕过
所谓虚实相生,真的里面有假的,当我们点开这个返回值中的链接,惊喜的发现又是一个滑块,惊不惊喜,意不意外;www
大大的一个滑块,流程还在上面,我们再来一次检测一下。
我勒个豆啊,没一点反应,就一直加载图片信息,有点恶心了,这样我可以猜测一下,有没有可能是cookie加密,或者是前端,但是为啥没有检验呢获取请求信息呢?查一下网页的源码.
大佬们可以自行阅读一下,我js也比较菜,大致我们可以分析出所有的操作都是在前端实现的,没有后端参与,说明什么,这是可以绕过的啊。我们让他滑动正确看看是什么情况(注意看包的加载,最好是借助抓包工具),我选择下一个xhr断点,当我们滑动正确时他断住了,我们往上跟一下看看
好家伙灯下黑,就在这里,取了一个id为v-value的属性的值,然后做一个拼接跳转。{:1_918:}
四、总结
入门级的网站大佬们可以玩玩,非常感谢我的小伙伴们@littlewhite11 ,还有几个偷着卷找不到{:1_932:},拓展了思路的滑块,绕过后面的步骤就是元素定位以及获取返回值,可以自行尝试,大佬们冲冲冲{:1_918:}
|