
Go to Top
Go to Top
1%의 보안 사각지대로 발생하는 침해사고, 이제는 화이트해커와 함께할 때 입니다
개인정보 유출로 이어질 취약점을 공격자의 시선으로 미리 찾아내고,
보안 수준을 한층 높여 대응하세요.
개인정보 유출로 이어질 취약점을 공격자의 시선으로 미리 찾아내고,
보안 수준을 한층 높여 대응하세요.
개인정보 유출로 이어질 취약점을 공격자의 시선으로 미리 찾아내고, 보안 수준을 한층 높여 대응하세요.
보안을 최우선으로 여기는 기업은
이미 엔키화이트햇을 선택했습니다.
보안을 최우선으로 여기는 기업은
이미 엔키화이트햇을 선택했습니다.
보안을 최우선으로 여기는 기업은
이미 엔키화이트햇을 선택했습니다.
다양한 산업군의 프로젝트 경험의 축적된 노하우로
업계 특성과 고객 니즈에 맞춘 맞춤형 솔루션을 제공합니다.
다양한 산업군의 프로젝트 경험의 축적된 노하우로
업계 특성과 고객 니즈에 맞춘 맞춤형 솔루션을 제공합니다.
다양한 산업군의 프로젝트 경험의 축적된 노하우로 업계 특성과 고객 니즈에 맞춘 맞춤형 솔루션을 제공합니다.

대기업

금융기관

IT 및 보안기업

군/공공기관










대기업

금융기관

IT 및 보안기업

군/공공기관










대기업

금융기관

IT 및 보안기업

군/공공기관









원인을 알 수 없는 해킹과
끊이지 않는 침해사고
원인을 알 수 없는 해킹과
끊이지 않는 침해사고
원인을 알 수 없는 해킹과
끊이지 않는 침해사고
막연한 불안은 쌓여만 가고, 책임의 압박은
온전히 실무자에게 가중됩니다.
막연한 불안은 쌓여만 가고, 책임의 압박은
온전히 실무자에게 가중됩니다.
막연한 불안은 쌓여만 가고, 책임의 압박은 온전히 실무자에게 가중됩니다.
계속 발생하는 개인정보 유출 사고,우리 기업은 안전할까요?
계속 발생하는 개인정보 유출 사고, 우리 기업은 안전할까요?
계속 발생하는 개인정보 유출 사고, 우리 기업은 안전할까요?
통제 불가 IT 자산
통제 불가 IT 자산
통제 불가 IT 자산
고도화되는 공격
고도화되는 공격
고도화되는 공격
잦은 기능 업데이트
잦은 기능 업데이트
잦은 기능 업데이트
잦은 기능 업데이트
늘어나는 협력사 연결
늘어나는 협력사 연결
늘어나는 협력사 연결
클라우드·원격 근무
클라우드·원격 근무
클라우드·원격 근무
AI 서비스 활용
AI 서비스 활용
AI 서비스 활용
AI 서비스 활용
부족한 보안 인력
부족한 보안 인력
부족한 보안 인력
강화되는 규제 요구
강화되는 규제 요구
강화되는 규제 요구
이제, 공격자보다 한 발 앞서 예방하세요
이제, 공격자보다 한 발 앞서 예방하세요
이제, 공격자보다 한 발 앞서 예방하세요
이제, 공격자보다 한 발 앞서 예방하세요
이제, 공격자보다 한 발 앞서 예방하세요
이제, 공격자보다 한 발 앞서 예방하세요
기업 보안은 치밀해야 합니다.
단 1%의 보안사각지대를 노리는 공격자에 맞서 이제는 공격자처럼 사고하고
선제적으로 점검·대응하는 보안이 필요합니다.
기업 보안은 치밀해야 합니다.
단 1%의 보안사각지대를 노리는 공격자에 맞서 이제는 공격자처럼 사고하고
선제적으로 점검·대응하는 보안이 필요합니다.
기업 보안은 치밀해야 합니다.
단 1%의 보안사각지대를 노리는 공격자에 맞서 이제는 공격자처럼 사고하고
선제적으로 점검·대응하는 보안이 필요합니다.
기업을 위협하는 크리티컬한 취약점을 찾습니다
기업을 위협하는 크리티컬한 취약점을 찾습니다
기업을 위협하는 크리티컬한 취약점을 찾습니다
윤리적인 화이트해커가 공격자의 관점으로
실제 기업에게 경제피해, 정보유출, 서비스 장애 등으로
이어질수있는 보안문제를 미리찾습니다.
윤리적인 화이트해커가 공격자의 관점으로
실제 기업에게 경제피해, 정보유출, 서비스 장애 등으로
이어질수있는 보안문제를 미리찾습니다.
윤리적인 화이트해커가 공격자의 관점으로 실제 기업에게 경제피해, 정보유출, 서비스 장애 등으로 이어질수있는 보안문제를 미리찾습니다.
서버 장악 및 권한 획득
서버 장악 및 권한 획득

원격지에서 서버 최상위 권한 취득 가능성 검증
원격지에서 서버 최상위 권한 취득 가능성 검증
미사용 포트 및 취약 서비스 기반 서버 장악 시나리오 확인
미사용 포트 및 취약 서비스 기반 서버 장악 시나리오 확인
서비스 취약점 분석을 통해 내부 서버 접근 경로 확인
서비스 취약점 분석을 통해 내부 서버 접근 경로 확인
악성 행위
악성 행위

전자화폐(포인트) 복제 및 부정 결제 시도 재현
전자화폐(포인트) 복제 및 부정 결제 시도 재현
악성 앱 제작 및 유포 가능성 입증
악성 앱 제작 및 유포 가능성 입증
취약점(XSS, 정보 노출 등)을 통한 권한 상승 가능성 확인
취약점(XSS, 정보 노출 등)을 통한 권한 상승 가능성 확인
외주 직원/임직원 단말 보안 우회 가능 경로 검증
외주 직원/임직원 단말 보안 우회 가능 경로 검증
자료 유출
자료 유출

고객 개인정보, 내부 문건 등 중요 정보 유출 가능성 확인
고객 개인정보, 내부 문건 등 중요 정보 유출 가능성 확인
임의 명령 실행을 통해 외부 유출 위험 입증
임의 명령 실행을 통해 외부 유출 위험 입증
관리자 권한 탈취 후, 고객 정보 접근 가능 경로 확인
관리자 권한 탈취 후, 고객 정보 접근 가능 경로 확인
보안 솔루션 우회로 인한 데이터 반출 가능성 검증
보안 솔루션 우회로 인한 데이터 반출 가능성 검증
SSH 터널링을 통한 외부 전송 시나리오 재현
SSH 터널링을 통한 외부 전송 시나리오 재현
엔키 제품
엔키 제품
ASM
ASM
ASM
시야 밖에 있던 위협을 누락없이 한눈에
시야 밖에 있던 위협을 누락없이 한눈에



Checklist/Offensive PT
Checklist/Offensive PT
Checklist/Offensive PT
ISMS-P 인증 최적화
원하는 만큼만, 특정 웹/앱/시스템 점검
ISMS-P 인증 최적화
원하는 만큼만, 특정 웹/앱/시스템 점검



Red Team
Red Team
Red Team
실전공격 시나리오로 전문 화이트해커의 End to End 보안점검
실전공격 시나리오로 전문 화이트해커의 End to End 보안점검



엔키 제품
엔키 제품
CAMP
CAMP
CAMP
긴급한 상황에서도 흔들리지않는 내부 대응력,
팀 전체의 실무역량을 한단계 더 끌어올리는
보안 역량 성장 플랫폼
긴급한 상황에서도 흔들리지않는 내부 대응력, 팀 전체의 실무역량을 한단계 더 끌어올리는 보안 역량 성장 플랫폼
CAMP 제품 자세히보기
CAMP 제품 자세히보기
CAMP 제품 자세히보기
교육
교육
교육



디지털 포렌식, 침해사고 대응, 악성코드 분석, 웹해킹,
보안장비운용 등 실무 중심의 이론과 실습을 통해
기초부터 탄탄하게 다지는 보안 역량
디지털 포렌식, 침해사고 대응, 악성코드 분석, 웹해킹, 보안장비운용 등 실무 중심의 이론과 실습을 통해 기초부터 탄탄하게 다지는 보안 역량
워게임
워게임
워게임



기술 분야별 실습 컨텐츠 풀이로 기본 역량을 강화하고
우수풀이(Write-up) 공유 및 랭크 시스템을 통한
학습 동기부여
기술 분야별 실습 컨텐츠 풀이로 기본 역량을 강화하고 우수풀이(Write-up) 공유 및 랭크 시스템을 통한 학습 동기부여
CTF
CTF
CTF



다양한 콘텐츠를 활용해 자체 CTF 환경을 비전공자도
쉽게 구성하고, 구성원 간 보안 역량 비교 진단
다양한 콘텐츠를 활용해 자체 CTF 환경을 비전공자도 쉽게 구성하고, 구성원 간 보안 역량 비교 진단
공방훈련
공방훈련
공방훈련



실제 해킹 사례 기반 콘텐츠(TTPs, 취약점, 시나리오) 를 활용하고 기업 환경을 반영한 가상 인프라에서
실시간 공격 및 방어 훈련을 통한 조직 내 협업 능력 강화
실제 해킹 사례 기반 콘텐츠(TTPs, 취약점, 시나리오) 를 활용하고 기업 환경을 반영한 가상 인프라에서 실시간 공격 및 방어 훈련을 통한 조직 내 협업 능력 강화
엔키 서비스
엔키 서비스

오펜시브 보안 점검
실전 경험과 높은 기술력을 갖춘 화이트해커가 기업 전반의 IT인프라를 점검하고, 경제적인 피해·정보 유출·서비스 장애로 이어질 수 있는 보안 위협을 사전에 식별·검증하여 대응 전략을 제시합니다.
자세히보기

레드팀

컴플라이언스 진단

모의해킹

이행점검

사이버 위협 인텔리전스
북한·중국·러시아 등 2만여 건 이상의 악성코드 분석 경험을 바탕으로, 전문가가 정제된 위협 인텔리전스와 맞춤 대응 전략을 제공합니다. 침해사고 시 공격자의 행위·피해 범위·침투 경로를 분석해 근본적인 위협을 제거합니다.
자세히보기

악성코드 분석

침해흔적 조사

보안 교육 및 훈련
사이버공격방어대회 국내 1위 기업의 노하우로, 실제 보안사고를 모사한 고품질 문제와 실전형 대회 운영을 제공합니다. 다수의 침투 테스트와 글로벌 대회 운영 경험을 바탕으로, 현업에 필요한 최신 보안 기술 교육과 맞춤형 실습 환경을 제공합니다.
자세히보기

실습형 교육

해킹 방어 대회 운영

악성 이메일 훈련

오펜시브 보안 점검
실전 경험과 높은 기술력을 갖춘 화이트해커가 기업 전반의 IT인프라를 점검하고, 경제적인 피해·정보 유출·서비스 장애로 이어질 수 있는 보안 위협을 사전에 식별·검증하여 대응 전략을 제시합니다.
자세히보기

레드팀

컴플라이언스 진단

모의해킹

이행점검

사이버 위협 인텔리전스
북한·중국·러시아 등 2만여 건 이상의 악성코드 분석 경험을 바탕으로, 전문가가 정제된 위협 인텔리전스와 맞춤 대응 전략을 제공합니다. 침해사고 시 공격자의 행위·피해 범위·침투 경로를 분석해 근본적인 위협을 제거합니다.
자세히보기

악성코드 분석

침해흔적 조사

보안 교육 및 훈련
사이버공격방어대회 국내 1위 기업의 노하우로, 실제 보안사고를 모사한 고품질 문제와 실전형 대회 운영을 제공합니다. 다수의 침투 테스트와 글로벌 대회 운영 경험을 바탕으로, 현업에 필요한 최신 보안 기술 교육과 맞춤형 실습 환경을 제공합니다.
자세히보기

실습형 교육

해킹 방어 대회 운영

악성 이메일 훈련

오펜시브 보안 점검
실전 경험과 높은 기술력을 갖춘 화이트해커가 기업 전반의 IT인프라를 점검하고, 경제적인 피해·정보 유출·서비스 장애로 이어질 수 있는 보안 위협을 사전에 식별·검증하여 대응 전략을 제시합니다.
자세히보기

레드팀

컴플라이언스 진단

모의해킹

이행점검

사이버 위협 인텔리전스
북한·중국·러시아 등 2만여 건 이상의 악성코드 분석 경험을 바탕으로, 전문가가 정제된 위협 인텔리전스와 맞춤 대응 전략을 제공합니다. 침해사고 시 공격자의 행위·피해 범위·침투 경로를 분석해 근본적인 위협을 제거합니다.
자세히보기

악성코드 분석

침해흔적 조사

보안 교육 및 훈련
사이버공격방어대회 국내 1위 기업의 노하우로, 실제 보안사고를 모사한 고품질 문제와 실전형 대회 운영을 제공합니다. 다수의 침투 테스트와 글로벌 대회 운영 경험을 바탕으로, 현업에 필요한 최신 보안 기술 교육과 맞춤형 실습 환경을 제공합니다.
자세히보기

실습형 교육

해킹 방어 대회 운영

악성 이메일 훈련

