這個符號竟然可以從右往左打印字符串

前言

最近,Err0r師傅把他們新生賽的賽題源碼甩給我,我直接點開ezphp,發現這題很巧妙,題目源碼不長,並且很有意思!這裏面涉及到的知識點在之前也是比較少接觸到的。因此,這篇文章將會對這道題從解題再到原理剖析逐步深入。

解題嘗試

首先,題目源碼在網頁中打開是這樣的

image-20211203182504145

當一個Web方向的CTFer初步審計完源代碼後,一定會覺得,這道題怎麼這麼簡單,不就傳兩個參數就能輸出flag了嘛

所以,Web手在初步審計完這道題之後,就會毫不猶豫地打出自己的一個payload(包括我):

?username=admin&password=s3cctf

image-20211203182747836

這個時候Web手就納悶了,命名傳參都是對的怎麼不輸出flag呢?

經過仔細地查看題目後就會發現,這源代碼眼見不爲實!

image-20211203183037861

我明明只選中了s3cpass的部分,怎麼後面註釋的部分也被選中了?

這裏面可能會有一些蹊蹺?

於是下定決心審計一下源代碼

image-20211203183340123

這一看,發現瀏覽器渲染的和源代碼有出入。原本$_GET後面是[password],怎麼這後面變成了CTF了呢?

審計源代碼可能對解題也沒有什麼幫助,那麼就把源碼複製下來之後看看

複製下來之後打開,和瀏覽器解析的做一個比較

image-20211203184423562

好傢伙,這個時候瀏覽器解析的和用sublime打開的又不一樣了

註釋後面的CTF跑到了前面的s3cctf中去了,兩個&&符號之間又多了奇奇怪怪的符號

因此瀏覽器和sublime都不能相信了,只能把文件用winhex打開才相對最可信

用winhex打開如下:

image-20211203184705878

在這裏我們就能看出變量名以及我們要傳的參數值到底是什麼了

其中需要的參數值如下:

image-20211203184901987

也就是:

E2 80 AE E2 81 A6 43  54 46 E2 81 A9 E2 81 A6  73 33 63 63 74 66

而變量名爲:

image-20211203185319790

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:

image-20211203190250865

那麼這道題究竟是怎麼出的?原理是什麼?接下來的篇幅將會進行分析!

原理剖析

在探究原理之前,我們先要有一雙善於發現異常的眼睛

除了上面提到的一個異常(選中部分字符,其餘未被選中的字符也被選中了),其實還有兩個異常點。

  1. 第三行註釋行的HelloCTFer也有異常

我們將其進行選中

image-20211203191136579

明明選中了//CTF的部分,中間的Hello卻沒有被選中

我們再換個姿勢進行選中

image-20211203191259033

明明只選中了// He的部分,後面的CTFer卻也被選中了

因此我們可以確定,在//後面一定有特殊的字符,使得原本應該在Hello前面的CTFer顯示在了後面。

  1. 第四行最後的註釋S3cCTF顏色有問題

同樣,如果仔細觀察第四行的註釋部分也會發現顯示有點問題

這裏的代碼都是通過show_source函數進行打印的,而show_source函數在高亮源代碼的時候,其代碼顏色是按照php.ini中的設置來的。

image-20211203191720639

也就是說,在註釋後面的藍色S3c本身應該屬於前面password中的內容,而後面的CTF同樣也應該是屬於前面s3cctf中的內容

那麼究竟是哪些神祕的字符導致這樣的現象呢?

同樣我們還是打開winhex

我們先查看比較短的// HelloCTFer註釋行,對其進行分析。

image-20211203192034798

內容如下:

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

稍作分析,對應的內容就是這樣:

image-20211203192432227

我們再對特殊字符進行分析,發現這個特殊字符應該是三個字節三個字節分開的

所以這裏面一共出現了三組三個字節的編碼分別是:E280AEE281A6E281A9

接下來對這三個特殊字符進行分析:

E280AE

對於這個特殊字符,它是Unicode編碼U+202E轉UTF-8對應的十六進制編碼

它的名字叫做從右往左強制符

在unicode-table.com網站中對其介紹如下:

image-20211203193206283

它的作用就是:根據內存順序從右至左顯示字符

image-20211203193407573

我們可以寫一個Python小腳本,來看看這個字符是怎麼顛覆我們的認知的。

if__name__== "__main__":
print("Hello"+u"\u202e"+"World")

輸出結果如下:

image-20211203195500689

可以看到,後面的World變成了dlroW,並且當我們選中的Hr字符時,後面的oW卻被選中了

E281A6

對於這個特殊字符,它的Unicode編號爲:U+2066

外網上對這個字符作用描述是:

image-20211203193632817

說人話就是:這之間的字符從左到右顯示,不影響waiwei字符

E281A9

這個字符的Unicode編號爲:U+2069

它的作用其實就是:作爲RLI、LRI、FSi翻轉結束的標識

image-20211203193845872

這個時候我們再把上面的HelloCTFer拿出來進行分析:

我們就可以知道那段註釋行的原理

原理就如下圖所示

image-20211203194141346

瀏覽器進行解析的時候,自然是按照上方十六進制的順序進行解析,但是解析並不代表着輸出,瀏覽器的輸出結果需要根據底層字符的含義進行輸出,當瀏覽器看到E280AE時,就知道後面的字符需要從右到左顯示,而解析到E281A6時,瀏覽器就會知道將後面的字符從左往右輸出,也就是CTFer輸出結果仍然爲CTFer而不是reFTC。當瀏覽器按照這樣的規則把Hello解析完成之後,便會根據E280AE的從右往左輸出的原則,將CTFerHello兩個交換順序,最終我們在瀏覽器中看到的結果便是HelloCTFer

即使輸出的結果是HelloCTFer,符合我們的認知,但是當我們用鼠標進行拖動的時候,電腦還是會那麼貼心的幫我們把特殊符號加上,導致我們拖動Hello的時候,CTFer也被選中了

image-20211203195011181

參考資料

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章