Laden...

Name des lokalen Administrators (Windows)

Erstellt von niceGuy vor einem Jahr Letzter Beitrag vor einem Jahr 761 Views
N
niceGuy Themenstarter:in
8 Beiträge seit 2022
vor einem Jahr
Name des lokalen Administrators (Windows)

Hallo Community,

Ich kann mit diesem Code den Namen der lokalen Administratorgruppe herauslesen:


using System.Security.Principal;

String sGroupAdministrators = new SecurityIdentifier(WellKnownSidType.BuiltinAdministratorsSid, null).Translate(typeof(NTAccount)).Value;
sGroupAdministrators = sGroupAdministrators.Substring(sGroupAdministrators.IndexOf('\\') + 1);

Console.WriteLine("Local Administrator Group=" + sGroupAdministrators);

Nun möchte ich den Namen des lokalen Administrators herauslesen. Mit folgendem Code funktioniert das als Applikation, nicht aber, wenn ich ihn als Dienst ausführe:


using System.Security.Principal;

String sLocalAdministratorUser = new SecurityIdentifier(WellKnownSidType.AccountAdministratorSid, WindowsIdentity.GetCurrent().User.AccountDomainSid).Translate(typeof(NTAccount)).Value;
sLocalAdministratorUser = sLocalAdministratorUser.Substring(sLocalAdministratorUser.IndexOf('\\') + 1);

Console.WriteLine("Local Administrator User=" + sLocalAdministratorUser);

Das Problem für mich ist, wie bekomme ich benötigte domainSID für "SecurityIdentifier" heraus, wenn ich den Code als Dienst laufen lasse?

Hat jemand eine Idee?

4.931 Beiträge seit 2008
vor einem Jahr

Hallo und willkommen,

sollte WellKnownSidType.BuiltinAdministratorsSid, laut WellKnownSidType, nicht schon dem Administrator-Account entsprechen (und nicht der Administrator-Gruppe)?

N
niceGuy Themenstarter:in
8 Beiträge seit 2022
vor einem Jahr

Hallo Th69,

Darüber bin ich auch schon gestolpert.

AccountAdministratorSid, sollte gemäss Beschreibung die SID der Gruppe sein.
BuiltinAdministratorsSid, sollte gemäss Beschreibung die SID des Benutzers sein.

Mit meinem Code, den ich gepostet habe, passiert aber das genaue Gegenteil!

4.931 Beiträge seit 2008
vor einem Jahr

Wenn ich mir die Namen anschaue (bzgl. Einzahl und Mehrzahl), so scheint wohl wirklich die Beschreibung in der (auch englischen) Doku falsch (vertauscht) zu sein.

Du kannst aus einem Dienst heraus (der ja unabhängig von einem aktuell eingeloggten User läuft) WindowsIdentity.GetCurrent() nicht benutzen (dies muß ja auch nicht zwangsläufig dann ein Administrator-Account sein).
Was passiert denn, wenn du den 2. Parameter von SecurityIdentifier(...) auf null setzt?

N
niceGuy Themenstarter:in
8 Beiträge seit 2022
vor einem Jahr

Wenn ich es mit null versuche:


String sLocalAdministratorUser = new SecurityIdentifier(WellKnownSidType.AccountAdministratorSid, null).Translate(typeof(NTAccount)).Value;
sLocalAdministratorUser = sLocalAdministratorUser.Substring(sLocalAdministratorUser.IndexOf('\\') + 1);
Console.WriteLine("Local Administrator User=" + sLocalAdministratorUser);

Ergibt dies als Resultat:> Fehlermeldung:

The domainSid parameter must be specified for creating well-known SID of type AccountAdministratorSid. (Parameter 'domainSid')

Und das verwirrt mich, denn ich möchte ja den lokalen Administrator Account. Also ohne Domäne.

16.807 Beiträge seit 2008
vor einem Jahr

In der Doku von SecurityIdentifier steht, dass die Angabe von domainSid erforderlich ist, wenn u.a. AccountAdministratorSid angefragt wird, was Du tust.
Dass Null also zu dem Fehler führt ist nachvollziehbar.

Ansonsten stimm ich Th69 zu, WindowsIdentity.GetCurrent() kannst Du aus dem Server nicht benutzen, wenn dieser nicht mit einer Identität konfiguriert wurde - was hier wohl der Fall ist. Es ist leider nicht ersichtlich, von was von einem Service Du sprichst (Registrierter Windows Service? IIS? ...?); aber eigentlich kannst Du an allen Stellen einen Benutzer konfigurieren, in dessen Context die App ausgeführt wird.

