Update README.md

This commit is contained in:
Ryan Kleffman
2025-10-04 13:24:41 -07:00
parent 9de21832bf
commit be730eb241
+65 -165
View File
@@ -7,13 +7,74 @@ An NTP tunnel for Cobalt Strike beacons using External-C2
The tunnel is fairly simple. Every packet is a normal NTP packet, and all the data hides in extension fields.
## Extension Fields
## How it works
There are two main jobs the client and controller have, and each has its own sets of extension fields.
There are two main jobs the Client and Controller have:
1. Payload Retrieveal: The initial Payload Retirival from the TeamServer
2. The Beacon Loop: The continuous comms between Client, Controller, and TeamServer
#### Payload Retireval:
1. Client sends a `getIdPacket` packet to get a client ID
2. Controller responds with a `idPacket` packet containing the client ID. Client saves this for all further outbound packets
3. Client sends a packet with a `giveMePayload` extension.
1. The data in this packet will either be `0x86`, or `0x64`, depending on the architecture of the host. This must be manually set in the client, this is not dynamically determined.
4. Controller reaches out to TeamServer to get the payload.
5. In the NTP response (to step 3), Controller returns a packet with a `sizePacket` extension, denoting the size of the payload.
6. The client initiates chunking by iterating over the inbound payload size, retrieving chunks until the entire payload has been received.
1. The data in this packet is `0x00`, which denotes "keep sending me chunks of the payload"
7. The packet back from the Controller is a `dataFromTeamserver` packet, which contains a chunk of payload.
8. (not shown below) Once the entire payload has been retrieved, it is in injected into a new thread, and run.
1. Note: This uses a basic CreateThread injection method. Its going to be detected — please modify or replace with your preferred technique. (Code is located in `injector.cpp`)
![payload_ret](https://github.com/user-attachments/assets/bddaa1f3-b0c1-4a12-baa2-120e22dd5459)
#### Beacon Loop:
1. Client reads beacon data from the named pipe.
2. Client sends a packet with a `sizePacket` extension, which contains the size of the data retreived from the beacon.
3. Controller responds with `sizePacketAcknowledge`
4. Client then initiates chunking by iterating over the beacon data size, sending chunks with `dataForTeamserver` extensions until the entire beacon data has been sent to the Controller
5. Controller sends `sizePacketAcknowledge` each chunked packet to signify it made it.
6. Once the Controller has all the data, it forwards the data onto the TeamServer.
7. The controller then gets the response of the teamserver.
8. Client then sends a packet with the `getDataFromTeamserverSize` extension.
9. The Controller responds with the size of the data from the Teamserver, via a packet with a `sizePacket` extension.
10. Client then initiates chunking by sending a packet with the `getDataFromTeamserver` extension.
11. The Controller responds with a packet with the `dataFromTeamserver` extension. This packet contiains a chunk of data of the TeamServers response.
12. Once the Client has all the data, it forwards the data onto the beacon, via the named pipe. It then loops to step 1.
![beacon_loop (1)](https://github.com/user-attachments/assets/943eade2-9bbd-458c-a9a0-96ad4ddc319c)
REMOVE_ME:
// Payload-related
[ ] giveMePayload = { 0x00, 0x01 };
// Teamserver requests/responses
[ ] getDataFromTeamserver = { 0x00, 0x02 };
[ ] dataFromTeamserver = { 0x02, 0x04 };
[ ] getDataFromTeamserverSize = { 0x03, 0x04 };
[ ] dataForTeamserver = { 0x02, 0x05 };
// Identification / ID
[X] getIdPacket = { 0x12, 0x34 };
[X] idPacket = { 0x1D, 0x1D };
// Size-related
[X] sizePacket = { 0x51, 0x2E };
[ ] sizePacketAcknowledge = { 0x50, 0x50 };
## Extension Fields
Both the Payload Retrieveal, and the Beacon Loop have their own set of extension fields
### Base Packet Format:
Before exploring the individual extension fields, it's important to understand their underlying structure.
@@ -51,139 +112,6 @@ Why extension fields, and why this exact structure? Two reasons:
So, if I want these packets to look legit, they need to be structured as such.
REMOVE_ME:
// Payload-related
[ ] giveMePayload = { 0x00, 0x01 };
// Teamserver requests/responses
[ ] getDataFromTeamserver = { 0x00, 0x02 };
[ ] dataFromTeamserver = { 0x02, 0x04 };
[ ] getDataFromTeamserverSize = { 0x03, 0x04 };
[ ] dataForTeamserver = { 0x02, 0x05 };
// Identification / ID
[X] getIdPacket = { 0x12, 0x34 };
[X] idPacket = { 0x1D, 0x1D };
// Size-related
[X] sizePacket = { 0x51, 0x2E };
[ ] sizePacketAcknowledge = { 0x50, 0x50 };
### Payload Retrieval & Execution Extension Fields
These Extension Fields are used to tunnel the payload to the client, through the Controller, from the Teamserver.
1. getSize
This extension field is used to communicate the size of an inbound message. This is crucial for chunk based communication.
```
Bytes 0-1: 0x51, 0x2E
Bytes 2-3: Size of Data
Bytes 4-7: Unique ID
Bytes 8-11 Size of total data to be sent
```
2. giveMePayload
```
Bytes 0-1: 0x00, 0x01
Bytes 2-3: Size of Data
Bytes 4-7: ClientID
Bytes 8: Architechure (0x86, 0x64, or 0x00) 0x00 = continue sending payload, 0x86/0x64 are their own respective arch.
```
3. getIdPacket
Used by the client to get an ID from the Controller.
```
Bytes 0-1: 0x12, 0x34
Bytes 2-3: Size of Data
Bytes 4-7: ClientID - by default, 0xFF,0xFF,0xFF,0xFF, aka blank client ID
```
4. idPacket
Used in response to a `getIdPacket` from the Controller to give the client an ID. This ID is stored in the Data section of the
extension field, NOT in the ClientID field (which is blank).
```
Bytes 0-1: 0x1D, 0x1D
Bytes 2-3: Size of Data
Bytes 4-7: ClientID - Blank (0xFF,0xFF,0xFF,0xFF)
Bytes 8-11: ClientID for the client.
```
5. dataFromTeamserver
Used in response from the Controller to tunnel data back in. Contains data that came from the teamserver.
```
Bytes 0-1: 0x02, 0x04
Bytes 2-3: Size of Data
Bytes 4-7: ClientID - Blank (0xFF,0xFF,0xFF,0xFF)
Bytes 4-?: Chunked data from teamserver
```
#### The Flow:
1. Client sends a `getIdPacket` packet to get a client ID
2. Controller responds with a `idPacket` packet containing the client ID. Client saves this for all further outbound packets
3. Client sends a packet with a `giveMePayload` extension.
1. The data in this packet will either be `0x86`, or `0x64`, depending on the architecture of the host. This must be manually set in the client, this is not dynamically determined.
4. Controller reaches out to TeamServer to get the payload.
5. In the NTP response (to step 3), Controller returns a packet with a `sizePacket` extension, denoting the size of the payload.
6. The client initiates chunking by iterating over the inbound payload size, retrieving chunks until the entire payload has been received.
1. The data in this packet is `0x00`, which denotes "keep sending me chunks of the payload"
7. The packet back from the Controller is a `dataFromTeamserver` packet, which contains a chunk of payload.
8. (not shown below) Once the entire payload has been retrieved, it is in injected into a new thread, and run.
1. Note: This uses a basic CreateThread injection method. Its going to be detected — please modify or replace with your preferred technique. (Code is located in `injector.cpp`)
![payload_ret](https://github.com/user-attachments/assets/bddaa1f3-b0c1-4a12-baa2-120e22dd5459)
### The Beacon Loop Extension Fields
These Extension Fields facilitate tunneling of beacon communications, routing data between the client and the Controller, and then between the Controller and the Teamserver.
#### The Flow:
1. Client reads beacon data from the named pipe.
2. Client sends a packet with a `sizePacket` extension, which contains the size of the data retreived from the beacon.
3. Controller responds with `sizePacketAcknowledge`
4. Client then initiates chunking by iterating over the beacon data size, sending chunks with `dataForTeamserver` extensions until the entire beacon data has been sent to the Controller
5. Controller sends `sizePacketAcknowledge` each chunked packet to signify it made it.
6. Once the Controller has all the data, it forwards the data onto the TeamServer.
7. The controller then gets the response of the teamserver.
8. Client then sends a packet with the `getDataFromTeamserverSize` extension.
9. The Controller responds with the size of the data from the Teamserver, via a packet with a `sizePacket` extension.
10. Client then initiates chunking by sending a packet with the `getDataFromTeamserver` extension.
11. The Controller responds with a packet with the `dataFromTeamserver` extension. This packet contiains a chunk of data of the TeamServers response.
12. Once the Client has all the data, it forwards the data onto the beacon, via the named pipe. It then loops to step 1.
![beacon_loop (1)](https://github.com/user-attachments/assets/943eade2-9bbd-458c-a9a0-96ad4ddc319c)
####
1. getSize
This extension field is used to communicate the size of an inbound message. This is crucial for chunk based communication.
```
Bytes 0-1: 0x51, 0x2E
Bytes 2-3: Size of Data
Bytes 4-7: Unique ID
Bytes 8-11 Size of total data to be sent
```
2.
### Payload Retrieval & Execution Extension Fields
These Extension Fields are used to tunnel the payload to the client, through the Controller, from the Teamserver.
@@ -246,35 +174,7 @@ Bytes 4-7: ClientID - Blank (0xFF,0xFF,0xFF,0xFF)
Bytes 4-?: Chunked data from teamserver
```
---
<!--
**TeamServer Communications**
Standard comms with teamserver, while in comms loop, use 2 common packet structures
### The Beacon Loop Extension Fields
### Outbound Packet `dataForTeamserver`
This structure defines what the client sends **to the TeamServer**.
```
Bytes 0-1: 0x00, 0x00 // Reserved / header indicator
Bytes 2-3: Size of Data // Length of payload (excluding header)
Bytes 4-7: Unique ID // Identifier for this client/session
Bytes 8-..: Total Data Size // Full size of data being transmitted
// (used for chunk reassembly if data is split)
```
---
### Inbound Packet `dataFromTeamserver`
This structure defines what the TeamServer sends **back to the client** in response.
```
Bytes 0-1: 0x00, 0x00 // Reserved / header indicator
Bytes 2-3: Size of Data // Length of payload (excluding header)
Bytes 4-7: Unique ID // Identifier for this client/session
Bytes 8-..: Total Data Size // Full size of data being transmitted
// (used for chunk reassembly if data is split)
```
** The Loop / At execution ** -->
These Extension Fields facilitate tunneling of beacon communications, routing data between the client and the Controller, and then between the Controller and the Teamserver.