Wachtwoord RDP verbinding encrypten

Pagina: 1
Acties:
  • 886 views sinds 30-01-2008
  • Reageer

Acties:
  • 0 Henk 'm!

Anoniem: 97275

Topicstarter
Je zal wel denken nadat je de topictitel las, wtf gaat deze gozer doen :?

Ik zal het uitleggen.

Hier op mijn werk hebben we klanten met servers. Op deze servers draait voornamelijk Windows. We houden van alle klanten een inventaris bij op ons intranet. Je kan ook op het externe IP adres van de klant klikken, waarna er via een ActiveX plugin (Remote Desktop Web Connection) een RDP verbinding wordt gelegd, inclusief het wachtwoord wat meegezonden wordt (en dat scheelt, want het zijn er complexe wachtwoorden).

Nu werkt die ActiveX shite niet onder Vista. Nu dacht ik, ik maak met PHP gewoon een RDP bestand met de gegevens die ik van de klant heb:

Een RDP'tje ziet er van binnen zo uit:

screen mode id:i:2
desktopwidth:i:1280
desktopheight:i:1024
session bpp:i:16
winposstr:s:0,3,0,0,800,600
full address:s:xxx.xxx.xxx.xxx
compression:i:1
keyboardhook:i:2
audiomode:i:0
redirectdrives:i:0
redirectprinters:i:1
redirectcomports:i:0
redirectsmartcards:i:1
displayconnectionbar:i:1
autoreconnection enabled:i:1
username:s:administrator
domain:s:xxxxxx
alternate shell:s:
shell working directory:s:
disable wallpaper:i:1
disable full window drag:i:1
disable menu anims:i:1
disable themes:i:0
disable cursor setting:i:0
bitmapcachepersistenable:i:1

Alleen, het wachtwoord wat je erin mee kan sturen wordt ge-encrypt.

Nu wil ik dus ook die wachtwoorden mee sturen met het .RDP bestand, en dan zal ik dus het wachtwoord moeten encrypten.

Iemand een idee?

Acties:
  • 0 Henk 'm!

  • __fred__
  • Registratie: November 2001
  • Laatst online: 10-07 07:28
Die ActiveX control werkt waarschijnlijk wel als je beveiligingsniveau van IE lager zet, of nog beter, de sites toevoegd aan je trusted sites.

Acties:
  • 0 Henk 'm!

Anoniem: 97275

Topicstarter
__fred__ schreef op maandag 13 augustus 2007 @ 17:14:
Die ActiveX control werkt waarschijnlijk wel als je beveiligingsniveau van IE lager zet, of nog beter, de sites toevoegd aan je trusted sites.
Da's een goeie. Dat ga ik morgen eens proberen, thanks.

Acties:
  • 0 Henk 'm!

  • Alex)
  • Registratie: Juni 2003
  • Laatst online: 04-07 10:37
Hier onder Vista werkt dat TSWeb prima hoor... je moet het ActiveX-control wel toestemming geven de eerste keer...

We are shaping the future


Acties:
  • 0 Henk 'm!

  • NMe
  • Registratie: Februari 2004
  • Laatst online: 11-07 17:04

NMe

Quia Ego Sic Dico.

Dit heeft meer met de praktijk van programmeren te maken dan met het ontwerp van software. Zie ook Waar hoort mijn topic? :)

SEA>>PRG

'E's fighting in there!' he stuttered, grabbing the captain's arm.
'All by himself?' said the captain.
'No, with everyone!' shouted Nobby, hopping from one foot to the other.


Acties:
  • 0 Henk 'm!

  • matthijsln
  • Registratie: Augustus 2002
  • Laatst online: 30-05 18:01
Als ik even Google dan kom je er al snel achter dat hiervoor de CryptProtectData() functie wordt gebruikt.

