【2022春节】解题领红包之二、三、四,新手单步解密过程

2022年2月23日 300点热度 0人点赞 0条评论

作者坛账号:dongye


【2022春节】解题领红包之二、三、番外,新手单步解密过程

by dongye

写在最前面,这篇帖子是纯新手破解、可以算上是手动单步调试的暴力破解,稍复杂一点的加密工作量就太大了,不过解密一些玩具类的题目应该也够用
技术实在有限, 安卓题环境搭起来了就花了不少时间, 最后动态调试虚拟机下没能启动成功, 静态调试不会找入口也不太看得懂, 有一点小遗憾, 看了官方解析,感觉还是太复杂了
以下正文:  

解题领红包之二

解题思路1:

盲猜,高端叫法可以叫做社工
打开解题文件熟悉的命令行窗口, 上次用OD还是2021春节时候, 偶尔逛论坛消遣一下, 已经忘了怎么用了, 但这个界面很熟悉, 和2021年是一样的
题目的注1:【 由于年前时间较紧,所以题目比往年少了一些,望大家海涵。】
那答案会不会也是一样的?
打开2021年的记事本,去年答案   【2021HappyNewYear52PoJie】,直接修改年份,输入   【2022HappyNewYear52PoJie】,成功  

图片

解题之后还发现了文件名还是  

图片

解题思路2:

脱壳破解
开始是用OD打开程序的,但里面非常多函数调用,看不太懂,猜测可能是有壳,查一下

图片

PEiD 扫描显示没有壳

图片

Exeinfo扫描,显示 Armadillo 和 PseudoSigner

搜索许久未找到是什么,可能就没有壳,还是用OD打开
执行一遍发现非常多的函数调用,并不明白是什么逻辑
四处下断点发现堆栈调用就有明文密码,应该是完全没有加密了,大概在输入口令后进行的加载
最后验证出一个方法:

  1. 首先运行程序等待用户输入时暂停

图片

  1. 随便输入数字 123 后通过 【执行到返回】六次, 一直执行回主函数 也就是 40xxxx 的地址

  2. 在堆栈记录里可以看到明文口令

图片

这里应该是输入口令后程序调用了读取或者比较的方法留下的痕迹
今年的第一题确实够简单的

2022解题领红包之三

第三题难度大了一些、由于工具用的很不熟,可以算得上是暴力破解了,相较去年题目应该是简单了一些
首先还是查壳

图片

UPX,老演员了,上OD,esp定律,论坛里有很多教程了,不再赘述
跟踪到一个循环判断,不知道是什么,直接修改值跳过循环  

图片

F8 跳转, 顺利转到程序入口  

图片

使用 OllyDump 直接脱壳, 脱壳顺利完成  

图片

再次用OD打开脱壳后程序
输入 id 和 key 之后暂停, F8跟踪到判断处

图片

追踪判断前的函数 401520
进入后F8跟踪观察
发现一大段循环,并观察到特殊字符串 flag{Happy_New_Year_52Pojie_2022}   猜测可能是解密口令
PS:开始以为目标key是 Happy_New_Year_52Pojie_2022 后面发现是    flag{Happy_New_Year_52Pojie_2022}

图片

再往后跟踪,很快到return,观察return就是把比较结果返回,主函数判断后结束
那判断部分函数就在这之间了,对之前调用的函数加断点,优先查看循环次数最多的方法,最终确定加密函数在 4011B0
进入后跟踪发现这个函数是将输入的口令进行变换,观察发现此处执行时每次循环会改变一个字符,此处变换代码很长,代码相似度高,看不懂,从外部入手  

图片

此处应该是将UID作为密钥将口令进行加密那么尝试输入不同UID观察变换规律
UID输入1-5,口令 Happy_New_Year_52Pojie_2022,得到结果如下  

 复制代码 隐藏代码