위협 인텔리전스
APT Down - The North Korea Files 공개 자료 상세 분석 보고서
본 장에서는 공격자 VMware VM 덤프 파일에서 확인된 악성코드와 VPS 덤프 파일에서 확인된 스피어 피싱 공격 및 인프라 운용 정황에 대한 내용을 다룬다. 특히 tomcat20220420_rootkit, tomcat20250414_rootkit_linux234 디렉토리에서 확인된 루트킷과 백도어는 과거 당사가 조사한 국내 금융회사 침해사고와 관련있다.1.1. tomcat20220420_rootkit1.1.1. Backdoorwork/home/user/Desktop/tomcat20220420_rootkit/tomcat20220420_rootkit/work 디렉토리 내에 백도어 소스코드가 존재한다. 백도어 주요 행위는 명령코드에 따라 악성 행위를 하거나 프록시 역할로 통신을 중계한다. 백도어는 단독으로 실행되지 않고, 항상 루트킷에 의해 실행된다. 백도어 실행 인자 정보는 아래 표와 같다.caption - 인자 옵션프록시 플래그가 활성화되어 있으면 명령코드 관련 로직은 실행되지 않고, AES-CBC-256으로 암호된 데이터(__step2__)를 수신할 때까지 대기한다.caption - master.c 데이터 검사 로직AES key와 iv는 아래와 같다.AES key: 603deb15153a715e2b73aef3857d758b1f552c573e6158d72d9811a33914defeiv: 603deb15153a715e2b73aef3857d758b1f552c573e6158d72d9811a33914defe백도어는 정상 통신으로 위장하기 위해 클라이언트와의 소켓 통신을 아래 프로토콜 중 하나로 설정한다.HTTPHTTPSSSLTCPSMTP실제로 사용하는 프로토콜은 install_common.h에 정의되어 있다.caption - install_common.h명령코드를 포함한 모든 송수신 데이터는 xor로 암·복호화된다. 이때 사용되는 키는 "1101link"인데, 암·복호화 로직을 보면 단일 바이트와 한 번 xor한 것과 동일하다. 따라서 "1101link"와 xor 한 결과는, 1과 xor한 것과 동일하다.caption - encrypt.c EncodeDecode 함수명령코드에 따른 행위는 아래 표와 같다.caption - 백도어 명령코드 행위1.1.2. syslogk rootkitwork/home/user/Desktop/tomcat20220420_rootkit/tomcat20220420_rootkit/main.c 파일은 syslogk로 명명된 루트킷 소스코드이다. 루트킷은 백도어 및 관련 악성코드가 위치한 디렉터리를 은닉하여 일반적으로 탐지되지 않도록 한다. 또한 매직 패킷 수신 시에만 백도어를 실행하여, 공격자가 원하는 시점에만 백도어가 동작한다.루트킷은 3개의 함수를 후킹해 프로세스, 포트, 디렉토리를 은닉한다. 후킹 관련 정보는 아래 표와 같다.caption - 후킹 정보후킹 함수 내부에서는 사전에 정의된 프로세스 이름, 경로, 포트 문자열과 대상 엔트리를 strstr 함수로 비교해, 일치할 경우 해당 엔트리를 반환하기 전에 제거하는 방식으로 은닉을 구현하였다.이후 Netfilter 관련 nf_register_hook 함수를 사용해 훅 지점에 콜백 함수를 등록한다. nf_reagister_hook에 의해 콜백 함수가 등록되는 두 개의 훅 지점에 대한 설명은 아래와 같다.NF_INET_LOCAL_IN : 로컬 호스트로 패킷을 보내기 전NF_INET_LOCAL_OUT : 로컬 호스트에서 패킷을 외부로 보내기 전caption - hkcap.c 후킹 함수 등록 로직위 방법으로 루트킷은 로컬 호스트에서 오고가는 모든 패킷을 감시하고, 공격자가 보낸 매직 패킷을 확인하면 악성 행위를 한다.NF_INET_LOCAL_IN 지점 콜백 함수는 수신한 패킷 프로토콜이 TCP이고, 페이로드를 복호화해 특정 조건들과 일치하는지 확인한다. 복호화에 사용되는 데이터는 아래 표와 같다.caption - 복호화 키 정보복호화 이후 검증하는 조건 목록과 처리 동작은 아래 표와 같다.caption - 조건 및 행위NF_INET_LOCAL_OUT 지점에서 콜백 함수는, 백도어가 보내는 패킷의 source를 백도어가 통신하지 않는 포트로 변경한다.Netfilter 콜백 함수 등록을 마친 후, 루트킷은 모듈 리스트에서 자기 자신을 제거해 탐지를 어렵게 한다. 이로 인해 lsmod 명령어를 입력해도 루트킷을 찾을 수 없다.caption - hide_module 함수모듈 리스트에서 제거된 루트킷에 install.h의 MAGIC_DRBIN 값을 작성하면 lsmod 명령어로 다시 확인할 수 있다.caption - proc_write 함수 로직1.1.3. Backdoor Clientwork/home/user/Desktop/tomcat20220420_rootkit/tomcat20220420_rootkit/work/tcat.c 파일은 백도어 클라이언트 소스코드이다. 이 파일을 공격자가 C&C 서버에서 실행한 것으로 보인다.실행 시 여러 옵션을 지정할 수 있다. 전체 옵션은 아래 표 참고 바란다.caption - 인자 옵션옵션에 따라 백도어에 명령어를 전달하는 방식은 아래와 같이 4가지로 나누어진다.single cmd : 입력받은 명령어를 백도어에서 실행하도록 전송한다.single daemon cmd : 입력받은 명령어를 백도어에서 새로운 프로세스를 생성하여 실행하도록 전송한다.input loop : exit을 입력받을 때까지 무한히 명령어를 입력받아 명령어에 따른 행위를 수행한다.kernel cmd : 입력받은 명령어를 커널 모듈에서 출력 없이 실행하도록 전송한다.input loop를 제외한 모든 명령어 전달 방식은 전송 이후 클라이언트가 종료된다. input loop에서 명령어에 따라 수행하는 행위는 아래 표와 같다.caption - 백도어 클라이언트 명령어 행위모든 통신은 xor key(1101link)로 암호화되어 이루어지고, common.h 파일에 정의된 GENERAL_MODULE, GENERAL_PROTOCOL 값을 패스워드와 함께 sha512로 해싱하여 항상 메시지의 맨 앞에 붙여 전송한다. 백도어와의 통신은 옵션에 따라 아래 프로토콜 중 하나로 설정된다.TCPHTTPOLD HTTP - OLD HTTP는 일반적인 HTTP와 달리 쿠키 값을 설정하지 않는다.1.2. tomcat20250414_rootkit_linux2341.2.1. Backdoorwork/mnt/hgfs/Desktop/tomcat20250414_rootkit_linux234/tomcat20250414_rootkit_linux2345/work 디렉토리 내에 2022년 버전의 백도어와 동일한 2025년 버전의 백도어 소스코드가 존재한다. 2022년 버전 백도어의 업그레이드 버전으로, callback 딜레이 통신 시 패스워드를 확인하며 시간을 지정하거나 파일 다운로드, 업로드 속도를 제한하는 등의 기능이 추가되었다. 전체 옵션은 아래 표와 같다.caption - 인자 옵션패스워드 외에 마스터 패스워드가 추가되었는데, 지정 포트로 소켓 서버를 생성하고, 클라이언트 연결 시 마스터 패스워드와 통신 설정 정보를 sha512로 해싱한다. 마스터 패스워드는 common.h에 정의된 !@nf4@#fndskgadnsewngaldfkl을 사용한다. 해시 값은 전역 변수에 저장되고, ssl 통신 시 통신 설정 정보가 올바른지 확인하지만 실제로 사용되지 않는다.이후 패스워드를 마스터 패스워드 확인 로직과 동일하게 통신 설정 정보와 sha512 해싱하여 동일한지 확인한다.caption - encrypt.c passcheck_check 함수패스워드는 Miu2jACgXeDsxd로, 패스워드를 포함한 설정 정보는 config.sh 파일에서 원하는 값으로 변경하면 빌드할 때 적용된다.caption - config.sh 기본 설정 정보통신에 사용되는 프로토콜 목록은 2022 백도어와 동일하다.HTTPHTTPSSSLTCPSMTP데이터를 암·복호화하는 xor key도 동일하지만 5개의 xor key와 암·복호화 함수가 추가되었다.caption - encrypt.c에서 확인한 전체 xor key2022 백도어에 비해 여러 행위가 추가되었고, 패킷 조건이 바뀌며 TRANSFER이 붙은 명령코드 행위가 변경되었다. 새로 추가된 명령코드는 아래와 같다.CMD_NEW_UPLOADCMD_NEW_DOWNLOADCMD_LISTEN_PROXY_TRANSCMD_TRANSFERCMD_PROXY_TRANSFERCMD_SOCKS_PROXY_TRANSFERCMD_SOCKS_PROXYCMD_NEW_SINGLE_CMD명령코드에 따른 행위는 아래 표와 같다.caption - 백도어 명령코드 행위1.2.2. syslogk rootkitwork/mnt/hgfs/Desktop/tomcat20250414_rootkit_linux234/tomcat20250414_rootkit_linux2345/main.c 파일은 2022년 버전 루트킷과 동일하게 Netfilter 훅 지점에 콜백 함수를 등록한다. 변경된 점은 함수 후킹, 모듈 은닉, 새로 추가된 Netfilter 훅 지점이다.2022 루트킷에서는 함수 후킹을 위해 udis86 라이브러리를 사용한 것과 달리 2025 루트킷에서는 khook 라이브러리를 사용하였다.caption - 좌)2022 루트킷 udis86 라이브러리, 우) 2025 루트킷 khook 라이브러리후킹 대상 함수가 3개였던 2022 루트킷과 달리 총 5개의 함수를 후킹한다. 후킹 관련 정보는 아래 표와 같다.caption - 후킹 정보Netfilter 훅은 기존 NF_INET_LOCAL_IN, NF_INET_LOCAL_OUT 2개의 훅 지점에서 2개가 추가되었다.NF_INET_LOCAL_IN : 로컬 호스트로 패킷을 보내기 전NF_INET_LOCAL_OUT : 로컬 호스트에서 패킷을 외부로 보내기 전NF_INET_PRE_ROUTING : 패킷이 네트워크 스택에 들어온 직후NF_INET_POST_ROUTING : 라우팅이 발생한 후 네트워크에 놓여지기 직전caption - hkcap.c 후킹 함수 등록 로직NF_INET_PRE_ROUTING 지점의 콜백 함수는 크게 2가지 행위를 한다.첫 번째는 2022 루트킷의 NF_INET_LOCAL_IN 지점과 동일하게 패킷 조건을 검사하여 백도어를 실행한다. 패킷 조건이 복잡한 2022 루트킷과 달리 NF_INET_PRE_ROUTING 지점 콜백 함수는 TCP + SYN 패킷이고, id와 seq 값이 id_list, seq_list에 존재하는지 확인한다.조건을 만족한 패킷의 window 값을 매직 패킷 값과 비교하여, 값에 따라 위장 프로토콜을 설정해 백도어를 실행한다. 매직 패킷 값에 따른 위장 프로토콜은 아래 표와 같다.caption - 위장 프로토콜 목록백도어를 실행하는 방법에도 큰 차이가 있다. /bin/sh -c 를 사용한 2022 루트킷과 달리, call_usermodehelper 함수로 백도어를 실행한다. 이때 포트는 3000 ~ 8000 사이의 랜덤한 포트를 사용한다.caption - hkcap.c kernel_run 함수두 번째는 백도어와 통신 중인 ip에서 전송된 패킷의 dest 값을 위에서 생성된 랜덤 포트로 변경한다. 이는 공격자가 랜덤으로 생성된 백도어의 포트를 몰라도 통신을 할 수 있는 로직이다.caption - 패킷의 dest 값을 변경하는 hkcap.c 코드NF_INET_LOCAL_IN 지점의 콜백 함수는 NF_IP_PRE_ROUTING에서 변경된 패킷의 dest 값을 실제 백도어에서 사용하는 포트로 변경한다. 이는 2번에 걸쳐 포트를 바꾸며 실제 백도어가 사용하는 포트를 찾기 어렵게 하기 위함으로 보인다.caption - 패킷의 dest 값을 백도어가 사용하는 포트로 변경하는 hkcap.c 코드NF_INET_LOCAL_OUT 지점의 콜백 함수는 백도어가 보낸 패킷의 source 값이 백도어의 listen 포트이면, 임의 포트로 변경하고 아닌 경우에는 실제로 외부로 보낼 포트로 변경한다.NF_INET_POST_ROUTING 지점의 콜백 함수는 source 값이 임의 포트로 변경된 패킷의 source 값을 실제로 외부로 보낼 포트로 변경한다.caption - 패킷의 dest 값을 공격자의 포트로 변경하는 hkcap.c 코드루트깃 은닉은 모듈 리스트에서 자기 자신을 제거하는 거 외에도 sysfs에서도 제거하는 함수가 추가되었다.caption - 모듈 은닉 hkmod.c 코드sysfs 관련 함수는 KoviD 루트킷의 kv_hide_mod 함수를 그대로 사용하였다.caption - KoviD 루트킷의 kv_hide_mod 함수은닉된 루트킷에 특정 문자열을 작성하면 다시 모듈이 보이는 것은 동일하지만 작성된 문자열에 따라 Netfilter 훅에서 변경하는 포트의 값을 지정하는 기능이 추가되었다.caption - 포트 값을 지정하는 hkcap.c 코드루트킷에 데이터를 작성할 때 모듈을 보이게 하는 문자열을 제외한 모든 문자열은 AES-CBC-256으로 복호화해 확인한다. AES key와 iv는 아래와 같다.AES key: d03deb92153a71458973aef3857d75b27e552cc63e6158a8339811873994de47iv: efa3c987532cc0bdac533845ad8df5ea루트킷에 작성한 문자열에 따른 행위는 아래와 같다.caption - 문자열 및 행위1.2.3. Backdoor Clientwork/mnt/hgfs/Desktop/tomcat20250414_rootkit_linux234/tomcat20250414_rootkit_linux2345/work/tcat.c 파일은 백도어 클라이언트 소스코드이다. 2022 백도어 클라이언트와 비교하였을 때, kernel cmd 기능이 사라진 점 외에는 큰 변화가 없으며 옵션 또한 kc 옵션이 사라지고 LLL 옵션이 생겼다. 전체 옵션은 아래 표 참고 바란다.caption - 인자 옵션앞서 언급한 거처럼 kernel cmd 기능이 삭제되어 백도어에 명령어를 전달하는 방식은 아래와 같이 3가지가 존재한다.single cmd : 입력 받은 명령어를 백도어에서 실행하도록 전송한다.single daemon cmd : 입력받은 명령어를 백도어에서 새로운 프로세스를 생성하여 실행하도록 전송한다.input loop : exit을 입력 받을 때까지 무한히 명령어를 입력 받아 명령어에 따라 다른 행위를 수행한다.2022 백도어 클라이언트는 오직 명령어만 입력받아 통신하였으나 2025 백도어 클라이언트는 명령어 별로 옵션을 지정할 수 있게 되어 명령어의 개수는 줄었지만 수행할 수 있는 행위는 더욱 정교해졌다. input loop에서 명령어에 따라 수행하는 행위는 아래 표와 같다.caption - 백도어 클라이언트 명령어 행위현재 tcat_new_send_file, tcat_new_recv_file과 같이 추가적으로 작성된 명령어의 주요 함수들이 정의가 안되어있어 추가된 기능의 상세 분석은 불가하였다.통신할 때 매번 패스워드의 sha512 해시 값을 보내던 2022 백도어 클라이언트와는 달리 2025 백도어 클라이언트는 첫 연결 시에만 패스워드의 sha512 해시 값을 전송한다.백도어와의 모든 통신은 2022 백도어 클라이언트와 동일하게 xor key(1101link)로 암호화되어 이루어진다. 하지만 3개의 프로토콜을 지정할 수 있는 2022 백도어 클라이언트와는 달리 2025 백도어 클라이언트는 아래 4개의 프로토콜 중 하나로 설정된다. 특히 OLD HTTP가 삭제되었으며 HTTPS, SMTP가 추가되었다.TCPHTTPHTTPSSMTP1.3. Cobalt Strike1.3.1. Cobalt Strike LoaderRust로 작성된 로더 악성코드로, 내장된 쉘코드를 복호화하고 메모리에서 실행한다. Cobalt Strike Loader 파일 경로는 아래와 같다.work/mnt/hgfs/Desktop/New folder (2)/DboRrmSS.exework/mnt/hgfs/Desktop/New folder (2)/m01QzOfI.exework/mnt/hgfs/Desktop/New folder (2)/voS9AyMZ.tar.gzwork/home/user/.cache/vmware/drag_and_drop/0pkbW4/3Powwovv.exework/home/user/.cache/vmware/drag_and_drop/gWMDML/GnAN3FhY.exework/home/user/.cache/vmware/drag_and_drop/QqiN9h/DboRrmSS.exework/home/user/.cache/vmware/drag_and_drop/rM0FG0/m01QzOfI.exeWindows API를 호출 할 때, djb2 해시 값을 계산해 동적으로 로드하고, 쉘코드는 AES-CBC-256으로 복호화한다. 이후 복호화된 쉘코드를 메모리에서 실행한다.caption - Window API 로딩 함수모든 Cobalt Strike Loader에서 사용하는 AES key와 iv는 아래 표와 같다.caption - Cobalt Strike Loader AES key, iv 목록1.3.2. ShellcodeCobalt Strike Loader에 의해 실행되는 쉘코드로, Cobalt Strike Beacon을 복호화하여 메모리에서 실행한다. 파일 형태로 존재하는 쉘코드 경로는 아래와 같다.work/home/user/.cache/vmware/drag_and_drop/5wdgDr/payload.binwork/home/user/.cache/vmware/drag_and_drop/6bX9mm/Black.x64.exework/home/user/.cache/vmware/drag_and_drop/NDBu65/payload.binwork/home/user/.cache/vmware/drag_and_drop/yf91yD/payload.binwork/home/user/.cache/vmware/drag_and_drop/zlLWeR/payload.binwork/home/user/.cache/vmware/drag_and_drop/6bX9mm/Black.x64.exe는 다른 쉘코드 파일들과 행위가 동일하지만 쉘코드가 아닌 컴파일된 실행 파일이다.caption - Black.x64.exe DIE 결과Cobalt Strike Loader와 마찬가지로 djb2 해시 값을 계산해 Windows API를 동적으로 로드한 뒤 호출하고, 이후 Cobalt Strike Beacon을 RC4로 복호화해 메모리에서 실행한다.caption - RC4 ksa 함수모든 쉘코드에서 사용하는 RC4 key는 아래 표와 같다. 파일 형태로 존재하지 않고, Cobalt Strike Loader에 의해 실행되는 쉘코드도 포함하였다.caption - 쉘코드 RC4 key 목록쉘코드에 의해 실행되는 Cobalt Strike Beacon은 ETW 관련 함수와 AMSI.dll 함수를 패치하여 Windows 보안 기능을 우회하는 로직이 존재한다. 하지만 암호화된 설정 정보가 온전하지 않아 설정 정보는 확인할 수 없었다.1.3.3. Cobalt Strike Beaconwork/mnt/hgfs/Desktop/111/beacon 디렉토리 내에 Cobalt Strike Beacon 소스코드가 존재한다. Beacon 실행 시 설정 정보는 1바이트 xor 키(46)로 복호화되고, 복호화된 설정 정보는 블록으로 구성되며, 각 블록은 아래와 같은 구조를 갖는다.복호화된 설정 정보는 파싱하여 전역변수에 저장된 후 필요한 값이 있을 때 인덱스로 접근하여 사용한다. CobaltStrikeParser를 이용해 파싱한 일부 설정 정보는 아래와 같다.caption - CobaltStrikeParser 결과복호화된 설정 정보에는 C&C 서버 주소와 엔드포인트가 포함되어 있으나, 실행 과정에서 해당 값은 사용되지 않고 소스코드에 하드코딩된 값을 사용한다.caption - comm.cpp send_Metadata 함수설정 정보 복호화가 완료되면 C&C 서버에 전송할 메타데이터를 생성한다. 주요 메타데이터 정보는 아래 표와 같다.caption - 메타데이터 정보메타데이터 생성이 완료되면 C&C 서버로 전송하고, 이후 5초마다 HTTP 기반 폴링 통신을 수행한다. 이때 명령 수신에는 GET, 결과 전송에는 POST가 사용된다. 수신한 명령 id에 따라 행위를 수행하고, 결과를 C&C 서버로 전송한다. 전체 행위는 아래 표와 같다.caption - Cobalt Strike Beacon 행위절반 이상의 행위가 미구현 또는 비활성화되어 있으며, Cobalt Strike Beacon은 미완성 악성코드로 추측된다.1.3.4. C# Loaderwork/home/user/Desktop/0128 디렉토리 내에는 다른 프로세스에 Cobalt Strike Beacon을 인젝션하는 C# 로더(ok.dll)와 소스코드(ok.cs), 해당 로더를 실행하는 스크립트(ok.sct) 등이 존재한다.함수 이름과 인자 값에 test 문자열이 다수 포함되어 있어 테스트용 파일로 추정된다.ok.htahxxp://192.168[.]123.200/ok.sct에 접속하여 스크립트를 다운받아 Fuk 함수를 실행한다.caption - ok.hta 파일 내용다운받는 스크립트는 같은 경로에 있는 ok.sct로 추정된다.ok.sct직렬화된 C# 객체를 역직렬화한 뒤 Work 함수를 실행한다. 이때 실행되는 파일은 ok.cs를 컴파일한 ok.dll이다. ok.cs에서 Work 함수를 확인할 수 있다.caption - C# Loader 역직렬화 코드C# 로더는 conhost.exe 프로세스에 Cobalt Strike Beacon을 인젝션하여 실행한다. Cobalt Strike Beacon은 zlib 압축 및 base64 인코딩되어 문자열로 저장되어 있다.caption - Cobalt Strike Beacon 디코딩 함수CobaltStrikeParser를 이용해 파싱한 Cobalt Strike Beacon의 일부 설정 정보는 아래와 같다.caption - C# Loader에 저장된 Cobalt Strike Beacon 설정 정보1.4. Ivanti Connect Secure1.4.1. BRUSHFIREwork/mnt/hgfs/Desktop/ivanti-new-exp-20241220.zip 파일의 압축을 해제하면 Ivanti Connect-Secure RCE 취약점을 악용하여 백도어를 유포하는 exp*.py 파일을 확인할 수 있다.python 스크립트에서 clientCapabilities 값의 길이를 256바이트를 초과하도록 설정하는데, 이는 clientCapabilities에서 발생하는 256바이트 버퍼 오버플로우로 인해 RCE로 이어지는 CVE-2025-0282를 사용하는 것으로 보인다.caption - ex*.py 로직CVE-2025-0282는 과거 중국 배후로 알려진 해킹 그룹 UNC5221에서 공격의 초기벡터로 사용한 적이 있는 취약점이다.해당 취약점을 악용하는 모든 exp*.py는 행위가 동일하고, 익스플로잇에 사용되는 함수 오프셋 혹은 접속하는 서비스의 엔드포인트에만 차이가 존재한다. 실행 인자에 따른 exp*.py 행위는 아래 표와 같다.caption - 인자 옵션백도어는 plugins/ssl_read 파일로, RCE로 트리거된 plugins/install 파일이 백도어를 ssl_read 함수에 후킹한다. 후킹된 ssl_read 함수는 ssl 통신을 수신할 때, 배포 시 설정된 매직 바이트 값이 존재하는 패킷을 탐지하면 exp*.py에서 무작위로 생성된 4바이트 키와 xor하여 쉘코드를 실행한다.caption - ssl_read 쉘코드 실행 로직exp*.py는 실행 인자에 따라 쉘코드를 생성하고 공격 대상 서버에 업로드한다. 이때 쉘코드의 하드코딩된 패턴을 replace 함수를 사용하여, 유효하지 않은 코드를 공격 대상에 유효한 값으로 변경한다. plugins 내에 존재하는 쉘코드를 업로드하는 exp*.py 실행 인자와 쉘코드 행위는 아래 표와 같다.caption - 실행 인자 및 쉘코드 행위plugins/ssl_read백도어 행위는 UNC5221 공격에 사용된 BRUSHFIRE 악성코드와 동일하며, 공격에서 확인된 BRUSHFIRE 파일 경로와 ssl_read 파일 경로가 동일하다.1.4.2. SPAWN Family Clientwork/mnt/hgfs/Desktop/New folder/203.234.192.200_client.zip 파일 내에는 터널링 스크립트와 ssh 클라이언트, 인증서 파일이 압축되어 있다. readme.txt 파일에는 client.py, controller.py를 사용하여 203.234[.]192.200 ip에 접속하는 방법이 적혀있으며 해당 ip는 한겨레 신문사의 ip 주소로 확인되었다.caption - readme.txt 파일 내용client.py는 네트워크 트래픽을 터널링하기 위한 SOCKS5 프록시를 실행하고, client.py의 옵션 별 기능은 아래와 같다.caption - 옵션 별 기능client.py에는 client_hello와 client_key_exchange 메시지 템플릿이 사전 정의되어 있다. 동작은 아래와 같다.client_hello인덱스 11–15 위치에, 인덱스 15–43(랜덤 28바이트)에 대한 CRC32 값을 삽입한 뒤 전송한다.sessionid 변수에 랜덤 32바이트를 저장하고, 이를 메시지에 포함해 전송한다.client_key_exchangepremaster 필드에 랜덤 256바이트, enc_handshake_msg 필드에 랜덤 32바이트를 포함해 전송한다.client.py에 정의된 client_hello 초기 값은 UNC5221 공격에서 확인된 SPAWNMOLE의 매직 패킷과 일치하다. 실행 시에는 client_hello의 인덱스 15–43 구간에 랜덤 28바이트를 기록하고, 그에 대한 CRC32를 인덱스 11–15에 덮어써 전송하는데, 이 방법은 JPCert 블로그 글에서 보고된 SPAWNCHIMERA 설명과 유사하다.SPAWNCHIMERA 역시 SPAWNMOLE과 동일하게 UNC5221 공격에 사용된 악성코드로, 앞서 ssl_read 백도어 유포에 악용된 CVE-2025-0282 취약점을 통해 유포된 악성코드이다.controller.py는 client.py에서 실행된 SOCKS5 프록시를 통해서 ssh 서버와 통신하는 클라이언트 스크립트이다.caption - ssh 서버와 통신하는 controller.pySPAWNMOLE은 ssh 서버를 생성하는 SPAWNSNAIL과 함께 확인되었고, SPAWNCHIMERA는 자체적으로 ssh 서버를 구동하는 기능을 포함한다. 이에 따라 controller.py는 SPAWNSNAIL 또는 SPAWNCHIMERA가 제공하는 ssh 서버에 접속하는 클라이언트로 판단된다.1.4.3. ROOTROT Clientwork/mnt/hgfs/Desktop/ivanti_control/main.py는 입력받은 명령어에 따라 Perl 스크립트 조각을 생성하고, 이를 Base64로 인코딩하여 특정 쿠키 값에 설정한 뒤 HTTP GET 요청을 전송한다. 명령어에 따른 Perl 스크립트는 다음과 같다.download {file_path}{command}두 Perl 스크립트 모두 실행 결과를 base64로 인코딩한 뒤 html 주석으로 감싸 출력한다. 이후 main.py는 서버 응답을 수신하면 본문 마지막 html 주석을 추출하여 base64 디코딩한 후 사용자에게 출력한다.caption - 요청을 보내고 주석의 내용을 디코딩하는 함수Perl로 작성된 웹쉘인 점, 쿠키 값을 base64로 디코딩하여 eval로 실행한다는 점, 실행 결과가 base64로 인코딩되어 html 주석으로 전달된다는 점을 토대로 main.py UNC5221 공격에 사용된 ROOTROT 악성코드의 클라이언트 스크립트로 추정된다.또한 ROOTROT 역시 앞서 언급한 UNC5221 공격에 사용된 악성코드들과 마찬가지로 Ivanti Connect Secure 취약점을 악용한 공격에서 발견되었다.1.5. 피싱 공격1.5.1. 네이버 중간자 공격work/mnt/hgfs/Desktop/New folder/vps2/Cipherishing 디렉토리 내에 있는 파일은 네이버 계정을 노린 중간자 공격과 관련있는 파일들이다. 특히 work/mnt/hgfs/Desktop/New folder/readme.txt 파일에서 중국어로 작성된 설정 방법을 확인할 수 있다.caption - readme.txt 파일 내용readme.txt 파일 내용 번역 결과는 아래와 같다.work/mnt/hgfs/Desktop/New folder/vps2/Cipherishing/cipherginx.py 파일은 C&C 서버에서 실행되고, 네이버와 피해자 사이에서 HTTPS 프록시 서버로 동작한다. 피해자가 C&C 서버를 통해 네이버 서비스에 접속하면 헤더와 쿠기, 그리고 아이디와 비밀번호가 cookies 디렉토리에 저장된다. 각 파일 이름은 아래와 같다.[nid_id].headers[nid_id].cookieaccounts.txtcaption - cipherginx.py accounts.txt 생성 로직work/mnt/hgfs/Desktop/New folder/vps2/Cipherishing/naverconfig.py 파일에 네이버 계정 정보를 탈취하는 자바스크립트 코드가 존재하고, 피해자가 로그인 페이지에 접속하면 원본 페이지에 해당 자바스크립트 코드를 삽입한다.caption - naverconfig.py 계정 정보 탈취 자바스크립트 코드탈취한 계정 정보를 이용해 피해자 네이버 메일, 주소록, 로그인 정보 등을 탈취하는 파일이 존재한다. 각 파일 경로와 설명은 아래 표와 같다.caption - 각 파일 설명1.5.2. 카카오 로그인 피싱 공격vps/var/www/html/templates/kakao.html 파일은 카카오 로그인 페이지 템플릿이고, vps/var/www/html/kakao-login.php 파일은 카카오 로그인 처리 서버측 스크립트로 확인되었다. kakao-login.php는 GET 요청 시 “ft” 쿠키 존재 여부를 검사하며, 값이 존재할 경우 “https://mail.daum.net”으로 리다이렉트 한다.caption - GET 요청 처리 코드“ft” 쿠키 값이 존재하지 않으면 카카오 로그인 페이지를 보여주고, 사용자가 로그인을 시도하면 입력한 로그인 정보가 POST 요청 본문에 담겨 피싱 페이지로 전송된다.POST 요청을 받으면 로그인 정보를 log/password_log.txt 파일에 작성하고, ft 쿠키 값을 no로 설정한다.caption - POST 요청 처리 코드password_log.txt 파일에 14개의 로그인 정보가 존재하나, 이 중 하나의 로그인 정보를 제외한 모든 내용은 테스트용으로 보인다. 123123, ttttt222, qwqwqw111 등의 데이터가 존재한다.1.5.3. 피싱 이메일 공격vps/var/www/html 디렉토리 내에는 피싱 이메일 생성과 피해자 관리 목적의 웹서버 파일이 존재한다.웹서버에서 동작하는 파일은 로그 파일을 생성하고, generator.php를 제외한 나머지 파일의 로그 형식은 아래와 같다.로그 파일은 생성될 때 .txt 확장자 뒤에 날짜 정보가 추가된다.generator.phpvps/var/www/html/generator.php파일은 피싱 이메일을 생성하는 파일이다. “HnoplYTfPX” 쿠키 값과 요청 메소드에 따라 실행 로직이 다르다. 아래 표 참고 바란다.caption - 실행 로직피싱 이메일 생성 시 정보를 입력받는 form의 형식은 아래 표와 같다.caption - 피싱 이메일 생성 form 형식피싱 이메일 생성이 완료되면 사용자에게 출력되는 정보는 아래 표와 같다.caption - 출력 정보피싱 이메일 내용이 content로 보이며, 피싱 이메일이 생성되면 log/generator_log.txt 파일에 로그를 작성한다. 로그 형식은 아래와 같다.또한 공격 대상이 피싱 이메일을 열람하였을 때 이메일 클라이언트가 외부 리소스를 로드하도록 설정되어 있으면 request.php가 로드된다.request.phpvps/var/www/html/request.php 파일은 공격 대상의 피싱 이메일 열람 여부를 로그로 남기는 파일이다. 요청이 오면 log/request_log.txt 파일에 로그를 작성한다.URI에 “.png”가 존재하면 무작위 색 이미지를 반환하고 이외의 경우 공격 대상의 브라우저에 따라 정보를 수집하는 자바스크립트 파일을 로드한다. 로드되는 자바스크립트 파일과 수집 정보는 아래 표 참고 바란다.caption - 자바스크립트 파일 및 수집 정보수집한 정보는 results 변수에 저장되고, 이후 response.php?i={b64encode(email)}&{results} 로 요청을 보낸다.response.phpvps/var/www/html/response.php 파일은 공격 대상의 ip, user-agent, locale를 검사하여 조건을 만족하면 i 파라미터 값을 base64 디코딩한 뒤 log/response_log.txt 파일에 로그를 작성한다. 조건은 다음과 같다.locale이 화이트리스트에 포함된 경우ip, user-agent가 블랙리스트에 포함되지 않은 경우locale 화이트리스트는 아래 참고 바란다.usjpjakrkouser-agent 블랙리스트는 아래 참고 바란다.botspidercrawltrendsymantecvirusspamsecureip 블랙리스트는 아래 표 참고 바란다.caption - ip 블랙리스트피싱 공격에 사용된 파일과 로그, 실제 피해 로그를 종합한 정보는 아래 표와 같다.caption - 전체 로그 및 실제 피해 로그1.6. 연세대학교 이메일 탈취 악성코드vps/var/www/html/js/chks.js 파일은 “https://mail.yonsei.ac.kr/common/json/agent.do”에서 유저 정보를 수집하고, 이메일 포워딩 주소 목록에 cimoon185@daum.net 를 추가한다.caption - chks.js Forward 함수이후 ent_{user}, TOTAL 메일함에서, 발송일이 2017-10-01 이후인 이메일을 탈취해 https://service.navers.org/emuy.php?i={user}로 전송한다.

엔키화이트햇
2025. 9. 22.

위협 인텔리전스
APT Down - The North Korea Files 공개 자료 상세 분석 보고서
본 장에서는 공격자 VMware VM 덤프 파일에서 확인된 악성코드와 VPS 덤프 파일에서 확인된 스피어 피싱 공격 및 인프라 운용 정황에 대한 내용을 다룬다. 특히 tomcat20220420_rootkit, tomcat20250414_rootkit_linux234 디렉토리에서 확인된 루트킷과 백도어는 과거 당사가 조사한 국내 금융회사 침해사고와 관련있다.1.1. tomcat20220420_rootkit1.1.1. Backdoorwork/home/user/Desktop/tomcat20220420_rootkit/tomcat20220420_rootkit/work 디렉토리 내에 백도어 소스코드가 존재한다. 백도어 주요 행위는 명령코드에 따라 악성 행위를 하거나 프록시 역할로 통신을 중계한다. 백도어는 단독으로 실행되지 않고, 항상 루트킷에 의해 실행된다. 백도어 실행 인자 정보는 아래 표와 같다.caption - 인자 옵션프록시 플래그가 활성화되어 있으면 명령코드 관련 로직은 실행되지 않고, AES-CBC-256으로 암호된 데이터(__step2__)를 수신할 때까지 대기한다.caption - master.c 데이터 검사 로직AES key와 iv는 아래와 같다.AES key: 603deb15153a715e2b73aef3857d758b1f552c573e6158d72d9811a33914defeiv: 603deb15153a715e2b73aef3857d758b1f552c573e6158d72d9811a33914defe백도어는 정상 통신으로 위장하기 위해 클라이언트와의 소켓 통신을 아래 프로토콜 중 하나로 설정한다.HTTPHTTPSSSLTCPSMTP실제로 사용하는 프로토콜은 install_common.h에 정의되어 있다.caption - install_common.h명령코드를 포함한 모든 송수신 데이터는 xor로 암·복호화된다. 이때 사용되는 키는 "1101link"인데, 암·복호화 로직을 보면 단일 바이트와 한 번 xor한 것과 동일하다. 따라서 "1101link"와 xor 한 결과는, 1과 xor한 것과 동일하다.caption - encrypt.c EncodeDecode 함수명령코드에 따른 행위는 아래 표와 같다.caption - 백도어 명령코드 행위1.1.2. syslogk rootkitwork/home/user/Desktop/tomcat20220420_rootkit/tomcat20220420_rootkit/main.c 파일은 syslogk로 명명된 루트킷 소스코드이다. 루트킷은 백도어 및 관련 악성코드가 위치한 디렉터리를 은닉하여 일반적으로 탐지되지 않도록 한다. 또한 매직 패킷 수신 시에만 백도어를 실행하여, 공격자가 원하는 시점에만 백도어가 동작한다.루트킷은 3개의 함수를 후킹해 프로세스, 포트, 디렉토리를 은닉한다. 후킹 관련 정보는 아래 표와 같다.caption - 후킹 정보후킹 함수 내부에서는 사전에 정의된 프로세스 이름, 경로, 포트 문자열과 대상 엔트리를 strstr 함수로 비교해, 일치할 경우 해당 엔트리를 반환하기 전에 제거하는 방식으로 은닉을 구현하였다.이후 Netfilter 관련 nf_register_hook 함수를 사용해 훅 지점에 콜백 함수를 등록한다. nf_reagister_hook에 의해 콜백 함수가 등록되는 두 개의 훅 지점에 대한 설명은 아래와 같다.NF_INET_LOCAL_IN : 로컬 호스트로 패킷을 보내기 전NF_INET_LOCAL_OUT : 로컬 호스트에서 패킷을 외부로 보내기 전caption - hkcap.c 후킹 함수 등록 로직위 방법으로 루트킷은 로컬 호스트에서 오고가는 모든 패킷을 감시하고, 공격자가 보낸 매직 패킷을 확인하면 악성 행위를 한다.NF_INET_LOCAL_IN 지점 콜백 함수는 수신한 패킷 프로토콜이 TCP이고, 페이로드를 복호화해 특정 조건들과 일치하는지 확인한다. 복호화에 사용되는 데이터는 아래 표와 같다.caption - 복호화 키 정보복호화 이후 검증하는 조건 목록과 처리 동작은 아래 표와 같다.caption - 조건 및 행위NF_INET_LOCAL_OUT 지점에서 콜백 함수는, 백도어가 보내는 패킷의 source를 백도어가 통신하지 않는 포트로 변경한다.Netfilter 콜백 함수 등록을 마친 후, 루트킷은 모듈 리스트에서 자기 자신을 제거해 탐지를 어렵게 한다. 이로 인해 lsmod 명령어를 입력해도 루트킷을 찾을 수 없다.caption - hide_module 함수모듈 리스트에서 제거된 루트킷에 install.h의 MAGIC_DRBIN 값을 작성하면 lsmod 명령어로 다시 확인할 수 있다.caption - proc_write 함수 로직1.1.3. Backdoor Clientwork/home/user/Desktop/tomcat20220420_rootkit/tomcat20220420_rootkit/work/tcat.c 파일은 백도어 클라이언트 소스코드이다. 이 파일을 공격자가 C&C 서버에서 실행한 것으로 보인다.실행 시 여러 옵션을 지정할 수 있다. 전체 옵션은 아래 표 참고 바란다.caption - 인자 옵션옵션에 따라 백도어에 명령어를 전달하는 방식은 아래와 같이 4가지로 나누어진다.single cmd : 입력받은 명령어를 백도어에서 실행하도록 전송한다.single daemon cmd : 입력받은 명령어를 백도어에서 새로운 프로세스를 생성하여 실행하도록 전송한다.input loop : exit을 입력받을 때까지 무한히 명령어를 입력받아 명령어에 따른 행위를 수행한다.kernel cmd : 입력받은 명령어를 커널 모듈에서 출력 없이 실행하도록 전송한다.input loop를 제외한 모든 명령어 전달 방식은 전송 이후 클라이언트가 종료된다. input loop에서 명령어에 따라 수행하는 행위는 아래 표와 같다.caption - 백도어 클라이언트 명령어 행위모든 통신은 xor key(1101link)로 암호화되어 이루어지고, common.h 파일에 정의된 GENERAL_MODULE, GENERAL_PROTOCOL 값을 패스워드와 함께 sha512로 해싱하여 항상 메시지의 맨 앞에 붙여 전송한다. 백도어와의 통신은 옵션에 따라 아래 프로토콜 중 하나로 설정된다.TCPHTTPOLD HTTP - OLD HTTP는 일반적인 HTTP와 달리 쿠키 값을 설정하지 않는다.1.2. tomcat20250414_rootkit_linux2341.2.1. Backdoorwork/mnt/hgfs/Desktop/tomcat20250414_rootkit_linux234/tomcat20250414_rootkit_linux2345/work 디렉토리 내에 2022년 버전의 백도어와 동일한 2025년 버전의 백도어 소스코드가 존재한다. 2022년 버전 백도어의 업그레이드 버전으로, callback 딜레이 통신 시 패스워드를 확인하며 시간을 지정하거나 파일 다운로드, 업로드 속도를 제한하는 등의 기능이 추가되었다. 전체 옵션은 아래 표와 같다.caption - 인자 옵션패스워드 외에 마스터 패스워드가 추가되었는데, 지정 포트로 소켓 서버를 생성하고, 클라이언트 연결 시 마스터 패스워드와 통신 설정 정보를 sha512로 해싱한다. 마스터 패스워드는 common.h에 정의된 !@nf4@#fndskgadnsewngaldfkl을 사용한다. 해시 값은 전역 변수에 저장되고, ssl 통신 시 통신 설정 정보가 올바른지 확인하지만 실제로 사용되지 않는다.이후 패스워드를 마스터 패스워드 확인 로직과 동일하게 통신 설정 정보와 sha512 해싱하여 동일한지 확인한다.caption - encrypt.c passcheck_check 함수패스워드는 Miu2jACgXeDsxd로, 패스워드를 포함한 설정 정보는 config.sh 파일에서 원하는 값으로 변경하면 빌드할 때 적용된다.caption - config.sh 기본 설정 정보통신에 사용되는 프로토콜 목록은 2022 백도어와 동일하다.HTTPHTTPSSSLTCPSMTP데이터를 암·복호화하는 xor key도 동일하지만 5개의 xor key와 암·복호화 함수가 추가되었다.caption - encrypt.c에서 확인한 전체 xor key2022 백도어에 비해 여러 행위가 추가되었고, 패킷 조건이 바뀌며 TRANSFER이 붙은 명령코드 행위가 변경되었다. 새로 추가된 명령코드는 아래와 같다.CMD_NEW_UPLOADCMD_NEW_DOWNLOADCMD_LISTEN_PROXY_TRANSCMD_TRANSFERCMD_PROXY_TRANSFERCMD_SOCKS_PROXY_TRANSFERCMD_SOCKS_PROXYCMD_NEW_SINGLE_CMD명령코드에 따른 행위는 아래 표와 같다.caption - 백도어 명령코드 행위1.2.2. syslogk rootkitwork/mnt/hgfs/Desktop/tomcat20250414_rootkit_linux234/tomcat20250414_rootkit_linux2345/main.c 파일은 2022년 버전 루트킷과 동일하게 Netfilter 훅 지점에 콜백 함수를 등록한다. 변경된 점은 함수 후킹, 모듈 은닉, 새로 추가된 Netfilter 훅 지점이다.2022 루트킷에서는 함수 후킹을 위해 udis86 라이브러리를 사용한 것과 달리 2025 루트킷에서는 khook 라이브러리를 사용하였다.caption - 좌)2022 루트킷 udis86 라이브러리, 우) 2025 루트킷 khook 라이브러리후킹 대상 함수가 3개였던 2022 루트킷과 달리 총 5개의 함수를 후킹한다. 후킹 관련 정보는 아래 표와 같다.caption - 후킹 정보Netfilter 훅은 기존 NF_INET_LOCAL_IN, NF_INET_LOCAL_OUT 2개의 훅 지점에서 2개가 추가되었다.NF_INET_LOCAL_IN : 로컬 호스트로 패킷을 보내기 전NF_INET_LOCAL_OUT : 로컬 호스트에서 패킷을 외부로 보내기 전NF_INET_PRE_ROUTING : 패킷이 네트워크 스택에 들어온 직후NF_INET_POST_ROUTING : 라우팅이 발생한 후 네트워크에 놓여지기 직전caption - hkcap.c 후킹 함수 등록 로직NF_INET_PRE_ROUTING 지점의 콜백 함수는 크게 2가지 행위를 한다.첫 번째는 2022 루트킷의 NF_INET_LOCAL_IN 지점과 동일하게 패킷 조건을 검사하여 백도어를 실행한다. 패킷 조건이 복잡한 2022 루트킷과 달리 NF_INET_PRE_ROUTING 지점 콜백 함수는 TCP + SYN 패킷이고, id와 seq 값이 id_list, seq_list에 존재하는지 확인한다.조건을 만족한 패킷의 window 값을 매직 패킷 값과 비교하여, 값에 따라 위장 프로토콜을 설정해 백도어를 실행한다. 매직 패킷 값에 따른 위장 프로토콜은 아래 표와 같다.caption - 위장 프로토콜 목록백도어를 실행하는 방법에도 큰 차이가 있다. /bin/sh -c 를 사용한 2022 루트킷과 달리, call_usermodehelper 함수로 백도어를 실행한다. 이때 포트는 3000 ~ 8000 사이의 랜덤한 포트를 사용한다.caption - hkcap.c kernel_run 함수두 번째는 백도어와 통신 중인 ip에서 전송된 패킷의 dest 값을 위에서 생성된 랜덤 포트로 변경한다. 이는 공격자가 랜덤으로 생성된 백도어의 포트를 몰라도 통신을 할 수 있는 로직이다.caption - 패킷의 dest 값을 변경하는 hkcap.c 코드NF_INET_LOCAL_IN 지점의 콜백 함수는 NF_IP_PRE_ROUTING에서 변경된 패킷의 dest 값을 실제 백도어에서 사용하는 포트로 변경한다. 이는 2번에 걸쳐 포트를 바꾸며 실제 백도어가 사용하는 포트를 찾기 어렵게 하기 위함으로 보인다.caption - 패킷의 dest 값을 백도어가 사용하는 포트로 변경하는 hkcap.c 코드NF_INET_LOCAL_OUT 지점의 콜백 함수는 백도어가 보낸 패킷의 source 값이 백도어의 listen 포트이면, 임의 포트로 변경하고 아닌 경우에는 실제로 외부로 보낼 포트로 변경한다.NF_INET_POST_ROUTING 지점의 콜백 함수는 source 값이 임의 포트로 변경된 패킷의 source 값을 실제로 외부로 보낼 포트로 변경한다.caption - 패킷의 dest 값을 공격자의 포트로 변경하는 hkcap.c 코드루트깃 은닉은 모듈 리스트에서 자기 자신을 제거하는 거 외에도 sysfs에서도 제거하는 함수가 추가되었다.caption - 모듈 은닉 hkmod.c 코드sysfs 관련 함수는 KoviD 루트킷의 kv_hide_mod 함수를 그대로 사용하였다.caption - KoviD 루트킷의 kv_hide_mod 함수은닉된 루트킷에 특정 문자열을 작성하면 다시 모듈이 보이는 것은 동일하지만 작성된 문자열에 따라 Netfilter 훅에서 변경하는 포트의 값을 지정하는 기능이 추가되었다.caption - 포트 값을 지정하는 hkcap.c 코드루트킷에 데이터를 작성할 때 모듈을 보이게 하는 문자열을 제외한 모든 문자열은 AES-CBC-256으로 복호화해 확인한다. AES key와 iv는 아래와 같다.AES key: d03deb92153a71458973aef3857d75b27e552cc63e6158a8339811873994de47iv: efa3c987532cc0bdac533845ad8df5ea루트킷에 작성한 문자열에 따른 행위는 아래와 같다.caption - 문자열 및 행위1.2.3. Backdoor Clientwork/mnt/hgfs/Desktop/tomcat20250414_rootkit_linux234/tomcat20250414_rootkit_linux2345/work/tcat.c 파일은 백도어 클라이언트 소스코드이다. 2022 백도어 클라이언트와 비교하였을 때, kernel cmd 기능이 사라진 점 외에는 큰 변화가 없으며 옵션 또한 kc 옵션이 사라지고 LLL 옵션이 생겼다. 전체 옵션은 아래 표 참고 바란다.caption - 인자 옵션앞서 언급한 거처럼 kernel cmd 기능이 삭제되어 백도어에 명령어를 전달하는 방식은 아래와 같이 3가지가 존재한다.single cmd : 입력 받은 명령어를 백도어에서 실행하도록 전송한다.single daemon cmd : 입력받은 명령어를 백도어에서 새로운 프로세스를 생성하여 실행하도록 전송한다.input loop : exit을 입력 받을 때까지 무한히 명령어를 입력 받아 명령어에 따라 다른 행위를 수행한다.2022 백도어 클라이언트는 오직 명령어만 입력받아 통신하였으나 2025 백도어 클라이언트는 명령어 별로 옵션을 지정할 수 있게 되어 명령어의 개수는 줄었지만 수행할 수 있는 행위는 더욱 정교해졌다. input loop에서 명령어에 따라 수행하는 행위는 아래 표와 같다.caption - 백도어 클라이언트 명령어 행위현재 tcat_new_send_file, tcat_new_recv_file과 같이 추가적으로 작성된 명령어의 주요 함수들이 정의가 안되어있어 추가된 기능의 상세 분석은 불가하였다.통신할 때 매번 패스워드의 sha512 해시 값을 보내던 2022 백도어 클라이언트와는 달리 2025 백도어 클라이언트는 첫 연결 시에만 패스워드의 sha512 해시 값을 전송한다.백도어와의 모든 통신은 2022 백도어 클라이언트와 동일하게 xor key(1101link)로 암호화되어 이루어진다. 하지만 3개의 프로토콜을 지정할 수 있는 2022 백도어 클라이언트와는 달리 2025 백도어 클라이언트는 아래 4개의 프로토콜 중 하나로 설정된다. 특히 OLD HTTP가 삭제되었으며 HTTPS, SMTP가 추가되었다.TCPHTTPHTTPSSMTP1.3. Cobalt Strike1.3.1. Cobalt Strike LoaderRust로 작성된 로더 악성코드로, 내장된 쉘코드를 복호화하고 메모리에서 실행한다. Cobalt Strike Loader 파일 경로는 아래와 같다.work/mnt/hgfs/Desktop/New folder (2)/DboRrmSS.exework/mnt/hgfs/Desktop/New folder (2)/m01QzOfI.exework/mnt/hgfs/Desktop/New folder (2)/voS9AyMZ.tar.gzwork/home/user/.cache/vmware/drag_and_drop/0pkbW4/3Powwovv.exework/home/user/.cache/vmware/drag_and_drop/gWMDML/GnAN3FhY.exework/home/user/.cache/vmware/drag_and_drop/QqiN9h/DboRrmSS.exework/home/user/.cache/vmware/drag_and_drop/rM0FG0/m01QzOfI.exeWindows API를 호출 할 때, djb2 해시 값을 계산해 동적으로 로드하고, 쉘코드는 AES-CBC-256으로 복호화한다. 이후 복호화된 쉘코드를 메모리에서 실행한다.caption - Window API 로딩 함수모든 Cobalt Strike Loader에서 사용하는 AES key와 iv는 아래 표와 같다.caption - Cobalt Strike Loader AES key, iv 목록1.3.2. ShellcodeCobalt Strike Loader에 의해 실행되는 쉘코드로, Cobalt Strike Beacon을 복호화하여 메모리에서 실행한다. 파일 형태로 존재하는 쉘코드 경로는 아래와 같다.work/home/user/.cache/vmware/drag_and_drop/5wdgDr/payload.binwork/home/user/.cache/vmware/drag_and_drop/6bX9mm/Black.x64.exework/home/user/.cache/vmware/drag_and_drop/NDBu65/payload.binwork/home/user/.cache/vmware/drag_and_drop/yf91yD/payload.binwork/home/user/.cache/vmware/drag_and_drop/zlLWeR/payload.binwork/home/user/.cache/vmware/drag_and_drop/6bX9mm/Black.x64.exe는 다른 쉘코드 파일들과 행위가 동일하지만 쉘코드가 아닌 컴파일된 실행 파일이다.caption - Black.x64.exe DIE 결과Cobalt Strike Loader와 마찬가지로 djb2 해시 값을 계산해 Windows API를 동적으로 로드한 뒤 호출하고, 이후 Cobalt Strike Beacon을 RC4로 복호화해 메모리에서 실행한다.caption - RC4 ksa 함수모든 쉘코드에서 사용하는 RC4 key는 아래 표와 같다. 파일 형태로 존재하지 않고, Cobalt Strike Loader에 의해 실행되는 쉘코드도 포함하였다.caption - 쉘코드 RC4 key 목록쉘코드에 의해 실행되는 Cobalt Strike Beacon은 ETW 관련 함수와 AMSI.dll 함수를 패치하여 Windows 보안 기능을 우회하는 로직이 존재한다. 하지만 암호화된 설정 정보가 온전하지 않아 설정 정보는 확인할 수 없었다.1.3.3. Cobalt Strike Beaconwork/mnt/hgfs/Desktop/111/beacon 디렉토리 내에 Cobalt Strike Beacon 소스코드가 존재한다. Beacon 실행 시 설정 정보는 1바이트 xor 키(46)로 복호화되고, 복호화된 설정 정보는 블록으로 구성되며, 각 블록은 아래와 같은 구조를 갖는다.복호화된 설정 정보는 파싱하여 전역변수에 저장된 후 필요한 값이 있을 때 인덱스로 접근하여 사용한다. CobaltStrikeParser를 이용해 파싱한 일부 설정 정보는 아래와 같다.caption - CobaltStrikeParser 결과복호화된 설정 정보에는 C&C 서버 주소와 엔드포인트가 포함되어 있으나, 실행 과정에서 해당 값은 사용되지 않고 소스코드에 하드코딩된 값을 사용한다.caption - comm.cpp send_Metadata 함수설정 정보 복호화가 완료되면 C&C 서버에 전송할 메타데이터를 생성한다. 주요 메타데이터 정보는 아래 표와 같다.caption - 메타데이터 정보메타데이터 생성이 완료되면 C&C 서버로 전송하고, 이후 5초마다 HTTP 기반 폴링 통신을 수행한다. 이때 명령 수신에는 GET, 결과 전송에는 POST가 사용된다. 수신한 명령 id에 따라 행위를 수행하고, 결과를 C&C 서버로 전송한다. 전체 행위는 아래 표와 같다.caption - Cobalt Strike Beacon 행위절반 이상의 행위가 미구현 또는 비활성화되어 있으며, Cobalt Strike Beacon은 미완성 악성코드로 추측된다.1.3.4. C# Loaderwork/home/user/Desktop/0128 디렉토리 내에는 다른 프로세스에 Cobalt Strike Beacon을 인젝션하는 C# 로더(ok.dll)와 소스코드(ok.cs), 해당 로더를 실행하는 스크립트(ok.sct) 등이 존재한다.함수 이름과 인자 값에 test 문자열이 다수 포함되어 있어 테스트용 파일로 추정된다.ok.htahxxp://192.168[.]123.200/ok.sct에 접속하여 스크립트를 다운받아 Fuk 함수를 실행한다.caption - ok.hta 파일 내용다운받는 스크립트는 같은 경로에 있는 ok.sct로 추정된다.ok.sct직렬화된 C# 객체를 역직렬화한 뒤 Work 함수를 실행한다. 이때 실행되는 파일은 ok.cs를 컴파일한 ok.dll이다. ok.cs에서 Work 함수를 확인할 수 있다.caption - C# Loader 역직렬화 코드C# 로더는 conhost.exe 프로세스에 Cobalt Strike Beacon을 인젝션하여 실행한다. Cobalt Strike Beacon은 zlib 압축 및 base64 인코딩되어 문자열로 저장되어 있다.caption - Cobalt Strike Beacon 디코딩 함수CobaltStrikeParser를 이용해 파싱한 Cobalt Strike Beacon의 일부 설정 정보는 아래와 같다.caption - C# Loader에 저장된 Cobalt Strike Beacon 설정 정보1.4. Ivanti Connect Secure1.4.1. BRUSHFIREwork/mnt/hgfs/Desktop/ivanti-new-exp-20241220.zip 파일의 압축을 해제하면 Ivanti Connect-Secure RCE 취약점을 악용하여 백도어를 유포하는 exp*.py 파일을 확인할 수 있다.python 스크립트에서 clientCapabilities 값의 길이를 256바이트를 초과하도록 설정하는데, 이는 clientCapabilities에서 발생하는 256바이트 버퍼 오버플로우로 인해 RCE로 이어지는 CVE-2025-0282를 사용하는 것으로 보인다.caption - ex*.py 로직CVE-2025-0282는 과거 중국 배후로 알려진 해킹 그룹 UNC5221에서 공격의 초기벡터로 사용한 적이 있는 취약점이다.해당 취약점을 악용하는 모든 exp*.py는 행위가 동일하고, 익스플로잇에 사용되는 함수 오프셋 혹은 접속하는 서비스의 엔드포인트에만 차이가 존재한다. 실행 인자에 따른 exp*.py 행위는 아래 표와 같다.caption - 인자 옵션백도어는 plugins/ssl_read 파일로, RCE로 트리거된 plugins/install 파일이 백도어를 ssl_read 함수에 후킹한다. 후킹된 ssl_read 함수는 ssl 통신을 수신할 때, 배포 시 설정된 매직 바이트 값이 존재하는 패킷을 탐지하면 exp*.py에서 무작위로 생성된 4바이트 키와 xor하여 쉘코드를 실행한다.caption - ssl_read 쉘코드 실행 로직exp*.py는 실행 인자에 따라 쉘코드를 생성하고 공격 대상 서버에 업로드한다. 이때 쉘코드의 하드코딩된 패턴을 replace 함수를 사용하여, 유효하지 않은 코드를 공격 대상에 유효한 값으로 변경한다. plugins 내에 존재하는 쉘코드를 업로드하는 exp*.py 실행 인자와 쉘코드 행위는 아래 표와 같다.caption - 실행 인자 및 쉘코드 행위plugins/ssl_read백도어 행위는 UNC5221 공격에 사용된 BRUSHFIRE 악성코드와 동일하며, 공격에서 확인된 BRUSHFIRE 파일 경로와 ssl_read 파일 경로가 동일하다.1.4.2. SPAWN Family Clientwork/mnt/hgfs/Desktop/New folder/203.234.192.200_client.zip 파일 내에는 터널링 스크립트와 ssh 클라이언트, 인증서 파일이 압축되어 있다. readme.txt 파일에는 client.py, controller.py를 사용하여 203.234[.]192.200 ip에 접속하는 방법이 적혀있으며 해당 ip는 한겨레 신문사의 ip 주소로 확인되었다.caption - readme.txt 파일 내용client.py는 네트워크 트래픽을 터널링하기 위한 SOCKS5 프록시를 실행하고, client.py의 옵션 별 기능은 아래와 같다.caption - 옵션 별 기능client.py에는 client_hello와 client_key_exchange 메시지 템플릿이 사전 정의되어 있다. 동작은 아래와 같다.client_hello인덱스 11–15 위치에, 인덱스 15–43(랜덤 28바이트)에 대한 CRC32 값을 삽입한 뒤 전송한다.sessionid 변수에 랜덤 32바이트를 저장하고, 이를 메시지에 포함해 전송한다.client_key_exchangepremaster 필드에 랜덤 256바이트, enc_handshake_msg 필드에 랜덤 32바이트를 포함해 전송한다.client.py에 정의된 client_hello 초기 값은 UNC5221 공격에서 확인된 SPAWNMOLE의 매직 패킷과 일치하다. 실행 시에는 client_hello의 인덱스 15–43 구간에 랜덤 28바이트를 기록하고, 그에 대한 CRC32를 인덱스 11–15에 덮어써 전송하는데, 이 방법은 JPCert 블로그 글에서 보고된 SPAWNCHIMERA 설명과 유사하다.SPAWNCHIMERA 역시 SPAWNMOLE과 동일하게 UNC5221 공격에 사용된 악성코드로, 앞서 ssl_read 백도어 유포에 악용된 CVE-2025-0282 취약점을 통해 유포된 악성코드이다.controller.py는 client.py에서 실행된 SOCKS5 프록시를 통해서 ssh 서버와 통신하는 클라이언트 스크립트이다.caption - ssh 서버와 통신하는 controller.pySPAWNMOLE은 ssh 서버를 생성하는 SPAWNSNAIL과 함께 확인되었고, SPAWNCHIMERA는 자체적으로 ssh 서버를 구동하는 기능을 포함한다. 이에 따라 controller.py는 SPAWNSNAIL 또는 SPAWNCHIMERA가 제공하는 ssh 서버에 접속하는 클라이언트로 판단된다.1.4.3. ROOTROT Clientwork/mnt/hgfs/Desktop/ivanti_control/main.py는 입력받은 명령어에 따라 Perl 스크립트 조각을 생성하고, 이를 Base64로 인코딩하여 특정 쿠키 값에 설정한 뒤 HTTP GET 요청을 전송한다. 명령어에 따른 Perl 스크립트는 다음과 같다.download {file_path}{command}두 Perl 스크립트 모두 실행 결과를 base64로 인코딩한 뒤 html 주석으로 감싸 출력한다. 이후 main.py는 서버 응답을 수신하면 본문 마지막 html 주석을 추출하여 base64 디코딩한 후 사용자에게 출력한다.caption - 요청을 보내고 주석의 내용을 디코딩하는 함수Perl로 작성된 웹쉘인 점, 쿠키 값을 base64로 디코딩하여 eval로 실행한다는 점, 실행 결과가 base64로 인코딩되어 html 주석으로 전달된다는 점을 토대로 main.py UNC5221 공격에 사용된 ROOTROT 악성코드의 클라이언트 스크립트로 추정된다.또한 ROOTROT 역시 앞서 언급한 UNC5221 공격에 사용된 악성코드들과 마찬가지로 Ivanti Connect Secure 취약점을 악용한 공격에서 발견되었다.1.5. 피싱 공격1.5.1. 네이버 중간자 공격work/mnt/hgfs/Desktop/New folder/vps2/Cipherishing 디렉토리 내에 있는 파일은 네이버 계정을 노린 중간자 공격과 관련있는 파일들이다. 특히 work/mnt/hgfs/Desktop/New folder/readme.txt 파일에서 중국어로 작성된 설정 방법을 확인할 수 있다.caption - readme.txt 파일 내용readme.txt 파일 내용 번역 결과는 아래와 같다.work/mnt/hgfs/Desktop/New folder/vps2/Cipherishing/cipherginx.py 파일은 C&C 서버에서 실행되고, 네이버와 피해자 사이에서 HTTPS 프록시 서버로 동작한다. 피해자가 C&C 서버를 통해 네이버 서비스에 접속하면 헤더와 쿠기, 그리고 아이디와 비밀번호가 cookies 디렉토리에 저장된다. 각 파일 이름은 아래와 같다.[nid_id].headers[nid_id].cookieaccounts.txtcaption - cipherginx.py accounts.txt 생성 로직work/mnt/hgfs/Desktop/New folder/vps2/Cipherishing/naverconfig.py 파일에 네이버 계정 정보를 탈취하는 자바스크립트 코드가 존재하고, 피해자가 로그인 페이지에 접속하면 원본 페이지에 해당 자바스크립트 코드를 삽입한다.caption - naverconfig.py 계정 정보 탈취 자바스크립트 코드탈취한 계정 정보를 이용해 피해자 네이버 메일, 주소록, 로그인 정보 등을 탈취하는 파일이 존재한다. 각 파일 경로와 설명은 아래 표와 같다.caption - 각 파일 설명1.5.2. 카카오 로그인 피싱 공격vps/var/www/html/templates/kakao.html 파일은 카카오 로그인 페이지 템플릿이고, vps/var/www/html/kakao-login.php 파일은 카카오 로그인 처리 서버측 스크립트로 확인되었다. kakao-login.php는 GET 요청 시 “ft” 쿠키 존재 여부를 검사하며, 값이 존재할 경우 “https://mail.daum.net”으로 리다이렉트 한다.caption - GET 요청 처리 코드“ft” 쿠키 값이 존재하지 않으면 카카오 로그인 페이지를 보여주고, 사용자가 로그인을 시도하면 입력한 로그인 정보가 POST 요청 본문에 담겨 피싱 페이지로 전송된다.POST 요청을 받으면 로그인 정보를 log/password_log.txt 파일에 작성하고, ft 쿠키 값을 no로 설정한다.caption - POST 요청 처리 코드password_log.txt 파일에 14개의 로그인 정보가 존재하나, 이 중 하나의 로그인 정보를 제외한 모든 내용은 테스트용으로 보인다. 123123, ttttt222, qwqwqw111 등의 데이터가 존재한다.1.5.3. 피싱 이메일 공격vps/var/www/html 디렉토리 내에는 피싱 이메일 생성과 피해자 관리 목적의 웹서버 파일이 존재한다.웹서버에서 동작하는 파일은 로그 파일을 생성하고, generator.php를 제외한 나머지 파일의 로그 형식은 아래와 같다.로그 파일은 생성될 때 .txt 확장자 뒤에 날짜 정보가 추가된다.generator.phpvps/var/www/html/generator.php파일은 피싱 이메일을 생성하는 파일이다. “HnoplYTfPX” 쿠키 값과 요청 메소드에 따라 실행 로직이 다르다. 아래 표 참고 바란다.caption - 실행 로직피싱 이메일 생성 시 정보를 입력받는 form의 형식은 아래 표와 같다.caption - 피싱 이메일 생성 form 형식피싱 이메일 생성이 완료되면 사용자에게 출력되는 정보는 아래 표와 같다.caption - 출력 정보피싱 이메일 내용이 content로 보이며, 피싱 이메일이 생성되면 log/generator_log.txt 파일에 로그를 작성한다. 로그 형식은 아래와 같다.또한 공격 대상이 피싱 이메일을 열람하였을 때 이메일 클라이언트가 외부 리소스를 로드하도록 설정되어 있으면 request.php가 로드된다.request.phpvps/var/www/html/request.php 파일은 공격 대상의 피싱 이메일 열람 여부를 로그로 남기는 파일이다. 요청이 오면 log/request_log.txt 파일에 로그를 작성한다.URI에 “.png”가 존재하면 무작위 색 이미지를 반환하고 이외의 경우 공격 대상의 브라우저에 따라 정보를 수집하는 자바스크립트 파일을 로드한다. 로드되는 자바스크립트 파일과 수집 정보는 아래 표 참고 바란다.caption - 자바스크립트 파일 및 수집 정보수집한 정보는 results 변수에 저장되고, 이후 response.php?i={b64encode(email)}&{results} 로 요청을 보낸다.response.phpvps/var/www/html/response.php 파일은 공격 대상의 ip, user-agent, locale를 검사하여 조건을 만족하면 i 파라미터 값을 base64 디코딩한 뒤 log/response_log.txt 파일에 로그를 작성한다. 조건은 다음과 같다.locale이 화이트리스트에 포함된 경우ip, user-agent가 블랙리스트에 포함되지 않은 경우locale 화이트리스트는 아래 참고 바란다.usjpjakrkouser-agent 블랙리스트는 아래 참고 바란다.botspidercrawltrendsymantecvirusspamsecureip 블랙리스트는 아래 표 참고 바란다.caption - ip 블랙리스트피싱 공격에 사용된 파일과 로그, 실제 피해 로그를 종합한 정보는 아래 표와 같다.caption - 전체 로그 및 실제 피해 로그1.6. 연세대학교 이메일 탈취 악성코드vps/var/www/html/js/chks.js 파일은 “https://mail.yonsei.ac.kr/common/json/agent.do”에서 유저 정보를 수집하고, 이메일 포워딩 주소 목록에 cimoon185@daum.net 를 추가한다.caption - chks.js Forward 함수이후 ent_{user}, TOTAL 메일함에서, 발송일이 2017-10-01 이후인 이메일을 탈취해 https://service.navers.org/emuy.php?i={user}로 전송한다.

엔키화이트햇
2025. 9. 22.

위협 인텔리전스
APT Down - The North Korea Files 공개 자료 상세 분석 보고서
본 장에서는 공격자 VMware VM 덤프 파일에서 확인된 악성코드와 VPS 덤프 파일에서 확인된 스피어 피싱 공격 및 인프라 운용 정황에 대한 내용을 다룬다. 특히 tomcat20220420_rootkit, tomcat20250414_rootkit_linux234 디렉토리에서 확인된 루트킷과 백도어는 과거 당사가 조사한 국내 금융회사 침해사고와 관련있다.1.1. tomcat20220420_rootkit1.1.1. Backdoorwork/home/user/Desktop/tomcat20220420_rootkit/tomcat20220420_rootkit/work 디렉토리 내에 백도어 소스코드가 존재한다. 백도어 주요 행위는 명령코드에 따라 악성 행위를 하거나 프록시 역할로 통신을 중계한다. 백도어는 단독으로 실행되지 않고, 항상 루트킷에 의해 실행된다. 백도어 실행 인자 정보는 아래 표와 같다.caption - 인자 옵션프록시 플래그가 활성화되어 있으면 명령코드 관련 로직은 실행되지 않고, AES-CBC-256으로 암호된 데이터(__step2__)를 수신할 때까지 대기한다.caption - master.c 데이터 검사 로직AES key와 iv는 아래와 같다.AES key: 603deb15153a715e2b73aef3857d758b1f552c573e6158d72d9811a33914defeiv: 603deb15153a715e2b73aef3857d758b1f552c573e6158d72d9811a33914defe백도어는 정상 통신으로 위장하기 위해 클라이언트와의 소켓 통신을 아래 프로토콜 중 하나로 설정한다.HTTPHTTPSSSLTCPSMTP실제로 사용하는 프로토콜은 install_common.h에 정의되어 있다.caption - install_common.h명령코드를 포함한 모든 송수신 데이터는 xor로 암·복호화된다. 이때 사용되는 키는 "1101link"인데, 암·복호화 로직을 보면 단일 바이트와 한 번 xor한 것과 동일하다. 따라서 "1101link"와 xor 한 결과는, 1과 xor한 것과 동일하다.caption - encrypt.c EncodeDecode 함수명령코드에 따른 행위는 아래 표와 같다.caption - 백도어 명령코드 행위1.1.2. syslogk rootkitwork/home/user/Desktop/tomcat20220420_rootkit/tomcat20220420_rootkit/main.c 파일은 syslogk로 명명된 루트킷 소스코드이다. 루트킷은 백도어 및 관련 악성코드가 위치한 디렉터리를 은닉하여 일반적으로 탐지되지 않도록 한다. 또한 매직 패킷 수신 시에만 백도어를 실행하여, 공격자가 원하는 시점에만 백도어가 동작한다.루트킷은 3개의 함수를 후킹해 프로세스, 포트, 디렉토리를 은닉한다. 후킹 관련 정보는 아래 표와 같다.caption - 후킹 정보후킹 함수 내부에서는 사전에 정의된 프로세스 이름, 경로, 포트 문자열과 대상 엔트리를 strstr 함수로 비교해, 일치할 경우 해당 엔트리를 반환하기 전에 제거하는 방식으로 은닉을 구현하였다.이후 Netfilter 관련 nf_register_hook 함수를 사용해 훅 지점에 콜백 함수를 등록한다. nf_reagister_hook에 의해 콜백 함수가 등록되는 두 개의 훅 지점에 대한 설명은 아래와 같다.NF_INET_LOCAL_IN : 로컬 호스트로 패킷을 보내기 전NF_INET_LOCAL_OUT : 로컬 호스트에서 패킷을 외부로 보내기 전caption - hkcap.c 후킹 함수 등록 로직위 방법으로 루트킷은 로컬 호스트에서 오고가는 모든 패킷을 감시하고, 공격자가 보낸 매직 패킷을 확인하면 악성 행위를 한다.NF_INET_LOCAL_IN 지점 콜백 함수는 수신한 패킷 프로토콜이 TCP이고, 페이로드를 복호화해 특정 조건들과 일치하는지 확인한다. 복호화에 사용되는 데이터는 아래 표와 같다.caption - 복호화 키 정보복호화 이후 검증하는 조건 목록과 처리 동작은 아래 표와 같다.caption - 조건 및 행위NF_INET_LOCAL_OUT 지점에서 콜백 함수는, 백도어가 보내는 패킷의 source를 백도어가 통신하지 않는 포트로 변경한다.Netfilter 콜백 함수 등록을 마친 후, 루트킷은 모듈 리스트에서 자기 자신을 제거해 탐지를 어렵게 한다. 이로 인해 lsmod 명령어를 입력해도 루트킷을 찾을 수 없다.caption - hide_module 함수모듈 리스트에서 제거된 루트킷에 install.h의 MAGIC_DRBIN 값을 작성하면 lsmod 명령어로 다시 확인할 수 있다.caption - proc_write 함수 로직1.1.3. Backdoor Clientwork/home/user/Desktop/tomcat20220420_rootkit/tomcat20220420_rootkit/work/tcat.c 파일은 백도어 클라이언트 소스코드이다. 이 파일을 공격자가 C&C 서버에서 실행한 것으로 보인다.실행 시 여러 옵션을 지정할 수 있다. 전체 옵션은 아래 표 참고 바란다.caption - 인자 옵션옵션에 따라 백도어에 명령어를 전달하는 방식은 아래와 같이 4가지로 나누어진다.single cmd : 입력받은 명령어를 백도어에서 실행하도록 전송한다.single daemon cmd : 입력받은 명령어를 백도어에서 새로운 프로세스를 생성하여 실행하도록 전송한다.input loop : exit을 입력받을 때까지 무한히 명령어를 입력받아 명령어에 따른 행위를 수행한다.kernel cmd : 입력받은 명령어를 커널 모듈에서 출력 없이 실행하도록 전송한다.input loop를 제외한 모든 명령어 전달 방식은 전송 이후 클라이언트가 종료된다. input loop에서 명령어에 따라 수행하는 행위는 아래 표와 같다.caption - 백도어 클라이언트 명령어 행위모든 통신은 xor key(1101link)로 암호화되어 이루어지고, common.h 파일에 정의된 GENERAL_MODULE, GENERAL_PROTOCOL 값을 패스워드와 함께 sha512로 해싱하여 항상 메시지의 맨 앞에 붙여 전송한다. 백도어와의 통신은 옵션에 따라 아래 프로토콜 중 하나로 설정된다.TCPHTTPOLD HTTP - OLD HTTP는 일반적인 HTTP와 달리 쿠키 값을 설정하지 않는다.1.2. tomcat20250414_rootkit_linux2341.2.1. Backdoorwork/mnt/hgfs/Desktop/tomcat20250414_rootkit_linux234/tomcat20250414_rootkit_linux2345/work 디렉토리 내에 2022년 버전의 백도어와 동일한 2025년 버전의 백도어 소스코드가 존재한다. 2022년 버전 백도어의 업그레이드 버전으로, callback 딜레이 통신 시 패스워드를 확인하며 시간을 지정하거나 파일 다운로드, 업로드 속도를 제한하는 등의 기능이 추가되었다. 전체 옵션은 아래 표와 같다.caption - 인자 옵션패스워드 외에 마스터 패스워드가 추가되었는데, 지정 포트로 소켓 서버를 생성하고, 클라이언트 연결 시 마스터 패스워드와 통신 설정 정보를 sha512로 해싱한다. 마스터 패스워드는 common.h에 정의된 !@nf4@#fndskgadnsewngaldfkl을 사용한다. 해시 값은 전역 변수에 저장되고, ssl 통신 시 통신 설정 정보가 올바른지 확인하지만 실제로 사용되지 않는다.이후 패스워드를 마스터 패스워드 확인 로직과 동일하게 통신 설정 정보와 sha512 해싱하여 동일한지 확인한다.caption - encrypt.c passcheck_check 함수패스워드는 Miu2jACgXeDsxd로, 패스워드를 포함한 설정 정보는 config.sh 파일에서 원하는 값으로 변경하면 빌드할 때 적용된다.caption - config.sh 기본 설정 정보통신에 사용되는 프로토콜 목록은 2022 백도어와 동일하다.HTTPHTTPSSSLTCPSMTP데이터를 암·복호화하는 xor key도 동일하지만 5개의 xor key와 암·복호화 함수가 추가되었다.caption - encrypt.c에서 확인한 전체 xor key2022 백도어에 비해 여러 행위가 추가되었고, 패킷 조건이 바뀌며 TRANSFER이 붙은 명령코드 행위가 변경되었다. 새로 추가된 명령코드는 아래와 같다.CMD_NEW_UPLOADCMD_NEW_DOWNLOADCMD_LISTEN_PROXY_TRANSCMD_TRANSFERCMD_PROXY_TRANSFERCMD_SOCKS_PROXY_TRANSFERCMD_SOCKS_PROXYCMD_NEW_SINGLE_CMD명령코드에 따른 행위는 아래 표와 같다.caption - 백도어 명령코드 행위1.2.2. syslogk rootkitwork/mnt/hgfs/Desktop/tomcat20250414_rootkit_linux234/tomcat20250414_rootkit_linux2345/main.c 파일은 2022년 버전 루트킷과 동일하게 Netfilter 훅 지점에 콜백 함수를 등록한다. 변경된 점은 함수 후킹, 모듈 은닉, 새로 추가된 Netfilter 훅 지점이다.2022 루트킷에서는 함수 후킹을 위해 udis86 라이브러리를 사용한 것과 달리 2025 루트킷에서는 khook 라이브러리를 사용하였다.caption - 좌)2022 루트킷 udis86 라이브러리, 우) 2025 루트킷 khook 라이브러리후킹 대상 함수가 3개였던 2022 루트킷과 달리 총 5개의 함수를 후킹한다. 후킹 관련 정보는 아래 표와 같다.caption - 후킹 정보Netfilter 훅은 기존 NF_INET_LOCAL_IN, NF_INET_LOCAL_OUT 2개의 훅 지점에서 2개가 추가되었다.NF_INET_LOCAL_IN : 로컬 호스트로 패킷을 보내기 전NF_INET_LOCAL_OUT : 로컬 호스트에서 패킷을 외부로 보내기 전NF_INET_PRE_ROUTING : 패킷이 네트워크 스택에 들어온 직후NF_INET_POST_ROUTING : 라우팅이 발생한 후 네트워크에 놓여지기 직전caption - hkcap.c 후킹 함수 등록 로직NF_INET_PRE_ROUTING 지점의 콜백 함수는 크게 2가지 행위를 한다.첫 번째는 2022 루트킷의 NF_INET_LOCAL_IN 지점과 동일하게 패킷 조건을 검사하여 백도어를 실행한다. 패킷 조건이 복잡한 2022 루트킷과 달리 NF_INET_PRE_ROUTING 지점 콜백 함수는 TCP + SYN 패킷이고, id와 seq 값이 id_list, seq_list에 존재하는지 확인한다.조건을 만족한 패킷의 window 값을 매직 패킷 값과 비교하여, 값에 따라 위장 프로토콜을 설정해 백도어를 실행한다. 매직 패킷 값에 따른 위장 프로토콜은 아래 표와 같다.caption - 위장 프로토콜 목록백도어를 실행하는 방법에도 큰 차이가 있다. /bin/sh -c 를 사용한 2022 루트킷과 달리, call_usermodehelper 함수로 백도어를 실행한다. 이때 포트는 3000 ~ 8000 사이의 랜덤한 포트를 사용한다.caption - hkcap.c kernel_run 함수두 번째는 백도어와 통신 중인 ip에서 전송된 패킷의 dest 값을 위에서 생성된 랜덤 포트로 변경한다. 이는 공격자가 랜덤으로 생성된 백도어의 포트를 몰라도 통신을 할 수 있는 로직이다.caption - 패킷의 dest 값을 변경하는 hkcap.c 코드NF_INET_LOCAL_IN 지점의 콜백 함수는 NF_IP_PRE_ROUTING에서 변경된 패킷의 dest 값을 실제 백도어에서 사용하는 포트로 변경한다. 이는 2번에 걸쳐 포트를 바꾸며 실제 백도어가 사용하는 포트를 찾기 어렵게 하기 위함으로 보인다.caption - 패킷의 dest 값을 백도어가 사용하는 포트로 변경하는 hkcap.c 코드NF_INET_LOCAL_OUT 지점의 콜백 함수는 백도어가 보낸 패킷의 source 값이 백도어의 listen 포트이면, 임의 포트로 변경하고 아닌 경우에는 실제로 외부로 보낼 포트로 변경한다.NF_INET_POST_ROUTING 지점의 콜백 함수는 source 값이 임의 포트로 변경된 패킷의 source 값을 실제로 외부로 보낼 포트로 변경한다.caption - 패킷의 dest 값을 공격자의 포트로 변경하는 hkcap.c 코드루트깃 은닉은 모듈 리스트에서 자기 자신을 제거하는 거 외에도 sysfs에서도 제거하는 함수가 추가되었다.caption - 모듈 은닉 hkmod.c 코드sysfs 관련 함수는 KoviD 루트킷의 kv_hide_mod 함수를 그대로 사용하였다.caption - KoviD 루트킷의 kv_hide_mod 함수은닉된 루트킷에 특정 문자열을 작성하면 다시 모듈이 보이는 것은 동일하지만 작성된 문자열에 따라 Netfilter 훅에서 변경하는 포트의 값을 지정하는 기능이 추가되었다.caption - 포트 값을 지정하는 hkcap.c 코드루트킷에 데이터를 작성할 때 모듈을 보이게 하는 문자열을 제외한 모든 문자열은 AES-CBC-256으로 복호화해 확인한다. AES key와 iv는 아래와 같다.AES key: d03deb92153a71458973aef3857d75b27e552cc63e6158a8339811873994de47iv: efa3c987532cc0bdac533845ad8df5ea루트킷에 작성한 문자열에 따른 행위는 아래와 같다.caption - 문자열 및 행위1.2.3. Backdoor Clientwork/mnt/hgfs/Desktop/tomcat20250414_rootkit_linux234/tomcat20250414_rootkit_linux2345/work/tcat.c 파일은 백도어 클라이언트 소스코드이다. 2022 백도어 클라이언트와 비교하였을 때, kernel cmd 기능이 사라진 점 외에는 큰 변화가 없으며 옵션 또한 kc 옵션이 사라지고 LLL 옵션이 생겼다. 전체 옵션은 아래 표 참고 바란다.caption - 인자 옵션앞서 언급한 거처럼 kernel cmd 기능이 삭제되어 백도어에 명령어를 전달하는 방식은 아래와 같이 3가지가 존재한다.single cmd : 입력 받은 명령어를 백도어에서 실행하도록 전송한다.single daemon cmd : 입력받은 명령어를 백도어에서 새로운 프로세스를 생성하여 실행하도록 전송한다.input loop : exit을 입력 받을 때까지 무한히 명령어를 입력 받아 명령어에 따라 다른 행위를 수행한다.2022 백도어 클라이언트는 오직 명령어만 입력받아 통신하였으나 2025 백도어 클라이언트는 명령어 별로 옵션을 지정할 수 있게 되어 명령어의 개수는 줄었지만 수행할 수 있는 행위는 더욱 정교해졌다. input loop에서 명령어에 따라 수행하는 행위는 아래 표와 같다.caption - 백도어 클라이언트 명령어 행위현재 tcat_new_send_file, tcat_new_recv_file과 같이 추가적으로 작성된 명령어의 주요 함수들이 정의가 안되어있어 추가된 기능의 상세 분석은 불가하였다.통신할 때 매번 패스워드의 sha512 해시 값을 보내던 2022 백도어 클라이언트와는 달리 2025 백도어 클라이언트는 첫 연결 시에만 패스워드의 sha512 해시 값을 전송한다.백도어와의 모든 통신은 2022 백도어 클라이언트와 동일하게 xor key(1101link)로 암호화되어 이루어진다. 하지만 3개의 프로토콜을 지정할 수 있는 2022 백도어 클라이언트와는 달리 2025 백도어 클라이언트는 아래 4개의 프로토콜 중 하나로 설정된다. 특히 OLD HTTP가 삭제되었으며 HTTPS, SMTP가 추가되었다.TCPHTTPHTTPSSMTP1.3. Cobalt Strike1.3.1. Cobalt Strike LoaderRust로 작성된 로더 악성코드로, 내장된 쉘코드를 복호화하고 메모리에서 실행한다. Cobalt Strike Loader 파일 경로는 아래와 같다.work/mnt/hgfs/Desktop/New folder (2)/DboRrmSS.exework/mnt/hgfs/Desktop/New folder (2)/m01QzOfI.exework/mnt/hgfs/Desktop/New folder (2)/voS9AyMZ.tar.gzwork/home/user/.cache/vmware/drag_and_drop/0pkbW4/3Powwovv.exework/home/user/.cache/vmware/drag_and_drop/gWMDML/GnAN3FhY.exework/home/user/.cache/vmware/drag_and_drop/QqiN9h/DboRrmSS.exework/home/user/.cache/vmware/drag_and_drop/rM0FG0/m01QzOfI.exeWindows API를 호출 할 때, djb2 해시 값을 계산해 동적으로 로드하고, 쉘코드는 AES-CBC-256으로 복호화한다. 이후 복호화된 쉘코드를 메모리에서 실행한다.caption - Window API 로딩 함수모든 Cobalt Strike Loader에서 사용하는 AES key와 iv는 아래 표와 같다.caption - Cobalt Strike Loader AES key, iv 목록1.3.2. ShellcodeCobalt Strike Loader에 의해 실행되는 쉘코드로, Cobalt Strike Beacon을 복호화하여 메모리에서 실행한다. 파일 형태로 존재하는 쉘코드 경로는 아래와 같다.work/home/user/.cache/vmware/drag_and_drop/5wdgDr/payload.binwork/home/user/.cache/vmware/drag_and_drop/6bX9mm/Black.x64.exework/home/user/.cache/vmware/drag_and_drop/NDBu65/payload.binwork/home/user/.cache/vmware/drag_and_drop/yf91yD/payload.binwork/home/user/.cache/vmware/drag_and_drop/zlLWeR/payload.binwork/home/user/.cache/vmware/drag_and_drop/6bX9mm/Black.x64.exe는 다른 쉘코드 파일들과 행위가 동일하지만 쉘코드가 아닌 컴파일된 실행 파일이다.caption - Black.x64.exe DIE 결과Cobalt Strike Loader와 마찬가지로 djb2 해시 값을 계산해 Windows API를 동적으로 로드한 뒤 호출하고, 이후 Cobalt Strike Beacon을 RC4로 복호화해 메모리에서 실행한다.caption - RC4 ksa 함수모든 쉘코드에서 사용하는 RC4 key는 아래 표와 같다. 파일 형태로 존재하지 않고, Cobalt Strike Loader에 의해 실행되는 쉘코드도 포함하였다.caption - 쉘코드 RC4 key 목록쉘코드에 의해 실행되는 Cobalt Strike Beacon은 ETW 관련 함수와 AMSI.dll 함수를 패치하여 Windows 보안 기능을 우회하는 로직이 존재한다. 하지만 암호화된 설정 정보가 온전하지 않아 설정 정보는 확인할 수 없었다.1.3.3. Cobalt Strike Beaconwork/mnt/hgfs/Desktop/111/beacon 디렉토리 내에 Cobalt Strike Beacon 소스코드가 존재한다. Beacon 실행 시 설정 정보는 1바이트 xor 키(46)로 복호화되고, 복호화된 설정 정보는 블록으로 구성되며, 각 블록은 아래와 같은 구조를 갖는다.복호화된 설정 정보는 파싱하여 전역변수에 저장된 후 필요한 값이 있을 때 인덱스로 접근하여 사용한다. CobaltStrikeParser를 이용해 파싱한 일부 설정 정보는 아래와 같다.caption - CobaltStrikeParser 결과복호화된 설정 정보에는 C&C 서버 주소와 엔드포인트가 포함되어 있으나, 실행 과정에서 해당 값은 사용되지 않고 소스코드에 하드코딩된 값을 사용한다.caption - comm.cpp send_Metadata 함수설정 정보 복호화가 완료되면 C&C 서버에 전송할 메타데이터를 생성한다. 주요 메타데이터 정보는 아래 표와 같다.caption - 메타데이터 정보메타데이터 생성이 완료되면 C&C 서버로 전송하고, 이후 5초마다 HTTP 기반 폴링 통신을 수행한다. 이때 명령 수신에는 GET, 결과 전송에는 POST가 사용된다. 수신한 명령 id에 따라 행위를 수행하고, 결과를 C&C 서버로 전송한다. 전체 행위는 아래 표와 같다.caption - Cobalt Strike Beacon 행위절반 이상의 행위가 미구현 또는 비활성화되어 있으며, Cobalt Strike Beacon은 미완성 악성코드로 추측된다.1.3.4. C# Loaderwork/home/user/Desktop/0128 디렉토리 내에는 다른 프로세스에 Cobalt Strike Beacon을 인젝션하는 C# 로더(ok.dll)와 소스코드(ok.cs), 해당 로더를 실행하는 스크립트(ok.sct) 등이 존재한다.함수 이름과 인자 값에 test 문자열이 다수 포함되어 있어 테스트용 파일로 추정된다.ok.htahxxp://192.168[.]123.200/ok.sct에 접속하여 스크립트를 다운받아 Fuk 함수를 실행한다.caption - ok.hta 파일 내용다운받는 스크립트는 같은 경로에 있는 ok.sct로 추정된다.ok.sct직렬화된 C# 객체를 역직렬화한 뒤 Work 함수를 실행한다. 이때 실행되는 파일은 ok.cs를 컴파일한 ok.dll이다. ok.cs에서 Work 함수를 확인할 수 있다.caption - C# Loader 역직렬화 코드C# 로더는 conhost.exe 프로세스에 Cobalt Strike Beacon을 인젝션하여 실행한다. Cobalt Strike Beacon은 zlib 압축 및 base64 인코딩되어 문자열로 저장되어 있다.caption - Cobalt Strike Beacon 디코딩 함수CobaltStrikeParser를 이용해 파싱한 Cobalt Strike Beacon의 일부 설정 정보는 아래와 같다.caption - C# Loader에 저장된 Cobalt Strike Beacon 설정 정보1.4. Ivanti Connect Secure1.4.1. BRUSHFIREwork/mnt/hgfs/Desktop/ivanti-new-exp-20241220.zip 파일의 압축을 해제하면 Ivanti Connect-Secure RCE 취약점을 악용하여 백도어를 유포하는 exp*.py 파일을 확인할 수 있다.python 스크립트에서 clientCapabilities 값의 길이를 256바이트를 초과하도록 설정하는데, 이는 clientCapabilities에서 발생하는 256바이트 버퍼 오버플로우로 인해 RCE로 이어지는 CVE-2025-0282를 사용하는 것으로 보인다.caption - ex*.py 로직CVE-2025-0282는 과거 중국 배후로 알려진 해킹 그룹 UNC5221에서 공격의 초기벡터로 사용한 적이 있는 취약점이다.해당 취약점을 악용하는 모든 exp*.py는 행위가 동일하고, 익스플로잇에 사용되는 함수 오프셋 혹은 접속하는 서비스의 엔드포인트에만 차이가 존재한다. 실행 인자에 따른 exp*.py 행위는 아래 표와 같다.caption - 인자 옵션백도어는 plugins/ssl_read 파일로, RCE로 트리거된 plugins/install 파일이 백도어를 ssl_read 함수에 후킹한다. 후킹된 ssl_read 함수는 ssl 통신을 수신할 때, 배포 시 설정된 매직 바이트 값이 존재하는 패킷을 탐지하면 exp*.py에서 무작위로 생성된 4바이트 키와 xor하여 쉘코드를 실행한다.caption - ssl_read 쉘코드 실행 로직exp*.py는 실행 인자에 따라 쉘코드를 생성하고 공격 대상 서버에 업로드한다. 이때 쉘코드의 하드코딩된 패턴을 replace 함수를 사용하여, 유효하지 않은 코드를 공격 대상에 유효한 값으로 변경한다. plugins 내에 존재하는 쉘코드를 업로드하는 exp*.py 실행 인자와 쉘코드 행위는 아래 표와 같다.caption - 실행 인자 및 쉘코드 행위plugins/ssl_read백도어 행위는 UNC5221 공격에 사용된 BRUSHFIRE 악성코드와 동일하며, 공격에서 확인된 BRUSHFIRE 파일 경로와 ssl_read 파일 경로가 동일하다.1.4.2. SPAWN Family Clientwork/mnt/hgfs/Desktop/New folder/203.234.192.200_client.zip 파일 내에는 터널링 스크립트와 ssh 클라이언트, 인증서 파일이 압축되어 있다. readme.txt 파일에는 client.py, controller.py를 사용하여 203.234[.]192.200 ip에 접속하는 방법이 적혀있으며 해당 ip는 한겨레 신문사의 ip 주소로 확인되었다.caption - readme.txt 파일 내용client.py는 네트워크 트래픽을 터널링하기 위한 SOCKS5 프록시를 실행하고, client.py의 옵션 별 기능은 아래와 같다.caption - 옵션 별 기능client.py에는 client_hello와 client_key_exchange 메시지 템플릿이 사전 정의되어 있다. 동작은 아래와 같다.client_hello인덱스 11–15 위치에, 인덱스 15–43(랜덤 28바이트)에 대한 CRC32 값을 삽입한 뒤 전송한다.sessionid 변수에 랜덤 32바이트를 저장하고, 이를 메시지에 포함해 전송한다.client_key_exchangepremaster 필드에 랜덤 256바이트, enc_handshake_msg 필드에 랜덤 32바이트를 포함해 전송한다.client.py에 정의된 client_hello 초기 값은 UNC5221 공격에서 확인된 SPAWNMOLE의 매직 패킷과 일치하다. 실행 시에는 client_hello의 인덱스 15–43 구간에 랜덤 28바이트를 기록하고, 그에 대한 CRC32를 인덱스 11–15에 덮어써 전송하는데, 이 방법은 JPCert 블로그 글에서 보고된 SPAWNCHIMERA 설명과 유사하다.SPAWNCHIMERA 역시 SPAWNMOLE과 동일하게 UNC5221 공격에 사용된 악성코드로, 앞서 ssl_read 백도어 유포에 악용된 CVE-2025-0282 취약점을 통해 유포된 악성코드이다.controller.py는 client.py에서 실행된 SOCKS5 프록시를 통해서 ssh 서버와 통신하는 클라이언트 스크립트이다.caption - ssh 서버와 통신하는 controller.pySPAWNMOLE은 ssh 서버를 생성하는 SPAWNSNAIL과 함께 확인되었고, SPAWNCHIMERA는 자체적으로 ssh 서버를 구동하는 기능을 포함한다. 이에 따라 controller.py는 SPAWNSNAIL 또는 SPAWNCHIMERA가 제공하는 ssh 서버에 접속하는 클라이언트로 판단된다.1.4.3. ROOTROT Clientwork/mnt/hgfs/Desktop/ivanti_control/main.py는 입력받은 명령어에 따라 Perl 스크립트 조각을 생성하고, 이를 Base64로 인코딩하여 특정 쿠키 값에 설정한 뒤 HTTP GET 요청을 전송한다. 명령어에 따른 Perl 스크립트는 다음과 같다.download {file_path}{command}두 Perl 스크립트 모두 실행 결과를 base64로 인코딩한 뒤 html 주석으로 감싸 출력한다. 이후 main.py는 서버 응답을 수신하면 본문 마지막 html 주석을 추출하여 base64 디코딩한 후 사용자에게 출력한다.caption - 요청을 보내고 주석의 내용을 디코딩하는 함수Perl로 작성된 웹쉘인 점, 쿠키 값을 base64로 디코딩하여 eval로 실행한다는 점, 실행 결과가 base64로 인코딩되어 html 주석으로 전달된다는 점을 토대로 main.py UNC5221 공격에 사용된 ROOTROT 악성코드의 클라이언트 스크립트로 추정된다.또한 ROOTROT 역시 앞서 언급한 UNC5221 공격에 사용된 악성코드들과 마찬가지로 Ivanti Connect Secure 취약점을 악용한 공격에서 발견되었다.1.5. 피싱 공격1.5.1. 네이버 중간자 공격work/mnt/hgfs/Desktop/New folder/vps2/Cipherishing 디렉토리 내에 있는 파일은 네이버 계정을 노린 중간자 공격과 관련있는 파일들이다. 특히 work/mnt/hgfs/Desktop/New folder/readme.txt 파일에서 중국어로 작성된 설정 방법을 확인할 수 있다.caption - readme.txt 파일 내용readme.txt 파일 내용 번역 결과는 아래와 같다.work/mnt/hgfs/Desktop/New folder/vps2/Cipherishing/cipherginx.py 파일은 C&C 서버에서 실행되고, 네이버와 피해자 사이에서 HTTPS 프록시 서버로 동작한다. 피해자가 C&C 서버를 통해 네이버 서비스에 접속하면 헤더와 쿠기, 그리고 아이디와 비밀번호가 cookies 디렉토리에 저장된다. 각 파일 이름은 아래와 같다.[nid_id].headers[nid_id].cookieaccounts.txtcaption - cipherginx.py accounts.txt 생성 로직work/mnt/hgfs/Desktop/New folder/vps2/Cipherishing/naverconfig.py 파일에 네이버 계정 정보를 탈취하는 자바스크립트 코드가 존재하고, 피해자가 로그인 페이지에 접속하면 원본 페이지에 해당 자바스크립트 코드를 삽입한다.caption - naverconfig.py 계정 정보 탈취 자바스크립트 코드탈취한 계정 정보를 이용해 피해자 네이버 메일, 주소록, 로그인 정보 등을 탈취하는 파일이 존재한다. 각 파일 경로와 설명은 아래 표와 같다.caption - 각 파일 설명1.5.2. 카카오 로그인 피싱 공격vps/var/www/html/templates/kakao.html 파일은 카카오 로그인 페이지 템플릿이고, vps/var/www/html/kakao-login.php 파일은 카카오 로그인 처리 서버측 스크립트로 확인되었다. kakao-login.php는 GET 요청 시 “ft” 쿠키 존재 여부를 검사하며, 값이 존재할 경우 “https://mail.daum.net”으로 리다이렉트 한다.caption - GET 요청 처리 코드“ft” 쿠키 값이 존재하지 않으면 카카오 로그인 페이지를 보여주고, 사용자가 로그인을 시도하면 입력한 로그인 정보가 POST 요청 본문에 담겨 피싱 페이지로 전송된다.POST 요청을 받으면 로그인 정보를 log/password_log.txt 파일에 작성하고, ft 쿠키 값을 no로 설정한다.caption - POST 요청 처리 코드password_log.txt 파일에 14개의 로그인 정보가 존재하나, 이 중 하나의 로그인 정보를 제외한 모든 내용은 테스트용으로 보인다. 123123, ttttt222, qwqwqw111 등의 데이터가 존재한다.1.5.3. 피싱 이메일 공격vps/var/www/html 디렉토리 내에는 피싱 이메일 생성과 피해자 관리 목적의 웹서버 파일이 존재한다.웹서버에서 동작하는 파일은 로그 파일을 생성하고, generator.php를 제외한 나머지 파일의 로그 형식은 아래와 같다.로그 파일은 생성될 때 .txt 확장자 뒤에 날짜 정보가 추가된다.generator.phpvps/var/www/html/generator.php파일은 피싱 이메일을 생성하는 파일이다. “HnoplYTfPX” 쿠키 값과 요청 메소드에 따라 실행 로직이 다르다. 아래 표 참고 바란다.caption - 실행 로직피싱 이메일 생성 시 정보를 입력받는 form의 형식은 아래 표와 같다.caption - 피싱 이메일 생성 form 형식피싱 이메일 생성이 완료되면 사용자에게 출력되는 정보는 아래 표와 같다.caption - 출력 정보피싱 이메일 내용이 content로 보이며, 피싱 이메일이 생성되면 log/generator_log.txt 파일에 로그를 작성한다. 로그 형식은 아래와 같다.또한 공격 대상이 피싱 이메일을 열람하였을 때 이메일 클라이언트가 외부 리소스를 로드하도록 설정되어 있으면 request.php가 로드된다.request.phpvps/var/www/html/request.php 파일은 공격 대상의 피싱 이메일 열람 여부를 로그로 남기는 파일이다. 요청이 오면 log/request_log.txt 파일에 로그를 작성한다.URI에 “.png”가 존재하면 무작위 색 이미지를 반환하고 이외의 경우 공격 대상의 브라우저에 따라 정보를 수집하는 자바스크립트 파일을 로드한다. 로드되는 자바스크립트 파일과 수집 정보는 아래 표 참고 바란다.caption - 자바스크립트 파일 및 수집 정보수집한 정보는 results 변수에 저장되고, 이후 response.php?i={b64encode(email)}&{results} 로 요청을 보낸다.response.phpvps/var/www/html/response.php 파일은 공격 대상의 ip, user-agent, locale를 검사하여 조건을 만족하면 i 파라미터 값을 base64 디코딩한 뒤 log/response_log.txt 파일에 로그를 작성한다. 조건은 다음과 같다.locale이 화이트리스트에 포함된 경우ip, user-agent가 블랙리스트에 포함되지 않은 경우locale 화이트리스트는 아래 참고 바란다.usjpjakrkouser-agent 블랙리스트는 아래 참고 바란다.botspidercrawltrendsymantecvirusspamsecureip 블랙리스트는 아래 표 참고 바란다.caption - ip 블랙리스트피싱 공격에 사용된 파일과 로그, 실제 피해 로그를 종합한 정보는 아래 표와 같다.caption - 전체 로그 및 실제 피해 로그1.6. 연세대학교 이메일 탈취 악성코드vps/var/www/html/js/chks.js 파일은 “https://mail.yonsei.ac.kr/common/json/agent.do”에서 유저 정보를 수집하고, 이메일 포워딩 주소 목록에 cimoon185@daum.net 를 추가한다.caption - chks.js Forward 함수이후 ent_{user}, TOTAL 메일함에서, 발송일이 2017-10-01 이후인 이메일을 탈취해 https://service.navers.org/emuy.php?i={user}로 전송한다.

