吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 12254|回复: 91
上一主题 下一主题
收起左侧

[CTF] 【2021春节】解题领红包之番外篇分析

  [复制链接]
跳转到指定楼层
楼主
周易 发表于 2021-2-27 00:24 回帖奖励
本帖最后由 周易 于 2021-7-25 21:11 编辑

【2021春节】解题领红包之番外篇分析

番外篇一

解压文件,得到番外篇.js。打开文件,如图所示。由题目描述或de4js易得此为JSFuck处理过的。

番外篇一很简单,直接使用de4js或利用控制台即可还原。
还原后代码如下:

function _52pojie_MMXXI_(t) {
    let e = [];
    for (let f of t) {
        let t = f.codePointAt(0),
            h = 0;
        t -= 0x1d4 << 0x1c8, "bkd0egfw002whccadqf6gm0q3mi2".match(/../g).forEach(f => {
            f = parseInt(f, 0x24), t >= f && t < f + 0x1A && e.push(h % 7), h++
        })
    }
    let f = [];
    for (; e.length >= 3;) {
        let t = 0x31 * e.shift();
        if (t += 7 * e.shift(), (t += e.shift()) > 0xff) break;
        f.push(t)
    }
    return new Uint8Array(f);
    const flag1 = 'n0w_wh3r3_1s_th3_c1ph3rt3xt?'
}

容易看出flag1为n0w_wh3r3_1s_th3_c1ph3rt3xt?

番外篇二

我们分析函数_52pojie_MMXXI_,不难发现上半部分使用到了Unicode字符。不妨改造代码将其打印,结果如下:

t = 0x1d4 << 0x1c8, "bkd0egfw002whccadqf6gm0q3mi2".match(/../g).forEach(f => {
    f = parseInt(f, 0x24);
    for (let i = 0; i < 26; i++) {
        document.write(String.fromCodePoint(t + f + i))
    }
    document.write('<br>')
})
𝗔𝗕𝗖𝗗𝗘𝗙𝗚𝗛𝗜𝗝𝗞𝗟𝗠𝗡𝗢𝗣𝗤𝗥𝗦𝗧𝗨𝗩𝗪𝗫𝗬𝗭
𝘈𝘉𝘊𝘋𝘌𝘍𝘎𝘏𝘐𝘑𝘒𝘓𝘔𝘕𝘖𝘗𝘘𝘙𝘚𝘛𝘜𝘝𝘞𝘟𝘠𝘡
𝘼𝘽𝘾𝘿𝙀𝙁𝙂𝙃𝙄𝙅𝙆𝙇𝙈𝙉𝙊𝙋𝙌𝙍𝙎𝙏𝙐𝙑𝙒𝙓𝙔𝙕
𝐀𝐁𝐂𝐃𝐄𝐅𝐆𝐇𝐈𝐉𝐊𝐋𝐌𝐍𝐎𝐏𝐐𝐑𝐒𝐓𝐔𝐕𝐖𝐗𝐘𝐙
𝑨𝑩𝑪𝑫𝑬𝑭𝑮𝑯𝑰𝑱𝑲𝑳𝑴𝑵𝑶𝑷𝑸𝑹𝑺𝑻𝑼𝑽𝑾𝑿𝒀𝒁
𝙰𝙱𝙲𝙳𝙴𝙵𝙶𝙷𝙸𝙹𝙺𝙻𝙼𝙽𝙾𝙿𝚀𝚁𝚂𝚃𝚄𝚅𝚆𝚇𝚈𝚉
𝖺𝖻𝖼𝖽𝖾𝖿𝗀𝗁𝗂𝗃𝗄𝗅𝗆𝗇𝗈𝗉𝗊𝗋𝗌𝗍𝗎𝗏𝗐𝗑𝗒𝗓
𝗮𝗯𝗰𝗱𝗲𝗳𝗴𝗵𝗶𝗷𝗸𝗹𝗺𝗻𝗼𝗽𝗾𝗿𝘀𝘁𝘂𝘃𝘄𝘅𝘆𝘇
𝘢𝘣𝘤𝘥𝘦𝘧𝘨𝘩𝘪𝘫𝘬𝘭𝘮𝘯𝘰𝘱𝘲𝘳𝘴𝘵𝘶𝘷𝘸𝘹𝘺𝘻
𝙖𝙗𝙘𝙙𝙚𝙛𝙜𝙝𝙞𝙟𝙠𝙡𝙢𝙣𝙤𝙥𝙦𝙧𝙨𝙩𝙪𝙫𝙬𝙭𝙮𝙯
𝐚𝐛𝐜𝐝𝐞𝐟𝐠𝐡𝐢𝐣𝐤𝐥𝐦𝐧𝐨𝐩𝐪𝐫𝐬𝐭𝐮𝐯𝐰𝐱𝐲𝐳
𝒂𝒃𝒄𝒅𝒆𝒇𝒈𝒉𝒊𝒋𝒌𝒍𝒎𝒏𝒐𝒑𝒒𝒓𝒔𝒕𝒖𝒗𝒘𝒙𝒚𝒛
𝚊𝚋𝚌𝚍𝚎𝚏𝚐𝚑𝚒𝚓𝚔𝚕𝚖𝚗𝚘𝚙𝚚𝚛𝚜𝚝𝚞𝚟𝚠𝚡𝚢𝚣

