【2022春节】解题领红包之二、三、四,新手单步解密过程
2022-2-24 08:40:0 Author: mp.weixin.qq.com(查看原文) 阅读量:5 收藏

作者坛账号:dongye

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


文章来源: http://mp.weixin.qq.com/s?__biz=MjM5Mjc3MDM2Mw==&mid=2651137296&idx=3&sn=9ab315f966cf2fd2f0416ee89adb84f2&chksm=bd50b5448a273c5262dbb61f3b0f64a7803b91956f1e310b07aa21377a033e4c9d16f6142705#rd
如有侵权请联系:admin#unsafe.sh