审计总结

一、PHP弱类型

常见函数

extract()
strcmp()
urldecode()
md5()
ereg()
empty()
isset()
is_numeric()
in_array()
array_search()
switch()
strpos()
比较运算符

二、代码执行漏洞

  • 什么是代码执行漏洞?

答:

字符串转化成代码的函数时,没有考虑到用户是否能控制这个字符串(说白了就是未对用户输入进行过滤或过滤不严),导致用户可以将代码注入到应用中执行才导致代码执行漏洞的产生

  • 代码执行漏洞的相关函数有:eval()、 assert() 、call_user_func_array()、preg_replace() 、call_user_func()等常规函数和动态函数$a($b) (比如$_GET($_POST["xxx"]),这些函数在什么情况下会有代码执行漏洞的危险?

答:

eval() 函数没有对用户数据进行严谨的过滤会导致代码执行漏洞产生

assert() 函数在,用户输入的参数是字符串,它将会被 assert() 当做 PHP 代码来执行

preg_replace() 函数特性的原因,如果pattern 中存在参数e修饰符时,pattern中存在参数e修饰符时,replacement 的值会被当成php代码来执行,会导致代码执行漏洞产生

触发该漏洞前提条件:

第一个参数需要e标识符,有了它可以执行第二个参数的命令

第一个参数需要在第三个参数中的中有匹配,不然echo会返回第三个参数而不执行命令

call_user_func() 函数并不是函数,我们这里统称为一类调用的函数,其余参数是被调用函数的参数,这一类调用函数经常用在框架中动态调用函数,一般都是较大的程序才会使用到这类函数。只要第一个参数 callback 是被调用的函数,其余参数是被调用函数的参数,其实我们有时只需要调用一个,这个一般是开发人员为了方便自己使用和调用静态方法时才会使用,这样就导致了代码执行漏洞的 产生

call_user_func_array()

跟call_user_func 类似

call_user_func(),call_user_func_array() 主要区别,参数格式

     //call_user_func(array($foo, 'test'), [$param, $param1, $param2])
    
     这种格式会把后面数组作为一个参数传递过去
    
 
    
     //call_user_func_array(array($foo, 'test'), [$param, $param1, $param2]) 
    
     这种格式会作为三个参数传递给回调函数,如果存在key ,忽略。

变量函数和普通函数调用(literal function)速度差别不大,和call_user_func相差有一倍以上,而call_user_func_array则要更慢。所以你给的代码才会尽量避免使用call_user_func_array而更倾向于使用变量函数。因为只有很少的函数会有5个以上的参数,所以上面代码里才把1到5个函数的调用用变量函数来写,而只留下小部分的函数用call_user_func_array调用,从而最大的加快程序执行速度.

在类方法参数个数不确定时,还是得使用 call_user_func_array() !

动态函数 例如获取 get 方式传递的变量名为 id 的变量值作为函数名,而变量 $_GET['data'] 则获取 get 方式传递的变量名为 data 的变量值作为函数的参数,这样看似很方便,但实则安全有很大问题

  • PHP代码执行漏洞和 Sql注入、PHP命令注入漏洞的区别是什么?

答:

Sql注入漏洞是将Sql语句注入到后台数据库中进行解析并执行

命令注入漏洞是指注入可以执行的系统命令(如windows中的CMD命令、linux中的Bash命令)并执行

PHP代码执行漏洞是将PHP代码注入到Web应用中通过Web容器执行

  • 针对这个漏洞,应该如何防范?

答:

使用白名单+正则表达式的方式对用户输入进行过滤,

另外:

  • 使用json保存数组,当读取时就不需要使用eval了

  • 对于必须使用eval的地方,一定严格处理用户数据

  • 字符串使用单引号包括可控代码,插入前使用addslashes转义

  • 放弃使用preg_replace的e修饰符,使用preg_replace_callback()替换

  • 若必须使用preg_replace的e修饰符,则必用单引号包裹正则匹配出的对象

三、命令注入漏洞

  • 什么是命令注入漏洞?

答:

由于Web应用程序对用户提交的数据过滤不严格,导致黑客可以通过构造特殊命令字符串的方式,将数据提交至Web应用程序中,并利用该方式执行外部程序或系统命令实施攻击,非法获取数据或者网络资源等

  • 相关函数有:system()、exec()、passthru()、shell_exec()、popen()、proc_open()、pcntl_exec()一共7个函数。这些函数被分为三类,分别在什么情况下会有命令注入漏洞的危险?

答:

第一类漏洞:

可以直接传入命令执行并返回结果,其中system()最简单,不需要输出函数,会自动打印命令执行结果

第二类漏洞:

可以指向进程的管道,该进程由派生给定的 command 命令执行而产生(系统的漏洞造成命令注入)

第三类漏洞

在当前进程空间执行指定程序。当发生错误时返回 FALSE,没有错误时没有返回。(调用的第三方组件存在代码执行漏洞)

  • 针对这个漏洞,应该如何防范?

答:

用白名单对用户输入进行过滤

除此之外这里有几项具体的建议:

  1. 使用自定义函数或函数库来替代外部命令的功能

  2. 使用 escapeshellarg()函数来处理命令参数

  3. 使用 safe_mode_exec_dir 指定可执行文件的路径

四、XSS 漏洞

  • 什么是 XSS 攻击 ?

答:

恶意攻击者往Web页面里插入恶意Script代码,当用户浏览该页之时,嵌入其中Web里面的Script代码会被执行,从而达到恶意攻击用户的目的

  • XSS 攻击被分为两种类型:反射性XSS和存储型XSS,他们之间的区别是什么?

答:

反射型XSS是即时响应,对网站造成的危害不大,且反射型XSS要考虑绕过浏览器的过滤问题,屏蔽性比存储型要差

存储型XSS则需要先把利用代码保存在比如数据库或文件中,当web程序读取利用代码时再输出在页面上执行利用代码,且存储型XSS不用考虑绕过浏览器的过滤问题,屏蔽性也要好很多

  • XSS 漏洞和PHP输出函数密切相关,常见的输出函数有: echo printf print print_r sprintf die var-dump var_export

  • 针对这个漏洞,应该如何防范?

答:

反射型xss漏洞防范

A.PHP直接输出html的,可以采用以下的方法进行过滤:

• 1.htmlspecialchars函数 • 2.htmlentities函数 • 3.HTMLPurifier.auto.php插件 • 4.RemoveXss函数

B.PHP输出到JS代码中,或者开发Json API的,则需要前端在JS中进行过滤:

• 1.尽量使用innerText(IE)和textContent(Firefox),也就是jQuery的text()来输出文本内容 • 2.必须要用innerHTML等等函数,则需要做类似php的htmlspecialchars的过滤

C.其它的通用的补充性防御手段

• 1.在输出html时,加上Content Security Policy的Http Header (作用:可以防止页面被XSS攻击时,嵌入第三方的脚本文件等) (缺陷:IE或低版本的浏览器可能不支持) • 2.在设置Cookie时,加上HttpOnly参数 (作用:可以防止页面被XSS攻击时,Cookie信息被盗取,可兼容至IE6) (缺陷:网站本身的JS代码也无法操作Cookie,而且作用有限,只能保证Cookie的安全) • 3.在开发API时,检验请求的Referer参数 (作用:可以在一定程度上防止CSRF攻击) (缺陷:IE或低版本的浏览器中,Referer参数可以被伪造)

存储型xss漏洞防范

存储型XSS对用户的输入进行过滤的方式和反射型XSS相同

使用htmlspecialchars() 函数 演示:

htmlentities() :把预定义的字符 "<" (小于)和 ">" (大于)转换为 HTML 实体

htmlspecialchars和htmlentities的区别:

htmlspecialchars 只转义 & 、" 、' 、< 、> 这几个html代码,而 htmlentities 却会转化所有的html代码,连同里面的它无法识别的中文字符也会转化

五、CSRF 漏洞

  • 什么是 CSRF 攻击 ?

答:

伪装来自受信任用户的请求来利用受信任的网站

  • CSRF 常和 XSS 混为一谈,其实他们的攻击原理完全不一样,他们之间的区别是什么?(比如XSS必须用到javascript,而CSRF不一定需要)

  • • XSS: XSS漏洞——构造payload——发送给受害人——受害人点击打开——攻击者获取受害人的cookie——攻击者使用受害人cookie完成攻击

    <p>&nbsp; &nbsp; &nbsp; &nbsp;•&nbsp;CSRF: CSRF漏洞——构造payload——发送给受害人——受害人点击打开——受害人执行代码——受害人完成攻击(不知情)</p>
    </li>
    <li>
    <p>针对这个漏洞,应该如何防范?</p>
    </li>
    12345

答:

服务器端防御CSRF攻击主要有四种策略:

  • 验证HTTP Referer 字段

  • 在请求地址中添加token并验证

  • 在HTTP头中自定义属性并验证

  • 添加验证码并验证

六、SQL注入漏洞

  • 什么是 SQL注入漏洞 ?

答:

通过构建特殊的输入作为参数传入Web应用程序,通过执行SQL语句进而执行攻击者所要的操作,其主要原因是程序没有细致地过滤用户输入的数据,致使非法数据侵入系统

  • SQL注入攻击的分类?常见的有哪几种类型?

答:

SQL注入两大分类:

普通SQL注入

编码SQL注入

常见类型:

宽字节注入

报错注入

延时注入

普通注入

  • 针对这个漏洞,应该如何防范?

宽字节注入防御

对于宽字节注入,有如下几种防御方式:

  • 使用mysql_set_charset函数设置连接所使用的字符集,再调用mysql_real_escape_string来过滤用户输入。

  • 将character_set_client设置为binary(二进制)

  • 使用参数化查询、pdo查询

其它的大同小异,就是使用白名单对用户数据进行过滤

七、文件包含漏洞

本地文件包含常用函数

require()
require_once()
include()
include_once()

远程文件包含前置条件

allow_url_include=off
all_url_open=on

常见文件读取函数

fopen()
fiel_get_contents()
fread
fgets
fgetss
file
fpassthru
parse_ini_file
readfile
  • 什么是文件包含漏洞?

答:

开发人员一般希望代码更灵活,所以将被包含的文件设置为变量,用来进行动态调用, 但正是由于这种灵活性,从而导致客户端可以调用一个恶意文件,而我们可以构造这个恶意文件来达到邪恶的目的,造成文件包含漏洞

  • 文件包含漏洞的分类?它们之间的区别是什么?

答:

分为本地文件包含和远程文件包含,两大分类

本地文件包含:包含本地文件,主要出现在模块加载、模板加载和cache调用之处

远程文件包含:包含的文件位于远程服务器上,需要设置allow_url_include = on

  • 文件包含相关函数有: include() require() include_once() require_once(),它们之间的区别是什么?

答:

include():

执行到include时才包含文件,找不到被包含文件时只会产生警告,代码会继续执行

require():

程序开始运行就预先包含文件,找不到被包含的文件时会产生致命错误,并停运行

include_once()和require_once():

功能和上面一样,但文件中代码已被包含则不会再次包含

  • 针对这个漏洞,应该如何防范?

答:

防御主要有两种方法:

  • 采用白名单的方式将允许包含的文件列出来,只允许包含白名单中的文件,这样就可以避免任意文件包含的风险。

  • 采用白名单的方式将文件包含漏洞利用过程中的一些特殊字符定义在黑名单中,对传入的参数进行过滤,但这样有时会因为过滤不全,导致被有经验的攻击者绕过

八、文件上传漏洞

  • 什么是文件上传漏洞?

答:

是指用户上传了一个可执行的脚本文件,并通过此脚本文件获得了执行服务器端命令的能力

  • 文件上传相关函数只有:move_uploaded_file(),在什么情况下会出现文件上传漏洞?

答:

没有限制上传的文件格式,导致可以直接上传危险文件

  • 针对这个漏洞,应该如何防范?

文件上传漏洞防御有以下几种:

1、文件上传的目录设置为不可执行

2、判断文件类型

3、使用随机数改写文件名和文件路径

4、单独设置文件服务器的域名

九、变量覆盖漏洞

常见函数

$$
extract()
parse_str()
import_request_variables()
  • 什么是变量覆盖漏洞?应该怎么利用?

答:

变量覆盖指的是用我们自定义的参数值替换程序原有的变量值,,一般变量覆盖漏洞需要结合程序的其它功能来实现完整的攻击

  • 变量覆盖漏洞相关函数有: :extract(), parse_str()和import_request_variables(),他们在什么情况下会有变量覆盖的危险?

答:

extract()函数

  • 当第二个参数为空或者EXTR_OVERWRITE时,变量注册如果遇到冲突会直接覆盖掉原变量。

  • 当第二个变量为EXTR_IF_EXISTS时,仅当原变量已存在是对其进行更新,否则不注册新变量。

parse_strc()函数

该函数在注册变量之前不会验证当前变量是否已存在,如果存在会直接覆盖

import_request_variables()函数

将 GET/POST/Cookie 变量导入到全局作用域中,import_request_variables()函数函数只能用在 PHP4.1 ~ PHP5.4之间

  • 针对这个漏洞,应该如何防范?

答:

extract()函数防御

将extract.php中extract()函数第二个参数修改为extr_skip:

parse_str()函数防御

parse_str()函数的防范,自己添加判断语句

mport_request_variables()函数防御

此函数是非常危险的函数,在PHP5.5之后已被官方删除!假如你任然在使用低版本的PHP环境,也建议你避免使用此函数

十、身份认证漏洞

  • 什么是身份认证漏洞?

答:

认证的目的是为了认出用户是谁,而授权的目的是为了决定用户能够做什么,身份认证实际上就是一个验证凭证的过程

  • 身份认证最常用的是cookie·session,他们之间的区别是什么?分别对应什么漏洞?

答:

Session是在服务端保存的一个数据结构,用来跟踪用户的状态,这个数据可以保存在集群、数据库、文件中

Cookie是客户端保存用户信息的一种机制,用来记录用户的一些信息,也是实现Session的一种方式

  • 针对这个漏洞,应该如何防范?

答:

漏洞防范

cookie身份认证漏洞防范

单纯的cookie容易被修改,添加session变量对cookie进行验证

session固定漏洞防御

常见的防御方案有如下几种:

  • 1、更改Session名称。PHP中Session的默认名称是PHPSESSID,此变量会保存在Cookie中,如果攻击者不分析站点,就不能猜到Session名称,阻挡部分攻击。

  • 2、关闭透明化Session ID。透明化Session ID指当浏览器中的Http请求没有使用Cookie来存放Session ID时,Session ID则使用URL来传递。

  • 3、设置HttpOnly。通过设置Cookie的HttpOnly为true,可以防止客户端脚本访问这个Cookie。

  • 4、每当用户登陆的时候就进行重置sessionID

  • 5、sessionID闲置过久时,进行重置sessionID

十一、Jsonp劫持

​ 在受到同源规则的限制下(同协议、同域名、同端口),资源不允许跨域访问,但是在实际的使用过程中总有一些地方需要跨域去调用其他域下的资源。

​ 这时候jsonp身为跨域的方法中的一个就孕育而生了,由于html标签中的<script><img><iframe> 这三个标签是允许进行资源的跨域获取的,jsonp就是利用了这三个标签中的其中一个 <script> 利用js代码动态生成script标签然后利用标签中的src属性来进行资源的跨域调用。

​ 利用回调函数'包'住我们的json数据返回

成因

​ 厂商没有对jsonp请求对来源进行校验和过滤导致任意域都能获取到数据

危害

​ 攻击者构造恶意的html页面,利用链接诱导受害者进行点击,从而获取到受害者的敏感信息

利用

本地构造poc来获取用户信息

<!DOCTYPE html>
<html lang='en'>
<head>
    <title>jsonp</title>
</head>
<body>
    jsonp劫持测试
</body>
    <script>
        function 回调函数的名字(data){
            alert(JSON.stringify(data));
        }
    </script> 
    <script src="https://www.xxx.com/api?jsonp=回调函数的名字"></script>    
</html>

src填写出现漏洞的网址

函数名填写回调函数的名字

这个就是我们的回调函数的名字

对应的poc改成如下即可

<!DOCTYPE html>
<html lang='en'>
<head>
    <title>jsonp</title>
</head>
<body>
    jsonp劫持测试
</body>
    <script>
        function jsonp2(data){
            alert(JSON.stringify(data));
        }
    </script> 
    <script src="https://www.xxx.com/api?jsonp=jsonp2"></script>    
</html>

SRC挖掘中只有返回了敏感信息的jsonp劫持才能算是有危害

修复措施

​ 在url中添加不可构造的token或时间戳,使得攻击者无法构造利用。

​ 对请求数据的来源域进行判断和校验。

[实例]网易163 Jsonp劫持

找到一个jsonp的页面

构造对应的poc

<!DOCTYPE html>
<html lang='en'>
<head>
    <meta charset="utf-8">
    <title>jsonp</title>
</head>
<body>
    鱼儿上钩辣
</body>
    <script>
        function jsonp_callback_X675Lgzu(data){
            alert(JSON.stringify(data));
        }
    </script> 
    <script src="https://xxxx.163.com/api/v1/products/a2869674571f77b5a0867c3d71db5856/users/myInfo?&callback=jsonp_callback_X675Lgzu"></script>    
</html>

本地进行访问

1、burp抓包,一般有jsonp的数据传输会在mimetype中显示为script,通过排序可以快速得找到

2、目前挖掘jsonp 一般是F12 寻找callback函数,推荐一款自动检测XSS jsonp的谷歌插件 XssSniper

当然还有其他的可能,字典用Intruder Fuzz一下试试:

    callback=attack

    cb=attack

    call=attack

    jsonp=attack

    jsonpcallback=attack

    jsonpcb=attack

    json=attack

    jsoncallback=attack

    jcb=attack

poc可以继续构造制定发送到自己的页面,可见jsonp的原理与csrf基本为一致的,利用用户的身份来做一些事情,或者发送自己的信息给别人.

绕过

一些对referer 进行验证,但是有的时候空referer可以绕过验证。

十二、CORS跨域资源劫持

0x00 前言

​ 上一篇文章说到了Jsonp跨域劫持,那么自然的CORS跨域劫持也要研究一波,其实cors和jsonp劫持我个人理解为都可以算是csrf的范畴,因为都需要使用受害者的身份信息。

0x01 同源策略

​ 同源策略是互联网通信的基石,要求同协议同域名同端口的网站才能进行资源的获取和共享,正因为有了同源策略才可以防止恶意网站对正常网站的资源获取。

0x02 CORS

​ 在有的地方需要进行跨域进行资源的获取(前后端分离的时候前后端的域名不一样),这时候就需要利用cors来进行资源的获取。

​ CORS也是h5官方支持的跨域获取资源手段之一,但是与Jsonp的动态生成script标签来实现跨域不同,CORS跨域是利用Origin头,说明本次请求的来源域是什么,然后根据相应包中的 Access-Control-Allow-Origin的内容来判断的

0x03 危害

​ CORS跨域资源劫持也是利用了用户的身份信息,构造poc之后利用链接来诱导受害者进行点击,受害者一点击我们的链接,我们就可以利用用户的身份信息来进行信息的获取。

0x04 如何发现

在请求包加上Origin:evil.com 如果返回的Access-Control-Allow-Origin含有evil.com那么就说明存在csrf

构造poc

<html>
    <body onload="cors()">
        </div>
        <script>
            function cors() {
            var xhr = new XMLHttpRequest();
            payload = '1=1';
            xhr.onreadystatechange = function() {
                if (this.readyState == 4 && this.status == 200) {
                document.getElementById("demo").innerHTML = alert(this.responseText);
                }
            };
            xhr.open("POST","https://xxxxxx", true);
            xhr.withCredentials = true;
            xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded");
            xhr.send(payload);
            }
        </script>
    </body>
</html>

成功劫持

0x05 防御手段

​ cors本质是跨域资源共享,但是既然资源要跨域共享那么一定要对资源共享等域进行严格的白名单。

十三、XXE漏洞

XML简介

​ xml全名可扩展标记语言,xml被设计出来的主要目的就是用于传输数据和存储数据(宗旨还是传输数据,和同为标记语言的html不同,html主要的功能是显示数据)

漏洞简介

​ xxe漏洞又名外部实体注入漏洞,漏洞的主要成因是由于xml在传输数据的过程中在引入外部实体数据的过程中没有对外部实体的数据进行一个严格的过滤,从而导致我们攻击者可以引入恶意实体,从而造成任意文件读取、任意代码执行等严重后果

​ xml文件解析依赖于libxml库,但是libxml2.9以前的版本是默认支持外部实体的引用的,所以当服务端对我们传输过去的xml文件的时候,没有对外部实体进行一个判断和过滤就会导致xxe漏洞的产生

常见函数

simplexml_load_string

XML文档结构

dtd用于规范显示效果,dtd中携带了关于自身格式的描述(全名文档类型定义)

​ 简单的xml格式这里就不过多赘述了,因为也比较简单,就是我们上面那个例子一样的标签化语言,我们主要来看一下含有DTD的xml文档格式,我们经常会在xxe的payload中看到<!DOCTYPE xxx [xxx]>这样的格式,这样其实就是DTD,我们在引入外部实体都是利用这个DTD来进行实现的

ENTITY代表一个实体,利用dtd结构来引入实体

<?xml version="1.0" encoding="utf-8"?> 
<!DOCTYPE foo [
    <!ENTITY  xxe SYSTEM "file:///etc/passwd" >
]>
<root><name>&xxe;</name></root>

​ DTD全名文档类型定义,DTD每次都会出现在xml文件的上面,我们可以将DTD理解为对xml文档的约束或者规范(如果没有DTD的声明的话,很多时候xml在不同浏览器上的显示效果都会不一样)

​ 通过 DTD,独立的团体可一致地使用某个标准的 DTD 来交换数据

​ 接下来我们来看一下一个带有DTD的xml文档

<?xml version="1.0"?>
<!DOCTYPE note [
<!ELEMENT note (to,from,heading,body)>
<!ELEMENT to (#PCDATA)>
<!ELEMENT from (#PCDATA)>
<!ELEMENT heading (#PCDATA)>
<!ELEMENT body (#PCDATA)>
]>
<note>
<to>Tove</to>
<from>Jani</from>
<heading>Reminder</heading>
<body>Don't forget me this weekend</body>
</note>

我们主要从第二行开始看

  • !DOCTYPE 定义这个文档时note类型的文档

  • !ELEMENT 定义note有四个元素分别为"to, from,heading,body"

  • 后面这几行就是定义这四个元素为#PCDATA类型

#PCDATA是xml元素类型中的一种。读取文件过程中会对文本进行解析

#CDATA”类型为字符数据(character data)。表示读文件但是不用解析,直接读文件的原始内容

这个类型就代表文本是会被解析器解析的类型。因为是会被解析器解析所以文本中是不允许出现 & < >之类的这种符号的,需要使用 & < > 实体来分别替换它们,否则就会报错

像上面的那个xxe中的DTD引用的是内部的

但是由于xxe的主要问题就是引入了恶意的外部DTD,所以在实战过程中我们通常都是引入外部恶意DTD来实现的,如下:

<!DOCTYPE test [
    <!ENTITY xxe SYSTEM "file:///etc/passwd">
  ]>
<root>&xxe;</root>

这里注意!分号不要漏掉

参考:http://wjlshare.com/archives/1314

十四、SSRF

常见函数

curl()
file_get_contents()
fsockopen/fopen()

十五、URL重定向

Javascript跳转

常见关键字
window.location.href 
self.location 
top.location 
window.navigate #只对IE系列浏览器有效

META标签内跳转

~
<meta http-equiv ... url

header头跳转

常见关键字
header("Location:

十六、PHP反序列化

Session反序列化漏洞

phar伪协议触发反序列化

魔法函数绕过

常见函数

_construct() _destruct()
_call() _callStatic()
_get() _set()
_isset() unset()
_sleep() _wakeup()
_toString() _invoke()
_set_state()
_clone()
_debutinfo()

十七、文件删除漏洞

常见函数

unlink()

Last updated

Was this helpful?