【猿人学WEB题目专解】猿人学第20题

第一届猿人学爬虫比赛1-20题题解 猿人学第一届Web端反混淆攻防赛1-20题题解 阅读详情

🌈据说,看我文章时 关注、点赞、收藏 的 帅哥美女们 心情都会不自觉的好起来。

前言:
🧡作者简介:大家好我是 user_from_future ,意思是 “ 来自未来的用户 ” ,寓意着未来的自己一定很棒~
✨个人主页:点我直达,在这里肯定能找到你想要的~
👍专栏介绍:猿人学WEB题目专解 ,提供猿人学WEB题目总计20题的解题思路与方法,如有讲述错误,请不吝赐教。

想看往期历史文章,可以浏览此博文: 历史文章目录,后续所有文章发布都会同步更新此博文~

人生苦短,我用python

题目网址

猿人学第20题

题目详情

在这里插入图片描述
界面是新的颜色,让我们计算 加和。

题目思路

老样子,进入 request 函数,参数入口挺直观的:
在这里插入图片描述
打上断点,点击下一页,就找到了我们的核心函数:
在这里插入图片描述
看得出来,这次是引用的“加强版”的 wasm ,上一次简单版的 wasm 还是在第15题。
人懒了,先再像第6题一样试一次 RPC 吧。

使用 RPC 远程过程调用解决

上次说到,为什么会有想用这个的想法呢?原因有几个:

  1. 使用 RPC 远程过程调用很简单。
  2. 函数入口明确,可以直接调用出结果。
  3. 懒得逆向 / 逆向恐惧 / 不会逆向 等原因。
  4. 没有用过 RPC 远程过程调用,想尝试。

这次很明确,函数入口明确 + 懒得逆向。
在 window.sign 函数调用前,加断点断住,然后在控制台注入 RPC 框架代码:

function Hlclient(wsURL) {
    this.wsURL = wsURL;
    this.handlers = {};
    this.socket = {};
    if (!wsURL) {
        throw new Error('wsURL can not be empty!!')
    }
    this.connect()
    this.handlers["_execjs"]=function (resolve,param){
        var res=eval(param)
        if (!res){
            resolve("没有返回值")
        }else{
            resolve(res)
        }

    }
}

Hlclient.prototype.connect = function () {
    console.log('begin of connect to wsURL: ' + this.wsURL);
    var _this = this;
    try {
        this.socket["ySocket"] = new WebSocket(this.wsURL);
        this.socket["ySocket"].onmessage = function (e) {
            try{
                let blob=e.data
                blob.text().then(data =>{
                    _this.handlerRequest(data);
                })
            }catch{
                console.log("not blob")
                _this.handlerRequest(blob)
            }

        }
    } catch (e) {
        console.log("connection failed,reconnect after 10s");
        setTimeout(function () {
            _this.connect()
        }, 10000)
    }
    this.socket["ySocket"].onclose = function () {
        console.log("connection failed,reconnect after 10s");
        setTimeout(function () {
            _this.connect()
        }, 10000)
    }

};
Hlclient.prototype.send = function (msg) {
    this.socket["ySocket"].send(msg)
}

Hlclient.prototype.regAction = function (func_name, func) {
    if (typeof func_name !== 'string') {
        throw new Error("an func_name must be string");
    }
    if (typeof func !== 'function') {
        throw new Error("must be function");
    }
    console.log("register func_name: " + func_name);
    this.handlers[func_name] = func;
    return true

}

//收到消息后这里处理,
Hlclient.prototype.handlerRequest = function (requestJson) {
    var _this = this;
    try {
        var result=JSON.parse(requestJson)
    } catch (error) {
		console.log("catch error",requestJson);
        result = transjson(requestJson)
    }
    //console.log(result)
    if (!result['action']) {
        this.sendResult('','need request param {action}');
        return
    }
    var action=result["action"]
    var theHandler = this.handlers[action];
    if (!theHandler){
        this.sendResult(action,'action not found');
        return
    }
    try {
        if (!result["param"]){
            theHandler(function (response) {
                _this.sendResult(action, response);
            })
        }else{
            var param=result["param"]
            try {
                param=JSON.parse(param)
            }catch (e){
                console.log("")
            }
            theHandler(function (response) {
                _this.sendResult(action, response);
            },param)
        }

    } catch (e) {
        console.log("error: " + e);
        _this.sendResult(action+e);
    }
}

Hlclient.prototype.sendResult = function (action, e) {
    this.send(action + atob("aGxeX14") + e);
}


function transjson(formdata){
    var regex = /"action":(?<actionName>.*?),/g
    var actionName = regex.exec(formdata).groups.actionName
    stringfystring =  formdata.match(/{..data..:.*..\w+..:\s...*?..}/g).pop()
    stringfystring= stringfystring.replace(/\\"/g,'"')
    paramstring = JSON.parse(stringfystring)
    tens = `{"action":`+ actionName + `,"param":{}}`
    tjson = JSON.parse(tens)
    tjson.param = paramstring
    return tjson
}

var demo = new Hlclient("ws://127.0.0.1:12080/ws?group=yrx&name=q20");

取消断点,继续运行即可。
单页 RPC 的Python代码:

index = 1
t = int(time.time()) * 1000
url = 'http://localhost:12080/execjs'
data = {
    'group': 'yrx',
    'name': "q20",
    'jscode': f'sign("{index}|{t}")'
}
sign = requests.post(url, data=data).json()['data']
url = f"https://match.yuanrenxue.cn/api/match/20?page={index}&sign={sign}&t={t}"
print(requests.get(url, headers=headers).json())

真是太轻松了,让我都不想处理 wasm 文件解决了~

正常处理 wasm 文件解决

首先,我们尝试向第15题一样,直接用 pywasm 导入 wasm ,没想到报错:
在这里插入图片描述
我们去搜一下又发现:
在这里插入图片描述
居然用万恶的 eval 来加载!
那先不管这个,我们来看看 sign 函数:
在这里插入图片描述
看到调用 wasm 时没有返回值,但最终是由另外一个函数返回的,现在看到几个数字,我们刷新或点下一页看看他会不会变化:
在这里插入图片描述
在这里插入图片描述
发现除了函数输入值 content 其他的所有数字都是定值!
再看看他返回的函数:
在这里插入图片描述
意思就是从指定内存获取数据,所以我们也可以通过这个函数获取 wasm 执行时的数据。
先回到 wasm 文件里。
在这里插入图片描述
在本地又不太好浏览,所以我们使用 wabt 将 wasm 格式转换为 wat 格式:
在这里插入图片描述
这下才看的舒服,然后搜索 export 看看导出了哪些:
在这里插入图片描述
确认过眼神,sign 就是我们想要的函数,全局搜索 $sign ,配合浏览器断点调试:
在这里插入图片描述
在这里插入图片描述
我们发现这 wat 转出来就是浏览器的简化版。等到我们熟练驾驭 wasm 的时候再来看这文件吧,我们先去浏览器调试看值。
先贴一下刚才的两个值:r0 = 1114360, r1 = 32 ,用函数获取值就是 getStringFromWasm0(1114360, 32) 。
我们将所有有关 sign 的函数打个断点,看看他会跳转到哪里去,每跳一次,就更改到 sign 栈,然后执行函数获取值看看。
我们发现在这个函数之前,获取到的值都是那一串:
在这里插入图片描述
经过那个 call 就得到了我们的值:
在这里插入图片描述
这样我们就压缩了查找的范围,多这样找几次,我们就能获得结果了!
第二次找到的值变化范围:
在这里插入图片描述
很明显能发现,这个 sign 执行了 MD5 ,然后我们兴致冲冲的去执行 MD5 ,发现:window.sign('1|1682259720000') 得到 '0acdc2760793e6bc16dc58225b31f654' ,但我们使用 MD5 加密的结果却是:84c504783d8bc98d3160554f19b99241 ,难道这是魔改的 md5 ?
算了,还是继续看变值吧:
在这里插入图片描述
在这里没有变化是我没想到的:
在这里插入图片描述
只能硬着头皮继续找下去了…
第三次值的变化:
在这里插入图片描述
执行完 call ,在这里用 32 的长度还报错了,往下试 31 可以:
在这里插入图片描述
可以看到后面跟了一串字符,我们刷新看看他变不变:
在这里插入图片描述
在这里插入图片描述
发现是一个固定值,我们先记录一下:D#uqGdcw41pWeNXm (不保证每个人的都一样)
然后把这新的值 MD5 加密一下:0acdc2760793e6bc16dc58225b31f654 ,和它的加密结果一模一样!

解题源码

import time
import hashlib
import requests
import jsonpath

headers = {
    'cookie': 'sessionid=6r3zqh6xc6lhl12enp6l07m7rasokbxo',
    'User-Agent': 'yuanrenxue.project'
}

value = 0
for index in range(1, 6):
    t = int(time.time()) * 1000
    # 使用 RPC 远程过程调用解决:var demo = new Hlclient("ws://127.0.0.1:12080/ws?group=yrx&name=q20");
    # url = 'http://localhost:12080/execjs'
    # data = {
    #     'group': 'yrx',
    #     'name': "q20",
    #     'jscode': f'sign("{index}|{t}")'
    # }
    # sign = requests.post(url, data=data).json()['data']
    # 正常逆向 WASM 解决
    sign = hashlib.md5(f'{index}|{t}D#uqGdcw41pWeNXm'.encode('utf-8')).hexdigest()
    url = f"https://match.yuanrenxue.cn/api/match/20?page={index}&sign={sign}&t={t}"
    # value += sum(v['value'] for v in requests.get(url, headers=headers).json()['data'])
    value += sum(jsonpath.jsonpath(requests.get(url, headers=headers).json(), '$..value'))
print(value)
【猿人学WEB题目专解】猿人学第5题 第五题 js 混淆 乱码增强 - 猿人学 阅读详情

相关推荐

猿人学第二届第二题

第一处是第二处拼接了个时间戳,时间戳好弄,要么是new Date生成的,要么是刚才那个图片包返回的,还有一处是第二处去掉来token=,所以我们直接跟这个变量,很容易就找到生成的地方。每次分页明显抓到两个包,一个数据包一个图片包,但这个图片包很奇怪,每次返回同样的,明显不合理,用fidder抓包或者python逆向下这个包,可以看到是返回一个时间戳。到这儿别慌,这是内存爆破引起的,碰到这样的问题,极大可能是格式监测引起的,我们可以借助压缩代码网站,把格式化后的代码还原回去。那就极大可能是缺少环境。

zhuangjoo的博客 1949

猿人学第20题(题目会不定时更新)

今天突然来感觉想写点什么,但是最近确实没啥技术长进,没东西可写。看了看文章发现好久没写猿人学的东西了,就去猿人学比赛网站逛了一圈,发现最新出来的20题还没有去搞,这怎么可以!但是自己也没啥wasm逆向的经验,在网上看了一下,也都是一些rpc的方案,正好这次就补充学习一下了什么是wasm:参考链接 在开始做题前呢先熟悉一下wasm,进入20题,f12查看参数发现需要解决的只有一个sign,老规矩点击调用堆栈信息进入发包位置: 可以看出sign是由页码加上时间戳经过方法之后返回的加密结果: 继续跟进,打断点进

Ig_thehao的博客 2995

【中等】 猿人学web第一届 第2题 js混淆 动态cookie 1

进入题目正常加载数据后 打开调试工具,等待一会(2~3分钟) 刷新页面 cookie 失效以后会弹窗 删除 cookie 中的 m 字段再刷新页面也是一样的 点击确定后,页面自动刷新完会进入 无限 debugger 查看上一层堆栈 生成 debugger 的代码 是经过混淆的 手动解混淆后的代码 加密参数定位 hook Cookie hook 到 cookie 后,向上查看堆栈就能找到生成 cookie m参数的位置 每次请求返回的代码都不一样,但执行逻辑是一样的,所以将 2.html

m0_69843492的博客 2840

爬虫攻守道 - 猿人学第20题 - 殊途同归

回到 JS 代码,选中 getStringFromWasm0(r0, r1) 部分,可以看到最终的 sign 已经生成。此时在 console 端口中输入 getStringFromWasm0(1114192, 31) —— 1114192和31 是 var55 和 var56 的值,1个代表内存地址,1个代表偏移量,表示从这个地址取这个长度的字符 —— 可以看到后面加了1串固定的字符串,也就是传说中的 md5 的盐?追踪 Sign 函数,调用的 wasm 代码。

biaobro的博客 908

YuanRenXue:猿人学Web端爬虫攻防赛第一季 习题练习

YuanRenXue 猿人学Web端爬虫攻防赛第一季 习题练习

手把手教你用MOS管设计双电源自动切换电路(附零压降方案)

本文详细介绍了使用MOS管设计双电源自动切换电路的完整方案,包括基础电路拓扑、零压降优化设计及实战调试技巧。针对外接电源与电池供电的无缝切换需求,提供低损耗MOS管选型建议和性能实测数据,帮助工程师解决传统二极管方案的压降与漏电问题。

h0i1j2k3l的博客 1438

猿人学第20题详解

猿人学--20题--动态调试

not_python1的博客 1022

Nettrace 源码分析

文章介绍:本文将围绕腾讯开源项目nettrace工具中数据采集,数据处理,数据分析三个模块深入源码分析其实现细节

abobob的博客 989

WASM进阶-猿人学第二十题

加密步骤其实只有这一步,len0 就是 content 的长度,下面几步是从内存中获取值,进入到 wasm 内部查看 sign函数。文件地址:https://match.yuanrenxue.com/api/match20/wasm。此时发现 content 长度发生变化,看一下长度,大概是经过了md5加密,那就先来看一下明文是啥?就是在 content 加了一段盐值,经过多次调试发现,盐值不变。一直往下滑,直到看到 md5 字样,然后再次进入函数内部。没办法,只能硬着头皮去肝wasm源码了,先上一段。

qq_40734108的博客 1116

CTF逆向实战:如何快速识别RC4、TEA和Base64的魔改变种?

本文针对CTF逆向比赛中常见的加密算法魔改问题,详细讲解了如何快速识别和破解RC4、TEA和Base64的变种。通过分析算法核心特征、常见魔改手法,并结合动态调试与脚本编写等实战技巧,帮助逆向分析人员有效应对算法混淆,提升解题效率。

agile9scrum的博客 781

单目视觉定位:深入解析PNP算法在机器人导航中的实战应用

本文深入解析了PNP算法在机器人单目视觉定位中的核心原理与实战应用。通过拆解坐标变换四步,详细阐述了如何从二维图像点反求相机三维位姿。文章结合OpenCV的solvePnP函数,提供了算法选择、参数调优及结果后处理的实用指南,并针对机器人导航中的特征匹配、尺度不确定性等挑战,给出了鲁棒性优化与实时性平衡的解决方案。

weixin_29083649的博客 419

【猿人学WEB题目专解】猿人学第7题

第七题 动态字体,随风漂移 - 猿人学

user_from_future的博客 9360

3DGS实战避坑指南:从零搭建到成功训练

本文详细介绍了3D Gaussian Splatting(3DGS)从环境配置到成功训练的实战避坑指南。涵盖git clone的正确使用、依赖安装的隐藏陷阱、CUDA版本兼容性解决方案、首次训练验证、常见报错急救方案、性能优化技巧及可视化调试方法,帮助开发者高效搭建和训练3DGS模型。

weixin_29053383的博客 365

【猿人学WEB题目专解】猿人学第1题

第一题 js混淆源码乱码 - 猿人学

user_from_future的博客 9798

RU.EXE实用指南:从基础操作到高级调试技巧

本文是RU.EXE(RW Everything)的实用指南,详细介绍了这款硬件调试工具从基础操作到高级技巧的全过程。文章阐述了RU.EXE作为直接读写硬件寄存器、内存和PCI配置空间的强大工具,如何帮助硬件工程师和开发人员高效进行底层系统调试与故障排查,并强调了安全操作的重要性。

weixin_29228203的博客 278

【猿人学WEB题目专解】猿人学第2题

第二题js 混淆 动态cookie 1 - 猿人学

user_from_future的博客 9939

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

【猿人学WEB题目专解】猿人学第6题

第六题 js 混淆 回溯 - 猿人学

user_from_future的博客 1万+

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

【猿人学WEB题目专解】猿人学第18题

第十八题 jsvmp 洞察先机 - 猿人学

user_from_future的博客 3万+

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

【猿人学WEB题目专解】猿人学第4题

第四题 雪碧图、样式干扰 - 猿人学

user_from_future的博客 9921

【猿人学WEB题目专解】猿人学第3题

第三题 罗生门 - 猿人学

user_from_future的博客 1万+

【猿人学WEB题目专解】专栏通知

🧡作者简介:大家好我是。

user_from_future的博客 9129

【猿人学WEB题目专解】猿人学第15题

备周则意怠 常见则不疑 - 猿人学

user_from_future的博客 478

【猿人学WEB题目专解】猿人学第13题

入门级cookie-猿人学

user_from_future的博客 402

【猿人学WEB题目专解】猿人学第19题

***检测

user_from_future的博客 466
上一篇: 【猿人学WEB题目专解】猿人学第19题
下一篇: 【猿人学WEB题目专解】猿人学第18题
user_from_future
博客等级 码龄5年 4066粉丝 115原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值