다행히 백도어가 소프트웨어 제품의 정식 릴리스에 진입해 일반 사용자에게도 배포된 최근 솔라윈즈(SolarWinds) 침해나 다른 공급망 공격과 같은 광범위한 영향은 없었다. 그러나 사고는 PHP를 유지하는 조직인 PHP 그룹(PHP Group)이 코드 인프라의 운영 방식을 재검토하는 계기가 됐다.
오픈소스 코드는 주요 인터넷 서비스의 중심에 위치하며 현대 애플리케이션 코드베이스의 대부분을 차지한다. 자원 봉사자에 의해 제한적인 리소스로 운영되는 경우가 많은 오픈소스 프로젝트를 대상으로 한 공급망 공격의 수는 지난 몇 년 동안 가파르게 증가했다. 또한 전문가들은 방어가 어려운 만큼 공격자 사이에서 공급망 공격 벡터의 인기가 앞으로 더 높아질 것으로 예상하고 있다.
PHP 리포지토리에 무슨 일이
최근 PHP 창안자이자 코어 개발자인 라스무스 러도프의 이름으로 git.php.net의 php-src 리포지토리에 "[skip-ci] Fix typo"라는 이름의 코드 커밋이 푸시됐다. 2시간 후 다른 PHP 기여자가 코드에 오타가 있다는 코멘트를 남겼고, 이후 다른 개발자가 코드의 역할이 무엇인지를 물었다. 이 질문은 보안 전문가인 한 개발자의 관심을 끌었다. 개발자는 '문자열이 'zerodium'으로 시작하는 경우 useragent HTTP 헤더 내에서 PHP 코드를 실행하는 코드'라고 답을 남겼다.기본적으로 이 코드는 백도어(backdoor)였다. 공격자가 HTTP 헤더에 특정 문자열이 포함된 요청을 보내는 간단한 방법으로 실행이 가능하며, 그러면 감염된 이 PHP 버전을 실행하는 모든 웹 서버에서 임의의 코드를 실행할 수 있게 된다. 다행히 효과적인 코드 리뷰 체계 덕분에 악성코드는 신속하게 발견됐고 아직 프로덕션에는 사용되지 않는 PHP 8.1의 개발 분기에만 영향을 미쳤다. 8.1 버전은 11월 이후에 출시될 예정이다.
그 다음에 일어난 일은 더 흥미롭다. 러도프의 이름으로 실행된 무단 커밋은 PHP 코어 개발자인 니키타 포포프에 의해 신속하게 되돌려졌지만, 얼마 후 그 되돌리기 자체가 포포프 자신의 계정에 의해 다시 되돌려졌다. 사실은 해커가 포포프를 가장한 계정을 사용해 악성코드를 다시 복구한 것이다.
세 번째 코어 개발자가 개입해 무단 커밋을 되돌리고 서버도 오프라인으로 내린 후 포포프는 PHP 메일링 리스트에 “어제(2021-3-28) 라스무스 러도프와 내 이름으로 2개의 악성 커밋이 php-src 리포지토리에 푸시됐다. 이 일이 정확히 어떤 경로로 발생했는지는 아직 모르지만 모든 정황상 하나의 깃 계정이 아닌 git.php.net 서버가 침해된 것으로 보인다”라는 메시지를 발표했다.
포포프에 따르면, 공격 이후 운영팀은 자체 깃 서버 운영을 중단하고 개발을 깃허브(GitHub)로 옮기기로 결정했다. 자체적으로 구축한 카르마 시스템을 접근 제어에 사용한 자체 깃 인프라를 유지하는 것이 '불필요한 보안 위험'이라고 판단했기 때문이다. PHP 그룹은 전부터 이미 깃허브를 자체 관리하는 깃 리포지토리의 미러로 사용하고 있었지만, 이제는 깃허브가 주 리포지토리가 된다. 현재 계정에 이중 요소 인증이 필요한 깃허브의 PHP 조직으로 모든 기여자를 옮기는 과정을 진행 중이다.
그레이햇 해커의 개념 증명 공격인가?
데브옵스 자동화 및 오픈소스 거버넌스 업체인 소나타입(Sonatype) CTO 일카 투루넨은 본지와의 이메일 인터뷰에서 “정황상 누군가가 메시지를 전하고자 한 것으로 보인다”면서, “물론 윤리적 해킹의 경계를 한참 넘은 행위지만, 상당히 노골적인 코드와 오타까지 포함하고 있었다. 자체 호스팅 깃 서버와 같은 노후화된 인프라로 인한 불필요한 공격 표면이 존재하며, 이로 인해 재앙적인 사고가 발생할 수 있다는 메시지를 전하고자 한 것 같다”라고 말했다.트위터와 해커 뉴스에 올라온 많은 의견에 따르면, 문제의 커밋에서는 공격을 숨기고자 하는 교묘함을 찾아볼 수 없었다. 우선 이름에 [skip-ci]가 있었는데, 이는 많은 CI(Continuous Integration) 도구에서 빌드 및 테스트 워크플로우를 생략하도록 하는 문자열이다. skip-ci는 개발자 커뮤니티에서 잘 알려진 규약이긴 하지만 프로젝트 자체에서 자주 사용되지 않는 한 주의를 끌 수밖에 없다.
또한 악성코드는 백도어 트리거로 “zerodium”이라는 문자열과 "REMOVETHIS: sold to zerodium, mid 2017."이라는 메시지를 포함하고 있었다. 제로디움(Zerodium)은 다양한 운영체제와 주요 데스크톱 및 웹 애플리케이션에 대한 제로데이 익스플로잇을 구매하는 기업으로, 여기에는 PHP용 익스플로잇도 포함된다. 제로디움 웹사이트에 따르면, PHP의 원격 코드 실행 취약점에 대해 제로디움은 최고 25만 달러를 제시한다.
제로디움의 창업자이자 CEO인 샤우키 베크라는 트위터를 통해 "문제의 해커는 트롤이며, 이번 사건은 제로디움과는 무관하다"라고 말했다.
무단 커밋이 쉽게 발견되도록 의도한 것인지 여부는 알 수 없지만, 공격자가 더욱 교묘한 취약점을 코드에 집어넣는 데 사용할 수 있는 높은 수준의 접근 권한을 확보했던 것은 사실이다(2003년의 리눅스 백도어 시도와 마찬가지). 그럴 목적이었다면 PHP 커뮤니티에서 러도프나 포포프만큼 눈에 잘 띄지 않는 다른 개발자를 가장했을 수도 있다. 포포프는 성명에서 PHP 프로젝트의 조사는 계속될 것이며, 이 조사에는 모든 리포지토리를 대상으로 추가적인 '변질'이 있는지 여부를 검토하는 작업이 포함될 것이라고 전했다. 포포프는 본지가 이메일로 보낸 추가 질문에는 답하지 않았다.
코드 커밋의 출처 검증하기
깃은 GPG 키를 사용한 코드 커밋 서명을 지원하며 이 기능은 깃허브에서도 웹 기반 인터페이스를 통해 커밋된 코드와 로컬 머신에서 커밋된 코드, 두 가지 모두에 적용된다. 코드 커밋에 서명하는 목적은 코드의 출처가 조직이 신뢰하는 계정 또는 개인인지 확인하는 데 있다. 공개키 암호화에 의존하는 일종의 ID 검증이다. 깃허브는 디지털 서명된 커밋에 녹색으로 '검증됨(Verified)' 표시를 붙인다.일부 PHP 기여자는 이미 커밋에 서명을 하고 있지만 PHP 프로젝트 차원에서 모든 커밋에 대해 서명 검증을 의무화하지는 않고 있다. 대규모 프로젝트에서는 이런 경우가 드물지 않다. 오픈소스 커뮤니티에서는 모든 커밋에 서명을 해야 한다는 의견과 태그(일반적으로 릴리스를 나타내는 코드 프리즈)만으로 된다는 의견이 오래전부터 충돌하고 있기 때문이다. 그러나 이번 공격 이후 PHP 개발자들은 최소한 php-src 리포지토리에 대해서는 서명된 커밋을 강제하는 방안을 검토 중이다.
투루넨은 “메이븐 센트럴 리포지토리(Maven Central Repository)의 스튜어드인 소나타입은 ID를 검증하기 위한 방법으로 처음부터 코드 서명을 의무화했다”면서, “코드 서명이 이와 같은 종류의 문제에 대한 만능 해결책은 아니고 센트럴은 다른 ID 검증 방법도 사용하지만 전체를 구성하는 요소 중의 하나로 진지하게 고려해야 한다. 물론 마찰 계층이 추가되고 엔지니어링 과제도 수반되고 궁극적으로 필요한 무결성 수준을 정하는 것은 각 프로젝트지만, 핵심적인 디지털 인프라의 경우 강력한 커미터 신원 증명이 필요하다는 것이 소나타입의 입장”이라고 말했다.
코드 커밋 서명이 모든 가장 공격을 차단하지는 못한다. 예를 들어 개별 개발자의 컴퓨터와 개인 GPG 키가 침해된다면 공격자는 로컬에서 악성코드에 서명한 다음 자신의 컴퓨터에서 커밋할 수 있다. 키를 외부 하드웨어 토큰이나 하드웨어 보안 모듈에 저장하는 등 추가 보안 메커니즘을 사용해 이와 같은 위험을 완화하는 방법은 있지만 이 경우 복잡성이 발생하고, 오픈소스 프로젝트는 일반적으로 자발적 기여 의지를 꺾을 수 있는 잠재적 장애물을 꺼린다. 다만 대형 프로젝트의 경우 포함될 코드를 제출하는 모든 개발자가 아닌, 신뢰성이 확인된 소수의 정규 기여자에게만 커밋 권한을 부여하는 경향이 있다.
투루넨은 “한쪽에는 오픈소스의 핵심 요소인 접근과 기여의 용이함이 있고 다른 쪽에는 보안과 강제적 규칙이 있다. 균형을 잡기가 어려운 부분이다. 완벽한 보안은 없고, 모든 주요 생태계에 걸쳐 반복적으로 확인된 바와 같이 오픈소스 생태계 역시 그 속성상 앞으로 계속 공급망 공격 시도의 대상이 될 것이다. 최소한 코드를 포함한 인프라의 핵심적인 부분에 대해서라도 커미터의 신원을 확인하고 검증하기 위한 조치가 필요하며, 소나타입은 메이븐 센트럴에서 그렇게 하고 있다”라고 말했다.
자체 호스팅 vs. 서드파티 서비스
많은 사람이 사용하고 의존하고 있음에도 불구하고 대다수 오픈소스 프로젝트는 인적, 금전적 자원 부족에 시달린다. 대규모 개발 프로젝트를 위한 인프라를 유지하고 그에 더해 인프라의 안전을 보장하는 것은 어려운 일이다. 상업적인 대기업조차 실패하는 경우가 많다. 많은 오픈소스 프로젝트는 직업이 따로 있는 자원봉사자들에 의해 운영된다. 예를 들어 2014년 오픈SSL에서 치명적인 하트블리드(Heartbleed) 버그가 발견됐을 당시, 수십억 개의 디바이스와 서버, 애플리케이션에 사용되는 방대하고 복잡한 코드베이스를 책임지는 정규 개발자가 단 두 명이라는 사실이 알려지면서 충격을 줬다. 이 사고 이후 리눅스 재단은 인터넷을 위한 주요 프로젝트에 자금을 지원하기 위해 여러 주요 인터넷 기업과 함께 코어 인프라 이니셔티브(Core Infrastructure Initiative, CII)를 출범했다.오픈소스 프로젝트는 코드 인프라를 깃허브와 같은 서드파티 서비스로 옮기면 서버 관리와 보안을 서비스 제공업체에 맡길 수 있다. 서비스 제공업체는 비즈니스의 성공과 평판이 걸려 있는 만큼 전문성을 갖춘 정규 직원을 채용해 서버 관리와 보안에 주력한다. PHP 그룹은 자체 호스팅 서비스 일부의 운영을 중단하기로 결정했다. 잠재적인 공급망 침해로부터 사용자를 보호하고자 하는 다른 프로젝트에서도 향후 이와 비슷한 결정을 내려야 할 가능성이 높다.
투루넨은 “인프라를 호스팅한다는 것은 단순한 소프트웨어 또는 서비스 업데이트 이상의 본격적인 유지보수 작업을 떠안는 것이다. 취약점이 발견되고 24시간 이내에 악용되는 사례가 빈번하고, 이는 자체 호스팅 인프라를 최신 상태로 유지해야 한다는 점에서 상당한 압박으로 작용한다. 인프라와 소프트웨어 유지보수 측면에서 대형 제공업체는 유지보수가 핵심 역량도 아닌 소규모 유지보수 팀으로는 달성할 수 없는 규모의 경제를 제공할 수 있다. 다만 오픈소스의 철학과 더 넓은 풍조를 염두에 두고 이러한 결정을 내리는 경우가 종종 있다. 보편적인 정답은 없지만 모든 주요 프로젝트가 앞으로 고려해야 할 옵션”이라고 말했다. editor@itworld.co.kr