【mugen】猴子也能看懂的mugen兇惡原理(1)——%n

工作之后驚訝的發(fā)現(xiàn)mugen中的兇惡技術居然和自己的工作相關,這下不得不研究一下了,錯誤之處評論區(qū)可以糾正。
1.???????? 什么是mugen
mugen是一個PC平臺的格斗游戲引擎,許多國家的人為其制作或者移植了非常多的格斗人物,變成了一款及其罕見的超多人制作的大亂斗游戲。
而又因為其程序本身存在漏洞(越界,棧溢出,字符串格式化),這些漏洞被利用起來加強人物殺傷力,導致出現(xiàn)了更罕見的兇惡玩法。
2.???????? %n初步學習
mugen中最出名也是最簡單的一個中期兇惡技術,叫做%n,本質上是一個字符串格式化漏洞。
以kfm和winmugen為例,mugen人物的邏輯代碼(比如定義一個人物的一個動作,執(zhí)行這個動作會調用哪些圖片,哪個音效,加多少氣等等)位于kfm.cns中。
需要先定義一個Statedef(狀態(tài)號),再在下面寫State(狀態(tài)控制器),感受下如下代碼。
兇惡代碼可以寫在[Statedef -3]中,因為它是最優(yōu)先運行的代碼,而且每一幀都會運行一次。比如可以寫一個簡單的加氣的代碼。
能稍微看懂這些我們就可以來嘗試%n了,代碼示例如下。
很明顯,存在漏洞的控制器是DisplayToClipBoard,以及AppendToClipBoard,從控制器名稱可以看得出來,這個功能本來是提供給制作者一個可以在剪切板中自由獲取值的接口。
它可以給Text設置占位符,同時輸入params,就會寫4931656(0x4b4048)內存上的值為0x30。任意調試器(od)打開mugen,載入人物進入watch就會發(fā)現(xiàn)地址成功被改寫。

好吧,這么看來都不需要字符串格式化漏洞那些高端的玩法,直接就是一個任意地址寫。
我們來嘗試追蹤下漏洞代碼,由于已經知道了會寫0x4b4048,可以下內存寫入的斷點,可以發(fā)現(xiàn)能斷在0x496CB6|mov dword ptr ds:[eax],ecx

Crtl+F9步進到retn之后回到0x4713AE,進入程序自定義的方法sub_46E800()。

可以發(fā)現(xiàn),上面的call 004967DF就是call _vsprintf,那么漏洞代碼發(fā)生在這里。a2和ArgList均可控制,這在pwn中是一個非常明顯的字符串格式化漏洞,通過%n可以實現(xiàn)任意地址寫。

重新斷點在0x4713A9,發(fā)現(xiàn)call之前已經完成壓棧。

就這樣簡簡單單我們擁有了任意地址寫。
?
3.???????? %n初步利用
有了任意地址寫,那么如何利用呢?先實驗一個簡單的修改當前人物信息的思路。
找到4B5B4C,這個位置存儲著mugen主程序絕對路徑的指針。


可以發(fā)現(xiàn)下方存儲著其他mugen相關屬性,參考https://qxmugen.com/article/11933.html
這里為了方便區(qū)分,弄兩個kfm人物包,并且修改name和/displayname
基地址3650048
+CD4,select.def內加載的人物數(shù)量
03650D1C? 00000002
+F7C,選人界面里,共有多少行
03650FC4? 00000007
+B654,P1 name指針
+B658,P2 name指針
0365B69C? 0CFC1C78 ASCII "kfm"
0365B6A0? 0D7AEAA0 ASCII "kfm2"

0CFC1C78? 006D666B? kfm.
P1 name指針+30 displayname
0CFC1CA8? 676E754B? Kung
0CFC1CAC? 20754620?? Fu
0CFC1CB0? 006E614D? Man.

如果手動用調試器修改0CFF1CA8地址的值,即可實時修改游戲中的顯示的人物名

如果我們拿%n修改人物名或者其他相關屬性不就可以達到目的了嗎?
但是由于ALSR原因,基地址3650048是不確定的,我們需要從4B5B4C拿到指針才知道具體的,而%n是無法返回某地址的值的(pwn中的傳統(tǒng)字符串格式化漏洞是可以的)。所以我們只能改寫那些固定的值,其中就包括按鍵輸出。
https://qxmugen.com/article/13197.html
mugen中F1可以讓2P側快速死亡,因此改寫這4B5948/4B594C/4B5548三個地址的值就夠了,可以多加一個判斷1P/2P的代碼,從而決定是否加ctrl(會導致1P死亡)。
?
這樣,一個最簡單的%n利用F1攻擊的代碼就出現(xiàn)了。