Scott Greenup

Holder of Coding Trinkets

Install Arch Linux

April 13, 2018


Install Arch Linux with the following features:

  • UEFI
  • GPT
  • Encrypted boot partition (i.e. kernel and initramfs)
  • Encrypted root partition with LVM on LUKS

I've never encrypted the boot partition before and have always wanted to learn how it would work; I decided to see if I could do it. The point of encrypting the boot partition is to defend against an offline attacker, who could replace parts of initramfs. Having it encrypted makes it even harder to attack your system, but still not impossible.

Note for Dell Precision Users

  1. Disable SecureBoot
  2. Change from SATA mode from RAID to AHCI
  3. When you reboot, your are going to have to manually add the EFI as a bootable option in BIOS

Create Partitions

We need to create two partitions:

  1. An EFI System Partition (ESP)
  2. A root partition

Optionally, you can create a home partition in the same fashion we create a root partition; don't forget to mount it and do the normal steps from the Arch Linux Installation Guide. I prefer to not have a seperate home partition, hence my instructions do not consider it.

# Use a GUID Partition Table (GPT)
$ parted /dev/nvme0n1 mklabel gpt

# Create an ESP partiion in the first 512MiB
$ parted /dev/nvme0n1 mkpart primary fat32 2048s 512MiB
$ parted /dev/nvme0n1 set 1 esp on
$ parted /dev/nvme0n1 name 1 esp

# Create our root partition
$ parted /dev/nvme0n1 mkpart primary ext4 512MiB 100%
$ parted /dev/nvme0n1 name 2 root

You can verify using parted <device> print:

$ parted /dev/nvme0n1 print
Partition Table: gpt
Disk Flags:

Number  Start   End     Size    File System     Name    Flags    
1       1049kB  537MB   536MB                   esp     boot, esp
2       537MB   512GB   512GB                   root

Note: We have not installed the File System yet, that is why it is currently blank.

We need to format the esp, leave the root partition for now.

# Format the esp partition with FAT32
$ mkfs.fat -F32 /dev/nvme0n1p1

Create the Root File System

We will follow most of the recommendations from the wiki.

important: Do not use luks2, the method for encrypting the bootloader does not support luks2 at the time of writing.

# Create the LUKS encrypted container
$ cryptsetup luksFormat /dev/nvme0n1p2

# Open the container to /dev/mapper/lvm
$ cryptsetup open /dev/nvme0n1p2 lvm

# Create the volumes
$ pvcreate /dev/mapper/lvm
$ vgcreate archvol /dev/mapper/lvm
$ lvcreate -L 8G archvol -n swap
$ lvcreate -l 100%FREE archvol -n root

# Format swap and root
$ mkswap /dev/mapper/archvol-swap
$ mkfs.ext4 /dev/mapper/archvol-root

For more information about LVM you can find plenty of tutorials online, I used this one from Linoxide.

Install Arch

To install Arch we need to mount our system to /mnt and use pacstrap.

# Mount the partitions
$ mount /dev/mapper/archvol-root /mnt
$ swapon /dev/mapper/archvol-swap

# Change your mirrorlist
$ vim /etc/pacman.d/mirrorlist

# Install arch
$ pacstrap /mnt base base-devel

After installing Arch, mount the ESP.

$ mkdir /mnt/boot/esp
$ mount /dev/nvme0n1p1 /mnt/boot/esp

Once that is installed, and you've mounted the ESP, follow the Configure The System part of the Installation Guide up until the Initramfs/mkinitcpio stage.

You should be chroot'd into your new install when you get to the initramfs stage.


We are going to remake the initramfs after chaning the config

Open the configuration file:

$ vim /etc/mkinitcpio.conf

Add the keyboard, encrypt and lvm2 hooks to mkinitcpio.conf:

HOOKS=(... keyboard block encrypt lvm2 ... filesystems ...)

Re-run mkinitcpio

$ mkinitcpio -p linux

Boot Loader

Here is the trickiest bit. I would read this to make sure the information here is not outdated: GRUB#UEFI_systems

We want UEFI to load the ESP, which needs to know how to decrypt Grub, and Grub needs to know how to decrypt the LUKS container and mount the LVM volumes.

