Strtuts2の脆弱性(S2-066、CVE-2023-50164)のやられ環境を作ってみた
はじめに
2023年12月9日にApache Struts2の新たな脆弱性(S2-066、CVE-2023-50164)が公表されました。
この脆弱性について分析を行うため、Struts2を使ったことがない状態の私が見よう見まねで脆弱性のやられ環境を作ったのでその際のメモです。
もっと効率的な作り方があるかもしれませんがそこはご愛敬。
Struts2の脆弱性の概要
この脆弱性は、ファイルアップロード時のパラメータをいじることでパストラバーサルを発生させ、悪意のあるファイルをアップロード可能になり、その結果リモートコード実行につながる可能性のある危険度の高い脆弱性です。
また、中華サイトでPoC(攻撃コード)が公開されています。
やられ環境の構築にあたってはPoCを公開しているサイトも参考にしました。
構築環境の概要
Javaの開発環境を一から作ったのですが、以下のような環境です。
Windows 10 Pro 22H2
Visual Stdio Code 1.85.0
JDK Development Kit 21.0.1
Maven 3.9.6
またやられ環境は下記サイトを参考にDockerで構築しました。
Apache Tomcat 9.0.84
Apache Struts 6.3.0
やられ環境の作り方
今回はStruts2のshowcaseサンプルアプリケーションを少しいじって環境を作りました。
まず以下からソースコードをダウンロードし適当な場所に展開します。
利用するのは src/apps/showcase のほうになります。
こちらのフォルダをVS Codeのファイル > フォルダーをワークスペースに追加 から追加します。
追加されると以下のような感じ。
無事追加出来たら、src\main\java\org\apache\struts2\showcase\fuleupload\FileUploadAction.javaを以下のように編集します。
元々のコードと比べてもらうと、そんなに大きく変更していないことがわかると思います。
なお、コメントを付与している部分の変数名を変更しないとPoCが刺さらなかったので、攻撃の成立条件に関連しているのかもしれません。
package org.apache.struts2.showcase.fileupload;
import com.opensymphony.xwork2.ActionSupport;
import org.apache.commons.io.FileUtils;
import org.apache.struts2.ServletActionContext;
import java.io.File;
/**
* Show case File Upload example's action. <code>FileUploadAction</code>
*/
public class FileUploadAction extends ActionSupport {
private static final long serialVersionUID = 5156288255337069381L;
private String contentType;
private File upload;
private String uploadFileName; // 元々の変数名はfileNameだが、そのままだとPoCが刺さらない
private String caption;
public String input() throws Exception {
return SUCCESS;
}
public String upload() throws Exception {
String path = ServletActionContext.getServletContext().getRealPath("/")+"upload";
String realPath = path + File.separator + uploadFileName;
System.out.println(realPath);
try{
FileUtils.copyFile(upload, new File(realPath));
} catch (Exception e){
e.printStackTrace();
}
return SUCCESS;
}
// since we are using <s:file name="upload" .../> the file name will be
// obtained through getter/setter of <file-tag-name>FileName
public String getUploadFileName() {
return uploadFileName;
}
public void setUploadFileName(String uploadFileName) {
this.uploadFileName = uploadFileName;
}
// since we are using <s:file name="upload" ... /> the content type will be
// obtained through getter/setter of <file-tag-name>ContentType
public String getUploadContentType() {
return contentType;
}
public void setUploadContentType(String contentType) {
this.contentType = contentType;
}
// since we are using <s:file name="upload" ... /> the File itself will be
// obtained through getter/setter of <file-tag-name>
public File getUpload() {
return upload;
}
public void setUpload(File upload) {
this.upload = upload;
}
public String getCaption() {
return caption;
}
public void setCaption(String caption) {
this.caption = caption;
}
public long getUploadSize() {
if (upload != null) {
return upload.length();
} else {
return 0;
}
}
}
上記のコードの変更を終えたら、maven installとコンパイルをします。
(下記サイトを参考にしました)
コンパイルまで実施すると、target配下にwarファイル(struts2-showcase.war)が生成されているはずです。
このwarファイルを使ってやられサーバのコンテナをビルドしていきます。
まずDockerfileを準備します。
FROM tomcat:9-jdk8
ADD struts2-showcase.war /usr/local/tomcat/webapps/
CMD ["catalina.sh", "run"]
続いてDockerコンテナをビルドして実行します。
docker build -t struts/s2_066 .
docker run -it --rm -p 8080:8080 struts/s2_066
アップロードされたかの確認のためにコンテナのシェルに入りたい場合は以下のようにします。
docker ps // CONTAINER IDを確認
docker exec -it <CONTAINER ID> bash
無事にコンテナが起動したら、ブラウザでアクセスしてみます。
http://locahost:8080/struts2-showcase/showcase.action
こんなページが表示されればOK
ファイルアップロードのページは、上部のメニューのFileからSingle File Uploadをクリックします。
適当なファイルをアップロードしてみます。
Captionは適当でOK。
コンテナの/usr/local/tomcat/webapps/struts2-showcase/upload/ 配下にアップロードしたファイルが保存されていればOK。
これで脆弱性を検証できる環境が整いました。
おわりに
作った環境に対してPoCを打ち込んでパストラバーサルができるところまでは確認できています。
攻撃原理は中国語の壁もあり解読が進んでいません。
ぼちぼちどこぞのセキュリティベンダが日本語の解説記事書いてくれることを期待(他力本願)
この記事が気に入ったらサポートをしてみませんか?