1. hosts 파일 소유자 및 권한 설정
정보통신기반시설 취약점 가이드에는 로컬 환경에서 호스트명과 IP주소를 맵핑하는 hosts 파일에 대해 600으로 권한 설정하도록 권고하고 있습니다.
root 계정만 읽고/쓰기가 가능하도록 하고 다른 계정에서는 읽기/쓰기를 금지하도록 설정을 권고하는데, 아마도 Hosts 파일 변조를 통해 악의적인 시스템으로 데이터 전송 경로를 방지하기 위한 권고사항으로 생각됩니다.
실제로 Hosts 파일은 DNS 보다 우선순위가 높기 때문에 동일한 호스트네임이 DNS와 Hosts파일 둘 다 존재할 경우 Hosts 파일의 IP주소를 우선 적용합니다.(Linux, Windows 공통)
문제는 Hosts 파일을 600으로 설정할 경우 일반 사용자는 Hosts 파일에 존재하는 호스트네임을 사용 할 수 없다는 점 입니다.
2. Hosts 권한 설정 테스트
우선 hosts 파일이 644 권한인 상태에서 root계정과 일반 사용자 계정으로 ping 테스트를 합니다.
hosts 파일에 구글 DNS 서버인 8.8.8.8 을 googledns 라는 이름으로 등록합니다.
root 계정으로 googledns 로 ping 명령 수행 시 정상적으로 ping 이 동작됩니다.
root가 아닌 일반사용자계정(sis1, uid=500) 으로 ping 수행 시에도 정상적으로 동작합니다.
이번에는 가이드의 권고사항대로 hosts 파일에 600 으로 권한을 설정하고 동일하게 테스트 합니다.
root 계정으로 ping 실행 시에는 정상적으로 동작합니다.
일반 사용자 계정 (sis1) 로 ping을 실행 시 host파일이 644 권한 일 때와 다르게 unknown host 라는 에러 메시지가 출력됩니다.
테스트를 통해 ping 명령이 hosts 파일 접근 권한에 따라 영향을 받고 있음을 알 수 있습니다.
3. Host명 탐색 절차
Host명과 IP주소를 맵핑하는 절차를 확인하기 위해 Linux ping 소스코드를 찾아 봤습니다.
ping 실행 시 매개변수로 받은 호스트이름을 target 변수에 할당하고, getaddrinfo()함수를 호출해서 target의 주소를 가져옵니다.
다음은 getaddrinfo()함수가 정의된 GNU C Library 의 getaddrinfo.c 소스코드 입니다.
전달받은 hostname을 gaih_inet 함수의 매개변수로 호출하는데, gaih_inet 함수에서 nss_database_lookup 함수 호출 시 "hosts"를 상수로 전달 하면서 hosts 파일의 정보를 recursive 하게 읽어오는 걸로 보입니다.
더 자세히 보지는 않았지만, getaddrinfo, gethostbyname 류 의 IP주소를 가져오는 glib 의 함수들은 hosts 파일에 직접 접근해서 hostname과 ip 주소를 맵핑하는 것으로 보입니다.
4. 흥미로운 사실들
ping 프로그램이 실행되는 과정을 뜯어 보다 알게 된 사실.(저만 몰랐을 수도..-_-a;;)
처음에는 다른 프로그램들은 hosts 접근 권한 600에 영향을 받아도 ping 프로그램은 상관없을 거라 생각했습니다. 왜냐하면 ping은 기본적으로 실행할 때 root권한을 가지는 setuid 권한을 가지고 있기 때문입니다.
(기본 권한 : rws r-x r-x)
그런데 일반 사용자 계정으로 ping을 실행하면 root 권한이 아닌 일반 사용자 권한으로 실행됩니다. (userid, ruserid, euserid 모두 일반사용자 id)
일반사용자 계정(sis1)로 ping 실행 후 ps 로 ping 프로세스의 user id 들을 살펴보면 root 가 아닌 sis1로 실행됨을 알 수 있습니다.
ping 프로그램은 3계층 icmp 프로토콜을 사용하므로 4계층 이상의 tcp나 udp 프로토콜과 다르게 소켓 생성 시 직접 raw socket을 핸들링해야 합니다. 그래서 root 권한이 필요하고 실제로 setuid 가 설정되어 있습니다.
그런데 root 권한으로 실행되는 ping 이 sis1 사용자id를 가지며, 600으로 퍼미션 설정된 hosts 파일에 접근하지 못하는 이유는 ping 실행 후 setuid()를 통해 원래 user id 로 변경하기 때문입니다.
raw socket 핸들링을 수행하고 나면 강제로 root 권한으로 수행되던 user id 를 강제로 권한을 낮춰서 안전하게 실행되도록 구현되어 있습니다.
4. 결론
hosts파일을 설정하면 막연하게 운영체제가 알아서 hostname과 ip를 맵핑하겠지.. 라고 생각했는데, 뜯어보니 실제로는 상당히 정교하게 (운영체제의 별다른 개입없이) glib 에서 많은 부분을 수행하고 있었습니다.
단순하게 hosts 파일을 보호하기 위해 600 퍼미션으로 설정하게 되면 DNS가 아닌 hosts파일을 참조하도록 설정된 상당수의 프로그램(root권한이 아닌)에서 문제가 생길 가능성이 있습니다.
hosts 파일의 변조를 막기 위해서라면 퍼미션을 644 정도로 타협하는게 괜찮지 않나 싶습니다.

댓글목록
등록된 댓글이 없습니다.