본문 바로가기

Reversing/Malware Analysis

[BPFDoor] 악성코드 분석 - 패킷 필터를 악용하는 악성코드

목차

  • 1. 개요
       1.1) 침해 지표
       1.2) 분석 파일 정보
  • 2. 상세 분석
       2.1) 중복 실행 감지
       2.2) to_open() - 복사본 생성/삭제/실행
       2.3) set_proc_name() - 프로세스 이름 변경
       2.4) 시그널 설정 후 독립 세션에서 동작
       2.5) packet_loop() - 패킷 필터
       2.6) packet_loop() - 독립 세션 생성
       2.7) packet_loop() - 명령 분기
       2.8) packet_loop() - 바인드 셸 방화벽 규칙 추가/삭제
  • 3. 실행 흐름
  • 4. 결론

 

 

 

 

1. 개요

BPF(Berkeley Packet Filter)는 원래 네트워크 패킷을 효율적으로 필터링하기 위해 설계된 기술로, 현재는 eBPF(extended BPF)로 확장되어 커널 내부에서 다양한 이벤트를 관찰·조작할 수 있는 강력한 메커니즘으로 발전하였다. 이러한 특성은 합법적 성능 모니터링 및 보안 도구 개발에 활용될 수 있지만, 동시에 공격자가 커널 레벨에서 은밀한 후킹과 통신을 수행할 수 있는 공격 표면을 제공한다.

 

최근 보고된 BPF Door 공격은 국가 배후 APT 그룹에 의해 수행된 것으로 알려져 있으며, BPF 프로그램을 로딩하여 패킷 필터링 기능이 트리거 역할로 동작하며, 별도의 네트워크 포트를 열지 않고 정상 시스템 프로세스와 유사한 형태로 위장하여 일반 백도어보다 탐지가 어렵고, 장기적인 잠복 활동에 적합하다는 점에서 심각한 위협으로 평가된다.

 

그림1) 공개된 BPFDoor 소스코드

 

공개 보고에 따르면 중국 APT 그룹인 Red Menshen과 관련이 있는 것으로 알려져 있다. 다만, 2022년에 소스코드가 GitHub 등에서 공개되어 여러 가지 변종이 나오고 있기에 추가적인 조사와 연구가 필요하다.

 

 

 

 

1.1) 침해 지표

그림2) KISA 보안 공지

 

지난 4월 25일, 한국인터넷진흥원(KISA) 보호나라는 공식 보안 공지를 통해 최근 해킹 공격에 악용된 악성코드 및 관련 IP 등 위협정보(IoC, Indicators of Compromise) 4종을 공개하고 주의를 당부했다.

 

공개된 침해지표는 다음과 같은 정보를 포함한다.

  • 악성코드 샘플 또는 파일 해시
  • 공격에 사용된 IP 주소
C2  165.232.174[.]130

 

filename size SHA256 MD5
hpasmmld 2,265KB c7f693f7f85b01a8c0e561bd369845f40bff423b0743c7aa0f4c323d9133b5d4 a47d96ffe446a431a46a3ea3d1ab4d6e
smartadm  2,067KB  3f6f108db37d18519f47c5e4182e5e33cc795564f286ae770aa03372133d15c4 227fa46cf2a4517aa1870a011c79eb54
hald-addon-volume 2,071KB 95fd8a70c4b18a9a669fec6eb82dac0ba6a9236ac42a5ecde270330b66f51595 f4ae0f1204e25a17b2adbbab838097bd
dbus-srv-bin.txt 34KB aa779e83ff5271d3f2d270eaed16751a109eb722fca61465d86317e03bbf49e4 714165b06a462c9ed3d145bc56054566

 

 

 

 

 

1.2) 분석 파일 정보

File name ec7d78a7ecbfcaba5e52e7541265f5e4aca7759a03c69c4ae60aead3faac299f
MD5 e086fabda4078355c40543d6eafeec91
SHA-256 39d8d80a727ffab6e08ae2b9551f7251a652f4d4edfe5df21d0e2684d042268f
File type ELF
File size 35.63 KB (36480 bytes)
Header ELF64 | Operation system: Unix [DYN AMD64-64]

 

본 BPFDoor 파일은 ELF64 형식으로, 운영체제는 Unix 계열, 아키텍처는 AMD64 (x86-64) 구조를 가진 형태임을 확인하였다.

 

 

2. 상세 분석

2.1) 중복 실행 감지