Was soll das ganze eigentlich werden?


sLocalAdministratorUser = sLocalAdministratorUser.Substring(sLocalAdministratorUser.IndexOf('\\') + 1);

Ist übrigens auch nicht 100% safe, denn es gibt zwei potentielle Formate:

  • Domain\User
  • User@Domain

PS: string statt String ist die sicherere Schreibweise (gilt auch für die anderen Varianten wie Int32 etc..).
Im Gegensatz zu Früher ist die klare Empfehlung nur noch die aliase (also die type keywords) zu verwenden.

2.078 Beiträge seit 2012
vor einem Jahr

PS: string statt String ist die sicherere Schreibweise (gilt auch für die anderen Varianten wie Int32 etc..).
Im Gegensatz zu Früher ist die klare Empfehlung nur noch die aliase (also die type keywords) zu verwenden.

Warum sicherer?
Ist doch beides äquivalent zueinander?

16.807 Beiträge seit 2008
vor einem Jahr

In der Runtime ja, während der Entwicklung nein.

Während string ein reserviertes Keyword ist, kannst Du String einfach als Klasse überschreiben.
Hat in der Vergangenheit auch zu Angriffsvektor-Möglichkeiten geführt. Ist daher nicht einfach nur eine Stil-Sache, sondern Frage der Code-Sicherheit.

String wurde damals wegen VB eingeführt, um Code leichter portieren zu können; nicht für die generelle Verwendung als string gedacht.
String als Variable verletzt auch die Coding Conventions (nicht die statischen Methoden).

N
niceGuy Themenstarter:in
8 Beiträge seit 2022
vor einem Jahr

Es ist leider nicht ersichtlich, von was von einem Service Du sprichst (Registrierter Windows Service? IIS? ...?);
...
aber eigentlich kannst Du an allen Stellen einen Benutzer konfigurieren, in dessen Context die App ausgeführt wird.

Ein registrierter Windows Dienst der ganz normal mit SYSTEM Rechten laufen soll

  
sLocalAdministratorUser = sLocalAdministratorUser.Substring(sLocalAdministratorUser.IndexOf('\\') + 1);  
  

Ist übrigens auch nicht 100% safe, denn es gibt zwei potentielle Formate:

  • Domain\User
  • User@Domain

Das muss ich anschauen, wenn ich den Dienst auf einem Domänenmitglied laufen lasse.

PS: string statt String ist die sicherere Schreibweise (gilt auch für die anderen Varianten wie Int32 etc..).
Im Gegensatz zu Früher ist die klare Empfehlung nur noch die aliase (also die type keywords) zu verwenden.

Oh, Danke, das werde ich beherzigen!

Zurück zu meinem Anliegen:
Es muss doch möglich sein, den Namen des lokalen Administrator Kontos in Erfahrung zu bringen?

16.807 Beiträge seit 2008
vor einem Jahr

Ein registrierter Windows Dienst der ganz normal mit SYSTEM Rechten laufen soll

Du meinst hoffentlich nicht NT AUTHORITY \ SYSTEM.

Willst Du quasi den Output von PowerShell Get-LocalGroupMember -Group "Administrators"?
Den Quellcode dazu kann man sich ja anschauen, was die machen.

Edit: müsste dem Code entsprechen


using System.DirectoryServices.AccountManagement;
using (PrincipalContext ctx = new PrincipalContext(ContextType.Machine))
using (GroupPrincipal grp = GroupPrincipal.FindByIdentity(ctx, IdentityType.Name, "Administrators"))
{
    if (grp is not null)
    {
        foreach (Principal p in grp.GetMembers(recursive: true))
        {
            Console.WriteLine(p.Name);
        }
    }
}

Liefert bei mir gleiches Ergebnis wie PowerShell, beide lokalen Admin Account Names.

Ansonsten stimmt halt Dein Konzept schon nicht.
Es gibt fix kein einzelnes Konto mit dem Namen Administrator, sondern nur eine Gruppe Administrators.
Und darin können beliebig viele User sein. Du musst also immer über Gruppen gehen bei einem Role-based Authorization Konzept, wie es Windows bzw. (Azure) Active Directory hat.

N
niceGuy Themenstarter:in
8 Beiträge seit 2022
vor einem Jahr

Da die SID des lokalen Administrator Accounts immer__ mit "S-1-5-21-" beginnt und mit "-500" endet, kann ich den Namen des Kontos hiermit lesen:


