반응형

출처: http://www.hides.kr/46


Log Injection



log injection이란 sql injection처럼 파라미터를 통해 로깅을 조절하는 방법을 말합니다


보통 웹 어플리케이션에서 log4j 등을 이용해 파일에 로깅을 합니다

일반적으로는 장애 발생시 에러 추적을 위해 사용됩니다

하지만 데이터 유실시 복구 방침으로 로깅을 하기도 하고요, 그냥 말 그대로 그냥 로깅을 하기도 하지요 또한 로그 파일을 파싱하여 무언가 통계를 내기도 합니다(웹CRM)


일반적으로 로그인에 대한 로깅을 파일에 다음과 같이 합니다 (로그인예가 아니더라도..)

String userid = request.getParameter("userid");

...

if (로그인성공)

    log.write("User login succeeded for : " + userid);

else

    log.write("User login failed for : " + userid);


로그가 정상적으로 기록된다면 아마 다음과 같은 형태가 될겁니다

User login succeeded for : guest

User login succeeded for : admin


그렇다면 로그인시 다음과 같은 문자열을 입력했으면 어떻게 될까요?

guest\nUser login succeeded for : admin


그럼 로그 결과는 다음과 같이 출력됩니다

User login succeeded for : guest

User login succeeded for : admin

User login succeeded for : admin

붉은색 부분이 사용자가 입력한 부분이죠


여기서는 간단한 예를 들었습니다만 여러가지면으로 활용이 가능할 겁니다

로깅파일을 100% 신뢰할 수 없다는 것이지요 ^^



반응형
반응형

출처: http://hackability.kr/entry/PHP-%EB%AC%B8%EC%9E%90%EC%97%B4-%ED%95%84%ED%84%B0%EB%A7%81-%ED%95%A8%EC%88%98ereg-eregi-%EC%B7%A8%EC%95%BD%EC%A0%90%EC%9D%84-%EC%9D%B4%EC%9A%A9%ED%95%9C-%EC%9A%B0%ED%9A%8C



오늘 포스팅 할 내용은 PHP 에서 입력 문자열 필터링 함수의 취약점을 이용한 우회 기법에 대한 내용입니다.


PHP 에서는 HTTP 메소드를 통해 들어 오는 사용자의 입력 검증 또는 필터링을 위해 eregi 와 같은 함수를 사용해 왔습니다. (POSIX Regex)


예를들어, 간단히 다음과 같이 id 입력에 대해 필터링하는 PHP 코드가 있다고 가정 합니다.


index.php

1
2
3
4
5
6
7
8
9
10
<?
 
$_id = $_GET[id];
 
if (eregi("admin",$_id))
  echo "Filtered !!" . "<br>";
else
  echo $_id . "<br>";
 
?>


간단히, index.php?id=admin 으로 접근을 하게 되면 "Filtered !!" 라고 뜨게 되고 그 외 아이디를 입력하게 되면 해당 문자열을 출력해주게 됩니다.


문제가 없어 보이지만, PHP 5.3+ 부터 POSIX Regex 함수들이 더이상 사용되지 않게 되었습니다. (As of PHP 5.3.0, the POSIX Regex extension is deprecated.) 또한, PHP 6.0 부터는 아예 삭제됩니다. PHP 5.3+ 부터는 POSIX Regex 대신 PCRE Regex 를 사용하게 됩니다.


먼저, 5.3+ 에서 어떻게 위의 필터링을 우회 하는지 보도록 하겠습니다. PHP 5.3+ 에서 POSIX Regex 함수들을 사용할 때, NULL 문자를 만나게 되면 더이상 뒤의 문자열을 체크하지 않게 됩니다. 아래는 5.2 와 5.3에서 위의 index.php 사용에 대한 예 입니다.


PHP 5.2+

/index.php?id=admin



PHP 5.3+

/index.php?id=admin



PHP 5.2+, 5.3+ 모두 정상적으로 필터링 되는 것을 확인할 수 있습니다. 하지만, 첫 바이트에 NULL을 넣어 입력 문자열을 더이상 점검하지 못하도록 하면 어떻게 될까요?


