<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>jh_dev.log</title>
        <link>https://velog.io/</link>
        <description>렛츠고</description>
        <lastBuildDate>Sun, 26 Jul 2026 03:30:19 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>jh_dev.log</title>
            <url>https://velog.velcdn.com/images/jh_devlog/profile/4ccbfee0-dff4-4666-8d36-e41a31f0d1a8/image.jpg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. jh_dev.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/jh_devlog" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[Confluence 취약점 악용을 통한 LockBit 침해사고]]></title>
            <link>https://velog.io/@jh_devlog/Confluence-%EC%B7%A8%EC%95%BD%EC%A0%90-%EC%95%85%EC%9A%A9%EC%9D%84-%ED%86%B5%ED%95%9C-LockBit-%EC%B9%A8%ED%95%B4%EC%82%AC%EA%B3%A0</link>
            <guid>https://velog.io/@jh_devlog/Confluence-%EC%B7%A8%EC%95%BD%EC%A0%90-%EC%95%85%EC%9A%A9%EC%9D%84-%ED%86%B5%ED%95%9C-LockBit-%EC%B9%A8%ED%95%B4%EC%82%AC%EA%B3%A0</guid>
            <pubDate>Sun, 26 Jul 2026 03:30:19 GMT</pubDate>
            <description><![CDATA[<h2 id="1-개요">1. 개요</h2>
<p>2024년 2월, 공격자는 인터넷에 노출된 Windows 기반 Confluence 서버의 원격 코드 실행 취약점 <code>CVE-2023-22527</code>을 악용해 SYSTEM 권한을 확보했다.</p>
<p>이후 <code>mshta.exe</code>와 PowerShell을 이용해 Metasploit Meterpreter C2 세션을 수립하고, AnyDesk와 신규 로컬 관리자 계정을 통해 지속적인 접근 수단을 마련했다. Mimikatz, Veeam 자격 증명 추출 스크립트와 평문 비밀번호 파일을 이용해 추가 계정을 확보한 뒤 RDP로 내부 서버에 이동했다.</p>
<p>공격자는 Rclone으로 내부 자료를 MEGA 클라우드에 유출하고 Windows 이벤트 로그를 삭제했다. 이후 백업 서버와 파일 서버에서 LockBit을 수동 실행한 뒤, PDQ Deploy와 SMB를 이용해 랜섬웨어를 네트워크 전반으로 확산했다.</p>
<p>최초 침입부터 랜섬웨어 실행까지 약 2시간 6분이 소요됐다.</p>
<hr>
<h2 id="2-사고-내용">2. 사고 내용</h2>
<h3 id="21-confluence-취약점을-통한-최초-침투">2.1 Confluence 취약점을 통한 최초 침투</h3>
<p>공격자는 <code>CVE-2023-22527</code> 취약점이 존재하는 Confluence 서버에 조작된 HTTP POST 요청을 전송했다.</p>
<p>해당 취약점은 서버 측 템플릿 인젝션을 통해 인증 없이 임의 명령을 실행할 수 있는 취약점이다. 공격자는 SYSTEM 권한으로 다음 명령을 실행해 사용자와 현재 권한을 확인했다.</p>
<pre><code class="language-cmd">net user
whoami</code></pre>
<h3 id="22-metasploit-c2-연결">2.2 Metasploit C2 연결</h3>
<p>공격자는 처음에 <code>curl</code>로 AnyDesk 설치 파일을 내려받으려 했지만 실패했다.</p>
<p>이후 <code>mshta.exe</code>를 이용해 외부 HTA 파일을 실행했다. HTA 파일에 포함된 난독화된 PowerShell 코드는 메모리에서 Metasploit Shellcode를 실행해 Meterpreter C2 세션을 수립했다.</p>
<pre><code class="language-text">Confluence 취약점 악용
→ AnyDesk 다운로드 시도 실패
→ mshta.exe로 외부 HTA 실행
→ PowerShell Stager 실행
→ Meterpreter C2 연결</code></pre>
<h3 id="23-기존-프로세스-종료와-c2-재연결">2.3 기존 프로세스 종료와 C2 재연결</h3>
<p>공격자는 <code>tasklist</code>로 실행 중인 프로세스를 확인한 뒤 일부 프로세스를 종료했다.</p>
<p>종료된 프로세스 중에는 이미 서버를 침해한 다른 위협 행위자의 C2 프로세스가 포함됐을 가능성이 있다. 공격자는 이 과정에서 자신의 Meterpreter가 실행되던 PowerShell 프로세스까지 종료했으며, Confluence 취약점을 다시 악용해 C2 세션을 복구했다.</p>
<h3 id="24-지속성-확보">2.4 지속성 확보</h3>
<p>공격자는 AnyDesk를 설치하고 무인 접속 비밀번호와 자동 시작 기능을 설정했다. AnyDesk는 Windows 서비스로 등록돼 재부팅 후에도 실행됐다.</p>
<p>또한 <code>backup</code>이라는 로컬 계정을 생성하고 <code>Administrators</code> 그룹에 추가해 RDP 접속에 사용했다.</p>
<h3 id="25-방어-회피와-자격-증명-접근">2.5 방어 회피와 자격 증명 접근</h3>
<p>공격자는 RDP 세션에서 Windows Defender를 비활성화했다.</p>
<p>또한 최초 침입 약 20분 뒤 Mimikatz를 실행해 <code>lsass.exe</code> 메모리에서 Administrator 계정의 인증 정보를 추출했다. 원문에서는 두 행위의 정확한 선후 관계가 명시되지 않았다.</p>
<p>이후 백업 서버에서는 <code>Veeam-Get-Creds-New.ps1</code>을 이용해 Veeam 자격 증명을 추출하고, 파일 서버에서는 도메인 관리자 계정이 포함된 평문 비밀번호 파일을 발견했다.</p>
<h3 id="26-내부-탐색과-이동">2.6 내부 탐색과 이동</h3>
<p>공격자는 다음 명령과 NetScan을 이용해 시스템 및 내부 네트워크를 조사했다.</p>
<pre><code class="language-cmd">hostname
ipconfig
tasklist
query user
net user</code></pre>
<p>확보한 계정으로 최초 침해된 Confluence 서버에서 다음 시스템으로 RDP 이동했다.</p>
<ul>
<li>백업 서버</li>
<li>파일 서버</li>
<li>도메인 컨트롤러</li>
<li>Exchange 서버</li>
</ul>
<h3 id="27-데이터-유출과-흔적-제거">2.7 데이터 유출과 흔적 제거</h3>
<p>최초 침입 약 1시간 11분 뒤 공격자는 파일 서버에서 Rclone을 실행해 내부 자료를 MEGA 클라우드로 전송했다.</p>
<p>데이터 유출 이후에는 <code>wevtutil</code>을 이용해 Windows 이벤트 로그를 삭제하고, 침해 과정에서 사용한 일부 도구와 파일도 제거했다.</p>
<pre><code class="language-cmd">wevtutil el
wevtutil cl [로그 이름]</code></pre>
<h3 id="28-lockbit-랜섬웨어-배포">2.8 LockBit 랜섬웨어 배포</h3>
<p>공격자는 먼저 활성화된 RDP 세션을 이용해 백업 서버와 파일 서버에서 LockBit을 수동으로 실행했다.</p>
<p>이후 PDQ Deploy를 이용해 LockBit 실행 파일과 <code>asd.bat</code>을 여러 시스템에 배포했다.</p>
<pre><code class="language-text">백업·파일 서버에서 LockBit 수동 실행
→ PDQ Deploy 패키지 생성
→ SMB로 원격 시스템에 파일 복사
→ PDQDeployRunner 서비스 실행
→ 네트워크 전반에서 LockBit 실행</code></pre>
<p>마지막으로 Exchange 서버에서 Exchange 및 SQL 관련 서비스를 종료하고, <code>test.bat</code>으로 원격 시스템의 <code>C$</code> 공유를 마운트해 누락된 시스템을 다시 암호화했다.</p>
<p>암호화된 파일에는 <code>.rhddiicoE</code> 확장자가 추가됐으며, <code>rhddiicoE.README.txt</code> 랜섬노트가 생성됐다.</p>
<h3 id="29-공격-인프라-관련-정황">2.9 공격 인프라 관련 정황</h3>
<p>최초 취약점 악용과 Metasploit 통신에는 <code>92[.]51.2.22</code>가 사용됐고, AnyDesk 관련 서버로 <code>92[.]51.2.27</code>이 확인됐다.</p>
<p>일부 인프라는 과거 LockBit 제휴 조직이나 ShadowSyndicate와 연관된 인프라와 겹치는 정황이 있었지만, 이를 근거로 공격 주체를 확정할 수는 없다.</p>
<hr>
<h2 id="3-공격-흐름-요약">3. 공격 흐름 요약</h2>
<table>
<thead>
<tr>
<th>단계</th>
<th>주요 행위</th>
</tr>
</thead>
<tbody><tr>
<td>최초 침투</td>
<td>Confluence <code>CVE-2023-22527</code> 취약점 악용</td>
</tr>
<tr>
<td>C2 연결</td>
<td><code>mshta.exe</code>와 PowerShell로 Meterpreter 실행</td>
</tr>
<tr>
<td>세션 복구</td>
<td>프로세스 종료 중 자신의 C2까지 종료한 뒤 재익스플로잇</td>
</tr>
<tr>
<td>지속성 확보</td>
<td>AnyDesk 서비스 등록, 로컬 관리자 계정 생성</td>
</tr>
<tr>
<td>방어 회피</td>
<td>Windows Defender 비활성화</td>
</tr>
<tr>
<td>자격 증명 접근</td>
<td>Mimikatz, Veeam 스크립트, 평문 비밀번호 활용</td>
</tr>
<tr>
<td>내부 탐색</td>
<td>Windows 명령과 NetScan으로 내부망 조사</td>
</tr>
<tr>
<td>내부 이동</td>
<td>RDP로 백업·파일·도메인·Exchange 서버 접근</td>
</tr>
<tr>
<td>데이터 유출</td>
<td>Rclone으로 MEGA 클라우드에 자료 전송</td>
</tr>
<tr>
<td>흔적 제거</td>
<td>Windows 이벤트 로그와 공격 도구 삭제</td>
</tr>
<tr>
<td>랜섬웨어 실행</td>
<td>백업·파일 서버에서 LockBit 수동 실행</td>
</tr>
<tr>
<td>대규모 배포</td>
<td>PDQ Deploy와 SMB로 LockBit 확산</td>
</tr>
<tr>
<td>2차 암호화</td>
<td>Exchange 서버의 <code>test.bat</code>으로 누락 시스템 공격</td>
</tr>
</tbody></table>
<hr>
<h2 id="4-주요-도구-및-구성요소">4. 주요 도구 및 구성요소</h2>
<table>
<thead>
<tr>
<th>도구·구성요소</th>
<th>역할</th>
</tr>
</thead>
<tbody><tr>
<td><code>CVE-2023-22527</code></td>
<td>Confluence 서버에서 인증 없이 명령 실행</td>
</tr>
<tr>
<td><code>mshta.exe</code></td>
<td>외부 HTA와 PowerShell Stager 실행</td>
</tr>
<tr>
<td>Metasploit·Meterpreter</td>
<td>C2 연결과 원격 명령 실행</td>
</tr>
<tr>
<td>AnyDesk</td>
<td>무인 원격 접속과 지속성 확보</td>
</tr>
<tr>
<td>Mimikatz</td>
<td>LSASS 메모리에서 인증 정보 추출</td>
</tr>
<tr>
<td>NetScan</td>
<td>내부 호스트와 서비스 포트 탐색</td>
</tr>
<tr>
<td>Rclone</td>
<td>내부 자료를 MEGA 클라우드로 유출</td>
</tr>
<tr>
<td>PDQ Deploy</td>
<td>LockBit 실행 파일의 대규모 배포</td>
</tr>
<tr>
<td>LockBit Black</td>
<td>파일 암호화와 랜섬노트 생성</td>
</tr>
</tbody></table>
<hr>
<h2 id="5-mitre-attck-매핑">5. MITRE ATT&amp;CK 매핑</h2>
<table>
<thead>
<tr>
<th>Tactic</th>
<th>Technique</th>
<th>ID</th>
</tr>
</thead>
<tbody><tr>
<td>Initial Access</td>
<td>Exploit Public-Facing Application</td>
<td><code>T1190</code></td>
</tr>
<tr>
<td>Execution</td>
<td>Windows Command Shell</td>
<td><code>T1059.003</code></td>
</tr>
<tr>
<td>Execution</td>
<td>PowerShell</td>
<td><code>T1059.001</code></td>
</tr>
<tr>
<td>Defense Evasion</td>
<td>System Binary Proxy Execution: Mshta</td>
<td><code>T1218.005</code></td>
</tr>
<tr>
<td>Defense Evasion</td>
<td>Impair Defenses: Disable or Modify Tools</td>
<td><code>T1562.001</code></td>
</tr>
<tr>
<td>Command and Control</td>
<td>Ingress Tool Transfer</td>
<td><code>T1105</code></td>
</tr>
<tr>
<td>Command and Control</td>
<td>Remote Access Software</td>
<td><code>T1219</code></td>
</tr>
<tr>
<td>Persistence</td>
<td>Create Account: Local Account</td>
<td><code>T1136.001</code></td>
</tr>
<tr>
<td>Persistence</td>
<td>Windows Service</td>
<td><code>T1543.003</code></td>
</tr>
<tr>
<td>Persistence·Privilege Escalation</td>
<td>Valid Accounts: Local Accounts</td>
<td><code>T1078.003</code></td>
</tr>
<tr>
<td>Credential Access</td>
<td>LSASS Memory</td>
<td><code>T1003.001</code></td>
</tr>
<tr>
<td>Credential Access</td>
<td>Credentials in Files</td>
<td><code>T1552.001</code></td>
</tr>
<tr>
<td>Discovery</td>
<td>System Network Configuration Discovery</td>
<td><code>T1016</code></td>
</tr>
<tr>
<td>Discovery</td>
<td>Remote System Discovery</td>
<td><code>T1018</code></td>
</tr>
<tr>
<td>Discovery</td>
<td>System Owner/User Discovery</td>
<td><code>T1033</code></td>
</tr>
<tr>
<td>Discovery</td>
<td>Network Service Discovery</td>
<td><code>T1046</code></td>
</tr>
<tr>
<td>Discovery</td>
<td>Process Discovery</td>
<td><code>T1057</code></td>
</tr>
<tr>
<td>Lateral Movement</td>
<td>Remote Desktop Protocol</td>
<td><code>T1021.001</code></td>
</tr>
<tr>
<td>Exfiltration</td>
<td>Exfiltration to Cloud Storage</td>
<td><code>T1567.002</code></td>
</tr>
<tr>
<td>Defense Evasion</td>
<td>Clear Windows Event Logs</td>
<td><code>T1070.001</code></td>
</tr>
<tr>
<td>Execution·Lateral Movement</td>
<td>Software Deployment Tools</td>
<td><code>T1072</code></td>
</tr>
<tr>
<td>Impact</td>
<td>Data Encrypted for Impact</td>
<td><code>T1486</code></td>
</tr>
</tbody></table>
<hr>
<h2 id="6-주요-ioc-및-로그-아티팩트">6. 주요 IOC 및 로그 아티팩트</h2>
<h3 id="주요-ioc">주요 IOC</h3>
<table>
<thead>
<tr>
<th>구분</th>
<th>확인 대상</th>
</tr>
</thead>
<tbody><tr>
<td>공격 IP</td>
<td><code>92[.]51.2.22</code>, <code>92[.]51.2.27</code></td>
</tr>
<tr>
<td>관련 파일</td>
<td><code>asd.bat</code>, <code>test.bat</code>, <code>passwords.txt</code></td>
</tr>
<tr>
<td>탐색 도구</td>
<td><code>netscan.exe</code>, <code>delete.me</code></td>
</tr>
<tr>
<td>자격 증명 도구</td>
<td>Mimikatz, <code>Veeam-Get-Creds-New.ps1</code></td>
</tr>
<tr>
<td>데이터 유출</td>
<td><code>rclone.exe</code>, MEGA 설정 파일</td>
</tr>
<tr>
<td>랜섬웨어</td>
<td><code>.rhddiicoE</code>, <code>rhddiicoE.README.txt</code></td>
</tr>
</tbody></table>
<h3 id="주요-로그-아티팩트">주요 로그 아티팩트</h3>
<table>
<thead>
<tr>
<th>로그</th>
<th>주요 확인 항목</th>
</tr>
</thead>
<tbody><tr>
<td>Confluence 접근 로그</td>
<td>비정상 POST 요청, OGNL 표현식, 출발지 IP</td>
</tr>
<tr>
<td>Sysmon <code>1</code></td>
<td>CMD·PowerShell·mshta·Mimikatz 실행</td>
</tr>
<tr>
<td>Sysmon <code>10</code></td>
<td>Mimikatz의 LSASS 접근</td>
</tr>
<tr>
<td>Sysmon <code>11</code></td>
<td><code>passwords.txt</code> 및 공격 파일 생성</td>
</tr>
<tr>
<td>Security <code>4624</code></td>
<td>RDP 로그인과 출발지 시스템</td>
</tr>
<tr>
<td>Security <code>4720</code></td>
<td>로컬 계정 생성</td>
</tr>
<tr>
<td>Security <code>4732</code></td>
<td>Administrators 그룹 구성원 추가</td>
</tr>
<tr>
<td>Security <code>5145</code></td>
<td>공유 폴더 접근과 <code>delete.me</code> 생성</td>
</tr>
<tr>
<td>System <code>7045</code></td>
<td>AnyDesk·PDQDeployRunner 서비스 생성</td>
</tr>
<tr>
<td>PowerShell <code>4104</code></td>
<td>PowerShell Stager와 Veeam 스크립트</td>
</tr>
<tr>
<td>Zeek·Suricata</td>
<td>Metasploit C2, Rclone 유출 및 외부 통신</td>
</tr>
</tbody></table>
<blockquote>
<p>Sysmon Event ID <code>3</code>은 원문에서 직접 확인된 증거는 아니지만 해당 이벤트 수집이 활성화돼 있다면 Metasploit, AnyDesk와 Rclone의 네트워크 연결 분석에 활용할 수 있다.</p>
</blockquote>
<hr>
<h2 id="7-탐지-포인트">7. 탐지 포인트</h2>
<p><strong>Confluence 취약점 악용</strong>
비정상 POST 요청 직후 Java 또는 Confluence 프로세스에서 <code>cmd.exe</code>, <code>whoami</code>, <code>net user</code> 등이 실행되는지 확인한다.</p>
<p><strong>mshta와 PowerShell 실행</strong>
<code>mshta.exe</code> 명령줄에 외부 URL이 포함되거나 <code>mshta.exe → powershell.exe</code> 흐름이 발생하는지 확인한다.</p>
<p><strong>프로세스 종료와 재익스플로잇</strong>
다수의 <code>taskkill</code> 실행 이후 C2 통신이 중단되고 동일한 취약점 악용 요청이 다시 발생하는지 분석한다.</p>
<p><strong>AnyDesk와 계정 생성</strong>
침해 직후 AnyDesk 서비스가 등록되거나 신규 로컬 계정이 관리자 그룹에 추가된 뒤 RDP 로그인이 발생하는지 확인한다.</p>
<p><strong>Defender와 자격 증명 접근</strong>
Windows Defender 설정 변경과 비표준 프로세스의 LSASS 접근을 각각 확인한다. 두 행위의 명확한 선후 관계는 원문에서 확인되지 않는다.</p>
<p><strong>내부망 탐색과 RDP 이동</strong>
짧은 시간 동안 다수 내부 IP의 SMB·RDP 포트에 접근하거나, Confluence 서버에서 여러 내부 서버로 RDP 로그인이 발생하는지 확인한다.</p>
<p><strong>Rclone 데이터 유출</strong>
파일 서버에서 Rclone이 실행되고 평소 사용하지 않던 클라우드 저장소로 대량 전송이 발생하는지 확인한다.</p>
<p><strong>LockBit 배포</strong>
백업·파일 서버에서 랜섬웨어가 수동 실행된 뒤 PDQ Deploy를 통해 동일 파일이 여러 시스템에 생성되는지 확인한다.</p>
<table>
<thead>
<tr>
<th>구분</th>
<th>정상 행위</th>
<th>의심 행위</th>
</tr>
</thead>
<tbody><tr>
<td>AnyDesk</td>
<td>승인된 원격 지원</td>
<td>침입 직후 설치 및 무인 접속 설정</td>
</tr>
<tr>
<td>Defender</td>
<td>승인된 정책 변경</td>
<td>비인가 RDP 세션에서 비활성화</td>
</tr>
<tr>
<td>RDP</td>
<td>승인된 서버 관리</td>
<td>거점 서버에서 여러 서버로 연속 접속</td>
</tr>
<tr>
<td>Rclone</td>
<td>승인된 백업</td>
<td>미승인 클라우드로 대량 전송</td>
</tr>
<tr>
<td>PDQ Deploy</td>
<td>승인된 소프트웨어 배포</td>
<td>알 수 없는 실행 파일의 일괄 배포</td>
</tr>
<tr>
<td>파일 변경</td>
<td>일반적인 문서 수정</td>
<td>대량 암호화와 랜섬노트 생성</td>
</tr>
</tbody></table>
<hr>
<h2 id="8-정리">8. 정리</h2>
<p>이 사례는 인터넷에 노출된 Confluence 서버의 취약점이 약 2시간 만에 데이터 유출과 네트워크 전반의 랜섬웨어 사고로 확대될 수 있음을 보여준다.</p>
<p>공격자는 취약점 악용으로 SYSTEM 권한을 확보한 뒤 Metasploit과 AnyDesk로 원격 접속 경로를 마련했다. 이후 자격 증명을 탈취해 RDP로 내부 서버에 이동하고, Rclone으로 데이터를 유출한 뒤 PDQ Deploy와 SMB를 이용해 LockBit 랜섬웨어를 확산시켰다.</p>
<p>특히 AnyDesk, NetScan, Rclone, PDQ Deploy처럼 정상 업무에도 사용되는 도구가 공격에 악용됐다. 따라서 실행 파일명만으로 판단하기보다 실행 계정, 부모 프로세스, 명령줄, 실행 시점, 외부 목적지와 후속 행위를 함께 분석해야 한다.</p>
<p>피해를 예방하려면 공개 서버의 신속한 패치와 외부 노출 최소화, 관리자 계정 분리, 비밀번호 재사용 방지, 평문 자격 증명 제거, 내부 RDP 통제와 중앙 로그 보존이 필요하다.</p>
<hr>
<h2 id="9-참고-자료">9. 참고 자료</h2>
<ol>
<li><p><strong>The DFIR Report</strong>
<a href="https://thedfirreport.com/2025/02/24/confluence-exploit-leads-to-lockbit-ransomware/">Confluence Exploit Leads to LockBit Ransomware</a></p>
</li>
<li><p><strong>Atlassian</strong>
<a href="https://confluence.atlassian.com/security/cve-2023-22527-rce-remote-code-execution-vulnerability-in-confluence-data-center-and-confluence-server-1333990257.html">CVE-2023-22527 – RCE Vulnerability in Confluence Data Center and Server</a></p>
</li>
<li><p><strong>MITRE ATT&amp;CK</strong><br><a href="https://attack.mitre.org/">MITRE ATT&amp;CK Enterprise Matrix</a></p>
</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[악성 OneNote 파일을 통한 IcedID·Nokoyawa 침해사고]]></title>
            <link>https://velog.io/@jh_devlog/%EC%95%85%EC%84%B1-OneNote-%ED%8C%8C%EC%9D%BC%EC%9D%84-%ED%86%B5%ED%95%9C-IcedIDNokoyawa-%EC%B9%A8%ED%95%B4%EC%82%AC%EA%B3%A0</link>
            <guid>https://velog.io/@jh_devlog/%EC%95%85%EC%84%B1-OneNote-%ED%8C%8C%EC%9D%BC%EC%9D%84-%ED%86%B5%ED%95%9C-IcedIDNokoyawa-%EC%B9%A8%ED%95%B4%EC%82%AC%EA%B3%A0</guid>
            <pubDate>Sat, 25 Jul 2026 10:03:31 GMT</pubDate>
            <description><![CDATA[<h2 id="1-개요">1. 개요</h2>
<p>2023년 2월 말, 공격자는 ‘보안 메시지(Secure Message)’를 위장한 피싱 이메일에 악성 Microsoft OneNote 첨부파일(<code>.one</code>)을 실어 유포했다. 사용자가 첨부파일 내 <code>Open</code> 버튼을 클릭하자 숨겨진 배치 파일이 실행되며 PowerShell로 IcedID 악성코드가 다운로드됐고, 이후 약 21일간은 눈에 띄는 추가 행위 없이 C2 Beaconing만 유지됐다.</p>
<p>22일째부터 시스템·도메인 정보를 탐색하기 시작한 공격자는 33일째에 Cobalt Strike를 배포해 AdFind·NetScan으로 내부망을 정찰했다. 이후 AnyDesk로 지속적인 원격 접속 수단을 마련하고, 이미 <code>Domain Admins</code> 그룹에 속해 있던 감염 계정을 그대로 활용해 별도의 권한 상승 없이 파일 서버와 백업 서버로 이동했다.</p>
<p>공격자는 중요 자료를 FileZilla로 외부에 유출한 뒤 Nokoyawa 랜섬웨어를 배포했다. 최초 감염부터 랜섬웨어 실행까지 약 812시간(34일)이 소요됐다.</p>
<hr>
<h2 id="2-사고-내용">2. 사고 내용</h2>
<h3 id="21-악성-onenote-파일을-통한-최초-침투">2.1 악성 OneNote 파일을 통한 최초 침투</h3>
<p>공격자는 ‘보안 메시지’가 포함되어 있다는 내용의 피싱 이메일을 여러 기업에 전송했다. 이메일에는 <code>.one</code> 파일이 첨부되어 있었고, 문서 안에는 흐릿한 이미지와 함께 <code>Open</code> 버튼이 표시되어 있었다. 버튼 뒤에는 <code>O p e n.cmd</code>라는 배치 파일이 숨겨져 있었으며, 사용자가 OneNote의 경고 메시지를 통과해 버튼을 실행하자 감염이 시작됐다.</p>
<h3 id="22-powershell을-이용한-icedid-다운로드-및-실행">2.2 PowerShell을 이용한 IcedID 다운로드 및 실행</h3>
<p>배치 파일은 <code>Invoke-WebRequest</code>를 호출해 외부 서버에서 파일을 다운로드했다. 요청 URL은 GIF 이미지처럼, 저장 파일(<code>C:\ProgramData\COIm.jpg</code>)은 JPG처럼 위장했지만 실제로는 IcedID DLL이었다. 공격자는 <code>rundll32.exe C:\ProgramData\COIm.jpg,init</code>으로 정상 Windows 프로그램을 이용해 악성 DLL을 실행했다.</p>
<pre><code>ONENOTE.EXE → cmd.exe(&quot;O p e n.cmd&quot;) → powershell.exe(다운로드) → rundll32.exe(init 실행)</code></pre><p>IcedID 실행 이후 감염 시스템은 외부 C2 서버와 HTTP·TLS 기반 통신을 시작했다.</p>
<h3 id="23-예약-작업을-통한-지속성-확보">2.3 예약 작업을 통한 지속성 확보</h3>
<p>IcedID는 <code>AppData\Roaming</code> 경로에 첫 번째 실행 단계인 <code>Cadiak.dll</code>과, 메모리에서 불러오는 인코딩된 두 번째 단계 데이터 <code>license.dat</code>를 생성했다. 이후 사용자가 로그인할 때마다 <code>rundll32.exe</code>로 <code>Cadiak.dll</code>이 재실행되도록 예약 작업을 등록해, 재부팅이나 재로그인 이후에도 자동으로 실행되도록 지속성을 확보했다.</p>
<h3 id="24-장기간의-c2-통신과-잠복">2.4 장기간의 C2 통신과 잠복</h3>
<p>초기 감염 이후 약 21일 동안은 눈에 띄는 추가 행위 없이 감염 시스템과 IcedID C2 서버 간 주기적인 Beaconing만 이어졌다(일부 연결은 약 10분 간격으로 12~28일간 지속). 22일째에는 IcedID가 <code>systeminfo</code>, <code>ipconfig /all</code>, <code>net view</code>, <code>net group &quot;Domain Admins&quot; /domain</code>, <code>nltest /domain_trusts</code> 등을 실행해 설치된 보안 제품, 운영체제·네트워크 설정, 도메인 신뢰 관계, 접근 가능한 내부 시스템, 도메인 관리자 그룹을 확인했다.</p>
<h3 id="25-cobalt-strike-배포-및-내부-환경-탐색">2.5 Cobalt Strike 배포 및 내부 환경 탐색</h3>
<p>침입 33일째, IcedID는 최초 감염 시스템에 여러 개의 Cobalt Strike Beacon을 생성·실행했다. DLL 형태 Beacon은 사용자 임시 폴더에 저장된 뒤 <code>regsvr32.exe</code>로 실행됐으며, 실행 파일 형태도 함께 사용됐다. Beacon은 정상 프로세스에 코드를 삽입하고, <code>AD.bat</code>와 <code>AdFind.exe</code>로 도메인 신뢰 관계·사용자·그룹·OU·서브넷·컴퓨터 정보를 수집했다. <code>nslookup</code>으로 내부 호스트명을 확인하고 NetScan으로 DNS(53), Kerberos(88), RPC(135), LDAP(389), HTTPS(443), SMB(445), RDP(3389) 등의 서비스 포트를 탐색했으며, <code>\postex_*</code>, <code>\status_*</code> 형태의 Cobalt Strike 특유 Named Pipe도 생성됐다.</p>
<h3 id="26-anydesk-설치와-고권한-계정-악용">2.6 AnyDesk 설치와 고권한 계정 악용</h3>
<p>공격자는 PowerShell 스크립트로 <code>C:\ProgramData</code>에 AnyDesk를 다운로드해 Windows 시작 시 자동 실행되도록 설치하고, 명령줄로 무인 접속 비밀번호를 설정했다(<code>--install</code>, <code>--start-with-win</code>, <code>--silent</code>, <code>--set-password</code>). 이를 통해 감염 시스템에 직접 접속해 파일과 공유 폴더를 확인했다.</p>
<p>특히 악성 OneNote 파일을 실행한 사용자 계정이 이미 <code>Domain Admins</code> 그룹에 포함되어 있어, 공격자는 별도의 권한 상승 과정 없이 도메인 관리자 권한을 곧바로 활용할 수 있었다.</p>
<h3 id="27-자격-증명-접근-및-중요-정보-수집">2.7 자격 증명 접근 및 중요 정보 수집</h3>
<p>공격자는 Cobalt Strike Beacon으로 <code>rundll32.exe</code> 프로세스를 생성해 <code>lsass.exe</code>에 접근했다. LSASS 프로세스 접근과 원격 스레드 생성이 확인됐으며, 메모리에 저장된 자격 증명을 추출해 최초 감염 계정과는 다른 도메인 관리자 계정을 추가로 사용한 정황도 확인됐다. 이후 파일 공유 경로에서 비밀번호 관련 파일, 개인 식별 정보, 금융·보험 문서, 업무 자료(Word·Excel·PDF)를 열람했다.</p>
<h3 id="28-rdp를-이용한-내부-이동">2.8 RDP를 이용한 내부 이동</h3>
<p>공격자는 확보한 고권한 계정으로 RDP를 이용해 백업 서버와 파일 서버에 접속했다. 새 서버에 접속할 때마다 Internet Explorer로 Cobalt Strike Beacon을 다운로드하고 동일한 AnyDesk 설치 스크립트를 배포해, 각 서버에 RDP 외에 별도의 재접속 경로를 추가로 확보했다.</p>
<h3 id="29-filezilla를-이용한-데이터-유출">2.9 FileZilla를 이용한 데이터 유출</h3>
<p>파일 서버에 접속한 공격자는 보험 관련 문서 등 업무 자료를 검토한 뒤 FileZilla를 다운로드했다. FileZilla로 외부 서버와 SSH·SFTP 연결을 수립해 수집한 자료를 수 시간 동안 전송했으며, 유출 시작 약 18시간 뒤 랜섬웨어 배포 단계로 넘어갔다. 이후 FileZilla를 삭제해 사용 흔적을 지우는 행위도 확인됐다.</p>
<h3 id="210-nokoyawa-랜섬웨어-배포">2.10 Nokoyawa 랜섬웨어 배포</h3>
<p>데이터 유출을 마친 공격자는 NetScan으로 내부망을 다시 조사한 뒤, 파일 서버와 백업 서버에 정상 프로세스명(<code>svchost.exe</code>)으로 위장한 Nokoyawa 랜섬웨어와 실행용 배치 스크립트를 배치했다. 배치 파일에는 네트워크 공유 파일 암호화, 숨겨진 드라이브 탐색, 특정 디렉터리·확장자 제외, 섀도 복사본 삭제, 랜섬노트 생성 기능이 포함되어 있었다.</p>
<p>백업 서버에서는 백업 프로그램이 일부 파일을 사용 중이어서 암호화가 실패하자, IObit Unlocker로 파일 잠금을 해제하고 Process Hacker와 Notepad++로 실행 문제를 확인하며 랜섬웨어를 여러 차례 재실행했다. 공격자는 전체 내부망이 아닌 파일 서버·백업 서버라는 핵심 시스템에 공격을 집중했다.</p>
<hr>
<h2 id="3-공격-흐름-요약">3. 공격 흐름 요약</h2>
<table>
<thead>
<tr>
<th>단계</th>
<th>주요 행위</th>
</tr>
</thead>
<tbody><tr>
<td>초기 침투</td>
<td>피싱 메일의 악성 OneNote 첨부파일 실행 → 배치 스크립트 → PowerShell로 IcedID DLL 다운로드·실행</td>
</tr>
<tr>
<td>지속성 확보</td>
<td>예약 작업으로 로그인마다 <code>Cadiak.dll</code> 재실행</td>
</tr>
<tr>
<td>잠복(약 21일)</td>
<td>IcedID C2와 주기적 Beaconing만 유지</td>
</tr>
<tr>
<td>정찰 (22일 차)</td>
<td>시스템 정보, 도메인 신뢰 관계, 관리자 그룹 확인</td>
</tr>
<tr>
<td>추가 도구 배포 (33일 차)</td>
<td>Cobalt Strike Beacon 실행, AdFind·NetScan으로 내부망 탐색</td>
</tr>
<tr>
<td>지속적 접근 확보</td>
<td>AnyDesk 설치, 이미 확보된 도메인 관리자(Domain Admins) 계정 활용</td>
</tr>
<tr>
<td>자격 증명 접근</td>
<td>LSASS 메모리 접근으로 추가 도메인 관리자 계정 확보</td>
</tr>
<tr>
<td>내부 이동</td>
<td>RDP로 백업·파일 서버 이동, 각 서버에 Cobalt Strike·AnyDesk 재설치</td>
</tr>
<tr>
<td>데이터 수집·유출</td>
<td>파일 서버 문서 확인 후 FileZilla로 SFTP 유출(약 18시간), 이후 도구 삭제</td>
</tr>
<tr>
<td>랜섬웨어 배포</td>
<td>파일·백업 서버에 Nokoyawa 배포, IObit Unlocker·Process Hacker로 재실행</td>
</tr>
</tbody></table>
<hr>
<h2 id="4-주요-도구-및-구성요소">4. 주요 도구 및 구성요소</h2>
<h3 id="41-악성-onenote-첨부파일">4.1 악성 OneNote 첨부파일</h3>
<p><code>.one</code> 파일 내부에 숨겨둔 <code>O p e n.cmd</code> 배치 파일을 실행시키는 최초 침투 수단이다. OneNote가 생성한 실행 파일과 Mark of the Web, 문서 프로그램에서의 CMD·PowerShell 실행 여부를 확인해야 한다.</p>
<h3 id="42-powershell">4.2 PowerShell</h3>
<p><code>Invoke-WebRequest</code>로 악성 DLL을 다운로드하는 데 사용됐다. 승인되지 않은 외부 서버 연결, <code>ProgramData</code>·<code>Temp</code> 경로의 파일 생성, <code>DownloadFile</code>·<code>-OutFile</code>·<code>IEX</code> 같은 문자열이 확인 대상이다.</p>
<h3 id="43-icedid">4.3 IcedID</h3>
<p>원래 뱅킹 트로이 목마로 알려진 모듈형 악성코드로, 초기 감염 유지·C2 통신·시스템 탐색·Cobalt Strike 배포에 사용됐다. 이미지 확장자로 위장한 DLL이 <code>rundll32.exe</code>로 실행되는 패턴이 특징이다.</p>
<h3 id="44-예약-작업scheduled-task">4.4 예약 작업(Scheduled Task)</h3>
<p>로그인 트리거로 <code>rundll32.exe</code>를 통해 DLL을 재실행하도록 등록한 지속성 메커니즘이다. 작업 이름뿐 아니라 XML에 포함된 실행 명령·인자·생성 계정을 함께 확인해야 한다.</p>
<h3 id="45-cobalt-strike">4.5 Cobalt Strike</h3>
<p>침투 테스트용 상용 도구로, 원격 명령 실행·프로세스 인젝션·내부 정찰·자격 증명 접근·추가 도구 배포에 악용됐다. <code>regsvr32.exe</code>를 통한 DLL 실행과 <code>\postex_*</code>, <code>\status_*</code> 형태의 Named Pipe가 특징적인 흔적이다.</p>
<h3 id="46-adfind와-netscan">4.6 AdFind와 NetScan</h3>
<p>AdFind는 AD의 사용자·그룹·컴퓨터·도메인 신뢰 관계를 조회하는 명령줄 도구이며, NetScan은 DNS·Kerberos·LDAP·SMB·RDP 등 내부 서비스 정보를 확인하는 네트워크 스캐너다. 두 도구 모두 정상 관리 업무에도 쓰이므로 실행 시점과 실행 계정이 판단 기준이 된다.</p>
<h3 id="47-anydesk">4.7 AnyDesk</h3>
<p>정상적인 원격 데스크톱 프로그램이지만, 감염 시스템과 내부 서버에 지속적으로 접속하는 수단으로 악용됐다. 비표준 경로 설치, <code>--silent</code>/<code>--start-with-win</code> 옵션, 명령줄을 통한 비밀번호 설정, Windows 서비스 등록 여부를 확인해야 한다.</p>
<h3 id="48-filezilla">4.8 FileZilla</h3>
<p>FTP·FTPS·SFTP 파일 전송 프로그램으로, 내부 자료를 외부 서버로 유출하는 데 사용됐다. 신규 설치, 알려지지 않은 외부 IP로의 장시간 대량 전송, 전송 종료 후 삭제 여부가 확인 대상이다.</p>
<h3 id="49-iobit-unlocker와-process-hacker">4.9 IObit Unlocker와 Process Hacker</h3>
<p>각각 다른 프로세스가 사용 중인 파일의 잠금을 해제하는 도구, 실행 중인 프로세스·서비스를 확인·제어하는 관리 도구다. 백업 프로그램이 점유한 파일을 암호화하고 랜섬웨어 실행 문제를 해결하는 과정에서 사용된 것으로 분석됐다.</p>
<h3 id="410-nokoyawa">4.10 Nokoyawa</h3>
<p>시스템 파일을 암호화하고 금전을 요구하는 랜섬웨어로, 파일 서버와 백업 서버를 중심으로 배포됐다. 정상 프로세스명(<code>svchost.exe</code>)으로 위장한 실행 파일, 네트워크 공유 암호화, 섀도 복사본 삭제, 랜섬노트 생성이 특징이다.</p>
<hr>
<h2 id="5-mitre-attck-매핑">5. MITRE ATT&amp;CK 매핑</h2>
<table>
<thead>
<tr>
<th>Tactic</th>
<th>Technique</th>
<th>ID</th>
</tr>
</thead>
<tbody><tr>
<td>Initial Access</td>
<td>Phishing</td>
<td><code>T1566</code></td>
</tr>
<tr>
<td>Execution</td>
<td>User Execution: Malicious File</td>
<td><code>T1204.002</code></td>
</tr>
<tr>
<td>Execution</td>
<td>Command and Scripting Interpreter (Windows Command Shell / PowerShell)</td>
<td><code>T1059.003</code> / <code>T1059.001</code></td>
</tr>
<tr>
<td>Command and Control</td>
<td>Ingress Tool Transfer</td>
<td><code>T1105</code></td>
</tr>
<tr>
<td>Defense Evasion</td>
<td>System Binary Proxy Execution (Rundll32 / Regsvr32)</td>
<td><code>T1218.011</code> / <code>T1218.010</code></td>
</tr>
<tr>
<td>Defense Evasion</td>
<td>Masquerading: Masquerade File Type</td>
<td><code>T1036.008</code></td>
</tr>
<tr>
<td>Persistence</td>
<td>Scheduled Task/Job</td>
<td><code>T1053.005</code></td>
</tr>
<tr>
<td>Command and Control</td>
<td>Application Layer Protocol: Web Protocols</td>
<td><code>T1071.001</code></td>
</tr>
<tr>
<td>Discovery</td>
<td>System Information Discovery</td>
<td><code>T1082</code></td>
</tr>
<tr>
<td>Discovery</td>
<td>Domain Trust Discovery</td>
<td><code>T1482</code></td>
</tr>
<tr>
<td>Discovery</td>
<td>Permission Groups Discovery: Domain Groups</td>
<td><code>T1069.002</code></td>
</tr>
<tr>
<td>Discovery</td>
<td>Network Service Discovery</td>
<td><code>T1046</code></td>
</tr>
<tr>
<td>Defense Evasion</td>
<td>Process Injection</td>
<td><code>T1055</code></td>
</tr>
<tr>
<td>Credential Access</td>
<td>OS Credential Dumping: LSASS Memory</td>
<td><code>T1003.001</code></td>
</tr>
<tr>
<td>Command and Control</td>
<td>Remote Access Software</td>
<td><code>T1219.002</code></td>
</tr>
<tr>
<td>Persistence</td>
<td>Create or Modify System Process: Windows Service</td>
<td><code>T1543.003</code></td>
</tr>
<tr>
<td>Lateral Movement</td>
<td>Remote Services: RDP</td>
<td><code>T1021.001</code></td>
</tr>
<tr>
<td>Collection</td>
<td>Data from Network Shared Drive</td>
<td><code>T1039</code></td>
</tr>
<tr>
<td>Exfiltration</td>
<td>Exfiltration Over Alternative Protocol</td>
<td><code>T1048</code></td>
</tr>
<tr>
<td>Defense Evasion</td>
<td>File Deletion</td>
<td><code>T1070.004</code></td>
</tr>
<tr>
<td>Impact</td>
<td>Data Encrypted for Impact</td>
<td><code>T1486</code></td>
</tr>
<tr>
<td>Impact</td>
<td>Inhibit System Recovery</td>
<td><code>T1490</code></td>
</tr>
</tbody></table>
<hr>
<h2 id="6-주요-ioc-및-로그-아티팩트">6. 주요 IOC 및 로그 아티팩트</h2>
<table>
<thead>
<tr>
<th>구분</th>
<th>확인 대상</th>
</tr>
</thead>
<tbody><tr>
<td>초기 침투 파일</td>
<td>악성 <code>.one</code> 첨부파일, <code>O p e n.cmd</code>, <code>COIm.jpg</code>(실제는 DLL)</td>
</tr>
<tr>
<td>지속성 아티팩트</td>
<td><code>Cadiak.dll</code>, <code>license.dat</code>, 로그인 트리거 예약 작업</td>
</tr>
<tr>
<td>C2·후속 도구</td>
<td>Cobalt Strike DLL/EXE Beacon, Named Pipe(<code>\postex_*</code>, <code>\status_*</code> 등)</td>
</tr>
<tr>
<td>내부 탐색 도구</td>
<td><code>AdFind.exe</code>, <code>AD.bat</code>, NetScan 실행 흔적</td>
</tr>
<tr>
<td>원격 접속 도구</td>
<td>AnyDesk 설치 경로(<code>C:\ProgramData</code>), 서비스 등록, Client ID</td>
</tr>
<tr>
<td>데이터 유출 도구</td>
<td>FileZilla 설정 XML, 외부 SFTP 접속 정보, 사후 삭제 흔적</td>
</tr>
<tr>
<td>랜섬웨어 관련</td>
<td>위장된 <code>svchost.exe</code>(Nokoyawa), 실행용 배치 스크립트, IObit Unlocker·Process Hacker 실행 흔적</td>
</tr>
<tr>
<td>주요 이벤트 ID</td>
<td>Sysmon <code>1</code>(프로세스), <code>3</code>(네트워크), <code>8</code>(원격 스레드), <code>10</code>(LSASS 접근), <code>11</code>(파일 생성), <code>15</code>(MOTW), <code>17</code>/<code>18</code>(Named Pipe)</td>
</tr>
<tr>
<td>Windows 이벤트</td>
<td>Security <code>4688</code>(프로세스 생성), <code>4698</code>(예약 작업), <code>4624</code>(RDP 로그인); System <code>7045</code>(서비스 설치); PowerShell <code>4104</code>(스크립트 블록)</td>
</tr>
</tbody></table>
<p>관련 로그가 생성되려면 Windows 감사 정책과 Sysmon 설정이 사전에 활성화되어 있어야 한다.</p>
<hr>
<h2 id="7-탐지-포인트">7. 탐지 포인트</h2>
<p><strong>OneNote를 통한 명령 실행</strong>: <code>ONENOTE.EXE → cmd.exe → powershell.exe/rundll32.exe</code>처럼 문서 프로그램에서 명령 인터프리터가 실행되는 흐름은 일반적인 문서 열람에서는 드물다. 생성된 <code>.cmd</code>/<code>.ps1</code>/<code>.dll</code> 파일의 Mark of the Web과 실행 직후의 외부 통신을 함께 확인한다.</p>
<p><strong>PowerShell 외부 통신과 파일 위장</strong>: <code>Invoke-WebRequest</code>/<code>WebClient</code>로 승인되지 않은 서버에 연결해 <code>ProgramData</code>·<code>Temp</code> 경로에 파일을 생성하는지 확인한다. 이미지 확장자를 가졌지만 실제로는 DLL/실행 파일이거나, <code>rundll32.exe</code>·<code>regsvr32.exe</code>의 인자로 전달된 파일은 의심 대상이다.</p>
<p><strong>예약 작업과 장기 Beaconing</strong>: 로그인 트리거로 <code>rundll32.exe</code>가 <code>AppData</code> 경로의 DLL을 참조하는 예약 작업, 그리고 동일 목적지로 일정 간격이 장기간 반복되는 통신(이번 사례는 최대 28일)을 함께 본다.</p>
<p><strong>내부 탐색과 Cobalt Strike</strong>: <code>systeminfo</code>, <code>net group</code>, <code>nltest</code> 등 탐색 명령의 연속 실행, <code>AdFind</code>/NetScan 실행, <code>regsvr32.exe</code>를 통한 DLL 로드와 Cobalt Strike 특유의 Named Pipe, LSASS 프로세스 접근·원격 스레드 생성을 확인한다.</p>
<p><strong>AnyDesk·RDP 오남용</strong>: 신규 설치(Event ID 7045) 후 무인 접속 비밀번호 설정, RDP 로그인 이후 곧바로 이어지는 추가 도구 다운로드와 재설치 여부를 연결해서 본다.</p>
<p><strong>FileZilla 유출과 랜섬웨어 실행</strong>: 신규 설치된 FileZilla가 알려지지 않은 외부 IP로 장시간 대량 전송한 뒤 삭제되는지, 이후 짧은 시간 안에 파일 대량 변경·확장자 변경·섀도 복사본 삭제·백업 프로세스 중단이 이어지는지 확인한다.</p>
<table>
<thead>
<tr>
<th>구분</th>
<th>정상 행위</th>
<th>의심 행위</th>
</tr>
</thead>
<tbody><tr>
<td>문서 실행 후 프로세스</td>
<td>뷰어 프로세스만 유지</td>
<td>명령 인터프리터·PowerShell 연쇄 실행</td>
</tr>
<tr>
<td>원격 관리 도구</td>
<td>사전 승인된 설치</td>
<td>감염 이후 신규 설치 후 무인 접속 설정</td>
</tr>
<tr>
<td>계정 권한</td>
<td>업무 계정과 관리자 계정 분리</td>
<td>일반 업무에 도메인 관리자 계정 상시 사용</td>
</tr>
<tr>
<td>데이터 전송 도구</td>
<td>승인된 목적지와 계정으로 사용</td>
<td>신규 설치 후 미승인 외부로 대량 전송, 이후 삭제</td>
</tr>
<tr>
<td>파일 행위</td>
<td>소수 파일 수정</td>
<td>짧은 시간 내 대량 수정·암호화, 백업 프로세스 중단 동반</td>
</tr>
</tbody></table>
<hr>
<h2 id="8-정리">8. 정리</h2>
<p>이 사례는 최초 감염부터 랜섬웨어 실행까지 약 34일이 소요돼 공격 단계마다 여러 차례 탐지 기회가 있었음을 보여준다. PowerShell, AnyDesk, FileZilla처럼 정상 업무에도 쓰이는 도구가 공격에 악용됐기 때문에, 프로그램 이름만으로 판단하기보다 실행 사용자·부모 프로세스·명령줄·파일 경로·네트워크 통신과 선후행 행위를 함께 봐야 한다.</p>
<p>특히 감염된 계정이 이미 <code>Domain Admins</code> 권한을 갖고 있었다는 점이 공격자의 권한 확보와 내부 이동을 크게 쉽게 만들어 피해 범위를 확대했다. 일반 업무 계정과 관리자 계정을 분리하고 최소 권한 원칙을 적용하는 것이 무엇보다 중요하다.</p>
<p>결국 IcedID의 장기간 잠복처럼 조용한 초기 단계라 하더라도, 예약 작업·비정상 파일 위장·장기 Beaconing 같은 흔적을 놓치지 않고 초기에 연결해서 보는 것이 34일의 여유를 실제 대응 시간으로 활용하는 길이다.</p>
<hr>
<h2 id="9-참고-자료">9. 참고 자료</h2>
<ol>
<li><strong>The DFIR Report</strong><br><a href="https://thedfirreport.com/2024/04/01/from-onenote-to-ransomnote-an-ice-cold-intrusion/">From OneNote to RansomNote: An Ice Cold Intrusion</a></li>
<li><strong>MITRE ATT&amp;CK</strong><br><a href="https://attack.mitre.org/">MITRE ATT&amp;CK Enterprise Matrix</a></li>
<li><strong>Microsoft Learn (Sysinternals)</strong><br><a href="https://learn.microsoft.com/en-us/sysinternals/downloads/sysmon">Sysmon - Windows Sysinternals</a></li>
<li><strong>Microsoft Learn</strong><br><a href="https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-10/security/threat-protection/auditing/event-4624">4624(S): An account was successfully logged on</a></li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[RDP Password Spray를 통한 RansomHub 침해사고]]></title>
            <link>https://velog.io/@jh_devlog/RDP-Password-Spray%EB%A5%BC-%ED%86%B5%ED%95%9C-RansomHub-%EC%B9%A8%ED%95%B4%EC%82%AC%EA%B3%A0</link>
            <guid>https://velog.io/@jh_devlog/RDP-Password-Spray%EB%A5%BC-%ED%86%B5%ED%95%9C-RansomHub-%EC%B9%A8%ED%95%B4%EC%82%AC%EA%B3%A0</guid>
            <pubDate>Sat, 25 Jul 2026 09:56:45 GMT</pubDate>
            <description><![CDATA[<h2 id="1-개요">1. 개요</h2>
<p>2024년 11월, 공격자는 인터넷에 노출된 RDP 서버를 대상으로 Password Spray 공격을 수행하고, 관리자 권한이 부여된 사용자 계정으로 RDP 세션에 접속했다. 이후 내부 시스템을 탐색하고 추가 자격 증명을 탈취해 도메인 컨트롤러, 파일 서버, 백업 서버, 하이퍼바이저 서버로 이동했다.</p>
<p>공격자는 중요 자료를 Rclone과 SFTP를 이용해 외부로 유출한 후 RansomHub 랜섬웨어를 배포했다. 최초 침입부터 랜섬웨어 실행까지는 약 118시간(6일)이 소요됐다.</p>
<hr>
<h2 id="2-사고-내용">2. 사고 내용</h2>
<h3 id="21-rdp-서버-대상-password-spray">2.1 RDP 서버 대상 Password Spray</h3>
<p>공격자는 인터넷에 노출된 RDP 서버를 대상으로 약 4시간 동안 여러 사용자 계정에 로그인 시도를 수행했다. 사용된 출발지 IP는 동일 ISP 대역의 두 개 IP였으며, OSINT 상으로도 방화벽·관리 인터페이스에 대한 인증 공격 이력이 확인된 IP였다.</p>
<p>Password Spray는 하나 또는 소수의 공통 비밀번호를 여러 계정에 대입하는 방식으로, 계정별 로그인 실패 횟수를 낮게 유지해 계정 잠금 정책과 단순 임계치 기반 탐지를 회피한다. 이번 사고에서는 동일 출발지 IP가 여러 계정에 낮은 실패 횟수로 접근한 끝에 6개 사용자 계정의 인증에 성공했다.</p>
<pre><code class="language-text">동일한 출발지 IP
+ 여러 사용자 계정에 로그인 시도
+ 계정별 로그인 실패 횟수는 적음
+ 일부 계정에서 인증 성공</code></pre>
<h3 id="22-탈취-계정을-이용한-rdp-침입">2.2 탈취 계정을 이용한 RDP 침입</h3>
<p>Password Spray가 시작된 약 4시간 뒤, 공격자는 인증에 성공한 계정 중 하나를 이용해 RDP 서버에 접속했다. 로그인 이벤트에서는 <code>Logon Type: 10</code>(RemoteInteractive)과 <code>Elevated Token: Yes</code>가 확인됐다. 즉 공격자는 최초 RDP 접속 단계부터 관리자 권한을 가진 세션을 확보한 상태였다.</p>
<p>특히 실제 RDP 침입에 사용된 IP(<code>164.138.90.2</code>)는 Password Spray를 수행한 IP와 달랐다. 따라서 동일한 IP에서 발생한 로그인 실패와 성공만 연결해서 분석하면 실제 침입을 놓칠 수 있으며, Password Spray 대상이 된 계정을 기준으로 이후의 로그인 이벤트를 추적해야 한다.</p>
<h3 id="23-시스템-및-네트워크-정보-탐색">2.3 시스템 및 네트워크 정보 탐색</h3>
<p>RDP 접속에 성공한 공격자는 Windows 기본 명령어와 네트워크 스캐너를 이용해 침해 시스템과 내부 네트워크를 조사했다.</p>
<p>확인된 주요 명령어는 다음과 같다.</p>
<pre><code class="language-powershell">nslookup
net user / net group
nltest
ipconfig
route
ping</code></pre>
<p>공격자는 이를 통해 다음 정보를 확인한 것으로 분석된다.</p>
<ul>
<li>내부 도메인 이름 및 도메인 컨트롤러 정보</li>
<li>로컬 및 도메인 계정, 그룹, 비밀번호 정책</li>
<li>도메인 신뢰 관계(Trust) 및 잠재적 이동 경로</li>
<li>네트워크 인터페이스, 라우팅 정보</li>
<li>접근 가능한 내부 시스템</li>
</ul>
<p>Advanced IP Scanner와 SoftPerfect NetScan도 내부 시스템과 서비스 탐색에 사용됐다. </p>
<p>Advanced IP Scanner는 공식 사이트에서 다운로드해 도메인 관리자 계정의 Downloads 폴더에서 3회 실행하고 매번 삭제하는 패턴을, NetScan은 여러 호스트의 Desktop 폴더에 배포되어 반복 실행되는 패턴을 보였다. NetScan이 공유 폴더 쓰기 권한을 확인할 때는 <code>delete.me</code>라는 파일이 원격 호스트에 생성되는 특징적인 흔적을 남긴다.</p>
<p>도메인 관리자 권한 확보 이후에는 <code>dnsmgmt.msc</code>, <code>domain.msc</code>, <code>dssite.msc</code>, <code>dsa.msc</code> 등 MMC 스냅인을 여러 도메인 컨트롤러에서 GUI로 직접 실행해 DNS, 도메인/포리스트 트러스트, AD 사이트 복제 토폴로지, 사용자·그룹 정보를 확인했다.</p>
<h3 id="24-자격-증명-접근">2.4 자격 증명 접근</h3>
<p>공격자는 CredentialsFileView로 Windows에 저장된 자격 증명 파일을 확인한 뒤, Mimikatz로 <code>lsass.exe</code> 프로세스 메모리에 접근해 추가 계정의 자격 증명을 추출했다(<code>sekurlsa::logonpasswords</code> 계열 명령 사용 정황).</p>
<pre><code class="language-text">CredentialsFileView 실행
→ 저장된 자격 증명 확인
→ Mimikatz 실행
→ lsass.exe 프로세스 접근
→ 추가 계정의 자격 증명 확보</code></pre>
<p>여기에 더해, 공격자는 여러 호스트에서 Mimikatz를 실행하면서 <strong>자식 도메인(child domain)명으로 이름 붙인 CSV 결과 파일</strong>을 다수 생성했다. 이는 Active Directory 동기화 관련 이벤트(Event ID 4662)와 함께 관찰되는데, 전체 계정을 동기화(DCSync)했다기보다는 확보한 도메인 관리자 계정이 여러 자식 도메인에서 동일한 비밀번호로 통용되는지를 확인하려는 목적으로 분석된다.</p>
<pre><code class="language-text">lsadump::dcsync /domain:CHILD.DOMAIN.EXAMPLE /user:DOMAINADMINUSER /csv &gt; CHILD.csv</code></pre>
<p>이를 통해 공격자는 최초 침입에 사용한 계정 외에도 여러 도메인에서 통용 가능한 고권한 계정을 확보했다.</p>
<h3 id="25-rdp를-이용한-내부-이동">2.5 RDP를 이용한 내부 이동</h3>
<p>최초 RDP 침입 후 약 2시간 뒤, 공격자는 가장 먼저 <strong>도메인 컨트롤러 2대</strong>로 이동했다. 이 시점부터 확보한 계정이 도메인 관리자 권한을 갖고 있었던 것으로 보인다.</p>
<p>이후 같은 날 백업 서버, 파일 서버, 하이퍼바이저 서버, 추가 도메인 컨트롤러로 이동을 확장했으며, 각 시스템에서 <code>net</code> 명령과 Mimikatz를 반복 수행했다. 첫날 마지막에는 확보한 고권한 계정으로 여러 파일 공유 서버에 접속해 문서를 열람했고, 2일 차에는 Beachhead 호스트로 돌아와 Advanced IP Scanner와 NetScan을 재실행해 더 폭넓은 네트워크 매핑을 수행했다.</p>
<p>5일 차에는 공격자가 도메인 컨트롤러를 포함한 여러 호스트에서 <code>net</code> 명령으로 다수 사용자 계정의 비밀번호를 동일한 값으로 초기화했다. 이 시점은 랜섬웨어 배포 직전과 맞물려 있어, 내부 확산을 돕거나 관리자의 계정 접근을 차단하려는 의도로 추정된다.</p>
<h3 id="26-지속적-접근-확보-atera·splashtop">2.6 지속적 접근 확보 (Atera·Splashtop)</h3>
<p>공격자는 <strong>백업 서버 2대</strong>에 Atera RMM 도구를 설치해 기존 RDP 연결이 차단되더라도 정상 관리 트래픽으로 위장해 재접속할 수 있는 수단을 마련했다.</p>
<p>5일 차에는 그중 한 백업 서버에 설치된 <strong>Splashtop</strong>을 통해 재접속했으며, 이 세션으로 NetScan 재실행, 도메인 컨트롤러 접속, 비밀번호 초기화, 랜섬웨어 바이너리 반입까지 수행했다. 즉 Atera는 지속성 확보용, Splashtop은 실제 재접속 경로로 역할이 구분됐다.</p>
<pre><code class="language-text">백업 서버 2대에 Atera 설치 (지속성 확보)
→ (5일 차) 백업 서버 1대의 Splashtop으로 재접속
→ NetScan 재실행 → DC 접속 → 계정 비밀번호 초기화
→ 랜섬웨어 바이너리 반입 및 실행</code></pre>
<h3 id="27-중요-자료-수집-및-외부-유출">2.7 중요 자료 수집 및 외부 유출</h3>
<p>3일 차 시작 시점, 공격자는 여러 파일 서버에서 Rclone을 이용한 데이터 유출을 수행했다. <code>nocmd.vbs</code>가 <code>rcl.bat</code>을 백그라운드로 실행하고, <code>rcl.bat</code>은 <code>include.txt</code>에 정의된 확장자(문서·스프레드시트류 외에 <code>.pst</code>, <code>.msg</code>, <code>.edb</code>, <code>.mbox</code> 등 이메일·DB 파일 포함) 목록을 기준으로 Rclone 작업을 수행했다.</p>
<p>외부 통신은 목적지 443번 포트로 이뤄졌지만 실제 프로토콜은 SFTP였으며, 약 40분간 총 2.03GB가 전송됐다. 이는 포트 번호만으로 프로토콜을 단정해서는 안 된다는 점을 보여준다.</p>
<p>공격자는 흔적을 완전히 지우지는 않았지만, <strong>유출로부터 약 20시간 뒤 파일 서버로 다시 접근해 Rclone 관련 파일을 삭제</strong>하는 정리 행위를 수행했다.</p>
<pre><code class="language-text">중요 파일 탐색
→ 수집 대상 파일 선별 (include.txt)
→ nocmd.vbs → rcl.bat → rclone 실행
→ 외부 서버(443/tcp, 실제 프로토콜 SFTP)로 연결
→ 약 40분간 2.03GB 전송</code></pre>
<h3 id="28-ransomhub-랜섬웨어-배포">2.8 RansomHub 랜섬웨어 배포</h3>
<p>6일 차, 공격자는 Splashtop 세션으로 반입한 <code>amd64.exe</code>를 cmd.exe에서 직접 실행했다. 랜섬웨어는 실행과 함께 다음 사전 조치를 수행했다.</p>
<ul>
<li>PowerShell로 특정 예외를 제외한 Hyper-V 가상머신을 강제 종료(<code>Stop-VM -Force</code>)</li>
<li><code>fsutil</code>로 원격→로컬/원격 심볼릭 링크 평가를 허용하도록 설정 변경 (원격 전파를 원활히 하기 위한 조치로 추정)</li>
<li><code>vssadmin</code>으로 섀도 복사본 삭제, <code>wevtutil</code>로 Security/System/Application 이벤트 로그 삭제</li>
</ul>
<p>이후 실행 파일은 SMB를 통해 다른 시스템으로 복사됐으며, 무작위 6자리 이름의 원격 Windows 서비스를 생성해 실행됐다(<code>-only-local</code> 플래그로 전파 루프 방지). 최초 침입부터 랜섬웨어 실행까지는 약 118시간(6일)이 소요됐다.</p>
<hr>
<h2 id="3-공격-흐름-요약">3. 공격 흐름 요약</h2>
<table>
<thead>
<tr>
<th>단계</th>
<th>주요 행위</th>
</tr>
</thead>
<tbody><tr>
<td>최초 접근</td>
<td>인터넷에 노출된 RDP 서버를 대상으로 Password Spray 수행</td>
</tr>
<tr>
<td>세션 확보</td>
<td>탈취한 계정으로 관리자 권한 RDP 세션 생성 (Elevated Token)</td>
</tr>
<tr>
<td>탐색</td>
<td>도메인·시스템·네트워크 정보 수집, MMC 스냅인 활용</td>
</tr>
<tr>
<td>자격 증명 접근</td>
<td>저장된 자격 증명, LSASS 메모리, 다중 도메인 계정 유효성 확인</td>
</tr>
<tr>
<td>내부 이동</td>
<td>RDP를 이용해 DC → 백업·파일·하이퍼바이저 서버로 확장 이동</td>
</tr>
<tr>
<td>지속적 접근</td>
<td>Atera(백업 서버 2대) 설치, 이후 Splashtop으로 재접속</td>
</tr>
<tr>
<td>정보 수집</td>
<td>문서, 이메일, DB 백업 등 중요 파일 수집</td>
</tr>
<tr>
<td>외부 유출</td>
<td>Rclone과 SFTP를 이용해 약 2.03GB 자료 전송</td>
</tr>
<tr>
<td>흔적 정리</td>
<td>유출 20시간 후 Rclone 관련 파일 삭제</td>
</tr>
<tr>
<td>확산 준비</td>
<td>다수 계정 비밀번호 초기화</td>
</tr>
<tr>
<td>영향</td>
<td>VM 종료, RansomHub 배포, 파일 암호화 및 복구 방해</td>
</tr>
</tbody></table>
<hr>
<h2 id="4-주요-도구-및-구성요소-분석">4. 주요 도구 및 구성요소 분석</h2>
<h3 id="41-password-spray">4.1 Password Spray</h3>
<p>하나 또는 소수의 공통 비밀번호를 여러 계정에 대입하는 방식이다. 계정별 실패 횟수는 낮게 유지되므로, 단일 계정의 실패 횟수보다 동일 출발지 IP가 접근한 고유 계정 수를 함께 확인해야 한다.</p>
<h3 id="42-rdp">4.2 RDP</h3>
<p>이번 사례에서는 외부에서의 최초 침투와 내부 시스템 간 이동에 모두 사용됐다. RDP는 정상적인 관리 기능이므로 출발지 IP, 로그인 계정, <code>Logon Type 10</code>, 관리자 권한 여부(Elevated Token), 접속 직후 실행된 프로세스, 평소 사용 여부를 함께 확인해야 한다.</p>
<h3 id="43-credentialsfileview">4.3 CredentialsFileView</h3>
<p>NirSoft 유틸리티로 Windows에 저장된 자격 증명 파일을 복호화할 수 있다. 정상 보안 점검에도 쓰이지만, 외부 RDP 침입 직후 사용자 Desktop 등 비표준 경로에서 실행됐다면 탈취 가능성을 확인해야 한다(Event ID 5379).</p>
<h3 id="44-mimikatz와-lsass">4.4 Mimikatz와 LSASS</h3>
<p><code>lsass.exe</code> 프로세스 메모리에서 자격 증명을 추출하는 도구로, 이번 사고에서는 자식 도메인별 결과 파일을 나눠 생성하며 계정의 다중 도메인 통용 여부를 검증하는 데도 활용됐다(DCSync 유사 패턴). 보안 프로그램도 LSASS에 접근할 수 있으므로 접근 프로세스의 경로·서명·계정·요청 권한을 함께 확인해야 한다.</p>
<h3 id="45-advanced-ip-scanner와-netscan">4.5 Advanced IP Scanner와 NetScan</h3>
<p>내부 네트워크의 시스템·서비스·포트·공유 자원을 탐색하는 스캐너다. 정상적인 자산 관리에도 쓰이지만, 외부 RDP 로그인 직후 서버에서 갑자기 실행되거나 짧은 시간에 다수 내부 IP·포트로 연결한다면 침해 가능성을 검토해야 한다.</p>
<h3 id="46-atera와-splashtop">4.6 Atera와 Splashtop</h3>
<p>정상적인 원격 관리 도구지만, 이번 사고에서는 Atera(백업 서버 2대, 지속성 확보)와 Splashtop(실제 재접속 경로)으로 역할이 구분됐다. 조직 승인 여부, 설치 계정·시간, 등록된 서비스(Event ID 7045), 연결한 외부 관리 서버를 함께 확인해야 한다.</p>
<h3 id="47-rclone">4.7 Rclone</h3>
<p>클라우드·원격 저장소 간 파일 동기화를 지원하는 정상 프로그램이지만, 대용량 전송이 가능해 데이터 유출에 악용된다. 이번 사고에서는 VBS/배치 스크립트로 은닉 실행됐고, 443번 포트로 위장한 SFTP 트래픽을 사용했다. 실행 경로, 전체 명령줄, 구성 파일, 목적지 IP·포트, 전송량을 확인해야 한다.</p>
<h3 id="48-smb와-windows-서비스">4.8 SMB와 Windows 서비스</h3>
<p>랜섬웨어 실행 파일이 SMB로 전파되고, 무작위 6자리 이름의 원격 서비스(Event ID 7045)로 실행됐다. 동일 크기의 무작위 파일명이 다수 시스템에 짧은 시간 내 생성된다면 확산 가능성을 확인해야 한다.</p>
<h3 id="49-ransomhub">4.9 RansomHub</h3>
<p>파일 암호화 외에도 Hyper-V VM 강제 종료, 심볼릭 링크 평가 설정 변경, 섀도 복사본·이벤트 로그 삭제 등 복구·전파 방해 행위를 함께 수행했다.</p>
<hr>
<h2 id="5-mitre-attck-매핑">5. MITRE ATT&amp;CK 매핑</h2>
<table>
<thead>
<tr>
<th>순서</th>
<th>공격 행위</th>
<th>Tactic</th>
<th>Technique</th>
<th>ATT&amp;CK ID</th>
</tr>
</thead>
<tbody><tr>
<td>1</td>
<td>여러 계정에 공통 비밀번호 대입</td>
<td>Credential Access</td>
<td>Brute Force: Password Spraying</td>
<td><code>T1110.003</code></td>
</tr>
<tr>
<td>2</td>
<td>탈취한 계정으로 로그인</td>
<td>Initial Access</td>
<td>Valid Accounts</td>
<td><code>T1078</code></td>
</tr>
<tr>
<td>3</td>
<td>인터넷에 노출된 RDP 서비스 이용</td>
<td>Initial Access</td>
<td>External Remote Services</td>
<td><code>T1133</code></td>
</tr>
<tr>
<td>4</td>
<td>로컬 계정 정보 확인</td>
<td>Discovery</td>
<td>Account Discovery: Local Account</td>
<td><code>T1087.001</code></td>
</tr>
<tr>
<td>5</td>
<td>도메인 계정 정보 확인</td>
<td>Discovery</td>
<td>Account Discovery: Domain Account</td>
<td><code>T1087.002</code></td>
</tr>
<tr>
<td>6</td>
<td>도메인 신뢰 관계 탐색 (nltest)</td>
<td>Discovery</td>
<td>Domain Trust Discovery</td>
<td><code>T1482</code></td>
</tr>
<tr>
<td>7</td>
<td>내부 호스트와 서비스 탐색</td>
<td>Discovery</td>
<td>Network Service Discovery</td>
<td><code>T1046</code></td>
</tr>
<tr>
<td>8</td>
<td>LSASS 메모리에서 자격 증명 추출</td>
<td>Credential Access</td>
<td>OS Credential Dumping: LSASS Memory</td>
<td><code>T1003.001</code></td>
</tr>
<tr>
<td>9</td>
<td>자식 도메인별 계정 유효성 확인</td>
<td>Credential Access</td>
<td>OS Credential Dumping: DCSync</td>
<td><code>T1003.006</code></td>
</tr>
<tr>
<td>10</td>
<td>RDP를 이용한 내부 이동</td>
<td>Lateral Movement</td>
<td>Remote Services: Remote Desktop Protocol</td>
<td><code>T1021.001</code></td>
</tr>
<tr>
<td>11</td>
<td>Atera·Splashtop을 이용한 원격 접속</td>
<td>Command and Control</td>
<td>Remote Access Software</td>
<td><code>T1219</code></td>
</tr>
<tr>
<td>12</td>
<td>원격 관리 도구 등을 서비스로 등록</td>
<td>Persistence</td>
<td>Create or Modify System Process: Windows Service</td>
<td><code>T1543.003</code></td>
</tr>
<tr>
<td>13</td>
<td>SMB를 통해 랜섬웨어 파일 전송</td>
<td>Lateral Movement</td>
<td>Lateral Tool Transfer</td>
<td><code>T1570</code></td>
</tr>
<tr>
<td>14</td>
<td>Rclone과 SFTP를 이용한 자료 유출</td>
<td>Exfiltration</td>
<td>Exfiltration Over Alternative Protocol</td>
<td><code>T1048</code></td>
</tr>
<tr>
<td>15</td>
<td>Windows 이벤트 로그 삭제</td>
<td>Defense Evasion</td>
<td>Clear Windows Event Logs</td>
<td><code>T1070.001</code></td>
</tr>
<tr>
<td>16</td>
<td>심볼릭 링크 평가 설정 변경</td>
<td>Defense Evasion</td>
<td>File and Directory Permissions Modification</td>
<td><code>T1222</code></td>
</tr>
<tr>
<td>17</td>
<td>섀도 복사본 삭제 / VM 강제 종료</td>
<td>Impact</td>
<td>Inhibit System Recovery</td>
<td><code>T1490</code></td>
</tr>
<tr>
<td>18</td>
<td>파일 암호화</td>
<td>Impact</td>
<td>Data Encrypted for Impact</td>
<td><code>T1486</code></td>
</tr>
</tbody></table>
<hr>
<h2 id="6-주요-ioc-및-로그-아티팩트">6. 주요 IOC 및 로그 아티팩트</h2>
<table>
<thead>
<tr>
<th>구분</th>
<th>확인 대상</th>
</tr>
</thead>
<tbody><tr>
<td>자격 증명 탈취 도구</td>
<td>Mimikatz, CredentialsFileView 실행 흔적, 자식 도메인명 CSV 파일</td>
</tr>
<tr>
<td>네트워크 스캐너</td>
<td>Advanced IP Scanner, NetScan 실행 흔적, <code>delete.me</code> 파일</td>
</tr>
<tr>
<td>데이터 전송 도구</td>
<td><code>rclone.exe</code>, <code>nocmd.vbs</code>, <code>rcl.bat</code>, <code>include.txt</code></td>
</tr>
<tr>
<td>원격 관리 도구</td>
<td>Atera, Splashtop 신규 설치</td>
</tr>
<tr>
<td>서비스 생성</td>
<td>승인되지 않은 신규 Windows 서비스(무작위 6자리 이름 포함)</td>
</tr>
<tr>
<td>복구/전파 방해</td>
<td>VM 강제 종료, 심볼릭 링크 설정 변경, 섀도 복사본 삭제</td>
</tr>
<tr>
<td>흔적 삭제</td>
<td>이벤트 로그 삭제, Rclone 관련 파일 사후 삭제</td>
</tr>
<tr>
<td>계정 조작</td>
<td>다수 계정 비밀번호 동일값 초기화</td>
</tr>
<tr>
<td>네트워크</td>
<td>외부 IP의 TCP 3389 다수 계정 접근, 443번 포트의 실제 SFTP 트래픽(약 2.03GB)</td>
</tr>
<tr>
<td>주요 이벤트 ID</td>
<td><code>4624</code>/<code>4625</code>(로그인), <code>5379</code>(자격 증명 읽기), <code>4662</code>(AD 동기화), <code>7045</code>(서비스 생성)</td>
</tr>
<tr>
<td>Sysmon</td>
<td><code>1</code>(프로세스 생성), <code>3</code>(네트워크 연결), <code>10</code>(LSASS 접근), <code>11</code>(파일 생성)</td>
</tr>
</tbody></table>
<hr>
<h2 id="7-탐지-포인트">7. 탐지 포인트</h2>
<p><strong>Password Spray 및 후속 로그인</strong>: 실패 횟수보다 하나의 출발지 IP가 접근한 고유 계정 수를 기준으로 탐지한다. Password Spray IP와 실제 침입 IP가 다를 수 있으므로, 대상이 된 계정을 기준으로 이후 새로운 IP·RDP Logon Type 10·Elevated Token 여부를 함께 추적해야 한다.</p>
<p><strong>RDP 로그인 후 탐색·자격 증명 접근</strong>: 외부 로그인 직후 <code>net</code>, <code>nltest</code> 등 탐색 명령이나 스캐너, MMC 스냅인이 짧은 시간 안에 연속 실행되는지 확인한다. Sysmon Event ID <code>10</code>(LSASS 접근)과 <code>4662</code>가 여러 자식 도메인을 대상으로 반복 발생한다면 DCSync 유사 행위 가능성을 검토한다.</p>
<p><strong>원격 관리 도구 오남용</strong>: 외부 RDP 로그인 직후 신규 설치(Event ID 7045) 후 그 도구를 통한 실제 재접속 세션과 후속 행위(계정 조작·파일 반입)가 이어지는지 연결해서 확인한다.</p>
<p><strong>Rclone을 이용한 데이터 유출</strong>: 443번 포트 연결의 실제 프로토콜이 HTTPS가 아닌 SSH/SFTP인지, 스크립트로 은닉 실행되는지, 장시간 대량 아웃바운드 전송이 있는지 확인한다. 포트 번호만으로 프로토콜을 판단해서는 안 된다.</p>
<p><strong>랜섬웨어 배포 단계</strong>: 다수 계정 비밀번호가 짧은 시간에 동일값으로 변경되는지, SMB를 통해 동일 크기의 무작위 파일명이 여러 시스템에 복사되고 신규 서비스로 실행되는지, VM 강제 종료·섀도 복사본 삭제·이벤트 로그 삭제가 연쇄적으로 발생하는지 확인한다.</p>
<table>
<thead>
<tr>
<th>구분</th>
<th>정상 행위</th>
<th>의심 행위</th>
</tr>
</thead>
<tbody><tr>
<td>로그인 실패</td>
<td>특정 계정에서 소수 발생</td>
<td>짧은 시간 내 여러 계정에서 발생</td>
</tr>
<tr>
<td>로그인 성공 위치</td>
<td>평소 사용하던 위치</td>
<td>Password Spray 이후 새로운 IP</td>
</tr>
<tr>
<td>원격 관리 도구</td>
<td>사전 승인된 설치</td>
<td>침입 직후 신규 설치, 이후 실제 재접속에 사용</td>
</tr>
<tr>
<td>계정 관리 활동</td>
<td>개별 계정의 개별 사유 변경</td>
<td>다수 계정이 짧은 시간에 동일값으로 변경</td>
</tr>
<tr>
<td>파일 행위</td>
<td>소수 파일 수정</td>
<td>짧은 시간 동안 대량 수정·암호화, VM 강제 종료 동반</td>
</tr>
</tbody></table>
<hr>
<h2 id="8-정리">8. 정리</h2>
<p>이번 사례는 인터넷에 노출된 RDP 서버와 취약한 계정 관리가 전체 내부망 침해로 이어질 수 있음을 보여준다. 공격자는 Password Spray로 확보한 계정으로 처음부터 관리자 권한 RDP 세션을 얻었고, Mimikatz로 LSASS 자격 증명은 물론 여러 자식 도메인에서 통용되는 계정까지 확보해 도메인 컨트롤러·백업·파일·하이퍼바이저 서버로 이동을 확장했다. 
이후 Atera·Splashtop으로 지속 접근 수단을 마련하고, Rclone·SFTP로 자료를 유출한 뒤 계정 비밀번호를 대량 초기화하고 VM을 강제 종료해 RansomHub를 SMB로 전파, 암호화했다.</p>
<p>특히 주목할 점은 두 가지다. </p>
<ol>
<li><p><strong>Password Spray 수행 IP와 실제 RDP 침입 IP가 달랐다.</strong> 
동일 IP의 로그인 실패·성공만 연결해서는 공격을 놓칠 수 있으며, 대상 계정을 기준으로 새로운 IP에서의 후속 로그인·탐색·내부 이동을 연계해 분석해야 한다. </p>
</li>
<li><p><strong>지속성 확보(Atera)와 실제 재접속(Splashtop) 도구가 구분되어 있었다.</strong> 
RDP, Rclone, Atera, Splashtop은 모두 정상 업무에도 쓰이는 도구이므로, 프로그램 이름이 아니라 실행 계정과 권한, 접속 시각과 경로, 명령줄, 외부 통신 목적지, 선후행 행위를 종합적으로 봐야 한다.</p>
</li>
</ol>
<p>결국 효과적인 침해 탐지는 하나의 이벤트나 IOC를 찾는 것이 아니라, 여러 로그의 행위를 시간 순서로 연결해 하나의 공격 흐름으로 재구성하는 데서 시작된다.</p>
<hr>
<h2 id="9-참고-자료">9. 참고 자료</h2>
<ol>
<li><strong>The DFIR Report</strong><br><a href="https://thedfirreport.com/2025/06/30/hide-your-rdp-password-spray-leads-to-ransomhub-deployment/">Hide Your RDP: Password Spray Leads to RansomHub Deployment</a></li>
<li><strong>MITRE ATT&amp;CK</strong><br><a href="https://attack.mitre.org/">MITRE ATT&amp;CK Enterprise Matrix</a></li>
<li><strong>Microsoft Learn</strong><br><a href="https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-10/security/threat-protection/auditing/event-4624">4624(S): An account was successfully logged on</a></li>
<li><strong>Microsoft Learn (Sysinternals)</strong><br><a href="https://learn.microsoft.com/en-us/sysinternals/downloads/sysmon">Sysmon - Windows Sysinternals</a></li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[Log4Shell을 이용한 미국 연방기관 침해사고]]></title>
            <link>https://velog.io/@jh_devlog/Log4Shell%EC%9D%84-%EC%9D%B4%EC%9A%A9%ED%95%9C-%EB%AF%B8%EA%B5%AD-%EC%97%B0%EB%B0%A9%EA%B8%B0%EA%B4%80-%EC%B9%A8%ED%95%B4%EC%82%AC%EA%B3%A0</link>
            <guid>https://velog.io/@jh_devlog/Log4Shell%EC%9D%84-%EC%9D%B4%EC%9A%A9%ED%95%9C-%EB%AF%B8%EA%B5%AD-%EC%97%B0%EB%B0%A9%EA%B8%B0%EA%B4%80-%EC%B9%A8%ED%95%B4%EC%82%AC%EA%B3%A0</guid>
            <pubDate>Wed, 15 Jul 2026 12:03:22 GMT</pubDate>
            <description><![CDATA[<h2 id="1-개요">1. 개요</h2>
<p>2022년 이란 정부 지원 APT 공격자는 미국의 한 연방 민간 행정부 기관이 운영하던 <strong>패치되지 않은 VMware Horizon 서버</strong>에서 Log4Shell 취약점 <code>CVE-2021-44228</code>을 악용해 내부 네트워크에 침투했다.</p>
<p>공격자는 원격 코드 실행 이후 Windows Defender의 탐지 범위를 축소하고 XMRig 암호화폐 채굴기를 설치했다. 이후 RDP와 탈취한 자격 증명을 이용해 내부로 이동한 뒤, 관리자 계정과 Ngrok 터널을 통해 지속적인 접근 경로를 확보했다.</p>
<table>
<thead>
<tr>
<th>항목</th>
<th>내용</th>
</tr>
</thead>
<tbody><tr>
<td>피해 조직</td>
<td>미국 연방 민간 행정부 기관·FCEB, 기관명 비공개</td>
</tr>
<tr>
<td>최초 침투 대상</td>
<td>외부에 공개된 VMware Horizon 서버</td>
</tr>
<tr>
<td>최초 침투 취약점</td>
<td><code>CVE-2021-44228</code>, Log4Shell</td>
</tr>
<tr>
<td>취약 구성요소</td>
<td>Apache Log4j 2의 <code>log4j-core</code></td>
</tr>
<tr>
<td>추정 공격 주체</td>
<td>이란 정부 지원 APT</td>
</tr>
<tr>
<td>최초 탐지 시점</td>
<td>2022년 4월</td>
</tr>
<tr>
<td>주요 공격 결과</td>
<td>암호화폐 채굴, 자격 증명 탈취, 내부 이동, 관리자 계정 생성, 원격 접근 경로 확보</td>
</tr>
<tr>
<td>주요 도구</td>
<td>XMRig, Mimikatz, PsExec, Ngrok, PowerShell</td>
</tr>
</tbody></table>
<h3 id="log4shell-취약점">Log4Shell 취약점</h3>
<p>Log4Shell은 Log4j가 로그 메시지에 포함된 JNDI Lookup 표현식을 평가하는 과정에서 공격자가 지정한 LDAP 등의 외부 서버로 연결하고, 특정 조건에서 외부 코드를 불러와 실행할 수 있었던 취약점이다.</p>
<p>공격자는 애플리케이션이 기록하는 HTTP 헤더나 요청 파라미터에 조작된 문자열을 삽입하는 것만으로 인증 없이 코드 실행을 유도할 수 있었다. 영향을 받는 주요 구성요소는 <code>log4j-core</code>이며, <code>log4j-api</code>만 사용하는 애플리케이션은 직접적인 영향을 받지 않는다.</p>
<pre><code class="language-text">공격 문자열이 포함된 HTTP 요청
        ↓
VMware Horizon이 요청값을 로그로 기록
        ↓
취약한 Log4j가 JNDI 표현식 평가
        ↓
공격자가 지정한 외부 서버로 연결
        ↓
VMware Horizon 서버에서 원격 코드 실행</code></pre>
<p>VMware는 2021년 12월 VMware Horizon을 포함한 여러 제품이 CVE-2021-44228과 관련 취약점의 영향을 받는다고 공지하고 패치와 임시 조치 방법을 안내했다. 그러나 피해 기관의 서버에는 필요한 조치가 적용되지 않았다.</p>
<hr>
<h2 id="2-사고-내용">2. 사고 내용</h2>
<h3 id="21-패치되지-않은-vmware-horizon-서버-침해">2.1 패치되지 않은 VMware Horizon 서버 침해</h3>
<p>공격자는 인터넷에 공개돼 있던 VMware Horizon 서버가 Log4Shell 패치를 적용하지 않은 상태라는 것을 확인하고 취약점을 악용했다.</p>
<p>피해 서버는 초기 공격 과정에서 알려진 악성 IP인 다음 주소와 통신했다.</p>
<p><code>182.54.217[.]2</code></p>
<p>CISA는 피해 VMware Horizon 서버와 해당 IP 사이의 통신을 확인했으며, 공격자가 취약점 공개 약 두 달 뒤인 2022년 2월경부터 내부에 접근했을 가능성이 있다고 판단했다. </p>
<h3 id="22-windows-defender-탐지-기능-약화">2.2 Windows Defender 탐지 기능 약화</h3>
<p>공격자는 Log4Shell을 통해 명령 실행 권한을 얻은 직후 PowerShell을 사용해 Windows Defender의 제외 경로를 수정했다.</p>
<p>특히 C:\ 드라이브 전체를 검사 제외 대상으로 추가해 이후 내려받는 도구와 악성 파일이 백신 검사에 탐지될 가능성을 낮췄다. </p>
<h3 id="23-xmrig-암호화폐-채굴기-설치">2.3 XMRig 암호화폐 채굴기 설치</h3>
<p>공격자는 PowerShell 스크립트와 압축 파일을 내려받아 VMware Horizon 서버에 XMRig 기반 암호화폐 채굴기를 설치했다.</p>
<p>확인된 주요 구성 파일은 다음과 같다.</p>
<ul>
<li><code>WinRing0x64.sys</code>: 하드웨어 접근에 사용되는 드라이버</li>
<li><code>wuaucltservice.exe</code>: XMRig 채굴기 실행 파일</li>
<li><code>config.json</code>: 채굴 서버 및 실행 설정</li>
<li><code>RuntimeBroker.exe</code>: 채굴기 실행과 지속성 확보에 사용된 파일</li>
<li><code>mde.ps1</code>: 후속 파일 다운로드에 사용된 PowerShell 스크립트</li>
</ul>
<p>공격자는 <code>RuntimeBrokerService</code>라는 예약 작업을 생성해 <code>RuntimeBroker.exe</code>가 매일 SYSTEM 권한으로 실행되도록 했다. 정상 Windows 구성요소와 유사한 이름을 사용해 관리자의 의심을 줄이려 한 것으로 볼 수 있다.</p>
<h3 id="24-기존-windows-기본-계정을-이용한-내부-이동">2.4 기존 Windows 기본 계정을 이용한 내부 이동</h3>
<p>암호화폐 채굴기 설치 이후 공격자는 VMware Horizon 서버에 머무르지 않고 내부 시스템으로 이동했다.</p>
<p>공격자는 기존 Windows 기본 계정인 DefaultAccount와 RDP를 이용해 VMware VDI-KMS 호스트에 접속한 뒤 Mimikatz, PsExec, Ngrok 등의 도구를 전송했다. 다만 공개 자료에는 해당 계정의 자격 증명을 어떤 경로로 확보했는지 명시되어 있지 않다.</p>
<h3 id="25-자격-증명-탈취와-관리자-계정-생성">2.5 자격 증명 탈취와 관리자 계정 생성</h3>
<p>공격자는 Mimikatz를 사용해 내부 이동에 필요한 자격 증명을 확보하고 LSASS 메모리 덤프를 시도했다. 일부 LSASS 덤프 시도는 피해 기관의 보안 제품에 의해 차단된 것으로 보고됐다.</p>
<p>획득한 자격 증명을 기반으로 공격자는 새로운 도메인 관리자 계정을 생성했다. 또한 기존 로컬 관리자 계정의 비밀번호를 변경해 새로 만든 계정이 발견되거나 삭제되더라도 다른 관리자 계정을 통해 접근을 유지할 수 있도록 했다.</p>
<h3 id="26-도메인-컨트롤러-접근과-내부-자산-정찰">2.6 도메인 컨트롤러 접근과 내부 자산 정찰</h3>
<p>공격자는 탈취한 관리자 권한으로 도메인 컨트롤러에 접근했다.</p>
<p>이후 PowerShell 명령을 이용해 도메인에 등록된 컴퓨터, 운영체제와 IP 주소 등을 수집하고 내부 네트워크 구조와 추가 공격 대상을 파악했다.</p>
<h3 id="27-ngrok을-이용한-접근-유지">2.7 Ngrok을 이용한 접근 유지</h3>
<p>공격자는 여러 내부 시스템에 Ngrok을 설치해 내부 RDP 서비스를 외부와 연결하는 암호화된 터널을 구성했다.</p>
<p>Ngrok은 정상적인 터널링 서비스지만, 공격자는 이를 악용해 별도의 인바운드 포트를 개방하지 않고도 외부에서 내부 호스트에 접근했다. 이 터널은 지속적인 원격 접근과 명령제어 경로로 활용될 수 있다.</p>
<hr>
<h2 id="3-공격-흐름">3. 공격 흐름</h2>
<pre><code class="language-text">외부 공개 VMware Horizon 서버에서 Log4Shell 악용
        ↓
PowerShell 실행 및 Windows Defender 탐지 범위 축소
        ↓
XMRig 설치와 예약 작업을 통한 지속성 확보
        ↓
RDP를 이용한 VDI-KMS 호스트 이동
        ↓
Mimikatz를 이용한 자격 증명 탈취와 관리자 계정 생성
        ↓
도메인 컨트롤러 접근 및 내부 자산 정찰
        ↓
여러 시스템에 Ngrok을 설치해 원격 접근 경로 확보</code></pre>
<hr>
<h2 id="4-주요-도구-및-구성요소-분석">4. 주요 도구 및 구성요소 분석</h2>
<h3 id="41-xmrig-및-runtimebrokerservice">4.1 XMRig 및 RuntimeBrokerService</h3>
<p>XMRig는 Monero 등의 암호화폐를 채굴할 수 있는 공개 소프트웨어다. 프로그램 자체는 합법적으로 사용할 수 있지만, 공격자는 피해 서버의 CPU 자원을 무단으로 이용하기 위해 이를 설치했다.</p>
<p>이 사고에서는 XMRig 실행 파일이 정상 Windows 구성요소와 유사한 <code>wuaucltservice.exe</code>라는 이름으로 위장됐다. 공격자는 악성 <code>RuntimeBroker.exe</code>를 실행하는 <code>RuntimeBrokerService</code> 예약 작업을 생성해 채굴기가 매일 SYSTEM 권한으로 실행되도록 했다.</p>
<p>정상 파일과 구분하기 위해서는 파일명뿐만 아니라 실행 경로, 디지털 서명, 파일 해시, 부모 프로세스, 명령행과 예약 작업 생성 시각을 함께 확인해야 한다.</p>
<h3 id="42-mimikatz">4.2 Mimikatz</h3>
<p>Mimikatz는 Windows 메모리에서 자격 증명과 인증 정보를 추출하는 데 사용될 수 있는 도구다.</p>
<p>공격자는 VDI-KMS 호스트에서 Mimikatz와 LSASS 메모리 덤프를 이용해 내부 이동에 필요한 자격 증명을 확보하려 했다. 확보된 권한은 도메인 관리자 계정 생성과 추가 시스템 접근에 사용됐다.</p>
<h3 id="43-psexec">4.3 PsExec</h3>
<p>PsExec은 Microsoft Sysinternals에서 제공하는 정상적인 원격 관리 도구다. 관리자는 원격 Windows 시스템에서 프로그램을 실행할 때 사용할 수 있지만, 공격자는 탈취한 관리자 권한을 이용해 다른 호스트에 명령을 실행하거나 파일을 배포하는 데 악용할 수 있다.</p>
<p>따라서 PsExec 실행 자체보다 비정상 계정의 사용, 관리자 공유 접근, 원격 서비스 생성과 짧은 시간 내 여러 호스트에서 발생한 실행 행위를 함께 확인해야 한다.</p>
<h3 id="44-ngrok">4.4 Ngrok</h3>
<p>Ngrok은 내부 포트를 외부 서비스와 연결하는 리버스 프록시·터널링 도구다.</p>
<p>공격자는 여러 내부 호스트에 Ngrok을 설치해 RDP 접근을 중계하고, 네트워크 경계 장비에서 직접적인 외부 인바운드 연결이 보이지 않도록 했다. 정상 개발 업무에도 사용될 수 있으므로 설치 주체, 대상 포트, 실행 계정, 실행 호스트와 접속 시각을 종합적으로 확인해야 한다.</p>
<h3 id="45-powershell">4.5 PowerShell</h3>
<p>PowerShell은 Windows Defender 제외 설정 변경, 외부 파일 다운로드, 네트워크 상태 확인, 도메인 자산 수집과 후속 도구 실행에 사용됐다.</p>
<p>따라서 PowerShell 자체를 차단하기보다 인코딩 명령, 보안 설정 변경, 외부 다운로드와 후속 프로세스 생성이 연속적으로 발생하는 행위를 탐지해야 한다.</p>
<hr>
<h2 id="5-mitre-attck-매핑">5. MITRE ATT&amp;CK 매핑</h2>
<p>아래 표는 공개 자료에서 확인된 공격 행위를 MITRE ATT&amp;CK 기법에 매핑한 것이다.</p>
<table>
<thead>
<tr>
<th align="right">순서</th>
<th>전술</th>
<th>기법</th>
<th>적용 내용</th>
</tr>
</thead>
<tbody><tr>
<td align="right">1</td>
<td>Initial Access</td>
<td><code>T1190</code> Exploit Public-Facing Application</td>
<td>공개된 VMware Horizon의 Log4Shell 취약점 악용</td>
</tr>
<tr>
<td align="right">2</td>
<td>Execution</td>
<td><code>T1059.001</code> PowerShell</td>
<td>백신 설정 변경, 파일 다운로드 및 정찰</td>
</tr>
<tr>
<td align="right">3</td>
<td>Defense Evasion</td>
<td><code>T1562.001</code> Impair Defenses</td>
<td>Windows Defender 제외 경로 추가</td>
</tr>
<tr>
<td align="right">4</td>
<td>Command and Control</td>
<td><code>T1105</code> Ingress Tool Transfer</td>
<td>XMRig, Mimikatz, PsExec, Ngrok 다운로드</td>
</tr>
<tr>
<td align="right">5</td>
<td>Persistence</td>
<td><code>T1053.005</code> Scheduled Task</td>
<td>RuntimeBrokerService 예약 작업 생성</td>
</tr>
<tr>
<td align="right">6</td>
<td>Impact</td>
<td><code>T1496.001</code> Compute Hijacking</td>
<td>XMRig을 통한 암호화폐 채굴</td>
</tr>
<tr>
<td align="right">7</td>
<td>Lateral Movement</td>
<td><code>T1021.001</code> Remote Desktop Protocol</td>
<td>Horizon 서버에서 내부 VDI-KMS로 이동</td>
</tr>
<tr>
<td align="right">8</td>
<td>Credential Access</td>
<td><code>T1003.001</code> LSASS Memory</td>
<td>LSASS 메모리 덤프 시도</td>
</tr>
<tr>
<td align="right">9</td>
<td>Credential Access</td>
<td><code>T1555</code> Credentials from Password Stores</td>
<td>Mimikatz로 저장된 자격 증명 추출</td>
</tr>
<tr>
<td align="right">10</td>
<td>Persistence</td>
<td><code>T1136.002</code> Domain Account</td>
<td>신규 도메인 관리자 계정 생성</td>
</tr>
<tr>
<td align="right">11</td>
<td>Persistence</td>
<td><code>T1098</code> Account Manipulation</td>
<td>로컬 관리자 계정 비밀번호 변경</td>
</tr>
<tr>
<td align="right">12</td>
<td>Discovery</td>
<td><code>T1018</code> Remote System Discovery</td>
<td>도메인 내부 시스템 목록 확인</td>
</tr>
<tr>
<td align="right">13</td>
<td>Discovery</td>
<td><code>T1016.001</code> Internet Connection Discovery</td>
<td>외부 네트워크 연결 여부 확인</td>
</tr>
<tr>
<td align="right">14</td>
<td>Command and Control</td>
<td><code>T1090</code> Proxy</td>
<td>Ngrok으로 암호화된 원격 접근 터널 구성</td>
</tr>
<tr>
<td align="right">15</td>
<td>Defense Evasion</td>
<td><code>T1070.004</code> File Deletion</td>
<td>다운로드에 사용한 PowerShell 스크립트 삭제</td>
</tr>
</tbody></table>
<hr>
<h2 id="6-주요-ioc">6. 주요 IoC</h2>
<p>아래 IoC는 본 사고에서 확인된 지표다. 현재도 동일한 인프라나 파일이 악성 활동에 사용된다는 의미는 아니므로, 차단 목록에 바로 적용하기보다 과거 침해 흔적을 조사하는 용도로 활용하는 것이 적절하다.</p>
<h3 id="61-네트워크-지표">6.1 네트워크 지표</h3>
<table>
<thead>
<tr>
<th>유형</th>
<th>지표</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td>IP</td>
<td><code>182.54.217[.]2</code></td>
<td>초기 Log4Shell 악용 및 후속 파일 다운로드와 관련된 악성 IP</td>
</tr>
<tr>
<td>서비스</td>
<td><code>ngrok</code></td>
<td>내부 RDP 접근을 중계한 리버스 프록시</td>
</tr>
<tr>
<td>외부 통신</td>
<td>LDAP·RMI·DNS</td>
<td>JNDI Lookup 악용 과정에서 발생할 수 있는 외부 연결</td>
</tr>
<tr>
<td>프로토콜</td>
<td>RDP</td>
<td>내부 시스템 이동</td>
</tr>
<tr>
<td>프로토콜</td>
<td>HTTPS</td>
<td>도구 다운로드와 Ngrok 터널 통신</td>
</tr>
</tbody></table>
<p><code>182.54.217[.]2</code>는 CISA가 해당 사고에서 확인한 알려진 악성 IP다. Ngrok과 RDP는 정상적으로도 사용될 수 있으므로 단독 IoC보다 실행 주체와 전후 행위를 함께 분석해야 한다.</p>
<h3 id="62-파일-및-해시">6.2 파일 및 해시</h3>
<table>
<thead>
<tr>
<th>파일명</th>
<th>MD5</th>
<th>역할</th>
</tr>
</thead>
<tbody><tr>
<td><code>WinRing0x64.sys</code></td>
<td><code>0c0195c48b6b8582fa6f6373032118da</code></td>
<td>XMRig 관련 하드웨어 접근 드라이버</td>
</tr>
<tr>
<td><code>wuaucltservice.exe</code></td>
<td><code>6b8d058db910487ff90fe39e1dcd93b8</code></td>
<td>XMRig 채굴기</td>
</tr>
<tr>
<td><code>config.json</code></td>
<td><code>910350d4f72b7b25f4fbecfc08d815cd</code></td>
<td>채굴기 설정 파일</td>
</tr>
</tbody></table>
<h3 id="63-파일·작업·프로세스-이름">6.3 파일·작업·프로세스 이름</h3>
<pre><code class="language-text">mde.ps1
file.zip
RuntimeBroker.exe
RuntimeBrokerService
WinRing0x64.sys
wuaucltservice.exe
config.json
mimikatz.exe
PsExec.exe
ngrok.exe</code></pre>
<p>파일명은 쉽게 변경될 수 있고 <code>RuntimeBroker.exe</code>, <code>PsExec.exe</code>, <code>WinRing0x64.sys</code> 등은 정상 파일과 이름이 같을 수 있다. 따라서 파일 해시, 디지털 서명, 실행 경로와 실제 행위를 함께 확인해야 한다.</p>
<hr>
<h2 id="7-탐지-포인트">7. 탐지 포인트</h2>
<h3 id="71-취약-패키지-및-자산-탐지">7.1 취약 패키지 및 자산 탐지</h3>
<ul>
<li>외부에 노출된 VMware Horizon·UAG 자산 식별</li>
<li>제품 버전과 Log4Shell 패치 적용 여부 확인</li>
<li>애플리케이션과 제품 내부의 <code>log4j-core</code> JAR 탐색</li>
<li>Fat JAR, WAR, 컨테이너 이미지 내부의 중첩 의존성 검사</li>
<li>SBOM과 SCA 결과를 실제 배포 자산과 비교</li>
<li>패치 적용 후 취약 구성요소가 제거됐는지 재검사</li>
</ul>
<p>자산 목록에 존재하는 서버만 점검해서는 관리되지 않는 외부 공개 시스템을 놓칠 수 있다. 외부 공격 표면과 실제 운영 환경을 함께 확인해야 한다.</p>
<h3 id="72-웹·애플리케이션-로그">7.2 웹·애플리케이션 로그</h3>
<p>다음 요청 영역에서 JNDI 관련 문자열과 변형된 표현식을 탐지한다.</p>
<ul>
<li><code>User-Agent</code></li>
<li><code>X-Forwarded-For</code></li>
<li><code>Referer</code></li>
<li><code>Cookie</code></li>
<li>URL 경로와 쿼리 파라미터</li>
<li>로그인 ID, 검색어와 JSON 요청 필드</li>
<li>오류 메시지에 포함된 사용자 입력값</li>
</ul>
<p>단순히 <code>${jndi:ldap:</code> 문자열만 검색하면 인코딩되거나 난독화된 요청을 놓칠 수 있다. URL 디코딩과 문자열 정규화를 수행한 뒤 <code>${lower:}</code>, <code>${upper:}</code>, 환경변수 치환 등의 우회 표현식을 함께 검사해야 한다.</p>
<h3 id="73-네트워크-로그">7.3 네트워크 로그</h3>
<p>다음 통신을 중점적으로 확인한다.</p>
<pre><code class="language-text">Java 또는 VMware 프로세스
→ 외부 LDAP/RMI/DNS 통신
→ 실행 파일 또는 스크립트 다운로드
→ 짧은 시간 내 PowerShell 실행</code></pre>
<ul>
<li>Java 또는 VMware 프로세스에서 발생한 외부 LDAP·RMI·DNS 연결</li>
<li>평소 외부 연결이 없던 Horizon 서버의 직접 인터넷 접속</li>
<li>외부 IP에서 실행 파일·ZIP·PowerShell 스크립트를 내려받는 행위</li>
<li>채굴 풀 또는 Stratum 프로토콜 방향의 반복 통신</li>
<li>Ngrok 인프라와 장시간 유지되는 TLS 세션</li>
<li>Horizon 서버에서 내부 VDI·KMS·도메인 컨트롤러로 발생한 RDP 연결</li>
</ul>
<p>네트워크 이벤트만 단독으로 판단하기보다 해당 시점의 웹 요청, 프로세스 실행과 계정 로그를 함께 분석해야 한다.</p>
<h3 id="74-powershell-및-보안-설정-변경">7.4 PowerShell 및 보안 설정 변경</h3>
<p>다음 PowerShell 행위는 높은 우선순위로 탐지해야 한다.</p>
<ul>
<li><code>Add-MpPreference</code> 또는 <code>Set-MpPreference</code> 실행</li>
<li>루트 드라이브나 광범위한 경로를 Defender 제외 대상으로 추가</li>
<li><code>-EncodedCommand</code>, <code>-enc</code> 사용</li>
<li><code>Invoke-WebRequest</code>, <code>WebClient</code>, <code>DownloadString</code> 을 이용한 외부 다운로드</li>
<li>외부 IP에서 ZIP·EXE·PS1 다운로드</li>
<li>다운로드한 스크립트 실행 후 즉시 삭제</li>
<li>PowerShell이 예약 작업이나 신규 프로세스를 생성</li>
</ul>
<p>특히 Java·VMware 프로세스가 PowerShell을 자식 프로세스로 생성하고, 이어서 Defender 설정 변경과 외부 다운로드가 발생하면 높은 우선순위로 조사해야 한다.</p>
<h3 id="75-지속성-및-계정-변경">7.5 지속성 및 계정 변경</h3>
<ul>
<li><code>RuntimeBrokerService</code>와 유사한 예약 작업 생성</li>
<li>SYSTEM 권한으로 주기적으로 실행되는 신규 작업</li>
<li>정상 Windows 파일명과 유사하지만 비정상 경로에서 실행되는 파일</li>
<li>신규 로컬·도메인 관리자 계정 생성</li>
<li>기존 관리자 계정의 비밀번호 변경</li>
<li>예약 작업 생성 직후 채굴기 실행 또는 CPU 사용률 상승</li>
</ul>
<p>계정과 예약 작업 이벤트는 생성 주체, 실행 계정, 대상 파일 경로와 발생 시간을 기준으로 상관분석해야 한다.</p>
<h3 id="76-채굴-행위">7.6 채굴 행위</h3>
<ul>
<li>서버 CPU가 장시간 높은 수준으로 유지</li>
<li>업무 시간과 무관하게 지속되는 높은 CPU 사용률</li>
<li><code>config.json</code>에서 채굴 풀 주소·지갑 설정 확인</li>
<li>XMRig 또는 이름이 변경된 유사 실행 파일 탐지</li>
<li><code>WinRing0x64.sys</code> 드라이버 로드</li>
<li>채굴 풀 방향으로 반복되는 외부 연결</li>
</ul>
<p>파일명 기반 탐지만으로는 이름이 변경된 XMRig을 놓칠 수 있으므로 CPU 사용 패턴, 드라이버 로드, 프로세스 계보와 외부 연결을 함께 분석해야 한다.</p>
<h3 id="77-자격-증명-탈취-및-내부-이동">7.7 자격 증명 탈취 및 내부 이동</h3>
<ul>
<li>비보안 프로세스가 LSASS에 접근하는 행위</li>
<li>LSASS 메모리 덤프 파일 생성 시도</li>
<li>Mimikatz 관련 명령, 메모리 패턴과 파일 해시</li>
<li>Horizon 서버에서 내부 VDI·KMS·도메인 컨트롤러로 발생한 RDP 연결</li>
<li>PsExec 사용 시 생성되는 원격 서비스와 관리자 공유 접근</li>
<li>짧은 시간에 여러 시스템에서 발생한 동일 관리자 계정 로그인</li>
<li>신규 도메인 관리자 계정 생성과 기존 로컬 관리자 비밀번호 변경</li>
</ul>
<h3 id="78-ngrok-탐지">7.8 Ngrok 탐지</h3>
<ul>
<li>서버 환경에서 승인되지 않은 <code>ngrok.exe</code> 실행</li>
<li>Ngrok 설정 파일 또는 인증 토큰 생성</li>
<li>Ngrok 도메인·인프라로 장시간 유지되는 TLS 연결</li>
<li>Ngrok 실행 이후 내부 RDP 포트 접근</li>
<li>개발자 단말이 아닌 서버·도메인 컨트롤러에서 Ngrok 실행</li>
</ul>
<p>조직에서 Ngrok을 정상적으로 사용한다면 허용 사용자, 호스트, 대상 포트와 업무 목적을 사전에 정의하고 예외 목록으로 관리해야 한다.</p>
<h3 id="79-권장-상관분석-시나리오">7.9 권장 상관분석 시나리오</h3>
<pre><code class="language-text">VMware Horizon에 Log4Shell 의심 요청
        ↓ (30초 이내)
Java·VMware 프로세스에서 PowerShell 실행
        ↓
Windows Defender 제외 설정 변경
        ↓ (5분 이내)
외부 IP에서 ZIP·EXE·PS1 다운로드
        ↓
신규 예약 작업 생성 및 채굴 프로세스 실행
        ↓
내부 호스트로 RDP·PsExec 이동
        ↓
신규 관리자 계정 또는 Ngrok 프로세스 생성</code></pre>
<p>각 이벤트를 단독으로 탐지하는 것보다 웹 요청, 프로세스, 보안 설정, 네트워크와 계정 이벤트를 연결하면 정확도를 높일 수 있다.</p>
<hr>
<h2 id="8-정리">8. 정리</h2>
<p>이 사고는 패치되지 않은 외부 공개 서버 하나가 내부 이동과 지속적인 원격 접근으로 확대될 수 있음을 보여준다. </p>
<p>공격자는 Log4Shell로 VMware Horizon 서버에서 코드를 실행한 뒤 Defender 탐지 범위를 축소하고, XMRig과 예약 작업을 설치했다. 이후 RDP와 탈취한 자격 증명을 이용해 도메인 환경으로 이동하고 Ngrok 터널을 통해 접근 경로를 유지했다.</p>
<p>특히 Log4Shell 패치와 대응 지침이 이미 공개된 이후에도 실제 운영 자산에 조치가 적용되지 않아 침해가 발생했다. 따라서 조직은 외부 공개 자산과 취약 구성요소를 지속적으로 식별하고, PowerShell 기반 보안 설정 변경, 서버 간 RDP, 특권 계정 생성과 비인가 터널링 도구 실행을 연계해 탐지해야 한다.</p>
<hr>
<h2 id="9-참고-자료">9. 참고 자료</h2>
<ol>
<li><p><strong>CISA·FBI</strong><br><a href="https://www.cisa.gov/news-events/cybersecurity-advisories/aa22-320a">Iranian Government-Sponsored APT Actors Compromise Federal Network, Deploy Crypto Miner, Credential Harvester</a></p>
</li>
<li><p><strong>CISA·미 해안경비대</strong><br><a href="https://www.cisa.gov/news-events/cybersecurity-advisories/aa22-174a">Malicious Cyber Actors Continue to Exploit Log4Shell in VMware Horizon Systems</a></p>
</li>
<li><p><strong>CISA</strong><br><a href="https://www.cisa.gov/news-events/cybersecurity-advisories/aa21-356a">Mitigating Log4Shell and Other Log4j-Related Vulnerabilities</a></p>
</li>
<li><p><strong>Apache Logging Services</strong><br><a href="https://logging.apache.org/security.html">Apache Log4j Security Vulnerabilities</a></p>
</li>
<li><p><strong>NIST NVD</strong><br><a href="https://nvd.nist.gov/vuln/detail/CVE-2021-44228">CVE-2021-44228 Detail</a></p>
</li>
<li><p><strong>VMware</strong><br><a href="https://www.vmware.com/security/advisories/VMSA-2021-0028.html">VMSA-2021-0028: VMware Response to Apache Log4j Remote Code Execution Vulnerabilities</a></p>
</li>
<li><p><strong>VMware Blogs</strong><br><a href="https://blogs.vmware.com/euc/2022/01/guidance-to-vmware-horizon-customers-regarding-log4j.html">Guidance to VMware Horizon Customers Regarding Log4j</a></p>
</li>
<li><p><strong>Picus Security</strong><br> <a href="https://www.picussecurity.com/resource/blog/cisa-alert-aa22-320a-iranian-apt-actors-target-us-federal-network">CISA Alert AA22-320A: Iranian APT Actors Target US Federal Network</a></p>
</li>
<li><p><strong>Check Point Software</strong><br> <a href="https://www.checkpoint.com/cyber-hub/threat-prevention/what-is-malware/xmrig-malware/">What Is XMRig Malware?</a></p>
</li>
<li><p><strong>MITRE ATT&amp;CK</strong><br><a href="https://attack.mitre.org/techniques/enterprise/">Enterprise Techniques</a></p>
</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[MOVEit Transfer 침해 사고:  SQL Injection을 통한 대규모 데이터 탈취]]></title>
            <link>https://velog.io/@jh_devlog/MOVEit-Transfer-%EC%B9%A8%ED%95%B4-%EC%82%AC%EA%B3%A0-SQL-Injection%EC%9D%84-%ED%86%B5%ED%95%9C-%EB%8C%80%EA%B7%9C%EB%AA%A8-%EB%8D%B0%EC%9D%B4%ED%84%B0-%ED%83%88%EC%B7%A8</link>
            <guid>https://velog.io/@jh_devlog/MOVEit-Transfer-%EC%B9%A8%ED%95%B4-%EC%82%AC%EA%B3%A0-SQL-Injection%EC%9D%84-%ED%86%B5%ED%95%9C-%EB%8C%80%EA%B7%9C%EB%AA%A8-%EB%8D%B0%EC%9D%B4%ED%84%B0-%ED%83%88%EC%B7%A8</guid>
            <pubDate>Wed, 15 Jul 2026 11:23:42 GMT</pubDate>
            <description><![CDATA[<h2 id="1-개요">1. 개요</h2>
<p>2023년 5월, Progress Software의 파일 전송 솔루션인 <strong>MOVEit Transfer</strong>에서 인증되지 않은 공격자가 데이터베이스에 접근할 수 있는 SQL Injection 취약점 <strong>CVE-2023-34362</strong>가 실제 공격에 악용되었다.</p>
<p>공격자는 인터넷에 공개된 MOVEit Transfer 서버의 취약점을 악용한 뒤 <strong>LEMURLOOT</strong>라는 전용 웹 셸을 설치했다. 이후 MOVEit 데이터베이스와 파일 저장소를 탐색하고 중요 파일을 탈취했다.</p>
<p>Mandiant는 관련 공격 활동을 처음에는 <code>UNC4857</code>로 추적했으나, 기존 FIN11 활동과의 공격 대상, 인프라 및 CL0P 데이터 유출 사이트 사용 정황을 바탕으로 해당 활동을 <strong>FIN11</strong>에 통합했다. 이후 CL0P 측은 공격의 배후를 주장하며, 금전을 지급하지 않으면 탈취한 데이터를 공개하겠다고 피해 조직을 협박했다.</p>
<blockquote>
<ul>
<li><strong>CL0P^_- LEAKS 데이터 유출 사이트 게시물</strong>
<img src="https://velog.velcdn.com/images/jh_devlog/post/9ad29329-47f1-49a2-8bb2-75cb27561722/image.png" alt=""></li>
</ul>
</blockquote>
<p><strong>CVE-2023-34362</strong>는 별도의 권한이나 사용자 상호작용 없이 네트워크를 통해 악용할 수 있는 SQL Injection 취약점이다. 공격자는 MOVEit Transfer 데이터베이스의 구조와 내용을 조회하고, 데이터베이스 요소를 변경하거나 삭제하는 SQL 문을 실행할 수 있었다.</p>
<p>NVD는 이 취약점을 CVSS 3.1 기준 9.8점으로 평가했으며, CISA는 2023년 6월 2일 실제 공격에 악용된 취약점 목록인 Known Exploited Vulnerabilities 카탈로그에 추가했다.</p>
<p><img src="https://velog.velcdn.com/images/jh_devlog/post/f6f66216-9924-4e15-875e-4cb2496f9dc3/image.png" alt=""></p>
<blockquote>
<p>공격자는 MOVEit Transfer의 SQL Injection 취약점을 이용해 LEMURLOOT 웹 셸을 설치하고, 정상 애플리케이션의 데이터베이스와 세션 기능을 악용해 중요 파일을 탈취했다.</p>
</blockquote>
<hr>
<h2 id="2-사고-내용">2. 사고 내용</h2>
<h3 id="21-moveit-transfer란">2.1 MOVEit Transfer란?</h3>
<p>MOVEit Transfer는 기업과 기관이 직원, 외부 고객, 협력사 및 다른 시스템 사이에서 중요 파일을 전송하고 관리할 수 있도록 지원하는 <strong>MFT(Managed File Transfer)</strong> 솔루션이다.</p>
<p>파일 업로드·다운로드, 사용자 권한 관리, 전송 기록 및 감사 로그 등의 기능을 제공하며, 온프레미스 Windows Server 또는 클라우드 환경에서 운영할 수 있다.</p>
<p>금융, 공공, 의료, 교육 등 민감한 정보를 처리하는 산업에서도 사용되기 때문에 MOVEit 서버가 침해되면 서버 운영 조직뿐 아니라 파일을 주고받은 고객과 협력사의 정보까지 함께 노출될 수 있다.</p>
<h3 id="22-취약점-악용-및-사고-발견">2.2 취약점 악용 및 사고 발견</h3>
<p>Mandiant가 확인한 최초 악용 정황은 2023년 5월 27일이다. 일부 피해 환경에서는 LEMURLOOT 웹 셸이 설치된 지 수분 만에 데이터 탈취가 시작될 정도로 공격이 빠르게 진행됐다.</p>
<p>이후 Progress Software는 취약점과 보안 업데이트를 공개했으며, CISA와 FBI도 관련 보안 권고문을 발표했다. 그러나 공식 대응이 시작되기 전에 이미 다수의 MOVEit Transfer 서버가 침해된 정황이 확인됐다.</p>
<p>Mandiant는 캐나다, 인도, 미국의 여러 산업에서 침해 사례를 조사했다. 또한 이탈리아, 파키스탄, 독일에서도 LEMURLOOT 샘플이 발견돼 실제 피해 범위는 공개된 조사 사례보다 더 넓었을 가능성이 있다.</p>
<h3 id="23-공격-주체-식별">2.3 공격 주체 식별</h3>
<p>Mandiant는 초기 공격 활동을 <code>UNC4857</code>이라는 임시 식별자로 추적했다. 이후 기존 FIN11 활동과 공격 대상, ISP, 네트워크 대역, IP 주소, 인증서 및 CL0P 데이터 유출 사이트 사용 정황이 겹치는 것을 확인하고 UNC4857을 FIN11 활동에 통합했다.</p>
<p>FIN11은 과거에도 중요 데이터가 집중된 파일 전송 솔루션(MFT)을 반복적으로 노리고, 탈취한 데이터의 공개를 빌미로 피해 조직을 협박해 온 것으로 분석된다.</p>
<p>따라서 MOVEit 침해 사고는 단발적인 공격이라기보다, MFT 솔루션을 대상으로 수행된 대규모 데이터 탈취 및 갈취 작전의 연장선으로 볼 수 있다.</p>
<h3 id="24-피해-확산과-공격-목적">2.4 피해 확산과 공격 목적</h3>
<p>MOVEit Transfer는 외부 사용자와 파일을 교환하기 위해 인터넷에 공개되는 경우가 많다. 공격자는 이러한 특성을 이용해 다수의 취약한 서버를 탐색하고 공격한 것으로 분석된다.</p>
<p>Mandiant는 여러 피해 환경에서 대량의 파일이 탈취된 사실을 확인했다. LEMURLOOT는 MOVEit 애플리케이션 설정에서 Azure Blob Storage 계정, 컨테이너 및 접근 키도 조회할 수 있었다. 따라서 MOVEit 데이터를 Azure에 저장한 환경에서는 클라우드 저장소까지 침해 범위를 조사할 필요가 있었다.</p>
<p>이번 공격에서는 시스템 전체를 암호화하는 전통적인 랜섬웨어 행위보다 <strong>데이터 탈취와 공개 협박</strong>이 중심적으로 관찰됐다.</p>
<p>따라서 이 사고는 단순한 랜섬웨어 공격이 아닌 <strong>제로데이 취약점을 대규모로 악용한 데이터 탈취 및 갈취 공격</strong>이다.</p>
<hr>
<h2 id="3-공격-흐름">3. 공격 흐름</h2>
<p>MOVEit Transfer 침해 사고의 전체 흐름은 다음과 같다.</p>
<pre><code class="language-text">인터넷에 공개된 MOVEit Transfer 서버 탐색
        ↓
CVE-2023-34362 SQL Injection 취약점 악용
        ↓
LEMURLOOT 웹 셸 설치
        ↓
MOVEit 데이터베이스 연결
        ↓
파일·폴더·사용자 및 저장소 정보 탐색
        ↓
고권한 계정 생성 및 활성 세션 삽입
        ↓
파일 조회 및 HTTP 통신을 통한 외부 전송
        ↓
공격용 계정 삭제
        ↓
탈취 데이터 공개를 이용한 협박</code></pre>
<h3 id="31-외부-노출-서버-탐색-및-취약점-악용">3.1 외부 노출 서버 탐색 및 취약점 악용</h3>
<p>공격자는 인터넷에서 접근할 수 있는 MOVEit Transfer 서버를 탐색하고, CVE-2023-34362에 취약한 시스템을 공격 대상으로 선정했다.</p>
<p>Mandiant는 다수의 사고에서 LEMURLOOT가 설치되기 전 정상 MOVEit 구성요소인 <code>guestaccess.aspx</code>를 대상으로 여러 차례 POST 요청이 발생한 사실을 확인했다. 이를 근거로 SQL Injection 공격 요청이 해당 엔드포인트를 통해 전달된 것으로 분석했다.</p>
<p>다만 <code>guestaccess.aspx</code>는 정상 파일이므로 해당 경로에 POST 요청이 발생했다는 사실만으로 공격을 확정해서는 안 된다. 다음 이벤트가 짧은 시간 안에 연결되는지를 함께 확인해야 한다.</p>
<pre><code class="language-text">guestaccess.aspx 비정상 POST 요청
→ 웹 루트에 신규 ASPX 파일 생성
→ human2.aspx 또는 유사 파일 접근
→ X-siLock-* HTTP 헤더 사용
→ 고권한 계정 생성
→ 대량 파일 조회 및 외부 전송</code></pre>
<p>초기 스캔과 취약점 악용에는 주로 <code>5.252.188.0/22</code> 대역이 사용됐다. 그러나 웹 셸 제어와 실제 데이터 탈취에는 다른 인프라가 사용됐기 때문에 해당 대역만으로 침해 여부를 판단해서는 안 된다.</p>
<h3 id="32-lemurloot-웹-셸-설치">3.2 LEMURLOOT 웹 셸 설치</h3>
<p>취약점 악용에 성공한 공격자는 MOVEit Transfer 웹 서버에 C# 기반 ASP.NET 웹 셸인 <strong>LEMURLOOT</strong>를 설치했다.</p>
<p>대표적으로 다음 파일명이 관찰됐다.</p>
<pre><code class="language-text">human2.aspx
_human2.aspx</code></pre>
<p>MOVEit Transfer에는 <code>human.aspx</code>라는 정상 구성요소가 존재한다. 공격자는 파일명에 숫자나 밑줄을 추가해 악성 파일이 MOVEit의 정상 구성요소처럼 보이도록 위장했다.</p>
<p>따라서 정확한 파일명만 검색하기보다 다음 조건을 함께 확인해야 한다.</p>
<ul>
<li>MOVEit 웹 루트에 새로 생성된 ASPX 파일</li>
<li><code>human.aspx</code>와 이름이 유사한 파일</li>
<li>정상 패치나 배포 시간과 일치하지 않는 파일 변경</li>
<li><code>X-siLock-*</code> 또는 <code>Health Check Service</code> 문자열이 포함된 파일</li>
<li>ASP.NET 실행 과정에서 새롭게 생성된 의심 DLL</li>
</ul>
<h3 id="33-데이터베이스-연결-및-정보-탐색">3.3 데이터베이스 연결 및 정보 탐색</h3>
<p>LEMURLOOT는 별도의 데이터베이스 접속 정보를 외부에서 전달받지 않았다. 대신 MOVEit 애플리케이션의 <code>SystemSettings.DatabaseSettings()</code>를 호출해 서버에 설정된 데이터베이스 연결 정보를 가져왔다.</p>
<p>이는 공격자가 MOVEit 서버에 이미 저장된 정상 설정을 그대로 악용했다는 의미다.</p>
<p>웹 셸은 데이터베이스를 통해 다음 정보를 조회할 수 있었다.</p>
<ul>
<li>파일 및 폴더 정보</li>
<li>파일 크기와 소유자</li>
<li>사용자와 기관 정보</li>
<li>Azure Blob Storage 계정</li>
<li>Azure Blob Storage 접근 키</li>
<li>Blob Storage 컨테이너 정보</li>
</ul>
<p>조회된 정보는 gzip 형식으로 압축되어 LEMURLOOT와 통신하는 외부 시스템으로 반환됐다.</p>
<h3 id="34-고권한-계정-생성-및-세션-삽입">3.4 고권한 계정 생성 및 세션 삽입</h3>
<p>LEMURLOOT는 MOVEit 애플리케이션 내부의 고권한 계정을 검색하고, 적절한 계정이 없으면 새로운 공격용 계정을 생성할 수 있었다.</p>
<p>생성된 계정에는 다음 이름이 사용됐다.</p>
<pre><code class="language-text">Health Check Service</code></pre>
<p>이 계정은 데이터베이스에만 추가되는 것이 아니라 <strong>활성 MOVEit 애플리케이션 세션에 삽입</strong>됐다. 공격자는 이를 통해 정상 사용자 세션을 이용하는 것처럼 MOVEit의 파일 접근 기능을 사용할 수 있었다.</p>
<pre><code class="language-text">기존 고권한 계정 검색
→ 적절한 계정이 없으면 공격용 계정 생성
→ 활성 애플리케이션 세션에 삽입
→ 정상 MOVEit 기능을 이용해 파일 접근</code></pre>
<h3 id="35-파일-조회-및-데이터-탈취">3.5 파일 조회 및 데이터 탈취</h3>
<p>LEMURLOOT는 전달받은 파일 ID와 폴더 ID를 이용해 MOVEit 저장소에서 특정 파일을 조회했다.</p>
<p>파일이 확인되면 gzip으로 압축한 뒤 HTTP 응답을 통해 공격자에게 반환했다. 명령 전달과 파일 반환에 동일한 웹 통신 경로가 사용됐기 때문에 정상적인 MOVEit HTTPS 통신처럼 보일 가능성이 있었다.</p>
<p>Mandiant가 조사한 일부 사례에서는 웹 셸 배포 후 수분 만에 데이터 탈취가 시작됐다. 따라서 하루 단위의 다운로드 통계만 확인하기보다 수분 단위로 발생하는 파일 접근량과 HTTP 응답 크기의 급증을 탐지해야 한다.</p>
<h3 id="36-공격-흔적-제거-및-공개-협박">3.6 공격 흔적 제거 및 공개 협박</h3>
<p>공격자는 데이터 탈취 작업이 끝난 뒤 생성한 <code>Health Check Service</code> 계정을 삭제할 수 있었다.</p>
<p>따라서 현재 사용자 목록에 해당 계정이 존재하지 않더라도 침해 가능성을 배제해서는 안 된다. MOVEit 감사 로그, 데이터베이스 변경 이력, 트랜잭션 로그 및 백업 데이터를 함께 확인해야 한다.</p>
<p>데이터 탈취 이후 CL0P는 데이터 유출 사이트를 통해 금전을 지급하지 않으면 탈취한 정보를 공개하겠다고 피해 조직을 위협했다.</p>
<p>초기 침해와 협박 사이에는 시간 차이가 존재할 수 있으므로, 금전 요구를 받지 않았다는 이유만으로 데이터 유출 가능성을 배제해서는 안 된다.</p>
<hr>
<h2 id="4-주요-도구-분석">4. 주요 도구 분석</h2>
<h3 id="41-lemurloot-개요">4.1 LEMURLOOT 개요</h3>
<p>LEMURLOOT는 C#으로 작성된 ASP.NET 웹 셸이다. 일반적인 웹 셸처럼 운영체제 명령을 폭넓게 실행하기보다, MOVEit Transfer의 데이터베이스 구조와 파일 관리 기능을 직접 활용하도록 설계됐다.</p>
<table>
<thead>
<tr>
<th>구분</th>
<th>내용</th>
</tr>
</thead>
<tbody><tr>
<td>악성코드 유형</td>
<td>ASP.NET 웹 셸</td>
</tr>
<tr>
<td>개발 언어</td>
<td>C#</td>
</tr>
<tr>
<td>주요 파일명</td>
<td><code>human2.aspx</code>, <code>_human2.aspx</code></td>
</tr>
<tr>
<td>정상 위장 대상</td>
<td><code>human.aspx</code></td>
</tr>
<tr>
<td>인증 헤더</td>
<td><code>X-siLock-Comment</code></td>
</tr>
<tr>
<td>명령 헤더</td>
<td><code>X-siLock-Step1</code>, <code>X-siLock-Step2</code>, <code>X-siLock-Step3</code></td>
</tr>
<tr>
<td>데이터베이스 연결</td>
<td><code>SystemSettings.DatabaseSettings()</code> 활용</td>
</tr>
<tr>
<td>주요 목적</td>
<td>파일 조회 및 데이터 탈취</td>
</tr>
<tr>
<td>계정 기능</td>
<td>계정 생성, 세션 삽입, 계정 삭제</td>
</tr>
<tr>
<td>데이터 반환</td>
<td>gzip 압축</td>
</tr>
<tr>
<td>은폐 방식</td>
<td>인증 실패 시 HTTP 404 반환</td>
</tr>
</tbody></table>
<h3 id="42-인증-방식">4.2 인증 방식</h3>
<p>LEMURLOOT는 수신한 HTTP 요청에 다음 헤더가 포함돼 있는지 확인했다.</p>
<pre><code class="language-text">X-siLock-Comment</code></pre>
<p>헤더 값에는 샘플마다 다른 <strong>36자리 GUID 형식의 문자열</strong>이 사용됐다. 이 값은 웹 셸에 접속하기 위한 비밀번호 역할을 했다.</p>
<p>올바른 헤더와 값이 전달되지 않으면 LEMURLOOT는 HTTP 404 상태 코드를 반환했다. 파일이 실제로 존재하더라도 인증값을 모르는 스캐너나 보안 담당자에게는 존재하지 않는 것처럼 보일 수 있었다.</p>
<p>인증에 성공하면 다음 응답 헤더를 반환해 명령을 받을 준비가 됐음을 알렸다.</p>
<pre><code class="language-text">X-siLock-Comment: comment</code></pre>
<h3 id="43-명령-처리-구조">4.3 명령 처리 구조</h3>
<p>LEMURLOOT는 URL 파라미터나 요청 본문 대신 커스텀 HTTP 헤더를 통해 명령과 인자를 전달받았다.</p>
<table>
<thead>
<tr>
<th>커스텀 HTTP 헤더</th>
<th>전달 값·조건</th>
<th>수행 기능</th>
</tr>
</thead>
<tbody><tr>
<td><code>X-siLock-Step1</code></td>
<td><code>-1</code></td>
<td>시스템 정보, 파일·폴더 목록 및 Azure Storage 설정을 조회해 gzip으로 반환</td>
</tr>
<tr>
<td><code>X-siLock-Step1</code></td>
<td><code>-2</code></td>
<td>생성했던 <code>Health Check Service</code> 계정 삭제</td>
</tr>
<tr>
<td><code>X-siLock-Step1</code></td>
<td>그 외의 값</td>
<td>Step2와 Step3를 파일 ID와 폴더 ID로 인식</td>
</tr>
<tr>
<td><code>X-siLock-Step2</code>, <code>X-siLock-Step3</code></td>
<td>값이 존재함</td>
<td>지정된 파일을 조회하고 gzip으로 압축해 반환</td>
</tr>
<tr>
<td><code>X-siLock-Step2</code>, <code>X-siLock-Step3</code></td>
<td>값이 비어 있음</td>
<td>고권한 계정을 찾거나 공격용 계정을 생성해 세션에 삽입</td>
</tr>
</tbody></table>
<p>이러한 명령 구조는 LEMURLOOT가 범용 명령 실행 도구가 아니라 <strong>MOVEit 내부 데이터 모델에 맞춰 제작된 전용 데이터 탈취 도구</strong>라는 점을 보여준다.</p>
<h3 id="44-은폐-및-탐지-회피-방식">4.4 은폐 및 탐지 회피 방식</h3>
<p>LEMURLOOT에서 확인되는 주요 은폐 방식은 다음과 같다.</p>
<ul>
<li>정상 파일 <code>human.aspx</code>와 유사한 파일명 사용</li>
<li>인증에 실패한 요청에 HTTP 404 반환</li>
<li>URL이 아닌 커스텀 HTTP 헤더로 명령 전달</li>
<li>정상 MOVEit 데이터베이스 설정 활용</li>
<li>공격용 계정을 정상 애플리케이션 세션에 삽입</li>
<li>작업 완료 후 공격용 계정 삭제</li>
<li>명령 전달과 파일 반환에 동일한 HTTP 통신 사용</li>
</ul>
<p>이러한 특성 때문에 파일 해시나 IP 주소만 검색하기보다 웹 요청, 파일 생성, 데이터베이스 변경, 사용자 세션 및 네트워크 전송량을 함께 분석해야 한다.</p>
<hr>
<h2 id="5-mitre-attck-매핑">5. MITRE ATT&amp;CK 매핑</h2>
<table>
<thead>
<tr>
<th>공격 단계</th>
<th>전술</th>
<th>기술</th>
<th>매핑 근거</th>
</tr>
</thead>
<tbody><tr>
<td>MOVEit 취약점 악용</td>
<td>Initial Access</td>
<td><strong>T1190 – Exploit Public-Facing Application</strong></td>
<td>인터넷 공개 웹 애플리케이션의 SQL Injection 취약점 악용</td>
</tr>
<tr>
<td>LEMURLOOT 설치</td>
<td>Persistence</td>
<td><strong>T1505.003 – Web Shell</strong></td>
<td>MOVEit 웹 서버에 ASP.NET 웹 셸 설치</td>
</tr>
<tr>
<td>공격용 계정 생성</td>
<td>Persistence</td>
<td><strong>T1136 – Create Account</strong></td>
<td>MOVEit 애플리케이션 내부에 고권한 계정 생성</td>
</tr>
<tr>
<td>파일 및 폴더 조회</td>
<td>Discovery</td>
<td><strong>T1083 – File and Directory Discovery</strong></td>
<td>파일, 폴더, 소유자 및 기관 정보 탐색</td>
</tr>
<tr>
<td>데이터 수집</td>
<td>Collection</td>
<td><strong>T1005 – Data from Local System</strong></td>
<td>MOVEit 서버와 연결 저장소의 파일 수집</td>
</tr>
<tr>
<td>웹 셸을 통한 유출</td>
<td>Exfiltration</td>
<td><strong>T1041 – Exfiltration Over C2 Channel</strong></td>
<td>웹 셸의 HTTP 통신 경로를 이용해 파일 반환</td>
</tr>
</tbody></table>
<p>계정이 Windows 로컬 계정이나 도메인 계정이 아니라 MOVEit 애플리케이션 내부 계정이므로 <code>T1136.001 – Local Account</code>로 세분화하기보다 상위 기술인 <strong>T1136 – Create Account</strong>로 매핑하는 것이 적절하다.</p>
<blockquote>
<p>SQL Injection은 취약점 유형이며 MITRE ATT&amp;CK 기술명이 아니다. SQL Injection을 통해 인터넷 공개 애플리케이션을 침해한 행위는 T1190으로 매핑한다.</p>
</blockquote>
<hr>
<h2 id="6-주요-ioc">6. 주요 IoC</h2>
<h3 id="61-파일명-및-요청-경로">6.1 파일명 및 요청 경로</h3>
<table>
<thead>
<tr>
<th>유형</th>
<th>IoC</th>
</tr>
</thead>
<tbody><tr>
<td>악성 파일명</td>
<td><code>human2.aspx</code></td>
</tr>
<tr>
<td>악성 파일명</td>
<td><code>_human2.aspx</code></td>
</tr>
<tr>
<td>정상 위장 대상</td>
<td><code>human.aspx</code></td>
</tr>
<tr>
<td>취약점 악용 관련 경로</td>
<td><code>/guestaccess.aspx</code></td>
</tr>
<tr>
<td>웹 셸 접근 경로</td>
<td><code>/human2.aspx</code></td>
</tr>
<tr>
<td>웹 셸 접근 경로</td>
<td><code>/_human2.aspx</code></td>
</tr>
</tbody></table>
<p><code>guestaccess.aspx</code>는 정상 MOVEit 파일이므로 해당 경로에 대한 POST 요청만으로 공격을 확정해서는 안 된다. 신규 ASPX 파일 생성, 커스텀 헤더, 계정 변경 및 대량 파일 접근을 함께 확인해야 한다.</p>
<h3 id="62-http-헤더-및-계정명">6.2 HTTP 헤더 및 계정명</h3>
<pre><code class="language-text">X-siLock-Comment
X-siLock-Step1
X-siLock-Step2
X-siLock-Step3
Health Check Service</code></pre>
<h3 id="63-공격-인프라">6.3 공격 인프라</h3>
<pre><code class="language-text">5.252.188.0/22</code></pre>
<p>해당 IP 대역은 여러 사고에서 초기 스캔과 취약점 악용에 사용됐다. 그러나 웹 셸 제어와 데이터 탈취에는 별도의 인프라가 사용됐으므로, 이 대역이 확인되지 않았다는 이유만으로 침해 가능성을 배제해서는 안 된다.</p>
<h3 id="64-대표-sha-256-해시">6.4 대표 SHA-256 해시</h3>
<table>
<thead>
<tr>
<th>구분</th>
<th>SHA-256</th>
</tr>
</thead>
<tbody><tr>
<td>LEMURLOOT ASP.NET 샘플</td>
<td><code>cf23ea0d63b4c4c348865cefd70c35727ea8c82ba86d56635e488d816e60ea45</code></td>
</tr>
<tr>
<td>LEMURLOOT 컴파일 DLL 샘플</td>
<td><code>c58c2c2ea608c83fad9326055a8271d47d8246dc9cb401e420c0971c67e19cbf</code></td>
</tr>
<tr>
<td>LEMURLOOT 샘플</td>
<td><code>38e69f4a6d2e81f28ed2dc6df0daf31e73ea365bd2cfc90ebc31441404cca264</code></td>
</tr>
<tr>
<td>LEMURLOOT 샘플</td>
<td><code>3a977446ed70b02864ef8cfa3135d8b134c93ef868a4cc0aa5d3c2a74545725b</code></td>
</tr>
<tr>
<td>LEMURLOOT 샘플</td>
<td><code>b1c299a9fe6076f370178de7b808f36135df16c4e438ef6453a39565ff2ec272</code></td>
</tr>
<tr>
<td>LEMURLOOT 샘플</td>
<td><code>c77438e8657518221613fbce451c664a75f05beea2184a3ae67f30ea71d34f37</code></td>
</tr>
</tbody></table>
<p>파일 해시는 이미 알려진 샘플을 식별하는 데 유용하지만, 공격자가 파일을 수정하거나 새로운 변형을 사용하면 탐지되지 않을 수 있다. 따라서 파일명, 문자열, 웹 요청 및 행위 기반 탐지를 함께 적용해야 한다.</p>
<hr>
<h2 id="7-탐지-포인트">7. 탐지 포인트</h2>
<h3 id="71-웹-요청-및-웹-셸-파일-탐지">7.1 웹 요청 및 웹 셸 파일 탐지</h3>
<p>IIS, WAF, 리버스 프록시 로그와 파일 무결성 모니터링 결과에서 다음 행위를 확인한다.</p>
<ul>
<li><code>guestaccess.aspx</code>를 대상으로 한 비정상적인 POST 요청</li>
<li><code>human2.aspx</code>, <code>_human2.aspx</code> 또는 유사 ASPX 파일 접근</li>
<li><code>X-siLock-Comment</code>, <code>X-siLock-Step*</code> 헤더가 포함된 요청</li>
<li>정상 배포 작업 없이 웹 루트에 생성된 ASPX 파일</li>
<li>ASP.NET 임시 컴파일 경로에 생성된 의심 DLL</li>
<li>특정 ASPX 경로에서 반복되는 404 이후 발생한 대용량 응답</li>
</ul>
<blockquote>
<p>⚠️ <strong>주의:</strong> LEMURLOOT는 올바른 인증 헤더인 <code>X-siLock-Comment</code>가 없으면 의도적으로 <strong>HTTP 404 Not Found</strong>를 반환한다. 따라서 HTTP 200 성공 로그만 모니터링하면 웹 셸의 존재를 놓칠 수 있다. 특정 ASPX 경로에서 발생하는 반복적인 404와 이후의 대용량 응답 또는 송신량 증가를 함께 추적해야 한다.</p>
</blockquote>
<h3 id="72-계정-생성·삭제-및-세션-탐지">7.2 계정 생성·삭제 및 세션 탐지</h3>
<p>MOVEit 감사 로그와 데이터베이스 변경 기록에서는 다음 행위를 확인한다.</p>
<ul>
<li><code>Health Check Service</code> 이름의 계정 생성 또는 삭제</li>
<li>무작위 사용자 이름을 가진 고권한 계정 생성</li>
<li>고권한 계정이 생성 직후 활성 세션에 추가된 행위</li>
<li>신규 계정이 여러 파일과 폴더에 접근한 행위</li>
<li>계정이 생성된 뒤 짧은 시간 안에 삭제된 행위</li>
</ul>
<p>LEMURLOOT는 작업용 계정을 삭제할 수 있기 때문에 현재 사용자 목록만으로는 침해 여부를 확인하기 어렵다. 데이터베이스 트랜잭션 로그, 백업본 및 MOVEit 애플리케이션 로그를 함께 조사해야 한다.</p>
<h3 id="73-대량-파일-접근-및-외부-전송-탐지">7.3 대량 파일 접근 및 외부 전송 탐지</h3>
<p>파일 접근 로그와 네트워크 로그에서는 다음과 같은 행위를 중점적으로 확인한다.</p>
<ul>
<li><strong>파일 접근 이상:</strong> 짧은 시간 동안 다수의 파일이나 여러 폴더에 연속 접근</li>
<li><strong>계정 이상:</strong> 새로 생성된 고권한 계정이나 평소 사용되지 않던 계정의 대량 다운로드</li>
<li><strong>네트워크 이상:</strong> 평소보다 큰 HTTP 응답 또는 MOVEit 서버의 외부 송신량 급증</li>
<li><strong>저장소 이상:</strong> Azure Blob Storage의 비정상적인 대량 조회 또는 새로운 외부 IP의 접근</li>
</ul>
<p>일부 사고에서는 웹 셸 배포 후 수분 만에 데이터 탈취가 진행됐다. 따라서 하루 단위의 임계치보다 <strong>5분 또는 10분 단위의 파일 접근량과 전송량 증가</strong>를 탐지하는 것이 효과적이다.</p>
<h3 id="74-공격-단계-간-상관분석">7.4 공격 단계 간 상관분석</h3>
<p>단일 IoC보다 다음 이벤트가 짧은 시간 안에 순차적으로 발생하는지를 분석하는 것이 중요하다.</p>
<pre><code class="language-text">guestaccess.aspx 비정상 POST
        ↓
웹 루트에 신규 ASPX 파일 생성
        ↓
X-siLock-* 헤더를 포함한 요청
        ↓
Health Check Service 계정 생성
        ↓
다수 파일 및 폴더 조회
        ↓
대용량 HTTP 응답
        ↓
Health Check Service 계정 삭제</code></pre>
<p>이러한 상관분석은 파일명이 변경되거나 알려진 공격 IP가 사용되지 않은 경우에도 공격자의 행위를 식별하는 데 도움이 된다.</p>
<h3 id="75-yara-기반-위협-헌팅">7.5 YARA 기반 위협 헌팅</h3>
<p>Mandiant가 공개한 LEMURLOOT YARA 규칙은 다음 문자열을 탐지에 활용한다.</p>
<pre><code class="language-text">Create_ASP_human2_aspx
X-siLock-Comment
X-siLock-Step2
X-siLock-Step3
Health Check Service
attachment; filename={0}</code></pre>
<p>원본 ASPX 파일뿐 아니라 ASP.NET에 의해 컴파일된 DLL도 탐지 대상에 포함된다.</p>
<p>다만 공개 YARA 규칙은 운영 환경에서 즉시 차단 규칙으로 사용할 목적이 아니라 위협 헌팅의 출발점으로 제공됐다. 조직 내부에서 성능과 오탐 가능성을 검증한 뒤 적용해야 한다.</p>
<hr>
<h2 id="8-정리">8. 정리</h2>
<p>MOVEit Transfer 침해 사고는 인터넷에 공개된 업무용 파일 전송 솔루션의 취약점 하나가 여러 조직의 대규모 데이터 유출로 이어질 수 있음을 보여준 사례다.</p>
<p>공격자는 CVE-2023-34362 SQL Injection 취약점을 악용해 MOVEit Transfer 서버에 접근하고, 전용 웹 셸인 LEMURLOOT를 설치했다. 이후 정상 애플리케이션의 데이터베이스 설정을 이용해 파일과 사용자 정보를 조회하고, 고권한 계정을 활성 세션에 삽입한 뒤 중요 파일을 외부로 탈취했다.</p>
<p>전체 흐름은 다음과 같이 정리할 수 있다.</p>
<pre><code class="language-text">SQL Injection 취약점 악용
→ LEMURLOOT 웹 셸 설치
→ MOVEit 데이터베이스 연결
→ 파일 및 저장소 정보 탐색
→ 공격용 계정 생성과 세션 삽입
→ HTTP 통신을 통한 데이터 탈취
→ 공격용 계정 삭제
→ 데이터 공개를 이용한 금전 요구</code></pre>
<p>이번 사고에서 주목할 부분은 공격자가 시스템 전체를 암호화하지 않고, 중요 데이터를 먼저 탈취한 뒤 공개를 빌미로 피해 조직을 협박했다는 점이다. 따라서 랜섬웨어 대응을 파일 암호화나 대량 확장자 변경 탐지에만 의존해서는 안 된다.</p>
<p>외부에 공개된 MFT, VPN, 원격 관리 솔루션 등은 중요한 공격 표면으로 관리해야 하며, 패치 적용과 함께 다음 행위를 지속적으로 감시해야 한다.</p>
<ul>
<li>웹 루트의 신규 파일 생성</li>
<li>비정상적인 HTTP 헤더와 반복적인 404 응답</li>
<li>애플리케이션 고권한 계정의 생성·삭제</li>
<li>짧은 시간 동안의 대량 파일 접근</li>
<li>외부 송신량 및 HTTP 응답 크기 증가</li>
<li>연결된 클라우드 저장소의 비정상 접근</li>
</ul>
<p>또한 패치 적용은 새로운 취약점 악용을 차단할 뿐, 이미 설치된 웹 셸이나 생성된 계정, 탈취된 인증정보를 제거해 주지는 않는다. 실제 공격에 악용된 경우에는 패치와 별도로 침해 여부 조사, 인증정보 교체 및 데이터 유출 범위 확인을 수행해야 한다.</p>
<blockquote>
<p>MOVEit Transfer 사고는 단순한 SQL Injection 공격이 아니라, 외부 노출 자산 관리와 애플리케이션 행위 모니터링, 데이터 이동 가시성의 중요성을 함께 보여준 침해사고였다.</p>
</blockquote>
<hr>
<h2 id="9-참고-자료">9. 참고 자료</h2>
<ol>
<li><p><strong>Mandiant / Google Cloud</strong>
<a href="https://cloud.google.com/blog/topics/threat-intelligence/zero-day-moveit-data-theft?hl=en">Zero-Day Vulnerability in MOVEit Transfer Exploited for Data Theft</a></p>
</li>
<li><p><strong>CISA·FBI</strong>
<a href="https://www.cisa.gov/news-events/cybersecurity-advisories/aa23-158a">CL0P Ransomware Gang Exploits CVE-2023-34362 MOVEit Vulnerability</a></p>
</li>
<li><p><strong>NIST NVD</strong>
<a href="https://nvd.nist.gov/vuln/detail/CVE-2023-34362">CVE-2023-34362 Detail</a></p>
</li>
<li><p><strong>Progress Software</strong>
<a href="https://community.progress.com/s/article/MOVEit-Transfer-Critical-Vulnerability-31May2023">MOVEit Transfer Critical Vulnerability – May 2023</a></p>
</li>
<li><p><strong>MITRE ATT&amp;CK</strong><br> <a href="https://attack.mitre.org/techniques/enterprise/">Enterprise Techniques</a></p>
</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[MITRE ATT&CK이란 무엇일까?]]></title>
            <link>https://velog.io/@jh_devlog/MITRE-ATTCK%EC%9D%B4%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%BC%EA%B9%8C</link>
            <guid>https://velog.io/@jh_devlog/MITRE-ATTCK%EC%9D%B4%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%BC%EA%B9%8C</guid>
            <pubDate>Sat, 11 Jul 2026 10:04:52 GMT</pubDate>
            <description><![CDATA[<h1 id="mitre-attck이란-무엇일까">MITRE ATT&amp;CK이란 무엇일까?</h1>
<h2 id="1-mitre-attck을-정리하게-된-이유">1. MITRE ATT&amp;CK을 정리하게 된 이유</h2>
<p>이번에 공격 탐지부터 알림과 대응, 오탐·미탐 판별까지의 과정을 자동화하는 보안 플랫폼 구축 프로젝트를 진행하게 되었다.</p>
<p>본격적인 구현에 앞서 실제 침해사고 사례를 조사하고, 공격자의 목적과 공격에 사용된 기술을 분석하여 프로젝트에서 재현할 공격 시나리오를 설계하기로 했다.</p>
<p>공격자의 행동을 체계적으로 분류하고 이에 맞는 탐지 규칙과 대응 절차를 수립하기 위해서는 공통된 분석 기준이 필요하다. 이에 실제 공격 사례에서 관찰된 공격자의 전술·기술·절차를 체계적으로 정리한 MITRE ATT&amp;CK 프레임워크를 활용하기로 했다.</p>
<p>이번 글에서는 침해사고 사례를 분석하고 이를 MITRE ATT&amp;CK의 TTP에 매핑하기에 앞서, MITRE ATT&amp;CK의 개념과 주요 구성 요소를 먼저 정리해 보고자 한다.</p>
<hr>
<h2 id="2-mitre-attck이란">2. MITRE ATT&amp;CK이란?</h2>
<p>MITRE ATT&amp;CK은 <strong>Adversarial Tactics, Techniques, and Common Knowledge</strong>의 약자로, 실제 사이버 침해사고에서 관찰된 공격자의 목적과 행동 방식을 체계적으로 분류하고 정리한 공개 지식 기반(<strong>Knowledge Base</strong>)이다.</p>
<p>이를 한 문장으로 표현하면 다음과 같다.</p>
<blockquote>
<p>공격자가 어떤 목적을 가지고, 어떤 기술을 사용하여 움직이는지 정리한 <strong>공격 행동 지도</strong></p>
</blockquote>
<p>예를 들어 공격자는 다음과 같은 과정을 거쳐 공격을 수행할 수 있다.</p>
<pre><code class="language-text">피싱 메일 전송 (최초 침투)
  ↓
악성 파일 실행 (실행)
  ↓
시스템과 계정 정보 확인 (탐색)
  ↓
계정 정보 탈취 (인증 정보 접근)
  ↓
다른 시스템으로 이동 (내부 이동)
  ↓
중요 자료 수집 (수집)
  ↓
수집한 자료를 외부로 전송 (정보 유출)</code></pre>
<p>MITRE ATT&amp;CK은 이처럼 일련의 공격 흐름 속에서 발생하는 개별 행동들을 공격자의 <strong>목적(Tactic)</strong>과 <strong>기술(Technique)</strong> 단위로 해석하여 매핑해 둔 것이다.</p>
<p>ATT&amp;CK 프레임워크는 대상 환경에 따라 크게 세 가지 영역으로 구분된다.</p>
<ul>
<li><strong>Enterprise</strong>: 기업의 서버, PC, 네트워크, 클라우드 환경</li>
<li><strong>Mobile</strong>: 스마트폰과 모바일 운영체제(Android, iOS) 환경</li>
<li><strong>ICS</strong>: 산업 제어 시스템 환경</li>
</ul>
<p><a href="https://attack.mitre.org/">🔗 MITRE ATT&amp;CK 공식 사이트</a></p>
<hr>
<h2 id="3-공격자의-행동-양식-ttp">3. 공격자의 행동 양식: TTP</h2>
<p>MITRE ATT&amp;CK을 이해하려면 핵심 개념인 <strong>TTP</strong>의 의미를 알아야 한다.</p>
<p>TTP는 다음 세 가지 개념을 의미한다.</p>
<pre><code class="language-text">- Tactic     : 공격의 목적 (Why)
- Technique  : 목적을 달성하기 위한 기술 (How)
- Procedure  : 실제 공격에 사용된 구체적인 절차와 구현 방식 (What/Who)</code></pre>
<h3 id="①-tactic-공격의-이유와-목적-why">① Tactic: 공격의 이유와 목적 (Why)</h3>
<p>Tactic은 공격자가 특정 행위를 하는 <strong>궁극적인 목적</strong>을 의미한다. 현재 Enterprise ATT&amp;CK v19.1 기준 총 15개의 Tactic이 정의되어 있다.</p>
<ul>
<li>예시: 공격자가 시스템 내부의 계정과 비밀번호를 훔치려고 한다면, 그 목적은 <code>Credential Access(인증 정보 접근)</code>라는 Tactic에 해당한다.</li>
</ul>
<h3 id="②-technique-목적을-달성하는-방법-how">② Technique: 목적을 달성하는 방법 (How)</h3>
<p>Technique은 공격자가 앞서 언급한 Tactic(목적)을 달성하기 위해 사용하는 <strong>구체적인 기술</strong>이다.</p>
<ul>
<li>예를 들어 <code>Credential Access</code>라는 목적을 달성하기 위해 공격자는 다음과 같은 기술(Technique)들을 사용할 수 있다.<ul>
<li>Brute Force (비밀번호 무차별 대입)</li>
<li>Credentials from Web Browsers (브라우저 저장 인증 정보 탈취)</li>
<li>OS Credential Dumping (운영체제 메모리 내 인증 정보 추출)</li>
</ul>
</li>
</ul>
<h3 id="③-sub-technique-기술의-세부-분류">③ Sub-technique: 기술의 세부 분류</h3>
<p>Sub-technique은 하나의 Technique을 <strong>더 구체적인 공격 방식이나 행동 단위로 세분화</strong>한 개념이다. Technique ID 뒤에 <code>.001</code>과 같은 번호가 추가된다.</p>
<ul>
<li>예를 들어 <code>Command and Scripting Interpreter(명령어 및 스크립트 인터프리터)</code> 기술은 다음과 같이 하위 기술로 쪼개진다.<ul>
<li>PowerShell (.001)</li>
<li>Windows Command Shell (.003)</li>
<li>Unix Shell (.004)</li>
</ul>
</li>
</ul>
<h3 id="④-procedure-실제-공격에서의-구체적인-구현-사례">④ Procedure: 실제 공격에서의 구체적인 구현 사례</h3>
<p>Procedure는 특정 공격 그룹이나 악성코드가 Technique 또는 Sub-technique을 <strong>실제 공격에서 어떻게 구현하고 사용했는지</strong> 보여주는 구체적인 사례다.</p>
<ul>
<li>예를 들어 APT29는 인코딩된 PowerShell 스크립트를 사용하여 추가 악성코드를 다운로드하고 설치한 사례가 있다.</li>
</ul>
<hr>
<h2 id="4-attck-matrix란">4. ATT&amp;CK Matrix란?</h2>
<p><img src="https://velog.velcdn.com/images/jh_devlog/post/2def31ca-8f1f-419b-9db7-9fb2f7130768/image.png" alt=""></p>
<blockquote>
<p>이미지 출처: MITRE ATT&amp;CK Enterprise Matrix, v19.1</p>
</blockquote>
<p>MITRE ATT&amp;CK 사이트에서는 앞서 설명한 Tactic과 Technique의 관계를 한눈에 볼 수 있도록 표 형태로 제공하는데, 이를 <strong>ATT&amp;CK Matrix</strong>라고 한다.</p>
<p>Matrix의 최상단 가로축에는 공격 목적에 해당하는 Tactic이 나열되어 있고, 각 Tactic 아래의 세로축에는 해당 목적을 달성하기 위해 사용할 수 있는 수많은 Technique(및 Sub-technique)들이 격자 형태로 배치되어 있다.</p>
<p>2026년 4월 공개된 <strong>Enterprise ATT&amp;CK v19.1 기준</strong>, 15개의 Tactic은 다음과 같다.</p>
<table>
<thead>
<tr>
<th>Tactic</th>
<th>의미</th>
</tr>
</thead>
<tbody><tr>
<td>Reconnaissance</td>
<td>공격 대상에 대한 정보 수집</td>
</tr>
<tr>
<td>Resource Development</td>
<td>공격에 필요한 계정·도메인·인프라 준비</td>
</tr>
<tr>
<td>Initial Access</td>
<td>대상 시스템에 처음 침투</td>
</tr>
<tr>
<td>Execution</td>
<td>악성 코드나 명령어 실행</td>
</tr>
<tr>
<td>Persistence</td>
<td>시스템에 계속 접근할 수 있는 상태 유지</td>
</tr>
<tr>
<td>Privilege Escalation</td>
<td>더 높은 권한 획득</td>
</tr>
<tr>
<td>Stealth</td>
<td>정상 행위처럼 위장하여 탐지 가능성 감소</td>
</tr>
<tr>
<td>Defense Impairment</td>
<td>보안 도구나 방어 기능 무력화</td>
</tr>
<tr>
<td>Credential Access</td>
<td>계정과 인증 정보 탈취</td>
</tr>
<tr>
<td>Discovery</td>
<td>시스템과 네트워크 환경 탐색</td>
</tr>
<tr>
<td>Lateral Movement</td>
<td>내부의 다른 시스템으로 이동</td>
</tr>
<tr>
<td>Collection</td>
<td>공격 대상의 중요 정보 수집</td>
</tr>
<tr>
<td>Command and Control</td>
<td>감염된 시스템과 공격 서버 간 통신</td>
</tr>
<tr>
<td>Exfiltration</td>
<td>수집한 데이터를 외부로 유출</td>
</tr>
<tr>
<td>Impact</td>
<td>시스템 파괴, 암호화 또는 서비스 중단</td>
</tr>
</tbody></table>
<p>ATT&amp;CK Matrix는 공격이 반드시 왼쪽(<code>Reconnaissance</code>)에서 시작해 오른쪽(<code>Impact</code>) 순서대로만 진행된다는 의미는 아니다.</p>
<p>실제 공격에서는 일부 단계가 생략되거나, 하나의 기술이 여러 목적에 사용되거나, 동일한 행동이 반복될 수 있다. 따라서 Matrix는 고정된 공격 순서도라기보다 <strong>공격자의 행동을 분류하기 위한 기준표</strong>에 가깝다.</p>
<hr>
<h2 id="5-공격-시나리오를-attck에-매핑해-보기">5. 공격 시나리오를 ATT&amp;CK에 매핑해 보기</h2>
<p>공격자가 회사 직원에게 악성 첨부파일을 전송했다고 가정해 보자.</p>
<p>직원이 첨부파일을 실행하자 PowerShell 명령어가 동작하고, 외부 서버에서 악성 파일을 다운로드했다고 한다.</p>
<p>이 공격을 ATT&amp;CK에 매핑하면 다음과 같이 정리할 수 있다.</p>
<table>
<thead>
<tr>
<th>공격자의 행동</th>
<th>Tactic</th>
<th>Technique</th>
</tr>
</thead>
<tbody><tr>
<td>악성 첨부파일이 포함된 이메일 전송</td>
<td>Initial Access</td>
<td>Spearphishing Attachment (<code>T1566.001</code>)</td>
</tr>
<tr>
<td>사용자가 악성 첨부파일 실행</td>
<td>Execution</td>
<td>User Execution: Malicious File (<code>T1204.002</code>)</td>
</tr>
<tr>
<td>PowerShell 명령어 실행</td>
<td>Execution</td>
<td>Command and Scripting Interpreter: PowerShell (<code>T1059.001</code>)</td>
</tr>
<tr>
<td>외부 서버에서 악성 파일 다운로드</td>
<td>Command and Control</td>
<td>Ingress Tool Transfer (<code>T1105</code>)</td>
</tr>
<tr>
<td>운영체제와 시스템 정보 확인</td>
<td>Discovery</td>
<td>System Information Discovery (<code>T1082</code>)</td>
</tr>
<tr>
<td>사용자 계정 확인</td>
<td>Discovery</td>
<td>Account Discovery (<code>T1087</code>)</td>
</tr>
<tr>
<td>LSASS 등에서 인증 정보 추출</td>
<td>Credential Access</td>
<td>OS Credential Dumping (<code>T1003</code>)</td>
</tr>
<tr>
<td>RDP·SMB 등으로 내부 시스템 접속</td>
<td>Lateral Movement</td>
<td>Remote Services (<code>T1021</code>)</td>
</tr>
<tr>
<td>로컬 시스템의 중요 파일 수집</td>
<td>Collection</td>
<td>Data from Local System (<code>T1005</code>)</td>
</tr>
<tr>
<td>기존 C2 채널로 자료 전송</td>
<td>Exfiltration</td>
<td>Exfiltration Over C2 Channel (<code>T1041</code>)</td>
</tr>
</tbody></table>
<p>MITRE ATT&amp;CK에서는 악성 첨부파일을 이용한 표적형 피싱을 <code>T1566.001</code>, PowerShell을 이용한 명령 실행을 <code>T1059.001</code>로 식별한다.</p>
<p>각 기술에 고유한 ID가 있기 때문에 서로 다른 보안 조직도 같은 기준으로 공격 행동을 표현할 수 있다.</p>
<pre><code class="language-text">Tactic       : Execution
Technique    : Command and Scripting Interpreter
Sub-technique: PowerShell
ATT&amp;CK ID    : T1059.001</code></pre>
<hr>
<h2 id="6-보안-담당자는-attck을-어떻게-활용할까">6. 보안 담당자는 ATT&amp;CK을 어떻게 활용할까?</h2>
<p>MITRE ATT&amp;CK은 공격 기술을 외우기 위한 목록이 아니다. 실제 보안 업무에서는 다음과 같이 활용할 수 있다.</p>
<h3 id="침해사고-분석">침해사고 분석</h3>
<p>수집된 로그와 공격자의 행동을 Technique에 연결하면 공격이 어느 단계까지 진행되었는지 파악할 수 있다.</p>
<p>예를 들어 다음과 같은 로그가 발견되었다고 가정해 보자.</p>
<pre><code class="language-text">WINWORD.EXE
└─ powershell.exe
   └─ 외부 서버 접속 및 파일 다운로드</code></pre>
<p>이를 통해 악성 문서 실행, PowerShell 악용, 외부 파일 다운로드로 이어지는 흐름을 추정할 수 있다.</p>
<h3 id="탐지-규칙-개발">탐지 규칙 개발</h3>
<p>ATT&amp;CK Technique을 기준으로 필요한 로그와 탐지 규칙을 설계할 수 있다.</p>
<p>PowerShell 악용을 탐지하려면 다음 데이터를 확인할 수 있다.</p>
<ul>
<li>Windows 프로세스 생성 로그</li>
<li>PowerShell Script Block 로그</li>
<li>부모·자식 프로세스 관계</li>
<li>명령줄 인자</li>
<li>외부 네트워크 연결</li>
<li>파일 생성 기록</li>
</ul>
<h3 id="보안-사각지대-점검">보안 사각지대 점검</h3>
<p>조직에서 수집하는 로그와 탐지 규칙을 ATT&amp;CK Matrix에 표시하면 어떤 Technique은 탐지할 수 있고, 어떤 Technique은 확인하기 어려운지 파악할 수 있다.</p>
<p>MITRE에서 제공하는 <strong>ATT&amp;CK Navigator</strong>를 사용하면 탐지 범위, 레드팀·블루팀 계획, 기술별 탐지 현황 등을 Matrix 위에 시각화할 수 있다.</p>
<h3 id="위협-인텔리전스-분석">위협 인텔리전스 분석</h3>
<p>보안 보고서에 등장하는 공격 그룹과 악성코드의 행동을 ATT&amp;CK 기준으로 정리하면 서로 다른 공격 사례를 비교하기 쉬워진다.</p>
<p>예를 들어 두 공격 그룹이 서로 다른 악성코드를 사용했더라도 모두 PowerShell을 이용해 악성 코드를 실행했다면 공통적으로 <code>T1059.001</code>에 매핑할 수 있다.</p>
<h3 id="모의해킹과-레드팀-훈련">모의해킹과 레드팀 훈련</h3>
<p>알려진 공격 그룹의 Technique을 참고하여 실제 공격자의 행동을 재현하고, 조직의 탐지 및 대응 체계가 정상적으로 동작하는지 검증할 수 있다.</p>
<hr>
<h2 id="7-attck을-사용할-때-주의할-점">7. ATT&amp;CK을 사용할 때 주의할 점</h2>
<p>MITRE ATT&amp;CK은 공격을 분석하는 데 유용하지만 Technique을 매핑하는 것만으로 분석이 끝나는 것은 아니다.</p>
<p>동일한 명령어나 프로그램이라도 실행된 상황에 따라 정상 행위일 수도 있고 공격 행위일 수도 있다.</p>
<blockquote>
<p>예를 들어 PowerShell은 시스템 관리자가 사용하는 정상적인 관리 도구이기도 하다. 따라서 단순히 PowerShell이 실행되었다는 이유만으로 공격이라고 판단해서는 안 된다.</p>
</blockquote>
<p>다음과 같은 주변 정보를 함께 살펴봐야 한다.</p>
<ul>
<li>어떤 사용자가 실행했는가?</li>
<li>어떤 부모 프로세스에서 실행되었는가?</li>
<li>실행된 명령어는 무엇인가?</li>
<li>외부 서버와 통신했는가?</li>
<li>평소에도 발생하던 행위인가?</li>
<li>실행 전후에 다른 의심스러운 이벤트가 있었는가?</li>
</ul>
<p>ATT&amp;CK은 공격을 자동으로 판정해 주는 도구가 아니라, 수집한 증거를 <strong>일관된 기준으로 설명하고 분석하도록 도와주는 프레임워크</strong>이다.</p>
<hr>
<h2 id="8-정리">8. 정리</h2>
<p>MITRE ATT&amp;CK은 실제 공격 사례를 기반으로 공격자의 목적과 행동 기술을 정리한 지식 기반이다.</p>
<p>MITRE ATT&amp;CK을 활용하면 단순히 “악성코드가 실행되었다”라고 기록하는 것에서 그치지 않고 다음과 같이 공격 흐름을 구조적으로 설명할 수 있다.</p>
<pre><code class="language-text">어떤 목적으로
→ 어떤 기술을 사용했고
→ 공격이 어디까지 진행되었으며
→ 이를 탐지하려면 어떤 로그가 필요한가</code></pre>
<p>따라서 MITRE ATT&amp;CK은 침해사고 대응, 보안 관제, 위협 인텔리전스, 탐지 규칙 개발 및 모의해킹 등 다양한 보안 업무에서 공격자와 방어자의 행동을 연결해 주는 공통 언어라고 할 수 있다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Man-in-the-Middle Attack이란 무엇일까?]]></title>
            <link>https://velog.io/@jh_devlog/Security-Man-in-the-Middle-Attack%EC%9D%B4%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%BC%EA%B9%8C</link>
            <guid>https://velog.io/@jh_devlog/Security-Man-in-the-Middle-Attack%EC%9D%B4%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%BC%EA%B9%8C</guid>
            <pubDate>Tue, 30 Jun 2026 00:57:30 GMT</pubDate>
            <description><![CDATA[<h1 id="man-in-the-middle-attack이란-무엇일까">Man-in-the-Middle Attack이란 무엇일까?</h1>
<h2 id="1-이-주제를-정리하게-된-이유">1. 이 주제를 정리하게 된 이유</h2>
<p>네트워크 보안 수업에서 ARP Spoofing 개념을 배우던 중, 강사님께서 <strong>Man-in-the-Middle Attack(MITM)</strong> 용어를 언급하셨다.</p>
<p>MITM 공격은 단순히 하나의 공격 기법이라기보다, 공격자가 통신 경로 중간에 위치하여 데이터를 가로채거나 변조하는 공격 구조를 의미한다. 따라서 이를 이해하기 위해서는 함께 언급되었던 <strong>ARP Spoofing</strong>과 *<em>in-path *</em> 개념도 함께 정리해볼 필요가 있다고 느꼈다.</p>
<p>이번 글에서는 <strong>Man-in-the-Middle Attack</strong>, 즉 <strong>중간자 공격</strong>이 무엇인지, 어떤 방식으로 동작하는지, 그리고 이를 방어하기 위해 어떤 보안 요소를 고려해야 하는지 정리해보고자 한다.</p>
<hr>
<h2 id="2-man-in-the-middle-attack이란">2. Man-in-the-Middle Attack이란?</h2>
<p><strong>Man-in-the-Middle Attack(MITM)</strong>은 공격자가 통신하는 두 대상 사이에 위치하여 데이터를 가로채거나 변조하는 공격 방식이다.</p>
<p>일반적인 통신 흐름은 다음과 같다.</p>
<pre><code class="language-text">사용자  &lt;----------------&gt;  서버</code></pre>
<p>하지만 MITM 공격이 발생하면 통신 구조는 다음과 같이 바뀐다.</p>
<pre><code class="language-text">사용자  &lt;------&gt;  공격자  &lt;------&gt;  서버</code></pre>
<p>사용자는 자신이 서버와 직접 통신하고 있다고 생각하지만, 실제로는 공격자를 거쳐 서버와 통신하게 된다. 서버 역시 사용자의 요청이라고 생각하지만, 그 중간에서 공격자가 데이터를 확인하거나 조작할 수 있다.</p>
<p>즉, MITM 공격의 핵심은 <strong>통신 당사자들이 공격자의 존재를 인식하지 못한 상태에서 통신을 계속한다는 점</strong>이다.</p>
<hr>
<h2 id="3-in-path란">3. in-path란?</h2>
<p>MITM 공격을 이해할 때 함께 알아두면 좋은 개념이 <strong>in-path</strong>이다.</p>
<p><strong>in-path</strong>는 공격자가 실제 통신 경로 안에 위치하는 상태를 의미한다. 즉, 사용자가 서버로 보내는 트래픽이 공격자를 거쳐 지나가고, 서버가 사용자에게 보내는 응답도 공격자를 거쳐 전달되는 구조이다.</p>
<blockquote>
<p>단순히 주변에서 트래픽을 관찰하는 수동적인 스니핑과 달리, in-path 상태에서는 실제 트래픽이 공격자를 거쳐 목적지로 전달된다.</p>
</blockquote>
<pre><code class="language-text">사용자  →  공격자  →  서버
사용자  ←  공격자  ←  서버</code></pre>
<p>이처럼 공격자가 통신 경로 안에 위치하면 단순히 패킷을 관찰하는 것뿐만 아니라, 필요에 따라 내용을 수정하거나 특정 요청을 차단하는 것도 가능해질 수 있다.</p>
<p>따라서 MITM 공격은 단순한 도청 공격이 아니라, 통신 흐름 자체를 공격자가 통제할 수 있다는 점에서 위험하다.</p>
<hr>
<h2 id="4-arp-spoofing과-mitm의-관계">4. ARP Spoofing과 MITM의 관계</h2>
<p><img src="https://velog.velcdn.com/images/jh_devlog/post/da4f48d3-67ae-4108-857e-9e5b774b6a87/image.png" alt=""></p>
<blockquote>
<p>이미지 출처: Wikimedia Commons</p>
</blockquote>
<p><strong>ARP Spoofing</strong>은 MITM 공격을 가능하게 만드는 대표적인 기법 중 하나이다.</p>
<p>ARP는 IP 주소에 해당하는 MAC 주소를 알아내기 위해 사용되는 프로토콜이다. ARP Spoofing은 일반적으로 공격자와 피해자가 같은 로컬 네트워크에 있을 때 시도될 수 있다.
예를 들어 같은 네트워크 안에서 특정 IP와 통신하려면, 먼저 해당 IP를 가진 장비의 MAC 주소를 알아야 한다.</p>
<p>이때 사용되는 정보가 <strong>ARP 테이블</strong>이다.</p>
<pre><code class="language-text">IP 주소        MAC 주소
192.168.0.1   aa:bb:cc:dd:ee:ff</code></pre>
<p>문제는 ARP가 기본적으로 상대방의 응답을 신뢰하는 방식으로 동작한다는 점이다. 공격자는 이 특성을 악용하여 피해자의 ARP 테이블에 잘못된 정보를 저장하게 만들 수 있다.</p>
<p>예를 들어 공격자가 피해자에게 다음과 같이 속인다고 가정해볼 수 있다.</p>
<blockquote>
<p>&quot;게이트웨이 IP의 MAC 주소는 공격자의 MAC 주소야.&quot;</p>
</blockquote>
<p>피해자가 이 정보를 믿고 ARP 테이블을 갱신하면, 원래 게이트웨이로 가야 할 패킷이 공격자에게 전달된다. 이후 공격자는 해당 패킷을 다시 게이트웨이로 전달하면서 통신이 끊기지 않은 것처럼 보이게 할 수 있다.</p>
<p>결과적으로 공격자는 사용자와 게이트웨이 사이의 통신 경로에 위치하게 되고, 이 구조가 MITM 공격으로 이어질 수 있다.</p>
<hr>
<h2 id="5-mitm-공격으로-발생할-수-있는-문제">5. MITM 공격으로 발생할 수 있는 문제</h2>
<p>MITM 공격이 위험한 이유는 단순히 패킷을 훔쳐보는 데서 끝나지 않기 때문이다.</p>
<p>공격자가 통신 중간에 위치하면 다음과 같은 문제가 발생할 수 있다.</p>
<h3 id="51-민감-정보-탈취">5.1 민감 정보 탈취</h3>
<p>암호화되지 않은 통신에서는 로그인 ID, 비밀번호, 세션 쿠키, 인증 토큰 등이 노출될 수 있다.</p>
<p>특히 HTTP처럼 평문으로 데이터를 주고받는 경우, 공격자가 패킷을 확인하면 사용자가 입력한 정보가 그대로 보일 수 있다.</p>
<h3 id="52-데이터-변조">5.2 데이터 변조</h3>
<p>공격자는 사용자가 서버로 보내는 요청이나, 서버가 사용자에게 보내는 응답을 중간에서 수정할 수 있다.</p>
<p>예를 들어 사용자가 정상 사이트에 접속했다고 생각하더라도, 공격자가 응답 내용을 바꿔 악성 링크나 가짜 로그인 페이지를 보여줄 수 있다.</p>
<h3 id="53-세션-탈취">5.3 세션 탈취</h3>
<p>사용자가 로그인한 뒤 발급받은 세션 쿠키가 탈취되면, 공격자는 해당 사용자인 것처럼 서비스에 접근할 수 있다.</p>
<p>이 경우 비밀번호를 직접 알지 못하더라도 로그인 상태를 악용할 수 있기 때문에 위험하다.</p>
<h3 id="54-내부망-침투로-이어질-가능성">5.4 내부망 침투로 이어질 가능성</h3>
<p>기업 환경에서는 MITM 공격을 통해 내부 시스템 접속 정보나 관리자 계정 정보가 노출될 수 있다.</p>
<p>이러한 정보가 탈취되면 단순한 네트워크 공격을 넘어 내부망 침투, 권한 상승, 추가 시스템 공격으로 이어질 수 있다.</p>
<hr>
<h2 id="6-mitm-공격-대응-방안">6. MITM 공격 대응 방안</h2>
<p>MITM 공격을 방어하기 위해서는 통신 구간의 암호화와 신뢰 검증이 중요하다.</p>
<h3 id="61-https-사용">6.1 HTTPS 사용</h3>
<p>가장 기본적인 대응 방법은 <strong>HTTPS</strong>를 사용하는 것이다.</p>
<p>HTTPS는 TLS를 이용해 사용자와 서버 간 통신을 암호화한다. 따라서 공격자가 중간에서 패킷을 가로채더라도 내용을 쉽게 확인하기 어렵다.</p>
<p>다만 HTTPS를 사용하더라도 인증서 검증이 제대로 이루어져야 한다. 브라우저에서 인증서 경고가 발생했는데 이를 무시하고 접속하면, 공격자가 준비한 가짜 인증서를 신뢰하게 될 위험이 있다.</p>
<h3 id="62-인증서-검증">6.2 인증서 검증</h3>
<p>HTTPS에서 인증서는 사용자가 접속한 서버가 실제로 신뢰할 수 있는 서버인지 확인하는 역할을 한다.</p>
<p>따라서 브라우저나 애플리케이션은 다음과 같은 내용을 확인해야 한다.</p>
<pre><code class="language-text">- 인증서가 신뢰할 수 있는 인증기관에서 발급되었는지
- 인증서의 도메인 정보가 접속한 사이트와 일치하는지
- 인증서가 만료되지 않았는지
- 인증서 경고가 발생하지 않는지</code></pre>
<p>사용자 입장에서도 인증서 경고가 나타났을 때 무시하고 접속하지 않는 습관이 중요하다.</p>
<h3 id="63-공용-와이파이-사용-주의">6.3 공용 와이파이 사용 주의</h3>
<p>카페, 공항, 도서관 등에서 제공하는 공용 와이파이는 여러 사용자가 함께 사용하는 네트워크이다.</p>
<p>이러한 환경에서는 공격자가 같은 네트워크에 접속해 트래픽을 관찰하거나 MITM 공격을 시도할 수 있다.</p>
<p>특히 보안 설정이 미흡한 공용 와이파이나, 공격자가 만든 가짜 AP에 접속하는 경우 MITM 공격 위험이 커질 수 있다.</p>
<p>따라서 공용 와이파이에서는 금융 서비스, 회사 업무 시스템, 관리자 페이지 접속처럼 민감한 작업은 피하는 것이 좋다. 필요한 경우 VPN을 사용하여 통신 구간을 추가로 보호할 수 있다.</p>
<h3 id="64-arp-spoofing-탐지-및-방어">6.4 ARP Spoofing 탐지 및 방어</h3>
<p>내부 네트워크에서는 ARP Spoofing을 탐지하고 차단하는 것도 중요하다.</p>
<p>대표적인 대응 방법은 다음과 같다.</p>
<pre><code class="language-text">- ARP 테이블 변경 모니터링
- 동일 IP에 대한 MAC 주소 변경 탐지
- Static ARP 설정
- DHCP Snooping
- Dynamic ARP Inspection
- 네트워크 장비의 보안 기능 활용</code></pre>
<p>특히 기업 환경에서는 스위치 단에서 비정상적인 ARP 패킷을 탐지하고 차단하는 설정이 중요하다.</p>
<hr>
<h2 id="7-정리">7. 정리</h2>
<p><strong>Man-in-the-Middle Attack(MITM)</strong>은 공격자가 통신 경로 중간에 개입하여 데이터를 가로채거나 변조하는 공격이다.</p>
<p>대표적으로 <strong>ARP Spoofing</strong>을 통해 공격자가 in-path 위치에 놓이면, 피해자의 트래픽이 공격자를 거쳐 전달되는 구조가 만들어질 수 있다.</p>
<p>이를 방어하기 위해서는 <strong>HTTPS 사용, 인증서 검증, ARP Spoofing 탐지, 네트워크 장비 보안 설정</strong> 등이 필요하다.</p>
<p>이번 내용을 통해 네트워크 보안에서는 통신 구조뿐만 아니라, 프로토콜의 신뢰 관계가 어떻게 악용될 수 있는지 이해하는 것이 중요하다는 점을 알 수 있었다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[취약점 분석은 어떻게 시작할까?]]></title>
            <link>https://velog.io/@jh_devlog/Security-%EC%B7%A8%EC%95%BD%EC%A0%90-%EB%B6%84%EC%84%9D%EC%9D%80-%EC%96%B4%EB%96%BB%EA%B2%8C-%EC%8B%9C%EC%9E%91%ED%95%A0%EA%B9%8C</link>
            <guid>https://velog.io/@jh_devlog/Security-%EC%B7%A8%EC%95%BD%EC%A0%90-%EB%B6%84%EC%84%9D%EC%9D%80-%EC%96%B4%EB%96%BB%EA%B2%8C-%EC%8B%9C%EC%9E%91%ED%95%A0%EA%B9%8C</guid>
            <pubDate>Thu, 25 Jun 2026 00:59:22 GMT</pubDate>
            <description><![CDATA[<h1 id="취약점-분석은-어떻게-시작할까">취약점 분석은 어떻게 시작할까?</h1>
<h2 id="1-이-주제를-정리하게-된-이유">1. 이 주제를 정리하게 된 이유</h2>
<p>보안 공부를 하다 보면 <strong>CVE, 취약점, 패치, 보안 권고문</strong>이라는 단어를 자주 보게 된다.</p>
<p>처음에는 취약점 분석이라고 하면 직접 공격 코드를 작성하거나 시스템을 해킹해보는 고급 기술처럼 느껴졌다. 하지만 공부를 하다 보니 취약점 분석은 반드시 공격을 수행하는 것만을 의미하지 않는다는 것을 알게 되었다.</p>
<p>실무에서는 공개된 취약점 정보를 확인하고, 어떤 제품이나 버전에 영향을 주는지 파악한 뒤, 현재 운영 중인 시스템에 해당 취약점이 적용되는지 판단하는 과정도 중요하다.</p>
<p>이번 글에서는 취약점 분석이 무엇인지, 어떤 흐름으로 시작하면 좋은지, 그리고 CVE, NVD, GitHub Advisory와 같은 취약점 정보를 어디서 확인할 수 있는지 정리해보려고 한다.</p>
<hr>
<h2 id="2-취약점-분석이란">2. 취약점 분석이란?</h2>
<p>취약점 분석은 시스템, 애플리케이션, 라이브러리, 네트워크 장비 등에 존재하는 <strong>보안 취약점</strong>을 파악하고, 이것이 실제 환경에서 어떤 위험으로 이어질 수 있는지 확인하는 과정이다.</p>
<p>여기서 자주 등장하는 용어로 <strong>CVE</strong>와 <strong>CWE</strong>가 있다.</p>
<p><strong>CVE</strong>는 공개된 개별 보안 취약점에 부여되는 식별 번호이고, <strong>CWE</strong>는 취약점이 발생할 수 있는 보안 약점의 유형을 분류한 것이다.</p>
<p>쉽게 말하면 CVE는 “특정 취약점의 번호표”, CWE는 “그 취약점이 어떤 약점에서 비롯되었는지 분류하는 기준”에 가깝다.</p>
<p>예를 들어 특정 소프트웨어에서 입력값 검증 부족이라는 <strong>보안 약점(CWE)</strong>으로 인해 실제 공격이 가능한 <strong>보안 취약점(CVE)</strong>이 발견될 수 있다.</p>
<p>즉, 취약점 분석은 이러한 CVE와 CWE 정보를 바탕으로 실제 운영 환경의 위험을 파악하는 과정이라고 볼 수 있다.</p>
<hr>
<h2 id="3-취약점-분석은-어떤-흐름으로-진행될까">3. 취약점 분석은 어떤 흐름으로 진행될까?</h2>
<p>취약점 분석은 일정한 흐름에 따라 정리하면 이해하기 쉽다.</p>
<blockquote>
<p>💡 <strong>취약점 분석 핵심 흐름</strong></p>
<ol>
<li><strong>정보 확인</strong>: CVE, NVD, 보안 권고문 확인</li>
<li><strong>영향 범위 파악</strong>: 영향을 받는 제품과 버전 확인</li>
<li><strong>원인 파악</strong>: 취약점 유형과 발생 원인 이해</li>
<li><strong>환경 적용 여부 판단</strong>: 우리 시스템에 해당하는지 확인</li>
<li><strong>대응 방안 정리</strong>: 패치 또는 임시 조치 검토</li>
<li><strong>문서화</strong>: 분석 결과와 대응 방안 정리</li>
</ol>
</blockquote>
<h3 id="1-취약점-정보-확인">1) 취약점 정보 확인</h3>
<p>CVE 번호, NVD, 벤더 공지, GitHub Advisory, 보안 뉴스 등을 통해 취약점이 공개되면, 단순히 번호만 보는 것이 아니라 다음 정보를 함께 수집해야 한다.</p>
<ul>
<li>취약점이 발생한 제품 또는 라이브러리</li>
<li>영향을 받는 버전</li>
<li>취약점 유형</li>
<li>심각도</li>
<li>공격 조건</li>
<li>패치 여부</li>
</ul>
<h3 id="2-영향을-받는-제품과-버전-확인">2) 영향을 받는 제품과 버전 확인</h3>
<p>취약점 분석에서 중요한 부분은 <strong>우리 환경에 영향을 주는지</strong> 판단하는 것이다.</p>
<p>아무리 심각도가 높은 취약점이라도 현재 사용 중인 제품이나 버전에 해당하지 않는다면 직접적인 영향은 없을 수 있다. 반대로 점수가 아주 높지 않더라도 외부에 노출된 서비스에서 실제 사용 중이라면 빠르게 대응해야 할 수 있다.</p>
<p>따라서 다음과 같은 질문을 던져볼 수 있다.</p>
<ul>
<li>우리 시스템에서 해당 제품이나 라이브러리를 사용하고 있는가?</li>
<li>사용 중이라면 취약한 버전인가?</li>
<li>외부에서 접근 가능한 위치에 있는가?</li>
<li>인증 없이 악용 가능한가?</li>
<li>이미 공격에 악용되고 있는 취약점인가?</li>
</ul>
<p>이 과정을 통해 단순히 “위험하다”가 아니라, <strong>우리 환경에서 얼마나 위험한가</strong>를 판단할 수 있다.</p>
<h3 id="3-취약점-원인-파악">3) 취약점 원인 파악</h3>
<p>소스코드 레벨까지 깊게 분석하기 어렵다면, 취약점 설명에 자주 등장하는 핵심 유형(CWE) 키워드를 이해하는 것부터 시작하면 좋다.</p>
<p>대표적인 취약점 유형은 다음과 같다.</p>
<ul>
<li>SQL Injection</li>
<li>XSS</li>
<li>Path Traversal</li>
<li>Remote Code Execution</li>
<li>Privilege Escalation</li>
<li>Authentication Bypass</li>
<li>Buffer Overflow</li>
<li>Insecure Deserialization</li>
</ul>
<p>이러한 키워드는 취약점이 어떤 방식으로 발생하는지 이해하는 데 도움이 된다.</p>
<h3 id="4-대응-방안-정리">4) 대응 방안 정리</h3>
<p>취약점에 대한 영향 범위와 원인을 확인했다면, 대응 방안을 정리해야 한다.</p>
<p>가장 기본적인 대응은 패치 또는 버전 업데이트이다. 하지만 바로 패치가 어려운 환경이라면 임시 대응 방안도 함께 검토해야 한다.</p>
<p>예를 들어 다음과 같은 대응이 있을 수 있다.</p>
<ul>
<li>취약한 버전을 안전한 버전으로 업데이트</li>
<li>취약한 기능 비활성화</li>
<li>외부 접근 차단</li>
<li>방화벽 또는 WAF 정책 적용</li>
<li>권한 설정 점검</li>
<li>로그 모니터링 강화</li>
<li>침해 흔적 확인</li>
</ul>
<p>보안 대응에서는 패치 전후로 영향 범위를 확인하고 이미 악용 흔적이 있는지도 함께 점검하는 것이 중요하다.</p>
<hr>
<h2 id="4-취약점-정보를-어디서-확인할-수-있을까">4. 취약점 정보를 어디서 확인할 수 있을까?</h2>
<p>취약점 분석을 시작할 때는 신뢰할 수 있는 공개 정보를 확인하는 것이 중요하다. 대표적으로 <strong>CVE, NVD, GitHub Advisory Database</strong>를 참고할 수 있다.</p>
<h3 id="1-cve">1) CVE</h3>
<p>CVE는 Common Vulnerabilities and Exposures의 약자로, 공개적으로 알려진 보안 취약점에 고유한 식별 번호를 부여하는 체계이다.</p>
<p>예를 들어 <code>CVE-2024-XXXX</code>와 같은 형식으로 표시된다. CVE 번호가 있으면 여러 보안 문서나 도구에서 같은 취약점을 동일하게 식별할 수 있다.</p>
<p>CVE는 취약점의 이름표와 같은 역할을 한다. 다만 CVE 정보만으로 모든 분석이 끝나는 것은 아니기 때문에, NVD, 벤더 공지, 패치 내역 등을 함께 확인하는 것이 좋다.</p>
<h3 id="2-nvd">2) NVD</h3>
<p>NVD는 National Vulnerability Database의 약자로, CVE 기반의 취약점 정보를 제공하는 데이터베이스이다.</p>
<p>NVD에서는 취약점 설명, 영향받는 제품, CVSS 점수, 취약점 유형, 참고 링크 등을 확인할 수 있다. CVSS 점수는 취약점의 심각도를 수치로 표현한 값으로, 대응 우선순위를 판단할 때 참고할 수 있다.</p>
<p>하지만 점수만 보고 위험도를 판단해서는 안 된다.</p>
<p>CVSS 점수는 취약점 자체의 기술적 심각도를 판단하는 데 도움이 되지만, 우리 환경의 자산 중요도나 외부 노출 여부까지 모두 반영하지는 못한다.</p>
<p>예를 들어 점수가 높은 취약점이라도 해당 시스템이 폐쇄망에 있고 외부 접근이 불가능하다면 대응 우선순위가 상대적으로 낮아질 수 있다. 반대로 점수가 비교적 낮더라도 대고객 서비스 전면에 노출되어 있다면 즉시 대응이 필요할 수 있다.</p>
<p>즉, 취약점의 위험도는 점수만으로 결정되는 것이 아니라 실제 운영 환경과 함께 판단해야 한다.</p>
<h3 id="3-github-advisory-database">3) GitHub Advisory Database</h3>
<p>GitHub Advisory Database는 GitHub에서 제공하는 보안 권고 데이터베이스이다. 특히 오픈소스 라이브러리나 패키지 취약점을 확인할 때 유용하다.</p>
<p>개발 프로젝트에서 npm, Maven, pip 같은 패키지 매니저를 사용한다면, GitHub Advisory를 통해 특정 라이브러리의 취약 버전과 패치 버전을 확인할 수 있다.</p>
<p>또한 GitHub의 Dependabot alerts를 사용하면 프로젝트에서 사용하는 의존성에 알려진 취약점이 있을 경우 알림을 받을 수 있다.</p>
<p>이처럼 GitHub Advisory는 개발 프로젝트에서 사용하는 오픈소스 의존성의 보안 위험을 확인하는 데 도움이 된다.</p>
<hr>
<h2 id="5-취약점-분석-시-주의할-점">5. 취약점 분석 시 주의할 점</h2>
<p>취약점 분석을 할 때는 몇 가지 주의할 점이 있다.</p>
<p>첫째, <strong>공개된 PoC 코드를 무분별하게 실행하면 안 된다.</strong></p>
<p>PoC는 취약점을 재현하기 위한 코드이지만, 공개된 코드라고 해서 항상 안전한 것은 아니다. 일부 PoC에는 악성 행위가 포함되어 있을 수도 있으므로, 반드시 격리된 실습 환경에서만 테스트해야 한다.</p>
<p>둘째, <strong>심각도 점수만으로 위험도를 판단하면 안 된다.</strong></p>
<p>CVSS 점수는 중요한 참고 지표이지만, 실제 대응 우선순위를 결정하는 유일한 기준은 아니다. 자산의 중요도, 외부 노출 여부, 실제 사용 여부, 공격 가능 조건 등을 함께 고려해야 한다.</p>
<p>셋째, <strong>하나의 정보원만 믿지 않는 것이 좋다.</strong></p>
<p>CVE, NVD, GitHub Advisory, 벤더 보안 공지, 패치 노트 등을 함께 확인해야 한다. 특히 벤더 공지에는 실제 패치 버전이나 임시 대응 방안이 더 구체적으로 정리되어 있는 경우가 많다.</p>
<p>넷째, <strong>허가되지 않은 시스템에서 테스트하면 안 된다.</strong></p>
<p>취약점 분석은 반드시 본인이 소유한 환경이나 명시적으로 허가받은 환경에서만 진행해야 한다. 학습 목적이라도 타인의 시스템을 대상으로 스캔하거나 공격 코드를 실행하는 것은 법적·윤리적 문제가 될 수 있다.</p>
<p>다섯째, <strong>분석 결과를 문서화해야 한다.</strong></p>
<p>취약점 이름, CVE 번호, 영향받는 버전, 위험도, 확인 방법, 대응 방안, 참고 링크를 정리해두면 이후 비슷한 취약점을 분석할 때 도움이 된다. CERT나 보안 관제 업무에서도 분석 내용을 명확하게 문서화하는 역량은 중요하다.</p>
<hr>
<h2 id="6-정리">6. 정리</h2>
<p>취약점 분석은 단순히 공격을 시도하는 과정이 아니라, 공개된 취약점 정보를 이해하고 실제 환경에 어떤 영향을 주는지 판단하는 과정이다.</p>
<p>처음에는 CVE 번호를 검색하고, NVD나 GitHub Advisory에서 취약점 설명과 영향을 받는 버전을 확인하는 것부터 시작하면 좋다. 이후 취약점의 원인, 공격 조건, 영향 범위, 대응 방안을 차례대로 정리하면 분석 흐름을 익힐 수 있다.</p>
<p>보안 공부를 하다 보면 어려운 용어와 복잡한 공격 기법이 많이 등장한다. 하지만 취약점 분석의 시작은 거창한 기술보다, 공개된 정보를 정확히 읽고 현재 환경에 맞게 해석하는 것에서 출발한다고 생각한다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[CSRF란 무엇일까?]]></title>
            <link>https://velog.io/@jh_devlog/Security-CSRF%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%BC%EA%B9%8C</link>
            <guid>https://velog.io/@jh_devlog/Security-CSRF%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%BC%EA%B9%8C</guid>
            <pubDate>Wed, 24 Jun 2026 00:57:46 GMT</pubDate>
            <description><![CDATA[<h1 id="csrf란-무엇일까">CSRF란 무엇일까?</h1>
<h2 id="1-이-주제를-정리하게-된-이유">1. 이 주제를 정리하게 된 이유</h2>
<p>웹 보안 취약점은 서버나 데이터베이스에서만 발생하는 것이 아니라, 사용자의 브라우저와 요청 흐름에서도 발생할 수 있다.</p>
<p>로그인, 비밀번호 변경, 게시글 작성, 결제처럼 사용자의 권한으로 처리되는 기능에서는 요청이 정말 사용자의 의도에 의해 발생한 것인지 확인하는 것이 중요하다.</p>
<p>이때 사용자가 로그인된 상태를 악용하여, 사용자가 의도하지 않은 요청을 서버로 보내게 만드는 공격이 <strong>CSRF</strong>이다.</p>
<p>이번 글에서는 CSRF가 무엇인지, 왜 발생하는지, 그리고 어떻게 방어할 수 있는지 정리해보려고 한다.</p>
<hr>
<h2 id="2-csrf란">2. CSRF란?</h2>
<p><strong>CSRF</strong>는 <strong>Cross-Site Request Forgery</strong>의 약자로, 우리말로는 <strong>사이트 간 요청 위조</strong>라고 한다.</p>
<p>CSRF는 사용자가 특정 웹 서비스에 로그인된 상태를 악용하여, 사용자가 원하지 않는 요청을 서버로 보내게 만드는 공격이다.</p>
<p>예를 들어 사용자가 어떤 사이트에 로그인한 상태에서 공격자가 만든 악성 페이지에 접속했다고 가정해보자. 이때 악성 페이지가 해당 사이트로 이메일 변경 요청을 보내도록 만들어져 있다면, 브라우저는 로그인 쿠키를 함께 전송할 수 있다.</p>
<p>서버가 쿠키만 보고 정상 사용자의 요청이라고 판단하면, 사용자는 원하지 않았는데도 이메일 주소가 변경될 수 있다.</p>
<p>즉, CSRF는 공격자가 사용자의 비밀번호를 직접 알아내는 공격이라기보다, <strong>이미 로그인된 사용자의 권한을 이용해 원하지 않는 요청을 실행시키는 공격</strong>이다.</p>
<hr>
<h2 id="3-csrf는-왜-발생할까">3. CSRF는 왜 발생할까?</h2>
<p>CSRF는 서버가 요청을 검증하는 방식이 부족할 때 발생한다.</p>
<p>웹 서비스는 사용자가 로그인하면 브라우저에 인증 쿠키를 저장한다. 이후 같은 사이트에 요청을 보낼 때 브라우저는 쿠키를 자동으로 함께 전송한다.</p>
<p>이 기능은 편리하지만, 서버가 단순히 “쿠키가 있으니 정상 요청이다”라고만 판단하면 문제가 생길 수 있다.</p>
<p>중요한 점은 <strong>인증된 사용자라는 사실과 사용자가 직접 의도한 요청이라는 사실은 다르다</strong>는 것이다.</p>
<p>CSRF가 발생하는 주요 원인은 다음과 같다.</p>
<ul>
<li>인증 쿠키가 요청에 자동으로 포함됨</li>
<li>서버가 요청의 출처나 의도를 충분히 검증하지 않음</li>
<li>중요한 기능에 추가 인증이 없음</li>
<li>CSRF Token 같은 방어 장치가 없음</li>
<li>쿠키의 SameSite 설정이 적절하지 않음</li>
</ul>
<p>최근 일부 모던 브라우저는 SameSite 속성이 명시되지 않은 쿠키를 Lax에 가깝게 처리한다. 이로 인해 단순한 CSRF 공격은 과거보다 어려워졌지만, 브라우저별 동작 차이나 서비스 구조에 따라 여전히 위험이 남을 수 있다. 따라서 SameSite 설정만 믿기보다는 CSRF Token 같은 서버 측 방어도 함께 적용하는 것이 안전하다.</p>
<hr>
<h2 id="4-예시로-이해하기">4. 예시로 이해하기</h2>
<p>예를 들어 어떤 사이트에 다음과 같은 기능이 있다고 가정해보자.</p>
<pre><code class="language-text">POST /change-email
email=attacker@example.com</code></pre>
<p>이 요청은 사용자의 이메일 주소를 변경하는 요청이다.</p>
<p>사용자가 직접 마이페이지에서 이메일을 수정했다면 정상적인 요청이다. 하지만 공격자가 만든 악성 페이지가 사용자의 브라우저를 통해 같은 요청을 보내게 만들 수도 있다.</p>
<p>사용자가 해당 사이트에 로그인된 상태라면 브라우저가 인증 쿠키를 함께 전송할 수 있고, 서버는 이를 정상 요청으로 오해할 수 있다.</p>
<p>이처럼 CSRF는 다음과 같은 동작을 유도할 수 있다.</p>
<ul>
<li>회원 정보 변경</li>
<li>비밀번호 변경 요청</li>
<li>게시글 또는 댓글 작성</li>
<li>상품 주문</li>
<li>결제 요청</li>
</ul>
<p>물론 실제 서비스에서는 결제나 비밀번호 변경 같은 중요한 기능에 추가 인증이 적용되는 경우가 많다. 하지만 이런 검증이 부족하면 CSRF 취약점으로 이어질 수 있다.</p>
<hr>
<h2 id="5-어떻게-방어할-수-있을까">5. 어떻게 방어할 수 있을까?</h2>
<h3 id="1-csrf-token-사용">1) CSRF Token 사용</h3>
<p>가장 대표적인 방어 방법은 <strong>CSRF Token</strong>을 사용하는 것이다.</p>
<p>서버는 사용자에게 예측하기 어려운 임의의 토큰 값을 발급하고, 중요한 요청을 보낼 때 이 값을 함께 전송하도록 한다.</p>
<p>서버는 요청에 포함된 토큰이 올바른지 확인한 뒤 요청을 처리한다. 공격자는 사용자의 CSRF Token 값을 알기 어렵기 때문에 요청을 위조하기 어려워진다.</p>
<hr>
<h3 id="2-samesite-cookie-설정">2) SameSite Cookie 설정</h3>
<p>쿠키에 <strong>SameSite 속성</strong>을 설정하면 외부 사이트에서 발생한 요청에 쿠키가 함께 전송되는 것을 제한할 수 있다.</p>
<p>대표적인 값은 다음과 같다.</p>
<table>
<thead>
<tr>
<th>값</th>
<th>의미</th>
</tr>
</thead>
<tbody><tr>
<td>Strict</td>
<td>같은 사이트 요청에만 쿠키 전송</td>
</tr>
<tr>
<td>Lax</td>
<td>외부 사이트에서 들어오더라도 최상위 이동과 GET 같은 안전한 요청 중심으로 쿠키 전송 허용</td>
</tr>
<tr>
<td>None</td>
<td>교차 사이트 요청에도 쿠키 전송 허용. 단, Secure 설정 필요</td>
</tr>
</tbody></table>
<p>최근 일부 브라우저는 SameSite 값을 지정하지 않은 쿠키를 Lax에 가깝게 처리하지만, 중요한 인증 쿠키에는 명시적으로 설정하는 것이 좋다.</p>
<p>예시는 다음과 같다.</p>
<pre><code class="language-text">Set-Cookie: sessionId=...; HttpOnly; Secure; SameSite=Lax</code></pre>
<hr>
<h3 id="3-get-요청으로-상태-변경을-하지-않기">3) GET 요청으로 상태 변경을 하지 않기</h3>
<p>정보 조회처럼 서버 상태를 변경하지 않는 요청은 GET을 사용하고, 회원 정보 변경, 삭제, 결제처럼 서버 상태를 바꾸는 요청은 POST, PUT, PATCH, DELETE 등을 사용해야 한다.</p>
<p>다만 <strong>POST 메서드를 사용한다고 해서 CSRF 공격이 차단되는 것은 아니다.</strong></p>
<p>공격자는 악성 페이지 안에 숨겨진 <code>&lt;form&gt;</code> 태그를 만들고 JavaScript로 <code>submit()</code>을 강제 실행하여 POST 요청도 위조할 수 있다.</p>
<p>따라서 GET 대신 POST를 쓰는 것은 CSRF 자체를 막는 방어책이라기보다, <strong>GET 요청은 서버의 상태를 변경하지 않아야 한다</strong>는 HTTP 메서드의 기본 원칙을 지키기 위함에 가깝다.</p>
<p>즉, 서버 상태를 변경하는 기능은 GET으로 만들지 않고, CSRF Token이나 SameSite 설정과 함께 보호해야 한다.</p>
<hr>
<h3 id="4-origin-referer-헤더-검증">4) Origin, Referer 헤더 검증</h3>
<p>서버는 요청이 어떤 출처에서 왔는지 확인하기 위해 Origin 또는 Referer 헤더를 검증할 수 있다.</p>
<p>예를 들어 회원 정보 변경 요청이 정상 사이트가 아닌 외부 사이트에서 발생했다면 차단할 수 있다.</p>
<p>다만 헤더는 환경에 따라 누락될 수 있으므로 단독 방어책보다는 CSRF Token과 함께 사용하는 것이 좋다.</p>
<hr>
<h3 id="5-중요한-기능에-재인증-적용">5) 중요한 기능에 재인증 적용</h3>
<p>비밀번호 변경, 결제, 회원 탈퇴처럼 중요한 기능은 사용자가 다시 비밀번호를 입력하게 하거나 2차 인증을 요구할 수 있다.</p>
<p>이 방식은 사용자가 실제로 해당 동작을 의도했는지 확인하는 데 도움이 된다.</p>
<hr>
<h3 id="6-jwt-사용-시-저장-위치-주의">6) JWT 사용 시 저장 위치 주의</h3>
<p>최근에는 세션 방식 대신 JWT(JSON Web Token)를 사용하는 서비스도 많다.</p>
<p>JWT를 사용할 때는 토큰을 어디에 저장하느냐에 따라 CSRF와 XSS에 대한 위험도가 달라지므로 주의해야 한다.</p>
<table>
<thead>
<tr>
<th align="left">JWT 저장 위치</th>
<th align="left">CSRF 위험</th>
<th align="left">XSS 위험</th>
<th align="left">특징</th>
</tr>
</thead>
<tbody><tr>
<td align="left">LocalStorage / SessionStorage</td>
<td align="left">낮음</td>
<td align="left">토큰 탈취 위험 높음</td>
<td align="left">브라우저가 토큰을 자동으로 전송하지 않음. JavaScript로 직접 헤더에 실어야 함</td>
</tr>
<tr>
<td align="left">httpOnly Cookie</td>
<td align="left">있음</td>
<td align="left">토큰 직접 탈취 위험은 낮음</td>
<td align="left">쿠키가 자동으로 전송되므로 세션 방식과 동일한 CSRF 방어가 필요함</td>
</tr>
</tbody></table>
<p>핵심은 <strong>인증 정보인 JWT가 브라우저에 의해 자동으로 전송되는 구조인지</strong>이다.</p>
<p>JWT를 LocalStorage나 SessionStorage에 저장하면 브라우저가 토큰을 자동으로 전송하지 않기 때문에 일반적인 CSRF 위험은 낮아진다. 하지만 XSS가 발생하면 JavaScript로 토큰을 탈취당할 수 있다.</p>
<p>반대로 JWT를 httpOnly 쿠키에 저장하면 JavaScript로 토큰 값을 직접 읽기 어렵다. 하지만 쿠키는 요청 시 자동으로 전송되므로 CSRF 위험이 생길 수 있다.</p>
<p>따라서 보안을 위해 JWT를 httpOnly 쿠키에 저장한다면, 전통적인 세션 방식과 마찬가지로 CSRF Token이나 SameSite 설정을 함께 적용해야 한다.</p>
<hr>
<h2 id="6-정리">6. 정리</h2>
<p>CSRF는 사용자가 로그인된 상태를 악용하여, 의도하지 않은 요청을 서버로 보내게 만드는 공격이다.</p>
<p>이를 방어하기 위해서는 CSRF Token, SameSite Cookie 설정, Origin/Referer 검증, 재인증 등을 함께 적용하고, JWT를 사용할 때도 저장 위치에 따른 보안 위험을 고려해야 한다.</p>
<p>이번 글을 정리하면서 가장 중요하다고 느낀 점은 <strong>로그인된 사용자의 요청이라고 해서 항상 사용자가 의도한 요청은 아니라는 것</strong>이다.</p>
<p>단순히 사용자가 인증되었는지만 확인하는 것이 아니라, <strong>그 요청이 정상적인 흐름에서 발생한 요청인지까지 함께 검증해야 한다는 점도 중요하다.</strong></p>
<p>결국 보안은 하나의 기능을 추가하는 문제가 아니라, 서비스의 요청 흐름을 얼마나 신중하게 설계하느냐와 연결되어 있다. 그런 점에서 CSRF는 웹 서비스를 개발할 때 꼭 이해하고 대비해야 할 취약점이라고 느꼈다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[XSS란 무엇일까?]]></title>
            <link>https://velog.io/@jh_devlog/Security-XSS%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%BC%EA%B9%8C</link>
            <guid>https://velog.io/@jh_devlog/Security-XSS%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%BC%EA%B9%8C</guid>
            <pubDate>Tue, 23 Jun 2026 00:56:32 GMT</pubDate>
            <description><![CDATA[<h1 id="xss란-무엇일까">XSS란 무엇일까?</h1>
<h2 id="1-이-주제를-정리하게-된-이유">1. 이 주제를 정리하게 된 이유</h2>
<p>이전 글에서 SQL Injection에 대해 정리하면서, 사용자 입력값을 안전하게 처리하지 않으면 보안 취약점으로 이어질 수 있다는 점을 알게 되었다.</p>
<p>웹 보안에서 SQL Injection과 함께 자주 등장하는 공격 중 하나가 <strong>XSS</strong>이다. SQL Injection이 데이터베이스에 영향을 주는 공격이라면, XSS는 사용자의 브라우저에서 악성 스크립트가 실행될 수 있다는 점에서 차이가 있다.</p>
<p>이번 글에서는 XSS가 무엇인지, 왜 발생하는지, 어떤 피해로 이어질 수 있는지, 그리고 어떻게 방어할 수 있는지 정리해보려고 한다.</p>
<hr>
<h2 id="2-xss란">2. XSS란?</h2>
<p>XSS는 <strong>Cross-Site Scripting</strong>의 약자로, 웹 페이지에 악성 스크립트를 삽입해 다른 사용자의 브라우저에서 실행되도록 만드는 공격이다.</p>
<p>게시글, 댓글, 검색창처럼 사용자가 입력한 내용이 다시 웹 페이지에 출력되는 기능은 많은 웹 서비스에서 사용된다. 이때 입력값이 안전하게 처리되지 않으면, 브라우저는 입력값을 단순한 텍스트가 아니라 실행 가능한 스크립트로 해석할 수 있다.</p>
<p>즉, XSS의 핵심은 <strong>사용자 입력값이 브라우저에서 실행 가능한 코드로 해석되는 문제</strong>라고 볼 수 있다.</p>
<hr>
<h2 id="3-xss는-왜-발생할까">3. XSS는 왜 발생할까?</h2>
<p>XSS는 사용자의 입력값을 검증하거나 안전하게 변환하지 않은 채 웹 페이지에 출력할 때 발생할 수 있다.</p>
<p>대표적인 발생 원인은 다음과 같다.</p>
<ul>
<li>사용자 입력값 검증 부족</li>
<li>출력 시 HTML 이스케이프 처리 부족</li>
<li>스크립트 실행이 가능한 위치에 입력값 삽입</li>
<li>외부 입력값을 신뢰하는 코드 작성</li>
</ul>
<p>결국 XSS는 웹 애플리케이션이 사용자 입력값을 안전한 텍스트로 처리하지 못할 때 발생하는 취약점이다.</p>
<hr>
<h2 id="4-예시로-이해하기">4. 예시로 이해하기</h2>
<p>예를 들어 댓글 기능이 있는 웹 페이지를 생각해보자.</p>
<p>사용자가 다음과 같이 댓글을 입력하면,</p>
<pre><code class="language-html">안녕하세요!</code></pre>
<p>화면에는 단순한 텍스트로 표시된다.</p>
<p>하지만 공격자가 다음과 같은 값을 입력하고, 서버가 이를 그대로 출력한다면 문제가 발생할 수 있다.</p>
<pre><code class="language-html">&lt;script&gt;alert(&#39;XSS&#39;)&lt;/script&gt;</code></pre>
<p>이 값이 안전하게 처리되지 않고 HTML 문서에 포함되면, 브라우저는 이를 단순한 글자가 아니라 실행 가능한 스크립트로 해석할 수 있다.</p>
<p>예를 들어 HTML에는 다음과 같은 형태로 포함될 수 있다.</p>
<pre><code class="language-html">&lt;p&gt;&lt;script&gt;alert(&#39;XSS&#39;)&lt;/script&gt;&lt;/p&gt;</code></pre>
<p>이 경우 브라우저는 <code>&lt;script&gt;</code> 태그를 코드로 해석하고 실행할 수 있다.</p>
<p>또 다른 예로 이미지 태그의 이벤트 속성을 악용하는 방식도 있다.</p>
<pre><code class="language-html">&lt;img src=&quot;x&quot; onerror=&quot;alert(&#39;XSS&#39;)&quot;&gt;</code></pre>
<p>중요한 점은 특정 공격 코드를 외우는 것이 아니다.
핵심은 <strong>사용자 입력값이 HTML 문서 안에서 코드로 해석될 수 있다는 점</strong>이다.</p>
<p>XSS가 발생하면 다음과 같은 피해로 이어질 수 있다.</p>
<ul>
<li>쿠키 또는 세션 정보 탈취</li>
<li>피싱 페이지 유도</li>
<li>사용자 권한으로 요청 수행</li>
<li>악성 사이트로 리다이렉트</li>
<li>웹 페이지 변조</li>
</ul>
<p>즉, XSS는 서버 자체보다 <strong>사용자의 브라우저와 세션을 노리는 공격</strong>에 가깝다.</p>
<hr>
<h2 id="5-xss의-종류">5. XSS의 종류</h2>
<p>XSS는 발생 방식에 따라 크게 세 가지로 나눌 수 있다.</p>
<h3 id="5-1-stored-xss">5-1. Stored XSS</h3>
<p>Stored XSS는 악성 스크립트가 서버에 저장된 뒤, 다른 사용자가 해당 페이지를 볼 때 실행되는 방식이다.</p>
<p>예를 들어 공격자가 게시글이나 댓글에 악성 스크립트를 저장하면, 이후 해당 글을 보는 사용자들에게 스크립트가 실행될 수 있다.</p>
<p>Stored XSS는 한 번 저장되면 여러 사용자에게 영향을 줄 수 있기 때문에 위험도가 큰 편이다.</p>
<h3 id="5-2-reflected-xss">5-2. Reflected XSS</h3>
<p>Reflected XSS는 사용자의 요청에 포함된 입력값이 서버 응답에 바로 반영되면서 발생하는 방식이다.</p>
<p>예를 들어 검색어가 화면에 그대로 출력되는 기능에서 입력값을 제대로 처리하지 않으면, 조작된 링크를 통해 스크립트가 실행될 수 있다.</p>
<p>Reflected XSS는 보통 사용자가 특정 링크를 클릭하도록 유도하는 방식과 함께 사용될 수 있다.</p>
<h3 id="5-3-dom-based-xss">5-3. DOM-based XSS</h3>
<p>DOM-based XSS는 브라우저에서 실행되는 JavaScript 코드가 DOM을 조작하는 과정에서 발생한다.</p>
<p>서버 응답보다 클라이언트 측 코드에서 입력값을 안전하게 처리하지 못할 때 발생할 수 있다.</p>
<hr>
<h2 id="6-어떻게-방어할-수-있을까">6. 어떻게 방어할 수 있을까?</h2>
<p>XSS를 방어하기 위해서는 사용자의 입력값이 브라우저에서 코드로 실행되지 않도록 처리해야 한다.</p>
<p>가장 중요한 방법은 <strong>출력 시 HTML 이스케이프 처리</strong>이다.</p>
<p>예를 들어 <code>&lt;script&gt;</code>라는 값이 있을 때, 이를 그대로 출력하면 브라우저가 태그로 해석할 수 있다. 하지만 HTML 이스케이프 처리를 하면 다음처럼 변환된다.</p>
<pre><code class="language-html">&amp;lt;script&amp;gt;</code></pre>
<p><code>&lt;</code>는 <code>&amp;lt;</code>, <code>&gt;</code>는 <code>&amp;gt;</code>로 변환되기 때문에 브라우저는 이를 코드가 아니라 문자열로 표시한다.</p>
<p>XSS 방어 방법은 다음과 같다.</p>
<ul>
<li>출력 시 HTML 이스케이프 처리</li>
<li>사용자 입력값 검증</li>
<li>스크립트 실행 위치에 입력값 직접 삽입 금지</li>
<li>쿠키에 <code>HttpOnly</code>, <code>Secure</code>, <code>SameSite</code> 속성 설정</li>
<li>CSP(Content Security Policy) 적용</li>
<li>프레임워크의 자동 이스케이프 기능 활용</li>
<li>WAF를 통한 웹 공격 탐지 및 차단</li>
</ul>
<p>여기서 중요한 점은 입력값 검증만으로는 부족할 수 있다는 것이다.
입력 단계에서 위험한 값을 걸러내는 것도 중요하지만, 최종적으로 화면에 출력할 때 안전하게 변환하는 처리가 필요하다.</p>
<p>또한 WAF는 XSS 공격 시도를 탐지하고 차단하는 데 도움을 줄 수 있지만, 근본적으로는 애플리케이션 코드에서 안전한 출력 처리가 적용되어야 한다.</p>
<p>즉, XSS 방어의 핵심은 <strong>사용자 입력값을 신뢰하지 않고, 브라우저가 코드로 해석하지 못하도록 안전하게 출력하는 것</strong>이다.</p>
<hr>
<h2 id="7-정리">7. 정리</h2>
<p>XSS는 공격자가 웹 페이지에 악성 스크립트를 삽입하여, 다른 사용자의 브라우저에서 실행되도록 만드는 공격이다.</p>
<ul>
<li><strong>원인</strong>: 입력값이 HTML 또는 JavaScript 코드로 해석됨</li>
<li><strong>영향</strong>: 세션 탈취, 피싱, 페이지 변조, 악성 사이트 이동</li>
<li><strong>방어</strong>: 출력 이스케이프, 입력값 검증, 쿠키 보안 설정, CSP, WAF 활용</li>
</ul>
<blockquote>
<p>XSS의 핵심은 사용자 입력값이 단순한 텍스트가 아니라 브라우저에서 실행 가능한 코드로 해석될 수 있다는 점이다.</p>
</blockquote>
<p>따라서 개발자는 사용자 입력값을 신뢰하지 않고, 화면에 출력할 때 브라우저가 코드로 해석하지 못하도록 안전하게 처리해야 한다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[SQL Injection이란 무엇일까?]]></title>
            <link>https://velog.io/@jh_devlog/Security-SQL-Injection%EC%9D%B4%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%BC%EA%B9%8C</link>
            <guid>https://velog.io/@jh_devlog/Security-SQL-Injection%EC%9D%B4%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%BC%EA%B9%8C</guid>
            <pubDate>Mon, 22 Jun 2026 10:23:46 GMT</pubDate>
            <description><![CDATA[<h1 id="sql-injection이란-무엇일까">SQL Injection이란 무엇일까?</h1>
<h2 id="1-이-주제를-정리하게-된-이유">1. 이 주제를 정리하게 된 이유</h2>
<p>이전 글에서 WAF에 대해 정리하면서, WAF가 탐지하거나 차단할 수 있는 대표적인 웹 공격 중 하나로 <strong>SQL Injection</strong>을 언급했다.</p>
<p>SQL Injection은 웹 보안에서 자주 등장하는 공격 기법이며, 로그인 우회나 데이터베이스 정보 유출과도 연결될 수 있는 중요한 개념이다.</p>
<p>개발을 공부하면서 SQL을 사용해 데이터를 조회하고 저장하는 과정은 익숙했지만, 사용자의 입력값이 어떻게 공격으로 이어질 수 있는지는 명확히 이해하지 못했다.</p>
<p>그래서 이번 글에서는 SQL Injection이 무엇인지, 왜 발생하는지, 그리고 어떻게 방어할 수 있는지 정리해보려고 한다.</p>
<hr>
<h2 id="2-sql-injection이란">2. SQL Injection이란?</h2>
<p>SQL Injection은 공격자가 입력값에 악의적인 SQL 구문을 삽입하여, 데이터베이스에 의도하지 않은 쿼리가 실행되도록 만드는 공격이다.</p>
<p>웹 애플리케이션은 사용자가 입력한 값을 바탕으로 데이터베이스에 질의하는 경우가 많다. 예를 들어 로그인, 검색, 게시글 조회, 회원 정보 수정 같은 기능에서 SQL 쿼리가 사용될 수 있다.</p>
<p>이때 사용자의 입력값이 제대로 검증되지 않고 SQL 문장에 직접 포함된다면, 공격자는 입력값을 조작해 원래 의도와 다른 SQL이 실행되도록 만들 수 있다.</p>
<p>즉, SQL Injection의 핵심은 <strong>사용자 입력값이 SQL 쿼리의 일부로 해석되는 문제</strong>라고 볼 수 있다.</p>
<hr>
<h2 id="3-sql-injection은-왜-발생할까">3. SQL Injection은 왜 발생할까?</h2>
<p>SQL Injection은 주로 사용자의 입력값을 신뢰하고, 그 값을 SQL 문장에 그대로 연결할 때 발생한다.</p>
<p>예를 들어 로그인 기능에서 사용자가 입력한 아이디와 비밀번호를 이용해 다음과 같은 SQL을 만든다고 가정해보자.</p>
<pre><code class="language-sql">SELECT *
FROM users
WHERE username = &#39;입력한 아이디&#39;
AND password = &#39;입력한 비밀번호&#39;;</code></pre>
<p>이 구조 자체가 항상 문제인 것은 아니다.
문제는 사용자가 입력한 값이 검증되지 않은 채 SQL 문자열에 그대로 이어 붙여질 때 발생한다.</p>
<p>공격자가 단순한 아이디나 비밀번호 대신 SQL 문법으로 해석될 수 있는 값을 입력하면, 데이터베이스는 이를 일반 문자열이 아니라 SQL 조건의 일부로 처리할 수 있다.</p>
<p>SQL Injection이 발생하는 대표적인 원인은 다음과 같다.</p>
<ul>
<li>사용자 입력값 검증 부족</li>
<li>SQL 문자열 직접 연결</li>
<li>Prepared Statement 미사용</li>
<li>데이터베이스 권한 과다 부여</li>
<li>에러 메시지를 통한 내부 정보 노출</li>
</ul>
<p>결국 SQL Injection은 웹 애플리케이션이 사용자 입력값을 안전하게 처리하지 못할 때 발생하는 취약점이다.</p>
<hr>
<h2 id="4-예시로-이해하기">4. 예시로 이해하기</h2>
<p>다음과 같은 로그인 쿼리가 있다고 가정해보자.</p>
<pre><code class="language-sql">SELECT *
FROM users
WHERE username = &#39;user&#39;
AND password = &#39;1234&#39;;</code></pre>
<p>이 쿼리는 아이디가 <code>user</code>이고, 비밀번호가 <code>1234</code>인 사용자를 찾기 위한 쿼리이다.</p>
<p>그런데 사용자의 입력값이 검증 없이 SQL 문장에 그대로 들어간다면 문제가 발생할 수 있다.</p>
<p>예를 들어 사용자가 다음과 같이 입력했다고 가정해보자.</p>
<ul>
<li>아이디: <code>admin</code></li>
<li>비밀번호: <code>&#39; OR &#39;1&#39;=&#39;1</code></li>
</ul>
<p>이 입력값이 그대로 SQL에 포함되면 다음과 같은 쿼리가 만들어질 수 있다.</p>
<pre><code class="language-sql">SELECT *
FROM users
WHERE username = &#39;admin&#39;
AND password = &#39;&#39; OR &#39;1&#39;=&#39;1&#39;;</code></pre>
<p>여기서 <code>&#39;1&#39;=&#39;1&#39;</code>은 항상 참이 되는 조건이다.</p>
<p>원래는 아이디와 비밀번호가 모두 일치해야 하지만, 입력값이 SQL 조건식으로 해석되면서 의도하지 않은 결과가 발생할 수 있다.</p>
<p>실제 공격에서는 뒤에 남는 SQL 구문을 무시하기 위해 주석 문법을 함께 사용하는 경우도 있다. 하지만 여기서 중요한 것은 특정 공격 문자열을 외우는 것이 아니라, <strong>사용자 입력값이 SQL 문법으로 해석되면 위험하다</strong>는 원리를 이해하는 것이다.</p>
<p>SQL Injection을 통해 발생할 수 있는 피해는 다음과 같다.</p>
<ul>
<li>로그인 우회</li>
<li>데이터베이스 정보 조회</li>
<li>개인정보 유출</li>
<li>데이터 변조 또는 삭제</li>
<li>관리자 권한 탈취 가능성 증가</li>
</ul>
<p>따라서 SQL Injection은 단순한 입력값 오류가 아니라, 데이터베이스와 서비스 전체의 보안에 영향을 줄 수 있는 취약점이다.</p>
<hr>
<h2 id="5-어떻게-방어할-수-있을까">5. 어떻게 방어할 수 있을까?</h2>
<p>SQL Injection을 방어하기 위해서는 사용자의 입력값이 SQL 문법으로 해석되지 않도록 처리해야 한다.</p>
<p>가장 기본적이고 중요한 방법은 <strong>Prepared Statement</strong> 또는 <strong>Parameterized Query</strong>를 사용하는 것이다.</p>
<pre><code class="language-sql">SELECT *
FROM users
WHERE username = ?
AND password = ?;</code></pre>
<p>Prepared Statement는 SQL 문장의 구조를 먼저 정해두고, 사용자 입력값은 나중에 파라미터로 바인딩하는 방식이다.</p>
<p>즉, 데이터베이스는 <code>?</code>가 들어간 쿼리의 구조를 먼저 분석하고, 이후 입력값은 SQL 문법이 아니라 단순한 데이터로 처리한다.</p>
<p>따라서 사용자가 <code>&#39; OR &#39;1&#39;=&#39;1</code> 같은 값을 입력하더라도, 데이터베이스는 이를 SQL 조건식이 아니라 하나의 문자열 값으로 인식한다. 입력값이 쿼리의 구조를 바꾸지 못하기 때문에 SQL Injection을 방어할 수 있다.</p>
<p>SQL Injection을 방어하기 위한 주요 방법은 다음과 같다.</p>
<ul>
<li>Prepared Statement 또는 Parameterized Query 사용</li>
<li>사용자 입력값 검증</li>
<li>ORM 사용 시 안전한 쿼리 작성 방식 준수</li>
<li>데이터베이스 계정 권한 최소화</li>
<li>에러 메시지에 내부 SQL 정보 노출 방지</li>
<li>WAF를 통한 웹 공격 탐지 및 차단</li>
</ul>
<p>여기서 중요한 점은 WAF만으로 SQL Injection을 완전히 막을 수는 없다는 것이다.</p>
<p>WAF는 공격 시도를 탐지하고 차단하는 데 도움을 줄 수 있지만, 근본적으로는 애플리케이션 코드에서 안전한 쿼리 작성 방식이 적용되어야 한다.</p>
<p>즉, SQL Injection 방어의 핵심은 <strong>입력값 검증 + 안전한 쿼리 작성 + 최소 권한 원칙</strong>이라고 볼 수 있다.</p>
<hr>
<h2 id="6-정리">6. 정리</h2>
<p>SQL Injection은 사용자의 입력값에 악의적인 SQL 구문이 삽입되어, 데이터베이스에 의도하지 않은 쿼리가 실행되도록 만드는 공격이다.</p>
<p>이 공격은 주로 사용자 입력값을 검증하지 않고 SQL 문자열에 그대로 연결할 때 발생한다.</p>
<ul>
<li><strong>원인</strong>: 입력값이 SQL 쿼리의 일부로 해석됨</li>
<li><strong>영향</strong>: 로그인 우회, 정보 유출, 데이터 변조 또는 삭제</li>
<li><strong>방어</strong>: Prepared Statement, 입력값 검증, 최소 권한, 에러 메시지 관리, WAF 활용</li>
</ul>
<blockquote>
<p>SQL Injection의 핵심은 사용자의 입력값이 단순한 데이터가 아니라 SQL 문법으로 해석될 수 있다는 점이다.</p>
</blockquote>
<p>이번 글을 정리하면서 SQL Injection은 단순히 SQL 문법을 악용하는 공격이 아니라, 입력값을 안전하게 처리하지 못했을 때 발생하는 대표적인 웹 취약점이라는 점을 알 수 있었다.</p>
<p>개발자는 사용자 입력값을 신뢰하지 않고, 입력값이 SQL 문장에 직접 연결되지 않도록 안전한 쿼리 작성 방식을 사용하는 것이 중요하다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[WAF는 방화벽과 무엇이 다를까?]]></title>
            <link>https://velog.io/@jh_devlog/Security-WAF%EB%8A%94-%EB%B0%A9%ED%99%94%EB%B2%BD%EA%B3%BC-%EB%AC%B4%EC%97%87%EC%9D%B4-%EB%8B%A4%EB%A5%BC%EA%B9%8C</link>
            <guid>https://velog.io/@jh_devlog/Security-WAF%EB%8A%94-%EB%B0%A9%ED%99%94%EB%B2%BD%EA%B3%BC-%EB%AC%B4%EC%97%87%EC%9D%B4-%EB%8B%A4%EB%A5%BC%EA%B9%8C</guid>
            <pubDate>Sat, 20 Jun 2026 09:06:38 GMT</pubDate>
            <description><![CDATA[<h1 id="waf는-방화벽과-무엇이-다를까">WAF는 방화벽과 무엇이 다를까?</h1>
<h2 id="1-이-주제를-정리하게-된-이유">1. 이 주제를 정리하게 된 이유</h2>
<p>이전 글에서 방화벽과 IDS/IPS에 대해 정리하면서, 네트워크 보안 장비들이 각각 다른 역할을 가진다는 점을 알게 되었다.</p>
<p>방화벽은 주로 IP 주소, 포트 번호, 프로토콜 같은 정보를 기준으로 트래픽을 허용하거나 차단한다. 하지만 웹 서비스처럼 80번, 443번 포트를 열어두어야 하는 경우에는, 허용된 포트를 통해 들어오는 공격까지 방화벽만으로 모두 막기는 어렵다.</p>
<p>예를 들어 공격자가 정상적인 웹 요청처럼 보이는 형태로 SQL Injection이나 XSS 같은 공격을 시도한다면, 일반적인 방화벽만으로는 요청 안에 담긴 내용을 자세히 분석하기 어렵다.</p>
<p>이때 웹 애플리케이션을 보호하기 위해 사용되는 보안 장비가 <strong>WAF</strong>이다. 이번 글에서는 WAF가 무엇인지, 일반 방화벽과 어떤 차이가 있는지 정리해보려고 한다.</p>
<hr>
<h2 id="2-waf란">2. WAF란?</h2>
<p>WAF는 <strong>Web Application Firewall</strong>의 약자로, 우리말로는 <strong>웹 애플리케이션 방화벽</strong>이라고 한다.</p>
<p>WAF는 웹 애플리케이션으로 들어오는 HTTP/HTTPS 요청을 검사하고, 공격으로 의심되는 요청을 탐지하거나 차단하는 보안 장비이다.</p>
<p>일반적인 방화벽이 네트워크 접근을 통제하는 역할에 가깝다면, WAF는 웹 애플리케이션을 대상으로 하는 공격을 탐지하고 차단하는 데 초점이 있다.</p>
<p>예를 들어 사용자가 웹사이트에 접속할 때 서버로 전달되는 요청에는 URL, 파라미터, 쿠키, 헤더와 같은 정보가 포함된다. WAF는 이러한 웹 요청 내용을 검사하여 악성 스크립트나 비정상적인 SQL 구문 등이 포함되어 있는지 확인할 수 있다.</p>
<p>최근 대부분의 웹사이트는 HTTPS를 사용하기 때문에 요청 내용이 암호화되어 전송된다. 이때 WAF가 SSL/TLS 종단 지점으로 구성되어 있다면, 암호화된 트래픽을 복호화한 뒤 HTTP 요청 내용을 검사할 수 있다. 이를 통해 일반 방화벽이 보기 어려운 웹 요청의 세부 내용을 분석할 수 있다.</p>
<p>즉, WAF의 핵심 역할은 <strong>웹 요청의 내용을 분석하여 웹 애플리케이션 공격을 탐지하고 차단하는 것</strong>이다.</p>
<hr>
<h2 id="3-일반-방화벽과-waf의-차이">3. 일반 방화벽과 WAF의 차이</h2>
<p>일반 방화벽과 WAF는 모두 트래픽을 허용하거나 차단할 수 있다는 점에서 비슷해 보일 수 있다. 하지만 판단하는 기준과 보호 대상이 다르다.</p>
<p>일반 방화벽은 주로 IP 주소, 포트 번호, 프로토콜 같은 네트워크 계층 정보를 기준으로 통신을 제어한다. 예를 들어 특정 IP에서 오는 요청을 차단하거나, 특정 포트만 허용하는 방식이다.</p>
<p>반면 WAF는 웹 요청의 내용을 더 자세히 확인한다. URL, 파라미터, 쿠키, 헤더, 요청 본문 등을 분석하여 웹 공격 패턴이 포함되어 있는지 판단한다.</p>
<table>
<thead>
<tr>
<th>구분</th>
<th>일반 방화벽</th>
<th>WAF</th>
</tr>
</thead>
<tbody><tr>
<td>의미</td>
<td>네트워크 방화벽</td>
<td>웹 애플리케이션 방화벽</td>
</tr>
<tr>
<td>작동 계층</td>
<td>주로 L3/L4 계층</td>
<td>주로 L7 계층</td>
</tr>
<tr>
<td>주요 기준</td>
<td>IP, 포트, 프로토콜</td>
<td>URL, 파라미터, 쿠키, 헤더, 요청 본문</td>
</tr>
<tr>
<td>보호 대상</td>
<td>네트워크 및 시스템 접근</td>
<td>웹 애플리케이션</td>
</tr>
<tr>
<td>주요 역할</td>
<td>허용되지 않은 네트워크 접근 차단</td>
<td>웹 공격 탐지 및 차단</td>
</tr>
<tr>
<td>대표 대응</td>
<td>불필요한 포트 차단</td>
<td>SQL Injection, XSS 등 웹 공격 차단</td>
</tr>
</tbody></table>
<p>정리하면, 일반 방화벽은 네트워크 접근을 통제하는 장비이고, WAF는 웹 애플리케이션 요청 내용을 분석해 웹 공격을 탐지하거나 차단하는 장비라고 볼 수 있다.</p>
<hr>
<h2 id="4-waf가-탐지하거나-차단할-수-있는-대표적인-공격">4. WAF가 탐지하거나 차단할 수 있는 대표적인 공격</h2>
<p>WAF는 웹 애플리케이션을 대상으로 하는 공격을 탐지하고 차단하는 데 사용된다. 대표적인 공격으로는 SQL Injection, XSS, 파일 업로드 공격 등이 있다.</p>
<h3 id="4-1-sql-injection">4-1. SQL Injection</h3>
<p>SQL Injection은 공격자가 입력값에 악성 SQL 구문을 삽입해 데이터베이스에 비정상적인 쿼리를 실행시키려는 공격이다. </p>
<p>WAF는 요청 파라미터에 비정상적인 SQL 패턴이 포함되어 있는지 확인하고, 공격으로 판단되면 차단할 수 있다.</p>
<h3 id="4-2-xss">4-2. XSS</h3>
<p>XSS는 <strong>Cross-Site Scripting</strong>의 약자로, 웹 페이지에 악성 스크립트를 삽입하는 공격이다.
공격자가 게시글, 댓글, 입력 폼 등에 스크립트를 삽입하면 다른 사용자의 브라우저에서 해당 스크립트가 실행될 수 있다. </p>
<p>WAF는 요청값에 스크립트 태그나 이벤트 핸들러처럼 의심스러운 패턴이 포함되어 있는지 검사할 수 있다.</p>
<h3 id="4-3-파일-업로드-공격">4-3. 파일 업로드 공격</h3>
<p>파일 업로드 기능이 있는 웹 서비스에서는 공격자가 악성 파일을 업로드하려고 시도할 수 있다.</p>
<p>예를 들어 웹쉘과 같은 악성 파일이 서버에 업로드되고 실행된다면, 공격자가 서버를 원격으로 조작할 위험이 있다.</p>
<p>WAF는 업로드 요청의 파일 확장자, Content-Type, 요청 패턴 등을 검사하여 비정상적인 업로드 시도를 탐지할 수 있다.</p>
<hr>
<h2 id="5-waf만-있으면-안전할까">5. WAF만 있으면 안전할까?</h2>
<p>WAF는 웹 공격을 탐지하고 차단하는 데 유용하지만, WAF만 있다고 해서 웹 서비스가 완전히 안전해지는 것은 아니다.</p>
<p>첫째, WAF는 설정된 정책이나 탐지 패턴을 기준으로 동작한다. 따라서 새로운 공격 기법이나 우회 기법이 사용되면 탐지하지 못할 수 있다.</p>
<p>둘째, 오탐이 발생할 수 있다. 정상적인 요청을 공격으로 잘못 판단해 차단할 수도 있고, 반대로 공격 요청을 정상 요청으로 판단할 수도 있다.</p>
<p>셋째, HTTPS 트래픽을 검사하려면 SSL/TLS 복호화 구성이 필요할 수 있다. 이 과정에서 인증서 관리, 복호화 구간의 보안, 성능 부담 등을 함께 고려해야 한다.</p>
<p>넷째, 애플리케이션 자체의 취약점이 해결되는 것은 아니다. WAF는 공격 요청을 막아주는 보안 장치이지만, 근본적으로 취약한 코드나 잘못된 인증·인가 로직을 수정해주는 것은 아니다.</p>
<p>따라서 WAF는 웹 애플리케이션 보안을 강화하는 중요한 장비이지만, 모든 공격을 완벽하게 막아주는 것은 아니므로 안전한 개발, 입력값 검증, 인증·인가 관리, 로그 모니터링, 취약점 점검 등과 함께 사용해야 한다.</p>
<hr>
<h2 id="6-정리">6. 정리</h2>
<p>WAF는 웹 애플리케이션을 대상으로 하는 공격을 탐지하고 차단하기 위한 보안 장비이다.</p>
<ul>
<li><strong>일반 방화벽</strong>: IP, 포트, 프로토콜 등을 기준으로 네트워크 접근을 통제한다.</li>
<li><strong>WAF</strong>: URL, 파라미터, 쿠키, 헤더, 요청 본문 등 HTTP/HTTPS 요청 내용을 분석해 웹 공격 여부를 판단한다.</li>
</ul>
<p>대표적으로 WAF는 SQL Injection, XSS, 파일 업로드 공격과 같은 웹 공격을 탐지하거나 차단하는 데 활용될 수 있다.</p>
<p>다만 WAF만으로 모든 웹 보안 문제를 해결할 수는 없다. WAF는 웹 공격을 줄이는 데 도움을 주는 보안 장비이지만, 안전한 코드 작성, 입력값 검증, 취약점 점검, 로그 모니터링과 함께 사용해야 더 효과적인 웹 보안 체계를 구성할 수 있다.</p>
<p>이번 글을 정리하면서 일반 방화벽과 WAF는 이름은 비슷하지만, 보호하는 대상과 판단 기준이 다르다는 점을 알 수 있었다. WAF는 웹 요청 내용을 분석해 웹 애플리케이션 공격을 줄이는 데 도움을 주는 보안 장비라고 이해할 수 있다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[IDS와 IPS의 차이]]></title>
            <link>https://velog.io/@jh_devlog/Security-IDS%EC%99%80-IPS%EC%9D%98-%EC%B0%A8%EC%9D%B4</link>
            <guid>https://velog.io/@jh_devlog/Security-IDS%EC%99%80-IPS%EC%9D%98-%EC%B0%A8%EC%9D%B4</guid>
            <pubDate>Thu, 18 Jun 2026 01:54:25 GMT</pubDate>
            <description><![CDATA[<h1 id="ids와-ips의-차이">IDS와 IPS의 차이</h1>
<h2 id="1-이-주제를-정리하게-된-이유">1. 이 주제를 정리하게 된 이유</h2>
<p>이전 글에서 방화벽의 역할에 대해 정리하면서, 방화벽은 네트워크 접근을 통제하는 중요한 보안 장치이지만 모든 공격을 막을 수는 없다는 점을 알게 되었다.</p>
<p>예를 들어 허용된 포트를 통해 들어오는 공격이나 정상적인 요청처럼 보이는 공격은 단순 방화벽 규칙만으로 탐지하기 어려울 수 있다.</p>
<p>그래서 방화벽과 함께 자주 언급되는 보안 장비가 <strong>IDS</strong>와 <strong>IPS</strong>이다. 두 용어는 이름도 비슷하고 모두 침입을 탐지한다는 공통점이 있어 헷갈리기 쉽다.</p>
<p>이번 글에서는 IDS와 IPS가 무엇인지, 그리고 두 장비가 어떤 차이가 있는지 정리해보려고 한다.</p>
<hr>
<h2 id="2-ids란">2. IDS란?</h2>
<p>IDS는 <strong>Intrusion Detection System</strong>의 약자로, 우리말로는 <strong>침입 탐지 시스템</strong>이라고 한다.</p>
<p>IDS는 네트워크나 시스템에서 발생하는 트래픽과 로그를 분석하여 비정상적인 행위나 공격 의심 행위를 탐지하는 역할을 한다.</p>
<p>예를 들어 특정 IP에서 짧은 시간 동안 여러 번 로그인 실패가 발생하거나, 알려진 공격 패턴과 유사한 요청이 감지된다면 IDS는 이를 이상 행위로 판단하고 관리자에게 알림을 보낼 수 있다.</p>
<p>IDS의 핵심은 <strong>탐지와 알림</strong>이다. 수상한 징후를 감시하고 알려주지만, 기본적으로 직접 트래픽을 차단하지는 않는다.</p>
<hr>
<h2 id="3-ips란">3. IPS란?</h2>
<p>IPS는 <strong>Intrusion Prevention System</strong>의 약자로, 우리말로는 <strong>침입 방지 시스템</strong>이라고 한다.</p>
<p>IPS는 IDS처럼 공격이나 이상 행위를 탐지하는 기능을 가지고 있다. 하지만 IDS와 달리 탐지한 공격을 차단하거나 패킷을 폐기하는 등 능동적인 대응까지 수행할 수 있다.</p>
<p>예를 들어 악성 트래픽이 탐지되면 IPS는 해당 트래픽을 차단하거나, 특정 IP의 접근을 막거나, 연결을 종료하는 방식으로 공격이 내부 시스템에 도달하지 못하게 할 수 있다.</p>
<p>IPS의 핵심은 <strong>탐지와 차단</strong>이다. 공격을 발견하는 것에서 그치지 않고, 공격이 실제 피해로 이어지지 않도록 중간에서 막는 역할을 한다.</p>
<hr>
<h2 id="4-ids와-ips의-차이">4. IDS와 IPS의 차이</h2>
<p><img src="https://velog.velcdn.com/images/jh_devlog/post/07a574a2-d863-4230-8ad7-e7db40c85b49/image.png" alt=""></p>
<blockquote>
<p>IDS는 일반적으로 통신 경로 바깥에서 복사된 트래픽을 분석하고, IPS는 통신 경로 중간에서 트래픽을 직접 검사하고 차단할 수 있다.</p>
</blockquote>
<p>IDS와 IPS는 모두 침입이나 이상 행위를 탐지한다는 공통점이 있다.
하지만 가장 큰 차이는 <strong>차단 기능의 유무</strong>와 <strong>네트워크 상의 배치 방식</strong>이다.</p>
<table>
<thead>
<tr>
<th>구분</th>
<th>IDS</th>
<th>IPS</th>
</tr>
</thead>
<tbody><tr>
<td>의미</td>
<td>침입 탐지 시스템</td>
<td>침입 방지 시스템</td>
</tr>
<tr>
<td>핵심 역할</td>
<td>탐지 및 알림</td>
<td>탐지 및 차단</td>
</tr>
<tr>
<td>배치 방식</td>
<td>Out-of-band</td>
<td>In-line</td>
</tr>
<tr>
<td>동작 방식</td>
<td>통신 경로 바깥에서 복사본 분석</td>
<td>실제 통신 경로 중간에서 검사 및 차단</td>
</tr>
<tr>
<td>장점</td>
<td>서비스 트래픽에 직접적인 영향을 주지 않음</td>
<td>공격을 실시간으로 차단 가능</td>
</tr>
<tr>
<td>주의점</td>
<td>차단은 별도 대응 필요</td>
<td>오탐 시 정상 트래픽도 차단될 수 있음</td>
</tr>
</tbody></table>
<p><strong>Out-of-band</strong>는 실제 통신 경로 바깥에서 복사된 트래픽을 분석하는 방식이고, <strong>In-line</strong>은 트래픽이 지나가는 경로 중간에 장비가 위치해 직접 검사하고 차단하는 방식이다.</p>
<p>쉽게 비유하면 IDS는 <strong>CCTV와</strong> 비슷하다. 수상한 행동을 발견하고 알려주지만, 직접 막지는 않는다.</p>
<p>반면 IPS는 <strong>출입 통제 시스템</strong>에 가깝다. 수상한 접근을 발견하면 알릴 뿐만 아니라, 필요에 따라 출입 자체를 막을 수 있다.</p>
<h3 id="4-1-idsips는-어떻게-공격을-탐지할까">4-1. IDS/IPS는 어떻게 공격을 탐지할까?</h3>
<p>IDS와 IPS는 공격을 탐지할 때 대표적으로 <strong>시그니처 기반 탐지</strong>와 <strong>이상 행위 기반 탐지</strong> 방식을 사용할 수 있다.</p>
<ul>
<li><p><strong>시그니처 기반 탐지</strong>
이미 알려진 공격 패턴을 기준으로 탐지하는 방식이다. 백신 프로그램이 악성코드 패턴을 비교해 탐지하는 것과 비슷하다.</p>
</li>
<li><p><strong>이상 행위 기반 탐지</strong>
평소와 다른 비정상적인 행위를 기준으로 탐지하는 방식이다. 예를 들어 로그인 실패가 갑자기 많아지거나 특정 트래픽이 급격히 증가하는 경우를 이상 행위로 볼 수 있다.</p>
</li>
</ul>
<hr>
<h2 id="5-ips가-있으면-ids는-필요-없을까">5. IPS가 있으면 IDS는 필요 없을까?</h2>
<p>IPS는 탐지뿐만 아니라 차단까지 수행할 수 있기 때문에, IDS보다 더 강력한 장비처럼 보일 수 있다. 하지만 IPS가 IDS를 완전히 대체한다고 보기는 어렵다.</p>
<p>IPS는 트래픽 경로 중간에 위치해 공격을 실시간으로 차단할 수 있다는 장점이 있다. 다만 오탐이 발생하면 정상 트래픽까지 차단될 수 있고, 장비 장애나 과부하가 발생하면 서비스 흐름에 영향을 줄 수 있다.</p>
<p>반면 IDS는 복사된 트래픽을 분석하므로 직접 차단은 어렵지만, 서비스 흐름에 영향을 주지 않고 이상 행위를 모니터링하는 데 유용하다.</p>
<p>따라서 IDS와 IPS는 우열 관계라기보다 <strong>역할이 다른 보안 장비</strong>라고 볼 수 있다. IPS는 차단에 강점이 있고, IDS는 탐지와 분석에 강점이 있기 때문에 실제 환경에서는 목적에 따라 함께 사용되기도 한다.</p>
<hr>
<h2 id="6-방화벽과-idsips는-어떻게-다를까">6. 방화벽과 IDS/IPS는 어떻게 다를까?</h2>
<p>방화벽, IDS, IPS는 모두 네트워크 보안을 위해 사용되지만 역할은 조금씩 다르다.</p>
<p>방화벽은 미리 정해진 규칙에 따라 트래픽의 통과 여부를 결정한다. (예: 특정 IP 차단, 특정 포트만 허용)</p>
<p>반면 IDS와 IPS는 단순히 IP나 포트만 보는 것이 아니라, 트래픽 내부의 패턴이나 행위 자체를 분석한다. 방화벽이 “22번 포트 접근을 허용할지”를 판단한다면, IDS/IPS는 “허용된 22번 포트 안에서 비정상적인 로그인 시도가 반복되는지”를 감시하는 식이다.</p>
<p>따라서 방화벽은 문지기 역할을 하는 접근 제어의 기본 장치이고, IDS/IPS는 문을 통과한 뒤의 이상 행위를 감시하고 대응하는 보완 장치라고 볼 수 있다.</p>
<hr>
<h2 id="7-정리">7. 정리</h2>
<p>IDS와 IPS는 모두 침입이나 이상 행위를 탐지하기 위한 보안 시스템이다.</p>
<blockquote>
<ul>
<li><strong>IDS</strong>: 네트워크나 시스템을 모니터링하며 이상 행위를 탐지하고 관리자에게 알림</li>
</ul>
</blockquote>
<ul>
<li><strong>IPS</strong>: 이상 행위를 탐지한 뒤 필요하면 실시간으로 트래픽을 차단</li>
</ul>
<p>이번 글을 정리하면서 방화벽, IDS, IPS는 모두 보안을 위한 장치이지만 각각의 역할이 다르다는 점을 알 수 있었다. 방화벽은 정해진 규칙으로 접근을 통제하고, IDS는 이상 행위를 탐지하며, IPS는 탐지한 공격을 차단한다.</p>
<p>따라서 실제 보안 환경에서는 하나의 장비만으로 모든 공격을 막기보다는, 여러 보안 장치를 함께 사용해 <strong>다층적인 방어 체계</strong>를 구성하는 것이 중요하다고 느꼈다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[HTTPS 사이트는 어떻게 차단될까? SNI 필드 차단 이해하기]]></title>
            <link>https://velog.io/@jh_devlog/Security-HTTPS-%EC%82%AC%EC%9D%B4%ED%8A%B8%EB%8A%94-%EC%96%B4%EB%96%BB%EA%B2%8C-%EC%B0%A8%EB%8B%A8%EB%90%A0%EA%B9%8C-SNI-%ED%95%84%EB%93%9C-%EC%B0%A8%EB%8B%A8-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@jh_devlog/Security-HTTPS-%EC%82%AC%EC%9D%B4%ED%8A%B8%EB%8A%94-%EC%96%B4%EB%96%BB%EA%B2%8C-%EC%B0%A8%EB%8B%A8%EB%90%A0%EA%B9%8C-SNI-%ED%95%84%EB%93%9C-%EC%B0%A8%EB%8B%A8-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0</guid>
            <pubDate>Wed, 17 Jun 2026 00:58:21 GMT</pubDate>
            <description><![CDATA[<h1 id="https-사이트는-어떻게-차단될까-sni-필드-차단-이해하기">HTTPS 사이트는 어떻게 차단될까? SNI 필드 차단 이해하기</h1>
<h2 id="1-이-주제를-정리하게-된-이유">1. 이 주제를 정리하게 된 이유</h2>
<p>최근 불법 사이트 긴급차단·접속차단 제도와 관련된 뉴스를 보면서, HTTPS 사이트는 어떤 방식으로 차단되는지 궁금해졌다.</p>
<p>HTTPS는 통신 내용이 암호화된다고 알고 있었기 때문에, 처음에는 “암호화된 사이트도 어떻게 차단할 수 있을까?”라는 의문이 들었다.</p>
<p>조사해보니 HTTPS 통신 내용 자체를 들여다보는 것이 아니라, TLS 연결 초기에 노출될 수 있는 SNI 정보를 이용해 차단할 수 있다는 것을 알게 되었다.</p>
<p>이번 글에서는 SNI가 무엇인지, 그리고 SNI 기반 차단이 어떤 원리로 동작하는지 간단히 정리해보려고 한다.</p>
<blockquote>
<p>참고 뉴스: <a href="https://www.etnews.com/20260510000040">https://www.etnews.com/20260510000040</a></p>
</blockquote>
<hr>
<h2 id="2-https는-모든-정보를-숨겨줄까">2. HTTPS는 모든 정보를 숨겨줄까?</h2>
<p>HTTPS는 <strong>HTTP에 TLS 암호화를 적용한 통신 방식</strong>이다. 사용자가 웹사이트와 주고받는 로그인 정보, 게시글 내용, 결제 정보 등은 암호화되어 보호된다.</p>
<p>하지만 HTTPS라고 해서 모든 정보가 완전히 숨겨지는 것은 아니다. 암호화 통신을 시작하기 전, 클라이언트와 서버는 먼저 TLS Handshake 과정을 거친다.</p>
<p>이 과정에서 클라이언트는 서버에 접속하기 위한 여러 정보를 전달하는데, 
TLS 연결 초기 단계에서는 사용자가 접속하려는 도메인 정보가 SNI 필드에 포함되어 암호화되지 않은 평문(Plaintext) 상태로 노출될 수 있다. </p>
<p>즉, HTTPS는 연결이 확립된 후 주고받는 데이터는 암호화하지만, 연결을 시작하는 과정에서 “어떤 도메인에 접속하려는지”에 대한 정보는 중간 네트워크 장비가 확인할 수 있다.</p>
<hr>
<h2 id="3-sni란-무엇인가">3. SNI란 무엇인가?</h2>
<p>SNI는 <strong>Server Name Indication</strong>의 약자로, 클라이언트가 TLS 연결을 시작할 때 접속하려는 서버 이름을 알려주는 기능이다.</p>
<p>하나의 IP 주소에서 여러 HTTPS 사이트를 운영하는 경우, 서버는 클라이언트가 어떤 도메인에 접속하려는지 알아야 적절한 인증서를 선택할 수 있다. 이때 사용되는 정보가 SNI이다.</p>
<p>예를 들어 같은 IP에서 아래 사이트들이 운영된다고 가정해보자.</p>
<ul>
<li>example.com</li>
<li>shop.example.com</li>
<li>blog.example.com</li>
</ul>
<p>서버는 SNI 값을 보고 클라이언트가 어떤 도메인에 접속하려는지 구분할 수 있다.</p>
<p>문제는 이 SNI 값이 TLS Handshake 단계에서 전달되기 때문에, 기존 TLS 환경에서는 암호화된 데이터 통신이 시작되기 전에 노출될 수 있다는 점이다.</p>
<hr>
<h2 id="4-sni-필드-차단은-어떻게-동작할까">4. SNI 필드 차단은 어떻게 동작할까?</h2>
<p>SNI 필드 차단은 TLS Handshake 초기에 보이는 SNI 값을 확인해, 접속하려는 도메인이 차단 대상인지 판단하는 방식이다.</p>
<p>흐름은 다음과 같다.</p>
<ol>
<li>사용자가 HTTPS 사이트에 접속한다.</li>
<li>브라우저가 서버와 TLS Handshake를 시작한다.</li>
<li>ClientHello 메시지에 SNI 값이 포함된다.</li>
<li>중간 네트워크 장비가 SNI 값을 확인한다.</li>
<li>차단 대상 도메인이면 연결을 차단한다.</li>
</ol>
<p>즉, SNI 차단은 사용자가 사이트에서 어떤 내용을 보는지 확인하는 것이 아니라, <strong>접속하려는 도메인 정보를 기준으로 차단하는 방식</strong>이다.</p>
<blockquote>
<p>📌 참고: SNI 노출을 줄이는 ECH(Encrypted ClientHello)</p>
<p>최근에는 SNI를 포함한 ClientHello 정보를 암호화하려는 ECH(Encrypted ClientHello) 기술도 등장했다. 
ECH가 적용되면 기존 TLS 환경에서 노출될 수 있었던 SNI 정보도 보호할 수 있다.</p>
</blockquote>
<hr>
<h2 id="5-정리">5. 정리</h2>
<p>HTTPS는 웹 통신 내용을 암호화해 보호하는 기술이다. 하지만 기존 TLS 환경에서는 연결 초기에 SNI 값이 노출될 수 있고, 이를 통해 사용자가 어떤 도메인에 접속하려는지 확인할 수 있다.</p>
<p>SNI 차단은 HTTPS 본문을 복호화하는 방식이 아니라, TLS Handshake 과정에서 보이는 SNI 값을 기준으로 접속을 차단하는 방식이다.</p>
<p>정리하면 다음과 같다.</p>
<ul>
<li>HTTPS는 사용자가 주고받는 실제 데이터를 암호화한다.</li>
<li>SNI는 클라이언트가 접속하려는 서버 이름을 알려주는 정보이다.</li>
<li>SNI 차단은 “내용 감청”이라기보다 “도메인 기반 차단”에 가깝다.</li>
</ul>
<p>이번 주제를 통해 HTTPS를 이해할 때는 단순히 “암호화되어 있다”는 사실만 볼 것이 아니라, 어떤 정보가 보호되고 어떤 정보가 노출될 수 있는지 구분해서 보는 것이 중요하다는 점을 알 수 있었다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[방화벽은 어떤 역할을 할까?]]></title>
            <link>https://velog.io/@jh_devlog/Security-%EB%B0%A9%ED%99%94%EB%B2%BD%EC%9D%80-%EC%96%B4%EB%96%A4-%EC%97%AD%ED%95%A0%EC%9D%84-%ED%95%A0%EA%B9%8C</link>
            <guid>https://velog.io/@jh_devlog/Security-%EB%B0%A9%ED%99%94%EB%B2%BD%EC%9D%80-%EC%96%B4%EB%96%A4-%EC%97%AD%ED%95%A0%EC%9D%84-%ED%95%A0%EA%B9%8C</guid>
            <pubDate>Mon, 15 Jun 2026 01:01:27 GMT</pubDate>
            <description><![CDATA[<h1 id="방화벽은-어떤-역할을-할까">방화벽은 어떤 역할을 할까?</h1>
<h2 id="1-이-주제를-정리하게-된-이유">1. 이 주제를 정리하게 된 이유</h2>
<p>이전 글에서 DoS와 DDoS, 정보보안의 3요소에 대해 정리하면서 서비스의 가용성과 접근 제어의 중요성을 알게 되었다.</p>
<p>보안에서 외부의 접근을 통제하는 대표적인 장치 중 하나가 방화벽이다. 방화벽이라는 용어는 자주 들어봤지만, 실제로 어떤 기준으로 트래픽을 허용하거나 차단하는지 명확히 알고 싶어 이번 글에서 정리해보려고 한다.</p>
<hr>
<h2 id="2-방화벽이란">2. 방화벽이란?</h2>
<p>방화벽은 네트워크를 오가는 트래픽을 확인하고, 정해진 보안 정책에 따라 허용하거나 차단하는 보안 장치이다.</p>
<p>쉽게 말하면 네트워크의 <strong>출입문</strong> 역할을 한다고 볼 수 있다.
외부에서 내부 시스템으로 들어오는 요청이나, 내부에서 외부로 나가는 통신을 확인한 뒤 허용할지 차단할지를 결정한다.</p>
<p>예를 들어 회사 내부 서버가 외부 인터넷과 연결되어 있다고 가정해보자. 모든 외부 요청을 그대로 허용하면 불필요한 접근이나 공격 시도가 내부 시스템까지 도달할 수 있다.</p>
<p>이때 방화벽은 미리 설정된 규칙에 따라 허용된 통신만 통과시키고, 허용되지 않은 통신은 차단한다.</p>
<p>즉, 방화벽의 핵심 역할은 <strong>네트워크 트래픽을 통제하여 내부 시스템을 보호하는 것</strong>이다.</p>
<hr>
<h2 id="3-방화벽은-무엇을-기준으로-허용하고-차단할까">3. 방화벽은 무엇을 기준으로 허용하고 차단할까?</h2>
<p>방화벽은 단순히 모든 통신을 막는 것이 아니라, 정해진 조건을 기준으로 트래픽을 허용하거나 차단한다.</p>
<p>이때 방화벽은 네트워크를 통과하는 데이터의 기본 단위인 <strong>패킷(Packet)</strong>의 정보를 확인한다.
패킷에는 출발지와 목적지, 사용되는 프로토콜, 포트 번호와 같은 정보가 포함되어 있다.</p>
<p>방화벽은 이러한 패킷의 헤더 정보를 바탕으로 통신을 허용할지 차단할지 판단한다.</p>
<table>
<thead>
<tr>
<th>기준</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td>출발지 IP</td>
<td>어떤 IP 주소에서 요청이 시작되었는지</td>
</tr>
<tr>
<td>목적지 IP</td>
<td>어떤 IP 주소로 요청이 향하는지</td>
</tr>
<tr>
<td>출발지 포트</td>
<td>요청을 보낸 쪽의 포트 번호</td>
</tr>
<tr>
<td>목적지 포트</td>
<td>어떤 서비스 포트로 접근하려는지</td>
</tr>
<tr>
<td>프로토콜</td>
<td>TCP, UDP, ICMP 등 어떤 통신 방식인지</td>
</tr>
</tbody></table>
<p>네트워크 보안에서는 위와 같은 기준 중 <strong>출발지 IP, 목적지 IP, 출발지 포트, 목적지 포트, 프로토콜</strong>을 묶어 <strong>5-Tuple</strong>이라고 부르기도 한다.</p>
<p>예를 들어 SSH는 보통 22번 포트를 사용한다.
외부에서 서버의 22번 포트로 접근하는 것을 허용하면 SSH 접속이 가능하지만, 차단하면 외부에서 SSH로 접속할 수 없다.</p>
<p>또 다른 예로 웹 서비스는 일반적으로 80번 포트와 443번 포트를 사용한다. 따라서 외부 사용자가 웹사이트에 접속해야 한다면 해당 포트에 대한 접근은 허용해야 한다.</p>
<p>이처럼 방화벽은 IP 주소, 포트 번호, 프로토콜 등을 기준으로 네트워크 접근을 제어한다.</p>
<hr>
<h2 id="4-방화벽의-주요-역할">4. 방화벽의 주요 역할</h2>
<h3 id="4-1-불필요한-접근-차단">4-1. 불필요한 접근 차단</h3>
<p>방화벽은 외부에서 내부 시스템으로 들어오는 불필요한 접근을 차단한다.</p>
<p>예를 들어 외부에서 접근할 필요가 없는 관리용 포트나 내부 서비스 포트를 차단하면, 공격자가 해당 서비스에 직접 접근하는 것을 줄일 수 있다.</p>
<h3 id="4-2-허용된-서비스만-접근-가능하게-제한">4-2. 허용된 서비스만 접근 가능하게 제한</h3>
<p>서버에서 웹 서비스를 운영한다면 일반적으로 80번 포트와 443번 포트만 외부에 공개할 수 있다.</p>
<p>반면 SSH와 같은 관리용 포트는 모든 IP에 열어두기보다, 특정 IP에서만 접근할 수 있도록 제한하는 것이 좋다.</p>
<p>이렇게 필요한 서비스만 열어두고 나머지는 차단하면 공격자가 접근할 수 있는 범위, 즉 <strong>공격 표면</strong>을 줄일 수 있다.</p>
<h3 id="4-3-내부망-보호">4-3. 내부망 보호</h3>
<p>방화벽은 외부 인터넷과 내부 시스템 사이에서 통신을 통제해 내부망을 보호한다.</p>
<p>외부의 모든 요청이 내부망으로 바로 들어오지 않도록 중간에서 통제하는 역할을 하며, 내부 시스템이 불필요하게 외부에 노출되는 것을 줄여준다.</p>
<h3 id="4-4-로그-기록">4-4. 로그 기록</h3>
<p>방화벽은 허용되거나 차단된 트래픽을 기록할 수 있다.</p>
<p>이 로그는 이후 보안 분석에 활용될 수 있다. 예를 들어 특정 IP에서 반복적으로 차단된 요청이 발생한다면, 비정상적인 접근 시도로 의심해볼 수 있다.</p>
<hr>
<h2 id="5-방화벽이-모든-공격을-막을-수-있을까">5. 방화벽이 모든 공격을 막을 수 있을까?</h2>
<p>방화벽은 네트워크 접근을 통제하는 중요한 보안 장치이지만, 모든 공격을 막을 수 있는 것은 아니다.</p>
<p>예를 들어 웹 서비스를 운영하려면 80번이나 443번 포트는 열어두어야 한다. 그런데 공격자가 허용된 웹 포트를 통해 SQL Injection과 같은 웹 공격을 시도한다면, 일반적인 L3/L4 방화벽만으로는 이를 탐지하거나 차단하기 어려울 수 있다.</p>
<p>쉽게 말해 일반적인 L3/L4 방화벽은 주로 <strong>출발지/목적지 IP, 포트, 프로토콜</strong> 같은 정보를 기준으로 통신을 판단한다.<br>비유하자면 편지의 <strong>봉투 정보</strong>는 확인할 수 있지만, 편지 안의 <strong>내용물</strong>까지 자세히 검사하는 데는 한계가 있는 것이다.</p>
<p>따라서 웹 공격이나 애플리케이션 취약점을 이용한 공격에 대응하기 위해서는 WAF, IDS, IPS, 로그 모니터링 등 다른 보안 장치와 함께 사용하는 것이 필요하다.</p>
<hr>
<h2 id="6-정리">6. 정리</h2>
<p>방화벽은 네트워크 트래픽을 확인하고, 보안 정책에 따라 허용하거나 차단하는 보안 장치이다.</p>
<table>
<thead>
<tr>
<th>구분</th>
<th>내용</th>
</tr>
</thead>
<tbody><tr>
<td>방화벽의 역할</td>
<td>네트워크 트래픽을 허용하거나 차단</td>
</tr>
<tr>
<td>판단 기준</td>
<td>IP 주소, 포트 번호, 프로토콜 등</td>
</tr>
<tr>
<td>주요 목적</td>
<td>불필요한 접근 차단, 내부망 보호</td>
</tr>
<tr>
<td>한계</td>
<td>허용된 통신 안에서 발생하는 공격은 별도 대응 필요</td>
</tr>
</tbody></table>
<blockquote>
<p>방화벽은 네트워크의 출입문처럼 트래픽을 통제하는 보안 장치이다. 다만 모든 공격을 막을 수는 없기 때문에, WAF, IDS, IPS, 로그 모니터링 등 다른 보안 장치와 함께 사용해야 한다.</p>
</blockquote>
<p>이번 글을 정리하면서 방화벽은 단순히 “막는 장치”가 아니라, 정해진 정책에 따라 필요한 통신은 허용하고 불필요한 접근은 차단하는 접근 제어 장치라는 점을 이해할 수 있었다.</p>
<p>또한 방화벽은 주로 패킷의 IP, 포트, 프로토콜 정보를 기준으로 통신을 판단하지만, 허용된 통신 안에서 발생하는 모든 공격까지 막을 수는 없다는 점도 알게 되었다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[정보보안의 3요소: 기밀성, 무결성, 가용성]]></title>
            <link>https://velog.io/@jh_devlog/Security-%EC%A0%95%EB%B3%B4%EB%B3%B4%EC%95%88%EC%9D%98-3%EC%9A%94%EC%86%8C-%EA%B8%B0%EB%B0%80%EC%84%B1-%EB%AC%B4%EA%B2%B0%EC%84%B1-%EA%B0%80%EC%9A%A9%EC%84%B1</link>
            <guid>https://velog.io/@jh_devlog/Security-%EC%A0%95%EB%B3%B4%EB%B3%B4%EC%95%88%EC%9D%98-3%EC%9A%94%EC%86%8C-%EA%B8%B0%EB%B0%80%EC%84%B1-%EB%AC%B4%EA%B2%B0%EC%84%B1-%EA%B0%80%EC%9A%A9%EC%84%B1</guid>
            <pubDate>Fri, 12 Jun 2026 00:55:00 GMT</pubDate>
            <description><![CDATA[<h1 id="정보보안의-3요소-기밀성-무결성-가용성">정보보안의 3요소: 기밀성, 무결성, 가용성</h1>
<h2 id="1-이-주제를-정리하게-된-이유">1. 이 주제를 정리하게 된 이유</h2>
<p>이전 글에서 DoS와 DDoS 공격에 대해 정리하면서, 두 공격이 서비스의 <strong>가용성</strong>을 위협한다는 내용을 다뤘다.</p>
<p>그런데 보안에서 말하는 가용성이 정확히 무엇인지 이해하려면, 정보보안의 기본 개념인 <strong>기밀성, 무결성, 가용성</strong>을 함께 알아둘 필요가 있다고 생각했다.</p>
<p>정보보안의 3요소는 보안 개념을 공부할 때 자주 등장하는 기본 개념이기 때문에, 이번 글에서는 각각의 의미를 간단히 정리해보려고 한다.</p>
<hr>
<h2 id="2-정보보안의-3요소란">2. 정보보안의 3요소란?</h2>
<p>정보보안의 3요소는 <strong>기밀성, 무결성, 가용성</strong>을 의미한다.</p>
<p>영어로는 각각 <strong>Confidentiality, Integrity, Availability</strong>라고 하며, 앞 글자를 따서 <strong>CIA Triad</strong>라고도 부른다.</p>
<ul>
<li><p><strong>기밀성(Confidentiality)</strong>
허가된 사람만 정보에 접근할 수 있어야 한다.</p>
</li>
<li><p><strong>무결성(Integrity)</strong>
정보가 허가 없이 변경되거나 훼손되지 않아야 한다.</p>
</li>
<li><p><strong>가용성(Availability)</strong>
필요한 순간에 정보나 서비스를 정상적으로 사용할 수 있어야 한다.</p>
</li>
</ul>
<p>즉, 정보보안은 단순히 정보를 숨기는 것만을 의미하지 않는다.
정보가 안전하게 보호되고, 변조되지 않으며, 필요할 때 정상적으로 사용할 수 있도록 보장하는 것까지 포함한다.</p>
<hr>
<h2 id="3-기밀성-허가된-사람만-접근할-수-있어야-한다">3. 기밀성: 허가된 사람만 접근할 수 있어야 한다</h2>
<p><strong>기밀성</strong>은 허가된 사람만 정보에 접근할 수 있도록 보호하는 것을 의미한다.</p>
<p>예를 들어 개인정보, 비밀번호, 기업 내부 문서, 고객 정보와 같은 데이터는 아무나 볼 수 있어서는 안 된다. 권한이 없는 사용자가 이러한 정보에 접근한다면 기밀성이 침해된 것이다.</p>
<p>기밀성을 지키기 위한 방법으로는 다음과 같은 것들이 있다.</p>
<ul>
<li>로그인 인증</li>
<li>접근 권한 설정</li>
<li>암호화</li>
<li>계정 및 권한 관리</li>
<li>중요 정보 마스킹</li>
</ul>
<p>예를 들어 관리자만 볼 수 있어야 하는 페이지에 일반 사용자가 접근할 수 있다면, 이는 기밀성 측면에서 문제가 될 수 있다.</p>
<p>기밀성의 핵심은 <strong>정보를 볼 수 있는 사람을 제한하는 것</strong>이다.</p>
<p>이러한 관점에서 개인정보 유출 사고는 대표적인 기밀성 침해 사례로 볼 수 있다. 허가되지 않은 주체가 개인정보에 접근하거나 정보가 외부로 노출되는 것은, 허가된 사람만 정보에 접근할 수 있어야 한다는 기밀성 원칙이 지켜지지 않은 경우이기 때문이다.</p>
<hr>
<h2 id="4-무결성-데이터가-변조되지-않아야-한다">4. 무결성: 데이터가 변조되지 않아야 한다</h2>
<p><strong>무결성</strong>은 정보가 허가 없이 변경되거나 삭제되지 않고, 정확한 상태를 유지하는 것을 의미한다.</p>
<p>데이터는 저장되거나 전송되는 과정에서 의도치 않게 손상될 수도 있고, 공격자에 의해 악의적으로 변경될 수도 있다. 이때 데이터가 원래 상태와 다르게 바뀐다면 무결성이 침해된 것이다.</p>
<p>예를 들어 사용자의 계좌 잔액이 임의로 변경되거나, 게시글 내용이 누군가에 의해 몰래 수정된다면 무결성 문제가 발생한 것이다.</p>
<p>무결성을 지키기 위한 방법으로는 다음과 같은 것들이 있다.</p>
<ul>
<li>데이터 변경 권한 관리</li>
<li>로그 기록</li>
<li>해시 값 검증</li>
<li>전자서명</li>
<li>백업 및 복구 체계</li>
</ul>
<p>무결성의 핵심은 <strong>정보가 허가 없이 바뀌지 않도록 보호하는 것</strong>이다.</p>
<hr>
<h2 id="5-가용성-필요할-때-서비스를-사용할-수-있어야-한다">5. 가용성: 필요할 때 서비스를 사용할 수 있어야 한다</h2>
<p><strong>가용성</strong>은 사용자가 필요할 때 정보나 서비스를 정상적으로 사용할 수 있도록 보장하는 것을 의미한다.</p>
<p>아무리 정보가 안전하게 보호되고 변조되지 않더라도, 정작 필요할 때 서비스를 사용할 수 없다면 보안이 잘 지켜지고 있다고 보기 어렵다.</p>
<p>예를 들어 웹사이트에 접속해야 하는데 서버가 다운되어 접속할 수 없거나, 시스템 장애로 인해 업무 서비스를 사용할 수 없는 상황은 가용성에 문제가 생긴 것이다.</p>
<p>가용성을 지키기 위한 방법으로는 다음과 같은 것들이 있다.</p>
<ul>
<li>서버 이중화</li>
<li>백업 시스템 구성</li>
<li>장애 대응 체계 마련</li>
<li>트래픽 모니터링</li>
<li>DDoS 대응 장비 또는 서비스 활용</li>
</ul>
<p>가용성의 핵심은 <strong>필요할 때 서비스를 정상적으로 사용할 수 있도록 하는 것</strong>이다.</p>
<hr>
<h2 id="6-정리">6. 정리</h2>
<p>정보보안의 3요소를 표로 정리하면 다음과 같다.</p>
<table>
<thead>
<tr>
<th>구분</th>
<th>의미</th>
<th>예시</th>
</tr>
</thead>
<tbody><tr>
<td>기밀성</td>
<td>허가된 사람만 정보에 접근할 수 있어야 한다</td>
<td>권한 없는 사용자가 개인정보를 볼 수 없도록 제한</td>
</tr>
<tr>
<td>무결성</td>
<td>정보가 허가 없이 변경되거나 훼손되지 않아야 한다</td>
<td>계좌 잔액이나 게시글 내용이 임의로 변경되지 않도록 보호</td>
</tr>
<tr>
<td>가용성</td>
<td>필요할 때 정보나 서비스를 정상적으로 사용할 수 있어야 한다</td>
<td>서버 장애나 DDoS 공격으로 서비스가 중단되지 않도록 대응</td>
</tr>
</tbody></table>
<blockquote>
<p>기밀성은 정보에 접근할 수 있는 사람을 제한하는 것, 무결성은 정보를 정확한 상태로 유지하는 것, 가용성은 서비스를 정상적으로 사용할 수 있게 하는 것이라고 이해할 수 있다.</p>
</blockquote>
<p>이번 글을 정리하면서 정보보안은 단순히 정보를 외부로부터 숨기는 것만을 의미하지 않는다는 점을 알 수 있었다.</p>
<p>정보가 허가된 사용자에게만 제공되고, 정확한 상태로 유지되며, 필요할 때 정상적으로 사용할 수 있어야 한다는 점에서 기밀성, 무결성, 가용성은 정보보안의 기본 기준이라고 느꼈다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[DoS와 DDoS는 무엇이 다를까?]]></title>
            <link>https://velog.io/@jh_devlog/Security-DoS%EC%99%80-DDoS%EB%8A%94-%EB%AC%B4%EC%97%87%EC%9D%B4-%EB%8B%A4%EB%A5%BC%EA%B9%8C</link>
            <guid>https://velog.io/@jh_devlog/Security-DoS%EC%99%80-DDoS%EB%8A%94-%EB%AC%B4%EC%97%87%EC%9D%B4-%EB%8B%A4%EB%A5%BC%EA%B9%8C</guid>
            <pubDate>Thu, 11 Jun 2026 13:23:03 GMT</pubDate>
            <description><![CDATA[<h1 id="dos와-ddos는-무엇이-다를까">DoS와 DDoS는 무엇이 다를까?</h1>
<h2 id="1-이-주제를-정리하게-된-이유">1. 이 주제를 정리하게 된 이유</h2>
<p>시큐리티 아카데미 면접에서 “DoS와 DDoS의 차이가 무엇인가요?”라는 질문을 받은 적이 있다.</p>
<p>DDoS는 뉴스나 보안 관련 기사에서 자주 들어본 개념이라 어느 정도 익숙했지만, DoS가 정확히 무엇인지, 그리고 DoS와 DDoS가 어떤 차이가 있는지는 명확하게 설명하기 어려웠다.</p>
<p>그래서 이번 글에서는 DoS와 DDoS의 개념과 차이를 정리해보려고 한다.</p>
<hr>
<h2 id="2-dos란-무엇인가">2. DoS란 무엇인가</h2>
<p>DoS는 <strong>Denial of Service</strong>의 약자로, 우리말로는 <strong>서비스 거부 공격</strong>이라고 한다.</p>
<p>DoS 공격은 특정 서버나 서비스에 과도한 요청을 보내거나 시스템 자원을 소모시켜, 정상적인 사용자가 서비스를 이용하지 못하게 만드는 공격이다.</p>
<p>예를 들어 하나의 시스템에서 특정 웹 서버에 계속해서 많은 요청을 보내면, 서버는 요청을 처리하느라 자원을 사용하게 된다. 이 과정에서 서버가 정상적인 요청을 처리하지 못하면 서비스 지연이나 장애가 발생할 수 있다.</p>
<p>즉, DoS의 핵심은 <strong>서비스의 정상적인 이용을 방해하는 것</strong>이다.</p>
<hr>
<h2 id="3-ddos란-무엇인가">3. DDoS란 무엇인가</h2>
<p>DDoS는 <strong>Distributed Denial of Service</strong>의 약자로, 우리말로는 <strong>분산 서비스 거부 공격</strong>이라고 한다.</p>
<p>DDoS는 DoS 공격이 여러 대의 시스템에서 동시에 발생하는 형태라고 볼 수 있다. 공격자는 여러 시스템을 동원해 대상 서버나 네트워크에 대량의 트래픽을 발생시키고, 이를 통해 서비스를 마비시키려고 한다.</p>
<p>DoS가 단일 출발지에서 발생하는 공격에 가깝다면, DDoS는 여러 출발지에서 동시에 발생하는 분산 공격이다.</p>
<p>따라서 DDoS는 공격 규모가 더 크고, 여러 IP에서 요청이 들어오기 때문에 탐지와 차단이 더 어렵다.</p>
<hr>
<h2 id="4-dos와-ddos의-차이">4. DoS와 DDoS의 차이</h2>
<p>DoS와 DDoS는 모두 정상적인 서비스 이용을 방해한다는 점에서는 같다.</p>
<p>하지만 가장 큰 차이는 <strong>공격에 동원되는 시스템의 수</strong>와 <strong>공격 출발지</strong>이다.</p>
<p>DoS는 보통 하나의 시스템 또는 단일 출발지에서 공격이 발생한다. 반면 DDoS는 여러 대의 시스템이 동시에 공격에 참여하기 때문에 트래픽 규모가 더 크고 방어가 어렵다.</p>
<p>정리하면, <strong>DDoS는 DoS의 분산 형태</strong>라고 이해할 수 있다.</p>
<hr>
<h2 id="5-왜-ddos가-더-대응하기-어려운가">5. 왜 DDoS가 더 대응하기 어려운가</h2>
<p>DDoS가 DoS보다 대응하기 어려운 이유는 공격 트래픽이 여러 곳에서 동시에 발생하기 때문이다.</p>
<p>DoS처럼 단일 IP에서 비정상적인 요청이 반복된다면, 해당 IP를 차단하는 방식으로 어느 정도 대응할 수 있다. 하지만 DDoS는 여러 IP에서 대량의 요청이 동시에 들어오기 때문에 특정 IP 하나만 차단해서는 공격을 막기 어렵다.</p>
<p>또한 여러 출발지에서 요청이 발생하다 보니, 어떤 요청이 정상 사용자 요청이고 어떤 요청이 공격 트래픽인지 구분하기도 쉽지 않다.</p>
<p>결국 DDoS 공격은 서버나 네트워크 자원을 빠르게 소모시켜 서비스 지연이나 장애를 유발할 수 있다. 이처럼 DoS와 DDoS는 시스템의 기밀성이나 무결성보다, 사용자가 서비스를 정상적으로 이용할 수 있는지와 관련된 <strong>가용성을 위협하는 공격</strong>이라고 볼 수 있다.</p>
<hr>
<h2 id="6-정리">6. 정리</h2>
<p>DoS와 DDoS의 주요 차이를 표로 정리하면 다음과 같다.</p>
<table>
<thead>
<tr>
<th>구분</th>
<th>DoS</th>
<th>DDoS</th>
</tr>
</thead>
<tbody><tr>
<td>의미</td>
<td>서비스 거부 공격</td>
<td>분산 서비스 거부 공격</td>
</tr>
<tr>
<td>공격 출발지</td>
<td>단일 시스템 또는 단일 출발지</td>
<td>여러 대의 분산된 시스템</td>
</tr>
<tr>
<td>공격 방식</td>
<td>한 곳에서 자원 소모 유발</td>
<td>여러 곳에서 동시에 자원 소모 유발</td>
</tr>
<tr>
<td>공격 규모</td>
<td>상대적으로 작음</td>
<td>상대적으로 큼</td>
</tr>
<tr>
<td>탐지/차단</td>
<td>상대적으로 쉬움</td>
<td>더 어려움</td>
</tr>
<tr>
<td>영향</td>
<td>서비스 지연 또는 마비</td>
<td>대규모 서비스 장애 가능</td>
</tr>
</tbody></table>
<blockquote>
<p>핵심은 DoS는 단일 출발지에서 발생하는 서비스 거부 공격이고, DDoS는 여러 출발지에서 동시에 발생하는 분산 서비스 거부 공격이라는 점이다.</p>
</blockquote>
<p>이번 글을 정리하면서 DDoS가 DoS의 확장된 형태라는 점을 이해할 수 있었다. 단순히 용어를 외우는 것보다, 공격이 어떤 방식으로 발생하고 서비스에 어떤 영향을 주는지 함께 이해하는 것이 중요하다고 느꼈다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Java] 코딩 테스트 개념 정리: 스택/큐]]></title>
            <link>https://velog.io/@jh_devlog/Java-%EC%BD%94%EB%94%A9-%ED%85%8C%EC%8A%A4%ED%8A%B8-%EA%B0%9C%EB%85%90-%EC%A0%95%EB%A6%AC-%EC%8A%A4%ED%83%9D%ED%81%90</link>
            <guid>https://velog.io/@jh_devlog/Java-%EC%BD%94%EB%94%A9-%ED%85%8C%EC%8A%A4%ED%8A%B8-%EA%B0%9C%EB%85%90-%EC%A0%95%EB%A6%AC-%EC%8A%A4%ED%83%9D%ED%81%90</guid>
            <pubDate>Sat, 17 Jan 2026 08:19:03 GMT</pubDate>
            <description><![CDATA[<h2 id="1-스택큐-개념">1. 스택/큐 개념?</h2>
<h3 id="1-1-스택">1-1. 스택</h3>
<ul>
<li><strong>LIFO (Last-In, First-Out)</strong>: 나중에 들어온 데이터가 먼저 나가는 “후입선출” 구조</li>
<li><strong>비유</strong>: 접시 더미에서 가장 위 접시부터 꺼내는 것</li>
<li><strong>활용</strong>: 뒤로 가기(Undo), 괄호 짝 맞추기, 재귀 함수 호출 관리, DFS(깊이 우선 탐색) 등</li>
</ul>
<h3 id="1-2-큐">1-2. 큐</h3>
<ul>
<li><strong>FIFO (First-In, First-Out)</strong>: 먼저 들어온 데이터가 먼저 나가는 “선입선출” 구조</li>
<li><strong>비유</strong>: 은행 창구 줄서기</li>
<li><strong>활용</strong>: 프린터 출력 대기열, 은행 창구 업무, 작업/프로세스 스케줄링, BFS(너비 우선 탐색) 등</li>
</ul>
<blockquote>
<p><strong>원형 큐(Circular Queue)</strong>란 ?
일반적인 선형 큐(배열 기반)는 dequeue 할 때 앞부분이 비게 됩니다. 이 빈 공간을 재사용하려면 데이터를 앞으로 당기는 작업(shift, O(n))이 필요할 수 있는데, 이를 해결하기 위해 배열의 끝과 시작이 연결된 것처럼 인덱스를 순환시키는 구조가 원형 큐입니다.</p>
</blockquote>
<ul>
<li>참고: Java의 <code>ArrayDeque</code>는 내부적으로 <strong>원형(서큘러 버퍼) + 자동 리사이즈</strong> 방식이라, 코딩 테스트에서는 별도로 원형 큐를 구현할 일이 거의 없습니다.</li>
</ul>
<h3 id="1-3-시간복잡도">1-3. 시간복잡도</h3>
<p>스택과 큐는 데이터의 입구/출구가 정해져 있어 성능이 매우 뛰어납니다.</p>
<table>
<thead>
<tr>
<th>연산</th>
<th align="right">시간 복잡도</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td>삽입 (Push/Offer)</td>
<td align="right">O(1)</td>
<td>끝(또는 위)에 추가 <em>(평균/분할 상환)</em></td>
</tr>
<tr>
<td>삭제 (Pop/Poll)</td>
<td align="right">O(1)</td>
<td>정해진 위치에서 제거</td>
</tr>
<tr>
<td>조회 (Peek)</td>
<td align="right">O(1)</td>
<td>제거 없이 가장 앞/위 확인</td>
</tr>
<tr>
<td>탐색 (Search)</td>
<td align="right">O(n)</td>
<td>특정 값 찾으려면 전체 순회 필요</td>
</tr>
</tbody></table>
<hr>
<h2 id="2-java에서-스택큐-다루기">2. Java에서 스택/큐 다루기</h2>
<h3 id="2-1-생성-및-초기화">2-1. 생성 및 초기화</h3>
<pre><code class="language-java">import java.util.*;

// 스택(LIFO)
Stack&lt;Integer&gt; stack1 = new Stack&lt;&gt;();
Deque&lt;Integer&gt; stack2 = new ArrayDeque&lt;&gt;();

// 큐(FIFO)
Queue&lt;Integer&gt; queue = new ArrayDeque&lt;&gt;();</code></pre>
<ul>
<li>스택처럼 쓸 때: <code>push / pop / peek</code></li>
<li>큐처럼 쓸 때: <code>offer / poll / peek</code> </li>
<li>Deque를 큐로 더 명시적으로 쓰고 싶으면: <code>addLast / pollFirst / peekFirst</code></li>
</ul>
<blockquote>
<p>Java의 <code>Stack</code> 클래스는 내부적으로 <code>Vector</code>를 상속받아 만들어졌고, 많은 메서드가 <code>synchronized</code> 기반이라 코딩 테스트처럼 단일 스레드 환경에서는 불필요한 오버헤드가 생길 수 있습니다. 그래서 보통 <code>ArrayDeque(Deque)</code> 를 스택/큐로 활용하는 것을 추천합니다.</p>
</blockquote>
<h3 id="2-2-자주-쓰는-유틸">2-2. 자주 쓰는 유틸</h3>
<ul>
<li><code>size()</code>: 현재 데이터 개수 확인</li>
<li><code>isEmpty()</code>: 비어있는지 확인 (pop/poll 전 필수)</li>
<li><code>clear()</code>: 전체 초기화</li>
</ul>
<hr>
<h2 id="3-기본-메서드">3. 기본 메서드</h2>
<h3 id="3-1-스택-메서드">3-1. 스택 메서드</h3>
<table>
<thead>
<tr>
<th>기능</th>
<th>메서드</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td>삽입</td>
<td><code>push(e)</code></td>
<td>맨 위에 요소 추가</td>
</tr>
<tr>
<td>삭제</td>
<td><code>pop()</code></td>
<td>맨 위 요소 제거 후 반환 <strong>(비어있으면 예외 발생)</strong></td>
</tr>
<tr>
<td>확인</td>
<td><code>peek()</code></td>
<td>제거 없이 맨 위 요소 확인</td>
</tr>
</tbody></table>
<h3 id="3-2-큐-메서드">3-2. 큐 메서드</h3>
<table>
<thead>
<tr>
<th>기능</th>
<th>메서드</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td>삽입</td>
<td><code>offer(e)</code></td>
<td>큐 뒤에 추가 <strong>(실패 시 false)</strong></td>
</tr>
<tr>
<td>삭제</td>
<td><code>poll()</code></td>
<td>큐 앞 요소 제거 후 반환 <strong>(비어있으면 null)</strong></td>
</tr>
<tr>
<td>확인</td>
<td><code>peek()</code></td>
<td>제거 없이 맨 앞 요소 확인</td>
</tr>
</tbody></table>
<h3 id="3-3-비었을-때-동작">3-3. 비었을 때 동작</h3>
<ul>
<li><strong>예외 발생 계열</strong>: <code>pop</code>, <code>remove</code>, <code>element</code> → 비어있으면 예외</li>
<li><strong>null 반환 계열(Queue/Deque)</strong>: <code>poll</code>, <code>peek</code> → 비어있으면 <code>null</code></li>
<li>(참고) <code>Stack</code> 클래스의 <code>pop()/peek()</code> 는 비어있으면 <code>EmptyStackException</code></li>
</ul>
<hr>
<h2 id="4-대표-패턴-및-실전-예제">4. 대표 패턴 및 실전 예제</h2>
<p>코딩 테스트에서 스택과 큐가 어떻게 쓰이는지, 가장 자주 나오는 패턴의 템플릿입니다.</p>
<h3 id="4-1-괄호-검사-stack">4-1. 괄호 검사 (Stack)</h3>
<p>문자열을 순회하며 짝이 맞는지 확인하는 전형적인 스택 문제입니다.</p>
<pre><code class="language-java">public boolean isValid(String s) {
    Deque&lt;Character&gt; stack = new ArrayDeque&lt;&gt;();
    for (char c : s.toCharArray()) {
        if (c == &#39;(&#39;) stack.push(&#39;)&#39;);
        else if (c == &#39;{&#39;) stack.push(&#39;}&#39;);
        else if (c == &#39;[&#39;) stack.push(&#39;]&#39;);
        else if (stack.isEmpty() || stack.pop() != c) return false;
    }
    return stack.isEmpty();
}</code></pre>
<h3 id="4-2-bfs-탐색-queue">4-2. BFS 탐색 (Queue)</h3>
<p>최단 거리나 인접 노드 탐색 시 사용되는 기본 구조입니다.</p>
<pre><code class="language-java">public void bfs(int startNode) {
    Queue&lt;Integer&gt; queue = new ArrayDeque&lt;&gt;();
    queue.offer(startNode);
    visited[startNode] = true;

    while (!queue.isEmpty()) {
        int curr = queue.poll();
        for (int next : adj[curr]) {
            if (!visited[next]) {
                visited[next] = true;
                queue.offer(next);
            }
        }
    }
}</code></pre>
<h3 id="4-3-우선순위-큐-priorityqueue">4-3. 우선순위 큐 (PriorityQueue)</h3>
<p>들어온 순서가 아니라 <strong>우선순위(값의 크기 등)</strong>에 따라 데이터가 나가는 자료구조입니다.
“가장 작은 값/큰 값”을 계속 뽑아야 할 때 유용합니다. (최소힙/최대힙)</p>
<pre><code class="language-java">// 최소 힙 (오름차순)
PriorityQueue&lt;Integer&gt; minHeap = new PriorityQueue&lt;&gt;();

// 최대 힙 (내림차순)
PriorityQueue&lt;Integer&gt; maxHeap = new PriorityQueue&lt;&gt;(Collections.reverseOrder());</code></pre>
<h3 id="4-4-요세푸스-문제-queuedeque">4-4. 요세푸스 문제 (Queue/Deque)</h3>
<p>큐의 <strong>회전(Rotate)</strong> 성질을 이용한 대표적인 문제입니다. 
$N$명의 사람이 원형으로 앉아 있을 때, $K$번째 사람을 계속해서 제거하는 로직입니다.</p>
<pre><code class="language-java">public List&lt;Integer&gt; josephus(int n, int k) {
    Deque&lt;Integer&gt; queue = new ArrayDeque&lt;&gt;();
    List&lt;Integer&gt; result = new ArrayList&lt;&gt;();

    // 1. 큐 초기화 (1번부터 N번까지)
    for (int i = 1; i &lt;= n; i++) queue.addLast(i);

    // 2. 큐가 빌 때까지 반복
    while (!queue.isEmpty()) {
        // K-1번 동안 맨 앞의 요소를 뒤로 보냄
        for (int i = 0; i &lt; k - 1; i++) {
            queue.addLast(queue.pollFirst());
        }
        // K번째 요소를 제거하고 결과 리스트에 추가
        result.add(queue.pollFirst());
    }
    return result;
}</code></pre>
<hr>
<h2 id="5-주의사항">5. 주의사항</h2>
<ol>
<li><p><strong>Empty Check</strong></p>
<ul>
<li><code>poll()/peek()</code>는 비어있을 때 <code>null</code>을 반환</li>
<li><code>pop()/remove()</code>는 비어있을 때 예외 발생
 → 코딩 테스트에서는 안전하게 <code>isEmpty()</code>로 먼저 확인하거나, <code>poll/peek</code> 계열을 선호하는 편이 좋습니다.</li>
</ul>
</li>
<li><p><strong>null 처리</strong></p>
<ul>
<li><code>poll()</code>이나 <code>peek()</code> 반환값은 비어있으면 <code>null</code></li>
<li>기본 타입 <code>int</code>에는 <code>null</code>을 담을 수 없으니 <code>Integer</code>로 받거나, <code>isEmpty()</code>로 먼저 검사하세요.</li>
</ul>
</li>
<li><p><strong>ArrayDeque vs LinkedList</strong></p>
<ul>
<li>단순 삽입/삭제만 반복하는 큐/스택 용도라면 보통 <code>ArrayDeque</code>가 더 빠르고 메모리 효율적입니다.</li>
<li><code>LinkedList</code>는 노드 객체가 많아져 오버헤드가 생길 수 있습니다.</li>
<li><code>ArrayDeque</code>는 null 요소를 허용하지 않습니다. (<code>offer(null)</code> 같은 것 금지)</li>
</ul>
</li>
</ol>
<hr>
<h2 id="마무리">마무리</h2>
<p>오늘은 알고리즘의 기초인 스택과 큐에 대하여 정리해 보았습니다.
공부하다 보면 구현 그 자체보다 <strong>&#39;이 문제에 왜 이 자료구조를 써야 하지?&#39;</strong>를 고민하는 게 가장 어려운 것 같습니다.
아직 어렵지만 문제를 많이 풀다보면, 적절한 자료구조를 찾는 것도 익숙해지지 않을까 싶습니다.☺️
다음 포스팅은 해시(Hash) 관련 내용을 정리해보겠습니다.🔥</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Java] 코딩 테스트 개념 정리: 배열(Array)]]></title>
            <link>https://velog.io/@jh_devlog/Java-%EC%BD%94%EB%94%A9-%ED%85%8C%EC%8A%A4%ED%8A%B8-%EA%B0%9C%EB%85%90-%EC%A0%95%EB%A6%AC-%EB%B0%B0%EC%97%B4Array</link>
            <guid>https://velog.io/@jh_devlog/Java-%EC%BD%94%EB%94%A9-%ED%85%8C%EC%8A%A4%ED%8A%B8-%EA%B0%9C%EB%85%90-%EC%A0%95%EB%A6%AC-%EB%B0%B0%EC%97%B4Array</guid>
            <pubDate>Thu, 08 Jan 2026 06:38:53 GMT</pubDate>
            <description><![CDATA[<h2 id="1-배열이-뭔데">1. 배열이 뭔데?</h2>
<h3 id="1-1-배열의-핵심-특징">1-1. 배열의 핵심 특징</h3>
<p><img src="https://velog.velcdn.com/images/jh_devlog/post/5a0f31f8-3c35-4ca1-9c23-41cf529cc854/image.png" alt=""></p>
<p>배열은 <strong>연속된 메모리 공간</strong>에 동일한 타입의 데이터를 순차적으로 저장하는 자료구조입니다.</p>
<ul>
<li><strong>고정 크기</strong>: 생성 시 크기를 지정하며, 한 번 정해진 크기는 변경할 수 없습니다.</li>
<li><strong>인덱스 접근</strong>: 0부터 시작하는 인덱스를 통해 데이터에 직접 접근하므로 속도가 매우 빠릅니다.</li>
<li><strong>논리적 순서 = 물리적 순서</strong>: 메모리 상에 데이터가 붙어 있어 CPU 캐시 효율이 좋습니다.</li>
</ul>
<h3 id="1-2-시간-복잡도">1-2. 시간 복잡도</h3>
<table>
<thead>
<tr>
<th>연산</th>
<th align="right">시간 복잡도</th>
<th>이유</th>
</tr>
</thead>
<tbody><tr>
<td>인덱스로 접근/수정 (<code>arr[i]</code>)</td>
<td align="right"><strong>O(1)</strong></td>
<td>주소 계산으로 바로 접근</td>
</tr>
<tr>
<td>전체 순회 (<code>for</code>)</td>
<td align="right"><strong>O(n)</strong></td>
<td>모든 원소를 한 번씩 확인</td>
</tr>
<tr>
<td>값 탐색(선형 탐색)</td>
<td align="right"><strong>O(n)</strong></td>
<td>최악의 경우 끝까지 확인 필요</td>
</tr>
<tr>
<td>정렬 (<code>Arrays.sort</code>)</td>
<td align="right">평균 <strong>O(n log n)</strong></td>
<td>비교 기반 정렬</td>
</tr>
<tr>
<td>중간 삽입/삭제(shift 발생)</td>
<td align="right"><strong>O(n)</strong></td>
<td>요소들을 한 칸씩 밀거나 당김</td>
</tr>
</tbody></table>
<blockquote>
<p>코테에서 “삽입/삭제가 자주 발생”한다면 배열 말고 다른 구조(<code>ArrayList</code>, <code>Deque</code>, <code>LinkedList</code> 등)도 같이 고려하는 게 좋습니다.</p>
</blockquote>
<hr>
<h2 id="2-java에서-배열-다루기">2. Java에서 배열 다루기</h2>
<h3 id="2-1-생성-및-초기화">2-1. 생성 및 초기화</h3>
<pre><code class="language-java">import java.util.Arrays;

int[] arr1 = new int[5];          // 0으로 초기화
int[] arr2 = {1, 2, 3, 4, 5};     // 선언과 동시에 초기화

Arrays.fill(arr1, -1);            // 특정 값으로 채우기
</code></pre>
<h3 id="2-2-자주-쓰는-유틸-javautilarrays">2-2. 자주 쓰는 유틸 (java.util.Arrays)</h3>
<ul>
<li>정렬: <code>Arrays.sort(arr);</code> </li>
<li>복사: <code>Arrays.copyOf(arr, newLength);</code> (새로운 배열 객체 생성)</li>
<li>출력: <code>Arrays.toString(arr);</code></li>
<li>리스트 변환: <code>Arrays.asList(arr);</code> (<strong>객체 배열</strong>일 때만 기대한 대로 동작)</li>
</ul>
<h3 id="2-3-다차원-배열-2차원">2-3. 다차원 배열 (2차원)</h3>
<p><img src="https://velog.velcdn.com/images/jh_devlog/post/2f0b70d5-b23b-49d9-9af4-0e6e128f7504/image.png" alt=""></p>
<p>2차원 배열에서는 <code>arr[row][col]</code> 순서(행 → 열)를 헷갈리지 않도록 주의해야 합니다. </p>
<pre><code class="language-java">int[][] matrix = new int[3][3]; // 3x3 격자

int rows = matrix.length;       // 행의 개수
int cols = matrix[0].length;    // 열의 개수</code></pre>
<hr>
<h2 id="3-arraylist-정리">3. ArrayList 정리</h2>
<p>크기가 동적으로 변경되는 배열이 필요할 때 <code>ArrayList</code>를 활용합니다.</p>
<h3 id="3-1-arraylist란">3-1. ArrayList란?</h3>
<p><code>ArrayList</code>는 Java의 대표적인 리스트 구현체로, 내부적으로 배열을 사용해 데이터를 저장합니다.
원소가 늘어나면 더 큰 배열을 만들어 복사(리사이징)하며 크기를 자동으로 확장합니다.</p>
<h4 id="리사이징resizing-동작-원리">리사이징(Resizing) 동작 원리</h4>
<ul>
<li>초기 용량(capacity)은 기본 10개입니다.</li>
<li>원소가 늘어나 용량이 가득 차면, 내부 배열을 약 1.5배 크기로 새로 만들고 기존 데이터를 복사합니다.</li>
<li>이 때문에 개별 추가는 평균 O(1)이지만, 리사이징 시점에는 O(n)이 걸립니다. (Amortized O(1))</li>
<li>원소 개수를 미리 알면 <code>new ArrayList&lt;&gt;(expectedSize)</code>로 초기화하여 리사이징을 줄일 수 있습니다.</li>
</ul>
<h3 id="3-2-배열-vs-arraylist-비교">3-2. 배열 vs ArrayList 비교</h3>
<table>
<thead>
<tr>
<th>항목</th>
<th>배열(Array)</th>
<th>ArrayList</th>
</tr>
</thead>
<tbody><tr>
<td>크기 변경</td>
<td>불가능</td>
<td>가능(자동 리사이징)</td>
</tr>
<tr>
<td>접근/수정</td>
<td>O(1)</td>
<td>O(1)</td>
</tr>
<tr>
<td>맨 뒤 추가</td>
<td>직접 구현 시 O(n) 복사 필요</td>
<td>평균 O(1), 리사이징 시 O(n)</td>
</tr>
<tr>
<td>중간 삽입/삭제</td>
<td>O(n)</td>
<td>O(n)</td>
</tr>
<tr>
<td>타입</td>
<td>primitive 가능(<code>int[]</code>)</td>
<td>객체만 가능(<code>Integer</code>)</td>
</tr>
<tr>
<td>메모리</td>
<td>상대적으로 효율적</td>
<td>오토박싱/객체 오버헤드 가능</td>
</tr>
</tbody></table>
<blockquote>
<p>고정 길이/성능 중심이면 배열, 가변 길이/구현 편의성이 필요하면 <code>ArrayList</code>를 선택합니다.</p>
</blockquote>
<h3 id="3-3-기본-패턴">3-3. 기본 패턴</h3>
<pre><code class="language-java">import java.util.*;

List&lt;Integer&gt; list = new ArrayList&lt;&gt;();

// 추가
list.add(10);           // 맨 뒤에 추가
list.add(0, 5);         // 인덱스 0에 삽입

// 조회
int v = list.get(0);

// 수정
list.set(0, 99);

// 삭제
list.remove(1);         // 인덱스 1 삭제
list.remove(Integer.valueOf(10)); // 값 10 삭제

// 크기
int size = list.size();

// 비었는지 여부 확인
boolean empty = list.isEmpty();

// 포함 여부 확인
boolean contains = list.contains(10);

// 정렬
Collections.sort(list);                    // 오름차순
list.sort(Comparator.reverseOrder());      // 내림차순
</code></pre>
<h3 id="3-4-주의사항">3-4. 주의사항</h3>
<h4 id="1-remove-오버로드">1) remove() 오버로드</h4>
<p><code>ArrayList&lt;Integer&gt;</code>에서 <code>remove(1)</code>은 “값 1 제거”가 아니라 <strong>인덱스 1 제거</strong>로 동작합니다.
값으로 제거하려면 <code>Integer.valueOf()</code>를 사용해야 합니다.</p>
<pre><code class="language-java">List&lt;Integer&gt; list = new ArrayList&lt;&gt;(List.of(1, 2, 3));

list.remove(1);                    // 인덱스 1 삭제 → 값 2가 삭제됨
list.remove(Integer.valueOf(1));   // 값 1 삭제
</code></pre>
<h4 id="2-primitive-배열-↔-arraylist-변환">2) primitive 배열 ↔ ArrayList 변환</h4>
<pre><code class="language-java">// int[] -&gt; List&lt;Integer&gt;
int[] nums1 = {1, 2, 3};
List&lt;Integer&gt; list1 = Arrays.stream(nums1)
                            .boxed()
                            .collect(Collectors.toList());

// List&lt;Integer&gt; -&gt; int[]
List&lt;Integer&gt; list2 = List.of(1, 2, 3);
int[] nums2 = list2.stream()
                   .mapToInt(Integer::intValue)
                   .toArray();
</code></pre>
<h4 id="3-arraysaslist는-객체-배열에서만-기대한-대로-동작">3) Arrays.asList()는 객체 배열에서만 기대한 대로 동작</h4>
<pre><code class="language-java">// 정상 동작
Integer[] objArr = {1, 2, 3};
List&lt;Integer&gt; ok = Arrays.asList(objArr);

// 주의: 원소 1개짜리 리스트처럼 동작
int[] primArr = {1, 2, 3};
List&lt;int[]&gt; weird = Arrays.asList(primArr);</code></pre>
<hr>
<h2 id="4-스트림stream-활용">4. 스트림(Stream) 활용</h2>
<p>Java 8부터 도입된 스트림은 배열과 컬렉션을 다룰 때 가독성을 높여줍니다. 특히 필터링이나 변환 작업에서 유용합니다.</p>
<pre><code class="language-java">int[] nums = {1, 2, 3, 4, 5};

// 1. 필터링 및 변환
int[] evenSquared = Arrays.stream(nums)
                          .filter(n -&gt; n % 2 == 0)
                          .map(n -&gt; n * n)
                          .toArray();

// 2. 집계 (max, sum 등)
int max = Arrays.stream(nums).max().orElse(0);

// 3. 인덱스 기반 스트림 (IntStream)
int weightedSum = IntStream.range(0, nums.length)
                           .map(i -&gt; nums[i] * i)
                           .sum();</code></pre>
<hr>
<h2 id="5-대표-패턴-및-실전-예제">5. 대표 패턴 및 실전 예제</h2>
<h3 id="5-1-빈도-세기-counting">5-1. 빈도 세기 (Counting)</h3>
<p>값의 범위가 작을 때 배열 인덱스를 키(Key)로 활용합니다. ($O(n)$)</p>
<pre><code class="language-java">int[] count = new int[26];
for (char c : &quot;hello&quot;.toCharArray()) {
    count[c - &#39;a&#39;]++; // 알파벳별 개수 저장
}</code></pre>
<h3 id="5-2-투-포인터-two-pointers">5-2. 투 포인터 (Two Pointers)</h3>
<p>정렬된 배열에서 양끝 포인터를 좁혀가며 조건을 찾습니다. ($O(n)$)</p>
<pre><code class="language-java">Arrays.sort(nums);
int left = 0;
int right = nums.length - 1;

while (left &lt; right) {
    int sum = nums[left] + nums[right];
    if (sum == target) return true;
    if (sum &lt; target) left++;
    else right--;
}
return false;
</code></pre>
<h3 id="5-3-누적합-prefix-sum">5-3. 누적합 (Prefix Sum)</h3>
<p>반복적인 구간 합 쿼리를 $O(1)$에 해결합니다.</p>
<pre><code class="language-java">int[] nums = {2, 1, 5, 3, 4};
int n = nums.length;

// 전처리: prefix[i] = 0부터 i-1까지의 합
int[] prefix = new int[n + 1];
for (int i = 0; i &lt; n; i++) prefix[i + 1] = prefix[i] + nums[i];

// 구간 [l, r] 합
int l = 1, r = 3; // 1 + 5 + 3 = 9
int sum = prefix[r + 1] - prefix[l];

</code></pre>
<h3 id="5-4-슬라이딩-윈도우-sliding-window">5-4. 슬라이딩 윈도우 (Sliding Window)</h3>
<p>고정된 크기 또는 가변 크기의 윈도우를 배열 위에서 이동시키며 조건을 만족하는 구간을 찾습니다. ($O(n)$)</p>
<pre><code class="language-java">public int minSubArrayLen(int target, int[] nums) {
    int left = 0, sum = 0;
    int minLen = Integer.MAX_VALUE;

    for (int right = 0; right &lt; nums.length; right++) {
        sum += nums[right];

        while (sum &gt;= target) {
            minLen = Math.min(minLen, right - left + 1);
            sum -= nums[left++];
        }
    }

    return minLen == Integer.MAX_VALUE ? 0 : minLen;
}</code></pre>
<h3 id="5-5-카데인-알고리즘-kadanes-algorithm">5-5. 카데인 알고리즘 (Kadane&#39;s Algorithm)</h3>
<p><strong>연속된 부분 배열의 최대 합</strong>을 구하는 DP의 기초 알고리즘입니다. ($O(n)$)</p>
<pre><code class="language-java">public int maxSubArray(int[] nums) {
    int maxSum = nums[0];
    int currentSum = nums[0];

    for (int i = 1; i &lt; nums.length; i++) {
        // [DP 로직] 현재 원소부터 새로 시작할지, 기존 합에 더해서 이어갈지 결정
        currentSum = Math.max(nums[i], currentSum + nums[i]);

        // 전체 구간 중 가장 컸던 합을 갱신
        maxSum = Math.max(maxSum, currentSum);
    }

    return maxSum;
}</code></pre>
<h3 id="5-6-그래프-인접-리스트-arraylist-활용">5-6. 그래프 인접 리스트 (ArrayList 활용)</h3>
<p>정점별 연결 정보를 저장해야 하는 그래프 문제에 활용합니다.($O(E)$)</p>
<pre><code class="language-java">import java.util.*;

public List&lt;List&lt;Integer&gt;&gt; buildGraph(int n, int[][] edges) {
    List&lt;List&lt;Integer&gt;&gt; graph = new ArrayList&lt;&gt;();
    for (int i = 0; i &lt; n; i++) graph.add(new ArrayList&lt;&gt;());

    for (int[] e : edges) {
        int u = e[0], v = e[1];
        graph.get(u).add(v);
        graph.get(v).add(u); // 무방향
    }
    return graph;
}</code></pre>
<h3 id="5-7-2차원-배열-상하좌우-탐색">5-7. 2차원 배열 상하좌우 탐색</h3>
<p>BFS/DFS로 격자에서 연결 요소 탐색, 최단거리, 영역 개수 세기, flood fill 등에 사용합니다. ($O(R*C)$)</p>
<pre><code class="language-java">import java.util.*;

public class GridBfsCount {
    static final int[] dr = {-1, 1, 0, 0};
    static final int[] dc = {0, 0, -1, 1};

    public static int countIslands(int[][] grid) {
        int R = grid.length, C = grid[0].length;
        boolean[][] visited = new boolean[R][C];

        int count = 0;
        for (int r = 0; r &lt; R; r++) {
            for (int c = 0; c &lt; C; c++) {
                if (grid[r][c] == 1 &amp;&amp; !visited[r][c]) {
                    bfs(grid, visited, r, c);
                    count++;
                }
            }
        }
        return count;
    }

    private static void bfs(int[][] grid, boolean[][] visited, int sr, int sc) {
        int R = grid.length, C = grid[0].length;

        Queue&lt;int[]&gt; q = new ArrayDeque&lt;&gt;();
        q.add(new int[]{sr, sc});
        visited[sr][sc] = true;

        while (!q.isEmpty()) {
            int[] cur = q.poll();
            int r = cur[0], c = cur[1];

            for (int d = 0; d &lt; 4; d++) {
                int nr = r + dr[d], nc = c + dc[d];
                if (nr &lt; 0 || nr &gt;= R || nc &lt; 0 || nc &gt;= C) continue;

                if (grid[nr][nc] == 1 &amp;&amp; !visited[nr][nc]) {
                    visited[nr][nc] = true;
                    q.add(new int[]{nr, nc});
                }
            }
        }
    }
}

</code></pre>
<hr>
<h2 id="6-자주-하는-실수">6. 자주 하는 실수</h2>
<ol>
<li>배열은 <code>arr.length</code> / <code>리스트는 list.size()</code></li>
<li><strong>2차원 배열 복사</strong>: <code>matrix.clone()</code>은 얕은 복사 -&gt; 행마다 <code>clone()</code> 필요</li>
<li><code>ArrayList.remove(int index)</code>: 값이 아니라 인덱스 삭제임</li>
<li><strong>빈 배열 예외</strong>: <code>max()</code>, <code>min()</code> 같은 연산은 빈 배열 처리를 하지 않으면 에러가 날 수 있음 (<code>orElse</code>, 조건문)</li>
</ol>
<hr>
<h2 id="마무리">마무리</h2>
<p>배열은 코딩 테스트에서 가장 자주 등장하는 기본 자료구조이기 때문에 꼭 알아둘 필요가 있습니다.
이번에 내용을 정리하면서 다시 공부해보았는데, 특히 자주 쓰는 패턴들을 정리하는 과정이 큰 도움이 되었습니다.</p>
<p>다음 포스팅에서는 <strong>Stack/Queue</strong>를 정리해보겠습니다.🙌</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[첫 면접, 도망가고 싶었지만 그래도 보길 잘했다]]></title>
            <link>https://velog.io/@jh_devlog/%EC%B2%AB-%EB%A9%B4%EC%A0%91-%EB%8F%84%EB%A7%9D%EA%B0%80%EA%B3%A0-%EC%8B%B6%EC%97%88%EC%A7%80%EB%A7%8C-%EA%B7%B8%EB%9E%98%EB%8F%84-%EB%B3%B4%EA%B8%B8-%EC%9E%98%ED%96%88%EB%8B%A4</link>
            <guid>https://velog.io/@jh_devlog/%EC%B2%AB-%EB%A9%B4%EC%A0%91-%EB%8F%84%EB%A7%9D%EA%B0%80%EA%B3%A0-%EC%8B%B6%EC%97%88%EC%A7%80%EB%A7%8C-%EA%B7%B8%EB%9E%98%EB%8F%84-%EB%B3%B4%EA%B8%B8-%EC%9E%98%ED%96%88%EB%8B%A4</guid>
            <pubDate>Tue, 06 Jan 2026 16:06:35 GMT</pubDate>
            <description><![CDATA[<p>오늘 첫 번째 면접을 봤고, 기억이 생생할 때 후기를 남겨보려고 한다.
(사실 완전 첫 면접은 아니지만, 백엔드 개발자로서는 처음이었다.)</p>
<p>면접 전에는 솔직히 준비가 많이 부족하다는 걸 스스로 느껴 도망가고 싶은 마음이 컸다.
그럼에도 &quot;실전 경험에서만 얻을 수 있는 게 분명히 있다&quot;고 생각했고,
면접이 끝난 지금은 역시 <strong>보길 잘했다</strong>는 결론이다.</p>
<hr>
<h3 id="어떤-회사였나">어떤 회사였나?</h3>
<p>이번에 면접 본 회사는 <strong>온라인 플랫폼/서비스를 운영하는 B2B 스타트업</strong>이었다.
설립된 지 오래되지는 않았지만, 서비스 방향과 성장 흐름을 보았을 때 성장 가능성이 커 보이는 팀이라는 인상을 받았다.</p>
<hr>
<h3 id="면접-방식">면접 방식</h3>
<p>면접은 크게 아래 3가지로 구성되어 있었다.</p>
<ul>
<li>간단한 실무 테스트</li>
<li>기술 면접(이력서 기반 포함)</li>
<li>기타 질문(컬쳐핏/커뮤니케이션/성향 질문)</li>
</ul>
<p>실무 테스트는 처음이라 정말 무서웠다.
어떻게 대비해야 하는지 감도 잘 안 잡혔고, 그래서 테스트 대비보다는 <strong>기술 질문 / 이력서 기반 질문 / 컬쳐핏 질문</strong> 위주로 준비했다.</p>
<hr>
<h3 id="실무-테스트｜20분-그리고-ai-자유-사용">실무 테스트｜20분, 그리고 AI 자유 사용</h3>
<p>실무 테스트는 메일로 전달받은 링크로 접속해 진행하는 방식이었다.
문제 상황이 주어지고, 질문별로 파트가 나뉘어 있었으며 각 파트마다 <strong>요구사항(무엇을 작성해야 하는지)</strong>도 정리되어 있었다.</p>
<p>가장 특이했던 점은 <strong>AI 사용이 완전히 허용</strong>되었다는 것.
면접관이 “AI를 어떻게 활용하는지도 함께 본다”고 말해주셔서, 요즘은 진짜로 <strong>AI 활용 역량</strong> 자체가 평가 요소가 될 수 있겠다는 걸 체감했다.</p>
<p>(화면 공유 상태로 진행되었고 손이 떨려 계속 오타가 났다. 😨)</p>
<h3 id="결국-주어진-시간에-문제를-다-풀지-못했다⏰">결국 주어진 시간에 문제를 다 풀지 못했다..⏰</h3>
<p>주어진 시간은 20분, 풀어야 하는 문제 상황은 2개였다.</p>
<p>그런데 첫 번째 문제부터 문제 파악 자체가 어려웠었다.</p>
<p>AI를 마음대로 써도 된다고는 했지만, “활용 방식도 본다”는 말이 신경 쓰여서 다음 방식으로 접근했다.</p>
<ul>
<li>먼저 <strong>내가 문제를 최대한 이해</strong>한다</li>
<li>그 다음 <strong>AI에게 상황 분석을 요청</strong>한다</li>
<li>결과 중 <strong>필요한 부분만 선택해서 정리</strong>한다</li>
</ul>
<p>다만 이 방식은 생각보다 시간이 많이 걸렸다.
결국 시간 배분에 실패했고, 두 번째 문제는 아예 손도 못 대고 끝나버렸다… 🥲</p>
<p>다른 지원자 분은 첫 문제를 푸는 동시에 두 번째 문제도 미리 AI에 붙여넣어 두 문제를 동시에 분석해두고 진행했다고 한다.
돌이켜보면 그 방향이 더 좋은 전략이었던 것 같다.
(특히 스타트업 환경에서는 “완벽한 이해”보다 <strong>제한된 시간 안에 요구사항을 빠르게 충족하는 능력</strong>을 더 중요하게 볼 것 같았다.)</p>
<p>면접 중에도 AI 활용 방식에 대한 질문이 있었고, 전반적으로 이 회사가 <strong>AI 도구 활용 역량</strong>을 꽤 중요하게 본다는 느낌을 강하게 받았다.
요즘은 기술 공부뿐 아니라, AI를 ‘어떻게 잘 쓰는지’도 꾸준히 연습해야겠다는 생각이 들었다.</p>
<hr>
<h3 id="기술-면접｜22-그리고-멘붕">기술 면접｜2:2, 그리고 멘붕</h3>
<p>면접은 <strong>2:2</strong>로 진행됐다.</p>
<p>이력서 기반 질문이 시작되자, 함께 면접 본 다른 지원자 분이 말을 너무 잘하셔서 나도 모르게 자신감이 급격히 떨어졌다.
게다가 준비하지 못한 질문도 나와 답변이 깔끔하게 나오지 않았고, 특히 <strong>기술 선택/의사결정 이유</strong>를 묻는 질문에서 준비 부족이 그대로 드러났다.</p>
<p>주로 내가 했던 선택의 이유를 묻는 질문이 많았다.</p>
<ul>
<li>특정 기능 고도화를 위해 기술을 도입했다가 다시 단순화했는데, 그때 <strong>복잡도와 가치의 균형</strong>을 어떤 기준으로 판단했는지</li>
<li>멀티 인스턴스 환경에서 채팅 메시지 동기화에 Redis를 선택한 이유는 무엇인지</li>
</ul>
<p>결국은 내가 내린 판단의 기준과 근거를 설명하는 질문들이었는데, 이 부분을 더 구조적으로 준비해야겠다고 느꼈다.</p>
<blockquote>
<p>“기술을 왜 선택했는지”는
단순히 경험을 나열하는 게 아니라,
<strong>기준과 근거를 구조적으로 설명할 수 있어야 한다.</strong></p>
</blockquote>
<hr>
<h3 id="컬쳐핏-질문｜오히려-더-편하게-답했다">컬쳐핏 질문｜오히려 더 편하게 답했다</h3>
<p>기술 면접 이후에는 기술 외 질문을 하는 시간도 있었다.</p>
<ul>
<li>개발을 시작한 계기</li>
<li>스트레스 해소 방식</li>
<li>갈등 해결 방식 등</li>
</ul>
<p>이런 질문들은 비교적 편하게 답할 수 있었다.
기술 질문보다 오히려 이쪽이 내 경험을 자연스럽게 꺼내기 쉬웠던 것 같다.</p>
<hr>
<h3 id="전체적인-평가">전체적인 평가</h3>
<p>이번 면접은 솔직히 잘 봤다고 말하기는 어렵다.
특히 실무 테스트에서는 시간 배분 실패로 아쉬움이 컸고, 기술 질문 중 일부는 준비가 부족해서 답변이 흔들렸다.</p>
<p>그럼에도 불구하고 이번 면접을 통해 얻은 건 많은 것 같다.</p>
<ul>
<li>실무 테스트는 ‘문제 파악 + 시간 관리’가 핵심</li>
<li>AI 활용 방식 자체가 평가 포인트가 될 수 있음</li>
<li>기술 선택 질문은 기준/근거/대안까지 준비해야 함</li>
<li>“면접 경험”은 준비 부족을 정확히 보여주는 최고의 피드백</li>
</ul>
<p>아쉬움이 남았지만, 다음 면접을 더 잘 보기 위한 확실한 피드백을 얻은 하루였다.</p>
<hr>
<h3 id="추가로">추가로...</h3>
<p>면접을 끝내고, 그냥 집에 가기엔 헛헛해서 교보문고에 들렀다.
장바구니에 담아두었던 책들도 사고, 잠깐 리프레시도 했다.</p>
<p><img src="https://velog.velcdn.com/images/jh_devlog/post/7ae6ca22-bf4f-497a-ab83-9f6765d8954e/image.jpeg" alt="">
(우울해서 책 샀슨....🥺)</p>
<p>다음 면접 전까지는 책도 조금씩 읽으면서 CS 공부를 매일 루틴으로 다시 잡아봐야겠다.
그래도 내내 걱정하던 면접이 끝났다는 사실만으로도 한결 후련하다. 🙂👍</p>
]]></description>
        </item>
    </channel>
</rss>