Автору видео реально большой респект. Помню, как на курсе АКС (архитектура компьютерных систем) в ВУЗе проходили данный простенький эксплойт, на специально еще заготовленной редхет линухе с полностью консольным интерфейсом, где и нужные программы стояли, штук 20 (на каждый вариант) вот таких вот небезопасных с точки зрения буфера программ, и gdb. Что лектор, что практик, хоть я этих мужчин уважаю очень сильно, не смогли так ясно и по простому объяснить переполнение буфера студентоте, что многие, чтоб просто как-то защитить лабу, чтоб закрыть ИУП, как роботы повторяли за теми, кто вроде как понял, а по итогу не могли толком ничего на защите ответить, соответственно и баллы получали такие, какие и заслужили. Я хоть этот материал и понял, и типа вроде и помню, но это освежило память, да и само объяснение очень наглядное, намного лучше, чем было в моем вузе. Я думаю - такое моим однопоточникам бы тогда показать, то все бы лабораторную на максимальный балл сдали)
Приветствую! Я не программист, но лет 20 назад изучал ассемблер, и, в принципе, ассемблерный код немного понимаю. И в своё время меня удивляло, откуда берётся переполнение буфера, если на ассемблере всегда контролируешь размер передаваемых переменных. Мне непонятно, почему буфер расположен в стеке, а не в отдельной области памяти?
Стек - это и есть область памяти, просто работа с ней производится своеобразно. При желании можно работать со стековой памятью как с обыкновенной. Организация такой работы связана с экономией ресурсов памяти и процессорных мощностей для организации функционирования локальных переменных. Используемый размер памяти то растёт (входим в функцию), то уменьшается (выходим из функции). Если бы не было стековой организации работы с локальными переменными, то используемый размер памяти постоянно бы рос и она быстро бы заканчивалась. Можно было бы обойтись без стека, выделяя и освобождая память для локальных переменных - именно так иногда и делается, когда её размер можно определить только динамически - в процессе выполнения программы. В таком случае нужно было бы использовать системные функции malloc и free для выделения и освобождения памяти. Но это функции - значит будет отниматься процессорная мощность. На ассемблере не всегда контролируется размер передаваемых переменных. В коде используются функции библиотеки Си. Они уже написаны. Мы их просто вызываем с помощью ассемблерных команд, точно так, как могли бы вызвать с помощью кода на Си. Некоторые из этих функций (gets) не предусматривают ограничения количества символов строки-аргумента адрес которой передаётся функции. Поэтому и существует уязвимость. Спасибо за интерес к каналу.
@@firststepsforward Плюс ко всему производители компов сильно любят экономить денежки, поэтому ставить лишние виртуальные машинки и песочницы им было в лом и железо тогда этого не позволяло, так что имеем то что имеем!
Да. Первый процессор x86 был представлен в 1978 году. Экономия памяти тогда была очень актуальна. Внедрили стековое решение... До сих пор оно эксплуатируется. Мы живём на наработках 1978 года :).
ты сам все путаешь. и в си, и в плюсах, и даже в ассемблере, переполнение буфера происходит по одной причине: ты пишешь данные за пределы выделенной памяти. не важно, стек это, куча или статическая область. автоматическое выделение в стеке не снимает с тебя ответственности за контроль границ. "эффективность" стека тут вообще ни при чем. переполнение буфера - это всегда ошибка программиста, который не проконтролировал размер данных. и да, я прекрасно знаю, как работает стек, и как раз поэтому понимаю, что переполнение буфера - это не проблема "абстракций", а банальная ошибка доступа к памяти. и еще, выделение памяти под буфер в куче не сильно увеличивает накладные расходы, если делать это грамотно.
@@firststepsforward буфер - это просто область памяти, а стек - это структура данных, которая организует работу с памятью по принципу LIFO. стек используется для хранения локальных переменных и адресов возврата, но это не значит, что все локальные переменные являются буферами. рост и уменьшение стека связаны с вызовами функций, а не с работой с буферами. malloc и free используются для динамического выделения памяти в куче, а не в стеке. и да, они "отнимают процессорную мощность", как и любая другая операция. на ассемблере ты можешь контролировать все, что угодно, включая размер передаваемых переменных. gets - это плохой пример, потому что это заведомо небезопасная функция. использование gets - это ошибка программиста, а не проблема ассемблера или си. уязвимость возникает не из-за отсутствия "ограничения количества символов", а из-за того, что программист не проверяет размер данных перед записью в буфер. "экономия ресурсов" тут вообще не при чем.
Нет. Во-первых, Канарейку на стек посадили в Линуксе и очень давно. Настолько давно, что там это научились перепрыгивать уже лет 15 назад. Во-вторых - в Windows пошли сразу путём ASLR и DEP . Но это обходится - ролики на эту тему планирую выложить. В третьих - как же не работает, когда работает :).
@firststepsforward тестил недавно DEP включён, пример собран msvc 2022 с включённым GS параметром. Ведёт себя по-разному то на ret выкидывает В общем трюк не проходит...
Я ещё раз повторюсь. То, что изложено в видео - работает. На бусти выложен шелкод и эксплоит. В данном случае не нужно выполнять код в стеке. В данном случае в стек записываются данные - другой адрес возврата. Канарейка бы спасала в этом случае, но MS VS (у меня 2019) и gcc (Pelles C) по умолчанию не включают её в проекте для Windows. Не будет работать по этому шелкоду при ASLR (включено по умолчанию в MS VS 2019) - потому что шелкод упрощён (канал вообще-то, для начинающих) и динамически не отслеживает реальный адрес, который естественно меняется при каждом новом запуске. Возможно, конечно, что в каких-то других средах разработки ( MS VS 2022) дефолтные настройки другие. Но Вы же понимаете, что стопроцентно действующих уязвимостей не бывает. Я делал всё как на видео. Среда разработки - RadAsm, ассемблер - masm32. Настройки по шаблону Console App->WinCon.tpl по умолчанию. Шелкод запускается коммандной строкой. Всё работает. И ещё раз повторюсь: Обойти запрет на исполнение в буфере (DEP) также можно достаточно просто. Спасибо за интерес к каналу!
Спасибо! Не преувеличивайте! Я не умею принципиальные схемы без пояснений читать... А сегодня не без помощи Ютуба с трудом прозвонил сломавшуюся кофемолку... Завтра поеду за термопредохранителем :). Так что, Вам аналогичный респект :)!
Это очень важная тема, с которой хотелось наконец разобраться, спасибо большое!
Автору видео реально большой респект.
Помню, как на курсе АКС (архитектура компьютерных систем) в ВУЗе проходили данный простенький эксплойт, на специально еще заготовленной редхет линухе с полностью консольным интерфейсом, где и нужные программы стояли, штук 20 (на каждый вариант) вот таких вот небезопасных с точки зрения буфера программ, и gdb.
Что лектор, что практик, хоть я этих мужчин уважаю очень сильно, не смогли так ясно и по простому объяснить переполнение буфера студентоте, что многие, чтоб просто как-то защитить лабу, чтоб закрыть ИУП, как роботы повторяли за теми, кто вроде как понял, а по итогу не могли толком ничего на защите ответить, соответственно и баллы получали такие, какие и заслужили.
Я хоть этот материал и понял, и типа вроде и помню, но это освежило память, да и само объяснение очень наглядное, намного лучше, чем было в моем вузе. Я думаю - такое моим однопоточникам бы тогда показать, то все бы лабораторную на максимальный балл сдали)
Благодарю!
Очень приятно слышать!
Заходите к нам на чат а Телеге :).
Как же красиво и четко всё описано. Большое спасибо автору!
Пожалуйста!
Автор красавчик, и видео интересное сделал, и в комментариях зо зрителям активно общается, респект!
Благодарю!
Приветствую! Я не программист, но лет 20 назад изучал ассемблер, и, в принципе, ассемблерный код немного понимаю. И в своё время меня удивляло, откуда берётся переполнение буфера, если на ассемблере всегда контролируешь размер передаваемых переменных. Мне непонятно, почему буфер расположен в стеке, а не в отдельной области памяти?
Стек - это и есть область памяти, просто работа с ней производится своеобразно. При желании можно работать со стековой памятью как с обыкновенной.
Организация такой работы связана с экономией ресурсов памяти и процессорных мощностей для организации функционирования локальных переменных.
Используемый размер памяти то растёт (входим в функцию), то уменьшается (выходим из функции). Если бы не было стековой организации работы с локальными переменными, то используемый размер памяти постоянно бы рос и она быстро бы заканчивалась.
Можно было бы обойтись без стека, выделяя и освобождая память для локальных переменных - именно так иногда и делается, когда её размер можно определить только динамически - в процессе выполнения программы. В таком случае нужно было бы использовать системные функции malloc и free для выделения и освобождения памяти.
Но это функции - значит будет отниматься процессорная мощность.
На ассемблере не всегда контролируется размер передаваемых переменных.
В коде используются функции библиотеки Си. Они уже написаны. Мы их просто вызываем с помощью ассемблерных команд, точно так, как могли бы вызвать с помощью кода на Си.
Некоторые из этих функций (gets) не предусматривают ограничения количества символов строки-аргумента адрес которой передаётся функции. Поэтому и существует уязвимость.
Спасибо за интерес к каналу.
@@firststepsforward Плюс ко всему производители компов сильно любят экономить денежки, поэтому ставить лишние виртуальные машинки и песочницы им было в лом и железо тогда этого не позволяло, так что имеем то что имеем!
Да.
Первый процессор x86 был представлен в 1978 году. Экономия памяти тогда была очень актуальна. Внедрили стековое решение...
До сих пор оно эксплуатируется. Мы живём на наработках 1978 года :).
ты сам все путаешь. и в си, и в плюсах, и даже в ассемблере, переполнение буфера происходит по одной причине: ты пишешь данные за пределы выделенной памяти. не важно, стек это, куча или статическая область. автоматическое выделение в стеке не снимает с тебя ответственности за контроль границ. "эффективность" стека тут вообще ни при чем. переполнение буфера - это всегда ошибка программиста, который не проконтролировал размер данных. и да, я прекрасно знаю, как работает стек, и как раз поэтому понимаю, что переполнение буфера - это не проблема "абстракций", а банальная ошибка доступа к памяти. и еще, выделение памяти под буфер в куче не сильно увеличивает накладные расходы, если делать это грамотно.
@@firststepsforward буфер - это просто область памяти, а стек - это структура данных, которая организует работу с памятью по принципу LIFO. стек используется для хранения локальных переменных и адресов возврата, но это не значит, что все локальные переменные являются буферами. рост и уменьшение стека связаны с вызовами функций, а не с работой с буферами. malloc и free используются для динамического выделения памяти в куче, а не в стеке. и да, они "отнимают процессорную мощность", как и любая другая операция. на ассемблере ты можешь контролировать все, что угодно, включая размер передаваемых переменных. gets - это плохой пример, потому что это заведомо небезопасная функция. использование gets - это ошибка программиста, а не проблема ассемблера или си. уязвимость возникает не из-за отсутствия "ограничения количества символов", а из-за того, что программист не проверяет размер данных перед записью в буфер. "экономия ресурсов" тут вообще не при чем.
Доброе утро
Лайк поставил 👍
Спасибо!
К сожалению этот метод не работает с тех пор как посадили кукушку на стек.
Нет.
Во-первых, Канарейку на стек посадили в Линуксе и очень давно. Настолько давно, что там это научились перепрыгивать уже лет 15 назад.
Во-вторых - в Windows пошли сразу путём ASLR и DEP . Но это обходится - ролики на эту тему планирую выложить.
В третьих - как же не работает, когда работает :).
@firststepsforward тестил недавно DEP включён, пример собран msvc 2022 с включённым GS параметром. Ведёт себя по-разному то на ret выкидывает
В общем трюк не проходит...
Я ещё раз повторюсь. То, что изложено в видео - работает. На бусти выложен шелкод и эксплоит. В данном случае не нужно выполнять код в стеке. В данном случае в стек записываются данные - другой адрес возврата.
Канарейка бы спасала в этом случае, но MS VS (у меня 2019) и gcc (Pelles C) по умолчанию не включают её в проекте для Windows.
Не будет работать по этому шелкоду при ASLR (включено по умолчанию в MS VS 2019) - потому что шелкод упрощён (канал вообще-то, для начинающих) и динамически не отслеживает реальный адрес, который естественно меняется при каждом новом запуске.
Возможно, конечно, что в каких-то других средах разработки ( MS VS 2022) дефолтные настройки другие.
Но Вы же понимаете, что стопроцентно действующих уязвимостей не бывает.
Я делал всё как на видео. Среда разработки - RadAsm, ассемблер - masm32. Настройки по шаблону Console App->WinCon.tpl по умолчанию. Шелкод запускается коммандной строкой.
Всё работает.
И ещё раз повторюсь: Обойти запрет на исполнение в буфере (DEP) также можно достаточно просто.
Спасибо за интерес к каналу!
@@firststepsforward я порой просто поражаюсь вашими знаниями) спасибо что делитесь
Спасибо!
Не преувеличивайте!
Я не умею принципиальные схемы без пояснений читать...
А сегодня не без помощи Ютуба с трудом прозвонил сломавшуюся кофемолку...
Завтра поеду за термопредохранителем :).
Так что, Вам аналогичный респект :)!