server.py
#!/usr/bin/python
# -*- coding: utf-8 -*-
from Crypto.Cipher import AES
from Crypto.Util.strxor import strxor
from Crypto.Random import get_random_bytes
from FLAG import flag
class MAC:
def __init__(self):
self.key = get_random_bytes(16)
self.iv = get_random_bytes(16)
def pad(self, msg):
pad_length = 16 - len(msg) % 16
return msg + chr(pad_length) * pad_length
def unpad(self, msg):
return msg[:-ord(msg[-1])]
def code(self, msg):
res = chr(0)*16
for i in range(len(msg)/16):
res = strxor(msg[i*16:(i+1)*16], res)
aes = AES.new(self.key, AES.MODE_CBC, self.iv)
return aes.encrypt(res).encode('hex')
def identity(self, msg, code):
if self.code(msg) == code:
msg = self.unpad(msg)
if msg == 'please send me your flag':
print 'remote: ok, here is your flag:%s' % flag
else:
print 'remote: I got it'
else:
print 'remote: hacker!'
if __name__ == '__main__':
mac = MAC()
message = 'see you at three o\'clock tomorrow'
print 'you seem to have intercepted something:{%s:%s}' %(mac.pad(message).encode('hex'), mac.code(mac.pad(message)))
print 'so send your message:'
msg = raw_input()
print 'and your code:'
code = raw_input()
mac.identity(msg.decode('hex'), code)
exit()
這里主要用到一個(gè)如下原理:
C = A xor B。若我們想得到X,則有以下推導(dǎo)
C = A xor B ==>> C xor A xor B = 0 ===>> C xor A xor B xor X = X
而整個(gè)解密過程中,B(密文)是我們可以控制的,A由于key未知,而無(wú)法準(zhǔn)確控制,C是原始的明文,在輸出端,無(wú)法控制。
所以,我們可以控制B,讓B首先變成C xor B xor X (這里的C是指原始的明文),這樣最終A與B的異或操作就能變成X
參考文獻(xiàn): http://momomoxiaoxi.com/2016/12/08/WebCrypt/
https://www.anquanke.com/post/id/158233
在這道題中我們進(jìn)行偽造,偽造主要繞過一下兩個(gè)條件:
- 使用code()的函數(shù)加完密的要等于你自己提供的code的值
- 使用unpad(msg.decode('hex'))消除填充之后,必須等于:please send me your flag
圖片.png
進(jìn)行偽造:
題目中會(huì)給出兩組數(shù)據(jù),如下圖所示:

偽造條件如下:
- 構(gòu)造 A xor B,也就是:
1.A的每十六字節(jié)“異或”并使用pad()填充:
msg=('706c656173652073656e64206d6520796f757220666c6167'+'8'*16).decode('hex')
print c
res = chr(0)*16
for i in range(len(msg)/16):
res = strxor(msg[i*16:(i+1)*16], res)
- B的每十六進(jìn)制“異或”并使用pad()填充“”
res1 = chr(0)*16
msg1=('73656520796f75206174207468726565206f27636c6f636b20746f6d6f72726f77'+'0f'*15).decode('hex')
for i in range(len(msg1)/16):
res1 = strxor(msg1[i*16:(i+1)*16], res1)
3.最終將他們異或 A xor B:
last_res = strxor(res1, res).encode('hex')
-
構(gòu)造第一個(gè)輸入:
1.由前一組16位和后一組16位異或:
圖片.png
2.我們只要構(gòu)造(A xor B) xor A =B:
(A xor B):
last_res = strxor(res1, res).encode('hex')
A:
msg
payload = (msg.encode('hex')+last_res).ljust(124,"a")+'27'
- 繞過 msg = self.unpad(msg)的檢測(cè):
- 可以看出:他用來填充的單位使用的是16的差值.
def pad(self, msg):
pad_length = 16 - len(msg) % 16
return msg + chr(pad_length) * pad_length
2.去除填充函數(shù),通過最后一位的數(shù)值,進(jìn)行去除,這里可以偽造:
'''
def unpad(self, msg):
return msg[:-ord(msg[-1])]
'''
3.偽造內(nèi)容在最后加一個(gè)數(shù)值,數(shù)值等于去掉“please send me your flag”之后,即可繞過保護(hù)。

代碼我借用一下別人的,代碼如下:
from pwn import *
from Crypto.Util.strxor import strxor
p=remote('47.240.41.112',12345)
p.recvuntil('0f:')
c = p.recv(32)
msg=('706c656173652073656e64206d6520796f757220666c6167'+'8'*16).decode('hex')
print c1
res = chr(0)*16
for i in range(len(msg)/16):
res = strxor(msg[i*16:(i+1)*16], res)
res1 = chr(0)*16
msg1=('73656520796f75206174207468726565206f27636c6f636b20746f6d6f72726f77'+'0f'*15).decode('hex')
for i in range(len(msg1)/16):
res1 = strxor(msg1[i*16:(i+1)*16], res1)
last_res = strxor(res1, res).encode('hex')
payload = (msg.encode('hex')+last_res).ljust(124,"a")+'27'
print payload
p.recvuntil("so send your message:\n")
p.sendline(payload)
p.recvuntil("and your code:\n")
p.sendline(c)
p.interactive()
參考網(wǎng)站:
http://www.itdecent.cn/p/02ef24117d7b
。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
基礎(chǔ)知識(shí):
異或兩個(gè)bytes
from Crypto.Util.strxor import strxor
strxor(b'abc', b'def')
參考網(wǎng)站:
http://www.itdecent.cn/p/02ef24117d7b
https://code.felinae98.cn/ctf/crypto/python%E4%B8%AD%E7%9A%84crypto%E5%9C%A8ctf%E4%B8%AD%E7%9A%84%E5%BA%94%E7%94%A8/

