Aggregator
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
S3 Bucket 如何配置才能做到只允许某一个IAM User操作?
聊一聊AssumeRole和Trust Relationship
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 实战指南
CNSS招新题中的一道ROP题
CNSS招新题目中有两道不错的Pwn题,拿来学习一波知识。然而其中有一道是内核ROP,复现了好几天。。还是有点问题,再加上研究生大作业集群来了(完全不能摸鱼,哭唧唧),所以那道内核题能做出来就放博客。
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。
平时注意字典的更新、整理和对实际情况的分析,再进行关联整合。