0x00 前言

关于AES-CBC的加密解密流程我们搞懂后,我们就可以搞定翻转字节攻击

image-20210809133332096

下面我们通过一道例题来完成讲解

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")

但本次题目并没有给代码来分析,而是只给了一个端口

连接上题目我们发现

image-20210811145523384

题目有一个工作量证明的机制,我们写出爆破脚本来解决

#/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:

image-20210811150543894

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)