Browse Source

ssh and smtp server

Roman Hergenreder 7 months ago
parent
commit
b3cd20ca8b
5 changed files with 157 additions and 2 deletions
  1. 1 1
      __init__.py
  2. 1 1
      gobuster.sh
  3. 40 0
      smtpserver.py
  4. 92 0
      sshserver.py
  5. 23 0
      util.py

+ 1 - 1
__init__.py

@@ -2,7 +2,7 @@ import os
 import sys
 
 __doc__ = __doc__ or ""
-__all__ = ["util", "fileserver", "xss_handler", "rev_shell", "xp_cmdshell", "dnsserver", "sqli"]
+__all__ = ["util", "fileserver", "xss_handler", "rev_shell", "xp_cmdshell", "dnsserver", "sqli", "smtpserver"]
 
 inc_dir = os.path.dirname(os.path.realpath(__file__))
 sys.path.append(inc_dir)

+ 1 - 1
gobuster.sh

@@ -6,4 +6,4 @@ if [ $# -lt 1 ]; then
 fi
 
 HOST=$1
-gobuster dir --url="${HOST}" --wordlist="/usr/share/wordlists/SecLists/Discovery/Web-Content/raft-large-words-lowercase.txt" -b "403,404"  "${@:2}"
+(set -x; gobuster dir --url="${HOST}" --wordlist="/usr/share/wordlists/SecLists/Discovery/Web-Content/raft-large-words-lowercase.txt" -b "403,404"  "${@:2}")

+ 40 - 0
smtpserver.py

@@ -0,0 +1,40 @@
+import smtpd
+import email
+import asyncore
+import threading
+
+class SMTPServer(smtpd.SMTPServer):
+
+    def __init__(self, addr='0.0.0.0', port=25):
+        super().__init__((addr, port), None)
+        self.listen_thread = None
+        self.verbose = False
+        self.on_message = None
+        self.is_running = True
+
+    def process_message(self, peer, mailfrom, rcpttos, data, **kwargs):
+        if self.verbose:
+            print(f"SMTP IN: {peer=} {mailfrom=} {rcpttos=} {len(data)} bytes, extra:", kwargs)
+        if self.on_message and callable(self.on_message):
+            mail = email.message_from_bytes(data)
+            self.on_message(peer, mailfrom, rcpttos, mail)
+
+    def start(self):
+        if self.verbose:
+            print(f"SMTP server running on: {self._localaddr[0]}:{self._localaddr[1]}")
+        try:
+            while self.is_running:
+                asyncore.loop(timeout=1, use_poll=True)
+        except KeyboardInterrupt:
+            self.close()
+
+    def start_background(self):
+        self.listen_thread = threading.Thread(target=self.start)
+        self.listen_thread.start()
+        return self.listen_thread
+
+    def stop(self):
+        self.is_running = False
+        self.close()
+        if self.listen_thread:
+            self.listen_thread.join()

+ 92 - 0
sshserver.py

@@ -0,0 +1,92 @@
+import socket
+import select
+import threading
+import paramiko
+
+class ParamikoConnection(paramiko.ServerInterface):
+    def __init__(self, server):
+        self.event = threading.Event()
+        self.server = server
+        
+    def check_channel_request(self, kind, chanid):
+        print("check_channel_request", kind, chanid)
+        if kind == 'session':
+            return paramiko.OPEN_SUCCEEDED
+        return paramiko.OPEN_FAILED_ADMINISTRATIVELY_PROHIBITED
+        
+    def check_auth_password(self, username, password):
+        if self.server.on_ssh_login:
+            return self.server.on_ssh_login(username, password)
+
+        print("check_auth_password", username, password)
+        return paramiko.AUTH_SUCCESSFUL
+
+class SSHServer:
+
+    def __init__(self, addr='0.0.0.0', port=22):
+        self.server_address = addr
+        self.listen_port = port
+        self.listen_socket = None
+        self.listen_thread = None
+        self.client_sockets = []
+        self.transports = []
+        self.verbose = True
+        self.on_message = None
+        self.is_running = True
+        self.private_key = None
+
+        # hooks
+        self.on_ssh_login = None
+
+
+    def load_private_key_from_file(self, path):
+        with open(path, "r") as f:
+            self.private_key = paramiko.RSAKey.from_private_key(f)
+
+    def start(self):
+
+        if self.private_key is None:
+            self.private_key = paramiko.RSAKey.generate(2048)
+
+        self.listen_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+        self.listen_socket.setblocking(False)
+        self.listen_socket.bind((self.server_address, self.listen_port))
+        self.listen_socket.listen()
+        if self.verbose:
+            print(f"SSH server running on: {self.server_address}:{self.listen_port}")
+        try:
+            while self.is_running:
+                try:
+                    client_socket, client_address = self.listen_socket.accept()
+                    if self.verbose:
+                        print("Incoming connection:", client_address)
+                    self.client_sockets.append(client_socket)
+                    transport = paramiko.Transport(client_socket)
+                    transport.add_server_key(self.private_key)
+                    paramiko_connection = ParamikoConnection(self)
+                    transport.start_server(server=paramiko_connection)
+                    self.transports.append(transport)
+                    # for client_sock in self.client_sockets:
+
+                except BlockingIOError:
+                    pass
+                # handle_client(client_socket, client_address)
+        finally:
+            self.listen_socket.close()
+
+    def start_background(self):
+        self.listen_thread = threading.Thread(target=self.start)
+        self.listen_thread.start()
+        return self.listen_thread
+
+    def close(self):
+        if self.listen_socket:
+            self.listen_socket.close()
+        for sock in self.client_sockets:
+            sock.close()
+
+    def stop(self):
+        self.is_running = False
+        self.close()
+        if self.listen_thread:
+            self.listen_thread.join()

+ 23 - 0
util.py

@@ -9,6 +9,8 @@ import string
 import sys
 import os
 import io
+import json
+
 from PIL import Image
 
 def isPortInUse(port):
@@ -80,6 +82,27 @@ def assert_header_present(res, header, err=None):
     err = f"[-] '{res.url}' did not return header: {header}" if err is None else err
     exit_with_error(res, err)
 
+def assert_not_empty(res, err=None):
+    if len(res.content) > 0:
+        return
+
+    err = f"[-] '{res.url}' did not return any data" if err is None else err
+    exit_with_error(res, err)
+
+def assert_json_path(res, path, value, err=None):
+    assert_content_type(res, "application/json")
+    assert_not_empty(res)
+
+    json_data = json.loads(res.text)
+    for key in filter(None, path.split(".")):
+        json_data = json_data[key]
+
+    if json_data == value:
+        return
+
+    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)
+
 def openServer(address, ports=None):
     listenPort = None
     retry = True