Kai tikėjausi toliau diskutuoti šia tema, leiskite jums papasakoti apie pažeidžiamumo istoriją, teoriją ir praktiką. Mes visi jau girdėjome, kad saugumo trūkumai gali kainuoti daug, visi žinome, kad turime nuolat atnaujinti savo programinę įrangą, visi žinome, kad daugelį atnaujinimų sukelia saugos klaidos. Bet šiandien aš jums šiek tiek papasakosiu, kaip šios klaidos randamos ir išnaudojamos. Tačiau prieš tai mes patiksliname keletą detalių, kad galėtume geriau apžvelgti.
Prieš pradėdami
Pirmiausia noriu jums pasakyti, kad daugiausia dėmesio skirsime pirmajam pažeidžiamumui, kurį išmokau išnaudoti, žinomam Buferio perpildymas, šiame pažeidžiamume pasinaudodami atminties patikrinimo trūkumu, kad atliktume įdomių dalykų things Bet paaiškinkime šiek tiek daugiau apie tai.
Tai nebus realaus pasaulio scenarijus
Negaliu sau leisti jų išmokyti nutraukti bet kokią matomą programą 🙂, nes tai pavojinga jų kompiuteriams, antra, nes tam prireiktų daugiau nei mano įprasta žodžių kvota.
Vykstame į kelionę į 80-uosius
Tai, ką jums parodysiu, galiu padaryti savo nešiojamuoju kompiuteriu, tačiau tai nereiškia, kad šiandien tai galima padaryti paprastai - daugelis šių sąvokų jau buvo panaudotos tiek kartų, kad atsirado naujų apsaugos metodų ir naujų būdų, kaip jų išvengti. 😛 bet tai grąžina mus į tą pačią vietą, nėra vietos visa tai pasakyti 🙂
Tai gali neveikti jūsų procesoriuje
Nors aš naudosiu labai paprastą pavyzdį, noriu, kad nuo pat pradžių būtų visiškai aišku, jog detalių yra tiek daug ir tiek įvairių, kad lygiai taip pat, kaip gali pasirodyti tas pats kaip aš, jei norite išbandyti, norimas efektas taip pat gali nepasiekti 🙂 Bet jūs galite įsivaizduoti, kad negaliu paaiškinti, jog šioje erdvėje, juolab, kad su šia įžanga aš jau paėmiau daugiau nei 300 žodžių, taigi mes einame tiesiai į savo tašką.
Kas yra a Buferio perpildymas
Norėdami atsakyti į tai, pirmiausia turime suprasti pirmąją šio derinio pusę.
Buferiai
Kadangi viskas yra susijusi su atmintimi kompiuteryje, logiška, kad turi būti tam tikro tipo informacijos talpykla. Kai kalbėsime apie įėjimai o išėjimai, mes pereiname tiesiai į sąvoką buferiai. Kad jis būtų trumpas, a buferis Tai apibrėžto dydžio atminties erdvė, kurioje ketiname saugoti paprastą informacijos kiekį
Kaip rodo pavadinimas, įvyksta perpildymai, kai buferis užpildo daugiau informacijos, nei ji gali sutvarkyti. Bet kodėl tai svarbu?
Sukrauti
Taip pat žinomi kaip kaminai, jie yra abstraktus duomenų tipas, kuriame mes galime kamino informacija, jų pagrindinė ypatybė yra ta, kad jie turi užsakymą LIFO (paskutinis pirmas išėjimas). Pagalvokime sekundę apie plokščių šūsnį, mes dedame jas po vieną ir tada išimame po vieną iš viršaus, todėl paskutinė mūsų įdėta plokštė (ta, kuri yra viršuje) yra pirmoji plokštė kad išimsime, aišku, jei vienu metu galime išimti tik vieną plokštelę ir nusprendžiame tai padaryti tokia tvarka: P.
Dabar, kai žinote šias dvi sąvokas, turime jas sutvarkyti. Šūsniai yra svarbūs, nes kiekviena mūsų vykdoma programa turi savo vykdymo kamino. Bet šis kaminas turi tam tikra charakteristika, auga žemyn. Vienintelis dalykas, kurį reikia žinoti apie tai, yra tai, kad kol programa veikia, kai iškviečiama funkcija, krūva pereina nuo skaičiaus X atmintyje prie skaičiaus (Xn). Tačiau norėdami tęsti turime suprasti dar vieną sąvoką.
Rodyklės
Tai yra koncepcija, kuri išprotėja daugelį programuotojų, kai jie pradeda veikti C pasaulyje, iš tikrųjų didelę C programavimo galią iš dalies lemia rodyklių naudojimas. Kad būtų paprasčiau, rodyklė nurodo atminties adresą. Tai skamba sudėtingai, bet nėra taip sudėtinga, mes visi turime savo mašinose RAM, tiesa? Na, tai galima apibrėžti kaip nuoseklus blokų išdėstymas, šios vietos paprastai išreiškiamos šešioliktainiais skaičiais (nuo 0 iki 9, tada nuo A iki F, pvz., 0x0, 0x1, 0x6, 0xA, 0xF, 0x10). Čia kaip smalsus užrašas, 0x10 NE yra lygus 10 😛, jei perskaičiuosime ją po kablelio, būtų tas pats, kas sakyti 15. Tai taip pat iš pradžių painioja daugiau nei vieną, bet leiskime prie jo.
Registros
Procesoriai dirba su daugeliu registros, kurios veikia perduodant vietas iš fizinės atminties į procesorių, architektūroms, naudojančioms 64 bitus, registrų skaičius yra didelis ir čia sunku jį apibūdinti, tačiau norint suprasti idėją, registrai yra tarsi rodyklės, be kitų daiktai, atminties vieta (vieta).
Dabar praktikuokitės
Aš žinau, kad iki šiol tai buvo daug informacijos apdorojimas, tačiau iš tikrųjų tai yra šiek tiek sudėtingi klausimai, kuriuos bandau paaiškinti labai paprastai, pamatysime mažą programą, kurioje naudojami buferiai, ir ketiname ją sulaužyti, kad suprastume tai apie perpildymus, akivaizdu, kad tai nėra Tai tikra programa, ir mes „išvengsime“ daugelio šiandien naudojamų atsakomųjų priemonių, kad tik parodytume, kaip viskas buvo padaryta anksčiau 🙂 ir kadangi kai kurie iš šių principų yra būtini norint išmokti sudėtingesnių dalykų 😉
GDB
Puiki programa, kurią, be abejo, dažniausiai naudoja „C“ programuotojai. Tarp daugybės dorybių turime tai, kad ji leidžia pamatyti visa tai, apie ką kalbėjome iki šiol, registrus, kaminą, buferius ir pan. 🙂 Pažiūrėkime programą, kurią naudosime savo pavyzdžiu.
pakartojimas.c
Tai gana paprasta programa, mes ketiname naudotis biblioteka stdio.h
kad būtų galima gauti informaciją ir parodyti ją terminale. Mes galime pamatyti funkciją, vadinamą return_input
kuris generuoja a buferis vadinamas masyvas, kurio ilgis yra 30 baitų (char tipo duomenų tipas yra 1 baitas).
Funkcija gets(array);
prašyti informacijos pagal konsolę ir funkciją printf()
grąžina masyvo turinį ir rodo jį ekrane.
Kiekviena programa, parašyta C, prasideda funkcija main()
, tai bus atsakinga tik už return_input iškvietimą, dabar mes sukursime programą.
Paimkime šiek tiek to, ką aš ką tik padariau. Variantas -ggdb
sako gcc, kad ji turi sukompiliuoti programą su informacija, kad gdb galėtų tinkamai derinti. -fno-stack-protector
Tai yra galimybė, kurios akivaizdžiai neturėtume naudoti, bet kurią ketiname naudoti, nes priešingu atveju būtų galima sukurti buferio perpildymą rietuvėje. Galų gale aš išbandžiau rezultatą. ./a.out
jis tiesiog vykdo tai, ką ką tik sukūriau, manęs prašo informacijos ir grąžina. Bėgimas 🙂
Įspėjimai
Čia dar viena pastaba. Ar matote įspėjimus? aišku, į ką reikia atsižvelgti dirbant su kodu ar kompiliuojant, tai yra šiek tiek akivaizdu ir yra nedaug programų, kurios šiandien atlieka funkciją gets()
Kode. Vienas „Gentoo“ pranašumas yra tas, kad kompiliuodamas kiekvieną programą matau, kas gali būti negerai, „idealioje“ programoje jų neturėtų būti, tačiau nustebtumėte, kiek daug didelių programų turi šiuos įspėjimus, nes jos yra tiesiog LABAI didelės ir jas sunku sekti. pavojingos funkcijos, kai vienu metu yra daug įspėjimų. Dabar, jei tęsime
Derinimas su programa
Dabar ši dalis gali būti šiek tiek paini, bet kadangi jau parašiau pakankamai, negaliu sau leisti visko paaiškinti, todėl atsiprašau, jei matai, kad einu per greitai 🙂
Kodo išjungimas
Pradėkime nuo mūsų sudarytos mašininės kalbos programos.
Tai yra mūsų pagrindinės funkcijos kodas Surinkimas, tai supranta mūsų procesorius, kairėje esanti eilutė yra fizinis adresas atmintyje, <+ n> yra žinomas kaip kompensuoti, iš esmės atstumas nuo funkcijos (pagrindinės) pradžios iki to sakinio (žinomo kaip kodas operacijos). Tada matome instrukcijos tipą (push / mov / callq ...) ir vieną ar daugiau registrų. Apibendrinant galime pasakyti, kad tai yra nuoroda, po kurios nurodomas šaltinis / kilmė ir paskirties vieta. <return_input>
nurodo mūsų antrąją funkciją, pažvelkime.
return_input
Tai yra šiek tiek sudėtingiau, bet aš tik noriu, kad patikrintumėte keletą dalykų, yra žyma, vadinama <gets@plt>
ir paskambino paskutinis opcode retq
nurodant funkcijos pabaigą. Į funkciją įvesime porą lūžių taškų gets
ir dar vienas retq
.
paleisti
Dabar vykdysime programą, kad pamatytume, kaip prasideda veiksmas.
Matome, kad atsiranda maža rodyklė, nurodanti opcode, kur esame, noriu, kad jie atsižvelgtų į kryptį 0x000055555555469b
, tai yra adresas po skambučio return_input
funkcijoje main
, tai yra svarbu, nes čia programa turėtų grįžti, kai baigsite gauti indėlis, pereikime prie funkcijos. Dabar prieš įvesdami funkciją patikrinsime atmintį gets
.
Aš jums sukūriau pagrindinę funkciją ir paryškinau kodą, į kurį kalbėjau, kaip matote endiškumas buvo padalintas į du segmentus, noriu, kad jie atsižvelgtų į kryptį 0x7fffffffdbf0
(pirmasis iš kairės po komandos x/20x $rsp
), nes tai yra vieta, kurią turime naudoti norėdami patikrinti gautų rezultatų rezultatus, tęskime:
Pažeisti programą
Aš juos išryškinau 0x44444444
nes jie atspindi mūsų Ds 🙂 dabar mes pradėjome pridėti indėlis į programą ir, kaip matote, mes esame tik dvi eilutės nuo norimo adreso, mes jį užpildysime, kol būsime prieš pat adresus, kuriuos paryškinome ankstesniame žingsnyje.
Grįžimo kelio keitimas
Dabar, kai mums pavyko įvesti šį kodo skyrių, kur jis rodo funkcijos grįžimą, pažiūrėkime, kas atsitiks, jei pakeisime adresą 🙂, o ne eisime į opcodo vietą, kuri seka tą, kurią mes turėjome prieš akimirką, ką jūs manote jei grįšime į return_input
? Bet tam būtina norimą adresą užrašyti dvejetainiu būdu, tai padarysime su funkcija printf
nuo bash 🙂
Dabar mes du kartus gavome informaciją 😀 programa tikrai nebuvo sukurta tam, bet mums pavyko sulaužyti kodą ir priversti jį pakartoti tai, ko jis neturėjo padaryti.
Apmąstymai
Šį paprastą pakeitimą galima laikyti a išnaudoti labai paprastas - jam pavyko nutraukti programą ir padaryti tai, ko mes norime.
Tai tik pirmas žingsnis beveik begaliniame sąraše dalykų, kuriuos reikia pamatyti ir pridėti, yra būdų, kaip pridėti daugiau dalykų, nei paprasčiausiai pakartoti užsakymą, tačiau šį kartą aš parašiau daug ir visko, kas susiję su lukšto kodavimas tai tema, kad sakyčiau daugiau nei straipsniai, visos knygos. Atsiprašau, jei nesugebėjau šiek tiek daugiau įsigilinti į temas, kurios man patiktų, bet tikrai bus galimybė 🙂 Sveikinimai ir ačiū, kad čia patekote.
Būkite tiesesni. Rašykite mažiau ir susitelkite į tai, kas svarbu
Sveiki, ačiū už komentarą.
Tiesą sakant, aš iškirpau nemažą dalį idėjų, tačiau net ir taip man atrodė, kad aš palikau minimumą, kad tas, kas neturi programavimo žinių, galėtų susidaryti idėją.
saludos
Problema ta, kad tie, kurie neturi programavimo žinių, nieko nesužinos, nes tai yra per daug sudėtinga, tačiau tie, kurie moka programuoti, vertina tiesiogiškumą.
Aš manau, kad jūs negalite pasiekti visų, jūs turite pasirinkti, ir šiuo atveju jūs nusidėjote, kad norite daug ką aprėpti.
Beje, sakau jums kaip konstruktyvią kritiką, man patinka šios temos ir norėčiau, kad jūs ir toliau rašytumėte straipsnius, sveikinu!
Manau, tas pats dalykas.
Labai ačiū abiem !! Tikrai sunku suprasti, kaip pasiekti tikslinę auditoriją, kai tiesa ta, kad mažai žmonių, turinčių aukštesnį programavimo lygį, skaitančių šiuos straipsnius (bent jau tai galima padaryti remiantis komentarais)
Aš tikrai nusidėjau norėdamas supaprastinti tai, ko supratimui reikalinga plati žinių bazė. Tikiuosi, jūs suprantate, kad kadangi tik pradedu rašyti dienoraščius, dar neatradau tikslaus taško, kur mano skaitytojai žino ir supranta, ką sakau. Tai būtų daug lengviau pasakyti tiesą 🙂
Pasistengsiu būti trumpesnis, kai to nusipelnys, nedesmenindamas formato, nes atskirti rašymo būdą nuo turinio yra šiek tiek sudėtingiau, nei galima įsivaizduoti, aš bent jau juos susieju, bet manau, kad galiausiai galėsiu pridėti eilučių užuot pjaustęs turinį.
saludos
Kur galėtumėte daugiau sužinoti apie šią temą? Bet kuri rekomenduojama knyga?
Pavyzdys buvo paimtas iš „The Shellcoder“ vadovo Chriso Anley, Johno Heasmano, Felixo Linderio ir Gerardo Richarte'o, tačiau norint atlikti 64 bitų vertimą turėjau sužinoti apie savo architektūrą, „Intel“ kūrėjo vadovas, 2 ir 3 tomai yra gana patikimas šaltinis tam. Taip pat gerai skaityti GDB dokumentus, kurie pateikiami kartu su komanda „info gdb“. Norėdami išmokti asamblėją ir C, yra daug labai gerų knygų, išskyrus tai, kad asamblėjos knygos yra šiek tiek senos, todėl yra spraga užpildyti kita tipo dokumentai.
Pats apvalkalas šiais laikais nebėra toks efektyvus dėl įvairių priežasčių, tačiau vis tiek įdomu išmokti naujų metodų.
Tikiuosi, kad tai šiek tiek padės 🙂 Sveikinimai
Geras straipsnis, senas dienoraštis desdelinux atgimė iš naujo =)
Sakydami, kad nuotolinis apvalkalas nėra toks efektyvus, turite omenyje atsakomąsias priemones, skirtas atakoms sušvelninti, jie tai vadina įžeidžiančiu saugumu.
Sveikinimai ir toliau
Labai ačiū Franzui, labai geri žodžiai, iš tikrųjų aš turėjau omenyje, kad „Shellcoding“ šiandien yra daug sudėtingesnis nei tai, ką mes matome čia. Mes turime ASLR (atsitiktinės atminties vietos generatorius) kamino apsaugą, įvairias priemones ir atsakomąsias priemones, kurios riboja opkodų, kuriuos galima įterpti į programą, skaičių, ir tai tik pradžia.
Pagarbiai,
Sveiki, ar atliksite dar vieną dalį, išplėsdami temą? Tai įdomu
Sveiki, žinoma, tema yra gana įdomi, tačiau sudėtingumo lygis, kurį mes pasirinktume, taptų labai aukštas, tikriausiai apimtų daugybę pranešimų, paaiškinančių įvairias prielaidas suprasti kitą. Aš tikriausiai parašysiu apie tai, bet tai nebus šie įrašai, noriu parašyti keletą temų prieš tęsdamas šią.
Sveikinimai ir ačiū už pasidalinimą
Labai gera che! Jūs prisidedate prie puikių pranešimų! Vienas klausimas, aš pradedu šį IT saugumo dalyką skaitydamas knygą „Saugumo užtikrinimas rašikliu išbandant“. Ar ši knyga rekomenduojama? Kaip jūs siūlote man pradėti teirautis šiais klausimais?
Sveiki, kaktusai, tai visa visata apie pažeidžiamumus, ir kiti, tiesą sakant, labai priklauso nuo to, kas atkreipia jūsų dėmesį, ir poreikių, kuriuos turite, IT vadybininkui nereikia žinoti to paties, kaip rašiklio testeriui, Arba pažeidžiamumo tyrėjas ar teismo analitikas, atkūrimo komanda yra labai skirtingų įgūdžių. Akivaizdu, kad kiekvienam iš jų reikia skirtingo lygio techninių žinių, aš rekomenduoju pradėti atrasti būtent tai, kas jums patinka, ir pradėti ryti knygas, straipsnius ir kitus, o svarbiausia - praktikuoti viską, ką skaitote, net jei tai yra pasenę. , tai galiausiai pakeis.
Pagarbiai,
Hey.
Labai ačiū, kad paaiškinote šią temą, taip pat pakomentavote, kad dėl papildomos informacijos turime „The Shellcoder's Handbook“. Aš jau laukiu skaitymo 😉