CISP-PTE - Web 安全漏洞

2021-05-13
2021-05-13
14 min read
Hits

  本文是 CISP-PTE 认证 Web 安全漏洞课程的学习笔记。

注入漏洞

SQL 注入

SQL 注入概念

SQL 注入概念请参阅维基百科 SQL注入

SQL 注入漏洞类型

  1. 简单注入(Simple SQL Injection)

    1. 永真式:最后加入 or 1=1 来保证无论如何都能获取数据

    2. 错误语句:让 Web 应用构造错误的 SQL 语句来抛异常,来判断数据库类型

    3. 结束注释:使用注释符注释剩余语句

    4. 联合查询:使用 union all 后面可以写要查询的真正语句

      select username, user_id from users where user_id = 1 and 1=2 union all select username, password from admin_user limit 1
      # 因为前面的条件变成 1 = 2,因此原本的内容会隐藏,而显示新写的内容。最后 limit 1 是因为返回多条数据,可能会出问题(视具体情况,酌情修改)
      
  2. 盲注(Blind SQL injection)

    1’ and length(database())=1     # 显示不存在
    1’ and length(database())=2     # 显示不存在
    1’ and length(database())=3     # 显示存在,判断数据库名长度为 3
    1’ and ascii(substr(databse(),1,1))=100     # 显示存在,判断数据库名第一个字符是 d
    

SQL 注入样例

1' and 1=1     # 判断是否可以被注入
1' or 1=1     # 尝试获取全部账号信息
1' union all select 1, 2     # 判断可以获取的参数数量
1' union all select 1,(@@version)     # 获取数据库版本
1' union all select 1,(database())     # 获取数据库名称
1' union all select 1, group_concat(column_name) from information_schema.columns where table_name='users'     # 获取 user 表所有列名

SQL 注入漏洞安全防护

SQL 注入漏洞的产生原因及防护措施

  1. 链接数据库的用户权限过大、数据库可以运行系统命令
    1. 用最小化权限的账户启动数据库
    2. 禁止让数据库执行系统命令
    3. 使用 IDS,WAF 等监控是否有异常操作
  2. 返回过多的错误信息
    1. 统一管理错误信息
    2. 禁止向用户提供错误信息
  3. 服务器未进行过滤
    1. 过滤所有客户端数据
    2. 审核数据

SQL 注入测试工具

  1. HP Weblnspect available at http://www.hpenterprisesecurity.com
  2. SQLDict available at http://ntsecuritv.nu
  3. HP Scrawlr available at https://h30406.www3.hp.com
  4. SQL Block Monitor available at http://sql-tools.net
  5. Acunetix Web Vulnerability Scanner available at http://www.acunetix.com
  6. GreenSQL Database Security available at http://www.greensql.com
  7. Microsoft Code Analysis Tool .NET (CAT.NET) available at http://www.microsoft.com
  8. NGS SQuirreL Vulnerability Scanners available at http://www.nccgroup.com
  9. WSSA - Web Site Security Scanning Service available at http://www.beyondsecurity.com
  10. N-Stalker Web Application Security Scanner available at http://www.nstalker.com

XML 注入

XML 注入概念

XML 注入类似于 SQL 注入,XML 文件一般用作存储数据及配置,如果在修改或新增数据时,没有对用户可控数据做转义,直接输入或输出数据,都将导致 XML 注入漏洞。

XML 注入样例

<?xml version="1.0" encoding="UTF-8"?>
<USER rule="guest">
<name>user</name>
<passwd>12345</passwd>
</USER>
<USER rule="admin">
<name>admin</name>
<passwd>123456</passwd>
</USER><!---</passwd>
</USER>
<USER role="admin">
<name>admin</name>
<passwd>1adtyr32e762t7te3</passwd>
</USER> 

XML 注入漏洞检测与防护

  对用户输入进行检查,限制输入长度和所包含的字符

  对特殊字符进行转码