1:  Crwwz_Ebh_Zbro_52Wnulb_2022
2:  Bknnu_Xqe_Uqkd_52Nsrwq_2022
3:  Ihyyd_Upz_Dphc_52Yjmxp_2022
4:  Johhi_Bac_Iaon_52Hepma_2022
5:  Mjiix_Whl_Xhju_52Ipyfh_2022

此时发现变换有一定规律, 相同字母在不同位置变换结果相同, 猜测变换为一一对应关系, 尝试输入:
ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789{}_
作为key, 观察变换后值,得到:
RAJSBKTCLUDMVENWFOXGPYHQZIrajsbktcludmvenwfoxgpyhqzi0123456789{}_
对比可以看出加密函数对字母进行了替换,相当于彩虹表,要想得到目标口令,通过加密后密文反查应该使用的明文得到以下对应关系:
flag{Happy_New_Year_52Pojie_2022}
qibt{Wbuuv_Onp_Vnba_52Urczn_2022}
经验证口令正确  

图片

中途由于猜测目标口令是Happy_New_Year_52Pojie_2022还走了一些弯路,基本都是通过F8看堆栈观察数据变化找到的关键代码段进行分析
有了这些信息应该可以写注册机了,但是不会做注入,无法实施
有一个思路,可以在加密时输入UID,使用全字符字典作为口令输入,在加密结果拿到后再使用目标口令进行反查,可以得到彩虹表和解密口令,这样可以在不解析加密算法的情况下做解密  

【2022解题领红包之番外篇】保姆级解析

准备工作

此题是 Fiddler 和 Web Archive 保存的日志文件, 我选择用 fiddler 文件 首先下载题目文件, 安装 fiddler everywhere 软件
官网地址https://www.telerik.com/fiddler

导出文件

使用 fiddler 打开 52tube.saz 文件
看了一下应该是一个视频的网络请求记录, 其中视频是 live.m3u8和一系列 ts文件
这是常用的视频加密播放方式, 整个请求包含了所有文件, 那就可以在本地运行这个视频站了
在 [ Session ] 列表的 [ 52tube ] 上右键导出, 选择 raw files 导出

图片

运行网站

将文件夹放入 nginx 搭建出本地网站, 将文件中的 xx.html 改成 index.html以便访问

图片

在浏览器中进行访问网站 http://localhost/52tube.mmxxii/F12 打开控制台, 查看出错情况

图片