그림3) 중복 실행 검사

 

초기 실행 시 환경을 검증하고 조건이 충족되지 않으면 자체 종료하도록 설계되어 있다.

 

먼저 /var/run/haldrund.pid 파일이 존재하는지 확인한다. 이는 이미 해당 악성코드가 실행 중인지 판단하기 위한 중복 실행 방지 루틴이다. 또한 getuid()로 루트 권한이 아닌 일반 사용자 권한으로 실행될 경우에도 종료하도록 되어 있다.

 

 

 

 

2.2) to_open() - 복사본 생성/삭제/실행

그림4) 복사본 실행

 

argc가 1일 경우 (첫 실행 시) to_open(argv[0], "kdmtmpflush")를 호출한다. to_open() 루틴이 반환되고, 이미 악성코드가 메모리에 상주하고 있는 경우에는 _exit(0)을 통해 원본 실행 파일을 즉시 종료한다. 만약 복사본이 성공적으로 실행되면, _exit(1)을 통해 원본을 종료한다.

 

그림5) to_open()

 

to_open() 루틴에서는 시스템 명령을 실행하여 자기 자신을 메모리 기반 임시 파일 시스템(/dev/shm)에 드랍하여 상주하도록 초기화 한다. /dev/shm은 임시 파일 시스템 경로며, 재부팅 시 초기화되거나 일시적으로 삭제될 수 있는 특성이 있어, 이를 활용하여 포렌식 흔적을 최소화하고 분석과 탐지를 어렵도록 한다.

 

복사본 실행 시에는  /dev/shm/kdmtmpflush --init 실행 옵션으로 인해 arg 값이 2가 되어 해당 if ( argc == 1 ) 조건을 스킵하게 된다.

 

to_open() 루틴에서 실행되는 명령은 다음과 같다.

/bin/rm -f /dev/shm/kdmtmpflush;          
/dev/shm/kdmtmpflush 경로에 이미 존재하는 복사본을 제거하여 중복 실행을 방지한다.

/bin/cp <원본> /dev/shm/kdmtmpflush    
초기 실행 파일을 /dev/shm/kdmtmpflush로 복사한다.

/bin/chmod 755 /dev/shm/kdmtmpflush
복사본에 실행 권한을 부여한다.

/dev/shm/kdmtmpflush --init
복사본을 --init 옵션과 함께 실행

/bin/rm -f /dev/shm/kdmtmpflush 
실행 후 파일을 삭제하여 흔적을 최소화

 

 

 

 

 

2.3) set_proc_name() - 프로세스 이름 변경

그림6) 자신 프로세스명 변경

 

실행된 kdmtmpflush 에서 복사본을 생성할 때 총 10가지 형태 중 하나를 랜덤하게 선택하여 프로세스명을 변경한다. 또한 setup_time()을 호출하여 생성 날짜를 특정 날짜와 시간대로 은닉하고, 프로세스명을 변경하여 정상 프로세스로 위장한다. 이후, fork()를 호출하여 자식 프로세스를 실행한다.

 

이때 랜덤 하게 선택되는 프로세스명 예시는 다음과 같다.

그림7) 랜덤하게 변경되는 프로세스 명

  • /sbin/udevd -d
  • /sbin/mingetty /dev/tty7
  • /usr/sbin/console-kit-daemon --no-daemon
  • hald-addon-acpi: listening on acpi kernel interface /proc/acpi/event
  • dbus-daemon --system
  • hald-runner
  • pickup -l -t fifo -u
  • avahi-daemon: chroot helper
  • /sbin/auditd -n
  • /usr/lib/systemd/systemd-journald

 

 

 

 

2.4) 시그널 설정 후 독립 세션에서 동작

그림8) 시그널 설정 - 독립 세션 실행

 

fork()로 자식 프로세스를 생성하고 좀비 프로세스로 남지 않도록 시그널을 설정한 뒤, setsid()를 호출하여 부모 터미널과 완전히 분리된 독립 세션에서 실행되도록 한다. 이를 통해 사용자가 로그아웃하거나 터미널을 종료해도 백그라운드에서 계속 동작할 수 있다. 초기화가 완료되면, 복사본은 실제 백도어 기능이 수행되는 packet_loop()에 진입한다.

 

이로써, /dev/shm/kdmtmpflush --init로 실행된 복사본은 초기화 및 은닉 작업을 마친 후, 부모 터미널과 완전히 분리된 독립 세션에서 은밀하게 상주하며 지속적으로 악성 행위를 수행하게 된다.

 

 

 

 

 

