Padding oracle attack!

1 篇文章 0 订阅

终于补题补到了这个题目!这个也是非常经典的问题了,但是一直没有搞明白,之前鸡哥的讲解已经非常清楚了,忍不住还是想佩服一下4ction。下面还是大概讲一下这个Padding oracle attack到底是个啥,这里采用白帽子上的讲解方式就很好了!

1.基础知识

(1)padding

由于CBC是块密码工作模式, 所以要求明文长度必须是块长度的整数倍.
对于不满足的数据, 会进行数据填充到满足整数倍. 即 padding,格式如下

** ** ** ** ** ** ** 01
** ** ** ** ** ** 02 02
** ** ** ** ** 03 03 03
** ** ** ** 04 04 04 04
** ** ** 05 05 05 05 05
** ** 06 06 06 06 06 06
** 07 07 07 07 07 07 07
08 08 08 08 08 08 08 08

当然这里是64位为一块的情况,其他的情况自行分析

(2)CBC分组密码的链接模式

这里写图片描述

CBC模式加密流程图

这里写图片描述

CBC模式解密流程图

理解以上两张图以后还需要知道以下这张图中的IV的意思,中间值,也是我们解密过程中最后的需要抑或的地方

这里写图片描述

这个的认识非常关键!下买你讲一下攻击的原理

    在Padding Oracle Attack攻击中,攻击者输入的参数是IV+Cipher,我们要通过对IV的”穷举”来请求服务器端对我们指定的Cipher进行解密,并对返回的结果进行判断。

    和SQL注入中的Blind Inject思想类似。我觉得Padding Oracle Attack也是利用了这个二值逻辑的推理原理,或者说这是一种”边信道攻击(Side channel attack)”

2.攻击条件

二者缺一不可

1.可以控制密文 或者 IV
2.如果解密后不满足 padding 服务端会报错.

然后这里需要搞清楚到底是怎样猜解,具体比较复杂,不多讲了。总之就是控制IV在解密的过程中寻找成功解密的IV值,并且根据填充的内容确定中间值。至于我们需要的明文只要中间值和原有的IV抑或一下就有了(本人就坑在这几个变量的关系上)

3.一个例子

题目来自于第三届上海大学生网络安全大赛中的is_aes_secure密码题目,题目中明显就是了利用此漏洞,给定一个rb,贴一下代码如下

#!/usr/bin/ruby -w
require 'openssl'
require 'base64'

def banner()
    puts ' ____________________________________________'
    puts '|                                            |'
    puts '| Welcome to our secure communication system |'
    puts '| Our system is secured by AES               |'    
    puts '| So...No key! No Message!                   |'
    puts '|____________________________________________|'
    puts ''
end

def option()
    puts '1. Get the secret message.'
    puts '2. Encrypt the message'
    puts '3. Decrypt the message.'
    puts 'Give your option:'
    STDOUT.flush
    op=gets
    return op.to_i
end

def init()
    file_key=File.new("./aeskey","r")
    $key=file_key.gets
    file_key.close()
end
def aes_encrypt(iv,data)
    cipher = OpenSSL::Cipher::AES.new(256, :CBC)
    cipher.encrypt
    cipher.key = $key
    cipher.iv  =  iv
    cipher.update(data) << cipher.final
end

def aes_decrypt(iv,data)
    cipher = OpenSSL::Cipher::AES.new(256, :CBC)
    cipher.decrypt
    cipher.key = $key
    cipher.iv  = iv
    data = cipher.update(data) << cipher.final
end

def output_secret()
    file_secret=File.new("./flag","r")
    secret=file_secret.gets
    puts secret
    file_secret.close
    secret_enc=aes_encrypt("A"*16,secret)
    secret_enc_b64=Base64.encode64(secret_enc)
    puts secret_enc_b64 
    STDOUT.flush
end

