概述
GNU wget 低于1.18版本均存在任意文件上传/可能还会造成远程代码执行CVE-2016-4971。当提供给wget一个恶意的url时,wget(版本低于1.18)会执行url所指向的webserver返回头中的30x跳转,造成wget会保存攻击者提供的任意远程文件。
验证
环境
webserver 10.0.97.225/192.168.1.148
logserver 10.0.97.243/192.168.1.149
步骤
在webserver上起了个nginx,nginx.conf里配置了一个302跳转,另外还起了一个ftp服务,监听21端口,python -m pyftpdlib -p21 -w
logserver上wget版本信息
在机器(logserver)上使用wget发起对webserver的访问,从debug信息可以看到wget在遇到30x返回码的时候是不做任何验证就去请求FTP了。
ftp的log:
结果
webserver上的/root/.bash_profile文件就被下载到了发起wget请求的logserver上了,而wget本来是想请求下载webserver上的safe-file.txt文件的。
利用场景
Cronjob
在webserver上准备好.wgetrc文件
|
|
假设现在有需求在服务器logserver上cron脚本每分钟去拉webserver的log文件
|
|
通过cron的日志可以看到job被执行了
|
|
这个job是root用户执行的,所以去root家目录下查看是否已经有.wgetrc文件了
这里有点鸡肋的是如果该目录下已经存在.wgetrc文件,那么wget下载回来的.wgetrc文件将被重命名,就没法控制目标的下载行为了。
既然上传了.wgetrc文件,接下来可以再深入点,反弹个shell试试:
在webserver上运行exploit-db提供的exp脚本
|
|
从logserver上发起到webserver的请求,此时webserver上监听的端口开始有回显
|
|
此时,在logserver上已经被写入了cron任务,每分钟执行一次的反弹shell任务
等待一分钟,cronjob执行,反弹shell成功
修复
官方的修复方案为在调用从FTP下载文件的函数时多传了一个原始URL参数,在生成本地文件的文件名时使用了原始的URL所带的文件名,而不是使用跳转后FTP连接中的文件名了。具体修改部分可以从commit上查看到。而我们用户要做的就是升级服务器上GNU wget版本至最新或1.18以上。
总结
我发你一个链接,你敢wget吗?