엔키화이트햇
2025. 9. 22.

위협 인텔리전스
국내 IP에서 유포된 PureCrypter 적용 Formbook 페이로드 분석
2025년 5월경 국내 ip 158.247.250[.]251와 관련있는 다수의 RAR, EXE 파일이 발견되었다. 해당 ip는 과거 DNS 기록에서 네이버 관련 피싱 인프라로 의심되는 도메인이 확인되었으며, VirusTotal에 네이버 로그인 관련 URL 질의 기록이 남아있다.caption - 158.247.250[.]251의 URL 질의 기록그중에 관련된 이메일 파일, 해당 이메일 첨부 파일인 RAR, EXE 파일은 한국에서 보고되었으며, 이메일을 수신한 이메일 계정 또한 한국 에너지 기업의 도메인이다. ip와 관련된 악성코드들은 한국 외에도 다양한 국가에 서로 다른 파일 이름으로 유포되었다. 유포된 파일은 분석 결과 PureCrypter로 패킹된 Formbook 악성코드로 확인되었다.

엔키화이트햇
2025. 8. 29.

위협 인텔리전스
국내 IP에서 유포된 PureCrypter 적용 Formbook 페이로드 분석
2025년 5월경 국내 ip 158.247.250[.]251와 관련있는 다수의 RAR, EXE 파일이 발견되었다. 해당 ip는 과거 DNS 기록에서 네이버 관련 피싱 인프라로 의심되는 도메인이 확인되었으며, VirusTotal에 네이버 로그인 관련 URL 질의 기록이 남아있다.caption - 158.247.250[.]251의 URL 질의 기록그중에 관련된 이메일 파일, 해당 이메일 첨부 파일인 RAR, EXE 파일은 한국에서 보고되었으며, 이메일을 수신한 이메일 계정 또한 한국 에너지 기업의 도메인이다. ip와 관련된 악성코드들은 한국 외에도 다양한 국가에 서로 다른 파일 이름으로 유포되었다. 유포된 파일은 분석 결과 PureCrypter로 패킹된 Formbook 악성코드로 확인되었다.

