SQL 질의문의 실행 결과가 직접적으로 출력되는 경우에는 UNION SQL Injection을 우선적으로 시도해 볼 수 있습니다
실행 결과가 출력되는 경우는 예를 들어 게시판 또는 검색 조회 페이지 등을 생각해 볼 수 있습니다
SQL 실행 결과가 직접적으로 화면에 출력될 경우, 우리가 얻고 싶은 데이터도 출력할 수 있는 가능성이 있다는 점을 이용해 SQL Injection을 시도하는 방법입니다
원하는 데이터를 출력하려면 우리가 원하는 테이블과 컬럼 데이터를 출력할 수 있어야 하기 때문에,
단순히 조건절에 SQL문을 삽입하는 것만으로는 어렵습니다
따라서 우리가 원하는 테이블과 컬럼을 선택하기 위해 UNION
을 활용합니다
❓ UNION SQL Injection 방법
1️⃣ SQLi 포인트 찾기
SQLi가 가능한 곳을 먼저 파악합니다
2️⃣ ORDER BY로 column 개수 찾기
select 문의 마지막에
order by 인덱스
를 추가하여 서버의 SQL문에서 몇 개의 column이 select 되고 있는지 확인합니다3️⃣ 출력되는 column 위치 찾기
select 되는 column들 중 직접적으로 출력이 되는 column과 그렇지 않은 column이 있을 수 있습니다.
데이터를 추출하기 위해서는 출력을 확인해야 하므로, 출력되는 column이 몇 번째 컬럼인지 확인합니다4️⃣ 데이터베이스 이름 확인
원하는 데이터 추출을 위한 SELECT 문 작성을 위해서는 DB 이름이 필요합니다
UNION
을 활용해select database()
를 하면 데이터베이스의 이름을 확인할 수 있습니다5️⃣ 테이블 이름 확인
SELECT 문 작성에는 테이블 이름이 필요합니다
이 테이블 이름은 4️⃣번에서 찾은 데이터베이스 이름으로 아래와 같이 찾을 수 있습니다
SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA='해당 DB명'
이 SQL을 서버의 SQL 문 컬럼 개수 등에 맞게UNION
을 활용하여 실행시켜 테이블 이름을 확인합니다6️⃣ 컬럼 이름 확인
SELECT 문 작성에는 컬럼 이름이 필요합니다
컬럼 이름은 5️⃣번에서 찾은 테이블 이름으로 아래와 같이 찾을 수 있습니다
SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='[해당 테이블명]'
이 SQL을 서버의 SQL 문 컬럼 개수 등에 맞게UNION
을 활용하여 실행시켜 컬럼 이름을 확인합니다7️⃣ 데이터 추출
이제 테이블과 컬럼 이름을 모두 알았으니 특정 데이터를 추출할 수 있습니다
SELECT 컬럼 FROM 테이블
을 서버의 SQL 문 컬럼 개수 등에 맞게UNION
을 활용하여 실행시키고, 원하는 데이터를 추출합니다
SQL 실행 결과가 화면에 출력되지 않는 경우도 있습니다
예를 들어, 로그인 같은 경우 로그인 성공/실패 여부만 알 뿐 어떠한 데이터가 출력되지는 않습니다
이럴 경우 시도할 수 있는 SQL Injection이 2가지 있습니다
실행 결과가 화면에 출력되지는 않지만, SQL 로직 에러가 발생할 때 에러메세지가 출력되는 케이스에서 Error based SQL Injection을 시도해 볼 수 있습니다
원하는 데이터가 포함된 에러메세지를 발생시키기 위해, 의도적으로 에러를 발생시키는 SQL 문을 작성합니다
❓ Error based SQL Injection 방법
1️⃣ SQLi 포인트 찾기
일부러 SQL 에러를 발생시켜 에러메세지가 출력되는지 확인합니다
2️⃣ 에러 유발할 함수 선택
Error base SQLi를 실행할 포인트를 찾았다면, 의도적으로 에러를 유발하면서 원하는 데이터가 출력될만한 함수를 선택해야 합니다
Mysql의 경우extractvalue
함수가 많이 사용되는 편입니다3️⃣ 공격 format 만들기
Error based SQLi를 실행할 공격 format을 만들어 필요한 SQL 문을 주입할 틀을 만들어 둡니다
이 공격 format은 서버에 어떤 쿼리문이 작성되어 있을지 웹의 동작 방식을 통해 추측한 후,
그에 맞게 만듭니다
예를 들어, 서버의 쿼리문이select * from member where id = '[입력값]'
로 작성되어 있다면,
공격 format은아이디' and extractvalue('1', concat(0x3a,(_SQL문_))) and '1'='1
와 같이 만들어 볼 수 있습니다4️⃣ 데이터베이스 이름 확인
원하는 데이터 추출을 위한 SELECT 문 작성을 위해서는 DB 이름이 필요합니다
select database()
를 공격 format에 맞게 삽입하여 데이터베이스 이름을 확인합니다5️⃣ 테이블 이름 확인
SELECT 문 작성에는 테이블 이름이 필요합니다
이 테이블 이름은 4️⃣번에서 찾은 데이터베이스 이름으로 아래와 같이 찾을 수 있습니다
SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA='해당 DB명'
이 SQL 문을 공격 format의 SQL문 자리에 넣어 테이블 이름을 확인할 수 있습니다6️⃣ 컬럼 이름 확인
SELECT 문 작성에는 컬럼 이름이 필요합니다
컬럼 이름은 5️⃣번에서 찾은 테이블 이름으로 아래와 같이 찾을 수 있습니다
SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='[해당 테이블명]'
이 SQL 문을 공격 format의 SQL문 자리에 넣어 컬럼 이름을 확인할 수 있습니다7️⃣ 데이터 추출
이제 테이블과 컬럼 이름을 모두 알았으니 특정 데이터를 추출할 수 있습니다
SELECT 컬럼 FROM 테이블
을 공격 format의 SQL문 자리에 넣어 출력된 에러메세지에서 데이터를 확인합니다
blind SQL Injection은 어떠한 출력도 없이 SQL 실행 결과의 참/거짓 여부만 알 수 있는 경우에 시도할 수 있는 SQLi입니다
예를 들어, 로그인 페이지에서 로그인 성공/실패 여부만 알 수 있는 경우가 이에 해당합니다
알 수 있는 정보가 성공/실패이기 때문에, blind SQL Injection에서는 이를 이용하여 주입한 SQL문이 참인지 거짓인지 확인하여 데이터를 추출합니다
❓ blind SQL Injection 방법
1️⃣ SQLi 포인트 찾기
blind SQL Injection은 SQL 실행 결과 참/거짓일 때의 차이를 이용하는 공격이기 때문에,
SQL문을 삽입 가능하면서 그 SQL문의 참/거짓에 따라 다른 결과가 나오는 곳을 찾습니다2️⃣ SELECT 사용 가능 여부 확인
데이터 추출을 위해서는
select
문을 사용해야 하므로,select
가 필터링 되고 있지는 않은지 먼저 확인합니다3️⃣ 공격 format 만들기
blind SQL Injection을 실행할 공격 format을 만들어 필요한 SQL 문을 주입할 틀을 만들어 둡니다
이 공격 format은 서버에 어떤 쿼리문이 작성되어 있을지 웹의 동작 방식을 통해 추측한 후,
그에 맞게 만듭니다
예를 들어, 서버의 쿼리문이select * from member where id = '[입력값]'
로 작성되어 있다면,
공격 format은아이디' and ascii(substr((_SQL문_),인덱스,1))>숫자 and '1'='1
로 작성할 수 있습니다4️⃣ 데이터베이스 이름 확인
원하는 데이터 추출을 위한 SELECT 문 작성을 위해서는 DB 이름이 필요합니다
select database()
를 공격 format의 SQL 부분에 삽입하여 데이터베이스 이름을 확인합니다
이때 데이터베이스의 이름을 한 글자씩 ascii 숫자 범위 좁히기를 통해 참/거짓 여부로 추측하는 방식으로 진행합니다5️⃣ 테이블 이름 확인
SELECT 문 작성에는 테이블 이름이 필요합니다
이 테이블 이름은 4️⃣번에서 찾은 데이터베이스 이름으로 아래와 같이 찾을 수 있습니다
SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA='해당 DB명'
이 SQL 문을 공격 format의 SQL문 자리에 넣어 테이블 이름을 확인할 수 있습니다
이때 데이터베이스 이름 확인 과정과 마찬가지로 테이블의 이름을 한 글자씩 아스키코드 숫자 추측을 통해 맞춰 나가야 합니다
테이블이 여러 개일 경우limit
함수를 이용해 테이블 이름을 한 개씩 맞춰 나갑니다6️⃣ 컬럼 이름 확인
SELECT 문 작성에는 컬럼 이름이 필요합니다
컬럼 이름은 5️⃣번에서 찾은 테이블 이름으로 아래와 같이 찾을 수 있습니다
SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='[해당 테이블명]'
이 SQL 문을 공격 format의 SQL문 자리에 넣어 컬럼 이름을 확인할 수 있습니다
컬럼 이름 역시 아스키코드 숫자 추측을 통해 한 글자씩 맞춰 나가야 하며, 컬럼이 여러 개일 경우에는limit
함수를 활용하여 컬럼을 한 개씩 찾아야 합니다7️⃣ 데이터 추출
이제 테이블과 컬럼 이름을 모두 알았으니 특정 데이터를 추출할 수 있습니다
SELECT 컬럼 FROM 테이블
을 공격 format의 SQL문 자리에 넣어 데이터를 찾습니다
역시나 아스키코드 추측을 통해 각 데이터의 글자 한 개씩 맞춰야 하며, 한 컬럼에 여러 개의 행이 있다면limit
함수를 활용하여 데이터를 1개씩 확인합니다
이렇게 여러가지 케이스에 대한 SQL Injection 방법에 대해 알아보았습니다