기본 콘텐츠로 건너뛰기

CVE-2017-12061_CVE-2017-12062

CVE-2017-12061, CVE-2017-12062

MantisBT는 오픈소스 이슈 트래킹 도구 중 하나이며 간편한 사용법으로 많은 사용자를 보유하고 있다. 최근 Cross Site Scripting 취약점 (CVE-2017-12061, CVE-2017-12062)이 발생하였고 조치가 완료되었다. 수정된 소스코드를 통해서 해당 취약점을 살펴보자.

CVE-2017-12061

취약점이 발생된 곳은 /admin/install.php 소스이다.

  • 영향 버전: 1.3.11 and older, 2.5.1 and older
  • 조치 버전: 1.3.12, 2.5.2, 2.6.0 (not yet released*)

POC

http://mantis.server/admin/install.php?install=3&database_name=%3Ch1%3EXSS&admin_username=%3Ch1%3EXSS

http://mantis.server//admin/install.php?install=3&database_name=%3Cscript%3Ealert(%27XSS%27)%3C/script%3E&admin_username=%3Cscript%3Ealert(%27XSS%27)%3C/script%3E

Fix

# the check only works on mysql if the database is open
        $t_version_info = @$g_db->ServerInfo();
    } else {
-       print_test_result( BAD, true, 'Does administrative user have access to the database? ( ' . db_error_msg() . ' )' );
+       print_test_result(
+           BAD,
+           true,
+           'Does administrative user have access to the database? ( ' . string_attribute( db_error_msg() ) . ' )'
+       );
        $t_version_info = null;
    }
    ?>
@@ -469,7 +473,11 @@ function print_test( $p_test_description, $p_result, $p_hard_fail = true, $p_mes
                print_test_result( GOOD );
            }
        } else {
-           print_test_result( BAD, false, 'Database user doesn\'t have access to the database ( ' . db_error_msg() . ' )' );
+           print_test_result(
+               BAD,
+               false,
+               'Database user doesn\'t have access to the database ( ' . string_attribute( db_error_msg() ) . ' )'
+           );
        }
        ?>
 </tr>
