#!/usr/bin/python3 ''' By Gal Kristal from SentinelOne (gkristal.w@gmail.com) @gal_kristal Refs: https://github.com/RomanEmelyanov/CobaltStrikeForensic/blob/master/L8_get_beacon.py https://github.com/nccgroup/pybeacon ''' import requests, struct, urllib3 import argparse from urllib.parse import urljoin import socket import json from base64 import b64encode from struct import unpack, unpack_from urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) EMPTY_UA_HEADERS = {"User-Agent":""} URL_PATHS = {'x86':'ab2g', 'x64':'ab2h'} class Base64Encoder(json.JSONEncoder): def default(self, o): if isinstance(o, bytes): return b64encode(o).decode() return json.JSONEncoder.default(self, o) def _cli_print(msg, end='\n'): if __name__ == '__main__': print(msg, end=end) def read_dword_be(fh): data = fh.read(4) if not data or len(data) != 4: return None return unpack(">I",data)[0] def get_beacon_data(url, arch): full_url = urljoin(url, URL_PATHS[arch]) try: resp = requests.get(full_url, timeout=30, headers=EMPTY_UA_HEADERS, verify=False) except requests.exceptions.RequestException as e: _cli_print('[-] Connection error: ', e) return if resp.status_code != 200: _cli_print('[-] Failed with HTTP status code: ', resp.status_code) return buf = resp.content # Check if it's a Trial beacon, therefore not xor encoded (not tested) eicar_offset = buf.find(b'EICAR-STANDARD-ANTIVIRUS-TEST-FILE') if eicar_offset != -1: return buf return decrypt_beacon(buf) def decrypt_beacon(buf): offset = buf.find(b'\xff\xff\xff') if offset == -1: _cli_print('[-] Unexpected buffer received') return offset += 3 key = struct.unpack_from('