Web_XCTF_WriteUp | simple_js
题目
提示:
小宁发现了一个网页,但却一直输不对密码。(Flag格式为 Cyberpeace{xxxxxxxxx} )
题目:
分析
F12 打开查看器找到一串 JS 代码:
分析一下大致意思:
function dechiffre(pass_enc){
var pass = "70,65,85,88,32,80,65,83,83,87,79,82,68,32,72,65,72,65"; // 变量pass赋值
var tab = pass_enc.split(','); // 变量tab接受pass_enc参数按“,”拆分返回的新数组
// 变量tab2接受pass参数按“,”返回的新数组
// 定义变量 i、j、k、l(初始化为0)、m、n、o、p(初始化为空字符串
// i初始化为0
// j初始化为tab中拆分数组的个数(即pass_enc被拆分的个数)
var tab2 = pass.split(',');var i,j,k,l=0,m,n,o,p = "";i = 0;j = tab.length;
k = j + (l) + (n=0); // n赋值为0,计算j+l+n的值赋给k
n = tab2.length; // n赋值为tab2中拆分数组的个数(即pass被拆分的个数)
// 变量o赋值为0,变量j接收变量n的赋值,变量k接收变量j的赋值。循环n次
// tab第i-l个元素赋给o
// tab2第i个元素赋值给o,p尾部拼接o创建的字符串
for(i = (o=0); i < (k = j = n); i++ ){o = tab[i-l];p += String.fromCharCode((o = tab2[i]));
// 当i等于5时跳出循环
if(i == 5)break;}
// 变量o赋值为0,变量j接收变量n的赋值,变量k接收变量j的赋值。循环n次
for(i = (o=0); i < (k = j = n); i++ ){
// tab第i-l个元素赋给o
o = tab[i-l];
// 如果i大于5且小于k-1
if(i > 5 && i < k-1)
// tab2第i个元素赋值给o,p尾部拼接o创建的字符串
p += String.fromCharCode((o = tab2[i]));
}
p += String.fromCharCode(tab2[17]); // p尾部拼接tab2第17个元素
pass = p;return pass; // p赋值给pass。返回pass
}
// 调用dechiffre,将返回值转为字符
String["fromCharCode"](dechiffre("\x35\x35\x2c\x35\x36\x2c\x35\x34\x2c\x37\x39\x2c\x31\x31\x35\x2c\x36\x39\x2c\x31\x31\x34\x2c\x31\x31\x36\x2c\x31\x30\x37\x2c\x34\x39\x2c\x35\x30"));
h = window.prompt('Enter password'); // 打开显示提示文本为“Enter password”的提示窗口
alert( dechiffre(h) ); // h作为参数调用函数dechiffre,弹窗显示
这个排版真是…(吸气)
整体看下来,dechiffre 函数里有两个字符串,分别是输入的 pass_enc 和原有的 pass。运行过程中,pass_enc 和 pass 按 “,” 被拆分,分别放在 tab 和 tab2 两个变量中。
在两个 for 循环中,变量 p 不断拼接 o 的字符串形式,并最终作为返回值传递。
变量 o 在被赋值为 tab 的第 i-l 个元素后没有进行任何操作,很快被赋值为 tab2 的第 i 个元素。
也就是说,我们输入的 pass_enc 值其实并没有参与运行,即输入的 Enter password 对输出结果不造成影响,而浏览器实际输出的是将 70,65,85,88,32,80,65,83,83,87,79,82,68,32,72,65,72,65
转化为字符串的结果。
同时,String["fromCharCode"](dechiffre("\x35\x35\x2c\x35\x36\x2c\x35\x34\x2c\x37\x39\x2c\x31\x31\x35\x2c\x36\x39\x2c\x31\x31\x34\x2c\x31\x31\x36\x2c\x31\x30\x37\x2c\x34\x39\x2c\x35\x30"));
似乎只是调用了 dechiffre 函数,结果并没有作为输出显示,很奇怪。
综上,我们需要将 tab2 和 tab 的地位进行替换,即将代码第 3 行的 tab 改为 tab2,第 8 行的 tab2 改为 tab,第 10 行的循环次数 n 的由 tab2.length 改为 tab.length。
但更改后的代码依旧需要在弹窗中输入密码,我们手头仅有的可能就是调用了 dechiffre 但没有输出的那串字符。尝试将这串字符作为输入直接填入代码。
一番摸索后,我们找到了将更改后的代码运行在浏览器上的方式,更改后的代码内容如下:
<html><body><script>
function dechiffre(pass_enc){
var pass = "70,65,85,88,32,80,65,83,83,87,79,82,68,32,72,65,72,65";
var tab2 = pass_enc.split(',');
var tab = pass.split(',');var i,j,k,l=0,m,n,o,p = "";i = 0;j = tab.length;
k = j + (l) + (n=0);
n = tab.length;
for(i = (o=0); i < (k = j = n); i++ ){o = tab[i-l];p += String.fromCharCode((o = tab2[i]));
if(i == 5)break;}
for(i = (o=0); i < (k = j = n); i++ ){
o = tab[i-l];
if(i > 5 && i < k-1)
p += String.fromCharCode((o = tab2[i]));
}
p += String.fromCharCode(tab2[17]);
pass = p;return pass;
}
h = window.prompt('Enter password');
alert(dechiffre("\x35\x35\x2c\x35\x36\x2c\x35\x34\x2c\x37\x39\x2c\x31\x31\x35\x2c\x36\x39\x2c\x31\x31\x34\x2c\x31\x31\x36\x2c\x31\x30\x37\x2c\x34\x39\x2c\x35\x30") );
</script></body></html>
将代码保存为 html 文件,用浏览器打开,点击确定后得到一串十位字符:
看字符串内容不像某种类型的编码,尝试作为 flag 提交,确定为 flag 内容。
Flag
Cyberpeace{786OsErtk12}
参考
JavaScript 教程-菜鸟教程
js中的连续赋值-瓶盖的盖-CSDN博客
JavaScript中字符串连接/拼接的四种方式-Colbyzn-CSDN
JavaScript String 对象-菜鸟教程
HTML(.htm或.html)文件怎么打开?-柚子-知乎.html
html基本格式-yzyggu-CSDN博客
HTML<script>标签-菜鸟教程