Deze functie kan je natuurlijk niet vanuit PHP aanroepen. Ook reverse engineeren heeft geen zin, omdat de data gesalt wordt met data specifiek van de user/computer (daarom kunnen RDP bestanden met een wachtwoord ook niet onder een ander user account of computer gebruikt worden). Die salt kan je niet te weten komen in PHP.

  • Thralas
  • Registratie: December 2002
  • Laatst online: 20:10
matthijsln schreef op woensdag 15 augustus 2007 @ 23:22:
Als ik even Google dan kom je er al snel achter dat hiervoor de CryptProtectData() functie wordt gebruikt.

Deze functie kan je natuurlijk niet vanuit PHP aanroepen. Ook reverse engineeren heeft geen zin, omdat de data gesalt wordt met data specifiek van de user/computer (daarom kunnen RDP bestanden met een wachtwoord ook niet onder een ander user account of computer gebruikt worden). Die salt kan je niet te weten komen in PHP.
Het zou kunnen met W32api extension.

  • ripexx
  • Registratie: Juli 2002
  • Laatst online: 10-07 20:56

ripexx

bibs

Ja maar dan gebruik je de info van de server en niet van de client. Dus gaat de RDP file, welke gegenereerd wordt op de server, niet op de client werken. Je ontkomt bij dit soort zaken niet aan een client side component.

buit is binnen sukkel


Acties:
  • 0 Henk 'm!

  • bommel
  • Registratie: Januari 2001
  • Laatst online: 09:42
