리눅스 오픈 소스 루트킷 Singularity: 숨김 기술과 방어 포인트
리눅스용 무료 오픈 소스 루트킷 Singularity가 공개되면서, “루트킷이 대체 뭘 숨기길래 무섭다”라는 질문이 다시 뜨거워졌습니다. Singularity는 보안 연구용 테스트베드 성격이 강하지만, 기능만 놓고 보면 네트워크 통신·파일·프로세스를 감쪽같이 숨기고 원격 코드 실행까지 가능한 ‘교과서급 커널 루트킷’에 가깝습니다.
이 글에서는 Singularity가 어떤 방식으로 존재를 지우는지(특히 ftrace 훅), 무엇을 어떻게 숨기는지(프로세스/파일/네트워크), 그리고 운영 환경에서는 어떤 지점을 막아야 하는지를 이해하기 쉽게 정리합니다. 악용은 범죄가 될 수 있으니, 방어와 연구 관점으로만 읽어주세요.
Singularity 루트킷이 특별히 위험한 이유
루트킷의 무서움은 “뭔가 나쁜 짓을 한다”보다 “나쁜 짓을 했다는 흔적을 지운다”에 있습니다. Singularity는 커널 레벨에서 동작하며, 표준 관리 도구가 보는 화면 자체를 바꿔치기하는 방식으로 숨어버립니다.
Hacker News 토론에서도 핵심은 비슷했습니다. 커널(ring0)까지 들어간 순간, SELinux 같은 커널 기반 방어도 ‘우회될 가능성’이 커지고, 결국 가장 중요한 건 애초에 악성 커널 모듈이 로드되지 못하게 막는 것이라는 의견이 강하게 나왔습니다.1
즉, Singularity는 “침입 이후의 은폐(Defense Evasion)”를 연구하기엔 훌륭하지만, 실제 환경에선 “모듈 로딩 차단”이 방어의 출발점이 됩니다.
ftrace 훅: ‘커널 함수 갈아끼우기’로 시야를 속인다
Singularity의 핵심 엔진은 ftrace입니다. ftrace는 원래 커널 디버깅과 성능 추적을 위한 기능 추적 프레임워크인데, 특정 커널 함수를 “가로채서” 다른 코드로 연결하는 방식이 가능합니다.2
쉽게 비유하면 이렇습니다. 관리자가 ls로 디렉터리를 봅니다. 그런데 ls가 직접 파일을 세는 게 아니라, 커널에게 “목록 좀 줘”라고 물어본 결과를 보기 좋게 출력할 뿐이죠. Singularity는 그 “목록 결과”가 사용자에게 올라오기 전에 중간에서 살짝 손을 대서, 특정 파일 이름이나 엔트리를 버퍼에서 제거해버립니다. 그러면 사용자는 “파일이 없는 것처럼” 보게 됩니다.
이런 ftrace 기반 훅은 시스템 콜 테이블을 직접 덮어쓰는 고전적 방식보다 흔적이 덜 눈에 띄고, 커널 버전에 따라 더 유연하게 작동할 가능성이 있어 연구자들이 주목합니다. 실제로 ftrace를 이용해 시스템 콜(예: getdents 계열)을 가로채 파일을 숨기는 기법은 다른 커널 모듈 루트킷 사례에서도 자세히 설명된 바 있습니다.3
프로세스·파일 은폐: “없애는 게 아니라, 안 보이게 한다”
Singularity가 하는 일은 대개 “삭제”가 아니라 “필터링”입니다. 공격자가 제어하는 프로세스나 파일은 그대로 존재하지만, 관리 도구가 조회할 때 결과에서 빠지도록 응답을 조작합니다.
프로세스 숨김은 특정 PID를 추적하는 식으로 운영됩니다. 내부적으로는 숨길 프로세스들의 식별자를 관리하고, 표준 도구가 프로세스 목록을 요청할 때 해당 PID가 포함된 결과만 조용히 누락시키는 방향으로 움직입니다.
파일 숨김은 더 노골적으로 ‘시스템 콜 훅킹’의 정석을 밟습니다. 디렉터리 목록을 가져오는 getdents() 계열, 파일 정보를 확인하는 stat(), 파일을 여는 openat() 같은 호출을 훅해서 특정 파일이 목록에 나타나지 않거나 접근이 막히도록 만들고, 동시에 파일 시스템 일관성이 깨져 들키지 않도록 신경 쓰는 방식입니다.
여기서 포인트는 “관리자가 쓰는 도구(예: ls, ps)가 틀렸다”가 아니라, “그 도구가 기대는 커널의 답안지가 바뀌었다”는 점입니다. 그래서 사용자 영역에서만 보는 점검은 한계가 생깁니다.
네트워크 은폐: 포트 8081과 ‘보이지 않는 통로’ 아이디어
Singularity는 네트워크 활동도 숨깁니다. 특히 공격자가 사용하는 통신을 특정 포트(예: TCP 8081)로 고정해두고, 그 트래픽이 패킷 캡처 도구나 표준 네트워크 조회에서 잘 보이지 않도록 ‘필터링’합니다.
또 한 가지 흥미로운 지점은 netlink 기반 조회 결과를 숨기는 방향입니다. 리눅스에서 ss 같은 도구가 소켓 정보를 볼 때 netlink를 활용하는데, Singularity는 이런 조회 흐름에 개입해 “소켓이 없는 것처럼” 보이게 만드는 연구 포인트가 언급됩니다.1
정리하면, 방화벽에서 8081을 막는 것만으로 해결될 문제가 아니라, “보이는 지표 자체가 조작될 수 있다”는 가정 하에 탐지 전략을 짜야 합니다.
운영 환경 방어 체크리스트: 핵심은 ‘모듈 로딩 차단’이다
커널 루트킷은 로드된 다음에 대응하면 이미 늦는 경우가 많습니다. 그래서 방어의 우선순위는 “탐지”보다 “진입 차단”에 더 가깝습니다.
가장 현실적인 방향은 커널 모듈 로딩 권한을 최소화하는 것입니다. 예를 들어 pid 1(systemd 등)이 자식 프로세스에게 CAP_SYS_MODULE 권한이 남지 않도록 bounding set에서 떨어뜨리는 접근이 논의됩니다.1 이렇게 되면 공격자가 insmod/modprobe로 악성 모듈을 끼워 넣을 길이 훨씬 좁아집니다.
또한 Secure Boot 환경에서는 서명되지 않은 커널 모듈이 로드되기 어려워져 공격 난도가 올라갑니다. 실제로 일부 불변(immutable) 성향의 운영 방식에서는 “커널 모듈을 끼워 넣는 것 자체가 장벽”이 된다는 의견도 나옵니다.1
탐지 측면에서는 전통적인 루트킷 스캐너도 여전히 의미가 있습니다. 예를 들어 rkhunter는 중요한 파일 해시 비교, 의심스러운 커널 모듈 문자열, 숨김 파일/권한 이상 등을 점검하는 도구로 널리 알려져 있고, 여러 배포판에서 패키지로 제공됩니다.4 다만 커널이 응답을 속이는 상황까지 커버하긴 어렵기 때문에 “기본 위생 점검” 정도로 보는 게 안전합니다.
시사점: ‘오픈 소스 루트킷’은 위협이자, 좋은 교재다
Singularity 같은 오픈 소스 루트킷이 등장하면 불편한 진실이 드러납니다. 커널 레벨로 들어가면, 우리가 믿던 보안 통제와 로깅이 “전부 100% 진실”이 아닐 수 있습니다.
하지만 역설적으로, 이런 프로젝트는 방어자에게도 득이 됩니다. 어떤 함수가 훅 포인트가 되는지, 은폐가 어떤 시스템 콜에서 일어나는지, 네트워크/프로세스/파일 은닉이 어떻게 결합되는지 눈으로 확인할 수 있으니까요. 그리고 결론은 대체로 하나로 모입니다. “침입 이후 탐지”도 중요하지만, 커널 모듈이 마음대로 로드되는 구조라면 방어는 계속 불리하다는 것.
실무적으로는 커널 모듈 로딩을 막고(권한/정책/서명), 의심스러운 로딩 시도를 로깅하며, 운영체제 무결성과 부팅 체인을 강화하는 쪽으로 투자 우선순위를 잡는 게 가장 효과적입니다.
참고
1Singularity Rootkit: SELinux bypass and netlink filter (ss/conntrack hidden) | Hacker News
3Rootkit Uncovered: How a Kernel Module Hides Files in Plain Sight | RavChat