엔키화이트햇
2025. 8. 29.

위협 인텔리전스
국내 IP에서 유포된 PureCrypter 적용 Formbook 페이로드 분석
2025년 5월경 국내 ip 158.247.250[.]251와 관련있는 다수의 RAR, EXE 파일이 발견되었다. 해당 ip는 과거 DNS 기록에서 네이버 관련 피싱 인프라로 의심되는 도메인이 확인되었으며, VirusTotal에 네이버 로그인 관련 URL 질의 기록이 남아있다.caption - 158.247.250[.]251의 URL 질의 기록그중에 관련된 이메일 파일, 해당 이메일 첨부 파일인 RAR, EXE 파일은 한국에서 보고되었으며, 이메일을 수신한 이메일 계정 또한 한국 에너지 기업의 도메인이다. ip와 관련된 악성코드들은 한국 외에도 다양한 국가에 서로 다른 파일 이름으로 유포되었다. 유포된 파일은 분석 결과 PureCrypter로 패킹된 Formbook 악성코드로 확인되었다.

엔키화이트햇
2025. 8. 29.

취약점 연구
From Blink to Nt: Codegate 2025 FullChain Write-up
Challenge OverviewThe goal of the challenge is to find vulnerabilities in the renderer process and develop an exploit code by analyzing the provided rce-sbx-138-0-7204-97.patch file.The patch file creates a new Blink module called minishell in the renderer. It provides various shell functions and file writing and saving, and the file data is managed through Codegate File System (CFS), which is a browser API.The available commands are:They are similar to the basic shell commands. Commands such as exec are not implemented, but there are several file operations.When a file is opened, it is managed through file_descriptor_ in the form of a FileBuffer class until Save.A user can invoke the minishell as follows:Callable methods can be bound in the *idl file.In short, one user can have multiple shells and execute each command in one shell.VulnerabilityWe can see the main functionality in mini_shell.cc.However, the vulnerability is pretty simple compared to the file size. The following shows the FileBuffer structure.In here, we can see the fixed-size buffer. Let’s check the part which uses it.There is a size check for the input data vector, but there is no any bound check for idx_ so an out-of-bounds (OOB) read/write occurs.Although the vulnerability is simple, we need to obtain arbitrary address read / write primitives with this relative address read / write, and finally achieve Arbitrary Code Execution.Exploit - AAR/WNow, we have relative read / write primitive of uint64_t size. In fact, there is no difference in the method to achieve arbitrary address read / write.However, in order to access an arbitrary address, we must know the address of the current object. This is because we need to measure the distance to move to the target.There are various ways to leak the address of a controllable object.In this challenge, it is difficult to achieve address leakage with just a simple OOB read because there is no valid address area written anywhere in the heap area. Among them, we tried using brand new technique that can stably leak objects by utilizing the characteristics of Oilpan GC.Oilpan GCThe Heap object of Oilpan GC has the following structure [link].Oilpan GC uses a different allocation method than PartitionAlloc (PA), which is mark-and-sweep and space. Unlike PA, which uses slot-bucket, Oilpan allocates space for the heap and divides (i.e., allocates) the heap object as much as requested size from the space when a request comes in.In other words, without a fixed slot, it dynamically allocates multiple sizes in each space.When they lose their reference and are GC reclaims them, they take the form of FreeList::Entry.When an object in the space is freed, the HeapObject changes to a FreeList::Entry, and additional next_ fields are created to point to the next freed object.Leak IdeaThe idea is as follows:Loop the action below enough times to allocate new spaceSpray shell objectSpray File in each shellTrigger gc()Read the next_ of the header of the next adjacent chunk of FileBuffer in the N-th Sprayed ObjectLeak (N-1)th Sprayed_objectSince each shell has only one File Buffer, N shells are needed to spray N File Buffers.Considering the characteristics of the Oilpan GC described above, consider the following chunk situation.Currently, there is only my object in space. When an object is dynamically divided(i.e., allocated) from space, gc() is executed and the small areas between each object will be treated as Free Entry, forming a FreeList as shown above.We can now read the chained Free Entry by reading temp = sizeof(FileBuffer) + 0x8 from the Sprayed2 object, and leak the Sprayed 1 address through heap_leak = temp - sizeof(FileBuffer)This allows us to leak the address of the object with only spray and out-of-bounds, regardless of how big the distance is between Sprayed 1 and Sprayed 2 whether there is a stable address.Since we have the address of the Sprayed 1 object and the relative address read / write, we can perform arbitrary address read / write.In the exploit, after sufficient spray, it triggers gc() and then leaks objects 90th to 89th.Exploit - Arbitrary Code ExecutionNow, we obtain the arbitrary address read / write primitives.In a typical V8 engine, addrof is used to obtain address of a Wasm RWX Page. However, we only have OOB, and it seems difficult to create an addrof primitive.So what should we do?Overwrite the vtable of HeapMojoRemote to call 0x4141414141414141?The challenge says that it should be exploited on chrome.exe running on Windows 11 24H2. That is, in order to achieve arbitrary function calls in the challenge, CFG Bypass must be accompanied. Of course, considering the huge size of the code base, there may be many gadgets that can bypass CFG.Also, Function::Invoker Chaining, a well-known technique, can bypass CFG.We wanted to find a more stable method, and after auditing the code, we found that there is a LazyInstance Getter for WasmCodePointerObject. We can leak Wasm RWX Page by reading WasmCodePointerTable → entrypoint_.Let's overwrite RWX Page with arbitrary shellcode and execute wasm exports function.In the end, we can stably execute arbitrary shellcode while maintaining persistence. An interesting fact is that the bug of the SBX challenge can be triggered even in the Renderer. However, triggering the vulnerability requires a slight race condition in the SBX Challenge, we are unsure whether UAF Object can be reliably occupied in Blink.

