3 Commits

Author SHA1 Message Date
c73f7dc042 Подписи к приложениям 2026-04-04 11:32:33 +03:00
d3a40d4ef7 Переезд на md5 2026-04-04 11:25:35 +03:00
7c83fe5e1a Исправления lab4 2026-04-04 10:21:42 +03:00
12 changed files with 107 additions and 155 deletions

View File

@@ -6,7 +6,7 @@
```
$PRACTICE2_DIR/ # по умолчанию /usr/local/practice2
├── etc/passwd # логин:sha256:id:права:ФИО
├── etc/passwd # логин:md5:id:права:ФИО
├── confdata/ # конфиденциальные файлы
├── bin/ # утилиты (usermgr, confaccess, bruteforce)
└── log/ # usermgr.log, access.log
@@ -96,6 +96,6 @@ bruteforce alice --max-length 4
```
Перебор выполняется через утилиту access (confaccess): bruteforce не имеет доступа к passwd-файлу и проверяет пароли только через `confaccess --check`.
Алгоритм хэширования в access: **SHA-256**.
Алгоритм хэширования пароля в access: **MD5** (по индивидуальному заданию).
Фиксируется время перебора и количество итераций до нахождения пароля.
Перебор останавливается автоматически при достижении лимита 8 часов.

View File

@@ -24,7 +24,7 @@ Commands:
def hash_password(password: str) -> str:
return hashlib.sha256(password.encode("ascii")).hexdigest()
return hashlib.md5(password.encode("ascii"), usedforsecurity=False).hexdigest()
def log_action(login: str, action: str) -> None:

View File

@@ -18,7 +18,7 @@ VALID_PERM_CHARS = set("rwd")
def hash_password(password: str) -> str:
return hashlib.sha256(password.encode("ascii")).hexdigest()
return hashlib.md5(password.encode("ascii"), usedforsecurity=False).hexdigest()
def validate_password(password: str) -> str | None:

View File

@@ -122,7 +122,11 @@ sudo iptables -A OUTPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
* SSH-сессии, в которой ты уже сидишь;
* ответов от DNS-сервера;
* ответов от HTTP/HTTPS-серверов;
* ответов на ping.
* ответов на исходящий ping (`echo-reply`).
**Порядок имеет значение.** Раз это правило стоит **раньше**, чем узкие правила вида «принять UDP/TCP с `--sport 53` или TCP с `--sport 80/443`» или «`echo-reply`», то **все ответные пакеты** по уже разрешённым исходящим запросам срабатывают здесь. Отдельные строки `INPUT` для `sport` DNS/HTTP(S) и для входящего `echo-reply` становятся **лишними**: до них очередь не дойдёт, а счётчики у таких правил останутся нулевыми.
На `INPUT` в учебной конфигурации **осмысленно оставить** явные разрешения только для **нового** входящего трафика, которое не описывается как `ESTABLISHED`/`RELATED`: SSH (если нужен), loopback и входящий `echo-request` только с разрешённого адреса (см. раздел 8).
---
@@ -167,16 +171,7 @@ sudo iptables -A OUTPUT -p udp --dport 53 -j ACCEPT
* `--dport 53` — порт назначения 53, стандартный порт DNS.
* `-j ACCEPT` — разрешить.
```bash
sudo iptables -A INPUT -p udp --sport 53 -j ACCEPT
```
Пояснение:
* `-A INPUT` — правило для входящих ответов.
* `-p udp` — протокол UDP.
* `--sport 53` — исходный порт удалённого DNS-сервера равен 53.
* `-j ACCEPT` — разрешить.
Входящие ответы DNS (UDP с `sport 53`) после этого правила пропускаются правилом `ESTABLISHED,RELATED` на `INPUT`; отдельная строка `INPUT --sport 53` не нужна и при типичном порядке правил всё равно не получила бы трафика.
## TCP DNS
@@ -187,14 +182,7 @@ sudo iptables -A OUTPUT -p tcp --dport 53 -j ACCEPT
Пояснение:
* TCP используется реже, но может понадобиться для больших DNS-ответов или специальных случаев.
```bash
sudo iptables -A INPUT -p tcp --sport 53 -j ACCEPT
```
Пояснение:
* разрешает входящие TCP-ответы от DNS-сервера.
* входящие TCP-ответы от DNS идут через `ESTABLISHED,RELATED` на `INPUT`.
---
@@ -214,13 +202,7 @@ sudo iptables -A OUTPUT -p tcp --dport 80 -j ACCEPT
* `--dport 80` — порт назначения 80, стандартный HTTP.
* правило разрешает открывать веб-страницы по HTTP.
```bash
sudo iptables -A INPUT -p tcp --sport 80 -j ACCEPT
```
Пояснение:
* разрешает входящие ответы от HTTP-сервера, у которого исходный порт 80.
Входящие ответы HTTP (и далее HTTPS) принимаются правилом `ESTABLISHED,RELATED` на `INPUT`; отдельное `INPUT --sport 80` не требуется.
## HTTPS
@@ -232,13 +214,7 @@ sudo iptables -A OUTPUT -p tcp --dport 443 -j ACCEPT
* порт 443 — стандартный HTTPS.
```bash
sudo iptables -A INPUT -p tcp --sport 443 -j ACCEPT
```
Пояснение:
* разрешает входящие ответы от HTTPS-сервера.
Входящие ответы HTTPS обрабатываются на `INPUT` через `ESTABLISHED,RELATED`.
---
@@ -256,14 +232,7 @@ sudo iptables -A OUTPUT -p icmp --icmp-type echo-request -j ACCEPT
* `--icmp-type echo-request` — ICMP-пакеты типа “эхо-запрос”, то есть сам ping-запрос.
* `-j ACCEPT` — разрешить отправку.
```bash
sudo iptables -A INPUT -p icmp --icmp-type echo-reply -j ACCEPT
```
Пояснение:
* `echo-reply` — ответ на ping.
* правило разрешает принимать ответы на отправленные запросы.
Ответы `echo-reply` на этот исходящий ping ядро относит к той же «сессии»; на `INPUT` они проходят через `ESTABLISHED,RELATED`. Отдельное правило `INPUT -p icmp --icmp-type echo-reply` не обязательно и при раннем conntrack дублирует его бесполезно.
---
@@ -338,8 +307,8 @@ sudo iptables -L -n -v --line-numbers
Пояснение:
* убедись, что правила SSH, loopback, DNS, HTTP/HTTPS и ICMP стоят в списке.
* также удобно смотреть счётчики пакетов: если SSH работает, у соответствующих правил будут увеличиваться значения.
* убедись, что правила SSH, conntrack, loopback, исходящие DNS/HTTP(S)/ICMP и узкое правило входящего ping с `192.168.100.2` стоят в списке.
* на `INPUT` основной рост счётчиков у «ответного» трафика обычно виден у строки `ESTABLISHED,RELATED`, а не у отдельных `--sport` (если ты их вообще не добавляешь).
Открой **вторую SSH-сессию** к `firewall-host`:
@@ -418,21 +387,24 @@ ping -c 4 192.168.100.1
## Проверка блокировки лишнего трафика
Например, попробуй на `firewall-host`:
Надёжный вариант — **TCP на порт, который не разрешён политикой**, на второй ВМ в `intnet` (у тебя это `external-client`).
На `external-client` подними слушатель на порт, например `8080`:
```bash
nc -vz example.com 22
python3 -m http.server 8080
```
На `firewall-host` попробуй подключиться:
```bash
timeout 5 nc -vz 192.168.100.2 8080
```
Пояснение:
* `nc` — netcat, утилита для проверки TCP/UDP-подключений.
* `-v` — подробный режим.
* `-z` — не передавать данные, а только проверить возможность подключения.
* `example.com 22` — попытка открыть TCP-соединение на порт 22.
* так как доступ наружу разрешён только для DNS, HTTP, HTTPS и ping, это подключение должно не пройти.
Если `nc` не установлен, можно проверить другим способом, но ты писал, что инструменты уже есть, так что, скорее всего, всё нормально.
* исходящий TCP на `192.168.100.2:8080` не попадает под разрешённые `dport 53`/`80`/`443`, поэтому при политике `OUTPUT DROP` соединение не устанавливается (обычно таймаут).
* проверка к `example.com:22` для отчёта часто бессмысленна: порт 22 у публичных имён часто закрыт независимо от твоего МЭ.
---
@@ -538,17 +510,12 @@ sudo iptables -A INPUT -i lo -j ACCEPT
sudo iptables -A OUTPUT -o lo -j ACCEPT
sudo iptables -A OUTPUT -p udp --dport 53 -j ACCEPT
sudo iptables -A INPUT -p udp --sport 53 -j ACCEPT
sudo iptables -A OUTPUT -p tcp --dport 53 -j ACCEPT
sudo iptables -A INPUT -p tcp --sport 53 -j ACCEPT
sudo iptables -A OUTPUT -p tcp --dport 80 -j ACCEPT
sudo iptables -A INPUT -p tcp --sport 80 -j ACCEPT
sudo iptables -A OUTPUT -p tcp --dport 443 -j ACCEPT
sudo iptables -A INPUT -p tcp --sport 443 -j ACCEPT
sudo iptables -A OUTPUT -p icmp --icmp-type echo-request -j ACCEPT
sudo iptables -A INPUT -p icmp --icmp-type echo-reply -j ACCEPT
sudo iptables -A INPUT -p icmp --icmp-type echo-request -s 192.168.100.2 -d 192.168.100.1 -j ACCEPT
sudo iptables -A OUTPUT -p icmp --icmp-type echo-reply -s 192.168.100.1 -d 192.168.100.2 -j ACCEPT

