Skip to content

Instantly share code, notes, and snippets.

@Sin42
Last active October 13, 2020 19:59
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save Sin42/feb693a5b29679f8137b2d751aeb1e31 to your computer and use it in GitHub Desktop.
Save Sin42/feb693a5b29679f8137b2d751aeb1e31 to your computer and use it in GitHub Desktop.
flare on 2019 level 12
import hashlib, os, sys, mmap, struct
from Crypto.Cipher import AES
"""
The first "part" of the challenge: https://www.youtube.com/watch?v=l0bxw6CZmIc&hd=1
Analysis of cng.sys :
vol.py --profile Win7SP1x64 -f ./help.dmp modules | grep -i cng.sys
0xfffffa800183f230 cng.sys 0xfffff88001000000 0x72000 \SystemRoot\System32\Drivers\cng.sys
In CngEncryptMemory we can see what happens for CryptProtectMemory if the flag is set to CRYPTPROTECTMEMORY_SAME_PROCESS
result = ZwQueryInformationProcess(-1i64, ProcessCookie, &proc_cookie);
cur_process = (struct _KPROCESS *)PsGetCurrentProcess(v18);
create_time_quad = PsGetProcessCreateTimeQuadPart(cur_process);
key_material_len = 12;
key_material_buf_ = (unsigned __int8 *)key_material_buf;
*(_DWORD *)key_material_buf = proc_cookie;
*(_QWORD *)&key_material_buf[4] = create_time_quad;
...
GenerateAESKey((struct AESTable_128 *)&aes_key, key_material_buf_, key_material_len);
...
for ( aes_iv = *(_OWORD *)&RandomSalt; v21; --v21 )
{
CBC(aes128, 16i64, v8, v8, &aes_key, v6, &aes_iv);
v8 += 16i64;
}
...
First, the IV used is at RandomSalt
.data:FFFFF88001068570 ?? ?? ?? ?? ?? ?? ?? ?? ??+?RandomSalt@@3PAEA xmmword ? ; DATA XREF: CngEncryptMemoryInitialize
In [12]: db(0xFFFFF88001068570)
0xfffff88001068570 35 3a d5 b5 19 db b2 64 ba e3 85 9e d7 b1 02 e8 5:.....d........
Next, the actual key is generated in the following way:
memcpy(&sha_ctx, &g_ShaHash, 0x60ui64);
A_SHAUpdate(&sha_ctx, key_material_buf, key_material_len);
A_SHAFinal(&sha_ctx, &sha_digest);
aeskey(outkey, &sha_digest, 10i64);
Due to the way the Sha1 hash works, since g_ShaHash has only been seeded with 24 bytes so far in CngEncryptMemoryInitialize, since 24 is less than the block size, they'll still be right there.
NewGenRandom(0i64, 0i64, &g_hash_initial_bytes, 24i64)
A_SHAInit(&g_ShaHash);
A_SHAUpdate(&g_ShaHash, &g_hash_initial_bytes, 24i64);
data:FFFFF88001068510 ?? ?g_ShaHash@@3UA_SHA_CTX@@A db ? ; ; DATA XREF: GenerateKey(_DES3TABLE *,uchar *,ulong)
In [15]: db(0xFFFFF88001068510, 24)
0xfffff88001068510 1c 81 87 7b 81 73 be 1b 99 da 11 35 10 43 4e da ...{.s.....5.CN.
0xfffff88001068520 97 9e b0 0e 37 cd 31 2b ....7.1+
Next, we need proc_cookie and create time quad for the process:
vol.py --profile Win7SP1x64 -f ./help.dmp pslist | grep KeePass
0xfffffa80026070b0 KeePass.exe 2648 1124 6 129 1 1 2019-08-02 14:37:12 UTC+0000
In [2]: obj.Object("_EPROCESS",0xfffffa80026070b0, vm=addrspace()).Cookie
Out[2]: [unsigned long]: 348144885
dt("_EPROCESS")
'_EPROCESS' (1232 bytes)
0x0 : Pcb ['_KPROCESS']
0x160 : ProcessLock ['_EX_PUSH_LOCK']
0x168 : CreateTime ['WinTimeStamp', {'is_utc': True}]
In [6]: dq(0xFFFFFA80026070B0+0x168, 1)
0xfffffa8002607218 0x1d5493fc578c885
"""
iv = "35 3a d5 b5 19 db b2 64 ba e3 85 9e d7 b1 02 e8".replace(" ", "").decode('hex')
sha_prev_bytes = "1c 81 87 7b 81 73 be 1b 99 da 11 35 10 43 4e da97 9e b0 0e 37 cd 31 2b".replace(" ", "").decode('hex')
assert len(sha_prev_bytes) == 24
cookie = 348144885
timestamp = 0x1d5493fc578c885
buf = struct.pack("<IQ", cookie, timestamp)
assert len(buf) == 12
h = hashlib.new("SHA1")
h.update(sha_prev_bytes)
h.update(buf)
key = h.digest()[:16]
cipher = AES.new(key, AES.MODE_CBC, iv)
a = open("./help.dmp", "rb+")
mm = mmap.mmap(a.fileno(), 0)
i = 0x72704ea8
x = cipher.decrypt( mm[i:i+0x30] )
print(repr(x))
#'f0ll0w_th3_br34dcrumbs@flare-on.com\x00master key.\x00'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment