说明

最近在看P神之前分析的漏洞的文章,本篇文章就是记录看了P神的贷齐乐系统最新版SQL注入之后的一点体会和收获。

本篇文章主要是要说明的是在PHP中由于对于$_REQUEST的认识不足或者是使用不当而导致的漏洞。目前漏洞类型主要是有两种,对$_REQUEST认识不足从而导致过滤失效,使用不当则指的存在HPP的漏洞从而导致全局WAF失效,这个漏洞也就是在P神文章中所说明的漏洞。

$_REQUEST使用不当绕过WAF

php手册上面对于$_REQUEST的说法是:

由于 $_REQUEST 中的变量通过 GET,POST 和 COOKIE 输入机制传递给脚本文件,因此可以被远程用户篡改而并不可信

这话是什么意思呢?表示的是$_REQUEST是直接从GET,POST 和 COOKIE中取值,不是他们的引用。即使后续GET,POST 和 COOKIE发生了变化,也不会影响$_REQUEST的结果。如下:

1

2

3

4

5foreach ($_REQUEST as $key=>$value) {

$_REQUEST[$key] = md5($value);

}

var_dump($_REQUEST);

var_dump($_GET);

我们访问http://localhost/test/index.php?id=1&uname=spoock&email=1@163.com的结果如下:

可以看到$_REQUEST的结果发生了改变,但是$_GET的结果并没有改变。

漏洞代码

假设如果存在如下的代码:

1

2

3

4

5

6

7

8

9foreach ($_REQUEST as $key=>$value) {

$_REQUEST[$key] = waf($value);

}

if(isset($_POST['submit'])) {

$id = $_POST['id'];

$sql = "select * from user where id=$id";

mysql_query($sql);

//....

}

虽然使用了waf进行过滤,但是waf过滤的是$_REQUEST,在业务代码中使用的是$_POST。这样就导致前面的WAF过滤没有任何的作用,防护完全失效。

这个特性在ripstech中的2017年的题目中就出现过。这种问题我相信一定会存在。

REQUEST导致的HPP漏洞

PHP中的特性

在说明这个漏洞之前,我们先需要了解一下在PHP中的几个小的特性。

