Hardened CTI Environment - bencrypted

Hardened CTI Environment

Purpose

Configure a hardened cyber threat intelligence (CTI) environment to reduce attack surface and attributable information that could lead back to the researcher. This threat model will focus on security and privacy alike.

Virtualization Software Selection

VMWare, Oracle VirtualBox, or QEMU are all options. VMWare and VirtualBox favor ease of configuration, however there are many QEMU front-ends that are available for simplifying/automating the use of QEMU. While most analysts will largely be confined to doing the majority of their research from a guest VM on top of their host, some situations may allow for access to a private virtual private server (VPS) that provides separation or a proxy for intelligence probing.

OS Selection

For the host OS, we are going to assume that the analyst is confined to Windows or MacOS. From here, we will focus on making the guest virtual machine (VM) or VPS follow minimalism with regards to the codebase and services.

Alpine Linux is the selection of choice due to their focus on security, minimalism, and ease of deployment. The MUSL codebase along with the OpenRC service manager allows for a non-standard environment without adding unneeded complexity and undesirable vulnerability trends.

To complement the environment, Alpine even has specialized kernels to fit particular use-cases. The following configuration, virt.x86_64.config is more fitting to our use-case with a dedicated guest VM. While the configuration certainly is not as hardened as a project such as the plague-kernel, it provides a reduced attack surface by gutting unnecessary hardware support and still has ground over other security projects such as the LTS kernel used by Whonix. For the lofty and ambitious, custom kernels can still be imported to Alpine.

Note: Alpine is not the only valid option. One could deploy PlagueOS, Whonix, or their own tailored distribution.

Obtain & Validate

Follow Alpine’s Verification process.

wget https://alpinelinux.org/keys/ncopa.asc
wget https://dl-cdn.alpinelinux.org/alpine/v3.16/releases/x86_64/alpine-virt-3.16.2-x86_64.iso.asc
gpg --import ncopa.asc
gpg --verify alpine-virt-*.iso.asc alpine-virt-*.iso

Results should appears as follows:

gpg:                using RSA key 0482D84022F52DF1C4E7CD43293ACD0907D9495A
gpg: Good signature from "Natanael Copa <ncopa@alpinelinux.org>" [unknown]
gpg: WARNING: This key is not certified with a trusted signature!
gpg:          There is no indication that the signature belongs to the owner.
Primary key fingerprint: 0482 D840 22F5 2DF1 C4E7  CD43 293A CD09 07D9 495A

Base configuration

Once Alpine has been booted, execute the setup-alpine -f answers.txt

Content of answers.txt:

KEYMAPOPTS="us us"
HOSTNAMEOPTS=host
DEVDOPTS=mdev
INTERFACESOPTS="-ar"
# DNSOPTS="-d 10.8.8.1" ## Not honored when using dhcp
TIMEZONEOPTS="UTC"
PROXYOPTS=none
APKREPOSOPTS="-1 -c"
USEROPTS="-a -u -g audio,video,wheel,netdev user"
SSHDOPTS="openssh"
NTPOPTS=none
DISKOPTS="-em sys -s 0"

Reboot & detach the mounted disk image

Proceed to configure the desktop environment with the following command:

setup-xorg-base gnome gnome-terminal gedit
rc-update add gdm

Note: I prefer Gnome due to both the aesthetics and the environment being solely Wayland rather than Xorg. Wayland has a better security model and provides window isolation. Many of the minimalist Windows Managers such as SwayWM lay claim to a pure Wayland environment, however the Wayland security model is largely ignored in implementation. At the time of writing, Gnome does still contain some Xorg dependencies in version 42. Version 43 removes the dependencies.

Hardening

Staging various configuration files

Note: There are many different ways to stage configs. This is simply using wget to pull PlagueOS’s pre-compiled configs.

### Modprobe blacklist
wget https://0xacab.org/optout/plagueos/-/raw/master/base_configs/etc/modprobe.d/blacklist.conf -P /etc/modprobe.d/