PHP 5.2+

/index.php?id=%00admin


 


PHP 5.3+

/index.php?id=%00admin


 


PHP 5.2+ 에서는 정상적으로 필터링 되지만, PHP 5.3+ 에서는 필터링이 정상적으로 되지 않는 것을 확인 할 수 있습니다. 이를 통해 PHP 5.3+ POSIX Regex 필터링을 우회 하는 것을 확인하였습니다.


마지막으로 PHP 5.3+ 에서 위의 문제를 수정하기 위해 POSIX Regex 함수들을 PCRE Regex 로 변경하는 것을 요구 하고 있습니다.


Function replacements

 POSIX

 PCRE 

 ereg_replace()

 preg_replace()

 ereg()

 preg_match()

 eregi_replace()

 preg_replace()

 eregi()

 preg_match()

 split()

 preg_split()

 spliti()

 preg_split()

 sql_regcase()

 No equivalent


반응형

'프로젝트 관련 조사 > ' 카테고리의 다른 글

워드프레스 준비물 - DB 생성  (0) 2016.06.22
Log Injection  (0) 2016.06.20
[PHP] strcmp 취약점을 이용한 인증 우회  (0) 2016.06.20
Burp Suite 사용법 정리  (0) 2016.06.20
document.URL.indexOf()  (0) 2016.06.20
반응형

출처: http://hackability.kr/entry/PHP-strcmp-%EC%B7%A8%EC%95%BD%EC%A0%90%EC%9D%84-%EC%9D%B4%EC%9A%A9%ED%95%9C-%EC%9D%B8%EC%A6%9D-%EC%9A%B0%ED%9A%8C



이번에 작성할 내용은 PHP 에서 strcmp 취약점을 이용한 인증 우회 기법 입니다.


