CVE-2023-25139
0x00 背景 TPCTF里和qym师傅研究了两天safehttpd这题(虽然我一直在背英语pre,没干什么活),把整个程序可能的漏洞点翻遍了也没找到突破口的off by null如何触发(实际上是测试过程中出现了重大失误,已经找对了地方却没有测试出漏洞),赛后看wp发现有这样一个CVE: 30068 – (CVE-2023-25139) incorrect printf output for integers with thousands separator and width field (CVE-2023-25139) (sourceware.org) 0x01 分析 先看上面链接中的复现样例: #include <stdio.h> #include <locale.h> int main (void) { if (setlocale (LC_ALL, "")) { printf ("1234567890123:\n"); printf ("%0+ -'13ld:\n", 1234567L); } return 0; } 在有漏洞的Glibc2.37下的输出: 1234567890123: +1,234,567 : 输出的长度是15而不是13,因为两个千位分隔符没有被计入宽度,导致输出时多补了两个空格。 这是一个glibc 2.37里短暂出现就被迅速修复的漏洞:千位分隔符在限制长度的格式化输出时没有被正确计入宽度,导致出现了溢出。 由该commit修复: Account for grouping in printf width (bug 30068) · bminor/glibc@c980549 (github.com) 下面就通过这个修复的commit分析一下这个bug是如何产生的。 其中第266行由 width -= workend - string + prec 改成了 width -= number_length + prec_inc 这里的width变量为补足宽度限制需要添加的字符的宽度。prec和prec_inc的值是相同的,区别在于number_length和workend - string并不等同:(168-182行) int number_length; #ifndef COMPILE_WPRINTF if (use_outdigits && base == 10) number_length = __translated_number_width (_NL_CURRENT_LOCALE, string, workend); else number_length = workend - string; if (group) number_length += iter.separators * strlen (thousands_sep); #else number_length = workend - string; /* All wide separators have length 1. */ if (group && thousands_sep != L'\0') number_length += iter.separators; #endif 在上面代码的后几行可以看到number_length是原本的数字长度加上千位分隔符的长度,而workend-string没有计算千位分隔符的长度,导致了错误的长度计算。 ...