2.5) packet_loop() - 패킷 필터

struct sock_filter bpf_code[] = {
        { 0x28, 0, 0, 0x0000000c },
        { 0x15, 0, 27, 0x00000800 },
        { 0x30, 0, 0, 0x00000017 },
        { 0x15, 0, 5, 0x00000011 },
        { 0x28, 0, 0, 0x00000014 },
        { 0x45, 23, 0, 0x00001fff },
        { 0xb1, 0, 0, 0x0000000e },
        { 0x48, 0, 0, 0x00000016 },
        { 0x15, 19, 20, 0x00007255 },
        { 0x15, 0, 7, 0x00000001 },
        { 0x28, 0, 0, 0x00000014 },
        { 0x45, 17, 0, 0x00001fff },
        { 0xb1, 0, 0, 0x0000000e },
        { 0x48, 0, 0, 0x00000016 },
        { 0x15, 0, 14, 0x00007255 },
        { 0x50, 0, 0, 0x0000000e },
        { 0x15, 11, 12, 0x00000008 },
        { 0x15, 0, 11, 0x00000006 },
        { 0x28, 0, 0, 0x00000014 },
        { 0x45, 9, 0, 0x00001fff },
        { 0xb1, 0, 0, 0x0000000e },
        { 0x50, 0, 0, 0x0000001a },
        { 0x54, 0, 0, 0x000000f0 },
        { 0x74, 0, 0, 0x00000002 },
        { 0xc, 0, 0, 0x00000000 },
        { 0x7, 0, 0, 0x00000000 },
        { 0x48, 0, 0, 0x0000000e },
        { 0x15, 0, 1, 0x00005293 },
        { 0x6, 0, 0, 0x0000ffff },
        { 0x6, 0, 0, 0x00000000 },
};

 

자신에게 전달될 신호를 감시하기 위해 커스텀 패킷 필터를 등록한다. 해당 BPF 필터는 네트워크 패킷을 모니터링하고, 특정 패턴(일명 매직 패킷)과 일치할 경우 BPFDoor에 이벤트를 전달한다. 이러한 방식 덕분에, 별도의 포트를 열거나 눈에 띄는 네트워크 연결을 만들지 않고도, 원격에서 은밀하게 명령을 수신할 수 있다.

 

등록된 필터는 IPv4 패킷 중 UDP의 경우 포트 29269(0x7255), TCP의 경우 포트 21139(0x5293)인 트래픽만 통과시킨다. 이 외의 모든 패킷은 즉시 drop 처리되어 필터링된다.

 

그림9) 특정 프로토콜 구분

 

IP 헤더의 protocol 필드를 확인한 뒤, TCP·UDP·ICMP 패킷만 선별적으로 처리한다.

특히 TCP 패킷의 경우, TCP 헤더 길이를 계산하여 실제 페이로드를 가리키는 mp (Magic Packet Data)를 가져온다.

 

 

 

 

 

2.6) packet_loop() - 독립 세션 생성

그림10) 독립 세션 실행

 

mp (Magic Packet Data)를 가져오면 새로운 프로세스를 fork()로 생성하여 자식 프로세스를 /usr/libexec/postfix/master로 프로세스명을 변경해 정상 프로세스로 보이도록 만든다. 생성 시 부모 프로세스는 종료되고 chdir("/"), setsid(), signal(1, 0)을 호출해 독립 세션에서 종료되지 않고 실행되도록 설정한다. 

 

 

 

 

2.7) packet_loop() - 명령 분기

그림11) RC4 암복호화 수행 및 명령 분기

 

BPFDoor는 매직 패킷 내부에 포함된 키(mp+10)를 활용하여 암호화 세션을 생성한다. 이후 공격자와 주고받는 모든 데이터는 RC4 암호화/복호화 과정을 거쳐 처리된다.

 

이후 logon() 루틴에는 전달되는 명령어를 처리하기 위한 인증 루틴을 수행한다. 내부적으로 문자열 비교를 통해 명령 타입을 식별하는데, 입력으로 들어온 문자열이 "justforfun"일 경우 0을 반환하고, "socket"일 경우 1을 반환한다. 두 문자열 중 어느 것과도 일치하지 않으면 2를 반환하여 별도의 처리 경로로 분기된다.

 

그림12) 공격자 명령 분기 후 동작

 