发现ping访问路径为 /api/ping/ 而静态资源路径为 /52tube.mmxxii/*,将/52tube.mmxxii/api 移动到根目录下

图片

修改后刷新网页, 出现新的错误, /api/drm 的 POST 请求出现 405, 这是因为网站只是放在了 nginx 下, 是只支持 GET 请求的, 自然会出现 405

图片

因为前面在fiddler中已经将 /api/drm 的 response 保存成文件, 因此这里就是要让前端页面请求到文件的内容, 有三种处理办法  

  • 第一种是修改 nginx 配置, 将 POST 请求转发成 GET  

  • 第二种是修改 前端的请求参数将 POST 改为 GET  

  • 第三种是起一个本地服务, 做一个 POST 接口, 返回 drm 数据

第二种方法最直观, 也比较顺手, 所以直接在代码中找请求出错的位置,
在出错请求的 Initiator 列中直接点击第一行 script.bundle.js:17199, 这是js代码格式化后的位置, 正是发起请求的位置

图片

由于现在没有服务器相应请求, 直接修改参数把 POST 改成 GET 就可以
参数的代码如下  

 复制代码 隐藏代码
var a = {
    method: "POST",
    headers: {
      "Content-Type": "application/x-www-form-urlencoded"
    },
    body: r
};

在本地文件中修改为

 复制代码 隐藏代码
var a = {
    method: "GET",
    params: r
};

保存后再次刷新网页, drm 和 ts 视频文件顺利加载, 但视频无法播放, 应该遇到正题了

图片

解密

来到 drm 请求的位置, 整个网站只有在这里有POST请求, 应该是向服务器请求密钥
看一下请求参数的构成, 是 h 和 id

 复制代码 隐藏代码
var r = new URLSearchParams;
r.append("h", n(e.buffer)),
r.append("id", t);
var a = {
    method: "GET",
    params: r
};

其中 id 是固定的 "live",那么发送的密钥应该就是 h 了, 再看 h 的生成,由 e 经过 n() 处理生成
n()是将传入的 t/e 每位的数字转换成长度为 2 的十六进制字符再拼接  

 复制代码 隐藏代码
function n(t) {
    return [...new Uint8Array(t)].map((t=>t.toString(16).padStart(2, "0"))).join("")
}

简单测试一下

 复制代码 隐藏代码
x = 27
x.toString(16).padStart(2, "0")
输出 '1b'

而 e 是由这段代码生成的

 复制代码 隐藏代码
let e = await async function() {
    let t = new Uint8Array(16);
    crypto.getRandomValues(t);
    let e = n(t.buffer) + Date.now() + Math.random();
    return new Uint8Array((await async function(t) {
        const e = (new TextEncoder).encode(t);
        return await crypto.subtle.digest("SHA-256", e)
    }(e)).slice(0, 16))
}();

e 的生成是由随机数和时间戳生成的, 那么从正向是不可能得到密钥的
到这里可以分析出视频加密的原理, 应该是生成的 n(e) 作为密码向服务器请求 一个 使用这个 密码e 对解密 ts 的密钥进行加密 的结果, 再用密码e对服务器返回结果进行解码得到ts的密钥, 流程大致如下

图片

 复制代码 隐藏代码
sequenceDiagram
客户端(e)->>服务端(key): 密码e 经过n(e) 得到h
服务端(key)->>客户端(e): 用 hkey 进行编码得到 drm
客户端(e)->>客户端(e): 对 drm 进行解码得到 key
客户端(e)->>视频: 使用 key 对视频进行解码

这里经过分析可以得到结论, 服务端返回的结果与发送的数据为解密关键, 现在我们有的是服务端返回的 drm 和对应的请求参数, 这个参数在 fiddler 中可以查看  

图片

h='7b10311e6e310f0df068d9ede10475a8'  

这个发送的参数是 n(e) 的结果, 解密时需要的是 e , 需要对 n(e)进行解码得到一个 e, 上面分析过 n() 的编码规则比较简单
只需要简单做一下反向编码, 替换掉随机密钥, 使之变成和保存下来的 drm 相对应的数据即可, 解码规则是每两位字符作为十六进制数转成十进制, 代码如下

 复制代码 隐藏代码
// let e = await async function() {
    // let t = new Uint8Array(16);
    // crypto.getRandomValues(t);
    // let e = n(t.buffer) + Date.now() + Math.random();
    // return new Uint8Array((await async function(t) {
        // const e = (new TextEncoder).encode(t);
        // return await crypto.subtle.digest("SHA-256", e)
    // }(e)).slice(0, 16))
// }();
let e = new Uint8Array(16);
let m = '0123456789abcdef';
let h = '7b10311e6e310f0df068d9ede10475a8'
for(let i=0;i<32; i+=2){
    e[i/2] = m.indexOf(h[i]) * 16 + m.indexOf(h[i+1] )
}

这是发送的参数 n(e) 就变成了 固定的 h='7b10311e6e310f0df068d9ede10475a8', 保存代码后再次刷新页面视频出现!!

图片

答案口令

题目口令从现在视频第 12 秒处

图片

完结撒花

活动已结束,题目打包放到爱盘供大家下载学习:
https://down.52pojie.cn/Challenge/Happy_New_Year_2022_Challenge.rar
欢迎发帖讨论分享分析过程和结果。


--

www.52pojie.cn


--

pojie_52

33270【2022春节】解题领红包之二、三、四,新手单步解密过程

这个人很懒,什么都没留下

文章评论