LOLBASline.psm1

<#
.SYNOPSIS
LOLBASline - A PowerShell tool for checking the presence and execution status of Living Off The Land Binaries and Scripts (LOLBAS).

.DESCRIPTION
LOLBASline checks for the existence of specified binaries and attempts to execute commands from the LOLBAS project definitions. It provides insights into which LOLBAS items are present and executable on a Windows system. Use this tool in controlled environments to assess system exposure to threats that use LOLBAS.

.AUTHOR
Name: Jose E Hernandez
Organization: MagicSword
Email: jose@magicsword.io

.NOTES
Version: 1
Last Updated: 03/11/2024
License: Apache 2.0
GitHub: https://github.com/magicsword-io/LOLBASline

.LINK
LOLBAS Project - https://github.com/LOLBAS-Project/LOLBAS
#>


function Invoke-LOLBASline {
    param (
        [string]$Path = $null,
        [string]$Output = "results.csv",
        [switch]$Verbose,
        [switch]$Help  # Add a help flag parameter
    )

    # Check if the Help flag is used and display help information
    if ($Help) {
        Write-Host "Usage of Invoke-LOLBASline:"
        Write-Host " -Path [string]: Specify the path to clone the LOLBAS repository."
        Write-Host " -Output [string]: Specify the output file for results. Default is 'results.csv'."
        Write-Host " -Verbose: Enable verbose output."
        Write-Host " -Help: Display this help message."
        return
    }

    Import-Module powershell-yaml -ErrorAction Stop

    function Clone-LOLBASRepo {
        param (
            [string]$Destination
        )

        # Check if git is available
        $gitInstalled = Get-Command "git" -ErrorAction SilentlyContinue
        if (-not $gitInstalled) {
            Write-Warning "Git is not installed. Please install Git to use this module."
            Write-Host "You can download Git from https://git-scm.com/downloads"
            # Exit the script if Git is not installed
            return $null
        }

        if (-not (Test-Path $Destination)) {
            $RepoURL = "https://github.com/LOLBAS-Project/LOLBAS.git"
            Write-Host "Cloning LOLBAS project to $Destination..."
            git clone $RepoURL $Destination
        } else {
            Write-Host "$Destination already exists. Using existing repository."
        }
        return "$Destination/yml/OSBinaries"
    }

    function Load-YAMLFiles {
        param (
            [string]$DirectoryPath
        )

        $YamlFiles = Get-ChildItem -Path $DirectoryPath -Filter *.yml -Recurse
        $YamlObjects = @()

        foreach ($File in $YamlFiles) {
            $YamlContent = Get-Content $File.FullName -Raw
            $YamlObject = ConvertFrom-Yaml $YamlContent
            $YamlObjects += $YamlObject
        }

        return $YamlObjects
    }

    function Check-Binaries {
        param (
            [System.Collections.ArrayList]$YamlData,
            [switch]$Verbose
        )

        $Results = @()

        foreach ($Data in $YamlData) {
            if ($Data.Commands) {
                foreach ($CommandInfo in $Data.Commands) {
                    $ExecutablePath = $Data.Full_Path[0].Path
                    try {
                        $Presence = if (Test-Path $ExecutablePath) { "Yes" } else { "No" }
                    } catch {
                        $Presence = "Error in Path"
                        if ($Verbose) {
                            Write-Host "Error testing path '$ExecutablePath': $_" -ForegroundColor Red
                        }
                    }
                    $ExecutableCommand = $CommandInfo.Command
                    $executionResult = "Not Executed"
                    
                    if ($Presence -eq "Yes") {
                        try {
                            $process = Start-Process -FilePath "cmd.exe" -ArgumentList "/c $ExecutableCommand" -PassThru -WindowStyle Hidden
                            Start-Sleep -Seconds 2 # Give the command a moment to execute; adjust as needed
                            if ($process.HasExited -eq $false) {
                                $process.Kill()
                                $executionResult = "Executed"
                            } else {
                                $executionResult = "Failed"
                            }
                        } catch {
                            $executionResult = "Error"
                        }
                    }

                    $Result = [PSCustomObject]@{
                        Name            = $Data.Name
                        Path            = $ExecutablePath
                        Presence        = $Presence
                        ExecutionResult = $executionResult
                        Command         = $ExecutableCommand
                        Description     = $CommandInfo.Description
                        Usecase         = $CommandInfo.Usecase
                        Category        = $CommandInfo.Category
                    }

                    $Results += $Result

                    if ($Verbose) {
                        $color = switch ($executionResult) {
                            "Executed" { "Green" }
                            "Failed"   { "Red" }
                            Default    { "Yellow" }
                        }
                        Write-Host "$($Data.Name): Presence = $($Presence), Execution result = $($executionResult)" -ForegroundColor $color
                    }
                }
            }
        }

        return $Results
    }

    $Path = Clone-LOLBASRepo -Destination "lolbas_repo"
    if (-not $Path) {
        Write-Host "Unable to continue without Git. Exiting script."
        return
    }

    $YamlData = Load-YAMLFiles -DirectoryPath $Path
    $Results = Check-Binaries -YamlData $YamlData -Verbose:$Verbose
    $Results | Export-Csv -Path $Output -NoTypeInformation
    Write-Host "Results written to $Output"
}