0x00 前言
关于AES-CBC的加密解密流程我们搞懂后,我们就可以搞定翻转字节攻击
下面我们通过一道例题来完成讲解
0x10 例题分析
题目主要代码如下:
BLOCK_SIZE=16
IV = Random.new().read(BLOCK_SIZE)
passphrase = Random.new().read(BLOCK_SIZE)
pad = lambda s: s + (BLOCK_SIZE - len(s) % BLOCK_SIZE) * chr(BLOCK_SIZE - len(s) % BLOCK_SIZE)
unpad = lambda s: s[:-ord(s[len(s) - 1:])]
prefix = "&userdata="
suffix = "&user=guest"
class Pwn_Task(SocketServer.BaseRequestHandler):
def menu(self):
self.request.send("1. encrypt\n")
self.request.send("2. decrypt\n")
return self.request.send("> ")
def encrypt(self):
self.request.send("encrypt data: ")
data = self.request.recv(1024)
plain = prefix+data+suffix
aes = AES.new(passphrase, AES.MODE_CBC, IV)
return base64.b64encode(aes.encrypt(pad(plain)))
def decrypt(self):
self.request.send("decrypt data: ")
data = self.request.recv(1024)
aes = AES.new(passphrase, AES.MODE_CBC, IV)
tmp = aes.decrypt(base64.b64decode(data))
self.request.send(tmp)
plain = unpad(tmp)
self.request.send('DEBUG ====> ' + plain+'\n')
if plain[-5:]=="admin":
self.request.send(FLAG)
else:
self.request.send("you are not admin\n")
但本次题目并没有给代码来分析,而是只给了一个端口
连接上题目我们发现
题目有一个工作量证明的机制,我们写出爆破脚本来解决
#/usr/bin/env python
#-*-coding:utf-8-*-
from pwn import *
import base64
import signal
import random
import os
import time
import string
import hashlib
context.log_level="debug"
def passpow(prefix,hash_value):
while 1:
answer=''.join(random.choice(string.ascii_letters + string.digits) for i in range(4))
hashresult=hashlib.sha256(answer+prefix).hexdigest()
if hashresult==hash_value:
return answer
def pwn(ip,port,debug):
global sh
if debug==1:
context.log_level="debug"
sh=process(proc)
else:
sh=remote(ip,port)
# pass pow
sh.recvuntil("sha256(XXXX+")
prefix=sh.recv(16)
log.info("pre:"+prefix)
sh.recvuntil(" == ")
hash_v=sh.recvline().replace("\n","")
log.info("hash:"+hash_v)
answer=passpow(prefix,hash_v)
log.info("answer:"+answer)
sh.sendafter("Give me XXXX:",answer)
sh.interactive()
if __name__ =="__main__":
pwn("62.234.155.106",20001,0)
爆破成功后题目返回给我们一个菜单,做为一个pwn手我们根据题目写出菜单,分析加密流程
def encrypt(data):
sh.sendlineafter("> ","1")
sh.sendafter("encrypt data: ",data)
enc = sh.recvline().replace("\n","")
log.info("enc: "+enc)
return enc
def decrypt(data):
sh.sendlineafter("> ","2")
sh.sendafter("decrypt data: ",data)
多次尝试后分析出加密流程
AES-CBC Encrypto + base64
取一组明文密文进行分析
9b4YKaSJNRQewm84ix7cfuGYy+WuyMhwAMIEnzBScJIWYxhtnrVJ/oOHqst7drYO
f5be1829a48935141ec26f388b1edc7e &userdata=aaaaaa
e198cbe5aec8c87000c2049f30527092 aaaaa&user=guest // user=guest => admin
1663186d9eb549fe8387aacb7b76b60e pading '\x10'*16
发现我们的输入会被拼接,而题目的要求应该就是要我们成为admin
这个时候我们就要利用翻转字节来进行攻击,将guest翻转成为admin
我们要修改第二组密文,所以我们要修改第一组密文来影响第二组密文的解密
因为AES的解密流程为:
msg[1] = decrypt(enc2,key)^enc1
我们要影响msg[1],就要修改enc1
由于我们要修改guest,因此我们要修改enc1[11*2:32]
ord('a')^ord('g')^enc1[22:24] 这样修改
虽然这样会使第一组密文解密成乱码,但这并不影响后面的解密
get flag:
0x20 final exp
Exp:
#/usr/bin/env python
#-*-coding:utf-8-*-
from pwn import *
import base64
import signal
import random
import os
import time
import string
import hashlib
context.log_level="debug"
def passpow(prefix,hash_value):
while 1:
answer=''.join(random.choice(string.ascii_letters + string.digits) for i in range(4))
hashresult=hashlib.sha256(answer+prefix).hexdigest()
if hashresult==hash_value:
return answer
def encrypt(data):
sh.sendlineafter("> ","1")
sh.sendafter("encrypt data: ",data)
enc = sh.recvline().replace("\n","")
log.info("enc: "+enc)
return enc
def decrypt(data):
sh.sendlineafter("> ","2")
sh.sendafter("decrypt data: ",data)
def pwn(ip,port,debug):
global sh
if debug==1:
context.log_level="debug"
sh=process(proc)
else:
sh=remote(ip,port)
# pass pow
sh.recvuntil("sha256(XXXX+")
prefix=sh.recv(16)
log.info("pre:"+prefix)
sh.recvuntil(" == ")
hash_v=sh.recvline().replace("\n","")
log.info("hash:"+hash_v)
answer=passpow(prefix,hash_v)
log.info("answer:"+answer)
sh.sendafter("Give me XXXX:",answer)
# &userdata=AAA&user=guest
enc = encrypt("a"*11)
enc2 = base64.b64decode(enc).encode('hex')
log.info("enc2: "+enc2)
log.info("enc2_lenth: "+str(len(enc2)))
fack_enc = enc2[:22]+ hex(int(enc2[22:24],16) ^ ord('g')^ord('a'))[2:]
fack_enc += hex(int(enc2[24:26],16) ^ ord('u')^ord('d'))[2:]
fack_enc += hex(int(enc2[26:28],16) ^ ord('e')^ord('m'))[2:]
fack_enc += hex(int(enc2[28:30],16) ^ ord('s')^ord('i'))[2:]
fack_enc += hex(int(enc2[30:32],16) ^ ord('t')^ord('n'))[2:]
fack_enc += enc2[32:96]
log.info("fack_enc: "+fack_enc)
log.info("fack_enc_lenth: "+str(len(fack_enc)))
fack_enc = base64.b64encode(fack_enc.decode('hex'))
decrypt(fack_enc)
sh.interactive()
if __name__ =="__main__":
pwn("62.234.155.106",20001,0)