반환값이 0(“justforfun”)일 경우, BPFDoor는 대상 시스템에 리버스 셸을 생성하여 공격자가 원격에서 명령을 실행할 수 있도록 한다.

 

반환값이 1(“socket”)일 경우, 먼저 iptables 규칙을 조작하여 특정 포트 통신을 허용한 후, 바인드 셸을 열어 외부에서 공격자가 직접 접속할 수 있는 환경을 만든다.

 

마지막으로 사전 정의된 문자열이 없을 경우(2 반환), 모니터링 모드(mon)에 진입한다. 해당 모드는 1바이트 UDP 패킷을 전송하는 방식으로 동작한다.

0 justforfun Reverse Shell
1 socket Bind Shell
2 x “1” 응답

 

 

 

 

 

 

2.8) packet_loop() - 바인드 셸 방화벽 규칙 추가/삭제

그림13) 바인드 셸 방화벽 규칙 설정

 

바인드 셸은 외부에서의 접근을 보장하기 위해 새로운 포트를 오픈한 후 iptables 규칙을 추가/삭제한다. 공격자가 지정한 IP와 포트를 대상으로 트래픽을 리다이렉트 하거나 허용하기 위해, 다음과 같은 명령을 사용한다.

 

/sbin/iptables -t nat -A PREROUTING -p tcp -s <공격자_IP> --dport <외부포트> -j REDIRECT --to-ports <로컬포트>
특정 IP에서 들어오는 TCP 트래픽을 로컬 바인드 셸 포트로 리다이렉트

/sbin/iptables -t nat -D PREROUTING -p tcp -s <공격자_IP> --dport <외부포트> -j REDIRECT --to-ports <로컬포트>
세션 종료 시 리다이렉트 규칙 삭제

/sbin/iptables -I INPUT -p tcp -s <공격자_IP> -j ACCEPT
공격자 IP에서 들어오는 패킷을 허용

/sbin/iptables -D INPUT -p tcp -s <공격자_IP> -j ACCEPT
필요 시 허용 규칙 제거

 

 

 

 

3. 실행 흐름

BPFDoor의 전체 실행 흐름을 요약하면 다음과 같다.

 

1. 중복 실행 방지
(1) /var/run/haldrund.pid 파일을 확인하여 이미 프로세스가 존재하면 종료한다.

2. 초기화 및 자기 복제
(2) 실행 시 argc == 1이면 (첫 실행) to_open(*argv, "kdmtmpflush")를 호출하여 /dev/shm에 자기 자신을 복제한다.
복제본이 성공적으로 생성되면 원본은 종료되고, 복제본의 프로세스명을 변경하여 정상 프로세스로 위장하고 자식 프로세스를 실행한다.

3. 은닉 및 탐지 회피
(3) 초기화 이후 복제본은 프로세스 이름을 /usr/libexec/postfix/master 등 정상 프로세스처럼 위장한다.
자식 프로세스를 실행하고 시그널을 초기화하여 좀비 프로세스가 되지 않도록 하고, setsid() 호출로 부모 터미널과 완전히 분리된 독립 세션에서 동작한다.

4. C2 통신 및 악성 행위 수행
(4) packet_loop()에서 수신되는 패킷을 필터링하고, 매직 패킷과 사전 정의된 명령 문자열(justforfun, socket)에 따라 리버스 셸, 바인드 셸, 모니터링 기능 등을 수행한다.
바인드 셸 동작 시 iptables 규칙을 추가/삭제하여 공격자 IP가 접근할 수 있도록 한다.

 

 

4. 결론

BPFDoor의 특징은 일반적인 백도어와 달리, 감염된 시스템에서 항상 C2 서버에 연결하거나 열린 포트를 유지할 필요가 없다는 점이다. 매직 패킷 기반 트리거 방식을 사용하여 눈에 띄는 네트워크 활동 없이 은밀하게 상주할 수 있으며, 공격자는 원격에서 원하는 시점에만 명령을 실행한다. 또한 정상 프로세스로 위장하여 탐지를 회피하며 독립 세션 실행(setsid)을 통해 부모 터미널과 완전히 분리된 환경에서 동작하도록 설계되어 있다.

 

이러한 구조 덕분에 BPFDoor는 포렌식 흔적을 최소화하면서 장기간 탐지되지 않은 상태로 잠복할 수 있으며, 목표 시스템에서 정보를 수집하거나 추가 악성 행위를 지속적으로 수행이 가능하다.