Навигация
0. Быстрый старт: общий CTF-пайплайн
0) Прочитай условие как спецификацию.
- Какие входные данные? (файл/сервис/URL/дамп/хэш)
- Какие ограничения? (доступные утилиты)
- Формат флага? (
flag{...}, CTF{...})
1) Снимай метаданные входа (файл/трафик/строка):
file target.bin
strings -n 6 target.bin | head
wc -c target.bin (размер)
xxd -g 1 -l 128 target.bin (если доступно; иначе Python hexdump)
2) Быстрые гипотезы по признакам:
- Base64 часто оканчивается
=; hex — только [0-9a-f]; JWT содержит . три части.
- AES-ECB «палится» повторяющимися блоками 16 байт.
- RSA-ключи:
-----BEGIN ... KEY-----.
3) Минимальный набор “CTF-папка”:
mkdir -p work/{in,out,tmp}
cp task_input work/in/
4) Всегда логируй команды (для форензики/самопроверки):
script -q -f work/session.log
# ... делаешь действия ...
exit
1. Криптография: Python-шаблоны (PyCryptodome + базовые алгоритмы)
Если библиотека PyCryptodome установлена, импорты будут вида from Crypto....
1.1. Энкодинги и базовые преобразования
Base64 / Base32 / Hex:
import base64, binascii
s = b"hello"
b64 = base64.b64encode(s)
print(b64) # b'aGVsbG8='
print(base64.b64decode(b64)) # b'hello'
b32 = base64.b32encode(s)
print(b32) # b'NBSWY3DP'
print(base64.b32decode(b32)) # b'hello'
hx = binascii.hexlify(s)
print(hx) # b'68656c6c6f'
print(binascii.unhexlify(hx)) # b'hello'
URL-safe base64 (часто JWT/веб):
import base64
def b64url_decode(data: str) -> bytes:
pad = '=' * ((4 - len(data) % 4) % 4)
return base64.urlsafe_b64decode(data + pad)
def b64url_encode(b: bytes) -> str:
return base64.urlsafe_b64encode(b).decode().rstrip('=')
Bytes ↔ str:
text = "привет"
b = text.encode("utf-8")
print(b)
print(b.decode("utf-8"))
1.2. Хэши: SHA/MD5 и HMAC
Хэш (как в твоём примере):
from Crypto.Hash import SHA256, SHA1, MD5
h = SHA256.new(b'hello_sha256')
print(h.digest())
print(h.hexdigest())
print(SHA1.new(b"abc").hexdigest())
print(MD5.new(b"abc").hexdigest())
HMAC (часто в токенах/подписях API):
from Crypto.Hash import HMAC, SHA256
key = b"secret"
msg = b"message"
mac = HMAC.new(key, msg, digestmod=SHA256).hexdigest()
print(mac)
# проверка
HMAC.new(key, msg, digestmod=SHA256).hexverify(mac)
1.3. XOR и «одноразовый блокнот»
XOR двух байтовых строк (повтор ключа):
def xor_bytes(data: bytes, key: bytes) -> bytes:
return bytes(d ^ key[i % len(key)] for i, d in enumerate(data))
pt = b"hello_xor"
key = b"k"
ct = xor_bytes(pt, key)
print(ct)
print(xor_bytes(ct, key))
Взлом XOR по известному префиксу (например, flag{):
def recover_repeating_xor_key(cipher: bytes, known_plain: bytes, offset=0) -> bytes:
k = bytes(cipher[offset+i] ^ known_plain[i] for i in range(len(known_plain)))
return k
cipher = b"\x0f\x07\x02\x1c\x0e" # пример
known = b"flag{"
print(recover_repeating_xor_key(cipher, known))
Частый трюк: если ключ повторяется и маленький — перебор длины ключа и скоринг по “похожести на текст” (частоты букв).
1.4. Цезарь, Виженер
Цезарь (только латиница) + перебор всех сдвигов:
import string
ALPH = string.ascii_lowercase
def caesar_shift(s: str, k: int) -> str:
out = []
for ch in s:
low = ch.lower()
if low in ALPH:
idx = (ALPH.index(low) + k) % 26
new = ALPH[idx]
out.append(new.upper() if ch.isupper() else new)
else:
out.append(ch)
return "".join(out)
cipher = "Khoor Zruog!"
for k in range(26):
print(k, caesar_shift(cipher, -k))
Виженер (латиница) — шифр/дешифр:
import string
ALPH = string.ascii_uppercase
def vigenere(text: str, key: str, decrypt=False) -> str:
text_u = text.upper()
key_u = "".join([c for c in key.upper() if c in ALPH])
out, j = [], 0
for c in text_u:
if c in ALPH:
k = ALPH.index(key_u[j % len(key_u)])
t = ALPH.index(c)
out.append(ALPH[(t - k) % 26] if decrypt else ALPH[(t + k) % 26])
j += 1
else:
out.append(c)
return "".join(out)
pt = "ATTACK AT DAWN"
key = "LEMON"
ct = vigenere(pt, key, decrypt=False)
print(ct)
print(vigenere(ct, key, decrypt=True))
1.5. AES (ECB/CBC/CTR) — шифрование и расшифрование
Общие заметки
- Размер ключа AES: 16/24/32 байта (AES-128/192/256).
- Блок: 16 байт.
- ECB не использует IV, но “палится” повторениями блоков.
- CBC требует IV 16 байт.
- CTR использует nonce/counter (в PyCryptodome —
nonce=).
Padding (PKCS#7)
def pkcs7_pad(data: bytes, bs=16) -> bytes:
pad = bs - (len(data) % bs)
return data + bytes([pad]) * pad
def pkcs7_unpad(data: bytes, bs=16) -> bytes:
if not data or len(data) % bs != 0:
raise ValueError("bad length")
pad = data[-1]
if pad == 0 or pad > bs or data[-pad:] != bytes([pad]) * pad:
raise ValueError("bad padding")
return data[:-pad]
AES-ECB (как в твоём примере)
from Crypto.Cipher import AES
key = b'7h1s_1s_7h3_k3y' # 16 bytes
cipher = AES.new(key=key, mode=AES.MODE_ECB)
pt = b'hello_aes'
ct = cipher.encrypt(pkcs7_pad(pt, 16))
print(ct)
pt2 = pkcs7_unpad(cipher.decrypt(ct), 16)
print(pt2)
AES-CBC
from Crypto.Cipher import AES
from Crypto.Random import get_random_bytes
key = get_random_bytes(16)
iv = get_random_bytes(16)
cipher = AES.new(key, AES.MODE_CBC, iv=iv)
pt = b"secret message"
ct = cipher.encrypt(pkcs7_pad(pt))
dec = AES.new(key, AES.MODE_CBC, iv=iv).decrypt(ct)
print(pkcs7_unpad(dec))
AES-CTR
from Crypto.Cipher import AES
from Crypto.Random import get_random_bytes
key = get_random_bytes(16)
nonce = get_random_bytes(8)
cipher = AES.new(key, AES.MODE_CTR, nonce=nonce)
pt = b"ctr mode stream"
ct = cipher.encrypt(pt)
pt2 = AES.new(key, AES.MODE_CTR, nonce=nonce).decrypt(ct)
print(pt2)
Быстрая проверка «похоже ли на ECB»
def looks_like_ecb(ciphertext: bytes, block=16) -> bool:
blocks = [ciphertext[i:i+block] for i in range(0, len(ciphertext), block)]
return len(blocks) != len(set(blocks))
print(looks_like_ecb(b"A"*64)) # пример
1.6. RSA (PEM/DER), подпись, «сырой» RSA
Чтение ключа PEM (как в твоём примере)
from Crypto.PublicKey import RSA
with open("key.pem", "rb") as f:
priv = RSA.import_key(f.read())
with open("key.pub", "rb") as f:
pub = RSA.import_key(f.read())
print(pub.n, pub.e)
print(priv.n, priv.e, priv.d)
Генерация ключа (как в твоём примере)
from Crypto.PublicKey import RSA
key = RSA.generate(2048)
with open("key.pem", "wb") as f:
f.write(key.export_key("PEM"))
with open("key.pub", "wb") as f:
f.write(key.publickey().export_key("PEM"))
RSA-OAEP (шифрование/расшифрование — «как надо»)
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_OAEP
pub = RSA.import_key(open("key.pub","rb").read())
priv = RSA.import_key(open("key.pem","rb").read())
enc = PKCS1_OAEP.new(pub)
dec = PKCS1_OAEP.new(priv)
pt = b"hello_rsa_oaep"
ct = enc.encrypt(pt)
print(dec.decrypt(ct))
Подпись RSA-PSS
from Crypto.PublicKey import RSA
from Crypto.Signature import pss
from Crypto.Hash import SHA256
priv = RSA.import_key(open("key.pem","rb").read())
pub = RSA.import_key(open("key.pub","rb").read())
msg = b"sign me"
h = SHA256.new(msg)
sig = pss.new(priv).sign(h)
pss.new(pub).verify(SHA256.new(msg), sig)
print("ok")
«Сырой» RSA (CTF-часто: m^e mod n без padding)
from Crypto.Util.number import bytes_to_long, long_to_bytes
n = 3233
e = 17
d = 2753
pt = b"hi"
m = bytes_to_long(pt)
c = pow(m, e, n)
m2 = pow(c, d, n)
print(long_to_bytes(m2))
1.7. BigInt: bytes_to_long / long_to_bytes
from Crypto.Util.number import bytes_to_long, long_to_bytes
plaintext = b'the quick brown fox jumps over lazy dog'
encoded = bytes_to_long(plaintext)
print(encoded)
print(long_to_bytes(encoded))
Сохрани как crypto_toolkit.py и используй как быстрый швейцарский нож.
import argparse, base64, binascii, sys, string
from Crypto.Cipher import AES
from Crypto.Hash import SHA256, SHA1, MD5
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_OAEP
ALPH = string.ascii_lowercase
def pkcs7_pad(data: bytes, bs=16) -> bytes:
pad = bs - (len(data) % bs)
return data + bytes([pad]) * pad
def pkcs7_unpad(data: bytes, bs=16) -> bytes:
pad = data[-1]
if pad == 0 or pad > bs or data[-pad:] != bytes([pad]) * pad:
raise ValueError("bad padding")
return data[:-pad]
def caesar(s: str, k: int) -> str:
out = []
for ch in s:
low = ch.lower()
if low in ALPH:
idx = (ALPH.index(low) + k) % 26
new = ALPH[idx]
out.append(new.upper() if ch.isupper() else new)
else:
out.append(ch)
return "".join(out)
def xor_bytes(data: bytes, key: bytes) -> bytes:
return bytes(d ^ key[i % len(key)] for i, d in enumerate(data))
def main():
p = argparse.ArgumentParser()
sp = p.add_subparsers(dest="cmd", required=True)
p_b64d = sp.add_parser("b64d")
p_b64d.add_argument("data")
p_b64e = sp.add_parser("b64e")
p_b64e.add_argument("data")
p_hexd = sp.add_parser("hexd")
p_hexd.add_argument("data")
p_hash = sp.add_parser("hash")
p_hash.add_argument("algo", choices=["md5","sha1","sha256"])
p_hash.add_argument("data")
p_ca = sp.add_parser("caesar")
p_ca.add_argument("k", type=int)
p_ca.add_argument("text")
p_x = sp.add_parser("xor")
p_x.add_argument("key")
p_x.add_argument("hexdata")
p_aes = sp.add_parser("aes_ecb_dec")
p_aes.add_argument("key")
p_aes.add_argument("hexct")
p_oaep = sp.add_parser("rsa_oaep_dec")
p_oaep.add_argument("priv_pem")
p_oaep.add_argument("hexct")
a = p.parse_args()
if a.cmd == "b64d":
print(base64.b64decode(a.data).decode("utf-8", "replace"))
elif a.cmd == "b64e":
print(base64.b64encode(a.data.encode()).decode())
elif a.cmd == "hexd":
print(binascii.unhexlify(a.data).decode("utf-8", "replace"))
elif a.cmd == "hash":
b = a.data.encode()
if a.algo == "md5":
print(MD5.new(b).hexdigest())
elif a.algo == "sha1":
print(SHA1.new(b).hexdigest())
else:
print(SHA256.new(b).hexdigest())
elif a.cmd == "caesar":
print(caesar(a.text, a.k))
elif a.cmd == "xor":
data = binascii.unhexlify(a.hexdata)
print(xor_bytes(data, a.key.encode()).hex())
elif a.cmd == "aes_ecb_dec":
key = a.key.encode()
ct = binascii.unhexlify(a.hexct)
c = AES.new(key, AES.MODE_ECB).decrypt(ct)
try:
c = pkcs7_unpad(c, 16)
except Exception:
pass
sys.stdout.buffer.write(c)
elif a.cmd == "rsa_oaep_dec":
priv = RSA.import_key(open(a.priv_pem,"rb").read())
ct = binascii.unhexlify(a.hexct)
pt = PKCS1_OAEP.new(priv).decrypt(ct)
sys.stdout.buffer.write(pt)
if __name__ == "__main__":
main()
Примеры:
python3 crypto_toolkit.py hash sha256 hello
python3 crypto_toolkit.py caesar -3 "Khoor"
python3 crypto_toolkit.py b64d aGVsbG8=
python3 crypto_toolkit.py xor k 0f07021c0e
2. Linux шпора: команды, примеры, пайпы
2.1. Файлы и директории
| Команда |
Зачем |
Частые флаги |
Примеры |
ls |
содержимое |
-la подробно+скрытые, -R рекурсивно |
ls -la, ls -R |
pwd |
текущая директория |
|
pwd |
cp |
копировать |
-r рекурсивно, -a атрибуты, -n не перезаписывать |
cp -a src dst/ |
mv |
переместить/переименовать |
-n, -i спросить |
mv a.txt b.txt |
touch |
создать/обновить mtime |
|
touch note.txt |
rm |
удалить |
-r рекурсивно, -f без вопросов, -i спросить |
rm -rf tmp/ |
mkdir |
создать директорию |
-p цепочка |
mkdir -p a/b/c |
rmdir |
удалить пустую директорию |
|
rmdir empty/ |
tar |
архивировать |
-c create, -x extract, -t list, -f file, -z gzip |
tar -czf out.tgz dir/ |
du |
размеры |
-h, -a файлы, --max-depth=1 |
du -h --max-depth=1 . |
df |
размеры ФС |
-h |
df -h |
ln |
ссылки |
-s симлинк |
ln -s /etc/passwd passwd.link |
file |
тип содержимого |
|
file sample.bin |
find |
поиск путей |
см. большой раздел |
find . -type f -name "*.log" |
grep |
поиск строк |
см. большой раздел |
grep -Rni "flag" . |
sed |
замена/трансформации |
-n, s///g, -E |
sed -E 's/[0-9]+/NUM/g' f |
strings |
строки в бинаре |
-n N мин длина |
strings -n 6 a.out | head |
Быстрые «файловые» трюки:
# 10 самых больших файлов в дереве
du -ab . 2>/dev/null | sort -nr | head -n 10 | cut -f2- | xargs -r ls -l
# Найти файлы, изменённые за последние 2 дня
find . -type f -mtime -2 -print
# Посмотреть первые/последние байты файла в hex через Python
python3 - <<'PY'
import sys, binascii
p=sys.argv[1] if len(sys.argv)>1 else "target.bin"
b=open(p,'rb').read()
print("head:", binascii.hexlify(b[:64]).decode())
print("tail:", binascii.hexlify(b[-64:]).decode())
PY
2.2. Данные и текстовые потоки
| Команда |
Зачем |
Частые флаги |
Примеры |
cat |
вывести файл |
|
cat out.txt |
tac |
как cat, но снизу вверх |
|
tac log.txt | head |
rev |
разворот строк |
|
echo abc | rev |
head |
начало |
-n 50 |
head -n 20 file |
tail |
конец |
-n, -f следить |
tail -n 50 -f app.log |
gzip |
сжатие |
-d распаковать, -c в stdout |
gzip -dc file.gz | head |
zstd |
сжатие |
-d |
zstd -d file.zst |
wc |
счёт |
-l строки, -w слова, -c байты |
wc -l *.log |
nl |
нумерация строк |
-ba нумеровать пустые |
nl -ba file |
sort |
сортировка |
-n числа, -r обратно, -u уник |
sort -nr nums.txt |
uniq |
убрать повторы (рядом) |
-c посчитать |
sort a | uniq -c | sort -nr |
tee |
копировать stdout в файл |
-a append |
cmd | tee out.txt |
cut |
вырезать поля |
-d разделитель, -f поля |
cut -d: -f1 /etc/passwd |
xargs |
строки → аргументы |
-0 для -print0, -I{} шаблон |
find . -type f -print0 | xargs -0 ls -l |
pv |
прогресс pipe |
|
pv bigfile | gzip > big.gz |
Unix-way пример (как в условии):
du -ab . | sort -nr | head -n 10 | cut -f2- | xargs -r ls -l
2.3. Процессы и система
| Команда |
Зачем |
Частые флаги |
Примеры |
ps |
список процессов |
aux (BSD стиль), -ef (SysV) |
ps aux | head |
pgrep |
поиск pid |
-a с командой, -f по всей строке |
pgrep -af python |
prlimit |
лимиты процесса |
--pid, --nofile=... |
prlimit --pid 1234 |
pkill |
остановить |
-9 SIGKILL, -f |
pkill -f "badproc" |
htop |
диспетчер задач |
|
htop |
Полезные добавки (часто доступны по умолчанию):
top
uptime
free -h
uname -a
id
whoami
2.4. Сеть и диагностика
Даже если на олимпиаде ограничили утилиты, часто доступны:
ip a
ip r
ss -lntup
curl -i http://host/path # если curl доступен
Если curl нет — аналог на Python:
python3 - <<'PY'
import requests
r = requests.get("http://example.com", timeout=5)
print(r.status_code)
print(r.headers)
print(r.text[:300])
PY
2.5. Права, пользователи, sudo
| Команда |
Зачем |
Примеры |
chmod |
права |
chmod 600 key.pem, chmod +x run.sh |
chown |
владелец |
chown user:user file |
umask |
маска прав |
umask |
id |
группы/uid |
id |
sudo -l |
что разрешено |
sudo -l |
CTF-намёк: если в задаче про Linux/Misc/защиту, часто ищут:
- слабые права на приватные ключи (
key.pem доступен всем),
- неожиданный
sudo на конкретную команду,
- world-writable директории с важными файлами.
2.6. Логи и «следы» в Linux
История команд:
history | tail -n 50
cat ~/.bash_history 2>/dev/null | tail
Системные логи (где доступны):
ls -la /var/log
grep -Rni "sudo" /var/log 2>/dev/null | head
Поиск подозрительных команд и артефактов:
grep -RniE "nc|netcat|curl|wget|ssh|chmod 777|base64|python" ~ 2>/dev/null | head
find ~ -type f -name "*id_rsa*" -o -name "*.pem" 2>/dev/null
3. Web: основы поиска уязвимостей
3.1. Избыточные данные в ответах (Overfetching)
Суть: UI показывает только username, но сервер отдаёт JSON с лишними полями (full_name, email, roles, phone), которые легко прочитать в ответе или через API.
Что делать на CTF:
- Смотри сырой ответ (не только то, что видно на странице).
- Проверяй скрытые поля:
is_admin, role, balance, flag, debug, internal_*.
Мини-проверка на Python:
import requests
r = requests.get("http://host/api/user/1")
print(r.status_code)
print(r.headers.get("content-type"))
print(r.text)
3.2. /docs, Swagger/OpenAPI, /openapi.json
Часто у API есть автодока:
/docs, /swagger, /swagger-ui, /redoc
/openapi.json, /swagger.json
Профит:
- список всех эндпоинтов,
- схемы параметров,
- иногда тестовая “Try it out”,
- иногда подсказки о ролях/токенах/админских ручках.
3.3. robots.txt и забытые эндпоинты
/robots.txt может содержать Disallow: /admin или /backup/.
Что искать:
/admin, /internal, /debug, /backup, /old, /test, /staging, /api/private.
3.4. IDOR
IDOR = доступ к чужим объектам по ID без проверки прав.
Признаки:
- URL типа
/api/orders/123, /profile?id=5, /download?file_id=77.
- Смена ID даёт чужие данные.
Тест:
- авторизуйся как обычный пользователь, получи объект
id=10
- замени на
id=9, id=11
- если возвращает чужое — IDOR
3.5. Path Traversal / LFI
Суть: параметр пути/файла позволяет выйти из директории.
Примеры:
/download?file=report.pdf
/img?path=cat.jpg
Payload-и:
../../../../etc/passwd
..%2f..%2f..%2fetc%2fpasswd
- двойное кодирование:
%252e%252e%252f
3.6. SQL Injection: как работает и самые частые payload-и
Идея: запрос строится конкатенацией строки, и твой ввод меняет SQL.
Типовые места:
id, search, username, sort, filter.
1) Логический тест
' OR '1'='1
" OR 1=1 --
1 OR 1=1
2) Комментарии
-- (важен пробел после -- во многих СУБД)
#
/* ... */
3) UNION-based (если выводятся результаты)
1 UNION SELECT 1,2,3 --
- Затем заменить числа на поля/функции
4) Ошибки/инфо-функции (зависит от СУБД)
- MySQL:
database(), version(), user()
- Postgres:
current_database(), version(), current_user
- SQLite:
sqlite_version()
5) Blind (если ничего не видно)
- boolean:
AND 1=1 vs AND 1=2
- time-based:
SLEEP(3) (MySQL), pg_sleep(3) (Postgres)
Важно: в Task-Based CTF обычно дают короткий путь: одна уязвимость → флаг (не «полный пентест»).
3.7. Мини-шаблон на requests для тестов
import requests
BASE = "http://host"
s = requests.Session()
def get(path, **kw):
r = s.get(BASE + path, timeout=7, **kw)
print("GET", path, r.status_code, r.headers.get("content-type"))
print(r.text[:400])
return r
def post(path, data=None, json=None, **kw):
r = s.post(BASE + path, data=data, json=json, timeout=7, **kw)
print("POST", path, r.status_code)
print(r.text[:400])
return r
4. Hashcat: как использовать и где полезен
Зачем: быстро ломать хэши (пароли), особенно если есть словари/маски.
База
-m — тип хэша (mode)
-a — режим атаки
0 словарь
3 маска (bruteforce по шаблону)
6 hybrid wordlist+mask
7 hybrid mask+wordlist
-o — файл с найденными
--show — показать уже найденные
Минимальный пример (словари)
hashcat -m 0 -a 0 hashes.txt rockyou.txt -o cracked.txt
hashcat -m 0 --show hashes.txt
Маска (например, 8 символов: строчные+цифры)
hashcat -m 0 -a 3 hashes.txt ?l?l?l?l?l?l?l?l
hashcat -m 0 -a 3 hashes.txt ?l?l?l?l?l?l?d?d
Частые -m (самые популярные)
0 — MD5
100 — SHA1
1400 — SHA-256
1700 — SHA-512
1800 — sha512crypt ($6$...) (Linux /etc/shadow)
3200 — bcrypt ($2a$...)
22000 — WPA/WPA2 (если вдруг, но обычно нужны capture-файлы)
Где полезен именно в твоих заданиях
- Крипта: “дан хэш пароля → восстановить пароль → расшифровать архив/флаг”.
- Форензика: нашли дамп/логи с хэшами → восстановили учётку.
- Web: слитые базы с хэшами → подобрать пароль → войти.
Практичные флаги
--status --status-timer=5 # прогресс каждые 5 секунд
--session myrun # имя сессии
--restore # продолжить
--potfile-disable # без potfile (если нужно)
--username # если формат user:hash
5. IPTABLES: подробная шпаргалка (файрвол)
iptables управляет фильтрацией пакетов на Linux. Главное — понять цепочки, политики, порядок правил.
Термины
- Таблицы:
filter — фильтрация (по умолчанию)
nat — NAT (DNAT/SNAT/MASQUERADE)
mangle — спец. правки пакетов (редко в CTF)
- Цепочки (в
filter):
INPUT — в локальную машину
OUTPUT — из локальной машины
FORWARD — транзит через машину
- Политика по умолчанию (
policy) цепочки: ACCEPT или DROP.
- Цель (
-j jump): ACCEPT, DROP, REJECT, LOG, DNAT, SNAT, MASQUERADE.
Посмотреть правила
iptables -L -n -v
iptables -S
iptables -t nat -S
-n не резолвить имена (быстрее)
-v счётчики/интерфейсы
Базовый синтаксис правила
iptables -A CHAIN <match-и> -j TARGET
-A append (в конец)
-I insert (в начало или позицию) — часто важнее!
-D delete (удалить)
-F flush (очистить цепочку)
Важнейшая концепция: порядок
Первое совпавшее правило отрабатывает (и пакет “заканчивает” путь), поэтому:
- разрешающие правила обычно ставят выше запрещающих,
- “drop all” — последним.
Пример: «по умолчанию всё запрещено, разрешаем только SSH»
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT ACCEPT
iptables -A INPUT -i lo -j ACCEPT
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
iptables -A INPUT -p tcp --dport 22 -j ACCEPT
conntrack (состояния соединений) — must-have
-m conntrack --ctstate NEW,ESTABLISHED,RELATED
Типовой паттерн:
- вход: разрешить
ESTABLISHED,RELATED
- новые — по нужным портам
Разрешить ICMP (ping) (по ситуации)
iptables -A INPUT -p icmp -j ACCEPT
Ограничить по IP
iptables -A INPUT -p tcp --dport 22 -s 192.168.1.10 -j ACCEPT
iptables -A INPUT -p tcp --dport 22 -j DROP
Логирование (аккуратно, чтобы не заспамить)
iptables -A INPUT -p tcp --dport 22 -j LOG --log-prefix "SSH " --log-level 4
NAT: проброс порта (DNAT) (частая практика)
Сценарий: на машине есть внешний интерфейс eth0, внутренний сервис на 10.0.0.5:8080, хотим публиковать на 80.
iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 80 -j DNAT --to-destination 10.0.0.5:8080
iptables -A FORWARD -p tcp -d 10.0.0.5 --dport 8080 -m conntrack --ctstate NEW,ESTABLISHED,RELATED -j ACCEPT
iptables -A FORWARD -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
SNAT/MASQUERADE (выход в интернет для внутренней сети)
Если внешний IP динамический:
iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
Если внешний IP фиксированный:
iptables -t nat -A POSTROUTING -o eth0 -j SNAT --to-source 203.0.113.10
Удаление правил
По номеру:
iptables -L INPUT -n --line-numbers
iptables -D INPUT 3
Или точным правилом (как в iptables -S):
iptables -D INPUT -p tcp --dport 22 -j ACCEPT
Сохранение/восстановление
На многих системах:
iptables-save > rules.v4
iptables-restore < rules.v4
Частые ошибки
- Забыл разрешить
lo → ломаются локальные сервисы.
- Забыл
ESTABLISHED,RELATED → “интернет не работает”.
- Ставишь
DROP раньше, чем ACCEPT.
- Путаешь
INPUT и FORWARD.
6. SSH: шпаргалка (подключение, туннели)
База
ssh user@host
ssh -p 2222 user@host
Ключи
ssh -i key.pem user@host
chmod 600 key.pem
Полезные флаги
-v / -vvv — подробный вывод (диагностика)
-o StrictHostKeyChecking=no — отключить проверку known_hosts (иногда на CTF)
-o UserKnownHostsFile=/dev/null — не записывать known_hosts
Пример:
ssh -vvv -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null user@host
Проброс портов (часто спасает)
- Локальный проброс: открыть у себя
127.0.0.1:9000, вести на remote:127.0.0.1:80
ssh -L 9000:127.0.0.1:80 user@host
# Теперь смотри http://127.0.0.1:9000 локально
- Обратный проброс (если нужно дать доступ “назад”):
ssh -R 9000:127.0.0.1:80 user@host
7. strings: шпаргалка
Зачем: извлекать читаемые строки из бинарей/дампов/образов. В реверсе/форензике часто сразу вываливает URL, ключи, пути, flag{...}.
База
strings file.bin | head
strings -n 6 file.bin | head
-n 6 — минимальная длина строки 6 (полезно для фильтрации мусора)
Фильтрация на “интересное”
strings -n 6 file.bin | grep -iE "flag|ctf|key|pass|http|token"
Где полезно в твоих заданиях
- Реверс: найти подсказки, константы, формат флага, ключи.
- Форензика: увидеть команды, домены, пути, user-agent.
- Web: вытащить эндпоинты/секреты из фронтенд-бандла (если дали файл).
8. netcat (nc): шпаргалка
Зачем: подключиться к TCP/UDP сервису, “ручками” слать запросы, слушать порт.
Подключиться к сервису (TCP)
nc host 31337
Слушать порт (TCP сервер)
nc -l -p 9000
Отправить одну строку и выйти
echo "hello" | nc host 31337
Быстрый HTTP руками (если нет curl)
printf "GET / HTTP/1.1\r\nHost: example.com\r\nConnection: close\r\n\r\n" | nc example.com 80
Где полезно в твоих заданиях
- Misc/сеть: сервис “на сокетах”.
- Web: ручные HTTP-запросы/проверка заголовков.
- Реверс: бинарь общается по сети — воспроизвести протокол.
9. binwalk: шпаргалка
Зачем: искать встроенные файлы/архивы/сигнатуры внутри бинаря/прошивки/образа. Часто “внутри” лежит zip/tar/ключ/картинка.
База (анализ)
binwalk file.bin
Извлечь найденное
binwalk -e file.bin
Агрессивнее (иногда помогает)
binwalk -e --dd='.*' file.bin
Где полезно в твоих заданиях
- Форензика: “дамп/образ/подозрительный файл” → извлечь вложенное.
- Misc: “файл выглядит как png, но внутри ещё что-то” → binwalk покажет.
- Реверс: самораспаковывающиеся образы.
10. grep + find: подробная шпаргалка
grep — поиск строк/паттернов
База
grep "needle" file.txt
grep -n "needle" file.txt # с номерами строк
grep -i "needle" file.txt # без учёта регистра
grep -E "a|b|c" file.txt # расширенные регулярки
grep -R "needle" . # рекурсивно по дереву
grep -Rni "needle" . # рекурсивно + номера + ignorecase
Важные флаги
-R / -r — рекурсивно
-n — номер строки
-i — ignore case
-E — ERE (без экранирования |, +, ?)
-F — фиксированная строка (быстрее, без регулярок)
-w — слово целиком
-C 3 — контекст 3 строки вокруг
--binary-files=without-match — не лезть в бинарь (иногда)
-a — “считать бинарник текстом” (если надо)
Примеры:
grep -RniE "flag\{|CTF\{|token|secret|password" .
grep -Rni "BEGIN RSA PRIVATE KEY" .
grep -RniF "admin=true" .
grep -Rni "sudo" /var/log 2>/dev/null | head
Поиск по нескольким словам (AND)
grep -Rni "error" . | grep -i "sql"
find — поиск файлов по атрибутам
База
find . -type f
find . -type d
По имени
find . -type f -name "*.log"
find . -type f -iname "*flag*"
По размеру
find . -type f -size +10M
find . -type f -size -1k
По времени
-mtime -2 изменён за последние 2 дня
-mmin -30 изменён за последние 30 минут
find . -type f -mmin -30
По правам (очень полезно)
find / -type f -perm -4000 2>/dev/null # SUID (часто для CTF)
find . -type f -perm -o+w # world-writable
find . -type f -name "*.pem" -o -name "*id_rsa*" 2>/dev/null
С запуском команды на найденных
-exec ... \; выполнить на каждом
-exec ... + пачкой (быстрее)
find . -type f -name "*.txt" -exec wc -l {} \;
find . -type f -name "*.txt" -print0 | xargs -0 grep -n "flag"
Комбо find + grep
find . -type f -name "*.conf" -print0 | xargs -0 grep -ni "password"
11. Бонус: полезные техники на муниципальный этап
11.1. Быстрые “сигнатуры” форматов
- PNG:
89 50 4E 47
- ZIP:
50 4B 03 04
- PDF:
%PDF-
- ELF:
7F 45 4C 46
- GZIP:
1F 8B
Проверка в Python:
import binascii
b=open("file","rb").read(8)
print(binascii.hexlify(b).decode())
11.2. Чтение бинаря без hexdump
import binascii
b=open("a.bin","rb").read(256)
for i in range(0, len(b), 16):
chunk=b[i:i+16]
print(f"{i:08x}", binascii.hexlify(chunk).decode())
11.3. Если дали “странную строку” — чек-лист
- это hex? (
[0-9a-fA-F] и чётная длина)
- это base64? (
A-Za-z0-9+/ и = в конце)
- это base64url? (
- и _, без =)
- это JWT? (
a.b.c) → декодируй base64url header/payload
- это набор чисел? возможно
bytes_to_long/RSA
JWT decode (без проверки подписи):
import json
def b64url_decode(s):
import base64
s += "=" * ((4 - len(s)%4)%4)
return base64.urlsafe_b64decode(s.encode())
t="eyJ...a.b.c"
h,p,_=t.split(".")
print(json.loads(b64url_decode(h)))
print(json.loads(b64url_decode(p)))
11.4. Мини-подсказки по реверсу без дизассемблера
strings + поиск “flag”, “key”, “secret”
- поиск входных аргументов/подсказок:
- “usage”, “enter”, “wrong”, “correct”
- иногда ключ — это строка в бинаре, а “шифрование” простое (xor/caesar)
11.5. Форензика: быстрое обнаружение “подозрительного”
- Найти новые/подозрительные файлы в
$HOME:
find ~ -type f -mmin -120 -ls 2>/dev/null | head
- Найти команды с сетью/кодировками/правами:
history | grep -iE "nc|ssh|base64|python|chmod|iptables" | tail
11.6. Ментальная модель на задания «СЗИ / iptables»
- Сначала политики (
-P) и базовые разрешения (lo, ESTABLISHED).
- Потом точечные разрешения по портам/подсетям.
- Проверяй порядок и счётчики (
iptables -L -n -v).