很明显,我们应该找到一段Unicode原文作为参数,才能得到flag2。但是参数在哪里?这里感谢逍遥一仙给了思路。
在JavaScript中,有一个函数负责将Unicode转为ANSI。这就是String.prototype.normalize()
因此不妨重载该函数,得到参数。

(function() {
    var oldString_prototype_normalize = String.prototype.normalize;
    String.prototype.normalize = function() {
        console.log(this.toString() + '\n');
        for (let a of arguments) {
            console.log(a.toString() + '\n');
        }
        return oldString_prototype_normalize.apply(this, arguments);
    }
})();

首先在控制台中运行如上代码,然后再次运行题目,得到结果如下。

𝗋𝐞𝚝𝐮𝚛𝘯 𝙛𝘂𝙣𝙘𝗍𝘪𝙤𝐧 _52𝐩𝐨𝐣𝘪𝘦_𝐌𝙈𝙓𝐗𝘐_(𝐭){𝚕𝘦𝙩 𝗲=[];𝙛𝙤𝗋(𝙡𝘦𝒕 𝐟 𝐨𝚏 𝘵){𝙡𝗲𝙩 𝙩=𝖿.𝙘𝘰𝒅𝒆𝐏𝚘𝘪𝙣𝘁𝘼𝙩(0),𝗁=0;𝗍-=0𝙭1𝖽4<<0𝒙1𝐜8,"𝐛𝘬𝘥0𝐞𝐠𝙛𝗐002𝚠𝐡𝐜𝗰𝙖𝐝𝚚𝘧6𝐠𝙢0𝐪3𝚖𝘪2".𝙢𝗮𝙩𝙘𝗁(/../𝗴).𝙛𝙤𝙧𝐄𝐚𝘤𝘩(𝒇=>{𝖿=𝘱𝒂𝙧𝐬𝐞𝗜𝙣𝒕(𝖿,0𝙭24),𝘁>=𝘧&&𝐭<𝚏+0𝘹1𝘼&&𝗲.𝙥𝙪𝗌𝙝(𝙝%7),𝗁++})}𝗹𝐞𝚝 𝘧=[];𝙛𝗼𝙧(;𝙚.𝗅𝙚𝘯𝒈𝐭𝐡>=3;){𝐥𝘦𝘵 𝒕=0𝗑31*𝘦.𝒔𝘩𝗂𝐟𝚝();𝗂𝚏(𝐭+=7*𝘦.𝘀𝒉𝘪𝗳𝚝(),(𝘵+=𝘦.𝘴𝘩𝗶𝐟𝘁())>0𝚡𝚏𝘧)𝗯𝙧𝘦𝗮𝗄;𝘧.𝙥𝙪𝘴𝗁(𝙩)}𝗋𝒆𝒕𝗎𝒓𝐧 𝗻𝐞𝘄 𝗨𝙞𝗇𝘁8𝘼𝒓𝗿𝘢𝒚(𝖿);𝒄𝐨𝗇𝒔𝚝 𝚏𝒍𝐚𝗀1='𝐧0𝗐_𝙬𝗁3𝚛3_1𝘴_𝒕𝐡3_𝙘1𝙥𝗵3𝘳𝒕3𝙭𝘵?'}

这就是我们期待已久的参数了。
重新利用原来的_52pojie_MMXXI_函数,得到数组。我们将其写入文件,不难发现又是JavaScript代码。

"𝕳ⁱ𝖉𝖊𝓘ₙᵁ𝔫ⅈᶜ𝖔𝖉ⅇ".normalize('NFKD')

在控制台中运行即可得到flag2为HideInUnicode

后记

