Research / Article

Enter the Dragon(Book), Part 1

Explore STL memory allocators and their security risks, including challenges with integer overflow checks and compiler crashes.

Compiler exploitsbackdoorhidingdefconinfosecioactive labs

See if you can find the backdoor, I’ll post the explanation and details on the flaw soon. // eBookLib.cpp : main project file. // Project requirements // Add/Remove/Query eBooks // One code file (KISS in effect) // // // **** Mostly generated from Visual Studio project templates **** // #define WIN32_LEAN_AND_MEAN #define _WIN32_WINNT 0x501 #include <windows.h> #include <stdio.h> #include <wchar.h> #include <msclrmarshal.h> #using <Microsoft.VisualC.dll> #using <System.dll> #using <System.Core.dll> using namespace System; using namespace System::IO; using namespace System::Threading; using namespace System::Threading::Tasks; using namespace System::Reflection; using namespace System::Diagnostics; using namespace System::Globalization; using namespace System::Collections::Generic; using namespace System::Security::Permissions; using namespace System::Runtime::InteropServices; using namespace System::IO::MemoryMappedFiles; using namespace System::IO; using namespace System::Runtime::CompilerServices; using namespace msclr; using namespace msclr::interop; // // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. // [assembly:AssemblyTitleAttribute(“eBookLib”)]; [assembly:AssemblyDescriptionAttribute(“”)]; [assembly:AssemblyConfigurationAttribute(“”)]; [assembly:AssemblyCompanyAttribute(“Microsoft”)]; [assembly:AssemblyProductAttribute(“eBookLib”)]; [assembly:AssemblyCopyrightAttribute(“Copyright (c) Microsoft 2010”)]; [assembly:AssemblyTrademarkAttribute(“”)]; [assembly:AssemblyCultureAttribute(“”)]; // // Version information for an assembly consists of the following four values: // // Major Version // Minor Version // Build Number // Revision // // You can specify all the value or you can default the Revision and Build Numbers // by using the ‘*’ as shown below: [assembly:AssemblyVersionAttribute(“1.0.*”)]; [assembly:ComVisible(false)]; [assembly:CLSCompliantAttribute(true)]; [assembly:SecurityPermission(SecurityAction::RequestMinimum, UnmanagedCode = true)]; //////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Native structures used from legacy system, // define the disk storage for our ebook, // // The file specified by the constructor is read from and loaded automatically, it is also auto saved when closed. //////////////////////////////////////////////////////////////////////////////////////////////////////////////// enum eBookFlag { NOFLAG = 0, ACTIVE = 1, PENDING_REMOVE = 2 }; typedef struct _eBookAccountingData { // Binary Data, may include nulls char PurchaseOrder[ACCOUNTING_SIZE]; char RecieptData[ACCOUNTING_SIZE]; size_t PurchaseOrderLength; size_t RecieptDataLength; } eBookAccountingData, *PeBookAccountingData; typedef struct _eBookPublicData { wchar_t ISBN[BUFSIZ]; wchar_t MISC[BUFSIZ]; wchar_t ShortName[BUFSIZ]; wchar_t Author[BUFSIZ]; wchar_t LongName[BUFSIZ]; wchar_t PathToFile[MAX_PATH]; int Rating; int SerialNumber; } eBookPublicData, *PeBookPublicData; typedef struct _eBook { eBookFlag Flag; eBookAccountingData Priv; eBookPublicData Pub; } eBook, *PeBook; // define managed analogues for native/serialized types namespace Client { namespace ManagedEbookLib { [System::FlagsAttribute] public enum class ManagedeBookFlag : int { NOFLAG = 0x0, ACTIVE = 0x1, PENDING_REMOVE = 0x2, };

public ref class ManagedEbookPublic { public: __clrcall ManagedEbookPublic() { ISBN = MISC = ShortName = Author = LongName = PathToFile = String::Empty; } Int32 Rating; String^ ISBN; String^ MISC; Int32 SerialNumber; String^ ShortName; String^ Author; String^ LongName; String^ PathToFile; };

