mirror of
https://github.com/ryanq47/CS-EXTC2-NTP
synced 2026-06-08 17:18:39 +00:00
Update README.md
This commit is contained in:
@@ -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. It’s going to be detected — please modify or replace with your preferred technique. (Code is located in `injector.cpp`)
|
||||
|
||||

|
||||
|
||||
|
||||
#### 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.
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
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. It’s going to be detected — please modify or replace with your preferred technique. (Code is located in `injector.cpp`)
|
||||
|
||||

|
||||
|
||||
### 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.
|
||||
|
||||

|
||||
|
||||
|
||||
####
|
||||
|
||||
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.
|
||||
|
||||
Reference in New Issue
Block a user