Aggregator
2.2 Million Users Affected By Latest Data Exposure: 4 Tips to Stay Secure
The digitalization of data allows it to move effortlessly and be accessed from devices and places around the world within...
The post 2.2 Million Users Affected By Latest Data Exposure: 4 Tips to Stay Secure appeared first on McAfee Blog.
漏洞之王:漫谈高阶漏洞攻防演进和现实威胁
Akamai Foundation and Social Responsibility
A simple story of DsSvc, "Live and Die"
Author: k0shl of 360 Vulcan Team
OverviewDsSvc is a data sharing service that provides data sharing between processes. I have not conducted an in-depth analysis of the specific functions of this service. It is known that it provides some methods of file sharing between processes. As shown in the following figure, the process specifies a shared file through DsSvc, and calls CoCreateGuid to create a GUID as a file token, and stores information such as its token and file path into DbTable. Other processes can obtain file objects through this token and perform other files operating.
Data sharing services contain many file operations, which also bring a lot of security issues. Microsoft spent nearly a year to fix the logical issue in this service. The security issue caused by file operations is one of the types of logical vulnerability. Important partitions, it's necessary to be careful when dealing with files' operation, especially for file security attributes. I will analyze the logical vulnerabilities in DsSvc, as well as Microsoft's patch, and bypass. Let's start our story.
The Beginning of story...In November 2018, Microsoft patched a data sharing service vulnerability discovered by SandboxEscaper (PolarBear). SandboxEscaper shared details about this vulnerability on the blog. Since this article on the SandboxEscaper's blog is inaccessible, it is not possible to reference the SandboxEscaper blog address. A description of vulnerability is as follows:
Bug description: RpcDSSMoveFromSharedFile(handle,L"token",L"c:\\blah1\\pci.sys"); This function exposed over alpc, has a arbitrary delete vuln. Hitting the timing was pretty annoying. But my PoC will keep rerunning until c:\windows\system32\drivers\pci.sys is deleted. I believe it’s impossible to hit the timing on a single core VM. I was able to trigger it using 4 cores on my VM. (Sadly I wasn’t able to use OPLOCKS with this particular bug) Root cause is basically just a delete without impersonation because of an early revert to self. Should be straight forward to fix it… Exploitation wise.. you either try to trigger dll hijacking issues in 3rd party software.. or delete temp files used by a system service in c:\windows\temp and hijack them and hopefully do some evil stuff.This is an arbitrary file deletion vulnerability. The vulnerability occurs in the RPC interface RpcDSSMoveFromSharedFile. The issue existed in function PolicyChecker::CheckFilePermission. The code is as follows:
__int64 __fastcall PolicyChecker::CheckFilePermission(const WCHAR *FileName, unsigned int a2, unsigned int a3, int a4, __int64 a5) { [...CreateFile flag check...] [...Impersonate...] v12 = CreateFileW(v5, dwDesiredAccess, dwShareMode, 0i64, 4u, 0x80u, 0i64); [...RevertToSelf...] if ( v12 == (void *)-1i64 ) { [...] } else { v17 = v14; if ( !a5 || (v8 = DSUtils::GetFinalPathFromHandle(v12, a5), (v8 & 0x80000000) == 0) ) { CloseHandle(v12);//Close v12 = (void *)-1i64; if ( v17 ) return v8; DeleteFileW(v5);//arbitrary file deletion } if ( v13 != (void *)-1i64 ) CloseHandle(v13); } return v8; }In this function, FileName is defined by the user. First, the parameters DesiredAccess and ShareMode will be checked. Then RpcImpersonateClient will be called to impersonate client and call CreateFile to open the file. DsSvc will delete the file after RevertToSelf.
Although DsSvc calls ImpersonateClient to open the file, which means that when I try to open a limit file, it will fail and return, but there is still have TOCTOU issue. Before calling CeateFile, you can create a junction to the user-controllable path, so CreateFile will succeed. After that, you can change the junction to a limit directory. It will invoke DeleteFile to delete limit file finally.
In the patch, Microsoft no longer uses DeleteFile but uses the FileDispositionInfo class of SetFileInformationByHandle to delete file. Thus, calling SetFileInformationByHandle refers to the file handle created by CreateFile instead of the file path. The final deletion is a normal file opened after ImpersonateClient.
else { v17 = v14; if ( !a5 || (v8 = DSUtils::GetFinalPathFromHandle(v13, a5), v8 >= 0) ) { if ( !v17 ) { FileInformation = 1; if ( !SetFileInformationByHandle(v13, FileDispositionInfo, &FileInformation, 1u) ) { [...] } } } CloseHandle(v13); My research has started...After this vulnerability was exposed, I started my study on the logic vulnerability. One day, when I was chatting with my friend 0x9k, he talked about the complete full chain of 11 Android logical vulnerabilities used by MWRLab in Pwn2Own. Then I read MWRLab's slide about this full chain exploitation which they talked on CanSecWest.
There is a show in this slide about the tool jandroid that they use when finding android logic vulnerabilities.
After read about jandroid in slide, I came up with the idea that such this method can be used to finding logical vulnerabilities on Windows? The answer is yes.
I think I can assist the subsequent reverse engineering by parsing the path travesal of the sensitive operation on the RPC-related dll. I took some time to implement my idea. (Later in August 2019 Adam Chester published a blog post about his RPC parsing implementation idea)
I used James Forshaw's project NtApiDotNet when writing the parsing code. It can complete pre-working in my parsing framework, there is a class called NdrProcedureDefinition in NtApiDotNet, which plays a key role in RPC interface parsing, it can parse out of the RPC interface of the DCE syntax, I made a few modifications to the NdrProcedureDefinition part of the method, so that it can parse the RPC interface of the Ndr64 syntax, which may resolve more potential attack surfaces in the x64 system. (The figure below shows the analysis result of Chakra.dll which use Ndr64 syntax)
Here are two points to mention.
[+] The first is that almost all RPC dlls in Windows x64 systems use DCE syntax, but also contain a very small number of RPC dlls for Ndr64 syntax, such as Chakra.dll.
[+] And the second is that I am not find the way to parsing incoming parameter of RPC interface of Ndr64 syntax, so I can only parse the RPC interface function without parameters, but this does not affect sensitive operation path travesal parsing.
The following picture shows the logs of some of the path travesals after I run my parsing code. Actually, I found out some interesting path travesals in DsSvc after that time, but James Forshaw report most of them :).
Get down to business
In January 2019, Microsoft patched 5 DsSvc EoP Vulnerabilities reported by James Forshaw , there is a interesting patch in these 5 vulnerabilities which about the MoveFileInheritSecurity function, the vulnerability code is as follows:
__int64 __fastcall PolicyChecker::MoveFileInheritSecurity(const WCHAR *lpNewFileName, const WCHAR *lpExistingFileName) { [...] if ( MoveFileExW(lpNewFileName, lpExistingFileName, 3u) ) { if ( !InitializeAcl(&pAcl, 8u, 2u) ) { LABEL_4: v6 = GetLastError(); goto LABEL_10; } v6 = SetNamedSecurityInfoW(lpExistingFileName, SE_FILE_OBJECT, 0x20000004u, 0i64, 0i64, &pAcl, 0i64); if ( v6 ) MoveFileExW(lpExistingFileName, lpNewFileName, 3u); } [...] }As the code show, DsSvc will set the DACL of the new file through SetNamedSecurityInfoW after the MoveFile. James forshaw create a hardlink to a limit file, and call RpcDSSMoveFromSharedFile interface, the DsSvc get the file path directly, but not check if the file is accessible, it will finally set the limit file's DACL.
Before patch:
__int64 __fastcall DSUtils::VerifyPathRoundTrip(wchar_t *Str2, wchar_t *a2) { [...] v3 = CreateFileW(Str2, 0x80000000, 7u, 0i64, 4u, 0x80u, 0i64); if ( v3 != (HANDLE)-1i64 ) { v2 = v3; LABEL_6: v5 = DSUtils::VerifyPathFromHandle(v1, v2); goto LABEL_7; } [...] }After patch:
__int64 __fastcall DSUtils::VerifyPathRoundTrip(wchar_t *Str2, wchar_t *a2) { [...] v5 = CreateFileW(Str2, 0x80000000, 7u, 0i64, 4u, 0x80u, 0i64); if ( v5 != (HANDLE)-1i64 ) { v4 = v5; LABEL_6: v7 = DSUtils::VerifyPathFromHandle(v3, v4); if ( v7 >= 0 ) v7 = DSUtils::VerifyFileIdFromHandle(v2, v4); goto LABEL_8; } [...] }After patch, function DSUtils::VerifyFileIdFromHandle is added. The function contains a check for the hardlink. The BY_HANDLE_FILE_INFORMATION structure returned by calling the GetFileInformationByHandle function contains the member variable nNumberOfLinks. If it is greater than 1, it indicates that there is a symbolic link, and function will fail and return.
__int64 __fastcall DSUtils::GetFileIdFromHandle(HANDLE hFile, __int64 a2) { [...] if ( GetFileInformationByHandle(v3, &FileInformation) ) goto LABEL_19; [...] LABEL_19: if ( FileInformation.nNumberOfLinks <= 1 ) { v11 = (_WORD *)*v2; v2[1] = *v2; *v11 = 0; } [...] } The story is far from ending...Obviously, Microsoft's patch still have problem. I found that there is still a time window between the end of the check of the symbolic link and the call to the MoveFileInheritSecurity function, which means that there is a TOCTOU vulnerability, I can make a hardlink to limit file after the symbolink check, so that when DsSvc calls the MoveFileInheritSecurity function, it will set the limit file's DACL finally. I later reported this vulnerability to Microsoft.
Microsoft's patch is very simple, they canceled RpcDSSMoveFromSharedFile and RpcDSSMoveToSharedFile two RPC interfaces of DsSvc in Windows 10 rs6 and later.
///After parse DsSvc RPC interface you can find out that ///RpcDSSMoveFromSharedFile and RpcDSSMoveToSharedFile are canceled [uuid("bf4dc912-e52f-4904-8ebe-9317c1bdd497"), version(1.0)] interface intf_bf4dc912_e52f_4904_8ebe_9317c1bdd497 { HRESULT RpcDSSCreateSharedFileToken( handle_t p0, [In] wchar_t[1]* p1, [In] struct Struct_0* p2, [In] /* ENUM16 */ int p3, [In] /* ENUM16 */ int p4, [Out] wchar_t** p5); HRESULT RpcDSSGetSharedFileName( handle_t p0, [In] wchar_t[1]* p1, [Out] wchar_t** p2); HRESULT RpcDSSGetSharingTokenInformation( handle_t p0, [In] wchar_t[1]* p1, [Out] wchar_t** p2, [Out] wchar_t** p3, [Out] /* ENUM16 */ int* p4); HRESULT RpcDSSDelegateSharingToken( handle_t p0, [In] wchar_t[1]* p1, [In] struct Struct_1* p2); HRESULT RpcDSSRemoveSharingToken( handle_t p0, [In] wchar_t[1]* p1); HRESULT RpcDSSOpenSharedFile( handle_t p0, [In] wchar_t[1]* p1, [In] int p2, [Out] long* p3); HRESULT RpcDSSCopyFromSharedFile( handle_t p0, [In] wchar_t[1]* p1, [In] wchar_t[1]* p2); HRESULT RpcDSSRemoveExpiredTokens(); }The old version still exists these two interfaces. In the old version, Microsoft's patch is also very simple. The PolicyChecker::MoveFileInheritSecurity function is directly deleted, and DsSvc use another method for file copy. I will share this method later.
Other attack surfacesIn my RPC parsing log, I noticed another RPC interface, DSSCopyFromSharedFile, which calls the CopyFile function to copy file to a controllable path.
__int64 __fastcall DSSCopyFromSharedFile(const unsigned __int16 *a1, wchar_t *a2) { [...Check File...] if ( !CopyFileW(*(LPCWSTR *)(v10 + 184), v4, 0) ) { [...] } [...] }This vulnerability is very obvious, although DsSvc checked the permissions of the copied target file before CopyFile, I can still use race condition to link the file to the limit file after checking the target file permissions, and finally copy the shared file to limit file. In this function, the shared file can be specified by the user, so it is easy to write the payload into the file under system32.
When I reported this vulnerability, Microsoft did not award bounty for the vulnerability because Microsoft introduced a mitigation for hardlink. Whether normal user have control permission for the target file, if not, the hard link cannot be created, that is, the hardlink cannot be used by normal user in rs6 and WIP.
DsSvc security feature bypassAfter receiving the reply from Microsoft, I made a quick review on the DsSvc service code again and found a very interesting place. In DsSvc, it will protect the folder where the target file is to be operated. Create a lock file to prevent this folder from being mounted to another directory. The function that implements this security feature is DSUtils::DirectoryLock::Lock. The function code is as follows:
__int64 __fastcall DSUtils::DirectoryLock::Lock(signed __int64 this, const unsigned __int16 *a2) { [...] v20 = CreateFileW(v19, 0x80000000, 7u, 0i64, 4u, 0x4000100u, 0i64); [...] }The function calls CreateFile to create the lock file. I found that the lock file inherits the security descriptor of the parent directory, so actually, I have full control on lock file. It means I can delete the lock file after the lock file is created and after that I mount the directory to limit directory(the directory will be empty after I delete file). This way, even if I don't use hardlink, I can finally call CopyFile to copy the payload to a limit file in the limit directory.
The story is still going onMicrosoft finally patched vulnerability I report. In CopyFromSharedFile, Microsoft use a new function DSUtils::CopyFileWithProgress with the following code:
__int64 __fastcall DSUtils::CopyFileWithProgress(BOOL *this, DSUtils *a2, DSUtils *a3, const unsigned __int16 *a4) { DSUtils::OpenFile((const WCHAR *)a2, (const unsigned __int16 *)0x80000000i64, 7u, 0, &hObject); v7 = DSUtils::OpenFile((const WCHAR *)a3, (const unsigned __int16 *)0x80000000i64, 3u, 0, &pbCancel); [...] DSUtils::IsHardLinkFile(pbCancel, &vars0); [...] v8 = DSUtils::GetFinalPathFromHandle(v7, (__int64)&lpData); if ( v8 >= 0 && !CopyFileExW( (LPCWSTR)a2, (LPCWSTR)a3, (LPPROGRESS_ROUTINE)CopyFileProgressRoutine, lpData, (LPBOOL)dwCopyFlags, 0) ) [...] }In the patch, Microsoft not only checks whether the file is hardlink, but also uses CopyFileExW function. This function calls a callback function CopyFileProgressRoutine when copying the file. The callback function will check if the target file path is the same as before the IsHardLinkFile check.
signed __int64 __fastcall CopyFileProgressRoutine(LARGE_INTEGER TotalFileSize, LARGE_INTEGER TotalBytesTransferred, LARGE_INTEGER StreamSize, LARGE_INTEGER StreamBytesTransferred, DWORD dwStreamNumber, DWORD dwCallbackReason, HANDLE hSourceFile, HANDLE hDestinationFile, LPVOID lpData) { [...] v9 = DSUtils::GetFinalPathFromHandle(hDestinationFile, (__int64)&Str2); if ( v9 >= 0 && _wcsicmp((const wchar_t *)lpData, Str2) ) [...] } Is it really over?After I analyze Microsoft's patch, I sent an email to Microsoft to confirm whether they fixed the problem I reported later, that is, the problem about lock file created. At that time, my suggestion was to create a lock file that can not be controlled by normal users. This way the user cannot delete the lock file and mount the current directory to another directory. Microsoft confirmed that it had fixed the previous problem, but they may did not understand my suggestion.
Although Microsoft added multiple checks, it can be found that Microsoft has finished checking the target file when it calls DSUtils::OpenFile to open the file and the callback function CopyFileProgressRoutine compares the file path before and after, so there is a very obvious issue:
If I still have full control over the lock file, I can still bypass the check in another way, James Forshaw's symboliclink-testing-tools introduce a method, this way it mounts the directory to the root directory of the namespace, and then links the named object to other files. This method will cause the file path to be resolved to other file when NT parsing the file path. Instead of setting the symbolic link through the SetFileInformation method, the advantage of this method is that the target file parsed when calling GetFileInformationByHandle is the target file, so the member variable nNumberOfLinks is still 1, you can easily bypass the IsHardlinkFile check.
Therefore, you can link file to other file in this way before OpenFile. After OpenFile, including the GetFinalPathNameByHandle in the callback function, they all will be parsed to the same path. Therefore, the patch is finally bypassed, and the payload file can still be copied to the limit file by CopyFile.
last of the last...Microsoft released a new patch in November 2019. Finally, Microsoft deleted the DirectoryLock function and the MoveFileInheritSecurity function I mentioned earlier, and used a new method DSUtils::OpenFileAlways to open the file and return the file handle which will be used in DSUtils::CopyFileWithProgress, it will opened until the function return. So, when the file is opened, the file no longer can be deleted and the mount point can not be created to other directory. Before CopyFile, the file directory to be copied is parsed by the GetFileInformationByHandle function.
///Instead of file path, DsSvc use file handle as incoming parameter DSUtils::CopyFileWithProgress(v5, (const unsigned __int16 *)hObject, hFile, (void *)v19); { [...] DSUtils::GetFinalPathFromHandle(hObject, (__int64)lpExistingFileName); [...] DSUtils::GetFinalPathFromHandle(hFile, (__int64)lpNewFileName); [...] DSUtils::IsHardLinkFile(hFile, dwCopyFlags, v8); [...] else if ( !CopyFileExW( lpExistingFileName[0], lpNewFileName[0], CopyFileProgressRoutine, v4, (LPBOOL)&dwCopyFlags[1], 0) ) [...] }And also, DsSvc uses ImpersonateClient to make sure the target file is an accessible file.
v6 = AutoImpersonate<1>::ImpersonateClient(&v39); [...] v6 = DSUtils::OpenFileAlways(lpFileName, Str, (unsigned __int64)&hFile); [...] if ( (_DWORD)v39 ) RpcRevertToSelf();Similarly, Microsoft has rewritten the CopyFileProgressRoutine callback function. In the function, DsSvc will compare the source file and target file with the FilePath and the FileID.
signed __int64 __fastcall CopyFileProgressRoutine(LARGE_INTEGER TotalFileSize, LARGE_INTEGER TotalBytesTransferred, LARGE_INTEGER StreamSize, LARGE_INTEGER StreamBytesTransferred, __int64 dwStreamNumber, __int64 dwCallbackReason) { [...] v7 = DSUtils::GetFileIdFromHandle(hFile); [...] v7 = DSUtils::GetFileIdFromHandle((HANDLE)dwStreamNumber); [...] v7 = DSUtils::GetFinalPathFromHandle(hFile, (__int64)&v33); [...] v7 = DSUtils::GetFinalPathFromHandle((HANDLE)dwStreamNumber, (__int64)&v36); [...] if ( (unsigned int)utl::basic_string<unsigned short,utl::char_traits<unsigned short>,utl::allocator<unsigned short>>::compare( dwCallbackReason, &v27) ) [...] if ( (unsigned int)utl::basic_string<unsigned short,utl::char_traits<unsigned short>,utl::allocator<unsigned short>>::compare( dwCallbackReason + 64, &v30) ) [...] if ( (unsigned int)utl::basic_string<unsigned short,utl::char_traits<unsigned short>,utl::allocator<unsigned short>>::compare( dwCallbackReason + 32, &v33) ) [...] if ( (unsigned int)utl::basic_string<unsigned short,utl::char_traits<unsigned short>,utl::allocator<unsigned short>>::compare( dwCallbackReason + 96, &v36) ) [...] }In the old version, MoveFromSharedFile and MoveToSharedFile also use CopyFileWithProgress to move files. The story about DsSvc ends here.
时间攻击
Regional Threat Perspectives, Fall 2019: Middle East
Customer Guidance for the Dopplepaymer Ransomware
Customer Guidance for the Dopplepaymer Ransomware
再谈 ZoomEye:打造世界领先网络空间测绘能力
福利 | 2019京麒国际安全峰会即将开幕
The One Thing You Can't Outsource: Risk
Fake Cozy Bear Group Making DDoS Extortion Demands
In Conversation: Successful Women
被好友嫌弃拉黑?这一招绝地反杀你一定不知道!
来到乙方的这六个月
控制python随机数
起因是看到v2ex有人发了个送E卡的推广 https://www.v2ex.com/t/618739#reply392 里面有说抽奖的方式
1 2 3 4 5 6 import random seed = [第 300 楼的用户 ID] random.seed(seed) print(sorted(random.sample(range(1, 300), 5)))选择第300楼的用户名作为种子,然后抽奖 一般来说,种子确定了,生成的随机数的序列就确定了。 python2 3之间生成序列不同,但是 python2或python3自己的小版本内序列是相同的
那么能否控制中奖楼层呢?
attack第300楼的用户ID是唯一的输入,而这个 ID是可以控制的,可以注册一个用户名,在第300楼回复即可。顺手写了个脚本来爆破可以生成指定中奖楼层的种子的代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 #!/usr/bin/env python # coding: utf-8 # In[5]: import random import string from itertools import product # In[96]: def find(seed, target): random.seed(seed) t = random.sample(range(1,300), 5) c = 0 for i in target: if i in t: c += 1 return c == len(target) # In[100]: count = 1 result = [] asc = string.ascii_letters+string.digits for s in product(asc, repeat=15): count += 1 if not count%100000: print("count: {:,d}".format(count)) s = "".join(s) if find(s, [1,2, 3,4]): # print(s) print(count, s) result.append(s) break # In[95]: print(set(result)) for seed in set(result): random.seed(seed) print(random.sample(range(1,300),5))这是计算密集型,可以多进程,但是我是丢到服务器上跑的,只有一个CPU :) 所以就单进程吧
result秒速爆破出来可以生成包含1,2,3位指定数字的种子
1 # trafbpcszonjeil hpscybwevjuzlkr 生成 1,2,3三十分钟跑到了可以生成包含四位指定随机数的种子 [1,2,3,4]
1 2 3 4 5 6 7 8 9 In [1]: seed = 'aaaaaaaaaaeNWk4' In [2]: import random In [3]: random.seed(seed) In [4]: random.sample(range(1,300),5) Out[4]: [1, 59, 3, 2, 4]ATT&CK 实战指南
WebFuzzing方法和漏洞案例总结
作者:Vulkey_Chen
博客:gh0st.cn
背景之前有幸做过一次线下的议题分享《我的Web应用安全模糊测试之路》,讲解了一些常用的WebFuzzing技巧和案例,该议题得到了很大的回响,很多师傅们也与我进行了交流,但考虑到之前分享过很多思路非常不全面,这里以本篇文章作为一次总结,以实战引出技巧思路(方法)。
我的Web应用安全模糊测试之路议题解读:https://gh0st.cn/archives/2018-07-25/1 (推荐阅读)
实战案例以下分享的案例都是个人在参与项目或私密众测邀请时遇见的真实案例,案例大多基于个人收集和整理的FuzzDict项目(字典库)。
其中涉及的一些漏洞可能无法作为Fuzzing归类,这里也进行了强行的归类,只是想告诉大家漏洞挖掘中思路发散的重要性,个人也觉得比较经典。
注: 漏洞案例进行了脱敏以及细节上的修改。
案例-Add [SQLi注入漏洞]1.获得项目子域:https://xxx.com
2.目录扫描发现/user/目录,二层探测发现/register接口,其意为:“注册”
3.根据返回状态信息去Fuzz用户名、密码参数->结果:uname\pwd
4.对uname参数进行SQL注入测试,简单的逻辑判断存在
5.注入点使用16进制的方式无法注入,SQLmap参数--no-escape即可绕过
[拒绝服务]图片验证码图片验证码DoS(拒绝服务攻击)这个思路很早就出来了,当时的第一想法就是采集样本收集参数,使用搜索引擎寻找存在图片验证码的点:
根据这些点写了个脚本进行半自动的参数收集:
在漏洞挖掘的过程中,经常会抓取图片验证码的请求进行Fuzz:
图片验证码地址:https://xxx/validateCode
Fuzz存在潜藏参数,可控验证码生成大小:
[JSONP]无中生有获得一个敏感信息返回的请求端点:http://xxx/getInfo
使用callback_dict.txt字典进行Fuzz:
成功发现callback这个潜藏参数:
[逻辑漏洞]响应变请求这里同样是获得一个敏感信息返回的请求端点:http://xxx/getInfo
返回的信息如下所示:
{"responseData":{"userid":"user_id","login":"user_name","password":"user_password","mobilenum":"user_mobilephone_number","mobileisbound":"01","email":"user_email_address"}}尝试了一些测试思路都无法发现安全漏洞,于是想到了响应变请求思路。
将响应报文的JSON字段内容转化为HTTP请求的字段内容(BurpSuite插件项目:https://github.com/gh0stkey/JSONandHTTPP):
将相关的信息字段内容替换为测试账号B的信息(例如:login=A -> login=B)
发现无法得到预期的越权漏洞,并尝试分析该网站其他请求接口对应的参数,发现都为大写,将之前的参数转换为大写:
继续Fuzz,结果却出人意料达到了预期:
案例-Update [逻辑漏洞]命名规律修改一个登录系统,跟踪JS文件发现了一些登录后的系统接口,找到其中的注册接口成功注册账户进入个人中心,用户管理处抓到如下请求:
POST URL: https://xxx/getRolesByUserId POST Data: userId=1028返回如下信息:
可以看见这里的信息并不敏感,但根据测试发现userId参数可以进行越权遍历
根据url判断这个请求的意思是根据用户id查看用户的身份,url中的驼峰方法(getRolesByUserId)惊醒了我,根据命名规则结构我将其修改成getUserByUserId,也就是根据用户id获取用户,也就成为了如下请求包。
POST URL: https://xxx/getUserByUserId POST Data: userId=1028成功返回了敏感信息,并通过修改userId可以越权获取其他用户的信息。
[逻辑漏洞]敏感的嗅觉在测一个刚上线的APP时获得这样一条请求:
POST /mvc/h5/jd/mJSFHttpGWP HTTP/1.1 …… param={"userPin":"$Uid$","addressType":0}而这个请求返回的信息较为敏感,返回了个人的一些物理地址信息:
在这里param参数是json格式的,其中"userPin":"$Uid$"引起我注意,敏感的直觉告诉我这里可以进行修改,尝试将$Uid$修改为其他用户的用户名、用户ID,成功越权:
[逻辑漏洞]熟能生巧收到一个项目邀请,全篇就一个后台管理系统。针对这个系统做了一些常规的测试之后除了发现一些 没用的弱口令外(无法登录系统的)没有了其他收获。
分析这个后台管理系统的URL:https://xxx/?m=index,该URL访问解析过来 的是主⻚信息。
尝试对请求参数m的值进行Fuzz,7K+的字典进行Fuzz,一段时间之后收获降临:
获得了一个有用的请求:?m=view,该请求可以直接未授权获取信息:
案例-Delete [逻辑漏洞]Token限制绕过在测业务的密码重置功能,发送密码重置请求,邮箱收到一个重置密码的链接:http://xxx/forget/pwd?userid=123&token=xxxx
这时候尝试删除token请求参数,再访问并成功重置了用户的密码:
[SQLi辅助]参数删除报错挖掘到一处注入,发现是root(DBA)权限:
但这时候,找不到网站绝对路径,寻找网站用户交互的请求http://xxx/xxxsearch?name=123,删除name=123,网站报错获取绝对路径:
成功通过SQLi漏洞进行GetWebshell。
总结核心其实还是在于漏洞挖掘时的心细,一件事情理解透彻之后万物皆可Fuzz。
平时注意字典的更新、整理和对实际情况的分析,再进行关联整合。
你用它上網,我用它進你內網! 中華電信數據機遠端代碼執行漏洞
大家好,我是 Orange! 這次的文章,是我在 DEVCORE CONFERENCE 2019 上所分享的議題,講述如何從中華電信的一個設定疏失,到串出可以掌控數十萬、甚至數百萬台的家用數據機漏洞!
身為 DEVCORE 的研究團隊,我們的工作就是研究最新的攻擊趨勢、挖掘最新的弱點、找出可以影響整個世界的漏洞,回報給廠商避免這些漏洞流至地下黑市被黑帽駭客甚至國家級駭客組織利用,讓這個世界變得更加安全!
把「漏洞研究」當成工作,一直以來是許多資訊安全技術狂熱份子的夢想,但大部分的人只看到發表漏洞、或站上研討會時的光鮮亮麗,沒注意到背後所下的苦工,事實上,「漏洞研究」往往是一個非常樸實無華,且枯燥的過程。
漏洞挖掘並不像 Capture the Flag (CTF),一定存在著漏洞以及一個正確的解法等著你去解出,在題目的限定範圍下,只要根據現有的條件、線索去推敲出題者的意圖,十之八九可以找出問題點。 雖然還是有那種清新、優質、難到靠北的比賽例如 HITCON CTF 或是 Plaid CTF,不過 「找出漏洞」 與 「如何利用漏洞」在本質上已經是兩件不同的事情了!
CTF 很適合有一定程度的人精進自己的能力,但缺點也是如果經常在限制住的小框框內,思路及眼界容易被侷限住,真實世界的攻防往往更複雜、維度也更大! 要在一個成熟、已使用多年,且全世界資安人員都在關注的產品上挖掘出新弱點,可想而知絕對不是簡單的事! 一場 CTF 競賽頂多也就 48 小時,但在無法知道目標是否有漏洞的前提下,你能堅持多久?
在我們上一個研究中,發現了三個知名 SSL VPN 廠商中不用認證的遠端代碼執行漏洞,雖然成果豐碩,但也是花了整個研究組半年的時間(加上後續處理甚至可到一年),甚至在前兩個月完全是零產出、找不到漏洞下持續完成的。 所以對於一個好的漏洞研究人員,除了綜合能力、見識多寡以及能否深度挖掘外,還需要具備能夠獨立思考,以及興趣濃厚到耐得住寂寞等等特質,才有辦法在高難度的挑戰中殺出一條血路!
漏洞研究往往不是一間公司賺錢的項目,卻又是無法不投資的部門,有多少公司能夠允許員工半年、甚至一年去做一件不一定有產出的研究? 更何況是將研究成果無條件的回報廠商只是為了讓世界更加安全? 這也就是我們 DEVCORE 不論在滲透測試或是紅隊演練上比別人來的優秀的緣故,除了平日軍火庫的累積外,當遇到漏洞時,也會想盡辦法將這個漏洞的危害最大化,利用駭客思維、透過各種不同組合利用,將一個低風險漏洞利用到極致,這也才符合真實世界駭客對你的攻擊方式!
故事回到今年初的某天,我們 DEVCORE 的情資中心監控到全台灣有大量的網路地址開著 3097 連接埠,而且有趣的是,這些地址並不是什麼伺服器的地址,而是普通的家用電腦。 一般來說,家用電腦透過數據機連接上網際網路,對外絕不會開放任何服務,就算是數據機的 SSH 及 HTTP 管理介面,也只有內部網路才能訪問到,因此我們懷疑這與 ISP 的配置失誤有關! 我們也成功的在這個連接埠上挖掘出一個不用認證的遠端代碼執行漏洞! 打個比喻,就是駭客已經睡在你家客廳沙發的感覺!
透過這個漏洞我們可以完成:
- 竊聽網路流量,竊取網路身分、PTT 密碼,甚至你的信用卡資料
- 更新劫持、水坑式攻擊、內網中繼攻擊去控制你的電腦甚至個人手機
- 結合紅隊演練去繞過各種開發者的白名單政策
- 更多更多…
而相關的 CVE 漏洞編號為:
相較於以往對家用數據機的攻擊,這次的影響是更嚴重的! 以往就算漏洞再嚴重,只要家用數據機對外不開放任何連接埠,攻擊者也無法利用,但這次的漏洞包含中華電信的配置失誤,導致你家的數據機在網路上裸奔,攻擊者僅僅 「只要知道你的 IP 便可不需任何條件,直接進入你家內網」,而且,由於沒有數據機的控制權,所以這個攻擊一般用戶是無法防禦及修補的!
經過全網 IPv4 的掃瞄,全台灣約有 25 萬台的數據機存在此問題,「代表至少 25 萬個家庭受影響」,不過這個結果只在 「掃描當下有連上網路的數據機才被納入統計」,所以實際受害用戶一定大於這個數字!
而透過網路地址的反查,有高達九成的受害用戶是中華電信的動態 IP,而剩下的一成則包含固定制 IP 及其他電信公司,至於為何會有其他電信公司呢? 我們的理解是中華電信作為台灣最大電信商,所持有的資源以及硬體設施也是其他電信商遠遠不及的,因此在一些比較偏僻的地段可能其他電信商到使用者的最後一哩路也還是中華電信的設備! 由於我們不是廠商,無法得知完整受影響的數據機型號列表,但筆者也是受害者 ╮(╯_╰)╭,所以可以確定最多人使用的中華電信光世代 GPON 數據機 也在受影響範圍內!
(圖片擷自網路)
只是一個配置失誤並不能說是什麼大問題,所以接下來我們希望能在這個服務上挖掘出更嚴重的漏洞! 軟體漏洞的挖掘,根據原始碼、執行檔以及 API 文件的有無可依序分為:
- 黑箱測試
- 灰箱測試
- 白箱測試
在什麼都沒有的的狀況下,只能依靠經驗以及對系統的了解去猜測每個指令背後的實作、並找出漏洞。
黑箱測試3097 連接埠提供了許多跟電信網路相關的指令,推測是中華電信給工程師遠端對數據機進行各種網路設定的除錯介面!
其中,可以透過 HELP 指令列出所有功能,其中我們發現了一個指令叫做 MISC ,看名字感覺就是把一堆不知道怎麼分類的指令歸類在這,而其中一個叫做 SCRIPT 吸引了我們! 它的參數為一個檔案名稱,執行後像是會把檔案當成 Shell Script 來執行,但在無法在遠端機器留下一個可控檔案的前提下,也無法透過這個指令取得任意代碼執行。 不過有趣的是,MISC SCRIPT 這個指令會將 STDERR 給顯示出來,因此可以透過這個特性去完成任意檔案讀取!
在漏洞的利用上,無論是記憶體的利用、或是網路的滲透,不外乎都圍繞著對目標的讀(Read)、 寫(Write) 以及代碼執行(eXecute) 三個權限的取得,現在我們取得了第一個讀的權限,接下來呢?
除錯介面貌似跑在高權限使用者下,所以可以直接透過讀取系統密碼檔得到系統使用者管理登入的密碼雜湊!
透過對 root 使用者密碼雜湊的破解,我們成功的登入數據機 SSH 將「黑箱」轉化成「灰箱」! 雖然現在可以成功控制自己的數據機,但一般家用數據機對外是不會開放 SSH 服務的,為了達到可以「遠端」控制別人的數據機,我們還是得想辦法從 3097 這個服務拿到代碼的執行權限。
整個中華電信的數據機是一個跑在 MIPS 處理器架構上的嵌入式 Linux 系統,而 3097 服務則是由一個在 /usr/bin/omcimain 的二進位檔案來處理,整個檔案大小有將近 5MB,對逆向工程來說並不是一個小數目,但與黑箱測試相較之下,至少有了東西可以分析了真棒!
$ uname -a Linux I-040GW.cht.com.tw 2.6.30.9-5VT #1 PREEMPT Wed Jul 31 15:40:34 CST 2019 [luna SDK V1.8.0] rlx GNU/Linux $ netstat -anp | grep 3097 tcp 0 0 127.0.0.1:3097 0.0.0.0:* LISTEN $ ls -lh /usr/bin/omcimain -rwxr-xr-x 1 root root 4.6M Aug 1 13:40 /usr/bin/omcimain $ file /usr/bin/omcimain ELF 32-bit MSB executable, MIPS, MIPS-I version 1 (SYSV), dynamically linked現在,我們可以透過逆向工程了解每個指令背後的原理及實作了! 不過首先,逆向工程是一個痛苦且煩悶的經過,一個小小的程式可能就包含幾萬、甚至十幾萬行的組合語言代碼,因此這時挖洞的策略就變得很重要! 從功能面來看,感覺會存在命令注入相關的漏洞,因此先以功能實作為出發點開始挖掘!
整個 3097 服務的處理核心其實就是一個多層的 IF-ELSE 選項,每一個小框框對應的一個功能的實作,例如 cli_config_cmdline 就是對應 CONFIG 這條指令,因此我們搭配著 HELP 指令的提示一一往每個功能實作挖掘!
研究了一段時間,並沒有發現到什麼嚴重漏洞 :( 不過我們注意到,當所有指命都匹配失敗時,會進入到了一個 with_fallback 的函數,這個函數的主要目的是把匹配失敗的指令接到 /usr/bin/diag 後繼續執行!
with_fallback 大致邏輯如下,由於當時 Ghidra 尚未出現,所以這份原始碼是從閱讀 MIPS 組合語言慢慢還原回來的! 其中 s1 為輸入的指令,如果指令不在定義好的列表內以及指令中出現問號的話,就與 /usr/bin/diag 拼湊起來丟入 system 執行! 理所當然,為了防止命令注入等相關弱點,在丟入 system 前會先根據 BLACKLISTS 的列表檢查是否存在有害字元。
char *input = util_trim(s1); if (input[0] == '\0' || input[0] == '#') return 0; while (SUB_COMMAND_LIST[i] != 0) { sub_cmd = SUB_COMMAND_LIST[i++]; if (strncmp(input, sub_cmd, strlen(sub_cmd)) == 0) break; } if (SUB_COMMAND_LIST[i] == 0 && strchr(input, '?') == 0) return -10; // ... while (BLACKLISTS[i] != 0) { if (strchr(input, BLACKLISTS[i]) != 0) { util_fdprintf(fd, "invalid char '%c' in command\n", BLACKLISTS[i]); return -1; } i++; } snprintf(file_buf, 64, "/tmp/tmpfile.%d.%06ld", getpid(), random() % 1000000); snprintf(cmd_buf, 1024, "/usr/bin/diag %s > %s 2>/dev/null", input, file_buf); system(cmd_buf);而 BLACKLISTS 定義如下:
char *BLACKLISTS = "|<>(){}`;";如果是你的話,能想到如何繞過嗎?
答案很簡單,命令注入往往就是這麼的簡單且樸實無華!
這裡我們示範了如何從 PTT 知道受害者 IP 地址,到進入它數據機實現真正意義上的「指哪打哪」!
故事到這邊差不多進入尾聲,整篇文章看似輕描淡寫,描述一個漏洞從發現到利用的整個經過,從結果論來說也許只是一個簡單的命令注入,但實際上中間所花的時間、走過的歪路是正在讀文章的你無法想像的,就像是在黑暗中走迷宮,在沒有走出迷宮前永遠不會知道自己正在走的這條路是不是通往目的正確道路!
挖掘出新的漏洞,並不是一件容易的事,尤其是在各式攻擊手法又已趨於成熟的今天,要想出全新的攻擊手法更是難上加難! 在漏洞研究的領域上,台灣尚未擁有足夠的能量,如果平常的挑戰已經滿足不了你,想體驗真實世界的攻防,歡迎加入與我們一起交流蕉流 :D
- 2019 年 07 月 28 日 - 透過 TWCERT/CC 回報中華電信
- 2019 年 08 月 14 日 - 廠商回覆清查並修補設備中
- 2019 年 08 月 27 日 - 廠商回覆九月初修補完畢
- 2019 年 08 月 30 日 - 廠商回覆已完成受影響設備的韌體更新
- 2019 年 09 月 11 日 - 廠商回覆部分用戶需派員更新, 延後公開時間
- 2019 年 09 月 23 日 - 與 TWCERT/CC 確認可公開
- 2019 年 09 月 25 日 - 發表至 DEVCORE CONFERENCE 2019
- 2019 年 11 月 11 日 - 部落格文章釋出