LIMB
Вход Регистрация

тема

ОС с двойным дном и взрывчаткой 🧨

ec5745y · · 3 ответов · 241 просмотров

Привет! В этой статье я расскажу о создании ОС с двойным дном.

Не удалось прогрузить медиа


В комментариях к статье /threads/1167/ появилась идея о создании ос, в которой будет использован этот механизм, однако в приведённом виде, это не имеет никакого смысла.
TL;DR:

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

Основная проблема заключается в том, что ключ шифрования от ОС может быть перехвачен, а после, расшифрован локально.
То есть, после извлечения диска, можно выяснить как работает шифрование, а после, подставить уже полученные данные и заставить человека ввести пароль от них.

Ниже я расскажу о том, как предотвратить эту и другие проблемы.

Сперва я переписал вебсервер под telnet:

Python:
# DMSserver.py
import socketserver, hashlib, os, base64

PRT = 8000

def save_hsh(FN, TPL, CNT=99999):
    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": "pass"},
    "pass2.txt": {"FIL": "2.txt", "TPL": "spass"}
}
ERS = {"TPL": "bpass"}

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 T(socketserver.BaseRequestHandler):
    def handle(self):
        self.request.settimeout(5)
        data = b""
        while True:
            byte = self.request.recv(1)
            if not byte or byte in (b'\r', b'\n'):
                break
            data += byte
 
        PWD = data.decode().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 os.path.isfile(V["FIL"]):
                    self.request.sendall(enc_fil(V["FIL"], PWD))
                return
 
        if PWD in ERS["HSH"]:
            os.system("echo 'ПарольОтRoot' | sudo -S bash DMS.sh")

socketserver.TCPServer.allow_reuse_address = True
socketserver.TCPServer(("", PRT), T).serve_forever()

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

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

Для шифрования скрипта я предлагаю использовать моё шифрование, оно достаточно надёжное. Скорость можно изменить, добавив большее колво байт за хеш.



Bash:
# cryptor.sh
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 -w 0 "$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

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

Bash:
# tui.sh
#!/usr/bin/env bash

clear
rows=$(tput lines); cols=$(tput cols)

