[心得] 基於記憶體溢位存取進行程式碼注入攻擊

看板ASM (組合語言)作者 (LeopardCat)時間1年前 (), 1年前編輯推噓6(602)
留言8則, 5人參與, 1年前最新討論串1/1
經驗分享──基於記憶體溢位存取進行程式碼注入攻擊 序、 自己於慕尼黑工業大學電機學院(TUM EI)中修習Embedded System and Security課程,其中作業與組合語言、嵌入式系統及資料安全相關,第一次學習這種系統安全的內容覺得相當有趣,但搞這個作業時也覺得相當挫敗,正好放假很閒,分享予各位。 平台為Infineon xmc4500 relax kit 開發板,arm cortex-m4 作業題目為在開發板上、於給定的程式中進行code injection attack,點亮開發板上的LED作為成功注入程式碼的證據。題目給定之程式為一加密功能的程式,要求便是攻擊此目標程式。透過於電腦上執行以python傳輸明碼(plaintext)至嵌入式平台,目標程式加密此plaintext,並將密文回傳至電腦上,流程圖如下,【攻擊方式便是透過特殊的plaintext輸入來執行攻擊】。作業內容算是偏簡單,給無經驗的駭客初學者練習個幾天多半就能完成。 https://i.imgur.com/vZ7Q2kF.jpg
Figure 0. flow chart 基本思路為透過stack overflow存取到return address (link register位置所儲存之資料),修改return address至injected code的位置,在pop pc指令時使pc (program counter)跳轉到injected code,完成code injection後再跳回正常程式的下個執行點。 自己在家要重現此事較為困難,由於需要有相似/相同之開發板XMC4500作為執行平台,並且由於原始碼著作權屬於課程助教,在此我不會提供完整題目程式碼,僅提供片段作為學習用途,但我想可能得有些先備知識才較能看懂我在寫什麼,出於懶貓貓問題我沒辦法把每件事情寫到很詳細,措辭可能會有不對的地方,例如lr其實不是個記憶體,是個register,但我會混用把儲存lr的記憶體位置稱作lr,不過應該差不多啦,自己搞過一遍應該能想通我在供三小。 各種內容都會中英混雜,搭配奇怪的縮寫,修embedded system時最恨的就是縮寫,教授跟助教永遠都用縮寫但我永遠都不知道是什麼意思,簡單列幾個大概會用到的 pc, program counter sp, stack pointer lr, link register fp, frame pointer KEY WORDS: code injection attack, stack-based buffer overflow, embedded system security 一、 基礎知識,Instruction memory與data memory 在記憶體儲存中的內容分為幾種,我這次用上的是instruction區和stack,分別對應儲存CPU指令內容(機器碼)跟local variable,其他還有像是heap儲存dynamic allocated variable、儲存initialized global variable的空間、儲存uninitialized global variable的空間,不過這些不重要。這些空間通常有固定的起始、終點記憶體位置,可以透過arm給的datasheet查到。在我這次使用的平台,arm cortex-m4,Instruction memory始於0x0800 0000,stack始於0x1000 0000,所以像是我的嵌入式系統在運作時,就會執行Instruction memory中的Machine Code (又或是可以視為反組譯後的Assembly code),function中使用的local variable就儲存在stack中。 在執行function call的時候,CPU會做幾件事情,0. Branch到function,pc跳轉到此function的instruction memory address,lr記錄caller的下個instruction memory address;1. 記錄lr,即下個instruction的address,作為在function return時pc要回到的位置,此數值push到stack;2. 記錄其他雜七雜八的register,一樣push到stack;3. 最後會把sp減去一定數值,把這些空出來的位置存local variable。這部分內容看看下方assembly code應該可以理解。 在執行function return時,CPU會做幾件事情,0. 把sp加回一定數值,因為local variable在function return後就沒用了;1. pop 一些register;2. pop pc,把過去lr記錄的數值弄回pc,這樣pc就會回到caller的下個instruction memory。一樣看看assembly code應該可以理解。 https://i.imgur.com/BCv8mUJ.jpg
Figure 1. instruction memory https://i.imgur.com/3kTHXgx.jpg
Figure 2. stack (local variable) 二、 基礎知識,buffer overflow與code injection attack 由於local variable和register、return address (lr)都儲存在stack中,如果在local variable中有靜態記憶體配置陣列,且user可以隨意賦予值而沒有長度確認,則可以輕鬆做到stack-based buffer overflow,即為漏洞,vulnerability,常見於memcpy, strcpy。 code injection attack就是透過把自己想要執行的程式碼,存到stack中,並將PC設定到這個地址來執行它。 透過寫入超過給定array長度的資料,做到stack-based buffer overflow,修改到return address的地址數值,就可以做到最簡單的code injection attack。 三、 本次題目的vulnerability 找漏洞算是很麻煩的地方,在這次作業中很貼心的附上了原始碼與debugger,但還是要些經驗才容易找到,至少一開始我花了整天在另一個function上。本題的加密其實跟要做code injection沒什麼關係,畢竟也不是要找ciphertext與plaintext的mapping,如下圖,加密只是XOR一個固定的數值,透過先加密個一串零就可以知道key是多少。 https://i.imgur.com/oME10vw.jpg
Figure 3. Vulnerability 上圖程式碼中,buf作為local variable且為靜態記憶體配置之陣列,會儲存128 bytes於stack中,由於沒有對長度作確認,當plaintext長度大於128 bytes時即發生stack overflow。透過debugger可以知道此frame中的各種情報,包含buf記憶體位置始於多少、lr位置為何,兩個一減就知道要寫入多長的資料到buf可以overflow到lr的位置。 https://i.imgur.com/e6lEXps.jpg
Figure 4. debugger, info frame 由上圖debugger資訊中,info frame 給了lr資料儲存於記憶體位置0x1000 07c4,print &buf給了buf資料始於0x1000 0738,寫入0x1000 07c4 - 0x1000 0738 + 4 bytes的資料至buf即可將最後的4bytes寫入到lr資料位置。 【只要將地址0x1000 07c4中的值,改寫成0x1000 0739】(某些原因要多1),function return後就會執行自buf開始的指令。意即,把自己要執行的機器碼塞到buf中,並且把lr改寫,讓return時pc跳轉到自buf開始的instruction memory address。 四、 Code injection attack攻擊實作 好,所以現在來回到一開始講的攻擊方式,透過輸入特殊的plaintext來攻擊,已知這段plaintext有0x1000 07c4 - 0x1000 0738 + 4 bytes,最後4bytes要為0x1000 0739,且要使buf前面一段作為injected code。 Injected code的生成,首先得搞出機器碼,這裡拿點亮板子上的LED為例,不過基本上就是你想幹嘛就幹嘛。要搞出機器碼也容易,寫個點亮LED的C code→編譯→反組譯出assembly code打開就會看到assembly code和machine code排排站站好了,取自己要的部分。 前述提及XOR加密部分,所以弄出來的machine code要先XOR一遍key,在function執行時會再XOR key一遍,才會回到正確的machine code。此外,需要逐byte作一些順序上的交換,畢竟到底記憶體要往上/下讀、讀完後要往上/下跑,這件事情很繁雜,不過拿debugger去查memory中存的值很好debug,就嘗試看看慢慢調整就好。 把plaintext寫到這裡應該可以點亮LED了,不過有個問題是程式接下來不會正常運行,畢竟把pc設到0x10開頭的地方本身就很有問題,正常的machine code存放在0x08開頭的地方,所以要再做一些加工,不過這裡就可能得寫assembly code了。 要讓程式回歸正常運行的辦法就是得把register中的值(包含pc/lr,其實它們也是個register)回復到正常的情況,當初為了修改到lr,一併修改了各個register中的值。因此在點亮LED的machine code後面加入一些對register賦值的machine code,最後把pc設回正常該回到的地方,就可以使程式繼續正常運行而不會發生錯誤。這邊由於得針對register作處理,我自己寫了幾行assembly code來編譯出machine code,這也是這次作業中自己要寫assembly code的地方了,其他就只是讀,然後寫C code。 五、 後話 基本上這份作業已經簡化相當多東西了,首先是提供source code、debugger,這是對駭客正常來說不會取得的東西(除非哪家廠商把自家產品firmware開源?),此外題目也經設計,多花點時間觀察、繞過各種陷阱就可以完成。 在軟體上,可以使用canary保護來避免overflow,即透過將locol variable整個用struct包起來,並在struct中最上方、最下方各擺一個canary變數,在一進function時賦同一值予此二canary變數,需隨機並且無法預判,如果overflow發生,則由於struct關係在改寫到register存放位置前一定會先改寫到其中一個canary的值,故在function結束前比較兩canary值是否仍相等,如不相等則overflow發生,報錯跳exception即可避免受攻擊。 在嵌入式系統中,也存在硬體保護,常見的有MPU (Memory Protect Unit),可以對記憶體區塊設置rwx權限(read, write, execute),所以例如說把stack設為rw-,把機器碼那塊設為r-x,當有人把對stack做code injection想要來執行時,pc就會跳到exception,停止執行,亦或是假如哪個人有超神方法可以改寫原始的machine code也會報錯,不過這就是作業第二題的內容了。相對應的攻擊方式變為code reuse attack (return-oriented attack),亦即不注入自己程式碼,而是透過不斷在原始machine code中return來、return去來達到自己要的目的,這個讓pc跳來跳去的過程奇複雜無比,要找到能用的code片段(稱為gadget, 小工具)就是難事,還得考慮sp的位置、register的值等等才能讓程式繼續正常運作而不報錯。 -- ※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 101.9.160.202 (臺灣) ※ 文章網址: https://www.ptt.cc/bbs/ASM/M.1584196474.A.217.html ※ 編輯: roger5486 (101.9.160.202 臺灣), 03/14/2020 23:11:35

