본문 바로가기

Skills/Drill or Guard

Workaround for systemd Denial of Service ( CVE-2016-7795, CVE-2016-7796 )

오랜만에 올리는 글,


https://fossbytes.com/this-single-line-of-code-can-crash-a-linux-system/


현재 위와 같은 systemd 관련 서비스 거부 취약점이 발견되면서

다소 두려워 하는 관리자들도 있을 것이라고 생각하여 대처방안을 생각해 보았다.


사실 대처방안이라고 하기에도 그렇고,  단순한 Workaround 가 아닐지도  모르고

어차피 패치된 버젼 나오면 그 패키지를 사용하면 되지만,


언제 나올지 모를(금방 나올테지만)  패치,  그리고 리부팅이 필요할 것으로 보이므로

리부팅이 부담되는 사람을 위한 꼼수를 생각해 내었다.


(원래 어제 하도 난리일때 기사도 제대로 안보고 있다가 오늘 퇴근하고 집에오면서 생각좀 해봄)


1. NOTIFY_SOCKET 을 세팅하는 과정에 시스템은 어떤  감사가 이루어 질까?


-  해당 내용을 확인하기 위해 우선 audit 설정을 해주었다.


# auditctl -w /usr/bin/systemd-notify -p x -k systemd_notify


위 설정은 systemd-notify 가 수행되면 systemd_notify 라는 라벨(키워드)  로

audit log 를 남기도록 설정한 룰이다.


간단히 테스트 해보자.


#  NOTIFY_SOCKET=/run/systemd/notify systemd-notify "test"

# ausearch -i -k systemd_notify

type=PATH msg=audit(10/06/16 08:02:05.657:79) : item=1 name=(null) inode=379981 dev=00:1d mode=file,755 ouid=root ogid=root rdev=00:00 obj=s
ystem_u:object_r:ld_so_t:s0
type=PATH msg=audit(10/06/16 08:02:05.657:79) : item=0 name=/usr/bin/systemd-notify inode=325712 dev=00:1d mode=file,755 ouid=root ogid=root
 rdev=00:00 obj=system_u:object_r:systemd_notify_exec_t:s0
type=CWD msg=audit(10/06/16 08:02:05.657:79) :  cwd=/root
type=EXECVE msg=audit(10/06/16 08:02:05.657:79) : argc=2 a0=systemd-notify a1=test                <<<<<<
type=SYSCALL msg=audit(10/06/16 08:02:05.657:79) : arch=x86_64 syscall=execve success=yes exit=0 a0=0x2491450 a1=0x232cfe0 a2=0x246f850 a3=0
x7ffde71a9e40 items=2 ppid=4535 pid=5743 auid=root uid=root gid=root euid=root suid=root fsuid=root egid=root sgid=root fsgid=root ses=6 tty
=pts1 comm=systemd-notify exe=/usr/bin/systemd-notify subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=systemd_notify


여기서 execve 타입에서 해당 Argument 가 나오는게 확인되었다.


자,  그럼 일단 감사시스템은 구축했으니,  그냥 누가 이거 실행하면 조지면 되는건가?


하지만 이미 시스템은 망가진 뒤  일텐데?


2.  기존 systemd-notify 를 대체할 만한 방법이 없을까?

-  이 아이디어를 바탕으로 고민해보다가 누구나 간단히 사용 할 수 있을 만한

Bash scripts 를 이용한 커맨드 대체 를 생각했다.


#!/bin/bash

if [ -n $NOTIFY_SOCKET ]
then
    systemd-notify_org $1
fi


그래,  문제의 원인은 NOTIFY_SOCKET 이라는 환경변수의 사용이며,

notify 프로그램 뒤에 Argument 를 넣지 않았다는 것이 핵심이었다.


따라서,  이를 체크하여 만약 해당 내용이 Null 이 아니라면

( 나의 테스트로는 Redhat 계열에선 기본 Null 인거같다 -  레댓계열밖에 몰라!)

해당 변수를 먼저 해제하거나 그냥 해당 내용을 echo 로 뿌려주면 될 것 이다.


만약 해당 변수가 아무것도 없다면,  혹은 정상적으로 사용된 것이라면

원래 있던 이름이 바뀐 systemd-notify 를  실행시켜주면  아무 문제 없이 수행 될 것이다.


테스트 해 보았다.


[root@perftest ~]# NOTIFY_SOCKET=/run/systemd/notify systemd-notify "test"
[root@perftest ~]# NOTIFY_SOCKET=/run/systemd/notify systemd-notify ""
systemd-notify_org [OPTIONS...] [VARIABLE=VALUE...]

Notify the init system about service status updates.

  -h --help            Show this help
     --version         Show package version
     --ready           Inform the init system about service start-up completion
     --pid[=PID]       Set main pid of daemon
     --status=TEXT     Set status text
     --booted          Check if the system was booted up with systemd
     --readahead=ACTION Controls read-ahead operations
[root@perftest ~]# echo $NOTIFY_SOCKET

[root@perftest ~]#


Audit 내용은 아래와 같다.


type=PATH msg=audit(10/06/16 09:05:33.533:199) : item=2 name=(null) inode=379981 dev=00:1d mode=file,755 ouid=root ogid=root rdev=00:00 obj=system_u:object_r:ld_so_t:s0
type=PATH msg=audit(10/06/16 09:05:33.533:199) : item=1 name=(null) inode=6081 dev=00:1d mode=file,755 ouid=root ogid=root rdev=00:00 obj=system_u:object_r:shell_exec_t:s0
type=PATH msg=audit(10/06/16 09:05:33.533:199) : item=0 name=/usr/bin/systemd-notify inode=437427 dev=00:1d mode=file,755 ouid=root ogid=root rdev=00:00 obj=system_u:object_r:systemd_notify_exec_t:s0
type=CWD msg=audit(10/06/16 09:05:33.533:199) :  cwd=/root
type=EXECVE msg=audit(10/06/16 09:05:33.533:199) : argc=2 a0=/bin/bash a1=/usr/bin/systemd-notify         <<<<<
type=EXECVE msg=audit(10/06/16 09:05:33.533:199) : argc=3 a0=/bin/bash a1=/usr/bin/systemd-notify a2=test
type=SYSCALL msg=audit(10/06/16 09:05:33.533:199) : arch=x86_64 syscall=execve success=yes exit=0 a0=0x1af3c00 a1=0x1b44a40 a2=0x1b28870 a3=0x7ffc2e391ca0 items=3 ppid=2191 pid=7914 auid=root uid=root gid=root euid=root suid=root fsuid=root egid=root sgid=root fsgid=root ses=1 tty=pts0 comm=systemd-notify exe=/usr/bin/bash subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=systemd_notify
----
type=PATH msg=audit(10/06/16 09:05:36.597:200) : item=2 name=(null) inode=379981 dev=00:1d mode=file,755 ouid=root ogid=root rdev=00:00 obj=system_u:object_r:ld_so_t:s0
type=PATH msg=audit(10/06/16 09:05:36.597:200) : item=1 name=(null) inode=6081 dev=00:1d mode=file,755 ouid=root ogid=root rdev=00:00 obj=system_u:object_r:shell_exec_t:s0
type=PATH msg=audit(10/06/16 09:05:36.597:200) : item=0 name=/usr/bin/systemd-notify inode=437427 dev=00:1d mode=file,755 ouid=root ogid=root rdev=00:00 obj=system_u:object_r:systemd_notify_exec_t:s0
type=CWD msg=audit(10/06/16 09:05:36.597:200) :  cwd=/root
type=EXECVE msg=audit(10/06/16 09:05:36.597:200) : argc=2 a0=/bin/bash a1=/usr/bin/systemd-notify
type=EXECVE msg=audit(10/06/16 09:05:36.597:200) : argc=3 a0=/bin/bash a1=/usr/bin/systemd-notify

type=SYSCALL msg=audit(10/06/16 09:05:36.597:200) : arch=x86_64 syscall=execve success=yes exit=0 a0=0x1b45a20 a1=0x1abb040 a2=0x1b28870 a3=0x7ffc2e391ca0 items=3 ppid=2191 pid=7916 auid=root uid=root gid=root euid=root suid=root fsuid=root egid=root sgid=root fsgid=root ses=1 tty=pts0 comm=systemd-notify exe=/usr/bin/bash subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=systemd_notify


사실 -z 를 넣어야 하는게 맞나?  싶었는데 테스트 해본결과 -n 로 넣어 놓는게 훨씬 무탈하고 자연스러워

해당 내용을  유지하기로 했다.


각자 script 및 원본 명령 위치등은 알아서 수정하면 될거같다.  보안적으로.


간단한 테스트만 하고 올린 글이라 각자 상황에 맞게 이런 컨셉으로 보완해 사용하시길.


아주 간단히 테스트만 한두시간 해보고 올리는 글이니 문제가 된다면 삭제할 예정

(나에게 책임이란 없다.)


끝.