& --> &amp;
< --> &lt;
> --> &gt;
" --> &quot;
` --> &#x60;
' --> &#x27;
/ --> &#x2F;

代码注入

远程文件包含漏洞

远程文件包含漏洞的概念

  程序开发人员通常会把可重复使用的函数写到单个文件中,在使用某些函数时,直接调用此文件,而无须再次编写,这种调用文件的过程一般被称为包含

  在通过 PHP 的函数引入文件时,由于传入的文件名没有经过合理的校验,从而操作了预想之外的文件,导致意外的文件泄露甚至恶意代码注入

  如果 PHP 的配置项 allow_url_include 为 ON 的话,则 include/require 函数是可以加载远程文件的,这种漏洞被称为远程文件包含漏洞

远程文件包含漏洞的检测
include()、include_once()、require()、require_once()、fopen()、readfile()     # PHP 常见的导致远程文件包含漏洞的函数
远程文件包含漏洞的安全防护

  不需要执行远程代码时,修改 php.ini 配置

allow_url_fopen = Off
allow_url_include = Off

  执行代码的参数或文件名禁止和用户输入相关,只能由开发人员定义代码内容,用户只能提交“1、2、3”等参数,代表相应代码。

本地文件包含漏洞

本地文件包含漏洞的概念

  与远程文件包含漏洞类似,可以读取任意的本地文件

  可以通过远程文件包含漏洞生成本地文件包含漏洞的代码来利用

  本地文件包含漏洞可以包含本地文件,在条件允许时甚至能执行代码

本地文件包含漏洞的利用

  上传图片马,然后包含

  1. 读敏感文件,读 PHP 文件
  2. 包含日志文件 GetShell
  3. 包含 /proc/self/envion 文件 GetShell
  4. 包含 data: 或 php://input 等伪协议
  5. 有 phpinfo 则可以包含临时文件

命令执行漏洞

  用户通过浏览器提交执行命令,由于服务器端没有针对执行函数做过滤,导致在没有指定绝对路径的情况下就执行命令,可能会允许攻击者通过改变 $PATH 或程序运行环境的其他方面来执行一个恶意构造的代码

PHP 和 JSP 执行系统命令的函数

system()     # 输出并返回最后一行 shell 结果
exec()     # 不输出结果,返回最后一行 shell 结果,所有结果可以保存到一个返回的数组里
passthru()     # 只调用命令,把命令的运行结果原样地直接输出到标准输出设备
Runtime.getRuntime().exec(<commandstr>)     # JSP

Struts2 的 DefaultActionMapper 支持一种方法,可以使用 action:、redirect:、redirectAction:对输入信息进行处理,从而改变前缀参数,这样操作的目的是方便表单中的操作。在 2.3.15.1 版本以前的 struts2 中,没有对 action:、redirect:、redirectAction:等进行处理,导致 ongl 表达式可以被执行。

命令执行漏洞的修复方法

  尽量不要执行外部命令

  尽量使用脚本解决工作,少用执行命令函数,PHP 中禁止 disable_functions

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

  程序参数和参数值用 escapshellcmd 过滤

  参数值尽量使用引号包裹,并在拼接前调用 addslashes 进行转义

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

XSS 漏洞

XSS(cross site script)跨站脚本是一种 Web 应用程序的漏洞,恶意攻击者往 Web 页面里插入恶意 Script 代码,当用户浏览该页之时,嵌入 Web 页面的 Script 代码会被执行,从而达到恶意攻击用户的目的。

XSS 的风险

  1. 盗取用户 cookie,然后伪造用户身份登录,泄漏用户个人身份及订单信息
  2. 操控用户浏览器,借助其他漏洞可能导致对 https 加密信息的破解,导致登录传输存在安全风险
  3. 结合浏览器及其插件漏洞,下载病毒木马到浏览者的计算机上执行
  4. 修改页面内容,产生钓鱼攻击效果,例如伪造登录框获取用户明文账号密码

存储式 XSS

存储式 XSS 的概念

  存储式 XSS,恶意代码是持久的存储在服务器中,当不可信的用户输入被处理,并在没有任何验证的情况下保存在文件或数据库,同时该不可信的数据从存储中被获取,然后在没有编码或转义的情况下反射回响应文中,导致了永久性的每次存储数据反射回响应文,代码就会在浏览器中执行。

存储式 XSS 的检测

由于攻击者输入的恶意数据保存在数据库,再由服务器脚本程序从数据库中读取数据。所以大部分的存储型 XSS 漏洞都是在表单提交上发生。针对这种特性,我们需要做的就是在程序任何有可能提交表单处进行验证。

<script>alert('1')</script>     # 任意可以输入的地方尝试是否会有弹窗
<img src=javascript:alert('1')"></img>
<img dynsrc=javascript:alert('1')"></img>     # 使用 img 标签尝试是否会有弹窗
<DIV STYLE="background-image: url(javascript:alert('1'))">     # 使用 div 标签尝试是否会有弹窗
<img src="knownsec" onerror=alert('1')>     # 构造错误属性尝试是否会有弹窗
<font style="TEST:expression(alert('1'));">     # 自行构造事件尝试是否会有弹窗

存储式 XSS 的安全防范

  浏览器解析顺序

  1. HTML 语言
  2. CSS 语言
  3. JavaScript 语言

  浏览器解码顺序

  1. HTML 编码
  2. URL 编码
  3. JavaScript 编码

  对于 HTML 属性中不可信字符串进行 HTML 转义,为所有属性加上单引号或双引号,不要使用反引号“`”

  除了字母、数字和字符,用格式(或命名实体)转义所有 ASCII 值小于 256 的字符以防止开关的值伸出属性。(不要使用类似的转义符号,因为引号符号可能被 HTML 属性解析器在第一次运行被匹配。这些转义字符也容易受到“转义已转义”的攻击,攻击者发送和漏洞代码转为使得可以成为引号。如果事件触发属性被正确引号,需要通过相应的引号来闭合。不带引号的属性可以被分割为许多字符)

  对于事件触发属性中的不可信字符串,先进行 JavaScript 转义,然后执行 HTML 转义。因为浏览器在执行 JavaScript 字符串解码前会先执行 HTML 属性解码。

  对 HTML 样式属性内的不可信字符串先做 CSS 字符串转义,然后进行 HTML 转义,因为解析器的解析顺序是先 HTML 解析然后再 CSS 解析,并且给所有属性加上引号。

  使用 UTF-8 为默认的字符编码以及设置 content为text/html。

  不要将用户可以控制的文本放在 标签前。通过使用不同的字符集注射可以导致 XSS。

  使用 告诉浏览器遵循标准进行 HTML 和 CSS 的渲染及执行。

