How My First Pentest Went

A while back (a long while back now!) a client of mine asked for a WAPT (Web Application Penetration Test) on their company's web app: it had been built on Microsoft stack, so it was all ASP.NET and the .NET framework — and that's how the challenge began.

A while back (a long while back now!) a client of mine asked for a WAPT (Web Application Penetration Test) on their company’s app: it had been built on Microsoft stack, so it was all ASP.NET and the .NET framework — and that’s how the challenge began.

I had no information at all about the system or the web app, which made it even more interesting. The only things I had were the web server version, the language the app was written in, and an admin account to test the internal parts too.
The application I was testing was in a pre-production environment, but production was actually sitting on the same IP, so I avoided testing against DoS (Denial of Service) attacks since it could have turned into a real problem (ugh!).


First step: Recon

Having no idea how the target was structured, I started from the basics: information gathering and reconnaissance.

DNS Lookup

This is often my first move when dealing with a web app. A DNS lookup can tell you a lot about how a company is structured internally, but that time I wasn’t so lucky: the only useful info I got was the nameserver, a foreign provider, so I stopped there.

NMAP Scan

Another great starting point is a scan with NMAP — even though the nature of the target (a web app in this case) isn’t really what this tool was built for, the information you can pull from it is still useful: open ports, firewalls, IDS, and so on.

# Nmap 7.80 scan initiated Tue Aug  3 15:11:12 2021 as: nmap -sC -sV -p- -v -oN nmap-1-65535-sV-sC.txt ---OMISSIS---.com
Nmap scan report for ---OMISSIS---.com (xxx.xxx.xxx.xxx)
Host is up (0.042s latency).
Not shown: 65533 filtered ports
PORT    STATE SERVICE  VERSION
80/tcp  open  http     Microsoft IIS httpd 10.0
|_http-favicon: Unknown favicon MD5: 0F7EXXXXXXXXXXXXXXXXXXXXXXXX2C16
| http-methods:
|_  Supported Methods: GET HEAD POST OPTIONS
|_http-server-header: Microsoft-IIS/10.0
| http-title:         ---OMISSIS---
|_Requested resource was http://---OMISSIS---.com/
443/tcp open  ssl/http Microsoft IIS httpd 10.0
| http-methods:
|_  Supported Methods: GET HEAD POST OPTIONS
|_http-server-header: Microsoft-IIS/10.0
|_http-title: Did not follow redirect to http://---OMISSIS---.com/
| ssl-cert: Subject: commonName=---OMISSIS---.com/organizationName=---OMISSIS---./countryName=IE
| Subject Alternative Name: DNS:---OMISSIS---.com
| Issuer: commonName=GeoTrust EV RSA CA 2018/organizationName=DigiCert Inc/countryName=US
| Public Key type: rsa
| Public Key bits: 4096
| Signature Algorithm: sha256WithRSAEncryption
| Not valid before: 2021-05-26T00:00:00
| Not valid after:  2022-06-14T23:59:59
| MD5:   7bf5 XXXX XXXX XXXX XXXX XXXX XXXX 1149
|_SHA-1: bb2c XXXX XXXX XXXX XXXX XXXX XXXX XXXX XXXX ce6c
|_ssl-date: 2021-08-03T13:13:37+00:00; 0s from scanner time.
| tls-alpn:
|   h2
|_  http/1.1
Service Info: OS: Windows; CPE: cpe:/o:microsoft:windows
Read data files from: /usr/bin/../share/nmap
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Tue Aug  3 15:13:38 2021 -- 1 IP address (1 host up) scanned in 145.48 seconds

Nothing doing — once again, no useful information, we have to keep going!

SSL Scan

After NMAP I wanted to try an sslscan — not that I was planning to go as far as attacking the ciphers, but it’s still extra information:

sslscan ---OMISSIS---.com                                                                                                                                    1 ⨯
Version: 2.0.7-static
OpenSSL 1.1.1j-dev  xx XXX xxxx
Connected to xxx.xxx.xxx.xxx
Testing SSL server ---OMISSIS---.com on port 443 using SNI name ---OMISSIS---.com
SSL/TLS Protocols:
SSLv2     disabled
SSLv3     enabled
TLSv1.0   enabled
TLSv1.1   enabled
TLSv1.2   enabled
TLSv1.3   disabled
TLS Fallback SCSV:
Server does not support TLS Fallback SCSV
TLS renegotiation:
Secure session renegotiation supported
TLS Compression:
Compression disabled
Heartbleed:
TLSv1.2 not vulnerable to heartbleed
TLSv1.1 not vulnerable to heartbleed
TLSv1.0 not vulnerable to heartbleed
Supported Server Cipher(s):
Preferred TLSv1.2  256 bits  ECDHE-RSA-AES256-GCM-SHA384   Curve 25519 DHE 253
Accepted  TLSv1.2  128 bits  ECDHE-RSA-AES128-GCM-SHA256   Curve 25519 DHE 253
Accepted  TLSv1.2  256 bits  DHE-RSA-AES256-GCM-SHA384     DHE 2048 bits
Accepted  TLSv1.2  128 bits  DHE-RSA-AES128-GCM-SHA256     DHE 2048 bits
Accepted  TLSv1.2  128 bits  RC4-SHA
Accepted  TLSv1.2  128 bits  RC4-MD5
Preferred TLSv1.1  128 bits  RC4-SHA
Accepted  TLSv1.1  128 bits  RC4-MD5
Preferred TLSv1.0  128 bits  RC4-SHA
Accepted  TLSv1.0  128 bits  RC4-MD5
SSL Certificate:
Signature Algorithm: sha256WithRSAEncryption
RSA Key Strength:    4096
Subject:  ---OMISSIS---.com
Altnames: DNS:---OMISSIS---.com
Issuer:   GeoTrust EV RSA CA 2018
Not valid before: May 26 00:00:00 2021 GMT
Not valid after:  Jun 14 23:59:59 2022 GMT

