2016-09-27 1 views
2

J'essaie de définir un exécutable à exécuter en tant qu'utilisateur local à faible privilège (différent de l'utilisateur actuellement connecté) par défaut. La commande Windows "runas/savecred/user: nom_utilisateur appname.exe" peut le faire, mais elle nécessite que l'utilisateur connecté en cours saisisse manuellement le mot de passe de l'utilisateur différent pour la première fois. Idéalement, je veux que le programme d'installation du programme définisse les informations d'identification, donc aucune interaction ne serait nécessaire pour l'utilisateur actuellement connecté. (Je ne veux pas faire le programme en tant que service Windows pour d'autres bonnes raisons.)C++: comment créer par programme des informations d'identification d'utilisateur local dans Windows Credential Manager afin que "runas/savecred" puisse l'utiliser?

Lorsque j'ai exécuté la commande "runas", j'ai observé qu'un nouveau mot de passe Windows "ouverture de session interactive" a été créé dans Credential Manager , où "Internet ou l'adresse réseau" a été défini comme "$ computer_name \ $ nom d'utilisateur (Interactive Logon)", "Nom d'utilisateur" a été défini comme "$ computer_name \ $ username", "mot de passe" affiché comme "***** *** ", et" Persistance "a été défini comme" Entreprise ". Sur la base de cette observation, j'ai trouvé une API Win32, CredWrite, mais j'ai du mal à la faire fonctionner. J'ai eu le code d'erreur 87 (ERROR_INVALID_PARAMETER - le paramètre est incorrect.) Quand CredWrite a été appelé.

#include <windows.h> 
#include <wincred.h> 
#include <tchar.h> 

void main() 
{ 
    char* password = "randompassword"; 
    DWORD blobsize= 1 + strlen(password); 

    CREDENTIAL cred = {0}; 
    cred.Flags = CRED_FLAGS_USERNAME_TARGET; 
    cred.Type = CRED_TYPE_DOMAIN_PASSWORD; 
    cred.TargetName = L"computername\\username"; 
    cred.CredentialBlobSize = blobsize; 
    cred.CredentialBlob = (LPBYTE) password; 
    cred.Persist = CRED_PERSIST_LOCAL_MACHINE; 
    cred.UserName = L"computername\\username"; 

    if (!CredWrite(&cred, 0)) 
    { 
     std::cerr << GetLastError() << std::endl; 
    } 
} 

Les références que j'ai examinées sont énumérées en bas. J'ai été capable de créer un identifiant de type CRED_TYPE_GENERIC mais il n'a pas été reconnu par RUNAS. Je suis vraiment perplexe sur la façon de définir des champs comme TargetName et Type afin de créer par programme un identifiant de connexion interactif comme le fait RUNAS. La documentation MSDN officielle n'est pas claire et il n'y a pas d'exemple.

CredWrite: https://msdn.microsoft.com/en-us/library/windows/desktop/aa375187(v=vs.85).aspx CREDENTIAL: https://msdn.microsoft.com/en-us/library/windows/desktop/aa374788(v=vs.85).aspx L'exemple de code pour créer une information d'identification de type CRED_TYPE_GENERIC: How do I store and retrieve credentials from the Windows Vault credential manager?

+0

voir cette url http://stackoverflow.com/questions/3729406/create-local-user-account – Proxytype

+0

Merci pour la réponse, Proxytype.I n'a eu aucun problème pour créer le compte local à faibles privilèges avec NetUserAdd. – Batistuta

+0

ressemble à: Certains champs ne peuvent pas être modifiés dans un identifiant existant. Cette erreur est renvoyée si un champ ne correspond pas à la valeur d'un champ protégé des informations d'identification existantes. - vous ne pouvez pas changer le paramètre après que l'utilisateur a créé, c'est moyen que vous devez le définir lorsque vous créez l'utilisateur .. https://msdn.microsoft.com/en-us/library/windows/desktop/aa375187(v= vs.85) .aspx – Proxytype

Répondre

0

L'erreur de ERROR_INVALID_PARAMETER (code d'erreur 87) a été provoquée par la mauvaise valeur de CredentialBlobSize. Si le membre Type est CRED_TYPE_DOMAIN_PASSWORD, ce membre contient le mot de passe Unicode en clair pour UserName Les membres CredentialBlob et CredentialBlobSize n'incluent pas de caractère de fin nul. " (CREDENTIAL: https://msdn.microsoft.com/en-us/library/windows/desktop/aa374788(v=vs.85).aspx)

Avec ce correctif, une référence Windows (non générique ou de certificat) peut être créée sans erreur.

#include <windows.h> 
#include <wincred.h> 
#include <tchar.h> 

void main() 
{ 
    char* password = "randompassword"; 
    DWORD blobsize= strlen(password); // Do NOT add 1 here. 

    CREDENTIAL cred = {0}; 
    cred.Flags = CRED_FLAGS_USERNAME_TARGET; 
    cred.Type = CRED_TYPE_DOMAIN_PASSWORD; 
    cred.TargetName = L"computername\\username"; 
    cred.CredentialBlobSize = blobsize; 
    cred.CredentialBlob = (LPBYTE) password; 
    cred.Persist = CRED_PERSIST_LOCAL_MACHINE; 
    cred.UserName = L"computername\\username"; 

    if (!CredWrite(&cred, 0)) 
    { 
     std::cerr << GetLastError() << std::endl; 
    } 
} 

Cependant, il y a encore une différence subtile. L '"adresse Internet ou réseau" de celle que j'ai créée était "$ nom_ordinateur \ $ nom_utilisateur (Identité Windows)" qui ne peut pas être reconnu par RUNAS. Celui créé par RUNAS était "$ computer_name \ $ username (Interactive Logon)". Comment ce bit est-il réglé?

Je peux utiliser CredRead pour lire les informations d'identification que j'ai créées, mais je ne parviens pas à le faire pour celui créé par RUNAS.

CREDENTIAL cred = { 0 }; 
PCREDENTIAL pcred = &cred; 
// Works for Windows Identity. TargetName is case-insensitive. 
CredRead(L"$computer_name\$username", CRED_TYPE_DOMAIN_PASSWORD, 0, &pcred); 
// Fails for Interactive Logon with error code 87 or 1168. I tried all possible CRED_TYPE_*. 
CredRead(L"$computer_name\$username", CRED_TYPE_*, 0, &pcred); 

Discussions similaires: 1. commande runas, vérification des pouvoirs de dérivation (https://community.spiceworks.com/topic/485852-runas-command-bypass-credentials) 2 .runas/savecred ... ne pas accepter CMDKEY/ajouter (informations d'identification) (runas /savecred... don't accept cmdkey /add (credentials)) 3. runas avec le commutateur/savecred n'accepte pas les informations d'identification stockées par la commande cmdkey (https://social.technet.microsoft.com/Forums/windowsserver/en-US/c0e398cc-224f-4390-bc69-0ee544f9b5cb/runas-with-the-savecred-switch-does-not-accept-a-credential-stored-by-the-cmdkey-command?forum=winserversecurity)

La commande CMDKEY m'a permis de créer un justificatif d'identité le plus proche de celui créé par RUNAS.Les deux se ressemblent dans le résultat renvoyé par "cmdkey/list". Cependant, celui créé par CMDKEY n'est pas honoré par RUNAS.

cmdkey /add:Domain:interactive=$computer_name\$username1 /user:$computer_name\$username1 /pass:$password 

cmdkey /list 

# created by CMDKEY 
Target: Domain:interactive=$computer_name\$username1 
Type: Domain Password 
User: $computer_name\$username1 

# created by RUNAS 
Target: Domain:interactive=$computer_name\$username2 
Type: Domain Password 
User: $computer_name\$username2 
1

Il y a un drapeau sans papier de la structure CREDENTIAL que vous passez à CredWrite.

Si vous appelez l'API avec le drapeau = 8196, vous obtiendrez le résultat que vous désirez

char* password1 = "randompassword"; 
DWORD blobsize = strlen(password1); // Do NOT add 1 here. 

CREDENTIAL cred = { 0 }; 
cred.Flags = 8196; 
cred.Type = 2; 
cred.TargetName = L"computername\\username"; 
cred.CredentialBlobSize = blobsize; 
cred.CredentialBlob = (LPBYTE)password1; 
cred.Persist = 3; 
cred.UserName = L"computername\\username"; 

if (!CredWrite(&cred, 0)) 
{ 
    std::cerr << GetLastError() << std::endl; 
}