bool mod_mimikatz_efs::toraw(vector<wstring> * arguments) { if(arguments->size() == 2) { PVOID pvContext = NULL; wcout << L"Opening : " << arguments->front() << endl; if(OpenEncryptedFileRaw(arguments->front().c_str(), 0, &pvContext) == ERROR_SUCCESS) { wcout << L"To : " << arguments->back() << endl; HANDLE hFile = CreateFile(arguments->back().c_str(), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL); if(ReadEncryptedFileRaw(ExportToFileCallback, &hFile, pvContext) == ERROR_SUCCESS) { wcout << L" * Export OK" << endl; } else wcout << L"* Error ReadEncryptedFileRaw : " << mod_system::getWinError() << endl; CloseHandle(hFile); CloseEncryptedFileRaw(pvContext); } else wcout << L"Error OpenEncryptedFileRaw : " << mod_system::getWinError() << endl; } return true; }
int send_whole_filel(struct asfd *asfd, #ifdef HAVE_WIN32 enum cmd cmd, #endif const char *datapth, int quick_read, uint64_t *bytes, struct cntr *cntr, struct BFILE *bfd, const char *extrameta, size_t elen) { int ret=0; size_t s=0; MD5_CTX md5; char buf[4096]=""; struct iobuf wbuf; if(!bfd) { logp("No bfd in %s()\n", __func__); return -1; } if(!MD5_Init(&md5)) { logp("MD5_Init() failed\n"); return -1; } if(extrameta) { size_t metalen=0; const char *metadata=NULL; metadata=extrameta; metalen=elen; // Send metadata in chunks, rather than all at once. while(metalen>0) { if(metalen>ZCHUNK) s=ZCHUNK; else s=metalen; if(!MD5_Update(&md5, metadata, s)) { logp("MD5_Update() failed\n"); ret=-1; } iobuf_set(&wbuf, CMD_APPEND, (char *)metadata, s); if(asfd->write(asfd, &wbuf)) { ret=-1; } metadata+=s; metalen-=s; *bytes+=s; } } else { #ifdef HAVE_WIN32 if(!ret && cmd==CMD_EFS_FILE) { struct winbuf mybuf; mybuf.md5=&md5; mybuf.quick_read=quick_read; mybuf.datapth=datapth; mybuf.cntr=cntr; mybuf.bytes=bytes; mybuf.asfd=asfd; // The EFS read function, ReadEncryptedFileRaw(), // works in an annoying way. You have to give it a // function that it calls repeatedly every time the // read buffer is called. // So ReadEncryptedFileRaw() will not return until // it has read the whole file. I have no idea why // they do not have a plain 'read()' function for it. ReadEncryptedFileRaw((PFE_EXPORT_FUNC)write_efs, &mybuf, bfd->pvContext); } else #endif if(!ret) { #ifdef HAVE_WIN32 int do_known_byte_count=0; size_t datalen=bfd->datalen; if(datalen>0) do_known_byte_count=1; #endif while(1) { #ifdef HAVE_WIN32 if(do_known_byte_count) { s=(uint32_t)bfd->read(bfd, buf, min((size_t)4096, datalen)); datalen-=s; } else { #endif s=(uint32_t)bfd->read(bfd, buf, 4096); #ifdef HAVE_WIN32 } #endif if(s<=0) break; *bytes+=s; if(!MD5_Update(&md5, buf, s)) { logp("MD5_Update() failed\n"); ret=-1; break; } iobuf_set(&wbuf, CMD_APPEND, buf, s); if(asfd->write(asfd, &wbuf)) { ret=-1; break; } if(quick_read) { int qr; if((qr=do_quick_read(asfd, datapth, cntr))<0) { ret=-1; break; } if(qr) { // client wants to interrupt break; } } #ifdef HAVE_WIN32 // Windows VSS headers tell us how many bytes to // expect. if(do_known_byte_count && datalen<=0) break; #endif } } } if(!ret) { uint8_t checksum[MD5_DIGEST_LENGTH]; if(!MD5_Final(checksum, &md5)) { logp("MD5_Final() failed\n"); return -1; } return write_endfile(asfd, *bytes, checksum); } return ret; }
bool mod_mimikatz_efs::full(vector<wstring> * arguments) { if(!arguments->empty()) { PVOID pvContext = NULL; if(OpenEncryptedFileRaw(arguments->front().c_str(), 0, &pvContext) == ERROR_SUCCESS) { SIMPLE_BYTE_ARRAY sba = {0, reinterpret_cast<BYTE *>(malloc(0))}; if(ReadEncryptedFileRaw(ExportToArrayCallback, &sba, pvContext) == ERROR_SUCCESS) { PEFS_FEK Fek = NULL; PEFS_STREAM_DATA_SEGMENT monDataSegment = NULL; for( PEFS_MARSHALED_STREAM monMarshaledStream = reinterpret_cast<PEFS_MARSHALED_STREAM>(sba.tableau + sizeof(EFS_RAW)); reinterpret_cast<PBYTE>(monMarshaledStream) < (sba.tableau + sba.nbElements); monMarshaledStream = reinterpret_cast<PEFS_MARSHALED_STREAM>(monDataSegment) ) { bool isEFSMetaData = (monMarshaledStream->NameLenght == 2) && (monMarshaledStream->StreamName[0] == 0x1910); wcout << endl << L"Marshaled Stream :" << endl << L" * Length : " << monMarshaledStream->Length << endl << L" * Flag : " << monMarshaledStream->Flag << endl << L" * Name : " << (isEFSMetaData ? wstring(L"(EFS Metadata stream)") : wstring(monMarshaledStream->StreamName, monMarshaledStream->NameLenght / sizeof(wchar_t))) << endl << L" * Type : " << (isEFSMetaData ? L"EFS Metadata" : L"DATA") << endl << endl; for( monDataSegment = reinterpret_cast<PEFS_STREAM_DATA_SEGMENT>(reinterpret_cast<PBYTE>(monMarshaledStream) + monMarshaledStream->Length); (reinterpret_cast<PBYTE>(monDataSegment) < (sba.tableau + sba.nbElements)) && (monDataSegment->GURE0 == 0x00550047) && (monDataSegment->GURE1 == 0x00450052); monDataSegment = reinterpret_cast<PEFS_STREAM_DATA_SEGMENT>(reinterpret_cast<PBYTE>(monDataSegment) + monDataSegment->Length) ) { wcout << L"DataSegment : " << endl; PBYTE StreamData = reinterpret_cast<PBYTE>(monDataSegment) + sizeof(EFS_STREAM_DATA_SEGMENT); if(isEFSMetaData) { wcout << L" EFS Metadata :" << endl; PEFS_METADATA_1 mesAttr = reinterpret_cast<PEFS_METADATA_1>(StreamData); wcout << L" * Version EFS : " << mesAttr->EFS_Version << endl; if(mesAttr->DDF_Offset) { wcout << L" * User(s) reported :" << endl; fullInfosFromEFS_KEY_LIST(mesAttr, mesAttr->DDF_Offset, &Fek); } if(mesAttr->DRF_Offset) { wcout << L" * Agent(s) covering :" << endl; fullInfosFromEFS_KEY_LIST(mesAttr, mesAttr->DRF_Offset, &Fek); } } else { wcout << L" DATA :" << endl; if(!monMarshaledStream->Flag) { wcout << L" DATA Segment Encryption Header :" << endl; PEFS_STREAM_DATA_SEGMENT_ENCRYPTION_HEADER monSegEncHead = reinterpret_cast<PEFS_STREAM_DATA_SEGMENT_ENCRYPTION_HEADER>(StreamData); wcout << L" * Length : " << monSegEncHead->Length << endl << L" * StartingFile_Offset : " << monSegEncHead->StartingFile_Offset << endl << L" * BytesWithinStreamSize : " << monSegEncHead->BytesWithinStreamSize << endl << L" * BytesWithinVDL : " << monSegEncHead->BytesWithinVDL << endl << L" * DataUnitShift : " << monSegEncHead->DataUnitShift << endl << L" * ChunkShift : " << monSegEncHead->ChunkShift << endl << L" * ClusterShift : " << monSegEncHead->ClusterShift << endl << L" * NumberOfDataBlocks : " << monSegEncHead->NumberOfDataBlocks << endl << endl; PEFS_EXTENDED_HEADER monExtHeader = reinterpret_cast<PEFS_EXTENDED_HEADER>(reinterpret_cast<PBYTE>(monSegEncHead) + FIELD_OFFSET(EFS_STREAM_DATA_SEGMENT_ENCRYPTION_HEADER, DataBlockSizes) + (sizeof(DWORD) * monSegEncHead->NumberOfDataBlocks)); if(monExtHeader->EXTD_Number == 'DTXE') { wcout << L" * Extended Header Flag : " << monExtHeader->Flags << endl; } for(DWORD block = 0; block < monSegEncHead->NumberOfDataBlocks; block++) { wcout << L" -> Block " << block+1 << L" ; taille : " << monSegEncHead->DataBlockSizes[block] << endl; PBYTE mesDatas = reinterpret_cast<PBYTE>(StreamData) + monSegEncHead->Length; wcout << mod_text::stringOfHex(mesDatas, monSegEncHead->DataBlockSizes[block], 16) << endl; if(Fek); } } else { wcout << L"TODO Data" << endl; } } } } } else wcout << L"Error ReadEncryptedFileRaw : " << mod_system::getWinError() << endl; free(sba.tableau); CloseEncryptedFileRaw(pvContext); } else wcout << L"Error OpenEncryptedFileRaw : " << mod_system::getWinError() << endl; } return true; }
int send_whole_file(char cmd, const char *fname, const char *datapth, int quick_read, unsigned long long *bytes, struct cntr *cntr, BFILE *bfd, FILE *fp, const char *extrameta, size_t elen) { int ret=0; size_t s=0; MD5_CTX md5; char buf[4096]=""; if(!MD5_Init(&md5)) { logp("MD5_Init() failed\n"); return -1; } if(extrameta) { size_t metalen=0; const char *metadata=NULL; metadata=extrameta; metalen=elen; // Send metadata in chunks, rather than all at once. while(metalen>0) { if(metalen>ZCHUNK) s=ZCHUNK; else s=metalen; if(!MD5_Update(&md5, metadata, s)) { logp("MD5_Update() failed\n"); ret=-1; } if(async_write(CMD_APPEND, metadata, s)) { ret=-1; } metadata+=s; metalen-=s; *bytes+=s; } } else { #ifdef HAVE_WIN32 if(!ret && cmd==CMD_EFS_FILE) { struct winbuf mybuf; mybuf.md5=&md5; mybuf.quick_read=quick_read; mybuf.datapth=datapth; mybuf.cntr=cntr; mybuf.bytes=bytes; // The EFS read function, ReadEncryptedFileRaw(), // works in an annoying way. You have to give it a // function that it calls repeatedly every time the // read buffer is called. // So ReadEncryptedFileRaw() will not return until // it has read the whole file. I have no idea why // they do not have a plain 'read()' function for it. ReadEncryptedFileRaw((PFE_EXPORT_FUNC)write_efs, &mybuf, bfd->pvContext); } if(!ret && cmd!=CMD_EFS_FILE) { while((s=(uint32_t)bread(bfd, buf, 4096))>0) { *bytes+=s; if(!MD5_Update(&md5, buf, s)) { logp("MD5_Update() failed\n"); ret=-1; break; } if(async_write(CMD_APPEND, buf, s)) { ret=-1; break; } if(quick_read) { int qr; if((qr=do_quick_read(datapth, cntr))<0) { ret=-1; break; } if(qr) { // client wants to interrupt break; } } } } #else //printf("send_whole_file: %s\n", fname); if(!ret) while((s=fread(buf, 1, 4096, fp))>0) { *bytes+=s; if(!MD5_Update(&md5, buf, s)) { logp("MD5_Update() failed\n"); ret=-1; break; } if(async_write(CMD_APPEND, buf, s)) { ret=-1; break; } if(quick_read) { int qr; if((qr=do_quick_read(datapth, cntr))<0) { ret=-1; break; } if(qr) { // client wants to interrupt break; } } } #endif } if(!ret) { unsigned char checksum[MD5_DIGEST_LENGTH+1]; if(!MD5_Final(checksum, &md5)) { logp("MD5_Final() failed\n"); return -1; } return write_endfile(*bytes, checksum); } return ret; }