此题考查Unicode编码在JavaScript中的应用。

  • 关于如何想出重载
    在JavaScript中,重载一些函数可以使分析更为便捷。常用的重载有eval()Function构造函数等。
    在此题中,重载eval()也能得到结果。

免费评分

参与人数 30吾爱币 +32 热心值 +26 收起 理由
Kenny0521 + 1 + 1 谢谢@Thanks!
SmallBridge + 1 + 1 我很赞同!
ZenRoi + 1 + 1 谢谢@Thanks!
KizunaAI_PRC + 1 + 1 用心讨论,共获提升!
黝黑游泳圈怪 + 1 + 1 我很赞同!
sapeu + 1 用心讨论,共获提升!
hiddenKARD + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
victos + 1 + 1 谢谢@Thanks!
louchen1994 + 1 + 1 我很赞同!
gaosld + 1 + 1 谢谢@Thanks!
uai1314 + 1 用心讨论,共获提升!
xuqi + 1 + 1 谢谢@Thanks!
xiaoyang.liu + 1 + 1 我很赞同!
Phantaminuam. + 1 热心回复!
wangxiaohong888 + 1 + 1 谢谢@Thanks!
lookip + 1 + 1 用心讨论,共获提升!
fengbolee + 1 + 1 用心讨论,共获提升!
Ah0NoR + 1 + 1 谢谢@Thanks!
hu_sa + 1 我很赞同!
Test1908 + 1 + 1 厉害了,我的哥。
高维可破 + 1 用心讨论,共获提升!
从小就很傻 + 1 + 1 谢谢@Thanks!
gunxsword + 1 + 1 谢谢@Thanks!
Takitooru + 1 + 1 用心讨论,共获提升!
pojie_dd + 1 + 1 谢谢这么快出分析
兜兜风f + 4 + 1 谢谢@Thanks!
p程。 + 1 + 1 我很赞同!
alittlebear + 1 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
为之奈何? + 1 + 1 我很赞同!
CrazyNut + 2 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

推荐
wmsuper 发表于 2021-2-27 11:12
我是使用了一个更为麻烦的方法:
在native层对eval函数下断点:

推荐
逍遥一仙 发表于 2021-2-27 09:40
周易 发表于 2021-2-27 09:27
使用的Unicode编码,需要fromCodePoint而不是fromCharCode。
还有就是方便分享一下其他的方法吗?

免费评分

参与人数 2热心值 +2 收起 理由
高维可破 + 1 我很赞同!
周易 + 1 我很赞同!

查看全部评分

推荐
高维可破 发表于 2021-2-27 10:05
本帖最后由 高维可破 于 2021-3-2 07:56 编辑
周易 发表于 2021-2-27 09:27
使用的Unicode编码,需要fromCodePoint而不是fromCharCode。
还有就是方便分享一下其他的方法吗?

我的思路是通过分析jsfuck代码   jsfuck只有 +![]() 这6个字符  
除了 +! 之外  '[' 和 ']'  以及  '(' 和 ')' 要匹配平衡
所以我写了段小代码提取  所有匹配平衡的区间  
然后对应区间最大的开始尝试分析  使用 eval(jsfuck字符串) 得到对应的js代码
我们先设代码字符串为codeStr
eval(codeStr.substring(2015, 48520) )   得到
return function _52pojie_MMXXI_(t){let e=[];for(let f of t){let t=f.codePointAt(0),h=0;t-=0x1d4<<0x1c8,"bkd0egfw002whccadqf6gm0q3mi2".match(/../g).forEach(f=>{f=parseInt(f,0x24),t>=f&&t<f+0x1A&&e.push(h%7),h++})}let f=[];for(;e.length>=3;){let t=0x31*e.shift();if(t+=7*e.shift(),(t+=e.shift())>0xff)break;f.push(t)}return new Uint8Array(f);const flag1='n0w_wh3r3_1s_th3_c1ph3rt3xt?'}