public ref class ManagedEbookAccounting { public: __clrcall ManagedEbookAccounting() { PurchaseOrder = gcnew array<Byte>(0); RecieptData = gcnew array<Byte>(0); } array<Byte>^ PurchaseOrder; array<Byte>^ RecieptData; };

public ref class ManagedEbook { public: __clrcall ManagedEbook() { Pub = gcnew ManagedEbookPublic(); Priv = gcnew ManagedEbookAccounting(); } ManagedeBookFlag Flag; ManagedEbookPublic^ Pub; ManagedEbookAccounting^ Priv; array<Byte^>^ BookData; }; } } using namespace Client::ManagedEbookLib; // extend marshal library for native/managed inter-op namespace msclr { namespace interop { template<> inline ManagedEbookAccounting^ marshal_as<ManagedEbookAccounting^, eBookAccountingData> (const eBookAccountingData& Src) { ManagedEbookAccounting^ Dest = gcnew ManagedEbookAccounting;

if(Src.PurchaseOrderLength > 0 && Src.PurchaseOrderLength < sizeof(Src.PurchaseOrder)) { Dest->PurchaseOrder = gcnew array<Byte>((int) Src.PurchaseOrderLength); Marshal::Copy(static_cast<IntPtr>(Src.PurchaseOrder[0]), Dest->PurchaseOrder, 0, (int) Src.PurchaseOrderLength); } if(Src.RecieptDataLength > 0 && Src.RecieptDataLength < sizeof(Src.RecieptData)) { Dest->RecieptData = gcnew array<Byte>((int) Src.RecieptDataLength); Marshal::Copy(static_cast<IntPtr>(Src.RecieptData[0]), Dest->RecieptData, 0, (int) Src.RecieptDataLength); }

return Dest; }; template<> inline ManagedEbookPublic^ marshal_as<ManagedEbookPublic^, eBookPublicData> (const eBookPublicData& Src) { ManagedEbookPublic^ Dest = gcnew ManagedEbookPublic; Dest->Rating = Src.Rating; Dest->ISBN = gcnew String(Src.ISBN); Dest->MISC = gcnew String(Src.MISC); Dest->SerialNumber = Src.SerialNumber; Dest->ShortName = gcnew String(Src.ShortName); Dest->Author = gcnew String(Src.Author); Dest->LongName = gcnew String(Src.LongName); Dest->PathToFile = gcnew String(Src.PathToFile); return Dest; }; template<> inline ManagedEbook^ marshal_as<ManagedEbook^, eBook> (const eBook& Src) { ManagedEbook^ Dest = gcnew ManagedEbook;

Dest->Priv = marshal_as<ManagedEbookAccounting^>(Src.Priv); Dest->Pub = marshal_as<ManagedEbookPublic^>(Src.Pub); Dest->Flag = static_cast<ManagedeBookFlag>(Src.Flag); return Dest; }; } } // Primary user namespace namespace Client { namespace ManagedEbooks { // “Store” is Client::ManagedEbooks::Store() public ref class Store { private: String^ DataStore; List<ManagedEbook^>^ Books; HANDLE hFile; // serialization from disk void __clrcall LoadDB() { Books = gcnew List<ManagedEbook^>(); eBook AeBook; DWORD red = 0; marshal_context^ x = gcnew marshal_context(); hFile = CreateFileW(x->marshal_as<const wchar_t*>(DataStore), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 0, OPEN_ALWAYS, 0, 0);

if(hFile == INVALID_HANDLE_VALUE) return; do { ReadFile(hFile, &AeBook, sizeof(eBook), &red, NULL);

if(red == sizeof(eBook)) Books->Add(marshal_as<ManagedEbook^>(AeBook)); } while(red == sizeof(eBook)); } // scan hay for anything that matches needle bool __clrcall MatchBook(ManagedEbook ^hay, ManagedEbook^ needle) { // check numeric values first if(hay->Pub->Rating != 0 && hay->Pub->Rating == needle->Pub->Rating) return true; if(hay->Pub->SerialNumber != 0 && hay->Pub->SerialNumber == needle->Pub->SerialNumber) return true; // scan each string if(!String::IsNullOrEmpty(hay->Pub->ISBN) && hay->Pub->ISBN->Contains(needle->Pub->ISBN)) return true; if(!String::IsNullOrEmpty(hay->Pub->MISC) && hay->Pub->MISC->Contains(needle->Pub->MISC)) return true; if(!String::IsNullOrEmpty(hay->Pub->ShortName) && hay->Pub->ShortName->Contains(needle->Pub->ShortName)) return true; if(!String::IsNullOrEmpty(hay->Pub->Author) && hay->Pub->Author->Contains(needle->Pub->Author)) return true; if(!String::IsNullOrEmpty(hay->Pub->LongName) && hay->Pub->LongName->Contains(needle->Pub->LongName)) return true; if(!String::IsNullOrEmpty(hay->Pub->PathToFile) && hay->Pub->PathToFile->Contains(needle->Pub->PathToFile)) return true; return false; }

