본문 바로가기
IT_정보보안/웹 모의해킹 프로젝트

37. 웹 모의해킹 실습 (4) : SQL Injection, SQL InjectionI (Blind)

by jys275 2024. 11. 12.

 

 

SQL Injection

 

 

개념
데이터베이스(DB)와 연동된 웹 애플리케이션에서 공격자가 입력 폼 및 URL입력란에 

SQL문을 삽입하여 DB로부터 정보를 열람(또는 조작)할 수 있는 취약점을 의미한다.

 

사용자가 웹 애플리케이션의 입력 폼이나 URL 쿼리 문자열에 SQL 구문을 포함한 악성 코드를 입력할 수 있는 경우, 

애플리케이션이 이 입력값을 제대로 검증하지 않고 SQL 쿼리에 포함시키면 SQL 인젝션 취약점이 발생하는 원리이다.  

웹 애플리케이션으로부터 전달된 사용자의 입력 값이 다시 웹서버에서 DB서버의 SQL분석기에 전달될 때, 

제대로 된 검증을 하지 않으면 SQL문 주입 취약점이 발생한다.

 

즉, 악의적인 사용자가 입력한 SQL 구문이 기존의 쿼리와 결합되어, 원래 의도된 쿼리와는 다른 동작을 하게 된다.

 

실습(Low Level)

아래는 Low Level의 SQL Injection 실습 페이지이다. 

해당 실습 페이지는 사용자 ID를 입력하여 조회하면 해당 ID에 대한 정보를 얻을 수 있는 기능을 수행한다.

 

ID : 3 입력 조회

 

아래 사진은 Burp Suite로 사용자 ID ’1’을 조회할 때의 HTTP 요청이다. 

 

요청 URL은 “http://localhost/DVWA/vulnerabilities/sqli/?id=5&Submit=Submit” 이다. 

DBMS(데이터베이스 관리 시스템) 조회에 사용되는 값은 ‘id’ 변수(또는 Submit)일 것이다.

 

즉, User ID 변수를 입력하면, 테이블에서 Frist name, Surname을 가져와 출력하는 것으로 유추할 수 있다.

이로써 User ID 변수를 대상으로 입력값 조작을 통해 SQL문을 추정할 수 있다고 생각할 수 있는 것이다.

 

이제 Error-based SQL Injection과 Union-based SQL Injection을 기반으로 공격을 수행한다.

 

Error-based SQL Injection

 

3’ 를 입력하여 SQL 문법 오류를 강제로 유발한다.

아래와 같이 오류가 발생하면 입력값이 제대로 처리되지 않음을 나타낸다.

즉, 해당 웹 애플리케이션은 SQL 주입 가능성이 존재하는 것이다.


일반적인 SQL 쿼리의 기본 구조는 특정 조건을 만족하는 레코드를 검색한다. 

예를 들어, “SELECT * FROM users WHERE id = 3;” 쿼리는 id가 3인 사용자의 정보를 가져오는 것이다. 

 

즉, 위의 실습은 “SELECT * FROM users WHERE id = 3’;”가 된다.

 

Error-based SQL Injection

 