### Misc restrictions via sysctl
wget https://0xacab.org/optout/plagueos/-/raw/master/base_configs/etc/sysctl.d/10_kernel.conf -P /etc/sysctl.d/
wget https://0xacab.org/optout/plagueos/-/raw/master/base_configs/etc/sysctl.d/20_network.conf -P /etc/sysctl.d/
wget https://0xacab.org/optout/plagueos/-/raw/master/base_configs/etc/sysctl.d/30_userspace.conf -P /etc/sysctl.d/

### Block soft and hard core dumps
wget https://0xacab.org/optout/plagueos/-/raw/master/base_configs/etc/security/limits.conf -P /etc/security/

### Add hardened boot parameters
wget https://0xacab.org/optout/plagueos/-/raw/master/base_configs/etc/default/grub -P /etc/grub.d/

### Hardened SSH configuration
wget https://0xacab.org/optout/plagueos/-/raw/master/base_configs/etc/ssh/sshd_config -P /etc/ssh/

### misc. additions and increased password hashing rounds
wget https://0xacab.org/optout/plagueos/-/raw/master/base_configs/etc/login.defs -P /etc/

### Set generic machine ID
echo "b08dfa6083e7567a1921a715000001fb" > /etc/machine-id

### Clear banners
> /etc/issue
> /etc/motd

Additional sources of entropy

apk add jitterentropy-library haveged haveged-openrc
echo "jitterentropy_rng" > /etc/modules-load.d/jitterentropy.conf

Configure Awall

This is Alpine’s default front-end for interfacing with IPTables.

apk add awall

Add the following content to /etc/awall/optional/default.json:

{
  "description": "block all inbound, allow essential outbound",

  "variable": { "internet_if": "eth0" },

  "zone": {
    "internet": { "iface": "$internet_if" }
  },

  "policy": [
    { "in": "internet", "action": "drop" },
    { "action": "reject" }
  ],

  "filter": [

    {
      "in": "_fw",
      "out": "internet",
      "service": [ "dns", "http", "https", "ntp" ],
      "action": "accept"
    }
  ]
}

Enable the new ruleset:

awall enable default
awall activate

Confirm that awall is running with:

awall list

Install GrapheneOS’s Hardened Memory Allocator (hmalloc)

apk add git make gcc libc-dev g++
git clone https://github.com/GrapheneOS/hardened_malloc.git
cd hardened_malloc
make \
  CONFIG_SLAB_QUARANTINE_RANDOM_LENGTH=0 \
  CONFIG_SLAB_QUARANTINE_QUEUE_LENGTH=0 \
  CONFIG_GUARD_SLABS_INTERVAL=8

install out/libhardened_malloc.so "/usr/local/lib/libhardened_malloc.so"
wget https://0xacab.org/optout/plagueos/-/raw/master/baseConfigs/etc/ld.so.preload -P /etc/

Secure fstab configuration

cat >> /etc/fstab<< EOF
### Only allow users to see their processes. Disallow other processes.
proc                /proc                   proc     nosuid,nodev,noexec,hidepid=2,gid=proc,rw                                  0 0

### Mount /tmp in tmpfs. All /tmp files will be held in RAM.
tmpfs               /tmp                    tmpfs    noexec,nosuid,nodev,size=512M,mode=1777,rw                                 0 0

### Mount /dev/shm in tmpfs. All /dev/shm files will be held in RAM.
tmpfs               /dev/shm                tmpfs    nodev,nosuid,noexec,size=512M,mode=1777,ro     
EOF

MAC Randomization (less important for virtual environments)

apk add macchanger
cat >> /etc/rc.local<< EOF
DEVICES=( $(ls /sys/class/net/) )

for i in ${DEVICES[@]}
do
  if [[ ! "$i" == "lo" ]]; then
    /usr/bin/macchanger -A "$i"

  fi
done
EOF

Browsing

Hardened variants of Chromium are advised, however compiled packages for the MUSL codebase are hard to come by.

To avoid pivoting towards a Chromium derivative project, the easiest path forward is to run Chromium with flags to disable various features, execute with non-persistence in incognito, and disable the JIT engine.

Install Chromium with the following command:

apk add chromium

Place the following content in /usr/bin/hchrome:

