lolbins.psm1

$lolbinData = Invoke-RestMethod "https://lolbas-project.github.io/api/lolbas.json"

###############################################################################
# 1) Test-LOLBinPaths
###############################################################################
function Test-LOLBinPaths {
<#
.SYNOPSIS
    Tests each LOLBin's known file paths to see which ones exist on the system.
 
.DESCRIPTION
    Loops through $lolbinData (which must already be loaded) and verifies
    whether each listed path exists. Returns a filtered LOLBin object
    containing only the valid paths.
 
.EXAMPLE
    Test-LOLBinPaths
#>

    [CmdletBinding()]
    param()

    if (-not $lolbinData) {
        Write-Warning "LOLBin data not loaded. Please run Update-LOLBinData first or ensure $lolbinData is populated."
        return
    }

    $foundBins = @()

    foreach ($bin in $lolbinData) {
        $validPaths = @()

        if ($bin.Full_Path) {
            foreach ($pathEntry in $bin.Full_Path) {
                $path = $pathEntry.Path
                if (Test-Path $path) {
                    $validPaths += @{ Path = $path }
                }
            }
        }

        if ($validPaths.Count -gt 0) {
            $filteredBin = $bin.PSObject.Copy()
            $filteredBin.Full_Path = $validPaths
            $foundBins += $filteredBin
        }
    }
    return $foundBins
}