Unfortunately, this was the only relevant result from the brief recon phase I did: SSLv3 and TLSv1.0 enabled (which we know haven’t been considered secure for a long time). To top it off there was a decent TLSv1.2, but paired with RC4 and MD5 — so not exactly great either.


Second step: Attack

Once the reconnaissance phase was done, I dug into the web application from another angle.

Static Code Analysis

Obviously I didn’t have the application’s source code, but I had the generated HTML: that means plenty of Javascript, libraries, external resources and — if you’re lucky — the occasional useful comment left in the code.

I started going through the HTML and noticed a lot of libraries in use, some of which were vulnerable or no longer maintained.

This analysis helped me a lot in the later stages.

Login form and Session Management

The first thing I looked at on the login page was cookies. The web app I was testing didn’t refresh the session ID after login, nor when the page was reloaded (while the user wasn’t authenticated), and there were also some cookies that remained valid even after logout.

Second, the password input wasn’t handled correctly: the input type was “text” rather than “password”, and the masking was done through a special font applied to that field.

On top of that, this field couldn’t correctly handle a single quote character ( ‘ ) — entering one crashed the login system, which just hung, and also removed the masking on the field. The cause was that the password was sent back to the client (by the server) inside a Javascript function that used single quotes to pass the argument (the password itself).

XSS

After a bit of work I found a few free-text fields, so I tried a dumb XSS payload:

<script>alert(1)</script>

Unexpectedly, the application crashed. Even though the framework did “notice” the potential attack, our XSS triggered an unhandled exception, revealing the framework version and the full stack trace.

Once I had the version the web app was built on, I did a bit of digging on Google and found a way to stop the application from crashing: use Unicode encoding instead.

I rebuilt the XSS payload using Unicode angle brackets and finally got a working stored XSS!


Reporting Phase

This phase is the most important one, and it should really start the moment you kick off the Penetration Test. Kali ships with a few dedicated tools for pentest reporting, but honestly you can just use vim if you want.

I split my report into 5 sections and 2 appendices:

  1. Activity Overview — This section describes the activity, the rules of engagement, the methodology used, and the tools involved.
  2. Findings — This section usually just contains the evidence for any vulnerabilities found via scanners or vulnerability-assessment software.
  3. Attack Narrative — This section instead walks through the actual attack phase: how the attack was carried out, against which specific vulnerability, how it was exploited, and how to fix it.
  4. Remediation Plan — The remediation section lists all the suggested fixes (both for the specific attack path and for the less critical findings).
  5. Conclusions — Here you wrap up the report with a summary.

It’s worth describing every step you followed as clearly as possible, and it’s just as important to include your contact details so the client can reach out to discuss the results.


Useful resources

International Security Guidelines

Secure Cipher Suites

OpenSSL Cipher Suite syntax

More links:


Conclusions

The web app I analyzed was reasonably secure, but there were still a few technical measures worth implementing to improve its overall security. Disabling SSLv3 and TLS 1.0/1.1, and using secure cipher suites, strengthens HTTPS connections and prevents certain kinds of man-in-the-middle attacks. Keeping dev/staging environments separate from production is always good practice, partly to avoid exactly this kind of exposure.
Proper session management drastically cuts the risk of Session Hijacking and CSRF (Cross-Site Request Forgery) attacks. Password fields on login forms need to be handled correctly and require some additional server-side checks. XSS can be avoided with deeper input validation, proper use of the development framework, correct output encoding, and solid exception handling.
Limiting the information disclosed (web server version, framework version, stack traces) can make life harder for an attacker and raise the overall security bar, even if only by a bit. Make sure every exception that could be thrown is handled properly, to avoid these kinds of unexpected situations.

Always stick to industry best practices: NIST, OWASP, ISECOM and the wider security community will be your best friends.

The only advice I can give you is to try, try again, and then try some more, because every application or system is different: no application is 100% secure, even if you’re a n00b like me.

Stay safe!