/usr/bin/chromium-browser %U --disable-reading-from-canvas --disable-3d-apis --disable-component-update --disable-background-networking --user-agent="" --no-default-browser-check --incognito --disable-breakpad --no-crash-upload --no-report-upload --disable-crash-reporter --disable-speech-synthesis-api --disable-speech-api --disable-cloud-policy-on-signin --disable-print-preview --disable-drive --disable-full-history-sync --disable-sync --js-flags="--jitless"

Note: Outside of disabling the JIT engine, the majority of the appended flags have an orientation towards privacy over security.

chmod +x /usr/bin/hchrome

Now execute hchrome from terminal any time chromium with the privacy-centric flags are desired

Hardened Kernel Compilation

  1. Install dependencies:
apk add alpine-sdk linux-headers

Additionally, you may need to install other packages based on your specific configuration and the features you want to compile into the kernel.

  1. Use curl to pull down linux-hardened kernel
# KVER='6.6.32-hardened1' # <- example variable for kernel version 
/usr/bin/curl --verbose --tlsv1.3 --proto =https -L -O --url "https://github.com/anthraxx/linux-hardened/archive/refs/tags/$KVER.tar.gz"
  1. Extract the source code:
tar xvf "$KVER".tar.gz
  1. Change to the extracted directory:
cd linux-hardened-"$KVER"
  1. Stage the plague-kernel config
wget https://0xacab.org/optout/plague-kernel/-/raw/main/hardened_host.config -O .config   
  1. Configure, compile, and install compiled modules:
make oldconfig && make -j$(nproc)
  1. Stage the compiled image under the /boot partition:
cp arch/x86/boot/bzImage /boot/vmlinuz-linux-hardened-"$KVER"
  1. Finally, the bootloader, whether that be syslinux or grub, needs to be updated to recognize the newly staged kernel.
mkinitfs -o /boot/initramfs-"$KVER" "$KVER"

Routing

This will vary largely depending upon the threat model and how critical non-attribution is to the operation.

The main options are leveraging TOR, mixnets, or VPNs.

  • TOR is acceptable for the threat model of non-attribution; it favors anonymity. Analysts will run into inaccessible sites and an excess of captchas (captcha hell) which will slow down the research operation. For operations where the analyst proceeds with the use of TOR, they should leverage a guest Whonix gateway and place their Alpine instance in an isolated network segment. I’ll avoid mimicking Whonix’s documentation, but for those interested, see the VirtualBox, KVM, and Physical Isolation instructions. While tailored towards Arch Linux, the same steps in this wiki apply to configuring Alpine with the isolated network and routing all traffic via the Whonix Gateway.
  • VPNs are advisable in a situation where a base level of privacy is needed. One should be aware that these do not achieve anonymity, nor are they suitable where the adversary has access to netflow data. Like all software-based traffic routing, it isn’t impervious to leakage, therefore I advise routing via a set VPN configuration on physical hardware when assurance is needed.
  • Mixnets are still in their adolescence and are largely unadvised.
  • CTI analysts may leverage an overlay network such as I2P for pulling data that is not found elsewhere, however one could not advise leveraging this overlay network as a primary method for research.

Hardening Checklist

  • Hardened kernel
  • Hardened memory allocator
  • Hardened boot parameters
  • Modprobe blacklist
  • Sysctl kernel restrictions
  • Awall Packet Filter (whitelist)
  • Added entropy with use of haveged and jitterentropy
  • Full Wayland Environment
  • Permission hardening & set UMASK 0077 to system-wide default
  • Use of doas, removal of sudo (default with Alpine)
  • Hardened SSH configuration, filtered traffic, or removed software
  • Secure fstab configuration (leveraging nodev, nosuid, and noexec)
  • Hardened Chromium variant with JIT disabled
  • Disable swap partition
  • Increased password hashing rounds

Non-Attribution Checklist

  • Generic hostname [host]
  • Generic username [user]
  • Generic machine ID
  • Randomized MAC address for Network Interface Controllers (NIC)
  • Hide process identifiers
  • Remove system identifiers in banners [i.e. /etc/motd]
  • [] Whonix-Gateway client only (for use-cases with TOR)