title="Внешний пароль"
tput cup $((rows/2-1)) $(((cols-${#title})/2)); printf "%s\n" "$title"
tput cup $((rows/2+1)) $(((cols-${#title})/2))

pass=""
while IFS= read -r -s -n 1 char; do
  [[ $char == $'\0' || $char == $'\n' || $char == $'\r' ]] && break
  [[ $char == $'\177' ]] && { (( ${#pass} > 0 )) && pass=${pass%?} && printf '\b \b'; continue; }
  pass+=$char; printf '*'
done



file=enc.txt
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"
}

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

# Запуск в ram
PID=$$; echo "$dec" | xxd -r -p | base32 -d > /dev/shm/$PID.sh chmod +x /dev/shm/$PID.sh && exec /dev/shm/$PID.sh; rm /dev/shm/$PID.sh

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


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


Bash:
origexp="937a92774f545dd85c916329ef97e62ee6e9672abd0f25ce73faf36f32f3ddee4ce08d65c2ce1c7ffa61e8657a76bc01f660f63b93ed0349a1663a9b66bc802f"
[[ $(sha512sum brutecrypt|cut -d' ' -f1) == $origexp ]] && title="Подмены содержимого нет" || title="Подмены содержимого нет!!"

После, как и в /threads/1167/ ввод пароля (вебсервер изменён на telnet)
Bash:
#!/bin/bash

clear
rows=$(tput lines); cols=$(tput cols)

origexp="937a92774f545dd85c916329ef97e62ee6e9672abd0f25ce73faf36f32f3ddee4ce08d65c2ce1c7ffa61e8657a76bc01f660f63b93ed0349a1663a9b66bc802f"
[[ $(sha512sum brutecrypt|cut -d' ' -f1) == $origexp ]] && title="Подмены содержимого нет" || title="Подмены содержимого нет!!"

tput cup $((rows/2-1)) $(((cols-${#title})/2)); printf "%s\n" "$title"
tput cup $((rows/2+1)) $(((cols-${#title})/2))

pass=""
while IFS= read -r -s -n 1 char; do
  [[ $char == $'\0' || $char == $'\n' || $char == $'\r' ]] && break
  [[ $char == $'\177' ]] && { (( ${#pass} > 0 )) && pass=${pass%?} && printf '\b \b'; continue; }
  pass+=$char; printf '*'
done


H=$(echo -n "$pass"| sha1sum | cut -d' ' -f1)
#Используйте proxychains для проксирования, если используете tor
hex=$((echo $H; echo)|nc xxxxxxxxxxxxxxx.onion 8000 | tr -d '\n')
hash=""; sec="ecstasy$H"
for((i=0;i<${#hex};i++));do
    h=$(echo -n "$sec"|sha512sum|awk '{print $1}')
    hash+="${h:0:1}"
    sec="${h:1:128}"
done
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
input=$(echo "$dec" | xxd -r -p | base32 -d | sha512sum | cut -d' ' -f1)

Теперь поговорим про brutecrypt. 
Это можно назвать защитой от перебора. Программа должна сильно повысить энтропию.
По сути это немного изменённый Proof of Work
Есть изначальная строка и префикс.
Из строки берёться sha512 и добовляеться число и вычисляться sha512, который при следущей итерации будет использован как изначальная строка
Это происходит до тех пор пока префикс не будет соответствовать запрошенному.


C:
// brutecrypt (Модифицировал PoW)
#include <stdio.h>
#include <string.h>
#include <openssl/evp.h>
#include <stdint.h>
int main(int c, char **v) {
    char b[512], h[129];
    strcpy(b, v[1]);
    size_t s = strlen(b);
    char *p = v[2];
    uint64_t n = 0;
    while (1) {
        sprintf(b + s, "%lx", n);
        EVP_MD_CTX *ctx = EVP_MD_CTX_new();
        EVP_DigestInit_ex(ctx, EVP_sha512(), NULL);
        EVP_DigestUpdate(ctx, b, strlen(b));
        unsigned char d[64];
        unsigned int l = 64;
        EVP_DigestFinal_ex(ctx, d, &l);
        EVP_MD_CTX_free(ctx);
        for (int i = 0; i < 64; i++)
            sprintf(h + i * 2, "%02x", d[i]);
        h[128] = 0;
        if (!strncmp(h, p, strlen(p))) {
            EVP_MD_CTX *ctx2 = EVP_MD_CTX_new();
            EVP_DigestInit_ex(ctx2, EVP_sha512(), NULL);
            EVP_DigestUpdate(ctx2, b, strlen(b));
            unsigned char f[64];
            unsigned int fl = 64;
            EVP_DigestFinal_ex(ctx2, f, &fl);
            EVP_MD_CTX_free(ctx2);
            EVP_MD_CTX *ctx3 = EVP_MD_CTX_new();
            EVP_DigestInit_ex(ctx3, EVP_sha512(), NULL);
            EVP_DigestUpdate(ctx3, f, 64);
            unsigned char ff[64];
            unsigned int ffl = 64;
            EVP_DigestFinal_ex(ctx3, ff, &ffl);
            EVP_MD_CTX_free(ctx3);
            for (int i = 0; i < 64; i++)
                printf("%02x", ff[i]);
            puts("");
            return 0;
        }
        memcpy(b, d, 64); b[64] = 0; s = 64;  // Убери эту строку и будет обычный PoW
    }
}

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


Bash:
clear
rows=$(tput lines); cols=$(tput cols)

title="Теперь секретное число: "
tput cup $((rows/2-1)) $(((cols-${#title})/2)); printf "%s\n" "$title"
tput cup $((rows/2+1)) $(((cols-${#title})/2))

pass=""
while IFS= read -r -s -n 1 char; do
  [[ $char == $'\0' || $char == $'\n' || $char == $'\r' ]] && break
  [[ $char == $'\177' ]] && { (( ${#pass} > 0 )) && pass=${pass%?} && printf '\b \b'; continue; }
  pass+=$char; printf '*'
done
clear

echo $input
sleep 100

brute=$(( (pass + pass % 2) / 2 )); brute=${brute:0:2}
for ((i=1; i<=brute; i++)); do
    input=$(./brutecrypt "$input" "$pass")
    echo "Раунд $i/$brute: $input"
done
input=$(echo -n $input | sha512sum | cut -d' ' -f1)
echo "Финализация: $input"

Ура! Теперь есть ключ который будет использован для шифрования.
Предвартельно получите как минимум два ключа ключа (один для двойного дна а второй для фейковой системы)

Теперь переходим к созданию ОС!
В примере я буду поднимать систему на arch linux. 

Сперва разбейте диск на три раздела, первый под efi, второй 4-6гб под лаунчер а третий для зашифрованной системы.

Bash:
sgdisk --new=1:0:+512M --typecode=1:ef00 --new=2:0:+6G --typecode=2:8300 --new=3:0:0 --typecode=3:8300 /dev/диск

На втором разделе будет линукс, который будет получать ключ из сервера и проводить с ним все операции для запуска системы из третьего раздела.

Я должен предупредить, что зашифрованная система после запуска не будет изолирована от лаунчера после запуска. Это не критически важно но вы должны это знать.
kexec может помочь вам с этим, однако в отличии от luks, он не будет работать с veracrypt о котором далее пойдет речь.
Далее во избежание путаницы я буду называть систему которая запускает зишифрованную ос - лаунчером.

Установка системы лаунчера:


Bash:
# Вы можете использовать этот гайд для установки базовой системы (https://mags.zone/help/arch-usb.html)
sudo mkfs.fat -F32 /dev/диск1
sudo mkfs.ext4 -F /dev/диск2

mkdir /mnt/outer
sudo mount /dev/sdb2 /mnt/outer
sudo mkdir -p /mnt/outer/boot/efi
sudo mount /dev/sdb1 /mnt/outer/boot/efi

sudo pacstrap /mnt/outer base linux linux-firmware pacman

genfstab -U /mnt/outer | sudo tee /mnt/outer/etc/fstab
sudo arch-chroot /mnt/outer
pacman -S efibootmgr  veracrypt networkmanager curl grub veracrypt device-mapper linux-headers mkinitcpio


ln -sf /usr/share/zoneinfo/Antarctica/South_Pole /etc/localtime
hwclock --systohc

echo "en_US.UTF-8 UTF-8" > /etc/locale.gen
locale-gen
echo "LANG=ru_RU.UTF-8" > /etc/locale.conf

echo "Anna's iPhone" > /etc/hostname        # :)
systemctl enable NetworkManager
grub-install --target=x86_64-efi --efi-directory=/boot/efi --bootloader-id=GRUB --removable
grub-mkconfig -o /boot/grub/grub.cfg

# Автологин
mkdir -p /etc/systemd/system/[email protected]/
echo -e '[Service]\nExecStart=\nExecStart=-/sbin/agetty --autologin root --noclear %I $TERM' > /etc/systemd/system/[email protected]/override.conf
systemctl enable [email protected]

# GRUB без логов, интерактива и ожидания
sed -i 's/GRUB_TIMEOUT=.*/GRUB_TIMEOUT=0/;s/GRUB_TIMEOUT_STYLE=.*/GRUB_TIMEOUT_STYLE=hidden/;s|GRUB_CMDLINE_LINUX_DEFAULT=.*|GRUB_CMDLINE_LINUX_DEFAULT="quiet loglevel=0 systemd.show_status=auto rd.udev.log_priority=3 vt.global_cursor_default=0 splash"|' /etc/default/grub
grub-mkconfig -o /boot/grub/grub.cfg

Далее дважды выполните

Bash:
veracrypt -t -c /dev/диск

В первый раз создайте Normal type, а во второй Hidden. 
Укажите ранее полученные пароли.
Желательно, чтобы размер Hidden был настолько маленьким, насколько это позволяют потребности, однако не стоит переусердствовать, ведь его размер расширить нельзя.
После создания, стоит заполнить Normal type всем чем попало.
Используйте эту команду чтобы загрузить данные с другого диска


Bash:
rsync -aAXv --progress /mnt/old/ /mnt/vc

После этого, монтируйтесь в двойное дно и настройте систему из которой будете работать.

Осталось закончить пару последних штрихов, в конец второго скрипта добавьте:

Bash:
# Если PIM не задан - опустите флаг
echo -n "$input" | veracrypt --non-interactive --pim $pass --stdin --mount /dev/nvme0n1p3 /mnt/vc;

mount /dev/mapper/veracrypt1 /mnt/vc
mkdir -p /mnt/vc/{dev/pts,proc,sys,run}
mount --bind /dev /mnt/vc/dev
mount --bind /dev/pts /mnt/vc/dev/pts
mount --bind /proc /mnt/vc/proc
mount --bind /sys /mnt/vc/sys
mount --bind /run /mnt/vc/run


arch-chroot /mnt/vc /bin/bash -c "sddm" # Запуск графического окружения
А после, зашифруйте этот скрипт на локальный пароль, используя cryptor.sh
Переместите файлы: brutecrypt, enc.txt и tui.sh на лаучер, а так же задайте автоматическое выполнение tui.sh при входе в систему.

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

Видео демонстрация входа в систему
Клирнет видео:


Если у вас есть предложения по улучшению или замечания - я постараюсь на всё ответить!


Автор @ec5745y
Специально для forum.LIMB.cc​
👍14 🔥2 😢3 💯1
"Но что делать если vps перестанет работать или тор заблокирован будет) Это же точка отказа."
Если тор перестанет работать - всё плохо. Ну а вообще можно использовать другие сети.
По поводу отказа vps - использовать несколько серверов.
Думаю, хорошей идеей будет устроить связь между серверами, чтобы сервер, на который успешно был отправлен пароль, отправлял его на на другие сервера.
Таким образом дубликатов не возникнет и DMS будет активирован.

Серверная часть


Python:
RESEV = [("xxxx.onion", 38731), ("xxxx.onion", 5745)]  # Список серверов
def SHARE(pwd):
    for ip, port in RESERV:
        try:
            s = socket.socket()
            s.connect((ip, port))
            s.sendall(f"{pwd}\n".encode())
            s.close()
        except:
            pass

На стороне клиента
Bash:
RESERV=("xxxxxx1.onion" "xxxxx2.onion")
PORTS=(38731 5745)
TIMEOUT=15
for i in "${!RESERV[@]}"; do
    RESERV="${RESERV[$i]}"
    PORT="${PORTS[$i]}"
    hex=$(echo -e "$H\n" | nc -w "$TIMEOUT" "$RESERV" "$PORT" 2>/dev/null | tr -d '\n')
    [ -n "$hex" ] || continue


Над легендой думайте сами, будет смшено если у всех она будет одинаковая ))
Ну и от кейса сильно зависит, на ум чего-то уникального не приходит.
Я юридически не подкован, поэтому бред советовать не буду.
👍2
Ответec5745y

"Но что делать если vps перестанет работать или тор заблокирован будет) Это же точка отказа." Если тор перестанет работать - всё плохо. Ну а вообще можно использовать другие сети. По поводу отказа vps - использовать…

Другие сети - это какие? 
Можем ли мы использовать немножко другую логику: 

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

Я посмотрел видеодемонстрацию очень плохое качество, почти ничего не видно и вы еще фильтр наложили это же не edit по компьютерной игре) Можете, пожалуйста сделать запись экрана. Если нет, то вы можете сделать просто скриншоты и из них создать видеоряд, чтобы людям было понятно. После этого подаем вашу статью на оплату.
👍4 ❤️1
ОтветModerator

Можем ли мы использовать немножко другую логику: если по каким либо причинам резервные сервера не отвечают, не доступны - нас попросят ввести пароль. Да, это разрушит всю схему, но должен же быть авайриный доступ к…

Да можно, более этого, система будет работать нормально.
Ответec5745y

Предвартельно получите как минимум два ключа ключа (один для двойного дна а второй для фейковой системы)

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

Так же можно запомнить эти пароли, а после отредактировать скрипт и восстановить ключи.
Ответec5745y

GRP = { "pass1.txt": {"FIL": "1.txt", "TPL": "pass"}, "pass2.txt": {"FIL": "2.txt", "TPL": "spass"}}

Гостевой просмотр. Чтобы отвечать и ставить реакции, войдите или зарегистрируйтесь.