Python SQL 주입 검사 플러그 인 인 인 스 턴 스 코드 구현
파충
먼저 파충 류 를 개발 하여 사이트 의 링크 를 수집 해 야 합 니 다.파충 류 는 이미 기어 오 른 링크 와 기어 오 르 려 는 링크 를 기록 하고 무 거 운 것 을 제거 해 야 합 니 다.Python 의 set()로 해결 할 수 있 습 니 다.대략적인 절 차 는:
URL 을 입력 하 십시오.
반복 순환
SQL 판단 사고
MySQL 은 SQL syntax 입 니 다.*MySQL
Microsoft SQL Server 는 Warning.*mssql
Microsoft Access 는 Microsoft Access Driver 입 니 다.
Oracle 은 Oracle error 입 니 다.
IBM DB2 는 DB2 SQL error 입 니 다.
SQLite 는 SQLite.Exception 입 니 다.
...
이 키워드 들 을 통 해 사용 하 는 데이터 베 이 스 를 판단 할 수 있다.
4.567917.waf 와 같은 것 도 판단 해 야 한다.이런 것 이 있 으 면 바로 멈춘다.간단 한 방법 은 특정 URL 로 접근 하 는 것 이다.IP banned,fierwall 같은 키워드 가 나 오 면 waf 로 판단 할 수 있다.구체 적 인 정규 표현 식 은(?i)(\A|\b)IP\b.*\b(banned|blocked|bl(a|o)ck\s?list|firewall) 개발 준비 전개 목록
이 라 이브 러 리 를 설치 해 주세요.
pip install requests
pip install beautifulsoup4
실험 환경 은 Linux 입 니 다.코드 디 렉 터 리 를 만 들 고 워 크 폴 더 를 만 들 고 작업 디 렉 터 리 로 사용 합 니 다.디 렉 터 리 구조
/w8ay.py // 프로젝트 시작 주 파일
/lib/core/핵심 파일 저장 디 렉 터 리
/lib/core/config.py/프로필
/script // 플러그 인 저장
/exp // exp 와 poc 저장
순서
SQL 검사 스 크 립 트 작성
DBMS_ERRORS = {
'MySQL': (r"SQL syntax.*MySQL", r"Warning.*mysql_.*", r"valid MySQL result", r"MySqlClient\."),
"PostgreSQL": (r"PostgreSQL.*ERROR", r"Warning.*\Wpg_.*", r"valid PostgreSQL result", r"Npgsql\."),
"Microsoft SQL Server": (r"Driver.* SQL[\-\_\ ]*Server", r"OLE DB.* SQL Server", r"(\W|\A)SQL Server.*Driver", r"Warning.*mssql_.*", r"(\W|\A)SQL Server.*[0-9a-fA-F]{8}", r"(?s)Exception.*\WSystem\.Data\.SqlClient\.", r"(?s)Exception.*\WRoadhouse\.Cms\."),
"Microsoft Access": (r"Microsoft Access Driver", r"JET Database Engine", r"Access Database Engine"),
"Oracle": (r"\bORA-[0-9][0-9][0-9][0-9]", r"Oracle error", r"Oracle.*Driver", r"Warning.*\Woci_.*", r"Warning.*\Wora_.*"),
"IBM DB2": (r"CLI Driver.*DB2", r"DB2 SQL error", r"\bdb2_\w+\("),
"SQLite": (r"SQLite/JDBCDriver", r"SQLite.Exception", r"System.Data.SQLite.SQLiteException", r"Warning.*sqlite_.*", r"Warning.*SQLite3::", r"\[SQLITE_ERROR\]"),
"Sybase": (r"(?i)Warning.*sybase.*", r"Sybase message", r"Sybase.*Server message.*"),
}
정규 표현 식 을 통 해 어느 데이터베이스 인지 판단 할 수 있 습 니 다.
for (dbms, regex) in ((dbms, regex) for dbms in DBMS_ERRORS for regex in DBMS_ERRORS[dbms]):
if (re.search(regex,_content)):
return True
다음은 저희 테스트 문장의 payload 입 니 다.
BOOLEAN_TESTS = (" AND %d=%d", " OR NOT (%d=%d)")
틀린 문장 으로 정확 한 내용 과 잘못된 내용 을 되 돌려 대비 하 다
for test_payload in BOOLEAN_TESTS:
# Right Page
RANDINT = random.randint(1, 255)
_url = url + test_payload % (RANDINT, RANDINT)
content["true"] = Downloader.get(_url)
_url = url + test_payload % (RANDINT, RANDINT + 1)
content["false"] = Downloader.get(_url)
if content["origin"] == content["true"] != content["false"]:
return "sql found: %" % url
이 구절
content["origin"] == content["true"] != content["false"]
원본 웹 페이지 가 정확 한 웹 페이지 와 같 지 않 을 때 이 주소 에 구멍 이 있 음 을 판단 할 수 있다 는 뜻 이다.전체 코드:
import re, random
from lib.core import Download
def sqlcheck(url):
if (not url.find("?")): # Pseudo-static page
return false;
Downloader = Download.Downloader()
BOOLEAN_TESTS = (" AND %d=%d", " OR NOT (%d=%d)")
DBMS_ERRORS = {
# regular expressions used for DBMS recognition based on error message response
"MySQL": (r"SQL syntax.*MySQL", r"Warning.*mysql_.*", r"valid MySQL result", r"MySqlClient\."),
"PostgreSQL": (r"PostgreSQL.*ERROR", r"Warning.*\Wpg_.*", r"valid PostgreSQL result", r"Npgsql\."),
"Microsoft SQL Server": (r"Driver.* SQL[\-\_\ ]*Server", r"OLE DB.* SQL Server", r"(\W|\A)SQL Server.*Driver", r"Warning.*mssql_.*", r"(\W|\A)SQL Server.*[0-9a-fA-F]{8}", r"(?s)Exception.*\WSystem\.Data\.SqlClient\.", r"(?s)Exception.*\WRoadhouse\.Cms\."),
"Microsoft Access": (r"Microsoft Access Driver", r"JET Database Engine", r"Access Database Engine"),
"Oracle": (r"\bORA-[0-9][0-9][0-9][0-9]", r"Oracle error", r"Oracle.*Driver", r"Warning.*\Woci_.*", r"Warning.*\Wora_.*"),
"IBM DB2": (r"CLI Driver.*DB2", r"DB2 SQL error", r"\bdb2_\w+\("),
"SQLite": (r"SQLite/JDBCDriver", r"SQLite.Exception", r"System.Data.SQLite.SQLiteException", r"Warning.*sqlite_.*", r"Warning.*SQLite3::", r"\[SQLITE_ERROR\]"),
"Sybase": (r"(?i)Warning.*sybase.*", r"Sybase message", r"Sybase.*Server message.*"),
}
_url = url + "%29%28%22%27"
_content = Downloader.get(_url)
for (dbms, regex) in ((dbms, regex) for dbms in DBMS_ERRORS for regex in DBMS_ERRORS[dbms]):
if (re.search(regex,_content)):
return True
content = {}
content['origin'] = Downloader.get(_url)
for test_payload in BOOLEAN_TESTS:
# Right Page
RANDINT = random.randint(1, 255)
_url = url + test_payload % (RANDINT, RANDINT)
content["true"] = Downloader.get(_url)
_url = url + test_payload % (RANDINT, RANDINT + 1)
content["false"] = Downloader.get(_url)
if content["origin"] == content["true"] != content["false"]:
return "sql found: %" % url
이 파일 을 sqlcheck.py 라 고 명명 하여/script 디 렉 터 리 에 놓 습 니 다.코드 의 네 번 째 줄 역할 은 URL 이 포함 되 어 있 는 지 찾 는 것 입 니 다.만약 포함 되 지 않 는 다 면,예 를 들 어 위 정적 페이지 는 주입 하기 가 쉽 지 않 을 수 있 으 므 로 여과 해 야 한다.파충류 의 집필
파충류 의 사고방식 에서 말 했 듯 이 URL 관 리 를 먼저 완성 하고 우 리 는 단독으로 그것 을 하나의 종류 로 삼 아 파일 을/lib/core/UrlManager.py 에 저장한다.
#-*- coding:utf-8 -*-
class UrlManager(object):
def __init__(self):
self.new_urls = set()
self.old_urls = set()
def add_new_url(self, url):
if url is None:
return
if url not in self.new_urls and url not in self.old_urls:
self.new_urls.add(url)
def add_new_urls(self, urls):
if urls is None or len(urls) == 0:
return
for url in urls:
self.add_new_url(url)
def has_new_url(self):
return len(self.new_urls) != 0
def get_new_url(self):
new_url = self.new_urls.pop()
self.old_urls.add(new_url)
return new_url
편리 함 을 위해 서,우 리 는 다운로드 기능 을 단독으로 하나의 클래스 로 사용 할 것 이 며,파일 은 lib/core/Downloader.py 에 저 장 됩 니 다.
#-*- coding:utf-8 -*-
import requests
class Downloader(object):
def get(self, url):
r = requests.get(url, timeout = 10)
if r.status_code != 200:
return None
_str = r.text
return _str
def post(self, url, data):
r = requests.post(url, data)
_str = r.text
return _str
def download(self, url, htmls):
if url is None:
return None
_str = {}
_str["url"] = url
try:
r = requests.get(url, timeout = 10)
if r.status_code != 200:
return None
_str["html"] = r.text
except Exception as e:
return None
htmls.append(_str)
특히,우리 가 쓰 려 는 파충 류 는 다 중 스 레 드 이기 때문에,클래스 중 하 나 는 다 중 스 레 드 다운로드 전용 다운로드 방법 입 니 다.lib/core/spider.py 에서 파충 류 를 작성 합 니 다.
#-*- coding:utf-8 -*-
from lib.core import Downloader, UrlManager
import threading
from urllib import parse
from urllib.parse import urljoin
from bs4 import BeautifulSoup
class SpiderMain(object):
def __init__(self, root, threadNum):
self.urls = UrlManager.UrlManager()
self.download = Downloader.Downloader()
self.root = root
self.threadNum = threadNum
def _judge(self, domain, url):
if (url.find(domain) != -1):
return True
return False
def _parse(self, page_url, content):
if content is None:
return
soup = BeautifulSoup(content, 'html.parser')
_news = self._get_new_urls(page_url, soup)
return _news
def _get_new_urls(self, page_url, soup):
new_urls = set()
links = soup.find_all('a')
for link in links:
new_url = link.get('href')
new_full_url = urljoin(page_url, new_url)
if (self._judge(self.root, new_full_url)):
new_urls.add(new_full_url)
return new_urls
def craw(self):
self.urls.add_new_url(self.root)
while self.urls.has_new_url():
_content = []
th = []
for i in list(range(self.threadNum)):
if self.urls.has_new_url() is False:
break
new_url = self.urls.get_new_url()
## sql check
try:
if (sqlcheck.sqlcheck(new_url)):
print("url:%s sqlcheck is valueable" % new_url)
except:
pass
print("craw:" + new_url)
t = threading.Thread(target = self.download.download, args = (new_url, _content))
t.start()
th.append(t)
for t in th:
t.join()
for _str in _content:
if _str is None:
continue
new_urls = self._parse(new_url, _str["html"])
self.urls.add_new_urls(new_urls)
파충 류 는 craw()방법 으로 한 사이트 에 들 어가 기어 다 니 며 다 중 스 레 드 방법 으로 기어 다 니 는 사 이 트 를 다운로드 하고 다운로드 한 소스 코드 는parse 방법 은 BeautifulSoup 을 호출 하여 분석 한 다음 에 분 석 된 URL 목록 을 URL 관리자 에 버 립 니 다.이렇게 순환 하면 마지막 에 웹 페이지 를 오 르 기만 하면 파충류 가 멈 춥 니 다.threading 라 이브 러 리 는 열 어야 할 스 레 드 수 를 사용자 정의 할 수 있 습 니 다.스 레 드 가 열 리 면 모든 스 레 드 는 하나의 url 을 받 아 다운로드 한 다음 스 레 드 가 막 히 고 막 힌 후에 스 레 드 가 실 행 됩 니 다.
파충류 와 SQL 검사 의 결합
lib/core/spider.py 파일 에서 from script import sqlcheck 을 참조 하고 craw()방법 에서 새로운 URL 을 꺼 내 호출 합 니 다.
##sql check
try:
if(sqlcheck.sqlcheck(new_url)):
print("url:%s sqlcheck is valueable"%new_url)
except:
pass
try 로 발생 할 수 있 는 이상 을 감지 하고 돌아 서 파일 w8ay.py 에서 테스트 합 니 다.
#-*- coding:utf-8 -*-
'''
Name: w8ayScan
Author: mathor
Copyright (c) 2019
'''
import sys
from lib.core.Spider import SpiderMain
def main():
root = "https://wmathor.com"
threadNum = 50
w8 = SpiderMain(root, threadNum)
w8.craw()
if __name__ == "__main__":
main()
중요 한 점!lib 와 script 폴 더 의.py 파일 을 모듈 로 인식 할 수 있 도록 lib,lib/core,script 폴 더 에 을 만 드 십시오.init__.py 파일,파일 에 아무것도 쓸 필요 가 없습니다.총결산
SQL 주입 검 측 은 일부 payload 를 통 해 페이지 에 오 류 를 일 으 키 고 원본 웹 페이지,정확 한 웹 페이지 를 판단 합 니 다.오류 웹 페이지 는 SQL 주입 구멍 이 있 는 지 확인 할 수 있 습 니 다.
sql 에서 잘못된 정 보 를 일치 시 키 면 사용 하 는 데이터 베 이 스 를 정규 적 으로 판단 할 수 있 습 니 다.
자,이상 이 이 글 의 전체 내용 입 니 다.본 논문 의 내용 이 여러분 의 학습 이나 업무 에 어느 정도 참고 학습 가치 가 있 기 를 바 랍 니 다.궁금 한 점 이 있 으 시 면 댓 글 을 남 겨 주 셔 서 저희 에 대한 지지 에 감 사 드 립 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
로마 숫자를 정수로 또는 그 반대로 변환그 중 하나는 로마 숫자를 정수로 변환하는 함수를 만드는 것이었고 두 번째는 그 반대를 수행하는 함수를 만드는 것이었습니다. 문자만 포함합니다'I', 'V', 'X', 'L', 'C', 'D', 'M' ; 문자열이 ...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.