엔키화이트햇
2025. 7. 21.

취약점 연구
From Blink to Nt: Codegate 2025 FullChain Write-up
Challenge OverviewThe goal of the challenge is to find vulnerabilities in the renderer process and develop an exploit code by analyzing the provided rce-sbx-138-0-7204-97.patch file.The patch file creates a new Blink module called minishell in the renderer. It provides various shell functions and file writing and saving, and the file data is managed through Codegate File System (CFS), which is a browser API.The available commands are:They are similar to the basic shell commands. Commands such as exec are not implemented, but there are several file operations.When a file is opened, it is managed through file_descriptor_ in the form of a FileBuffer class until Save.A user can invoke the minishell as follows:Callable methods can be bound in the *idl file.In short, one user can have multiple shells and execute each command in one shell.VulnerabilityWe can see the main functionality in mini_shell.cc.However, the vulnerability is pretty simple compared to the file size. The following shows the FileBuffer structure.In here, we can see the fixed-size buffer. Let’s check the part which uses it.There is a size check for the input data vector, but there is no any bound check for idx_ so an out-of-bounds (OOB) read/write occurs.Although the vulnerability is simple, we need to obtain arbitrary address read / write primitives with this relative address read / write, and finally achieve Arbitrary Code Execution.Exploit - AAR/WNow, we have relative read / write primitive of uint64_t size. In fact, there is no difference in the method to achieve arbitrary address read / write.However, in order to access an arbitrary address, we must know the address of the current object. This is because we need to measure the distance to move to the target.There are various ways to leak the address of a controllable object.In this challenge, it is difficult to achieve address leakage with just a simple OOB read because there is no valid address area written anywhere in the heap area. Among them, we tried using brand new technique that can stably leak objects by utilizing the characteristics of Oilpan GC.Oilpan GCThe Heap object of Oilpan GC has the following structure [link].Oilpan GC uses a different allocation method than PartitionAlloc (PA), which is mark-and-sweep and space. Unlike PA, which uses slot-bucket, Oilpan allocates space for the heap and divides (i.e., allocates) the heap object as much as requested size from the space when a request comes in.In other words, without a fixed slot, it dynamically allocates multiple sizes in each space.When they lose their reference and are GC reclaims them, they take the form of FreeList::Entry.When an object in the space is freed, the HeapObject changes to a FreeList::Entry, and additional next_ fields are created to point to the next freed object.Leak IdeaThe idea is as follows:Loop the action below enough times to allocate new spaceSpray shell objectSpray File in each shellTrigger gc()Read the next_ of the header of the next adjacent chunk of FileBuffer in the N-th Sprayed ObjectLeak (N-1)th Sprayed_objectSince each shell has only one File Buffer, N shells are needed to spray N File Buffers.Considering the characteristics of the Oilpan GC described above, consider the following chunk situation.Currently, there is only my object in space. When an object is dynamically divided(i.e., allocated) from space, gc() is executed and the small areas between each object will be treated as Free Entry, forming a FreeList as shown above.We can now read the chained Free Entry by reading temp = sizeof(FileBuffer) + 0x8 from the Sprayed2 object, and leak the Sprayed 1 address through heap_leak = temp - sizeof(FileBuffer)This allows us to leak the address of the object with only spray and out-of-bounds, regardless of how big the distance is between Sprayed 1 and Sprayed 2 whether there is a stable address.Since we have the address of the Sprayed 1 object and the relative address read / write, we can perform arbitrary address read / write.In the exploit, after sufficient spray, it triggers gc() and then leaks objects 90th to 89th.Exploit - Arbitrary Code ExecutionNow, we obtain the arbitrary address read / write primitives.In a typical V8 engine, addrof is used to obtain address of a Wasm RWX Page. However, we only have OOB, and it seems difficult to create an addrof primitive.So what should we do?Overwrite the vtable of HeapMojoRemote to call 0x4141414141414141?The challenge says that it should be exploited on chrome.exe running on Windows 11 24H2. That is, in order to achieve arbitrary function calls in the challenge, CFG Bypass must be accompanied. Of course, considering the huge size of the code base, there may be many gadgets that can bypass CFG.Also, Function::Invoker Chaining, a well-known technique, can bypass CFG.We wanted to find a more stable method, and after auditing the code, we found that there is a LazyInstance Getter for WasmCodePointerObject. We can leak Wasm RWX Page by reading WasmCodePointerTable → entrypoint_.Let's overwrite RWX Page with arbitrary shellcode and execute wasm exports function.In the end, we can stably execute arbitrary shellcode while maintaining persistence. An interesting fact is that the bug of the SBX challenge can be triggered even in the Renderer. However, triggering the vulnerability requires a slight race condition in the SBX Challenge, we are unsure whether UAF Object can be reliably occupied in Blink.

