RADIUS authentication and dynamic VLAN assignment for WPA2 Enterprise using SQLite in FreeRADIUS

I recently bought a UniFI AP AC Pro [1] access point to replace my old useless AP. For obvious geeky reasons I wanted to use WPA2 Enterprise instead of WPA2 Personal. In that way, I can have different accounts for accessing my wireless network, which means I can easily revoke access to someone using my WiFi.

Using WPA2 Enterprise requires the use of a RADIUS server, so I have written down the steps I used to configure this together with RADIUS assigned VLANs, so that different accounts gets different VLANs. I have stored this configuration inside an SQLite database for simplicity. An interesting and possible future tweak may be to move to an LDAP server instead.

My RADIUS server will be running FreeBSD, if you use some other system, the paths may vary.

Start by installing the FreeRADIUS port. Remember to include support for SQLite when building.

# portmaster net/freeradius3

First of all, modify the /usr/local/etc/raddb/clients.conf file and include a new block for the RADIUS client (i.e. your access point) and select a good secret. You then need to enter this together with the RADIUS server’s IP in your APs configuration.

client apname {
        ipaddr          = my.ap.example.com
        secret          = nogoodsecret
        nas_type        = other

Modify the configuration file so that an SQLite database is used as backend. Edit /usr/local/etc/raddb/mods-available/sql and modify the driver line to:

driver = "rlm_sql_sqlite"

In the same file, uncomment the following block and set the correct database filename.

sqlite {
                # Path to the sqlite database
                filename = "/usr/local/etc/raddb/freeradius.db"

                # How long to wait for write locks on the database to be
                # released (in ms) before giving up.
                busy_timeout = 200

                # If the file above does not exist and bootstrap is set
                # a new database file will be created, and the SQL statements
                # contained within the bootstrap file will be executed.
                bootstrap = "${modconfdir}/${..:name}/main/sqlite/schema.sql"

Finally enable the sql module.

# cd /usr/local/etc/raddb/mods-enabled
# ln -s ../mods-available/sql

Next step is to initialize the database schema and set the correct permissions.

# cd /usr/local/etc/raddb
# sqlite3 freeradius.db < mods-config/sql/main/sqlite/schema.sql
# chown freeradius:freeradius freeradius.db
# chmod 660 freeradius.db

After this, populate the database with some user accounts and groups. I have created two different user groups, family and friends, which will be used later on to differentiate VLAN assignments. I have opted to store the passwords as an NT-hash, since that allows us to use EAP-PEAP-MSCHAPv2 as EAP method later on. This EAP method is widely supported on many platforms (including e.g. Windows). The other possibility would be to store the passwords in clear text, which allows us to use any EAP method. But for obvious security reasons that is just stupid.

Before inserting the password hashes in the database, we need to calculate them. This can be done by using the program smbencrypt. After this we insert them into the database.

$ smbencrypt password1 password2 password3
LM Hash			 	NT Hash
--------------------------------	--------------------------------
E52CAC67419A9A2238F10713B629B565	5835048CE94AD0564E29A924A03510EF
E52CAC67419A9A22F96F275E1115B16F	E22E04519AA757D12F1219C4F31252F4
E52CAC67419A9A221B087C18752BDBEE	BD7DFBF29A93F93C63CB84790DA00E63
# sqlite3 freeradius.db
sqlite> INSERT INTO radusergroup (username,groupname) VALUES ('user1', 'family');
sqlite> INSERT INTO radusergroup (username,groupname) VALUES ('user2', 'friends');
sqlite> INSERT INTO radusergroup (username,groupname) VALUES ('user3', 'friends');

sqlite> INSERT INTO radcheck (username,attribute,op,value) VALUES ('user1','NT-Password',':=','5835048CE94AD0564E29A924A03510EF');
sqlite> INSERT INTO radcheck (username,attribute,op,value) VALUES ('user2','NT-Password',':=','E22E04519AA757D12F1219C4F31252F4');
sqlite> INSERT INTO radcheck (username,attribute,op,value) VALUES ('user3','NT-Password',':=','BD7DFBF29A93F93C63CB84790DA00E63');

You may now start the RADIUS server. It should work for EAP authentication.

However, we’re still using the example certificates which is suboptimal. Let’s generate a new certificate signed by a CA. Just follow the instructions in /usr/local/etc/raddb/certs/README. The instructions are excellent. However, do note that if you change the password from whatever you also need to change it inside passwords.mk. If you changed the server key password, don’t forget to change it inside FreeRADIUS config as well. In /usr/local/etc/raddb/mods-available/eap change private_key_password to your password. After this, restart the RADIUS server and enjoy.

VLAN assignment

I want to assign a client to different VLANs depending on the groups above. If a user belongs to the family group, they should be assigned to VLAN 1, otherwise to VLAN 149. Note that to do this you need to update both UniFI controller to a recent version >5.0.0 and the AP’s firmware. I initially forgot to upgrade the AP’s firmware (it was still at, which created the unfortunate situation that the option Enable RADIUS assigned VLAN was available in the controller, but it didn’t have an actual effect on the AP due to lack of support in the firmware. I spent many hours debugging this… For a Ubiquiti access point the following attributes should be added to the RADIUS response [2].

Tunnel-Type = 13,
Tunnel-Medium-Type = 6,
Tunnel-Private-Group-Id = "149"   # <=== add your vlan id for each user.

To add the attributes above, add them to the SQLite database as below:

# sqlite3 freeradius.db
sqlite> INSERT INTO radgroupreply (groupname, attribute, value, op) VALUES ('friends', 'Tunnel-Type', '13', ':=');
sqlite> INSERT INTO radgroupreply (groupname, attribute, value, op) VALUES ('friends', 'Tunnel-Medium-Type', '6', ':=');
sqlite> INSERT INTO radgroupreply (groupname, attribute, value, op) VALUES ('friends', 'Tunnel-Private-Group-Id', '149', ':=');

Since VLAN 1 is the default VLAN, I do not add entries for the family group (note that things actually will not work if you do!). Note that for the attributes to propagate to the final RADIUS Access-Accept used by the AP to do the VLAN assignment, you need to modify /usr/local/etc/raddb/sites-available/inner-tunnel and go the section post-auth and uncomment the following two blocks so it looks like this:

        #  Instead of "use_tunneled_reply", uncomment the
        #  next two "update" blocks.
        update {
                &outer.session-state: += &reply:

        #  These attributes are for the inner session only.
        #  They MUST NOT be sent in the outer reply.
        #  If you uncomment the previous block and leave
        #  this one commented out, WiFi WILL NOT WORK,
        #  because the client will get two MS-MPPE-keys
        update outer.session-state {
                MS-MPPE-Encryption-Policy !* ANY
                MS-MPPE-Encryption-Types !* ANY
                MS-MPPE-Send-Key !* ANY
                MS-MPPE-Recv-Key !* ANY
                Message-Authenticator !* ANY
                EAP-Message !* ANY
                Proxy-State !* ANY

After this, everything should work flawlessly!


[1] https://www.ubnt.com/unifi/unifi-ap-ac-pro/
[2] https://help.ubnt.com/hc/en-us/articles/219654087-UniFi-Using-VLANs-with-UniFi-Wireless-Routing-Switching-Hardware

HTTPS Kerberos authentication with Apache 2.4

So I wanted to put my shiny Kerberos server to some use on my network, and decided that I want some web services protected by Kerberos authentication. By doing so, I will automatically have access to those services on my local machine (because I get a Kerberos ticket upon local login, see my previous post). My web server will run Apache 2.4, and run on FreeBSD.

I start by installing Apache 2.4:

# portmaster www/apache24

The default settings works fine. I proceed with configuring Apache as usual, with SSL certificates and so on. We then proceed by building the Kerberos module for Apache.

# portmaster www/mod_auth_kerb2

I use the Kerberos-version from base. Choose appropriately.

Next, we need to generate a new keytab on the Kerberos server. The name must match the host the server is running on. Thus, if your webserver has the domain name web.example.com, the Kerberos principal should be HTTP/web.example.com. Move the principal file somewhere safe, I put mine in /usr/local/etc/apache24/extra/.

Next, add the following directives to the <Location> or <Directory> you want to protect:

# Should have been added by default to the top of the file.
LoadModule auth_kerb_module   libexec/apache24/mod_auth_kerb.so


<Location />
    AuthType            Kerberos
    AuthName            "Kerberos login for ZOZS.SE"
    KrbMethodNegotiate  On
    KrbMethodK5Passwd   Off
    KrbAuthRealms       ZOZS.SE
    Krb5KeyTab          /usr/local/etc/apache24/extra/my.keytab
    require valid-user

With the config above, I require Kerberos Authentication for everything, and I will only allow actual Kerberos tickets to be used. If you want basic authentication fallback (which will then grab username and password from the user, and then try to acquire a Kerberos ticket on their behalf), you can set KrbMethodK5Passwd On.

Add Apache to your /etc/rc.conf and start it with service start apache24 and you’re done!

Network boot (PXE) of HTPC

I recently bought an Intel NUC (NUC5i3RYK to be precise). I have equipped it with 8 GB of RAM, but with no storage. My goal is to make the HTPC boot completely over the network using PXE. This should load Kodi (XBMC) and be able to access all shared files located on my file server.

Since I want the network boot and HTPC root filesystem separated from the rest of the network, so that it won’t interfere with my regular DHCP server, I have located them on an separate VLAN. It is also possible to put everything on the same VLAN if you would like to, but then you would need to configure the DHCP server you usually use to point to the TFTP server used for PXE boot.


The server needs to provide DHCP address and an TFTP server. It also provides the root system for the Linux installation on which Kodi runs. The root filesystem is mounted over NFS. The server itself runs FreeBSD. I will use dnsmasq to provide both DHCP and TFTP. I believe this is easier than running separate daemons for both services.


Install dns/dnsmasq from ports. Ensure that the system it is running on has a static IP address, and runs dnsmasq on boot, fixed by setting e.g:

ifconfig_xn0="inet netmask"

in /etc/rc.conf

Now we need to configure dnsmasq to provide both DHCP and TFTP services. I use the following configuration file:

# Accept DNS queries only from hosts whose address is on a local
# subnet, ie a subnet for which an interface exists on the server.
# This option only has effect if there are no --interface
# --except-interface, --listen-address or --auth-server options.

# Uncomment this to enable the integrated DHCP server, you need
# to supply the range of addresses available for lease and optionally
# a lease time. If you have more than one network, you will need to
# repeat this for each network on which you want to supply DHCP
# service.

# Override the default route supplied by dnsmasq and send no default
# route at all. Note that this only works for the options sent by
# default (1, 3, 6, 12, 28) the same line will send a zero-length option
# for all other option numbers.

# Set the boot filename for netboot/PXE. You will only need
# this is you want to boot machines over the network and you will need
# a TFTP server; either dnsmasq's built in TFTP server or an
# external one. (See below for how to enable the TFTP server.)

# NFS mountpoint

# Enable dnsmasq's built-in TFTP server

# Set the root directory for files available via FTP.

As you can see, /htpc will be used as the root of our PXE-served Linux installation.

NFS server

I export the /htpc directory over NFS using the following /etc/exports configuration:

/htpc   -maproot=root   -network -mask

and enable the NFS server by appending this to /etc/rc.conf


We must allow clients to mount the filesystem with root rights (the -maproot option fixes this).

Preparing the NFS root directory with a Linux installation

The /htpc directory must be filled with some interesting contents to actually boot a system.

I want my HTPC to run Kodi, and I initially planned to use OpenELEC for simplicity. However, OpenELEC does not support the use of NFSv4 mounts, and since my file server is only configured to serve media over a kerberized NFSv4 mount, I had to abandon the idea of OpenELEC, and instead use my own setup. I based this on Arch Linux.

Following the guide for Diskless systems from the Arch wiki [1], we see that we must initialize the base system in our /htpc directory. Since this directory is located on a FreeBSD system, it is a bit tricky to do just by following the instructions as written on the wiki. However, since my desktop uses Arch Linux, I solved this by mounting the NFS share on my desktop computer, and proceeded according to the instructions on the wiki after this:

# mount -t nfs -o hard,nolock server:/htpc /htpc
# pacstrap -d /htpc base mkinitcpio-nfs-utils nfs-utils

This prepares an Arch Linux installation in the /htpc directory on the NFS server. The initramfs must be generated to support an NFS root. Ensure that /htpc/etc/mkinitcpio.conf has the following lines:

MODULES="nfs e1000 e1000e"
HOOKS="base udev autodetect modconf block net filesystems keyboard fsck"

I used the module e1000e to match my network card, otherwise the NFS root mount will fail. Adapt this to your own network adapter. If you want to try to boot in VirtualBox before actually booting on the NUC, you need e1000. Then regenerate the initramfs by calling:

# arch-chroot /htpc mkinitcpio -p linux

I proceeded with setting the hostname, locale, timezone, etc. as usual in an Arch Linux installation. Check the Installation guide [2] on the wiki for this.

Next it is time to setup the bootloader. I will use PXELINUX. From my desktop system, I copied the PXELINUX files to the NFS mount.

# cp /usr/lib/syslinux/bios/pxelinux.0 /htpc/boot
# cp /usr/lib/syslinux/bios/ldlinux.c32 /htpc/boot
# mkdir /htpc/boot/pxelinux.cfg

I then proceed by creating the /htpc/boot/pxelinux.cfg/default configuration file:

default linux

label linux
kernel vmlinuz-linux net.ifnames=0
append initrd=initramfs-linux.img quiet ip=:::::eth0:dhcp nfsroot=

The base system is now ready, and should be able to boot over PXE! The kernel parameter net.ifnames=0 was added to avoid network device renaming on boot. This interfered with my NFS root and VLANs, you may not need it.

Further configuration of the Linux installation

You may skip this section if you have an ordinary system. It covers other stuff relevant for my own case, e.g. creating new interfaces for my other VLANs.

This contains some final steps required for my specific setup. Since I just mounted the root filesystem on a specific VLAN, I want to mount my ordinary file server from my default VLAN. This is done by creating a new network interface with the correct VLAN.

I use the following netctl configuration file for Arch Linux in /etc/netctl/regular0-vlan

Description='Regular VLAN on interface eth0'
# The variable name is plural, but needs precisely one interface

and I then enabled the profile by using

# netctl enable regular0-vlan

To mount my NFS file server on boot I use the systemd automounter and include the following line in my fstab.

file.server.host:/media		/mnt/media			nfs4		users,noauto,x-systemd.automount,x-systemd.device-timeout=10,timeo=14,noatime,nfsvers=4,sec=krb5,soft		0 0

In addition, the usual NFS Client configuration from [3] is required.

Installation of Kodi and related stuff

We begin by installing the Intel graphics drivers.

# pacman -S xf86-video-intel mesa-libgl libva-intel-driver libva mesa xorg-xinit xorg-server udisks upower polkit

Now to the fun part, we want to install Kodi and have it to start automatically.

# pacman -S kodi unrar unzip libcec

Also install kodi-standalone-service from the AUR. Enable and start the service with

# systemctl enable kodi.service

To be able to shutdown the computer from within Kodi, add the user to the power and storage groups. If you want to use a HDMI-CEC adapter such as [4], you also need to add the kodi user to the groups uucp and lock.

# gpasswd -a kodi power
# gpasswd -a kodi storage
# gpasswd -a kodi uucp
# gpasswd -a kodi lock

Reboot your NUC, and Kodi will start just as expected!


[1] https://wiki.archlinux.org/index.php/Diskless_system
[2] https://wiki.archlinux.org/index.php/Installation_guide
[3] https://wiki.archlinux.org/index.php/NFS#Client
[4] http://www.pulse-eight.com/store/products/104-usb-hdmi-cec-adapter.aspx

Validating server certificates signed by own CA in Swift

In one of my recent apps I wanted to download data from an internal server, which had a certificate signed by an in-house certificate authority. To avoid hard-coding fingerprints in the application, I would rather validate the certificate to ensure that it was signed by any trusted CA, including my own.

To download files I have used NSUrlConnection asynchronously, thus my class needs to implement the protocol NSURLConnectionDataDelegate. The function which handles server certificate validation (together with for example HTTP Basic authentication) is connection:willSendRequestForAuthenticationChallenge.

Thus, all the code should go into this function:

func connection(connection: NSURLConnection, willSendRequestForAuthenticationChallenge challenge: NSURLAuthenticationChallenge) {

Allowing a single CA

We first add our DER-formatted certificate authority to the XCode project. We can then extract the path to it using:

let rootCa = "rootca"
let rootCaPath = NSBundle.mainBundle().pathForResource(rootCa, ofType: "der")

After this we read the data from the path into an NSData object.

let rootCaData = NSData(contentsOfFile: rootCaPath)

And finally we create a certificate out of it (in unmanaged memory) using SecCertificateCreateWithData

let rootCert = SecCertificateCreateWithData(nil, rootCaData).takeRetainedValue()

Finally we are ready to set the list of allowed certificates. If we also want to allow certificates signed by the regular CA list provided by iOS, we need the call to SecTrustSetAnchorCertificatesOnly, otherwise only our own CA would be trusted.

SecTrustSetAnchorCertificates(trust, [rootCert])
SecTrustSetAnchorCertificatesOnly(trust, 0) // also allow regular CAs.

The complete code, with if let for handling nil is below, which also includes the evaluation step using SecTrustEvaluate

func connection(connection: NSURLConnection, willSendRequestForAuthenticationChallenge challenge: NSURLAuthenticationChallenge) {
	if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust {
		// First load our extra root-CAs to be trusted from the app bundle.
		let trust = challenge.protectionSpace.serverTrust
		let rootCa = "eitroot"
		if let rootCaPath = NSBundle.mainBundle().pathForResource(rootCa, ofType: "der") {
			if let rootCaData = NSData(contentsOfFile: rootCaPath) {
				let rootCert = SecCertificateCreateWithData(nil, rootCaData).takeRetainedValue()
				SecTrustSetAnchorCertificates(trust, [rootCert])
				SecTrustSetAnchorCertificatesOnly(trust, 0) // also allow regular CAs.
		var trustResult: SecTrustResultType = 0
		SecTrustEvaluate(trust, &trustResult)
		if (Int(trustResult) == kSecTrustResultUnspecified ||
			Int(trustResult) == kSecTrustResultProceed) {
				// Trust certificate.
				let credential = NSURLCredential(forTrust: challenge.protectionSpace.serverTrust)
				challenge.sender.useCredential(credential, forAuthenticationChallenge: challenge)
		} else {
			NSLog("Invalid server certificate.")
	} else {
		NSLog("Got unexpected authentication method \(challenge.protectionSpace.authenticationMethod)");

Trusting multiple CA certificates

Since the SecTrustSetAnchorCertificates takes an array as input, this can be easily achieved with some Swift-functional-magic as below:

// ...  ...
// First load our extra root-CAs to be trusted from the app bundle.
let trust = challenge.protectionSpace.serverTrust
let rootCaFiles = ["zozsseca", "eitroot"]
let rootCaCerts = rootCaFiles.map() {
	(file: String) -> NSData? in
	let path = NSBundle.mainBundle().pathForResource(file, ofType: "der")
	return path != nil ? NSData(contentsOfFile: path!) : nil
}.filter({$0 != nil}).map() {
	SecCertificateCreateWithData(nil, $0!).takeRetainedValue()
// rootCaCerts now is an array of all (existent) root CAs. Tell iOS to trust them.
SecTrustSetAnchorCertificates(trust, rootCaCerts)
SecTrustSetAnchorCertificatesOnly(trust, 0) // Also allow default root-cert list.

var trustResult: SecTrustResultType = 0
SecTrustEvaluate(trust, &trustResult)
// ...  ...

If any of the root CA files could not be found, it will simply be ignored, and because of SecTrustSetAnchorCertificatesOnly the worst-case scenario of no readable custom root CAs, the default system list will be used.

Acquiring Kerberos ticket upon local login

So I recently setup a Kerberos server on my local network to use with a file server running NFSv4. The share is mounted upon boot using systemd and /etc/fstab. So far so good. However, because the NFS share is secured with sec=krb5, a Kerberos ticket is required to be able to actually access anything on the share.

However, it would be nice to actually acquire this ticket automatically upon logging in on my desktop computer, rather than having to run kinit manually.

As I use the same password for my local login as for my Kerberos principal, I felt that this should be possible. What I want is the following:

  • Upon login I enter my local UNIX password to authenticate myself. Thus I don’t want to use Kerberos authentication. This is because I still want to be able to login even if something happens to my Kerberos server. Accessing the file server is not critical, since I don’t have my home directory there anyway.
  • As I do the local login above, I want a Kerberos ticket, without having to enter my password twice. This should be possible, since I use the same password on my local computer and for my Kerberos principal.

pam_krb5 to the rescue!

This can be solved by using pam_krb5 [1]. I start by installing pam_krb5. Since I use Arch Linux, I install it from the AUR.

# yaourt -S pam_krb5

I then proceed to configure PAM to actually use the newly installed module. I want to use the module for local logins only, thus I modify /etc/pam.d/system-local-login to this:


auth      include   system-login
auth      optional  pam_krb5.so    minimum_uid=1000 use_first_pass
account   include   system-login
account   optional  pam_krb5.so
password  include   system-login
session   include   system-login
session   optional  pam_krb5.so
  • I set the control field to optional to avoid doing actual authorization with Kerberos. Thus, access control is still done locally with pam_unix.
  • I include the minimum_uid option to avoid contacting the Kerberos server on root logins (good if the Kerberos server is unresponsive).
  • I use use_first_pass to use the previously entered password for pam_unix for Kerberos authentication. If the passwords do not match, login proceeds anyway, but without a Kerberos ticket of course.


[1] http://www.eyrie.org/~eagle/software/pam-krb5/

ACR122U, mfcuk, and mfoc: Cracking MIFARE Classic on Arch Linux


I recently bought an ACR122U reader [1] to play around with RFID, and especially MIFARE Classic cards because of their low security [2,3,4,5] and widespread adoption.

The different sectors of the MIFARE Classic card are protected by different keys. To be able to decrypt the content of the card, the keys must be found. There are two well-known applications for this: mfcuk [6] and mfoc [7]. A typical attack scenario is to use mfcuk to find the first key of the card (which may take quite some time). When one key is found, mfoc can be used to find all other keys within minutes.

The problem

After installing libnfc [8], together with mfcuk and mfoc using AUR in Arch Linux, everything seemed to work. I launched an attack using mfcuk and got a key back after some time. The key was, however, incorrect. I assume that the bug described in [9] is the one causing trouble. The “fix” seems to be to use an older version of mfcuk. However, this will also require an older version of libnfc. This older version is, in turn, not compatible with mfoc.

Deep sigh.

So, let’s install duplicate copies of libnfc to get everything working.

Command-line frenzy

Note that # command means that the command should be executed as root, and that $ command should be executed as your own user. Also, take care to replace all instances of <user> with your own username.

I use yaourt to install packages from the AUR. You may use whatever tool you want.

mfcuk r65 and libnfc 1.5.1

A working combination of mfcuk and libnfc seems to be mfcuk r65 and libnfc 1.5.1. So let’s start by getting these, together with pcsclite and the PC/SC drivers for the ACR122U.

# pacman -S pcsclite
$ yaourt -S acsccid
$ mkdir -p ~/builds/nfc
$ cd ~/builds/nfc
$ wget https://libnfc.googlecode.com/files/libnfc-1.5.1.tar.gz
$ svn checkout -r 65 http://mfcuk.googlecode.com/svn/trunk/ mfcuk-r65
$ tar zxf libnfc-1.5.1.tar.gz

Now, let’s compile this older libnfc version and install it in a local directory to avoid messing up the system libraries.

$ cd libnfc-1.5.1
$ ./configure --prefix=/home/<user>/builds/nfc/prefix
$ make
$ make install
$ cd ..

Now, let’s compile mfcuk and make it use our newly compiled version of libnfc.

$ cd mfcuk-r65
$ autoreconf -is
$ LIBNFC_CFLAGS=-I/home/<user>/builds/nfc/prefix/include LIBNFC_LIBS="-L/home/<user>/builds/nfc/prefix/lib -lnfc" ./configure --prefix=/home/<user>/builds/nfc/prefix
$ make
$ make install
$ cd ..

Now lets continue to mfoc.

Note: You cannot use mfcuk just yet, because libnfc 1.7.1 needs to be installed to blacklist the kernel’s built-in drivers for the ACR122U, which will otherwise interfere with pcsclite.

mfoc 0.10.6 and libnfc 1.7.1

I will use the latest version of both libnfc and mfoc in the AUR, which (as of this writing) is 1.7.1 and 0.10.6.

$ yaourt -S libnfc mfoc


Cracking MIFARE Classic

To decrypt the contents of a MIFARE Classic card, we must first find the keys. This will be done in two steps.

Find the first key using mfcuk

Now, here is the tricky part. libnfc 1.5.1 must use pcsclite to be able to communicate with the reader, while newer versions of libnfc seem to prefer not to use pcsclite at all. Follow the instructions in the order written. If something goes wrong, unplug everything, remove the card, and try again from the beginning.

  1. Open a terminal window and run (as root): pcscd -f to start the pcsclite daemon in foreground.
  2. Connect your reader (without card)
  3. Put card on reader.
  4. Run mfcuk (as root) in a new window using the not-so-nice command-line:
    # LD_LIBRARY_PATH=/home/<user>/builds/nfc/prefix/lib /home/<user>/builds/nfc/prefix/bin/mfcuk -C -R 0:A -s 250 -S 250 -v 3

    This will start cracking the first key of the first sector. This may take some time (up to hours).

  5. When finished, the program will print something like (key censored as XXXXXXXXXXXX):
  6. INFO: block 3 recovered KEY: XXXXXXXXXXXX
     1 2 3 4 5 6 7 8 9 a b c d e f
    Sector	|    Key A	|ACTS | RESL	|    Key B	|ACTS | RESL
    0	|  XXXXXXXXXXXX	| . R | . R	|  000000000000	| . . | . .
    1	|  000000000000	| . . | . .	|  000000000000	| . . | . .
    2	|  000000000000	| . . | . .	|  000000000000	| . . | . .
    3	|  000000000000	| . . | . .	|  000000000000	| . . | . .
    4	|  000000000000	| . . | . .	|  000000000000	| . . | . .
    5	|  000000000000	| . . | . .	|  000000000000	| . . | . .
    6	|  000000000000	| . . | . .	|  000000000000	| . . | . .
    7	|  000000000000	| . . | . .	|  000000000000	| . . | . .
    8	|  000000000000	| . . | . .	|  000000000000	| . . | . .
    9	|  000000000000	| . . | . .	|  000000000000	| . . | . .
    10	|  000000000000	| . . | . .	|  000000000000	| . . | . .
    11	|  000000000000	| . . | . .	|  000000000000	| . . | . .
    12	|  000000000000	| . . | . .	|  000000000000	| . . | . .
    13	|  000000000000	| . . | . .	|  000000000000	| . . | . .
    14	|  000000000000	| . . | . .	|  000000000000	| . . | . .
    15	|  000000000000	| . . | . .	|  000000000000	| . . | . .
  7. Finally, kill the pcscd daemon with Ctrl-C.

This key can now be used together with mfoc to crack the remaining keys.

Find the remaining keys using mfoc

Since mfoc will use the newer version of libnfc, the command will be much simpler. Ensure that you have killed pcscd above before continuing. Replace XXXXXXXXXXXX with the key you got from mfcuk above.

# mfoc -O carddump.dmp -k XXXXXXXXXXXX

When finished, mfoc will dump the contents of your card both to the screen and to carddump.dmp.


[1] http://www.acs.com.hk/en/products/3/acr122u-usb-nfc-reader/
[2] https://www.usenix.org/legacy/events/sec08/tech/full_papers/nohl/nohl.pdf
[3] http://www.cs.ru.nl/~flaviog/publications/Attack.MIFARE.pdf
[4] http://www.cs.ru.nl/~flaviog/publications/Dismantling.Mifare.pdf
[5] http://www.cs.ru.nl/~flaviog/publications/Pickpocketing.Mifare.pdf
[6] https://code.google.com/p/mfcuk/
[7] https://code.google.com/p/mfoc/
[8] http://nfc-tools.org/index.php?title=Libnfc
[9] https://code.google.com/p/mfcuk/issues/detail?id=21

XenServer 6.2: Booting and installing from USB

Preparing the USB stick

The first step was to prepare a USB-stick with the XenServer 6.2 ISO downloaded from http://www.xenserver.org. Since my workstation runs Linux, I initially tried using dd, but my server refused to boot from the USB stick.

After trying virtually every guide on the Internet, I could finally put something together that worked.

On my home computer I run Arch Linux, some paths in the commands below might have to be adapted for your system (most probably the /usr/lib/syslinux/bios paths). Throughout the commands /dev/sdX is the USB stick. Make sure you choose the correct path!

First of all, to be able to transfer the ISO-image to the USB-stick it is important that the USB stick:

  1. Has a MBR partition table.
  2. Has a single FAT32 partition.
  3. Has the the boot-flag set on the first partition.

I fixed the requirements above using gparted.

First, let’s install syslinux on the USB stick.

# syslinux -i /dev/sdX1
# dd conv=notrunc bs=440 count=1 if=/usr/lib/syslinux/bios/mbr.bin of=/dev/sdX

Now, mount the USB stick’s partition, and also mount the XenServer 6.2 ISO.

# mount /dev/sdX1 /path/to/usb
# mount -o loop /path/to/XenServer-6.2.0-install-cd.iso /path/to/isomount

Copy all files from the XenServer ISO to the USB stick. Also rename the original CD/DVD-bootloaders config files such that syslinux can read them.

# cp -R /path/to/isomount/* /path/to/usb/
# cd /path/to/usb
# mv boot/isolinux boot/syslinux
# mv boot/syslinux/isolinux.cfg boot/syslinux/syslinux.cfg

Since the .c32-files on the XenServer ISO is made for ISOLinux, they have to be replaced by our own syslinux modules, otherwise the USB will not boot. I copied every possible .c32 file because I was lazy.

# cp /usr/lib/syslinux/bios/*.c32 boot/syslinux/

After unmounting the drive, the stick could finally be used to boot the XenServer installation.

TP-Link TL-WN725N in Arch Linux ARM

EDIT 2013-11-24: As of kernel 3.12, the driver has been included in the staging area of the Linux kernel [1]. Upgrading your kernel to get the included driver may be easier than compiling your own kernel module.

[1] http://kernelnewbies.org/Linux_3.12-DriversArch#head-535f1b62f845d5e0d9d20c2980ab6b35525f67c5

So I recently bought a TP-Link TL-WN725N wireless adapter to use together with my Raspberry Pi. The main reason to buy this particular model was that it should work out of the box together with the Linux kernel in Raspberry Pi.

It did not.

As it turns out, I have got the second version of the wireless dongle, which featured another chip – RTL8188EU. This chip does require another kernel module to be compiled and loaded into the kernel. Compiling kernel modules isn’t exactly my favourite way to spend my free time, so I looked desperately for some pre-compiled versions, but did not find any. Tough luck, eh?

Anyhow, here are the steps to produce a working kernel module for the dongle:

  1. First install the kernel headers, which will be required later on.
    # pacman -S linux-headers-raspberrypi
  2. Then clone the git repo with source code for the rtl8188eu chip.
    $ git clone https://github.com/lwfinger/rtl8188eu
  3. For me the module worked very unreliable (80 % packet loss) when power saving was enabled, so I disabled it before compiling. Go into the cloned git repo and open the Makefile.
    $ cd rtl8188eu
    $ vim Makefile
  4. Change the following line. Last time I cloned the repo it was at line 22, your mileage may vary.


  5. Finally the code is ready to be compiled! This will compile the code as a kernel module for the currently running kernel. It assumes the kernel headers are installed as described in the first step!
    $ CONFIG_RTL8188EU=m make -C /usr/src/linux-`uname -r` M=`pwd`
  6. Finally the kernel module can be copied into the kernel module directory and be loaded into the kernel.
    # install -p -m 644 8188eu.ko /lib/modules/`uname -r`/kernel/drivers/net/wireless/
    # depmod -a
    # modprobe 8188eu

Good luck!