From ed4d60c64de169bec5ecc968bbf6d5d104b1c278 Mon Sep 17 00:00:00 2001 From: Aidan Feess <145503050+AidanFeess@users.noreply.github.com> Date: Thu, 14 Dec 2023 12:34:32 -0800 Subject: [PATCH] Add winpeas to json powershell parser --- parsers/peas2json.ps1 | 205 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 205 insertions(+) create mode 100644 parsers/peas2json.ps1 diff --git a/parsers/peas2json.ps1 b/parsers/peas2json.ps1 new file mode 100644 index 0000000..ffa1217 --- /dev/null +++ b/parsers/peas2json.ps1 @@ -0,0 +1,205 @@ +# Based on https://github.com/carlospolop/PEASS-ng/blob/master/parsers/peas2json.py + +# Pattern to identify main section titles +$CHAR_1 = [String][char]0x2550 # ═ +$CHAR_2 = [String][char]0x2554 # ╔ +$CHAR_3 = [String][char]0x2563 # ╣ +$CHAR_4 = [String][char]0x255a # ╚ +$TITLE_CHARS = [String][char]0x2550, [String][char]0x2554, [String][char]0x2563, [String][char]0x255a # ═, ╔, ╣, ╚ +$TITLE1_PATTERN = $CHAR_1*14 + $CHAR_3 #══════════════╣# +#The size of the first pattern varies, but at least should be that large +$TITLE2_PATTERN = $CHAR_2 + $CHAR_1*10 + $CHAR_3 #╔══════════╣# +$TITLE3_PATTERN = $CHAR_1*2 + $CHAR_3 #══╣# +$INFO_PATTERN = $CHAR_4 #╚ # + +$encoding = [System.Text.Encoding]::UTF8 + +# Patterns from color +## The order is important, the first string colored with a color will be the one selected (the same string cannot be colored with different colors) +$global:COLORS = @{ + "REDYELLOW" = "\x1b\[1;31;103m"; + "RED" = "\x1b\[1;31m"; + "GREEN" = "\x1b\[1;32m"; + "YELLOW" = "\x1b\[1;33m"; + "BLUE" = "\x1b\[1;34m"; + "MAGENTA" = "\x1b\[1;95m", "\x1b\[1;35m"; + "CYAN" = "\x1b\[1;36m", "\x1b\[1;96m"; + "LIGHT_GREY" = "\x1b\[1;37m"; + "DARKGREY" = "\x1b\[1;90m"; +} + +$global:FINAL_JSON = @{} + +$global:C_SECTION = $FINAL_JSON +$global:C_MAIN_SECTION = $FINAL_JSON +$global:C_2_SECTION = $FINAL_JSON +$global:C_3_SECTION = $FINAL_JSON + +function is_section { + param ( + [string] $line, + [string] $pattern + ) + + # Checks ifa line matches the pattern + return $line.contains($pattern) +} + +function clean_colors { + param ( + [string] $line + ) + + # Given a line, clean the colors inside of it + + $line = $line -replace '\x1b\[[0-9;]*m','' + $line = $line.Trim() + return $line + +} + +function clean_title { + param ( + [string] $line + ) + # Given a title, clean it + foreach($c in $TITLE_CHARS){ + $line = $line.Replace($c, "") + } + + $line = [System.Text.Encoding]::ASCII.GetString($encoding.GetBytes($line)) + $line = $line.Trim() + return $line + +} + +function get_colors { + param ( + [string] $line + ) + + [hashtable]$colors = @{} + + $global:COLORS.GetEnumerator() | ForEach-Object { + $colors[$_.Key] = '' + foreach($reg in $_.Value){ # eq reg in regexs in py + $split_color = $line -split $reg + # Start from index 1 as the index 0 isn't colored + if($split_color -And $split_color.Length -gt 1){ + $split_color = $split_color | Select-Object -Skip 1 + + # For each potential color, find the string before any possible color termination + foreach($potential_color_str in $split_color){ + $color_str1 = ($potential_color_str -split "\x1b")[0] + $color_str2 = ($potential_color_str -split "\[0m")[0] + $color_str = $color_str2 + if($color_str1.Length -lt $color_str2.Length){ + $color_str = $color_str1 + } + + if($color_str){ + $color_str = clean_colors $color_str.trim() + # Avoid having the same color for the same string + if($color_str){ + $colors[$_.Key] += $color_str + } + } + } + } + + + } + if(-not $colors[$_.Key]){ + $colors.Remove($_.Key) + } + } + + return $colors + +} + +function parse_title { + param ( + [string] $line + ) + # Given a title, clean it + + $cleaned_title_pt = clean_title($line) + return clean_colors $cleaned_title_pt + +} + +function parse_line { + param ( + [string] $line + ) + #Parse the given line, adding it to the FINAL_JSON structure + + if( $line.Contains("Cron jobs") ){ + $a = 1 + } + + # for debug + #$line + #Start-Sleep -Milliseconds 500 + + if(is_section $line $TITLE1_PATTERN){ + $title = parse_title $line + #New-Object System.Collections.Generic.List[System.Object] + $FINAL_JSON.add($title, @{ "sections" = @{}; "lines" = @(); "infos" = @() }) + $global:C_MAIN_SECTION = $global:FINAL_JSON.$title + $global:C_SECTION = $global:C_MAIN_SECTION + } + elseif(is_section $line $TITLE2_PATTERN){ + $title = parse_title $line + $global:C_MAIN_SECTION.'sections'.Add($title, @{ "sections" = @{}; "lines" = @(); "infos" = @() }) + $global:C_2_SECTION = $global:C_MAIN_SECTION.'sections'.$title + $global:C_SECTION = $global:C_2_SECTION + } + elseif(is_section $line $TITLE3_PATTERN){ + $title = parse_title $line + $global:C_2_SECTION.'sections'.add($title, @{ "sections" = @{}; "lines" = @(); "infos" = @() }) + $global:C_3_SECTION = $global:C_2_SECTION.'sections'.$title + $global:C_SECTION = $global:C_3_SECTION + } + elseif(is_Section $line $INFO_PATTERN){ + $title = parse_title $line + $global:C_SECTION["infos"] += $title + } + + #If here, then it's text + else{ + #If no main section parsed yet, pass + if($global:C_SECTION -eq @{}){ + return + } + $global:C_SECTION['lines'] += @{"raw_text" = $line; "colors" = get_colors $line;"clean_text" = clean_title(clean_colors $line)} + } +} + +function main { + foreach($line in Get-Content -LiteralPath $OUTPUT_PATH){ + $line = $line.Trim() + #Write-Host $line + if(-not $line -or -not (clean_colors $line)){ #Remove empty lines or lines just with colors hex + continue + } + + parse_line $line + } + + $FINAL_JSON | ConvertTo-Json -depth 100 | Out-File $JSON_PATH + +} + + +try { + $OUTPUT_PATH = $(Read-Host "Output Path") + $JSON_PATH = $(Read-Host "JSON Path") +} +catch { + Write-Host "Error: Please pass the peas.out file and the path to save the json`npeas2json.ps1 " + exit +} + +main \ No newline at end of file