密码控件安全技术浅析及攻击实例
https://bbs.pediy.com/thread-175448.htm
密码控件是一个很常见的控件,这篇文章主要介绍一下安全密码控件的一些实现思路和攻击思路。
1 物理密码键盘和密码控件的对比
先说一下程序中的密码控件和现实中的密码键盘的对比。几乎每个人都在银行或者ATM机器上输入过密码,那在输入密码的过程中你接触到的那个键盘就是一个金融密码键盘。一般柜台的密码键盘都像鼠标一样带一个数据线,这个数据线就是连接密码键盘和银行处处理终端的。结构图如下:
上图显而易见,如果一个坏人想要去窃取密码信息,由两个方式:
A. 在终端记录用户的输入按键
B. 从数据线中截获用户密码输入
对于第一种方法,就靠用户在输入密码时候的自我保护了,而第二种方法也不是轻易能实现的。不要小瞧了这个密码键盘,这个密码键盘的制造标准都是有国标规定的,国标规定的一点是:从键盘流出的数据一定要是用户输入加密后的数据,所以即使截获到键盘流出的数据想要破解出密码也需要先得到该密码键盘在加密过程中使用的密钥(这里使用的是对称加密算法)。
其实密码控件就是密码键盘的软件实现,在一个使用密码控件的软件系统中(多是网络校验系统),密码控件的整个软件实现就相当于整个物理的密码键盘,对于物理的数据线路和银行终端这样的角色,在密码控件系统中没有绝对的对应。因为密码控件可能只是简单的把用户输入的数据加密后发送到网络上,这时候网络就是物理的数据线路;而另一种情况是用密码控件产生的数据流向整个本地程序的另一个模块,这时候计算机内存就成为了物理的数据线路的角色。
无论如何,上述的物理密码键盘肯定要比各种密码控件安全,因为他们使用的场合有限,能够接触到密码键盘内部的人很少,所以就无法从密码键盘的内部来做一些恶意攻击行为。而软件实现的密码控件就现对显得捉襟见肘了,因为要部署到用户终端,而用户终端的环境十分的复杂,并且权限十分的宽松。
2 软键盘密码控件原理和攻击方法
Windows系统的内置的控件中没有专门的密码控件这一说,而只是对一个SingleLine的Edit控件设置一个属性password,这样就实现了这个Edit的输入内容只会显示成一种不可识别的字符。但是这种原生的密码控件从安全的角度来说就只有一点:从视觉上看不到用户输入的密码,但是整个密码控件仍然遵循Win32 消息派遣处理流程,也就是说,写一个标准的程序就可以达到先于密码空间获得用户输入从而记录密码的效果。
因此很多软件厂商出于安全的考虑就做出了各式各样的“安全密码控件”,常见的密码控件类型:
1. 低级键盘钩子,改变消息参数以及派遣路径
2. 软键盘,完全绕过键盘输入消息
3. 暂时还没想到……
下面简单介绍一下以上两种控件的原理
2.1 软键盘式密码控件
由于第2种方案使用的不是很多,所以简单介绍,这种方法使用不多的原因之一就是用户体验不如键盘输入。这种密码控件的方法就是把键盘输入转为鼠标按键输入,而鼠标按键消息中并没有携带原始的密码字符,而是按键的坐标,然后程序把坐标映射到相应的字符,而映射过程中遵循的F(x,y)是程序开发者自行设计并且可以实时动态更新(变序)。
先不考虑其他的保护措施,如果要攻击这种安全控件,从设计这种控件的程序员的角度来考虑,如果要获取用户输入密码,至少需要两个条件
A. 鼠标点击坐标(x,y)
B. 内存中映射算法F(x,y)
攻击者可以截获鼠标点击坐标(x,y)然后根据破解出来的F(x,y)来计算出用户输入,这种方法对于一个没有做到全方位保护的软键盘密码控件可能有效,但是还是太麻烦了,其实有个捷径,攻击者只要识别出用户的鼠标点击操作发生在软键盘上,然后在每次用户点击鼠标时就来一个屏幕截图,全屏or局部都可以,然后把截取的图片排序,就可以得到用户输入的密码数据了,完全绕过程序的映射算法。
所以从以上攻击方法可以看出,软件盘密码控件如果要做到更安全那就必须对两个事件进行处理,
A. 用户点击鼠标的消息不被其他程序截获
B. 发生截屏操作时对本程序的所有窗口DC做黑屏处理
关于软键盘密码控件就介绍这么多,只是原理性的介绍,并没有实践代码,但是原理和攻击方法已经十分清晰了,所以有兴趣的同学可以帮助一些采用软键盘密码控件的厂商做下安全测试。
2.2 低级键盘钩子式密码控件
这个就是现如今流行并且典型的密码控件实现方式了,这种方式下键盘还是那个键盘,输入框还是那个输入框,唯一的不同是这个输入框的消息派遣路径,贱了不少,各个厂商都想方设法的在Windows消息处理机制中寻找解决安全问题的途径。
正常的输入框,在接收用户的键盘输入时会相应WM_CHAR消息,这个消息是如何来的呢?当按下一个键,键盘驱动产生硬件中断IRQ,然后经过HAL映射中断请求级别(IRQL)如果这个级别比CPU的允许的级别高,那就发生中断,CPU取出键盘中断号,然后用该中断号作为索引取出IDT中的对应的描述符,然后执行该描述符所指向的一个键盘处理程序,键盘中断处理程序的作用就是处理原始的键盘扫描码生成数据结构,然后缓存数据。
然后就是键盘驱动的工作,键盘驱动的工作就是为了完成设备栈顶部的一个功能号为IRP_MJ_READ的IRP,这个IRP是win32子系统进程csrss.exe中的一个线程RIT(Raw input thread)产生的,当这个IRP被完成后,RIT负责用键盘事件产生的数据生成一个按键消息并且放入对应的GUI线程的输入队列中。
而后对应的GUI线程在消息循环中使用GetMessage获取消息,就会取出一个WM_KEYDOWN消息,然后如果该GUI线程中使用了TranslateMessage处理这个WM_KEYDOWN消息,则会生成一个WM_CHAR消息存入自身的POST消息队列,然后下次再去GetMessage的时候就会取出WM_CHAR消息,并且把该消息携带的char传入相应的Window Procedure,如果没有使用TranslateMessage处理这个消息就不会产生WM_CHAR消息。
完整的流程图如下:
从上面的描述以及流程图来看,如果作为一个攻击者想要获取用户输入的密码,很简单的做法就是截获WM_CHAR消息,的确是这样的,用Spy++就可以轻而易于的获得一个原生密码输入框的所有WM_CHAR消息,所以安全密码控件的目标就是让攻击者无法截获WM_CHAR消息,或者截获到WM_CHAR消息的时候这个VirtualKeyCode是假的,而真正的VirtualKeyCode已经被处理。因为在从用户按键到密码框多出一个显示字符的过程中只有WM_CHAR这个消息是明文记录了用户键入的数据。
对于保护WM_CHAR消息的做法,必然是要在得到WM_KEYDOWN这个消息的时候就进行,因为只要有了WM_KEYDWON这个消息就可以绕过系统后续的处理先于系统计算出用户按下的Virtual Key,然后保存这个案件对应的Char,然后再返回一个修改过的WM_KEYDOWN消息,后面的数据都不用再管了,WM_KEYDOWN被修改,Virtual Key被修改,导致后续调用TranselateMessage消息时产生的WM_CHAR也不正确,所以攻击者就算截获到WM_CHAR也是徒劳的。
产生假WM_CHAR的的方法各个厂商迥异,比如QQ的就是(此处过滤5000字)。再比如支x宝,如果一个用户的密码是mypasswordisaccess,那么按照这个键序列输入后,控件返回的char序列会是1234556789054qqw55,也就是说在支x宝安全控件每次初始化之后,当用户输入一个键,控件就会为这个键设置一个映射char,如果下次用户再输入这个键,那就不用设置直接返回上次设置的char,策略就是用户输入键之后控件负责生成映射关系,这个映射的值的产生方式很简单:
如上图的四行键位,从上到下从左到右排列。
上面说了原理,要实现的话,必然用到Windows的一种技术,那就是基于消息的Hook机制了(此Hook跟inline,IAT,SSDT等Hook完全不是一回事),因为要处理在系统生成WM_CHAR之前就处理WM_KEYDWON并且修改,就必须要使用低级键盘钩子,WH_KEYBOARD_LL。
2.3 支x宝安全密码控件原理分析实践
好了,不纸上谈兵了,找个靶子分析分析吧,为了避免律师函,还是选择支x宝吧宝,支x宝的密码控件用在了登陆和支付密码的输入过程中,两处使用的都是同一个密码控件,先来调试下吧。
按照前面的讲到的,该密码控件使用了windows hook机制,那就先从SetWindowsHookEx这个函数入手吧。
1
2
3
4
|
ntdll!DbgBreakPoint:
00000000`77410530 cc int 3
0:209> bp USER32!SetWindowsHookExW
0:209> g
|
然后操作网页,让控件获取焦点,触发断点,看下堆栈:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
(271c.4d7c): Break instruction exception - code 80000003 (first chance)
Breakpoint 0 hit
USER32!SetWindowsHookExW:
76d77603 8bff mov edi,edi
0:173:x86> kvn L10
# ChildEBP RetAddr Args to Child
00 4000ba84 73e94267 0000000d [COLOR=red]5c1cca08 5c1c0000[ /COLOR ] USER32!SetWindowsHookExW (FPO: [Non-Fpo])
*** WARNING: Unable to verify checksum for npAliSecCtrl.DLL
*** ERROR: Symbol file could not be found. Defaulted to export symbols for npAliSecCtrl.DLL -
01 4000bab4 5c1ccaf5 0000000d 5c1cca08 5c1c0000 IEShims!NS_SetWindowsHookEx::APIHook_SetWindowsHookExW+0x6b (FPO: [Non-Fpo])
WARNING: Stack unwind information not available. Following frames may be wrong.
02 4000bb04 5c1c62d2 00140154 [COLOR=red]00000007[ /COLOR ] 0014050a npAliSecCtrl!NP_Initialize+0x21c7
03 4000bb50 76d662fa 4e1c3070 00000007 0014050a npAliSecCtrl!NP_Shutdown+0x269a
04 4000bb7c 76d66d3a 05940920 00140154 [COLOR=red]00000007[ /COLOR ] USER32!InternalCallWinProc+0x23
05 4000bbf4 76d66de8 00000000 05940920 00140154 USER32!UserCallWinProcCheckWow+0x109 (FPO: [Non-Fpo])
06 4000bc50 76d66e44 010e22c0 00000000 00000007 USER32!DispatchClientMessage+0xe0 (FPO: [Non-Fpo])
07 4000bc8c 775b010a 4000bca4 00000000 4000bde0 USER32!__fnDWORD+0x2b (FPO: [Non-Fpo])
08 4000bcc4 5c1c9054 00140154 4e1c2f1c 00000001 ntdll_775a0000!KiUserCallbackDispatcher+0x2e (FPO: [0,0,0])
09 4000bcfc 5c1c5d79 0014050a 00000007 000c0822 npAliSecCtrl!NP_Shutdown+0x541c
0a 4000bd4c 76d662fa 4e1c2f1c 4000c01c 000c0822 npAliSecCtrl!NP_Shutdown+0x2141
0b 4000bd78 76d66d3a 05940d80 0014050a 00000007 USER32!InternalCallWinProc+0x23
0c 4000bdf0 76d66de8 00000000 05940d80 0014050a USER32!UserCallWinProcCheckWow+0x109 (FPO: [Non-Fpo])
0d 4000be4c 76d66e44 00e9fdf0 00000000 00000007 USER32!DispatchClientMessage+0xe0 (FPO: [Non-Fpo])
0e 4000be88 775b010a 4000bea0 00000000 4000bf38 USER32!__fnDWORD+0x2b (FPO: [Non-Fpo])
0f 4000bec0 5c1c6df4 0014050a 00000000 4e1c2ed4 ntdll_775a0000!KiUserCallbackDispatcher+0x2e (FPO: [0,0,0])
|
然后看一下动态的设置两个断点:
1
2
3
4
5
6
|
0:170:x86> bp USER32!SetWindowsHookExW ".printf \"Hit USER32!SetWindowsHookExW\\r\\n\"; g"
0:170:x86> bp USER32!NtUserUnhookWindowsHookEx ".printf \"Hit USER32!UnhookWindowsHookEx\\r\\n\"; g"
0:170:x86> bl
0 e x86 76d8f52b 0001 (0001) 0:**** USER32!NtUserUnhookWindowsHookEx ".printf \"Hit USER32!UnhookWindowsHookEx\\r\\n\"; g"
1 e x86 76d77603 0001 (0001) 0:**** USER32!SetWindowsHookExW ".printf \"Hit USER32!SetWindowsHookExW\\r\\n\"; g"
0:170:x86> g
|
然后就来来回回操作让控件获取和失去焦点:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
(271c.1618): Unknown exception - code 800706ba (first chance)
Hit USER32!SetWindowsHookExW
Hit USER32!UnhookWindowsHookEx
Hit USER32!SetWindowsHookExW
Hit USER32!UnhookWindowsHookEx
Hit USER32!SetWindowsHookExW
Hit USER32!UnhookWindowsHookEx
Hit USER32!SetWindowsHookExW
Hit USER32!UnhookWindowsHookEx
Hit USER32!SetWindowsHookExW
Hit USER32!UnhookWindowsHookEx
Hit USER32!SetWindowsHookExW
Hit USER32!UnhookWindowsHookEx
|
然后看一下调用SetWindowsHookExW的时候,设置的Hook处理函数所在模块以及偏移
1
2
3
|
0:173:x86> lm a 5c1c0000
start end module name
5c1c0000 5c27d000 npAliSecCtrl C ( export symbols) npAliSecCtrl.DLL
|
下面就不调试了,直接去分析这个处理函数了,找到模块npAliSecCtrl,先脱壳,然后找到偏移ca008
然后就逆吧……我没有把这些代码逆完,只是一个大致框架出来了。
其实只要知道他的HOOK实现机制就Ok了,这个控件的原理就是当控件获取焦点的时候就设置一个低级键盘钩子,这个键盘钩子的作用就是截获WM_KEYDOWN然后处理消息,修改消息。在调试中还发现,在其设置了一个低级键盘钩子之后并没有再设置一个调试钩子,这样就很容易突破这种保护机制了,只要照准时机在他的低级键盘钩子设置后再设置一个低级键盘钩子,那么就可以先于控件自身的钩子获取到键盘输入消息了,不知道这个是否属于考虑欠缺的一个设计,不过即使加一个调试钩子,也并不是毫无破绽的,仍让有方法可以攻击。
2.4 支x宝安全密码控件攻击实例
上面说了即使加了调试钩子,也还是不能阻止攻击的,原因是Windows 消息钩子的层次太高了,在如此高的系统层次上面去做一些防护,基本没有办法做到绝对安全。对于支x宝的密码控件,只要一个Inline Hook就可以完全破除了。
原理:进入到浏览器的进程内存空间,Inline Hook住User32!SetWindowsHookExW/A函数,分析该函数的参数,判断如果传入的模块是属于目标模块并且钩子类型是低级键盘钩子,则调用原函数,等待原函数返回成功之后,再调用原函数设置一个低级键盘钩子,然后返回。这样就相当于在控件本身的钩子之上加了一个钩子,而这个钩子是我们的钩子,我们可以先于控件钩子得到键盘输入,从而计算出用户输入的字符,达到键盘记录的目的。
xxxx种原因,我不能在这里提供源码,只有一图和一个bin供各位研究了。
转载于:https://www.cnblogs.com/davidwang456/articles/8944441.html
密码控件安全技术浅析及攻击实例相关推荐
- php支付密码控件,Android高仿微信支付密码输入控件实例代码
这篇文章主要为大家详细介绍了Android高仿微信支付密码输入控件的具体实现代码,供大家参考,具体内容如下 像微信支付密码控件,在app中是一个多么司空见惯的功能.最近,项目需要这个功能,于是乎就实现 ...
- pythongui项目实例_python GUI库图形界面开发之PyQt5状态栏控件QStatusBar详细使用方法实例...
PyQt5状态栏控件QStatusBar简介 MainWindow对象在底部保留有一个水平条,作为状态栏(QstatusBar),用于显示永久或临时的状态信息 QStatusBar类中的常用方法 方法 ...
- python 自动化测试(2):针对密码输入框为密码控件时的解决方案
一.前言 使用selenium进行自动化测试,节约了我们的人工和时间成本,增加测试的便利性.然而有些时候selenium也不能完全帮我们解决一些页面问题.我这篇主要写一下遇到有密码控件的输入框时的解决 ...
- 人行征信密码控件卸载后残留,导致fiddler自动关闭解决办法
人行征信密码控件卸载后,fiddler自动关闭解决办法 前段时间去下载了人行征信查询密码输入插件.也就是 这个东西.使用完了,之后卸载了. 但是当我打开平时使用的调试工具fiddler的时候后,不能正 ...
- 手势密码控件--只需调用本控件即可实现自动锁屏的控件
手势密码在很多应用中应用较多,手势密码的view代码用的系统手势键盘的代码. 包括手势密码的设置,手势密码的验证,以及应用的自动锁屏. 本控件可保护应用内隐私 本控件以实现x秒之后无操作自动锁屏.使用 ...
- 用Silverlight打造一个相对安全的密码控件
笔者最近的一个项目涉及到了支付动作,出于安全考虑,需要在密码控制上防键盘记录,传输加密等进行处理,其中难点在于防键盘记录. 现有的银行.支付宝.财付通.快钱等的支付控件都是自行开发,还需要对控件进行证 ...
- wpf 图案密码控件
1. 界面预览 2. 图案密码控件功能介绍 图案密码控件有两种模式, 一种模式是输入密码模式,在这种模式下,密码输入成功后即可进入管理界面或授权页面. 另一种模式是重设密码模式,在这种模式下,先输入旧 ...
- 密码控件解密流程和原理
文章目录 密码控件解密流程和原理 1.1 RSA 1.2 国密 2.1随机数生成 3引申知识hex和base64 3.1hex 3.2 base64 4.国产密码算法 参考文档 密码控件解密流程和原理 ...
- pythongui界面实例带注释_python GUI库图形界面开发之PyQt5状态栏控件QStatusBar详细使用方法实例...
PyQt5状态栏控件QStatusBar简介 MainWindow对象在底部保留有一个水平条,作为状态栏(QstatusBar),用于显示永久或临时的状态信息 QStatusBar类中的常用方法 方法 ...
最新文章
- windows oracle path,Oracle-Windows平台Path的问题
- JAVA实现服务器间拷贝文件,寻找在Java服务器之间传输大文件的好方法
- 不好好学C++还想做好算法?
- Vue build之后访问dist目录静态资源不加载问题解决
- DOM操作中,遍历动态集合的注意事项。ex: elem.children
- 动态内存的基本功能和使用
- JEPaas代码_((表单)_输入字段值而改变值)
- 在caffe中使用hdf5的数据
- LeetCode 1182. 与目标颜色间的最短距离(二分查找/DP)
- find命令批量修改权限和用户和删除指定时间文件
- 【连载】如何掌握openGauss数据库核心技术?秘诀三:拿捏存储技术(5)
- 计算机硬件系统的安全,维护硬件系统的计算机安全论文
- java ajax文字搜素,JAVA-WEB AJAX 搜索条自动提示
- 【2018盘点VR一体机那些事】手机VR眼镜和VR一体机有什么区别?AR,VR眼镜和VR一体机哪个好?
- docker——Ubuntu镜像操作和apache web容器操作小实训
- 一篇文章带你理清宽带、带宽、网速、吞吐量与宽带上下行
- 算法时间复杂度的渐进表示法 + 分析窍门
- 土地利用转移矩阵分析与制图(以沮漳河流域为例)
- 直接插入排序:监视哨的作用
- gitlab 私有化管理npm包