密碼控件安全技術(shù)淺析及攻擊實(shí)例
密碼控件是一個(gè)很常見(jiàn)的控件,這篇文章主要介紹一下安全密碼控件的一些實(shí)現(xiàn)思路和攻擊思路。
1 物理密碼鍵盤和密碼控件的對(duì)比
先說(shuō)一下程序中的密碼控件和現(xiàn)實(shí)中的密碼鍵盤的對(duì)比。幾乎每個(gè)人都在銀行或者ATM機(jī)器上輸入過(guò)密碼,那在輸入密碼的過(guò)程中你接觸到的那個(gè)鍵盤就是一個(gè)金融密碼鍵盤。一般柜臺(tái)的密碼鍵盤都像鼠標(biāo)一樣帶一個(gè)數(shù)據(jù)線,這個(gè)數(shù)據(jù)線就是連接密碼鍵盤和銀行處處理終端的。結(jié)構(gòu)圖如下:
上圖顯而易見(jiàn),如果一個(gè)壞人想要去竊取密碼信息,由兩個(gè)方式:
A. 在終端記錄用戶的輸入按鍵
B. 從數(shù)據(jù)線中截獲用戶密碼輸入
對(duì)于第一種方法,就靠用戶在輸入密碼時(shí)候的自我保護(hù)了,而第二種方法也不是輕易能實(shí)現(xiàn)的。不要小瞧了這個(gè)密碼鍵盤,這個(gè)密碼鍵盤的制造標(biāo)準(zhǔn)都是有國(guó)標(biāo)規(guī)定的,國(guó)標(biāo)規(guī)定的一點(diǎn)是:從鍵盤流出的數(shù)據(jù)一定要是用戶輸入加密后的數(shù)據(jù),所以即使截獲到鍵盤流出的數(shù)據(jù)想要破解出密碼也需要先得到該密碼鍵盤在加密過(guò)程中使用的密鑰(這里使用的是對(duì)稱加密算法)。
其實(shí)密碼控件就是密碼鍵盤的軟件實(shí)現(xiàn),在一個(gè)使用密碼控件的軟件系統(tǒng)中(多是網(wǎng)絡(luò)校驗(yàn)系統(tǒng)),密碼控件的整個(gè)軟件實(shí)現(xiàn)就相當(dāng)于整個(gè)物理的密碼鍵盤,對(duì)于物理的數(shù)據(jù)線路和銀行終端這樣的角色,在密碼控件系統(tǒng)中沒(méi)有絕對(duì)的對(duì)應(yīng)。因?yàn)槊艽a控件可能只是簡(jiǎn)單的把用戶輸入的數(shù)據(jù)加密后發(fā)送到網(wǎng)絡(luò)上,這時(shí)候網(wǎng)絡(luò)就是物理的數(shù)據(jù)線路;而另一種情況是用密碼控件產(chǎn)生的數(shù)據(jù)流向整個(gè)本地程序的另一個(gè)模塊,這時(shí)候計(jì)算機(jī)內(nèi)存就成為了物理的數(shù)據(jù)線路的角色。
無(wú)論如何,上述的物理密碼鍵盤肯定要比各種密碼控件安全,因?yàn)樗麄兪褂玫膱?chǎng)合有限,能夠接觸到密碼鍵盤內(nèi)部的人很少,所以就無(wú)法從密碼鍵盤的內(nèi)部來(lái)做一些惡意攻擊行為。而軟件實(shí)現(xiàn)的密碼控件就現(xiàn)對(duì)顯得捉襟見(jiàn)肘了,因?yàn)橐渴鸬接脩艚K端,而用戶終端的環(huán)境十分的復(fù)雜,并且權(quán)限十分的寬松。
2 軟鍵盤密碼控件原理和攻擊方法
Windows系統(tǒng)的內(nèi)置的控件中沒(méi)有專門的密碼控件這一說(shuō),而只是對(duì)一個(gè)SingleLine的Edit控件設(shè)置一個(gè)屬性password,這樣就實(shí)現(xiàn)了這個(gè)Edit的輸入內(nèi)容只會(huì)顯示成一種不可識(shí)別的字符。但是這種原生的密碼控件從安全的角度來(lái)說(shuō)就只有一點(diǎn):從視覺(jué)上看不到用戶輸入的密碼,但是整個(gè)密碼控件仍然遵循Win32 消息派遣處理流程,也就是說(shuō),寫一個(gè)標(biāo)準(zhǔn)的程序就可以達(dá)到先于密碼空間獲得用戶輸入從而記錄密碼的效果。
因此很多軟件廠商出于安全的考慮就做出了各式各樣的“安全密碼控件”,常見(jiàn)的密碼控件類型:
1. 低級(jí)鍵盤鉤子,改變消息參數(shù)以及派遣路徑
2. 軟鍵盤,完全繞過(guò)鍵盤輸入消息
3. 暫時(shí)還沒(méi)想到……
下面簡(jiǎn)單介紹一下以上兩種控件的原理
2.1 軟鍵盤式密碼控件
由于第2種方案使用的不是很多,所以簡(jiǎn)單介紹,這種方法使用不多的原因之一就是用戶體驗(yàn)不如鍵盤輸入。這種密碼控件的方法就是把鍵盤輸入轉(zhuǎn)為鼠標(biāo)按鍵輸入,而鼠標(biāo)按鍵消息中并沒(méi)有攜帶原始的密碼字符,而是按鍵的坐標(biāo),然后程序把坐標(biāo)映射到相應(yīng)的字符,而映射過(guò)程中遵循的F(x,y)是程序開(kāi)發(fā)者自行設(shè)計(jì)并且可以實(shí)時(shí)動(dòng)態(tài)更新(變序)。
先不考慮其他的保護(hù)措施,如果要攻擊這種安全控件,從設(shè)計(jì)這種控件的程序員的角度來(lái)考慮,如果要獲取用戶輸入密碼,至少需要兩個(gè)條件
A. 鼠標(biāo)點(diǎn)擊坐標(biāo)(x,y)
B. 內(nèi)存中映射算法F(x,y)
攻擊者可以截獲鼠標(biāo)點(diǎn)擊坐標(biāo)(x,y)然后根據(jù)破解出來(lái)的F(x,y)來(lái)計(jì)算出用戶輸入,這種方法對(duì)于一個(gè)沒(méi)有做到全方位保護(hù)的軟鍵盤密碼控件可能有效,但是還是太麻煩了,其實(shí)有個(gè)捷徑,攻擊者只要識(shí)別出用戶的鼠標(biāo)點(diǎn)擊操作發(fā)生在軟鍵盤上,然后在每次用戶點(diǎn)擊鼠標(biāo)時(shí)就來(lái)一個(gè)屏幕截圖,全屏or局部都可以,然后把截取的圖片排序,就可以得到用戶輸入的密碼數(shù)據(jù)了,完全繞過(guò)程序的映射算法。
所以從以上攻擊方法可以看出,軟件盤密碼控件如果要做到更安全那就必須對(duì)兩個(gè)事件進(jìn)行處理,
A. 用戶點(diǎn)擊鼠標(biāo)的消息不被其他程序截獲
B. 發(fā)生截屏操作時(shí)對(duì)本程序的所有窗口DC做黑屏處理
關(guān)于軟鍵盤密碼控件就介紹這么多,只是原理性的介紹,并沒(méi)有實(shí)踐代碼,但是原理和攻擊方法已經(jīng)十分清晰了,所以有興趣的同學(xué)可以幫助一些采用軟鍵盤密碼控件的廠商做下安全測(cè)試。
2.2 低級(jí)鍵盤鉤子式密碼控件
這個(gè)就是現(xiàn)如今流行并且典型的密碼控件實(shí)現(xiàn)方式了,這種方式下鍵盤還是那個(gè)鍵盤,輸入框還是那個(gè)輸入框,唯一的不同是這個(gè)輸入框的消息派遣路徑,賤了不少,各個(gè)廠商都想方設(shè)法的在Windows消息處理機(jī)制中尋找解決安全問(wèn)題的途徑。
正常的輸入框,在接收用戶的鍵盤輸入時(shí)會(huì)相應(yīng)WM_CHAR消息,這個(gè)消息是如何來(lái)的呢?當(dāng)按下一個(gè)鍵,鍵盤驅(qū)動(dòng)產(chǎn)生硬件中斷IRQ,然后經(jīng)過(guò)HAL映射中斷請(qǐng)求級(jí)別(IRQL)如果這個(gè)級(jí)別比CPU的允許的級(jí)別高,那就發(fā)生中斷,CPU取出鍵盤中斷號(hào),然后用該中斷號(hào)作為索引取出IDT中的對(duì)應(yīng)的描述符,然后執(zhí)行該描述符所指向的一個(gè)鍵盤處理程序,鍵盤中斷處理程序的作用就是處理原始的鍵盤掃描碼生成數(shù)據(jù)結(jié)構(gòu),然后緩存數(shù)據(jù)。
然后就是鍵盤驅(qū)動(dòng)的工作,鍵盤驅(qū)動(dòng)的工作就是為了完成設(shè)備棧頂部的一個(gè)功能號(hào)為IRP_MJ_READ的IRP,這個(gè)IRP是win32子系統(tǒng)進(jìn)程csrss.exe中的一個(gè)線程RIT(Raw input thread)產(chǎn)生的,當(dāng)這個(gè)IRP被完成后,RIT負(fù)責(zé)用鍵盤事件產(chǎn)生的數(shù)據(jù)生成一個(gè)按鍵消息并且放入對(duì)應(yīng)的GUI線程的輸入隊(duì)列中。
而后對(duì)應(yīng)的GUI線程在消息循環(huán)中使用GetMessage獲取消息,就會(huì)取出一個(gè)WM_KEYDOWN消息,然后如果該GUI線程中使用了TranslateMessage處理這個(gè)WM_KEYDOWN消息,則會(huì)生成一個(gè)WM_CHAR消息存入自身的POST消息隊(duì)列,然后下次再去GetMessage的時(shí)候就會(huì)取出WM_CHAR消息,并且把該消息攜帶的char傳入相應(yīng)的Window Procedure,如果沒(méi)有使用TranslateMessage處理這個(gè)消息就不會(huì)產(chǎn)生WM_CHAR消息。
完整的流程圖如下:
從上面的描述以及流程圖來(lái)看,如果作為一個(gè)攻擊者想要獲取用戶輸入的密碼,很簡(jiǎn)單的做法就是截獲WM_CHAR消息,的確是這樣的,用Spy++就可以輕而易于的獲得一個(gè)原生密碼輸入框的所有WM_CHAR消息,所以安全密碼控件的目標(biāo)就是讓攻擊者無(wú)法截獲WM_CHAR消息,或者截獲到WM_CHAR消息的時(shí)候這個(gè)VirtualKeyCode是假的,而真正的VirtualKeyCode已經(jīng)被處理。因?yàn)樵趶挠脩舭存I到密碼框多出一個(gè)顯示字符的過(guò)程中只有WM_CHAR這個(gè)消息是明文記錄了用戶鍵入的數(shù)據(jù)。
對(duì)于保護(hù)WM_CHAR消息的做法,必然是要在得到WM_KEYDOWN這個(gè)消息的時(shí)候就進(jìn)行,因?yàn)橹灰辛薟M_KEYDWON這個(gè)消息就可以繞過(guò)系統(tǒng)后續(xù)的處理先于系統(tǒng)計(jì)算出用戶按下的Virtual Key,然后保存這個(gè)案件對(duì)應(yīng)的Char,然后再返回一個(gè)修改過(guò)的WM_KEYDOWN消息,后面的數(shù)據(jù)都不用再管了,WM_KEYDOWN被修改,Virtual Key被修改,導(dǎo)致后續(xù)調(diào)用TranselateMessage消息時(shí)產(chǎn)生的WM_CHAR也不正確,所以攻擊者就算截獲到WM_CHAR也是徒勞的。
產(chǎn)生假WM_CHAR的的方法各個(gè)廠商迥異,比如QQ的就是(此處過(guò)濾5000字)。再比如支x寶,如果一個(gè)用戶的密碼是mypasswordisaccess,那么按照這個(gè)鍵序列輸入后,控件返回的char序列會(huì)是1234556789054qqw55,也就是說(shuō)在支x寶安全控件每次初始化之后,當(dāng)用戶輸入一個(gè)鍵,控件就會(huì)為這個(gè)鍵設(shè)置一個(gè)映射char,如果下次用戶再輸入這個(gè)鍵,那就不用設(shè)置直接返回上次設(shè)置的char,策略就是用戶輸入鍵之后控件負(fù)責(zé)生成映射關(guān)系,這個(gè)映射的值的產(chǎn)生方式很簡(jiǎn)單:
如上圖的四行鍵位,從上到下從左到右排列。
上面說(shuō)了原理,要實(shí)現(xiàn)的話,必然用到Windows的一種技術(shù),那就是基于消息的Hook機(jī)制了(此Hook跟inline,IAT,SSDT等Hook完全不是一回事),因?yàn)橐幚碓谙到y(tǒng)生成WM_CHAR之前就處理WM_KEYDWON并且修改,就必須要使用低級(jí)鍵盤鉤子,WH_KEYBOARD_LL。
2.3 支x寶安全密碼控件原理分析實(shí)踐
好了,不紙上談兵了,找個(gè)靶子分析分析吧,為了避免律師函,還是選擇支x寶吧寶,支x寶的密碼控件用在了登陸和支付密碼的輸入過(guò)程中,兩處使用的都是同一個(gè)密碼控件,先來(lái)調(diào)試下吧。
按照前面的講到的,該密碼控件使用了windows hook機(jī)制,那就先從SetWindowsHookEx這個(gè)函數(shù)入手吧。
代碼:
然后操作網(wǎng)頁(yè),讓控件獲取焦點(diǎn),觸發(fā)斷點(diǎn),看下堆棧:
代碼:
然后看一下動(dòng)態(tài)的設(shè)置兩個(gè)斷點(diǎn):
代碼:
然后就來(lái)來(lái)回回操作讓控件獲取和失去焦點(diǎn):
代碼:
然后看一下調(diào)用SetWindowsHookExW的時(shí)候,設(shè)置的Hook處理函數(shù)所在模塊以及偏移
代碼:
下面就不調(diào)試了,直接去分析這個(gè)處理函數(shù)了,找到模塊npAliSecCtrl,先脫殼,然后找到偏移ca008
然后就逆吧……我沒(méi)有把這些代碼逆完,只是一個(gè)大致框架出來(lái)了。
其實(shí)只要知道他的HOOK實(shí)現(xiàn)機(jī)制就Ok了,這個(gè)控件的原理就是當(dāng)控件獲取焦點(diǎn)的時(shí)候就設(shè)置一個(gè)低級(jí)鍵盤鉤子,這個(gè)鍵盤鉤子的作用就是截獲WM_KEYDOWN然后處理消息,修改消息。在調(diào)試中還發(fā)現(xiàn),在其設(shè)置了一個(gè)低級(jí)鍵盤鉤子之后并沒(méi)有再設(shè)置一個(gè)調(diào)試鉤子,這樣就很容易突破這種保護(hù)機(jī)制了,只要照準(zhǔn)時(shí)機(jī)在他的低級(jí)鍵盤鉤子設(shè)置后再設(shè)置一個(gè)低級(jí)鍵盤鉤子,那么就可以先于控件自身的鉤子獲取到鍵盤輸入消息了,不知道這個(gè)是否屬于考慮欠缺的一個(gè)設(shè)計(jì),不過(guò)即使加一個(gè)調(diào)試鉤子,也并不是毫無(wú)破綻的,仍讓有方法可以攻擊。
2.4 支x寶安全密碼控件攻擊實(shí)例
上面說(shuō)了即使加了調(diào)試鉤子,也還是不能阻止攻擊的,原因是Windows 消息鉤子的層次太高了,在如此高的系統(tǒng)層次上面去做一些防護(hù),基本沒(méi)有辦法做到絕對(duì)安全。對(duì)于支x寶的密碼控件,只要一個(gè)Inline Hook就可以完全破除了。
原理:進(jìn)入到瀏覽器的進(jìn)程內(nèi)存空間,Inline Hook住User32!SetWindowsHookExW/A函數(shù),分析該函數(shù)的參數(shù),判斷如果傳入的模塊是屬于目標(biāo)模塊并且鉤子類型是低級(jí)鍵盤鉤子,則調(diào)用原函數(shù),等待原函數(shù)返回成功之后,再調(diào)用原函數(shù)設(shè)置一個(gè)低級(jí)鍵盤鉤子,然后返回。這樣就相當(dāng)于在控件本身的鉤子之上加了一個(gè)鉤子,而這個(gè)鉤子是我們的鉤子,我們可以先于控件鉤子得到鍵盤輸入,從而計(jì)算出用戶輸入的字符,達(dá)到鍵盤記錄的目的。
xxxx種原因,我不能在這里提供源碼,只有一圖和一個(gè)bin供各位研究了。
原文地址:http://bbs.pediy.com/showthread.php?t=175448