Ik heb dit al eens uitgedokterd. Zie onder mijn Delphi (Pascal) Unit. Lijkt me niet al te moeilijk om te zetten naar andere talen:
Delphi: uRDPHash.pas
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
{******************************************************************}
{ Author: Remko Weijnen (r dot weijnen at gmail dot com)           }
{ Version: 0.1                                                     }
{ Date: 21-03-2007                                                 }
{                                                                  }
{ The contents of this file are subject to                         }
{ the Mozilla Public License Version 1.1 (the "License"); you may  }
{ not use this file except in compliance with the License. You may }
{ obtain a copy of the License at                                  }
{ http://www.mozilla.org/MPL/MPL-1.1.html                          }
{                                                                  }
{ Software distributed under the License is distributed on an      }
{ "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or   }
{ implied. See the License for the specific language governing     }
{ rights and limitations under the License.                        }
{******************************************************************}

unit uRDPHash;

interface

uses Windows, Sysutils, Classes, JwaWinCrypt;

function CryptRDPPassword(sPassword: string): string;
function DecryptRDPPassword(sPasswordHash: string): string;
function BlobDataToHexStr(P: PByte; I: Integer): string;
function PasswordHashToBlobData(sPasswordHash: string): DATA_BLOB;

implementation

{***********************************************************}
{ HexToByte: Converts Hex value to Byte                     }
{ Found this somewhere on the internet                      }
{***********************************************************}
function HexToByte(s : String) : Byte;
const
  cs = '0123456789ABCDEF';
begin
  result := 0;
  if (length(s) = 2) and
     (s[1] in ['0'..'9','A'..'F']) and
     (s[2] in ['0'..'9','A'..'F']) then
    result := ((pos(s[1],cs)-1) *16) + (pos(s[2],cs)-1)
  else raise EConvertError.CreateFmt('%s is not a Hexformatstring',[s]);
end;

{***********************************************************}
{ PasswordHashToBlobData2: Converts a RDP password Hash to  }
{                         a DATA_BLOB structure             }
{ sPasswordHash : RDP Password Hash (HEX String             }
{***********************************************************}
function PasswordHashToBlobData2(sPasswordHash: string): DATA_BLOB;
var Buf: array of Byte;
  dwBufSize: Cardinal;
begin

  dwBufSize := Length(sPasswordHash) shr 1;
  SetLength(Buf, dwBufSize);
  HexToBin(@sPasswordHash[1], @buf[0], dwBufSize);
  Result.pbData := PByte(AllocMem(dwBufSize));
//  GetMem(DataOut.pbData, dwBufSize);
  Result.cbData := dwBufSize;
  Result.pbData := PByte(Buf);

end;


{***********************************************************}
{ PasswordHashToBlobData: Converts a RDP password Hash to   }
{                         a DATA_BLOB structure             }
{ sPasswordHash : RDP Password Hash (HEX String             }
{***********************************************************}
function PasswordHashToBlobData(sPasswordHash: string): DATA_BLOB;
var Buf: array of Byte;
  dwBufSize: Cardinal;
  i: Cardinal;
  j: Cardinal;
  dwHashSize: Cardinal;
begin
  dwBufSize := Length(sPassWordHash) DIV 2;
  dwHashSize := Length(sPasswordHash);
  SetLength(Buf, dwBufSize);

  i := 1;
  j := 0;
  while i < dwHashSize do begin
    Buf[j] := HexToByte(sPassWordHash[i] + sPassWordHash[i+1]);
    Inc(i, 2);
    Inc(j);
  end;

  GetMem(Result.pbData, dwBufSize);
  Result.cbData := dwBufSize;
  Result.pbData := PByte(Buf);
end;

{***********************************************************}
{ BlobDataToHexStr: Converts a PByte from a DATA_BLOB       }
{                   to a Hex String so it can be saved in   }
{                   an RDP file                             }
{ P : PByte (pbData) from DATA_BLOB                         }
{ I : Integer (cbData) from DATA_BLOB                       }
{***********************************************************}
function BlobDataToHexStr(P: PByte; I: Integer): string;
var HexStr: string;
begin
  HexStr := '';
  while (I > 0) do begin
    Dec(I);
    HexStr := HexStr + IntToHex(P^, 2);
    Inc(P);
  end;
  Result := HexStr;
end;

{***********************************************************}
{ CryptRDPPassword: Converts a plaintext password to        }
{                   encrypted password hash                 }
{                   an RDP file                             }
{ sPassword: plaintext password                             }
{***********************************************************}
function CryptRDPPassword(sPassword: string): string;
var DataIn: DATA_BLOB;
    DataOut: DATA_BLOB;
    pwDescription: PWideChar;
    PwdHash: string;
begin
  PwdHash := '';

  DataOut.cbData := 0;
  DataOut.pbData := nil;

  // RDP uses UniCode
  DataIn.pbData := Pointer(WideString(sPassword));
  DataIn.cbData := Length(sPassword) * SizeOf(WChar);

  // RDP always sets description to psw
  pwDescription := WideString('psw');

  if CryptProtectData(@DataIn,
                      pwDescription,
                      nil,
                      nil,
                      nil,
                      CRYPTPROTECT_UI_FORBIDDEN,  // Never show interface
                      @DataOut) then
  begin
    PwdHash := BlobDataToHexStr(DataOut.pbData, DataOut.cbData);
  end;
  Result := PwdHash;

  // Cleanup
  LocalFree(Cardinal(DataOut.pbData));
  LocalFree(Cardinal(DataIn.pbData));

end;

{***********************************************************}
{ DecryptRDPPassword: Converts an RDP Password Hash back    }
{                     to it's original password.            }
{                     Note that this only works for the user}
{                     who encrypted the password (or on the }
{                     same computer in case it was encrypted}
{                     with the computerkey)                 }
{ sPasswordHash: Password hash (string)                     }
{***********************************************************}
function DecryptRDPPassword(sPasswordHash: string): string;
var DataIn: DATA_BLOB;
    DataOut: DATA_BLOB;
    sPassword: string;
    pwDecrypted: PWideChar;
    pwDescription: PWideChar;
begin

  DataIn.cbData := 0;
  DataIn.pbData := nil;
  DataIn := PassWordHashToBlobData2(sPasswordHash);

//  DataOut.cbData := 0;
//  DataOut.pbData := nil;

  if CryptUnprotectData(@DataIn,
                        @pwDescription,
                        nil,
                        nil,
                        nil,
                        CRYPTPROTECT_UI_FORBIDDEN,  // Never show interface
                        @DataOut) then
  begin
    Getmem(pwDecrypted, DataOut.cbData);
    lstrcpynW(pwDecrypted, PWideChar(DataOut.pbData), (DataOut.cbData DIV 2) + 1);
    sPassword := pwDecrypted;
    FreeMem(pwDecrypted);
  end
  else
  begin
    raise EConvertError.CreateFmt('Error decrypting: %s',[SysErrorMessage(GetLastError)]);
  end;

  Result := sPassword;

  // Cleanup
  if DataIn.cbData > 0 then
  begin
    LocalFree(Cardinal(DataIn.pbData));
  end;
  if DataOut.cbData > 0 then
  begin
    LocalFree(Cardinal(DataOut.pbData));
//    FreeMem(DataOut.pbData);
  end;
end;


end.


Hier heb ik ook nog een voorbeeld voor het aanmaken van een .rdp file (let op .rdp files zijn in UniCode je moet dus een Byte Order Mark zetten)

Acties:
  • 0 Henk 'm!

  • bommel
  • Registratie: Januari 2001
  • Laatst online: 09:42
Hier het voorbeeld ook maar meteen, scheelt weer wat klikken :-)
Delphi: RDPSample.pas
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
uses uRDPHash, Windows, JwaWinNt, SysUtils, Classes, shFolder, LbCipher, LbClass; 
{$R *.res} 
const 
   BOM_UTF16 = $FEFF;   // BOM = Byte Order Mark 
var 
   fs : TFileStream; 
   BOM : WideString; 
   sFolder: string; 
   sRDPFileName: string; 
   LocalAppData: PAnsiChar; 
   lpRect: TRect; 
   Helper: TLbRijndael; 
   sServer: string; 
   si: _STARTUPINFOW; 
   pi: PROCESS_INFORMATION; 
   pwCmdLine: PWideChar; 
   pwMsg: PWideChar; 
const 
  SHGFP_TYPE_CURRENT = 0;   // current value for user, verify it exists 

procedure WriteLnFs(var fs: TFileStream; sLine: String); 
var ws: WideString; 
begin 
  ws := WideString(sLine) + WideChar($0D) + WideChar($0A);; 
  try 
    fs.WriteBuffer(ws[1], Length(ws) * SizeOf(WideChar)); 
  except 
    // Handle Exception 
  end; 
end; 

begin 
  // Set folder path 
  sFolder := 'C:\Temp\gprmc.rdp'; 

  // Try to find LocalAppData folder 
  GetMem(LocalAppData, MAX_PATH); 
  if ShGetFolderPath(THandle(nil), 
                     CSIDL_LOCAL_APPDATA, 
                     THandle(nil), 
                     SHGFP_TYPE_CURRENT, 
                     LocalAppData) = S_OK then 
  begin 
    // and create GPRMC subfolder 
    sFolder := String(LocalAppData + '\GPRMC'); 
    if not DirectoryExists(sFolder) then 
    begin 
      MkDir(sFolder); 
    end; 

    sRDPFilename := sFolder + '\GPRMC.rdp'; 
    // Cleanup 
    FreeMem(LocalAppData); 
  end 
  else 
  begin 
    MessageBox(0, PAnsiChar(SysErrorMessage(GetLastError)), 'ShGetFolderPath', MB_OK); 
  end; 

  sServer := 'SERVER'; 

  // Obfuscate the password key 
  Helper := TLbRijndael.Create(nil); 
  Helper.CipherMode := cmECB; 
  Helper.KeySize := ks128; 
  Helper.GenerateKey('The Secret Key Which you should hide somewhere'); 

  // Get Screen Width and Height 
  GetWindowRect(GetDesktopWindow, lpRect); 

  // RDP Unicode Byte Order Mark (BOM) 
  BOM := Widechar(BOM_UTF16); 

  // Create RDP File 
  fs := TFileStream.Create(sRDPFileName, fmCreate); 

  // Write BOM 
  fs.WriteBuffer(BOM[1], Length(BOM)*sizeof(Widechar)); 

  // Write RDP file 
  WriteLnFs(fs, 'screen mode id:i:1'); 
  WriteLnFs(fs, Format('desktopwidth:i:%d', [lpRect.Right])); 
  WriteLnFs(fs, Format('desktopheight:i:%d', [lpRect.Bottom - 50])); 
  WriteLnFs(fs, 'session bpp:i:16'); 
  WriteLnFs(fs, 'winposstr:s:2,3,247,0,1055,627'); 
  WriteLnFs(fs, Format('full address:s:%s', [sServer])); 
  WriteLnFs(fs, 'compression:i:1'); 
  WriteLnFs(fs, 'keyboardhook:i:2'); 
  WriteLnFs(fs, 'audiomode:i:2'); 
  WriteLnFs(fs, 'redirectdrives:i:0'); 
  WriteLnFs(fs, 'redirectprinters:i:0'); 
  WriteLnFs(fs, 'redirectcomports:i:0'); 
  WriteLnFs(fs, 'redirectsmartcards:i:0'); 
  WriteLnFs(fs, 'displayconnectionbar:i:1'); 
  WriteLnFs(fs, 'autoreconnection enabled:i:1'); 
  WriteLnFs(fs, Format('username:s:%s', ['USERNAME'])); 
  WriteLnFs(fs, Format('domain:s:%s', ['DOMAIN'])); 
  WriteLnFs(fs, 'password 51:b:' + CryptRdpPassWord(Helper.DecryptString('GSMZHifunaBaegL6ehnkmw=='))); 
  WriteLnFs(fs, 'disable wallpaper:i:1'); 
  WriteLnFs(fs, 'disable full window drag:i:1'); 
  WriteLnFs(fs, 'disable menu anims:i:1'); 
  WriteLnFs(fs, 'disable themes:i:1'); 
  WriteLnFs(fs, 'disable cursor setting:i:0'); 
  WriteLnFs(fs, 'bitmapcachepersistenable:i:1'); 

  // Cleanup 
  Helper.Free; 
  fs.Free; 

  ZeroMemory(@si, SizeOf(si)); 
  si.cb := SizeOf(si); 
  si.lpDesktop := nil; 
  
  pwCmdLine := PWideChar(WideString('mstsc.exe ' + '"' + sRDPFileName + '"')); 
  if not CreateProcessW(nil, 
                        pwCmdLine, 
                        nil, 
                        nil, 
                        False, 
                        0, 
                        nil, 
                        nil, 
                        si, 
                        pi) then 
  begin 
    pwMsg := PWideChar(WideString('Failed to start MSTSC.EXE' +#10#13+ 
                                  SysErrorMessage(GetLastError))); 
    MessageBoxExW(0, 
                  pwMsg, 
                  'Sample Program', 
                  MB_ICONERROR or MB_OK, 
                  MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL)); 
  end; 
end.

Acties:
  • 0 Henk 'm!

  • matthijsln
  • Registratie: Augustus 2002
  • Laatst online: 30-05 18:01
In de code die je post staat zelfs waarom het server-side niet werkt zoals de OP het wil gebruiken.

Regel 161

Acties:
  • 0 Henk 'm!

  • bommel
  • Registratie: Januari 2001
  • Laatst online: 09:42
De vraag was: hoe encrypt ik het rdp wachtwoord. De wijze waarop dit gebeurt impliceert idd wel dat het encrypten in de context van de user die de rdp start (of de machine, zie regel 161) moet plaatsvinden. Aangezien er gesproken wordt over een intranet zijn er wel diverse oplossingen die ik kan bedenken, bijvoorbeeld:
Los het op met iets dat clientside draait zoals Java op desnoods roep je een commandline .exe aan met parameters.

Anoniem: 74303

Nice, exact wat ik zocht! Is er nog een duistere truuk mogelijk om het buiten de juiste context ook goed te laten werken?

[ Voor 65% gewijzigd door Anoniem: 74303 op 23-08-2007 17:13 ]


Anoniem: 97275

Topicstarter
Wow, wat goed zeg.

Ben even gaan zoeken, en ik kwam hier uit, dat betekent dat je gewoon Delphi meuk onder Linux kan runnen.

Dat is erg interessant, dat betekent gewoon vanuit PHP die binary aanroepen en de output fetchen.

_/-\o_

Acties:
  • 0 Henk 'm!

  • matthijsln
  • Registratie: Augustus 2002
  • Laatst online: 30-05 18:01
Anoniem: 97275 schreef op donderdag 23 augustus 2007 @ 23:26:
Wow, wat goed zeg.

Ben even gaan zoeken, en ik kwam hier uit, dat betekent dat je gewoon Delphi meuk onder Linux kan runnen.

Dat is erg interessant, dat betekent gewoon vanuit PHP die binary aanroepen en de output fetchen.
Je hebt hierboven toch wel gelezen waarom dat niet kan werken?

En met kylix kan je geen windows API als CryptProtectData() aanroepen vanuit Linux, dus dat zal al helemaal niet werken.

Acties:
  • 0 Henk 'm!

  • bommel
  • Registratie: Januari 2001
  • Laatst online: 09:42
Mocht iemand meer info zoeken over dit onderwerk (encypting & decrypting rdp passwords) kijk dan eens op mijn site: http://remkoweijnen.nl/bl...-passwords-are-encrypted/. Je vindt er oa een tool dat rdp wachtwoorden versleutelt en ontsleutelt.

Acties:
  • 0 Henk 'm!

  • voodooless
  • Registratie: Januari 2002
  • Laatst online: 19:18

voodooless

Sound is no voodoo!

Niet om het een of ander, maar als ik het goed begrijp enctypt is niets, je maakt er enkel en alleen een hash van. Kortom: als je de hash hebt kun je ook daarmee doen wat je wil: inloggen met dat zelfde filetje. De vraag is: schiet je zo wel iets op?

En als de file alleen werkt op de betreffende PC, dan zul je die file dus ook op die PC moeten maken (of je moet zijn key achterhalen)... lijkt me dus voor een webapplicatie niet echt handig werken.

[ Voor 28% gewijzigd door voodooless op 22-10-2007 14:47 ]

Do diamonds shine on the dark side of the moon :?


Acties:
  • 0 Henk 'm!

  • bommel
  • Registratie: Januari 2001
  • Laatst online: 09:42
Het is meer dan een hash (de functie heet ook CryptProtect), wat het dus doet is versleutelen van een wachtwoord zodanig dan alleen dezelfde windows (op dezelfde machine) het kan ontsleutelen zonder dat je een "secret" nodig hebt. Het doel van de unit is eigenlijk om wachtwoorden die door de Terminal Server Client (mstsc) zijn opgeslagen te ontsleutelen cq deze wachtwoorden zelf te kunnen versleutelen en zo zelf rdp files maken (of bijv. bulk wachtwoord aanpassingen in rdp files na wijzigen wachtwoord). Optioneel is het mogelijk om ook een "secret" (entropy) mee te geven maar dan is het niet meer compatible met de Terminal Server client.

Acties:
  • 0 Henk 'm!

  • kunnen
  • Registratie: Februari 2004
  • Niet online
Kun je niet simpelweg van elke client/server éénmaal een .RDP-bestand genereren, en de password hash daarvan opslaan en gebruiken?

Acties:
  • 0 Henk 'm!

  • bommel
  • Registratie: Januari 2001
  • Laatst online: 09:42
Als het wachtwoord hetzelfde is hoeft dat niet eens. Het wachtwoord is user en niet server gebonden. maw iedere user moet het wachtwoord een keer genereren en opslaan.
Pagina: 1