Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
86
Help us understand the problem. What is going on with this article?
@kawasima

S2-020類似攻撃のStruts1での対策方法

More than 5 years have passed since last update.

恐ろしいことですが、実装が全然違うStruts2の脆弱性S2-020と同様の攻撃手法で、Struts1も脆弱性があることが分かりました。
http://www.lac.co.jp/security/alert/2014/04/24_alert_01.html

ここではあまり明らかになっていませんが、原因は

RequestUtils.java
        // Set the corresponding properties of our bean
        try {
            BeanUtils.populate(bean, properties);
        } catch(Exception e) {
            throw new ServletException("BeanUtils.populate", e);
        } finally {
            if (multipartHandler != null) {
                // Set the multipart request handler for our ActionForm.
                // If the bean isn't an ActionForm, an exception would have been
                // thrown earlier, so it's safe to assume that our bean is
                // in fact an ActionForm.
                ((ActionForm) bean).setMultipartRequestHandler(multipartHandler);
            }
        }

BeanUtils.populate(bean, properties)で値を検証すること無く、populateを呼んでることに起因します。

populateはBeanUtilsBeansetPropertyを順次呼び出していくわけですが、ここに問題があります。
BeanUtilsの仕様にNestedPropertyというのがあって、要はA.B.Cとプロパティをドットつなぎで書いておくと、bean.getA().getB()と順次呼び出され、最後にsetC()で値がセットされます。ここがノーチェックなので、class.classLoader.などと書いておくと、getclass().getClassLoader()と等価であり、クラスローダにもアクセスできてしまうことになるわけです。

なので、対策としてはStruts1というよりは、commons-beanutilsにチェックロジックを入れるべきかと思います。逆にいうとStruts1使っていなくても、commons-beanutilsのpopulateをユーザ入力値ノーバリデーションで使っていれば、同じ脆弱性が存在することになります。

commons-beanutilsのバージョン1.8.xからは、このプロパティを辿っていくロジックが定義できるようになりました。したがって、これを置き換えてしまえば、脆弱性はなくなるはずです。

(4/30 修正) nakamura-toさんにオシャレにしていただいたのでそちらをお使いください。
https://gist.github.com/nakamura-to/11347570

package example;

import org.apache.commons.beanutils.expression.DefaultResolver;

public class SafeResolver extends DefaultResolver {

    @Override
    public String next(String expression) {
        String property = super.next(expression);
        if ("class".equalsIgnoreCase(property)) {
            return "";
        }
        return property;
    }
}

(4/30 追記)
上記のBeanUtilsに対する修正は、Struts1だけでなく独自にユーザ入力値をBeanにマッピングするような処理にも有効ですが、ことStruts1だけの対応であれば、以下に示すようにRequestProcessorを置き換えることで脆弱性対応可能です。
古いシステムに対してBeanUtilsのバージョンアップがちょっとハードル高い(対応に時間がかかる)という声があったので、そういう場合にお使い頂ければよいかと思います。

@yuuyu さんからの指摘を受けて書き直しました。

これで、struts-config.xmlで、このRequestProcessorを使うようにしておけば、悪意のあるパラメータにはServletExceptionがthrowされるようになります。

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE struts-config PUBLIC
        "-//Apache Software Foundation//DTD Struts Configuration 1.3//EN"
        "http://struts.apache.org/dtds/struts-config_1_2.dtd">

<struts-config>
    <controller processorClass="example.SafeRequestProcessor"/>
</struts-config>

そしてこれであれば、本記事のコメントServletFilterによる対処で指摘のあったMultipartリクエストに対しても、有効かと思います。


ちなみに、SAStrusはpublicフィールドもプロパティとして扱うため、BeanUtilsは使っていなく、かつ、
SnapCrab_NoName_2014-4-25_10-58-36_No-00.png

という状況なので、おそらく大丈夫かと思われます。

(4/30 追記) ひがさんからSAStrutsは大丈夫という声明が発表されております。
http://d.hatena.ne.jp/higayasuo/20140425/1398403491

86
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
kawasima
Clojure関連のことをブログがわりに書き綴ります。 ※ここでの発言はシステムエンジニアを代表するものであって、所属する組織は二の次です。

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
86
Help us understand the problem. What is going on with this article?