- Astra linux трассировка ptrace
- 1. чЧЕДЕОЙЕ
- 2. рПДТПВОЕЕ
- 2.лБЛ ТБВПФБЕФ ptrace().
- PTRACE_TRACEME:
- PTRACE_ATTACH:
- PTRACE_DETACH:
- PTRACE_PEEKTEXT, PTRACE_PEEKDATA, PTRACE_PEEKUSER:
- PTRACE_POKETEXT, PTRACE_POKEDATA, PTRACE_POKEUSER:
- PTRACE_SYSCALL, PTRACE_CONT:
- PTRACE_SINGLESTEP:
- PTRACE_KILL:
- 2.2 бРРБТБФОП-ЪБЧЙУЙНЩЕ ЪОБЮЕОЙС ДМС БТЗХНЕОФБ request
- PTRACE_GETREGS, PTRACE_GETFPREGS, PTRACE_GETFPXREGS:
- PTRACE_SETREGS, PTRACE_SETFPREGS, PTRACE_SETFPXREGS:
- 2.3 чПЪЧТБЭБЕНЩЕ ЪОБЮЕОЙС УЙУФЕНОПЗП ЧЩЪПЧБ ptrace()
- 3. оЕВПМШЫПК РТЙНЕТ.
- 4. ъБЛМАЮЕОЙЕ
- Введение в ptrace или инъекция кода в sshd ради веселья
- Что такое ptrace?
- Основы ptrace
- Инъекция в sshd
- Загружаем .so в sshd
- Конструктор в динамических библиотеках
- Динамическая библиотека sshd
- Инъекция в действии
Astra linux трассировка ptrace
фТБУУЙТПЧЛБ РТПГЕУУПЧ У РПНПЭША Ptrace — юБУФШ 1.
бЧФПТ: Sandeep S
рЕТЕЧПД: бОДТЕК лЙУЕМЕЧ
уЙУФЕНОЩК ЧЩЪПЧ ptrace СЧМСЕФУС ПУОПЧПК ПУОПЧ ДМС РТПЗТБНН-ПФМБДЮЙЛПЧ, ФБЛЙИ ЛБЛ gdb, ОП ЧУЕ ЦЕ РТЙОГЙРЩ ТБВПФЩ У ЬФЙН УЙУФЕНОЩН ЧЩЪПЧПН ОЕДПУФБФПЮОП ИПТПЫП ПУЧЕЭЕОЩ Ч ДПЛХНЕОФБГЙЙ, ЕУМЙ ОЕ УЮЙФБФШ, ЮФП УБНПК МХЮЫЕК ДПЛХНЕОФБГЙЕК СЧМСАФУС ЙУИПДОЩЕ ФЕЛУФЩ СДТБ! с РПУФБТБАУШ РТПДЕНПОУФТЙТПЧБФШ ПУОПЧОЩЕ РТЙЕНЩ РТЙ ТБВПФЕ У ptrace Й ОЕЛПФПТЩЕ ЕЗП ЖХОЛГЙПОБМШОЩЕ ЧПЪНПЦОПУФЙ, ДПУФХРОЩЕ Ч ЙОУФТХНЕОФБМШОЩИ УТЕДУФЧБИ РПДПВОЩИ gdb.
1. чЧЕДЕОЙЕ
ptrace() — ЬФП УЙУФЕНОЩК ЧЩЪПЧ, ЛПФПТЩК ДБЕФ ЧПЪНПЦОПУФШ ПДОПНХ РТПГЕУУХ ХРТБЧМСФШ ЙУРПМОЕОЙЕН ДТХЗПЗП. пО ФБЛ ЦЕ РПЪЧПМСЕФ ЙЪНЕОСФШ УПДЕТЦЙНПЕ РБНСФЙ ФТБУУЙТХЕНПЗП РТПГЕУУБ. фТБУУЙТХЕНЩК РТПГЕУУ ЧЕДЕФ УЕВС ЛБЛ ПВЩЮОП ДП ФЕИ РПТ РПЛБ ОЕ РПМХЮЙФ УЙЗОБМ. лПЗДБ ЬФП РТПЙУИПДЙФ, РТПГЕУУ РЕТЕИПДЙФ Ч УПУФПСОЙЕ ПУФБОПЧБ, Б РТПГЕУУ-ФТБУУЙТПЧЭЙЛ ЙОЖПТНЙТХЕФУС ПВ ЬФПН ЧЩЪПЧПН wait(). рПУМЕ ЬФПЗП РТПГЕУУ-ФТБУУЙТПЧЭЙЛ, ЮЕТЕЪ ЧЩЪПЧЩ ptrace, ПРТЕДЕМСЕФ ТЕБЛГЙА ФТБУУЙТХЕНПЗП РТПГЕУУБ. йУЛМАЮЕОЙЕ УПУФБЧМСЕФ УЙЗОБМ SIGKILL, ЛПФПТЩК УБНП УПВПК ТБЪХНЕЕФУС, ХОЙЮФПЦБЕФ РТПГЕУУ.
лТПНЕ ФПЗП, НПЦОП ЪБДБФШ РЕТЕИПД ФТБУУЙТХЕНПЗП РТПГЕУУБ Ч УПУФПСОЙЕ ПУФБОПЧБ РП ПРТЕДЕМЕООПНХ УПВЩФЙА, ЛПФПТПЕ ЧПЪОЙЛМП Ч ИПДЕ ЕЗП ЙУРПМОЕОЙС. ьФП РТПЙУИПДЙФ ФПМШЛП Ч ФПН УМХЮБЕ, ЕУМЙ РТПГЕУУ-ФТБУУЙТПЧЭЙЛ ХУФБОПЧЙМ ЛБЛЙЕ-МЙВП ЖМБЗЙ УПВЩФЙК Ч ЛПОФЕЛУФЕ ФТБУУЙТХЕНПЗП РТПГЕУУБ. фТБУУЙТПЧЭЙЛ НПЦЕФ ДБЦЕ ЪБЧЕТЫЙФШ ФТБУУЙТХЕНЩК РТПГЕУУ, ХУФБОПЧЙЧ РТЙ ЬФПН ЛПД ЕЗП ЪБЧЕТЫЕОЙС. рПУМЕ ЧЩРПМОЕОЙС ЛБЛЙИ-МЙВП ДЕКУФЧЙК ФТБУУЙТПЧЭЙЛ НПЦЕФ ЪБЧЕТЫЙФШ ПФМБЦЙЧБЕНЩК РТПГЕУУ ЙМЙ РТПДПМЦЙФШ ЕЗП ЙУРПМОЕОЙЕ.
пВТБФЙФЕ ЧОЙНБОЙЕ: Ptrace() ПЮЕОШ УЙМШОП ЪБЧЙУЙФ ПФ БРРБТБФОПК БТИЙФЕЛФХТЩ. рТЙМПЦЕОЙС, ЙУРПМШЪХАЭЙЕ ptrace, ПЮЕОШ ФСЦЕМП РЕТЕОПУСФУС ОБ ДТХЗЙЕ БРРБТБФОЩЕ РМБФЖПТНЩ.
2. рПДТПВОЕЕ
пВЯСЧМЕОЙЕ ptrace() ЧЩЗМСДЙФ УМЕДХАЭЙН ПВТБЪПН.
чЩЪПЧХ РЕТЕДБАФУС ЮЕФЩТЕ БТЗХНЕОФБ, ЗДЕ request — ПРТЕДЕМСЕФ ЮФП ОЕПВИПДЙНП УДЕМБФШ. pid — ЬФП ID ФТБУУЙТХЕНПЗП РТПГЕУУБ. addr — ЬФП УНЕЭЕОЙЕ Ч РПМШЪПЧБФЕМШУЛПН РТПУФТБОУФЧЕ ФТБУУЙТХЕНПЗП РТПГЕУУБ, ПФЛХДБ ВХДЕФ РТПЮЙФБОП УМПЧП ДБООЩИ Й ЧПЪЧТБЭЕОП Ч ЛБЮЕУФЧЕ ТЕЪХМШФБФБ ТБВПФЩ ЧЩЪПЧБ.
тПДЙФЕМШУЛЙК РТПГЕУУ НПЦЕФ РПТПДЙФШ ДПЮЕТОЙК РТПГЕУУ Й ЧЩРПМОСФШ ЕЗП ФТБУУЙТПЧЛХ РПУТЕДУФЧПН ЧЩЪПЧБ ptrace У БТЗХНЕОФПН request, ЙНЕАЭЙН ЪОБЮЕОЙЕ PTRACE_TRACEME. рТПГЕУУ-ФТБУУЙТПЧЭЙЛ НПЦЕФ ЧЩРПМОСФШ ФТБУУЙТПЧЛХ ХЦЕ УХЭЕУФЧХАЭЕЗП РТПГЕУУБ, ЙУРПМШЪХС ЪОБЮЕОЙЕ PTRACE_ATTACH ДМС БТЗХНЕОФБ request. ъОБЮЕОЙС, ЛПФПТЩЕ НПЦЕФ РТЙОЙНБФШ БТЗХНЕОФ request, ПВУХЦДБАФУС ОЙЦЕ.
2.лБЛ ТБВПФБЕФ ptrace().
чУСЛЙК ТБЪ, ЛПЗДБ ЧЩЪЩЧБЕФУС ptrace, Ч РЕТЧХА ПЮЕТЕДШ ЧЩРПМОСЕФУС ВМПЛЙТПЧЛБ СДТБ. б ОЕРПУТЕДУФЧЕООП РЕТЕД ЧПЪЧТБФПН ВМПЛЙТПЧЛБ УОЙНБЕФУС. тБУУНПФТЙН ТБВПФХ ptrace() ДМС ТБЪМЙЮОЩИ ЪОБЮЕОЙК БТЗХНЕОФБ request.
PTRACE_TRACEME:
ьФП ЪОБЮЕОЙЕ ЙУРПМШЪХЕФУС РТЙ ФТБУУЙТПЧЛЕ ДПЮЕТОЕЗП РТПГЕУУБ. лБЛ ХЦЕ ЗПЧПТЙМПУШ ЧЩЫЕ, МАВПК УЙЗОБМ (ЪБ ЙУЛМАЮЕОЙЕН SIGKILL), ЛБЛ РПУФХРЙЧЫЙК ПФ УЙУФЕНЩ, ФБЛ Й РПУФХРЙЧЫЙК ЮЕТЕЪ ЧЩЪПЧ exec, ПФ УБНПЗП РТПГЕУУБ, ЧЩОХЦДБЕФ РТПГЕУУ РЕТЕКФЙ Ч УПУФПСОЙЕ ПУФБОПЧБ, ЮФП РПЪЧПМСЕФ «ТПДЙФЕМА» ПРТЕДЕМСФШ ДБМШОЕКЫЙК ИПД ТБЪЧЙФЙС УПВЩФЙК. еДЙОУФЧЕООПЕ, ЮФП ДЕМБЕФ ptrace() Ч ЬФПН УМХЮБЕ — РТПЧЕТСЕФ, ХУФБОПЧМЕО МЙ ЖМБЗ PT_PTRACED ДМС ФЕЛХЭЕЗП РТПГЕУУБ. еУМЙ ЖМБЗ ОЕ ХУФБОПЧМЕО, ФП РТПЧЕТСАФУС РТБЧБ ДПУФХРБ Й ЖМБЗ ХУФБОБЧМЙЧБЕФУС. чУЕ ПУФБМШОЩЕ БТЗХНЕОФЩ ЙЗОПТЙТХАФУС.
PTRACE_ATTACH:
ьФП ЪОБЮЕОЙЕ ЙУРПМШЪХЕФУС Ч ФПН УМХЮБЕ, ЕУМЙ ОЕПВИПДЙНП ЧЩРПМОЙФШ ФТБУУЙТПЧЛХ УХЭЕУФЧХАЭЕЗП РТПГЕУУБ. еДЙОУФЧЕООПЕ ЪБНЕЮБОЙЕ: ОЙ ПДЙО РТПГЕУУ ОЕ УНПЦЕФ РПМХЮЙФШ ЛПОФТПМШ ОБД РТПГЕУУПН init ЙМЙ ОБД УБНЙН УПВПК. фТБУУЙТПЧЛБ ЬФЙИ РТПГЕУУПЧ СЧМСЕФУС ОЕДПРХУФЙНПК. чЩРПМОЙЧ ЧЩЪПЧ ptrace, У ЬФЙН ЪОБЮЕОЙЕН БТЗХНЕОФБ request, РТПГЕУУ УФБОПЧЙФУС «ТПДЙФЕМЕН» ДМС РТПГЕУУБ У ID ТБЧОЩН pid. пДОБЛП, ЧЩЪПЧ getpid(), ЧЩРПМОСЕНЩК «ДПЮЕТОЙН» РТПГЕУУПН, РП-РТЕЦОЕНХ ВХДЕФ ЧПЪЧТБЭБФШ PID ТЕБМШОПЗП ТПДЙФЕМС.
рПУМЕ ПВЩЮОПК РТПЧЕТЛЙ РТБЧ ДПУФХРБ, РТПЧЕТСЕФУС — ОЕ РТПЙЪЧПДЙФУС МЙ РПРЩФЛБ РПМХЮЙФШ ЛПОФТПМШ ОБД РТПГЕУУПН init ЙМЙ ОБД УБНЙН УПВПК, ОЕ ХУФБОПЧМЕО МЙ ЖМБЗ PT_PTRACED. еУМЙ РТПВМЕН ОЕ ЧПЪОЙЛМП, ФП ХУФБОБЧМЙЧБЕФУС ЖМБЗ PT_PTRACED. ъБФЕН ЙУРТБЧМСАФУС УУЩМЛЙ ФТБУУЙТХЕНПЗП РТПГЕУУБ, ОБРТЙНЕТ, ПО ХДБМСЕФУС ЙЪ ПЮЕТЕДЙ ЪБДБЮ, РПМЕ УУЩМЛЙ ОБ ТПДЙФЕМШУЛЙК РТПГЕУУ ЙЪНЕОСЕФУС (РПДМЙООЩК ТПДЙФЕМШ ПУФБЕФУС ФЕН ЦЕ УБНЩН). рТПГЕУУ УОПЧБ РПНЕЭБЕФУС Ч ПЮЕТЕДШ Й ЕНХ РЕТЕДБЕФУС УЙЗОБМ SIGSTOP. бТЗХНЕОФЩ addr Й data ЙЗОПТЙТХАФУС.
PTRACE_DETACH:
рТЕЛТБЭБЕФ ФТБУУЙТПЧЛХ РТПГЕУУБ. ч ЬФПФ НПНЕОФ РТЙОЙНБЕФУС ТЕЫЕОЙЕ П РТЕЛТБЭЕОЙЙ ЙМЙ РТПДПМЦЕОЙЙ ТБВПФЩ ФТБУУЙТХЕНПЗП РТПГЕУУБ. пФНЕОСАФУС ЧУЕ ЙЪНЕОЕОЙС, РТПЙЪЧЕДЕООЩЕ РП PTRACE_ATTACH/PTRACE_TRACEME. юЕТЕЪ БТЗХНЕОФ data ХУФБОБЧМЙЧБЕФУС ЛПД ЪБЧЕТЫЕОЙС. ч РПМЕ УЧСЪЙ, Х ФТБУУЙТХЕНПЗП РТПГЕУУБ, ЧПУУФБОБЧМЙЧБЕФУС УУЩМЛБ ОБ ОБУФПСЭЕЗП ТПДЙФЕМС. уВТБУЩЧБЕФУС ВЙФ РПЫБЗПЧПК ПФМБДЛЙ. й ОБЛПОЕГ, ФТБУУЙТХЕНЩК РТПГЕУУ «РТПВХЦДБЕФУС». бТЗХНЕОФ addr ЙЗОПТЙТХЕФУС.
PTRACE_PEEKTEXT, PTRACE_PEEKDATA, PTRACE_PEEKUSER:
рТЙ ЪОБЮЕОЙСИ БТЗХНЕОФБ request PTRACE_PEEKTEXT Й PTRACE_PEEKDATA, ТПДЙФЕМШУЛПНХ РТПГЕУУХ ЧПЪЧТБЭБЕФУС УМПЧП, ОБИПДСЭЕЕУС РП БДТЕУХ addr Ч БДТЕУОПН РТПУФТБОУФЧЕ ФТБУУЙТХЕНПЗП (ДПЮЕТОЕЗП) РТПГЕУУБ. пВБ ЬФЙ ЪОБЮЕОЙС request РТЙЧПДСФ Л ПДЙОБЛПЧЩН ТЕЪХМШФБФБН. ч УМХЮБЕ PTRACE_PEEKUSER — ЮЙФБЕФУС УМПЧП ЙЪ УФТХЛФХТЩ ФЙРБ user (УН. sys/user.h), ТБЪНЕЭЕООПК Ч УЙУФЕНОПН БДТЕУОПН РТПУФТБОУФЧЕ Й УППФЧЕФУФЧХАЭЕК ФТБУУЙТХЕНПНХ РТПГЕУУХ. бТЗХНЕОФ addr ЪБДБЕФ УНЕЭЕОЙЕ ПФ ОБЮБМБ УФТХЛФХТЩ. рТПЮЙФБООПЕ УМПЧП ЧПЪЧТБЭБЕФУС ЮЕТЕЪ БТЗХНЕОФ data. ч УМХЮБЕ ХУРЕИБ ЧПЪЧТБЭБЕФУС 0. йУИПДОПЕ ЪОБЮЕОЙЕ БТЗХНЕОФБ data ЙЗОПТЙТХЕФУС.
PTRACE_POKETEXT, PTRACE_POKEDATA, PTRACE_POKEUSER:
рТЙ ЪОБЮЕОЙСИ request, PTRACE_POKETEXT Й PTRACE_POKEDATA, РТПЙЪЧПДЙФУС ЪБРЙУШ ЪОБЮЕОЙС БТЗХНЕОФБ data РП БДТЕУХ addr Ч РТПУФТБОУФЧЕ ФТБУУЙТХЕНПЗП РТПГЕУУБ. пВБ ЬФЙ ЪОБЮЕОЙС РТЙЧПДСФ Л ПДЙОБЛПЧЩН ТЕЪХМШФБФБН.
ч УМХЮБЕ PTRACE_POKEUSER, РТПЙЪЧПДЙФУС ЪБРЙУШ Ч УФТХЛФХТХ ФЙРБ user , УППФЧЕФУФЧХАЭЕК ФТБУУЙТХЕНПНХ РТПГЕУУХ. уМЕДХЕФ ВЩФШ ПЮЕОШ ПУФПТПЦОЩН РТЙ ТБВПФЕ У ЬФЙН РБТБНЕФТПН, РПУЛПМШЛХ Ч ДБООПН УМХЮБЕ НЩ ЧФПТЗБЕНУС Ч ПВМБУФШ СДТБ. рПУМЕ ЧЩРПМОЕОЙС ВПМШЫПЗП ЛПМЙЮЕУФЧБ РТПЧЕТПЛ, ptrace ЧЩРПМОСЕФ ЪБРЙУШ Ч ХЛБЪБООХА РПЪЙГЙА УФТХЛФХТЩ, РТЙ ЬФПН ДПУФХРОЩНЙ ДМС ЪБРЙУЙ ПЛБЪЩЧБАФУС ДБМЕЛП ОЕ ЧУЕ ЬМЕНЕОФЩ УФТХЛФХТЩ. бТЗХНЕОФ addr Ч ДБООПН УМХЮБЕ ПРТЕДЕМСЕФ УНЕЭЕОЙЕ ПФОПУЙФЕМШОП ОБЮБМБ УФТХЛФХТЩ.
PTRACE_SYSCALL, PTRACE_CONT:
пВЕ ЬФЙ ЛПНБОДЩ БЛФЙЧЙТХАФ ФТБУУЙТХЕНЩК РТПГЕУУ. ч УМХЮБЕ PTRACE_SYSCALL ДПЮЕТОЕНХ РТПГЕУУХ РТЕДРЙУЩЧБЕФУС ПУФБОПЧЙФШУС ОБ УМЕДХАЭЕН УЙУФЕНОПН ЧЩЪПЧЕ. PTRACE_CONT — РТПУФП ЧПЪПВОПЧМСЕФ ТБВПФХ ФТБУУЙТХЕНПЗП РТПГЕУУБ. й Ч ФПН Й Ч ДТХЗПН УМХЮБЕ, ЕУМЙ БТЗХНЕОФ data ОЕ ТБЧЕО ОХМА ЙМЙ SIGSTOP, ptrace() РЕТЕДБЕФ ЕЗП РТПГЕУУХ ЛБЛ УЙЗОБМ, ЛПФПТЩК ОЕПВИПДЙНП ПВТБВПФБФШ. рТЙ ЬФПН ptrace() УВТБУЩЧБЕФ ВЙФ РПЫБЗПЧПК ФТБУУЙТПЧЛЙ Й ХУФБОБЧМЙЧБЕФ/УВТБУЩЧБЕФ ВЙФ ФТБУУЙТПЧЛЙ УЙУФЕНОЩИ ЧЩЪПЧПЧ. бТЗХНЕОФ addr ЙЗОПТЙТХЕФУС.
PTRACE_SINGLESTEP:
йНЕЕФ ФПФ ЦЕ УНЩУМ, ЮФП Й PTRACE_SYSCALL, ЪБ ЙУЛМАЮЕОЙЕН ФПЗП, ЮФП ФТБУУЙТХЕНЩК РТПГЕУУ ПУФБОБЧМЙЧБЕФУС РПУМЕ ЙУРПМОЕОЙС ЛБЦДПК ЙОУФТХЛГЙЙ. хУФБОБЧМЙЧБЕФ ВЙФ РПЫБЗПЧПК ФТБУУЙТПЧЛЙ. лБЛ Й ЧЩЫЕ, БТЗХНЕОФ data УПДЕТЦЙФ ЛПД ЪБЧЕТЫЕОЙС ДМС ФТБУУЙТХЕНПЗП РТПГЕУУБ. бТЗХНЕОФ addr ЙЗОПТЙТХЕФУС.
PTRACE_KILL:
йУРПМШЪХЕФУС ДМС ЪБЧЕТЫЕОЙС ФТБУУЙТХЕНПЗП РТПГЕУУБ. ъБЧЕТЫЕОЙЕ РТПЙЪЧПДЙФУС УМЕДХАЭЙН ПВТБЪПН. Ptrace() РТПЧЕТСЕФ — «ЦЙЧ» МЙ ФТБУУЙТХЕНЩК РТПГЕУУ, ЪБФЕН ХУФБОБЧМЙЧБЕФ ЛПД ЪБЧЕТЫЕОЙС ДПЮЕТОЕЗП РТПГЕУУБ Ч ЪОБЮЕОЙЕ sigkill, УВТБУЩЧБЕФ ВЙФ РПЫБЗПЧПК ФТБУУЙТПЧЛЙ Й БЛФЙЧЙТХЕФ ДПЮЕТОЙК РТПГЕУУ, ЛПФПТЩК Ч УППФЧЕФУФЧЙЙ У ЛПДПН ЪБЧЕТЫЕОЙС РТЕЛТБЭБЕФ УЧПА ТБВПФХ.
2.2 бРРБТБФОП-ЪБЧЙУЙНЩЕ ЪОБЮЕОЙС ДМС БТЗХНЕОФБ request
пРЙУБООЩЕ ЧЩЫЕ ЪОБЮЕОЙС БТЗХНЕОФБ request СЧМСАФУС БРРБТБФОП-ОЕЪБЧЙУЙНЩНЙ. ъОБЮЕОЙС, ПРЙУЩЧБЕНЩЕ ОЙЦЕ, РПЪЧПМСАФ ЮЙФБФШ/ЙЪНЕОСФШ ТЕЗЙУФТЩ РТПГЕУУПТБ ДПЮЕТОЕЗП РТПГЕУУБ, Б РПФПНХ ПЮЕОШ ФЕУОП УЧСЪБОЩ У БРРБТБФОПК ТЕБМЙЪБГЙЕК УЙУФЕНЩ. оБВПТ ДПУФХРОЩИ ТЕЗЙУФТПЧ ЧЛМАЮБЕФ Ч УЕВС ТЕЗЙУФТЩ ПВЭЕЗП ОБЪОБЮЕОЙС Й ТЕЗЙУФТЩ FPU (БТЙЖНЕФЙЮЕУЛПЗП УПРТПГЕУУПТБ).
PTRACE_GETREGS, PTRACE_GETFPREGS, PTRACE_GETFPXREGS:
рТЙ ЬФЙИ ЪОБЮЕОЙСИ request, РПУМЕ ПВЩЮОПК РТПЧЕТЛЙ РТБЧ ДПУФХРБ, РТПЙЪЧПДЙФУС ЛПРЙТПЧБОЙЕ ЪОБЮЕОЙК ТЕЗЙУФТПЧ ПВЭЕЗП ОБЪОБЮЕОЙС, ТЕЗЙУФТПЧ У РМБЧБАЭЕК ФПЮЛПК, ДПРПМОЙФЕМШОЩИ ТЕЗЙУФТПЧ У РМБЧБАЭЕК ФПЮЛПК ДПЮЕТОЕЗП РТПГЕУУБ Ч РЕТЕНЕООХА ТПДЙФЕМШУЛПЗП РТПГЕУУБ data. лПРЙТПЧБОЙЕ ЧЩРПМОСЕФУС У РПНПЭША ЖХОЛГЙК getreg() Й __put_user(), БТЗХНЕОФ addr ЙЗОПТЙТХЕФУС.
PTRACE_SETREGS, PTRACE_SETFPREGS, PTRACE_SETFPXREGS:
рТЙ ЬФЙИ ЪОБЮЕОЙСИ БТЗХНЕОФБ request ЧЩРПМОСЕФУС ЪБРЙУШ Ч ТЕЗЙУФТЩ РТПГЕУУПТБ ФТБУУЙТХЕНПЗП РТПГЕУУБ. ч ДБООПН УМХЮБЕ ДПУФХР Л ПФДЕМШОЩН ТЕЗЙУФТБН ПЗТБОЙЮЙЧБЕФУС. ъОБЮЕОЙС ТЕЗЙУФТПЧ ВЕТХФУС ЙЪ БТЗХНЕОФБ data. бТЗХНЕОФ addr ЙЗОПТЙТХЕФУС.
2.3 чПЪЧТБЭБЕНЩЕ ЪОБЮЕОЙС УЙУФЕНОПЗП ЧЩЪПЧБ ptrace()
ч УМХЮБЕ ХУРЕИБ ptrace() ЧПЪЧТБЭБЕФ ОПМШ. ч УМХЮБЕ ЧПЪОЙЛОПЧЕОЙС ПЫЙВЛЙ — ЧПЪЧТБЭБЕФУС ЪОБЮЕОЙЕ -1, Б ЛПД ПЫЙВЛЙ — Ч РЕТЕНЕООПК errno. рПУЛПМШЛХ РТЙ ЧЩРПМОЕОЙЙ ПРЕТБГЙК PEEKDATA/PEEKTEXT, ДБЦЕ Ч УМХЮБЕ ХУРЕИБ НПЦЕФ ВЩФШ ЧПЪЧТБЭЕОП ЪОБЮЕОЙЕ -1, ФП МХЮЫЕ ЧЩРПМОСФШ РТПЧЕТЛХ ОБ ОБМЙЮЙЕ ПЫЙВЛЙ РП РЕТЕНЕООПК errno. лПДЩ ПЫЙВПЛ НПЗХФ ВЩФШ УМЕДХАЭЙНЙ
EPERM : пФУХФУФЧЙЕ РТБЧ ДПУФХРБ.
ESRCH : фТЕВХЕНЩК РТПГЕУУ ОЕ ОБКДЕО ЙМЙ ХЦЕ ФТБУУЙТХЕФУС.
EIO : оЕДПРХУФЙНЩК ЛПД ЪБРТПУБ (request) ЙМЙ ЪБДБО ОЕДПРХУФЙНЩК БДТЕУ РБНСФЙ ДМС ЮФЕОЙС/ЪБРЙУЙ.
EFAULT : вЩМБ УДЕМБОБ РПРЩФЛБ ЪБРЙУЙ ЙОЖПТНБГЙЙ Ч ПВМБУФШ РБНСФЙ, ОП УЛПТЕЕ ЧУЕЗП ЬФБ РБНСФШ ОЕ УХЭЕУФЧХЕФ ЙМЙ ОЕДПУФХРОБ.
л УПЦБМЕОЙА, ЪБЮБУФХА ПЫЙВЛЙ EIO Й EFAULT РПТПЦДБАФУС РТБЛФЙЮЕУЛЙ ЙДЕОФЙЮОЩНЙ УЙФХБГЙСНЙ, ЙЪ-ЪБ ЮЕЗП ПЮЕОШ УМПЦОП ЙОФЕТРТЕФЙТПЧБФШ ТБЪОЙГХ НЕЦДХ ОЙНЙ.
3. оЕВПМШЫПК РТЙНЕТ.
еУМЙ ЧЩ ОБЫМЙ ПРЙУБОЙЕ БТЗХНЕОФПЧ ЮЕТЕУЮХТ УХИЙН, ОЕ ПФЮБЙЧБКФЕУШ. дБМЕЕ С РПРТПВХА РТЕДУФБЧЙФШ ТСД НБМЕОШЛЙИ РТПЗТБНН, ЛПФПТЩЕ РТПЙММАУФТЙТХАФ ЧУЕ ЧЩЫЕУЛБЪБООПЕ.
чПФ РЕТЧЩК РТЙНЕТ. ъДЕУШ ТПДЙФЕМШУЛЙК РТПГЕУУ РПДУЮЙФЩЧБЕФ ЮЙУМП ЙОУФТХЛГЙК, ЧЩРПМОЕООЩИ ФЕУФПЧПК РТПЗТБННПК, ЛПФПТБС ЪБРХУЛБЕФУС ЛБЛ ДПЮЕТОЙК РТПГЕУУ.
фЕУФПЧБС РТПЗТБННБ ЧЩЧПДЙФ УПДЕТЦЙНПЕ ФЕЛХЭЕЗП ЛБФБМПЗБ Й РПДУЮЙФЩЧБЕФ ЛПМЙЮЕУФЧП ЪБФТБЮЕООЩИ НБЫЙООЩИ ЙОУФТХЛГЙК.
уЛПРЙТХКФЕ ФЕЛУФ РТПЗТБННЩ Ч ФЕЛУФПЧЩК ТЕДБЛФПТ, УПИТБОЙФЕ ЕЕ Ч ЖБКМ file.c Й ДБКФЕ ЛПНБОДЩ ОБ ЧЩРПМОЕОЙЕ:
ч ТЕЪХМШФБФЕ ТБВПФЩ РТПЗТБННЩ, ОБ ЬЛТБО ВХДХФ ЧЩЧЕДЕОЩ УПДЕТЦЙНПЕ ФЕЛХЭЕЗП ЛБФБМПЗБ Й ЛПМЙЮЕУФЧП ЪБФТБЮЕООЩИ НБЫЙООЩИ ЙОУФТХЛГЙК. фЕРЕТШ РПРТПВХКФЕ РЕТЕКФЙ Ч ДТХЗПК ЛБФБМПЗ Й ЪБРХУФЙФШ РТПЗТБННХ ПФФХДБ. уТБЧОЙФЕ РПМХЮЕООЩЕ ТЕЪХМШФБФЩ. (пВТБФЙФЕ ЧОЙНБОЙЕ, ЕУМЙ Х ЧБУ НЕДМЕООБС НБЫЙОБ, ФП ЧЩЧПД НПЦЕФ ЪБОСФШ ДПЧПМШОП РТПДПМЦЙФЕМШОПЕ ЧТЕНС). (оБ P4 1.7 ззГ ОБ ЬФП ХЫМП ПЛПМП 7 УЕЛХОД. рТЙН.ТЕД.)
4. ъБЛМАЮЕОЙЕ
Ptrace() — ЬФП УТЕДУФЧП ПФМБДЛЙ РТПЗТБНН. пО НПЦЕФ ЙУРПМШЪПЧБФШУС Й ДМС ФТБУУЙТПЧЛЙ УЙУФЕНОЩИ ЧЩЪПЧПЧ. тПДЙФЕМШУЛЙК РТПГЕУУ НПЦЕФ ОБЮБФШ ФТБУУЙТПЧЛХ, ЧЩЪЧБЧ УОБЮБМБ ЖХОЛГЙА fork(2), ДМС ЪБРХУЛБ ДПЮЕТОЕЗП РТПГЕУУБ, Б ЪБФЕН ДПЮЕТОЙК РТПГЕУУ НПЦЕФ ЧЩРПМОЙФШ PTRACE_TRACEME, ЪБ ЛПФПТЩН (ЛБЛ РТБЧЙМП) УМЕДХЕФ ЧЩРПМОЕОЙЕ exec(3) (Ч РТЙНЕТЕ ЧЩЫЕ — ЬФП РТПЗТБННБ «ls»). ъБФЕН, РПУМЕ ЧЩРПМОЕОЙС ЛБЦДПК ЙОУФТХЛГЙЙ, ТПДЙФЕМШ НПЦЕФ РТПУНБФТЙЧБФШ ЪОБЮЕОЙС ТЕЗЙУФТПЧ РПФПНЛБ, ДБООЩЕ Ч РБНСФЙ Й ЧМЙСФШ ОБ РТПФЕЛБОЙЕ РТПГЕУУБ ЙУРПМОЕОЙС. ч УМЕДХАЭЕК ЮБУФЙ УФБФШЙ С РТЙЧЕДХ РТЙНЕТ РТПЗТБННЩ, ЛПФПТБС ЙУРПМШЪХЕФ ТБЪМЙЮОЩЕ ПУПВЕООПУФЙ ptrace(). дП УЛПТПК ЧУФТЕЮЙ!
Источник
Введение в ptrace или инъекция кода в sshd ради веселья
Цель, которой я задался, была весьма проста: узнать введённый в sshd пароль, используя ptrace. Конечно, это несколько искусственная задача, так как есть множество других, более эффективных, способов достичь желаемого (и с гораздо меньшей вероятностью получить SEGV ), однако, мне показалось клёвым сделать именно так.
Что такое ptrace?
Те, кто знаком с инъекциями в Windows, наверняка знают функции VirtualAllocEx() , WriteProcessMemory() , ReadProcessMemory() и CreateRemoteThread() . Эти вызовы позволяют выделять память и запускать потоки в другом процессе. В мире linux ядро предоставляет нам ptrace , благодаря которому отладчики могут взаимодействовать с запущенным процессом.
Ptrace предлагает несколько полезных для отладки операций, например:
- PTRACE_ATTACH — позволяет присоединиться к одному процессу, поставив на паузу отлаживаемый процесс
- PTRACE_PEEKTEXT — позволяет прочитать данные из адресного пространства другого процесса
- PTRACE_POKETEXT — позволяет записать данные в адресное пространство другого процесса
- PTRACE_GETREGS — читает текущее состояние регистров процесса
- PTRACE_SETREGS — записывает состояние регистров процесса
- PTRACE_CONT — продолжает выполнение отлаживаемого процесса
Хотя это неполный список возможностей ptrace, однако, я столкнулся с трудностями из-за отсутствия знакомых мне из Win32 функций. Например, в Windows можно выделить память в другом процессе с помощью функции VirtualAllocEx() , которая возвращает тебе указатель на свежевыделенную память. Так как в ptrace такого не существует, придётся импровизировать, если хочется внедрить свой код в другой процесс.
Ну что ж, давайте подумаем о том, как захватить управление над процессом с помощью ptrace.
Основы ptrace
Первое, что мы должны сделать — присоединиться к интересующему нас процессу. Чтобы сделать это, достаточно вызывать ptrace с параметром PTRACE_ATTACH:
Этот вызов прост как пробка, он принимает PID процесса, к которому мы хотим присоединиться. Когда происходит вызов, отправляется сигнал SIGSTOP, который вынуждает интересующий процесс остановиться.
После присоединения есть повод сохранить состояние всех регистров прежде, чем мы начнём что-то изменять. Это позволит нам восстановить работу программы позже:
Далее необходимо найти место, куда мы сможем записать наш код. Самый простой способ — извлечь информацию из файла maps, который можно найти в procfs для каждого процесса. Например, «/proc/PID/maps» у запущенного процесса sshd на Ubuntu выглядит так:
Нам необходимо найти область памяти, выделенную с правом на выполнение (скорее всего «r-xp»). Сразу, как найдём подходящую нам область, по аналогии с регистрами, сохраним содержимое, чтобы потом корректно восстановить работу:
С помощью ptrace можно читать по одному машинному слову данных (32 бита на х86 или 64 бита на х86_64) по указанному адресу, то есть для чтения бо́льшего количества данных необходимо совершить несколько вызовов, увеличивая адрес.
Примечание: в linux так же есть process_vm_readv() и process_vm_writev() для работы с адресным пространством другого процесса. Однако, в этой статье я буду придерживаться использования ptrace. При желании сделать что-то своё, лучше прочитать об этих функциях.
Теперь, когда мы сделали резервную копию понравившейся нам области памяти, мы можем начать перезапись:
Аналогично PTRACE_PEEKTEXT, этот вызов может записывать только по одному машинному слову за раз по указанному адресу. Так же, для записи больше одного машинного слова потребуется множество вызовов.
После загрузки своего кода необходимо передать ему управление. Чтобы не перезаписывать данные в памяти (например, стек), мы будем использовать сохранённые ранее регистры:
Наконец, мы можем продолжить выполнение с помощью PTRACE_CONT:
Но как мы узнаем, что наш код закончил выполнение? Мы будем использовать программное прерывание, так же известное как инструкция «int 0x03», генерирующее SIGTRAP. Мы будем ждать этого с помощью waitpid():
waitpid() — блокирующий вызов, который дождётся остановки процесса с идентификатором PID и запишет причину остановки в переменную status. Здесь очень кстати есть куча макросов, которые упростят жизнь в выяснении причины остановки.
Чтобы узнать, была ли остановка из-за SIGTRAP (по причине вызова int 0x03), мы можем сделать так:
В этот момент наш встроенный код уже выполнился и всё, что нам требуется — восстановить исходное состояние процесса. Восстановим все регистры:
Затем вернём оригинальные данные в памяти:
И отсоединимся от процесса:
На этом хватит теории. Двинемся к более интересной части.
Инъекция в sshd
Я должен предупредить, что есть некоторая вероятность уронить sshd, так что будьте осторожны и, пожалуйста, не пытайтесь проверять это на рабочей системе и тем более, на удалённой системе через SSH 😀
Более того, есть несколько более хороших способов достичь того же результата, я демонстрирую именно этот исключительно в качестве весёлого способа показать мощь ptrace (согласитесь, это круче инъекции в Hello World 😉
Единственное, что я хотел сделать — это получить комбинацию логин-пароль из запущенного sshd, когда пользователь проходит аутентификацию. При просмотре исходного кода мы можем видеть что-то такое:
Это выглядит, как отличное место для попытки изъять логин/пароль, переданные пользователем в открытом виде.
Нам хочется найти сигнатуру функции, которая позволит нам найти её [функцию] в памяти. Я использую мою любимую утилиту для дизасемблирования, radare2:
Необходимо найти последовательность байт, которая уникальна и встречается только в функции auth_password. Для этого мы воспользуемся поиском в radare2:
Так случилось, что последовательность xor rdx, rdx; cmp rax, 0x400 подходит под наши требования и встречается всего один раз во всём ELF-файле.
В качестве примечания… Если у вас нет этой последовательности, убедитесь, что у вас самая новая версия, которая так же закрывает уязвимость середины 2016. (в версии 7.6 такая последовательность так же есть и уникальна — прим.пер.)
Следующий шаг — инъекция кода.
Загружаем .so в sshd
Для загрузки нашего кода в sshd мы сделаем небольшую заглушку, которая позволит нам вызывать dlopen() и загрузить динамическую библиотеку, которая уже осуществит подмену «auth_password».
dlopen() — вызов для динамической линковки, который принимает в аргументах путь до динамической библиотеки и загружает её в адресное пространство вызывающего процесса. Эта функция находится в libdl.so, которая динамически линкуется к приложению.
К счастью, в нашем случае libdl.so уже загружена в sshd, так что нам остаётся только выполнить dlopen(). Однако, из-за ASLR очень маловероятно, что dlopen() будет в одном и том же месте каждый раз, так что придётся найти её адрес в памяти sshd.
Для того, чтобы найти адрес функции, нужно посчитать смещение — разность между адресом функции dlopen() и начальным адресом libdl.so:
Теперь, когда мы посчитали смещение, нужно найти начальный адрес libdl.so из maps-файла:
Зная базовый адрес libdl.so в sshd (0x7f0490a0d000, как следует из скриншота выше), мы можем добавить смещение и получить адрес dlopen(), чтобы вызывать из кода-инъекции.
Все необходимые адреса передадим через регистры с помощью PTRACE_SETREGS.
Так же необходимо записать путь до вживляемой библиотеки в адресное пространство sshd, например:
Делая как можно во время подготовки инъекции и загружая указатели на аргументы прямо в регистры, мы можем сделать код-инъекцию проще. Например:
То есть, код-инъекция весьма прост:
Настало время создать нашу динамическую библиотеку, которая будет загружена кодом-инъекцией.
Прежде, чем мы двинемся дальше, рассмотрим одну важную вещь, которая будет использована… Конструктор динамической библиотеки.
Конструктор в динамических библиотеках
Динамические библиотеки могут выполнять код при загрузке. Для этого необходимо пометить функции декоратором «__attribute__((constructor))». Например:
Скопилировать можно простой командой:
А затем проверить работоспособность:
Когда библиотека загрузится, конструктор так же вызовется:
Мы так же используем эту функциональность, чтобы сделать нашу жизнь проще при инъекции кода в адресное пространство другого процесса.
Динамическая библиотека sshd
Теперь, когда у нас есть возможность загрузить нашу динамическую библиотеку, нужно создать код, который изменит поведение auth_password() во времени выполнения.
Когда наша динамическая библиотека загружена, мы можем найти начальный адрес sshd с помощью файла «/proc/self/maps» в procfs. Мы ищем область с правами «r-x», в которой мы будем искать уникальную последовательность в auth_password():
Раз у нас есть диапазон адресов для поиска, ищем функцию:
Когда у нас нашлось совпадение, необходимо использовать mprotect(), чтобы изменить права на доступ к области памяти. Это всё потому что область памяти доступна на чтение и выполнение, а для изменения на ходу требуются права на запись:
Отлично, у нас есть право на запись в нужную область памяти и теперь настало время добавить в начале функции auth_password небольшой трамплин, который передаст управление в хук:
Это эквивалентно такому коду:
Конечно, адрес 0x4142434445464748 нам не подходим и он будет заменён на адрес нашего хука:
Теперь мы можем просто вставить наш трамплин в sshd. Чтобы инъекция была красивой и чистой, вставим трамплин в самое начало функции:
Теперь мы должны реализовать хук, который будет заниматься логгированием проходящих данных. Мы должны быть уверены, что сохранили все регистры до начала хука и восстановили перед возвращением к оригинальному коду:
Ну и это всё… в каком-то смысле…
К сожалению, после всего проделанного, это ещё не всё. Даже если инъекция кода в sshd удалась, можно заметить, что искомые пользовательские пароли всё ещё недоступны. Это связано с тем, что sshd на каждое соединение создает нового ребёнка. Именно новый ребёнок обрабатывает подключение и именно в него мы должны установить хук.
Чтобы быть уверенным, что мы работает с детьми sshd, я решил сканировать procfs на stats файлы, в которых указан Parent PID sshd. Как только находится такой процесс, инжектор запускается и для него.
В этом есть даже свои плюсы. Если всё пойдёт не по плану и код-инъекция упадёт с SIGSEGV, будет убит только процесс одного пользователя, а не родительский процесс sshd. Не самое большое утешение, но оно явно делает отладку проще.
Инъекция в действии
Окей, давай посмотрим демо:
Полный код можно найти здесь.
Надеюсь, это путешествие подарило тебе достаточно информации для того, чтобы потыкать ptrace самостоятельно.
Хочу поблагодарить следующих людей и сайты, которые помогли разобраться с ptrace:
Источник