아래와 같이 간단히 인증을 하는 login.php 가 있다고 가정해봅니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
<?php 
 
    $ps = 'pass';
 
    if (!isset($_GET['user_id']) || !isset($_GET['password'])) 
        die("parameter error"); 
 
    if (($_GET['user_id'] == 'admin'
        && (strcmp($ps$_GET['password']) == 0))
        die("login succeed..");
    else 
        die("login failed..");
 
?>


3번째 라인에서는 user_id 와 password 파라미터가 세팅 되었는지 체크하고 


6번째 라인에서는 user_id 가 admin 이고 password 가 ps와 비교합니다. (예를 위해서 미리 $ps 에 값을 대입하였습니다.)


일단 기본 동작은 아래와 같습니다.


http://127.0.0.1/login.php?user_id=admin&password=pass

=> login succeed..


http://127.0.0.1/login.php?user_id=admin&password=asdf

=> login failed..


여기서 재미있는 부분은 strcmp 함수에서 발생됩니다. strcmp 의 함수 내용은 다음과 같습니다.


Description ¶

int strcmp ( string $str1 , string $str2 )


Return Values ¶

Returns < 0 if str1 is less than str2; > 0 if str1 is greater than str2, and 0 if they are equal.


strcmp($a, $b) 를 실행 할 때, $a가 작으면 음수, $b가 작으면 양수, 그리고 $a와 $b가 같으면 0 이 반환됩니다. 만약 우리가 password를 몰라도 strcmp 함수에서 0을 리턴할 수 있는 방법이 있다면 암호 비교 구문을 우회 할 수 있을 것 같습니다.


PHP 특정 버전에서는 위와 같이 우회 할 수 있는 방법이 있는데요. 입력 값으로 배열을 넣으면 strcmp 함수가 0을 리턴합니다. (해당 PHP 버전은 아래 설명합니다.)

(검색 키워드 : strcmp() expects parameter 2 to be string, array given in )


아래는 예제 코드 입니다.


1
2
3
4
5
6
7
8
9
10
11
<?php 
 
$a = Array("a");
$b = 'pass';
 
if (strcmp($a$b) == 0)
  echo "Strings are same !";
else
  echo "Strings are different ...";
 
?>



결과는 "Strings are same !" 으로 출력이 됩니다.


이를 통해 알 수 있는 것은 strcmp 함수에 문자열을 인자로 넣어야 하는데 배열을 인자로 넣으면 반환 값이 0 임을 알 수 있습니다.


그러면 다시 login.php로 돌아가 strcmp 구문을 우회 해보도록 하겠습니다. 우회 코드는 아래와 같습니다.


http://127.0.0.1/login.php?user_id=admin&password[]=a 


위와 같은 입력을 통해 strcmp 의 비교 구문에 문자열이 아닌 배열을 넣을 수 있었고 "login succeed" 를 볼 수 있었습니다.


추가 사항으로 위 취약점은 PHP 버전에 따라 다른 형태를 보입니다. 버전별로 strcmp 반환값을 처리 하는 방식이 다른데요.


PHP 버전 5.2 에서는 strcmp(String, Array()) 시에 Integer (1 or -1) 을 반환하고, 

PHP 버전 5.3 에서는 strcmp(String, Array()) 시에 NULL 을 반환합니다.

(PHP 버전 5.2에서는 Array()를 "Array" 라는 문자열로 변환하여 비교를 하게 됩니다.)


현재 문제가 발생하는 버전은 PHP 5.3 버전인데요. 위 내용으로 유추 해보면 strcmp 함수의 인자 값으로 문자열이 들어 오지 않는 경우 NULL 을 반환하는데 이 부분에서 strcmp의 동작 방식과 충돌이 발생되어 생기는 문제임을 생각해볼 수 있습니다.


문제는 아래와 같이 비교 하는 구문인데요. 

if (strcmp(String, Array() == 0)


PHP 5.3 버전에서 strcmp 입력값으로 Array를 주었을 경우, 결과적으로 아래와 같은 행위를 하게 됩니다.


if (NULL == 0)


우리는 미리 결과를 봤기 때문에 NULL == 0 의 결과가 TRUE 라는 것을 알 수 있는데요, 그러면 결과적으로 NULL은 0 인 것일까요?


아래 PHP 자료형 비교표를 보시면 됩니다.


"==" 으로 느슨한 비교를 한 결과


"===" 으로 엄격한 비교를 한 결과


위 두 표를 보시면 아시겠지만 느슨한 비교를 할 시에는 NULL이 숫자 0과 같기 때문에 0 == NULL 이 TRUE를 반환하지만 NULL이 0과 같은 타입이 아니기 때문에 0 === NULL 시에는 FALSE를 얻게 됩니다.


다시 처음으로 돌아가서 login.php 의 코드를 보면, 이 코드를 보강하기 위해서는 아래와 같이 strcmp 비교 구문을 기존에 "==" 에서 "===" 으로 엄격한 비교를 해주면 보강됨을 알 수 있습니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
<?php 
 
    $ps = 'pass';
 
    if (!isset($_GET['user_id']) || !isset($_GET['password'])) 
        die("parameter error"); 
 
    if (($_GET['user_id'] == 'admin') && (strcmp($ps$_GET['password']) === 0))
        die("login succeed..");
    else 
        die("login failed..");
 
?>


결론적으로 PHP 5.3+ 버전에서는 strcmp 시 String 값에 Array 타입이 들어 가게되면 NULL이 반환되게 되는데 이를 "==" 처럼 단순비교 했을 시 생기는 코딩 취약점 입니다. 이를 해결하기 위해서는 위에서 언급했던 것 처럼 "===" 와 같이 강력한 비교를 하거나 is_string, is_array와 같이 입력값에 대한 검증을 한 번 거친 뒤 비교를 해주시면 될 것 같습니다.


2015.01.20 추가 내용


좋은 내용이 댓글에 있어서 내용을 추가 합니다. GET의 경우에는 위와 같이 취약하지만 POST의 경우 역시 위에 의해 취약점이 발생되는지에 대한 내용입니다. 


테스트 환경은 php 5.5 버전에서 진행하였으며 위의 테스트 결과 5.5 버전 역시 strcmp 에 취약한 버전으로 결과가 나왔기 때문에 이 버전으로 POST 테스트를 진행하였습니다.


테스트 코드는 다음과 같습니다.



POST로 패스워드를 받고 "password"와 같으면 admin이라고 해주고 그 외에는 admin이 아니라는 표시를 합니다.


POST로 데이터를 전송하기 위해 curl 프로그램을 사용하였습니다. curl 프로그램의 -X 파라미터를 이용하여 POST로 전송을 하였고, -d 옵션을 이용하여 데이터 부분을 채울 수 있었습니다.



테스트 결과 POST 역시 배열에 의해 GET과 동일하게 취약함을 알 수 있었습니다.

반응형
반응형

출처: http://lng1982.tistory.com/139


XSS (Cross Site Scripting) 공격을 통해 웹 사이트의 보안을 취약하게 할 수 있는 툴이 있다.

Burp Suite 라는 툴인데, 이 툴을 이용하게 되면 javascript를 이용한 validation체크를 우회할 수 있다.

이 말은 웹 사이트의 보안을 유지하려면 client단에서의 javascript 유효성 체크뿐만 아니라 서버단에서의 유효성 체크도 해야 한다는 것이다. 간혹 우리 개발자들은 바쁘고 시간이 없다는 이유로 클라이언트의 유효성 체크만 하고 넘어가는 경우가 비일비재하다. 물론 나 또한 그런 경험이 있다.


Burp Suite의 동작 원리는 간단하다.

1. local PC 웹 브라우저에서 naver.com HTTP request

2. proxy server(Burp Suite)

3. 네이버 사이트 접속

4. 네이버 사이트 HTTP response

5. Proxy server(Burp Suite)

6. local PC 웹 브라우저


위의 순서를 보면 HTTP 요청과 응답 시 항상 proxy server를 거쳐 데이터가 이동하게 되는데 이곳에서 웹 사이트의 우회 공격을 할 수 있게 조작을 할 수 있는 것이다.

가령 response 응답의 HTML에서 자바스크립트 패스워드 유효성 체크 로직 부분을 삭제한 후 local PC 웹 브라우저에 return하게 되면 사용자 웹 브라우저에는 패스워드 검증 로직은 삭제되어 있는 HTML 결과 페이지를 받게 되는 것이다.


또 한 가지 SMS 인증과 같은 예를 들 수 있다.

HTTP/1.0 200 OK

Date: Wed, 28 Nov 2012 17:19:49 GMT

Server: Apache

Pragma: no-cache

Expires: Thu, 01 Jan 1970 00:00:00 GMT

Cache-Control: no-cache

Cache-Control: no-store

Content-Length: 38

Connection: close

Content-Type: text/plain


{"check":0,"msg":"MOBILE_AUTH_FAIL"}


위와 같이 서버로부터 response를 받으면 proxy server가 이를 가로채고 Burp Suite tool을 이용하여 데이터를 조작 후 브라우저로 response 보낼 수 있다.

다음과 같이 데이터를 조작하여 SMS 인증을 받고, 다음 절차로 진행할 수 있는 것이다.

{"check":1,"msg":"MOBILE_AUTH_SUCCESS"}



XSS 공격 테스트를 위한 Burp Suite 설정은 간단하다.


1.

http://portswigger.net/burp/ 에서 다운로드 받는다. jar로 되어 있고, 로컬 PC에 Java JDK가 설치되어 있어야 한다.


2.

Burp Suite 실행 > Proxy 탭 이동 > 바로 아래에 있는 Options 클릭 후 다음과 같이 설정

127.0.0.1:8080과 같이 설정


3.

IE > 도구 > 인터넷 옵션 > 연결 탭 이동

"LAN 설정" 버튼 클릭 후 프록시 서버 지정

주소 : 127.0.0.1

포트 : 8080


4.

Proxy 탭의 Intercept 클릭

Intercept is on 클릭

IE에서 테스트할 URL 입력하면 화면이 멈추게 되는데 이때 Burp Suite 화면에 가서 Forward를 클릭하면 정상적으로 페이지 로딩이 된다.

반응형

+ Recent posts