反射式 XSS

反射式 XSS 的概念

  反射式 XSS 一般是提交信息的一部分内容通过服务器解析后反馈到浏览器,而不存储到服务器(与存储式 XSS 的不同点)。

  攻击方法一般都是构造了有恶意代码的链接(一般都是可信度高的网站)发送给受害者,受害者点击链接,当 URL 地址被打开时,特定的代码参数会被 HTML 解析并执行,如此就可以获取用户的 COOIKE,进而盗号登陆。

反射式 XSS 的检测

  检测与修复方式与存储行XSS类似,区别仅仅是不能存储到服务端。

DOM 式 XSS

DOM 式 XSS 的特征

  DOM 式 XSS 漏洞不存储于服务器且不需要服务器进行解析,而是利用 js 代码提取了 url 地址中的部分内容(JS 中使用document.location.href代码可以提取 URL 地址)

  触发形式与反射式 XSS 类似,也是需要访问页面。

DOM 式 XSS 的检测与防范

  检测 JS 代码

document.location
document.URL
document.referrer

JS 代码过滤

  1. 写入页面前先转义。在取值写入页面或动态执行的业务场景下,在将各种来源获取到的参数值传入 JavaScript “三姐妹”函数 innerHTML、document.write、eval 处理前,对传入数据中的 HTML 特殊字符进行转义处理能防止大部分 DOM-XSS 的产生。此外,根据不同业务的真实情况,还应使用正则表达式,针对传入的数据做更严格的过滤限制,才能保证万无一失 
  2. 慎用危险的“eval”。需要强调的是,由于 JavaScript 中的 eval 函数十分灵活,能够支持执行的字符串编码纷繁复杂。强烈建议,不到万不得已,不要使用 eval 函数处理不可控的外部数据
  3. 编写安全的函数方法,从看似“可靠”的数据源获取参数值。无论是从 cookie,还是从 localStorage、Referer、Window name、SessionStorage 中获取数据,都应使用安全的函数,对传入的数据做过滤后,再传递给相关函数写入页面或执行。
  4. 参考或使用 filter.js 库。filter.js 由一系列针对常见业务场景下造成 DOM-XSS 的恶意数据开展过滤的函数组成。其中包括 VaildURL、HtmlEncode、HtmlAttributeEncode 等函数方法。在使用过程中,针对上面一部分提到的不同的场景需要,使用与之对应的过滤函数进行验证,才可以从根本上防止 DOM-XSS 产生

请求伪造漏洞

SSRF 漏洞

