개요

Apache HTTP Server에서 입력값 검증이 미흡하여 발생하는 버퍼오버플로우 취약점(CVE-2021-44790)
공격자가 조작된 요청을 mod_lua*모듈로 처리 할 때 버퍼 오버플로가 가능한 취약점

 

영향받는 버전

Apache HTTP Server 2.4.51 및 이전 버전

 

해결방안

1. 취약점 업데이트 (패치 적용 前 업무시스템의 서비스 영향 검토 후 적용할 것)
    -   2.4.51 및 이전 버전의 경우, 최신 버전(2.4.52) 업그레이드 적용[2]
 
2. 임시 조치방안
    - mod_lua 모듈 非활성화 (디폴트로 비활성화 되어있음)
    ※ 모듈 확인방법 : 소스 트리의 httpd.conf 내 "LoadModule lua_module modules/mod_lua.so" 검색 > 주석 처리

관리자 계정명 관리

 

관리자 계정명 미변경 및 기본유저 로그인 가능할 시 취약하다.

관리자 콘솔 사용시 User name 확인
[4.x / 5.x] - /[Tomcat path]/conf/tomcat-users.xml

 

<tomcat-users> 
<role rolename=""tomcat""/>
  <role rolename=""admin-gui""/>
  <role rolename=""manager-gui""/>
  <role rolename=""role1""/>
  <user username=""autoever"" password=""autoever"" roles=""admin-gui,manager-gui""/>
  <user username=""tomcat"" password=""tomcat"" roles=""tomcat""/>
  <user username=""both"" password=""tomcat"" roles=""tomcat,role1""/>
  <user username=""role1"" password=""tomcat"" roles=""role1""/> </tomcat-users>

[6.x / 7.x / 9.x] - /[tomcat path]/conf/tomcat-users.xml

 

(apt-get 으로 설치한 경우 /etc/tomcat7/tomcat-users.xml에 있을 수 있음)

 

[시스템현황] [ tomcat dir ]\conf\tomcat-users.xml 'tomcat-user' 설정 미존재

 

 

조치사항

 

1. [4.x / 5.x] - 관리자 콘솔 사용시 User name 확인 및 변경

   [6.x / 7.x] – 아래의 설정 파일을 통해 User name 확인 및 변경 설정 파일 : /[Tomcat path]/conf/tomcat-users.xml

 

2. [4.x / 5.x] - 관리자 콘솔의 [User Definition | Users | RoleName]에서 계정명을 설정

 

3. [6.x / 7.x] - 기본 유저와 패스워드를 삭제 또는 주석으로 처리해 주어 기본 유저로의 로그인이 불가능 하도록 권고한다.

 

설정 파일 : /[Tomcat path]/conf/tomcat-users.xml

관리자 콘솔 관리

Default 포트(8080)를 사용하고 있고, 관리자 콘솔 사용시 취약하다.

Tomcat 관리자 콘솔 사용 유무 확인함.
예) http://[Domain]/manager, http://[Domain]/admin/

