Extending and Customizing Kali

10.3. Extending and Customizing Kali Linux

Sometimes you need to modify Kali Linux to make it fit your local needs. The best way to achieve this is to maintain your own package repository hosting the modified versions of the Kali packages that you had to fork, as well as supplementary packages providing custom configuration and extra software (not provided by Kali Linux).

10.3.1. Forking Kali Packages

Please refer to Section 9.1, "Modifying Kali Packages" for explanations about this topic.

All packages can be forked if you have a good reason but you must be aware that forking a package has a cost, since you have to update it every time that Kali publishes an update. Here are some reasons why you might want to fork a package:

  • To add a patch to fix a bug or add a new feature. Although in most cases, you will want to submit that patch to the upstream developers so that the bug is fixed or the feature is added at the source.
  • To compile it with different options (assuming that there are good reasons why Kali did not compile it with those options; otherwise it might be best to discuss this with Kali developers to see if they can enable the desired options).

By contrast, here are some bad reasons to fork a package along with suggestions of how to handle your problem:

  • To modify a configuration file. You have multiple, better options like using configuration management to automatically install a modified configuration file or installing a configuration package that will put a file in a configuration directory (when available) or that will divert the original configuration file.
  • To update to a newer upstream version. Again, it is better to work with developers to update the package directly in Debian or Kali. With the rolling release model, updates are rather quick to reach end users.

Among all the available packages, there are some that are building blocks of Kali Linux and that could be interesting to fork in some situations:

  • kali-meta: this source package builds all the kali-linux-* meta packages and notably kali-linux-full, which defines what packages are installed in the default Kali Linux ISO image.
  • desktop-base: This source package contains various miscellaneous files that are used by default in desktop installations. Consider forking this package if you would like to show your organization's brand in the default background or change the theme of the desktop.
  • kali-menu: this package defines the structure of the Kali menu and provides .desktop files for all applications that should be listed in the Kali menu.

10.3.2. Creating Configuration Packages

Now that we have touched on PXE booting and discussed configuration management with SaltStack as well as package forking, it is time to wrap these processes up into a practical example and extend the scenario by creating a custom configuration package to deploy a custom configuration to multiple machines semi-automatically.

In this example, you will create a custom package that sets up and utilizes your own package repository and GnuPG signing key, distributes a SaltStack configuration, pushes a custom background, and provides default desktop settings in a unified way to all your Kali installations.

This may seem like a daunting task (especially if you glance through the Debian New Maintainer Guide) but fortunately for us, a configuration package is mainly a sophisticated file archive and turning it into a package is rather easy.

Looking into a Sample Package

If you want to look into a real package that is basically a configuration package, consider the kali-defaults package. It is not as simple as the sample in this section but it has all the relevant characteristics and even uses some advanced techniques (like dpkg-divert) to replace files already provided by other packages.

The offsec-defaults package will contain a few files:

  • /etc/apt/sources.list.d/offsec.list: a sources.list entry for APT, enabling the company's internal package repository
  • /etc/apt/trusted.gpg.d/offsec.gpg: the GnuPG key used to sign the company's internal package repository
  • /etc/salt/minion.d/offsec.conf: a SaltStack configuration file to indicate where to find the Salt master
  • /usr/share/images/offsec/background.png: a nice background image with the Offensive Security logo
  • /usr/share/glib-2.0/schemas/90_offsec-defaults.gschema.override: a file providing alternate default settings for the GNOME desktop

First, create an offsec-defaults-1.0 directory and put all the files in that directory. Then run dh_make --native (from the dh-make package) to add Debian packaging instructions, which will be stored in a debiansub-directory:

First, you are prompted for a package type. In the example, we selected indep, which indicates that this source package will generate a single binary package that can be shared across all architectures (Architecture: all). single acts as a counterpart, and produces a single binary package that is dependent on the target architecture (Architecture: any). In this case, indep is more relevant, since the package only contains text files and no binary programs, so that it can be used similarly on computers of all architectures. The library type is useful for shared libraries, since they need to follow strict packaging rules. In a similar fashion, python should be restricted to Python modules.

Maintainer's Name and Email Address

Most of the programs involved in package maintenance will look for your name and email address in the DEBFULLNAMEand DEBEMAIL or EMAIL environment variables. Defining them, once and for all, prevents re-typing them multiple times. If your usual shell is Bash, it is a simple matter of adding the following two lines in your ~/.bashrc file. For example:

The dh_make command created a debian subdirectory containing many files. Some are required, in particular rules, control, changelog, and copyright. Files with the .ex extension are example files that can be used by modifying them and removing the extension. When they are not needed, we recommend removing them. The compat file should be kept, since it is required for the correct functioning of the debhelper suite of programs (all beginning with the dh_ prefix) used at various stages of the package build process.

The copyright file must contain information about the authors of the documents included in the package, and the related license. If the default license selected by dh_make does not suit you, then you must edit this file. Here is the modified version of the copyright file:

The default changelog file is generally appropriate; replacing the "Initial release" with a more verbose explanation should be enough:

In the example, we will make changes to the control file. We will change the Section field to misc and remove the Homepage, Vcs-Git, and Vcs-Browser fields. Lastly, we will fill in the Description field:

The rules file usually contains a set of rules used to configure, build, and install the software in a dedicated subdirectory (named after the generated binary package). The contents of this subdirectory are then archived within the Debian package as if it were the root of the filesystem. In this case, files will be installed in the debian/offsec-defaults/ subdirectory. For example, to end up with a package installing /etc/apt/sources.list.d/offsec.list, install the file in debian/offsec-defaults/etc/apt/sources.list.d/offsec.list. The rules file is used as a Makefile, with a few standard targets (including clean and binary, used respectively to clean the source directory and generate the binary package).

What is a Makefile file?

You may have noticed the message concerning the missing Makefile at the end of the dh_make output and the mention of its similarity to the rules file. A Makefile is a script file used by the make program; it describes rules for how to build a set of files from each other in a tree of dependencies. For instance, a program can be built from a set of source files. The Makefile file describes these rules in the following format:

The interpretation of such a rule is as follows: if one of the source* files is more recent than the target file, then the target needs to be generated, using command1 and command2.

Note that the command lines must start with a tab character; also note that when a command line starts with a dash character (-), failure of the command does not interrupt the whole process.

Although this file is the heart of the process, it contains only the bare minimum for running a standard set of commands provided by the debhelper tool. Such is the case for files generated by dh_make. To install most of your files, we recommend configuring the behaviour of the dh_install command by creating the following debian/offsec-defaults.install file:

You could also use this to install the gsettings override file but debhelper provides a dedicated tool for this (dh_installgsettings) so you can rely on it. First, put your settings in debian/offsec-defaults.gsettings-override:

Next, override the dh_installgsettings call in debian/rules to increase the priority to the level expected for an organization override (which is 90 according to the manual page):

At this point, the source package is ready. All that is left to do is to generate the binary package with the same method used previously for rebuilding packages: run the dpkg-buildpackage -us -uc command from within the offsec-defaults-1.0 directory:

10.3.3. Creating a Package Repository for APT

Now that you have a custom package, you can distribute it through an APT package repository. Use reprepro to create the desired repository and to fill it. This tool is rather powerful and its manual page is certainly worth reading.

A package repository is typically hosted on a server. To properly separate it from other services running on the server, it is best to create a user dedicated to this service. In the dedicated user account, you will be able to host the repository files and also the GnuPG key that will be used to sign the package repository:

Note that when you are prompted for a passphrase, you should enter an empty value (and confirm that you don't want to protect your private key) as you want to be able to sign the repository non-interactively. Note also that gpg requires write access to the terminal to be able to securely prompt for a passphrase: that is why you changed the ownership of the virtual terminal (which is owned by root since you initially connected as that user) before starting a shell as pkgrepo.

Now you can start setting up the repository. A dedicated directory is necessary for reprepro and inside that directory you have to create a conf/distributions file documenting which distributions are available in the package repository:

The required fields are Codename, which gives the name of the distribution, Architectures, which indicates which architectures will be available in the distribution (and accepted on the input side), and Components, which indicates the various components available in the distribution (components are a sort of sub-section of the distribution, which can be enabled separately in APT's sources.list). The Origin and Description fields are purely informative and they are copied as-is in the Release file. The SignWith field asks reprepro to sign the repository with the GnuPG key whose identifier is listed (put the full fingerprint here to ensure you use the correct key, and not another one colliding on the short identifier). The AlsoAcceptFor setting is not required but makes it possible to process .changes files whose Distribution field has a value listed here (without this, it would only accept the distribution's codename in that field).

With this basic setup in place, you can let reprepro generate an empty repository:

As you can see, reprepro created the repository meta-information in a dists sub-directory. It also initialized an internal database in a db sub-directory.

It is now time to add your first package. First, copy the files generated by the build of the offsec-defaultspackage (offsec-defaults_1.0.dsc, offsec-defaults_1.0.tar.xz, offsec-defaults_1.0_all.deb, and offsec-defaults_1.0_amd64.changes) into /tmp on the server hosting the package repository and ask reprepro to include the package:

As you can see, it added the files into its own package pool in a pool sub-directory.

The dists and pool directories are the two directories that you need to make (publicly) available over HTTP to finish the setup of your APT repository. They contain all the files that APT will want to download.

Assuming that you want to host this on a virtual host named pkgrepo.offsec.com, you could create the following Apache configuration file, save it to /etc/apache2/sites-available/pkgrepo.offsec.com.conf, and enable it with a2ensite pkgrepo.offsec.com):

And the corresponding sources.list entry to add on machines that need packages from this repository would look like this:

Your package is now published and should be available to your networked hosts.

Although this has been a lengthy setup, the "heavy lifting" is now completed. You can boot your networked machines via PXE, install a customized version of Kali Linux without interaction thanks to a network-delivered preseed, configure SaltStack to manage your configurations (and control minions!), create forked custom packages, and distribute those packages through your own package repository. This provides centralized management and enterprise-level control over multiple Kali Linux installations. In short, you can now quickly deploy highly secure Kali systems preconfigured for your specific needs and keep them synchronized thanks to Kali's (semi-automatic) installation of all package updates.