栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Python

Crypto日记之AES-CBC bit翻转攻击

Python 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Crypto日记之AES-CBC bit翻转攻击

0x01 前言

攻防世界刷题遇到了一道AES-CBC 字节翻转攻击的题目,CISCN-2018-Quals-intersting。

0x02 题目CISCN-2018-Quals-intersting

下载附件得到了两个文档,一个python脚本和一个heheda.txt的文档,python脚本如下:

import flag
import hashlib
from Crypto.Util.number import getPrime, long_to_bytes, bytes_to_long
from Crypto.Cipher import AES
import random

def gen_iv(seed):
    s=random.Random()
    s.seed(seed)
    while True:
        iv=long_to_bytes(s.randint(0xfffffffffffffffffffffffffffffff,0xffffffffffffffffffffffffffffffff))
        if hashlib.sha256(iv).hexdigest()[0:4]==hashlib.sha256(long_to_bytes(seed)).hexdigest()[0:4]:
            return iv
def gen_password(seed):
    s=random.Random()
    s.seed(seed)
    while True:
        password=long_to_bytes(s.randint(0xfffffffffffffffffffffffffffffff,0xffffffffffffffffffffffffffffffff))
        if hashlib.sha256(password).hexdigest()[4:8]==hashlib.sha256(long_to_bytes(seed)).hexdigest()[4:8]:
            return password
def gen_seed():
    iv=flag.iv
    key=flag.key
    evil=flag.evil
    m="token=5t43g5g2j1;admin=0;group=0"
    c="bMPWOsg+YH0eSwchPY6HTEvf3ESETSrEQ3/M1d0lUm0=".decode("base64")
    cipher = AES.new(key, AES.MODE_CBC, iv)
    testc = cipher.encrypt(m)
    assert testc==c
    assert "admin=1" in evil
    assert "group=1" in evil
    cipher = AES.new(key, AES.MODE_CBC, iv)
    monster = cipher.encrypt(evil)
    counter=0
    for i in range(len(monster)):
        if monster[i]!=c[i]:
            counter+=1
    assert counter==2
    return int(hashlib.sha256(monster).hexdigest(),16)

def main():
    msgtemp=str(int(flag.encode(flag.flag),16))
    msg=msgtemp+"A"*(16-len(msgtemp)%16)
    seed=gen_seed()
    iv=gen_iv(seed)
    password=gen_password(seed)
    cipher = AES.new(password, AES.MODE_CBC, iv)
    c = cipher.encrypt(msg)
    open("heheda.txt","w").write(c.encode("hex"))

if __name__ == '__main__':
    main()

代码分析

      初看感觉代码很长,分析发现定义了三个函数,gen_iv()、gen_password()和gen_seed(),main函数中首先调用gen_seed()得到seed,再以seed为参数调用另外两个函数生成了iv和password,再利用iv和password对msg进行加密生成heheda.txt的密文。

      如此就需要主要去看gen_seed函数中seed是如何生成的了。

      返回的seed是int(hashlib.sha256(monster).hexdigest(),16),monster是对evil进行aes-cbc加密得到,而evil中包含admin=1和group=1。

    m="token=5t43g5g2j1;admin=0;group=0"
    c="bMPWOsg+YH0eSwchPY6HTEvf3ESETSrEQ3/M1d0lUm0=".decode("base64")
    cipher = AES.new(key, AES.MODE_CBC, iv)
    testc = cipher.encrypt(m)
    assert testc==c
    assert "admin=1" in evil
    assert "group=1" in evil
    cipher = AES.new(key, AES.MODE_CBC, iv)
    monster = cipher.encrypt(evil)
    counter=0
    for i in range(len(monster)):
        if monster[i]!=c[i]:
            counter+=1
    assert counter==2

CBC 字节翻转攻击

      网上针对AES-CBC加密模式的介绍很多,CBC:一种循环模式,前一个分组的密文与当前分组的明文进行异或操作后再加密。

      在CBC模式下,明文分组并与前一组密文进行异或操作的模式造成了CBC模式的bit翻转攻击。在不知道密钥的情况下,如果我们有一组明密文,就可以通过修改密文,来使密文解密出来的特定位置的字符变成我们想要的字符。

