前言
最近,Err0r師傅把他們新生賽的賽題源碼甩給我,我直接點開ezphp,發現這題很巧妙,題目源碼不長,並且很有意思!這裏面涉及到的知識點在之前也是比較少接觸到的。因此,這篇文章將會對這道題從解題再到原理剖析逐步深入。
解題嘗試
首先,題目源碼在網頁中打開是這樣的
當一個Web方向的CTFer初步審計完源代碼後,一定會覺得,這道題怎麼這麼簡單,不就傳兩個參數就能輸出flag了嘛
所以,Web手在初步審計完這道題之後,就會毫不猶豫地打出自己的一個payload(包括我):
?username=admin&password=s3cctf
這個時候Web手就納悶了,命名傳參都是對的怎麼不輸出flag呢?
經過仔細地查看題目後就會發現,這源代碼眼見不爲實!
我明明只選中了s3c到pass的部分,怎麼後面註釋的部分也被選中了?
這裏面可能會有一些蹊蹺?
於是下定決心審計一下源代碼
這一看,發現瀏覽器渲染的和源代碼有出入。原本$_GET
後面是[password]
,怎麼這後面變成了CTF
了呢?
審計源代碼可能對解題也沒有什麼幫助,那麼就把源碼複製下來之後看看
複製下來之後打開,和瀏覽器解析的做一個比較
好傢伙,這個時候瀏覽器解析的和用sublime打開的又不一樣了
註釋後面的CTF跑到了前面的s3cctf中去了,兩個&&
符號之間又多了奇奇怪怪的符號
因此瀏覽器和sublime都不能相信了,只能把文件用winhex打開才相對最可信
用winhex打開如下:
在這裏我們就能看出變量名以及我們要傳的參數值到底是什麼了
其中需要的參數值如下:
也就是:
E2 80 AE E2 81 A6 43 54 46 E2 81 A9 E2 81 A6 73 33 63 63 74 66
而變量名爲:
E2 80 AE E2 81 A6 53 33 63 E2 81 A9 E2 81 A6 70 61 73 73 77 6F 72 64
因此將其進行URL編碼後傳參:
?username=admin&%E2%80%AE%E2%81%A6%53%33%63%E2%81%A9%E2%81%A6%70%61%73%73%77%6F%72%64=%E2%80%AE%E2%81%A6%43%54%46%E2%81%A9%E2%81%A6%73%33%63%63%74%66
即可得到flag:
那麼這道題究竟是怎麼出的?原理是什麼?接下來的篇幅將會進行分析!
原理剖析
在探究原理之前,我們先要有一雙善於發現異常的眼睛
除了上面提到的一個異常(選中部分字符,其餘未被選中的字符也被選中了),其實還有兩個異常點。
-
第三行註釋行的
HelloCTFer
也有異常
我們將其進行選中
明明選中了//
到CTF
的部分,中間的Hello
卻沒有被選中
我們再換個姿勢進行選中
明明只選中了// He
的部分,後面的CTFer
卻也被選中了
因此我們可以確定,在//
後面一定有特殊的字符,使得原本應該在Hello
前面的CTFer
顯示在了後面。
-
第四行最後的註釋
S3cCTF
顏色有問題
同樣,如果仔細觀察第四行的註釋部分也會發現顯示有點問題
這裏的代碼都是通過show_source
函數進行打印的,而show_source
函數在高亮源代碼的時候,其代碼顏色是按照php.ini
中的設置來的。
也就是說,在註釋後面的藍色S3c
本身應該屬於前面password
中的內容,而後面的CTF
同樣也應該是屬於前面s3cctf
中的內容
那麼究竟是哪些神祕的字符導致這樣的現象呢?
同樣我們還是打開winhex
我們先查看比較短的// HelloCTFer
註釋行,對其進行分析。
內容如下:
2F 2F 20 E2 80 AE E2 81 A6 43 54 46 65 72 E2 81 A9 E2 81 A6 48 65 6C 6C 6F
我們將其稍作拼接,將可見的ASCII碼字符拼接在一起
拼接之後的內容如下:
2F2F20 E280AEE281A6 4354466572 E281A9E281A6 48656C6C6F
稍作分析,對應的內容就是這樣:
我們再對特殊字符進行分析,發現這個特殊字符應該是三個字節三個字節分開的
所以這裏面一共出現了三組三個字節的編碼分別是:E280AE、E281A6、E281A9
接下來對這三個特殊字符進行分析:
E280AE
對於這個特殊字符,它是Unicode編碼U+202E
轉UTF-8對應的十六進制編碼
它的名字叫做從右往左強制符
在unicode-table.com網站中對其介紹如下:
它的作用就是:根據內存順序從右至左顯示字符
我們可以寫一個Python小腳本,來看看這個字符是怎麼顛覆我們的認知的。
if__name__== "__main__": print("Hello"+u"\u202e"+"World")
輸出結果如下:
可以看到,後面的World
變成了dlroW
,並且當我們選中的H
到r
字符時,後面的oW
卻被選中了
E281A6
對於這個特殊字符,它的Unicode編號爲:U+2066
外網上對這個字符作用描述是:
說人話就是:這之間的字符從左到右顯示,不影響waiwei字符
E281A9
這個字符的Unicode編號爲:U+2069
它的作用其實就是:作爲RLI、LRI、FSi
翻轉結束的標識
這個時候我們再把上面的HelloCTFer
拿出來進行分析:
我們就可以知道那段註釋行的原理
原理就如下圖所示
瀏覽器進行解析的時候,自然是按照上方十六進制的順序進行解析,但是解析並不代表着輸出,瀏覽器的輸出結果需要根據底層字符的含義進行輸出,當瀏覽器看到E280AE
時,就知道後面的字符需要從右到左顯示,而解析到E281A6
時,瀏覽器就會知道將後面的字符從左往右輸出,也就是CTFer
輸出結果仍然爲CTFer
而不是reFTC
。當瀏覽器按照這樣的規則把Hello
解析完成之後,便會根據E280AE
的從右往左輸出的原則,將CTFer
與Hello
兩個交換順序,最終我們在瀏覽器中看到的結果便是HelloCTFer
。
即使輸出的結果是HelloCTFer
,符合我們的認知,但是當我們用鼠標進行拖動的時候,電腦還是會那麼貼心的幫我們把特殊符號加上,導致我們拖動Hello
的時候,CTFer
也被選中了