Post

Apache Explained

Apache Explained

So recently, an Intern at our company asked me several question about Apache web server and SSL certificates. I decided to do a blog post on the same and hopefully you’ll also get to learn a thing or two. With that said, let me breakdown what this blog post entails.

  • Installing Apache WebServer
  • Apache Logs
  • Creating SSL Certificates
  • Securing your webserver

Installing Apache WebServer

In this walkthrough, i will be using a clean install of Ubuntu 20.04 LTS. By default, the Apache web root or Document root folder location is at /var/www/html. On a clean server however, we dont have the /www/html directories.

image

To install Apache webserver, simply run:

sudo apt install apache2

With that done, we need to start the service.

image

If we now load the server’s ip on the browser, we should get the default It Works! page.

image

I know many of you dont read this page.😅

i see you

I see you. But this page contains some good information related to the web server. Such information includes:

  • The configuration layout for an Apache2 web server installation
  • Explanation on different config files and binaries.

Don’t worry, i’ll walk you through them.

Apache Configuration Layout

Before we get into the flesh, lets do a few network configurations. We need to assign a static ip for our webserver.

Since this server uses netplan as its default network management tool, we can get the configuration file in /etc/netplan. Before we make any changes to the config file, you need to make a backup copy of the same incase you need to revert back to its original state. You can then use a text editor of your choice to edit the file. In our case, we will assign the server an IP of 192.168.1.50 as shown in the snippet below.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
dev@dev:/etc$ cd netplan/
dev@dev:/etc/netplan$ ls -la
total 12
drwxr-xr-x   2 root root 4096 Apr 23 13:00 .
drwxr-xr-x 100 root root 4096 Apr 23 13:46 ..
-rw-r--r--   1 root root  116 Apr 23 13:00 00-installer-config.yaml
dev@dev:/etc/netplan$ sudo cp 00-installer-config.yaml 00-installer-config.yaml.bak
[sudo] password for dev:
dev@dev:/etc/netplan$ cat 00-installer-config.yaml
# This is the network config written by 'subiquity'
network:
  ethernets:
    ens33:
      dhcp4: true
  version: 2

Modify the configuration file to resemble the one below:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
dev@dev:/etc/netplan$ sudo vi 00-installer-config.yaml
dev@dev:/etc/netplan$ cat 00-installer-config.yaml
# This is the network config written by 'subiquity'
network:
  version: 2
  renderer: networkd
  ethernets:
    ens33:
      dhcp4: no
      addresses:
        - 192.168.1.50/24
      gateway4: 192.168.1.1
      nameservers:
          addresses: [8.8.8.8, 1.1.1.1]
dev@dev:/etc/netplan$ sudo netplan apply

After saving changes, run the sudo netplan apply command for changes to apply.

NB:For a few seconds, you will be disconnected from your session and required to ssh back in using the set IP

image

For practice purposes, lets also modify our hostname to theoffice.com

1
2
3
4
5
6
7
8
dev@dev:~$ cat /etc/hostname
dev
dev@dev:~$ sudo vi /etc/hostname
[sudo] password for dev:
dev@dev:~$ cat /etc/hostname
theoffice.com
dev@dev:~$ reboot

After the reboot, our server will now be recognized across the network as theoffice.com. We can confirm changes took place by running the command below:

1
2
3
dev@theoffice:~$ hostname
theoffice.com
dev@theoffice:~$

We also need to make some changes on the hosts file as highlighted below:

image

Since the ubuntu server doesnt have a UI, we need to map that domain on my windows hosts file in order to resolve the site. The hosts file in windows is located in C:\Windows\System32\drivers\etc.

image

If we save the changes and visit the domain, it works.

image

With that done, we’re going to leave the default Apache virtual host configuration pointing to theoffice.com and set up a subdomain called pass.theoffice.com

We start by creating a directory in /var/www/ called pass. I’m just gonna clone a random password generator project from github that we can quickly host on this VHOST.

1
2
3
4
dev@theoffice:~$ cd /var/www/
dev@theoffice:/var/www$ sudo mkdir pass
[sudo] password for dev:
dev@theoffice:/var/www$ cd pass/

Transfer the files required to that directory

1
2
3
4
5
6
7
8
9
dev@theoffice:/var/www/pass$ ls -la
total 28
drwxr-xr-x 5 root root 4096 Apr 23 15:35 .
drwxr-xr-x 4 root root 4096 Apr 23 15:33 ..
drwxr-xr-x 2 root root 4096 Apr 23 15:34 css
drwxr-xr-x 2 root root 4096 Apr 23 15:34 images
-rw-r--r-- 1 root root 3693 Apr 23 15:34 index.html
drwxr-xr-x 2 root root 4096 Apr 23 15:34 js
-rw-r--r-- 1 root root  205 Apr 23 15:34 README.md

By default, as seen earlier, apache comes with its default site which can be found in the /var/www/html directory and its configuration files can be found in /etc/apache2/sites-enabled/000-default.conf

But before we look at the configuration file, i feel like its important first to understand the /etc/apache2/ directory structure.

image

sites-available and sites-enabled are directories used for managing virtual hosts.

  • The sites-available directory contains configuration files for all the available virtual hosts on the server. These configuration files define the settings for each virtual host, such as the domain name, document root, and any other directives required to serve the site.
  • The sites-enabled directory contains symbolic links to the configuration files of the virtual hosts that are currently enabled on the server. These symbolic links are created to activate a particular virtual host. Enabling a site simply means creating a symbolic link from the configuration file in the sites-available directory to the sites-enabled directory.

We then need to create a VirtualHost file for our VHOST. To do this, we can navigate to /etc/apache2/sites-available/. Since Apache came with a default VirtualHost file, let’s use that as our base config file and create a replica which we can modify.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
dev@theoffice:/var/www/pass$ cd /etc/apache2/sites-available/
dev@theoffice:/etc/apache2/sites-available$ ls -la
total 20
drwxr-xr-x 2 root root 4096 Apr 23 13:46 .
drwxr-xr-x 8 root root 4096 Apr 23 13:46 ..
-rw-r--r-- 1 root root 1332 Feb 23  2021 000-default.conf
-rw-r--r-- 1 root root 6338 Feb 23  2021 default-ssl.conf
dev@theoffice:/etc/apache2/sites-available$ sudo cp 000-default.conf pass.conf
dev@theoffice:/etc/apache2/sites-available$ ls -la
total 24
drwxr-xr-x 2 root root 4096 Apr 23 15:52 .
drwxr-xr-x 8 root root 4096 Apr 23 13:46 ..
-rw-r--r-- 1 root root 1332 Feb 23  2021 000-default.conf
-rw-r--r-- 1 root root 6338 Feb 23  2021 default-ssl.conf
-rw-r--r-- 1 root root 1332 Apr 23 15:52 pass.conf

I named my config file pass.conf to match our VHOST name.

By default, the config file looks like this:

image

Here, we want the DocumentRoot directive to point to the directory our site files are hosted on.

The default file doesn’t come with a ServerName directive so we’ll have to add and define it by adding this line below the DocumentRoot

image

Since our files are already on the directory, we need to activate the virtual hosts configuration file to enable it. We do that by running the following command in the configuration file directory:

1
2
3
4
5
dev@theoffice:/etc/apache2/sites-available$ sudo a2ensite pass.conf
Enabling site pass.
To activate the new configuration, you need to run:
  systemctl reload apache2
dev@theoffice:/etc/apache2/sites-available$ sudo systemctl reload apache2

To load the new site, you need to restart the webserver.

a2ensite is a script that enables the specified site (which contains a < VirtualHost > block) within the apache2 configuration. It does this by creating symlinks within /etc/apache2/sites-enabled.

While at it

a2dis-site disables a site by removing those symlinks. It is not an error to enable a site which is already enabled, or to disable one which is already disabled.

If we now navigate to pass.theoffice.com on our browser, we should be able to access our website.

image

Creating SSL certificate

We can create a self-signed SSL/TLS certificate in Linux using the OpenSSL command line tool. Here are the steps to create a self-signed certificate:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
root@theoffice:/home/dev# openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -sha256 -days 3650
Generating a RSA private key
....++++
......................................................................................................................................................................................................................................................................................................................................................................++++
writing new private key to 'key.pem'
Enter PEM pass phrase:
Verifying - Enter PEM pass phrase:
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:KE
State or Province Name (full name) [Some-State]:Nairobi
Locality Name (eg, city) []:Nairobi
Organization Name (eg, company) [Internet Widgits Pty Ltd]:The Office
Organizational Unit Name (eg, section) []:dev
Common Name (e.g. server FQDN or YOUR name) []:theoffice.com
Email Address []:dev@theoffice.com

A short explanation of the command above:

  • -x509: This option generates a self-signed certificate.
  • -newkey rsa:4096 : This option generates a new RSA 4096-bit key for the certificate.
  • -keyout key.pem: This option specifies the filename for the private key.
  • -out cert.pem: This option specifies the filename for the certificate.
  • -sha256: This option specifies the hash algorithm to use for the certificate.
  • -days 3650: This option sets the expiration date for the certificate to 10 years (3650 days) from the current date.

A common location to store SSL/TLS certificates in Apache is /etc/ssl/certs, while the corresponding private keys are typically stored in /etc/ssl/private.

1
2
root@theoffice:/etc/apache2/sites-available# cp /home/dev/key.pem /etc/ssl/private
root@theoffice:/etc/apache2/sites-available# cp /home/dev/cert.pem /etc/ssl/cert

We also need to modify our VHOST configuration file again to reference the certificate files Inside the VirtualHost block as shown below:

image

Apache has a tool called apachectl that we can use to test if our configuration has correct syntax and directives. In my case, i got an error regarding SSLEngine.

1
2
3
4
5
root@theoffice:/etc/apache2/sites-available# apachectl -t
AH00526: Syntax error on line 14 of /etc/apache2/sites-enabled/pass.conf:
Invalid command 'SSLEngine', perhaps misspelled or defined by a module not included in the server configuration
Action '-t' failed.
The Apache error log may have more information.

A quick google search, i learn that this is caused by the fact that the server’s basic configuration does not have mod_ssl module installed/enabled which is responsible for creating and serving SSL connections.

A quick fix for this is simply running sudo a2enmod ssl as shown:

1
2
3
4
5
6
7
8
9
10
11
12
root@theoffice:/etc/apache2/sites-available# a2enmod ssl
Considering dependency setenvif for ssl:
Module setenvif already enabled
Considering dependency mime for ssl:
Module mime already enabled
Considering dependency socache_shmcb for ssl:
Enabling module socache_shmcb.
Enabling module ssl.
See /usr/share/doc/apache2/README.Debian.gz on how to configure SSL and create self-signed certificates.
To activate the new configuration, you need to run:
  systemctl restart apache2
root@theoffice:/etc/apache2/sites-available#

This should fix the problem. If we now test our configuration file, we should get a Syntax OK

1
2
3
root@theoffice:/etc/apache2/sites-available# apachectl -t
Syntax OK
root@theoffice:/etc/apache2/sites-available# 

Now lets restart apache. This time, we’ll be prompted to enter a passphrase for SSL/TLS keys

1
2
root@theoffice:/etc/apache2/sites-available# systemctl restart apache2
Enter passphrase for SSL/TLS keys for pass.theoffice.com:443 (RSA): *********

We are now able to visit our VHOST over https. 😎

image

Now that we are deploying certs, why dont we do it with Security in mind.😎

With help from the following resources, i was able to add the following entries outside the < VirtualHost> block.

image

In a nutshell, i’ll try explain what each of the above entries mean.

  • SSLProtocol all -SSLv3 -TLSv1 -TLSv1.1 - SSL 3.0 and TLS 1.0 are susceptible to known attacks on the protocol; they are disabled entirely. Disabling TLS 1.1 is (as of August 2016) mostly optional; TLS 1.2 provides stronger encryption options, but 1.1 is not yet known to be broken. Disabling 1.1 may mitigate attacks against some broken TLS implementations.
  • Enabling SSLHonorCipherOrder ensures that the server’s cipher preferences are followed instead of the client’s.
  • Disabling SSLSessionTickets ensures Perfect Forward Secrecy is not compromised if the server is not restarted regularly.
  • Disabling SSLCompression prevents TLS compression oracle attacks (e.g. CRIME).
  • SSLUseStapling On - Enabling OCSP Stapling improves performance by providing the clients with up-to-date status of your certificate.
  • SSLStaplingCache "shmcb:logs/ssl_stapling(32768)" - Specifies the OCSP cache response location and size.
  • SSLCipherSuite HIGH:!SSLv2:!RC4:!aNULL@STRENGTH - The SSLCipherSuite directive is used in the Apache configuration file to specify the list of SSL/TLS cipher suites that are allowed for SSL/TLS connections.
    • !RC4 - Specifies not to use any RC4 suites.
    • HIGH - Specifies that only cipher suites using strong encryption should be allowed. The HIGH value is a shorthand for a list of cipher suites that use AES, Camellia, and other strong encryption algorithms.
    • !aNULL - This specifies that cipher suites that allow null authentication (i.e., no authentication of the server or client) should not be used.
    • !SSLv2 - This specifies that SSLv2 should not be used, as it is an insecure protocol that is susceptible to a number of vulnerabilities.
    • @STRENGTH: This specifies that cipher suites should be listed in order of strength, with the strongest cipher suites listed first.

In order to test our ssl

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
➜  sslscan https://pass.theoffice.com                          
Version: 2.0.15-static
OpenSSL 1.1.1q-dev  xx XXX xxxx

Connected to 192.168.1.50

Testing SSL server pass.theoffice.com on port 443 using SNI name pass.theoffice.com

  SSL/TLS Protocols:
SSLv2     disabled
SSLv3     disabled
TLSv1.0   disabled
TLSv1.1   disabled
TLSv1.2   enabled
TLSv1.3   enabled

  TLS Fallback SCSV:
Server supports TLS Fallback SCSV

  TLS renegotiation:
Session renegotiation not supported

  TLS Compression:
Compression disabled

  Heartbleed:
TLSv1.3 not vulnerable to heartbleed
TLSv1.2 not vulnerable to heartbleed

  Supported Server Cipher(s):
Preferred TLSv1.3  256 bits  TLS_AES_256_GCM_SHA384        Curve 25519 DHE 253
Accepted  TLSv1.3  256 bits  TLS_CHACHA20_POLY1305_SHA256  Curve 25519 DHE 253
Accepted  TLSv1.3  128 bits  TLS_AES_128_GCM_SHA256        Curve 25519 DHE 253
Preferred TLSv1.2  256 bits  ECDHE-RSA-AES256-GCM-SHA384   Curve 25519 DHE 253
Accepted  TLSv1.2  256 bits  DHE-RSA-AES256-GCM-SHA384     DHE 4096 bits
Accepted  TLSv1.2  256 bits  ECDHE-RSA-CHACHA20-POLY1305   Curve 25519 DHE 253
Accepted  TLSv1.2  256 bits  DHE-RSA-CHACHA20-POLY1305     DHE 4096 bits
Accepted  TLSv1.2  256 bits  DHE-RSA-AES256-CCM8           DHE 4096 bits
Accepted  TLSv1.2  256 bits  DHE-RSA-AES256-CCM            DHE 4096 bits
Accepted  TLSv1.2  256 bits  ECDHE-ARIA256-GCM-SHA384      Curve 25519 DHE 253
Accepted  TLSv1.2  256 bits  DHE-RSA-ARIA256-GCM-SHA384    DHE 4096 bits
Accepted  TLSv1.2  256 bits  ECDHE-RSA-AES256-SHA384       Curve 25519 DHE 253
Accepted  TLSv1.2  256 bits  DHE-RSA-AES256-SHA256         DHE 4096 bits
Accepted  TLSv1.2  256 bits  ECDHE-RSA-CAMELLIA256-SHA384  Curve 25519 DHE 253
Accepted  TLSv1.2  256 bits  DHE-RSA-CAMELLIA256-SHA256    DHE 4096 bits
Accepted  TLSv1.2  256 bits  ECDHE-RSA-AES256-SHA          Curve 25519 DHE 253
Accepted  TLSv1.2  256 bits  DHE-RSA-AES256-SHA            DHE 4096 bits
Accepted  TLSv1.2  256 bits  DHE-RSA-CAMELLIA256-SHA       DHE 4096 bits
Accepted  TLSv1.2  256 bits  AES256-GCM-SHA384            
Accepted  TLSv1.2  256 bits  AES256-CCM8                  
Accepted  TLSv1.2  256 bits  AES256-CCM                   
Accepted  TLSv1.2  256 bits  ARIA256-GCM-SHA384           
Accepted  TLSv1.2  256 bits  AES256-SHA256                
Accepted  TLSv1.2  256 bits  CAMELLIA256-SHA256           
Accepted  TLSv1.2  256 bits  AES256-SHA                   
Accepted  TLSv1.2  256 bits  CAMELLIA256-SHA              
Accepted  TLSv1.2  128 bits  ECDHE-RSA-AES128-GCM-SHA256   Curve 25519 DHE 253
Accepted  TLSv1.2  128 bits  DHE-RSA-AES128-GCM-SHA256     DHE 4096 bits
Accepted  TLSv1.2  128 bits  DHE-RSA-AES128-CCM8           DHE 4096 bits
Accepted  TLSv1.2  128 bits  DHE-RSA-AES128-CCM            DHE 4096 bits
Accepted  TLSv1.2  128 bits  ECDHE-ARIA128-GCM-SHA256      Curve 25519 DHE 253
Accepted  TLSv1.2  128 bits  DHE-RSA-ARIA128-GCM-SHA256    DHE 4096 bits
Accepted  TLSv1.2  128 bits  ECDHE-RSA-AES128-SHA256       Curve 25519 DHE 253
Accepted  TLSv1.2  128 bits  DHE-RSA-AES128-SHA256         DHE 4096 bits
Accepted  TLSv1.2  128 bits  ECDHE-RSA-CAMELLIA128-SHA256  Curve 25519 DHE 253
Accepted  TLSv1.2  128 bits  DHE-RSA-CAMELLIA128-SHA256    DHE 4096 bits
Accepted  TLSv1.2  128 bits  ECDHE-RSA-AES128-SHA          Curve 25519 DHE 253
Accepted  TLSv1.2  128 bits  DHE-RSA-AES128-SHA            DHE 4096 bits
Accepted  TLSv1.2  128 bits  DHE-RSA-CAMELLIA128-SHA       DHE 4096 bits
Accepted  TLSv1.2  128 bits  AES128-GCM-SHA256            
Accepted  TLSv1.2  128 bits  AES128-CCM8                  
Accepted  TLSv1.2  128 bits  AES128-CCM                   
Accepted  TLSv1.2  128 bits  ARIA128-GCM-SHA256           
Accepted  TLSv1.2  128 bits  AES128-SHA256                
Accepted  TLSv1.2  128 bits  CAMELLIA128-SHA256           
Accepted  TLSv1.2  128 bits  AES128-SHA                   
Accepted  TLSv1.2  128 bits  CAMELLIA128-SHA              

  Server Key Exchange Group(s):
TLSv1.3  128 bits  secp256r1 (NIST P-256)
TLSv1.3  192 bits  secp384r1 (NIST P-384)
TLSv1.3  260 bits  secp521r1 (NIST P-521)
TLSv1.3  128 bits  x25519
TLSv1.3  224 bits  x448
TLSv1.2  128 bits  secp256r1 (NIST P-256)
TLSv1.2  192 bits  secp384r1 (NIST P-384)
TLSv1.2  260 bits  secp521r1 (NIST P-521)
TLSv1.2  128 bits  x25519
TLSv1.2  224 bits  x448

  SSL Certificate:
Signature Algorithm: sha256WithRSAEncryption
RSA Key Strength:    4096

Subject:  theoffice.com
Issuer:   theoffice.com

Not valid before: Apr 23 16:55:12 2023 GMT
Not valid after:  Apr 20 16:55:12 2033 GMT

We can also use nmap

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
nmap -p 443 --script ssl-cert,ssl-enum-ciphers pass.theoffice.com
Nmap scan report for pass.theoffice.com (192.168.1.50)

Host is up (0.00088s latency).

rDNS record for 192.168.1.50: theoffice.com

PORT    STATE SERVICE

443/tcp open  https
| ssl-cert: Subject: commonName=theoffice.com/organizationName=The Office/stateOrProvinceName=Nairobi/countryName=KE
| Issuer: commonName=theoffice.com/organizationName=The Office/stateOrProvinceName=Nairobi/countryName=KE
| Public Key type: rsa
| Public Key bits: 4096
| Signature Algorithm: sha256WithRSAEncryption
| Not valid before: 2023-04-23T16:55:12
| Not valid after:  2033-04-20T16:55:12
| MD5:   93c1442a5091523bb2c2131f60cd49e5
|_SHA-1: 340755f163d86343b23ea3d4ca28e1f81495931a

| ssl-enum-ciphers: 
|   TLSv1.2: 
|     ciphers: 
|       TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (ecdh_x25519) - A
|       TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 (dh 4096) - A
|       TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 (ecdh_x25519) - A
|       TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256 (dh 4096) - A
|       TLS_DHE_RSA_WITH_AES_256_CCM_8 (dh 4096) - A
|       TLS_DHE_RSA_WITH_AES_256_CCM (dh 4096) - A
|       TLS_ECDHE_RSA_WITH_ARIA_256_GCM_SHA384 (ecdh_x25519) - A
|       TLS_DHE_RSA_WITH_ARIA_256_GCM_SHA384 (dh 4096) - A
|       TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 (ecdh_x25519) - A
|       TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 (dh 4096) - A
|       TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384 (ecdh_x25519) - A
|       TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 (dh 4096) - A
|       TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA (ecdh_x25519) - A
|       TLS_DHE_RSA_WITH_AES_256_CBC_SHA (dh 4096) - A
|       TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA (dh 4096) - A
|       TLS_RSA_WITH_AES_256_GCM_SHA384 (rsa 4096) - A
|       TLS_RSA_WITH_AES_256_CCM_8 (rsa 4096) - A
|       TLS_RSA_WITH_AES_256_CCM (rsa 4096) - A
|       TLS_RSA_WITH_ARIA_256_GCM_SHA384 (rsa 4096) - A
|       TLS_RSA_WITH_AES_256_CBC_SHA256 (rsa 4096) - A
|       TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256 (rsa 4096) - A
|       TLS_RSA_WITH_AES_256_CBC_SHA (rsa 4096) - A
|       TLS_RSA_WITH_CAMELLIA_256_CBC_SHA (rsa 4096) - A
|       TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (ecdh_x25519) - A
|       TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 (dh 4096) - A
|       TLS_DHE_RSA_WITH_AES_128_CCM_8 (dh 4096) - A
|       TLS_DHE_RSA_WITH_AES_128_CCM (dh 4096) - A
|       TLS_ECDHE_RSA_WITH_ARIA_128_GCM_SHA256 (ecdh_x25519) - A
|       TLS_DHE_RSA_WITH_ARIA_128_GCM_SHA256 (dh 4096) - A
|       TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 (ecdh_x25519) - A
|       TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 (dh 4096) - A
|       TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 (ecdh_x25519) - A
|       TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 (dh 4096) - A
|       TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA (ecdh_x25519) - A
|       TLS_DHE_RSA_WITH_AES_128_CBC_SHA (dh 4096) - A
|       TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA (dh 4096) - A
|       TLS_RSA_WITH_AES_128_GCM_SHA256 (rsa 4096) - A
|       TLS_RSA_WITH_AES_128_CCM_8 (rsa 4096) - A
|       TLS_RSA_WITH_AES_128_CCM (rsa 4096) - A
|       TLS_RSA_WITH_ARIA_128_GCM_SHA256 (rsa 4096) - A
|       TLS_RSA_WITH_AES_128_CBC_SHA256 (rsa 4096) - A
|       TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256 (rsa 4096) - A
|       TLS_RSA_WITH_AES_128_CBC_SHA (rsa 4096) - A
|       TLS_RSA_WITH_CAMELLIA_128_CBC_SHA (rsa 4096) - A
|     compressors: 
|       NULL
|     cipher preference: server
|   TLSv1.3: 
|     ciphers: 
|       TLS_AKE_WITH_AES_256_GCM_SHA384 (ecdh_x25519) - A
|       TLS_AKE_WITH_CHACHA20_POLY1305_SHA256 (ecdh_x25519) - A
|       TLS_AKE_WITH_AES_128_GCM_SHA256 (ecdh_x25519) - A
|     cipher preference: server
|_  least strength: A

MAC Address: 00:0C:29:28:C3:2B (VMware)



Nmap done: 1 IP address (1 host up) scanned in 2.84 seconds

Security Headers

‘HTTP Security Response Headers’ allow a server to push additional security information to web browsers and govern how the web browsers and visitors are able to interact with your web application.

Having the appropriate Security Header Response policies in place adds another level of protection that can stop common attacks such as code injection, cross-site scripting attacks and clickjacking. For most CMS sites such as WordPress and hosts using Apache servers, these Header Response policies can be set via the .htaccess file.

To learn more about security headers, i’ve included some resources that might help.

To begin, lets use a couple of tools to identify missing headers on our VHOST.

Using ZAP, we can see some of the headers and policies not set.

image

We can also use other tools like Nuclei vulnerability scanner to identify missing headers.

image

From the output above, we can identify more missing headers. I’m going to walk you through how you can configure/set some of them.

On our VHOST configuration file (pass.conf), we need to the folowing configuration block:

1
2
3
4
5
6
7
8
Header set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
Header always set Content-Security-Policy "default-src 'self'; font-src *;img-src * data:; script-src *; style-src *;"
Header set X-XSS-Protection "1; mode=block"
Header always set X-Frame-Options "SAMEORIGIN"
Header always set X-Content-Type-Options "nosniff"
Header always set Referrer-Policy "strict-origin"
Header always set Permissions-Policy "geolocation=(),midi=(),sync-xhr=(),microphone=(),camera=(),magnetometer=(),gyroscope=(),fullscreen=(self),payment=()"
Header always set Clear-Site-Data "cache"

image

Also, from our Nuclei output, we identified Apache’s ServerToken Directive which discloses Our Apache version information. In order to hide server information in Apache, we can add the following directives to our VHOST configuration file.

1
2
3
# Hiding Apache ServerToken Directive
ServerSignature Off
ServerTokens Prod

I choose to set ServerTokens Prod as the directive since i dont want people guessing or identifying the exact version.

NB: The config lines should be added outside the < VirtualHost > block as shown.

image

Other configuration options include:

1
2
3
4
5
6
7
8
9
10
11
12
ServerTokens Full (or not specified)
    Server sends (e.g.): Server: Apache/2.4.2 (Unix) PHP/4.2.2 MyMod/1.2
ServerTokens Prod[uctOnly]
    Server sends (e.g.): Server: Apache
ServerTokens Major
    Server sends (e.g.): Server: Apache/2
ServerTokens Minor
    Server sends (e.g.): Server: Apache/2.4
ServerTokens Min[imal]
    Server sends (e.g.): Server: Apache/2.4.2
ServerTokens OS
    Server sends (e.g.): Server: Apache/2.4.2 (Unix)

With that done, we can save changes made to the file and check if there might be any syntax errors.

1
2
3
4
5
6
root@theoffice:/etc/apache2/sites-available# nano pass.conf
root@theoffice:/etc/apache2/sites-available# apachectl -t
AH00526: Syntax error on line 19 of /etc/apache2/sites-enabled/pass.conf:
Invalid command 'Header', perhaps misspelled or defined by a module not included in the server configuration
Action '-t' failed.
The Apache error log may have more information.

Ooops! Another error 😫. By doing a quick google search, i learnt this is because mod_headers had not been enabled. To resolve this, we can use the a2enmod utility to enable the module as shown:

1
2
3
4
root@theoffice:/etc/apache2/sites-available# sudo a2enmod headers
Enabling module headers.
To activate the new configuration, you need to run:
  systemctl restart apache2

Apache Module mod_headers provides directives to control and modify HTTP request and response headers. Headers can be merged, replaced or removed.

This time, we can restart the webserver and confirm if the response header fields which is sent back to clients includes a description of the generic OS-type of the server as well as information about compiled-in modules.

Using nmap, we can identify if the headers have propagated as shown:

image

We can also check if Apache version information has been disabled as shown:

image

Apache Logs

Apache creates several log files in the /var/log/apache2/ subdirectory.

The :

  • access.log file records all requests made to the server to access files.
  • error.log records all errors thrown by the server.

A typical configuration for the access log might look as follows.

1
2
3
4
5
6
7
8
9
10
root@theoffice:~# cd /var/log/apache2/
root@theoffice:/var/log/apache2# ls -la
total 7860
drwxr-x---  2 root adm       4096 May  7 12:15 .
drwxrwxr-x 10 root syslog    4096 May  7 11:27 ..
-rw-r-----  1 root adm    7671026 May  7 11:54 access.log
-rw-r-----  1 root adm     362599 May  7 11:54 error.log
root@theoffice:/var/log/apache2# tail access.log
192.168.1.103 - - [07/May/2023:12:18:45 +0000] "GET /.env HTTP/1.1" 404 852 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36"
192.168.1.103 - - [07/May/2023:12:18:45 +0000] "GET /.git/config HTTP/1.1" 404 852 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36"

Lets break down the first request and see understand each part of the log entry:

  • 192.168.1.103 - This is the IP address of the client (remote host) which made the request to the server. If HostnameLookups is set to On, then the server will try to determine the hostname and log it in place of the IP address. However, this configuration is not recommended since it can significantly slow the server. Instead, it is best to use a log post-processor such as logresolve to determine the hostnames.
  • [07/May/2023:12:18:45 +0000] - The time that the request was received. The format is:
    • [day/month/year:hour:minute:second zone]
      • day = 2digit
      • month = 3letter
      • year = 4digit
      • hour = 2digit
      • minute = 2digit
      • second = 2digit
      • zone = (+-) 4*digit
  • "GET /.env HTTP/1.1" - The request line from the client is given in double quotes. The request line contains a great deal of useful information. First, the method used by the client is GET. Second, the client requested the resource .env, and third, the client used the protocol HTTP/1.1.
  • 404 - This is the status code that the server sends back to the client. This information is very valuable, because it reveals whether the request resulted in a successful response (codes beginning in 2), a redirection (codes beginning in 3), an error caused by the client (codes beginning in 4), or an error in the server (codes beginning in 5). The full list of possible status codes can be found in the HTTP specification (RFC2616 section 10).
  • 852 - The last part indicates the size of the object returned to the client, not including the response headers. If no content was returned to the client, this value will be “-“. To log “0” for no content.
  • "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36" - The User-Agent HTTP request header. This is the identifying information that the client browser reports about itself.
    • Mozilla/5.0: This is the product token and version number that identifies the browser as a version of Mozilla. Many modern browsers use this token in their user agent strings for compatibility reasons.
    • (Windows NT 10.0; Win64; x64): This is the operating system token, which indicates that the client is running on a 64-bit version of Windows 10. The Win64 and x64 parameters indicate that the operating system and CPU architecture are both 64-bit.
    • AppleWebKit/537.36: This is the rendering engine token, which identifies the browser’s layout engine. This token indicates that the browser is based on the WebKit engine, which is used by several popular browsers including Chrome and Safari. The version number is 537.36.
    • (KHTML, like Gecko): This is an optional token that some browsers include to indicate that they are compatible with the rendering engine used by Mozilla Firefox (Gecko) and Konqueror (KHTML).
    • Chrome/113.0.0.0: This is the browser token, which identifies the specific browser that is being used. In this case, it indicates that the client is using version 113.0.0.0 of the Google Chrome browser.
    • Safari/537.36: This is an optional token that some browsers include to indicate that they are compatible with the Safari browser. In this case, it indicates that the client is compatible with version 537.36 of Safari’s rendering engine.
  • Apache - Log Files
This post is licensed under CC BY 4.0 by the author.

Comments powered by Disqus.