Skip to content

Commit

Permalink
[xfreerdp] Open pandorabox...
Browse files Browse the repository at this point in the history
Signed-off-by: XiaoliChan <[email protected]>
  • Loading branch information
XiaoliChan committed Sep 18, 2023
1 parent 977e186 commit 5560b4d
Show file tree
Hide file tree
Showing 5 changed files with 143 additions and 0 deletions.
108 changes: 108 additions & 0 deletions nxc/protocols/xfreerdp.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
import uuid, subprocess, os, re

from datetime import datetime
from termcolor import colored

from nxc.connection import *
from nxc.logger import CMEAdapter
from nxc.config import process_secret
from nxc.config import host_info_colors

success_flag = "Authentication only, exit status 0"

status_dict = {
'(Account has been locked)':['ERRCONNECT_ACCOUNT_LOCKED_OUT'],
'(Account has been disabled)':['ERRCONNECT_ACCOUNT_DISABLED [0x00020012]'],
'(Account was expired)':['0x0002000D','0x00000009'],
'(Not support NLA)':['ERRCONNECT_SECURITY_NEGO_CONNECT_FAILED [0x0002000C]'],
'(Password expired)':['0x0002000E','0x0002000F','0x00020013'],
'(RDP login failed)':['0x00020009','0x00020014'],
'Failed':['Resource temporarily unavailable', 'Broken pipe', 'ERRCONNECT_CONNECT_FAILED [0x00020006]', 'Connection timed out', 'Connection reset by peer']
}

class xfreerdp(connection):

def __init__(self, args, db, host):
self.output_filename = None
self.domain = None
self.nla = False

connection.__init__(self, args, db, host)

def proto_logger(self):
self.logger = CMEAdapter(
extra={
"protocol": "XFREERDP",
"host": self.host,
"port": self.args.port,
"hostname": self.hostname,
}
)

def print_host_info(self):
nla = colored(f"nla:{self.nla}", host_info_colors[3], attrs=['bold']) if self.nla else colored(f"nla:{self.nla}", host_info_colors[2], attrs=['bold'])
if not self.nla:
self.logger.display(f"Old version OS which means not support NLA (name:{self.host}) {nla}")
else:
self.logger.display(f"(name:{self.hostname}) {nla}")
return True

def create_conn_obj(self):
try:
connection = subprocess.Popen(f'xfreerdp /v:"{self.host}" /port:{self.args.port} +auth-only /d:"{str(uuid.uuid4())}" /u:"{str(uuid.uuid4())}" /p:"{str(uuid.uuid4())}" /cert-tofu /tls-seclevel:0 /timeout:{self.args.rdp_timeout * 1000}', stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
output_error = connection.stderr.read().decode('utf-8')
if any(single_word in output_error for single_word in status_dict['Failed']):
return False
else:
CN_match = re.search(r'CN = (\S+)', output_error)
if CN_match:
hostname = CN_match.group(1)
self.nla = True
self.hostname = hostname
self.logger.extra["hostname"] = hostname
else:
self.logger.extra["hostname"] = self.host

self.output_filename = os.path.expanduser(f"~/.cme/logs/{self.hostname}_{self.host}_{datetime.now().strftime('%Y-%m-%d_%H%M%S')}".replace(":", "-"))
return True
except Exception as e:
self.logger.error(str(e))
return False

def plaintext_login(self, domain, username, password):
try:
connection = subprocess.Popen(f'xfreerdp /v:"{self.host}" /port:{self.args.port} +auth-only /d:"{domain}" /u:"{username}" /p:"{password}" /cert-ignore /tls-seclevel:0 /timeout:{self.args.rdp_timeout * 1000}', stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
output_error = connection.stderr.read().decode('utf-8')
if success_flag in output_error:
self.admin_privs = True
self.logger.success(f"{domain}\\{username}:{process_secret(password)} {self.mark_pwned()}")
else:
for k,v in status_dict.items():
if any(single_word in output_error for single_word in v):
self.logger.fail(f"{domain}\\{username}:{process_secret(password)} {k}")
return False

if not self.args.continue_on_success:
return True

except Exception as e:
self.logger.error(str(e))

def hash_login(self, domain, username, ntlm_hash):
try:
connection = subprocess.Popen(f'xfreerdp /v:"{self.host}" /port:{self.args.port} +auth-only /d:"{domain}" /u:"{username}" /p:"" /pth:{ntlm_hash} /sec:nla /cert-ignore /tls-seclevel:0 /timeout:{self.args.rdp_timeout * 1000}', stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
output_error = connection.stderr.read().decode('utf-8')
if success_flag in output_error:
self.admin_privs = True
self.logger.success(f"{domain}\\{username}:{process_secret(ntlm_hash)} {self.mark_pwned()}")
else:
for k,v in status_dict.items():
if any(single_word in output_error for single_word in v):
self.logger.fail(f"{domain}\\{username}:{process_secret(ntlm_hash)} {k}")
return False

if not self.args.continue_on_success:
return True

except Exception as e:
self.logger.error(str(e))
Empty file.
19 changes: 19 additions & 0 deletions nxc/protocols/xfreerdp/database.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
class database:

def __init__(self, conn):
self.conn = conn

@staticmethod
def db_schema(db_conn):
db_conn.execute('''CREATE TABLE "credentials" (
"id" integer PRIMARY KEY,
"username" text,
"password" text
)''')

db_conn.execute('''CREATE TABLE "hosts" (
"id" integer PRIMARY KEY,
"ip" text,
"hostname" text,
"port" integer
)''')
5 changes: 5 additions & 0 deletions nxc/protocols/xfreerdp/db_navigator.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from nxc.nxcdb import DatabaseNavigator


class navigator(DatabaseNavigator):
pass
11 changes: 11 additions & 0 deletions nxc/protocols/xfreerdp/proto_args.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
def proto_args(parser, std_parser, module_parser):
xfreerdp_parser = parser.add_parser('xfreerdp', help="own stuff using RDP (xfreerdp)", parents=[std_parser, module_parser])
xfreerdp_parser.add_argument("-H", '--hash', metavar="HASH", dest='hash', nargs='+', default=[], help='NTLM hash(es) or file(s) containing NTLM hashes')
xfreerdp_parser.add_argument("--port", type=int, default=3389, help="Custom RDP port")
xfreerdp_parser.add_argument("--rdp-timeout", type=int, default=5, help="RDP timeout on socket connection, defalut is %(default)ss")

dgroup = xfreerdp_parser.add_mutually_exclusive_group()
dgroup.add_argument("-d", metavar="DOMAIN", dest='domain', type=str, default=None, help="domain to authenticate to")
dgroup.add_argument("--local-auth", action='store_true', help='authenticate locally to each target')

return parser

0 comments on commit 5560b4d

Please sign in to comment.