前情回顧:
線程老哥執行memcpy越界訪問溢出,堆棧里的一眾對象難逃噩運。
詳情參見:堆棧里的悄悄話——智能指針
神秘的0xCC
“去吧,為了首領的偉大理想出發”
我是一段二進制代碼shellcode,0xCC大人精心創造了我,一同誕生的還有一個HTML表單文件小P,我就棲身在小P的身上,隨着一個POST請求,我們朝着目標奔去。
很快我們就抵達目的地,這是一個Linux帝國,無數的數據包在這里來來往往。
“這里可真熱鬧”
“噓,先別說話,馬上要經過防火牆,藏好了,可別被發現了”,小P一把捂住了我的嘴。
說完我們就來到了防火牆面前,當差的守衛查看了我們的源IP和端口,又看了目的IP和目的端口,接着瞟了一眼負載數據,當他望向我這邊時,我緊張的大氣都不敢出一聲,把頭深深的埋着。
守衛凶神惡煞的問到:“你是去80端口的?這里面裝的是什么?”
“回大人的話,這里面是個HTML表單,這單業務比較急,還望大爺行個方便”,小P一邊說一邊悄悄給守衛的衣袖里塞了一些銀兩。
“走吧,放行!”,總算等來了守衛的這句話。
通過了安檢,我倆被安排到了一個隊列等待,一會兒,一個自稱是Apache公司的線程大哥把我們取走了。
棧溢出 & Stack Cannary
線程大哥把我倆放到了一片陌生的區域。
“你等我一下,我去打聽下情況”,小P叮囑完我后,和隔壁一個對象聊了起來。
“我打聽清楚了,這里是進程的堆區,你可還記得主人交代的任務嗎?”,小P問我。
“當然記得,我是shellcode,我要獲得執行機會,潛伏起來,和主人取得聯系,等待下一步指示”
“嗯,很好,一會我會找機會讓你獲得執行機會,先等等”“你要怎么辦到啊?”,我有點好奇。
“你看到那個線程的棧沒?”,小P一邊說一邊給我指。順着小P指的方向望去,我看到了他口中所說的棧,線程大哥正在旁邊忙碌,一會push,一會兒pop。
“我看到了,你猜你是想用棧溢出攻擊覆蓋返回地址,劫持指令寄存器,讓我獲得執行機會吧?”,我轉頭看着小P。
“小子,知道的不少嘛!不過你只回答對了一半,咱這次沒法覆蓋返回地址來獲得執行機會”
“哦,這卻是為何”
小P又指向了線程棧,“你看,返回地址前面有個8字節數字,那個叫Stack Cannary,是Linux帝國抵御棧溢出攻擊的手段”
“不就是8個字節的數字,有什么可怕的?”,我不屑一顧。
“可不要小瞧了它,當棧溢出數據被修改后,函數return時,在從棧中取出返回地址之前會檢查它有沒有被修改,一旦被發現修改過,進程就會終止,咱們的計划不就泡湯了嗎?”
“這程序員還挺聰明的嘛!居然還做了檢查”
“這可不是程序員做的,這是GCC編譯器干的,只要編譯的時候添加了-fstack-protector標記就會自動添加,對原來的程序代碼是透明的”
聽着小P的話,我陷入了沉思。
C++虛函數表
“如此一來,那豈不是不能使用棧溢出了?”
“也不盡然。直接覆蓋返回地址是基本不太可能了,過不了函數返回時的檢查。但可以在它做檢查之前就動手,搶先一步劫持執行流程,就沒有機會做檢查了。”,說完小P朝我眨了眨眼睛。
還有這種操作,我還是第一次聽說,“不覆蓋返回地址怎么能劫持到執行流程呢?你打算怎么做?”
“噓!線程大哥來了!”我一下趴着不敢動彈,余光中瞥見線程大哥取出了隔壁對象的前面8個字節后就離開了。
“好險,差點被發現,你呀,說話別那么大聲,計划敗露那就全完了,知道嗎!”,小P把我訓了一頓。
“好啦,我知道了。我剛才問你的問題你還沒回答我呢”,這一次我壓低了音量。
“你猜剛剛線程大哥過來讀取的是什么?”小P神秘地說。
“不是取的隔壁對象的內容嗎?你也看到了啊還問我”
“這我當然知道,我是問你那內容是什么?”
“這我怎么知道,我又不知道那是個什么對象”
小P用手臂把我的頭挽在胸前,在我耳邊輕輕說到:“他讀取的應該是對象的虛函數表指針,你看線程大哥讀完內容后,又去這內容指向的地方了,你再看那里有一個表格,表格里每一項都是一個函數的地址”我按他說的看過去,果如他所言,只見線程大哥讀取了表格中的一項后轉身就去執行那里的代碼了。
“你饒了半天,還沒告訴我你打算怎么讓我獲得執行機會呢”,我又一次提出了我的疑問。
“你別着急啊,這秘訣就在這虛函數表指針上。你再看看線程棧,瞧見沒有,那里也有一個對象,咱只要把它的虛函數表指針覆蓋,待會兒線程大哥調用它的方法時,來讀取的地址,我就安排成你的地址,就能讓你有機會執行了”
我腦子飛速運轉想象了一下這幅畫面:
“果然是妙招!不過你怎么知道對象的虛函數表指針在哪里呢?”,我向小P提出了疑問。
“虛表指針一般都是在對象的頭部,也就是最前面8個字節”
“所有對象都是嗎?”小P搖搖頭,“那倒也不是,有些對象所屬的類根本沒有虛函數,那也就沒有虛函數表,虛表指針更是無從談起了。不過這個對象是有的,主人在創造我們時已經都提前研究好了。咱們只需靜待時機,按計划行事即可。”
DNS隱蔽通信
“快醒醒,該我們上了”,小P把我叫醒,不知過了多少時間, 我竟然睡着了。
只見線程大哥執行了memcpy,把我和小P一起復制到了棧里。
我昏沉的腦袋一下子清醒了過來,下意識的看了一下之前那對象,現在他就在我上面不遠處,已經被小P的身體覆蓋掉了,再仔細一看這對象的前8個字節,指向的函數表就在我的頭頂,而表中每一項都指向了我所在的地址,0xCC大人果然安排的天衣無縫。
果不出乎所料,按照周密的計划,我終於等來了執行的機會,潛伏這么久,總算是可以活動活動了。
“你在干嘛?”,小P大聲喝住了我。
“按照計划,我在和0xCC大人聯系啊”
“你就這樣直接建立網絡連接嗎?一會兒防火牆就會發現了”,小P面色凝重。
我有點不解,“那要怎么辦?我怎么和大人聯系上?”
“臨行前大人叮囑我了,用DNS請求把數據帶出去,把數據編碼后作為請求的域名,分多片發出去”
按照小P的策略,我把通信內容先進行了一次加密,然后再使用base64編碼后,拆成了三段,准備用三個DNS請求給發出去。
“等一下,你不能使用0xCC大人的IP作為目的IP地址,會被防火牆發現的,就使用這里默認的DNS服務器地址就好了”,小P又一次喝止了我。
“使用這里默認的DNS服務器地址,那大人怎么能收到消息呢?”,我有點納悶。
“放心,路由器那里已經安排好了!”
未完待續·······
彩蛋
“咦,DNS數據包發送失敗了!”
“應該是沒有權限,快翻一下大人給你准備的Linux提權指南”
欲知后事如何,請關注后續精彩......
往期熱門文章: