Use PowerShell to Keep a CookieJar and POST to a Web Form That Prohibits XSS

I recently had a project that required I log into a site and submit a form. Initially, I had a Start-Process that launched iexplore but then I decided it would be best to..

scriptallthethings

My initial attempts to automate this process failed with the server response "403 Forbidden." As it turns out, the web server which is some modified version of jetty (I believe) was hardened to prevent XSS attacks. I knew that I had to use cookies, but doing so in PowerShell turned out to be a bit more challenging than it was in VBScript.

I like this script because it covers a lot of ground, from bypassing the SSL warning, to getting credentials to submitting a form. It took about a day to figure out, but ultimately, I was able to:

  1. Authenticate using BASIC authentication
  2. Bypass SSL warnings
  3. Keep cookies
  4. Submit the information from a hidden field in the form

There are additional steps in between each of those, which include

  • Prompting for the website credentials
  • Associating those credentials to the website
  • Placing cookies in the cookie jar
  • Parsing the form for the information I needed
  • Passing back the information

Essentially, I create a web request using System.Net.HTTPWebRequest (using webclient proved too messy), create a response stream, "upload" the data as bytes, get the second response. You can modify this to submit other portions of a form, or just parse from page to page. Hope you find it useful!

#URL to parse
$url = "https://vcenter.base.local/mob/?moid=vpxd-securitymanager&method=reloadSslCertificate&vmodl=1"

# Get Credentaials, add them to cache
\[Net.ServicePointManager\]::ServerCertificateValidationCallback = {$true} #ignore ssl warning
$msg = "Enter your vCenter Server admin username and password"; 
$creds = $Host.UI.PromptForCredential($caption,$msg,"$env:userdomain\\$env:username",$domain)
$vcusername = $creds.username;	$vcpassword = $creds.GetNetworkCredential().password
$credCache = new-object System.Net.CredentialCache
$creds = new-object System.Net.NetworkCredential($vcusername,$vcpassword)
$credCache.Add($url, "Basic", $creds)
$cookiejar = New-Object System.Net.CookieContainer

# Login
$webrequest = \[System.Net.HTTPWebRequest\]::Create($url);
$webrequest.CookieContainer = New-Object System.Net.CookieContainer;
$webrequest.Method = "GET"
$webrequest.Credentials = $credCache
if ($cookiejar -ne $null) { $webrequest.CookieContainer = $cookiejar }
$response = $webrequest.GetResponse()
$responseStream = $response.GetResponseStream()
$streamReader = New-Object System.IO.Streamreader($responseStream)
$output = $streamReader.ReadToEnd()

# Get sessiononce or server will think it's forgery
$null = $output -match 'name="vmware-session-nonce" type="hidden" value="?(\[^\\s^"\]+)"'
$sessionnonce = $matches\[1\]
$postdata = "vmware-session-nonce=$sessionnonce"
$bytearray = \[System.Text.Encoding\]::UTF8.GetBytes($postdata)

# Second request
$webrequest = \[System.Net.HTTPWebRequest\]::Create($url)
$webrequest.Credentials = $credCache
if ($cookiejar -ne $null) { $webrequest.CookieContainer=$cookiejar }
$webrequest.Method = "POST"
$webrequest.ContentType = "application/x-www-form-urlencoded"
$webrequest.ContentLength = $bytearray.Length
$requestStream = $webrequest.GetRequestStream()

# Post data
$requestStream.Write($bytearray, 0, $bytearray.Length)
$requestStream.Close()
$response = $webrequest.GetResponse()
$responseStream  = $response.GetResponseStream()

# Get Response
$streamReader = New-Object System.IO.Streamreader($responseStream)
$output = $streamReader.ReadToEnd()

Thanks to Captain Abstraction for breaking this whole down and making it way easier to understand than most of the webpages I visited.