Двойное дно с фишкой - Решение проблемы ввода пароля под принуждением, Rubber-hose.

Papa Carder

Professional
Messages
188
Reaction score
176
Points
43
Привет!
Проблема слива данных под давлением существует уже давно и почему-то до сих пор не имеет универсального решения.

Сперва про проблему касательно хранения данных в зашифрованном виде:
Если хранить данные в зашифрованном виде, всегда остаётся риск раскрытия пароля под давлением. Использование техники двойного дна тоже не помогает, потому что каждый криптоаналитик легко заметит подобный приём.
Полное уничтожение информации также не гарантирует безопасности, ведь перед вскрытием всегда создаётся битовая копия, и даже если оригинал будет уничтожен, бекап сохранится в резерве.

Решение: Данные стоит хранить не на устройстве, к которому можно получить физический доступ!

Предлагаю следующую логику работы вебсервера:
При вводе настоящего, первого специального пароля пользователь получает доступ к реальным данным.
Если пароль введён неправильно, система просто запрашивает повтор.
При вводе второго специального пароля сервер выдаёт данные из двойного дна.
При вводе третьего специального пароля данные уничтожаются, на заранее выбранные сервисы и каналы связи отправляется сигнал о том, что человек деанонимизирован и подвергается пыткам; взаимодействовать с ним больше не следует. Одновременно его товарищи получают инструкции, как действовать в такой ситуации.

Такой подход можно рассматривать как модифицированную идею Dead Man Switch (системы, которая выполняет заранее заданные действия, если владелец оказывается недоступен).
Подход можно интегрировать не только в файловое хранилище, но и, например, в аккаунт пользователя. Специальный пароль позволит сообщить о том, что человек за аккаунтом скомпрометирован.

Если вспомнить ситуацию с XSS.IS, подобное решение могло бы предотвратить превращение форума в ловушку. Администратор при наличии такой системы мог бы заранее подать сигнал тревоги и избежать некоторых последствий.

В этой статье я создам сервис для хранения файлов и добавлю несколько полезных функций. Это готовое решение, которое можно адаптировать под различные нужды.

Сперва необходимо выделить отдельный диск на сервере для хранения. Идеально подойдёт HDD, желательно с низкой вместимостью.

Сам диск не нужно шифровать никаким образом, просто используйте этот скрипт для шифрования файлов (взято из одной из предыдущих статей).

Bash:
#!/bin/bash

read -p "Действие (e/d): " act
read -p "Файл: " file
read -s -p "Пароль: " pass
echo

gen_hash() {
sec="$pass"; hash=""
for ((i=0;i<$1;i++)); do
h=$(echo -n "$sec" | sha512sum | awk '{print $1}')
hash+=${h:0:1}
sec=${h:1:128}
done
echo "$hash"
}

