Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
#ide stuff
*.idea
.idea/

# Binaries for programs and plugins
*.exe
*.exe~
Expand Down
Empty file modified embed/linux/triage/firewall.sh
100644 → 100755
Empty file.
25 changes: 25 additions & 0 deletions triage/domain_info_linux.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package triage

import (
"fmt"
"os"
"os/exec"
"strings"
)

func getDomainInfo() string {
// Check 1: sssd.conf
content, err := os.ReadFile("/etc/sssd/sssd.conf")
if err == nil {
fmt.Println("sssd.conf")
return strings.TrimSpace(string(content)) + "\t"
}

// Check 2: realm list (if available)
out, err := exec.Command("realm", "list").Output()
if err == nil && len(out) > 0 {
return strings.TrimSpace(string(out)) + "\t"
}

return "Not Domain Jointed" + "\t"
}
27 changes: 27 additions & 0 deletions triage/domain_info_windows.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package triage

import (
"os/exec"
"strings"
)

func getDomainInfo() string {
out, err := exec.Command("wmic", "computersystem", "get", "domain").Output()
if err != nil {
return "Not Domain Joined" + "\t"
}

lines := strings.Split(strings.TrimSpace(string(out)), "\n")
for _, line := range lines {
line = strings.TrimSpace(line)
if line == "" || line == "Domain" {
continue
}
if line == "WORKGROUP" {
return "Not Domain Joined" + "\t"
}
return line + "\t"
}

return "Not Domain Joined" + "\t"
}
21 changes: 18 additions & 3 deletions triage/firewall_linux.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,22 @@
package triage

import "github.com/UT-CTF/landschaft/util"
import (
"strings"

func runFirewallTriage() {
util.RunAndPrintScript("triage/firewall.sh")
"github.com/UT-CTF/landschaft/util"
)

func runFirewallTriage() string {
result := util.RunAndPrintScript("triage/firewall.sh")
result = strings.ReplaceAll(result, "\n", " ")
result = strings.ReplaceAll(result, "\r", "")
result = strings.Join(strings.Fields(result), " ")
result = strings.ReplaceAll(result, "=", "")
result += "\t"

if strings.Contains(result, "No supported firewall") {
result = "No Firewall!\t"
}

return result
}
91 changes: 89 additions & 2 deletions triage/firewall_windows.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,96 @@
package triage

import (
"fmt"
"strings"

"github.com/UT-CTF/landschaft/util"
)

func runFirewallTriage() {
util.RunAndPrintScript("triage/firewall.ps1")
func runFirewallTriage() string {
result := parseFirewall(util.RunAndPrintScript("triage/firewall.ps1")) + "\t"
return result
}

func parseFirewall(result string) string {
lines := strings.Split(result, "\n")

type iface struct {
name string
alias string
category string
}

var interfaces []iface
profileEnabled := make(map[string]bool)
profileState := make(map[string]string)
profilePolicy := make(map[string]string)
currentProfile := ""

for _, line := range lines {
Comment thread
thankgod4rob marked this conversation as resolved.
trimmed := strings.TrimSpace(line)

if strings.HasPrefix(trimmed, "Name") || strings.HasPrefix(trimmed, "----") || trimmed == "" || strings.HasPrefix(trimmed, "Interfaces:") {
continue
}

fields := strings.Fields(trimmed)

if strings.HasPrefix(trimmed, "Profile:") {
parts := strings.Split(trimmed, " - ")
profileName := strings.TrimSpace(strings.TrimPrefix(parts[0], "Profile:"))
if len(parts) > 1 {
profileEnabled[profileName] = strings.TrimSpace(parts[1]) == "Enabled"
}
continue
}

if strings.HasSuffix(trimmed, "Profile Settings:") {
currentProfile = strings.TrimSuffix(trimmed, " Profile Settings:")
continue
}

if currentProfile != "" {
if strings.HasPrefix(trimmed, "State") {
profileState[currentProfile] = strings.TrimSpace(strings.TrimPrefix(trimmed, "State"))
continue
}
if strings.HasPrefix(trimmed, "Firewall Policy") {
profilePolicy[currentProfile] = strings.TrimSpace(strings.TrimPrefix(trimmed, "Firewall Policy"))
continue
}
}

// interface line - last field is category, second to last is alias, rest is name
if len(fields) >= 3 {
category := fields[len(fields)-1]
alias := fields[len(fields)-2]
name := strings.Join(fields[:len(fields)-2], " ")
interfaces = append(interfaces, iface{name, alias, category})
}
}

var parts []string
for _, i := range interfaces {
enabled := "Disabled"
check := false
if profileEnabled[i.category] {
enabled = "Enabled"
check = true
}
state := profileState[i.category]
policy := profilePolicy[i.category]

if check {
parts = append(parts, fmt.Sprintf("%s - %s \n\t%s - %s \n\tState %s \n\tFirewall Policy: %s",
i.name, i.alias, i.category, enabled, state, policy))
} else {
parts = append(parts, fmt.Sprintf("%s - %s \n\t%s - %s",
i.name, i.alias, i.category, enabled))
}

}

return "\"" + strings.Join(parts, "\n\n ") + "\""

}
67 changes: 62 additions & 5 deletions triage/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,74 @@ package triage

import (
"fmt"
"os"
"path/filepath"
"runtime"
"strings"

"github.com/UT-CTF/landschaft/util"
)

func Run() {
file, err := os.Create("triage.tsv")
if err != nil {
fmt.Println("Error creating csv file:", err)
}

fmt.Println(util.TitleColor.Render("Network"))
runNetworkTriage()
fmt.Println(util.TitleColor.Render("Users & Groups"))
runUsersTriage()

hostname, csv := runNetworkTriage()

fmt.Println(util.TitleColor.Render("OS Version"))
runOSVersionTriage()

if _, err := file.Write([]byte(hostname + "\t" + runOSVersionTriage() + "\t" + csv)); err != nil {
// ignore error
}

fmt.Println(util.TitleColor.Render("Users & Groups"))

if _, err := file.Write([]byte(runUsersTriage())); err != nil {
// ignore error
}

fmt.Println(util.TitleColor.Render("Firewall"))
runFirewallTriage()

if _, err := file.Write([]byte(runFirewallTriage())); err != nil {
// ignore error
}

if _, err := file.Write([]byte(getDomainInfo())); err != nil {
// ignore error
}

errF := file.Close()
if errF != nil {

}

printCopyInstructions()

}

func printCopyInstructions() {
sshConn := os.Getenv("SSH_CONNECTION")
fields := strings.Fields(sshConn)
serverUser := os.Getenv("USER")
serverIP := "<ip>"
if len(fields) >= 3 {
serverIP = fields[2]
}

exePath, _ := os.Executable()
tsvPath := filepath.Join(filepath.Dir(exePath), "triage.tsv")

catCmd := "cat"
if runtime.GOOS == "windows" {
catCmd = "type"
serverUser = os.Getenv("USERNAME")
}

fmt.Println("To copy to clipboard:")
fmt.Printf("\tIf your host is linux: ssh %s@%s \"%s %s\" | xclip -selection clipboard\n\n", serverUser, serverIP, catCmd, tsvPath)
fmt.Printf("\tIf your host is windows: ssh %s@%s \"%s %s\" | clip.exe\n\n\n", serverUser, serverIP, catCmd, tsvPath)
}
Loading