엔키화이트햇
2025. 7. 21.

취약점 연구
From Blink to Nt: Codegate 2025 FullChain Write-up
Challenge OverviewThe goal of the challenge is to find vulnerabilities in the renderer process and develop an exploit code by analyzing the provided rce-sbx-138-0-7204-97.patch file.The patch file creates a new Blink module called minishell in the renderer. It provides various shell functions and file writing and saving, and the file data is managed through Codegate File System (CFS), which is a browser API.The available commands are:They are similar to the basic shell commands. Commands such as exec are not implemented, but there are several file operations.When a file is opened, it is managed through file_descriptor_ in the form of a FileBuffer class until Save.A user can invoke the minishell as follows:Callable methods can be bound in the *idl file.In short, one user can have multiple shells and execute each command in one shell.VulnerabilityWe can see the main functionality in mini_shell.cc.However, the vulnerability is pretty simple compared to the file size. The following shows the FileBuffer structure.In here, we can see the fixed-size buffer. Let’s check the part which uses it.There is a size check for the input data vector, but there is no any bound check for idx_ so an out-of-bounds (OOB) read/write occurs.Although the vulnerability is simple, we need to obtain arbitrary address read / write primitives with this relative address read / write, and finally achieve Arbitrary Code Execution.Exploit - AAR/WNow, we have relative read / write primitive of uint64_t size. In fact, there is no difference in the method to achieve arbitrary address read / write.However, in order to access an arbitrary address, we must know the address of the current object. This is because we need to measure the distance to move to the target.There are various ways to leak the address of a controllable object.In this challenge, it is difficult to achieve address leakage with just a simple OOB read because there is no valid address area written anywhere in the heap area. Among them, we tried using brand new technique that can stably leak objects by utilizing the characteristics of Oilpan GC.Oilpan GCThe Heap object of Oilpan GC has the following structure [link].Oilpan GC uses a different allocation method than PartitionAlloc (PA), which is mark-and-sweep and space. Unlike PA, which uses slot-bucket, Oilpan allocates space for the heap and divides (i.e., allocates) the heap object as much as requested size from the space when a request comes in.In other words, without a fixed slot, it dynamically allocates multiple sizes in each space.When they lose their reference and are GC reclaims them, they take the form of FreeList::Entry.When an object in the space is freed, the HeapObject changes to a FreeList::Entry, and additional next_ fields are created to point to the next freed object.Leak IdeaThe idea is as follows:Loop the action below enough times to allocate new spaceSpray shell objectSpray File in each shellTrigger gc()Read the next_ of the header of the next adjacent chunk of FileBuffer in the N-th Sprayed ObjectLeak (N-1)th Sprayed_objectSince each shell has only one File Buffer, N shells are needed to spray N File Buffers.Considering the characteristics of the Oilpan GC described above, consider the following chunk situation.Currently, there is only my object in space. When an object is dynamically divided(i.e., allocated) from space, gc() is executed and the small areas between each object will be treated as Free Entry, forming a FreeList as shown above.We can now read the chained Free Entry by reading temp = sizeof(FileBuffer) + 0x8 from the Sprayed2 object, and leak the Sprayed 1 address through heap_leak = temp - sizeof(FileBuffer)This allows us to leak the address of the object with only spray and out-of-bounds, regardless of how big the distance is between Sprayed 1 and Sprayed 2 whether there is a stable address.Since we have the address of the Sprayed 1 object and the relative address read / write, we can perform arbitrary address read / write.In the exploit, after sufficient spray, it triggers gc() and then leaks objects 90th to 89th.Exploit - Arbitrary Code ExecutionNow, we obtain the arbitrary address read / write primitives.In a typical V8 engine, addrof is used to obtain address of a Wasm RWX Page. However, we only have OOB, and it seems difficult to create an addrof primitive.So what should we do?Overwrite the vtable of HeapMojoRemote to call 0x4141414141414141?The challenge says that it should be exploited on chrome.exe running on Windows 11 24H2. That is, in order to achieve arbitrary function calls in the challenge, CFG Bypass must be accompanied. Of course, considering the huge size of the code base, there may be many gadgets that can bypass CFG.Also, Function::Invoker Chaining, a well-known technique, can bypass CFG.We wanted to find a more stable method, and after auditing the code, we found that there is a LazyInstance Getter for WasmCodePointerObject. We can leak Wasm RWX Page by reading WasmCodePointerTable → entrypoint_.Let's overwrite RWX Page with arbitrary shellcode and execute wasm exports function.In the end, we can stably execute arbitrary shellcode while maintaining persistence. An interesting fact is that the bug of the SBX challenge can be triggered even in the Renderer. However, triggering the vulnerability requires a slight race condition in the SBX Challenge, we are unsure whether UAF Object can be reliably occupied in Blink.

엔키화이트햇
2025. 7. 21.
언론보도
언론보도
보안 인사이트
보안 인사이트

치밀한 보안을 시작할 준비 되셨나요?
걱정없는 내일을 향한
첫 걸음을 내딛어보세요

치밀한 보안을 시작할 준비 되셨나요?
걱정없는 내일을 향한 첫 걸음을
내딛어보세요

치밀한 보안을 시작할 준비 되셨나요?