기본 콘텐츠로 건너뛰기

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 ...

Insecure-programming-abo1

Insecure-programming-abo1 Insecure Programming by example Advanced Buffer Overflow 1 int main ( int argv , char * * argc ) { char buf [ 256 ] ; strcpy ( buf , argc [ 1 ] ) ; } Advanced Buffer Overflow 첫 번째 문제는 사용자 인자 값 검증 없이 버퍼에 strcpy() 함수로 복사하여 발생되는 오버플로우 예이다. 먼저 objdump 를 이용하여 어셈블리어를 살펴보자. # objdump -d -M intel ./abo1 | grep -A 16 "<main>" 08048374 <main>: 8048374: 55 push ebp 8048375: 89 e5 mov ebp,esp 8048377: 81 ec 18 01 00 00 sub esp,0x118 804837d: 83 e4 f0 and esp,0xfffffff0 8048380: b8 00 00 00 00 mov eax,0x0 8048385: 29 c4 sub esp,eax 8048387: 8b 45 0c mov eax,DWORD PTR [ebp+12] 804838a: 83 c0 04 add eax,0x4 804838d: 8b 00 mov eax,DWORD PTR [eax] 804838f: 89 44 24 04 mov ...

Insecure-programming-stack5

Insecure-programming-stack5 Insecure Programming by example Stack 5 이번 문제에서는 조건절 안에 “you win!” 문구 대신 "you loose!"가 있는 것을 볼 수 있다. # include <stdio.h> int main ( ) { int cookie ; char buf [ 80 ] ; printf ( "buf: %08x cookie: %08xn" , & buf , & cookie ) ; gets ( buf ) ; if ( cookie == 0x000d0a00 ) printf ( "you loose!\n" ) ; } 따라서 이번 문제를 해결하기 위해서는 임의로 작성한 별도의 코드를 프로그램에서 호출하도록 하여 “you win!” 구문 출력을 이끌어 내야한다. "you win!"을 출력하고 종료하는 간단한 어셈블리어 코드를 작성한다. section .text global _start _start: jmp short ender starter: xor eax, eax xor ebx, ebx xor ecx, ecx xor edx, edx mov al, 4 mov dbl, 91 pop ecx mov bdl, 14 int 0x80 xor eax, eax inc eaxal dec bl int 0x80 ender: call starter db 'you win!\n' 작성이 완료되었다면 nasm 을 이용하여 오브젝트 파일을 생성한 후 ld 명령어로 실행 파일을 만들어 제대로 동작하는 지 확인해보하고 objdump 를 이용하여 코드 덤프를 만들자. # nasm -f elf -o stack54_sh_code....