Improved Windows version fingerprinting and fixed console window not being focused on double-click.
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
import winim, os, net, strutils, registry, zippy
|
import winim, os, net, strutils, registry, zippy, strformat
|
||||||
|
|
||||||
import ../../common/[types, serialize, sequence, crypto, utils]
|
import ../../common/[types, serialize, sequence, crypto, utils]
|
||||||
import ../../modules/manager
|
import ../../modules/manager
|
||||||
@@ -69,16 +69,9 @@ proc getIPv4Address(): string =
|
|||||||
# getPrimaryIPAddr from the 'net' module finds the local IP address, usually assigned to eth0 on LAN or wlan0 on WiFi, used to reach an external address. No traffic is sent
|
# getPrimaryIPAddr from the 'net' module finds the local IP address, usually assigned to eth0 on LAN or wlan0 on WiFi, used to reach an external address. No traffic is sent
|
||||||
return $getPrimaryIpAddr()
|
return $getPrimaryIpAddr()
|
||||||
|
|
||||||
# Windows Version fingerprinting
|
|
||||||
type
|
|
||||||
ProductType = enum
|
|
||||||
UNKNOWN = 0
|
|
||||||
WORKSTATION = 1
|
|
||||||
DC = 2
|
|
||||||
SERVER = 3
|
|
||||||
|
|
||||||
# API Structs
|
# API Structs
|
||||||
type OSVersionInfoExW {.importc: protect("OSVERSIONINFOEXW"), header: protect("<windows.h>").} = object
|
type
|
||||||
|
OSVersionInfoExW {.importc: protect("OSVERSIONINFOEXW"), header: protect("<windows.h>").} = object
|
||||||
dwOSVersionInfoSize: ULONG
|
dwOSVersionInfoSize: ULONG
|
||||||
dwMajorVersion: ULONG
|
dwMajorVersion: ULONG
|
||||||
dwMinorVersion: ULONG
|
dwMinorVersion: ULONG
|
||||||
@@ -91,68 +84,79 @@ type OSVersionInfoExW {.importc: protect("OSVERSIONINFOEXW"), header: protect("<
|
|||||||
wProductType: UCHAR
|
wProductType: UCHAR
|
||||||
wReserved: UCHAR
|
wReserved: UCHAR
|
||||||
|
|
||||||
|
# Windows Version fingerprinting
|
||||||
|
ProductType {.size: sizeof(uint8).} = enum
|
||||||
|
UNKNOWN = "Unknown"
|
||||||
|
WORKSTATION = "Workstation"
|
||||||
|
DC = "Domain Controller"
|
||||||
|
SERVER = "Server"
|
||||||
|
|
||||||
|
WindowsVersion = object
|
||||||
|
major: DWORD
|
||||||
|
minor: DWORD
|
||||||
|
buildMin: DWORD # Minimum build number (0 = any)
|
||||||
|
buildMax: DWORD # Maximum build number (0 = any)
|
||||||
|
productType: ProductType
|
||||||
|
name: string
|
||||||
|
|
||||||
|
const VERSIONS = [
|
||||||
|
# Windows 11 / Server 2022+
|
||||||
|
# WindowsVersion(major: 10, minor: 0, buildMin: 22631, buildMax: 0, productType: WORKSTATION, name: protect("Windows 11 23H2")),
|
||||||
|
# WindowsVersion(major: 10, minor: 0, buildMin: 22621, buildMax: 22630, productType: WORKSTATION, name: protect("Windows 11 22H2")),
|
||||||
|
WindowsVersion(major: 10, minor: 0, buildMin: 22000, buildMax: 0, productType: WORKSTATION, name: protect("Windows 11")),
|
||||||
|
WindowsVersion(major: 10, minor: 0, buildMin: 26100, buildMax: 0, productType: SERVER, name: protect("Windows Server 2025")),
|
||||||
|
WindowsVersion(major: 10, minor: 0, buildMin: 20348, buildMax: 26099, productType: SERVER, name: protect("Windows Server 2022")),
|
||||||
|
|
||||||
|
# Windows 10 / Server 2016-2019
|
||||||
|
WindowsVersion(major: 10, minor: 0, buildMin: 19041, buildMax: 19045, productType: WORKSTATION, name: protect("Windows 10 2004/20H2/21H1/21H2/22H2")),
|
||||||
|
WindowsVersion(major: 10, minor: 0, buildMin: 17763, buildMax: 19040, productType: WORKSTATION, name: protect("Windows 10 1809+")),
|
||||||
|
WindowsVersion(major: 10, minor: 0, buildMin: 10240, buildMax: 17762, productType: WORKSTATION, name: protect("Windows 10")),
|
||||||
|
WindowsVersion(major: 10, minor: 0, buildMin: 17763, buildMax: 17763, productType: SERVER, name: protect("Windows Server 2019")),
|
||||||
|
WindowsVersion(major: 10, minor: 0, buildMin: 14393, buildMax: 14393, productType: SERVER, name: protect("Windows Server 2016")),
|
||||||
|
WindowsVersion(major: 10, minor: 0, buildMin: 0, buildMax: 0, productType: SERVER, name: protect("Windows Server (Unknown Build)")),
|
||||||
|
|
||||||
|
# Windows 8.x / Server 2012
|
||||||
|
WindowsVersion(major: 6, minor: 3, buildMin: 0, buildMax: 0, productType: WORKSTATION, name: protect("Windows 8.1")),
|
||||||
|
WindowsVersion(major: 6, minor: 3, buildMin: 0, buildMax: 0, productType: SERVER, name: protect("Windows Server 2012 R2")),
|
||||||
|
WindowsVersion(major: 6, minor: 2, buildMin: 0, buildMax: 0, productType: WORKSTATION, name: protect("Windows 8")),
|
||||||
|
WindowsVersion(major: 6, minor: 2, buildMin: 0, buildMax: 0, productType: SERVER, name: protect("Windows Server 2012")),
|
||||||
|
|
||||||
|
# Windows 7 / Server 2008 R2
|
||||||
|
WindowsVersion(major: 6, minor: 1, buildMin: 0, buildMax: 0, productType: WORKSTATION, name: protect("Windows 7")),
|
||||||
|
WindowsVersion(major: 6, minor: 1, buildMin: 0, buildMax: 0, productType: SERVER, name: protect("Windows Server 2008 R2")),
|
||||||
|
|
||||||
|
# Windows Vista / Server 2008
|
||||||
|
WindowsVersion(major: 6, minor: 0, buildMin: 0, buildMax: 0, productType: WORKSTATION, name: protect("Windows Vista")),
|
||||||
|
WindowsVersion(major: 6, minor: 0, buildMin: 0, buildMax: 0, productType: SERVER, name: protect("Windows Server 2008")),
|
||||||
|
|
||||||
|
# Windows XP / Server 2003
|
||||||
|
WindowsVersion(major: 5, minor: 2, buildMin: 0, buildMax: 0, productType: WORKSTATION, name: protect("Windows XP x64 Edition")),
|
||||||
|
WindowsVersion(major: 5, minor: 2, buildMin: 0, buildMax: 0, productType: SERVER, name: protect("Windows Server 2003")),
|
||||||
|
WindowsVersion(major: 5, minor: 1, buildMin: 0, buildMax: 0, productType: WORKSTATION, name: protect("Windows XP")),
|
||||||
|
]
|
||||||
|
|
||||||
|
proc matchesVersion(version: WindowsVersion, info: OSVersionInfoExW, productType: ProductType): bool =
|
||||||
|
if info.dwMajorVersion != version.major or info.dwMinorVersion != version.minor:
|
||||||
|
return false
|
||||||
|
if productType != version.productType:
|
||||||
|
return false
|
||||||
|
if version.buildMin > 0 and info.dwBuildNumber < version.buildMin:
|
||||||
|
return false
|
||||||
|
if version.buildMax > 0 and info.dwBuildNumber > version.buildMax:
|
||||||
|
return false
|
||||||
|
return true
|
||||||
|
|
||||||
proc getWindowsVersion(info: OSVersionInfoExW, productType: ProductType): string =
|
proc getWindowsVersion(info: OSVersionInfoExW, productType: ProductType): string =
|
||||||
let
|
for version in VERSIONS:
|
||||||
major = info.dwMajorVersion
|
if version.matchesVersion(info, if productType == DC: SERVER else: productType): # Process domain controllers as servers, otherwise they show up as unknown
|
||||||
minor = info.dwMinorVersion
|
if productType == DC:
|
||||||
build = info.dwBuildNumber
|
return version.name & protect(" (Domain Controller)")
|
||||||
spMajor = info.wServicePackMajor
|
else:
|
||||||
|
return version.name
|
||||||
|
|
||||||
if major == 10 and minor == 0:
|
# Unknown windows version, return as much information as possible
|
||||||
if productType == WORKSTATION:
|
return fmt"Windows {$int(info.dwMajorVersion)}.{$int(info.dwMinorVersion)} {$productType} (Build: {$int(info.dwBuildNumber)})"
|
||||||
if build >= 22000:
|
|
||||||
return protect("Windows 11")
|
|
||||||
else:
|
|
||||||
return protect("Windows 10")
|
|
||||||
|
|
||||||
else:
|
|
||||||
case build:
|
|
||||||
of 20348:
|
|
||||||
return protect("Windows Server 2022")
|
|
||||||
of 17763:
|
|
||||||
return protect("Windows Server 2019")
|
|
||||||
of 14393:
|
|
||||||
return protect("Windows Server 2016")
|
|
||||||
else:
|
|
||||||
return protect("Windows Server 10.x (Build: ") & $build & protect(")")
|
|
||||||
|
|
||||||
elif major == 6:
|
|
||||||
case minor:
|
|
||||||
of 3:
|
|
||||||
if productType == WORKSTATION:
|
|
||||||
return protect("Windows 8.1")
|
|
||||||
else:
|
|
||||||
return protect("Windows Server 2012 R2")
|
|
||||||
of 2:
|
|
||||||
if productType == WORKSTATION:
|
|
||||||
return protect("Windows 8")
|
|
||||||
else:
|
|
||||||
return protect("Windows Server 2012")
|
|
||||||
of 1:
|
|
||||||
if productType == WORKSTATION:
|
|
||||||
return protect("Windows 7")
|
|
||||||
else:
|
|
||||||
return protect("Windows Server 2008 R2")
|
|
||||||
of 0:
|
|
||||||
if productType == WORKSTATION:
|
|
||||||
return protect("Windows Vista")
|
|
||||||
else:
|
|
||||||
return protect("Windows Server 2008")
|
|
||||||
else:
|
|
||||||
discard
|
|
||||||
|
|
||||||
elif major == 5:
|
|
||||||
if minor == 2:
|
|
||||||
if productType == WORKSTATION:
|
|
||||||
return protect("Windows XP x64 Edition")
|
|
||||||
else:
|
|
||||||
return protect("Windows Server 2003")
|
|
||||||
elif minor == 1:
|
|
||||||
return protect("Windows XP")
|
|
||||||
else:
|
|
||||||
discard
|
|
||||||
|
|
||||||
return protect("Unknown Windows Version")
|
|
||||||
|
|
||||||
proc getProductType(): ProductType =
|
proc getProductType(): ProductType =
|
||||||
# The product key is retrieved from the registry
|
# The product key is retrieved from the registry
|
||||||
|
|||||||
@@ -201,6 +201,10 @@ proc main(ip: string = "localhost", port: int = 37573) =
|
|||||||
console.draw(connection)
|
console.draw(connection)
|
||||||
newConsoleTable[agentId] = console
|
newConsoleTable[agentId] = console
|
||||||
|
|
||||||
|
if sessionsTable.focusedConsole.len() > 0:
|
||||||
|
igSetWindowFocus_Str(sessionsTable.focusedConsole.cstring)
|
||||||
|
sessionsTable.focusedConsole = ""
|
||||||
|
|
||||||
# Update the consoles table with only those sessions that have not been closed yet
|
# Update the consoles table with only those sessions that have not been closed yet
|
||||||
# This is done to ensure that closed console windows can be opened again
|
# This is done to ensure that closed console windows can be opened again
|
||||||
consoles = newConsoleTable
|
consoles = newConsoleTable
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ type
|
|||||||
agentImpersonation*: Table[string, string]
|
agentImpersonation*: Table[string, string]
|
||||||
selection: ptr ImGuiSelectionBasicStorage
|
selection: ptr ImGuiSelectionBasicStorage
|
||||||
consoles: ptr Table[string, ConsoleComponent]
|
consoles: ptr Table[string, ConsoleComponent]
|
||||||
|
focusedConsole*: string
|
||||||
|
|
||||||
proc SessionsTable*(title: string, consoles: ptr Table[string, ConsoleComponent]): SessionsTableComponent =
|
proc SessionsTable*(title: string, consoles: ptr Table[string, ConsoleComponent]): SessionsTableComponent =
|
||||||
result = new SessionsTableComponent
|
result = new SessionsTableComponent
|
||||||
@@ -23,6 +24,7 @@ proc SessionsTable*(title: string, consoles: ptr Table[string, ConsoleComponent]
|
|||||||
result.agentActivity = initTable[string, int64]()
|
result.agentActivity = initTable[string, int64]()
|
||||||
result.selection = ImGuiSelectionBasicStorage_ImGuiSelectionBasicStorage()
|
result.selection = ImGuiSelectionBasicStorage_ImGuiSelectionBasicStorage()
|
||||||
result.consoles = consoles
|
result.consoles = consoles
|
||||||
|
result.focusedConsole = ""
|
||||||
|
|
||||||
proc cmp(x, y: UIAgent): int =
|
proc cmp(x, y: UIAgent): int =
|
||||||
return cmp(x.firstCheckin, y.firstCheckin)
|
return cmp(x.firstCheckin, y.firstCheckin)
|
||||||
@@ -39,9 +41,7 @@ proc interact(component: SessionsTableComponent) =
|
|||||||
if not component.consoles[].hasKey(agent.agentId):
|
if not component.consoles[].hasKey(agent.agentId):
|
||||||
component.consoles[][agent.agentId] = Console(agent)
|
component.consoles[][agent.agentId] = Console(agent)
|
||||||
|
|
||||||
# Focus the existing console window
|
component.focusedConsole = fmt"[{agent.agentId}] {agent.username}@{agent.hostname}"
|
||||||
else:
|
|
||||||
igSetWindowFocus_Str(fmt"[{agent.agentId}] {agent.username}@{agent.hostname}".cstring)
|
|
||||||
|
|
||||||
component.selection.ImGuiSelectionBasicStorage_Clear()
|
component.selection.ImGuiSelectionBasicStorage_Clear()
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user