Warning: Undefined array key "HTTP_ACCEPT_LANGUAGE" in /usr/www/users/georgxx/.www/index.php on line 31
Georg Sieber - IT-Dienstleistungen

Prolog

Wir schreiben das Jahr 2021 und noch immer ist es nicht möglich Kennwörter während einer automatisierten Windows-Installation zu setzen, wenn man dabei den Anspruch hat das Kennwort vor den Blicken Unbefugter zu schützen. Der häufigste Anwendungsfall dürfte das Setzen des Kennworts für den lokalen Administrator bei einer Standard-Client-Installation im Unternehmen sein. Microsoft bietet in der unattend.xml lediglich folgende Konfigurationsoption an - das Administrator-Kennwort im Klartext anzugeben ist allerdings keine sichere Lösung, da jeder, der die XML-Datei in die Finger bekommt das Kennwort sofort sehen kann.

<settings pass="oobeSystem"> <component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <UserAccounts> <AdministratorPassword> <Value>abc123</Value> <PlainText>true</PlainText> </AdministratorPassword> </UserAccounts> </component> </settings>

Doch Moment, was passiert, wenn wir die Option PlainText auf false setzen? Microsoft liefert im zugehörigen Support-Artikel die Antwort: das Windows-Setup erwartet dann einen Base64-kodierten String als Value für das Passwort. Ein schlechter Witz, denn Base64 ist lediglich eine andere Darstellungsform des Klartextes. Mit dem simplen Kommando echo -en "BASE64STRING" | base64 -d auf der Linux-Shell kann man jederzeit das Klartext-Passwort wiederherstellen.

We need more Hash!

Vom Debian-Setup bin ich gewohnt das root-Kennwort als Hash in der Preseed-Datei anzugeben. Dort kann man sogar den gewünschten Hash-Algorithmus auswählen (ich verwende SHA512). Ein Hash ist im Vergleich zur Base64-Kodierung -vereinfacht gesprochen- eine Art Prüfsumme über das Passwort, welches eben nicht zurück in den Klartext gewandelt werden kann (außer durch sehr zeitaufwendige Brute-Force-Attacken).

Um nun einen Passwort-Hash direkt in die Windows-Passwortdatenbank (C:\Windows\system32\config\SAM) schreiben zu können müssen wir auf das Open Source Tool "Mimikatz" zurück greifen. Mit dem Kommando mimikatz.exe "lsadump::setntlm /user:administrator /ntlm:HASH" "exit" können wir unseren gewünschten Hash direkt in die Passwortdatenbank einfügen.

Diesen Aufruf fügen wir nun in unsere unattend.xml ein. Die Mimikatz-Binaries müssen dazu auf das Installationsmedium in das Verzeichnis sources\$OEM$\$$\Setup\Files\mimikatz\ kopiert werden. Das Windows-Setup kopiert den Inhalt von sources\$OEM$\$$\ während der Installation auf das Zielsystem in das Verzeichnis C:\Windows\.

<settings pass="specialize"> <component name="Microsoft-Windows-Deployment" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <RunSynchronous> <RunSynchronousCommand wcm:action="add"> <Order>1</Order> <Path>cmd.exe /c "C:\Windows\Setup\Files\mimikatz\mimikatz.exe ^"lsadump::setntlm /user:administrator /ntlm:1d35161ed640f8371b8464aff6a5861f^" ^"exit^" > nul"</Path> <WillReboot>Never</WillReboot> </RunSynchronousCommand> <RunSynchronousCommand wcm:action="add"> <Order>2</Order> <Path>net user Administrator /active:Yes</Path> <WillReboot>Never</WillReboot> </RunSynchronousCommand> </RunSynchronous> </component> </settings>

Windows erwartet einen MD4-Hash über ein UTF-16LE-kodiertes Passwort. Das lässt sich einfach mit dem folgenden Python-Snippet berechnen.

import binascii, hashlib print( binascii.hexlify(hashlib.new('md4', 'abc123'.encode('utf-16le')).digest()) )

Oder auch mit PHP, falls man eine Weboberfläche bauen möchte:

echo hash('md4', mb_convert_encoding('abc123', 'UTF-16LE', 'UTF-8'));

Voilà! Die Windows-Installation ist jetzt ein Stück sicherer.