if [[ "$act" == "e" ]]; then
hex=$(base32 "$file" | od -An -tx1 | tr -d ' \n')
hash=$(gen_hash ${#hex})
enc=""
for ((i=0;i<${#hex};i++)); do
c=$((0x${hex:i:1}+0x${hash:i:1}))
((c>15)) && c=$((c-16))
enc+=$(printf "%x" $c)
done
echo "$enc" > enc.txt
echo "Готово! Принимай enc.txt"

elif [[ "$act" == "d" ]]; then
hex=$(tr -d '\n' < "$file")
hash=$(gen_hash ${#hex})
dec=""
for ((i=0;i<${#hex};i++)); do
c=$((0x${hex:i:1}-0x${hash:i:1}))
((c<0)) && c=$((c+16))
dec+=$(printf "%x" $c)
done
echo "$dec" | xxd -r -p | base32 -d > dec.txt
echo "Готово! Принимай dec.txt"
else
echo "Буквочка 'e' для шифрования, а 'd' для дешифровки."
fi

В примере будут фигурировать файлы 1.txt (настоящий файл) и 2.txt (файл для двойного дна), хоть файлы и текстовые, вы можете поместить внутрь них всё что угодно через различные кодировки, в примере base32.
Файлы 1.txt и 2.txt должны иметь одинаковые размер, иначе можно установить, что поддельный файл был выдан за настоящий.

Теперь, в директории где будет размещён вебсервер, наобходимо создать скрипт, который будет сценарием DeadManSwitch.
Можно создать инструкцию, исходя из твоей сферы деятельности, однако всегда будет полезно сообщить, что к тебе применют силу и заставляют вводить пароли. Так же критически важно уничтожить важные файлы, в первую очередь ключи и пароли. Для этого и необходим был отдельный диск.

В конце скрипта добавьте эту часть:
Bash:
partition="/dev/sdX"
lsblk -ln -o NAME,MOUNTPOINT "$partition" | awk '$2!="" {print $1}' | xargs -I{} sudo umount /dev/{}

#Для HDD:
while true; do
dd if=/dev/urandom of="$partition" bs=1M status=progress
dd if=/dev/zero of="$partition" bs=1M status=progress
dd if=/dev/zero bs=1M count=0 2>/dev/null | tr "\000" "\377" | sudo dd of="$partition" bs=1M status=progress
done

#Для SSD:
sudo hdparm --user-master u --security-set-pass DO@NOT@TOUCH@MY@DISK0000 "$partition"
sudo hdparm --user-master u --security-erase DO@NOT@TOUCH@MY@DISK0000 "$partition"

Во избежание проблем с MITM, ключ для скачивания файла, как и сам файл будет динамическим.
В качестве пароля выступет хешсумма строки и случайное значение в заданном диапазоне.
Например, если мастерпароль это "password", то паролями могут быть:
echo -n "password1234" | sha1sum ---> e6b6afbd6d76bb5d2041542d7d2e3fac5bb05593
echo -n "password1000" | sha1sum ---> 0f6f1bd08d7dfde9b46cc004badd2b60a890027a
echo -n "password3928" | sha1sum ---> cc28edaf01df41cef69ae081f75cf498bdd72064

Для шифрования файлов будут использованы те же самые хешсуммы, но с добавлением соли в начало.
Например "ecstasy"
Ключём для расшифровки будет:
ecstasye6b6afbd6d76bb5d2041542d7d2e3fac5bb05593
ecstasy0f6f1bd08d7dfde9b46cc004badd2b60a890027a
ecstasycc28edaf01df41cef69ae081f75cf498bdd72064


1.png


2.png


3.png


4.png


Возможно не совсем понятно, зачем это всё нужно.
Если и раз за разом это будет один и тот же зашифрованный файл, его можно просто изъять из трафика и заставить человека расшифровать его содержимое. Если при получении файла двойного дна он будет отличаться от того, который многократно был получен ранее - будет ясно, что это подмена. При дубликате пароля - wrong password, файл не будет скачан.

Python:
from http.server import BaseHTTPRequestHandler, HTTPServer
from urllib.parse import parse_qs
import hashlib, os, base64

PRT = 8000        #Порт вебсервера

#После запуска скрипта сразу будут создана база данных хешей.
def save_hsh(FN, TPL, CNT=44444):        #Количество всех паролей. Уничтожение после каждого использования. Если они закончаться - получить файл будет невозможно.
HSH = [hashlib.sha1(f"{TPL}{i}".encode()).hexdigest() for i in range(CNT)]
open(FN, "w").write("\n".join(HSH))
 return HSH

#Все файлы, включая этот скрипт, должны храниться на выделенном диске, который может быть полностью уничтожен в одном из сценариев.
GRP = {
"pass1.txt": {"FIL": "1.txt", "TPL": "ПервыйПарольчик"},        #Локация файла; Пароль от настоящего файла
"pass2.txt": {"FIL": "2.txt", "TPL": "ВторойПарольчик"},        #Локация файла; Пароль от файла двойного дна, который будет выдан за настоящий
}
ERS = {"FIL": None, "TPL": "ТретийПлохойПарольчик"}        #Пароль, при получении которого будет активирована инструкция DMS, которая сообщит о компрометации и уничтожит важные файлы

for K,V in GRP.items():
V["HSH"] = save_hsh(K, V["TPL"])
ERS["HSH"] = save_hsh("pass_erase.txt", ERS["TPL"])

def gen_hsh(PWD, LEN):
H, S = "", "ecstasy" + PWD        #Соль для шифрования файла
for _ in range(LEN):
        D = hashlib.sha512(S.encode()).hexdigest()
H += D[0]; S = D[1:129]
 return H

def enc_fil(FIL, PWD):
B = base64.b32encode(open(FIL,"rb").read()).decode()
H = gen_hsh(PWD, len(B)*2)
return "".join(f"{(int(C,16)+int(H[I],16))%16:x}" for I,C in enumerate("".join(f"{ord(X):02x}" for X in B))).encode()

class H(BaseHTTPRequestHandler):
def do_GET(self):
self.send_response(200)
self.send_header("Content-type","text/html")
        self.end_headers()
self.wfile.write('''
<html><head><title>EC5745Y</title><style>
body{background:#0a0a0a;color:#0f0;font-family:monospace;display:flex;justify-content:center;align-items:center;height:100vh;margin:0}
form{display:flex;flex-direction:column;gap:1em;background:rgba(0,0,0,.7);padding:2em;border:1px solid #0f0;border-radius:8px}
input{background:#0a0a0a;border:1px solid #0f0;color:#0f0;padding:.5em;font-family:monospace}
input[type=submit]{cursor:pointer;transition:.2s}
input[type=submit]:hover{background:#0f0;color:#0a0a0a}
</style></head><body>
<form method="POST"><input type="text" name="PWD" placeholder="Password"><input type="submit" value="Download"></form>
</body></html>'''.encode())

def do_POST(self):
PWD = parse_qs(self.rfile.read(int(self.headers["Content-Length"])).decode()).get("PWD",[""])[0].strip()
   
for PWD_FIL,V in GRP.items():
if PWD in V["HSH"]:
V["HSH"].remove(PWD)
open(PWD_FIL,"w").write("\n".join(V["HSH"]))
if not os.path.isfile(V["FIL"]):
self.send_response(404); self.end_headers(); self.wfile.write(b"File not found"); return
D = enc_fil(V["FIL"],PWD)
self.send_response(200)
self.send_header("Content-type","application/octet-stream")
self.send_header("Content-Disposition",'attachment; filename="data.txt"')
self.send_header("Content-Length",str(len(D)))
                self.end_headers()
                self.wfile.write(D)
return
           
if PWD in ERS["HSH"]:
os.system("echo 'ПарольОтRoot' | sudo -S bash DMS.sh")        #Рут пароль и скрипт DMS
return
self.send_response(401); self.end_headers(); self.wfile.write(b"Wrong password")
   
HTTPServer(("",PRT),H).serve_forever()

Надеюсь, изложенное было понятно и полезно.

Буду рад ответить на ваши вопросы и обсудить интересные идеи!

(c) ec5745y
 
Last edited:
Хорошая статья, идея из неё мне показалась очень интересной. Было бы здорово увидеть её реализацию не только как отдельную программу, но и в контексте ос. Например, чтобы при вводе второго неверного пароля открывалась фальшивая среда, а при третьем неверном пароле уничтожались данные, точнее, ключи. При этом мне кажется более уместным отправлять предупреждение о деанонимизации при втором пароле, так как при третьем времени на уничтожение данных может быть всего несколько секунд.

По поводу самого инструмента могу предложить несколько советов по улучшению. Во-первых, я не совсем понимаю, зачем нужен веб-сервер. Если бы он был удалённым и использовался для хранения и скачивания файлов, это было бы оправдано, но в текущей версии он работает локально и может создать дополнительный вектор атак. На мой взгляд, более уместно реализовать это через консоль или, возможно, gui (хотя gui на Python очень хороший, и в этом случае лучше переписать на другой язык). Также, если важен размер файлов, полезно было бы выравнивать их, добавляя недостающие байты с последующим восстановлением. Ещё вместо base64 для для кодирования содержимого файлов я бы использовал AES-GCM, все же мне кажется это будет как то надёжнее.

Плюс, даже если пароли хранятся на выделенном диске, файл с ними хорошо бы как-нибудь дополнительно скрывать. Ещё по поводу хэширования паролей, можно добавить bcrypt или Argon2, мне кажется это поможет для большей безопасности.
 
Хорошая статья, идея из неё мне показалась очень интересной. Было бы здорово увидеть её реализацию не только как отдельную программу, но и в контексте ос. Например, чтобы при вводе второго неверного пароля открывалась фальшивая среда, а при третьем неверном пароле уничтожались данные, точнее, ключи. При этом мне кажется более уместным отправлять предупреждение о деанонимизации при втором пароле, так как при третьем времени на уничтожение данных может быть всего несколько секунд.

По поводу самого инструмента могу предложить несколько советов по улучшению. Во-первых, я не совсем понимаю, зачем нужен веб-сервер. Если бы он был удалённым и использовался для хранения и скачивания файлов, это было бы оправдано, но в текущей версии он работает локально и может создать дополнительный вектор атак. На мой взгляд, более уместно реализовать это через консоль или, возможно, gui (хотя gui на Python очень хороший, и в этом случае лучше переписать на другой язык). Также, если важен размер файлов, полезно было бы выравнивать их, добавляя недостающие байты с последующим восстановлением. Ещё вместо base64 для для кодирования содержимого файлов я бы использовал AES-GCM, все же мне кажется это будет как то надёжнее.

Плюс, даже если пароли хранятся на выделенном диске, файл с ними хорошо бы как-нибудь дополнительно скрывать. Ещё по поводу хэширования паролей, можно добавить bcrypt или Argon2, мне кажется это поможет для большей безопасности.
Привет! Спасибо за комментарий!
Сервер должен быть исключительно удалённым, иначе во всей схеме нет особого смысла.
Удаление данных не занимает "несколько секунд" - этот процесс может длиться часами. При этом для SSD он вообще не гарантирует полной безопасности (многое зависит от конкретной модели).
Двойное дно в ОС теряет смысл, потому что криптоаналитик в любом случае снимет полную копию диска и обнаружит скрытую область. В варианте, который я описал, выявить существование двойного дна невозможно.
По поводу выравнивания размеров файлов - важно лишь, чтобы оригинальный файл был меньше двойного дна. Если же дополнять двойное дно ложными байтами, то несоответствие будут заметны.
 
Top