eval(codeStr.substring(3044, 44250) )   得到
𝗋𝐞𝚝𝐮𝚛𝘯 𝙛𝘂𝙣𝙘𝗍𝘪𝙤𝐧 _52𝐩𝐨𝐣𝘪𝘦_𝐌𝙈𝙓𝐗𝘐_(𝐭){𝚕𝘦𝙩 𝗲=[];𝙛𝙤𝗋(𝙡𝘦𝒕 𝐟 𝐨𝚏 𝘵){𝙡𝗲𝙩 𝙩=𝖿.𝙘𝘰𝒅𝒆𝐏𝚘𝘪𝙣𝘁𝘼𝙩(0),𝗁=0;𝗍-=0𝙭1𝖽4<<0𝒙1𝐜8,"𝐛𝘬𝘥0𝐞𝐠𝙛𝗐002𝚠𝐡𝐜𝗰𝙖𝐝𝚚𝘧6𝐠𝙢0𝐪3𝚖𝘪2".𝙢𝗮𝙩𝙘𝗁(/../𝗴).𝙛𝙤𝙧𝐄𝐚𝘤𝘩(𝒇=>{𝖿=𝘱𝒂𝙧𝐬𝐞𝗜𝙣𝒕(𝖿,0𝙭24),𝘁>=𝘧&&𝐭<𝚏+0𝘹1𝘼&&𝗲.𝙥𝙪𝗌𝙝(𝙝%7),𝗁++})}𝗹𝐞𝚝 𝘧=[];𝙛𝗼𝙧(;𝙚.𝗅𝙚𝘯𝒈𝐭𝐡>=3;){𝐥𝘦𝘵 𝒕=0𝗑31*𝘦.𝒔𝘩𝗂𝐟𝚝();𝗂𝚏(𝐭+=7*𝘦.𝘀𝒉𝘪𝗳𝚝(),(𝘵+=𝘦.𝘴𝘩𝗶𝐟𝘁())>0𝚡𝚏𝘧)𝗯𝙧𝘦𝗮𝗄;𝘧.𝙥𝙪𝘴𝗁(𝙩)}𝗋𝒆𝒕𝗎𝒓𝐧 𝗻𝐞𝘄 𝗨𝙞𝗇𝘁8𝘼𝒓𝗿𝘢𝒚(𝖿);𝒄𝐨𝗇𝒔𝚝 𝚏𝒍𝐚𝗀1='𝐧0𝗐_𝙬𝗁3𝚛3_1𝘴_𝒕𝐡3_𝙘1𝙥𝗵3𝘳𝒕3𝙭𝘵?'}


这里就发现 这两段代码字面上看起来是一模一样  再加上之前对 _52pojie_MMXXI_ 的分析可以猜出对第二段代码里边包含了 _52pojie_MMXXI_ 涉及到的字符
于是 在区间 (2015, 48519) 中 除去 (3044, 44249) 应该还有  (2016, 3044) 以及 (44250, 48519) 这两个区间 通过分析
eval(codeStr.substring(2016, 3044) )  得到  
ƒ eval() { [native code] }


另外 (44250, 48519)  的这个并不是函数  没法eval得到结果  
从上述两步可以估计出整段jsfuck代码的动作是  eval(第二段代码字符串)     
     这里也说明可以通过hook eval方法得到我们要的参数的原因

这是我的大概思路  不过由于没有得出最终结果  所以就不了了之了

补充
整段jsfuck代码可以翻译为如下
Function(
    eval(`\`𝗋𝐞𝚝𝐮𝚛𝘯 𝙛𝘂𝙣𝙘𝗍𝘪𝙤𝐧 _52𝐩𝐨𝐣𝘪𝘦_𝐌𝙈𝙓𝐗𝘐_(𝐭){𝚕𝘦𝙩 𝗲=[];𝙛𝙤𝗋(𝙡𝘦𝒕 𝐟 𝐨𝚏 𝘵){𝙡𝗲𝙩 𝙩=𝖿.𝙘𝘰𝒅𝒆𝐏𝚘𝘪𝙣𝘁𝘼𝙩(0),𝗁=0;𝗍-=0𝙭1𝖽4<<0𝒙1𝐜8,"𝐛𝘬𝘥0𝐞𝐠𝙛𝗐002𝚠𝐡𝐜𝗰𝙖𝐝𝚚𝘧6𝐠𝙢0𝐪3𝚖𝘪2".𝙢𝗮𝙩𝙘𝗁(/../𝗴).𝙛𝙤𝙧𝐄𝐚𝘤𝘩(𝒇=>{𝖿=𝘱𝒂𝙧𝐬𝐞𝗜𝙣𝒕(𝖿,0𝙭24),𝘁>=𝘧&&𝐭<𝚏+0𝘹1𝘼&&𝗲.𝙥𝙪𝗌𝙝(𝙝%7),𝗁++})}𝗹𝐞𝚝 𝘧=[];𝙛𝗼𝙧(;𝙚.𝗅𝙚𝘯𝒈𝐭𝐡>=3;){𝐥𝘦𝘵 𝒕=0𝗑31*𝘦.𝒔𝘩𝗂𝐟𝚝();𝗂𝚏(𝐭+=7*𝘦.𝘀𝒉𝘪𝗳𝚝(),(𝘵+=𝘦.𝘴𝘩𝗶𝐟𝘁())>0𝚡𝚏𝘧)𝗯𝙧𝘦𝗮𝗄;𝘧.𝙥𝙪𝘴𝗁(𝙩)}𝗋𝒆𝒕𝗎𝒓𝐧 𝗻𝐞𝘄 𝗨𝙞𝗇𝘁8𝘼𝒓𝗿𝘢𝒚(𝖿);𝒄𝐨𝗇𝒔𝚝 𝚏𝒍𝐚𝗀1='𝐧0𝗐_𝙬𝗁3𝚛3_1𝘴_𝒕𝐡3_𝙘1𝙥𝗵3𝘳𝒕3𝙭𝘵?'}\``)
    ["normalize"]("NFKD")
)


