/**
* Output parsing utilities for various security tools
*/
/**
* Parse nmap output for open ports
*/
export function parseNmapPorts(output: string): Array<{
port: number;
protocol: string;
state: string;
service: string;
version?: string;
}> {
const ports: Array<{
port: number;
protocol: string;
state: string;
service: string;
version?: string;
}> = [];
const lines = output.split("\n");
for (const line of lines) {
// Match lines like: "80/tcp open http nginx 1.18.0"
const match = line.match(/^(\d+)\/(tcp|udp)\s+(\w+)\s+(\S+)(?:\s+(.+))?/);
if (match) {
ports.push({
port: parseInt(match[1]!, 10),
protocol: match[2]!,
state: match[3]!,
service: match[4]!,
version: match[5]?.trim(),
});
}
}
return ports;
}
/**
* Parse nmap hosts
*/
export function parseNmapHosts(output: string): Array<{
ip: string;
hostname?: string;
status: string;
}> {
const hosts: Array<{
ip: string;
hostname?: string;
status: string;
}> = [];
const lines = output.split("\n");
for (const line of lines) {
// Match: "Nmap scan report for example.com (192.168.1.1)"
const match1 = line.match(/Nmap scan report for (.+) \(([^)]+)\)/);
if (match1) {
hosts.push({
hostname: match1[1],
ip: match1[2]!,
status: "up",
});
continue;
}
// Match: "Nmap scan report for 192.168.1.1"
const match2 = line.match(/Nmap scan report for ([0-9.]+)/);
if (match2) {
hosts.push({
ip: match2[1]!,
status: "up",
});
}
}
return hosts;
}
/**
* Parse gobuster directory results
*/
export function parseGobusterResults(output: string): Array<{
path: string;
status: number;
size: string;
}> {
const results: Array<{
path: string;
status: number;
size: string;
}> = [];
const lines = output.split("\n");
for (const line of lines) {
// Match: "/admin (Status: 200) [Size: 1234]"
const match = line.match(/^(\S+)\s+\(Status:\s+(\d+)\)\s+\[Size:\s+([^\]]+)\]/);
if (match) {
results.push({
path: match[1]!,
status: parseInt(match[2]!, 10),
size: match[3]!,
});
}
}
return results;
}
/**
* Parse SQLMap output for vulnerabilities
*/
export function parseSQLMapResults(output: string): {
vulnerable: boolean;
injectionType?: string;
dbms?: string;
details: string[];
} {
const result = {
vulnerable: false,
injectionType: undefined as string | undefined,
dbms: undefined as string | undefined,
details: [] as string[],
};
const lines = output.split("\n");
for (const line of lines) {
if (line.includes("sqlmap identified the following injection point")) {
result.vulnerable = true;
}
const injectionMatch = line.match(/Type:\s+(.+)/);
if (injectionMatch) {
result.injectionType = injectionMatch[1]?.trim();
}
const dbmsMatch = line.match(/back-end DBMS:\s+(.+)/i);
if (dbmsMatch) {
result.dbms = dbmsMatch[1]?.trim();
}
if (line.trim().startsWith("Parameter:") || line.includes("Payload:")) {
result.details.push(line.trim());
}
}
return result;
}
/**
* Parse Nikto vulnerabilities
*/
export function parseNiktoResults(output: string): Array<{
id: string;
severity: string;
description: string;
}> {
const vulns: Array<{
id: string;
severity: string;
description: string;
}> = [];
const lines = output.split("\n");
for (const line of lines) {
// Match: "+ OSVDB-3092: /admin/: This might be interesting..."
const match = line.match(/^\+\s+(OSVDB-\d+):\s+(.+)/);
if (match) {
vulns.push({
id: match[1]!,
severity: "info",
description: match[2]!.trim(),
});
}
}
return vulns;
}
/**
* Parse Hydra results
*/
export function parseHydraResults(output: string): Array<{
host: string;
port: number;
service: string;
username: string;
password: string;
}> {
const results: Array<{
host: string;
port: number;
service: string;
username: string;
password: string;
}> = [];
const lines = output.split("\n");
for (const line of lines) {
// Match: "[22][ssh] host: 192.168.1.1 login: admin password: password123"
const match = line.match(/\[(\d+)\]\[(\w+)\]\s+host:\s+(\S+)\s+login:\s+(\S+)\s+password:\s+(\S+)/);
if (match) {
results.push({
port: parseInt(match[1]!, 10),
service: match[2]!,
host: match[3]!,
username: match[4]!,
password: match[5]!,
});
}
}
return results;
}
/**
* Parse searchsploit results
*/
export function parseSearchsploitResults(output: string): Array<{
title: string;
path: string;
id?: string;
}> {
const results: Array<{
title: string;
path: string;
id?: string;
}> = [];
const lines = output.split("\n");
let inResults = false;
for (const line of lines) {
// Skip header lines
if (line.includes("---") || line.includes("Exploit Title")) {
inResults = true;
continue;
}
if (!inResults || line.trim().length === 0) {
continue;
}
// Parse result line
const parts = line.split("|");
if (parts.length >= 2) {
const title = parts[0]?.trim();
const path = parts[1]?.trim();
if (title && path) {
results.push({
title,
path,
});
}
}
}
return results;
}
/**
* Parse theHarvester results
*/
export function parseHarvesterResults(output: string): {
emails: string[];
hosts: string[];
ips: string[];
} {
const result = {
emails: [] as string[],
hosts: [] as string[],
ips: [] as string[],
};
const lines = output.split("\n");
let section = "";
for (const line of lines) {
if (line.includes("[*] Emails found:")) {
section = "emails";
continue;
} else if (line.includes("[*] Hosts found:")) {
section = "hosts";
continue;
} else if (line.includes("[*] IPs found:")) {
section = "ips";
continue;
}
const trimmed = line.trim();
if (trimmed && !trimmed.startsWith("[")) {
if (section === "emails" && trimmed.includes("@")) {
result.emails.push(trimmed);
} else if (section === "hosts") {
result.hosts.push(trimmed);
} else if (section === "ips" && /\d+\.\d+\.\d+\.\d+/.test(trimmed)) {
result.ips.push(trimmed);
}
}
}
return result;
}
/**
* Parse WPScan results
*/
export function parseWPScanResults(output: string): {
version?: string;
theme?: string;
plugins: string[];
vulnerabilities: Array<{
title: string;
references: string[];
}>;
} {
const result = {
version: undefined as string | undefined,
theme: undefined as string | undefined,
plugins: [] as string[],
vulnerabilities: [] as Array<{
title: string;
references: string[];
}>,
};
const lines = output.split("\n");
for (const line of lines) {
const versionMatch = line.match(/WordPress version (\S+)/i);
if (versionMatch) {
result.version = versionMatch[1];
}
const themeMatch = line.match(/WordPress theme in use: (\S+)/i);
if (themeMatch) {
result.theme = themeMatch[1];
}
if (line.includes("[+]") && line.toLowerCase().includes("plugin")) {
const pluginMatch = line.match(/\[.\]\s+(.+)/);
if (pluginMatch) {
result.plugins.push(pluginMatch[1]!.trim());
}
}
}
return result;
}
/**
* Parse enum4linux results
*/
export function parseEnum4LinuxResults(output: string): {
domain?: string;
users: string[];
shares: string[];
groups: string[];
} {
const result = {
domain: undefined as string | undefined,
users: [] as string[],
shares: [] as string[],
groups: [] as string[],
};
const lines = output.split("\n");
let section = "";
for (const line of lines) {
if (line.includes("Domain Name:")) {
const match = line.match(/Domain Name:\s+(\S+)/);
if (match) {
result.domain = match[1];
}
}
if (line.includes("===") && line.includes("Users")) {
section = "users";
continue;
} else if (line.includes("===") && line.includes("Share")) {
section = "shares";
continue;
} else if (line.includes("===") && line.includes("Groups")) {
section = "groups";
continue;
}
const trimmed = line.trim();
if (trimmed && section) {
if (section === "users" && trimmed.startsWith("user:")) {
const userMatch = trimmed.match(/user:\[([^\]]+)\]/);
if (userMatch) {
result.users.push(userMatch[1]!);
}
} else if (section === "shares" && trimmed.includes("Sharename:")) {
const shareMatch = trimmed.match(/Sharename:\s+(\S+)/);
if (shareMatch) {
result.shares.push(shareMatch[1]!);
}
} else if (section === "groups" && trimmed.startsWith("group:")) {
const groupMatch = trimmed.match(/group:\[([^\]]+)\]/);
if (groupMatch) {
result.groups.push(groupMatch[1]!);
}
}
}
}
return result;
}
/**
* Parse binwalk results
*/
export function parseBinwalkResults(output: string): Array<{
offset: string;
description: string;
}> {
const results: Array<{
offset: string;
description: string;
}> = [];
const lines = output.split("\n");
for (const line of lines) {
// Match: "0 0x0 PNG image"
const match = line.match(/^(\d+)\s+(0x[0-9A-Fa-f]+)\s+(.+)/);
if (match) {
results.push({
offset: match[2]!,
description: match[3]!.trim(),
});
}
}
return results;
}
/**
* Extract CVE IDs from text
*/
export function extractCVEs(text: string): string[] {
const cveRegex = /CVE-\d{4}-\d{4,}/gi;
const matches = text.match(cveRegex);
return matches ? Array.from(new Set(matches)) : [];
}
/**
* Extract IP addresses from text
*/
export function extractIPs(text: string): string[] {
const ipRegex = /\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/g;
const matches = text.match(ipRegex);
return matches ? Array.from(new Set(matches)) : [];
}
/**
* Extract URLs from text
*/
export function extractURLs(text: string): string[] {
const urlRegex = /https?:\/\/[^\s]+/g;
const matches = text.match(urlRegex);
return matches ? Array.from(new Set(matches)) : [];
}
/**
* Extract email addresses from text
*/
export function extractEmails(text: string): string[] {
const emailRegex = /[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/g;
const matches = text.match(emailRegex);
return matches ? Array.from(new Set(matches)) : [];
}
/**
* Extract domains from text
*/
export function extractDomains(text: string): string[] {
const domainRegex = /\b([a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}\b/g;
const matches = text.match(domainRegex);
return matches ? Array.from(new Set(matches)) : [];
}