服务端请求伪造漏洞概念

  一种由攻击者构造形成由服务端发起请求的一个安全漏洞,一般情况下,SSRF 攻击的目标是从外网无法访问的内部系统。

  可以对外网、内网、本地进行端口扫描,某些情况下端口的 Banner 会回显出来(如 3306)

  使用“file:///协议”读取本地文件

  web 应用提供了从其他的服务器上获取数据的功能,使用用户指定的 URL,web 应用可以获取图片、下载文件、读取文件内容等。可以利用存在缺陷的 web 应用作为代理,攻击远程和本地的服务器。当攻击者提供的是一个企业私网 IP 时,服务器可能会访问对应网址当前后把结果返回。如果应用程序对用户提供的 URL 和远端服务器返回的信息没有进行合适的验证和过滤,就可能存在这种服务端请求伪造的缺陷。

服务端请求伪造漏洞的攻击方式

  1. 信息收集
    1. 对外网、服务器所在内网、和本地进行端口扫描,获取一些服务的 banner 信息
    2. 对内网 web 应用进行指纹识别(通过访问默认文件实现)
    3. 利用 file 协议读取本地文件等
  2. 执行指令
    1. 攻击内外网的 web 应用,主要是使用 get 参数就可以实现的攻击(比如 struts2、sqli 等)
    2. 攻击运行在内网或本地的应用程序(比如溢出)

服务端请求伪造漏洞的安全防范

  过滤返回信息,验证远程服务器对请求的响应

  统一错误信息,避免用户可以根据错误信息来判断远端服务器端口的状态

  限制请求的端口为 http 常用的端口,如:80、443、8080、8090

  将内网 IP 假如黑名单,避免应用被用来获取内网数据,攻击内网

  禁用不需要的协议,仅允许 http 和 https 请求

CSRF 漏洞

跨站请求伪造漏洞概念

CSRF(Cross-site request forgery)即跨站请求伪造,是攻击者利用被攻击者的身份发起了某些被攻击者原本不知情的网络请求。

  与其它漏洞不同,CSRF 漏洞需要特定的条件

  1. 受害者必须登陆过网站(或者有权限)
  2. 攻击者(黑客)提供的恶意链接受害者必须打开
  3. 网站除了验证 Cookie,没有特殊验证方法

跨站请求伪造漏洞的原理

  1. 受害者在浏览器正常输入网站 A 进行登陆
  2. 浏览器向网站 A 发送请求
  3. 网站 A 带着会话所需的 Cookie 值告诉浏览器
  4. 浏览器记录了与网站 A 交互时所需的 Cookie
    1. 这之后,所有与网站 A 的交互,不需要登陆
    2. 所有访问网站 A 时浏览器自动带 上Cookie
  5. 黑客向受害者发送一个网站 B 地址诱骗受害者点击
  6. 受害者点击了网站 B
  7. 浏览器向有问题的网站 B 进行访问
  8. 网站 B 返回了带有恶意 JS 语句的内容
  9. 浏览器解析网站 B 内容的时候,运行里面的 JS 语句
    1. 此时,受害者是不知道浏览器运行这些代码的
    2. 解析过程,都会被隐藏,用户根本感受不到有什么问题
    3. JS 会构造请求,请求内容有可能是更改内容,提交订单,进行转账等
  10. 浏览器根据 JS 的请求,使用之前网站 A 的 Cookie 向网站 A 进行请求(此时如果网站 A 只验证 Cookie,就会认为此请求就是来自用户,认为是一个合法请求)

文件处理漏洞

任意文件上传

任意文件上传漏洞的原理与分析

Web 应用程序在处理用户上传的文件操作时,如果用户上传文件的路径、文件名、扩展名成为用户可控数据,就会导致直接上传脚本木马到 web 服务器上,直接控制 web 服务器

  1. 文件上传时检查不严
    1. 没有进行文件格式检查
    2. 在客户端进行了格式检查但很容易绕过
    3. 在服务器端进行了不严格的黑/白名单检查
    4. 忽略大小写(将 .php 改为 .Php 即可绕过检查)
    5. 忽略了 %00 截断符(xxx.php%00.jpg 保存时变成 xxx.php)
    6. 只对文件类型(Content-Type)进行检查
  2. 文件上传后修改文件名时处理不当(允许用户修改文件名后缀)

任意文件上传漏洞的安全防范

  对文件类型进行限制(Content-Type),但很容易被绕过(直接使用 burpsuite 等软件可以更改为允许的类型)

  对文件后缀名进行限制(黑/白名单),可使用 %00 等截断方式,或使用大小写方式绕过黑名单

  单独设置文件服务器的域名且文件上传的目录设置为不可执行,只能静态访问 HTML、图片等

  对于图片处理,使用 resize(或类似)函数来破坏源代码

  使用随机数存储文件