@@ -791,7 +799,11 @@ function print_test( $p_test_description, $p_result, $p_hard_fail = true, $p_mes

                if( !$t_rs ) {
                    $t_result = false;
-                   print_test_result( BAD, true, 'Does administrative user have access to create the database? ( ' . db_error_msg() . ' )' );
+                   print_test_result(
+                       BAD,
+                       true,
+                       'Does administrative user have access to create the database? ( ' . string_attribute( db_error_msg() ) . ' )'
+                   );
                    $t_install_state--; # db creation failed, allow user to re-enter user/password info
                } else {
                    print_test_result( GOOD );
@@ -814,9 +826,18 @@ function print_test( $p_test_description, $p_result, $p_hard_fail = true, $p_mes
                    }

                    if( $t_db_exists ) {
-                       print_test_result( BAD, false, 'Database already exists? ( ' . db_error_msg() . ' )' );
-                   } else {
-                       print_test_result( BAD, true, 'Does administrative user have access to create the database? ( ' . db_error_msg() . ' )' );
+                       print_test_result(
+                           BAD,
+                           false,
+                           'Database already exists? ( ' . string_attribute( db_error_msg() ) . ' )'
+                       );
+                   }
+                   else {
+                       print_test_result(
+                           BAD,
+                           true,
+                           'Does administrative user have access to create the database? ( ' . string_attribute( db_error_msg() ) . ' )'
+                       );
                        $t_install_state--; # db creation failed, allow user to re-enter user/password info
                    }
                }
@@ -847,7 +868,11 @@ function print_test( $p_test_description, $p_result, $p_hard_fail = true, $p_mes
        if( $t_result == true ) {
            print_test_result( GOOD );
        } else {
-           print_test_result( BAD, false, 'Database user doesn\'t have access to the database ( ' . db_error_msg() . ' )' );
+           print_test_result(
+               BAD,
+               false,
+               'Database user doesn\'t have access to the database ( ' . string_attribute( db_error_msg() ) . ' )'
+           );
        }
        $g_db->Close();
    ?>
@@ -1242,7 +1267,11 @@ function print_test( $p_test_description, $p_result, $p_hard_fail = true, $p_mes
    if( $t_result == true ) {
        print_test_result( GOOD );
    } else {
-       print_test_result( BAD, false, 'Database user does not have access to the database ( ' . db_error_msg() . ' )' );
+       print_test_result(
+           BAD,
+           false,
+           'Database user does not have access to the database ( ' . string_attribute( db_error_msg() ) . ' )'
+       );
    }

    if( $f_db_type == 'db2' ) {
@@ -1264,7 +1293,11 @@ function print_test( $p_test_description, $p_result, $p_hard_fail = true, $p_mes
    if( $t_result != false ) {
        print_test_result( GOOD );
    } else {
-       print_test_result( BAD, true, 'Database user does not have SELECT access to the database ( ' . db_error_msg() . ' )' );
+       print_test_result(
+           BAD,
+           true,
+           'Database user does not have SELECT access to the database ( ' . string_attribute( db_error_msg() ) . ' )'
+       );
    }
    ?>
 </tr>
@@ -1279,7 +1312,11 @@ function print_test( $p_test_description, $p_result, $p_hard_fail = true, $p_mes
    if( $t_result != false ) {
        print_test_result( GOOD );
    } else {
-       print_test_result( BAD, true, 'Database user does not have INSERT access to the database ( ' . db_error_msg() . ' )' );
+       print_test_result(
+           BAD,
+           true,
+           'Database user does not have INSERT access to the database ( ' . string_attribute( db_error_msg() ) . ' )'
+       );
    }
    ?>
 </tr>
@@ -1294,7 +1331,11 @@ function print_test( $p_test_description, $p_result, $p_hard_fail = true, $p_mes
    if( $t_result != false ) {
        print_test_result( GOOD );
    } else {
-       print_test_result( BAD, true, 'Database user does not have UPDATE access to the database ( ' . db_error_msg() . ' )' );
+       print_test_result(
+           BAD,
+           true,
+           'Database user does not have UPDATE access to the database ( ' . string_attribute( db_error_msg() ) . ' )'
+       );
    }
    ?>
 </tr>
@@ -1309,7 +1350,11 @@ function print_test( $p_test_description, $p_result, $p_hard_fail = true, $p_mes
    if( $t_result != false ) {
        print_test_result( GOOD );
    } else {
-       print_test_result( BAD, true, 'Database user does not have DELETE access to the database ( ' . db_error_msg() . ' )' );
+       print_test_result(
+           BAD,
+           true,
+           'Database user does not have DELETE access to the database ( ' . string_attribute( db_error_msg() ) . ' )'
+       );
    }
    ?>
 </tr>

소스코드에서 확인할 수 있듯이 db_error_msg()함수를 string_attribute()함수로 감싸는 형식으로 조치한 것을 볼 수 있다. POC Code에서 스크립트 구문 삽입 시 사용된 database_name, admin_username 파라미터의 값을 db_error_msg()함수가 그대로 사용자에게 반환하여 판단되며 스크립트 관련 특수 문자를 걸러내기 위해서 string_attribute()함수를 적용시킨 것으로 보인다.

이제 string_attribute()함수를 살펴보자. string_attribute()함수는 mantisbt/core/string_api.php 231번 줄에 위치하고 있다.

function string_attribute( $p_string ) {
    return string_html_specialchars( $p_string );
}

string_html_specialchars()함수를 호출하는 것 외에는 다른 내용이 없다. string_html_specialchars()함수는 동일한 파일의 908번 줄에 위치하고 있다.

function string_html_specialchars( $p_string ) {
    # Remove any invalid character from the string per XML 1.0 specification
    # http://www.w3.org/TR/2008/REC-xml-20081126/#NT-Char
    $p_string = preg_replace( '/[^\x9\xA\xD\x20-\x{D7FF}\x{E000}-\x{FFFD}\x{10000}-\x{10FFFF}]+/u', '', $p_string );
    # achumakov: @ added to avoid warning output in unsupported codepages
    # e.g. 8859-2, windows-1257, Korean, which are treated as 8859-1.
    # This is VERY important for Eastern European, Baltic and Korean languages
    return preg_replace( '/&amp;(#[0-9]+|[a-z]+);/i', '&$1;', @htmlspecialchars( $p_string, ENT_COMPAT, 'utf-8' ) );
}

Cross Site Scripting에 관련된 부분은 @htmlspecialchars( $p_string, ENT_COMPAT, 'utf-8' )이 부분으로 $p_string변수의 문자열 값 중 특수문자를 HTML 엔터티 값으로 변환하는 데, ENT_COMPAT을 설정하였으므로 따옴표 중 겹따옴표만 변환하며 문자셋은 utf-8을 사용하게 된다.

  • 치환 특수문자
    • ’&’ : &amp;
    • ‘”’ : &quot;
    • ”’ : &#039;
    • ‘<’ : &lt;
    • ‘>’ : &gt;

CVE-2017-12062

취약점이 발생된 곳은 manage_user_page.php 소스이다.

영향 버전: 2.1.0 through 2.5.1
조치 버전: 2.5.2, 2.6.0 (not yet released*)

POC

http://localhost/mantisbt/manage_user_page.php
?sort=username
&dir=desc
&save=1
&hideinactive=0
&showdisabled=0
&filter=ALL"><SVG ONLOAD=&#97&<a href="/bugs/view.php?id=108" title="[종료된 이슈] When adding a bugnote can we have at some other detail on the page." class="resolved">0000108</a>&#101&<a href="/bugs/view.php?id=114" title="[종료된 이슈] Make date format displayed configurable." class="resolved">0000114</a>&#116(1)><IMG SRC="

<svg onload=&#97&#108&#101&#114&#116(1)>

Fix

        <input type="hidden" name="sort" value="<?php echo $c_sort ?>" />
            <input type="hidden" name="dir" value="<?php echo $c_dir ?>" />
            <input type="hidden" name="save" value="1" />
-           <input type="hidden" name="filter" value="<?php echo $f_filter ?>" />
+           <input type="hidden" name="filter" value="<?php echo string_attribute( $f_filter ); ?>" />
            <label class="inline">
            <input type="checkbox" class="ace" name="hideinactive" value="<?php echo ON ?>" <?php check_checked( (int)$c_hide_inactive, ON ); ?> />
            <span class="lbl"> <?php echo lang_get( 'hide_inactive' ) ?></span>

조치된 방법은 CVE-2017-12061 취약점과 동일하다.

이 블로그의 인기 게시물

데일 카네기 인간관계론 정리

Remove-Server-Header

응답 메시지 내 서버 버전 정보 제거 1. Apache 1) 조치 방법 “/etc/htpd/conf/httpd.conf” 파일 안에서 1. ServerTokens OS → ServerTokens Prod 2. ServerSignature On → ServerSignature Off 로 변경한 후 아파치를 재시작하면 헤더 값의 아파치 버전 정보 및 OS 정보를 제거할 수 있다. 2) 참고 URL http://zetawiki.com/wiki/CentOS_ 아파치_보안권장설정_ServerTokens_Prod,_ServerSignature_Off 2. IIS 1) 조치 방법 IIS 6.0 urlscan_setup 실행. 설치. \windows\system32\inetsrv\urlscan\urlscan.ini 파일을 열어 다음 수정(RemoveServerHeader=0 을 RemoveServerHeader=1 로 변경) 서비스에서 IIS Admin Service 재시작. IIS 7.0 IIS 관리자를 열고 관리하려는 수준으로 이동합니다. 기능 보기에서 HTTP 응답 헤더를 두 번 클릭합니다. HTTP 응답 헤더 페이지에서 제거할 헤더를 선택합니다. 작업 창에서 제거를 클릭하고 예를 클릭합니다. 2) 참고 URL IIS 6.0 : http://gonnie.tistory.com/entry/iis6- 응답헤더-감추기 IIS 7.0 : https://technet.microsoft.com/ko-kr/library/cc733102(v=ws.10).aspx 3. jetty 1) 조치 방법 “jetty.xml” 파일에서 jetty.send.server.version=false 설정 2) 참고 URL http://attenuated-perspicacity.blogspot.kr/2009/09/jetty-61x-hardening.html 4. Nginx ...

American Fuzzy Lop And Address Sanitizer

American Fuzzy Lop And Address Sanitizer Address Sanitizer(ASAN) 단지 gcc/clang에 -fsanitize=address 옵션을 추가하는 것으로 간단히 사용할 수 있지만 그 효과는 충분하다. Example Out Of Bounds Read #include <stdio.h> int main() { int a[ 2 ] = { 3 , 1 }; int i = 2 ; printf ( "%i\n" , a[i]); } 예제 파일을 OutOfBoundsRead.c 로 생성하고 ASAN 옵션을 지정하여 clang 으로 컴파일하자. clang -g -fsanitize = address -fno -omit -frame -pointer OutOfBoundsRead . c -o OutOfBoundsRead 생성된 OutBoundsRead 파일을 실행하면 다음과 같은 결과를 볼 수 있다. ================================================================= ==3678==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7ffc0ba87428 at pc 0x47b7db bp 0x7ffc0ba87390 sp 0x7ffc0ba87388 READ of size 4 at 0x7ffc0ba87428 thread T0 ==3678==WARNING: Trying to symbolize code, but external symbolizer is not initialized! #0 0x47b7da (/root/ASAN/OutOfBoundsRead+0x47b7da) #1 0x7faba0260f44 (/lib/x86_64-linux-gnu/libc.so.6+0x21f44) #2 0x...