php自身在解析请求的时候,如果参数名字中包含空格、.、[这几个字符,会将他们转换成_。测试如下:

php在遇到相同参数时接受的是第二个参数。

通过$_SERVER['REQUEST_URI']方式获得的参数并不会进行转换。如:

基于以上三种PHP的特性,就可能会导致存在HPP漏洞,从而绕过系统防护。

漏洞代码1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45<?php

function dhtmlspecialchars($string){

if (is_array($string)) {

foreach ($string as $key => $val) {

$string[$key] = dhtmlspecialchars($val);

}

}

else {

$string = str_replace(array('&', '"', '', '(', ')'), array('&', '"', '<', '>', '(', ')'), $string);

if (strpos($string, '&#') !== false) {

$string = preg_replace('/&((#(\d{3,5}|x[a-fA-F0-9]{4}));)/', '&\\1', $string);

}

}

return $string;

}

function dowith_sql($str){

$check = preg_match('/select|insert|update|delete|\'|\/\*|\*|\.\.\/|\.\/|union|into|load_file|outfile/is', $str);

if ($check) {

echo "非法字符!";

exit();

}

return $str;

}

// 经过第一个waf处理

foreach ($_REQUEST as $key => $value) {

$_REQUEST[$key] = dowith_sql($value);

}

// 经过第二个WAF处理

$request_uri = explode("?", $_SERVER['REQUEST_URI']);

var_dump($request_uri);

if (isset($request_uri[1])) {

$rewrite_url = explode("&", $request_uri[1]);

foreach ($rewrite_url as $key => $value) {

$_value = explode("=", $value);

if (isset($_value[1])) {

$_REQUEST[$_value[0]] = dhtmlspecialchars(addslashes($_value[1]));

}

}

}

// 业务处理

if (isset($_REQUEST['submit'])) {

$user_id = $_REQUEST['user_id'];

$sql = "select * from users where id=$user_id";

var_dump($sql);

}

第一个WAF,采用了dowith_sql()函数,如果$_REQUEST存在select|insert|update|delete等敏感关键字或者是字符,则直接exit()。如果不存在,则原字符串返回。

第二个WAF,通过$_SERVER['REQUEST_URI']得到请求参数,之后利用explode("&", $request_uri[1])得到每个参数,包括参数名和参数值。对每个参数值采用dhtmlspecialchars()过滤,对字符& " < > ( )都进行了替换。替换完毕之后重新得到_REQUEST。

在最后的业务处理中,通过$_REQUEST获取参数进行处理。

如果能够利用HPP漏洞的原理,在WAF对参数进行过滤时处理的是一个参数,但是在进入到业务中处理的是第二个参数,那么我们就能够绕过WAF了。用一个简单的例子进行说明:

1

2

3

4

5

6

7

8

9

10

11

12

13// test.php

var_dump($_REQUEST);

$request_uri = explode("?", $_SERVER['REQUEST_URI']);

if (isset($request_uri[1])) {

$rewrite_url = explode("&", $request_uri[1]);

foreach ($rewrite_url as $key => $value) {

$_value = explode("=", $value);

if (isset($_value[1])) {

$_REQUEST[$_value[0]] = addslashes($_value[1]);

}

}

}

var_dump($_REQUEST);

我们访问URL是:test.php?submit=&user_id=select&user.id=123。得到的结果如下:

第一次输出$_REQUEST仅仅只会输出user_id=123。因为php会将user.id替换为user_id,此时出现了两个user_id,而根据php的原则,则会选取第二个参数,所以第一次输出仅仅只会有user_id=123

第二次输出$_REQUEST会输出user_id=select&user.id=123是因为$_SERVER['REQUEST_URI']并不会对特殊的符号进行替换,因此所有的参数均不会变化,所有的参数都会原样输出。

按照以上的两种特性,我们利用参数污染的方法,是第一个WAF在处理时处理的是正常请求参数的URL,第二个WAF即使处理的是带有payload的参数,但是因为dhtmlspecialchars()的方法很容易被绕过,最终我们的payload就会进入到正常的业务请求中。用一个图来说明这个问题。

我们请求参数是user_id=payload&user.id=123

在经过第一个WAF时,由于$_REQUEST会将参数中的>替换为_,所以会得到两个user_id变为了user_id=payload&user_id=123。按照PHP的特性遇到相同的参数去第二个参数,所以第一个WAF取的是user_id=123,此时正常地通过第一个WAF。

进入到第二个WAF时,由于是通过$_SERVER['REQUEST_URI']取参数,user.id参数并不会被替换为user_id,所以两个参数都会第二个经过WAF

我们的payload绕过了第二个WAF之后(比较容易绕过),user_id=payload&user.id=123进入到业务请求中执行SQL语句,导致SQL注入。

漏洞利用

请求URL,http://localhost/test/index.php?submit=&user_id=1/**/union/**/select/**/1,2,3&user.id=123,得到的最后结果是:

小结

这个洞的挖掘包括利用其实很巧妙,利用的是hpp+php特性,来绕过CMS应用中变态的WAF。但是这个hpp的漏洞只是恰好在这个cms存在了,因为刚好使用了$_SERVER['REQUEST_URI']能够得到正常的请求,而$_REQUEST恰好会对特殊字符进行转义,这样就导致WAF处理的“正常”的参数,但是最后进入到业务数据中的确实我们的payload。

关于HPP的实际漏洞利用,可以参考HTTP参数污染

总结

以上的两个案例都和$_REQUEST的特性有关,对于开发者来说对于所使用的语言以及相关的函数都需要很了解否则就很容易出现漏洞。对于攻击者来说,同样需要了解一些函数的用法,参数、返回值等等,同时还需要掌握函数在一些特殊情况下的用法,这样就能够了解在开发者错误使用了函数时可能会存在的问题。

request与在php安全,request导致的安全性问题分析相关推荐

  1. 一道考查request导致的安全性问题的ctf题

    这道题是在看红日安全团队的代码审计系列文章时碰到的,感觉挺有意思的,所以做了下.题目代码如下 //index.php <?php require 'db.inc.php';function dh ...

  2. Spring学习总结(28)——Spring获取request对象的几种方法及线程安全性总结

    分享一个大神的人工智能教程.零基础!通俗易懂!风趣幽默!还带黄段子!希望你也加入到人工智能的队伍中来!点击浏览教程 前言 在使用Spring MVC开发Web系统时,经常需要在处理请求时使用reque ...

  3. Spring 中获取 request 的几种方法,及其线程安全性分析

    概述 在使用Spring MVC开发Web系统时,经常需要在处理请求时使用request对象,比如获取客户端ip地址.请求的url.header中的属性(如cookie.授权信息).body中的数据等 ...

  4. axios上传文件错误:Current request is not a multipart request

    报错信息 其实整个过程我一共经历了三个报错信息,分别是 1.Current request is not a multipart request:当前请求不是multipart 请求 2.the re ...

  5. java定时器任务中获取request对象 @Scheduled 获取request 对象 quartz中获取request对象

    java定时器任务中获取request对象 @Scheduled 获取request 对象 quartz中获取request对象 一.问题描述 1.在java定时任务中,使用 @Scheduled 注 ...

  6. VUE+Spring Boot,文件上传el-upload报错--Current request is not a multipart request,记录

    做了个简单的文件上传功能,测试时发现报错Current request is not a multipart request,网上查了很多办法,记录一下: 1.最多的:当前请求不是multipart ...

  7. 【GitHub】GitHub 的 Pull Request 和 GitLab 的 Merge Request 有区别吗?

    GitHub 的 Pull Request 和 GitLab 的 Merge Request 有区别吗? 在 GitHub 上混久了,对 Pull Request 就-- 在 GitLab 上混久了, ...

  8. 错误记录:Current request is not a multipart request

    springboot 报错:Current request is not a multipart request 这个一般是controller是带有上传文件的服务,类似@RequestParam M ...

  9. request对象_爬虫:request库的简介

    一. request库的安装 在命令行输入pip install requests进行安装 随后进行调用,发现成功 二. request库的最常用方法:get 方法 r= request.get(ur ...

  10. java request 原理_JavaWeb response和request对象原理及实例解析

    HttpServletResponse: HttpServletResponse对象服务器的响应.这个对象中封装了向客户端发送数据.发送响应头,发送响应状态码的方法. 字符编码格式: 方法一: // ...

最新文章

  1. 存储过程—导出table数据为inser sqlt语句
  2. javaswing引入百度地图_【react】React怎么引用百度地图
  3. UITabBarController详解
  4. 【Python】WordCloud库的使用
  5. yb3防爆电机型号含义_YBK3防爆电机介绍
  6. Juery On事件的 事件触发流程
  7. 曲线图绘制软件_OpenFoam离心泵数值仿真及不同CFD软件间对比
  8. 翻译: Swift 中的委托保留周期 如何在“纯”Swift(没有@objc)中进行弱协议引用
  9. chrome open axure 自动跳转到axure插件
  10. rcnn fastrcnn fasterrcnn总结
  11. AspUpload中文手册及语法
  12. 红警2补丁和联机网络配置
  13. 【Web】Webhacking.kr旧版第五题
  14. WPS个人版如何启用VBA(宏)
  15. new relic_Datadog,SignalFX,New Relic,Wavefront –您应该选择哪个仪表板?
  16. VLog制作之素材拍摄和音乐选择
  17. TikTok与抖音有什么不同?为什么TikTok被称为“海外版抖音”?
  18. 我生命中的钱事:童年!
  19. SW_DVD5_Office_Professional_Plus_2013_W32_ChnSimp_MLF_X18-55126
  20. 如何科学预测后代的身高

热门文章

  1. 需求分析报告和需求规格说明书有什么区别
  2. IPSEC 安全连接
  3. 66. Landing Page
  4. 55. mysqli 扩展库(2)
  5. 从现实抽象出类的步骤
  6. 《第一本docker书》第4章 使用docker镜像和仓库 读书笔记
  7. 百度地图集成Plist文件需要增加的字段
  8. 云,git,blog,感想
  9. 数据库连接失败could not find driver 解决方法
  10. 浅谈 HTTPS 和 SSL -TLS 协议的背景与基础