11.远程代码执行漏洞

命令执行和代码执行漏洞
1.命令执行漏洞
1.1

PHP中常见命令执行函数

1.2

命令执行漏洞防御

2.代码执行漏洞
2.1

PHP中代码执行函数

2.2

代码执行漏洞防御

1.命令执行漏洞

命令执行直接调用操作系统命令。其原理是,在操作系统中,“&、|、||”都可以作为命令连接符使用,用户通过浏览器提交执行命令,由于服务器端没有针对执行函数做过滤,将用户的输入作为系统命令的参数拼接到命令行中,在没有过滤用户输入的情况下,造成命令执行漏洞。

command1&command2    两个命令同时执行

command1&&command2   只有前面命令执行成功,后面命令才继续执行

command1;command2    不管前面命令执行成功没有,后面的命令继续执行

command1||command2    顺序执行多条命令,当碰到执行正确的命令后将不执行后面的命令

1.1PHP中常见的命令执行函数

1.system():执行一个外部的应用程序的输入并显示输出的结果
2.exec():执行一个外部的应用程序,但不显示输出的结果
3.passthru():执行一个系统命令并显示原始的输出
4.shell_exec():执行shell命令并返回输出的结果的字符串
5. `` :与shell_exec函数的功能相同
6.popen()
7.proc_open()
8.pcntl_exec():需要开启pcntl扩展

1.2命令执行漏洞防御:

1.进入命令执行的函数或者方法之前,对参数进行过滤
2.参数的值尽量用引号包裹(单引号变量不解析),并在拼接前调用addslashes进行转义
3.禁止能执行系统命令的含食宿,可在php的配置文件中设置 disable_functions

2.代码执行漏洞

应用程序在调用一些能够将字符串转换为代码的函数(如PHP中的eval(),eval可以将字符串当做函数进行执行)时,没有考虑用户是否控制这个字符串,将造成代码执行漏洞。一般很难通过黑盒查找漏洞,大部分都是根据源代码判断代码执行漏洞。

2.1PHP中代码执行函数

1.eval():将字符串当做函数进行执行(需要传入一个完整的语句),执行后会输出一个hello
2.assert():判断是否为字符串,是则当成代码执行。php官方在php7中更改了assert函数。在php7.0.29之后的版本不支持动态调用。

7.0之后的demo:

3.call_user_func():回调函数,可以使用is_callable查看是否可以进行调用
4.call_user_fuc_array():回调函数,参数为数组
5.create_function():创建匿名函数
5.preg_replace():当php版本小于7时,当为 /e 时代码会执行
6.array_map():为数组的每个元素应用回调函数
7.array_filter():依次将 array 数组中的每个值传递到 callback 函数。如果 callback 函数返回 true,则 array 数组的当前值会被包含,在返回的结果数组中。数组的键名保留不变。

8.usort():使用自定义函数对数组进行排序

9.${}:中间的php代码将会被解析

一句话木马就是利用的代码执行漏洞:

<?php @eval($_POST[x]);?>

2.2代码执行漏洞防御

1.保证用户不能轻易接触 eval()函数 的参数或者用正则严格判断输入的数据格式
2.字符串使用单引号包裹,并在插入前进行 addslashes()
3.对preg_replace()放弃使用e修饰符,保证第二个参数中对于正则匹配出的对象,用单引号包裹

12.CORS跨域资源共享漏洞

CORS跨域资源共享漏洞
1.CORS跨域资源共享
1.1

简答跨域请求

1.2

非简单请求

2.CORS安全问题

1.CORS跨域资源共享

跨域资源共享(CORS)是一种放宽同源策略的机制,它允许浏览器向跨源服务器,发出XMLHttpRequset请求,从而克服了AJAX只能同源使用的限制,以使用不同的网站可以跨域获取数据。

这里先简述一下CORS跨域资源的过程:

CORS定义了两种跨域请求:简单请求和非简单请求。