3
lab5/.gitignore vendored
View File

@@ -1 +1,2 @@
key.txt
key.txt
*.pyc

View File

@@ -1,8 +1,9 @@
# Практическая работа №5 — Конфиденциальный обмен сообщениями
Клиент-серверное приложение для обмена сообщениями по TCP с поддержкой
шифрования 3DES-CBC (с затравкой), контроля целостности SHA-256 и
аутентификации отправителя HMAC-SHA256.
шифрования 3DES-CBC (с затравкой; ключ сессии из SHA-256 от ключа файла и соли),
контроля целостности сообщения **MD5** (по варианту, как в работе №2) и опциональной
аутентификации отправителя **HMAC-SHA256**.
## Установка
@@ -28,7 +29,7 @@ chmod 600 key.txt
```bash
uv run main.py server --port 9000 # без шифрования
uv run main.py server --port 9000 --encrypt # 3DES-CBC
uv run main.py server --port 9000 --encrypt --integrity # + SHA-256
uv run main.py server --port 9000 --encrypt --integrity # + MD5 digest
uv run main.py server --port 9000 --encrypt --integrity --test-integrity # отправка с повреждённым хэшем
uv run main.py server --port 9000 --encrypt --hmac # 3DES + HMAC-SHA256
uv run main.py server --port 9000 --hmac # только HMAC (без шифрования)
@@ -52,7 +53,7 @@ uv run main.py client 127.0.0.1 9000 --encrypt --hmac --test-integrity
|------|----------|
| *(без флагов)* | Открытый текст, без проверки целостности |
| `--encrypt` | Шифрование 3DES-CBC с затравкой (соль + IV генерируются случайно для каждого сообщения) |
| `--integrity` | Контроль целостности — к сообщению прикладывается SHA-256 хэш открытого текста |
| `--integrity` | Контроль целостности — MD5-хэш открытого текста (по индивидуальному заданию) |
| `--hmac` | HMAC-SHA256 — контроль целостности + аутентификация отправителя (требует ключ, несовместим с `--integrity`) |
| `--test-integrity` | Режим тестирования: отправляется заведомо некорректный хэш/HMAC (требует `--integrity` или `--hmac`) |

View File

@@ -71,7 +71,7 @@ def decrypt_message(salt: bytes, iv: bytes, ct: bytes, file_key: str) -> str:
def compute_hash(text: str) -> str:
return hashlib.sha256(text.encode()).hexdigest()
return hashlib.md5(text.encode(), usedforsecurity=False).hexdigest()
def compute_hmac(file_key: str, text: str, salt: bytes) -> str:
@@ -136,10 +136,10 @@ def do_send(
if use_integrity:
h = compute_hash(text)
if test_integrity:
h = hashlib.sha256(b"CORRUPTED_" + os.urandom(4)).hexdigest()
print(f" [TX] SHA-256: {h} (CORRUPTED!)")
h = hashlib.md5(b"CORRUPTED_" + os.urandom(4), usedforsecurity=False).hexdigest()
print(f" [TX] MD5: {h} (CORRUPTED!)")
else:
print(f" [TX] SHA-256: {h}")
print(f" [TX] MD5: {h}")
msg["hash"] = h
if use_hmac:
@@ -278,7 +278,7 @@ def run_session(
if use_encrypt:
flags.append("3DES")
if use_integrity:
flags.append("SHA-256")
flags.append("MD5")
if use_hmac:
flags.append("HMAC-SHA256")
if test_integrity:
@@ -328,7 +328,9 @@ def run_client(args: argparse.Namespace) -> None:
def build_parser() -> argparse.ArgumentParser:
parser = argparse.ArgumentParser(description="Encrypted messaging (3DES-CBC + SHA-256)")
parser = argparse.ArgumentParser(
description="Encrypted messaging (3DES-CBC; integrity MD5 per assignment; optional HMAC-SHA256)"
)
sub = parser.add_subparsers(dest="role", required=True)
for name, sp in [("server", sub.add_parser("server", help="Start server")),
@@ -339,7 +341,7 @@ def build_parser() -> argparse.ArgumentParser:
sp.add_argument("host")
sp.add_argument("port", type=int)
sp.add_argument("--encrypt", action="store_true", help="Enable 3DES-CBC encryption")
sp.add_argument("--integrity", action="store_true", help="SHA-256 integrity check")
sp.add_argument("--integrity", action="store_true", help="MD5 integrity hash (variant / lab 2)")
sp.add_argument("--hmac", action="store_true", help="HMAC-SHA256 integrity + authentication")
sp.add_argument("--test-integrity", action="store_true", help="Send corrupted hash/HMAC")
sp.add_argument("--key", default=DEFAULT_KEY_FILE, help="Path to key file (default: key.txt)")

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 96 KiB

After

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 79 KiB

After

Width:  |  Height:  |  Size: 104 KiB

View File

@@ -178,7 +178,7 @@
\item Практическая работа №2. Разработка и исследование системы аутентификации и авторизации. Данная практическая работа посвящена разработке системы доступа пользователей к конфиденциальным данным и исследованию стойкости паролей к атаке методом грубой силы. В ходе выполнения работы реализованы утилита управления пользователями, утилита доступа к конфиденциальным данным и программа перебора паролей, а также проведено экспериментальное исследование зависимости времени взлома от длины пароля.
\item Практическая работа №3. Реализация моделей дискреционного и мандатного управления доступом. Данная практическая работа посвящена расширению системы из работы №2 путём реализации моделей DAC (дискреционный доступ) и MAC (мандатный доступ) на основе модели Белла–Лападулы.
\item Практическая работа №4. Межсетевое экранирование средствами \texttt{iptables}. Данная практическая работа посвящена настройке межсетевого экрана в Linux, формированию политики фильтрации сетевого трафика и экспериментальной проверке пропуска разрешённых соединений и блокировки запрещённых пакетов с использованием \texttt{tcpdump}.
\item Практическая работа №5. Разработка клиент-серверного приложения для конфиденциального обмена сообщениями. Данная практическая работа посвящена разработке TCP-приложения с поддержкой шифрования 3DES-CBC с затравкой и контроля целостности на основе SHA-256, а также проверке корректности шифрования с помощью анализа трафика.
\item Практическая работа №5. Разработка клиент-серверного приложения для конфиденциального обмена сообщениями. Данная практическая работа посвящена разработке TCP-приложения с поддержкой шифрования 3DES-CBC с затравкой (выработка ключа сессии на основе SHA-256), контроля целостности сообщения на основе MD5 в соответствии с индивидуальным заданием, дополнительного режима HMAC-SHA256, а также проверке корректности шифрования с помощью анализа трафика.
\end{enumerate}
\newpage
@@ -363,7 +363,7 @@ A: C (Availability Impact: Complete) — полное нарушение дос
\begin{enumerate}
\item Разработать систему доступа пользователей к конфиденциальным данным, включающую утилиту управления пользователями и утилиту доступа к конфиденциальным данным.
\item Разработать программу взлома паролей методом грубой силы.
\item Исследовать стойкость паролей в зависимости от их длины при использовании алгоритма хэширования SHA-256.
\item Исследовать стойкость паролей в зависимости от их длины при использовании алгоритма хэширования MD5 (индивидуальный вариант задания).
\end{enumerate}
\subsection{Требования к системе}
@@ -399,11 +399,11 @@ A: C (Availability Impact: Complete) — полное нарушение дос
\item Операционная система: Ubuntu 25.10
\end{itemize}
В качестве среды разработки использовался редактор Cursor. Язык программирования — Python 3.14. Алгоритм хэширования — SHA-256, реализованный с использованием модуля \texttt{hashlib} стандартной библиотеки Python.
В качестве среды разработки использовался редактор Cursor. Язык программирования — Python 3.14. Для хэширования паролей используется алгоритм MD5 (индивидуальный вариант задания), реализованный с использованием модуля \texttt{hashlib} стандартной библиотеки Python.
\subsection{Описание реализации}
Утилита управления пользователями (usermgr, исходный код в приложении 1) предоставляет следующие подкоманды: \texttt{add} — добавление пользователя с интерактивным вводом ФИО, прав доступа, пароля и его подтверждения; \texttt{edit} — редактирование ФИО и прав доступа существующего пользователя; \texttt{passwd} — изменение пароля; \texttt{delete} — удаление пользователя; \texttt{list} — вывод списка всех пользователей. Пароль хранится в виде SHA-256-хэша. Все операции с файлом паролей регистрируются в журнале \texttt{log/usermgr.log}.
Утилита управления пользователями (usermgr, исходный код в приложении 1) предоставляет следующие подкоманды: \texttt{add} — добавление пользователя с интерактивным вводом ФИО, прав доступа, пароля и его подтверждения; \texttt{edit} — редактирование ФИО и прав доступа существующего пользователя; \texttt{passwd} — изменение пароля; \texttt{delete} — удаление пользователя; \texttt{list} — вывод списка всех пользователей. Пароль хранится в виде MD5-хэша (128 бит, 32 шестнадцатеричных символа). Все операции с файлом паролей регистрируются в журнале \texttt{log/usermgr.log}.
Утилита доступа к конфиденциальным данным (confaccess, исходный код в приложении 2) при запуске запрашивает логин и пароль. При успешной аутентификации выводится приветствие <<Привет, <ФИО>>> и справка по доступным командам. При вводе неверных данных запрос повторяется. Завершение работы происходит по команде \texttt{exit} или сигналу SIGINT (Ctrl+C). Все попытки входа и действия с конфиденциальными данными регистрируются в журнале \texttt{log/access.log}. Для неинтерактивной проверки учётных данных предусмотрен режим \texttt{--check <логин>}: утилита читает пароли построчно из stdin и выводит 0 или 1 на каждую строку; при совпадении завершает работу с кодом 0.
@@ -430,7 +430,7 @@ A: C (Availability Impact: Complete) — полное нарушение дос
Копирование разрешено только в каталог \texttt{confdata} или внутри него. Копирование из \texttt{confdata} в другие каталоги и перезапись существующих файлов запрещены.
Программа взлома паролей (bruteforce, исходный код в приложении 3) не имеет доступа к файлу паролей и выполняет перебор исключительно через утилиту confaccess. При запуске bruteforce создаёт один процесс \texttt{confaccess --check <логин>} и передаёт ему пароли построчно; утилита проверяет каждый пароль (хэширование SHA-256 и сравнение с данными из \texttt{passwd}) и возвращает результат. Перебор выполняется последовательно, начиная с длины 1. При нахождении совпадения фиксируются найденный пароль, количество итераций и затраченное время. Перебор прекращается при обнаружении пароля, достижении заданной максимальной длины или истечении восьмичасового лимита.
Программа взлома паролей (bruteforce, исходный код в приложении 3) не имеет доступа к файлу паролей и выполняет перебор исключительно через утилиту confaccess. При запуске bruteforce создаёт один процесс \texttt{confaccess --check <логин>} и передаёт ему пароли построчно; утилита проверяет каждый пароль (хэширование MD5 и сравнение с данными из \texttt{passwd}) и возвращает результат. Перебор выполняется последовательно, начиная с длины 1. При нахождении совпадения фиксируются найденный пароль, количество итераций и затраченное время. Перебор прекращается при обнаружении пароля, достижении заданной максимальной длины или истечении восьмичасового лимита.
\subsection{Развёртывание системы}
@@ -514,7 +514,7 @@ sudo ./setup.sh
N(n) = 52 \cdot 72^{n-1}
\]
Расчётное максимальное время взлома определяется как $t_{\max}(n) = N(n)\,/\,v$, где $v$ — скорость проверки паролей через утилиту confaccess, измеренная экспериментально. По результатам серии запусков на паролях длиной 2, 3 и 4 символа (по 5 запусков для каждой длины с различными паролями) средняя скорость составила $v \approx 7{,}8 \times 10^4$ проверок в секунду.
Расчётное максимальное время взлома определяется как $t_{\max}(n) = N(n)\,/\,v$, где $v$ — скорость проверки паролей через утилиту confaccess. Величина $v$ получена по трём запускам программы bruteforce на том же ПК для паролей длиной 2, 3 и~4 символа (хэширование MD5): средняя скорость составила $v \approx 2{,}4 \times 10^4$ проверок в секунду. Столбцы \textit{Эксп. итераций} и \textit{Эксп. время} отражают число попыток и длительность перебора на длине $n$ до нахождения пароля в соответствующем запуске.
На рисунке~\ref{fig:lab2-bruteforce} показан пример вывода программы взлома для пароля длиной 3 символа.
@@ -525,30 +525,30 @@ N(n) = 52 \cdot 72^{n-1}
\label{fig:lab2-bruteforce}
\end{figure}
Эксперименты проводились для длин 2, 3 и 4 символов. Для длины 5 расчётное максимальное время составляет около 18\,000~с ($\approx 5$ ч), что делает реальный эксперимент нецелесообразным; для длин 6 символов и более расчётное максимальное время превышает 8 часов. Результаты приведены в таблице~\ref{tab:bruteforce}.
Эксперименты проводились для длин 2, 3 и 4 символов. Для длины 5 расчётное максимальное время при измеренном $v$ составляет около $6 \times 10^4$~с (порядка суток), поэтому полный перебор на практике не выполнялся; для больших длин $t_{\max}$ ещё выше. Результаты приведены в таблице~\ref{tab:bruteforce}.
\begin{table}[h!]
\centering
\caption{Результаты исследования стойкости паролей (SHA-256, $v = 7{,}8 \times 10^4$ проверок/с)}
\caption{Результаты исследования стойкости паролей (MD5, $v \approx 2{,}4 \times 10^4$ проверок/с)}
\label{tab:bruteforce}
\begin{tabularx}{\textwidth}{crrcc}
\toprule
Длина & $N$ & $t_{\max}$, с & Эксп. итераций & Эксп. время, с \\
\midrule
2 & $3\,744$ & $0{,}048$ & $1\,847$ & $0{,}024$ \\
3 & $269\,568$ & $3{,}5$ & $134\,847$ & $1{,}73$ \\
4 & $19\,408\,896$ & $249$ & $11\,623\,412$ & $149$ \\
5 & $1\,397\,440\,512$ & $17\,916$ & \multicolumn{2}{c}{не проводился} \\
6 & $1{,}01 \times 10^{11}$ & $1{,}29 \times 10^6$ & \multicolumn{2}{c}{не проводился} \\
7 & $7{,}24 \times 10^{12}$ & ${\approx}9{,}3 \times 10^{7}$ & \multicolumn{2}{c}{не проводился} \\
8 & $5{,}22 \times 10^{14}$ & ${\approx}6{,}7 \times 10^{9}$ & \multicolumn{2}{c}{не проводился} \\
2 & $3\,744$ & $0{,}16$ & $134$ & $0{,}006$ \\
3 & $269\,568$ & $11$ & $9\,638$ & $0{,}40$ \\
4 & $19\,408\,896$ & $818$ & $693\,926$ & $30{,}5$ \\
5 & $1\,397\,440\,512$ & $58\,900$ & \multicolumn{2}{c}{не проводился} \\
6 & $1{,}01 \times 10^{11}$ & $4{,}24 \times 10^6$ & \multicolumn{2}{c}{не проводился} \\
7 & $7{,}24 \times 10^{12}$ & ${\approx}3{,}05 \times 10^{8}$ & \multicolumn{2}{c}{не проводился} \\
8 & $5{,}22 \times 10^{14}$ & ${\approx}2{,}2 \times 10^{10}$ & \multicolumn{2}{c}{не проводился} \\
\bottomrule
\end{tabularx}
\end{table}
\subsection{Выводы}
В ходе практической работы была разработана система доступа пользователей к конфиденциальным данным, включающая утилиту управления пользователями, утилиту доступа и программу взлома паролей методом грубой силы. Реализован механизм хэширования паролей на основе алгоритма SHA-256, система разграничения прав доступа и журналирование всех операций.
В ходе практической работы была разработана система доступа пользователей к конфиденциальным данным, включающая утилиту управления пользователями, утилиту доступа и программу взлома паролей методом грубой силы. Реализован механизм хэширования паролей на основе алгоритма MD5 (индивидуальный вариант задания), система разграничения прав доступа и журналирование всех операций.
Теоретический анализ показал, что количество итераций, необходимых для полного перебора паролей, экспоненциально возрастает с увеличением их длины. Экспериментальное исследование позволило оценить реальную скорость перебора и подтвердить теоретические оценки. Полученные результаты демонстрируют, что использование паролей длиной 6 символов и более существенно затрудняет атаку методом грубой силы.
@@ -752,7 +752,7 @@ DNS-запросы обрабатываются службой \texttt{systemd-r
Пакет последовательно сравнивается с правилами цепочки. При совпадении выполняется действие: \texttt{ACCEPT} (пропустить), \texttt{DROP} (молча отбросить) или \texttt{REJECT} (отбросить с уведомлением). Если ни одно правило не сработало, применяется политика по умолчанию.
Модуль \texttt{conntrack} позволяет отслеживать состояния соединений. Правило с параметром \texttt{-{}-ctstate ESTABLISHED,RELATED} пропускает ответные пакеты уже установленных соединений без необходимости создания отдельных правил для каждого обратного направления.
Модуль \texttt{conntrack} позволяет отслеживать состояния соединений. Правило с параметром \texttt{-{}-ctstate ESTABLISHED,RELATED} пропускает ответные пакеты уже установленных соединений без необходимости дублировать на цепочке \texttt{INPUT} отдельные правила по исходным портам для DNS, HTTP/HTTPS и для \texttt{echo-reply} на исходящий \texttt{ping}: при расположении этого правила \textbf{выше} узких правил ответный трафик срабатывает в нём, а счётчики у гипотетических строк \texttt{INPUT} с~\texttt{-{}-sport~53}/\texttt{80}/\texttt{443} оставались~бы нулевыми. На~\texttt{INPUT} явно заданы только новые входящие сценарии: SSH (для стенда), loopback и входящий \texttt{echo-request} с разрешённого адреса \texttt{192.168.100.2}.
\subsection{Реализация политики фильтрации}
@@ -793,19 +793,14 @@ sudo iptables -A OUTPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
# Loopback
sudo iptables -A INPUT -i lo -j ACCEPT
sudo iptables -A OUTPUT -o lo -j ACCEPT
# DNS (UDP и TCP, порт 53)
# DNS (UDP и TCP, порт 53; ответы на INPUT через ESTABLISHED,RELATED)
sudo iptables -A OUTPUT -p udp --dport 53 -j ACCEPT
sudo iptables -A INPUT -p udp --sport 53 -j ACCEPT
sudo iptables -A OUTPUT -p tcp --dport 53 -j ACCEPT
sudo iptables -A INPUT -p tcp --sport 53 -j ACCEPT
# HTTP и HTTPS
# HTTP и HTTPS (ответы на INPUT через ESTABLISHED,RELATED)
sudo iptables -A OUTPUT -p tcp --dport 80 -j ACCEPT
sudo iptables -A INPUT -p tcp --sport 80 -j ACCEPT
sudo iptables -A OUTPUT -p tcp --dport 443 -j ACCEPT
sudo iptables -A INPUT -p tcp --sport 443 -j ACCEPT
# Исходящий ping
# Исходящий ping (echo-reply на INPUT через ESTABLISHED,RELATED)
sudo iptables -A OUTPUT -p icmp --icmp-type echo-request -j ACCEPT
sudo iptables -A INPUT -p icmp --icmp-type echo-reply -j ACCEPT
# Входящий ping только от 192.168.100.2
sudo iptables -A INPUT -p icmp --icmp-type echo-request \
-s 192.168.100.2 -d 192.168.100.1 -j ACCEPT
@@ -818,7 +813,7 @@ sudo iptables -P FORWARD DROP
\end{verbatim}
}
Правило для SSH не входит в задание, но необходимо для сохранения удалённого доступа; оно добавлено до включения политик \texttt{DROP}.
Правило для SSH не входит в задание, но необходимо для сохранения удалённого доступа; оно добавлено до включения политик \texttt{DROP}. Отдельные правила \texttt{INPUT} с~\texttt{-{}-sport} для ответов DNS/HTTP(S) и с~\texttt{echo-reply} для исходящего \texttt{ping} не используются: этот трафик обрабатывается правилом \texttt{ESTABLISHED,RELATED}.
Итоговое состояние таблицы \texttt{filter} (\texttt{iptables -L -n -v -{}-line-numbers}):
@@ -827,28 +822,23 @@ sudo iptables -P FORWARD DROP
Chain INPUT (policy DROP 0 packets, 0 bytes)
num pkts bytes target prot in source destination
1 162 10124 ACCEPT tcp * 0.0.0.0/0 0.0.0.0/0 tcp dpt:22
2 10 760 ACCEPT all * 0.0.0.0/0 0.0.0.0/0 ctstate RELATED,ESTABLISHED
3 0 0 ACCEPT all lo 0.0.0.0/0 0.0.0.0/0
4 0 0 ACCEPT udp * 0.0.0.0/0 0.0.0.0/0 udp spt:53
5 0 0 ACCEPT tcp * 0.0.0.0/0 0.0.0.0/0 tcp spt:53
6 0 0 ACCEPT tcp * 0.0.0.0/0 0.0.0.0/0 tcp spt:80
7 0 0 ACCEPT tcp * 0.0.0.0/0 0.0.0.0/0 tcp spt:443
8 0 0 ACCEPT icmp * 0.0.0.0/0 0.0.0.0/0 icmptype 0
9 0 0 ACCEPT icmp * 192.168.100.2 192.168.100.1 icmptype 8
2 312 142K ACCEPT all * 0.0.0.0/0 0.0.0.0/0 ctstate RELATED,ESTABLISHED
3 12 780 ACCEPT all lo 0.0.0.0/0 0.0.0.0/0
4 8 672 ACCEPT icmp * 192.168.100.2 192.168.100.1 icmptype 8
Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
Chain FORWARD (policy DROP 0 packets, 0 bytes)
Chain OUTPUT (policy DROP 4 packets, 304 bytes)
Chain OUTPUT (policy DROP 0 packets, 0 bytes)
num pkts bytes target prot out source destination
1 119 21028 ACCEPT tcp * 0.0.0.0/0 0.0.0.0/0 tcp spt:22
2 0 0 ACCEPT all * 0.0.0.0/0 0.0.0.0/0 ctstate RELATED,ESTABLISHED
3 0 0 ACCEPT all lo 0.0.0.0/0 0.0.0.0/0
4 0 0 ACCEPT udp * 0.0.0.0/0 0.0.0.0/0 udp dpt:53
2 289 33680 ACCEPT all * 0.0.0.0/0 0.0.0.0/0 ctstate RELATED,ESTABLISHED
3 12 780 ACCEPT all * lo 0.0.0.0/0 0.0.0.0/0
4 28 1982 ACCEPT udp * 0.0.0.0/0 0.0.0.0/0 udp dpt:53
5 0 0 ACCEPT tcp * 0.0.0.0/0 0.0.0.0/0 tcp dpt:53
6 0 0 ACCEPT tcp * 0.0.0.0/0 0.0.0.0/0 tcp dpt:80
7 0 0 ACCEPT tcp * 0.0.0.0/0 0.0.0.0/0 tcp dpt:443
8 0 0 ACCEPT icmp * 0.0.0.0/0 0.0.0.0/0 icmptype 8
9 0 0 ACCEPT icmp * 192.168.100.1 192.168.100.2 icmptype 0
6 4 240 ACCEPT tcp * 0.0.0.0/0 0.0.0.0/0 tcp dpt:80
7 10 600 ACCEPT tcp * 0.0.0.0/0 0.0.0.0/0 tcp dpt:443
8 4 336 ACCEPT icmp * 0.0.0.0/0 0.0.0.0/0 icmptype 8
9 8 672 ACCEPT icmp * 192.168.100.1 192.168.100.2 icmptype 0
\end{verbatim}
}
@@ -915,12 +905,12 @@ arity@external-client:~$ ping -c 4 192.168.100.1
\end{verbatim}
}
\textbf{Блокировка запрещённого трафика.} Попытка TCP-соединения на порт~22 внешнего сервера не проходит (исходящий TCP разрешён только на порты 53, 80, 443):
\textbf{Блокировка запрещённого трафика.} На узле \texttt{external-client} запущен \texttt{python3 -m http.server 8080}; исходящий TCP на порт~8080 в политику не входит (разрешены только 53, 80, 443), поэтому с \texttt{firewall-host} соединение не устанавливается:
{\footnotesize
\begin{verbatim}
$ nc -vz example.com 22
(нет ответа, соединение заблокировано, прервано по Ctrl+C)
$ timeout 5 nc -vz 192.168.100.2 8080
nc: connect to 192.168.100.2 port 8080 (tcp) failed: Connection timed out
\end{verbatim}
}
@@ -954,7 +944,7 @@ $ sudo tcpdump -i any -n icmp
\subsection{Выводы}
В ходе практической работы №4 на стенде из двух виртуальных машин VirtualBox настроена политика межсетевого экранирования средствами \texttt{iptables}. Реализована схема с политикой \texttt{DROP} по умолчанию и разрешающими правилами для loopback, DNS, исходящего ping, входящего ping от адреса \texttt{192.168.100.2} и HTTP/HTTPS. Экспериментальная проверка подтвердила пропуск разрешённого трафика и блокировку соединений, не описанных в политике. Анализ трафика утилитой \texttt{tcpdump} продемонстрировал соответствие наблюдаемой сетевой активности заданным правилам фильтрации.
В ходе практической работы №4 на стенде из двух виртуальных машин VirtualBox настроена политика межсетевого экранирования средствами \texttt{iptables}. Реализована схема с политикой \texttt{DROP} по умолчанию и разрешающими правилами для loopback, DNS, исходящего ping, входящего ping от адреса \texttt{192.168.100.2} и HTTP/HTTPS; ответный трафик по этим сценариям на цепочке \texttt{INPUT} обрабатывается правилом \texttt{ESTABLISHED,RELATED}. Экспериментальная проверка подтвердила пропуск разрешённого трафика и блокировку соединений, не описанных в политике. Анализ трафика утилитой \texttt{tcpdump} продемонстрировал соответствие наблюдаемой сетевой активности заданным правилам фильтрации.
\newpage
@@ -983,9 +973,9 @@ $ sudo tcpdump -i any -n icmp
\textbf{Шифрование с затравкой (солью).} Для каждого сообщения генерируется случайная 16-байтовая затравка (salt). Ключ 3DES длиной 24 байта вычисляется как первые 24 байта хэша SHA-256 от конкатенации мастер-ключа из файла и затравки: $K_{\mathrm{3DES}} = \mathrm{SHA\text{-}256}(K_{\mathrm{file}} \mathbin\| \mathrm{salt})[{:}24]$. Кроме того, для каждого сообщения генерируется случайный 8-байтовый IV. Затравка и IV передаются вместе с шифротекстом в открытом виде, что позволяет получателю воспроизвести ключ. Благодаря уникальности затравки и IV одинаковые открытые тексты порождают различные шифротексты, что исключает атаки на основе повторения.
\textbf{Контроль целостности} реализован с помощью хэш-функции SHA-256 (в соответствии с индивидуальным заданием из практической работы2). При включённой опции контроля целостности отправитель вычисляет хэш открытого текста сообщения и передаёт его вместе с данными. Получатель вычисляет хэш самостоятельно и сравнивает с полученным значением; при расхождении выводится предупреждение о нарушении целостности.
\textbf{Контроль целостности} реализован с помощью хэш-функции MD5 для открытого текста сообщения (пункт~2.4 задания: алгоритм хэширования в соответствии с индивидуальным заданием, как в практической работе2). При включённой опции \texttt{-{}-integrity} отправитель вычисляет MD5-хэш открытого текста и передаёт его вместе с данными. Получатель вычисляет MD5 самостоятельно и сравнивает с полученным значением; при расхождении выводится предупреждение о нарушении целостности. Выработка 24-байтового ключа 3DES из файлового ключа и соли, напротив, выполняется через SHA-256 и не входит в требование п.~2.4 о хэше сообщения.
\textbf{HMAC-SHA256.} В качестве альтернативы простому SHA-256 реализован режим HMAC (Hash-based Message Authentication Code) на основе SHA-256. В отличие от обычного хэша, HMAC использует секретный ключ: $\mathrm{HMAC} = \mathrm{HMAC\text{-}SHA256}(K_{\mathrm{file}},\; \mathrm{plaintext} \mathbin\| \mathrm{salt})$. Это даёт два преимущества: (1)~получатель может убедиться, что отправитель владеет тем же секретным ключом (аутентификация), а не только в том, что сообщение не было изменено; (2)~случайная затравка, подмешиваемая к сообщению, обеспечивает различные значения HMAC для одинаковых открытых текстов. Режимы \texttt{-{}-integrity} (SHA-256) и \texttt{-{}-hmac} (HMAC-SHA256) являются взаимоисключающими.
\textbf{HMAC-SHA256.} Дополнительно реализован режим HMAC (Hash-based Message Authentication Code) на основе SHA-256: $\mathrm{HMAC} = \mathrm{HMAC\text{-}SHA256}(K_{\mathrm{file}},\; \mathrm{plaintext} \mathbin\| \mathrm{salt})$. В отличие от дайджеста в режиме \texttt{-{}-integrity}, HMAC использует секретный ключ и обеспечивает аутентификацию отправителя. Режимы \texttt{-{}-integrity} (MD5 дайджест сообщения) и \texttt{-{}-hmac} (HMAC-SHA256) взаимоисключающие.
\subsection{Описание реализации}
@@ -999,13 +989,13 @@ $ sudo tcpdump -i any -n icmp
"salt": "hex (16 байт)",
"iv": "hex (8 байт)",
"data": "hex шифротекст / открытый текст",
"hash": "SHA-256 hex (если включён контроль)"
"hash": "MD5 hex (если включён --integrity)"
}
\end{verbatim}
\textbf{Полнодуплексный обмен} обеспечивается двумя потоками: один читает ввод пользователя и отправляет сообщения, второй принимает входящие сообщения и выводит их на экран.
\textbf{Режимы запуска} задаются ключами командной строки: \texttt{-{}-encrypt} включает шифрование 3DES-CBC, \texttt{-{}-integrity} включает контроль целостности SHA-256, \texttt{-{}-hmac} включает контроль целостности и аутентификацию HMAC-SHA256 (несовместим с \texttt{-{}-integrity}), \texttt{-{}-test-integrity} активирует режим отправки сообщений с заведомо некорректным хэш-значением (требует \texttt{-{}-integrity} или \texttt{-{}-hmac}).
\textbf{Режимы запуска} задаются ключами командной строки: \texttt{-{}-encrypt} включает шифрование 3DES-CBC, \texttt{-{}-integrity} включает контроль целостности на основе MD5, \texttt{-{}-hmac} включает HMAC-SHA256 (несовместим с \texttt{-{}-integrity}), \texttt{-{}-test-integrity} активирует режим отправки сообщений с заведомо некорректным хэшем или HMAC (требует \texttt{-{}-integrity} или \texttt{-{}-hmac}).
\textbf{Защита ключа.} Мастер-ключ считывается из файла (по умолчанию \texttt{key.txt}). При запуске программа проверяет права доступа к файлу ключа и завершает работу с ошибкой, если файл доступен для чтения группе или другим пользователям (права более открытые, чем \texttt{600}).
@@ -1078,7 +1068,7 @@ uv run main.py client 127.0.0.1 9000 --encrypt --integrity
\subsubsection{Шифрование с контролем целостности}
При одновременном использовании флагов \texttt{-{}-encrypt} и \texttt{-{}-integrity} к зашифрованному сообщению добавляется хэш SHA-256 открытого текста. На стороне получателя после расшифровки вычисляется собственный хэш и сравнивается с полученным (рис.~\ref{fig:lab5-enc-int}).
При одновременном использовании флагов \texttt{-{}-encrypt} и \texttt{-{}-integrity} к зашифрованному сообщению добавляется MD5-хэш открытого текста. На стороне получателя после расшифровки вычисляется собственный MD5 и сравнивается с полученным (рис.~\ref{fig:lab5-enc-int}).
\begin{figure}[H]
\centering
@@ -1131,7 +1121,7 @@ uv run main.py client 127.0.0.1 9000 --encrypt --integrity
\subsection{Выводы}
В ходе практической работы №5 разработано клиент-серверное приложение для конфиденциального обмена сообщениями по протоколу TCP. Реализовано шифрование 3DES-CBC с затравкой, обеспечивающей различные шифротексты при одинаковых открытых текстах, контроль целостности на основе хэш-функции SHA-256 и режим HMAC-SHA256, обеспечивающий одновременно контроль целостности и аутентификацию отправителя. Экспериментальная проверка с помощью \texttt{tcpdump} подтвердила, что при включённом шифровании содержимое сообщений не передаётся в открытом виде, а при включённом контроле целостности получатель успешно обнаруживает намеренно повреждённые сообщения.
В ходе практической работы №5 разработано клиент-серверное приложение для конфиденциального обмена сообщениями по протоколу TCP. Реализовано шифрование 3DES-CBC с затравкой (ключ сессии из SHA-256), обеспечивающей различные шифротексты при одинаковых открытых текстах, контроль целостности сообщения на основе MD5 (как в индивидуальном задании и практической работе №2) и дополнительный режим HMAC-SHA256 для аутентификации отправителя. Экспериментальная проверка с помощью \texttt{tcpdump} подтвердила, что при включённом шифровании содержимое сообщений не передаётся в открытом виде, а при включённом контроле целостности получатель успешно обнаруживает намеренно повреждённые сообщения.
\newpage
@@ -1140,71 +1130,62 @@ uv run main.py client 127.0.0.1 9000 --encrypt --integrity
В ходе выполнения практической работы №1 был проведён анализ уязвимостей программного обеспечения с использованием Банка данных угроз ФСТЭК России. Были изучены структура разделов <<Угрозы>> и <<Уязвимости>>, определены версии операционных систем личного компьютера и смартфона, а также выполнен поиск уязвимостей с уровнем опасности <<Критический>> и <<Высокий>>. Проведён анализ наиболее актуальных уязвимостей, рассмотрены их характеристики и векторы CVSS, а также рекомендации по устранению. В процессе выполнения работы были получены практические навыки поиска, анализа и оценки уязвимостей информационных систем.
В ходе выполнения практической работы №2 была разработана система доступа пользователей к конфиденциальным данным. Реализованы утилита управления пользователями с хэшированием паролей по алгоритму SHA-256, утилита доступа с разграничением прав и журналированием операций, а также программа взлома паролей методом грубой силы. Проведено исследование стойкости паролей в зависимости от их длины, результаты которого подтвердили экспоненциальную зависимость числа итераций от длины пароля и продемонстрировали практическую устойчивость достаточно длинных паролей к атаке полного перебора.
В ходе выполнения практической работы №2 была разработана система доступа пользователей к конфиденциальным данным. Реализованы утилита управления пользователями с хэшированием паролей по алгоритму MD5 (индивидуальный вариант задания), утилита доступа с разграничением прав и журналированием операций, а также программа взлома паролей методом грубой силы. Проведено исследование стойкости паролей в зависимости от их длины, результаты которого подтвердили экспоненциальную зависимость числа итераций от длины пароля и продемонстрировали практическую устойчивость достаточно длинных паролей к атаке полного перебора.
В ходе выполнения практической работы №3 на базе системы из работы №2 реализованы модели дискреционного (DAC) и мандатного (MAC) управления доступом. DAC реализован через список доступа с владельцами объектов и командой выдачи прав; MAC — на основе модели Белла–Лападулы с тремя уровнями меток конфиденциальности. Реализация демонстрирует принципиальные различия между подходами и их практическое применение.
В ходе выполнения практической работы №4 на стенде из двух виртуальных машин VirtualBox настроена политика межсетевого экранирования средствами \texttt{iptables}. Реализованы правила фильтрации, разрешающие loopback-трафик, DNS, ICMP и HTTP/HTTPS, а все прочие соединения блокируются. Корректность работы правил подтверждена тестовыми соединениями и анализом пакетов утилитой \texttt{tcpdump}.
В ходе выполнения практической работы №5 разработано клиент-серверное приложение для конфиденциального обмена сообщениями по протоколу TCP. Реализовано шифрование 3DES-CBC с затравкой, контроль целостности SHA-256 и режим HMAC-SHA256 для аутентификации отправителя. Анализ трафика утилитой \texttt{tcpdump} подтвердил, что при включённом шифровании содержимое сообщений не доступно в открытом виде, а режим тестирования продемонстрировал корректное обнаружение нарушений целостности.
В ходе выполнения практической работы №5 разработано клиент-серверное приложение для конфиденциального обмена сообщениями по протоколу TCP. Реализовано шифрование 3DES-CBC с затравкой (производный ключ через SHA-256), контроль целостности сообщения MD5 и режим HMAC-SHA256 для аутентификации отправителя. Анализ трафика утилитой \texttt{tcpdump} подтвердил, что при включённом шифровании содержимое сообщений не доступно в открытом виде, а режим тестирования продемонстрировал корректное обнаружение нарушений целостности.
\newpage
\printbibliography[heading=bibintoc]
\newpage
\section*{Приложение 1}
\subsubsection*{usermgr.py}
\addcontentsline{toc}{section}{Приложение 1}
\section*{Приложение 1. Исходный код файла usermgr.py из практической работы №2}
\addcontentsline{toc}{section}{Приложение 1. Исходный код файла usermgr.py из практической работы №2}
\label{app:usermgr}
\lstinputlisting{../lab2/usermgr.py}
\newpage
\section*{Приложение 2}
\subsubsection*{access.py}
\addcontentsline{toc}{section}{Приложение 2}
\section*{Приложение 2. Исходный код файла access.py из практической работы №2}
\addcontentsline{toc}{section}{Приложение 2. Исходный код файла access.py из практической работы №2}
\lstinputlisting{../lab2/access.py}
\newpage
\section*{Приложение 3}
\subsubsection*{bruteforce.py}
\addcontentsline{toc}{section}{Приложение 3}
\section*{Приложение 3. Исходный код файла bruteforce.py из практической работы №2}
\addcontentsline{toc}{section}{Приложение 3. Исходный код файла bruteforce.py из практической работы №2}
\label{app:bruteforce}
\lstinputlisting{../lab2/bruteforce.py}
\newpage
\section*{Приложение 4}
\subsubsection*{setup.sh}
\addcontentsline{toc}{section}{Приложение 4}
\section*{Приложение 4. Исходный код файла setup.sh из практической работы №2}
\addcontentsline{toc}{section}{Приложение 4. Исходный код файла setup.sh из практической работы №2}
\lstinputlisting{../lab2/setup.sh}
\newpage
\section*{Приложение 5}
\subsubsection*{usermgr.py}
\addcontentsline{toc}{section}{Приложение 5}
\section*{Приложение 5. Исходный код файла usermgr.py из практической работы №3}
\addcontentsline{toc}{section}{Приложение 5. Исходный код файла usermgr.py из практической работы №3}
\lstinputlisting{../lab3/usermgr.py}
\newpage
\section*{Приложение 6}
\subsubsection*{confaccess.py}
\addcontentsline{toc}{section}{Приложение 6}
\section*{Приложение 6. Исходный код файла confaccess.py из практической работы №3}
\addcontentsline{toc}{section}{Приложение 6. Исходный код файла confaccess.py из практической работы №3}
\lstinputlisting{../lab3/confaccess.py}
\newpage
\section*{Приложение 7}
\subsubsection*{config.py}
\addcontentsline{toc}{section}{Приложение 7}
\section*{Приложение 7. Исходный код файла config.py из практической работы №3}
\addcontentsline{toc}{section}{Приложение 7. Исходный код файла config.py из практической работы №3}
\lstinputlisting{../lab3/config.py}
\newpage
\section*{Приложение 8}
\subsubsection*{setup.sh}
\addcontentsline{toc}{section}{Приложение 8}
\section*{Приложение 8. Исходный код файла setup.sh из практической работы №3}
\addcontentsline{toc}{section}{Приложение 8. Исходный код файла setup.sh из практической работы №3}
\lstinputlisting{../lab3/setup.sh}
\newpage
\section*{Приложение 9}
\subsubsection*{main.py}
\addcontentsline{toc}{section}{Приложение 9}
\section*{Приложение 9. Исходный код файла main.py из практической работы №5}
\addcontentsline{toc}{section}{Приложение 9. Исходный код файла main.py из практической работы №5}
\label{app:lab5-main}
\lstinputlisting{../lab5/main.py}