任意文件下载

任意文件下载漏洞的原理与分析

  网站由于业务需求,提供文件查看或下载功能,但对用户查看或下载的文件不做限制,恶意用户可以查看或下载任意敏感文件,如脚本代码、服务及系统配置文件等。还可对获取到的代码进一步代码审计,得到更多可利用漏洞。

任意文件下载漏洞的检测与修复

  检测任意文件下载漏洞

  1. 查找传入文件名的参数:导入文件等参数,如果可以直接输入文件名,就有可能有注入点

    RealPath,FilePath,filepath,Path,path,inputFile,url,urls,Lang,dis,data,readfile,filep,src,menu,META-INF,WEB-INF     # 注意这些参数名
    
  2. 代码中查找漏洞(以 PHP 为例)

    readfile、fopen、file_get_contents     # 有这些代码,就有可能存在任意文件下载漏洞
    

  以 PHP 为例修复任意文件下载漏洞

  1. 过滤“.”,使用户在 url 中不能回溯上级目录
  2. 正则严格判断用户输入参数的格式
  3. php.ini 配置 open_basedir 限定文件访问范围

访问控制漏洞

横向越权

横向越权漏洞的概念

Web 应用程序接收到用户请求,修改某条数据时,没有判断数据的所属人,或者在判断数据所属人时从用户提交的表单参数中获取了 userid,导致攻击者可以自行修改 userid 来修改不属于自己的数据。只要权限验证不是使用 cookie,用户名是以参数方式传递的等等,都有可能发生横向越权漏洞。

横向越权漏洞的检测与防范

  横向越权漏洞,很多时候是业务分析到程序设计时产生的,因此很多时候需要更改程序逻辑。

  用户 ID、用户名等禁止通过参数来传递,直接取 Cookie 里的值。

  私有信息访问时需要验证用户身份,在数据库取数据时,需要验证。

select * from blogs where blog_id = xx     # 原语句
select * from blogs where blog_id = xx and owner = yy     # 修改后

  用户 ID 等使用 MD5 码等难以进行遍历的方式进行混淆。

垂直越权

垂直越权漏洞的概念

  垂直权限攻击又叫做权限提升攻击。其原理是由于 Web 应用没有做权限控制,或仅仅在菜单上做了权限控制,导致恶意用户只要猜测其他管理页面的 URL,就可以访问或控制其他角色拥有的数据或页面,达到权限提升的目的。后台管理页面一般只允许管理员访问,如果普通用户可以访问,就存在向上越权漏洞。

垂直越权漏洞的检测与防范

  在每个页面的加载之前,对每个敏感页面(管理员页面)都进行服务器权限验证,验证时,从 session 获取对应的用户信息,且 session 中用户信息存放在服务端,用户不能修改。

会话管理漏洞

会话劫持

会话劫持漏洞的概念与原理

  会话劫持(Session hijacking)是一种通过获取用户 SESSIONID,使用该 SESSIONID 登录目标账号的攻击方法,此时攻击者实际上是使用了目标账户的有效 Session。会话劫持的第一步是取得一个合法的会话标识来伪装成合法用户。

会话劫持漏洞基本防御方法

  使用 https、http-only 和 secure 来防止 js 获取 Cookie中的 SESSIONID 信息。

会话固定

会话固定漏洞的概念与原理

  会话固定(Session fixation)是一种诱骗受害者使用攻击者指定的会话标识(SESSIONID)的攻击手段,这是攻击者获取合法会话标识的最简单的方法。会话固定也可以看成是会话劫持的一种类型,原因是会话固定的攻击主要目的同样是获得目标用户的合法会话,不过会话固定还可以是强迫受害者使用攻击者设定的一个有效会话,以此来获得用户的敏感信息。

  访问网站时,网站会设置 Cookie 中的 Session,当用户登录后,Cookie 中的 Session 保持不变。只要获取登陆前的 Session 内容,就可以知道登陆后的 Session。

会话固定漏洞基本防御方法

  在用户登录成功后重新创建一个 SESSIONID,登录前的匿名会话强制失效。

  SESSIONID 与浏览器绑定,SESSIONID 与所访问浏览器有变化,就立即重制。

  SESSIONID 与所访问的 IP 绑定,SESSIONID 与所访问 IP 有变化,就立即重制。