(1)简单的跨域请求就是使用设定的请求方式请求数据。
(2)非简单的跨域请求则是在使用设定的请求方式请求数据之前,先发送一个OPTIONS预检请求,验证请求源是否为服务端允许源,只有“预检”通过之后才会发送一次请求用于数据传输。

当我们需要发送一个跨域请求的时候,浏览器会首先检查这个请求,如果它是简单跨域请求,浏览器就会立刻发送这个请求,如果它不是简单跨域请求,这时候浏览器不会马上发送这个请求,而是有一个服务器预检验证的过程。

1.1简单跨域请求

Contenet-Type:application/x-www-form-urlencoded 
multipart/form-data text/plain

只有同时满足以上两个条件,才是简答请求,否则为非简单请求。

浏览器判断该请求为简单请求时,会在Request Header中添加Origin字段,它表示我们的请求源
如下简单请求头:

Request Headers
Origin:http://192.168.0.1 # Origin字段
Referer:http://192.168.0.1/html
User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36
(KHTML, like Gecko)Chrome/69.0.3497 Safair/537.36

CORS服务端会将该字段作为跨源标志。CORS接收到此次请求后,首先会判断Origin是否在允许源(由服务器决定)范围之内。

如果Orgin指定的源在许可范围之内,即验证通过,服务端会在Response Header添加下面几个字段:

Access-Control-Allow-Origin:该字段是必须的。它的值要么是请求时Origin字段的值,要么是一个*,表示接受任意域名的请求。

Acceess-Control-Allow-Credentials:该字段可选,它是一个布尔值,表示是否允许发送Cookie,默认情况下,Cookie不包括在CORS请求之中,当设置为True时,即表示服务器明确许可,Cookie可以包含在请求之中,一起发送给服务器。这个值也只能设定为true,如果服务器不要浏览器发送Cookie,删除该字段即可。

Access-Control-Expose-Headers:该字段可选,CORS请求时,XMLHttpRequest对象的getReponseHeader()方法只能拿到6个基本字段:

Cache-Control
Content-Language
Content_Type
Expires
Last-Modified
Pragma

如果想拿到其他字段,就必须在Access-Control-Expose-Headers里面指定。
如下:CROS服务端的回应:

Response Headers
Accept-Ranges:bytes
Access-Control-Allow-Origin:http://192.168.0.1 
Content-Length:4
Content-Type:text/plain
Date:Thu, 17 Jan 2021 09:42:36 GMT
Server:Apache/2.4.23(Win32) OpenSSL/1.0.2j PHP/5.4.45

如果Origin置顶的源不在许可范围内,即验证失败,服务器也会也会返回一个正常的HTTP回应。浏览器发现,这个回应的头信息Access-Control-Allow-Origin字段不包含访问源,就知道出错了,从而抛出同源检测异常的错误。注意,这种错误无法通过状态码识别,因为HTTP回应的状态码有可能是200。
截屏2022-03-20 下午8.43.48.png

上面说到,CORS请求默认不发送Cookie和HTTP认证信息。如果要把Cookie发到服务器,一般要服务器同意,指定Access-Control-Allow-Crendentails字段。

Access-Control-Allow-Crendentails:true

另一方面,开发者必须在AJAX请求中打开withCrendentials属性

var xhr = new XMLHttpRequest();
xhr.withCrendentails = true;

否则,即使服务器同意向浏览器发送Cookie,浏览器也不会发送,或者服务器要求Cookie,浏览器也不会处理。

但是,如果省略weithCredentials设置,有的浏览器还是会一起发送Cookie。这时,可以显示关闭withCredentials

xhr.withCrendentails = false;

需要注意的是,如果要发送Cookie,即Access-Control-Allow-Credentials:true时,Access-Control-Allow-Origin就不能设为星号,必须指定明确的,与请求网页一致的域名,同时,Cookie依然遵循同源政策,只有用服务器域名设置的Cookie才会上传,其他域名的Cookie并不会上传,且(跨源)原网页代码中的document.cookie也不无法读取服务器域名下的Cookie。

总结:简单请求只需要CORS服务端在接收到携带Origin字段的跨域请求后,在Response header中添加Access-Control-Allow-Origin等字段给浏览器做同源判断。

1.2非简单请求

非简单请求就是那种对服务器有特殊请求的,比如请求方式是PUT或者DELETE,或者Content-Type字段的类型是application/json。非简单的请求的CORS请求,会在正式通信之前,增加一次OPTIONS方法的预检请求。

浏览器先询问服务器,当前网页所在的域名是否在服务器的许可名单之中,以及可以使用哪些HTTP动词和头信息字段。只有得到肯定答复,浏览器才会发出正式的XMLHttpRequest请求,否则就报错。

下面简单分析一下非简单跨域请求的过程。浏览器先发送一个OPTIONS方法的预检请求。带有如下字段:

1.Origin:在CORS中专门作为Origin信息供后端比对,表面来源域。
2.Access-Control-Requeste-Method:接下来请求的方法
3.Access-Control-Request-Headers:自定义的头部,所有用setRequestHeader方法设置的头部都会以逗号该开的形式包含在这个头部。

然后如果服务器配置了CORS,会返回对应的字段,具体字段含义在返回结果是一并解释。

1.ccess-Control-Allow-Origin:   允许进行跨域请求的域名
2.Access-Control-Allow-Methods:  允许进行跨域请求的方式
3.Access-Control-Allow-Headers:  允许进行跨区请求的头部

如下,OPTIONS预检的请求与响应

然后浏览器再根据服务器的返回值判断是否发送为非简单请求,然后服务器处理完请求之后,再返回结果中加上如下控制字段。

1.Access-Control-Allow-Origin: 允许跨域访问的域,可以是一个域的列表,也可以是通配符"*"。这里要注意Origin规则只对域名有效,并不会对子目录有效。即http://foo.example/subdir/ 是无效的。但是不同子域名需要分开设置,这里的规则可以参照同源策略
2.Access-Control-Allow-Credentials: 是否允许请求带有验证信息
3.Access-Control-Expose-Headers: 允许脚本访问的返回头,请求成功后,脚本可以在XMLHttpRequest中访问这些头的信息
4.Access-Control-Max-Age: 缓存此次请求的秒数。在这个时间范围内,所有同类型的请求都将不再发送预检请求而是直接使用此次返回的头作为判断依据,非常有用,大幅优化请求次数
5.Access-Control-Allow-Methods: 允许使用的请求方法,以逗号隔开
6.Access-Control-Allow-Headers: 允许自定义的头部,以逗号隔开,大小写不敏感

然后浏览器通过返回结果的这些控制字段来决定是将结果开放给客户端脚本读取还是屏蔽掉。如果服务器没有配置CORS,返回结果没有控制字段,浏览器会屏蔽脚本对返回信息的读取,并报出同源检测异常的错误!

通过上面叙述,我们得知借助CORS我们不必关心发出的请求是否跨域,浏览器会帮我们处理这些事情,但是服务端需要支持CORS,服务端实现CORS的原理也很简单,在服务端完全可以对请求做上下文处理,已达到接口允许跨域访问的目的。

当然,也有很多第三方的CORS插件,例如:Spring MVC 在4.2以上版本也支持了CORS配置,这样,服务端也无需自己操心了!

2.CORS的安全问题

CORS非常有用,可以共享许多内容,不过这里存在风险。因为它完全是一个盲目的协议,只是通过HTTP头来控制的。那么,CORS跨域资源共享漏洞是怎么发生的呢?由于程序员配置不当,Origin源不严格,从而造成跨域问题

由以上可知,网站可以通过发送以下HTTP响应头部来启用CORS:

Access-Control-Allow-Origin: https://example.com

这样的话,就可以允许指定的源(http://example.com)来跨域请求服务器端的资源,并且服务器会响应。在默认情况下,发送跨域请求时不会携带cookie或其他凭据。因此,它不能用于窃取与用户相关的敏感信息(如CSRF令牌)。不过,网站服务器可以使用以下头部来启用凭据传输:

Access-Control-Allow-Credentials:true

这样浏览器在请求数据的时候就需要带上cookie。

实现对单个域的信任是非常容易的事情。不过,如果需要信任多个域的话,那该怎么办呢?根据相关规范的建议,只需列出相关的域,并用空格加以分隔即可,例如:

Access-Control-Allow-Origin:http://a.example.com  http://example.com

但是,没有哪个浏览器真正支持这一特性。

于是,我们可以通过使用通配符来信任所有子域,具体方法是:

Access-Control-Allow-Origin:  *.example.com

可是有一些偷懒的程序员,将Access-Control-Allow-Origin设置为允许来自所有域*的跨域请求。

Access-Control-Allow-Origin:*

这样,所有的网站都可以对其进行跨域资源请求了,这是非常危险的。不过先别高兴的太早。其实这里在设计的时候有一个很好的限制。xmlhttprequest发送的请求需要使用 "withCredentials" 来带上Cookie,如果一个目标域设置成了允许任意域的跨域请求,这个请求又带着 Cookie 的话,这个请求是不合法的。(就是如果需要实现带 Cookie 的跨域请求,CORS服务端需要明确的配置允许来源的域,使用任意域的配置是不合法的)浏览器会屏蔽掉返回的结果。Javascript 就没法获取返回的数据了。这是CORS模型最后一道防线。假如没有这个限制的话,那么 Javascript 就可以获取返回数据中的 Cookie 和 CSRF Token,以及各种敏感数据。这个限制极大的降低了CORS的风险。

如下,这是不允许的:

Access-Control-Allow-Origin: *

Access-Control-Allow-Credentials: true

这时,将在浏览器控制台中收到错误消息:当凭证标志为true时,无法在Access-Control-Allow-Origin中使用通配符(各个浏览器报错显示的不一样)。

那么,CORS的漏洞到底出现在哪里呢?

1.CORS服务端的 Access-Control-Allow-Origin 设置为了 *,并且 Access-Control-Allow-Credentials 设置为false,这样任何网站都可以获取该服务端的任何数据了。

2.有一些网站的Access-Control-Allow-Origin他的设置并不是固定的,而是根据用户跨域请求数据的Origin来定的。这时,不管Access-Control-Allow-Credentials 设置为了 true 还是 false。任何网站都可以发起请求,并读取对这些请求的响应。意思就是任何一个网站都可以发送跨域请求来获得CORS服务端上的数据。

下面的代码是通过AJAX来跨域请求获取服务端的数据

 <meta charset="UTF-8">

    <script type="text/javascript">

            var xmlhttp=new XMLHttpRequest();

            var url="http://127.0.0.1/1.txt";   //要跨域访问的资源

            xmlhttp.open("POST",url,true);   

            //xmlhttp.setRequestHeader('X-PINGOTHER','AAAA');   
  //自定义头部,如果这样的话,就属于非简单请求了

            //xmlhttp.setRequestHeader('Content-
  Type','text/xml');   //自定义头部,如果这样的话,就属于非简单请求了

            xmlhttp.send();

            xmlhttp.onreadystatechange=function()

                if (xmlhttp.readyState==4 && xmlhttp.status==200)

                     
  document.getElementById("my").innerHTML=xmlhttp.responseText;

    <button id="btn" onclick="foo()">确定</button>

    <p id="my">hello,word!</p>
最后修改:2022 年 03 月 20 日 09 : 20 PM
如果觉得这篇文章不错,不妨赏我碎银几两。