// destructor __clrcall !Store() { Close(); }

// serialization to disk happens here void __clrcall _Close() { if(hFile == INVALID_HANDLE_VALUE) return; SetFilePointer(hFile, 0, NULL, FILE_BEGIN); for each(ManagedEbook^ book in Books) { eBook save; DWORD wrote=0; marshal_context^ x = gcnew marshal_context(); ZeroMemory(&save, sizeof(save)); save.Pub.Rating = book->Pub->Rating; save.Pub.SerialNumber = book->Pub->SerialNumber; save.Flag = static_cast<eBookFlag>(book->Flag); swprintf_s(save.Pub.ISBN, sizeof(save.Pub.ISBN), L”%s”, x->marshal_as<const wchar_t*>(book->Pub->ISBN)); swprintf_s(save.Pub.MISC, sizeof(save.Pub.MISC), L”%s”, x->marshal_as<const wchar_t*>(book->Pub->MISC)); swprintf_s(save.Pub.ShortName, sizeof(save.Pub.ShortName), L”%s”, x->marshal_as<const wchar_t*>(book->Pub->ShortName)); swprintf_s(save.Pub.Author, sizeof(save.Pub.Author), L”%s”, x->marshal_as<const wchar_t*>(book->Pub->Author)); swprintf_s(save.Pub.LongName, sizeof(save.Pub.LongName), L”%s”, x->marshal_as<const wchar_t*>(book->Pub->LongName)); swprintf_s(save.Pub.PathToFile, sizeof(save.Pub.PathToFile), L”%s”, x->marshal_as<const wchar_t*>(book->Pub->PathToFile)); if(book->Priv->PurchaseOrder->Length > 0) { pin_ptr<Byte> pin = &book->Priv->PurchaseOrder[0];

save.Priv.PurchaseOrderLength = min(sizeof(save.Priv.PurchaseOrder), book->Priv->PurchaseOrder->Length); memcpy(save.Priv.PurchaseOrder, pin, save.Priv.PurchaseOrderLength); pin = nullptr; } if(book->Priv->RecieptData->Length > 0) { pin_ptr<Byte> pin = &book->Priv->RecieptData[0];

save.Priv.RecieptDataLength = min(sizeof(save.Priv.RecieptData), book->Priv->RecieptData->Length); memcpy(save.Priv.RecieptData, pin, save.Priv.RecieptDataLength); pin = nullptr; }

WriteFile(hFile, &save, sizeof(save), &wrote, NULL); if(wrote != sizeof(save)) return; } CloseHandle(hFile); hFile = INVALID_HANDLE_VALUE; } protected: // destructor forwards to the disposable interface virtual __clrcall ~Store() { this->!Store(); } public:

// possibly hide this void __clrcall Close() { _Close(); } // constructor __clrcall Store(String^ DataStoreDB) { DataStore = DataStoreDB; LoadDB(); } // add ebook void __clrcall Add(ManagedEbook^ eBook) { Books->Add(eBook); } // remove ebook void __clrcall Remove(ManagedEbook^ eBook) { Books->Remove(eBook); } // get query list List<ManagedEbook^>^ __clrcall Query(ManagedEbook^ eBook) { List<ManagedEbook^>^ rv = gcnew List<ManagedEbook^>(); for each(ManagedEbook^ book in Books) { if(MatchBook(book, eBook)) rv->Add(book); } return rv; } }; } }

Want the research before the news cycle?

Get in touch