这里先对 字符串模板进行 eval , 然后对eval的结果进行 normalize  最后作为参数传递给 Function  生成一个匿名函数

免费评分

参与人数 2吾爱币 +16 热心值 +1 收起 理由
Coxxs + 15 + 1 最后的数组是 UTF-8 编码的字符串,感谢分享!
周易 + 1 用心讨论,共获提升!

查看全部评分

推荐
BestSum 发表于 2021-2-27 15:57
本帖最后由 BestSum 于 2021-2-27 16:21 编辑

把发的数据后面的()去掉,然后在后面加上.toString(),放入控制台即可还原全部代码,不过我做到这一步还是不会做。。
结合大佬做的成果写的html  :  https://ddms.lanzouj.com/iDzx4m8xamf
沙发
青春莫相随 发表于 2021-2-27 00:40
学习了学习了
3#
sauterne 发表于 2021-2-27 01:31
这个太强了吧  来学习了!不过最后那个真的不是乱码吗&#128514;
头像被屏蔽
4#
First丶云心 发表于 2021-2-27 07:12
学习学习!
5#
刀大喵 发表于 2021-2-27 08:27
本帖最后由 刀大喵 于 2021-2-27 08:31 编辑

我就是卡在这里了   期待其他题目解题思路
答案竟然还能提交  150CB到手
6#
gunxsword 发表于 2021-2-27 08:40
JS不懂,FLAG1,通过努力,也成功了,但是这个题二,怎么也看不懂,实在是没办法
所以一直在期待教程,要学习一波
但是....我真没看懂,55555555
7#
zhangchuanfei 发表于 2021-2-27 08:43
学习了学习了
8#
 楼主| 周易 发表于 2021-2-27 08:47 |楼主
gunxsword 发表于 2021-2-27 08:40
JS不懂,FLAG1,通过努力,也成功了,但是这个题二,怎么也看不懂,实在是没办法
所以一直在期待教程,要学习一波 ...

进行了补充,可以看后记。
JavaScript的加密常常用到执行字符串表达式、创建函数。
因此重载eval()或Function构造函数可以便于分析。
相当于HOOK。
9#
fightf1y 发表于 2021-2-27 08:53
学习了!!!!
10#
高维可破 发表于 2021-2-27 09:13
本帖最后由 高维可破 于 2021-2-27 09:34 编辑

我通过另外的方式也得到了作者同样的参数字符串  
但使用 _52pojie_MMXXI_函数 得到如下 长度为 66的 Uint8 数组
[JavaScript] 纯文本查看 复制代码
[34, 240, 157, 149, 179, 226, 129, 177, 240, 157, 150, 137, 240, 157, 150, 138, 240, 157, 147, 152, 226, 130, 153, 225, 181, 129, 240, 157, 148, 171, 226, 133, 136, 225, 182, 156, 240, 157, 150, 148, 240, 157, 150, 137, 226, 133, 135, 34, 46, 110, 111, 114, 109, 97, 108, 105, 122, 101, 40, 39, 78, 70, 75, 68, 39, 41]

使用  String.fromCodePoint.apply(null, 数组) 得到的是 这样的代码
[JavaScript] 纯文本查看 复制代码
"e&#157;&#8226;3a&#129;±e&#157;–‰e&#157;–&#352;e&#157;“&#732;a&#8218;&#8482;áμ&#129;e&#157;”&#171;a…&#710;á&#182;&#339;e&#157;–”e&#157;–‰a…&#8225;".normalize('NFKD') 

就一直卡在这
不太理解作者怎么得到上述的代码的   好奇好奇
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-15 07:53

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表