03/15 04:04, 1年前 , 1F
找 gadget 的話 ropper 或 ROPgadget 或 pwntools 可能
03/15 04:04, 1F

03/15 04:04, 1年前 , 2F
能幫上忙....?沒碰過 arm的不太清楚,不過可以試試
03/15 04:04, 2F
修改內文加入gadget了,不過覺得近期自己不會再碰相關內容了......,讀assembly code 跟trace stack真的太辛苦了 ※ 編輯: roger5486 (101.9.160.202 臺灣), 03/15/2020 08:26:25

03/15 14:30, 1年前 , 3F
離開時funtion時push 那段是不是改成pop
03/15 14:30, 3F

03/15 14:31, 1年前 , 4F
離開function時push那段是不是應改成pop
03/15 14:31, 4F
沒錯,已修正~

03/15 15:08, 1年前 , 5F
感謝分享 ..近來最像asm板文章的一篇
03/15 15:08, 5F
※ 編輯: roger5486 (101.9.160.202 臺灣), 03/15/2020 20:40:19 ※ 編輯: roger5486 (101.9.160.202 臺灣), 03/15/2020 20:43:31

03/18 18:01, 1年前 , 6F
感謝分享
03/18 18:01, 6F

04/28 01:55, 1年前 , 7F
感謝分享
04/28 01:55, 7F

05/14 00:07, 1年前 , 8F
玩破解蠻基本的 但你算厲害了 很快就上手
05/14 00:07, 8F
文章代碼(AID): #1UREjw8N (ASM)
文章代碼(AID): #1UREjw8N (ASM)