Files
MaorSabag c0fc8d878b Initial commit: NoNameAx public release
Position-independent C2 beacon for Adaptix Framework with:
- PIC shellcode beacon (PEB walk, FNV1a hashing)
- BeaconGate API proxy + WFSO PoC sleepmask (extensible)
- BOF execution with module stomping
- Malleable C2 profiles with runtime switching
- WinHTTP transport (proxy-aware)
- Token manipulation (steal, impersonate, create)
- TCP tunneling (SOCKS, lportfwd, rportfwd)
- SMB pivoting
- Stardust UDRL loader with module stomping
2026-06-28 09:44:19 -04:00

222 lines
7.8 KiB
Markdown

# Token Commands
NaX supports Windows access token manipulation for impersonation, privilege escalation, and lateral movement. Eight commands cover the full token lifecycle: query identity, steal tokens from processes, impersonate, create tokens from credentials, and manage the token store.
---
## Architecture
### Token Store
The beacon maintains an in-memory linked list of stolen/created tokens (`NAX_TOKEN_NODE`). Each entry holds the token handle, a numeric ID, and the resolved `DOMAIN\user` string. The store persists across heartbeats until explicitly cleared.
### Impersonation Model
When a token is activated (via `token steal` with auto-impersonate, `token use`, or `token make`), the beacon calls `ImpersonateLoggedOnUser` on its main thread. All subsequent operations (file I/O, network access, process creation) run under the impersonated identity. The Adaptix console header updates to show the impersonated user with a `*` prefix.
### Command IDs
Each token operation has its own command ID (Adaptix pattern), not a single command with sub-command dispatch:
| Command | ID | Description |
|---------|----|-------------|
| `token getuid` | `0x50` | Current identity (process or impersonated) |
| `token steal` | `0x51` | Duplicate token from a running process |
| `token use` | `0x52` | Impersonate a stored token by ID |
| `token list` | `0x53` | List all tokens in the store |
| `token rm` | `0x54` | Remove a token from the store |
| `token revert` | `0x55` | Drop impersonation, revert to process token |
| `token make` | `0x56` | Create token from credentials (LogonUserA) |
| `token privs` | `0x57` | List privileges on the current token |
---
## Commands
### token getuid
Return the current effective identity. If impersonating, returns the impersonated user; otherwise returns the process token user.
```
token getuid
```
**Result:** `DOMAIN\username` with an elevated flag (`Yes`/`No`).
**Implementation detail:** Uses `OpenThreadToken(..., OpenAsSelf=TRUE)` to avoid `ERROR_ACCESS_DENIED` when impersonating a non-admin user. Falls back to `OpenProcessToken` if no thread token exists.
### token steal
Duplicate a token from a target process and optionally impersonate it immediately.
```
token steal <pid> [impersonate]
```
| Argument | Description |
|----------|-------------|
| `pid` | Target process ID |
| `impersonate` | If present (any value), auto-impersonate the stolen token |
```
token steal 4832
token steal 4832 true
```
Opens the process with `PROCESS_QUERY_INFORMATION`, duplicates the token with `TOKEN_ALL_ACCESS`, resolves the token's user/domain via `GetTokenInformation`, and stores it. If `impersonate` is set, calls `ImpersonateLoggedOnUser` and updates the console header.
### token use
Impersonate a previously stored token by its numeric ID.
```
token use <token_id>
```
```
token use 1
token use 3
```
Looks up the token in the store, calls `ImpersonateLoggedOnUser`, and updates the console header with the token's `DOMAIN\user`.
### token list
List all tokens currently in the store.
```
token list
```
Output is a table with columns: ID, Handle, User, Domain.
### token rm
Remove a token from the store and close its handle.
```
token rm <token_id>
```
```
token rm 2
```
If the removed token was the currently impersonated one, impersonation is NOT automatically reverted -- use `token revert` separately.
### token revert
Drop impersonation and revert to the process token.
```
token revert
```
Calls `RevertToSelf()` and clears the console header's impersonation indicator.
### token make
Create a new token from plaintext credentials using `LogonUserA`. Supports multiple logon types for different use cases.
```
token make [-t <type>] <domain> <username> <password>
```
| Argument | Description |
|----------|-------------|
| `-t <type>` | Logon type (optional, default: `new_credentials`) |
| `domain` | Target domain (e.g., `CORP`, `sevenkingdoms.local`, `.` for local) |
| `username` | Account username |
| `password` | Account password |
#### Logon Types
| Type | Value | Behavior |
|------|-------|----------|
| `interactive` | 2 | Full logon. Token SID shows the actual user. Local and network access as the target user. Requires the password to be valid. |
| `network` | 3 | Network logon. Token valid for network resources only. |
| `network_cleartext` | 8 | Like network but credentials available for delegation. Useful for Kerberos double-hop. |
| `new_credentials` | 9 | (Default) Network-only credentials. Token SID remains the caller's identity locally, but network access uses the supplied credentials. Does NOT validate the password locally. |
```
token make sevenkingdoms.local cersei.lannister il0vejaime
token make -t interactive CORP admin P@ssw0rd!
token make -t network_cleartext . svc_account SecretPass
```
**Type 9 vs Type 2:** With `new_credentials` (default), `token getuid` still shows the original user because the token SID isn't changed -- only outbound network authentication uses the new credentials. Use `-t interactive` when you need the token to fully reflect the target identity.
### token privs
List all privileges on the current effective token (thread token if impersonating, process token otherwise).
```
token privs
```
Output is a table with columns: Privilege Name, Status (Enabled/Disabled).
Uses `OpenThreadToken(..., OpenAsSelf=TRUE)` like `token getuid` for the same access-check safety.
---
## Console Header
When impersonation is active, the Adaptix console header shows the impersonated identity with a `*` prefix:
```
*SEVENKINGDOMS\cersei.lannister
```
This is updated via `TsAgentUpdateDataPartial` with the `Impersonated` field. Commands that set impersonation (`token steal` with impersonate flag, `token use`, `token make`) set the header. `token revert` clears it.
---
## Wire Format
### Task (server -> beacon)
All token commands use the standard task frame: `cmdId(1) | taskId(4) | args(variable)`.
| Command | Args format |
|---------|-------------|
| `token getuid` | (none) |
| `token steal` | `pid(4LE) \| impersonate(1)` |
| `token use` | `tokenId(4LE)` |
| `token list` | (none) |
| `token rm` | `tokenId(4LE)` |
| `token revert` | (none) |
| `token make` | `logonType(4LE) \| domainLen(4LE) \| domain \| userLen(4LE) \| user \| passLen(4LE) \| pass` |
| `token privs` | (none) |
### Result (beacon -> server)
| Command | Success data |
|---------|-------------|
| `token getuid` | `userLen(4LE) \| user \| domainLen(4LE) \| domain \| elevated(1)` |
| `token steal` | `tokenId(4LE) \| userLen(4LE) \| user \| domainLen(4LE) \| domain \| impersonate(1)` |
| `token use` | `userLen(4LE) \| user \| domainLen(4LE) \| domain` |
| `token list` | `count(4LE) \| [tokenId(4LE) \| handle(8LE) \| userLen(4LE) \| user \| domainLen(4LE) \| domain] * count` |
| `token rm` | (empty) |
| `token revert` | (empty) |
| `token make` | `tokenId(4LE) \| userLen(4LE) \| user \| domainLen(4LE) \| domain` |
| `token privs` | `count(4LE) \| [nameLen(4LE) \| name \| status(4LE)] * count` |
On error (`status=0x01`), all token commands return the Win32 error code as `errorCode(4LE)` in the result data.
---
## Files
| File | Role |
|------|------|
| `src_beacon/include/Wire.h` | `NAX_CMD_TOKEN_GETUID` through `NAX_CMD_TOKEN_PRIVS` (0x50-0x57) |
| `src_beacon/include/Nax.h` | Forward declarations for all 8 `CmdToken*` functions |
| `src_beacon/src/Commands/Token.c` | Beacon-side implementations |
| `src_beacon/src/Commands/Dispatch.c` | 8 separate `case` entries routing to each handler |
| `src_server/agent_nonameax/pl_main.go` | `CMD_TOKEN_*` Go constants |
| `src_server/agent_nonameax/pl_commands.go` | Command packing (args -> wire format) |
| `src_server/agent_nonameax/pl_format.go` | Result decoders (`decodeTokenGetUidResult`, etc.) |
| `src_server/agent_nonameax/pl_results.go` | Result processing + console header updates |
| `src_server/agent_nonameax/ax_config.axs` | AxScript command registration + UI |