Target Management¶
Targets represent discovered hosts across your engagement -- machines identified through Nmap imports, beacon check-ins, manual entry, or batch generation from CIDR ranges. The target inventory gives operators a unified view of every machine in scope, whether compromised or not.
Architecture¶
Targets are stored in PostgreSQL and exposed through a REST API. They can be created individually, in bulk from IP ranges, or imported directly from Nmap XML scan output. The system uses upsert semantics -- if a target with the same IP already exists, metadata fields are updated while operator-set notes are preserved.
graph LR
subgraph Sources
A[Manual Entry]
B[Batch Create<br/>IP / CIDR / Range]
C[Nmap XML Import]
D[Beacon Check-in]
end
subgraph Backend
E[Target Handler]
F[Nmap Importer]
G[targets table]
H[services table]
end
A --> E
B --> E
C --> F
D --> E
E --> G
F --> G
F --> H Target Model¶
Each target record contains the following fields:
| Field | Type | Description |
|---|---|---|
id | UUID | Unique identifier (auto-generated) |
ip | string | IPv4 address (unique constraint -- used for upsert matching) |
hostname | string | DNS hostname or NetBIOS name |
netbios_name | string | NetBIOS computer name |
os | string | Operating system (e.g., "Windows 10", "Ubuntu 22.04") |
arch | string | CPU architecture (e.g., "amd64", "x86") |
note | string | Operator-set note (preserved across upserts) |
source | string | Discovery source: manual, nmap, beacon |
last_seen | timestamp | Last time this target was observed |
discovered_at | timestamp | When the target was first discovered |
created_at | timestamp | Record creation time |
updated_at | timestamp | Last record modification time |
Upsert behavior
When a target is created with an IP that already exists, the system updates hostname, os, arch, netbios_name, source, and last_seen -- but only if the new values are non-empty. The note field is never overwritten on conflict, ensuring operator annotations are preserved across scan imports and beacon check-ins.
Creating Targets¶
Single Target¶
Create a single target by specifying at minimum an IP address. All other fields are optional.
curl -s -X POST https://stentor.app/api/v1/targets \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"ip": "10.10.10.21",
"hostname": "WS01.lab.local",
"netbios_name": "WS01",
"os": "Windows 10 Pro",
"arch": "amd64",
"note": "Developer workstation",
"source": "manual"
}' | jq
{
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"ip": "10.10.10.21",
"hostname": "WS01.lab.local",
"netbios_name": "WS01",
"os": "Windows 10 Pro",
"arch": "amd64",
"note": "Developer workstation",
"source": "manual",
"last_seen": "2026-02-21T12:00:00Z",
"discovered_at": "2026-02-21T12:00:00Z",
"created_at": "2026-02-21T12:00:00Z",
"updated_at": "2026-02-21T12:00:00Z"
}
Request fields:
| Field | Type | Required | Description |
|---|---|---|---|
ip | string | Yes | IPv4 address of the target |
hostname | string | No | DNS hostname |
netbios_name | string | No | NetBIOS computer name |
os | string | No | Operating system |
arch | string | No | CPU architecture |
note | string | No | Operator note |
source | string | No | Discovery source (defaults to manual) |
Automatic deduplication
If a target with the same IP already exists, the record is updated rather than duplicated. This makes it safe to re-import scan results without creating duplicate entries.
Batch Create¶
Create multiple targets at once from a single IP address, a CIDR block, or an IP range. Useful for populating the target inventory from scope lists before scanning begins.
Request fields:
| Field | Type | Required | Description |
|---|---|---|---|
address | string | Yes | Single IP, CIDR (e.g., 10.0.0.0/24), or range (e.g., 10.0.0.1-50 or 10.0.0.1-10.0.0.50) |
hostname | string | No | Hostname applied to all targets in the batch |
os | string | No | OS applied to all targets |
note | string | No | Note applied to all targets |
Address format examples:
| Format | Example | Description |
|---|---|---|
| Single IP | 192.168.1.100 | Creates one target |
| CIDR | 192.168.1.0/24 | Expands to 254 IPs (skips network and broadcast for /24+) |
| Short range | 192.168.1.1-50 | Expands to 50 IPs (last octet range) |
| Full range | 192.168.1.1-192.168.1.50 | Expands to 50 IPs (explicit start and end) |
Expansion limits
Batch creation is limited to 1024 IPs per request. CIDR blocks larger than /22 are rejected. Use multiple requests for larger scopes.
Nmap XML Import¶
Import targets and services directly from Nmap XML output. The importer parses <host>, <address>, <hostname>, <os>, and <port> elements from the XML and creates target and service records accordingly.
Import behavior:
- Only hosts with
state="up"are imported - The first IPv4 (or IPv6) address found on each host is used as the target IP
- The first
<hostname>element is used as the hostname - The highest-accuracy OS match from
<osmatch>is used as the OS name - Only ports with
state="open"are imported as services - Service banners are assembled from
product,version, andextrainfoattributes - All imported targets have
sourceset tonmap - Existing targets (matched by IP) are updated; notes are preserved
Nmap scan command
For best results, run Nmap with OS detection and service version scanning:
File size limit
The maximum accepted XML payload is 50 MB. For very large scans, split the results into multiple files.
Bulk OS Update¶
Update the operating system field on multiple targets at once. Useful after identifying OS versions through post-exploitation or when correcting Nmap OS fingerprinting results.
Request fields:
| Field | Type | Required | Description |
|---|---|---|---|
target_ids | UUID[] | Yes | Array of target UUIDs to update |
os | string | Yes | New OS value to set |
Listing Targets¶
Retrieve all targets, ordered by discovery time (newest first).
[
{
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"ip": "10.10.10.21",
"hostname": "WS01.lab.local",
"netbios_name": "WS01",
"os": "Windows 10 Pro",
"arch": "amd64",
"note": "Developer workstation",
"source": "nmap",
"last_seen": "2026-02-21T12:00:00Z",
"discovered_at": "2026-02-21T11:45:00Z",
"created_at": "2026-02-21T11:45:00Z",
"updated_at": "2026-02-21T12:00:00Z"
}
]
Get Single Target¶
Retrieve a specific target by its UUID.
curl -s https://stentor.app/api/v1/targets/a1b2c3d4-e5f6-7890-abcd-ef1234567890 \
-H "Authorization: Bearer $TOKEN" | jq
Updating Notes¶
Update the operator note on a specific target. Notes are free-text fields for tagging targets with engagement context.
Deleting Targets¶
Remove a target by its UUID. Returns 204 No Content on success.
curl -s -X DELETE https://stentor.app/api/v1/targets/a1b2c3d4-e5f6-7890-abcd-ef1234567890 \
-H "Authorization: Bearer $TOKEN" -w "%{http_code}\n"
API Reference¶
| Method | Endpoint | Description |
|---|---|---|
GET | /api/v1/targets | List all targets |
GET | /api/v1/targets/:id | Get a single target |
POST | /api/v1/targets | Create or upsert a target |
POST | /api/v1/targets/batch | Batch create from IP/CIDR/range |
POST | /api/v1/targets/import/nmap | Import from Nmap XML |
PUT | /api/v1/targets/bulk-os | Bulk update OS field |
PUT | /api/v1/targets/:id/note | Update target note |
DELETE | /api/v1/targets/:id | Delete a target |
Workflow Example¶
A typical target management workflow during an engagement:
- Scope import -- Batch create targets from the client-provided scope using CIDR notation.
- Nmap scan -- Run network discovery and import results via the Nmap XML endpoint.
- Beacon enrichment -- As beacons check in, target records are automatically updated with hostname, OS, and architecture from the implant.
- Operator notes -- Tag high-value targets (domain controllers, admin workstations) with notes for prioritization.
- OS correction -- Use bulk OS update after confirming versions through post-exploitation.
sequenceDiagram
participant Op as Operator
participant API as Stentor API
participant DB as PostgreSQL
Op->>API: POST /targets/batch (scope CIDR)
API->>DB: Upsert 254 targets
API-->>Op: {created: 254}
Op->>API: POST /targets/import/nmap (scan XML)
API->>DB: Upsert targets + services
API-->>Op: {targets_created: 12, services_created: 47}
Note over API,DB: Beacon checks in from 10.10.10.21
API->>DB: Upsert target (hostname, OS from beacon)
Op->>API: PUT /targets/:id/note
API->>DB: Update note (preserved on future upserts)
API-->>Op: {status: "updated"}