Пожалуйста, обратите внимание, что пользователь заблокирован
Интро
В процессе серфинга интернета, я наткнулся случайно на одну вакансию, на позицию vulnerability researcher'а. Всё как обычно, обычная вакансия, за исключением требовался человек, который преимущественно понимает алгоритмы работы AddressSanitizer (ASan), а так же знает технологии DBI (Dynamic Binary Instrumentation, DBI).Вот частичное описание этой вакансии (не реклама)
Если с DBI всё понятно, но ASan? Как можно не знать и не понимать как он работает? ... Многие наверно слышали об этом инструменте, некоторые знают о нём и используют его, а другие и вовсе не знают. Так или иначе сегодня мы будем говорить об Asan'е. Это очень мощный инструмент, который помогает искать ЖИРНЫЕ баги. Сегодня я расскажу, как с помощью Asan'а можно найти 0-day уязвимости в OpenSource проектах, но найдете ли вы уязвимости или нет зависит только от вас. От себя же, я покажу простейший метод, с помощью которого можно искать баги в самых разных проектах. В общем предлагаю сегодня погрузится в тему баг-хантинга, ПОЕХАЛИ!!!
Что такое AddressSanitizer?
Это быстрый динамический анализатор кода, для детектирования ошибок связанных с памятью - во время исполнения, для программ написанных на С\С++.
AddressSanitizer (ASan) разработала компания Google, как инструмент поика уязвимотей повреждения памяти, ASan обнаруживает ошибки в форме неопределенного или подозрительного поведения с помощью компилятора, вставляющего инструментальный код во время компиляции.
Впервые ASan был представлен на конференции USENIX в 2012 году, как более универсальный детектор ошибок в отличие от существующих на тот момент, по скольку большинство из них либо работали медленно, либо обнаруживали ограниченный набор ошибок, либо то и другое...
Вот ссылка на это событие, там же можно посмотреть запись выступления "AddressSanitizer: A Fast Address Sanity Checker", а так же прочитать статью и посмотреть слайды.
Событие
AddressSanitizer: A Fast Address Sanity Checker | USENIX
Видео
Слайды
Статья
С момента реализа этого инструмента было обнаружено 300+ уязвимостей в Chromium, только за первые 10 месяцев его использования. И это не считая другие проекты, такие как Firefox, FFmpeg, FreeType, MySQL итд. Поскольку инструмент показал себя эффективным с точки зрения обнаружения багов, его быстро стали интегрировать, добавлять во все компиляторы.
AddressSanitizer теперь является частью LLVM, начиная с версии 3.1, и частью GCC, начиная с версии 4.8. А так же Xcode с версии 7.0. А с 2019 года он был интегрирован в Visual Studio начиная с версии компилятора (MSVC) 16.9, как дополнительный установочный компонент.
Правда в Windows он всё еще бета, по крайне мере для меня.
Какие баги он определяет?
ASan определяет достаточно широкий спектр багов, о чем свидетельствуют многочисленные баг репорты на багтрек лентах.
Примеры репортов
1355 - project-zero - Project Zero - Monorail
1606 - project-zero - Project Zero - Monorail
2002 - project-zero - Project Zero - Monorail
2103 - project-zero - Project Zero - Monorail
2335 - project-zero - Project Zero - Monorail
Собственно ASan умеет определять следующие баги.
Stack Buffer Overflow
Stack Buffer Underflow
Dynamic Stack Buffer Overflow
Stack-Use-After-Return
Stack-Use-After-Scope
Global Buffer Overflow
Alloc-Dealloc Mismatch
Allocation size too Big
Calloc parametrs Overflow
Container Overflow
Invalid Allocation Alignment
Memcpy parametr Overlap
Strncat parametr Overlap
New & Delete type Mismatch
Use After Poison
Heap Buffer Overflow
Heap Use-After-Free
Double Free
Initialization Order Bugs
Memory Leaks
Из этого списка я выделил самые ЖИРНЫЕ баги, которые может обнаружить ASAN.
CWE-121: Stack-based Buffer Overflow
CWE - CWE-121: Stack-based Buffer Overflow (4.19.1)
Common Weakness Enumeration (CWE) is a list of software weaknesses.
CWE-122: Heap-based Buffer Overflow
CWE - CWE-122: Heap-based Buffer Overflow (4.19.1)
Common Weakness Enumeration (CWE) is a list of software weaknesses.
CWE-416: Use After Free
CWE - CWE-416: Use After Free (4.19.1)
Common Weakness Enumeration (CWE) is a list of software weaknesses.
В любом случае при обнаружение других багов из списка в процессе тестирования ПО это всё равно уcпех. Но в первую очередь нас будет интересовать именно эти баги, а пока перейдем к процессу работы самого ASan'a.
Как его использовать?
Если уж говорить совсем простыми словами, то ASan работает по принципу "доступа за пределами границ" (out-of-bounds access). Аналогично с защитой стека - стековой куки, стек канарейкой. Когда в стеке у нас перезаписывается кука, мы знаем, что произошло переполнение. Другими словами, когда у нас что-то выходит за пределы и перезаписывается, ASan это детектит. В асане для это существует red зона и зона карантина. Red zone для отлова OOB, карантин для UAF.
ASan находит внешний доступ к памяти используя специальный аллокатор и используя инструментацию кода, тем самым обнаруживая доступ за пределы границ для стека, кучи и глобальных объектов.
Как я уже сказал выше AddressSanitizer уже встроен во многие компиляторы, и чтобы его задействовать достаточно указать специальный ключик при компиляции программы. Тогда проект соберется с Asan'ом, т.е. будет проинструментирован проверками.
Например у нас есть такой код.
C:
/*
* stack-buffer-overflow.c
* CWE-121: Stack-based Buffer Overflow
* https://cwe.mitre.org/data/definitions/121.html
*/
#include <stdio.h>
#include <string.h>
#define BUFSIZE 100
int main(int argc, char *argv[])
{
char array[BUFSIZE];
/* vulnerability */
strcpy(array, argv[1]);
printf("string: %s\n", array);
return 0;
}
Компилируем
Код:
gcc stack.c -o stack -fsanitize=address
И запускаем с рандомными аргументами
Код:
./stack 1
./stack 1dasd
Программа не падает, и даже не определяет переполнение буфера в программе. Но если мы повторно запустим программу и передадим ей большую строку.
Код:
./stack AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA...
То программа сразу упадет.
Всё дело в том, что Asan не анализирует программу, он анализирует исполнение программы. Как видно из скриншота, ASan любезно нам предоставил лог падения со всеми подробностями.
Пользоваться таким инструментом достаточно просто, вызываем (триггерим) баг и получаем лог от Asan'a.
Лог асана кстати можно улучшить, добавив такой ключик как "-g". Чтобы компилятор добавил отладочные символы. А так же для лучшей эффективности свяжем библиотеку асана статически, флагом "-static-libasan".
Код:
gcc stack.c -o stack -fsanitize=address -static-libasan -g
Ниже скриншот улучшенного лога асана. Улучшение заключается в том, что помимо оффсетов, нам указавают еще номер строки в исходном коде где находится сама уязвимость это очень удобно.
Еще пару примеров...
heap buffer overflow
C:
/*
* heap-buffer-overflow.c
* CWE-122: Heap-based Buffer Overflow
* https://cwe.mitre.org/data/definitions/122.html
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BUFSIZE 100
int main(int argc, char *argv[])
{
char *ptr = malloc(BUFSIZE);
/* vulnerability */
strcpy(ptr, argv[1]);
printf("string: %s\n", ptr);
free(ptr);
return 0;
}
use after free
C:
/*
* use-after-free.c
* CWE-416: Use After Free
* https://cwe.mitre.org/data/definitions/416.html
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, const char *argv[])
{
char *array = malloc(100);
free(array);
/* vulnerability */
strcpy(array, argv[1]);
printf("string is: %s\n", array);
return 0;
}
Объединим два примера выше.
C:
/*
* example_vuln.c
* heap overflow & use-after-free
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[])
{
char *array = malloc(100);
/* vulnerability - heap overflow */
strcpy(array, argv[1]);
printf("string: %s\n", array);
free(array);
printf("Input: ");
/* vulnerability - use after free */
scanf("%s", array);
printf("string is: %s\n", array);
return 0;
}
Тестируем
Как видно из этого скриншота мы обнаружила переполние буфера в куче, но не обнаружили UAF.
Протестируем еще раз
Тут мы успешно обнаружили использование памяти после освобождения, но не обнаружили heap buffer overflow.
Этот пример наглядно демонстрирует, то о чем я говорил ранее. Asan не анализирует программу, он анализирует исполнение программы. Другими словами если мы не вызовим баг мы не узнаем о существование уязвимости. В иделе асан должен применяться с фаззерами на основе покрытия (сoverage-guided). Чтобы как раз и находит подобные случаи.
Иногда при ручном тестировании или фаззинге нужно оптимизировать работу приложения, чтобы ускорить его на определенном участке. Как это сделать? Ведь ASan замедляет работу приложения в 2 раза. Всё на самом деле очень просто, для этого были добавлены опции игнорирования определенных функций, которые не нужно инструментировать.
Ниже пример макроса, при добавление которого можно указать какую функцию игнорировать при инструментировании кода.
C:
#if defined(__clang__) || defined (__GNUC__)
# define ATTRIBUTE_NO_SANITIZE_ADDRESS __attribute__((no_sanitize_address))
#else
# define ATTRIBUTE_NO_SANITIZE_ADDRESS
#endif
...
ATTRIBUTE_NO_SANITIZE_ADDRESS
void ThisFunctionWillNotBeInstrumented() {...
Посмотрим как это выглядит на практике. Напишем простую программу с уязвимостью.
C:
#if defined(__clang__) || defined (__GNUC__)
# define ATTRIBUTE_NO_SANITIZE_ADDRESS __attribute__((no_sanitize_address))
#else
# define ATTRIBUTE_NO_SANITIZE_ADDRESS
#endif
#include <stdio.h>
#include <string.h>
int vuln_func(char *s);
int main(void)
{
char *param = "AAAAAAAAAAAAAAAAAAAA";
int result=0;
result = vuln_func(param); /* no instrumentation */
printf("Len: %d\n", result);
return 0;
}
//ATTRIBUTE_NO_SANITIZE_ADDRESS
int vuln_func(char *s)
{
int len=0;
char buff[40];
strcpy(buff, s);
printf("Buffer: %s\n", buff);
len = strlen(buff);
return len;
}
В примере 1 - обычное выполнение с инструментированием кода, но без длинной строки.
В примере 2 - передается большая строка и игнорируется уязвимая функция (которая не была инструментирована)
В примере 3 - так же передается большая строка, но происходит инструментирование всего кода.
В примере 2 видно, что мы можем отключать инструментирование определенных фунций, это выгодно, когда вы разобрали какую-то определенную функцию и вам известно, что в данной функции уж точно не будет багов и накладные вычислительные расходы вам не нужны при тестах. Или же чтобы выйграть в борьбе за ресурсы, мы можем тестировать ПО частями. Так как инструментированный код ASan'a в среднем съедает в 2 раза больше ресурсов.
Так же можно игнорировать сразу целый список функций не копаясь в сорцах, правда этот вариант доступен только для clang.
Код:
-fsanitize-blacklist=my_ignores.txt
Список команд GCC можно посмотреть тут.
gcc.gnu.org/onlinedocs/gcc/Instrumentation-Options.html
Список команда для Clang
clang.llvm.org/docs/UsersManual.html#controlling-code-generation
clang.llvm.org/docs/ClangCommandLineReference.html#compilation-options
MSVC
learn.microsoft.com/en-us/cpp/sanitizers/asan?view=msvc-170#command-prompt
learn.microsoft.com/en-us/cpp/sanitizers/asan?view=msvc-170#ide-msbuild
learn.microsoft.com/en-us/cpp/sanitizers/asan?view=msvc-170#ide-cmake
XCode
developer.apple.com/documentation/xcode/diagnosing-memory-thread-and-crash-issues-early
1001 зиродей
Теперь я думаю самое время рассмотреть реальные кейсы... Пока коллеги играют с веб запросами через curl, мы будем играть с исходниками и асаном. И так, чтобы протестировать ПО на предмет багов идем на гитхаб или любой другой хостинг проектов и выбираем любой проект который написан на С\С++. Собираем его из исходников с асаном и пытаемся в ручном режиме уронить программу. На вход программе подаём некорректные данные. Т.е в любом месте где программа обрабатывает данные мы пихаем на вход большую строку типа AAAAAAAAAAAAAAAAAA..... Короче говоря любыми всевозможными способами пихаем в программу некорректные данные.
Тут стоит сказать вот что... По хорошему мы должны скомбинировать какой-либо фаззер и наш асан для теста ПО. Но так, как эта статья посвящена конкретно инструменту AddressSaninizer мы исключим использование фаззеров =/
В таком случае шанс на успех у нас уменьшается, так как мы не сможешь покрыть всё, используя ручной ввод.
От вас требуетсялишь навык сборки и компиляции программ, разбираться во всяких confugure, make, cmake править мейки и добавлять флаги -fsanitize=address -static-libasan -g
Ниже я приведу несколько примитивных примеров, по некоторым соображениям... Которые должны дать вам пищу для размышления, о том, что вполне можно скачать любой понравившийся вам проект, затем собрать его с асаном, далее щупать его в эрогенных зонах.
Minitox клиент
GitHub - hqwrong/minitox: Minimal client for Tox
Minimal client for Tox. Contribute to hqwrong/minitox development by creating an account on GitHub.
/add TOX_ID AAAAAAAAAAA.......
лог
Чем не зиродей? Хотя я уже показывал этот баг. Когда был шум с токсом. Да, можно сказать, что уязвимость находится в простой поделке, однако мы нашли уязвимость в чужом коде!!!==20030==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x615000000280 at pc 0x55b92c934b51 bp 0x7fff37a8b510 sp 0x7fff37a8b500
WRITE of size 1 at 0x615000000280 thread T0
#0 0x55b92c934b50 in arepl_readline /home/weaver/test/software/minitox/minitox.c:502
#1 0x55b92c93a2b8 in repl_iterate /home/weaver/test/software/minitox/minitox.c:1263
#2 0x55b92c93ae4d in main /home/weaver/test/software/minitox/minitox.c:1344
#3 0x7fb3f2c29d8f in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58
#4 0x7fb3f2c29e3f in __libc_start_main_impl ../csu/libc-start.c:392
#5 0x55b92c85c764 in _start (/home/weaver/test/software/minitox/minitox+0xd764)
0x615000000280 is located 0 bytes to the right of 512-byte region [0x615000000080,0x615000000280)
allocated by thread T0 here:
#0 0x55b92c8ec4b7 in malloc (/home/weaver/test/software/minitox/minitox+0x9d4b7)
#1 0x55b92c933452 in setup_arepl /home/weaver/test/software/minitox/minitox.c:390
#2 0x55b92c93add0 in main /home/weaver/test/software/minitox/minitox.c:1335
#3 0x7fb3f2c29d8f in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58
SUMMARY: AddressSanitizer: heap-buffer-overflow /home/weaver/test/software/minitox/minitox.c:502 in arepl_readline
Shadow bytes around the buggy address:
0x0c2a7fff8000: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c2a7fff8010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c2a7fff8020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c2a7fff8030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c2a7fff8040: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x0c2a7fff8050:[fa]fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c2a7fff8060: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c2a7fff8070: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c2a7fff8080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c2a7fff8090: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c2a7fff80a0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
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
Shadow gap: cc
==20030==ABORTING
Smallchat
GitHub - antirez/smallchat: A minimal programming example for a chat server
A minimal programming example for a chat server. Contribute to antirez/smallchat development by creating an account on GitHub.
Пропускаем ввод никнейна в клиенте /nick и просто вводим "А"
лог
Далее мне попался код какого-то амера, который на ютубе делал уроки по использованию сокетов. Опять видим, что нам удалось найти баг, при чем в узком месте.=================================================================
==79261==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x602000000037 at pc 0x55d3589834e9 bp 0x7ffc069f0fe0 sp 0x7ffc069f0758
READ of size 8 at 0x602000000037 thread T0
#0 0x55d3589834e8 in printf_common(void*, char const*, __va_list_tag*) (/home/weaver/test/software/smallchat/smallchat-server+0x434e8)
#1 0x55d358985135 in vsnprintf (/home/weaver/test/software/smallchat/smallchat-server+0x45135)
#2 0x55d3589853c6 in __interceptor___snprintf_chk (/home/weaver/test/software/smallchat/smallchat-server+0x453c6)
#3 0x55d358949c1b in snprintf /usr/include/x86_64-linux-gnu/bits/stdio2.h:71
#4 0x55d358949c1b in main /home/weaver/test/software/smallchat/smallchat-server.c:255
#5 0x7fbe5f229d8f in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58
#6 0x7fbe5f229e3f in __libc_start_main_impl ../csu/libc-start.c:392
#7 0x55d35894a074 in _start (/home/weaver/test/software/smallchat/smallchat-server+0xa074)
0x602000000037 is located 0 bytes to the right of 7-byte region [0x602000000030,0x602000000037)
allocated by thread T0 here:
#0 0x55d3589d9dc7 in malloc (/home/weaver/test/software/smallchat/smallchat-server+0x99dc7)
#1 0x55d358a2099c in chatMalloc /home/weaver/test/software/smallchat/chatlib.c:137
SUMMARY: AddressSanitizer: heap-buffer-overflow (/home/weaver/test/software/smallchat/smallchat-server+0x434e8) in printf_common(void*, char const*, __va_list_tag*)
Shadow bytes around the buggy address:
0x0c047fff7fb0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c047fff7fc0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c047fff7fd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c047fff7fe0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c047fff7ff0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x0c047fff8000: fa fa 00 00 fa fa[07]fa fa fa fa fa fa fa fa fa
0x0c047fff8010: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c047fff8020: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c047fff8030: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c047fff8040: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c047fff8050: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
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
Shadow gap: cc
==79261==ABORTING
Alpha-Chat
GitHub - alphadose/Alpha-Chat: A chatroom in C made using Berkley Sockets
A chatroom in C made using Berkley Sockets. Contribute to alphadose/Alpha-Chat development by creating an account on GitHub.
./client 127.0.0.1 AAAA
лог
Этот пример просто кривого чата, который и вовсе не запустился, даже если на вход подать нормальные входные данные. На этот чат я не стал тратить свое время. Но баг есть баг, при чём это чужой код.=================================================================
==105401==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7ffebf4bd7c8 at pc 0x55e962e69523 bp 0x7ffebf4bd510 sp 0x7ffebf4bccb8
WRITE of size 1000 at 0x7ffebf4bd7c8 thread T0
#0 0x55e962e69522 in memset (/home/weaver/test/software/Alpha-Chat/client+0x1e522)
#1 0x55e962f29e1d in get_username /home/weaver/test/software/Alpha-Chat/client.c:64
#2 0x55e962f2a1e8 in connect_to_server /home/weaver/test/software/Alpha-Chat/client.c:108
#3 0x55e962f2b37f in main /home/weaver/test/software/Alpha-Chat/client.c:309
#4 0x7f2aaac29d8f in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58
#5 0x7f2aaac29e3f in __libc_start_main_impl ../csu/libc-start.c:392
#6 0x55e962e54414 in _start (/home/weaver/test/software/Alpha-Chat/client+0x9414)
Address 0x7ffebf4bd7c8 is located in stack of thread T0 at offset 88 in frame
#0 0x55e962f2b1e4 in main /home/weaver/test/software/Alpha-Chat/client.c:299
This frame has 2 object(s):
[48, 88) 'connection' (line 300)
[128, 256) 'file_descriptors' (line 301) <== Memory access at offset 88 partially underflows this variable
HINT: this may be a false positive if your program uses some custom stack unwind mechanism, swapcontext or vfork
(longjmp and C++ exceptions *are* supported)
SUMMARY: AddressSanitizer: stack-buffer-overflow (/home/weaver/test/software/Alpha-Chat/client+0x1e522) in memset
Shadow bytes around the buggy address:
0x100057e8faa0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 f1 f1
0x100057e8fab0: f1 f1 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x100057e8fac0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x100057e8fad0: 00 00 00 00 00 04 f3 f3 f3 f3 f3 f3 f3 f3 00 00
0x100057e8fae0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 f1 f1
=>0x100057e8faf0: f1 f1 f1 f1 00 00 00 00 00[f2]f2 f2 f2 f2 00 00
0x100057e8fb00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 f3 f3
0x100057e8fb10: f3 f3 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x100057e8fb20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x100057e8fb30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x100057e8fb40: 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
Shadow gap: cc
==105401==ABORTING
C-Chatroom
GitHub - lovenery/c-chatroom: A simple chat room in C. Demo: https://youtu.be/3FvHW3uzZA0
A simple chat room in C. Demo: https://youtu.be/3FvHW3uzZA0 - lovenery/c-chatroom
nc 127.0.0.1 8888 AAAAAAAAAAAAAA......
лог
Это пример почти хорошего программирования сокетов. Клиент мне не удалось уронить, как и сервер. Все фильтруется, ник, ввод, символы. Однако хакерская смекалка взяла вверх, по сколько влиять на сервер я мог только используя клиент, я подумал, а почему бы мне не подключится к серверу через netcat (который будет выступать в роли аналога клиента), и тогда я обойду фильтры встроенные в клиенте, чтобы накормить сервер вкусной строкой. Так и случилось, сервер туже секунду рухнул.=================================================================
==8685==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7f53aadfcc45 at pc 0x560776676eb9 bp 0x7f53aadfc190 sp 0x7f53aadfb908
READ of size 103 at 0x7f53aadfcc45 thread T3
#0 0x560776676eb8 in printf_common(void*, char const*, __va_list_tag*) (/home/weaver/test/software/c-chatroom/server.out+0x42eb8)
#1 0x560776678032 in __interceptor_vsprintf (/home/weaver/test/software/c-chatroom/server.out+0x44032)
#2 0x5607766782b6 in __interceptor___sprintf_chk (/home/weaver/test/software/c-chatroom/server.out+0x442b6)
#3 0x560776713c92 in sprintf /usr/include/x86_64-linux-gnu/bits/stdio2.h:38
#4 0x560776713c92 in client_handler src/server.c:70
#5 0x7f53af294ac2 in start_thread nptl/pthread_create.c:442
#6 0x7f53af32684f (/lib/x86_64-linux-gnu/libc.so.6+0x12684f)
Address 0x7f53aadfcc45 is located in stack of thread T3 at offset 197 in frame
#0 0x56077671341f in client_handler src/server.c:42
This frame has 3 object(s):
[32, 63) 'nickname' (line 44)
[96, 197) 'recv_buffer' (line 45)
[240, 441) 'send_buffer' (line 46) <== Memory access at offset 197 partially underflows this variable
HINT: this may be a false positive if your program uses some custom stack unwind mechanism, swapcontext or vfork
(longjmp and C++ exceptions *are* supported)
Thread T3 created by T0 here:
#0 0x5607766715b5 in __interceptor_pthread_create (/home/weaver/test/software/c-chatroom/server.out+0x3d5b5)
#1 0x56077663d90c in main src/server.c:141
SUMMARY: AddressSanitizer: stack-buffer-overflow (/home/weaver/test/software/c-chatroom/server.out+0x42eb8) in printf_common(void*, char const*, __va_list_tag*)
Shadow bytes around the buggy address:
0x0feaf55b7930: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0feaf55b7940: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0feaf55b7950: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0feaf55b7960: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0feaf55b7970: f1 f1 f1 f1 00 00 00 07 f2 f2 f2 f2 00 00 00 00
=>0x0feaf55b7980: 00 00 00 00 00 00 00 00[05]f2 f2 f2 f2 f2 00 00
0x0feaf55b7990: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0feaf55b79a0: 00 00 00 00 00 00 00 01 f3 f3 f3 f3 f3 f3 f3 f3
0x0feaf55b79b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0feaf55b79c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0feaf55b79d0: 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
Shadow gap: cc
==8685==ABORTING
Софт для исследования можно брать не только с github, gitlab, но и так же с sourceforge.net.
Все это я делал не подыскивая специально уязвимые примеры т.е. рандомные примеры с асаном, а представьте если это все дело объединить с анализатором сорцов? Или фаззером, я думаю нас ждал бы успех на все 300% процентов. Продолжая разговор о поиске багов, я уже как-то говорил о том, что некоторые исследователи выкладывают скриншоты в свиттере и это действительно так. Возвращаясь к этому обсуждению, стоит сказать, что на различных баг-трек лентах так же встречаются логи асана. Чужие логи дают нам информацию о недавно закрытых багах, в том числе информацию об 0-day уязвимостях.
Искать логи можно например так
vulners.com/search?query=AddressSanitizer
К слову это специальный поисковик который парсит все существующие базы эксплойтов и все отчеты об уязвимостях.
Вот к примеру один из таких отчетов
vulners.com/talos/TALOS-2024-1931
В данном отчете присутствует логи асана и описание найденных уязвимостей в то числе как можно воспроизвести PoC. Кстати DICOM очень интересный формат файла и интересный вектор для атаки.
Еще один отчет
vulners.com/talos/TALOS-2024-1922
Который так же свидетельствует о наличие уязвимости в библиотеке которая отвечает за обработку биомедицинских сигналов =)
И таких отчетов т.е. логов асана в сети целая куча. Логи асана это очень ценная информация. Особенно если ты занимаешься разработкой эксплойтов. Не буду многословен скажу лишь, то что Asan это очень мощный инструмент который помогает отыскать быги в дебрях говнокода. Типичный процесс баг-хантинга выглядит следующим образом. Берем опенсурс продукт С\С++ смотрим его сорцы на предмет опасный функций типа strcpy, gets и тому подобных, определяем места в программе, где обрабатываются данные, т.е. анализируем логику кода, сам же проект собираем с асаном и запускаем какой нибудь фаззер на основе покрытия типа AFL ждем креш = профит. Как итог $$$$ \ CVE который расширяет ваше портфолио.
Заключение
На Asan'е не заканчивается история, существуют и другие инструменты. После того, как был написан ASan, люди подумали, а не плохо бы сделать аналогичные инструменты для тестирования. Так и родилась группа инструментов под категорией санитайзеров =) В основном санитайзеры делятся на два типа, те которые работают в ядре, и те которые работают в пользовательском пространстве.По мимом ASan'а существуют такие инструменты как: HWASan, KASAN, BoKASAN, GWP-ASan, KFENCE, KMSAN, KCSAN, KTSAN, , UBSan (IntSan, BoundSan), MSan, LSan, TSan etc...
Ниже будет краткое описание.
Примечание: Большинство Sanitizer'ов хранятся в репозитории ядра Linux и не размещаютя на github.
HWASan (Hardware-assisted AddressSanitizer) - это тот же самый ASan, но с аппаратной поддержкой. HWAsan доступен только на Android 10 и выше и только на оборудовании AArch64 (ARM64). HWAsan более производительный, чем ASan из-за аппаратной поддержки.
Документация:
Hardware-assisted AddressSanitizer | Android Open Source Project
KASAN (Kernel Address Sanitizer) - это тот же ASan, но он предназначен для ядра. KASAN добавлен в ядро Linux начиная с v4.0.
BoKASAN (Binary-only Kernel Address Sanitizer) - это тот же KASAN, но для работы с закрытым исходным кодом. Он появился в прошлом году (2023) и идеально подходит для тестирования коммерческих ОС c закрытым исходным кодом. Работает на основе DBI.
Событие:
Git:
GitHub - seclab-yonsei/BoKASAN: BoKASAN: Binary-only Kernel Address Sanitizer for Effective Kernel Fuzzing
BoKASAN: Binary-only Kernel Address Sanitizer for Effective Kernel Fuzzing - seclab-yonsei/BoKASAN
GWP-ASan (Will Provide Allocation SANity) - это тот же ASAN, но он разработан с учетом промышленной разработки и тестов экосистемы Android. Так же у него более лучшая производительность по сравнению с Asan. Он интегрирован в Android 11 и Chromium. Заточен под user-mode, так же он не требует исходного кода и работает уже с готовыми билдами по принципу DBI.
Документация:
GWP-ASan | Android NDK | Android Developers
KFENCE (Kernel Electric-Fence) - это еще один санитайзер для ядра. KFENCE создан на основе GWP-ASan, инструмента для пользовательского пространства с аналогичными свойствами. KFENCE добавлен в ядро Linux начиная с v5.12. Ключевые отличия KFENCE от KASAN в производительности. У KFENCE с этим нет проблем и поэтому он применяется в промышленном производстве на рабочих машинах, а не на тестовых. К тому же KFENCE позволяет маштабировать тесты.
KMSAN (KernelMemorySanitizer) - этот санитайзер работает с ядром. Задача этого санитайзера заключается в поиске неинициализированного доступа к памяти в ядре Linux. Работает по принципу CTI. Начиная с Linux 6.1+ содержит полностью работающую реализацию KMSAN, которую можно использовать из коробки.
GitHub - google/kmsan: KernelMemorySanitizer, a detector of uses of uninitialized memory in the Linux kernel
KernelMemorySanitizer, a detector of uses of uninitialized memory in the Linux kernel - google/kmsan
KCSAN (Kernel Concurrency Sanitizer) - это еще один санитайзер для ядра. KCSAN специально нацелен на гонки данных, распространенную проблему в параллельном программировании внутри ядра. Он добавлен в ядро Linux начиная с v5.8. но официально он еще не интегрирован и все еще находится на стадии разработки.
Документация:
KTSAN (Kernel Thread Sanitizer) - это санитайзер так же работает с ядром, и так нацелен поиск состояний гонки (race condition). Аналогично KSCAN так же ищет дата рейсы, но различие их заключается в реализации и подходе к обнаружения гонок.
GitHub - google/kernel-sanitizers at ktsan
Linux Kernel Sanitizers, fast bug-detectors for the Linux kernel - GitHub - google/kernel-sanitizers at ktsan
Примечание
KCSAN: В первую очередь фокусируется на обнаружении гонок за данными между простым и маркированным доступом . Это означает, что он определяет ситуации, когда один поток обращается к общей памяти без надлежащей синхронизации, в то время как другой поток может читать или записывать в то же место.
KTSAN: Наоборот фокусируется на общих гонках данных, происходящих между любыми потоками, независимо от того, отмечены обращения к памяти или нет. Это обеспечивает более широкий охват для обнаружения состояний гонок.
UBSan (Undefined Behavior Sanitizer) - еще один санитайзер, который состоит из двух дополнительных инструментов IntSan и BoundSan. IntSan (Integer Overflow Sanitizer) как можно понять из названия обнаруживает целочисленные переполнения. А BoundSan (BoundsSanitizer) обнаруживает доступ к памяти за пределами границ (OOB), это всяческого рода проверки массивов. UBSan универсальный инструмент который может работать как с ядром, так и пользовательскоми приложениями. Добавлен в ядро начиная с v4.5
MSan (MemorySanitizer) - этот санитайзер проверяет операции чтения из неинициализированной памяти.Неинициализированные значения возникают, когда память, выделенная в стеке или куче, считывается до ее записи. В основном применяется для user-mode приложений, в редкий случаях может применятся для отдельных модулей ядра (но лучше отдать эту задачу KernelMemorySanitizer).
LSan (LeakSanitizer) - это санитайзер применяется для поиска утечек памяти. Работает он c user-mode приложениями. LSan перехватывает функции выделения и освобождения памяти, такие как malloc() и free() и отслеживает их. LSan обычно работает в паре с ASan'ом.
AddressSanitizerLeakSanitizer
AddressSanitizer, ThreadSanitizer, MemorySanitizer - google/sanitizers
TSan (ThreadSanitizer) - аналогично KTSAN так же применяется для поиска дата рейсов и дедлоков. Но заточен под user-mode приложения.
ThreadSanitizerCppManual
AddressSanitizer, ThreadSanitizer, MemorySanitizer - google/sanitizers
Вопросы о KASAN и других санитайзерах можно всегда задать в списке рассылки kasan-dev@googlegroups.com.
address-sanitizer - Google Groups
groups.google.com
На последок хочу сказать, что поиск багов это не такое уж и сложное занятие, главное в этом деле смекалка и упорство. А комбинация различных методов и инструментов в совокупности помогают действительно отыскать поистине уникальные баги. Из этой статьи можно сделать следующий вывод, что бинарный баг-баунти не такой уж и сложный. Надеюсь вам понравился мой рассказ об AddressSanitizer'е и да прибудит с вами темная сила =)
Ссылки
Combining compile-time and run-time instrumentation for testing tools
swsys.ru/index.php?page=article&id=3593&lang=en
Finding Memory Bugs with Google Address Sanitizer (ASAN) on Microcontrollers
mcuoneclipse.com/2021/05/31/finding-memory-bugs-with-google-address-sanitizer-asan-on-microcontrollers
AddressSanitizer, или как сделать программы на C\С++ надежнее и безопаснее
youtube.com/watch?v=vKtNwALHb2k
Анатомия AddressSanitizer
youtube.com/watch?v=7WyBAUJ8UA8
Автор: weaver
Написано специально для xss.pro (с)