CBC bit 翻转攻击实现

        题目中 m="token=5t43g5g2j1;admin=0;group=0" ,明文长度共32个字节,16个字节为一组,其实将明文分为了两组:

token=5t43g5g2j1;admin=0;group=0

        在CBC模式中,首先对第一组进行加密,并对初始向量iv进行异或操作,再对第二组进行加密,并与第一组的密文进行异或操作。因为第二组加密后与第一组进行了异或操作,所以可以利用异或进行明文的修改:

      这里,我们想要将admin=0和group=0改成admin=1和group=1,也就是将第二组的第7个字符和第15个字符由0变成1:

chr(ord(c[7])^ord('0')^ord('1'))
chr(ord(c[15])^ord('0')^ord('1'))

      已知分组密码的明文和密文长度都是相同的,都是两组,而第二组的第7个字符异或过第一组的第7个字符的密文,第二组的第15个字符异或过第一组的第15个字符的密文,所以可以得到新的密文:

new_c=c[:7]+chr(ord(c[7])^ord('0')^ord('1'))+c[8:15]+chr(ord(c[15])^ord('0')^ord('1'))+c[16:]

      该题整个seed的生成代码如下:

m="token=5t43g5g2j1;admin=0;group=0"
c="bMPWOsg+YH0eSwchPY6HTEvf3ESETSrEQ3/M1d0lUm0=".decode("base64")
new_c=c[:7]+chr(ord(c[7])^ord('0')^ord('1'))+c[8:15]+chr(ord(c[15])^ord('0')^ord('1'))+c[16:]
seed=int(hashlib.sha256(new_c).hexdigest(),16)
print(seed)
# 94006254731428276046668737204765414644085700289999454456188227654864539227609

完整exp

      获取到了seed后就是常规的AES解密了,解密后的密文还经过了多重加密,可以利用CyberChef进行解密,完整代码如下:

import hashlib
from Crypto.Util.number import getPrime, long_to_bytes, bytes_to_long
from Crypto.Cipher import AES
import random
def gen_iv(seed):
    s=random.Random()
    s.seed(seed)
    while True:
        iv=long_to_bytes(s.randint(0xfffffffffffffffffffffffffffffff,0xffffffffffffffffffffffffffffffff))
        if hashlib.sha256(iv).hexdigest()[0:4]==hashlib.sha256(long_to_bytes(seed)).hexdigest()[0:4]:
            return iv
def gen_password(seed):
    s=random.Random()
    s.seed(seed)
    while True:
        password=long_to_bytes(s.randint(0xfffffffffffffffffffffffffffffff,0xffffffffffffffffffffffffffffffff))
        if hashlib.sha256(password).hexdigest()[4:8]==hashlib.sha256(long_to_bytes(seed)).hexdigest()[4:8]:
            return password

m="token=5t43g5g2j1;admin=0;group=0"
c="bMPWOsg+YH0eSwchPY6HTEvf3ESETSrEQ3/M1d0lUm0=".decode("base64")
new_c=c[:7]+chr(ord(c[7])^ord('0')^ord('1'))+c[8:15]+chr(ord(c[15])^ord('0')^ord('1'))+c[16:]
seed=int(hashlib.sha256(new_c).hexdigest(),16)

iv=gen_iv(seed)
password=gen_password(seed)
cipher = AES.new(password, AES.MODE_CBC, iv)
f=open('heheda.txt','rb').read().decode('hex')
c = cipher.decrypt(f)
while c[-1]=='A':
    c=c[:-1]
c=int(c,10)
print(hex(c)[2:-1].decode('hex'))

 得到flag:flag{ri_bu_luo_de_xia_tian_ai_de_ming_xing+pian}

0x03 总结

        根据题目对ASE-CBC bit翻转攻击有了进一步的了解。在CTF题目中,ASE-CBC bit翻转攻击出现在web中的机率更大一些,利用该攻击可以修改访问权限提升至管理员,从而获取flag。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/769738.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号