2019 m. rugpjūtį „Microsoft“ paskelbė, kad pataisė KPP klaidų rinkinį, iš kurių dvi buvo užkrėstos. Kirminų klaidos, CVE-2019-1181 ir CVE-2019-1182, turi įtakos kiekvienai OS nuo Windows 7 iki Windows 10. Kyla painiavos dėl to, kuri CVE yra, nors gali būti, kad abu susiję su ta pačia klaida. Pažeidžiamas kodas yra ir RDP kliente, ir serveryje, todėl jį galima išnaudoti bet kuria kryptimi.
Iš ankstesnio darbo su RDP manau, kad funkcijas DecodeFormatData ir SendFormatDataRequest galima iškviesti tik po autentifikavimo; paliekant tik išskleidimo funkciją.
Originalus kodas (kairėje) yra šiek tiek netvarka, nes jis buvo optimizuotas į vieną if teiginį. Atnaujintas kodas (dešinėje) yra šiek tiek mažiau netvarkingas ir turi tam tikrą papildomą patvirtinimą.
24 eilutėje pridedamas kodas, kuris patikrina, ar v11 + 0x2000 yra mažesnis nei v11. Jei sąlyga teisinga, nustatomas klaidos kodas, dėl kurio vėliau funkcija nutraukiama. Galbūt klausiate, kaip čekis gali nepavykti. Kaip prie sveikojo skaičiaus pridėjus 0x2000 jis gali būti mažesnis nei anksčiau? Atsakymas yra: per sveikojo skaičiaus perpildymą.
Nežymėtas sveikasis skaičius yra 4 baitai ir gali turėti bet kokią reikšmę nuo 0 iki 0xFFFFFFFF (4 294 967 295). Jei sveikasis skaičius padidinamas virš didžiausios vertės, jis sukasi iki nulio. Taigi, jei v11 buvo 0xFFFFFFFF, pridėjus 0x2000, galutinė vertė būtų 0x1FFF, kuri yra mažesnė nei pradinė.
v11 naudojamas kaip krūvos paskirstymo, atliekamo naudojant „naują“ operatorių, dydis. Daroma prielaida, kad jei galime perpildyti v11, paskirstymas būtų mažesnis nei išspausti duomenys, o tai sukeltų krūvos perpildymą.
Kad geriau suprasčiau, kaip išnaudoti sveikųjų skaičių perpildymą, turėjau žinoti, kokias vertes valdau ir kaip iškviesti pažeidžiamą funkciją. Norėdami tai padaryti, aš parodžiau DecompressUnchopper::DecompressUnchopper (DecompressUnchopper klasės inicijavimo funkcija). Tada aš ir toliau naudoju „xrefs to“, kad vaikščiočiau atgal, kol radau funkciją, kuri naudoja šią klasę. Galiausiai atėjau į CRdpDynVCMgr::HandleIncomingDvcData.
Iš ankstesnio darbo su RDP (dokumentų skaitymo valandos) žinojau, kad DynVC buvo trumpinys „Dynamic Virtual Channel“. DVC sąsaja leidžia palaikyti ryšį tarp kliento ir serverio modulių ir palaiko neapdorotus ir suspaustus duomenis. Tikėtina, kad pažeidžiama „išskleidimo“ funkcija gali būti paveikta siunčiant suglaudintus duomenis.
Jau turėdamas pasirinktinį KPP klientą, parašytą „BlueKeep“ išnaudojimui, pridėjau kodą, kad atidaryčiau DVC kanalą ir atsiųsčiau kai kuriuos bandymo duomenis.
Prijungęs derintuvą prie KPP serverio proceso, DecompressUnchopper::Decompress nustatiau pertraukos tašką ir paleidau savo kodą.
rdx (2-asis argumentas) yra mano išsiųsti bandymo duomenys, o r8 (3-as argumentas) yra duomenų ilgis. Dabar, žinodamas funkcijos parametrus, galėjau išvalyti dekompiliuotą kodą.
Dabar laikas pažiūrėti, ar galiu sukelti avariją.
Siekdamas patikrinti pažeidžiamumą sudaužydamas RDP serverį, sukūriau kenkėjišką DVC paketą.
Nustačiau lauką uncompressedSize į 1 – 0x2000 (0xFFFFE001), kad pridėjus 0x2000, jis būtų maždaug 1. Tada nustatiau, kad suspaustuose duomenyse būtų raidė „A”, kartojama 0x200 kartų, todėl turėtų susidaryti krūva. buferis perpildytas 0x1FF baitais.
Puiku, dabar galiu įrašyti savavališkus savavališko dydžio duomenis į gretimus krūvos paskirstymus! Ši klaida yra galinga, nes objektų egzemplioriai saugomi toje pačioje krūvoje, todėl juos galima perrašyti.
Pavyzdžiui, pakeičiau objekto VTable žymeklį, kad programa atliktų ptr skambutį adresu 0x1337133713371337.