Skip to content

百家网站(上上中)

更新: 2025/2/24 字数: 0 字 时长: 0 分钟

本章节将展示针对100家网站进行逆向的过程。

网易云音乐

题目难度:中等

地址:https://music.163.com/#/song?id=1901371647

网易云音乐(NetEase CloudMusic),是一款由网易开发的音乐产品,是网易杭州研究院的成果,依托专业音乐人、DJ、好友推荐及社交功能,在线音乐服务主打歌单、社交、大牌推荐和音乐指纹,以歌单、DJ节目、社交、地理位置为核心要素,主打发现和分享。

**首先我们打开地址,目的就是采集歌曲下面的评论信息。**在Network当中XHR定位到了评论的出处:

20220707113002

该请求的信息如下:

链接:https://music.163.com/weapi/comment/resource/comments/get?csrf_token=
方法:POST
参数:加密参数params、加密参数encSecKey

点击Initiator追溯请求发送,定位加密参数params、加密参数encSecKey生成方式:

20220707114159

点击第一个,跳转到对应的位置,打上断点,刷新网页后断住,但是我们要注意一点就是,可能很多的请求都会走这个逻辑,需要判断是不是请求评论信息的那个url请求,可以看到下面这个url和上面的url不同,因此需要放过该断点:

20220707114632

几次放过请求后,断住了我们需要的获取评论的请求,点击右下角的回调栈,开始一步步往上追溯:

20220707115649

最终在 t9k.be9V 函数中定位到了两个加密参数的生成过程:

params: bKB1x.encText
encSecKey: bKB1x.encSeckey

20220707120142

两个加密参数全都是 bKB1x 的属性,其中 bKB1x 内容如下:

javascript
var bKB1x = window.asrsea(JSON.stringify(i9b), buV0x(["流泪", "强"]), buV0x(Rg4k.md), buV0x(["爱心", "女孩", "惊恐", "大笑"]));

我们将断点断在 bKB1x 处,输出当中几部分的内容的值:

20220707121318

还原后内容如下,需要注意的是,下面被还原的值,在我们第二次刷新网页请求后,不会改变:

javascript
var bKB1x = window.asrsea('{"rid":"R_SO_4_1901371647","threadId":"R_SO_4_1901371647","pageNo":"1","pageSize":"20","cursor":"-1","offset":"0","orderType":"1","csrf_token":""}', '010001', '00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fccf695280104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46bee255932575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b3ece0462db0a22b8e7', '0CoJUm6Qyw8W8jud');

接下来就要还原 window.asrsea() 方法逻辑,点击该方法跳转,发现是 window.asrsea() 方法实际就是 d 方法,而这些都在一个大的自执行函数当中:

20220707135910

其加密参数params、加密参数encSecKey生成方式就很明朗了,结合上面的还原值,可以得到下面结论:

params:由两次CBC模式的AES加密生成。
  第一次加密内容:{"rid":"R_SO_4_1901371647","threadId":"R_SO_4_1901371647","pageNo":"1","pageSize":"20","cursor":"-1","offset":"0","orderType":"1","csrf_token":""}
  第一次加密密钥:0CoJUm6Qyw8W8jud
  第二次加密内容:第一次加密的结果
  第二次加密密钥:随机16位字符串(这里我们可以固定该值)
encSecKey:由一次RAS加密生成,由于加密传入的参数全部是固定值,所以我们可以直接用RAS加密后生成的值。

**为了方便,我们将随机16位字符串固定为 0CoJUm6Qyw8W8jud 值,包括下面RAS加密所需的参数 i 也固定为 0CoJUm6Qyw8W8jud 值。**这里我们先通过RAS加密获取生成后的值,直接就是encSecKey的值:

20220707142232

最终通过Python还原代码如下:

20220707143536

百姓网

题目难度:中等

地址:https://china.baixing.com/gongzuo

百姓网成立于2005年3月,是国内领先的分类信息生态服务商,是中国互联网轻资产模式的典范。百姓网致力于创造以分类信息业务为平台、多条垂直业务线布局的生态圈。为用户提供涵盖生活服务、招聘求职、房屋租售、二手车买卖、二手交易、教育培训、同城交友等一站式本地生活服务信息平台,同时为中小微商户建立全方位的精准营销解决方案。

打开Chrome浏览器无痕访问上面地址时,看到如下页面:

20221011175734

当我们点击”继续访问“或者刷新按钮时,就进入了我们需要的招聘页面,注意这时网址没有发生任何改变,而且后面如何刷新页面,也不会进入第一个页面了,除非重新打开无痕浏览器访问地址才会出现第一个页面:

20221011175953**上面的现象说明这一个网址上面挂了两个页面,进入第一个页面的过程中会给访问者带上一些参数,带着这些参数继续访问网址才会返回招聘页面,否则就还是会返回第一个页面。**现在我们回看Chrome开发者工具抓包,观察 Doc 文档,左边就是返回的第一个面和招聘页面,其中第一个页面的响应头返回一个重要参数 __trackId 值:

20221014163633

继续访问招聘页面,发现需要验证Cookie值:

20221014160923

经过几次访问和观察,Cookie的值字段和规律如下:

__trackId: 每次都有变化,来源第一个页面响应头的Set-Cookie中的__trackId; 
__city: 不改变,可以省略掉;
c0fc276cce08ba22dc: 不改变,可以省略掉;
c1fc276cce08ba22dc: 不改变,可以省略掉;
bxf: 不改变,可以省略掉;
sbxf: 不改变,必须带上;

这看起来似乎很简单,只需要把第一页响应头的Set-Cookie中 __trackId 值拿出来,加到第二次访问的Cookie上就能拿到招聘页面的内容。但实际输出却不是,具体看下图,可以看到,即使我们拿到第一页响应头返回的 __trackId 去进行招聘页的请求,返回的还是第一个页面的响应。

20221014163214

问题就出在这里,为什么浏览器拿到 __trackId 去进行招聘页的请求,可以拿到内容,而程序却不行。我们把视角放到所有类型的请求上,发现了中间可能会影响后续请求成功的3个请求:

20221014165516

这3个请求都是GET请求,经过几次访问和观察,URL规律如下:

# url不改变,目的是请求js内容
https://china.baixing.com/shield/bf.js
# url不改变,返回了图片的base64编码
https://china.baixing.com/shield/s.webp?cf=0&s=87f20699bb395052353975c3b746ccba&f=24711eb211dc390981c2138e881baddde85
# url中的s的值会变,返回了图片的base64编码
https://china.baixing.com/shield/s.webp?cf=1&s=0894376fa7561fe170aff959391bf298&f=24711eb211dc390981c2138e881baddde85

不变的不用管,只关心变化了的,对最后一个请求的URL进行反向追溯,发现 s 的值来源于 ce 当中,而 ce 的生成参数中包含图片的base64编码:

20221014171849

我们和上一个请求返回的图片的base64编码进行比对发现一模一样:

20221014172639

到此,我们就已经把所有的流程都走完了,这里要注意的是中间请求获取JS的流程不能省略,否则也请求不到招聘页面内容的,只有带上第一个请求返回的 __trackId 把所有的流程都走完才会被允许进入招聘页面。

当乐网

难度:中等

网址:https://oauth.d.cn/auth/goLogin.html

当乐成立于2004年2月,是中国手机游戏下载网站,致力于为中国近5亿智能手机用户提供手机游戏下载、游戏资讯、游戏活动、游戏工具、道具交易 、攻略评测、玩家互动社区等全方位的移动娱乐游戏服务,以及全球移动游戏开发商的游戏代理、发行与投资。首先,我们随便填写一个账户进行登录,抓取到对应的数据包,查看请求头没有关键的加密字段,查看POST提交的参数,可以看到账户名 name 是没有进行加密,而账户密码 pwd 进行了加密:

20230611005458

网站的登录一定会有一个参数(账户名、账户密码)提交的过程,而触发这个提交过程的“点击事件”就是“登录按钮”。这里我们就选中登录按钮,在Elements栏中选择 Event Listeners 事件监听,点击 click 点击事件,选中 button 后面地址进行跳转:

20230611010701

我们来到跳转后打上断点,再次点击登录,一步步进行调试,可以看到前面密码都还是明文,当经过 rsa(passwordVal) 处理后,就变成了密文,而且刚好就是请求中提交的 pwd 字段的值:

20230611011718

那么我们就把 rsa() 函数的JS代码扣出来即可,这里需要扣的函数有一点多,需要一点耐心,最终的效果如下:

20230611015753

艺恩网

难度:中等

题目地址:不提供项目地址

艺恩致力于通过大数据、AI技术连接内容与消费者数据,以驱动客户业务增长。由于在页面源代码中不存在页面所展示的数据,因此断定网页使用了动态数据展示:

20230604011424

我们刷新页面进行抓包,在XHR请求里面看到响应内容是一堆密文信息:

20230604011721

拷贝URL路径进行搜索,点击第一个结果,确定内容所在一个JS文件:

20230604012838

在源面板中打开JS文件:

20230604013037

在JS文件中搜索关键词 JSON.parse 确定数据序列化的位置,我们在此处打上断点:

20230604013345

刷新页面后,断点断住,其实这里就可以看到 e 其实就是密文数据,而 webInstace.shell(e) 就是将密文数据转换为明文数据:

20230604014106

选中 webInstace.shell() 出现源码所在位置:

20230604014401

点击进入到源码所在位置,可以看到文件内容是混淆的JS代码,并且定位在一个 webDES 对象里面:

20230604015129

我们新建一个JS文件并将 webDES 对象里面的代码全部扣出来,并将加密数据复制出来,通过 webInstace.shell() 方法进行执行,报错其中的一个函数未被定义:

20230604015737

我们拷贝未定义的函数名,来到源面板进行搜索,发现该函数全局都在被使用:

20230604020035

这种情况,我们就把整个的JS文件内容都给复制下来,这样做的好处在于我们不用一步一步去查什么内容有丢失,因为它本身就是混淆的代码,如果一步一步去跟栈是很头疼的一件事:

20230604020628

现在我们重新执行代码,报错在第2240行中 navigator 变量未定义,其实这个变量就是浏览器中的环境变量,在JS代码中很常见:

20230604020749

现在我们回到源面板中,搜索 navigator 变量,找到相应的位置打上断点,继续执行流程,断点断住:

20230604021240

在控制台我们打印一下 navigator 变量,可以看到输出了浏览器的环境信息:

20230604021406

这样的话,我们就在代码中设定一个全局的 navigator 变量,内容为浏览器的 userAgent 信息,来模拟浏览器:

20230604021741

现在我们重新运行我们的代码,发现可以解密被加密的数据了:

20230604022014