1. 在项目管理界面发现漏洞
- 这里直接把页面源码给你了,可以看到page参数是必不可少的
- 第二段代码是重点
这段代码的功能是通过POST方法上传文件,用户需要制定文件内容与文件名,系统分别接受这两个参数,对文件名后缀进行正则匹配,会将文件上传到./uploaded/backup/这个目录中
重点是这个正则表,**/.+\.ph(p[3457]?|t|tml)$/i**
, 这个过滤机制看上去是比较严格的 , 但是因为采用黑名单过滤 , 很大程度上存在被绕过的可能
并且想要执行上面这段代码 , 需要有一个名为**admin**
的session , 这个session怎么获得现在还不知道
不过可以猜到 , 利用这个文件上传功能可以上传WebShell.
- 第三段代码展示了如何获得
admin
这个session
从URL中获取一个id参数,这个id参数要满足不为’1’,且最后一位为’9’。当通过这个判断后,将其带入数据库操作,如果返回的结果不为空,那么将会设置
**$_SESSION['admin'] = True**
.
这里利用了数据库操作,第一反应就是SQL注入,但是代码中使用了mysql_real_escap_string()函数,该函数用于转义SQL语句中使用的字符串中的特殊字符,防御SQL注入,虽然key利用宽字节注入绕过这个防御机制,但是要求目标站点使用GBK编码,但是这些细节信息我都不知,所以想要注入还是比较难的。
再看看代码,发现只要有返回信息就能到session,那么是否可以不采用sql注入,让数据库完成一次有返回值的查询就可以了呢?
代码中哪个floatval()其实给了足够的提示,floatval()函数用获取变量中的浮点值,并且与’1’进行比较,注意这里比较采用的是!==,PHP若类型比较(松散比较)出国很多安全问题,这样使用严格比较,严格比较会比较两者的数据类型,所以这里flatval($——GET[id])!==’1’是恒成立的,请看下图
并且floatval()在碰到特殊字符时,会剪短后面的部分(比如空格),比如这里输入1 2,flaotval()只会返回float(1)
2. 获得$_SESSION[‘admin’]=True
前面已经找到了如何绕过判断,为了满足要求,这里构造id字段为’1 9’,并且空格在带入数据库时会被截断,所以成功返回id=1的用户信息,有因为存在返回信息,所以成功获得session
- Payload :
**?page=flag.php&id=1%209**
3. 上传webshell
拿到了Session,下面就可以上传文件了
文件最终被传到/uploaded/backup/,这个目录是可以直接访问的。
为什么会传到这个目录呢?
上传路径原本在根目录下的/backup/目录下面,由于加了个chdir()函数,因此将根目录后面加上了/uploaded/目录,然后在跟/backup/目录。那么如何访问上传的文件已经不再是问题,需要做的仅仅是突破这个正则过滤,正则对文件后缀进限制,所以关键点还是在文件名后缀上
入伙突破文件名后缀的限制?主要思路有如下三种
- 一种是Web中间件的解析漏洞,因为已经知道了中间件是Apache2,使用的是php,所以无非就是Apache解析漏洞或者PHP CGI解析漏洞
- 一种是上传.htaccess文件,该文件是Apache的一大特殊,其中一个功能便是修改不同的MIME类型文件使用的解析器,但是使用该功能需要Apache在配置文件中设置 AllowOverrideAll,并且开启Rewrite模块,经过测试发现上传的.htaccess无法生效
# 举个例子 : 上传 .htaccess 文件 , 其中写入如下内容
<FilesMatch "shell.jpg">
SetHandler application/x-httpd-php
</FilesMatch>
# 此时 , shell.jpg 会被解析为PHP文件
# 但是经过测试这里 .htaccess 功能被禁用了
- 罕见文件后缀,想要解析PHP文件,并非后缀要是*.php,如果查看mime.types,会发现很多文件后缀名都使用了
application/x-httpd-php
这个解析器
其中Phps和php3p都是源代码文件,无法被执行,而上下的所有的后缀名都被正则表过滤,所以这种方式也无法成功上传可执行文件
所以最后还是回到了中间件解析漏洞上,但是经过测试发现这并不是一个常规的解析漏洞,而是利用了一个Linux的目录u结构特性,请看下面代码
创建了一个目录为1.php,在1.php下创建了一个子目录为2.php,Linux下每创建一个新目录都会再其中自动创建两个隐藏文件
其中.. :代表的是目录的父目录
. :代表的是当前目录。
**./1.php/2.php/..**
代表访问 **2.php**
的父目录 , 也就是访问 **1.php**
. 这个点我以前都没有注意过
因此在这里构造数据包时,可以构造如下POST数据
Payload : **con=<?php @eval($_POST[cmd]);?>&file=test.php/1.php/..**
将一句话木马写入**test.php**
, 而上传的文件名也成功绕过正则表的限制
4. 成功上传webshell
4.另一种绕过方式
正则的话是判断.之后的字符,因此我们可以利用‘/.’的方式绕过,这个方式的意思是在文件名目录下在加个空目录,相当于没加,因此达到绕过正则的目的。
5.总结
这题其实也不算难 , 思路还算清晰 . 我在如何构造文件名绕过正则表过滤上花费了很长时间 , 因为一直想着利用解析漏洞等 … 这种访问子目录的父目录的方式真的学到了!