Mark S
Mark S

Reputation: 21

Powershell WebClient gives up on encountering SNI error

Has anyone found a way to either force a Powershell TLS client to not use SNI, or to continue with a connection past an SNI error from the server?

I'm trying to make a powershell script download a big list of networks from our DHCP server, and format it for import into another system.

I can download the data with a browser - watching the connection with Wireshark, I see the browser start the TLS handshake, send an SNI indication, the server respond with a "TLS Alert (Level: Warning, Description: Unrecognized Name)", the browser continue with the TLS connection unfazed, and the download succeeds.

To debug the requests, I ran the connection through a local proxy (burp suite, which is a Java app), so I could see both the encrypted tunnel, and the content of the HTTP request. This caused the connection to fail and the proxy to immediately return an error. Apparently Java TLS code is unwilling to continue to connect past the TLS error that browsers take in stride. If I force the proxy not to include Server Name Identification (SNI) in the request, it works (see the commented-out debug code below).

Finally, removing the proxy from the mix, it seems the network code Powershell uses is also unwilling to continue past the error - it sends the same SNI indicator, receives the same TLS error, and then just hangs - no more packets are exchanged until 100 seconds have passed, then the connection is closed with a FIN packet, and Powershells returns a timeout error:

Exception calling "DownloadFile" with "2" argument(s): "The operation has timed out"

The code I'm using is this:

$webclient = new-object System.Net.WebClient

#DEBUG for now - send requests through proxy

#$proxy = new-object System.Net.WebProxy
#$proxy.Address = "http://localhost:8080"
#$webclient.proxy = $proxy

# have to do this to ignore invalid certs from proxy
#[System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$true}

#Also have to force the JRE running the proxy to not send SNI in the request - invoke as
#java -Djsse.enableSNIExtension=false -jar c:\Users\MarkS\Burp\burpsuite_pro_v1.6.09.jar

#end DEBUG

$server = $(
    $input = Read-Host "server to connect to [our-DHCP-server-name]"
    if($input) {$input} else {"our-DHCP-server-name"}
)

$current_id = [Environment]::Username
$user_id = $(
    $input = Read-Host "user ID to connect as [$current_id]"
    if($input) {$input} else {$current_id}
)

$password = Read-Host -AsSecureString 'password to connect with'

$pscreds = new-object System.Management.Automation.PSCredential($user_id,$password)
$webclient.Credentials = new-object System.Net.NetworkCredential($user_id, $pscreds.GetNetworkCredential().Password)

#connect...

$tempfile = [System.IO.Path]::GetTempFileName()
$tempfile

#...and download
#NOTE - don't use XML - server returns badly malformed XML
$url = "https://$server/wapi/v1.2.1/network?_max_results=10000000&_return_type=json-pretty&_return_fields%2B=extattrs"


$webclient.DownloadFile($url, $tempfile)

Thanks very much!

Upvotes: 2

Views: 1166

Answers (1)

Mark S
Mark S

Reputation: 21

I have a sort-of solution. More of a work-around that happens to work for me; it still isn't a general purpose solution.

Adding:

[System.Net.ServicePointManager]::SecurityProtocol = 'Ssl3'

before the connection attempt will force the client side to only use SSLv3 (which this server is configured to support), which prevents SNI from coming into play since it's a TLS-only feature.

Of course this wouldn't help anyone trying to connect to a server that only supports TLS, and it only helps me so long as SSLv3 remains supported by our server...

Upvotes: 0

Related Questions