작은따옴표(')와 OR 조건 뒤에 MySQL 주석인 #를 추가한다. 

주석 # 이후의 내용은 무시되므로, OR 1=1 조건만 유효하게 남는다. 

 

이를 통해 모든 사용자의 데이터가 반환되면 SQL Injection 가능성을 확인할 수 있는 것이다.

“SELECT * FROM users WHERE id = 3' OR 1=1#;” 해당 쿼리에서 OR 1=1은 항상 참인 조건이다. 

이 조건이 쿼리에 추가됨으로써, 전체 조건이 항상 참이 되어 모든 사용자 데이터를 반환하게 된다. 

 

즉, id = 3이거나 1=1이 참이므로, 모든 사용자의 정보가 반환된다.


이제 SELECT문의 컬럼 수 확인, 데이터베이스 목록 확인, 각 데이터베이스의 테이블 목록 확인, 

테이블의 컬럼 목록 확인, 테이블 내용 조회의 과정을 거쳐서 DB를 유출할 수 있다.

Union-based SQL Injection

 

UNION은 여러 SELECT 쿼리의 결과를 결합하는 데 사용되는데,

첫 번째 SELECT 쿼리의 결과와 두 번째 SELECT 쿼리의 결과를 합쳐서 하나의 결과로 반환한다.

 

‘UNION SELECT 1, 2’는 두 번째 SELECT 쿼리를 추가하여 1과 2라는 값을 반환한다.

 

 

 

결과를 보면 First name에 1, Surname에 2가 출력된다. 

원래 SQL문의 SELECT에서 조회하는 컬럼의 수는 두 개라는 것과 각 컬럼의 값이 출력되는 위치가 확인된 것이다. 

 

즉, 특정 테이블에 정의된 컬럼이 First name, surname 두 가지 값이 존재하는 것이다.

만약 “3’ UNION SELECT 1#”을 입력하면, 아래와 같이 “different number of columns”

라는 경고를 볼 수 있는데, 앞 SELECT문이 조회하는 컬럼의 수가 1은 아니라는 뜻이다. 

즉, 이전 과정은 뒷 SELECT 문의 컬럼 수를 하나씩 증가시켜서 확인해 본 것이다.

 

“3' UNION SELECT TABLE_SCHEMA, 2 FROM INFORMATION_SCHEMA.TABLES#” 입력

 

INFORMATION_SCHEMA.TABLES는 데이터베이스의 메타데이터를 포함하는 시스템 테이블이다. 

이 테이블은 데이터베이스 내의 모든 테이블에 대한 정보를 제공한다. 

 

TABLE_SCHEMA 컬럼은 테이블이 속한 데이터베이스의 이름을 반환한다. 

두 번째 컬럼은 2라는 상수를 반환한다. 이건 단순히 정수 2를 사용하여 결과의 구조를 맞추기 위해 사용되는 것이다.

 

information_schema, dvwa 두 개의 데이터베이스를 확인할 수 있는데,

이 중 ’dvwa’ 데이터베이스에 포함된 테이블 목록을 확인하도록 한다. 

“3' UNION SELECT 1,TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA='dvwa’#” 입력

 

dvwa 데이터베이스는 위와같이 guestbook, users 2개의 테이블로 구성되어 있는 것을 확인할 수 있다.

이 중 회원정보로 유추되는 users 테이블의 컬럼을 확인해 본다.

“5' UNION SELECT 1,COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='users’#” 입력

 

dvwa의 users 테이블은 총 8개의 컬럼으로 구성된 것을 알 수 있는데, 실습 페이지의 입력 값인

User ID는 user_id 컬럼일 것으로 유추가 되며, 이중 user, password 두 가지 컬럼을 열람해 보도록 한다.

“5' UNION SELECT user,password FROM dvwa.users#” 입력

 

admin, gordonb, 1337, pablo, smithy 총 5명의 회원 계정과 비밀번호 해쉬를 확인할 수 있다.

 

해당 비밀번호를 암호화한 알고리즘은 md5로 확인되기 때문에,

md5 복호화 툴을 이용하면 아래와 같이 ‘smithy’ 유저의 패스워드는 ‘password’ 임을 확인할 수 있다.

 

알아낸 User ID 및 password를 통해 DVWA 홈페이지 로그인 시

아래와 같이 정상적으로 로그인이 완료되는 것을 확인할 수 있다.

 

 

실습(Medium Level)

아래는 Medium Level 실습 페이지이다.

 

Burp Suite를 통해 ID 3을 Submit 하였을 때, 패킷을 확인해 보면 아래와 같이 id 변수가 존재하는 것을 확인할 수 있다.

 

해당 변수를 “3 or 1=1#”로 변경하여 HTTP 요청을 조작한다.

 

공격이 그대로 성공하는 것을 확인할 수 있다.

 

실습(High Level)

High Level 실습 페이지의 경우 아래와 같이 별도의 클릭 링크를 새로 만들어 놓아 새 창에서 값을 입력하는 형태이다.

 

“3’ OR 1=1#”을 입력하면 그대로 우회가 가능하다.

 

소스코드를 확인해 본다.

SQL문에서 사용할 id 값을 서버의 세션(session)으로부터 읽어서 사용하는 것과 

WHERE user_id = '$id' LIMIT 1;” 부분에서 limit 1으로 출력되는 레코드 수를 조절해 놓은 것을 확인할 수 있다. 


서버의 세션으로부터 읽어서 사용하는 것은 실질적으로 사용자(웹 브라우저)가 

서버에 저장된 세션 내의 값을 조작할 수 있는 방법이 없기 때문에 안전한 방법이라고 할 수 있다. 

하지만, DVWA는 특수하게 변경할 수 있는 웹 애플리케이션을 제공하기 때문에 #을 이용해 

뒷부분을 주석처리 하여 레코드 수를 조절하는 부분을 우회하여 값을 추출할 수 있다.

 

실습(Impossible Level)

Impossible Level 실습 페이지의 형태는 Low Level 실습 페이지와 동일하며, 소스코드를 살펴본다.

Anti-CSRF token을 적용하였고, is_numberic 함수를 통해 id 값이 숫자인 경우에만 SQL문으로 전달하도록 제한해 두었다.

 

 


 

 

SQL Injection(Blind)

 

 

실습(Low Level)

SQL Injection(Blind) 실습 탭에서는 아래와 같이 User ID를 입력하여도 

회원 정보를 바로 출력해 주는 것이 아니라 회원의 존재 유무만을 알려준다.

 

그럼에도 SQL 구문을 입력하면 User ID가 존재한다는 메시지를 출력한다. 

즉, 해당 애플리케이션도 SQL Injection에 취약점이 존재한다는 것을 알 수 있다.

이와 같은 애플리케이션에서 유의미한 정보를 추출하기 위해서는 공격자가 SQL문을 수차례 입력하여 정보를 추출해야 한다. 

여러 가지 SQL문을 통해 칼럼 수를 확인하고, DB 길이, 문자열 등을 하나씩 확인할 수 있게 되는 것이다.

 

하지만 이러한 방법으로 모든 과정을 처리하기에는 막대한 시간이 소요될 수 있다. 

이를 해결하기 위해 자동화된 SQL Injection 공격 도구인 SQLMap을 사용할 수 있다. 

SQLMap을 사용하기 위해 User ID 3을 Submit 했을 때, 쿠키값과 URL을 알아낸다.

 

“sqlmap -u "http://localhost/DVWA/vulnerabilities/sqli_blind/?id=3&Submit=Submit" --cookie="PHPSESSID=dheo00a264pj9jok5g3u0hgfpi; security=low" --dbs”

 

명령어를 통해 공격할 URL과 웹 요청에 사용할 쿠키를 지정하고,

이전 SQL Injection 과정과 동일하게 먼저 –dbs 옵션을 통해 서버에 있는 데이터베이스의 목록을 열람한다.

 

[INFO] GET parameter 'id' appears to be ~ 부분에서 ‘id’ 파라미터를 기반으로

AND boolean-based blind 공격이 가능할 것 같다고 나타난다.

 

Y를 입력하면 다른 불필요한 테스트를 무시하고 자동으로 공격이 진행된다.

‘dvwa’와 ‘information_schema’ 이름으로 된 데이터베이스가 존재하는 것을 확인할 수 있다.

 

“sqlmap -u "http://localhost/DVWA/vulnerabilities/sqli_blind/?id=3&Submit=Submit" --cookie="PHPSESSID=dheo00a264pj9jok5g3u0hgfpi; security=low" -D dvwa --tables” 

명령어를 통해 ’dvwa’ 데이터베이스 내의 테이블 목록을 조회한다.

‘guestbook’과 ‘users’ 테이블이 존재하는 것을 확인할 수 있다.

 

“sqlmap -u "http://localhost/DVWA/vulnerabilities/sqli_blind/?id=3&Submit=Submit" --cookie="PHPSESSID=dheo00a264pj9jok5g3u0hgfpi; security=low" -D dvwa -T users --columns” 

명령어를 통해 dvwa 데이터베이스의 users 테이블을 지정하여 해당 테이블의 컬럼 목록을 조회한다.

 

“sqlmap -u "http://localhost/DVWA/vulnerabilities/sqli_blind/?id=3&Submit=Submit" --cookie="PHPSESSID=dheo00a264pj9jok5g3u0hgfpi; security=low" -D dvwa -T users -C user,password --dump” 

명령어를 통해 dvwa 데이터베이스의 users 테이블에 접근하여 user와 password 컬럼의 데이터를 가져온다.

md5 암호화를 복호화한 결과까지 같이 제공되는 것을 확인할 수 있다.

 

실습(Medium Level)

아래는 Medium Level 실습 페이지의 화면이다. 

submit 버튼을 통해 전송하고, Low Level과 같이 ?id=1&Submit=Submit 처럼

GET 요청의 URL 파라미터로도 공격이 가능한 형태가 아니라 POST 요청을 통해서만 입력을 처리하도록 구성되어 있다.

 

이러한 POST 요청을 요구하는 것을 우회하기 위해서 --data ‘id=3&Submit=Submit’ 옵션을 추가하여,

“sqlmap -u "http://localhost/DVWA/vulnerabilities/sqli_blind/#" --cookie="PHPSESSID=

dheo00a264pj9jok5g3u0hgfpi; security=medium" --data 'id=3&Submit=Submit’ --dbs”

명령을 입력하면 공격이 성공하는 것을 확인할 수 있다.

 

실습(High Level)

High Level 또한 SQL 문을 입력하면 우회가 가능하다.

 

소스코드를 살펴본다.

SQL Injection의 코드와 유사하게 limit 1으로 출력되는 레코드 수를 조절해 놓았다. 

 

3’를 통하여 user_id=‘1’의 형태를 만든 후 or 1=1 구문을 이용하여 참으로 만든 후 #을 이용하여,

뒷부분을 주석처리하여 레코드 수를 조절하는 부분을 우회할 수 있는 것이다.

 

실습(Impossible Level)

Impossible Level 또한 동일하다.

 

 

대응방안

  1. 웹 서버의 오류 정보가 일반 사용자에게 노출되지 않도록 조치한다.
    이 오류 정보를 필터링하지 않으면 어디 어디 경로에서 오류가 났는지,
    오류가 난 운영체제와 웹서버에 사용하는 버전은 무엇인지, 이러한 불필요한 정보들이 노출이 되는 것이다.

  2. 웹 애플리케이션과 연동되는 데이터베이스의 접근 권한을 최소화하고, 
    사용자 입력 폼(로그인 폼, 검색 폼, URL 등)을 대상으로 특수문자, 특수구분 필터링 규칙을 적용한다. 

  3. 홈페이지 소스코드는 사용자로부터 입력되는 입력 값에 대한 검증과 예외처리를 한다.
    - 모든 입력란에 특수문자를 입력하지 못하도록 한다.
    - 입력 값에 정의된 문자 길이를 검증하여 SQL문이 추가 삽입되지 않도록 예외처리한다.

    추가로 정기적인 점검, 예방에 대한 교육, 시큐어 코딩 교육과 같은 관리적인 부분들 또한 같이 적용하여,
    모의 해킹 등의 여러 취약한 환경에 노출되지 않고 보호할 수 있다.

 

 


 

 

다음 글에서는 Weak Session IDs, XSS(DOM)을 주제로 실습을 진행할 예정이다.