前段时间打的某个ctf里遇到的...由于一些小问题当时并没有做出来...
只是表述一下思路
下文的0x00 == '\x00', 以此类推
#!/usr/bin/ruby
require "base64"
require "..."
/*
A demo for AES CBC Padding Oracle Attack
author: Minty_He
*/
LENGTH = 16
origin_iv = "AAAAAAAAAAAAAAAA" //初始iv
flag = Base64.decode64("flag") //密文
/*
...
...
cchunk1 = flag[0..15]
cchunk2 = flag[16..31]
将密文分块
16个为一块
...
...
*/
def get_result(iv, chunk)
cipher = chunk
// 使用cipher和当前iv调用nc
result = file.readline
// result是通过nc获取到的解密成功与否的结果
// 如果返回结果为"Decrpytion Done" 说明解密成功,函数返回true
return true or false
end
def get_plaintext(origin_iv, chunk)
/*
主要逻辑部分:
从最后一位开始从右向左遍历整个块
通过get_result返回的值猜测当前位iv(从0~255)
如果猜测成功,当前位iv xor 0xpos xor 当前位原iv 结果即为当前位的明文
*/
plaintext = 0x00 * LENGTH //储存明文
mid = 0x00 * LENGTH //mid储存经过aes key解密后还未与iv进行xor运算的中间值
//从块末往前遍历,pos表示在跑当前块的倒数第几位
for pos in 1..16
string = 0x00 * (length - pos) + (0xpos * pos)
/*
string就是我们构造出来的明文
string的构造为0x000000.......pos
如果pos为1,string即为0x000000......01
如果pos为2,string即为0x000000....0202
依此类推
*/
//开始爆破iv
for char in 0..255
iv = 0x00 * (length - pos) + 0xchar + (mid[(length - pos + 1)..15] xor (0xpos * (pos - 1))) //这里需要检查是否越界,越界返回空字符串
if get_result(iv, chunk)
mid[length - pos] = iv[length - pos] xor 0xpos
plaintext[length - pos] = mid[length - pos] xor origin_iv[length - pos]
break
end
end
return plaintext
end
plaintext = get_plaintext(origin_iv, cchunk1) + get_plaintext(cchunk1, cchunk2) +
get_plaintext(cchunk2, cchunk3) + get_plaintext(cchunk3, cchunk4) +
.......................................................................
附上题目:
#!/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
file_secret.close
secret_enc=aes_encrypt("A"*16,secret)
secret_enc_b64=Base64.encode64(secret_enc)
puts secret_enc_b64
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 "Decrpytion Done"
STDOUT.flush
else
puts 'Wrong Option'
STDOUT.flush
end
rescue Exception => e
puts e.message
STDOUT.flush
retry
end
end