漏洞信息
漏洞来源:https://hackerone.com/reports/2644244
官方安全公告:https://www.djangoproject.com/weblog/2024/aug/06/security-releases/
漏洞影响:Django版本小于5.0.8或小于4.2.15
简介:Hackerone上给出的漏洞简介为django.utils.numberformat.floatformat() 中的内存耗尽,当给出具有大指数的科学计数法数字的字符串表示形式时,floatformat 模板过滤器会消耗大量内存。
漏洞复现
一、正常调用,传入正常数字1,查看耗时为:0.0072176456451416016 秒
二、传入大指数9e99999,查看耗时为:0.46574854850769043 秒
三、增大传入指数9e999999,查看耗时为:45.13413095474243 秒
四、根据耗时结果来看,确实可以达到DOS效果,升级5.0.10版本后,重试(前面没有输出结果是因为输出的数字过于长,这里看到修复之后是把指数直接原样输出出来了,没有做转换)
漏洞分析
一、下断点调试,查看是哪里耗时,第一步进入floatformat函数,就找到了耗时的地方(两个断点)
二、很明显就是int转换的时候产生了耗时,并且int转换的内容是Decimal转换过的对象,那么先看Decimal是什么类型
看上去就是让浮点数更精准,尝试用起来貌似正常使用和普通浮点数也没什么区别
三、再来看int方法是可以处理指数的
但是在处理较大指数时就会报错,如下图
如果这个指数先使用Decimal来处理过呢?
这个奇怪的现象,问下GPT,如下图ChatGPT4o不太行
还得是ChatGPT o1-preview
四、总结一下:浮点数超过无穷大是处理不了的,但是可以用Decimal先把大数转换为一个精确的十进制数,就避免了报错,然后把这个大数传给int去处理转换,从而消耗资源。
官方修复方法分析
一、在代码中加入了一个判断逻辑如下
二、交给GPT分析
简单来说就是计算实际大小,经过一系列测试,包括各种科学技术法的变形,以及使用无穷等,也没找到绕过方法,有绕过思路的大佬可以讨论下。
扩展延伸
搜了一下Django代码中还有哪里符合这种漏洞的,找到了一处比较符合,但是利用不了的,在from django.utils.translation.__init__.py的round_away_from_one方法,方法如下:
但经过测试,该方法传入的value是str类型时,由于类型不匹配,在Decimal方法中-1时会报错:
但Decimal方法处理大数解析为精确浮点型时,只接受字符串类型的大数,而数字类型的大数会解析为正无穷
int处理正无穷会报错
所以这里也没办法传入一个大数给int处理,也就无法造成DOS漏洞了。