###############################################################################
# 2) Update-LOLBinData
###############################################################################
function Update-LOLBinData {
<#
.SYNOPSIS
    Refreshes $lolbinData from the LOLBAS API endpoint.
 
.DESCRIPTION
    By default, downloads the JSON from the LOLBAS GitHub endpoint
    (https://lolbas-project.github.io/api/lolbas.json) and updates the
    $lolbinData variable in the current session. You can override the URL
    if the API changes or you have a local mirror.
 
.EXAMPLE
    Update-LOLBinData
 
    # Then confirm:
    $lolbinData.Count
#>

    [CmdletBinding()]
    param(
        [Parameter(ValueFromPipelineByPropertyName=$true)]
        [string]
        $Url = "https://lolbas-project.github.io/api/lolbas.json"
    )

    try {
        Write-Verbose "Downloading LOLBAS data from: $Url"
        $global:lolbinData = Invoke-RestMethod -Uri $Url
        Write-Host "LOLBin data successfully updated from $Url. Total items: $($global:lolbinData.Count)"
    }
    catch {
        Write-Warning "Failed to update data from $Url. Error: $_"
    }
}


###############################################################################
# 3) Get-LOLBinSummary
###############################################################################
function Get-LOLBinSummary {
<#
.SYNOPSIS
    Provides a concise overview of LOLBins (Name, Description, Author, etc.).
 
.DESCRIPTION
    Returns core properties of a single LOLBin if -Name is specified, or
    of all LOLBins if not. This is a quick way to see top-level info
    without drilling into commands or detection details.
 
.EXAMPLE
    Get-LOLBinSummary -Name "AddinUtil.exe"
 
.EXAMPLE
    Get-LOLBinSummary
#>

    [CmdletBinding()]
    param(
        [Parameter(ValueFromPipelineByPropertyName=$true)]
        [string]
        $Name
    )

    if (-not $lolbinData) {
        Write-Warning "LOLBin data not loaded. Please run Update-LOLBinData first."
        return
    }

    $filtered = if ($Name) {
        $lolbinData | Where-Object { $_.Name -eq $Name }
    }
    else {
        $lolbinData
    }

    $filtered | ForEach-Object {
        [PSCustomObject]@{
            Name        = $_.Name
            Description = $_.Description
            Author      = $_.Author
            Created     = $_.Created
            Categories  = ($_.Commands.Category | Sort-Object -Unique) -join ", "
            Privileges  = ($_.Commands.Privileges | Sort-Object -Unique) -join ", "
            OS          = ($_.Commands.OperatingSystem | Sort-Object -Unique) -join ", "
        }
    }
}


###############################################################################
# 4) Get-LOLBinByName
###############################################################################
function Get-LOLBinByName {
<#
.SYNOPSIS
    Retrieves the raw JSON object for a specific LOLBin by Name.
 
.DESCRIPTION
    Matches a LOLBin by its Name property and returns the entire JSON
    object, including Commands, Detection, Resources, etc.
 
.EXAMPLE
    Get-LOLBinByName -Name "Certutil.exe"
#>

    [CmdletBinding()]
    param(
        [Parameter(Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [string]
        $Name
    )

    if (-not $lolbinData) {
        Write-Warning "LOLBin data not loaded."
        return
    }

    $lolbinData | Where-Object { $_.Name -eq $Name }
}


###############################################################################
# 5) Get-LOLBinUsage
###############################################################################
function Get-LOLBinUsage {
<#
.SYNOPSIS
    Shows all commands and usage info for the specified LOLBin.
 
.DESCRIPTION
    Each LOLBin can contain multiple command entries (in .Commands).
    This function returns them in a more detailed, readable format.
 
.EXAMPLE
    Get-LOLBinUsage -Name "Bitsadmin.exe"
#>

    [CmdletBinding()]
    param(
        [Parameter(Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [string]
        $Name
    )

    if (-not $lolbinData) {
        Write-Warning "LOLBin data not loaded."
        return
    }

    $bin = $lolbinData | Where-Object { $_.Name -eq $Name }
    if (-not $bin) {
        Write-Warning "LOLBin '$Name' not found."
        return
    }

    return $bin.Commands | Select-Object Command, Description, Usecase, Category, Privileges, MitreID, OperatingSystem
}


###############################################################################
# 6) Search-LOLBin
###############################################################################
function Search-LOLBin {
<#
.SYNOPSIS
    Searches LOLBins by a keyword across multiple fields.
 
.DESCRIPTION
    Searches for a given keyword within each LOLBin's Description,
    Commands.Command text, or other optional fields if -Extended is specified.
    Returns matching LOLBins.
 
.EXAMPLE
    Search-LOLBin -Keyword "proxy"
#>

    [CmdletBinding()]
    param(
        [Parameter(Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [string]
        $Keyword,

        [switch] 
        $Extended
    )

    if (-not $lolbinData) {
        Write-Warning "LOLBin data not loaded."
        return
    }

    $keywordRegex = [Regex]::Escape($Keyword)

    # Basic search in Description or Command
    $results = $lolbinData | Where-Object {
        ($_.Description -match $keywordRegex) -or
        ($_.Commands.Command -match $keywordRegex)
    }

    # Optionally include advanced fields
    if ($Extended) {
        $results += $lolbinData | Where-Object {
            ($_.Commands.Usecase -match $keywordRegex) -or
            ($_.Commands.Category -match $keywordRegex) -or
            ($_.Commands.Tags -match $keywordRegex)
        }
        $results = $results | Sort-Object -Unique
    }

    return $results
}


###############################################################################
# 7) Find-LOLBinByMitreID
###############################################################################
function Find-LOLBinByMitreID {
<#
.SYNOPSIS
    Finds LOLBins that reference a given MITRE ATT&CK ID in their Commands.
 
.DESCRIPTION
    Checks each LOLBin's Commands array for a match in the .MitreID property.
 
.EXAMPLE
    Find-LOLBinByMitreID -MitreID "T1218"
#>

    [CmdletBinding()]
    param(
        [Parameter(Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [string]
        $MitreID
    )

    if (-not $lolbinData) {
        Write-Warning "LOLBin data not loaded."
        return
    }

    $lolbinData | Where-Object {
        $_.Commands.MitreID -contains $MitreID
    }
}


###############################################################################
# 8) Find-LOLBinByTag
###############################################################################
function Find-LOLBinByTag {
<#
.SYNOPSIS
    Finds LOLBins whose Commands array has a given Tag entry.
 
.DESCRIPTION
    Some LOLBins have "Tags" for certain usage (e.g. "Download", "AWL Bypass").
    This function returns all LOLBins that have a matching Tag anywhere in
    their Commands[].Tags[] array.
 
.EXAMPLE
    Find-LOLBinByTag -Tag "Download"
#>

    [CmdletBinding()]
    param(
        [Parameter(Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [string]
        $Tag
    )

    if (-not $lolbinData) {
        Write-Warning "LOLBin data not loaded."
        return
    }

    $lolbinData | Where-Object {
        # Check if Commands[].Tags[] exist AND if any of them contain $Tag
        $_.Commands.Tags -and (
            $_.Commands.Tags | Where-Object { $_.PSObject.Properties.Value -contains $Tag }
        )
    }
}


###############################################################################
# 9) Get-LOLBinCategory
###############################################################################
function Get-LOLBinCategory {
<#
.SYNOPSIS
    Lists all distinct categories if no parameter is specified,
    or returns LOLBins in a specific category if -Category is given.
 
.DESCRIPTION
    Each LOLBin can have one or more categories in its Commands[].Category
    property. This function either returns the distinct category names
    or the LOLBins that match a specific category.
 
.EXAMPLE
    # Get all unique category names
    Get-LOLBinCategory
 
.EXAMPLE
    # Get all LOLBins in "Execute" category
    Get-LOLBinCategory -Category "Execute"
#>

    [CmdletBinding()]
    param(
        [string]
        $Category
    )

    if (-not $lolbinData) {
        Write-Warning "LOLBin data not loaded."
        return
    }

    if (-not $Category) {
        # Return all distinct categories across all Commands
        $allCats = $lolbinData.Commands.Category | Where-Object { $_ } | Sort-Object -Unique
        return $allCats
    }
    else {
        # Return LOLBins that contain the specified category
        return $lolbinData | Where-Object {
            $_.Commands.Category -contains $Category
        }
    }
}


###############################################################################
# 10) Get-LOLBinDetection
###############################################################################
function Get-LOLBinDetection {
<#
.SYNOPSIS
    Returns detection-related info (Sigma, Splunk, Elastic, IOCs, etc.)
    for a given LOLBin.
 
.DESCRIPTION
    Some LOLBins have an array of detection references in .Detection.
    This function displays them in a structured way.
 
.EXAMPLE
    Get-LOLBinDetection -Name "AddinUtil.exe"
#>

    [CmdletBinding()]
    param(
        [Parameter(Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [string]
        $Name
    )

    if (-not $lolbinData) {
        Write-Warning "LOLBin data not loaded."
        return
    }

    $bin = $lolbinData | Where-Object { $_.Name -eq $Name }
    if (-not $bin) {
        Write-Warning "LOLBin '$Name' not found."
        return
    }

    # Return the raw detection objects, or flatten if needed
    $bin.Detection
}