(단, Tomcat 5.5.x의 버전의 경우 admin을 따로 다운로드 받아 설치하여야 하며
6.0 이상의 버전엔 http://[Domain]/admin/ 자체가 존제하지 않으므로 http://[Domain]/manager 만 확인)

 

 

조치사항

1. Default포트인 8080은 공격자가 유추 할 수 있으므로, 유추할 수 없는 포트로 변경. 번호를 지정하여 사용하기를 권고함 (권장 포트 범위 : 1024~65534)

 

    - 설정 파일 : /[Tomcat path]/conf/server.xml

    - server.xml 파일 변경 후 Tomcat 서버를 Stop하고 다시 start 시켜야 적용됨


2. 필요 시에만 관리자 콘솔 운영을 권고함, 필요한 경우에 한하여 관리자 콘솔을 사용하고 불필요한 경우 프로세스를 종

 

XSS란?

XSS(cross-site scripting)는 웹페이지에 악의적인 스크립트 코드를 주입할 수 있는 취약점이다.

 

XSS(Cross Site Scripting) 방지를 위해 널리 쓰이는 훌륭한 lucy-xss-servlet-filter는 Servlet Filter 단에서 < 등의 특수 문자를 &lt; 등으로 변환해주며, 여러 가지 관련 설정을 편리하게 지정할 수 있어 정말 좋다.

그런데 그 처리가 form-data에 대해서만 적용되고 Request Raw Body로 넘어가는 JSON에 대해서는 처리해주지 않는다는 단점이 있다. 그래서 JSON을 주고 받는 API 서버의 경우에는 직접 처리를 해줘야 한다.

 

즉, Lucy는 RequestParameter관련한 지원만 해준다.

 

 

그래서 이를 보완하기 위해서 여러가지 방법이 있겠지만, 가장 많이 사용되는 방법인 Request를 Wrapping 하여 적용하도록 한다. (기존에 Lucy XSS Filter를 사용하고 있다는 가정하에 작성)

 

준비물 : 2개의 Java Class, web.xml, Lucy XSS Filter

 

# Lucy XSS Filter는 Maven Central Repository 에 배포되어 있다. pom.xml 에 아래와 같이 의존성을 선언한다.

1
2
3
4
5
<dependency>
    <groupId>com.navercorp.lucy</groupId>
    <artifactId>lucy-xss</artifactId>
    <version>X.X.X</version>
</dependency>
cs

 

 

RequestWrapper.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
 
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
 
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
 
import com.nhncorp.lucy.security.xss.XssFilter;
 
public class RequestWrapper extends HttpServletRequestWrapper {
    private byte[] b;
 
    public RequestWrapper(HttpServletRequest request) throws IOException {
        super(request);
        XssFilter filter = XssFilter.getInstance("lucy-xss-sax.xml");
        b = new String(filter.doFilter(getBody(request))).getBytes("UTF-8");
    }
 
    public ServletInputStream getInputStream() throws IOException {
        final ByteArrayInputStream bis = new ByteArrayInputStream(b);
        return new ServletInputStreamImpl(bis);
    }
 
    class ServletInputStreamImpl extends ServletInputStream {
        private InputStream is;
 
        public ServletInputStreamImpl(InputStream bis) {
            is = bis;
        }
 
        public int read() throws IOException {
            return is.read();
        }
 
        public int read(byte[] b) throws IOException {
            return is.read(b);
        }
    }
 
    public static String getBody(HttpServletRequest request) throws IOException {
        String body = null;
       BufferedReader br= null;
       StringBuilder sb= new StringBuilder();
        try {
            InputStream inputStream = request.getInputStream();
            if (inputStream != null) {
               br = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
                char[] charBuffer = new char[128];
                int bytesRead = -1;
                while ((bytesRead = br.read(charBuffer)) > 0) {
                   sb.append(charBuffer, 0, bytesRead);
                }
              
            } else {
               sb.append("");
            }
        } catch (IOException ex) {
            throw ex;
        } finally {
            if (br!= null) {
                try {
                   br.close();
                } catch (IOException ex) {
                    throw ex;
                }
            }
        }
        body = sb.toString();
        return body;
    }
}
 
cs

 

실제 필터링 기능을 수행하는 Java class이다. 

주의할 부분은 해당 작업을 수행할 경우 한글이 깨져서 chain.doFilter(requestWrapper, response);가 수행될 때 Json 오류가 날 수 있다.

그러므로 br= new BufferedReader(new InputStreamReader(inputStream, "UTF-8")); 항목에 인코딩 설정을 명시해서 해당 오류를 피해 가도록 한다.

 

 

 

RequestBodyXSSFIleter.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
public class RequestBodyXSSFIleter implements Filter {
    private List<String> extUrl;
 
    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
            throws IOException, ServletException {
        
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) res;
       RequestWrapper reqWrapper = null;
        String path = ((HttpServletRequest) req).getServletPath();
 
        try {
            if (!extUrl.contains(path)) {
              
               reqWrapper = new RequestWrapper(request);
               chain.doFilter(reqWrapper , response);
            } else {
                chain.doFilter(request, response);
            }
 
        } catch (Exception e) {
            e.printStackTrace();
        }
 
    }
 
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        String excludePattern = filterConfig.getInitParameter("extUrls");
       extUrl = Arrays.asList(excludePattern.split(","));
    }
 
    @Override
    public void destroy() {
    }
}
 
cs

 

requestBody에 XSS Filter를 적용할 경우 Multipart(일반적으로 파일 업로드) 일 때 파일이 손상되는 일이 발생한다.

이를 방지하기위해 파일을 송신하는 URL의 경우 web.xml의 init-param을 이용하여 필터링을 제외할 수 있다.

 

RequestBodyXSSFIleter의 init시 filterConfig에서 해당 파라미터에 접근하여 제외할 URL목록을 콤마(,)로 구분하여 작성 후 필터를 적용하지 않는 방법으로 우회할 수 있다.

 

 

web.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
    <!-- Xss Filter Start -->
    <filter>
        <filter-name>xssEscapeServletFilter</filter-name>
        <filter-class>com.navercorp.lucy.security.xss.servletfilter.XssEscapeServletFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>xssEscapeServletFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    
    <filter>
        <filter-name>RequestBodyXSSFilter</filter-name>
        <filter-class>com.your.pkg.path.filter.RequestBodyXSSFIleter</filter-class>
        <init-param>
            <param-name>extUrls</param-name>
            <param-value>/linkUrl1,/linkUrl2,/linkUrl2</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>RequestBodyXSSFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    <!-- Xss Filter End -->
cs

 

서버 정보 노출 및 에러코드의 노출을 방지하기 위해 대부분의 사이트가 HTTP 403, 404 등 HTTP 에러 발생 시 별도의 에러 페이지로 리다이렉트 시키고 있다.

 

하지만 헤더정보를 통해 에러정보를 노출 시키고 있다. 

 

따라서 Error Page에서 Http Status를 강제로 고정시키는 처리가 필요하다. 

 

리다이렉트 되는 에러페이지에 <%response.setStatus(200);%> 입력 시 에러 페이지로 리다이렉트와 동시에 헤더 정보내 노출되는 에러코드 노출을 방지할 수 있다.



1
2
3
4
5
6
7
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>

<% response.setStatus(200); %>

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
cs

 

+ Recent posts