We're sorry but this page doesn't work properly without JavaScript enabled. Please enable it to continue.
Feedback

Malproxy Leave Your Malware at Home

00:00

Formal Metadata

Title
Malproxy Leave Your Malware at Home
Title of Series
Number of Parts
335
Author
License
CC Attribution 3.0 Unported:
You are free to use, adapt and copy, distribute and transmit the work or content in adapted or unchanged form for any legal purpose as long as the work is attributed to the author in the manner specified by the author or licensor.
Identifiers
Publisher
Release Date
Language

Content Metadata

Subject Area
Genre
Abstract
During a classic cyber attack, one of the major offensive goals is to execute code remotely on valuable machines. The purpose of that code varies on the spectrum from information extraction to physical damage. As defenders, our goal is to detect and eliminate any malicious code activity, while hackers continuously find ways to bypass the most advanced detection mechanisms. It’s an endless cat-and-mouse game where new mitigations and features are continuously added to the endpoint protection solutions and even the OS itself in order to protect the users against newly discovered attack techniques. In this talk, we present a new approach for malicious code to bypass most of endpoint protection measures. Our approach covertly proxies the malicious code operations over the network, never deploying the actual malicious code on the victim side. We are going to execute code on an endpoint, without really storing the code on disk or loading it to memory. This technique potentially allows attackers to run malicious code on remote victims, in such a way that the code is undetected by the victim’s security solutions. We denote this technique as “malproxying”. Hila Cohen Hila Cohen is a passionate Security Researcher at XM Cyber, where she investigates new attack techniques and develops detection and mitigation capabilities. Hila has a vast knowledge in the fields of malware analysis, reverse engineering and incident response. Amit Waisel Amit Waisel is a Senior Technical Leader at XM Cyber. He is a seasoned data security expert with vast experience in cyber offensive projects. Prior to XM Cyber, Amit filled multiple data security positions in the Israeli intelligence community. Amit is well experienced with malware detection and analysis techniques, operating system internals and security-oriented software development. He graduated with honors from Tel Aviv University with a MSc. in Computer Science.
Cohen's kappaHill differential equationMalwareLimit (category theory)CyberneticsInformation securityMotion captureMathematical analysisMoment (mathematics)MalwareMultiplication signCyberneticsSpeech synthesisComputer animation
Demo (music)Proxy serverMalwareCodeInformation securitySoftwareProxy serverPhysical systemWeb pageOperator (mathematics)Virtual machineMechanism designComputer virusDemo (music)Computer animation
Information securityGame theoryInformation securityGame theoryComputer-assisted translationMereologyOcean currentEscape characterStack (abstract data type)Multiplication signSelf-organizationComputer animation
Information securityLine (geometry)BefehlsprozessorBlack boxVirtual machineOcean currentComputer animation
Computer-assisted translationInformation securityGame theorySequencePrice indexElectronic signatureMechanism designFluid staticsRule of inferenceComputer fileMultiplication signString (computer science)Pattern languageCore dumpImplementationQuicksortPerspective (visual)Category of beingPhysical systemMalwareDecision theoryCodeOperating systemHeuristicMachine codeComputer animationSource code
Fluid staticsScalable Coherent InterfaceInclusion mapHeuristicCategory of beingAddress spaceNatural numberFile systemBinary codeString (computer science)Rule of inferenceEmailSheaf (mathematics)Computer fileTouchscreenHeuristicPosition operatorCategory of beingDifferent (Kate Ryan album)Combinational logicCodeElectronic signaturePresentation of a groupMultiplication signRow (database)FlagWindowCASE <Informatik>MalwareSequenceInformation securityMathematical analysisSoftware testingExistenceQuicksortCondition numberBinary fileFunktionalanalysisAlgorithmSemiconductor memoryProbability density functionSpacetimeGastropod shellCartesian coordinate system
Physical systemRule of inferenceProcess (computing)Electronic signatureElectronic mailing listFluid staticsInformationstheorieOrder (biology)PasswordSemiconductor memoryTouchscreenPosition operatorPattern languageEntire functionCodeThread (computing)LoginData miningSource codeComputer animation
Electronic signatureCalculusInformation securityAntivirus softwareMechanism designWindowParameter (computer programming)
CodeInformation securityProxy serverHacker (term)Interactive televisionVirtual machineMechanism designMathematicsCodeComputer filePhysical systemCategory of beingMalwareException handlingOperator (mathematics)Computer animation
Group actionMalwareFunction (mathematics)Operations researchComputer networkCodeStructural loadPhysical systemMalwarePhysical systemMessage passingConnectivity (graph theory)WebsiteProcess (computing)System callCodeSoftwareResultantComputer fileVirtual machineStructural loadInformation securityDependent and independent variablesMotion captureOperating systemFunktionalanalysisProgram flowchart
Function (mathematics)Asynchronous Transfer ModeBit rateTerm (mathematics)Kernel (computing)FunktionalanalysisPhysical systemAsynchronous Transfer ModeKernel (computing)CodeSystem callTerm (mathematics)Library (computing)Operator (mathematics)Operating systemGroup actionResultantProxy serverUMLProgram flowchart
Asynchronous Transfer ModeComputerTerm (mathematics)MalwareProxy serverAsynchronous Transfer ModeSystem callKernel (computing)Physical systemLogicGroup actionFunktionalanalysisWebsiteOperator (mathematics)Dataflow
Process (computing)Open setTable (information)Address spacePhysical systemSystem callCodeControl flowFunction (mathematics)LogicTerm (mathematics)WindowFunktionalanalysisMalwareStructural loadSeitentabelleSoftwareAddress spaceMessage passingPhysical systemInformation securityCodeInteractive televisionData structureBootingProxy serverSystem callGame controllerLogicOperating systemMathematicsImplementationReal numberWebsiteResultantParameter (computer programming)JSON
Function (mathematics)Term (mathematics)Parameter (computer programming)WebsiteData structureSystem calloutputFunktionalanalysisProxy serverType theoryCategory of beingCombinational logicPointer (computer programming)Computer animation
Function (mathematics)Data bufferResource allocationPrototypeSystem callPointer (computer programming)outputBuffer solutionLemma (mathematics)Physical systemProcess (computing)LengthOvalFunction (mathematics)Physical systemoutputMalwareProxy serverSystem callData bufferFunktionalanalysisBuffer solutionMemory managementParameter (computer programming)Different (Kate Ryan album)Type theoryInformationstheorieData structureAddress spaceMessage passingPointer (computer programming)Process (computing)CASE <Informatik>Multiplication signOrder (biology)Complete metric spaceLogicElement (mathematics)VirtualizationTranslation (relic)WindowSerial portSemiconductor memoryLeakWebsitePoint (geometry)Analytic continuationSource codeComputer animation
OvalLengthMessage passingProgrammable read-only memoryArithmetic meanProcess (computing)Message passingBuffer solutionInformationstheorieLengthParameter (computer programming)Physical systemSystem callObject (grammar)Subject indexingNumberOpen setTable (information)Order (biology)Function (mathematics)WebsiteSerial portoutputComputer cluster
Message passingOvalLengthDependent and independent variablesoutputParameter (computer programming)LengthSemiconductor memoryComplex analysisAddress spaceFunction (mathematics)Process (computing)Block (periodic table)Message passingAnalytic continuationDependent and independent variablesData structureInformationstheorieLogicSpacetimeNumberCASE <Informatik>Pointer (computer programming)Resource allocationVirtualizationThomas BayesJSON
OvalDependent and independent variablesMessage passingCodeStructural loadFunction (mathematics)Physical systemCodeResultantFunktionalanalysisProxy serverFunction (mathematics)Operator (mathematics)Complex analysisWebsiteData structureDataflowParameter (computer programming)System callStructural loadMalwareSingle-precision floating-point formatPhysical systemMessage passingDependent and independent variablesSoftwareProgram flowchart
Graphical user interfacePrincipal ideal domainProxy serverComputer virusPasswordLoginTotal S.A.Order (biology)LogicAntivirus softwareProcess (computing)String (computer science)Integrated development environmentUniform resource locatorPhysical systemAddress spaceInformationstheorieFlagArithmetic meanFunktionalanalysisMetadataSemiconductor memoryReading (process)Vector potentialBuffer solutionDataflowData bufferSystem callVirtualizationElectronic mailing listForm (programming)Equaliser (mathematics)Query languageWebsiteTheoryVisualization (computer graphics)Open setJSONComputer animationUML
Exploit (computer security)DataflowVideo gameReal numberWebsiteCodeWindowInformation securityOperator (mathematics)Virtual machineLoginPasswordPatch (Unix)Computer animation
Installation artWindowMultilaterationToken ringSystem administratorSet (mathematics)WebsiteComputer animation
Operator (mathematics)PasswordVirtual machine2 (number)WindowLine (geometry)Hash functionRight angleResultantStructural loadSemiconductor memoryMobile appWebsiteLoginFunktionalanalysisSource code
WindowCodeInformation securityProxy serverMechanism designSource codeComputer animation
Rule of inferenceHeuristicFluid staticsProxy serverMalwareString (computer science)Electronic signatureMechanism designFluid staticsHeuristicPhysical systemCategory of beingInformation securityLogicRule of inferenceWebsiteComputer animation
Block (periodic table)Set (mathematics)Operator (mathematics)System callResultantInformation securityCASE <Informatik>Product (business)Mechanism designElectronic signatureLimit (category theory)Computer animation
Proxy serverElectronic signatureMalwareMechanism designInteractive televisionOperator (mathematics)Electronic signatureLine (geometry)TouchscreenCodeSystem callAddress spaceProxy serverComputer configurationPhysical systemOperating systemComputer animation
System programmingPivot elementSheaf (mathematics)Kernel (computing)Dynamic random-access memoryBlogCodeComputer animation
Transcript: English(auto-generated)
Alright so yeah this is uh malproxy leave your malware at home so here we go. Thank you. Hi everyone we really appreciate your time coming here today. Uh so my name is Amit and with me is my colleague Ela. Both come from Israel and as you understand this is our
first time in Defcon speaking in Defcon. Uh we both come from a start up company called XM cyber and really do offensive cyber so we can't talk much about our background that's why we decided to put some cool trivia stuff about us but let's move on to the actual topic. So today we're going to show you a new and cool technique to execute malicious
code bypassing existing endpoint security solutions. Because as attackers we continuously try to find new ways to execute our malicious code under the presence of those solutions. I know there are many existing techniques like fileless viruses or executable packers but but
most of those techniques require modifications on the malicious code side. So it is harder for the attackers to implement them over and over again to every piece of malicious code. So here we present a generic technique that simply proxies system API calls over the network so
the malicious code is never present on the target machine on the victim. And because it's never there most of the defenses and security mechanisms implemented inside the endpoint security solutions will simply not detect the code. And because the code is unaware of that proxying operation uh no modifications are required in it at all. So in this talk today we'll
cover some basic protection mechanisms that exist in most of the endpoint security solutions in the market today. Just to keep everyone on the same page. Then we'll uh describe our malproxy solution in detail including a demo and we'll end of course with
some mitigations. So why do we actually speak specifically about endpoint security solutions? Mainly because they are a major part of every organization security stack. Those solutions evolved over time alongside the attackers because sometimes the attacker successfully penetrated the defenses so the security community had to keep up the pace and
put another defenses more advanced defenses to cope with the new attacks. But it's like a cat and mouse game where the cat keeps chasing the mouse and the mouse keeps getting away. But it is an unfair game because the mouse has to find a single way to escape the cat while the cat has to predict all the possible ways of escape of the mouse uh to
block it from escaping before it happens. So what do we actually know about the current status of endpoint security solutions? For many of us it's just a black box with a lot of fairy dust, some cool UI and of course machine learning inside uh that
consumes ooh that consumes most of our CPU on the endpoints. But most of us don't actually know what happens inside. But in the bottom line we know that there are cyber attacks in the world and there are successful penetrations of most of the defenses. So we can actually sum up the current status of endpoint security solutions in one short
sentence. Not great, not terrible. But let's understand why. So thanks to the cat and mouse game, over the years the endpoint security solutions evolved significantly and developed more and more uh advanced protection mechanisms. So historically we can start with
the first protection mechanism that was implemented which is the static signatures. Those look on what we called IOCs, indications of compromise. Those can be binary sequences in a file or in a memory dump or simply strings, readable strings from a file. The next mechanisms that came to close some gaps in the static signature mechanisms is
the heuristic rules. Those don't look on the actual uh data inside a file but look on the different properties from a higher perspective. It can be where the file is located, what API's it uses or uh whether it is encrypted or not and so on. Those rules basically
calculate some sort of heuristic score and in many endpoint security solutions a negative score means malicious and positive score means innocent. So that's the whole purpose to give some score and decide whether a file is malicious based on this score. The last mechanism is the behavioural signatures and those come to actually look on the impact that
a piece of code uh does on a system and not on the actual implementation. So every piece of code that runs on a system interacts with the operating system in some way through API calls. So when we monitor those API calls and look for some malicious
patterns in that activity log we may get uh we may verdict some of those uh pieces of code without actually knowing them in advance. So it it it deals with the unknown malware. So the solution that we present here actually handles the first 2 mechanisms successfully and it
gives very hard time for the behavioural signatures to catch us. So let's dive into the first category the static signatures to understand them better. And let's take this piece of code as an example of malicious code. I know it's not but let's think it is. See it defines some string and calls printf and now I would like to create a static
signatures that verdicts that piece of code but not other pieces of code. So I can use a technology called Yara and create some rules and test those rules on various binary files. I didn't actually write this Yara rule I took it from some website online but you can see defines some strings and a binary sequence which is an ELF header. This is a Unix
based executable and the condition is that the ELF header exists in the first 4 bytes of the file and there is either the ADM string or corpse string. So if we compile the code that we saw before and apply the Yara rule on it we can see that Yara verdicts the file because we have the ELF header and we have the ADM string inside some offset in the
file. So that's a very basic static signature. But now let's uh let's create another uh static signature that captures Mimikatz. We love Mimikatz and uh we use it as demonstration uh across this talk. So those 6 strings I extracted from uh Mimikatz
Binari. So the question is can we create a Yara rule based on those 6 strings only that verdicts all the files that contains those uh 6 strings. So the answer is not because even this presentation file this PDF file actually contains those strings and as far as I know it
is not Mimikatz. So we can cannot simply uh verdict a file based on some stupid strings. We have to be very gentle and very careful when we create static signatures because otherwise we might get false positives. And false positives are one of the worst nightmares of the security researchers that create the static signatures. Let's move on
to the second category, the heuristic rules. And as I said those look on uh different properties or features in a file in the file system or in the memory. And they try to classify for each property whether it is malicious or innocent. And that's the whole
purpose of those heuristic rules. To distinguish between malicious properties and innocent properties. Some heuristic rules can be generated by a human being by a security researcher while other can be generated by some fancy you AI algorithm. It doesn't matter. The whole purpose is to create some sort of holistic heuristic score based on
a combination of different properties. So on the screen you can see an example of an analysis of a PE file, portable executable file in Windows. And you can see we have the dot text section which is the code, the dot data which is the data of course, and another custom section called UPX2. And we know that UPX is a famous executable packer. So as
you can see there are some red flags in this analysis. We can look at the text section and you can see that the row size is different than the virtual size. Most of the time it does but the the values are more close together. In our case the row size is zero bytes long so it sounds suspicious. Another red flag is that the text section is actually
writable. And actually there is no uh reason that the text section should be writable. It just contains code. Another red flag is the existence of the UPX uh section. Because we know that UPX actually takes some blob of binary data from the data section, decrypts the
data, and executes it as a shellcode or some sort of binary code. So we know that uh this application, this code actually hides its true nature from us. So if we are a security and uh an end point security solution and we want to inspect what this uh what this
file actually does, uh we know that this true the true nature of this file is hidden from us. On the other hand, if we have a digitally signed file on the file system that imports some API functions that interact with the user, we may assume that this file is
innocent because it has a very uh many innocent features inside it. So uh over the years we know that uh malicious files, malicious pieces of code actually penetrated the static signatures and the heuristic rules. And that's what the behavioral signatures came to solve. They look on the actual uh activity that a piece of code does on the system in a
live environment or in a sandbox, it doesn't matter. And analyzes that activity log of a single thread or an entire process in order to look for malicious patterns inside. So similarly to the static signature case, finally determining whether uh a pattern is
malicious or not is very uh delicate bef- because we might get false positives also here. On the screen you can see an example of uh MIMICAT's log on passwords command execution. So you see we call anti-query system information to got a- to get a process list then we
open a handle to LSAS and later we will read its memory using grid process memory. So can we take this activity log and assume it is malicious wherever we find it? So the answer is no. Similarly to the static signatures because otherwise we might get false positives. Microsoft exported this- those APIs for a reason. It is legitimate to open a
handle to another process and read its memory. Otherwise those APIs will not be exposed to the user. A very good example of uh the long way that the behavioral signatures have to go before they become more trustworthy can be seen in one of the- of Benjamin Delphi's latest posts a few weeks ago. He discovered that if you take
calc.exe and add some command arguments that are related to MIMICAT's, Windows Defender actually blocks calc.exe- execution and verdicts it as MIMICAT's. So uh and as we know calc.exe is one of the most innocent executables I know. So uh there is a long
way for the anti-viruses to go before we can trust the behavioral signature mechanism. Now Willa will show you how we can bypass those security mechanisms that they talked about. Thank you Amit. So for every protection mechanism there are ways to go around it. And endpoint protection solutions are no exception. We can change the
properties, IOCs and behavior of every malicious file thus making it undetected by security solutions. But those changes require a lot of manual work and expertise from the attacker. It has to be done for every malicious file separately so it's not feasible or
scalable to do it over and over again. We can also use other techniques that uh Amit mentioned to bypass security solutions but they may require to do some modifications in the malware code. It will present our technique to bypass security solutions. We call this technique malproxy and you will understand why shortly. So now we know that endpoint
protection solutions try to find our code and its properties, analyze and verdict it. So let's make it impossible for those solutions to even look at our code. We can simply avoid deploying the malicious code on the target machine by separating the code from its
interaction with the operating system. Let's assume we have a machine with operating system that executes a process with malicious code inside it. The code interacts with operating system using API calls as you can see in the sketch. The malicious code is present on the target machine so it can be captured by any security solution. Can we
migrate the malicious code somewhere it won't be detected by those solutions? Of course we can. Our solution allows to generically load and execute malicious uh malicious code and send the API calls it executes to the target side over the network. For the
malicious code it seems like it is executed on the target system as it cannot tell otherwise. It interacts with the operating system using API calls thus emulating them makes it looks like it is executed on the target system. Our solution consists of two major components. The attacker side stab and the target side stab. The attacker side loads
and executes the malicious the malicious code. It controls its API calls and redirects them over a network tunnel to the target side. The target code looks innocent and doesn't contain any malicious activity pre-coded in it. It receives the API calls and arguments, execute
those calls and returns the results back to the attacker side. Then the attacker side return the results back to the malicious code the same way they would be returned if the malicious code had called those requests locally. It's important to emphasize that the malicious code is totally unaware to the long journey that the response went through until it
reached its final destination. Let's take create file function for example. Our malicious code calls it and malproxy captures that call and create a detailed message for the attacker for the target side which contains the create file function name and the
path of blah dot txt. Then malproxy sends this message to the target side which parses and executes create file function as instructed. After the call the operating system returns a handle to that file and now malproxy has to send this handle back to the attacker side.
Then malproxy returns the handle back to the malicious code and as far as it is concerned we now have a valid handle to blah dot txt. To describe our solution in depth let's agree on some fundamental key terms. We all know what a system system call is and here is a schematic sketch of how API call is executed. The top function is
called by the users code and it can call other functions from other libraries if needed. Sometimes those calls reach the native API layer which makes the transition between the user mode and kernel mode. After reaching the kernel the operating system executes the
operations to fulfill the task and return the results back to the user. To proxy a system call without making any adjustment to the malicious code we can implement our malproxy in any layer of the stack. We can get inside the transition between the user mode and
kernel mode and proxy any system call that we want. However it was proved quite difficult. After experimenting with this proxying logic we found out it's much easier and convenient to intervene and implement our malproxy in the top layers of the API call and not necessarily in the native API layer. Every API call that doesn't trigger a system
call is irrelevant to our solution because it executes the same flow on both the attacker side and the target side. So let's let those functions execute on the attacker side. Why waste pretty good bytes on the wire for any an- any unnecessary operation? So how do we
proxy a system call or any API function call in that matter? We use a technique called hooking which redirects the system call to our code instead of the real operating system implementation. A full control over any API function allows us to inspect all
arguments, change them if needed and construct a message that will be sent to the target side over the network. Moreover we can change the value that is returned from the function. There are many techniques to perform hooking and this talk is too short to describe them all. We use a technique called import address table hooking technique which
is very common and easy to implement thanks to the fact that we have full control over the malicious code load and execution. The import address table describes all the functions that are used by the Windows executable. While loading the Windows loader resolves the address of every imported API function and places those addresses in the
import address table structure. Using this technique of uh changing the addresses of API functions allows us to separate between the malicious code's logic and its interaction with the operating system. The loading and hooking of the malicious code is done on the attacker side so it's not monitored by any security solution. Now let's
inspect the structure of API function call. Every API function consists of 3 main properties. The return value type, the calling convention and the function arguments. The return value type is the type of the value that will be returned from the function and it
can be either primitive, a well known structure or a pointer to some address. The calling convention defines how the arguments are passed from the caller to the caller. And every argument can be also either a primitive, a well known structure or or a pointer and can be treated as an input and output or combination of both. To proxy
system call we need to handle each of those properties by serializing and deserializing them on both the attacker side and the target side. Now Amit will explain you how we use those concepts to proxy API function call. Thank you
Ella. So now we understand that our top priority is to proxy win API functions. And to do that we have to pay close attention to all the elements that Ella mentioned in the function prototype. The return value, the calling convention but most importantly the arguments because the argument the arguments may be very hard to handle. We might have
many types of arguments, some may be input, some may be output or a combination, some may be structures or pointers to some structures that contains other pointers to structures. The memory might not be, might not even be continuous in the virtual address space. So our serialization and deserialization logic on both the attacker
side and the target side have to take all the different aspects into account in order to handle all possible argument types. Uh so once we implement all the different argument types uh we can uh simply add more and more API calls and it is quite trivial because once we cover all the different argument types it's very easy to add more API calls. Uh as
there are many argument types to handle and our time here is short, I chose to focus on what I think is one of the interesting cases and is handling uh memory buffers in API calls. We can actually uh divide the API, the Windows APIs into two main types of
main groups. Those who handle user allocated memory buffers or the user pre allocates the buffer before calling the API function and system allocated memory buffers or the system call itself is responsible for the memory allocation and afterwards when the user is
done using the buffer uh is responsible to call another API function for listing that memory. So when we do the proxying between the target side and the attacker side of those memory buffers we might keep it we must keep a translation between the virtual address space on the attacker side and the virtual address space on the target side
because we cannot promise that the same addresses will be allocated for both sides. So when we get some address from the target side that was allocated by some system call and we use that address on the attacker side of course the translated address the malicious code will later call the release function of that buffer but the address the
malicious code will use will be the address of the attacker side so we have to translate it again for the target side to actually release the resources otherwise we'll leak those resources. So uh in order to understand it better we'll look at some example. In this we
chose to show you anti-query information process. First because it is used by mucas as you'll show as you'll see later and second you can see in the third argument it uses an opaque buffer. We do not know its structure in advance and the structure is set by the value of the second argument, the process information class. You can see we
have three input arguments and two output arguments and actually those output arguments are not input as well so they are output only and the system will override whatever's data stored inside. So as far as we're concerned in the request side we can treat those uh buffers as complete garbage. We don't have to serialize it to
serialize the data into the request message. Now let's see how we handle each one of those arguments. So the first argument is the process handle. A handle is simply an index in the object table of some process and once we proxy uh this call to the target side, the handle must have meaning on the target side. So we probably got it from some
previously proxied API call for example to open process or create process or whatever API that returns us a handle to a process. This handle is a numeric value so it's very easy to uh serialize it into the request message and as I said it doesn't have any
meaning on the attacker side. It has a meaning only on the target side. So we serialize it into the request message. Now we serialize also the process information class. It's also a numeric value so we serialize it easily into the request message. But we have to keep uh to remember what value it is in order to deal with the buffer and
the third argument later on. As I said, the buffer, the process information buffer, we can treat it as garbage because uh its data will be overridden by the system API. So we don't have to add it into the request message at all. Now the process information length is the size of that buffer. We do have to serialize it before as you'll see later, we do
have to allocate a buffer on the target side for the actual system API call. The return length is also an output only argument so we don't have to serialize it into the request message. Now we have all the data we need in the request and we can send it to the target side where we deserialize all the input arguments. Now we have to allocate enough
memory space for the output arguments. The third argument size, we know it because it is set in the fourth argument value. The fifth argument size is fixed. It's an unsigned long, it's always 4 bytes long so we can allocate enough memory for it and call the
actual API. Now once we uh the API returns we need to serialize the output arguments to the response message. So let's start with the easiest case which is the return length because we know it's size in advance, we know the structure is simply an unsigned long so we can uh serialize it into the response message. But handling the process
information might be difficult because it might be a complex data structure that has pointers to other data structures, that has more pointers to other data structures. And this memory block might not be, it might not even be continuous in the virtual address space. So we do have to take all the information, the relevant information and serialize it into one continuous memory block in the response message and we have to
implement the deserialization logic to deserialize and rebuild the complex data structure bay uh back on the attacker side. All is left is to serialize the return value and the status which is also defined to be numeric value. And uh now we are ready
to send the message back to the attacker side where we need to deserialize all the output arguments, rebuild the complex data structure and return the values back to the caller code. And the caller code is totally unaware of the of that proxying operation. As far as it's concerned it called the API function and got the results back where it
expected them to be. Now let's have a quick recap of what we have here. We have two stubs, the attacker side stub and the target side stub that proxies system API calls over a network tunnel. The attacker side loads the malicious codes and hooks some of the of the API functions that interact with the target side operating system. The target side
receives the commands that should be executed, the API calls and the arguments and actually makes the call to uh to the target operating system. All the results, the response message and sent to the attacker side which deserializes them and returns them to
the original caller code. And as I said the caller is unaware of those proxying operations so we don't have to modify it at all. We just we can just take a pre-compiled malicious code and execute it. This flow happens over and over again for every API that is called and proxied. So now we understand how a single API call can be
proxied. Now let's have a look on the scope of an entire process. And for that we chose to show you again Mimikatz because first we love it and second it is uh verdicted by most of the antivirus engines in virus total. So it is a very good challenge to execute its logic without being detected. So in order to run uh specifically the login password command
in Mimikatz uh you can see we analyze some of the API calls that are used by the login passwords command. And in fact we don't have to proxy them all. We can just proxy those functions that interact with the target operating system. So let's simplify the
execution flow of the login passwords command. So it can be simplified to this flow of API calls. And let's inspect them one by one. What APIs we need to proxy and what APIs we don't need to proxy. So first RTL just privilege actually gives us an elevated token and we need an elevated token in order to interact with the target side
LSAS. And because we need to interact with the target side LSAS, we need an elevated token on the target side. So we do need to proxy this API call to the target. Then we need to enumerate all the processes in the target system to get some metadata about LSAS because we need to interact with the target side LSAS. So we call anti-query
system information with some flags that indicate that this the process list should be returned from that API. And we get all the data we need inside a user allocated buffer. We proxy that API call to get the information from the target side. Now once we have all
the information we need in the user allocated buffer, we can just look for LSAS in the metadata list simply by comparing strings using RTL equal Unicode string and this can be done entirely locally on the attacker's side. Then we call open process with the process ID that we extracted from the metadata. And the open process is called on the target
side because we need a handle to the target side LSAS. And we get back that handle. And as you remember, the handle has a meaning only on the target side. As far as the attacker is concerned, this is some magical value that doesn't have any meaning in the process besides calling other API functions. For example, anti-query information process. Mimikatz uses that to get the location of the processing environment block,
the PB. So it queries the PB location and based on the data stored in that PB, it calculates what memory buffers are of interest and contain potential credentials in LSAS. Then all those memory buffers are read using read process memory. It reads memory form and distant process. So we need to proxy this API as well because we need
to, to query the memory of the target side LSAS. Once Mimikatz contains all the information needed inside, uh, its virtual address space on the attacker side, we can simply decrypt the data and now we got the password we need and we won, uh, we pawned
the system. So this is all nice in theory, but let's see how it works in real life. And for that we installed two, two Windows 10 machines. One is the attacker and one is the victim, the target. And the victim has a window and has the w- latest Windows 10 with
Windows Defender active with the latest security patches. And our goal is to execute Mimikatz slogan password operation without being detected by Windows Defender. So in this demonstration I will simply double click the, uh, the target side stub, but in real life it will be executed by some exploitation, exploitation flow or whatever. It
doesn't matter for the demonstration purposes, but keep in mind that we do have to execute our code on the target side. So let's see how it actually works. So this is our, uh, target side. And as you can see, we have Windows Defender installed. Everything is
active, all the checks are green. And we have zero threats in the, in the history and the settings are all active. We didn't define any exclusions or whatever. And now we launch our target side stub. To do that we run it as an admin to get an elevator token later. And
as far as we know, Windows Defender didn't detect anything. Now let's look on the attacker side. You can see this is the command line on the attacker side. We run on the attacker machine under the attacker user. And we want to, uh, run our attacker side stub. And to do that, we simply launch it with the command line arguments of the
path to the actual Mimikatz executable downloaded from GitHub and the hostname NTCP port of the target side. So now, let's look how both sides interact with one another. On the left side you can see the attacker and on the right side you see the victim, the target. And every operation that is executed by the attacker will be reflected on the target
side. So when we launch Mimikatz, many DLLs are loaded and those, uh, DLL loads are reflected on the right hand side. Now the first command that we execute is privilege debug. This will give us the elevator token we need. And it, it is reflected by calling RTL adjust privilege on the target side. You can see it in the bottom line. Now the
second command that, that we execute is the secure LSA log on passwords command. And this actually opens a handle to LSAs, read its memory and passes the credentials. So while they are called, the results are already passed on the, on the attacker's side. So now
we have the credentials we need. We can scroll and inspect them and find whatever we look for. And in this example, this is the NTLM hash of the victim account. So we got what we wanted. But did we do it silently? So let's inspect the Windows Defender. As far
as we can see, we have zero threats in history still. And we do, do not have any quarantined items or threats, uh, detected. But most importantly, we do not, uh, we didn't get blocked by Windows Defender. We successfully executed whatever we wanted without being detected. So now we'll, I will, uh, talk about how we implemented our code to
bypass those security mechanisms. So all of the fun that we showed so far runs under the
radar of many security solutions. Why? Because our target stab looks innocent. And as we know, naive idiots are not a threat. So why do we run under the radar? This is not a magic. We now know what are the major mechanisms existing most of the security solutions to
detect malicious code. Our target stab avoids the static signatures detection because it doesn't have any malicious logic in its base form. The malicious code is never deployed on the target side, so the Mimikatz executable strings that Ami showed you earlier will never be on the target operating system. Moreover, our target stab avoids the heuristic
holes detection because it doesn't have any of the Mimikatz executable properties. So static signatures and heuristic holes are not a threat to us. But let's keep in mind that the behavior signatures might detect us. And this is the only mechanism that might detect our malicious activity. But those signatures are expensive. Expensive to develop
and expensive to execute. We executed malproxy under the leading security solutions in the market and here are the results. As you can see, in most cases, malproxy executed Mimikatz successfully, while in other cases, sec- uh security solution blocked some API
call with access deny error. The operation has simply failed but no verdict was made. So, we are almost at the end of our talk. We have seen the limitations in existing security products and showed a way to bypass their detection mechanisms. So, how can those
products catch us? As we said, our ops lie on behavior signatures. Obviously, our target stab can be statically signed by its IOCs and start another race between the defense and offense players to find the best IOCs on one end and change the code to avoid
detection on the other end. We believe that pretty good static signatures can be generated to detect our tool. But as we have seen during this talk, this mechanism is far from being hermetic. Another option is to improve the behavior signatures detection. As we said, in the bottom line, the operating system interacts with the
malicious code, interacts with the target operating system. We can monitor the operations taken by the malicious code to make sure that all system calls are fully tracked. The signatures, the building the log of executed system calls and the signatures which define
what malicious behavior is, have to become more robust. So, those are the ideas that we had. But you are more than welcome to think about more ways to bypass detection on one end and detect your bypasses on the other end. You are welcome to send your ideas to
the address presented now on the screen. So, we want to thank our colleague Yaron Shani for pointing out this concept to us and maintaining this cool blog with lots of interesting stuff inside. We also want to mention other articles which were published many years ago and describe this proxying concept briefly. Thank you very much for
coming. We really appreciate it. So, we do actually, uh, we'll publish the code of Melproxy online on GitHub, uh, shortly. Just have to make a few fixes in the code. And
then it will be publicly available if anyone is interested. Thank you.