string sLocalAdministratorUser = "";

ManagementScope scope = new(@"\\.\root\CIMV2");
scope.Connect();

ObjectQuery query = new("SELECT Name from Win32_UserAccount WHERE SID LIKE 'S-1-5-21%-500'");
ManagementObjectSearcher searcher = new(scope, query);

ManagementObjectCollection results = searcher.Get();

foreach (var item in results)
{
	sLocalAdministratorUser = item["Name"].ToString();
	break;
}

Console.WriteLine("Local Administrator User=" + sLocalAdministratorUser);

Bezüglich der absoluten Aussage immer__:
How Can I Determine if the Local Administrator Account has been Renamed on a Computer?

Was ich noch nicht begriffen habe ist, wie ich direkt auf das erste und einzige item zugreifen kann, statt über eine abgebrochene foreach Schlaufe.

16.807 Beiträge seit 2008
vor einem Jahr

Weil der Gedanke

Was ich noch nicht begriffen habe ist, wie ich direkt auf das erste und einzige item zugreifen kann, statt über eine abgebrochene foreach Schlaufe.

nicht korrekt ist.

Weil

Ansonsten stimmt halt Dein Konzept schon nicht.
Es gibt fix kein einzelnes Konto mit dem Namen Administrator, sondern nur eine Gruppe Administrators.
Und darin können beliebig viele User sein.

Du musst also immer mit mehreren Treffern rechnen. Gibt keine Garantie, dass es nur "ein einziges, erstes Item" ist.
Darüber hinaus machst Du auf umständliche Art und Weise (nun via WMI), was Du eben auch mit dem System.DirectoryServices.AccountManagement Namespace direkt machen kannst.

Aber wie gesagt; Deine Grundvorgehen ist falsch, weil

bei einem Role-based Authorization Konzept, wie es Windows bzw. (Azure) Active Directory hat

PS: Nicht eine Admingruppe auf meiner Rechner endet mit 500.

N
niceGuy Themenstarter:in
8 Beiträge seit 2022
vor einem Jahr

Aber wie gesagt; Deine Grundvorgehen ist falsch, weil

bei einem Role-based Authorization Konzept, wie es Windows bzw. (Azure) Active Directory hat

Viele Dank für Deine Ausführungen.

Vermutlich schreiben wir aneinander vorbei:
Ich benötige den aktuellen Namen des lokalen Administrator Kontos.
--> Das Originale, echte welches Microsoft vorgesehen hat.
Kein zusätzlich in die lokale Administratorgruppe hinzugefügtes Benutzerkonto.

Das wäre in meinem Fall dieses Konto welches ebenfalls in der lokalen Admingruppe ist:
S-1-5-21-nnnnnnnnnn-nnnnnnnnnn-nnnnnnnnnn-1001
--> Diese SID (und weitere Mitglieder der lokalen Admingruppe) endet mit etwas anderem als -500

Ich orientiere mich dabei an folgendem devblog Eintrag und gehe davon aus, dass der Autor über die benötigten internen Informationen bei Microsoft verfügt:
https://devblogs.microsoft.com/scripting/how-can-i-determine-if-the-local-administrator-account-has-been-renamed-on-a-computer

Vermutlich wird es noch weitere Wege geben. Für den Moment habe ich eine Lösung die sprachenunabhängig und domänenunabhängig mir den lokalen Administrator nennt.

16.807 Beiträge seit 2008
vor einem Jahr

Hab ich verstanden; trotzdem interessiert es die Windows Schnittstelle nicht was Du logisch (ein Item) brauchst, wenn die Technik eben mit einer Liste arbeitet.
Entsprechend sind die Windows und .NET Schnittstellen. Wenn die Liste in Deiner Logik eben immer nur ein Treffer hat, dann musst Du das technisch umsetzen; zB mit Linq FirstOrDefault oder SingleOrDefault etc...

Der Blogartikel, den Du verlinkst, ist 17 Jahre alt. Ich würde nun nicht unbedingt viel drauf wetten, dass das heute noch so ist.
Beim Windows Accountmanagement hat sich enorm viel getan seit 2015.

Wie Du schon selbst bemerkt hast, endet die Administratorsgruppe nicht zwangsläufig mit 500, obwohl es so im Artikel steht.
Es gibt kein verlässliches Merkmal, das den ersten lokalen Admin-User eindeutig kennzeichnet.

Und wie gesagt: kannst auch komplett auf WMI verzichten und einfach typsicher den PrincipalSearcher nehmen.