
تقرير وإثبات المفهوم (PoC) لثغرة تجاوز سعة المخزن المؤقت العام في SmallBASAC قبل 02364eff880ba62afac67bcceebafade2b40d21f
SmallBASIC هو مترجم لغة BASIC سريع وسهل التعلم، مثالي للحسابات اليومية والنصوص والنماذج الأولية. يتضمن SmallBASIC دوال مثلثية ومصفوفات وجبر، وبيئة تطوير متكاملة مدمجة، ومكتبة نصوص قوية، وأوامر نظام وصوت ورسوم، بالإضافة إلى بناء جملة برمجية منظمة.
في السطر 277 من src/platform/sdl/main.cpp، تم استدعاء strcpy لنسخ argv إلى المتغير العمومي opt_command، المُعرَّف في src/common/smbas.h. المتغير العمومي هو مصفوفة ذات حجم ثابت، وفقاً للماكرو OPT_CMD_CZ المُعرَّف في نفس الملف.
// src/common/smbas.h:105
EXTERN char opt_command[OPT_CMD_CZ] //
// src/platform/sdl/main.cpp:263
while (1) {
int option_index = 0;
int c = getopt_long(argc, argv, "hvkc:f:r:x:n:m:e:d:p:", OPTIONS, &option_index);
if (c == -1) {
// no more options
if (!option_index) {
for (int i = 1; i < argc; i++) {
const char *s = argv[i];
int len = strlen(s);
if (runFile == NULL
&& ((strcasecmp(s + len - 4, ".bas") == 0 && access(s, 0) == 0)
|| (strstr(s, "://") != NULL))) {
runFile = strdup(s);
} else if (chdir(s) != 0) {
strcpy(opt_command, s); // VULNERABLE
}
}
}
break;
}
وفقاً لـ src/common/smbas.h، OPT_CMD_CZ مُعرَّف بـ 1024.
#define OPT_CMD_CZ 1024
على عكس دالة strlcpy، لا تتحقق strcpy من عدد البايتات المراد نسخها. لذلك يمكن نسخ أكثر من 1024 بايت إلى المصفوفة opt_command. وبما أن وسيط سطر الأوامر قد يكون أطول من 1024 بايت، يمكن للمدخلات الكتابة فوق الكائنات الأخرى. قد يؤدي هذا إلى سلوك غير متوقع للبرنامج sbasicg.
لاحظ أن الحد الأقصى لطول السلسلة التي يمكن استخدامها في موجه الأوامر في Windows هو 8191 حرفاً. في Linux، يعتمد الطول على ARG_MAX و MAX_ARG_STRINGS.
قم ببناء مشروع SmallBASIC، ثم شغّل:
$ src/platform/sdl/sbasicg $(python -c 'print("a"*1024)')
يسبّب ذلك تجاوز سعة المخزن المؤقت العمومي أثناء تحليل وسيط سطر الأوامر المُنفَّذ في الدالة main. فيما يلي المخرجات من Address Sanitizer:
=================================================================
==5322==ERROR: AddressSanitizer: global-buffer-overflow on address 0x0000016c22a0 at pc 0x0000004ba2e4 bp 0x7ffeb3ebac70 sp 0x7ffeb3eba428
WRITE of size 1025 at 0x0000016c22a0 thread T0
#0 0x4ba2e3 in strcpy (/home/ch1keen/fuzz/SmallBASIC/src/platform/sdl/sbasicg+0x4ba2e3) (BuildId: 4a800899b4dac082870bb647e1d872811e8633ea)
#1 0x8759c6 in main /home/ch1keen/fuzz/SmallBASIC/src/platform/sdl/main.cpp:277:13
#2 0x79e3ca62a1c9 in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16
#3 0x79e3ca62a28a in __libc_start_main csu/../csu/libc-start.c:360:3
#4 0x4378b4 in _start (/home/ch1keen/fuzz/SmallBASIC/src/platform/sdl/sbasicg+0x4378b4) (BuildId: 4a800899b4dac082870bb647e1d872811e8633ea)
0x0000016c22a0 is located 0 bytes after global variable 'opt_command' defined in '/home/ch1keen/fuzz/SmallBASIC/src/common/smbas.h:105' (0x16c1ea0) of size 1024
SUMMARY: AddressSanitizer: global-buffer-overflow (/home/ch1keen/fuzz/SmallBASIC/src/platform/sdl/sbasicg+0x4ba2e3) (BuildId: 4a800899b4dac082870bb647e1d872811e8633ea) in strcpy
Shadow bytes around the buggy address:
0x0000016c2000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0000016c2080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0000016c2100: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0000016c2180: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0000016c2200: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x0000016c2280: 00 00 00 00[f9]f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9
0x0000016c2300: f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9
0x0000016c2380: f9 f9 f9 f9 00 00 00 00 00 00 00 00 00 00 00 00
0x0000016c2400: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0000016c2480: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0000016c2500: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
==5322==ABORTING
تأثير الثغرة غير واضح. لكن تجاوز سعة المخزن المؤقت العمومي قد يكتب فوق المتغيرات العمومية الأخرى، مما قد يؤدي إلى الكتابة فوق علامات وإعدادات البرنامج.
تم إصلاح الثغرة عن طريق استبدال جميع استخدامات strcpy تقريباً بـ strlcpy، بما في ذلك المشكلة التي أبلغت عنها.
@@ -277,1 +277,1 @@ int main(int argc, char* argv[]) {
< strcpy(opt_command, command);
---
> strlcpy(opt_command, command, sizeof(opt_command));
انظر الـ commit للحصول على التصحيح التفصيلي.