From 9c5a532e652855b2f98fdd6867f654fef309f12b Mon Sep 17 00:00:00 2001 From: Translator Date: Sat, 17 May 2025 05:01:22 +0000 Subject: [PATCH] Translated ['src/pentesting-cloud/gcp-security/gcp-to-workspace-pivoting --- .../gcp-to-workspace-pivoting/README.md | 64 ++--- theme/ai.js | 236 ++++++++++-------- 2 files changed, 163 insertions(+), 137 deletions(-) diff --git a/src/pentesting-cloud/gcp-security/gcp-to-workspace-pivoting/README.md b/src/pentesting-cloud/gcp-security/gcp-to-workspace-pivoting/README.md index 8d89e3f48..b867c1bc3 100644 --- a/src/pentesting-cloud/gcp-security/gcp-to-workspace-pivoting/README.md +++ b/src/pentesting-cloud/gcp-security/gcp-to-workspace-pivoting/README.md @@ -4,12 +4,12 @@ ## **GCP से GWS तक** -### **डोमेन वाइड डेलीगेशन के मूल बातें** +### **डोमेन वाइड डेलीगेशन की मूल बातें** Google Workspace का डोमेन-वाइड डेलीगेशन एक पहचान वस्तु, या तो एक **बाहरी ऐप** जो Google Workspace मार्केटप्लेस से है या एक आंतरिक **GCP सेवा खाता**, को **उपयोगकर्ताओं की ओर से Workspace में डेटा तक पहुंचने** की अनुमति देता है। > [!NOTE] -> इसका मतलब यह है कि **GCP परियोजनाओं** के अंदर **सेवा खाते** एक संगठन के **Workspace उपयोगकर्ताओं** की नकल कर सकते हैं (या यहां तक कि किसी अलग संगठन के भी)। +> इसका मतलब यह है कि **GCP परियोजनाओं** के अंदर **सेवा खाते** एक संगठन के Workspace उपयोगकर्ताओं की **नकल** कर सकते हैं (या यहां तक कि किसी अन्य संगठन के उपयोगकर्ताओं की भी)। इसकी कार्यप्रणाली के बारे में अधिक जानकारी के लिए देखें: @@ -19,16 +19,16 @@ gcp-understanding-domain-wide-delegation.md ### मौजूदा डेलीगेशन का समझौता -यदि एक हमलावर ने **GCP पर कुछ पहुंच का समझौता किया** और **कंपनी के एक मान्य Workspace उपयोगकर्ता ईमेल** (अधिमानतः **सुपर एडमिन**) को जानता है, तो वह **सभी परियोजनाओं की सूची बना सकता है** जिन तक उसे पहुंच है, **परियोजनाओं के सभी SAs की सूची बना सकता है**, यह जांच सकता है कि उसे **कौन से सेवा खातों तक पहुंच है**, और **हर SA के साथ इन सभी चरणों को दोहरा सकता है** जिसे वह नकल कर सकता है।\ -एक **सेवा खातों की पूरी सूची** और **Workspace** **ईमेल्स** के साथ, हमलावर **प्रत्येक सेवा खाते के साथ उपयोगकर्ता की नकल करने** की कोशिश कर सकता है। +यदि एक हमलावर ने **GCP पर कुछ पहुंच का समझौता किया** और **कंपनी का एक मान्य Workspace उपयोगकर्ता ईमेल** (अधिमानतः **सुपर एडमिन**) जानता है, तो वह **सभी परियोजनाओं की सूची बना सकता है** जिन तक उसे पहुंच है, **परियोजनाओं के सभी SAs की सूची बना सकता है**, यह जांच सकता है कि उसे **कौन से सेवा खातों तक पहुंच है**, और **हर SA के साथ इन सभी चरणों को दोहरा सकता है** जिसे वह नकल कर सकता है।\ +उसके पास **सभी सेवा खातों की एक सूची** और **Workspace** **ईमेल** की सूची होने पर, हमलावर **प्रत्येक सेवा खाते के साथ उपयोगकर्ता की नकल करने** की कोशिश कर सकता है। > [!CAUTION] -> ध्यान दें कि डोमेन वाइड डेलीगेशन को कॉन्फ़िगर करते समय किसी Workspace उपयोगकर्ता की आवश्यकता नहीं होती है, इसलिए बस जानें कि **एक मान्य उपयोगकर्ता नकल के लिए पर्याप्त और आवश्यक है**।\ -> हालाँकि, **नकली उपयोगकर्ता के विशेषाधिकारों का उपयोग किया जाएगा**, इसलिए यदि यह सुपर एडमिन है तो आप सब कुछ एक्सेस कर सकेंगे। यदि इसके पास कोई पहुंच नहीं है तो यह बेकार होगा। +> ध्यान दें कि डोमेन वाइड डेलीगेशन को कॉन्फ़िगर करते समय किसी Workspace उपयोगकर्ता की आवश्यकता नहीं होती है, इसलिए बस जान लें कि **एक मान्य उपयोगकर्ता होना पर्याप्त है और नकल के लिए आवश्यक है**।\ +> हालाँकि, **नकल किए गए उपयोगकर्ता के विशेषाधिकारों का उपयोग किया जाएगा**, इसलिए यदि यह सुपर एडमिन है तो आप सब कुछ एक्सेस कर सकेंगे। यदि इसके पास कोई पहुंच नहीं है तो यह बेकार होगा। #### [GCP Generate Delegation Token](https://github.com/carlospolop/gcp_gen_delegation_token) -यह सरल स्क्रिप्ट **नियुक्त उपयोगकर्ता के रूप में एक OAuth टोकन उत्पन्न करेगी** जिसे आप फिर अन्य Google APIs तक पहुंचने के लिए उपयोग कर सकते हैं, चाहे `gcloud` के साथ हो या बिना: +यह सरल स्क्रिप्ट **नियुक्त उपयोगकर्ता के रूप में एक OAuth टोकन उत्पन्न करेगी** जिसे आप अन्य Google APIs तक पहुंचने के लिए `gcloud` के साथ या बिना उपयोग कर सकते हैं: ```bash # Impersonate indicated user python3 gen_delegation_token.py --user-email --key-file @@ -36,22 +36,26 @@ python3 gen_delegation_token.py --user-email --key-file --key-file --scopes "https://www.googleapis.com/auth/userinfo.email, https://www.googleapis.com/auth/cloud-platform, https://www.googleapis.com/auth/admin.directory.group, https://www.googleapis.com/auth/admin.directory.user, https://www.googleapis.com/auth/admin.directory.domain, https://mail.google.com/, https://www.googleapis.com/auth/drive, openid" ``` +#### [**DelePwn**](https://github.com/n0tspam/delepwn) + +यह DeleFriend टूल पर आधारित है, लेकिन इसमें कुछ अतिरिक्त सुविधाएँ हैं जैसे डोमेन, ड्राइव, जीमेल, कैलेंडर को सूचीबद्ध करने की क्षमता और अन्य संचालन करने की क्षमता। + #### [**DeleFriend**](https://github.com/axon-git/DeleFriend) -यह एक उपकरण है जो निम्नलिखित चरणों का पालन करके हमले को अंजाम दे सकता है: +यह एक टूल है जो निम्नलिखित चरणों का पालन करते हुए हमला कर सकता है: -1. **GCP प्रोजेक्ट्स की गणना करें** Resource Manager API का उपयोग करके। -2. प्रत्येक प्रोजेक्ट संसाधन पर पुनरावृत्ति करें, और **GCP सेवा खाता संसाधनों की गणना करें** जिन तक प्रारंभिक IAM उपयोगकर्ता की पहुंच है _GetIAMPolicy_ का उपयोग करके। -3. **प्रत्येक सेवा खाता भूमिका पर पुनरावृत्ति करें**, और लक्षित सेवा खाता संसाधन पर _**serviceAccountKeys.create**_ अनुमति के साथ अंतर्निहित, बुनियादी, और कस्टम भूमिकाएँ खोजें। यह ध्यान रखना चाहिए कि संपादक भूमिका स्वाभाविक रूप से इस अनुमति को रखती है। -4. प्रत्येक सेवा खाता संसाधन के लिए **नया `KEY_ALG_RSA_2048`** निजी कुंजी बनाएं जो IAM नीति में प्रासंगिक अनुमति के साथ पाया गया है। -5. **प्रत्येक नए सेवा खाते पर पुनरावृत्ति करें और इसके लिए एक `JWT`** **ऑब्जेक्ट** बनाएं जो SA निजी कुंजी क्रेडेंशियल्स और एक OAuth स्कोप से बना होता है। नए _JWT_ ऑब्जेक्ट को बनाने की प्रक्रिया **oauth_scopes.txt** सूची से सभी मौजूदा OAuth स्कोप के संयोजनों पर पुनरावृत्ति करेगी, ताकि सभी प्रतिनिधित्व संभावनाओं को खोजा जा सके। सूची **oauth_scopes.txt** को उन सभी OAuth स्कोप के साथ अपडेट किया गया है जो हमने Workspace पहचानियों का दुरुपयोग करने के लिए प्रासंगिक पाया है। -6. `_make_authorization_grant_assertion` विधि एक लक्षित कार्यक्षेत्र उपयोगकर्ता, जिसे _subject_ के रूप में संदर्भित किया गया है, को घोषित करने की आवश्यकता को प्रकट करती है, ताकि DWD के तहत JWT उत्पन्न किए जा सकें। जबकि यह एक विशिष्ट उपयोगकर्ता की आवश्यकता प्रतीत हो सकती है, यह समझना महत्वपूर्ण है कि **DWD एक डोमेन के भीतर हर पहचान को प्रभावित करता है**। परिणामस्वरूप, **किसी भी डोमेन उपयोगकर्ता** के लिए JWT बनाना उस डोमेन में सभी पहचानियों को प्रभावित करता है, जो हमारे संयोजन गणना जांच के अनुरूप है। सीधे शब्दों में कहें, एक मान्य Workspace उपयोगकर्ता आगे बढ़ने के लिए पर्याप्त है।\ -इस उपयोगकर्ता को DeleFriend के _config.yaml_ फ़ाइल में परिभाषित किया जा सकता है। यदि लक्षित कार्यक्षेत्र उपयोगकर्ता पहले से ज्ञात नहीं है, तो उपकरण GCP प्रोजेक्ट्स पर भूमिकाओं के साथ डोमेन उपयोगकर्ताओं को स्कैन करके मान्य कार्यक्षेत्र उपयोगकर्ताओं की स्वचालित पहचान की सुविधा प्रदान करता है। यह फिर से ध्यान देने योग्य है कि JWT डोमेन-विशिष्ट होते हैं और हर उपयोगकर्ता के लिए उत्पन्न नहीं होते; इसलिए, स्वचालित प्रक्रिया प्रति डोमेन एक अद्वितीय पहचान को लक्षित करती है। -7. **प्रत्येक JWT के लिए एक नया बियरर एक्सेस टोकन की गणना करें और टोकन को tokeninfo API के खिलाफ मान्य करें।** +1. **GCP प्रोजेक्ट्स की सूची बनाना** Resource Manager API का उपयोग करके। +2. प्रत्येक प्रोजेक्ट संसाधन पर इटरेट करें, और **GCP सेवा खाता संसाधनों की सूची बनाएं** जिन तक प्रारंभिक IAM उपयोगकर्ता की पहुँच है _GetIAMPolicy_ का उपयोग करके। +3. **प्रत्येक सेवा खाता भूमिका पर इटरेट करें**, और उन अंतर्निहित, बुनियादी, और कस्टम भूमिकाओं को खोजें जिनमें _**serviceAccountKeys.create**_ अनुमति है लक्षित सेवा खाता संसाधन पर। यह ध्यान रखना महत्वपूर्ण है कि संपादक भूमिका स्वाभाविक रूप से इस अनुमति को रखती है। +4. प्रत्येक सेवा खाता संसाधन के लिए एक **नया `KEY_ALG_RSA_2048`** निजी कुंजी बनाएं जो IAM नीति में प्रासंगिक अनुमति के साथ पाया गया है। +5. **प्रत्येक नए सेवा खाते पर इटरेट करें और इसके लिए एक `JWT`** **ऑब्जेक्ट** बनाएं जो SA निजी कुंजी क्रेडेंशियल्स और एक OAuth स्कोप से बना है। एक नया _JWT_ ऑब्जेक्ट बनाने की प्रक्रिया **oauth_scopes.txt** सूची से सभी मौजूदा OAuth स्कोप के संयोजनों पर इटरेट करेगी, ताकि सभी प्रतिनिधित्व संभावनाओं को खोजा जा सके। सूची **oauth_scopes.txt** को उन सभी OAuth स्कोप के साथ अपडेट किया गया है जो हमने Workspace पहचानियों का दुरुपयोग करने के लिए प्रासंगिक पाया है। +6. `_make_authorization_grant_assertion` विधि एक लक्षित कार्यक्षेत्र उपयोगकर्ता को घोषित करने की आवश्यकता को प्रकट करती है, जिसे _subject_ के रूप में संदर्भित किया जाता है, JWTs को DWD के तहत उत्पन्न करने के लिए। जबकि यह एक विशिष्ट उपयोगकर्ता की आवश्यकता प्रतीत हो सकती है, यह समझना महत्वपूर्ण है कि **DWD एक डोमेन के भीतर हर पहचान को प्रभावित करता है**। परिणामस्वरूप, **किसी भी डोमेन उपयोगकर्ता** के लिए JWT बनाना उस डोमेन में सभी पहचानों को प्रभावित करता है, जो हमारे संयोजन सूचीकरण जांच के अनुरूप है। सीधे शब्दों में कहें, एक मान्य Workspace उपयोगकर्ता आगे बढ़ने के लिए पर्याप्त है।\ +इस उपयोगकर्ता को DeleFriend के _config.yaml_ फ़ाइल में परिभाषित किया जा सकता है। यदि लक्षित कार्यक्षेत्र उपयोगकर्ता पहले से ज्ञात नहीं है, तो यह टूल GCP प्रोजेक्ट्स पर भूमिकाओं के साथ डोमेन उपयोगकर्ताओं को स्कैन करके मान्य कार्यक्षेत्र उपयोगकर्ताओं की स्वचालित पहचान की सुविधा प्रदान करता है। यह ध्यान रखना महत्वपूर्ण है (फिर से) कि JWT डोमेन-विशिष्ट होते हैं और हर उपयोगकर्ता के लिए उत्पन्न नहीं होते; इसलिए, स्वचालित प्रक्रिया प्रति डोमेन एक अद्वितीय पहचान को लक्षित करती है। +7. **प्रत्येक JWT के लिए एक नया बियरर एक्सेस टोकन सूचीबद्ध करें और टोकन को tokeninfo API के खिलाफ मान्य करें।** #### [Gitlab का Python स्क्रिप्ट](https://gitlab.com/gitlab-com/gl-security/threatmanagement/redteam/redteam-public/gcp_misc/-/blob/master/gcp_delegation.py) -Gitlab ने [यह Python स्क्रिप्ट](https://gitlab.com/gitlab-com/gl-security/gl-redteam/gcp_misc/blob/master/gcp_delegation.py) बनाई है जो दो चीजें कर सकती है - उपयोगकर्ता निर्देशिका की सूची बनाना और SA क्रेडेंशियल्स और अनुकरण करने के लिए उपयोगकर्ता के साथ एक नया प्रशासनिक खाता बनाना। यहाँ इसका उपयोग कैसे करें: +Gitlab ने [यह Python स्क्रिप्ट](https://gitlab.com/gitlab-com/gl-security/gl-redteam/gcp_misc/blob/master/gcp_delegation.py) बनाई है जो दो चीजें कर सकती है - उपयोगकर्ता निर्देशिका की सूची बनाना और एक नया प्रशासनिक खाता बनाना जबकि SA क्रेडेंशियल्स और अनुकरण करने के लिए उपयोगकर्ता के साथ एक json को इंगित करना। यहाँ इसका उपयोग कैसे किया जाएगा: ```bash # Install requirements pip install --upgrade --user oauth2client @@ -77,28 +81,28 @@ pip install --upgrade --user oauth2client यह संभव है कि **डोमेन वाइड प्रतिनिधित्व की जांच करें** [**https://admin.google.com/u/1/ac/owl/domainwidedelegation**](https://admin.google.com/u/1/ac/owl/domainwidedelegation)**.** -एक हमलावर जिसके पास **GCP प्रोजेक्ट में सेवा खातों को बनाने की क्षमता** और **GWS के लिए सुपर एडमिन विशेषाधिकार** है, वह कुछ GWS उपयोगकर्ताओं का अनुकरण करने के लिए SAs को अनुमति देने वाला एक नया प्रतिनिधित्व बना सकता है: +एक हमलावर जिसके पास **GCP प्रोजेक्ट में सेवा खातों को बनाने की क्षमता** और **GWS के लिए सुपर एडमिन विशेषाधिकार** है, वह एक नई प्रतिनिधित्व बना सकता है जो SAs को कुछ GWS उपयोगकर्ताओं का अनुकरण करने की अनुमति देती है: -1. **एक नया सेवा खाता और संबंधित कुंजी जोड़ी उत्पन्न करना:** GCP पर, नए सेवा खाता संसाधनों को या तो कंसोल के माध्यम से इंटरैक्टिव रूप से या सीधे API कॉल और CLI उपकरणों का उपयोग करके प्रोग्रामेटिक रूप से उत्पन्न किया जा सकता है। इसके लिए **भूमिका `iam.serviceAccountAdmin`** या किसी भी कस्टम भूमिका की आवश्यकता होती है जिसमें **`iam.serviceAccounts.create`** **अनुमति** हो। एक बार सेवा खाता बन जाने के बाद, हम एक **संबंधित कुंजी जोड़ी** उत्पन्न करने की प्रक्रिया में आगे बढ़ेंगे (**`iam.serviceAccountKeys.create`** अनुमति)। -2. **नए प्रतिनिधित्व का निर्माण**: यह समझना महत्वपूर्ण है कि **केवल सुपर एडमिन भूमिका के पास Google Workspace में वैश्विक डोमेन-वाइड प्रतिनिधित्व स्थापित करने की क्षमता है** और डोमेन-वाइड प्रतिनिधित्व **प्रोग्रामेटिक रूप से स्थापित नहीं किया जा सकता,** इसे केवल Google Workspace **कंसोल** के माध्यम से **हाथ से** बनाया और समायोजित किया जा सकता है। +1. **एक नया सेवा खाता और संबंधित कुंजी जोड़ी उत्पन्न करना:** GCP पर, नए सेवा खाता संसाधनों को या तो इंटरैक्टिव रूप से कंसोल के माध्यम से या सीधे API कॉल और CLI उपकरणों का उपयोग करके प्रोग्रामेटिक रूप से उत्पन्न किया जा सकता है। इसके लिए **भूमिका `iam.serviceAccountAdmin`** या किसी भी कस्टम भूमिका की आवश्यकता होती है जिसमें **`iam.serviceAccounts.create`** **अनुमति** हो। एक बार सेवा खाता बन जाने के बाद, हम एक **संबंधित कुंजी जोड़ी** उत्पन्न करने के लिए आगे बढ़ेंगे (**`iam.serviceAccountKeys.create`** अनुमति)। +2. **नई प्रतिनिधित्व का निर्माण**: यह समझना महत्वपूर्ण है कि **केवल सुपर एडमिन भूमिका के पास Google Workspace में वैश्विक डोमेन-वाइड प्रतिनिधित्व स्थापित करने की क्षमता है** और डोमेन-वाइड प्रतिनिधित्व **प्रोग्रामेटिक रूप से स्थापित नहीं किया जा सकता,** इसे केवल Google Workspace **कंसोल** के माध्यम से **हाथ से** बनाया और समायोजित किया जा सकता है। - नियम का निर्माण **API नियंत्रण → Google Workspace Admin कंसोल में डोमेन-वाइड प्रतिनिधित्व प्रबंधित करें** पृष्ठ के तहत पाया जा सकता है। -3. **OAuth स्कोप विशेषाधिकार संलग्न करना**: एक नए प्रतिनिधित्व को कॉन्फ़िगर करते समय, Google केवल 2 पैरामीटर की आवश्यकता होती है, क्लाइंट आईडी, जो **GCP सेवा खाता** संसाधन का **OAuth आईडी** है, और **OAuth स्कोप** जो परिभाषित करता है कि प्रतिनिधित्व को कौन से API कॉल की आवश्यकता है। +3. **OAuth स्कोप विशेषाधिकार संलग्न करना**: एक नई प्रतिनिधित्व को कॉन्फ़िगर करते समय, Google को केवल 2 पैरामीटर की आवश्यकता होती है, क्लाइंट आईडी, जो **GCP सेवा खाता** संसाधन का **OAuth आईडी** है, और **OAuth स्कोप** जो परिभाषित करता है कि प्रतिनिधित्व को कौन से API कॉल की आवश्यकता है। - **OAuth स्कोप की पूरी सूची** [**यहाँ**](https://developers.google.com/identity/protocols/oauth2/scopes) पाई जा सकती है, लेकिन यहाँ एक सिफारिश है: `https://www.googleapis.com/auth/userinfo.email, https://www.googleapis.com/auth/cloud-platform, https://www.googleapis.com/auth/admin.directory.group, https://www.googleapis.com/auth/admin.directory.user, https://www.googleapis.com/auth/admin.directory.domain, https://mail.google.com/, https://www.googleapis.com/auth/drive, openid` -4. **लक्षित पहचान के पक्ष में कार्य करना:** इस बिंदु पर, हमारे पास GWS में एक कार्यशील प्रतिनिधित्व वस्तु है। अब, **GCP सेवा खाता निजी कुंजी का उपयोग करके, हम API कॉल कर सकते हैं** (OAuth स्कोप पैरामीटर में परिभाषित स्कोप में) इसे सक्रिय करने और **Google Workspace में मौजूद किसी भी पहचान के पक्ष में कार्य करने के लिए।** जैसा कि हमने सीखा, सेवा खाता अपनी आवश्यकताओं के अनुसार और REST API अनुप्रयोगों के लिए उसके पास मौजूद अनुमति के अनुसार एक्सेस टोकन उत्पन्न करेगा। +4. **लक्ष्य पहचान के पक्ष में कार्य करना:** इस बिंदु पर, हमारे पास GWS में एक कार्यशील प्रतिनिधित्व वस्तु है। अब, **GCP सेवा खाता निजी कुंजी का उपयोग करके, हम API कॉल कर सकते हैं** (OAuth स्कोप पैरामीटर में परिभाषित स्कोप में) इसे सक्रिय करने के लिए और **Google Workspace में मौजूद किसी भी पहचान के पक्ष में कार्य कर सकते हैं**। जैसा कि हमने सीखा, सेवा खाता अपनी आवश्यकताओं के अनुसार और REST API अनुप्रयोगों के लिए उसके पास मौजूद अनुमतियों के अनुसार एक्सेस टोकन उत्पन्न करेगा। - इस प्रतिनिधित्व का उपयोग करने के लिए कुछ **उपकरणों** के लिए **पिछले अनुभाग** की जांच करें। #### क्रॉस-ऑर्गनाइजेशनल प्रतिनिधित्व -OAuth SA ID वैश्विक है और इसका उपयोग **क्रॉस-ऑर्गनाइजेशनल प्रतिनिधित्व** के लिए किया जा सकता है। क्रॉस-ग्लोबल प्रतिनिधित्व को रोकने के लिए कोई प्रतिबंध लागू नहीं किया गया है। सरल शब्दों में, **विभिन्न GCP संगठनों के सेवा खातों का उपयोग अन्य Workspace संगठनों पर डोमेन-वाइड प्रतिनिधित्व कॉन्फ़िगर करने के लिए किया जा सकता है।** इसका परिणाम होगा कि **Workspace के लिए केवल सुपर एडमिन पहुंच की आवश्यकता है**, और उसी GCP खाते तक पहुंच की आवश्यकता नहीं है, क्योंकि प्रतिकूल व्यक्ति अपने व्यक्तिगत रूप से नियंत्रित GCP खाते पर सेवा खातों और निजी कुंजी बना सकता है। +OAuth SA ID वैश्विक है और इसका उपयोग **क्रॉस-ऑर्गनाइजेशनल प्रतिनिधित्व** के लिए किया जा सकता है। क्रॉस-वैश्विक प्रतिनिधित्व को रोकने के लिए कोई प्रतिबंध लागू नहीं किया गया है। सरल शब्दों में, **विभिन्न GCP संगठनों के सेवा खातों का उपयोग अन्य Workspace संगठनों पर डोमेन-वाइड प्रतिनिधित्व कॉन्फ़िगर करने के लिए किया जा सकता है**। इसका परिणाम **केवल Workspace के लिए सुपर एडमिन पहुंच की आवश्यकता** होगी, और उसी GCP खाते तक पहुंच की आवश्यकता नहीं होगी, क्योंकि प्रतिकूल व्यक्ति अपने व्यक्तिगत रूप से नियंत्रित GCP खाते पर सेवा खातों और निजी कुंजी बना सकता है। ### Workspace को सूचीबद्ध करने के लिए एक प्रोजेक्ट बनाना -**डिफ़ॉल्ट** रूप से Workspace **उपयोगकर्ताओं** को **नए प्रोजेक्ट बनाने** की अनुमति होती है, और जब एक नया प्रोजेक्ट बनाया जाता है तो **निर्माता को उस पर मालिक की भूमिका मिलती है।** +**डिफ़ॉल्ट** रूप से Workspace **उपयोगकर्ताओं** को **नए प्रोजेक्ट बनाने** की अनुमति होती है, और जब एक नया प्रोजेक्ट बनाया जाता है तो **निर्माता को उस पर मालिक की भूमिका मिलती है**। -इसलिए, एक उपयोगकर्ता **एक प्रोजेक्ट बना सकता है**, अपने नए प्रोजेक्ट में Workspace को सूचीबद्ध करने के लिए **APIs** को **सक्षम** कर सकता है और इसे **सूचीबद्ध** करने का प्रयास कर सकता है। +इसलिए, एक उपयोगकर्ता **एक प्रोजेक्ट बना सकता है**, **API** को सक्षम कर सकता है ताकि वह अपने नए प्रोजेक्ट में Workspace को सूचीबद्ध कर सके और इसे **सूचीबद्ध** करने की कोशिश कर सके। > [!CAUTION] -> एक उपयोगकर्ता के लिए Workspace को सूचीबद्ध करने के लिए, उसे पर्याप्त Workspace अनुमतियों की भी आवश्यकता होती है (हर उपयोगकर्ता निर्देशिका को सूचीबद्ध करने में सक्षम नहीं होगा)। +> एक उपयोगकर्ता को Workspace को सूचीबद्ध करने के लिए उसे पर्याप्त Workspace अनुमतियों की भी आवश्यकता होती है (हर उपयोगकर्ता निर्देशिका को सूचीबद्ध करने में सक्षम नहीं होगा)। ```bash # Create project gcloud projects create --name=proj-name @@ -124,7 +128,7 @@ gcloud beta identity groups preview --customer ### Gcloud क्रेडेंशियल्स का दुरुपयोग -आप लॉगिन के लिए `gcloud` प्रवाह के बारे में अधिक जानकारी पा सकते हैं: +आप `gcloud` लॉगिन के प्रवाह के बारे में और जानकारी पा सकते हैं: {{#ref}} ../gcp-persistence/gcp-non-svc-persistence.md @@ -135,12 +139,12 @@ gcloud beta identity groups preview --customer ```bash gcloud auth login --enable-gdrive-access ``` -यदि एक हमलावर एक उपयोगकर्ता के कंप्यूटर को समझौता करता है, तो वह फ़ाइल `google-cloud-sdk/lib/googlecloudsdk/core/config.py` को भी संशोधित कर सकता है और **`CLOUDSDK_SCOPES`** में स्कोप **`'https://www.googleapis.com/auth/drive'`** जोड़ सकता है: +यदि एक हमलावर एक उपयोगकर्ता के कंप्यूटर से समझौता करता है, तो वह फ़ाइल `google-cloud-sdk/lib/googlecloudsdk/core/config.py` को भी संशोधित कर सकता है और **`CLOUDSDK_SCOPES`** में स्कोप **`'https://www.googleapis.com/auth/drive'`** जोड़ सकता है:
> [!WARNING] -> इसलिए, अगली बार जब उपयोगकर्ता लॉग इन करेगा, तो वह **ड्राइव तक पहुंच के साथ एक टोकन बनाएगा** जिसका उपयोग हमलावर ड्राइव तक पहुंच प्राप्त करने के लिए कर सकता है। स्पष्ट रूप से, ब्राउज़र यह संकेत देगा कि उत्पन्न टोकन ड्राइव तक पहुंच रखेगा, लेकिन चूंकि उपयोगकर्ता स्वयं **`gcloud auth login`** करेगा, वह शायद **कुछ भी संदेह नहीं करेगा।** +> इसलिए, अगली बार जब उपयोगकर्ता लॉग इन करेगा, तो वह **ड्राइव तक पहुंच के साथ एक टोकन बनाएगा** जिसका उपयोग हमलावर ड्राइव तक पहुंच प्राप्त करने के लिए कर सकता है। स्पष्ट रूप से, ब्राउज़र यह संकेत देगा कि उत्पन्न टोकन को ड्राइव तक पहुंच प्राप्त है, लेकिन चूंकि उपयोगकर्ता स्वयं **`gcloud auth login`** करेगा, इसलिए वह शायद **कुछ भी संदेह नहीं करेगा।** > > ड्राइव फ़ाइलों की सूची बनाने के लिए: **`curl -H "Authorization: Bearer $(gcloud auth print-access-token)" "https://www.googleapis.com/drive/v3/files"`** @@ -150,7 +154,7 @@ gcloud auth login --enable-gdrive-access यदि एक हमलावर GWS पर पूर्ण पहुंच रखता है, तो वह GCP पर विशेषाधिकार पहुंच वाले समूहों या यहां तक कि उपयोगकर्ताओं तक पहुंच प्राप्त कर सकेगा, इसलिए GWS से GCP में जाना आमतौर पर अधिक "सरल" होता है क्योंकि **GWS में उपयोगकर्ताओं के पास GCP पर उच्च विशेषाधिकार होते हैं**। -### Google समूहों में विशेषाधिकार वृद्धि +### Google समूहों का विशेषाधिकार वृद्धि डिफ़ॉल्ट रूप से, उपयोगकर्ता **संगठन के कार्यक्षेत्र समूहों में स्वतंत्र रूप से शामिल हो सकते हैं** और उन समूहों को **GCP अनुमतियाँ** असाइन की जा सकती हैं (अपने समूहों की जांच करें [https://groups.google.com/](https://groups.google.com/))। diff --git a/theme/ai.js b/theme/ai.js index bb8af53b7..c94992d5f 100644 --- a/theme/ai.js +++ b/theme/ai.js @@ -1,27 +1,28 @@ /** - * HackTricks AI Chat Widget v1.15 – Markdown rendering + sanitised - * ------------------------------------------------------------------------ - * • Replaces the static “…” placeholder with a three-dot **bouncing** loader - * • Renders assistant replies as Markdown while purging any unsafe HTML - * (XSS-safe via DOMPurify) - * ------------------------------------------------------------------------ + * HackTricks AI Chat Widget v1.16 – resizable sidebar + * --------------------------------------------------- + * ❶ Markdown rendering + sanitised (same as before) + * ❷ NEW: drag‑to‑resize panel, width persists via localStorage */ (function () { - const LOG = "[HackTricks-AI]"; - - /* ---------------- User-tunable constants ---------------- */ - const MAX_CONTEXT = 3000; // highlighted-text char limit - const MAX_QUESTION = 500; // question char limit + const LOG = "[HackTricks‑AI]"; + /* ---------------- User‑tunable constants ---------------- */ + const MAX_CONTEXT = 3000; // highlighted‑text char limit + const MAX_QUESTION = 500; // question char limit + const MIN_W = 250; // ← resize limits → + const MAX_W = 600; + const DEF_W = 350; // default width (if nothing saved) const TOOLTIP_TEXT = - "💡 Highlight any text on the page,\nthen click to ask HackTricks AI about it"; + "💡 Highlight any text on the page,\nthen click to ask HackTricks AI about it"; const API_BASE = "https://www.hacktricks.ai/api/assistants/threads"; - const BRAND_RED = "#b31328"; // HackTricks brand + const BRAND_RED = "#b31328"; /* ------------------------------ State ------------------------------ */ let threadId = null; let isRunning = false; + /* ---------- helpers ---------- */ const $ = (sel, ctx = document) => ctx.querySelector(sel); if (document.getElementById("ht-ai-btn")) { console.warn(`${LOG} Widget already injected.`); @@ -31,44 +32,37 @@ ? document.addEventListener("DOMContentLoaded", init) : init()); - /* ==================================================================== */ - /* 🔗 1. 3rd-party libs → Markdown & sanitiser */ - /* ==================================================================== */ + /* =================================================================== */ + /* 🔗 1. 3rd‑party libs → Markdown & sanitiser */ + /* =================================================================== */ function loadScript(src) { - return new Promise((resolve, reject) => { + return new Promise((res, rej) => { const s = document.createElement("script"); s.src = src; - s.onload = resolve; - s.onerror = () => reject(new Error(`Failed to load ${src}`)); + s.onload = res; + s.onerror = () => rej(new Error(`Failed to load ${src}`)); document.head.appendChild(s); }); } - async function ensureDeps() { const deps = []; - if (typeof marked === "undefined") { + if (typeof marked === "undefined") deps.push(loadScript("https://cdn.jsdelivr.net/npm/marked/marked.min.js")); - } - if (typeof DOMPurify === "undefined") { + if (typeof DOMPurify === "undefined") deps.push( loadScript( "https://cdnjs.cloudflare.com/ajax/libs/dompurify/3.2.5/purify.min.js" ) ); - } if (deps.length) await Promise.all(deps); } + const mdToSafeHTML = (md) => + DOMPurify.sanitize(marked.parse(md, { mangle: false, headerIds: false }), { + USE_PROFILES: { html: true } + }); - function mdToSafeHTML(md) { - // 1️⃣ Markdown → raw HTML - const raw = marked.parse(md, { mangle: false, headerIds: false }); - // 2️⃣ Purify - return DOMPurify.sanitize(raw, { USE_PROFILES: { html: true } }); - } - - /* ==================================================================== */ + /* =================================================================== */ async function init() { - /* ----- make sure marked & DOMPurify are ready before anything else */ try { await ensureDeps(); } catch (e) { @@ -76,14 +70,14 @@ return; } - console.log(`${LOG} Injecting widget… v1.15`); + console.log(`${LOG} Injecting widget… v1.16`); await ensureThreadId(); injectStyles(); const btn = createFloatingButton(); createTooltip(btn); - const panel = createSidebar(); + const panel = createSidebar(); // ← panel with resizer const chatLog = $("#ht-ai-chat"); const sendBtn = $("#ht-ai-send"); const inputBox = $("#ht-ai-question"); @@ -100,15 +94,8 @@ function addMsg(text, cls) { const b = document.createElement("div"); b.className = `ht-msg ${cls}`; - - // ✨ assistant replies rendered as Markdown + sanitised - if (cls === "ht-ai") { - b.innerHTML = mdToSafeHTML(text); - } else { - // user / context bubbles stay plain-text - b.textContent = text; - } - + b[cls === "ht-ai" ? "innerHTML" : "textContent"] = + cls === "ht-ai" ? mdToSafeHTML(text) : text; chatLog.appendChild(b); chatLog.scrollTop = chatLog.scrollHeight; return b; @@ -116,30 +103,28 @@ const LOADER_HTML = ''; - function setInputDisabled(d) { + const setInputDisabled = (d) => { inputBox.disabled = d; sendBtn.disabled = d; - } - function clearThreadCookie() { + }; + const clearThreadCookie = () => { document.cookie = "threadId=; Path=/; Max-Age=0"; - threadId = null; - } - function resetConversation() { + threadId = null; + }; + const resetConversation = () => { chatLog.innerHTML = ""; clearThreadCookie(); panel.classList.remove("open"); - } + }; /* ------------------- Panel open / close ------------------- */ btn.addEventListener("click", () => { if (!savedSelection) { - alert("Please highlight some text first to then ask HackTricks AI about it."); + alert("Please highlight some text first."); return; } if (savedSelection.length > MAX_CONTEXT) { - alert( - `Highlighted text is too long (${savedSelection.length} chars). Max allowed: ${MAX_CONTEXT}.` - ); + alert(`Highlighted text is too long. Max ${MAX_CONTEXT} chars.`); return; } chatLog.innerHTML = ""; @@ -157,11 +142,10 @@ addMsg("Please wait until the current operation completes.", "ht-ai"); return; } - isRunning = true; setInputDisabled(true); - const loadingBubble = addMsg("", "ht-ai"); - loadingBubble.innerHTML = LOADER_HTML; + const loading = addMsg("", "ht-ai"); + loading.innerHTML = LOADER_HTML; const content = context ? `### Context:\n${context}\n\n### Question to answer:\n${question}` @@ -178,43 +162,39 @@ try { const e = await res.json(); if (e.error) err = `Error: ${e.error}`; - else if (res.status === 429) - err = "Rate limit exceeded. Please try again later."; + else if (res.status === 429) err = "Rate limit exceeded."; } catch (_) {} - loadingBubble.textContent = err; + loading.textContent = err; return; } const data = await res.json(); - loadingBubble.remove(); + loading.remove(); if (Array.isArray(data.response)) - data.response.forEach((p) => { + data.response.forEach((p) => addMsg( p.type === "text" && p.text && p.text.value ? p.text.value : JSON.stringify(p), "ht-ai" - ); - }); + ) + ); else if (typeof data.response === "string") addMsg(data.response, "ht-ai"); else addMsg(JSON.stringify(data, null, 2), "ht-ai"); } catch (e) { console.error("Error sending message:", e); - loadingBubble.textContent = "An unexpected error occurred."; + loading.textContent = "An unexpected error occurred."; } finally { isRunning = false; setInputDisabled(false); chatLog.scrollTop = chatLog.scrollHeight; } } - async function handleSend() { const q = inputBox.value.trim(); if (!q) return; if (q.length > MAX_QUESTION) { - alert( - `Your question is too long (${q.length} chars). Max allowed: ${MAX_QUESTION}.` - ); + alert(`Question too long (${q.length}). Max ${MAX_QUESTION}.`); return; } inputBox.value = ""; @@ -228,9 +208,9 @@ handleSend(); } }); - } + } /* end init */ - /* ==================================================================== */ + /* =================================================================== */ async function ensureThreadId() { const m = document.cookie.match(/threadId=([^;]+)/); if (m && m[1]) { @@ -241,62 +221,67 @@ const r = await fetch(API_BASE, { method: "POST", credentials: "include" }); const d = await r.json(); if (!r.ok || !d.threadId) throw new Error(`${r.status} ${r.statusText}`); - threadId = d.threadId; + threadId = d.threadId; document.cookie = `threadId=${threadId}; Path=/; Secure; SameSite=Strict; Max-Age=7200`; } catch (e) { console.error("Error creating threadId:", e); - alert("Failed to initialise the conversation. Please refresh and try again."); + alert("Failed to initialise the conversation. Please refresh."); throw e; } } - /* ==================================================================== */ + /* =================================================================== */ function injectStyles() { const css = ` - #ht-ai-btn{position:fixed;bottom:20px;left:50%;transform:translateX(-50%);width:60px;height:60px;border-radius:50%;background:#1e1e1e;color:#fff;font-size:28px;display:flex;align-items:center;justify-content:center;cursor:pointer;z-index:99999;box-shadow:0 2px 8px rgba(0,0,0,.4);transition:opacity .2s} - #ht-ai-btn:hover{opacity:.85} - @media(max-width:768px){#ht-ai-btn{display:none}} - #ht-ai-tooltip{position:fixed;padding:6px 8px;background:#111;color:#fff;border-radius:4px;font-size:13px;white-space:pre-wrap;pointer-events:none;opacity:0;transform:translate(-50%,-8px);transition:opacity .15s ease,transform .15s ease;z-index:100000} - #ht-ai-tooltip.show{opacity:1;transform:translate(-50%,-12px)} - #ht-ai-panel{position:fixed;top:0;right:0;height:100%;width:350px;max-width:90vw;background:#000;color:#fff;display:flex;flex-direction:column;transform:translateX(100%);transition:transform .3s ease;z-index:100000;font-family:system-ui,-apple-system,Segoe UI,Roboto,"Helvetica Neue",Arial,sans-serif} - #ht-ai-panel.open{transform:translateX(0)} - @media(max-width:768px){#ht-ai-panel{display:none}} - #ht-ai-header{display:flex;justify-content:space-between;align-items:center;padding:12px 16px;border-bottom:1px solid #333} - #ht-ai-header .ht-actions{display:flex;gap:8px;align-items:center} - #ht-ai-close,#ht-ai-reset{cursor:pointer;font-size:18px;background:none;border:none;color:#fff;padding:0} - #ht-ai-close:hover,#ht-ai-reset:hover{opacity:.7} - #ht-ai-chat{flex:1;overflow-y:auto;padding:16px;display:flex;flex-direction:column;gap:12px;font-size:14px} - .ht-msg{max-width:90%;line-height:1.4;padding:10px 12px;border-radius:8px;white-space:pre-wrap;word-wrap:break-word} - .ht-user{align-self:flex-end;background:${BRAND_RED}} - .ht-ai{align-self:flex-start;background:#222} - .ht-context{align-self:flex-start;background:#444;font-style:italic;font-size:13px} - #ht-ai-input{display:flex;gap:8px;padding:12px 16px;border-top:1px solid #333} - #ht-ai-question{flex:1;min-height:40px;max-height:120px;resize:vertical;padding:8px;border-radius:6px;border:none;font-size:14px} - #ht-ai-send{padding:0 18px;border:none;border-radius:6px;background:${BRAND_RED};color:#fff;font-size:14px;cursor:pointer} - #ht-ai-send:disabled{opacity:.5;cursor:not-allowed} - /* Loader animation */ - .ht-loading{display:inline-flex;align-items:center;gap:4px} - .ht-loading span{width:6px;height:6px;border-radius:50%;background:#888;animation:ht-bounce 1.2s infinite ease-in-out} - .ht-loading span:nth-child(2){animation-delay:0.2s} - .ht-loading span:nth-child(3){animation-delay:0.4s} - @keyframes ht-bounce{0%,80%,100%{transform:scale(0);}40%{transform:scale(1);} } - ::selection{background:#ffeb3b;color:#000} - ::-moz-selection{background:#ffeb3b;color:#000}`; +#ht-ai-btn{position:fixed;bottom:20px;left:50%;transform:translateX(-50%);min-width:60px;height:60px;border-radius:30px;background:linear-gradient(45deg, #b31328, #d42d3f, #2d5db4, #3470e4);background-size:300% 300%;animation:gradientShift 8s ease infinite;color:#fff;font-size:18px;display:flex;align-items:center;justify-content:center;cursor:pointer;z-index:99999;box-shadow:0 2px 8px rgba(0,0,0,.4);transition:opacity .2s;padding:0 20px} +#ht-ai-btn span{margin-left:8px;font-weight:bold} +@keyframes gradientShift{0%{background-position:0% 50%}50%{background-position:100% 50%}100%{background-position:0% 50%}} +#ht-ai-btn:hover{opacity:.85} +@media(max-width:768px){#ht-ai-btn{display:none}} +#ht-ai-tooltip{position:fixed;padding:6px 8px;background:#111;color:#fff;border-radius:4px;font-size:13px;white-space:pre-wrap;pointer-events:none;opacity:0;transform:translate(-50%,-8px);transition:opacity .15s ease,transform .15s ease;z-index:100000} +#ht-ai-tooltip.show{opacity:1;transform:translate(-50%,-12px)} +#ht-ai-panel{position:fixed;top:0;right:0;height:100%;max-width:90vw;background:#000;color:#fff;display:flex;flex-direction:column;transform:translateX(100%);transition:transform .3s ease;z-index:100000;font-family:system-ui,-apple-system,Segoe UI,Roboto,"Helvetica Neue",Arial,sans-serif} +#ht-ai-panel.open{transform:translateX(0)} +@media(max-width:768px){#ht-ai-panel{display:none}} +#ht-ai-header{display:flex;justify-content:space-between;align-items:center;padding:12px 16px;border-bottom:1px solid #333} +#ht-ai-header .ht-actions{display:flex;gap:8px;align-items:center} +#ht-ai-close,#ht-ai-reset{cursor:pointer;font-size:18px;background:none;border:none;color:#fff;padding:0} +#ht-ai-close:hover,#ht-ai-reset:hover{opacity:.7} +#ht-ai-chat{flex:1;overflow-y:auto;padding:16px;display:flex;flex-direction:column;gap:12px;font-size:14px} +.ht-msg{max-width:90%;line-height:1.4;padding:10px 12px;border-radius:8px;white-space:pre-wrap;word-wrap:break-word} +.ht-user{align-self:flex-end;background:${BRAND_RED}} +.ht-ai{align-self:flex-start;background:#222} +.ht-context{align-self:flex-start;background:#444;font-style:italic;font-size:13px} +#ht-ai-input{display:flex;gap:8px;padding:12px 16px;border-top:1px solid #333} +#ht-ai-question{flex:1;min-height:40px;max-height:120px;resize:vertical;padding:8px;border-radius:6px;border:none;font-size:14px} +#ht-ai-send{padding:0 18px;border:none;border-radius:6px;background:${BRAND_RED};color:#fff;font-size:14px;cursor:pointer} +#ht-ai-send:disabled{opacity:.5;cursor:not-allowed} +/* Loader */ +.ht-loading{display:inline-flex;align-items:center;gap:4px} +.ht-loading span{width:6px;height:6px;border-radius:50%;background:#888;animation:ht-bounce 1.2s infinite ease-in-out} +.ht-loading span:nth-child(2){animation-delay:0.2s} +.ht-loading span:nth-child(3){animation-delay:0.4s} +@keyframes ht-bounce{0%,80%,100%{transform:scale(0);}40%{transform:scale(1);} } +::selection{background:#ffeb3b;color:#000} +::-moz-selection{background:#ffeb3b;color:#000} +/* NEW: resizer handle */ +#ht-ai-resizer{position:absolute;left:0;top:0;width:6px;height:100%;cursor:ew-resize;background:transparent} +#ht-ai-resizer:hover{background:rgba(255,255,255,.05)}`; const s = document.createElement("style"); s.id = "ht-ai-style"; s.textContent = css; document.head.appendChild(s); } + /* =================================================================== */ function createFloatingButton() { const d = document.createElement("div"); d.id = "ht-ai-btn"; - d.textContent = "🤖"; + d.innerHTML = "🤖HackTricksAI"; document.body.appendChild(d); return d; } - function createTooltip(btn) { const t = document.createElement("div"); t.id = "ht-ai-tooltip"; @@ -311,11 +296,16 @@ btn.addEventListener("mouseleave", () => t.classList.remove("show")); } + /* =================================================================== */ function createSidebar() { + const saved = parseInt(localStorage.getItem("htAiWidth") || DEF_W, 10); + const width = Math.min(Math.max(saved, MIN_W), MAX_W); + const p = document.createElement("div"); p.id = "ht-ai-panel"; + p.style.width = width + "px"; // ← applied width p.innerHTML = ` -
HackTricks AI Chat +
HackTricks AI Chat
@@ -326,7 +316,39 @@
`; + /* NEW: resizer strip */ + const resizer = document.createElement("div"); + resizer.id = "ht-ai-resizer"; + p.appendChild(resizer); document.body.appendChild(p); + addResizeLogic(resizer, p); return p; } + + /* ---------------- resize behaviour ---------------- */ + function addResizeLogic(handle, panel) { + let startX, startW, dragging = false; + + const onMove = (e) => { + if (!dragging) return; + const dx = startX - e.clientX; // dragging leftwards ⇒ +dx + let newW = startW + dx; + newW = Math.min(Math.max(newW, MIN_W), MAX_W); + panel.style.width = newW + "px"; + }; + const onUp = () => { + if (!dragging) return; + dragging = false; + localStorage.setItem("htAiWidth", parseInt(panel.style.width, 10)); + document.removeEventListener("mousemove", onMove); + document.removeEventListener("mouseup", onUp); + }; + handle.addEventListener("mousedown", (e) => { + dragging = true; + startX = e.clientX; + startW = parseInt(window.getComputedStyle(panel).width, 10); + document.addEventListener("mousemove", onMove); + document.addEventListener("mouseup", onUp); + }); + } })();