init
banner
while true do
    begin
        op=option
        if op==1
            output_secret
        elsif op==2
            puts "IV:"
            STDOUT.flush
            iv=Base64.decode64(gets)
            puts "Data:"
            STDOUT.flush
            data=Base64.decode64(gets)
            data_enc=aes_encrypt iv,data
            puts Base64.encode64(data_enc)
            puts "Encrytion Done"    
            STDOUT.flush
        elsif op==3
            puts "IV:"
            STDOUT.flush
            iv=Base64.decode64(gets)
            puts "Data:"
            STDOUT.flush
            data=Base64.decode64(gets)
            data_dec=aes_decrypt iv,data
            puts "233"
            puts data_dec
            puts "Decrpytion Done"
            STDOUT.flush
        else
            puts 'Wrong Option'
            STDOUT.flush
        end
    rescue Exception => e  
        puts e.message
        STDOUT.flush
        retry
    end
end

代码的逻辑非常清楚,然后我们需要进行一些设置将服务挂起来

安装socat,这个可以看我前面的介绍
socat安装使用指南
还需要配置几个文件

1.创建flag文件输入flag
flag{flag_is_here_but_you_cannont_see}
2.创建aeskey输入密码
因为这个我们在做题中不可得,填入任意的32字节长的字符串

然后我们挂载起来服务即可

之后就是做题了,首先我们输入1得到经过加密的flag内容,然后大概分析一下b64解密后长度为48,需要将之分为3组,然后就比较简单了,直接上程序,我写的程序可能比较乱,但是思路尽可能写清楚
ps:这里注意owntools的使用,这里在接收东西的时候用recvuntil远远比recv要稳定的多!!!之前做不出来就是因为这个!!!长见识了!!!

# coding:utf-8
from pwn import *

using_words=''  #从0-255的字符
flag = ''   #最终的flag
temp_flag=''    #获取的每一块的flag值
def make_using_words():
    global using_words
    for i in range(0,255):
        using_words+=chr(i)

def make_new(ans,sigal,pos):    #这个函数生成爆破的IV向量,我们尤其需要注意ans值,和下面的的return值理清关系
    ret=''
    for i in range(pos):    #添加前导零
        ret+="0"
    ret+=sigal
    for i in range(len(ans)):
        ret+=chr(ord(ans[i])^(16-pos))  #加入要填充nbyte,保证后n-1byte是0xn
    return ret

def decode_sigal_word(conn,iv,block,ans,pos):   #爆破一个byte
    global using_words
    for sigal in using_words:
        padding = make_new(ans,sigal,pos)  #NO.16-pos word
        conn.send('3\n')
        conn.recvuntil('IV:\n')     #注意用recvuntil比较稳定
        conn.send(base64.b64encode(padding)+"\n")   #注意用\n才会进入下一步
        conn.recvuntil('Data:\n')
        conn.send(base64.b64encode(block)+"\n")
        content =  conn.recv()
        #print content
        if "Decrpytion Done"  in content:   #我们在文章中描述的二叉值的来源,Decrpytion Done说明解密成功了
            global temp_flag 
            temp_flag+= chr(ord(sigal)^(16-pos)^ord(iv[pos]))   #抑或原来的IV,得到直接是flag的值
            return chr(ord(sigal)^(16-pos))     #注意这里不需要抑或原来的IV,后面只要num^(16-pos)^(15-pos),自己想清楚!!!

def decode_words(conn,iv,block):    #爆破一整串
    global temp_flag
    temp_flag = ''
    ans=''
    for i in range(15,-1,-1):   #从尾向头爆破
        ans+=decode_sigal_word(conn,iv,block,ans[::-1],i)
        #print ans
    #return ans



if __name__=='__main__':
    decode_total = 'zCGS96d+kbkerCze6RFPRz+0+0Lg6NzXbdhmLgXtliGJyJuoW4aAQT18u6AGkmFR' #我们按下1得到的密文
    IV = "QUFBQUFBQUFBQUFBQUFBQQ==" #"A"×16的base64加密值
    make_using_words()
    decode = base64.b64decode(IV)+base64.b64decode(decode_total)    #链接起来
    conn = remote('127.0.0.1',3333)
    print conn.recvuntil('option:\n')
    global flag
    global temp_flag
    for i in range(1,4):    #按照位置分片,前一个为IV值后一个为密文
        iv = decode[i*16-16:i*16]
        decode_block = decode[i*16:i*16+16]
        decode_words(conn,iv,decode_block)
        flag+=temp_flag[::-1]
    print flag

这里写图片描述

学习到了,开心啊,再膜4ction师傅














  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值