Threadless Injection. Делаем инъекции в чужие процессы, чтобы обойти EDR

Се­год­ня мы погово­рим о тех­нике инъ­екции в сто­рон­ний про­цесс, которая называ­ется Threadless Injection. На момент написа­ния статьи она работа­ла на Windows 11 23H2 x64 с акти­виро­ван­ными средс­тва­ми защиты ОС на изо­лиро­ван­ной от сети вир­туаль­ной машине. info

Чи­тай так­же мою пре­дыду­щую статью, где я показы­вал, как устро­ена и как реали­зует­ся тех­ника инжекта под наз­вани­ем Process Ghosting.

Итак, давай вспом­ним, как про­исхо­дит стан­дар­тная инъ­екция шелл‑кода с пос­леду­ющим его выпол­нени­ем.

  • По­луче­ние дес­крип­тора про­цес­са (OpenProcessNtOpenProcess).
  • Вы­деле­ние памяти для полез­ной наг­рузки (VirtualAllocExNtMapViewOfSection).
  • За­пись полез­ной наг­рузки в эту память (WriteProcessMemoryGhost Writing).
  • Вы­пол­нение шелл‑кода (CreateRemoteThreadNtQueueApcThread).
  • Эта пос­ледова­тель­ность хорошо извес­тна всем средс­твам EDR, и если какое‑то ПО ее реали­зует, то сра­зу будет крас­ный флаг и завер­шение про­цес­са.

    Нель­зя ли все это написать таким обра­зом, что­бы дей­ствия выпол­нялись те же, но без пря­мого исполь­зования перечис­ленных фун­кций WinAPI? С пер­выми шагами такое про­делать мож­но, но с выпол­нени­ем шелл‑кода все не так прос­то. Пря­мой вызов фун­кций CreateRemoteThreadNtQueueApcThread даст алерт EDR с веро­ятностью 100%.

    Сло­вом, что­бы обвести защиту вок­руг паль­ца, нам надо сло­мать эту пос­ледова­тель­ность. Нап­ример, почему бы не перех­ватить какие‑нибудь вызовы API в сто­рон­нем при­ложе­нии, в экспор­тиру­емой фун­кции DLL и потом зас­тавить эту фун­кцию работать на нас?

    warning

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

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

  • Най­ти область памяти code cave, которая смо­жет вмес­тить наш шелл‑код и трам­плин.
  • За­писать шелл‑код и трам­плин в эту память.
  • Про­пат­чить экспор­тиру­емую фун­кцию DLL, нас­тро­ив ее на запуск нашего кода.
  • По­дож­дать вызова этой фун­кции, что­бы шелл‑код выпол­нился.
  • Но в динами­чес­ких биб­лиоте­ках могут быть сот­ни и тысячи фун­кций, и не факт, что ран­домно выб­ранная нам подой­дет. Ведь нет никаких гаран­тий, что она будет выз­вана в разум­ное для нас вре­мя или вооб­ще будет выз­вана.

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

    Но не сле­дует зло­упот­реблять этим пра­вилом: если при­ложе­ние вызыва­ет API слиш­ком час­то (нап­ример, нес­коль­ко раз в секун­ду) и ты захочешь перех­ватить вызов, то неиз­бежны раз­ные глю­ки.

    Что­бы про­вес­ти подоб­ное иссле­дова­ние, вос­поль­зуем­ся прог­раммой API Monitor. В этой же прог­рамме мы смо­жем уви­деть, как в реаль­ном вре­мени про­исхо­дит вызов WinAPI, какие дей­ствия в инте­ресу­ющей нас прог­рамме на это вли­яют. Кро­ме того, мож­но уви­деть, какие DLL при­цеп­лены к про­цес­су и какие API они реали­зуют (то есть это не прос­то спи­сок WinAPI непонят­но отку­да). Исхо­дя из дан­ных монито­рин­га, мы дол­жны решить для себя, какую фун­кцию из экспор­та исполь­зуемой биб­лиоте­ки перех­ватывать.

    При­мер исполь­зования прог­раммы API Monitor для прос­мотра вызыва­емых фун­кций WinAPI

    Пос­ле того как подопыт­ная прог­рамма иссле­дова­на и нуж­ные WinAPI выяв­лены, мож­но начинать кодить.

    Кодим

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

    Источник: xakep.ru

    Ответить

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