OpenVPN Connectivität testen mit PowerShell
Moin,
ich würde für ein PowerShell Tool eine funktion benötigen bei dem die aktuelle erreichbarkeit eines OpenVPN Dienstes geprüft wird. Also wirklich der "Dienst" auf UDP 500 und nicht der Server.
Das UDP Packet versenden und auf Antwort warten funtioniert, nach dem Post hier:
https://learn-powershell.net/2011/02/21/querying-udp-ports-with-powershe ...
Nun ist es so das hier gemeint wird das der OpenVPN Server alle Pakete verwirft die nicht die Richtige HMAC haben wenn tls-auth an ist (was sie ist):
https://serverfault.com/questions/262474/how-to-check-that-an-openvpn-se ...
Soweit auch okay, ich könnte einen validen key für den OpenVPN Server generieren und damit meine pakete signieren, irgendwie kanns ja PowerShell:
https://gist.github.com/jokecamp/2c1a67b8f277797ecdb3
Okay, jetzt finde ich leider nicht wie das Paket genau aussehen soll damit es eine response den OpenVPN triggert
Was ich fand ist dieses Python Skript das für Nagios / Icinga OpenVPN erreichbarkeit checkt, und er baut ein Paket mit der richtigen HMAC signatur:
https://github.com/liquidat/nagios-icinga-openvpn/blob/master/bin/check_ ...
(zeile 37-61)
Leider steige ich da aus den Code komplett zu verstehen und in Powershell umzuschreiben
Hoffe jemand kann mir da aushelfen
MFG
N-Dude
ich würde für ein PowerShell Tool eine funktion benötigen bei dem die aktuelle erreichbarkeit eines OpenVPN Dienstes geprüft wird. Also wirklich der "Dienst" auf UDP 500 und nicht der Server.
Das UDP Packet versenden und auf Antwort warten funtioniert, nach dem Post hier:
https://learn-powershell.net/2011/02/21/querying-udp-ports-with-powershe ...
$payload = "bla"
#UDP Client Object erstellen, mit dem highport 11222
$udpobject = new-Object system.Net.Sockets.Udpclient(11222)
#Timeout auf 10sek setzen (in ms):
$udpobject.Client.ReceiveTimeout = 10000
#payload basteln
$AsciiObject = New-Object System.Text.ASCIIEncoding
$Bytes = $AsciiObject.GetBytes($payload)
#pseudo "Connection" herstellen (UDP hat keine connection!)
$udpobject.Connect("192.168.1.50",500)
#das UDP Packet versenden:
[void]$udpobject.Send($bytes,$bytes.length)
#IP Endpoint fürs empfangen
$remoteendpoint = New-Object system.net.ipendpoint([system.net.ipaddress]::Any,0)
#Receiveendpoint:
$receivebytes = $udpobject.Receive([ref]$remoteendpoint)
#den returnvalue umwandeln zu string:
[string]$returndata = $a.GetString($receivebytes)
#schaun was zurückkommt
Write-Host "Das kam zurück: $($returndata.ToString())"
Write-Host "Von: $($remoteendpoint.address.ToString()) $($remoteendpoint.Port.ToString())"
Nun ist es so das hier gemeint wird das der OpenVPN Server alle Pakete verwirft die nicht die Richtige HMAC haben wenn tls-auth an ist (was sie ist):
https://serverfault.com/questions/262474/how-to-check-that-an-openvpn-se ...
Soweit auch okay, ich könnte einen validen key für den OpenVPN Server generieren und damit meine pakete signieren, irgendwie kanns ja PowerShell:
https://gist.github.com/jokecamp/2c1a67b8f277797ecdb3
Okay, jetzt finde ich leider nicht wie das Paket genau aussehen soll damit es eine response den OpenVPN triggert
Was ich fand ist dieses Python Skript das für Nagios / Icinga OpenVPN erreichbarkeit checkt, und er baut ein Paket mit der richtigen HMAC signatur:
https://github.com/liquidat/nagios-icinga-openvpn/blob/master/bin/check_ ...
(zeile 37-61)
Leider steige ich da aus den Code komplett zu verstehen und in Powershell umzuschreiben
Hoffe jemand kann mir da aushelfen
MFG
N-Dude
Bitte markiere auch die Kommentare, die zur Lösung des Beitrags beigetragen haben
Content-ID: 625166
Url: https://administrator.de/contentid/625166
Ausgedruckt am: 24.11.2024 um 00:11 Uhr
11 Kommentare
Neuester Kommentar
Zitat von @NetzwerkDude:
Moin,
ich würde für ein PowerShell Tool eine funktion benötigen bei dem die aktuelle erreichbarkeit eines OpenVPN Dienstes geprüft wird. Also wirklich der "Dienst" auf UDP 500 und nicht der Server.
Hast du den Port angepasst? OpenVPN läuft normalerweise auf 1194. Bestenfalls auf 443 um Blockaden zu umgehenMoin,
ich würde für ein PowerShell Tool eine funktion benötigen bei dem die aktuelle erreichbarkeit eines OpenVPN Dienstes geprüft wird. Also wirklich der "Dienst" auf UDP 500 und nicht der Server.
Keine besonders gute und auch intelligente Wahl für einen "Dude", denn das ist bekanntlich weltweit fest dem IKE Protokoll (ISAKMP) zugewiesen was selber wieder ein Teil der IPsec VPN Protokoll Suite ist. Bei 80% der Anschlüsse antwortet dir dann der ISAKMP Server.
Also besser UDP 1194 behalten oder wenn, dann wie immer, einen der Ephemeral Ports von 49152 bis 65535 wie z.B. 51194 verwenden o.ä. Hat zudem den Vorteil das die allermeisten der bösen Portscanner diesen Bereich nicht nutzen.
https://en.wikipedia.org/wiki/Ephemeral_port
Oder...lädt einen Beispieltrace und filtert dann einmal nach OpenVPN.
Also besser UDP 1194 behalten oder wenn, dann wie immer, einen der Ephemeral Ports von 49152 bis 65535 wie z.B. 51194 verwenden o.ä. Hat zudem den Vorteil das die allermeisten der bösen Portscanner diesen Bereich nicht nutzen.
https://en.wikipedia.org/wiki/Ephemeral_port
wie das Paket genau aussehen soll damit es eine response den OpenVPN triggert
Der pfiffige NetzwerkDude nimmt dafür bekanntlich den Wireshark oder tcpdump und sniffert das mit, dann weiss er es bis aufs Bit genau ! Oder...lädt einen Beispieltrace und filtert dann einmal nach OpenVPN.
Servus @NetzwerkDude,
hab dir mal das Erzeugen und Senden des UDP-Packets in eine kleine Function gepresst (hier nur die reine UDP-Variante). Hostname, Port, Timeout, TA-Secretfile und TLS-AUTH Verfahren kannst du der Function Send-OpenVPNClientResetMessage als Parameter übergeben Die Funktion gibt bei Erfolg ein Custom-Object inkl. Server Response zurück ansonsten nichts bzw. passende Fehlermeldung. Die zweite Funktion Validate-OpenVPNServerResponse validiert die von der ersten Funktion zurückgelieferte Server-Response indem man sie einfach in die Pipeline hinter die erste Funktion schaltet.
Ein Beispielaufruf findest du in der letzten Zeile des Codes.
Viel Spaß damit
Grüße Uwe
hab dir mal das Erzeugen und Senden des UDP-Packets in eine kleine Function gepresst (hier nur die reine UDP-Variante). Hostname, Port, Timeout, TA-Secretfile und TLS-AUTH Verfahren kannst du der Function Send-OpenVPNClientResetMessage als Parameter übergeben Die Funktion gibt bei Erfolg ein Custom-Object inkl. Server Response zurück ansonsten nichts bzw. passende Fehlermeldung. Die zweite Funktion Validate-OpenVPNServerResponse validiert die von der ersten Funktion zurückgelieferte Server-Response indem man sie einfach in die Pipeline hinter die erste Funktion schaltet.
Ein Beispielaufruf findest du in der letzten Zeile des Codes.
function Send-OpenVPNClientResetMessage {
param(
[Parameter(mandatory=$true)][string]$hostname,
[Parameter(mandatory=$false)][int]$port = 1194,
[Parameter(mandatory=$true)][string]$authfile,
[Parameter(mandatory=$false)][int]$timeout = 5000,
[Parameter(mandatory=$false)][ValidateSet('HMACSHA1','HMACSHA256','HMACSHA384','HMACSHA512')][string]$hashalgorithm = 'HMACSHA1'
)
# load secret key from file
$ta_bytes = [regex]::matches(([regex]::match((gc $authfile -raw),'(?ism)(?<=-$).*?(?=^-)').Value.trim() -replace '[^\da-f]'),'.{2}').Value | %{[byte][convert]::ToUInt32($_,16)}
#$serverkey = $ta_bytes[64..127]
# create HMAC with secret client key
$hmac = [System.Security.Cryptography.HMAC]::Create($hashalgorithm)
# set clientkey for HMAC
$hmac.Key = $ta_bytes[192..(192+($hmac.HashSize / 8)-1)]
# create random 8 byte session id
[byte[]]$sid = 1..255 | get-random -Count 8 | %{[byte]$_}
# generate unix time in 4 bytes
[byte[]]$time = [System.BitConverter]::GetBytes([uint32][double]::Parse((Get-Date (get-date).ToUniversalTime() -UFormat %s)))
# convert time to big endian
[array]::Reverse($time)
# create HMAC header
[byte[]]$hmac_payload = 0,0,0,1 + $time + 56 + $sid + 0,0,0,0,0
# create final packet
[byte[]]$payload = (,56) + $sid + $hmac.ComputeHash($hmac_payload) + 0,0,0,1 + $time + 0,0,0,0,0
$result = $null, $udpobject = $null
try{
# create udp client
$udpobject = new-Object system.Net.Sockets.Udpclient
# set client timeout
$udpobject.Client.ReceiveTimeout = $timeout
# create local udp endpoint
$remoteendpoint = New-Object system.net.ipendpoint([system.net.ipaddress]::Any,0)
# send udp payload
[void]$udpobject.Send($payload,$payload.Length,$hostname,$port)
# receive response bytes
$buffer = $udpobject.Receive([ref]$remoteendpoint)
return [pscustomobject]@{
Sid = $sid
KeyData = $ta_bytes[64..(64+($hmac.HashSize/8)-1)]
ResponseBuffer = $buffer
HashAlgorithm = $hashalgorithm
}
}catch{
write-host $_.Exception.Message -F Red
}finally{
if ($udpobject) {$udpobject.Close();$udpobject.Dispose()}
}
}
# Validate Server response function
function Validate-OpenVPNServerResponse {
[cmdletbinding()]
param(
[Parameter(mandatory=$true, ValueFromPipelineByPropertyName=$true)][ValidateNotNullOrEmpty()][byte[]]$ResponseBuffer,
[Parameter(mandatory=$true, ValueFromPipelineByPropertyName=$true)][ValidateNotNullOrEmpty()][Alias('Sid')][byte[]]$QuerySid,
[Parameter(mandatory=$true, ValueFromPipelineByPropertyName=$true)][ValidateNotNullOrEmpty()][byte[]]$KeyData,
[Parameter(mandatory=$true, ValueFromPipelineByPropertyName=$true)][ValidateNotNullOrEmpty()][string]$HashAlgorithm
)
process{
$digest_size = $KeyData.Length
# identify packet
$ident = $ResponseBuffer.Length - $ResponseBuffer[9] * 4
if ($ident -eq 14){
$plen = 0
}elseif($ident -eq 22){
$plen = 1
}elseif(($ResponseBuffer.Length - $ResponseBuffer[(17 + $digest_size)] * 4) -eq (30+$digest_size)){
$plen = 2
}else{
write-error -Message "Packet could not be identified!"
return $null
}
# parse packet
$ptype = $ResponseBuffer # packet type
$sid = $ResponseBuffer[1..8] # sessionid
if ($plen -ge 2){
$phmac = $ResponseBuffer[9..(9+$digest_size-1)]
$_pid = $ResponseBuffer[($digest_size+12)]
$time = $ResponseBuffer[($digest_size+13)..($digest_size+16)]
}
$mpidlen = $ResponseBuffer[($digest_size+17)] # message packet id array length
$mpidarray = 0..$midplen | %{$ResponseBuffer[($digest_size+18+$_)..($digest_size+21+$_)]}
$cpos = $digest_size+18+($midplen * 4)
if ($plen -ge 1){
$rsid = $ResponseBuffer[$cpos..($cpos + 7)] # remote session id
}
$mpid = $ResponseBuffer[($cpos + 12)] # message packet id
# validate packet
if ($ptype -ne 64) {
write-error -Message "Wrong packet type."
return $null
}
if ($mpid -ne 0){
write-error -Message "Wrong message packet id."
return $null
}
if($plen -ge 1 -and (!(compare $rsid $QuerySid))){
write-error -Message "Wrong session id."
return $null
}
if ($plen -ge 2 -and $KeyData){
if ($_pid -ne 1){
write-error -Message "Wrong pid."
return $null
}
# generate hmac
# create HMAC with secret server key
$hmac = [System.Security.Cryptography.HMAC]::Create($HashAlgorithm)
$hmac.Key = $KeyData
[byte[]]$payload = (0,0,0,$_pid) + $time + $ptype + $sid + $mpidlen + 0,0,0,0 + $rsid + $mpid
if (!(Compare $phmac $hmac.ComputeHash($payload))){
Write-Error -Message "Invalid HMAC"
return $null
}
write-host "Response validated - checked HMAC!" -F Green
return $true
}
write-host "Response validated!" -F Green
return $true
}
}
Send-OpenVPNClientResetMessage -hostname "openvpn.server.tld" -port 1194 -authfile 'D:\openvpn\ta.key' -hashalgorithm HMACSHA1 -timeout 4000 | Validate-OpenVPNServerResponse
Viel Spaß damit
Grüße Uwe
Jau, unser Uwe, ich staune auch immer wieder, wie er das Zeug grad mal so im Vorbeigehen aus dem Ärmel schüttelt. 👍
lks
Bei nützlichen Skripts für die Nachwelt bin ich immer mit dabei sofern das runde mit den zwei Zeigern es zulässt und keiner mit "Kloppe" vorbei kommt .