1. 拿到敏感文件
打开环境会看到一个弹窗,提示请登录,然后会跳转到登录界面
没有找到注册按钮,随便输入用户密码密码登录后会有提示弹窗:网站建设中!
看到弹窗就觉得这里登录并不是关键,应该有其他的利用点,于是拿
dirsearch扫描一下后台文件
**<font style="color:#FA8C16;">/admin</font>**
|**<font style="color:#FA8C16;">/admin/</font>**
|**<font style="color:#FA8C16;">/admin/?/login</font>**
|**<font style="color:#FA8C16;">/admin/index.ph</font>**
四个页面都提示 **please continue**
**<font style="color:#FA8C16;">/admin/admin.php</font>**
弹窗显示 **you need to log in**
, 然后跳转到 login.php
页面
**<font style="color:#FA8C16;">/image</font>**
**/images**
会跳转到 **/images/**
并返回 403 , 没有任何利用点 .
**<font style="color:#FA8C16;">robots.txt</font>**
发现了两个敏感文件 **hint.php**
和 **Hack.php**
, 分别查看他们 .
**<font style="color:#FA8C16;">hint.php</font>**
给了个提示 , **/etc/nginx/sites-enabled/site.conf**
文件的配置可能有问题 . 该文件应该是 Nginx 的站点核心配置文件之一 .
**<font style="color:#FA8C16;">Hack.php</font>**
访问该文件得到一个空白页面 , 猜测该文件没有直接输出任何语句 .
1.1 可利用的点
**<font style="color:#FA8C16;">/admin/admin.php</font>**
页面
该页面需要登录后才能访问,但是我们没有账号密码,也没有拿到注册界面,所以账号密码登录是不太现实的,同意爆破密码也不太可能,现在最理想的情况是在该站点某个地方泄露了Cookie,我们可以凭借这个Cookie以某个用户身份登录
**<font style="color:#FA8C16;">/etc/nginx/sites-enabled/site.conf</font>**
文件
这个文件是题目中给出的提示,肯定有用。但是现在没有地方去读取这个文件,最常用的文件漏洞有”文件包含”与”任意文件下载(读取)”,但是先要找到这个利用点,
**<font style="color:#FA8C16;">Hack.php</font>**
页面
这是不知道这个页面是干啥用的,不过看着名字肯定有利用点。
整理思路后 , 拿 **BurpSuite**
代理走一遍刚才的流程 .
2. 本地文件包含读取Nginx配置文件
BurpSuite发现一个奇怪的Cookie
在访问的该站点的每一个页面时,都会带有isLogin的Cookie,这没有任何问题,但是isLogin字段的值确实被定义为”0”。
想到Cookie是用来识别用户,维持用户登录状态的,这里”0”可能代表布尔值,因此手动将它改为”isLogin=1“
然后再访问 /admin/admin.php
, 发现我们成功登录到了站点后台 .
2.1 本地文件包含漏洞拿到/etc/nginx/sites-enabled/site.conf
后台看起来有很多选项卡,其实大部分都是假的,即使有几个选项存在页面跳转,也都是指向index.php,没有什么问题。
真正的利用点在于”管理中心”选项卡,在访问它时会有如下这个HTTP请求
- 注意这个参数 :
**file=index?ext=php**
,file
参数值是文件名 ,ext
参数值是文件扩展名 . 那么这里是否存在LFI( 本地文件包含漏洞 ) , 可以包含其他文件呢 ?
2.1.1 ./测试
Payload : **file=./index&ext=php**
提示 **please continue**
.
2.1.2 ../测试
Payload : **file=../index&ext=php**
响应结果与 ./
完全相同 , 看起来 **../**
并没有被解析处理 , 或者说是被过滤掉了 .
2.1.3 ….//测试
既然 **../**
可能被过滤了 , 那么就重叠写为 **....//**
. 这样即使 **../**
被过滤删除 , 剩下的内容也还是 **../**
Payload : **file=....//index&ext=php**
页面内容出现了变化 , 不再出现 please continue
, 这里可能因为过滤检测后 ../index.php
文件不存在 , 而导致站点自动跳转到 ./index.php
主页 .**
因此重写法绕过 **../**
过滤可能是成功的 , 我们继续测试 .
2.1.4 去除ext参数值测试
如果 HTTP 请求中 ext=php
是必须存在且无法更改的 , 那么这里的利用会非常困难 . 因为我们的目标是 /etc/nginx/sites-enabled/site.conf
, 而不是 PHP 文件 .
Payload : **file=index&ext=**
没有出现 please continue
, 因此这里看到的页面可能是因为当前目录下 index
文件不存在而强制跳转到的 index.php
.
2.1.5 去除ext参数值,并在file参数中添加文件扩展名测试
那么如何验证上述 **没有出现 please continue 字符串是因为站点没有找到文件而做的强制跳转**
这个猜想是正确的呢 ?
我们不在 ext
参数字段中添加任何值 , 而是在 file
参数中添加文件扩展名 , 如果出现了 please continue
则表示读取到了文件 .
Payload : **file=index.php&ext=**
出现了 please continue
, 说明读取到了当前目录下的 index.php
. 而前面 Payload : **file=index&ext=**
因为站点没有读到 index
这个文件 , 直接跳转到 index.php
, 因此没有出现 please continue
.
这也说明了我上面所有的猜测都是正确的 . 我们可以利用重写 **../**
来绕过站点的过滤删除机制 .
现在我们可以直接读取到 **/etc/nginx/sites-enabled/site.conf**
.
Payload : **file=....//....//....//....//etc/nginx/sites-enabled/site.conf&ext=**
成功读取到 **/etc/nginx/sites-enabled/site.conf**
配置文件
3. 目录遍历漏洞拿到WebShell
利用上面的本地文件包含漏洞,我们可以读取到所有一直文件名的文件,但是对于那些我们不知道的文件,就没有办法去读取,必须拿到其他的利用点。
查看 /etc/nginx/sites-enabled/site.conf
, 很容易发现其中存在的问题 .
![](https://cdn.nlark.com/yuque/0/2020/png/573149/1586248677469-b6802bfa-d89c-4cf7-bbd8-9d48ed69ab7e.png)
这段代码给 **/web-img**
目录设置了一个别名 **/images/**
, 并且开启了 **autoindex**
.
这里给不熟悉Nginx的同学说下,
alias 用于给 localtion 指定的路径设置别名 , 在路径匹配时 , alias 会把 location 后面配置的路径丢弃掉 , 并把当前匹配到的目录指向到 alias 指定的目录 .
注意 ! alias
会丢弃掉 location
的路径 , 因此 alias
后面的路径是从系统根目录开始的 , 然后直接跟指定的路径 . 它和 root
的用法不一样 . 可以参考这个链接 .
而 **autoindex**
是一个目录浏览功能 , 用于列出当前目录的所有文件及子目录 .
总之 , 这里在 URL 访问 **/web-img**
, 就会访问系统根目录下的 **/images/**
而如果在 URL 访问 **/web-img../**
, 则相当于访问 **/images/../**
, 即访问系统根目录 . 且由于开启了 **autoindex**
, 我们可以直接在浏览器里看到根目录下的所有内容 !
这里就是一个目录遍历漏洞 . 我们可以通过它查看系统中的所有文件~
遍历目录 , 在 /var/www
下能找到 hack.php.bak
这是 hack.php
的自动备份文件 . 点击即可下载到本地 .
打开后发现代码很乱 , 不清楚有什么用 .
但是这玩意怎么看怎么像用 weevely
生成的 WebShell 后门 .
weevely 生成的后门如下
所以猜测这也一个WebShell,只不过经过了加密混淆,我们需要做的就是分析出该后门的构造思路,并且编写连接脚本,以连接这个WebShell
4. 分析后门代码
hack.php.bak
里代码的思路是很简单的 , 先定义多个变量 , 然后通过 str_replace()
函数进行字符替换并拼接 , 接着通过 create_function()
创建了一个匿名函数 , 最后执行该函数 .
str_replace()
函数替换拼接后的代码就是匿名函数$g
的内容 . 因此这里输出$g
, 看看该函数到底在做什么 .
还是很乱 , 需要稍微整理下 , 这里增加了一些注释 .
4.1 先是预定义阶段 , 定义了两个字符串和一个 x()
函数 , 后面会用到
4.2 然后就需要获取攻击者发送的数据了 , 这里攻击代码是通过 Referer
字段传输的
需要注意这个正则函数 preg_match_all()
, 该函数从 Accept-Language
取值 , 然后通过正则匹配后输出到 $m 数组中 . 单独拿出来看 , $m 数组的输出内容是如下这样的 .
$m[0] : 所有可选语言及其权重系数
$m[1] : 所有可选语言的首字母
$m[2] : 所有可选语言的权重值( 不清楚该怎么说 , 反正你能明白 )
简单的说下这个 Accept-Language
( 参考链接 )
举个例子 : Accept-Language: zh-cn,zh;q=0.5
1. Accept-Language表示浏览器所支持的语言类型 .
2. zh-CN 表示简体中文 , zh 表示中文 , 不同语言之间用逗号分割 .
3. q 是权重系数 , 范围为 [0,1] . q 值越大 , 请求越倾向于获得其对应语言表示的内容 . 若没有指定 q 值,则默认为1 . 若被赋值为0 , 则用于提醒服务器该语言是浏览器不接受的内容类型 .
然后拼接了前两种可选语言的首字母 , 和预定义的字符串拼接并进行 md5 校验 , 截取等操作 . 然后赋值给 $h
和 $f
两个变量 .
4.3 拼接payload
循环中的 $p .= $q[$m[2][$z]]
会不断从 $q
中提取数据 . 结合之前的代码 , 攻击代码是放在 Referer
中的( 最后会放在 $q
中 ) , 因此这里可以看作是拼接攻击代码 , 组合成 Payload . ‘
然后判断 $h 是否出现在 Payload 的开头 , 若是则设置 $_SESSION['$i'] = ""
, 同时删除 Payload 的 $h 部分 .
接着判断 $_SESSION
中那个是否存在 $i
这个键名 , 若是则将 Payload 赋值给 $_SESSION[$i]
, 然后查找 $_SESSION[$i]
( 也就是 Payload ) 中 $f
第一次出现的位置 .
4.4 解密并执行payload
紧跟上面的代码 , 若在 Payload 中找到了 $f
第一次出现的位置( 也就是说明 $f
存在于 Payload 中 ) , 就会继续执行如下过程 .
- 生成密钥
**$k**
, 该值由预定义的两个字符串拼接而成 , 然后打开输出控制缓冲区 . - 截取 Payload 中从开头到
**$f**
出现位置的这部分字符串( 由此可以判断**$f**
应该是出现在 Payload 的末尾 , 这里删去 $f ) - 利用
**preg_replace()**
函数 , 正则替换字符串中的 “**_**
“ 和 “**-**
“ 为 “**/**
“ 和 “**+**
“ . - 对替换后的字符串进行
**Base64_decode**
解码操作 - 对解码后的字符串进行循环异或运算( 也就是调用
**x()**
函数 ) - 对计算后的字符串调用
**gzuncompress()**
函数进行解压 . - 通过
**eval()**
执行解压后的字符串 . - 返回输出到缓冲区的内容 , 然后清空并关闭输出缓冲区 .
- 对缓冲区输出的内容通过
**gzcompress()**
函数压缩 , 再通过**x()**
函数循环异或计算 , 最后通过**Base64_encode**
编码并输出 .
整个后门代码的思路应该就是如上这样的 , 攻击者通过 **Referer**
传输攻击代码 , 这段攻击代码的格式应该为 **填充字符串 + 加密混淆后的Payload + 填充字符串**
该后门脚本接收到攻击者传送的数据包 , 先按照一定顺序取出攻击代码 , 然后把前后两侧的填充字符串去除 , 拿到 Payload , 然后对 Payload 进行解密反混淆操作 , 接着通过 **eval()**
执行攻击者指定的命令 , 最后将命令执行结果加密编码呈现给攻击者 .
整体的解密流程还是非常清晰的 , 我们知道了后门是如何处理攻击者发送的恶意数据包 . 但现在我们没有连接脚本 , 无法构造出后门能处理的请求 . 因此这里需要逆向整个解密过程 , 以便构造出请求数据包 .
就这样吧 啥时候能力到了再说