NT-Password (NT Hash) unter Windows generieren
Hallo,
es muss doch irgendwie möglich sein ein NT-Password (einen NT-Hash) unter Windows zu erzeugen!?
Es ist doch ein "Windows-Ding":
Die einzigen Möglichkeiten des Erzeugens, die ich gefunden habe, sind entweder nur online oder unter Linux.
Online: https://tobtu.com/lmntlm.php
Linux: /usr/bin/smbencrypt "geheim"
Ich benötige es, weil ich einen Radiusserver betreiben möchte, der auf einer LinuxVM läuft, sich aber die Zugangsdaten aus einer MySQL-Datenbank seines Windows-Hosts holen soll.
Ich möchte die Eingabe und Pflege der Zugangsdaten, die in der selbstentworfenen MySQL-Datenbank gespeichert werden, unter Windows (per selbstgeschriebenen Webinterface) durchführen.
Weniger aus Sicherheitsgründen, mehr aus Gründen der Diskretion, möchte ich die Kennwörter nicht im Klartext in der Datenbank ablegen.
(Ich möchte nicht sehen können, wer welches Kennwort nutzt.)
Das kompatibelste Hash-Format ist NT-Password (NT-Hash)
Quelle: http://deployingradius.com/documents/protocols/compatibility.html
Was ich Suche ist ein offline Hash-Generator für Windows.
Das kann gerne eine der folgenden Ansätze sein:
- exe
- PowerShell
- php
- MySQL
- JavaScript
- eventuell Sonstiges
Ich habe mir jetzt einen Workaroud geschrieben, der nicht gerade das Ei des Kolumbus ist (bestenfalls sein Linkes).
Workaround
Auf der Linux-VM namens "linuxvm" habe ich Apache 2.4 und php 7.0 installiert.
Im Webroot der Linux-VM habe ich ein php-Skript abgelegt, das ein per Get übergegenes Kennwort mit exex() an das Tool /usr/bin/smbencrypt übergibt.
Die Ausgabe des php-Skripts ist inhaltlich wie eine php-Datei, die lediglich eine Variable zuweist.
Auf dem Windows-Rechner ist ebenfalls Apache und php installiert.
Zusätzlich ist dort das Tool "WGet" vorhanden.
Auf dem Windowsrechner liegt im Web-Ordner ein php-Skript, das ein per Get übergegenes Kennwort mit exex() an das Tool wget.exe übergibt.
WGet ruft damit das php-Script der Linux-VM auf und speichert dessen Ausgabe in eine temporäre php-Datei, die im Skript per include eingebunden und gleich wieder gelöscht wird.
Ab dann steht dem php-Skript auf dem Windowsrechner das gehashte Kennwort in einer Variablen namens "verschluesselt" zur weiteren Verarbeitung zur Verfügung.
php-Skript "nthash.php" auf der Linux-VM
Beim Aufruf per http://linuxvm/nthash.php?kennwort=geheim&modus=php
wird Folgendes generiert:
php-Skript "nthash.php" auf dem Windows-Host
Beim Aufruf per http://windowshost/nthash.php?kennwort=geheim
steht im Skript die Variable "verschluesselt" mit dem NT-Hash als Inhalt, zur Verfügung.
Resultat:
(Kennwort "geheim" wir zu "C2AE1FE6E648846352453E816F2AEB93")
...und schon ist die Aufgabe erledigt.
(Die Eingangs erwähnte Diskretion sollte mich noch dazu veranlassen die Übergaben des Kennworts per Post und nicht per Get auszuführen.)
Mit der Behauptung "Das muss auch einfacher gehen" stehe ich hoffentlich nicht alleine da.
Gruß Frank
es muss doch irgendwie möglich sein ein NT-Password (einen NT-Hash) unter Windows zu erzeugen!?
Es ist doch ein "Windows-Ding":
NT-Password = Windows NT hashed passwords
Quelle: https://freeradius.org/radiusd/man/rlm_pap.txtDie einzigen Möglichkeiten des Erzeugens, die ich gefunden habe, sind entweder nur online oder unter Linux.
Online: https://tobtu.com/lmntlm.php
Linux: /usr/bin/smbencrypt "geheim"
Ich benötige es, weil ich einen Radiusserver betreiben möchte, der auf einer LinuxVM läuft, sich aber die Zugangsdaten aus einer MySQL-Datenbank seines Windows-Hosts holen soll.
Ich möchte die Eingabe und Pflege der Zugangsdaten, die in der selbstentworfenen MySQL-Datenbank gespeichert werden, unter Windows (per selbstgeschriebenen Webinterface) durchführen.
Weniger aus Sicherheitsgründen, mehr aus Gründen der Diskretion, möchte ich die Kennwörter nicht im Klartext in der Datenbank ablegen.
(Ich möchte nicht sehen können, wer welches Kennwort nutzt.)
Das kompatibelste Hash-Format ist NT-Password (NT-Hash)
Quelle: http://deployingradius.com/documents/protocols/compatibility.html
Was ich Suche ist ein offline Hash-Generator für Windows.
Das kann gerne eine der folgenden Ansätze sein:
- exe
- PowerShell
- php
- MySQL
- JavaScript
- eventuell Sonstiges
Ich habe mir jetzt einen Workaroud geschrieben, der nicht gerade das Ei des Kolumbus ist (bestenfalls sein Linkes).
Workaround
Auf der Linux-VM namens "linuxvm" habe ich Apache 2.4 und php 7.0 installiert.
Im Webroot der Linux-VM habe ich ein php-Skript abgelegt, das ein per Get übergegenes Kennwort mit exex() an das Tool /usr/bin/smbencrypt übergibt.
Die Ausgabe des php-Skripts ist inhaltlich wie eine php-Datei, die lediglich eine Variable zuweist.
Auf dem Windows-Rechner ist ebenfalls Apache und php installiert.
Zusätzlich ist dort das Tool "WGet" vorhanden.
Auf dem Windowsrechner liegt im Web-Ordner ein php-Skript, das ein per Get übergegenes Kennwort mit exex() an das Tool wget.exe übergibt.
WGet ruft damit das php-Script der Linux-VM auf und speichert dessen Ausgabe in eine temporäre php-Datei, die im Skript per include eingebunden und gleich wieder gelöscht wird.
Ab dann steht dem php-Skript auf dem Windowsrechner das gehashte Kennwort in einer Variablen namens "verschluesselt" zur weiteren Verarbeitung zur Verfügung.
php-Skript "nthash.php" auf der Linux-VM
<?php
$kennwort="";
$kennwort=$_GET['kennwort'];
if ($kennwort == "") {
die;
};
$modus="";
$modus=$_GET['modus'];
if ($modus != "php") {
$modus = "show";
}
$befehl="/usr/bin/smbencrypt \"".$kennwort."\"";
exec($befehl, $ausgabe, $fehler);
if ($fehler != 0) {
die;
};
$teile = explode("\t", $ausgabe[0]);
$verschluesselt=$teile[1];
if ($modus == "show") {
echo $verschluesselt;
}
if ($modus == "php") {
echo "<?php \$verschluesselt=\"$verschluesselt\" ?>";
}
?>
wird Folgendes generiert:
<?php $verschluesselt="C2AE1FE6E648846352453E816F2AEB93" ?>
php-Skript "nthash.php" auf dem Windows-Host
<?php
$kennwort="";
$kennwort=$_GET['kennwort'];
if ($kennwort == "") {
die;
}
// WGet mit Parametern vorbereiten
$url="http://linuxvm/nthash.php?kennwort=".$kennwort."^&modus=php";
$nthashtmp="D:\www\webroot\Test\\nthashtmp.php";
$befehl="\"C:\Program Files (x86)\Tools\WGET\WGET.EXE\" ".$url." -O ".$nthashtmp;
// Achtung:
// Enthält ein Pfad "\t" oder "\n" so ist entweder "\\t" bzw. "\\n" anzugeben
// oder Großbuchstaben zu verwenden: "\T" bzw. "\N", damit nicht Tab oder NewLine daraus wird.
//Ausgabe zur Überprüfung
//echo "nthashtmp: ".$nthashtmp."<br>\n";
//echo "Befehl : ".$befehl."<br>\n";
// php-Datei des Linux-Rechners mit WGet aufrufen
exec($befehl, $ausgabe, $fehler);
// Erzeugte Datei einbinden und dann löschen
if ($fehler == 0) {
include $nthashtmp;
unlink($nthashtmp);
}
else {
$verschluesselt="Fehler";
}
// Ergebnis ausgeben (alternativ mit der Variablen andere Dinge machen)
echo $verschluesselt."\n";
?>
steht im Skript die Variable "verschluesselt" mit dem NT-Hash als Inhalt, zur Verfügung.
Resultat:
$verschluesselt="C2AE1FE6E648846352453E816F2AEB93"
...und schon ist die Aufgabe erledigt.
(Die Eingangs erwähnte Diskretion sollte mich noch dazu veranlassen die Übergaben des Kennworts per Post und nicht per Get auszuführen.)
Mit der Behauptung "Das muss auch einfacher gehen" stehe ich hoffentlich nicht alleine da.
Gruß Frank
7 Antworten
- LÖSUNG wiesi200 schreibt am 10.02.2018 um 14:59:10 Uhr
- LÖSUNG Pedant schreibt am 10.02.2018 um 16:53:26 Uhr
- LÖSUNG 135333 schreibt am 10.02.2018 um 17:02:55 Uhr
- LÖSUNG wiesi200 schreibt am 10.02.2018 um 17:16:20 Uhr
- LÖSUNG 135333 schreibt am 10.02.2018 um 17:28:41 Uhr
- LÖSUNG Pedant schreibt am 10.02.2018 um 17:47:06 Uhr
- LÖSUNG Pedant schreibt am 10.02.2018 um 16:53:26 Uhr
- LÖSUNG 135333 schreibt am 10.02.2018 um 15:33:34 Uhr
LÖSUNG 10.02.2018, aktualisiert um 15:03 Uhr
Hallo,
hab das jetzt vor ein Paar wochen auch gemacht, für ein Mitarbeiter W-LAN. Nur Liegt das Webfrontend (PHP) auf nem Linux Server.
Ich such's kurz raus und Schick es dir.
Wo ich das gefunden hab, kann ich leider nicht mehr sagen.
hab das jetzt vor ein Paar wochen auch gemacht, für ein Mitarbeiter W-LAN. Nur Liegt das Webfrontend (PHP) auf nem Linux Server.
Ich such's kurz raus und Schick es dir.
function NTLMHash($Input) {
// Convert the password from UTF8 to UTF16 (little endian)
$Input=iconv('UTF-8','UTF-16LE',$Input);
// Encrypt it with the MD4 hash
$MD4Hash=bin2hex(mhash(MHASH_MD4,$Input));
// You could use this instead, but mhash works on PHP 4 and 5 or above
// The hash function only works on 5 or above
//$MD4Hash=hash('md4',$Input);
// Make it uppercase, not necessary, but it's common to do so with NTLM hashes
$NTLMHash=strtoupper($MD4Hash);
// Return the result
return($NTLMHash);
}
LÖSUNG 10.02.2018, aktualisiert um 15:33 Uhr
LÖSUNG 10.02.2018 um 16:53 Uhr
Hallo wiesi200,
danke für den Code.
Ich habe ihn hier eingesetzt und ausprobiert.
nthash.php
Aufruf: http://windowshost/nthash.php?kennwort=geheim
Hier erhalte ich für "geheim"
Verwende ich mhash() statt hash() erhalte ich:
Hallo snap,
danke für den PowerShell-Link.
In Bezug auf PS bin ich noch sehr unbedarft.
Ich habe den dortigen Code in eine Datei kopiert und diese Get-MD4Hash.ps genannt.
Rufe ich sie dann auf:
PS D:\Temp> ./Get-MD4Hash -DataToHash $([Text.Encoding]::Unicode.GetBytes("geheim"))
erhalte ich:
Eine Funktion ist also noch kein Skript.
"Schade" dachte sich da der Ochs' vorm Berg.
Gruß Frank
danke für den Code.
Ich habe ihn hier eingesetzt und ausprobiert.
nthash.php
<?php
$kennwort="";
$kennwort=$_GET['kennwort'];
if ($kennwort == "") {
die;
}
// Convert the password from UTF8 to UTF16 (little endian)
$Input=iconv('UTF-8','UTF-16LE',$Input);
// Encrypt it with the MD4 hash
//$MD4Hash=bin2hex(mhash(MHASH_MD4,$Input));
// You could use this instead, but mhash works on PHP 4 and 5 or above
// The hash function only works on 5 or above
$MD4Hash=hash('md4',$Input);
// Make it uppercase, not necessary, but it's common to do so with NTLM hashes
$verschluesselt=strtoupper($MD4Hash);
// Return the result
// Ergebnis ausgeben (alternativ mit der Variablen andere Dinge machen)
echo $verschluesselt."\n";
?>
Hier erhalte ich für "geheim"
31D6CFE0D16AE931B73C59D7E0C089C0
und nichtC2AE1FE6E648846352453E816F2AEB93
Verwende ich mhash() statt hash() erhalte ich:
Fatal error: Call to undefined function mhash() in D:\www\webroot\test\nthash2.php on line 11
Installiert ist hier: PHP Version 5.2.10Hallo snap,
danke für den PowerShell-Link.
In Bezug auf PS bin ich noch sehr unbedarft.
Ich habe den dortigen Code in eine Datei kopiert und diese Get-MD4Hash.ps genannt.
Rufe ich sie dann auf:
PS D:\Temp> ./Get-MD4Hash -DataToHash $([Text.Encoding]::Unicode.GetBytes("geheim"))
erhalte ich:
Fehler beim Ausführen des Programms "Get-MD4Hash.ps": Der angegebenen Datei ist keine Anwendung zugeordnetIn Zeile:1
Zeichen:1
+ ./Get-MD4Hash.ps -DataToHash $([Text.Encoding]::Unicode.GetBytes("geh ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~.
In Zeile:1 Zeichen:32
+ ... MD4Hash.ps -DataToHash $([Text.Encoding]::Unicode.GetBytes("geheim"))
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ResourceUnavailable: (:) [], ApplicationFailedException
+ FullyQualifiedErrorId : NativeCommandFailed
"Schade" dachte sich da der Ochs' vorm Berg.
Gruß Frank
LÖSUNG 10.02.2018, aktualisiert um 17:14 Uhr
Zitat von Pedant:
In Bezug auf PS bin ich noch sehr unbedarft.
Ich habe den dortigen Code in eine Datei kopiert und diese Get-MD4Hash.ps genannt.
Rufe ich sie dann auf:
PS D:\Temp> ./Get-MD4Hash -DataToHash $([Text.Encoding]::Unicode.GetBytes("geheim"))
erhalte ich:
Das ist falsch. Die PS1 muss ja erst mal so aufgerufen werden damit die Funktion der aktuellen Powershell-Konsole bekannt ist.In Bezug auf PS bin ich noch sehr unbedarft.
Ich habe den dortigen Code in eine Datei kopiert und diese Get-MD4Hash.ps genannt.
Rufe ich sie dann auf:
PS D:\Temp> ./Get-MD4Hash -DataToHash $([Text.Encoding]::Unicode.GetBytes("geheim"))
erhalte ich:
Mach es folgendermaßen, kopiere den u.s. Code in eine PS1 und dann rufst du diese in der Powershell so auf
.\script.ps1 'Geheim'
param(
[parameter(mandatory=$true)][string]$password
)
Function Get-MD4Hash
{
<#
.SYNOPSIS
This cmdlet returns the MD4 hash of the data that is input.
WARNING: MD4 is not secure, so it should NEVER be used to
protect sensitive data. This cmdlet is for research purposes only!
.DESCRIPTION
This cmdlet returns the MD4 hash of the data that is input.
WARNING: MD4 is not secure, so it should NEVER be used to
protect sensitive data. This cmdlet is for research purposes only!
This cmdlet uses Microsoft's implementation of MD4, exported
from bcrypt.dll. The implementation is fully compliant with
RFC 1320. This cmdlet takes a byte array as input, not a string.
So if you wanted to hash a string (such as a password,) you
need to convert it to a byte array first.
.EXAMPLE
Get-MD4Hash -DataToHash $([Text.Encoding]::Unicode.GetBytes("YourPassword1!"))
.PARAMETER DataToHash
A byte array that represents the data that you want to hash.
.INPUTS
A byte array containing the data you wish to hash.
.OUTPUTS
A 128-bit hexadecimal string - the MD4 hash of your data.
.NOTES
Author: Ryan Ries, 2014, ryan@myotherpcisacloud.com
.LINK
https://myotherpcisacloud.com
#>
[CmdletBinding()]
Param ([Parameter(Mandatory=$True, ValueFromPipeline=$False)]
[Byte[]]$DataToHash)
END
{
Set-StrictMode -Version Latest
Add-Type -TypeDefinition @'
using System;
using System.Text;
using System.Runtime.InteropServices;
public class BCrypt
{
[DllImport("bcrypt.dll", CharSet = CharSet.Auto)]
public static extern NTStatus BCryptOpenAlgorithmProvider(
[Out] out IntPtr phAlgorithm,
[In] string pszAlgId,
[In, Optional] string pszImplementation,
[In] UInt32 dwFlags);
[DllImport("bcrypt.dll")]
public static extern NTStatus BCryptCloseAlgorithmProvider(
[In, Out] IntPtr hAlgorithm,
[In] UInt32 dwFlags);
[DllImport("bcrypt.dll", CharSet = CharSet.Auto)]
public static extern NTStatus BCryptCreateHash(
[In, Out] IntPtr hAlgorithm,
[Out] out IntPtr phHash,
[Out] IntPtr pbHashObject,
[In, Optional] UInt32 cbHashObject,
[In, Optional] IntPtr pbSecret,
[In] UInt32 cbSecret,
[In] UInt32 dwFlags);
[DllImport("bcrypt.dll")]
public static extern NTStatus BCryptDestroyHash(
[In, Out] IntPtr hHash);
[DllImport("bcrypt.dll")]
public static extern NTStatus BCryptHashData(
[In, Out] IntPtr hHash,
[In, MarshalAs(UnmanagedType.LPArray)] byte[] pbInput,
[In] int cbInput,
[In] UInt32 dwFlags);
[DllImport("bcrypt.dll")]
public static extern NTStatus BCryptFinishHash(
[In, Out] IntPtr hHash,
[Out, MarshalAs(UnmanagedType.LPArray)] byte[] pbInput,
[In] int cbInput,
[In] UInt32 dwFlags);
[Flags]
public enum AlgOpsFlags : uint
{
BCRYPT_PROV_DISPATCH = 0x00000001,
BCRYPT_ALG_HANDLE_HMAC_FLAG = 0x00000008,
BCRYPT_HASH_REUSABLE_FLAG = 0x00000020
}
// This is a gigantic enum and I don't want to copy all of it into this Powershell script.
// Basically anything other than zero means something went wrong.
public enum NTStatus : uint
{
STATUS_SUCCESS = 0x00000000
}
}
'@
[Byte[]]$HashBytes = New-Object Byte[] 16
[IntPtr]$PHAlgorithm = [IntPtr]::Zero
[IntPtr]$PHHash = [IntPtr]::Zero
$NTStatus = [BCrypt]::BCryptOpenAlgorithmProvider([Ref] $PHAlgorithm, 'MD4', $Null, 0)
If ($NTStatus -NE 0)
{
Write-Error "BCryptOpenAlgorithmProvider failed with NTSTATUS $NTStatus"
If ($PHAlgorithm -NE [IntPtr]::Zero)
{
$NTStatus = [BCrypt]::BCryptCloseAlgorithmProvider($PHAlgorithm, 0)
}
Return
}
$NTStatus = [BCrypt]::BCryptCreateHash($PHAlgorithm, [Ref] $PHHash, [IntPtr]::Zero, 0, [IntPtr]::Zero, 0, 0)
If ($NTStatus -NE 0)
{
Write-Error "BCryptCreateHash failed with NTSTATUS $NTStatus"
If ($PHHash -NE [IntPtr]::Zero)
{
$NTStatus = [BCrypt]::BCryptDestroyHash($PHHash)
}
If ($PHAlgorithm -NE [IntPtr]::Zero)
{
$NTStatus = [BCrypt]::BCryptCloseAlgorithmProvider($PHAlgorithm, 0)
}
Return
}
$NTStatus = [BCrypt]::BCryptHashData($PHHash, $DataToHash, $DataToHash.Length, 0)
$NTStatus = [BCrypt]::BCryptFinishHash($PHHash, $HashBytes, $HashBytes.Length, 0)
If ($PHHash -NE [IntPtr]::Zero)
{
$NTStatus = [BCrypt]::BCryptDestroyHash($PHHash)
}
If ($PHAlgorithm -NE [IntPtr]::Zero)
{
$NTStatus = [BCrypt]::BCryptCloseAlgorithmProvider($PHAlgorithm, 0)
}
$HashString = New-Object System.Text.StringBuilder
Foreach ($Byte In $HashBytes)
{
[Void]$HashString.Append($Byte.ToString("X2"))
}
Return $HashString.ToString()
}
}
Get-MD4Hash -DataToHash ([System.Text.Encoding]::Unicode.getBytes($password))
LÖSUNG 10.02.2018 um 17:16 Uhr
LÖSUNG 10.02.2018, aktualisiert um 17:33 Uhr
Ich schätze mal das kommt vom unterschiedlichen PHP-Encoding seiner PHP-Umgebung. Er sollte prüfen ob alles auf UTF-8 kodiert vorliegt/eingestellt ist. Oder eben das Input-Encoding mit mb_http_input auslesen und an iconv übergeben.
LÖSUNG 10.02.2018 um 17:47 Uhr
Hallo snap,
prima, danke.
So funktioniert's.
Hallo wiesi200,
bei mir funktioniert es jetzt auch.
Es war lediglich Schlamperei meinerseits.
Ich hatte den Get-Parameter in $kennwort gespeichert, aber dann unverändert mit $Input gearbeitet.
$Input war dann aber unbelegt und damit wurde dann "Nichts" gehasht.
Hier der korrigierte Code:
nthash.php
Aufruf per http://windowshost/nthash.php?kennwort=geheim
Euch Beiden recht herzlichen Dank
Gruß Frank
prima, danke.
So funktioniert's.
PS D:\Temp> ./ntcrypt.ps1 geheim
C2AE1FE6E648846352453E816F2AEB93
C2AE1FE6E648846352453E816F2AEB93
Hallo wiesi200,
bei mir funktioniert es jetzt auch.
Es war lediglich Schlamperei meinerseits.
Ich hatte den Get-Parameter in $kennwort gespeichert, aber dann unverändert mit $Input gearbeitet.
$Input war dann aber unbelegt und damit wurde dann "Nichts" gehasht.
Hier der korrigierte Code:
nthash.php
<?php
$kennwort="";
$kennwort=$_GET['kennwort'];
if ($kennwort == "") {
die;
}
// Convert the password from UTF8 to UTF16 (little endian)
$kennwort=iconv('UTF-8','UTF-16LE',$kennwort);
// Encrypt it with the MD4 hash
//$MD4Hash=bin2hex(mhash(MHASH_MD4,$kennwort));
// You could use this instead, but mhash works on PHP 4 and 5 or above
// The hash function only works on 5 or above
$MD4Hash=hash('md4',$kennwort);
// Make it uppercase, not necessary, but it's common to do so with NTLM hashes
$verschluesselt=strtoupper($MD4Hash);
// Return the result
// Ergebnis ausgeben (alternativ mit der Variablen andere Dinge machen)
echo $verschluesselt."\n";
?>
C2AE1FE6E648846352453E816F2AEB93
Euch Beiden recht herzlichen Dank
Gruß Frank