Install Grub (make sure you are chroot'd in to your /mnt)

$ pacman -S grub efibootmgr

Let GRUB know about the LUKS encrypted device. We are going to need the UUID of the device, I use blkid to get this.

$ blkid >> /tmp/blkid.out
$ vim -O /tmp/blkid.out /etc/default/grub

In /etc/default/grub we want to change two things:

  1. Add a cryptdeviuce and root argument as kernel paramters
  2. Enable CRYPTODISK

Adding the kernel parameters:

# Change this Line

# TO something like this, ensuring:
# - you get the right UUID (from the blkid output)
# - use the correct device name (during crypsetup open, and pvcreate)
# - use the correct volume name (during vgcreate)
GRUB_CMDLINE_LINUX="cryptdevice=UUID=<insert-device-uuid-for-nvme0n1p2-here>:lvm root=/dev/mapper/archvol-root"

Install Grub, if you have an intel cpu, install the 'intel-ucode' package before doing this.

$ grub-mkconfig -o /boot/grub/grub.cfg
$ grub-install --target=x86_64-efi --efi-directory=/boot/esp --bootloader-id=grub_arch


We can now reboot after we dismount everything.

# Exit the chroot
$ exit

# Close everything
$ swapoff /dev/mapper/archvol-swap
$ umount -R /mnt
$ vgchange -an archvol
$ cryptsetup close /dev/mapper/lvm

# Cross your fingers
$ reboot

You may have to manually add the EFI as a bootable option in BIOS. I had to on a Dell.

Refreshing New Website

September 22, 2017

I decided to rewrite my website in Django. The previous iteration was written in Golang and use 0 libraries, with the goal to painstakingly implement every feature myself. However, I realised that I was wasting more time on developing the site rather than producing useful content, or working on other projects that are more interesting to me.

I've used Pygments (with this theme for the code) and Markdown2 to make blog posting simpler. There are still features to add, like comments and social media buttons.

But, now writing code examples is prettier!

#include <stdio.h>
int main(void) {
    printf("Hello, world!\n");
    return 0;

Messing with Windows

September 1, 2016

Mounting Windows on Linux

$ sudo pacman -S ntfs-3g
$ mkdir /mnt/windows
$ mount /dev/sdxX /mnt/windows


Utilman.exe is a program run by windows with the hokey "windows + U". It even runs before the user has logged in at the login screen. The other important thing to note, is it runs under the SYSTEM user on Windows; this is equivalent to root on *nix systems. Therefore, we can replace the Utilman.exe with an executable of our own, for example, I used cmd.exe. I've got a bootable USB with Arch Linux on it and I have used it to mount the Windows file system and change the executables around.

$ cd /mnt/windows/Windows/System32
$ cp Utilman.exe Utilman.exe.bak
$ cp cmd.exe Utilman.exe

After rebooting, hit the hotkey and you now have a SYSTEM command prompt. I then added a user with:

net user anonymoususername password1234 /add
net localgroup Administrators anonymoususername /add

Clearing the Admin Password

If you ever forget your administrator password and don't want to mess with SYSTEM files, you can just clear the admin password with a program called chntpw. It's a prety self explanatory program that you run interactively.

Cracking the Hashes

If you ever have access to a system and you want to get the original password out, we will need to crack the password hash. This could take some time to crack, I'd highly recommend using a few password lists from github when doing this. Links below. First of all, we need to get the hashes out. To do that, we mount the windows system on linux, and then use samdump2 to dump the hashes.

$ cd /mnt/windows/Windows/System32/config/
$ sudo samdump2 SYSTEM SAM > /tmp/hashes

That file now has the hashes in it. Mine were of this form:


I cracked this with john the ripper and a word list called rockyou.txt.

john --wordlist=rockyou.txt --format=NT2 /tmp/hashes

nginx and SELinux

July 7, 2016

I am learning nginx and decided to use a RHEL linux server to do so. I installed and ran nginx and hit the delightful "Welcome to nginx!" when accessing the public IP (e.g. of the site. Okay, all good.

I wanted to use server_name to run multiple webservers on the same port on the same machine. I pointed a different URL of mine at the IP ( using (e.g. and created a second config file that would address and serve a very basic HTML file from a different directory.

server {
    listen 80;
    root /var/www/;

    location / {
        try_files $uri /index.html;

I then modified the default.conf to only handle the IP of the site.

server {
    listen       80;

    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;

    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;

Okay, looks good. I restarted nginx and deciding to check It showed me the welcome page as expected. However, showed a 403 forbidden error.

Let's check the permissions:

$ namei -l /var/www/
f: /var/www/
dr-xr-xr-x root root /
drwxr-xr-x root root var
drwxr-xr-x root root www
drwxr-xr-x root root
-rw-r--r-- root root index.html

They look fine to me... so what's going on? Let's check to see if it matches the directory nginx is currently serving out of for

dr-xr-xr-x root root /
drwxr-xr-x root root usr
drwxr-xr-x root root share
drwxr-xr-x root root nginx
drwxr-xr-x root root html
-rw-r--r-- root root index.html

They seem to match to me. What is going on... I found the error log for nginx under /var/log/nginx/error.log which showed me this line:

... "/var/www/" is forbidden (13: Permission denied)...

Not very helpful, after some research I found this post which fixed my problem. It turns out that this thing called SELinux was stopping nginx from accessing that directory. I had never heard of SELinux before and after some research I found that it was a very powerful security tool for managing fine-grained access between processes and objects like ports, files, and dirs. It does this by tagging objects with a user, role, and type. The type is most important here. A process tagged with type A can only access certain types. For example, we can see nginx's type using the Z flag.

$ ps -eZ | grep nginx
system_u:system_r:httpd_t:s0    30956 ?        00:00:00 nginx
system_u:system_r:httpd_t:s0    30957 ?        00:00:00 nginx

The Z flag allows us to see the security data in the from of user:role:type. You can see that the type of the nginx process is httpdt. It can access certain types like usrt and httpdsyscontentt. The content I was attempting to serve was vart, something httpdt processes can not access. All I had to do was change the type of my files that I am serving to a proper type and everything should be dandy. I will also changed the user to be systemu to make things consistent.

$ chcon -R -t httpd_sys_content_t -u system_u /var/www
$ ls -Zd /var/www
drwxr-xr-x. root root system_u:object_r:httpd_sys_content_t:s0 www/
$ ls -Zd /var/www/
drwxr-xr-x. root root system_u:object_r:httpd_sys_content_t:s0
$ ls -Zd /var/www/
-rw-r--r--. root root system_u:object_r:httpd_sys_content_t:s0 index.html

Now, I restarted nginx for good measure and I can now see my page with 200 OK.

I'd highly recommened watching this video and learning some things about SELinux if your a webmaster, web-admin, using Apache, NGINX, httpd or similar. Some useful commands to checkout are:

getsebool -- gets a list of all booleans SELinux has
setsebool -- sets a boolean, temporarily or permanently
chcon -- change the user, role, or type of a dir/file
sestatus -- gets the current status of SELinux
getenforce -- gets the current enforcing mode of SELinux
setenforce -- change the current enforcing mode, (i.e. turns SELinux on/off)

Contains the booleans that differ from default:

Contains the default modes:


January 20, 2016

It's kind of like a traceroute but does a geolookup as well. This requires geoip and traceroute to be installed.

$ pacman -S geoip traceroute

The python script is below. It basically just does a traceroute and then runs a geoip lookup on every IP in the traceroute result. It is a very basic script but it is interesting to see where your routes are going.

#!/usr/bin/env python2

from subprocess import Popen
from subprocess import PIPE

import sys

if len(sys.argv) < 2:
    print "usage:", sys.argv[0], "target_ip"

target = sys.argv[1]

print "performing traceroute...\n"
x = Popen("sudo traceroute -I", shell=True, stdout=PIPE)

splat = x.split('\n')
splat = splat[2:]

for i in splat:
    if "* * *" in i:
        print "* * *"
        print ""
    if "(" not in i:

    ip =  i.split("(")[1].split(")")[0]
    hostname = i.split(" ")
    for j in hostname:
        if "." in j:
            hostname = j

    print "IPv4:", ip
    print "HOSTNAME:", hostname
    geo = Popen("geoiplookup " + ip, shell=True, stdout=PIPE)
    print geo