[CTF/网络安全] 攻防世界 simple_js 解题详析
- 代码分析
- 代码漏洞
- 姿势
- String[fromCharCode]
- 总结
题目描述:小宁发现了一个网页,但却一直输不对密码。(Flag格式为 Cyberpeace{xxxxxxxxx} )
页面源代码:
代码分析
function dechiffre(pass_enc){
// 定义密钥,格式为 ASCII 码值的十进制数,以逗号分隔
var pass = "70,65,85,88,32,80,65,83,83,87,79,82,68,32,72,65,72,65";
// 将密文按逗号分隔,转换为数组形式
var tab = pass_enc.split(',');
// 定义一些变量
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 = tab2.length;
// 循环第一部分密文
for(i = (o=0); i < (k = j = n); i++ ){
o = tab[i-l];
// 将解密后的明文字符拼接到字符串 p 中
p += String.fromCharCode((o = tab2[i]));
if(i == 5)break;
}
// 循环第二部分密文
for(i = (o=0); i < (k = j = n); i++ ){
o = tab[i-l];
// 将解密后的明文字符拼接到字符串 p 中
if(i > 5 && i < k-1)
p += String.fromCharCode((o = tab2[i]));
}
// 将最后一个明文字符拼接到字符串 p 中
p += String.fromCharCode(tab2[17]);
// 将明文密码赋值给变量 pass
pass = p;
// 返回明文密码
return pass;
}
// 调用解密函数
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');
// 调用解密函数,并将解密结果弹出提示框显示给用户
alert(dechiffre(h));
代码漏洞
在代码中,使用了以下语句将明文密码赋值给变量 pass:
// 将明文密码赋值给变量 pass
pass = p;
然而,在解密函数的开头,我们并没有定义变量 p。 因此,JavaScript 将自动为我们创建一个全局 p 变量,并将所有未声明的变量都放在全局作用域中。
这意味着,用户输入密码(密文)并调用解密函数时,虽然得到了正确的明文密码,但是该明文密码被存储在了全局变量 p 中。
因此,当我们再次调用解密函数时,它会使用全局变量 p 中存储的上一次解密结果
而不是当前解密结果。
在解密函数 dechiffre()
的最后一行
return p || "FAUX PASSWORD HAHA";
使用了逻辑或运算符 ||
,如果变量 p
的值为假(如空字符串、null 或 undefined),则返回字符串 FAUX PASSWORD HAHA
由于代码在函数开始前并没有将全局变量 p
初始化,所以第一次运行时,变量 p
的值为 undefined,根据逻辑或运算符的规则,函数会返回字符串 FAUX PASSWORD HAHA
。而从第二次开始,因为变量 p
被全局污染,函数每次都会返回上一次的解密结果(即字符串 FAUX PASSWORD HAHA )
姿势
综上所述,输入的密码赋值给h,但h经过dechiffre函数处理后只会返回FAUX PASSWORD HAHA到页面。
切入点应该在:
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"));
String[fromCharCode]
String["fromCharCode"]
是 JavaScript 中的一个特殊属性,它是 String 对象的静态方法 fromCharCode() 的一个引用。该方法接收一系列 Unicode 码值作为参数,然后将这些码值转换成对应的字符,并返回一个新字符串。
例如,我们可以将 Unicode 码值 65 和 66 传递给 fromCharCode() 方法,以获取对应的字符 A 和 B:
var str = String.fromCharCode(65, 66);
console.log(str); // 输出 "AB"
将
\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
转换为ASCII码
const asciiString = "\\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";
const asciiArray = eval(`[${asciiString}]`);
console.log(asciiArray); // 输出 [55, 56, 54, 79, 115, 69, 114, 116, 107, 49, 50]
再进行ASCII编码
const asciiArray = [55, 56, 54, 79, 115, 69, 114, 116, 107, 49, 50];
const charSequence = String.fromCharCode(...asciiArray);
console.log(charSequence); // 输出 "786OsErtk12"
结合题目要求,Cyberpeace{786OsErtk12}
即为所求flag
总结
该题考察Javascript代码的解读
及不同数值类型的转换姿。
我是秋说,我们下次见,