Einzelnen Beitrag anzeigen

Benutzerbild von Remko
Remko

Registriert seit: 10. Okt 2006
Ort: 's-Hertogenbosch, Die Niederlande
222 Beiträge
 
RAD-Studio 2010 Arc
 
#1

Password hash in RDP files

  Alt 20. Mär 2007, 09:35
Note: this topic is followup off a previous topic: Base64 encoding
With MSTSC.EXE you can save connection settings in an RDP file. This file will then also contain an hashed or encrypted password which is valid only for the user who created the RDP file. Analysis of MSTSC learns that the hash is created using MSDN-Library durchsuchenCryptProtectData API. The encrypted password is a fixed size (always 1329 bytes) and contains only HEX chars. And might look like this:
Code:
password 51:b:01000000D08C9DDF0115D1118C7A00C04FC297EB0100000062B
(removed the rest, you get the picture)

With the code below I'm able to produce a working RDP file with some remarks: The produced hash is smaller in size (about 350 bytes) and seems to work only during the same logon session.
So the question is, how to produce the same hash as MSTSC?
In the previous topic Marabu suggested the MSDN-Library durchsuchenCryptStringToBinary API. I also saw on MSDN there's a MSDN-Library durchsuchenCryptBinaryToString API. I've added Delphi translations for these functions to JwaCrypt CVS version.

Delphi-Quellcode:
Uses JwaCrypt;

var DataIn: DATA_BLOB;
    DataOut: DATA_BLOB;
    Description: PWideChar;
    Hash2: String;
    I: Integer;
    P: PByte;
    sRDPFileName: string;
    RDPFile: TStringList;
    LocalAppData: PAnsiChar;
    sFolder: string;
    si: _STARTUPINFOW;
    pi: PROCESS_INFORMATION;
    pwCmdLine: PWideChar;
    pchString: DWord;
    Res: Boolean;
    pszString: PWideChar;

begin
  GetMem(LocalAppData, MAX_PATH);
  if ShGetFolderPath(THandle(nil),
                     CSIDL_LOCAL_APPDATA,
                     THandle(nil),
                     SHGFP_TYPE_CURRENT,
                     LocalAppData) = S_OK then
  begin
    sRDPFileName := String(LocalAppData + '\GPRMC');

    if not DirectoryExists(sRDPFileName) then
    begin
      MkDir(sRDPFileName);
    end;

    sRDPFileName := sRDPFileName + '\GPRMC.rdp';
    Memo1.Lines.Add(sRDPFileName);
  end;
  FreeMem(LocalAppData);

  DataOut.cbData := 0;
  DataOut.pbData := nil;
  DataIn.pbData := Pointer(WideString(Edit1.Text));
  DataIn.cbData := Length(Edit1.Text) * SizeOf(WChar);
  Description := WideString('psw');
  if CryptProtectData(@DataIn,
                      Description,
                      nil,
                      nil,
                      nil,
                      CRYPTPROTECT_UI_FORBIDDEN,
                      @DataOut) then
  begin
    P := DataOut.pbData;
    I := DataOut.cbData;

    Hash2 := '';
    while (I > 0) do begin
      Dec(I);
      Hash2 := Hash2 + IntToHex(P^, 2);
      Inc(P);
    end;

    RDPFile := TStringList.Create;
    RDPFile.Add('screen mode id:i:1');
    RDPFile.Add(Format('desktopwidth:i:%d', [Screen.Width]));
    RDPFile.Add(Format('desktopheight:i:%d', [Screen.Height - 50]));
    RDPFile.Add('session bpp:i:16');
    RDPFile.Add('winposstr:s:2,3,247,0,1055,627');
    RDPFile.Add('full address:s:SERVERNAME');
    RDPFile.Add('compression:i:1');
    RDPFile.Add('keyboardhook:i:2');
    RDPFile.Add('audiomode:i:2');
    RDPFile.Add('redirectdrives:i:0');
    RDPFile.Add('redirectprinters:i:0');
    RDPFile.Add('redirectcomports:i:0');
    RDPFile.Add('redirectsmartcards:i:0');
    RDPFile.Add('displayconnectionbar:i:1');
    RDPFile.Add('autoreconnection enabled:i:1');
    RDPFile.Add('username:s:USERNAME');
    RDPFile.Add('domain:s:DOMAIN');
    RDPFile.Add('alternate shell:s:');
    RDPFile.Add('shell working directory:s:');
    RDPFile.Add('password 51:b:' + Hash2);
    RDPFile.Add('disable wallpaper:i:1');
    RDPFile.Add('disable full window drag:i:1');
    RDPFile.Add('disable menu anims:i:1');
    RDPFile.Add('disable themes:i:1');
    RDPFile.Add('disable cursor setting:i:0');
    RDPFile.Add('bitmapcachepersistenable:i:1');
    RDPFile.SaveToFile(sRDPFileName);
    RDPFile.Free;

    ZeroMemory(@si, SizeOf(si));
    si.cb := SizeOf(si);
    si.lpDesktop := nil;
    pwCmdLine := PWideChar(WideString('mstsc.exe ' + '"' + sRDPFileName + '"'));
    if CreateProcessW(nil,
                      pwCmdLine,
                      nil,
                      nil,
                      False,
                      0,
                      nil,
                      nil,
                      si,
                      pi) then
    begin
      // Succes
    end
    else begin
      // Failure
    end;
  end;
end;
Debugging MSTSC.EXE while saving an RDP shows this sequence:

CryptProtectData - CRYPT32.dll
CryptUnprotectData - CRYPT32.dll
CryptUnprotectData - CRYPT32.dll
CryptProtectData - CRYPT32.dll

It seems like the first CryptProtectData crypts the username (I passed Username as user)
http://web.inter.nl.net/users/weijnen/dp/Info1.jpg
And the 2nd CryptProtectData the Password (I passed Password as the password string)
http://web.inter.nl.net/users/weijnen/dp/Info2.jpg
  Mit Zitat antworten Zitat