Page 1 of 3 1 2 3 LastLast
Results 1 to 15 of 33

Thread: DPAPI en CryptUnprotectData

Hybrid View

  1. #1

    DPAPI en CryptUnprotectData

    Hoi,

    ik ben al enkele dagen mijn hoofd aan het breken over iets en zowel ik als mijn collega geraken er niet aan uit, ik hoop dat iemand hier redding kan brengen.

    We willen uit de chrome cookies file, versie 80 of hoger, een waarde uitlezen uit de sqllite db.
    Dat lukt, alleen is die waarde versleuteld.

    De manier waarop dit gebeurd staat mooi beschreven op https://xenarmor.com/how-to-recover-...-google-chrome alleen gaat het hier over paswoorden maar de werkwijze is identiek voor de cookies encrypted data.

    De waarde in die sqllite db is dus AES-256-GCM versleuteld, met een key die op zich ook versleuteld is en in het chrome bestand 'local state' zit.

    Om de waarde op te halen moet ik dus eerst en vooral die local state 'os_crypt' ophalen, dit lukt, dit is een json bestand.

    Die waarde moet ik dan base64 decoderen, vervolgens van die waarde de eerste 5 karakters verwijderen en vervolgens door CryptUnprotectData laten gaan.
    Dat geeft me de sleutel waarmee de cookie waarde AES-256 versleuteld is en moet ik deze decrypteren.

    Ik heb een voorbeeld gevonden in python die perfect doet wat ik nodig heb maar ik krijg het niet werkend in Delphi en ik ken helemaal niet veel van python.
    Ook de tool 'ChromeCookiesView' van Nirsoft toont mooi de waarde die ik nodig heb.

    In delphi kan ik nu enkel de eerste stap uitvoeren met hetzelfde resultaat als in python, vanaf de base64decode heb ik al iets anders, TBytes of een String en in Python lijkt het op een soort HexString.
    Vervolgens neem ik de eerste 5 karakters weg en doe de Cryptunprotect maar die retourneert False en ik heb geen idee waarom.

    Iemand hier ervaring mee?

    Localstate os_crypt=
    RFBBUEkBAAAA0Iyd3wEV0RGMegDAT8KX6wEAAAB4PpTCtodTQ4 nQLEGqadm7AAAAAAIAAAAAABBmAAAAAQAAIAAAAPhwZ7vhFrl1 jZ+NUwEXAMzeUi8jMR16yMde10Nq5aROAAAAAA6AAAAAAgAAIA AAAJl7QrqvaIkHJR1HvjDyBBh3SDZtJ6dksOLJrO0NBTDWMAAA AHU2A+ojxTYeKTBmCqYGynLMNZif2xRqrhNmiPwLGfPs6VkeFt fuS0StX2tOXrEQmkAAAAAdmTwrGXIdycrWkM8sc2Tll42s1Ucn x4j1+H13Qyuq78nSLSrmagsyAngs4knVf/roywQdsqEHTA8YmvzopwHO
    In python resulteert de base64decode in
    DPAPI\x01\x00\x00\x00\xd0\x8c\x9d\xdf\x01\x15\xd1\ x11\x8cz\x00\xc0O\xc2\x97\xeb\x01\x00\x00\x00x>\x9 4\xc2\xb6\x87SC\x89\xd0,A\xaai\xd9\xbb\x00\x00\x00 \x00\x02\x00\x00\x00\x00\x00\x10f\x00\x00\x00\x01\ x00\x00 \x00\x00\x00\xf8pg\xbb\xe1\x16\xb9u\x8d\x9f\x8dS\x 01\x17\x00\xcc\xdeR/#1\x1dz\xc8\xc7^\xd7Cj\xe5\xa4N\x00\x00\x00\x00\x0 e\x80\x00\x00\x00\x02\x00\x00 \x00\x00\x00\x99{B\xba\xafh\x89\x07%\x1dG\xbe0\xf2 \x04\x18wH6m'\xa7d\xb0\xe2\xc9\xac\xed\r\x050\xd60 \x00\x00\x00u6\x03\xea#\xc56\x1e)0f\n\xa6\x06\xcar \xcc5\x98\x9f\xdb\x14j\xae\x13f\x88\xfc\x0b\x19\xf 3\xec\xe9Y\x1e\x16\xd7\xeeKD\xad_kN^\xb1\x10\x9a@\ x00\x00\x00\x1d\x99<+\x19r\x1d\xc9\xca\xd6\x90\xcf ,sd\xe5\x97\x8d\xac\xd5G'\xc7\x88\xf5\xf8}wC+\xaa\ xef\xc9\xd2-*\xe6j\x0b2\x02x,\xe2I\xd5\x7f\xfa\xe8\xcb\x04\x1d \xb2\xa1\x07L\x0f\x18\x9a\xfc\xe8\xa7\x01\xce
    Maar in Delphi
    DPAPI'#1#0#0#0''#$008C#$009D''#1#$15''#$11#$008 C'z'#0'O'#$0097''#1#0#0#0'x>'#$0094'¶'#$0087'S C'#$0089',Aiٻ'#0#0#0#0#2#0#0#0#0#0#$10'f'#0#0#0 #1#0#0' '#0#0#0'pg'#$16'u'#$008D#$009F#$008D'S'#1#$17# 0'R/#1'#$1D'z^CjN'#0#0#0#0#$E#$0080#0#0#0#2#0#0' '#0#0#0#$0099'{Bh'#$0089#7'%'#$1D'G0'#4#$18'wH 6m''dɬ'#$D#5'00'#0#0#0'u6'#3'#6'#$1E')0f'# $A''#6'r5'#$0098#$009F''#$14'j'#$13'f'#$0088' '#$B#$19'Y'#$1E#$16'KD'#$00AD'_kN^'#$10#$00 9A'@'#0#0#0#$1D#$0099'<+'#$19'r'#$1D''#$0090', sd'#$0097#$008D'G'''#$0088'}wC+-*j'#$B'2'#2'x,I'#$7F''#4#$1D''#7'L'#$F#$18 #$009A''#1'
    Het zou best zijn als ik dezelfde string kan terugkrijgen als in python dan weet ik dat die stap alvast ok is.

    Ik heb tal van voorbeelden gevonden over de CryptUnprotectData maar zonder succes, als iemand daar iets van weet, graag.

    Alvast bedankt.

  2. #2
    Quote Originally Posted by Delphiwizard View Post
    In python resulteert de base64decode in
    Maar in Delphi
    En wat is het problem.
    Die string in python is toch hetzelfde als die in Delphi?

    Alleen de stringnotatie van delphi is anders dan die van pyhton.
    \x01 = #0
    \x00 = #0
    etc

    Maar zover ik kan zien zijn ze verder hetzelfde.

  3. #3
    Quote Originally Posted by rvk View Post
    En wat is het problem.
    Die string in python is toch hetzelfde als die in Delphi?

    Alleen de stringnotatie van delphi is anders dan die van pyhton.
    \x01 = #0
    \x00 = #0
    etc

    Maar zover ik kan zien zijn ze verder hetzelfde.
    Bedankt voor je antwoord Rik, ja daar ging ik ook vanuit maar kon het niet zo gemakkelijk controleren, dus was ik op zoek naar een functie om deze om te zetten naar dezelfde Hex string ter controle.
    Maar goed, verder moet deze dus door CryptUnprotect gaan en deze retourneert altijd false.
    var DataIn: DATA_BLOB;
    DataOut: DATA_BLOB;

    ...
    DataIn.pbData := PByte(PAnsiChar(LocalStateEncodedKey));
    DataIn.cbData := StrLen(PAnsiChar(LocalStateEncodedKey)) + 1;

    if CryptUnprotectData(@DataIn, nil, nil, nil, nil, 0, @DataOut) then
    showmessage('worked!');
    DATA_BLOB definitie:
    type
    _CRYPTOAPI_BLOB = record
    cbData: DWORD;
    pbData: PByte;
    end;

    PDATA_BLOB = ^DATA_BLOB;
    DATA_BLOB = _CRYPTOAPI_BLOB;
    function CryptUnprotectData(pDataIn: PDATA_BLOB; ppszDataDescr: PPWideChar;
    pOptionalEntropy: PDATA_BLOB; pvReserved: Pointer; pPromptStruct:
    PCRYPTPROTECT_PROMPTSTRUCT; dwFlags: DWORD; pDataOut: PDATA_BLOB): BOOL;
    stdcall; external 'Crypt32.dll';

  4. #4
    Je bent niet vergeten de eerste 5 characters te strippen?

    Maak je trouwens met PByte(PAnsiChar(LocalStateEncodedKey)) ook geen dubbele pointer aan?

    Moet het niet PByte(LocalStateEncodedKey) zijn?

  5. #5
    Nee hoor,

    Voor het strippen:
    'DPAPI'#1#0#0#0''#$008C#$009D''#1#$15''#$11#$00 8C'z'#0'O'#$0097''#1#0#0#0'x>'#$0094'¶'#$0087' SC'#$0089',Aiٻ'#0#0#0#0#2#0#0#0#0#0#$10'f'#0#0# 0#1#0#0' '#0#0#0'pg'#$16'u'#$008D#$009F#$008D'S'#1#$17# 0'R/#1'#$1D'z^CjN'#0#0#0#0#$E#$0080#0#0#0#2#0#0' '#0#0#0#$0099'{Bh'#$0089#7'%'#$1D'G0'#4#$18'wH 6m''dɬ'#$D#5'00'#0#0#0'u6'#3'#6'#$1E')0f'# $A''#6'r5'#$0098#$009F''#$14'j'#$13'f'#$0088' '#$B#$19'Y'#$1E#$16'KD'#$00AD'_kN^'#$10#$00 9A'@'#0#0#0#$1D#$0099'<+'#$19'r'#$1D''#$0090', sd'#$0097#$008D'G'''#$0088'}wC+-*j'#$B'2'#2'x,I'#$7F''#4#$1D''#7'L'#$F#$18 #$009A''#1''
    Na het strippen.
    #1#0#0#0''#$008C#$009D''#1#$15''#$11#$008C'z'#0 'O'#$0097''#1#0#0#0'x>'#$0094'¶'#$0087'SC'#$00 89',Aiٻ'#0#0#0#0#2#0#0#0#0#0#$10'f'#0#0#0#1#0#0 ' '#0#0#0'pg'#$16'u'#$008D#$009F#$008D'S'#1#$17# 0'R/#1'#$1D'z^CjN'#0#0#0#0#$E#$0080#0#0#0#2#0#0' '#0#0#0#$0099'{Bh'#$0089#7'%'#$1D'G0'#4#$18'wH 6m''dɬ'#$D#5'00'#0#0#0'u6'#3'#6'#$1E')0f'# $A''#6'r5'#$0098#$009F''#$14'j'#$13'f'#$0088' '#$B#$19'Y'#$1E#$16'KD'#$00AD'_kN^'#$10#$00 9A'@'#0#0#0#$1D#$0099'<+'#$19'r'#$1D''#$0090', sd'#$0097#$008D'G'''#$0088'}wC+-*j'#$B'2'#2'x,I'#$7F''#4#$1D''#7'L'#$F#$18 #$009A''#1''
    De fout moet hem ergens bij het invullen van die data_blob variabelen zijn denk ik, of er zijn karakters die verloren gaan doordat alles in een string zit.
    Met TBytes ook geprobeerd maar dit werkte ook niet.

  6. #6
    Quote Originally Posted by Delphiwizard View Post
    De fout moet hem ergens bij het invullen van die data_blob variabelen zijn denk ik, of er zijn karakters die verloren gaan doordat alles in een string zit.
    Je probeert dit toch wel op hetzelfde systeem als waar het cookie staat h.

    En heb je die dubbele pointer referentie al weggehaald?
    Dus geen pbyte(pansichar(string)) maar direct pbyte(string).

  7. #7
    Bedankt voor het advies Rik, ik zit ondertussen iets verder, de CryptUnprotectData is dan gelukt.

    Nu ik die sleutel heb moet ik verder met AES-256 decrypt.
    Ik bestudeer dit verder, als ik opnieuw vast zit post ik het hier wel.

    Ik heb de waarde van de Base64 decodering dan naar een TBytes gedaan, daarvan moet ik volgens de info die ik heb de eerste 5 karakters weglaten.
    Ik deed dus LocalStateEncodedKey := Copy(LocalStateEncodedKey, 6, Length(LocalStateEncodedKey));
    Maar dan zag ik in mijn resultaat dat de eerste waarde die ik nodig heb niet meer in de string zat, in dit voorbeeld '1'.

    Als ik LocalStateEncodedKey := Copy(LocalStateEncodedKey, 5, Length(LocalStateEncodedKey)); doe dan lukt het wel.

    Dus:
    Waarde ophalen uit local state json bestand ok
    Deze waarde base64 decodering naar tbytes ok
    de eerste 5 karakters weglaten ok
    deze waarde dan cryptunprotect ok

    De waarde uit de chrome cookie heb ik ook reeds, nu moet ik daarmee verder en aes-256 decrypt doen met de waarden die ik heb.
    Daar ken ik ook niets van dus dat wordt ook nog een opdracht.

  8. #8
    Counting your refs Paul-Jan's Avatar
    Join Date
    Feb 2002
    Location
    Lage Zwaluwe
    Posts
    2,152
    Algemene tip die hier misschien handig is: als je een wat groter blok binaire data uit twee verschillende debugger-omgevingen met elkaar wilt vergelijken, loont het bijna altijd de moeite om ze even naar een bestandje weg te schrijven zodat je die een in hexedit tooltje kunt bekijken en/of diffen.

    Uiteraard kan er bij het wegschrijven ook van alles fout gaan (zeker als er binaire data in een string zit, met welke encoding je wegschrijft is dan relevant), maar toch... het levert vaak wat op.

  9. #9
    Ja uiteraard op hetzelfde systeem Rik, beide ChromeCookiesView en het python programma halen de waarde die ik nodig heb mooi op.
    En zonder die pansichar zelfde fout.

    RaiseLastOsError is trouwens 'invalid data'

  10. #10
    Ik ga er even vanuit dat LocalStateEncodedKey een ansistring is???

    Werkt dit dan wel?

    Delphi Code:
    1. var
    2.   fpDataIn: tBytes
    3.   DataIn: DATA_BLOB;
    4.   DataOut: DATA_BLOB;
    5. //...
    6. SetLength(fpDataIn, Length(LocalStateEncodedKey));
    7. Move(LocalStateEncodedKey[1], fpDataIn[0], Length(LocalStateEncodedKey));  
    8. DataIn.pbData := @fpDataIn[0];
    9. DataIn.cbData := Length(fpDataIn);
    10. //...
    11. if CryptUnprotectData(@DataIn, nil, nil, nil, nil, 0, @DataOut) then
    12.   ShowMessage('worked!');

  11. #11
    Klopt:

    Code:
    function UnProtectLocalState(EncodedKey: TBytes): String;
       var  DataIn: DATA_BLOB;
            DataOut: DATA_BLOB;
       begin
          Result := '';
          DataIn.cbData := Length(EncodedKey);
          DataIn.pbData := Pointer(EncodedKey);
    
          if CryptUnprotectData(DataIn, nil, nil, 0, nil, 0, DataOut) then
          begin
             Result := AnsiString(PAnsiChar(DataOut.pbData));
             LocalFree(Cardinal(DataOut.pbData));
          end else
             RaiseLastOSError;
       end;

  12. #12
    mov rax,marcov; push rax marcov's Avatar
    Join Date
    Apr 2004
    Location
    Ehv, Nl
    Posts
    10,342
    Wat is LocalStateEncodedKey voor type? Om pansichar te laten werken dient het expliciet ANSISTRING te zijn OF D2007 en ouder gewoon string.

  13. #13
    Quote Originally Posted by Delphiwizard View Post
    Ik heb de waarde van de Base64 decodering dan naar een TBytes gedaan, daarvan moet ik volgens de info die ik heb de eerste 5 karakters weglaten.
    Als je de decode naar tbyte gedaan hebt kun je die ook rechtstreeks in de functie proppen.

    Delphi Code:
    1. var
    2.   fpDataIn: tBytes
    3.   DataIn: DATA_BLOB;
    4.   DataOut: DATA_BLOB;
    5. //...
    6. DataIn.pbData := @fpDataIn[5];
    7. DataIn.cbData := Length(fpDataIn) - 5;
    8. //...
    9. if CryptUnprotectData(@DataIn, nil, nil, nil, nil, 0, @DataOut) then
    10.   ShowMessage('worked!');

    Dan ga ik ervan uit dat je fpDataIn de decodeerde data bevat.

  14. #14
    Hoi,

    zoals reeds kort besproken op het discord channel ben ik al een tijdje aan het proberen om een specieke chrome cookie value op te halen en te decrypteren.
    De methode hiervoor is veranderd in Chrome versie 80 dus specifiek voor chrome versie 80 of hoger.

    Het wordt hier perfect uitgelegd hoe dit in elkaar zit en ik heb een werkend python tooltje gevonden en aangepast die het prima doet maar we krijgen het maar niet voor elkaar in Delphi, en we hebben hieraan de voorkeur aangezien niemand bij ons veel python kent.

    Ik ben dus op zoek naar iemand die geinteresseert is in de technologie hierachter en die python en delphi kent en eens zou willen kijken waar we in de fout gaan.
    Als je het graag eens zou willen bekijken, stuur een pm en ik stuur je beide projectjes.
    Ook de tool ChromeCookiesView doet het prima dus handig voor debugging.

    Wat de stappen zijn volgens mij is:
    1- ophalen van de beveiligde machine key uit het chrome local state json bestand
    2- Deze key base64 decoderen
    3- de eerste 5 karakters van dat resultaat (DPAPI) verwijderen
    4- het resultaat door de windows CryptUnprotectData functie halen.
    5- Dan de cookie value ophalen, dit met behulp van unidac in mijn demo maar kan ook met iets anders, de COOKIES file is SqlLite db
    Tot hier is alles correct denk ik.

    Dan moet ook een gedeelte van die cookie value genomen worden, en moet deze AES-256 decrypted worden met als secret key het resultaat van de gedecrypteerde machinekey maar hierin slagen we dus niet.
    We hebben geprobeerd met Chilkat en Lockbox, ik ken zelf niets van ecrypties en zo dus als iemand het eens verder wil bekijken, graag!
    Alvast bedankt.

  15. #15
    Counting your refs Paul-Jan's Avatar
    Join Date
    Feb 2002
    Location
    Lage Zwaluwe
    Posts
    2,152

    Thumbs up

    Je koopt er verder niets voor, maar ik wilde je even complimenteren met deze zeer duidelijke en complete probleemomschrijving. ?????? <- dit is een emoji van een duimpje: het forum houdt niet van unicode, ik wel.

Page 1 of 3 1 2 3 LastLast

Thread Information

Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •