This tutorial was proposed to be a continuation of my research on Internet security last semester-- taking what I learned and using it to study penetration testing. I would like to use this essay as an opportunity to explain what penetration testing is and isn't, and software security in general. Armed with those definitions I will then recite my work on the mechanics of penetration testing.
Methodology
Penetration testing, also shortened to pen test, is defined by Wikipedia as:
“...an attack on a computer system that looks for security weaknesses, potentially gaining access to the computer's features and data.”
I feel this is an incomplete definition as it provides no context to overarching goal of penetration testing, or how it fits into the life cycle of security vulnerabilities. Furthermore, 'attack' doesn't specify the pen test as automated or manual, as they have differing uses. I also feel 'attack' adds a nefarious connotation, brings more questions like: is an illegal hacking attempt a pen test then? Is a requested pen test the same as nefarious hacking?
I'd like to begin this writeup by delving into the methodology of computer security, and using that theoretical knowledge to explain the role of pen testing in the grander scheme of improving security. Only then can I fully explain my work in applying this knowledge.
Computer Security
Software security, which encompasses the cycle of designing, building, and testing software for security, is the heart of computer security. It aims to identify and remove vulnerabilities in the software itself. The mentality of software security is to build software that can withstand attacks pro-actively. Computer security is simply an umbrella term as computer systems are compilations of software.
Computer security has always been a cat and mouse game, but in the past has been primarily a reactive process. If your network software has a vulnerability, throw a firewall on it. If your encryption breaks at the application layer, start the encrypting at a layer above. The reactive approach treats the wounds of vulnerabilities, but not the disease. Software security aims to cut the head off the vulnerability snake.
Bugs, Flaws and Defects
“The beginning of wisdom is to call things by their right names.”–Chinese Proverb
Francis Bacon popularized the saying ‘knowledge is power’ and there is power in naming things. To continue talking about security, and where penetration testing fits in, I feel the need to introduce basic terminology: defect, bug, flaw, and risk. This should help clarify categorizing vulnerabilities and give a foundation to what pen testing is meant to accomplish:
- Defect: This is both implementation, and software design problems. Defects are classified by the fact they can lie dormant for years before being uncovered and exploited– usually causing major consequences if found. Examples would be application logic errors or development functions left in production releases. Defects are not necessarily initiated by normal program operation.
- Bug: A bug is a software problem existing in code. Though the term bug is applied quite generally by many software practitioners, I reserve use of the term to encompass fairly simple implementation errors. For example, buffer overflows or off-by-one fence post errors. A way to categorize bugs would be, easy-to-fix errors.
- Flaw: These types of problems exist in a deeper level then bugs. Flaws are categorized by their subtle nature and are more complex than simply an off-by-one error in an array reference or use of an incorrect system call. A flaw is instantiated in software code, but it is also present (or absent!) at the design level. For example, a number of classic flaws exist in error-handling and recovery systems that fail in an insecure or inefficient fashion. Automated technologies to detect design-level flaws do not yet exist, though manual risk-analysis processes (like pen testing) can identify flaws.
- Risk: Flaws and bugs lead to risk. Risks are not failures. Risks capture the probability that a flaw or a bug will impact the purpose of the software (that is, risk = probability x impact). Risk measures must also take into account the potential damage that can occur. A very high risk is not only likely to happen but also likely to cause great harm. A goal of computer security is to minimize risk, and in a perfect scenario have zero risk. Risk analysts answer the hypothetical equation, where would a defect need to be to cause the most impact? This risk analysis can guide penetration testing to be more effective.
The schism between bugs and flaws is a lot less clear in practice. Sometimes determining whether a defect is a flaw or a bug is difficult. That's because flaws and bugs exist along a continuum of defects. The defects found in systems can range from local implementation errors (like use of the gets() function call in C) to inter-procedural errors (like a race condition in a database operation) to much higher design-level mistakes (like error-handling and recovery systems that fail).
Gary McGraw, author of “Building Security In”, proposes similar definitions for defect, bug, flaw and risk. He also includes a very powerful metaphor: that computer security, is like building a house. Low-level coding are the bricks. Depending on what type of building material you use for your walls, impacts how easy it is for someone to break-in. Function calls likely to cause buffer-overflows are like bricks made of sawdust.
Even though the type of brick is important, over all it is more important that your house have four walls and a roof. That is to say, have a design that supports security. “Which system calls and libraries are used and how they are used is important, but overall design properties often count for more. In general, [computer] security to date has paid much more attention to bricks than to walls.” The argument being that security needs to be thought of during the software development process. Penetration testing should be for testing walls, not adding them.
Penetration testing
Security testing in general makes use of both white hat and black hat methodologies: making sure the software works as intended, and that functionality can't be used in unintended ways to compromise security. Penetration testing is the most commonly applied of all software security testing. This is not necessarily a good thing. Often penetration testing is a final security checklist item at the end of the software development life-cycle, as per the old adage “penetrate and patch”.
This is an antiqued approach. If a company has not thought about security during the development process, finding vulnerabilities late in the development cycle can be prohibitively expensive (money and time-wise) to fix. Simple code review during the software development process can fix small bugs. Lexical code analysis tools, and even compilers can fix bugs– like a function call to gets(). Penetration testing is meant to combat midrange vulnerabilities. I would define a mid range vulnerability as one that involves a defect stemming from multiple parts of the code base. A simple vulnerability might be a syntax error or vulnerable function call, whereas a midrange vulnerability might be a race condition. Race conditions, and by extension mid-range vulnerabilities for example, cannot be detected by a lexical analysis tool or analyzing one specific section of code. They involve several functions and require extensive knowledge of the subject and implementation specifics.
Penetration testing shouldn't be used to add security to code– security should be built in during the development process and penetration testing should fix security. The real value of penetration testing comes from probing a system in its final operating environment. Uncovering environment and configuration problems and concerns is the best result of any penetration test. This is mostly because such problems can actually be fixed late in the life-cycle. Knowing whether or not your application server is properly set up and your firewall plays nicely with it is just as important to final security posture as is building solid code. Penetration testing gets to the heart of these environment and configuration issues quickly and that's how it should be used.
If there should be any outcome of my plan research, it should be to change the definition on Wikipedia. These days, software needs to include security in every step of development-- that is to say, including security should just be good coding practice. Penetration testing should be used to find software vulnerabilities that arise in production environments– which is a specific distinction to be made.
Summary of work
- Set up a penetration testing lab
- Two Main Projects
Recitation and Grade
The overall takeaway from my tutorial was what penetration testing really is, and how it fits into computer security. In former years, software development was creating functionality, and penetration testing was used to add security after the fact. However, in my essay above I explore why this is bad security cycle. Little bugs that are easy to fix, or could be prevented in the development cycle, are costly to fix when found during penetration testing. Furthermore, the point of penetration testing is not code review in this sense-- but to test software in it's production environment. For example, in a webserver, fixing buffer-overflows should be part of software development. Pen testing, should be making sure it can handle malformed packets or race conditions.
The actual practice of penetration testing can be applied to applications or networks specifically. Both forms require expert knowledge in each field. The majority of my tutorial work was leaving no stone un-turned and exploring. I believe I deserve an A in this tutorial due to my range of topics covered in creating a lab, creating a tool to implement ARP spoofing, and exploring application pen testing through creating an intentionally vulnerable application. I know this isn't a fair metric but I'd like to point out the fact I got hired by a company that does nothing but penetration testing, and their interview process was thorough to say the least.
Pen Testing Lab
In the beginning of the semester, a big under taking of mine was setting up a penetration testing lab-- a private network to carry out lab work safely. There are different ways to set one up, and each way has costs and benefits. One way would be complete virtualization. Simulating multiple computers on one machine with the use of VirtualBox or Vmware. The downsides here, are that: any packets sent between the virtual machines might not be sent through a physical router and behave different in testing, and that you need a large amount of RAM to emulate multiple machines. The RAM constraints is what forced me to go a physical route, i.e. set up actual hardware and use a router and switch to emulate the internet.
Going physical presented its own challenges as well. I had to learn and explore network administration. With the blessing of Jon Baker, I set up a physical TP-LINK router, and programed a Cisco switch. Once set up I also explored current opensource router software: DD-WRT. This involved flashing new firmware on my router. Before the lab came together, I also explored installing ZeroShell and DD-WRT x86 (router operating system software) on an old computer from the gadgets room. Although an easy network set-up in retrospect, doing this was my first network admin experience and I took the time to explore current technologies.
Network Penetration Testing
With the lab set up I was free to explore network penetration testing. My week to week work exploration consisted mainly of talking points to present.
These discussions accumulated with my creation and execution of arp spoofing software: ARPy. This should be considered my Mid-Term project. It is tool to impletment ARP spoofing, which I explored last semester in hand-wavy-theory. My code represents a lot of hours spent learning raw socket programming, and exploring protocol security much before it was introduced in computer systems. Easy distribution was also a concern of mine while developing, as I intend to have software for my plan easy to install. My implementation was just as effective as Ettercap and I didn't rely on networking libraries. (like libcap or pcap)
Application Penetration Testing
Beyond my own lab, I also explored pen testing labs online. I created an account on Hackthiswebsite.org (my profile:
https://www.hackthissite.org/user/view/dylanmm/) and completed several exercise labs. Mid semester I made the transition (mainly due to a potential intership) to application penetration testing-- specifically in regards to web applications. After much research in web aplication secruity, I created Freaking Vulnerable Web Application
https://github.com/dylanmm/FVWA which should be considered my final project in conjunction with my essay.
What guided my research was OWASPs top ten security vulnerabilites. FVWA is an example of broken session management, bad authentication handling, and XSS.
Web application security revolves around input sanitation. XSS_01 is a lab that inputs user's comments into a database, and displays all comments. Here is an important snippet:
<?php
//open the database
$db = new PDO('sqlite:xss01_Db_PDO.sqlite');
//create the database
$db->exec("CREATE TABLE IF NOT EXISTS Posts (Id INTEGER PRIMARY KEY, Comment TEXT)");
$r = $db->query('SELECT * FROM Posts');
if ($r->fetchColumn() < 1){
$db->exec("INSERT INTO Posts (Comment) VALUES ('Hello, World!');");
}
if (isset($_GET['comment'])) {
$comment = $_GET['comment'];
$db->exec("INSERT INTO Posts (Comment) VALUES ('$comment');");
}
?>
Here, malicious javascript (or another scripting language interpreted by browsers) could be inserted into a comment and executed every time a user requests the page. The idea here is XSS javascript could be used to access the DOM and retrieve cookie data containing a session token and then used to login as that user. If there was a webpage on the website that handled money transactions, that page could be called through javascript or any html tag really like <img src="money.php?from=victim&to=attacker&money=$400" />, the parameters edited on the users behalf and executed aswell (CSRF).
XSS_02 takes security up a notch, but barely.
<?php
//open the database
$db = new PDO('sqlite:xss02_Db_PDO.sqlite');
//create the database
$db->exec("CREATE TABLE IF NOT EXISTS Posts (Id INTEGER PRIMARY KEY, Comment TEXT)");
$r = $db->query('SELECT * FROM Posts');
if ($r->fetchColumn() < 1){
$db->exec("INSERT INTO Posts (Comment) VALUES ('Hello, World!');");
}
$blacklist = array("<script>",
"</script>"
);
if (isset($_GET['comment'])) {
$comment = $_GET['comment'];
foreach ($blacklist as $key) {
$comment = str_replace($key, '', $comment);
}
$db->exec("INSERT INTO Posts (Comment) VALUES ('$comment');");
//hi'); INSERT INTO Posts (Comment) VALUES ('ATTACK
}
?>
Here I am employing a method of input sanitation known as black lists. I have an array of "bad terms" and remove them from the comment. No longer will script tags work. However, because this function is not recursive, a script tag embedded in a script tag,<scr<script>ipt>, would leave a script tag. Easy to beat.
XSS_03 improves the blacklisting functionality by making it recursive.
<?php
//open the database
$db = new PDO('sqlite:xss03_Db_PDO.sqlite');
//create the database
$db->exec("CREATE TABLE IF NOT EXISTS Posts (Id INTEGER PRIMARY KEY, Comment TEXT)");
$r = $db->query('SELECT * FROM Posts');
if ($r->fetchColumn() < 1){
$db->exec("INSERT INTO Posts (Comment) VALUES ('Hello, World!');");
}
$blacklist = array("<script>",
"</script>"
);
if (isset($_GET['comment'])) {
$comment = $_GET['comment'];
$clean = false;
while (!$clean) {
$clean = true;
foreach ($blacklist as $key) {
if (strstr($comment, $key)) {
$clean = false;
}
}
foreach ($blacklist as $key) {
$comment = str_replace($key, '', $comment);
}
}
$db->exec("INSERT INTO Posts (Comment) VALUES ('$comment');");
}
?>
This is recursive, so script tags within script tags will not work. It seems like a better solution, but javascript for example, can be executed in multiple tags, so security is not really improved. THis is the downside of blacklisting, recursive functions are computationally expensive and there are too many terms to black list.
XSS_04 implements white-listing.
<?php
//open the database
$db = new PDO('sqlite:xss03_Db_PDO.sqlite');
//create the database
$db->exec("CREATE TABLE IF NOT EXISTS Posts (Id INTEGER PRIMARY KEY, Comment TEXT)");
$r = $db->query('SELECT * FROM Posts');
if ($r->fetchColumn() < 1){
$db->exec("INSERT INTO Posts (Comment) VALUES ('Hello, World!');");
}
if (isset($_GET['comment'])) {
$comment = $_GET['comment'];
$comment = preg_replace( "/[^a-zA-Z0-9_]/", "", $comment);
$db->exec("INSERT INTO Posts (Comment) VALUES ('$comment');");
}
?>
White listing is the process of only allowing certain characters or tags. It is much easy to specify what you allow then specify what you don't allow. Here I am using regular expressions to only allow letters and numbers. No more XSS...
easy_auth_attack is an example of an easily brute force-able login form. The password is password and the username is admin. This was easily brute-forced with jack the ripper (dictionary attack tool).
<?php
$logged_in = false;
if (isset($_GET['user']) && isset($_GET['password'])) {
if ($_GET['user'] == "admin" && $_GET['password'] == "password") {
$logged_in = true;
}
}
if (!$logged_in) {
// NOT LOGGED IN
?>
med_auth_attack tries to avoid brute-forcing with session variables.
<?php
$logged_in = false;
if (isset($_GET['user']) && isset($_GET['password'])) {
$_SESSION['login_attempts'] += 1;
if ($_GET['user'] == "admin" && $_GET['password'] == "password") {
$logged_in = true;
}
}
if (!$logged_in && $_SESSION['login_attempts'] <= 3) {
// NOT LOGGED IN
?>
Basically by using the session, we can keep track of the number of password attempts. You get three tried before the application locks you out. Much safer right? Wrong. The session token is stored as a cookie in the clients browser. By disabling cookies, you can remove the session check and continue with a standard dictionary attack. The best method to negate brute-forcing is simply strong passwords, or two factored authentication.