Compare commits
301 Commits
v0.5.4.0
...
update_cop
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3a486c7626 | ||
|
|
aa0cb30963 | ||
|
|
dbd24bb3a7 | ||
|
|
5a7b7fb107 | ||
|
|
de0cab665b | ||
|
|
5dd8715f56 | ||
|
|
214a3993f8 | ||
|
|
33f47d9d42 | ||
|
|
e62573fbf2 | ||
|
|
92b2954112 | ||
|
|
4b72bce53a | ||
|
|
4545121093 | ||
|
|
46556428ad | ||
|
|
03da278bc1 | ||
|
|
3286ef88f4 | ||
|
|
acf5bd60bb | ||
|
|
bea58a8cdb | ||
|
|
77dada0251 | ||
|
|
1a27e3b0c5 | ||
|
|
629db4fe20 | ||
|
|
f5fae026ce | ||
|
|
267c6e3198 | ||
|
|
554d42b2c6 | ||
|
|
ae25108c93 | ||
|
|
57482fbb6f | ||
|
|
e0ff71a582 | ||
|
|
a6757bedd0 | ||
|
|
ea8e661831 | ||
|
|
231c425f98 | ||
|
|
ed410c2ccd | ||
|
|
3965d83ba0 | ||
|
|
961e8d4ef9 | ||
|
|
23a2b79020 | ||
|
|
5e2b60ae00 | ||
|
|
9992499bae | ||
|
|
82f733783a | ||
|
|
4dddb2d0f7 | ||
|
|
f359ad5283 | ||
|
|
6e944a0c2c | ||
|
|
6e13b1aedc | ||
|
|
aba70bbfae | ||
|
|
5f9efcb455 | ||
|
|
86c3b5e6cc | ||
|
|
471d025bae | ||
|
|
bfbc73c989 | ||
|
|
ca933d76c4 | ||
|
|
727d422bd4 | ||
|
|
1f0c5d7ee9 | ||
|
|
ffd8b1b670 | ||
|
|
63f691994e | ||
|
|
4e9fdb4f18 | ||
|
|
d40d22d22b | ||
|
|
fd9855c3be | ||
|
|
e323c80581 | ||
|
|
b3ff3f2f6f | ||
|
|
0d44721e04 | ||
|
|
8f7246514e | ||
|
|
70729ef5ae | ||
|
|
7b948b8d8a | ||
|
|
268e8ed250 | ||
|
|
9d270cb9f6 | ||
|
|
13264cbe8a | ||
|
|
4a87b68f7b | ||
|
|
705049a2ad | ||
|
|
654ce1affb | ||
|
|
272ca32e43 | ||
|
|
624176e6ac | ||
|
|
61528a408a | ||
|
|
a154c1dbc1 | ||
|
|
03c87c2879 | ||
|
|
3593d49df8 | ||
|
|
6ac3e22bb1 | ||
|
|
dd2eceef0c | ||
|
|
03ebb78a95 | ||
|
|
9800848918 | ||
|
|
6789774000 | ||
|
|
bff0aba576 | ||
|
|
5d0ee52496 | ||
|
|
e7870c002e | ||
|
|
45b81eae52 | ||
|
|
1f5b6b0b01 | ||
|
|
51fdcbe313 | ||
|
|
088fad8aee | ||
|
|
5f292e1913 | ||
|
|
1791386c64 | ||
|
|
df552885b4 | ||
|
|
82e4d36464 | ||
|
|
da3c48ad5e | ||
|
|
4eb6ff3dba | ||
|
|
85d27188ee | ||
|
|
6183f936cb | ||
|
|
c100d0b1d1 | ||
|
|
943a6fd226 | ||
|
|
eb5959a975 | ||
|
|
0faf517d8f | ||
|
|
4a4eb307bc | ||
|
|
0742b5aef4 | ||
|
|
22b91faf71 | ||
|
|
09c2128388 | ||
|
|
c6618cd932 | ||
|
|
a3b0d88999 | ||
|
|
93b0171436 | ||
|
|
ed69915062 | ||
|
|
6887774823 | ||
|
|
58efd34f8c | ||
|
|
92fe621425 | ||
|
|
cc56090ba4 | ||
|
|
996edf9ed8 | ||
|
|
3a10a15aae | ||
|
|
3b5c359ab4 | ||
|
|
221fbddec2 | ||
|
|
f8cba6e952 | ||
|
|
5de295533b | ||
|
|
e1ed67b5d3 | ||
|
|
173d8009a7 | ||
|
|
a5d08d727a | ||
|
|
bcd08657f1 | ||
|
|
dd2e95f38c | ||
|
|
724dc834aa | ||
|
|
a29682c7b9 | ||
|
|
ba3bd4f80d | ||
|
|
30f8d869a9 | ||
|
|
4901aed041 | ||
|
|
073c7f7f24 | ||
|
|
b7894d0e40 | ||
|
|
3e4b4bc910 | ||
|
|
b6b435f6b7 | ||
|
|
d4c5baee8b | ||
|
|
1db0b79092 | ||
|
|
cfac1c4043 | ||
|
|
8d9c3f09ff | ||
|
|
b83e06d5e0 | ||
|
|
e79fc57e49 | ||
|
|
411e0e196f | ||
|
|
0d28649e65 | ||
|
|
57a8a13511 | ||
|
|
f6fd7141ad | ||
|
|
0f9779e4cd | ||
|
|
9fde75863b | ||
|
|
9d58695636 | ||
|
|
f5fb224be0 | ||
|
|
07e90b1b7c | ||
|
|
0b3dd03da2 | ||
|
|
fdd6d028d5 | ||
|
|
93e7afcdc6 | ||
|
|
12ab63f541 | ||
|
|
486a9bb329 | ||
|
|
edbbaa7ee2 | ||
|
|
b0646647c8 | ||
|
|
4f5e81f943 | ||
|
|
8f0d52538f | ||
|
|
6a960d5bd5 | ||
|
|
2f5ea15208 | ||
|
|
919e44c2c4 | ||
|
|
a335d0e070 | ||
|
|
a2d197a8b9 | ||
|
|
c7a25c7501 | ||
|
|
6b8525ce1b | ||
|
|
2138b51ee3 | ||
|
|
c83019ca1d | ||
|
|
fd1bb71f3e | ||
|
|
52a8afe3ef | ||
|
|
fb62b825fc | ||
|
|
1d9012b1e6 | ||
|
|
a69ec9e378 | ||
|
|
46b38616bf | ||
|
|
235d457ff2 | ||
|
|
596e29a8c8 | ||
|
|
6d7872f4f5 | ||
|
|
4b6e7a84af | ||
|
|
56945df5b8 | ||
|
|
8ccbd4b52f | ||
|
|
721705e067 | ||
|
|
dec3b4a6d4 | ||
|
|
e789fbd71c | ||
|
|
e3ee48415b | ||
|
|
024b2f3e78 | ||
|
|
50c06a9a29 | ||
|
|
d188edf25b | ||
|
|
ea86221710 | ||
|
|
c302bf78f6 | ||
|
|
b993c55e9a | ||
|
|
71a678cf9a | ||
|
|
10e984c94b | ||
|
|
dc9e41c55a | ||
|
|
03f70879f2 | ||
|
|
1152715646 | ||
|
|
8abae7cc85 | ||
|
|
6041cbf595 | ||
|
|
ed4c9169b3 | ||
|
|
d8b5331544 | ||
|
|
a0b589ecd2 | ||
|
|
6f5f5e7493 | ||
|
|
b3d2ee8016 | ||
|
|
cbc5ce1601 | ||
|
|
8a0e122dc9 | ||
|
|
74325078cc | ||
|
|
111a07c016 | ||
|
|
c318b31fd7 | ||
|
|
72261c4fcd | ||
|
|
92e5a50f9b | ||
|
|
9f99d65e39 | ||
|
|
8d98a8e205 | ||
|
|
77983167db | ||
|
|
d1df07f13d | ||
|
|
70685c94a4 | ||
|
|
d761611056 | ||
|
|
87318f5a14 | ||
|
|
94063f2f33 | ||
|
|
fc7df4748f | ||
|
|
24dd89884b | ||
|
|
e69281e341 | ||
|
|
ddc06f1d7e | ||
|
|
8d23c0e482 | ||
|
|
28618367ea | ||
|
|
b1382e0be3 | ||
|
|
c1e63d2486 | ||
|
|
b56345fcdf | ||
|
|
0221a1c7da | ||
|
|
de60112928 | ||
|
|
7a1e500946 | ||
|
|
eea9740f4f | ||
|
|
73a3d17f29 | ||
|
|
f68e420318 | ||
|
|
b87463a60d | ||
|
|
107cdd3f54 | ||
|
|
d9d2c9c64b | ||
|
|
b911c8df23 | ||
|
|
9bc8d017e6 | ||
|
|
a7a4c81468 | ||
|
|
cbe9f66990 | ||
|
|
1c395a3153 | ||
|
|
0636e815db | ||
|
|
b46edb4d1a | ||
|
|
5fdd96f576 | ||
|
|
033dbc1192 | ||
|
|
67892d46a8 | ||
|
|
d2f27e6f2e | ||
|
|
57ab7fda84 | ||
|
|
139359a760 | ||
|
|
38b7ac7c23 | ||
|
|
52996d4fc5 | ||
|
|
4dbced4f55 | ||
|
|
c5e17be6db | ||
|
|
1c7a6e9fef | ||
|
|
f104a5daff | ||
|
|
216d312ebe | ||
|
|
9b277a0276 | ||
|
|
c7a3d4c032 | ||
|
|
1c4ffa33d3 | ||
|
|
908b6a7a0c | ||
|
|
14d7975c7a | ||
|
|
f9f2121219 | ||
|
|
e22d262bbf | ||
|
|
ae9976b050 | ||
|
|
124c9d60b3 | ||
|
|
9f7e1ecfc1 | ||
|
|
b68fcecd46 | ||
|
|
29e025bbfc | ||
|
|
01c3413687 | ||
|
|
a64480dfab | ||
|
|
bbe805f017 | ||
|
|
aa7a6f9e64 | ||
|
|
43af6391f0 | ||
|
|
5f143a8e41 | ||
|
|
bbe4fda350 | ||
|
|
afec9fbaa2 | ||
|
|
20f9f2e530 | ||
|
|
060a3bfae2 | ||
|
|
e75f5a87c2 | ||
|
|
d9cc5cb364 | ||
|
|
dd82546998 | ||
|
|
7c4a90c51a | ||
|
|
fb622e8c4c | ||
|
|
d0e2894137 | ||
|
|
448c3e864b | ||
|
|
9770e09d96 | ||
|
|
8294784268 | ||
|
|
fe7627e169 | ||
|
|
0d084f00c6 | ||
|
|
5f4610a4cb | ||
|
|
35e1f36f44 | ||
|
|
c2a2ce4a4c | ||
|
|
77a30ae720 | ||
|
|
3ed9e7ab2f | ||
|
|
f33e2698a0 | ||
|
|
a606a0bd77 | ||
|
|
e3ec7708e3 | ||
|
|
fe7a07d6c5 | ||
|
|
260c3fc52a | ||
|
|
e0d208e508 | ||
|
|
9e882cd9d5 | ||
|
|
d96af71220 | ||
|
|
2f08343015 | ||
|
|
113e6214f2 | ||
|
|
21fd7ca0c5 | ||
|
|
0b41775618 | ||
|
|
9181c83a87 | ||
|
|
66257f1cf3 | ||
|
|
b42aebd99f | ||
|
|
77c9991a35 |
@@ -1,2 +1,3 @@
|
||||
---
|
||||
BUNDLE_WITHOUT: "development:test"
|
||||
BUNDLE_WITH: "geoip:ext_msf:ext_notifications:ext_dns:ext_qrcode"
|
||||
|
||||
8
.dockerignore
Normal file
8
.dockerignore
Normal file
@@ -0,0 +1,8 @@
|
||||
# Don't copy over git files
|
||||
.git
|
||||
.github
|
||||
.gitignore
|
||||
doc
|
||||
docs
|
||||
test
|
||||
update-beef
|
||||
77
.github/ISSUE_TEMPLATE.md
vendored
77
.github/ISSUE_TEMPLATE.md
vendored
@@ -1,66 +1,31 @@
|
||||
# Submit Issue
|
||||
|
||||
Verify first that your issue/request has not been posted previously:
|
||||
|
||||
* https://github.com/beefproject/beef/issues
|
||||
* https://github.com/beefproject/beef/wiki/FAQ
|
||||
|
||||
Ensure you're using the [latest version of BeEF](https://github.com/beefproject/beef/releases/tag/v0.5.3.0).
|
||||
|
||||
Please do your best to provide as much information as possible. It will help substantially if you can enable and provide debugging logs with your issue. Instructions for enabling debugging logs are below:
|
||||
|
||||
1. In the `config.yaml` file of your BeEF root folder set debug and client_debug (lines 11 & 13 respectively) to `true`
|
||||
* If using a standard installation of `beef-xss` the root folder will typically be `/usr/share/beef-xss`
|
||||
2. Reproduce your error
|
||||
3. Retrieve your client-side logs from your browser's developer console (Ctrl + Shift + I)
|
||||
4. Retrieve your server-side logs from `~/.beef/beef.log`
|
||||
5. **If using `beef-xss`:** Retrieve your service logs using `journalctl -u beef-xss`
|
||||
|
||||
Thank you, this will greatly aid us in identifying the root cause of your issue :)
|
||||
|
||||
**If we request additional information and we don't hear back from you within a week, we will be closing the ticket off.**
|
||||
Feel free to open it back up if you continue to have issues.
|
||||
|
||||
## Summary
|
||||
|
||||
**Q:** Please provide a brief summary of the issue that you experienced.
|
||||
**A:**
|
||||
|
||||
## Environment
|
||||
|
||||
*Please identify the environment in which your issue occurred.*
|
||||
|
||||
1. **BeEF Version:**
|
||||
|
||||
2. **Ruby Version:**
|
||||
|
||||
3. **Browser Details (e.g. Chrome v81.0):**
|
||||
|
||||
4. **Operating System (e.g. OSX Catalina):**
|
||||
## First Steps
|
||||
|
||||
1. Confirm that your issue has not been posted previously by searching here: https://github.com/beefproject/beef/issues
|
||||
2. Confirm that the wiki does not contain the answers you seek: https://github.com/beefproject/beef/wiki
|
||||
3. Check the FAQ: https://github.com/beefproject/beef/wiki/FAQ
|
||||
4. BeEF Version:
|
||||
5. Ruby Version:
|
||||
6. Browser Details (e.g. Chrome v81.0):
|
||||
7. Operating System (e.g. OSX Catalina):
|
||||
|
||||
## Configuration
|
||||
|
||||
**Q:** Have you made any changes to your BeEF configuration?
|
||||
**A:**
|
||||
|
||||
**Q:** Have you enabled or disabled any BeEF extensions?
|
||||
**A:**
|
||||
|
||||
## Expected vs. Actual Behaviour
|
||||
|
||||
**Expected Behaviour:**
|
||||
<br />
|
||||
**Actual Behaviour:**
|
||||
<br />
|
||||
1. Have you made any changes to your BeEF configuration? Yes/No
|
||||
2. Have you enabled or disabled any BeEF extensions? Yes/No
|
||||
|
||||
## Steps to Reproduce
|
||||
|
||||
*Please provide steps to reproduce this issue.*
|
||||
1. (eg. I ran install script, which ran fine)
|
||||
2. (eg. when launching console with './beef' I get an error as follows: <error here>)
|
||||
3. (eg. beef does not launch)
|
||||
|
||||
1.
|
||||
## How to enable and capture detailed logging
|
||||
|
||||
1. Edit `config.yaml` in the root directory
|
||||
* If using Kali **beef-xss** the root dir will be `/usr/share/beef-xss`
|
||||
2. Update `client_debug` to `true`
|
||||
3. Retrieve browser logs from your browser's developer console (Ctrl + Shift + I or F12 depending on browser)
|
||||
4. Retrieve your server-side logs from `~/.beef/beef.log`
|
||||
* If using **beef-xss** logs found with `journalctl -u beef-xss`
|
||||
|
||||
## Additional Information
|
||||
|
||||
Please provide any additional information which may be useful in resolving this issue, such as debugging output and relevant screen shots. Debug output can be retrieved by following the instructions towards the top of the issue template.
|
||||
**If we request additional information and we don't hear back from you within a week, we will be closing the ticket off.**
|
||||
|
||||
72
.github/workflows/codeql.yml
vendored
Normal file
72
.github/workflows/codeql.yml
vendored
Normal file
@@ -0,0 +1,72 @@
|
||||
# For most projects, this workflow file will not need changing; you simply need
|
||||
# to commit it to your repository.
|
||||
#
|
||||
# You may wish to alter this file to override the set of languages analyzed,
|
||||
# or to provide custom queries or build logic.
|
||||
#
|
||||
# ******** NOTE ********
|
||||
# We have attempted to detect the languages in your repository. Please check
|
||||
# the `language` matrix defined below to confirm you have the correct set of
|
||||
# supported CodeQL languages.
|
||||
#
|
||||
name: "CodeQL"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
pull_request:
|
||||
# The branches below must be a subset of the branches above
|
||||
branches: [ master ]
|
||||
schedule:
|
||||
- cron: '36 1 * * 0'
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
name: Analyze
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
security-events: write
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
language: [ 'javascript', 'ruby' ]
|
||||
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
|
||||
# Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v2
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||
# By default, queries listed here will override any specified in a config file.
|
||||
# Prefix the list here with "+" to use these queries and those in the config file.
|
||||
|
||||
# Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
|
||||
queries: security-extended,security-and-quality
|
||||
|
||||
|
||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||
# If this step fails, then you should remove it and run the build manually (see below)
|
||||
# - name: Autobuild
|
||||
# uses: github/codeql-action/autobuild@v2
|
||||
|
||||
# ℹ️ Command-line programs to run using the OS shell.
|
||||
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
|
||||
|
||||
# If the Autobuild fails above, remove it and uncomment the following three lines.
|
||||
# modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance.
|
||||
|
||||
# - run: |
|
||||
# echo "Run, Build Application using script"
|
||||
# ./location_of_script_within_repo/buildscript.sh
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v2
|
||||
8
.github/workflows/github_actions.yml
vendored
8
.github/workflows/github_actions.yml
vendored
@@ -42,15 +42,19 @@ jobs:
|
||||
- name: 'Setting up Ruby'
|
||||
uses: ruby/setup-ruby@v1
|
||||
with:
|
||||
ruby-version: 2.7.2 # Not needed with a .ruby-version file
|
||||
ruby-version: 3.0.3 # Not needed with a .ruby-version file
|
||||
|
||||
- name: 'Build and run tests'
|
||||
- name: 'Update and Install Dwpendencies'
|
||||
run: |
|
||||
sudo apt update
|
||||
sudo apt install libcurl4 libcurl4-openssl-dev
|
||||
- name: 'Configure Bundle testing and install gems'
|
||||
run: |
|
||||
bundle config unset --local without
|
||||
bundle config set --local with 'test' 'development'
|
||||
bundle install
|
||||
- name: 'Run BrowserStack simple verification'
|
||||
run: |
|
||||
bundle exec rake browserstack --trace
|
||||
|
||||
- name: 'BrowserStackLocal Stop' # Terminating the BrowserStackLocal tunnel connection
|
||||
|
||||
35
.github/workflows/stale.yml
vendored
Normal file
35
.github/workflows/stale.yml
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
# This workflow warns and then closes issues and PRs that have had no activity for a specified amount of time.
|
||||
#
|
||||
# You can adjust the behavior by modifying this file.
|
||||
# For more information, see:
|
||||
# https://github.com/actions/stale
|
||||
name: Mark stale issues and pull requests
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '5 * * * *'
|
||||
|
||||
jobs:
|
||||
stale:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
issues: write
|
||||
pull-requests: write
|
||||
|
||||
steps:
|
||||
- uses: actions/stale@v5
|
||||
with:
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
days-before-stale: 7
|
||||
days-before-pr-stale: 14
|
||||
days-before-close: 7
|
||||
days-before-pr-close: 14
|
||||
stale-issue-message: 'This issue as been marked as stale due to inactivity and will be closed in 7 days'
|
||||
stale-pr-message: 'Stale pull request message'
|
||||
stale-issue-label: 'Stale'
|
||||
stale-pr-label: 'no-pr-activity'
|
||||
exempt-issue-labels: 'Critical, High, Low, Medium, Review, Backlog'
|
||||
exempt-milestones: true
|
||||
exempt-draft-pr: true
|
||||
start-date: '2022-06-15'
|
||||
54
.rubocop.yml
54
.rubocop.yml
@@ -4,7 +4,8 @@ AllCops:
|
||||
- 'tmp/**/*'
|
||||
- 'tools/**/*'
|
||||
- 'doc/**/*'
|
||||
TargetRubyVersion: 2.6
|
||||
TargetRubyVersion: 3.0
|
||||
NewCops: enable
|
||||
|
||||
Layout/LineLength:
|
||||
Enabled: true
|
||||
@@ -22,57 +23,20 @@ Metrics/ClassLength:
|
||||
Metrics/MethodLength:
|
||||
Enabled: false
|
||||
|
||||
Metrics/ModuleLength:
|
||||
Enabled: false
|
||||
|
||||
Metrics/PerceivedComplexity:
|
||||
Enabled: false
|
||||
|
||||
Metrics/CyclomaticComplexity:
|
||||
Enabled: false
|
||||
|
||||
Naming/ClassAndModuleCamelCase:
|
||||
Enabled: false
|
||||
|
||||
Style/FrozenStringLiteralComment:
|
||||
Enabled: false
|
||||
|
||||
# TODO: review these
|
||||
Layout/SpaceBeforeBrackets:
|
||||
Enabled: false
|
||||
Lint/AmbiguousAssignment:
|
||||
Enabled: false
|
||||
Lint/DeprecatedConstants:
|
||||
Enabled: false
|
||||
Lint/DuplicateBranch:
|
||||
Enabled: false
|
||||
Lint/DuplicateRegexpCharacterClassElement:
|
||||
Enabled: false
|
||||
Lint/EmptyBlock:
|
||||
Enabled: false
|
||||
Lint/EmptyClass:
|
||||
Enabled: false
|
||||
Lint/LambdaWithoutLiteralBlock:
|
||||
Enabled: false
|
||||
Lint/NoReturnInBeginEndBlocks:
|
||||
Enabled: false
|
||||
Lint/RedundantDirGlobSort:
|
||||
Enabled: false
|
||||
Lint/ToEnumArguments:
|
||||
Enabled: false
|
||||
Lint/UnexpectedBlockArity:
|
||||
Enabled: false
|
||||
Lint/UnmodifiedReduceAccumulator:
|
||||
Enabled: false
|
||||
Style/ArgumentsForwarding:
|
||||
Enabled: false
|
||||
Style/CollectionCompact:
|
||||
Enabled: false
|
||||
Style/DocumentDynamicEvalDefinition:
|
||||
Enabled: false
|
||||
Style/EndlessMethod:
|
||||
Enabled: false
|
||||
Style/HashExcept:
|
||||
Enabled: false
|
||||
Style/NegatedIfElseCondition:
|
||||
Enabled: false
|
||||
Style/NilLambda:
|
||||
Enabled: false
|
||||
Style/RedundantArgument:
|
||||
Enabled: false
|
||||
Style/SwapValues:
|
||||
Style/Documentation:
|
||||
Enabled: false
|
||||
|
||||
@@ -1 +1 @@
|
||||
2.7.2
|
||||
3.0.3
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
{
|
||||
"id": "3b5f29e6-c8eb-4d23-bf52-c01255f22f08",
|
||||
"name": "BeEF",
|
||||
"values": [
|
||||
{
|
||||
"key": "hostname",
|
||||
"value": "127.0.0.1",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"key": "username",
|
||||
"value": "beef",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"key": "password",
|
||||
"value": "beef",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"key": "token",
|
||||
"value": "",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"key": "session",
|
||||
"value": "",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"key": "module_id",
|
||||
"value": "",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"key": "cmd_id",
|
||||
"value": "",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"key": "dnsrule_id",
|
||||
"value": "",
|
||||
"enabled": true
|
||||
}
|
||||
],
|
||||
"_postman_variable_scope": "environment",
|
||||
"_postman_exported_at": "2020-01-03T06:00:29.827Z",
|
||||
"_postman_exported_using": "Postman/7.14.0"
|
||||
}
|
||||
94
Dockerfile
94
Dockerfile
@@ -4,61 +4,85 @@
|
||||
## Please read the Wiki Installation section on set-up using Docker prior to building this container. ##
|
||||
## BeEF does NOT allow authentication with default credentials. So please, at the very least ##
|
||||
## change the username:password in the config.yaml file to something secure that is not beef:beef ##
|
||||
## before building or you will to denied access and have to rebuild anyway. ##
|
||||
## before building or you will be denied access and have to rebuild anyway. ##
|
||||
## ##
|
||||
###########################################################################################################
|
||||
###########################################################################################################
|
||||
|
||||
# ---------------------------- Start of Builder 0 - Gemset Build ------------------------------------------
|
||||
FROM ruby:2.6.3-alpine AS builder
|
||||
LABEL maintainer="Beef Project: github.com/beefproject/beef"
|
||||
|
||||
# Install gems in parallel with 4 workers to expedite build process.=
|
||||
ARG BUNDLER_ARGS="--jobs=4"
|
||||
|
||||
# Set gemrc config to install gems without Ruby Index (ri) and Ruby Documentation (rdoc) files
|
||||
RUN echo "gem: --no-ri --no-rdoc" > /etc/gemrc
|
||||
FROM ruby:3.2.1-slim-bullseye AS builder
|
||||
|
||||
COPY . /beef
|
||||
|
||||
# Add bundler/gem dependencies and then install
|
||||
RUN apk add --no-cache git curl libcurl curl-dev ruby-dev libffi-dev make g++ gcc musl-dev zlib-dev sqlite-dev && \
|
||||
bundle install --system --clean --no-cache --gemfile=/beef/Gemfile $BUNDLER_ARGS && \
|
||||
# Temp fix for https://github.com/bundler/bundler/issues/6680
|
||||
rm -rf /usr/local/bundle/cache
|
||||
|
||||
WORKDIR /beef
|
||||
|
||||
# So we don't need to run as root
|
||||
RUN chmod -R a+r /usr/local/bundle
|
||||
# Set gemrc config to install gems without Ruby Index (ri) and Ruby Documentation (rdoc) files.
|
||||
# Then add bundler/gem dependencies and install.
|
||||
# Finally change permissions of bundle installs so we don't need to run as root.
|
||||
RUN echo "gem: --no-ri --no-rdoc" > /etc/gemrc \
|
||||
&& apt-get update \
|
||||
&& apt-get install -y --no-install-recommends \
|
||||
git \
|
||||
curl \
|
||||
xz-utils \
|
||||
make \
|
||||
g++ \
|
||||
libcurl4-openssl-dev \
|
||||
ruby-dev \
|
||||
libffi-dev \
|
||||
zlib1g-dev \
|
||||
libsqlite3-dev \
|
||||
sqlite3 \
|
||||
&& bundle install --gemfile=/beef/Gemfile --jobs=`nproc` \
|
||||
&& rm -rf /usr/local/bundle/cache \
|
||||
&& chmod -R a+r /usr/local/bundle \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
# ------------------------------------- End of Builder 0 -------------------------------------------------
|
||||
|
||||
|
||||
# ---------------------------- Start of Builder 1 - Final Build ------------------------------------------
|
||||
FROM ruby:2.6.3-alpine
|
||||
LABEL maintainer="Beef Project: github.com/beefproject/beef"
|
||||
FROM ruby:3.2.1-slim-bullseye
|
||||
LABEL maintainer="Beef Project" \
|
||||
source_url="github.com/beefproject/beef" \
|
||||
homepage="https://beefproject.com/"
|
||||
|
||||
# Create service account to run BeEF
|
||||
RUN adduser -h /beef -g beef -D beef
|
||||
# BeEF UI/Hook port
|
||||
ARG UI_PORT=3000
|
||||
ARG PROXY_PORT=6789
|
||||
ARG WEBSOCKET_PORT=61985
|
||||
ARG WEBSOCKET_SECURE_PORT=61986
|
||||
|
||||
COPY . /beef
|
||||
|
||||
# Create service account to run BeEF and install BeEF's runtime dependencies
|
||||
RUN adduser --home /beef --gecos beef --disabled-password beef \
|
||||
&& apt-get update \
|
||||
&& apt-get install -y --no-install-recommends \
|
||||
curl \
|
||||
openssl \
|
||||
libssl-dev \
|
||||
libreadline-dev \
|
||||
libyaml-dev \
|
||||
libxml2-dev \
|
||||
libxslt-dev \
|
||||
libncurses5-dev \
|
||||
libsqlite3-dev \
|
||||
sqlite3 \
|
||||
zlib1g \
|
||||
bison \
|
||||
nodejs \
|
||||
&& apt-get -y clean \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Use gemset created by the builder above
|
||||
COPY --chown=beef:beef . /beef
|
||||
COPY --from=builder /usr/local/bundle /usr/local/bundle
|
||||
|
||||
# Grant beef service account owner and groups rights over our BeEF working directory.
|
||||
RUN chown -R beef:beef /beef
|
||||
|
||||
# Install BeEF's runtime dependencies
|
||||
RUN apk add --no-cache curl git build-base openssl readline-dev zlib zlib-dev libressl-dev yaml-dev sqlite-dev sqlite libxml2-dev libxslt-dev autoconf libc6-compat ncurses5 automake libtool bison nodejs
|
||||
|
||||
WORKDIR /beef
|
||||
|
||||
# Ensure we are using our service account by default
|
||||
USER beef
|
||||
|
||||
# Expose UI, Proxy, WebSocket server, and WebSocketSecure server
|
||||
EXPOSE 3000 6789 61985 61986
|
||||
# Expose UI, Proxy, WebSocket server, and WebSocketSecure server ports
|
||||
EXPOSE $UI_PORT $PROXY_PORT $WEBSOCKET_PORT $WEBSOCKET_SECURE_PORT
|
||||
|
||||
HEALTHCHECK --interval=30s --timeout=30s --start-period=5s --retries=3 CMD [ "curl", "-fS", "localhost:$UI_PORT" ]
|
||||
|
||||
WORKDIR /beef
|
||||
ENTRYPOINT ["/beef/beef"]
|
||||
# ------------------------------------- End of Builder 1 -------------------------------------------------
|
||||
# ------------------------------------- End of Builder 1 -------------------------------------------------
|
||||
|
||||
101
Gemfile
101
Gemfile
@@ -1,92 +1,91 @@
|
||||
# BeEF's Gemfile
|
||||
|
||||
#
|
||||
# Copyright (c) 2006-2021 Wade Alcorn - wade@bindshell.net
|
||||
# Copyright (c) 2006-2024 Wade Alcorn - wade@bindshell.net
|
||||
# Browser Exploitation Framework (BeEF) - http://beefproject.com
|
||||
# See the file 'doc/COPYING' for copying permission
|
||||
#
|
||||
#gem 'simplecov', require: false, group: :test
|
||||
gem 'eventmachine'
|
||||
gem 'thin'
|
||||
gem 'sinatra', '>= 2.0.2'
|
||||
gem 'rack', '>= 2.2.3'
|
||||
gem 'rack-protection', '>= 2.0.0'
|
||||
gem 'em-websocket' # WebSocket support
|
||||
gem 'uglifier', '>= 2.7.2'
|
||||
gem 'mime-types'
|
||||
gem 'execjs'
|
||||
gem 'ansi'
|
||||
gem 'term-ansicolor', :require => 'term/ansicolor'
|
||||
|
||||
gem 'net-smtp', require: false
|
||||
gem 'json'
|
||||
gem 'rubyzip', '>= 1.2.2'
|
||||
gem 'espeak-ruby', '>= 1.0.4' # Text-to-Voice
|
||||
gem 'rake', '>= 12.3.3'
|
||||
gem 'otr-activerecord', '>= 1.4.2'
|
||||
gem 'sqlite3'
|
||||
gem 'rubocop', '~> 1.22.3', require: false
|
||||
|
||||
gem 'eventmachine', '~> 1.2', '>= 1.2.7'
|
||||
gem 'thin', '~> 1.8'
|
||||
gem 'sinatra', '~> 3.0'
|
||||
gem 'rack', '~> 2.2'
|
||||
gem 'rack-protection', '~> 3.0.5'
|
||||
gem 'em-websocket', '~> 0.5.3' # WebSocket support
|
||||
gem 'uglifier', '~> 4.2'
|
||||
gem 'mime-types', '~> 3.4', '>= 3.4.1'
|
||||
gem 'execjs', '~> 2.9'
|
||||
gem 'ansi', '~> 1.5'
|
||||
gem 'term-ansicolor', :require => 'term/ansicolor'
|
||||
gem 'rubyzip', '~> 2.3'
|
||||
gem 'espeak-ruby', '~> 1.1.0' # Text-to-Voice
|
||||
gem 'rake', '~> 13.1'
|
||||
# gem 'otr-activerecord', '~> 2.1', '>= 2.1.2'
|
||||
gem 'otr-activerecord', '= 2.1.2'
|
||||
gem 'sqlite3', '~> 1.6'
|
||||
gem 'rubocop', '~> 1.59.0', require: false
|
||||
|
||||
# Geolocation support
|
||||
group :geoip do
|
||||
gem 'maxmind-db'
|
||||
gem 'maxmind-db', '~> 1.2'
|
||||
end
|
||||
|
||||
gem 'parseconfig'
|
||||
gem 'erubis'
|
||||
gem 'parseconfig', '~> 1.1', '>= 1.1.2'
|
||||
gem 'erubis', '~> 2.7'
|
||||
|
||||
# Metasploit Integration extension
|
||||
group :ext_msf do
|
||||
gem 'msfrpc-client'
|
||||
gem 'xmlrpc'
|
||||
gem 'msfrpc-client', '~> 1.1', '>= 1.1.2'
|
||||
gem 'xmlrpc', '~> 0.3.3'
|
||||
end
|
||||
|
||||
# Notifications extension
|
||||
group :ext_notifications do
|
||||
# Pushover
|
||||
gem 'rushover'
|
||||
gem 'rushover', '~> 0.3.0'
|
||||
# Slack
|
||||
gem 'slack-notifier'
|
||||
# Twitter
|
||||
gem 'twitter', '>= 5.0.0'
|
||||
gem 'slack-notifier', '~> 2.4'
|
||||
end
|
||||
|
||||
# DNS extension
|
||||
group :ext_dns do
|
||||
gem 'async-dns'
|
||||
gem 'async-dns', '~> 1.3'
|
||||
gem 'async', '~> 1.31'
|
||||
end
|
||||
|
||||
# QRcode extension
|
||||
group :ext_qrcode do
|
||||
gem 'qr4r'
|
||||
gem 'qr4r', '~> 0.6.1'
|
||||
end
|
||||
|
||||
# For running unit tests
|
||||
group :test do
|
||||
gem 'test-unit'
|
||||
gem 'test-unit-full'
|
||||
gem 'rspec'
|
||||
gem 'rdoc'
|
||||
gem 'test-unit-full', '~> 0.0.5'
|
||||
gem 'rspec', '~> 3.12'
|
||||
gem 'rdoc', '~> 6.6'
|
||||
gem 'browserstack-local', '~> 1.4'
|
||||
|
||||
gem 'irb', '~> 1.11'
|
||||
gem 'pry-byebug', '~> 3.10', '>= 3.10.1'
|
||||
|
||||
gem 'rest-client', '~> 2.1.0'
|
||||
gem 'websocket-client-simple', '~> 0.6.1'
|
||||
|
||||
# curb gem requires curl libraries
|
||||
# sudo apt-get install libcurl4-openssl-dev
|
||||
gem 'curb'
|
||||
gem 'curb', '~> 1.0', '>= 1.0.5'
|
||||
|
||||
# selenium-webdriver 3.x is incompatible with Firefox version 48 and prior
|
||||
# gem 'selenium' # Requires old version of selenium which is no longer available
|
||||
gem 'geckodriver-helper'
|
||||
gem 'selenium-webdriver'
|
||||
# nokogirl is needed by capybara which may require one of the below commands
|
||||
gem 'geckodriver-helper', '~> 0.24.0'
|
||||
gem 'selenium-webdriver', '~> 4.16'
|
||||
|
||||
# nokogiri is needed by capybara which may require one of the below commands
|
||||
# sudo apt-get install libxslt-dev libxml2-dev
|
||||
# sudo port install libxml2 libxslt
|
||||
gem 'capybara'
|
||||
# RESTful API tests/generic command module tests
|
||||
gem 'rest-client', '>= 2.0.1'
|
||||
gem 'irb'
|
||||
gem 'pry-byebug'
|
||||
gem "websocket-client-simple", "~> 0.3.0"
|
||||
gem "browserstack-local", "~> 1.3"
|
||||
gem 'capybara', '~> 3.39'
|
||||
end
|
||||
|
||||
source 'https://rubygems.org'
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
327
Gemfile.lock
327
Gemfile.lock
@@ -1,35 +1,33 @@
|
||||
GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
activemodel (6.1.4.1)
|
||||
activesupport (= 6.1.4.1)
|
||||
activerecord (6.1.4.1)
|
||||
activemodel (= 6.1.4.1)
|
||||
activesupport (= 6.1.4.1)
|
||||
activesupport (6.1.4.1)
|
||||
activemodel (7.0.4.3)
|
||||
activesupport (= 7.0.4.3)
|
||||
activerecord (7.0.4.3)
|
||||
activemodel (= 7.0.4.3)
|
||||
activesupport (= 7.0.4.3)
|
||||
activesupport (7.0.4.3)
|
||||
concurrent-ruby (~> 1.0, >= 1.0.2)
|
||||
i18n (>= 1.6, < 2)
|
||||
minitest (>= 5.1)
|
||||
tzinfo (~> 2.0)
|
||||
zeitwerk (~> 2.3)
|
||||
addressable (2.8.0)
|
||||
public_suffix (>= 2.0.2, < 5.0)
|
||||
addressable (2.8.4)
|
||||
public_suffix (>= 2.0.2, < 6.0)
|
||||
ansi (1.5.0)
|
||||
archive-zip (0.12.0)
|
||||
io-like (~> 0.3.0)
|
||||
ast (2.4.2)
|
||||
async (1.30.1)
|
||||
async (1.31.0)
|
||||
console (~> 1.10)
|
||||
nio4r (~> 2.3)
|
||||
timers (~> 4.1)
|
||||
async-dns (1.3.0)
|
||||
async-io (~> 1.15)
|
||||
async-io (1.32.2)
|
||||
async-io (1.34.3)
|
||||
async
|
||||
browserstack-local (1.3.0)
|
||||
buftok (0.2.0)
|
||||
browserstack-local (1.4.3)
|
||||
byebug (11.1.3)
|
||||
capybara (3.36.0)
|
||||
capybara (3.39.2)
|
||||
addressable
|
||||
matrix
|
||||
mini_mime (>= 0.1.3)
|
||||
@@ -38,161 +36,157 @@ GEM
|
||||
rack-test (>= 0.6.3)
|
||||
regexp_parser (>= 1.5, < 3.0)
|
||||
xpath (~> 3.2)
|
||||
childprocess (3.0.0)
|
||||
coderay (1.1.3)
|
||||
concurrent-ruby (1.1.9)
|
||||
console (1.13.1)
|
||||
concurrent-ruby (1.2.2)
|
||||
console (1.16.2)
|
||||
fiber-local
|
||||
curb (0.9.11)
|
||||
curb (1.0.5)
|
||||
daemons (1.4.1)
|
||||
diff-lcs (1.4.4)
|
||||
diff-lcs (1.5.0)
|
||||
domain_name (0.5.20190701)
|
||||
unf (>= 0.0.5, < 1.0.0)
|
||||
em-websocket (0.5.2)
|
||||
em-websocket (0.5.3)
|
||||
eventmachine (>= 0.12.9)
|
||||
http_parser.rb (~> 0.6.0)
|
||||
equalizer (0.0.11)
|
||||
http_parser.rb (~> 0)
|
||||
erubis (2.7.0)
|
||||
espeak-ruby (1.0.4)
|
||||
espeak-ruby (1.1.0)
|
||||
event_emitter (0.2.6)
|
||||
eventmachine (1.2.7)
|
||||
execjs (2.8.1)
|
||||
ffi (1.15.4)
|
||||
ffi-compiler (1.0.1)
|
||||
ffi (>= 1.0.0)
|
||||
rake
|
||||
execjs (2.9.1)
|
||||
fiber-local (1.0.0)
|
||||
geckodriver-helper (0.24.0)
|
||||
archive-zip (~> 0.7)
|
||||
hashie (4.1.0)
|
||||
hashie (5.0.0)
|
||||
hashie-forbidden_attributes (0.1.1)
|
||||
hashie (>= 3.0)
|
||||
http (4.4.1)
|
||||
addressable (~> 2.3)
|
||||
http-cookie (~> 1.0)
|
||||
http-form_data (~> 2.2)
|
||||
http-parser (~> 1.2.0)
|
||||
http-accept (1.7.0)
|
||||
http-cookie (1.0.4)
|
||||
http-cookie (1.0.5)
|
||||
domain_name (~> 0.5)
|
||||
http-form_data (2.3.0)
|
||||
http-parser (1.2.3)
|
||||
ffi-compiler (>= 1.0, < 2.0)
|
||||
http_parser.rb (0.6.0)
|
||||
i18n (1.8.10)
|
||||
http_parser.rb (0.8.0)
|
||||
i18n (1.12.0)
|
||||
concurrent-ruby (~> 1.0)
|
||||
io-console (0.5.9)
|
||||
io-console (0.7.1)
|
||||
io-like (0.3.1)
|
||||
irb (1.3.7)
|
||||
reline (>= 0.2.7)
|
||||
json (2.6.1)
|
||||
irb (1.11.0)
|
||||
rdoc
|
||||
reline (>= 0.3.8)
|
||||
json (2.6.3)
|
||||
language_server-protocol (3.17.0.3)
|
||||
matrix (0.4.2)
|
||||
maxmind-db (1.1.1)
|
||||
memoizable (0.4.2)
|
||||
thread_safe (~> 0.3, >= 0.3.1)
|
||||
maxmind-db (1.2.0)
|
||||
method_source (1.0.0)
|
||||
mime-types (3.3.1)
|
||||
mime-types (3.4.1)
|
||||
mime-types-data (~> 3.2015)
|
||||
mime-types-data (3.2021.0901)
|
||||
mime-types-data (3.2023.0218.1)
|
||||
mini_mime (1.1.2)
|
||||
mini_portile2 (2.6.1)
|
||||
minitest (5.14.4)
|
||||
mojo_magick (0.6.6)
|
||||
minitest (5.18.0)
|
||||
mojo_magick (0.6.7)
|
||||
msfrpc-client (1.1.2)
|
||||
msgpack (~> 1)
|
||||
msgpack (1.4.2)
|
||||
multipart-post (2.1.1)
|
||||
mustermann (1.1.1)
|
||||
msgpack (1.6.1)
|
||||
mustermann (3.0.0)
|
||||
ruby2_keywords (~> 0.0.1)
|
||||
naught (1.1.0)
|
||||
net-protocol (0.2.1)
|
||||
timeout
|
||||
net-smtp (0.4.0)
|
||||
net-protocol
|
||||
netrc (0.11.0)
|
||||
nio4r (2.5.8)
|
||||
nokogiri (1.12.5)
|
||||
mini_portile2 (~> 2.6.1)
|
||||
nokogiri (1.15.2-arm64-darwin)
|
||||
racc (~> 1.4)
|
||||
otr-activerecord (2.0.3)
|
||||
nokogiri (1.15.2-x86_64-linux)
|
||||
racc (~> 1.4)
|
||||
otr-activerecord (2.1.2)
|
||||
activerecord (>= 4.0, < 7.1)
|
||||
hashie-forbidden_attributes (~> 0.1)
|
||||
parallel (1.21.0)
|
||||
parallel (1.24.0)
|
||||
parseconfig (1.1.2)
|
||||
parser (3.0.2.0)
|
||||
parser (3.2.2.4)
|
||||
ast (~> 2.4.1)
|
||||
power_assert (2.0.1)
|
||||
pry (0.13.1)
|
||||
racc
|
||||
power_assert (2.0.3)
|
||||
pry (0.14.2)
|
||||
coderay (~> 1.1)
|
||||
method_source (~> 1.0)
|
||||
pry-byebug (3.9.0)
|
||||
pry-byebug (3.10.1)
|
||||
byebug (~> 11.0)
|
||||
pry (~> 0.13.0)
|
||||
public_suffix (4.0.6)
|
||||
pry (>= 0.13, < 0.15)
|
||||
psych (5.1.2)
|
||||
stringio
|
||||
public_suffix (5.0.1)
|
||||
qr4r (0.6.1)
|
||||
mojo_magick (~> 0.6.5)
|
||||
rqrcode_core (~> 0.1)
|
||||
racc (1.6.0)
|
||||
rack (2.2.3)
|
||||
rack-protection (2.1.0)
|
||||
racc (1.7.3)
|
||||
rack (2.2.7)
|
||||
rack-protection (3.0.6)
|
||||
rack
|
||||
rack-test (1.1.0)
|
||||
rack (>= 1.0, < 3)
|
||||
rainbow (3.0.0)
|
||||
rake (13.0.6)
|
||||
rdoc (6.3.2)
|
||||
regexp_parser (2.1.1)
|
||||
reline (0.2.7)
|
||||
rack-test (2.1.0)
|
||||
rack (>= 1.3)
|
||||
rainbow (3.1.1)
|
||||
rake (13.1.0)
|
||||
rdoc (6.6.2)
|
||||
psych (>= 4.0.0)
|
||||
regexp_parser (2.8.3)
|
||||
reline (0.4.1)
|
||||
io-console (~> 0.5)
|
||||
rest-client (2.1.0)
|
||||
http-accept (>= 1.7.0, < 2.0)
|
||||
http-cookie (>= 1.0.2, < 2.0)
|
||||
mime-types (>= 1.16, < 4.0)
|
||||
netrc (~> 0.8)
|
||||
rexml (3.2.5)
|
||||
rexml (3.2.6)
|
||||
rqrcode_core (0.2.0)
|
||||
rr (3.0.7)
|
||||
rspec (3.10.0)
|
||||
rspec-core (~> 3.10.0)
|
||||
rspec-expectations (~> 3.10.0)
|
||||
rspec-mocks (~> 3.10.0)
|
||||
rspec-core (3.10.1)
|
||||
rspec-support (~> 3.10.0)
|
||||
rspec-expectations (3.10.1)
|
||||
rr (3.1.0)
|
||||
rspec (3.12.0)
|
||||
rspec-core (~> 3.12.0)
|
||||
rspec-expectations (~> 3.12.0)
|
||||
rspec-mocks (~> 3.12.0)
|
||||
rspec-core (3.12.1)
|
||||
rspec-support (~> 3.12.0)
|
||||
rspec-expectations (3.12.2)
|
||||
diff-lcs (>= 1.2.0, < 2.0)
|
||||
rspec-support (~> 3.10.0)
|
||||
rspec-mocks (3.10.2)
|
||||
rspec-support (~> 3.12.0)
|
||||
rspec-mocks (3.12.4)
|
||||
diff-lcs (>= 1.2.0, < 2.0)
|
||||
rspec-support (~> 3.10.0)
|
||||
rspec-support (3.10.2)
|
||||
rubocop (1.22.3)
|
||||
rspec-support (~> 3.12.0)
|
||||
rspec-support (3.12.0)
|
||||
rubocop (1.59.0)
|
||||
json (~> 2.3)
|
||||
language_server-protocol (>= 3.17.0)
|
||||
parallel (~> 1.10)
|
||||
parser (>= 3.0.0.0)
|
||||
parser (>= 3.2.2.4)
|
||||
rainbow (>= 2.2.2, < 4.0)
|
||||
regexp_parser (>= 1.8, < 3.0)
|
||||
rexml
|
||||
rubocop-ast (>= 1.12.0, < 2.0)
|
||||
rexml (>= 3.2.5, < 4.0)
|
||||
rubocop-ast (>= 1.30.0, < 2.0)
|
||||
ruby-progressbar (~> 1.7)
|
||||
unicode-display_width (>= 1.4.0, < 3.0)
|
||||
rubocop-ast (1.12.0)
|
||||
parser (>= 3.0.1.1)
|
||||
ruby-progressbar (1.11.0)
|
||||
unicode-display_width (>= 2.4.0, < 3.0)
|
||||
rubocop-ast (1.30.0)
|
||||
parser (>= 3.2.1.0)
|
||||
ruby-progressbar (1.13.0)
|
||||
ruby2_keywords (0.0.5)
|
||||
rubyzip (2.3.2)
|
||||
rushover (0.3.0)
|
||||
json
|
||||
rest-client
|
||||
selenium-webdriver (3.142.7)
|
||||
childprocess (>= 0.5, < 4.0)
|
||||
rubyzip (>= 1.2.2)
|
||||
simple_oauth (0.3.1)
|
||||
sinatra (2.1.0)
|
||||
mustermann (~> 1.0)
|
||||
rack (~> 2.2)
|
||||
rack-protection (= 2.1.0)
|
||||
selenium-webdriver (4.16.0)
|
||||
rexml (~> 3.2, >= 3.2.5)
|
||||
rubyzip (>= 1.2.2, < 3.0)
|
||||
websocket (~> 1.0)
|
||||
sinatra (3.0.6)
|
||||
mustermann (~> 3.0)
|
||||
rack (~> 2.2, >= 2.2.4)
|
||||
rack-protection (= 3.0.6)
|
||||
tilt (~> 2.0)
|
||||
slack-notifier (2.4.0)
|
||||
sqlite3 (1.4.2)
|
||||
sqlite3 (1.6.9-arm64-darwin)
|
||||
sqlite3 (1.6.9-x86_64-linux)
|
||||
stringio (3.1.0)
|
||||
sync (0.5.0)
|
||||
term-ansicolor (1.7.1)
|
||||
tins (~> 1.0)
|
||||
test-unit (3.5.1)
|
||||
test-unit (3.5.7)
|
||||
power_assert
|
||||
test-unit-context (0.5.1)
|
||||
test-unit (>= 2.4.0)
|
||||
@@ -209,90 +203,79 @@ GEM
|
||||
test-unit (>= 2.5.2)
|
||||
test-unit-runner-tap (1.1.2)
|
||||
test-unit
|
||||
thin (1.8.1)
|
||||
thin (1.8.2)
|
||||
daemons (~> 1.0, >= 1.0.9)
|
||||
eventmachine (~> 1.0, >= 1.0.4)
|
||||
rack (>= 1, < 3)
|
||||
thread_safe (0.3.6)
|
||||
tilt (2.0.10)
|
||||
timers (4.3.3)
|
||||
tins (1.29.1)
|
||||
tilt (2.1.0)
|
||||
timeout (0.4.0)
|
||||
timers (4.3.5)
|
||||
tins (1.32.1)
|
||||
sync
|
||||
twitter (7.0.0)
|
||||
addressable (~> 2.3)
|
||||
buftok (~> 0.2.0)
|
||||
equalizer (~> 0.0.11)
|
||||
http (~> 4.0)
|
||||
http-form_data (~> 2.0)
|
||||
http_parser.rb (~> 0.6.0)
|
||||
memoizable (~> 0.4.0)
|
||||
multipart-post (~> 2.0)
|
||||
naught (~> 1.0)
|
||||
simple_oauth (~> 0.3.0)
|
||||
tzinfo (2.0.4)
|
||||
tzinfo (2.0.6)
|
||||
concurrent-ruby (~> 1.0)
|
||||
uglifier (4.2.0)
|
||||
execjs (>= 0.3.0, < 3)
|
||||
unf (0.1.4)
|
||||
unf_ext
|
||||
unf_ext (0.0.7.7)
|
||||
unicode-display_width (2.1.0)
|
||||
webrick (1.7.0)
|
||||
websocket (1.2.9)
|
||||
websocket-client-simple (0.3.0)
|
||||
unf_ext (0.0.8.2)
|
||||
unicode-display_width (2.5.0)
|
||||
webrick (1.8.1)
|
||||
websocket (1.2.10)
|
||||
websocket-client-simple (0.6.1)
|
||||
event_emitter
|
||||
websocket
|
||||
xmlrpc (0.3.2)
|
||||
xmlrpc (0.3.3)
|
||||
webrick
|
||||
xpath (3.2.0)
|
||||
nokogiri (~> 1.8)
|
||||
zeitwerk (2.5.1)
|
||||
|
||||
PLATFORMS
|
||||
ruby
|
||||
arm64-darwin-22
|
||||
x86_64-linux
|
||||
|
||||
DEPENDENCIES
|
||||
ansi
|
||||
async-dns
|
||||
browserstack-local (~> 1.3)
|
||||
capybara
|
||||
curb
|
||||
em-websocket
|
||||
erubis
|
||||
espeak-ruby (>= 1.0.4)
|
||||
eventmachine
|
||||
execjs
|
||||
geckodriver-helper
|
||||
irb
|
||||
ansi (~> 1.5)
|
||||
async (~> 1.31)
|
||||
async-dns (~> 1.3)
|
||||
browserstack-local (~> 1.4)
|
||||
capybara (~> 3.39)
|
||||
curb (~> 1.0, >= 1.0.5)
|
||||
em-websocket (~> 0.5.3)
|
||||
erubis (~> 2.7)
|
||||
espeak-ruby (~> 1.1.0)
|
||||
eventmachine (~> 1.2, >= 1.2.7)
|
||||
execjs (~> 2.9)
|
||||
geckodriver-helper (~> 0.24.0)
|
||||
irb (~> 1.11)
|
||||
json
|
||||
maxmind-db
|
||||
mime-types
|
||||
msfrpc-client
|
||||
otr-activerecord (>= 1.4.2)
|
||||
parseconfig
|
||||
pry-byebug
|
||||
qr4r
|
||||
rack (>= 2.2.3)
|
||||
rack-protection (>= 2.0.0)
|
||||
rake (>= 12.3.3)
|
||||
rdoc
|
||||
rest-client (>= 2.0.1)
|
||||
rspec
|
||||
rubocop (~> 1.22.3)
|
||||
rubyzip (>= 1.2.2)
|
||||
rushover
|
||||
selenium-webdriver
|
||||
sinatra (>= 2.0.2)
|
||||
slack-notifier
|
||||
sqlite3
|
||||
maxmind-db (~> 1.2)
|
||||
mime-types (~> 3.4, >= 3.4.1)
|
||||
msfrpc-client (~> 1.1, >= 1.1.2)
|
||||
net-smtp
|
||||
otr-activerecord (= 2.1.2)
|
||||
parseconfig (~> 1.1, >= 1.1.2)
|
||||
pry-byebug (~> 3.10, >= 3.10.1)
|
||||
qr4r (~> 0.6.1)
|
||||
rack (~> 2.2)
|
||||
rack-protection (~> 3.0.5)
|
||||
rake (~> 13.0)
|
||||
rdoc (~> 6.5)
|
||||
rest-client (~> 2.1.0)
|
||||
rspec (~> 3.12)
|
||||
rubocop (~> 1.59.0)
|
||||
rubyzip (~> 2.3)
|
||||
rushover (~> 0.3.0)
|
||||
selenium-webdriver (~> 4.16)
|
||||
sinatra (~> 3.0)
|
||||
slack-notifier (~> 2.4)
|
||||
sqlite3 (~> 1.6)
|
||||
term-ansicolor
|
||||
test-unit
|
||||
test-unit-full
|
||||
thin
|
||||
twitter (>= 5.0.0)
|
||||
uglifier (>= 2.7.2)
|
||||
websocket-client-simple (~> 0.3.0)
|
||||
xmlrpc
|
||||
test-unit-full (~> 0.0.5)
|
||||
thin (~> 1.8)
|
||||
uglifier (~> 4.2)
|
||||
websocket-client-simple (~> 0.6.1)
|
||||
xmlrpc (~> 0.3.3)
|
||||
|
||||
BUNDLED WITH
|
||||
2.1.4
|
||||
2.4.8
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
===============================================================================
|
||||
|
||||
Copyright (c) 2006-2021 Wade Alcorn - wade@bindshell.net
|
||||
Copyright (c) 2006-2024 Wade Alcorn - wade@bindshell.net
|
||||
Browser Exploitation Framework (BeEF) - http://beefproject.com
|
||||
See the file 'doc/COPYING' for copying permission
|
||||
|
||||
@@ -21,9 +21,9 @@ Or cloning the Git repository from Github:
|
||||
Prerequisites
|
||||
--------------
|
||||
|
||||
BeEF requires Ruby 2.5+.
|
||||
BeEF requires Ruby 3.0+.
|
||||
|
||||
If your operating system package manager does not support Ruby version 2.5,
|
||||
If your operating system package manager does not support Ruby version 3.0,
|
||||
you can add the brightbox ppa repository for the latest version of Ruby:
|
||||
|
||||
$ sudo apt-add-repository -y ppa:brightbox/ruby-ng
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
===============================================================================
|
||||
|
||||
Copyright (c) 2006-2021 Wade Alcorn - wade@bindshell.net
|
||||
Copyright (c) 2006-2024 Wade Alcorn - wade@bindshell.net
|
||||
Browser Exploitation Framework (BeEF) - http://beefproject.com
|
||||
See the file 'doc/COPYING' for copying permission
|
||||
|
||||
@@ -30,12 +30,13 @@ __Security Bugs:__ security@beefproject.com
|
||||
|
||||
__Twitter:__ [@beefproject](https://twitter.com/beefproject)
|
||||
|
||||
__Discord:__ https://discord.gg/ugmKmHarKc
|
||||
|
||||
Requirements
|
||||
------------
|
||||
|
||||
* Operating System: Mac OSX 10.5.0 or higher / modern Linux. Note: Windows is not supported.
|
||||
* [Ruby](http://ruby-lang.org): 2.5 or newer
|
||||
* [Ruby](https://www.ruby-lang.org): 3.0 or newer
|
||||
* [SQLite](http://sqlite.org): 3.x
|
||||
* [Node.js](https://nodejs.org): 10 or newer
|
||||
* The gems listed in the Gemfile: https://github.com/beefproject/beef/blob/master/Gemfile
|
||||
|
||||
@@ -1,567 +0,0 @@
|
||||
{
|
||||
"info": {
|
||||
"_postman_id": "3b47c3ff-c03f-446c-8edb-cacaab481425",
|
||||
"name": "RESTful API",
|
||||
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
|
||||
},
|
||||
"item": [
|
||||
{
|
||||
"name": "Authentication",
|
||||
"event": [
|
||||
{
|
||||
"listen": "test",
|
||||
"script": {
|
||||
"id": "8e1a5f48-1d41-469d-a153-6cd5ee751912",
|
||||
"exec": [
|
||||
"var jsonData = JSON.parse(responseBody);",
|
||||
"pm.environment.set(\"token\", jsonData.token);"
|
||||
],
|
||||
"type": "text/javascript"
|
||||
}
|
||||
}
|
||||
],
|
||||
"request": {
|
||||
"method": "POST",
|
||||
"header": [
|
||||
{
|
||||
"key": "Content-Type",
|
||||
"name": "Content-Type",
|
||||
"value": "application/json",
|
||||
"type": "text"
|
||||
}
|
||||
],
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": "{\n\t\"username\": \"{{username}}\",\n\t\"password\": \"{{password}}\"\n\t\n}",
|
||||
"options": {
|
||||
"raw": {
|
||||
"language": "json"
|
||||
}
|
||||
}
|
||||
},
|
||||
"url": {
|
||||
"raw": "http://{{hostname}}:3000/api/admin/login",
|
||||
"protocol": "http",
|
||||
"host": [
|
||||
"{{hostname}}"
|
||||
],
|
||||
"port": "3000",
|
||||
"path": [
|
||||
"api",
|
||||
"admin",
|
||||
"login"
|
||||
]
|
||||
},
|
||||
"description": "In order to use the API, a token parameter must always be added to requests, otherwise a 401 error (Not Authorized) is returned.\n\nA new pseudo-random token is generated each time BeEF starts, using BeEF::Core::Crypto::api_token. The token is added to the BeEF::Configuration object.\n\nWhen BeEF starts the token is printed to the console. It should look something like:\n\n[16:02:47][*] RESTful API key: 320f3cf4da7bf0df7566a517c5db796e73a23f47\nGrabbing the Token from BeEF's API\n\nYou can issue a POST request to /api/admin/login using the BeEF credentials you have set in the main config.yaml file. This request will return the token in the response. You can parse the JSON and use it for your next requests requiring authentication."
|
||||
},
|
||||
"response": []
|
||||
},
|
||||
{
|
||||
"name": "Get All Hooked Browsers",
|
||||
"request": {
|
||||
"method": "GET",
|
||||
"header": [],
|
||||
"url": {
|
||||
"raw": "http://{{hostname}}:3000/api/hooks?token={{token}}",
|
||||
"protocol": "http",
|
||||
"host": [
|
||||
"{{hostname}}"
|
||||
],
|
||||
"port": "3000",
|
||||
"path": [
|
||||
"api",
|
||||
"hooks"
|
||||
],
|
||||
"query": [
|
||||
{
|
||||
"key": "token",
|
||||
"value": "{{token}}"
|
||||
}
|
||||
]
|
||||
},
|
||||
"description": "Provides information (browser and OS version, cookies, enabled plugins, etc) about all hooked browsers (both online and offline)."
|
||||
},
|
||||
"response": []
|
||||
},
|
||||
{
|
||||
"name": "Get Specific Hooked Browser",
|
||||
"request": {
|
||||
"method": "GET",
|
||||
"header": [],
|
||||
"url": {
|
||||
"raw": "http://{{hostname}}:3000/api/hooks/{{session}}?token={{token}}",
|
||||
"protocol": "http",
|
||||
"host": [
|
||||
"{{hostname}}"
|
||||
],
|
||||
"port": "3000",
|
||||
"path": [
|
||||
"api",
|
||||
"hooks",
|
||||
"{{session}}"
|
||||
],
|
||||
"query": [
|
||||
{
|
||||
"key": "token",
|
||||
"value": "{{token}}"
|
||||
}
|
||||
]
|
||||
},
|
||||
"description": "\n Provides information (browser and OS version, cookies, enabled plugins, etc) about a specific hooked browser.\n"
|
||||
},
|
||||
"response": []
|
||||
},
|
||||
{
|
||||
"name": "Get All Hooked Browsers Logs",
|
||||
"request": {
|
||||
"method": "GET",
|
||||
"header": [],
|
||||
"url": {
|
||||
"raw": "http://{{hostname}}:3000/api/logs?token={{token}}",
|
||||
"protocol": "http",
|
||||
"host": [
|
||||
"{{hostname}}"
|
||||
],
|
||||
"port": "3000",
|
||||
"path": [
|
||||
"api",
|
||||
"logs"
|
||||
],
|
||||
"query": [
|
||||
{
|
||||
"key": "token",
|
||||
"value": "{{token}}"
|
||||
}
|
||||
]
|
||||
},
|
||||
"description": "The logs handler gives information about all hooked browser's logs, both global and relative."
|
||||
},
|
||||
"response": []
|
||||
},
|
||||
{
|
||||
"name": "Get Specific Hooked Browsers Logs",
|
||||
"request": {
|
||||
"method": "GET",
|
||||
"header": [],
|
||||
"url": {
|
||||
"raw": "http://{{hostname}}:3000/api/logs/{{session}}?token={{token}}",
|
||||
"protocol": "http",
|
||||
"host": [
|
||||
"{{hostname}}"
|
||||
],
|
||||
"port": "3000",
|
||||
"path": [
|
||||
"api",
|
||||
"logs",
|
||||
"{{session}}"
|
||||
],
|
||||
"query": [
|
||||
{
|
||||
"key": "token",
|
||||
"value": "{{token}}"
|
||||
}
|
||||
]
|
||||
},
|
||||
"description": " The logs handler gives information about a specified hooked browser's logs.\n"
|
||||
},
|
||||
"response": []
|
||||
},
|
||||
{
|
||||
"name": "List All Command Modules",
|
||||
"request": {
|
||||
"method": "GET",
|
||||
"header": [],
|
||||
"url": {
|
||||
"raw": "http://{{hostname}}:3000/api/modules?token={{token}}",
|
||||
"protocol": "http",
|
||||
"host": [
|
||||
"{{hostname}}"
|
||||
],
|
||||
"port": "3000",
|
||||
"path": [
|
||||
"api",
|
||||
"modules"
|
||||
],
|
||||
"query": [
|
||||
{
|
||||
"key": "token",
|
||||
"value": "{{token}}"
|
||||
}
|
||||
]
|
||||
},
|
||||
"description": "List all available BeEF command modules."
|
||||
},
|
||||
"response": []
|
||||
},
|
||||
{
|
||||
"name": "Get Information on Specific Module",
|
||||
"request": {
|
||||
"method": "GET",
|
||||
"header": [],
|
||||
"url": {
|
||||
"raw": "http://{{hostname}}:3000/api/modules/{{module_id}}?token={{token}}",
|
||||
"protocol": "http",
|
||||
"host": [
|
||||
"{{hostname}}"
|
||||
],
|
||||
"port": "3000",
|
||||
"path": [
|
||||
"api",
|
||||
"modules",
|
||||
"{{module_id}}"
|
||||
],
|
||||
"query": [
|
||||
{
|
||||
"key": "token",
|
||||
"value": "{{token}}"
|
||||
}
|
||||
]
|
||||
},
|
||||
"description": "Get detailed information about a specific BeEF command module.\n"
|
||||
},
|
||||
"response": []
|
||||
},
|
||||
{
|
||||
"name": "Launch Command Module on a Specific Browser",
|
||||
"request": {
|
||||
"method": "POST",
|
||||
"header": [
|
||||
{
|
||||
"key": "Content-Type",
|
||||
"name": "Content-Type",
|
||||
"value": "application/json",
|
||||
"type": "text"
|
||||
}
|
||||
],
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": "",
|
||||
"options": {
|
||||
"raw": {
|
||||
"language": "json"
|
||||
}
|
||||
}
|
||||
},
|
||||
"url": {
|
||||
"raw": "http://{{hostname}}:3000/api/modules/{{session}}/{{module_id}}?token={{token}}",
|
||||
"protocol": "http",
|
||||
"host": [
|
||||
"{{hostname}}"
|
||||
],
|
||||
"port": "3000",
|
||||
"path": [
|
||||
"api",
|
||||
"modules",
|
||||
"{{session}}",
|
||||
"{{module_id}}"
|
||||
],
|
||||
"query": [
|
||||
{
|
||||
"key": "token",
|
||||
"value": "{{token}}"
|
||||
}
|
||||
]
|
||||
},
|
||||
"description": "Launch a specific BeEF command module on a given hooked browser.\n"
|
||||
},
|
||||
"response": []
|
||||
},
|
||||
{
|
||||
"name": "Return Information About Previously Executed Module",
|
||||
"protocolProfileBehavior": {
|
||||
"disableBodyPruning": true
|
||||
},
|
||||
"request": {
|
||||
"method": "GET",
|
||||
"header": [
|
||||
{
|
||||
"key": "Content-Type",
|
||||
"name": "Content-Type",
|
||||
"value": "application/json",
|
||||
"type": "text"
|
||||
}
|
||||
],
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": "",
|
||||
"options": {
|
||||
"raw": {
|
||||
"language": "json"
|
||||
}
|
||||
}
|
||||
},
|
||||
"url": {
|
||||
"raw": "http://{{hostname}}:3000/api/modules/{{session}}/{{module_id}}/{{cmd_id}}?token={{token}}",
|
||||
"protocol": "http",
|
||||
"host": [
|
||||
"{{hostname}}"
|
||||
],
|
||||
"port": "3000",
|
||||
"path": [
|
||||
"api",
|
||||
"modules",
|
||||
"{{session}}",
|
||||
"{{module_id}}",
|
||||
"{{cmd_id}}"
|
||||
],
|
||||
"query": [
|
||||
{
|
||||
"key": "token",
|
||||
"value": "{{token}}"
|
||||
}
|
||||
]
|
||||
},
|
||||
"description": "Returns information about a specific previously launched BeEF command module.\n"
|
||||
},
|
||||
"response": []
|
||||
},
|
||||
{
|
||||
"name": "Send a Metasploit Module",
|
||||
"request": {
|
||||
"method": "POST",
|
||||
"header": [],
|
||||
"url": {
|
||||
"raw": "http://{{hostname}}:3000/api/modules/{{session}}/{{module_id}}?token={{token}}",
|
||||
"protocol": "http",
|
||||
"host": [
|
||||
"{{hostname}}"
|
||||
],
|
||||
"port": "3000",
|
||||
"path": [
|
||||
"api",
|
||||
"modules",
|
||||
"{{session}}",
|
||||
"{{module_id}}"
|
||||
],
|
||||
"query": [
|
||||
{
|
||||
"key": "token",
|
||||
"value": "{{token}}"
|
||||
}
|
||||
]
|
||||
},
|
||||
"description": "Launch a specific Metasploit module on a given hooked browser\n"
|
||||
},
|
||||
"response": []
|
||||
},
|
||||
{
|
||||
"name": " Send a Module to Multiple Hooked Browsers",
|
||||
"request": {
|
||||
"method": "POST",
|
||||
"header": [
|
||||
{
|
||||
"key": "Content-Type",
|
||||
"name": "Content-Type",
|
||||
"value": "application/json",
|
||||
"type": "text"
|
||||
}
|
||||
],
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": "",
|
||||
"options": {
|
||||
"raw": {
|
||||
"language": "json"
|
||||
}
|
||||
}
|
||||
},
|
||||
"url": {
|
||||
"raw": "http://{{hostname}}:3000/api/modules/multi_browser?token={{token}}",
|
||||
"protocol": "http",
|
||||
"host": [
|
||||
"{{hostname}}"
|
||||
],
|
||||
"port": "3000",
|
||||
"path": [
|
||||
"api",
|
||||
"modules",
|
||||
"multi_browser"
|
||||
],
|
||||
"query": [
|
||||
{
|
||||
"key": "token",
|
||||
"value": "{{token}}"
|
||||
}
|
||||
]
|
||||
},
|
||||
"description": "Fire a new command module to multiple hooked browsers. Returns the command IDs of the launched module, or 0 if firing got issues."
|
||||
},
|
||||
"response": []
|
||||
},
|
||||
{
|
||||
"name": " Send Multiple Modules to a Single Hooked Browser",
|
||||
"request": {
|
||||
"method": "POST",
|
||||
"header": [
|
||||
{
|
||||
"key": "Content-Type",
|
||||
"name": "Content-Type",
|
||||
"value": "application/json",
|
||||
"type": "text"
|
||||
}
|
||||
],
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": "",
|
||||
"options": {
|
||||
"raw": {
|
||||
"language": "json"
|
||||
}
|
||||
}
|
||||
},
|
||||
"url": {
|
||||
"raw": "http://{{hostname}}:3000/api/modules/multi_module?token={{token}}",
|
||||
"protocol": "http",
|
||||
"host": [
|
||||
"{{hostname}}"
|
||||
],
|
||||
"port": "3000",
|
||||
"path": [
|
||||
"api",
|
||||
"modules",
|
||||
"multi_module"
|
||||
],
|
||||
"query": [
|
||||
{
|
||||
"key": "token",
|
||||
"value": "{{token}}"
|
||||
}
|
||||
]
|
||||
},
|
||||
"description": "Fire multiple command modules to a single hooked browser. Returns the command IDs of the launched modules, or 0 if firing got issues."
|
||||
},
|
||||
"response": []
|
||||
},
|
||||
{
|
||||
"name": "List the DNS ruleset",
|
||||
"request": {
|
||||
"method": "GET",
|
||||
"header": [],
|
||||
"url": {
|
||||
"raw": "http://{{hostname}}:3000/api/dns/ruleset?token={{token}}",
|
||||
"protocol": "http",
|
||||
"host": [
|
||||
"{{hostname}}"
|
||||
],
|
||||
"port": "3000",
|
||||
"path": [
|
||||
"api",
|
||||
"dns",
|
||||
"ruleset"
|
||||
],
|
||||
"query": [
|
||||
{
|
||||
"key": "token",
|
||||
"value": "{{token}}"
|
||||
}
|
||||
]
|
||||
},
|
||||
"description": "Returns the current set of DNS rules.\n"
|
||||
},
|
||||
"response": []
|
||||
},
|
||||
{
|
||||
"name": "List a Specific DNS Rule",
|
||||
"request": {
|
||||
"method": "GET",
|
||||
"header": [],
|
||||
"url": {
|
||||
"raw": "http://{{hostname}}:3000/api/dns/rule/{{dnsrule_id}}?token={{token}}",
|
||||
"protocol": "http",
|
||||
"host": [
|
||||
"{{hostname}}"
|
||||
],
|
||||
"port": "3000",
|
||||
"path": [
|
||||
"api",
|
||||
"dns",
|
||||
"rule",
|
||||
"{{dnsrule_id}}"
|
||||
],
|
||||
"query": [
|
||||
{
|
||||
"key": "token",
|
||||
"value": "{{token}}"
|
||||
}
|
||||
]
|
||||
},
|
||||
"description": "Returns an individual DNS rule given its unique id.\n"
|
||||
},
|
||||
"response": []
|
||||
},
|
||||
{
|
||||
"name": "Add a New DNS Rule",
|
||||
"request": {
|
||||
"method": "POST",
|
||||
"header": [
|
||||
{
|
||||
"key": "Content-Type",
|
||||
"name": "Content-Type",
|
||||
"value": "application/json",
|
||||
"type": "text"
|
||||
}
|
||||
],
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": "",
|
||||
"options": {
|
||||
"raw": {
|
||||
"language": "json"
|
||||
}
|
||||
}
|
||||
},
|
||||
"url": {
|
||||
"raw": "http://{{hostname}}:3000/api/dns/rule?token={{token}}",
|
||||
"protocol": "http",
|
||||
"host": [
|
||||
"{{hostname}}"
|
||||
],
|
||||
"port": "3000",
|
||||
"path": [
|
||||
"api",
|
||||
"dns",
|
||||
"rule"
|
||||
],
|
||||
"query": [
|
||||
{
|
||||
"key": "token",
|
||||
"value": "{{token}}"
|
||||
}
|
||||
]
|
||||
},
|
||||
"description": "Adds a new DNS rule or \"resource record\". Does nothing if rule is already present.\n"
|
||||
},
|
||||
"response": []
|
||||
},
|
||||
{
|
||||
"name": "Remove an Existing DNS Rule",
|
||||
"request": {
|
||||
"method": "DELETE",
|
||||
"header": [],
|
||||
"url": {
|
||||
"raw": "http://{{hostname}}:3000/api/dns/rule/{{dnsrule_id}}?token={{token}}",
|
||||
"protocol": "http",
|
||||
"host": [
|
||||
"{{hostname}}"
|
||||
],
|
||||
"port": "3000",
|
||||
"path": [
|
||||
"api",
|
||||
"dns",
|
||||
"rule",
|
||||
"{{dnsrule_id}}"
|
||||
],
|
||||
"query": [
|
||||
{
|
||||
"key": "token",
|
||||
"value": "{{token}}"
|
||||
}
|
||||
]
|
||||
},
|
||||
"description": "Removes an individual DNS rule with a specified unique ID.\n"
|
||||
},
|
||||
"response": []
|
||||
}
|
||||
],
|
||||
"protocolProfileBehavior": {}
|
||||
}
|
||||
50
Rakefile
50
Rakefile
@@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (c) 2006-2021 Wade Alcorn - wade@bindshell.net
|
||||
# Copyright (c) 2006-2024 Wade Alcorn - wade@bindshell.net
|
||||
# Browser Exploitation Framework (BeEF) - http://beefproject.com
|
||||
# See the file 'doc/COPYING' for copying permission
|
||||
#
|
||||
@@ -88,15 +88,6 @@ namespace :rdoc do
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
################################
|
||||
# Install
|
||||
|
||||
#task :install do
|
||||
# sh "export BEEF_TEST=true"
|
||||
#end
|
||||
|
||||
|
||||
################################
|
||||
# X11 set up
|
||||
|
||||
@@ -134,7 +125,7 @@ task :beef_start => 'beef' do
|
||||
config = YAML.safe_load(File.read('./config.yaml'))
|
||||
config['beef']['credentials']['user'] = test_user
|
||||
config['beef']['credentials']['passwd'] = test_pass
|
||||
Dir.mkdir('tmp') unless Dir.exists?('tmp')
|
||||
Dir.mkdir('tmp') unless Dir.exist?('tmp')
|
||||
File.open(@beef_config_file, 'w') { |f| YAML.dump(config, f) }
|
||||
|
||||
# set the environment creds -- in case we're using bad_fred
|
||||
@@ -217,43 +208,6 @@ task :dmg do
|
||||
end
|
||||
|
||||
|
||||
################################
|
||||
# Create CDE Package
|
||||
# This will download and make the CDE Executable and
|
||||
# gnereate a CDE Package in cde-package
|
||||
|
||||
task :cde do
|
||||
puts "\nCloning and Making CDE...";
|
||||
sh "git clone git://github.com/pgbovine/CDE.git";
|
||||
Dir.chdir "CDE";
|
||||
sh "make";
|
||||
Dir.chdir "..";
|
||||
puts "\nCreating CDE Package...\n";
|
||||
sh "bundle install"
|
||||
Rake::Task['cde_beef_start'].invoke
|
||||
Rake::Task['beef_stop'].invoke
|
||||
puts "\nCleaning Up...\n";
|
||||
sleep (2);
|
||||
sh "rm -rf CDE";
|
||||
puts "\nCDE Package Created...\n";
|
||||
end
|
||||
|
||||
################################
|
||||
# CDE/BeEF environment set up
|
||||
|
||||
@beef_process_id = nil;
|
||||
|
||||
task :cde_beef_start => 'beef' do
|
||||
printf "Starting CDE BeEF (wait 10 seconds)..."
|
||||
@beef_process_id = IO.popen("./CDE/cde ruby beef -x 2> /dev/null", "w+")
|
||||
delays = [2, 2, 1, 1, 1, 0.5, 0.5, 0.5, 0.3, 0.2, 0.1, 0.1, 0.1, 0.05, 0.05]
|
||||
delays.each do |i| # delay for 10 seconds
|
||||
printf '.'
|
||||
sleep (i)
|
||||
end
|
||||
puts '.'
|
||||
end
|
||||
|
||||
################################
|
||||
# ActiveRecord
|
||||
namespace :db do
|
||||
|
||||
4
VERSION
4
VERSION
@@ -1,7 +1,7 @@
|
||||
#
|
||||
# Copyright (c) 2006-2021 Wade Alcorn - wade@bindshell.net
|
||||
# Copyright (c) 2006-2024 Wade Alcorn - wade@bindshell.net
|
||||
# Browser Exploitation Framework (BeEF) - http://beefproject.com
|
||||
# See the file 'doc/COPYING' for copying permission
|
||||
#
|
||||
|
||||
0.5.4.0-pre
|
||||
0.5.4.0
|
||||
|
||||
@@ -1,9 +1,5 @@
|
||||
{"name": "Display an alert",
|
||||
"author": "mgeeky",
|
||||
"browser": "ALL",
|
||||
"browser_version": "ALL",
|
||||
"os": "ALL",
|
||||
"os_version": "ALL",
|
||||
"modules": [
|
||||
{"name": "alert_dialog",
|
||||
"condition": null,
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
{"name": "Start CoinHive JavaScript miner",
|
||||
"author": "bcoles",
|
||||
"browser": "ALL",
|
||||
"browser_version": "ALL",
|
||||
"os": "ALL",
|
||||
"os_version": "ALL",
|
||||
"modules": [
|
||||
{"name": "coinhive_miner",
|
||||
"condition": null,
|
||||
"options": {
|
||||
"public_token":"Ofh5MIvjuCBDqwJ9TCTio7TYko0ig5TV",
|
||||
"mode":"FORCE_EXCLUSIVE_TAB",
|
||||
"mobile_enabled":""
|
||||
}
|
||||
}
|
||||
],
|
||||
"execution_order": [0],
|
||||
"execution_delay": [0],
|
||||
"chain_mode": "sequential"
|
||||
}
|
||||
@@ -1,9 +1,5 @@
|
||||
{"name": "Confirm Close Tab",
|
||||
"author": "mgeeky",
|
||||
"browser": "ALL",
|
||||
"browser_version": "ALL",
|
||||
"os": "ALL",
|
||||
"os_version": "ALL",
|
||||
"modules": [
|
||||
{"name": "confirm_close_tab",
|
||||
"condition": null,
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
"name": "Firefox Extension Dropper",
|
||||
"author": "antisnatchor",
|
||||
"browser": "FF",
|
||||
"browser_version": "ALL",
|
||||
"os": "OSX",
|
||||
"os_version": ">= 10.8",
|
||||
"modules": [{
|
||||
@@ -17,4 +16,4 @@
|
||||
"execution_order": [0],
|
||||
"execution_delay": [0],
|
||||
"chain_mode": "sequential"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
{
|
||||
"name": "Get Cookie",
|
||||
"author": "@benichmt1",
|
||||
"browser": "ALL",
|
||||
"browser_version": "ALL",
|
||||
"os": "ALL",
|
||||
"os_version": "ALL",
|
||||
"modules": [
|
||||
{"name": "get_cookie",
|
||||
"condition": null,
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
"name": "HTA PowerShell",
|
||||
"author": "antisnatchor",
|
||||
"browser": "IE",
|
||||
"browser_version": "ALL",
|
||||
"os": "Windows",
|
||||
"os_version": ">= 7",
|
||||
"modules": [
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
{"name": "LAN CORS Scan",
|
||||
"author": "bcoles",
|
||||
"browser": ["FF", "C"],
|
||||
"browser_version": "ALL",
|
||||
"os": "ALL",
|
||||
"os_version": "ALL",
|
||||
"modules": [
|
||||
{"name": "get_internal_ip_webrtc",
|
||||
"condition": null,
|
||||
|
||||
@@ -1,9 +1,5 @@
|
||||
{"name": "LAN CORS Scan (Common IPs)",
|
||||
"author": "bcoles",
|
||||
"browser": "ALL",
|
||||
"browser_version": "ALL",
|
||||
"os": "ALL",
|
||||
"os_version": "ALL",
|
||||
"modules": [
|
||||
{"name": "cross_origin_scanner_cors",
|
||||
"condition": null,
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
{"name": "LAN Fingerprint",
|
||||
"author": "bcoles",
|
||||
"browser": ["FF", "C"],
|
||||
"browser_version": "ALL",
|
||||
"os": "ALL",
|
||||
"os_version": "ALL",
|
||||
"modules": [
|
||||
{"name": "get_internal_ip_webrtc",
|
||||
"condition": null,
|
||||
|
||||
@@ -1,9 +1,5 @@
|
||||
{"name": "LAN Fingerprint (Common IPs)",
|
||||
"author": "antisnatchor",
|
||||
"browser": "ALL",
|
||||
"browser_version": "ALL",
|
||||
"os": "ALL",
|
||||
"os_version": "ALL",
|
||||
"modules": [
|
||||
{"name": "internal_network_fingerprinting",
|
||||
"condition": null,
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
{"name": "LAN Flash Scan",
|
||||
"author": "bcoles",
|
||||
"browser": ["FF", "C"],
|
||||
"browser_version": "ALL",
|
||||
"os": "ALL",
|
||||
"os_version": "ALL",
|
||||
"modules": [
|
||||
{"name": "get_internal_ip_webrtc",
|
||||
"condition": null,
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
{"name": "LAN Flash Scan (Common IPs)",
|
||||
"author": "bcoles",
|
||||
"browser": ["FF", "C"],
|
||||
"browser_version": "ALL",
|
||||
"os": "ALL",
|
||||
"os_version": "ALL",
|
||||
"modules": [
|
||||
{"name": "cross_origin_scanner_flash",
|
||||
"condition": null,
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
{"name": "LAN HTTP Scan",
|
||||
"author": "bcoles",
|
||||
"browser": ["FF", "C"],
|
||||
"browser_version": "ALL",
|
||||
"os": "ALL",
|
||||
"os_version": "ALL",
|
||||
"modules": [
|
||||
{"name": "get_internal_ip_webrtc",
|
||||
"condition": null,
|
||||
|
||||
@@ -1,9 +1,5 @@
|
||||
{"name": "LAN HTTP Scan (Common IPs)",
|
||||
"author": "bcoles",
|
||||
"browser": "ALL",
|
||||
"browser_version": "ALL",
|
||||
"os": "ALL",
|
||||
"os_version": "ALL",
|
||||
"modules": [
|
||||
{"name": "get_http_servers",
|
||||
"condition": null,
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
{"name": "LAN Ping Sweep",
|
||||
"author": "bcoles",
|
||||
"browser": "FF",
|
||||
"browser_version": "ALL",
|
||||
"os": "ALL",
|
||||
"os_version": "ALL",
|
||||
"modules": [
|
||||
{"name": "get_internal_ip_webrtc",
|
||||
"condition": null,
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
{"name": "LAN Ping Sweep (Common IPs)",
|
||||
"author": "bcoles",
|
||||
"browser": "FF",
|
||||
"browser_version": "ALL",
|
||||
"os": "ALL",
|
||||
"os_version": "ALL",
|
||||
"modules": [
|
||||
{"name": "ping_sweep",
|
||||
"condition": null,
|
||||
|
||||
@@ -1,9 +1,5 @@
|
||||
{"name": "LAN Port Scan",
|
||||
"author": "aburro & aussieklutz",
|
||||
"browser": "ALL",
|
||||
"browser_version": "ALL",
|
||||
"os": "ALL",
|
||||
"os_version": "ALL",
|
||||
"modules": [
|
||||
{"name": "get_internal_ip_webrtc",
|
||||
"condition": null,
|
||||
|
||||
@@ -1,9 +1,5 @@
|
||||
{"name": "LAN SW Port Scan",
|
||||
"author": "aburro & aussieklutz",
|
||||
"browser": "ALL",
|
||||
"browser_version": "ALL",
|
||||
"os": "ALL",
|
||||
"os_version": "ALL",
|
||||
"modules": [
|
||||
{"name": "get_internal_ip_webrtc",
|
||||
"condition": null,
|
||||
|
||||
@@ -1,9 +1,5 @@
|
||||
{"name": "Perform Man-In-The-Browser",
|
||||
"author": "mgeeky",
|
||||
"browser": "ALL",
|
||||
"browser_version": "ALL",
|
||||
"os": "ALL",
|
||||
"os_version": "ALL",
|
||||
"modules": [
|
||||
{"name": "man_in_the_browser",
|
||||
"condition": null,
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
{
|
||||
"name": "Raw JavaScript",
|
||||
"author": "wade@bindshell.net",
|
||||
"browser": "ALL",
|
||||
"browser_version": "ALL",
|
||||
"os": "ALL",
|
||||
"os_version": "ALL",
|
||||
"modules": [
|
||||
{"name": "raw_javascript",
|
||||
"condition": null,
|
||||
|
||||
@@ -1,9 +1,5 @@
|
||||
{"name": "Collects multiple snapshots of the webpage within Same-Origin",
|
||||
"author": "mgeeky",
|
||||
"browser": ["FF", "C", "O", "IE", "S"],
|
||||
"browser_version": "ALL",
|
||||
"os": "ALL",
|
||||
"os_version": "ALL",
|
||||
"modules": [
|
||||
{"name": "spyder_eye",
|
||||
"condition": null,
|
||||
|
||||
@@ -2,10 +2,7 @@
|
||||
{
|
||||
"name": "Windows Fake Malware",
|
||||
"author": "bcoles",
|
||||
"browser": "ALL",
|
||||
"browser_version": "ALL",
|
||||
"os": "Windows",
|
||||
"os_version": "ALL",
|
||||
"modules": [
|
||||
{
|
||||
"name": "blockui",
|
||||
|
||||
34
beef
34
beef
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env ruby
|
||||
|
||||
#
|
||||
# Copyright (c) 2006-2021 Wade Alcorn - wade@bindshell.net
|
||||
# Copyright (c) 2006-2024 Wade Alcorn - wade@bindshell.net
|
||||
# Browser Exploitation Framework (BeEF) - http://beefproject.com
|
||||
# See the file 'doc/COPYING' for copying permission
|
||||
#
|
||||
@@ -12,11 +12,12 @@
|
||||
$VERBOSE = nil
|
||||
|
||||
#
|
||||
# @note Version check to ensure BeEF is running Ruby 2.5+
|
||||
# @note Version check to ensure BeEF is running Ruby 3.0+
|
||||
#
|
||||
if RUBY_VERSION < '2.5'
|
||||
min_ruby_version = '3.0'
|
||||
if RUBY_VERSION < min_ruby_version
|
||||
puts
|
||||
puts "Ruby version #{RUBY_VERSION} is no longer supported. Please upgrade to Ruby version 2.5 or later."
|
||||
puts "Ruby version #{RUBY_VERSION} is no longer supported. Please upgrade to Ruby version #{min_ruby_version} or later."
|
||||
puts
|
||||
exit 1
|
||||
end
|
||||
@@ -57,7 +58,7 @@ if File.exist?("#{$root_dir}git") && BeEF::Core::Console::CommandLine.parse[:upd
|
||||
puts '-- BeEF Update Available --'
|
||||
print 'Would you like to update to lastest version? y/n: '
|
||||
response = gets
|
||||
`git pull && bundle` if response.strip == 'y'
|
||||
`git pull && bundle` if response&.strip == 'y'
|
||||
end
|
||||
rescue Timeout::Error
|
||||
puts "\nUpdate Skipped with input timeout"
|
||||
@@ -183,8 +184,14 @@ db_file = config.get('beef.database.file')
|
||||
# @note Resets the database if the -x flag was passed
|
||||
if BeEF::Core::Console::CommandLine.parse[:resetdb]
|
||||
print_info 'Resetting the database for BeEF.'
|
||||
File.delete(db_file) if File.exists?(db_file)
|
||||
begin
|
||||
File.delete(db_file) if File.exist?(db_file)
|
||||
rescue => e
|
||||
print_error("Could not remove '#{db_file}' database file: #{e.message}")
|
||||
exit(1)
|
||||
end
|
||||
end
|
||||
|
||||
# Connect to DB
|
||||
ActiveRecord::Base.logger = nil
|
||||
OTR::ActiveRecord.migrations_paths = [File.join('core', 'main', 'ar-migrations')]
|
||||
@@ -194,6 +201,7 @@ OTR::ActiveRecord.configure_from_hash!(adapter:'sqlite3', database:db_file)
|
||||
if Gem.loaded_specs['otr-activerecord'].version > Gem::Version.create('1.4.2')
|
||||
OTR::ActiveRecord.establish_connection!
|
||||
end
|
||||
|
||||
# Migrate (if required)
|
||||
context = ActiveRecord::Migration.new.migration_context
|
||||
if context.needs_migration?
|
||||
@@ -207,7 +215,12 @@ print_info 'BeEF is loading. Wait a few seconds...'
|
||||
#
|
||||
# @note Execute migration procedure, checks for new modules
|
||||
#
|
||||
BeEF::Core::Migration.instance.update_db!
|
||||
begin
|
||||
BeEF::Core::Migration.instance.update_db!
|
||||
rescue => e
|
||||
print_error("Could not update '#{db_file}' database file: #{e.message}")
|
||||
exit(1)
|
||||
end
|
||||
|
||||
#
|
||||
# @note Create HTTP Server and prepare it to run
|
||||
@@ -215,6 +228,13 @@ BeEF::Core::Migration.instance.update_db!
|
||||
http_hook_server = BeEF::Core::Server.instance
|
||||
http_hook_server.prepare
|
||||
|
||||
begin
|
||||
BeEF::Core::Logger.instance.register('System', 'BeEF server started')
|
||||
rescue => e
|
||||
print_error("Database connection failed: #{e.message}")
|
||||
exit(1)
|
||||
end
|
||||
|
||||
#
|
||||
# @note Prints information back to the user before running the server
|
||||
#
|
||||
|
||||
48
config.yaml
48
config.yaml
@@ -1,12 +1,12 @@
|
||||
#
|
||||
# Copyright (c) 2006-2021 Wade Alcorn - wade@bindshell.net
|
||||
# Copyright (c) 2006-2024 Wade Alcorn - wade@bindshell.net
|
||||
# Browser Exploitation Framework (BeEF) - http://beefproject.com
|
||||
# See the file 'doc/COPYING' for copying permission
|
||||
#
|
||||
# BeEF Configuration file
|
||||
|
||||
beef:
|
||||
version: '0.5.4.0-pre'
|
||||
version: '0.5.4.0'
|
||||
# More verbose messages (server-side)
|
||||
debug: false
|
||||
# More verbose messages (client-side)
|
||||
@@ -45,22 +45,23 @@ beef:
|
||||
# Enabling WebSockets is generally better (beef.websocket.enable)
|
||||
xhr_poll_timeout: 1000
|
||||
|
||||
# Host Name / Domain Name
|
||||
# If you want BeEF to be accessible via hostname or domain name (ie, DynDNS),
|
||||
# These settings will be used to create a public facing URL
|
||||
# This public facing URL will be used for all hook related calls
|
||||
# set the public setting below:
|
||||
# public:
|
||||
# host: "" # public hostname/IP address
|
||||
# port: "" # public port will default to 80 if no https 443 if https
|
||||
# and local if not set but there is a public host
|
||||
# https: false # true/false
|
||||
# Public Domain Name / Reverse Proxy / Port Forwarding
|
||||
#
|
||||
# In order for the client-side BeEF JavaScript hook to be able to connect to BeEF,
|
||||
# the hook JavaScript needs to be generated with the correct connect-back details.
|
||||
#
|
||||
# If you're using a public domain name, reverse proxy, or port forwarding you must
|
||||
# configure the public-facing connection details here.
|
||||
|
||||
# Reverse Proxy / NAT
|
||||
# If you want BeEF to be accessible behind a reverse proxy or NAT,
|
||||
# set both the publicly accessible hostname/IP address and port below:
|
||||
# NOTE: Allowing the reverse proxy will enable a vulnerability where the ui/panel can be spoofed
|
||||
# by altering the X-FORWARDED-FOR ip address in the request header.
|
||||
#public:
|
||||
# host: "beef.local" # public hostname/IP address
|
||||
# port: "443" # public port (443 if the public server is using HTTPS)
|
||||
# https: false # true/false
|
||||
|
||||
# If using any reverse proxy you should also set allow_reverse_proxy to true below.
|
||||
# Note that this causes the BeEF server to trust the X-Forwarded-For HTTP header.
|
||||
# If the BeEF server is directly accessible, clients can spoof their connecting
|
||||
# IP address using this header to bypass the IP address permissions/exclusions.
|
||||
allow_reverse_proxy: false
|
||||
|
||||
# Hook
|
||||
@@ -93,8 +94,6 @@ beef:
|
||||
# Experimental HTTPS support for the hook / admin / all other Thin managed web services
|
||||
https:
|
||||
enable: false
|
||||
# Enabled this config setting if you're external facing uri is using https
|
||||
public_enabled: false
|
||||
# In production environments, be sure to use a valid certificate signed for the value
|
||||
# used in beef.http.public (the domain name of the server where you run BeEF)
|
||||
key: "beef_key.pem"
|
||||
@@ -120,17 +119,10 @@ beef:
|
||||
dns_hostname_lookup: false
|
||||
|
||||
# IP Geolocation
|
||||
# NOTE: requires MaxMind database. Run ./updated-geoipdb to install.
|
||||
geoip:
|
||||
enable: true
|
||||
database: '/opt/GeoIP/GeoLite2-City.mmdb'
|
||||
|
||||
# Integration with PhishingFrenzy
|
||||
# If enabled BeEF will try to get the UID parameter value from the hooked URI, as this is used by PhishingFrenzy
|
||||
# to uniquely identify the victims. In this way you can easily associate phishing emails with hooked browser.
|
||||
integration:
|
||||
phishing_frenzy:
|
||||
enable: false
|
||||
# GeoLite2 City database created by MaxMind, available from https://www.maxmind.com
|
||||
database: '/usr/share/GeoIP/GeoLite2-City.mmdb'
|
||||
|
||||
# You may override default extension configuration parameters here
|
||||
# Note: additional experimental extensions are available in the 'extensions' directory
|
||||
|
||||
24
core/api.rb
24
core/api.rb
@@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (c) 2006-2021 Wade Alcorn - wade@bindshell.net
|
||||
# Copyright (c) 2006-2024 Wade Alcorn - wade@bindshell.net
|
||||
# Browser Exploitation Framework (BeEF) - http://beefproject.com
|
||||
# See the file 'doc/COPYING' for copying permission
|
||||
#
|
||||
@@ -117,7 +117,7 @@ module BeEF
|
||||
next unless r['method'] == method
|
||||
next unless is_matched_params? r, params
|
||||
|
||||
owners << { :owner => r['owner'], :id => r['id'] }
|
||||
owners << { owner: r['owner'], id: r['id'] }
|
||||
end
|
||||
owners
|
||||
end
|
||||
@@ -184,25 +184,21 @@ module BeEF
|
||||
mods = get_owners(clss, mthd, args)
|
||||
return nil unless mods.length.positive?
|
||||
|
||||
unless verify_api_path(clss, mthd) && clss.ancestors[0].to_s > 'BeEF::API'
|
||||
print_error "API Path not defined for Class: #{clss} method:#{method}"
|
||||
unless verify_api_path(clss, mthd) && clss.ancestors.first.to_s.start_with?('BeEF::API')
|
||||
print_error "API Path not defined for Class: #{clss} method: #{mthd}"
|
||||
return []
|
||||
end
|
||||
|
||||
data = []
|
||||
method = get_api_path(clss, mthd)
|
||||
mods.each do |mod|
|
||||
begin
|
||||
# Only used for API Development (very verbose)
|
||||
# print_info "API: #{mod} fired #{method}"
|
||||
# Only used for API Development (very verbose)
|
||||
# print_info "API: #{mod} fired #{method}"
|
||||
|
||||
result = mod[:owner].method(method).call(*args)
|
||||
unless result.nil?
|
||||
data << { :api_id => mod[:id], :data => result }
|
||||
end
|
||||
rescue => e
|
||||
print_error "API Fire Error: #{e.message} in #{mod}.#{method}()"
|
||||
end
|
||||
result = mod[:owner].method(method).call(*args)
|
||||
data << { api_id: mod[:id], data: result } unless result.nil?
|
||||
rescue StandardError => e
|
||||
print_error "API Fire Error: #{e.message} in #{mod}.#{method}()"
|
||||
end
|
||||
|
||||
data
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (c) 2006-2021 Wade Alcorn - wade@bindshell.net
|
||||
# Copyright (c) 2006-2024 Wade Alcorn - wade@bindshell.net
|
||||
# Browser Exploitation Framework (BeEF) - http://beefproject.com
|
||||
# See the file 'doc/COPYING' for copying permission
|
||||
#
|
||||
@@ -7,14 +7,11 @@
|
||||
module BeEF
|
||||
module API
|
||||
module Extension
|
||||
|
||||
attr_reader :full_name, :short_name, :description
|
||||
|
||||
@full_name = ''
|
||||
@short_name = ''
|
||||
@description = ''
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,21 +1,18 @@
|
||||
#
|
||||
# Copyright (c) 2006-2021 Wade Alcorn - wade@bindshell.net
|
||||
# Copyright (c) 2006-2024 Wade Alcorn - wade@bindshell.net
|
||||
# Browser Exploitation Framework (BeEF) - http://beefproject.com
|
||||
# See the file 'doc/COPYING' for copying permission
|
||||
#
|
||||
module BeEF
|
||||
module API
|
||||
module Extensions
|
||||
|
||||
# @note Defined API Paths
|
||||
API_PATHS = {
|
||||
'post_load' => :post_load
|
||||
}
|
||||
'post_load' => :post_load
|
||||
}.freeze
|
||||
|
||||
# API hook fired after all extensions have been loaded
|
||||
def post_load;
|
||||
end
|
||||
|
||||
def post_load; end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,22 +1,19 @@
|
||||
#
|
||||
# Copyright (c) 2006-2021 Wade Alcorn - wade@bindshell.net
|
||||
# Copyright (c) 2006-2024 Wade Alcorn - wade@bindshell.net
|
||||
# Browser Exploitation Framework (BeEF) - http://beefproject.com
|
||||
# See the file 'doc/COPYING' for copying permission
|
||||
#
|
||||
module BeEF
|
||||
module API
|
||||
module Configuration
|
||||
|
||||
# @note Defined API Paths
|
||||
API_PATHS = {
|
||||
module API
|
||||
module Configuration
|
||||
# @note Defined API Paths
|
||||
API_PATHS = {
|
||||
'module_configuration_load' => :module_configuration_load
|
||||
}
|
||||
|
||||
# Fires just after module configuration is loaded and merged
|
||||
# @param [String] mod module key
|
||||
def module_configuration_load(mod); end
|
||||
}.freeze
|
||||
|
||||
# Fires just after module configuration is loaded and merged
|
||||
# @param [String] mod module key
|
||||
def module_configuration_load(mod); end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,21 +1,18 @@
|
||||
#
|
||||
# Copyright (c) 2006-2021 Wade Alcorn - wade@bindshell.net
|
||||
# Copyright (c) 2006-2024 Wade Alcorn - wade@bindshell.net
|
||||
# Browser Exploitation Framework (BeEF) - http://beefproject.com
|
||||
# See the file 'doc/COPYING' for copying permission
|
||||
#
|
||||
module BeEF
|
||||
module API
|
||||
module Migration
|
||||
|
||||
# @note Defined API Paths
|
||||
API_PATHS = {
|
||||
module API
|
||||
module Migration
|
||||
# @note Defined API Paths
|
||||
API_PATHS = {
|
||||
'migrate_commands' => :migrate_commands
|
||||
}
|
||||
}.freeze
|
||||
|
||||
# Fired just after the migration process
|
||||
def migrate_commands; end
|
||||
|
||||
# Fired just after the migration process
|
||||
def migrate_commands; end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,36 +1,34 @@
|
||||
#
|
||||
# Copyright (c) 2006-2021 Wade Alcorn - wade@bindshell.net
|
||||
# Copyright (c) 2006-2024 Wade Alcorn - wade@bindshell.net
|
||||
# Browser Exploitation Framework (BeEF) - http://beefproject.com
|
||||
# See the file 'doc/COPYING' for copying permission
|
||||
#
|
||||
module BeEF
|
||||
module API
|
||||
module NetworkStack
|
||||
module Handlers
|
||||
module AssetHandler
|
||||
module API
|
||||
module NetworkStack
|
||||
module Handlers
|
||||
module AssetHandler
|
||||
# Binds a file to be accessible by the hooked browser
|
||||
# @param [String] file file to be served
|
||||
# @param [String] path URL path to be bound, if no path is specified a randomly generated one will be used
|
||||
# @param [String] extension to be used in the URL
|
||||
# @param [Integer] count amount of times the file can be accessed before being automatically unbound. (-1 = no limit)
|
||||
# @return [String] URL bound to the specified file
|
||||
# @todo Add hooked browser parameter to only allow specified hooked browsers access to the bound URL. Waiting on Issue #336
|
||||
# @note This is a direct API call and does not have to be registered to be used
|
||||
def self.bind(file, path = nil, extension = nil, count = -1)
|
||||
BeEF::Core::NetworkStack::Handlers::AssetHandler.instance.bind(file, path, extension, count)
|
||||
end
|
||||
|
||||
# Binds a file to be accessible by the hooked browser
|
||||
# @param [String] file file to be served
|
||||
# @param [String] path URL path to be bound, if no path is specified a randomly generated one will be used
|
||||
# @param [String] extension to be used in the URL
|
||||
# @param [Integer] count amount of times the file can be accessed before being automatically unbound. (-1 = no limit)
|
||||
# @return [String] URL bound to the specified file
|
||||
# @todo Add hooked browser parameter to only allow specified hooked browsers access to the bound URL. Waiting on Issue #336
|
||||
# @note This is a direct API call and does not have to be registered to be used
|
||||
def self.bind(file, path=nil, extension=nil, count=-1)
|
||||
return BeEF::Core::NetworkStack::Handlers::AssetHandler.instance.bind(file, path, extension, count)
|
||||
# Unbinds a file made accessible to hooked browsers
|
||||
# @param [String] url the bound URL
|
||||
# @todo Add hooked browser parameter to only unbind specified hooked browsers binds. Waiting on Issue #336
|
||||
# @note This is a direct API call and does not have to be registered to be used
|
||||
def self.unbind(url)
|
||||
BeEF::Core::NetworkStack::Handlers::AssetHandler.instance.unbind(url)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Unbinds a file made accessible to hooked browsers
|
||||
# @param [String] url the bound URL
|
||||
# @todo Add hooked browser parameter to only unbind specified hooked browsers binds. Waiting on Issue #336
|
||||
# @note This is a direct API call and does not have to be registered to be used
|
||||
def self.unbind(url)
|
||||
BeEF::Core::NetworkStack::Handlers::AssetHandler.instance.unbind(url)
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,43 +1,40 @@
|
||||
#
|
||||
# Copyright (c) 2006-2021 Wade Alcorn - wade@bindshell.net
|
||||
# Copyright (c) 2006-2024 Wade Alcorn - wade@bindshell.net
|
||||
# Browser Exploitation Framework (BeEF) - http://beefproject.com
|
||||
# See the file 'doc/COPYING' for copying permission
|
||||
#
|
||||
module BeEF
|
||||
module API
|
||||
module Server
|
||||
|
||||
# @note Defined API Paths
|
||||
API_PATHS = {
|
||||
module API
|
||||
module Server
|
||||
# @note Defined API Paths
|
||||
API_PATHS = {
|
||||
'mount_handler' => :mount_handler,
|
||||
'pre_http_start' => :pre_http_start
|
||||
}
|
||||
|
||||
# Fires just before the HTTP Server is started
|
||||
# @param [Object] http_hook_server HTTP Server object
|
||||
def pre_http_start(http_hook_server); end
|
||||
|
||||
# Fires just after handlers have been mounted
|
||||
# @param [Object] server HTTP Server object
|
||||
def mount_handler(server); end
|
||||
|
||||
# Mounts a handler
|
||||
# @param [String] url URL to be mounted
|
||||
# @param [Class] http_handler_class the handler Class
|
||||
# @param [Array] args an array of arguments
|
||||
# @note This is a direct API call and does not have to be registered to be used
|
||||
def self.mount(url, http_handler_class, args = nil)
|
||||
BeEF::Core::Server.instance.mount(url, http_handler_class, *args)
|
||||
end
|
||||
}.freeze
|
||||
|
||||
# Unmounts a handler
|
||||
# @param [String] url URL to be unmounted
|
||||
# @note This is a direct API call and does not have to be registered to be used
|
||||
def self.unmount(url)
|
||||
# Fires just before the HTTP Server is started
|
||||
# @param [Object] http_hook_server HTTP Server object
|
||||
def pre_http_start(http_hook_server); end
|
||||
|
||||
# Fires just after handlers have been mounted
|
||||
# @param [Object] server HTTP Server object
|
||||
def mount_handler(server); end
|
||||
|
||||
# Mounts a handler
|
||||
# @param [String] url URL to be mounted
|
||||
# @param [Class] http_handler_class the handler Class
|
||||
# @param [Array] args an array of arguments
|
||||
# @note This is a direct API call and does not have to be registered to be used
|
||||
def self.mount(url, http_handler_class, args = nil)
|
||||
BeEF::Core::Server.instance.mount(url, http_handler_class, *args)
|
||||
end
|
||||
|
||||
# Unmounts a handler
|
||||
# @param [String] url URL to be unmounted
|
||||
# @note This is a direct API call and does not have to be registered to be used
|
||||
def self.unmount(url)
|
||||
BeEF::Core::Server.instance.unmount(url)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,24 +1,21 @@
|
||||
#
|
||||
# Copyright (c) 2006-2021 Wade Alcorn - wade@bindshell.net
|
||||
# Copyright (c) 2006-2024 Wade Alcorn - wade@bindshell.net
|
||||
# Browser Exploitation Framework (BeEF) - http://beefproject.com
|
||||
# See the file 'doc/COPYING' for copying permission
|
||||
#
|
||||
module BeEF
|
||||
module API
|
||||
module Server
|
||||
module Hook
|
||||
module API
|
||||
module Server
|
||||
module Hook
|
||||
# @note Defined API Paths
|
||||
API_PATHS = {
|
||||
'pre_hook_send' => :pre_hook_send
|
||||
}.freeze
|
||||
|
||||
# @note Defined API Paths
|
||||
API_PATHS = {
|
||||
'pre_hook_send' => :pre_hook_send
|
||||
}
|
||||
|
||||
# Fires just before the hook is sent to the hooked browser
|
||||
# @param [Class] handler the associated handler Class
|
||||
def pre_hook_send(handler); end
|
||||
|
||||
# Fires just before the hook is sent to the hooked browser
|
||||
# @param [Class] handler the associated handler Class
|
||||
def pre_hook_send(handler); end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,26 +1,24 @@
|
||||
#
|
||||
# Copyright (c) 2006-2021 Wade Alcorn - wade@bindshell.net
|
||||
# Copyright (c) 2006-2024 Wade Alcorn - wade@bindshell.net
|
||||
# Browser Exploitation Framework (BeEF) - http://beefproject.com
|
||||
# See the file 'doc/COPYING' for copying permission
|
||||
#
|
||||
module BeEF
|
||||
module API
|
||||
|
||||
module Command
|
||||
end
|
||||
|
||||
module Module
|
||||
|
||||
# @note Defined API Paths
|
||||
API_PATHS = {
|
||||
'pre_soft_load' => :pre_soft_load,
|
||||
'post_soft_load' => :post_soft_load,
|
||||
'pre_hard_load' => :pre_hard_load,
|
||||
'post_hard_load' => :post_hard_load,
|
||||
'get_options' => :get_options,
|
||||
'get_payload_options' => :get_payload_options,
|
||||
'override_execute' => :override_execute
|
||||
}
|
||||
'pre_soft_load' => :pre_soft_load,
|
||||
'post_soft_load' => :post_soft_load,
|
||||
'pre_hard_load' => :pre_hard_load,
|
||||
'post_hard_load' => :post_hard_load,
|
||||
'get_options' => :get_options,
|
||||
'get_payload_options' => :get_payload_options,
|
||||
'override_execute' => :override_execute
|
||||
}.freeze
|
||||
|
||||
# Fired before a module soft load
|
||||
# @param [String] mod module key of module about to be soft loaded
|
||||
@@ -54,8 +52,6 @@ module BeEF
|
||||
# @return [Hash] a hash of options
|
||||
# @note the option hash is merged with all other API hook's returned hash. Hooking this API method prevents the default options being returned.
|
||||
def get_payload_options; end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,22 +1,18 @@
|
||||
#
|
||||
# Copyright (c) 2006-2021 Wade Alcorn - wade@bindshell.net
|
||||
# Copyright (c) 2006-2024 Wade Alcorn - wade@bindshell.net
|
||||
# Browser Exploitation Framework (BeEF) - http://beefproject.com
|
||||
# See the file 'doc/COPYING' for copying permission
|
||||
#
|
||||
module BeEF
|
||||
module API
|
||||
|
||||
module Modules
|
||||
|
||||
# @note Defined API Paths
|
||||
API_PATHS = {
|
||||
'post_soft_load' => :post_soft_load
|
||||
}
|
||||
'post_soft_load' => :post_soft_load
|
||||
}.freeze
|
||||
|
||||
# Fires just after all modules are soft loaded
|
||||
def post_soft_load; end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,24 +1,22 @@
|
||||
#
|
||||
# Copyright (c) 2006-2021 Wade Alcorn - wade@bindshell.net
|
||||
# Copyright (c) 2006-2024 Wade Alcorn - wade@bindshell.net
|
||||
# Browser Exploitation Framework (BeEF) - http://beefproject.com
|
||||
# See the file 'doc/COPYING' for copying permission
|
||||
#
|
||||
module BeEF
|
||||
module Core
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
## @note Include the BeEF router
|
||||
require 'core/main/router/router'
|
||||
require 'core/main/router/api'
|
||||
require 'core/main/router/error_responses'
|
||||
|
||||
|
||||
## @note Include http server functions for beef
|
||||
require 'core/main/server'
|
||||
require 'core/main/handlers/modules/beefjs'
|
||||
require 'core/main/handlers/modules/legacybeefjs'
|
||||
require 'core/main/handlers/modules/multistagebeefjs'
|
||||
require 'core/main/handlers/modules/command'
|
||||
require 'core/main/handlers/commands'
|
||||
require 'core/main/handlers/hookedbrowsers'
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
#
|
||||
# Copyright (c) 2006-2021 Wade Alcorn - wade@bindshell.net
|
||||
# Copyright (c) 2006-2024 Wade Alcorn - wade@bindshell.net
|
||||
# Browser Exploitation Framework (BeEF) - http://beefproject.com
|
||||
# See the file 'doc/COPYING' for copying permission
|
||||
#
|
||||
module BeEF
|
||||
module Core
|
||||
|
||||
end
|
||||
module Core
|
||||
end
|
||||
end
|
||||
|
||||
# @note Includes database models - the order must be consistent otherwise DataMapper goes crazy
|
||||
@@ -20,6 +19,7 @@ require 'core/main/models/optioncache'
|
||||
require 'core/main/models/browserdetails'
|
||||
require 'core/main/models/rule'
|
||||
require 'core/main/models/execution'
|
||||
require 'core/main/models/legacybrowseruseragents'
|
||||
|
||||
# @note Include the constants
|
||||
require 'core/main/constants/browsers'
|
||||
@@ -38,4 +38,3 @@ require 'core/main/geoip'
|
||||
# @note Include the command line parser and the banner printer
|
||||
require 'core/main/console/commandline'
|
||||
require 'core/main/console/banners'
|
||||
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
#
|
||||
# Copyright (c) 2006-2021 Wade Alcorn - wade@bindshell.net
|
||||
# Copyright (c) 2006-2024 Wade Alcorn - wade@bindshell.net
|
||||
# Browser Exploitation Framework (BeEF) - http://beefproject.com
|
||||
# See the file 'doc/COPYING' for copying permission
|
||||
#
|
||||
module BeEF
|
||||
module Extension
|
||||
|
||||
# Checks to see if extension is set inside the configuration
|
||||
# @param [String] ext the extension key
|
||||
# @return [Boolean] whether or not the extension exists in BeEF's configuration
|
||||
@@ -15,9 +14,10 @@ module BeEF
|
||||
|
||||
# Checks to see if extension is enabled in configuration
|
||||
# @param [String] ext the extension key
|
||||
# @return [Boolean] whether or not the extension is enabled
|
||||
# @return [Boolean] whether or not the extension is enabled
|
||||
def self.is_enabled(ext)
|
||||
return false unless is_present(ext)
|
||||
|
||||
BeEF::Core::Configuration.instance.get("beef.extension.#{ext}.enable") == true
|
||||
end
|
||||
|
||||
@@ -26,10 +26,11 @@ module BeEF
|
||||
# @return [Boolean] whether or not the extension is loaded
|
||||
def self.is_loaded(ext)
|
||||
return false unless is_enabled(ext)
|
||||
|
||||
BeEF::Core::Configuration.instance.get("beef.extension.#{ext}.loaded") == true
|
||||
end
|
||||
|
||||
# Loads an extension
|
||||
# Loads an extension
|
||||
# @param [String] ext the extension key
|
||||
# @return [Boolean] whether or not the extension loaded successfully
|
||||
def self.load(ext)
|
||||
@@ -41,7 +42,7 @@ module BeEF
|
||||
end
|
||||
print_error "Unable to load extension '#{ext}'"
|
||||
false
|
||||
rescue => e
|
||||
rescue StandardError => e
|
||||
print_error "Unable to load extension '#{ext}':"
|
||||
print_more e.message
|
||||
end
|
||||
|
||||
@@ -1,16 +1,15 @@
|
||||
#
|
||||
# Copyright (c) 2006-2021 Wade Alcorn - wade@bindshell.net
|
||||
# Copyright (c) 2006-2024 Wade Alcorn - wade@bindshell.net
|
||||
# Browser Exploitation Framework (BeEF) - http://beefproject.com
|
||||
# See the file 'doc/COPYING' for copying permission
|
||||
#
|
||||
module BeEF
|
||||
module Extensions
|
||||
|
||||
# Returns configuration of all enabled extensions
|
||||
# @return [Array] an array of extension configuration hashes that are enabled
|
||||
def self.get_enabled
|
||||
BeEF::Core::Configuration.instance.get('beef.extension').select { |k,v| v['enable'] == true }
|
||||
rescue => e
|
||||
BeEF::Core::Configuration.instance.get('beef.extension').select { |_k, v| v['enable'] == true }
|
||||
rescue StandardError => e
|
||||
print_error "Failed to get enabled extensions: #{e.message}"
|
||||
print_error e.backtrace
|
||||
end
|
||||
@@ -18,8 +17,8 @@ module BeEF
|
||||
# Returns configuration of all loaded extensions
|
||||
# @return [Array] an array of extension configuration hashes that are loaded
|
||||
def self.get_loaded
|
||||
BeEF::Core::Configuration.instance.get('beef.extension').select {|k,v| v['loaded'] == true }
|
||||
rescue => e
|
||||
BeEF::Core::Configuration.instance.get('beef.extension').select { |_k, v| v['loaded'] == true }
|
||||
rescue StandardError => e
|
||||
print_error "Failed to get loaded extensions: #{e.message}"
|
||||
print_error e.backtrace
|
||||
end
|
||||
@@ -28,12 +27,12 @@ module BeEF
|
||||
# @note API fire for post_load
|
||||
def self.load
|
||||
BeEF::Core::Configuration.instance.load_extensions_config
|
||||
self.get_enabled.each { |k,v|
|
||||
get_enabled.each do |k, _v|
|
||||
BeEF::Extension.load k
|
||||
}
|
||||
end
|
||||
# API post extension load
|
||||
BeEF::API::Registrar.instance.fire BeEF::API::Extensions, 'post_load'
|
||||
rescue => e
|
||||
rescue StandardError => e
|
||||
print_error "Failed to load extensions: #{e.message}"
|
||||
print_error e.backtrace
|
||||
end
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
#
|
||||
# Copyright (c) 2006-2021 Wade Alcorn - wade@bindshell.net
|
||||
# Copyright (c) 2006-2024 Wade Alcorn - wade@bindshell.net
|
||||
# Browser Exploitation Framework (BeEF) - http://beefproject.com
|
||||
# See the file 'doc/COPYING' for copying permission
|
||||
#
|
||||
module BeEF
|
||||
module Filters
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -1,199 +1,214 @@
|
||||
#
|
||||
# Copyright (c) 2006-2021 Wade Alcorn - wade@bindshell.net
|
||||
# Copyright (c) 2006-2024 Wade Alcorn - wade@bindshell.net
|
||||
# Browser Exploitation Framework (BeEF) - http://beefproject.com
|
||||
# See the file 'doc/COPYING' for copying permission
|
||||
#
|
||||
module BeEF
|
||||
module Filters
|
||||
module Filters
|
||||
# Check if the string is not empty and not nil
|
||||
# @param [String] str String for testing
|
||||
# @return [Boolean] Whether the string is not empty
|
||||
def self.is_non_empty_string?(str)
|
||||
return false if str.nil?
|
||||
return false unless str.is_a? String
|
||||
return false if str.empty?
|
||||
|
||||
# Check if the string is not empty and not nil
|
||||
# @param [String] str String for testing
|
||||
# @return [Boolean] Whether the string is not empty
|
||||
def self.is_non_empty_string?(str)
|
||||
return false if str.nil?
|
||||
return false unless str.is_a? String
|
||||
return false if str.empty?
|
||||
true
|
||||
true
|
||||
end
|
||||
|
||||
# Check if only the characters in 'chars' are in 'str'
|
||||
# @param [String] chars List of characters to match
|
||||
# @param [String] str String for testing
|
||||
# @return [Boolean] Whether or not the only characters in str are specified in chars
|
||||
def self.only?(chars, str)
|
||||
regex = Regexp.new('[^' + chars + ']')
|
||||
regex.match(str.encode('UTF-8', invalid: :replace, undef: :replace, replace: '')).nil?
|
||||
end
|
||||
|
||||
# Check if one or more characters in 'chars' are in 'str'
|
||||
# @param [String] chars List of characters to match
|
||||
# @param [String] str String for testing
|
||||
# @return [Boolean] Whether one of the characters exists in the string
|
||||
def self.exists?(chars, str)
|
||||
regex = Regexp.new(chars)
|
||||
!regex.match(str.encode('UTF-8', invalid: :replace, undef: :replace, replace: '')).nil?
|
||||
end
|
||||
|
||||
# Check for null char
|
||||
# @param [String] str String for testing
|
||||
# @return [Boolean] If the string has a null character
|
||||
def self.has_null?(str)
|
||||
return false unless is_non_empty_string?(str)
|
||||
|
||||
exists?('\x00', str)
|
||||
end
|
||||
|
||||
# Check for non-printable char
|
||||
# @param [String] str String for testing
|
||||
# @return [Boolean] Whether or not the string has non-printable characters
|
||||
def self.has_non_printable_char?(str)
|
||||
return false unless is_non_empty_string?(str)
|
||||
|
||||
!only?('[:print:]', str)
|
||||
end
|
||||
|
||||
# Check if num characters only
|
||||
# @param [String] str String for testing
|
||||
# @return [Boolean] If the string only contains numbers
|
||||
def self.nums_only?(str)
|
||||
return false unless is_non_empty_string?(str)
|
||||
|
||||
only?('0-9', str)
|
||||
end
|
||||
|
||||
# Check if valid float
|
||||
# @param [String] str String for float testing
|
||||
# @return [Boolean] If the string is a valid float
|
||||
def self.is_valid_float?(str)
|
||||
return false unless is_non_empty_string?(str)
|
||||
return false unless only?('0-9\.', str)
|
||||
|
||||
!(str =~ /^\d+\.\d+$/).nil?
|
||||
end
|
||||
|
||||
# Check if hex characters only
|
||||
# @param [String] str String for testing
|
||||
# @return [Boolean] If the string only contains hex characters
|
||||
def self.hexs_only?(str)
|
||||
return false unless is_non_empty_string?(str)
|
||||
|
||||
only?('0123456789ABCDEFabcdef', str)
|
||||
end
|
||||
|
||||
# Check if first character is a number
|
||||
# @param [String] String for testing
|
||||
# @return [Boolean] If the first character of the string is a number
|
||||
def self.first_char_is_num?(str)
|
||||
return false unless is_non_empty_string?(str)
|
||||
|
||||
!(str =~ /^\d.*/).nil?
|
||||
end
|
||||
|
||||
# Check for space characters: \t\n\r\f
|
||||
# @param [String] str String for testing
|
||||
# @return [Boolean] If the string has a whitespace character
|
||||
def self.has_whitespace_char?(str)
|
||||
return false unless is_non_empty_string?(str)
|
||||
|
||||
exists?('\s', str)
|
||||
end
|
||||
|
||||
# Check for non word characters: a-zA-Z0-9
|
||||
# @param [String] str String for testing
|
||||
# @return [Boolean] If the string only has alphanums
|
||||
def self.alphanums_only?(str)
|
||||
return false unless is_non_empty_string?(str)
|
||||
|
||||
only?('a-zA-Z0-9', str)
|
||||
end
|
||||
|
||||
# @overload self.is_valid_ip?(ip, version)
|
||||
# Checks if the given string is a valid IP address
|
||||
# @param [String] ip string to be tested
|
||||
# @param [Symbol] version IP version (either <code>:ipv4</code> or <code>:ipv6</code>)
|
||||
# @return [Boolean] true if the string is a valid IP address, otherwise false
|
||||
#
|
||||
# @overload self.is_valid_ip?(ip)
|
||||
# Checks if the given string is either a valid IPv4 or IPv6 address
|
||||
# @param [String] ip string to be tested
|
||||
# @return [Boolean] true if the string is a valid IPv4 or IPV6 address, otherwise false
|
||||
def self.is_valid_ip?(ip, version = :both)
|
||||
return false unless is_non_empty_string?(ip)
|
||||
|
||||
if case version.inspect.downcase
|
||||
when /^:ipv4$/
|
||||
ip =~ /^((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}
|
||||
(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])$/x
|
||||
when /^:ipv6$/
|
||||
ip =~ /^(([0-9a-f]{1,4}:){7,7}[0-9a-f]{1,4}|
|
||||
([0-9a-f]{1,4}:){1,7}:|
|
||||
([0-9a-f]{1,4}:){1,6}:[0-9a-f]{1,4}|
|
||||
([0-9a-f]{1,4}:){1,5}(:[0-9a-f]{1,4}){1,2}|
|
||||
([0-9a-f]{1,4}:){1,4}(:[0-9a-f]{1,4}){1,3}|
|
||||
([0-9a-f]{1,4}:){1,3}(:[0-9a-f]{1,4}){1,4}|
|
||||
([0-9a-f]{1,4}:){1,2}(:[0-9a-f]{1,4}){1,5}|
|
||||
[0-9a-f]{1,4}:((:[0-9a-f]{1,4}){1,6})|
|
||||
:((:[0-9a-f]{1,4}){1,7}|:)|
|
||||
fe80:(:[0-9a-f]{0,4}){0,4}%[0-9a-z]{1,}|
|
||||
::(ffff(:0{1,4}){0,1}:){0,1}
|
||||
((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]).){3,3}
|
||||
(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|
|
||||
([0-9a-f]{1,4}:){1,4}:
|
||||
((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]).){3,3}
|
||||
(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))$/ix
|
||||
when /^:both$/
|
||||
is_valid_ip?(ip, :ipv4) || is_valid_ip?(ip, :ipv6)
|
||||
end
|
||||
true
|
||||
else
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
# Checks if the given string is a valid private IP address
|
||||
# @param [String] ip string for testing
|
||||
# @return [Boolean] true if the string is a valid private IP address, otherwise false
|
||||
# @note Includes RFC1918 private IPv4, private IPv6, and localhost 127.0.0.0/8, but does not include local-link addresses.
|
||||
def self.is_valid_private_ip?(ip)
|
||||
return false unless is_valid_ip?(ip)
|
||||
|
||||
ip =~ /\A(^127\.)|(^192\.168\.)|(^10\.)|(^172\.1[6-9]\.)|(^172\.2[0-9]\.)|(^172\.3[0-1]\.)|(^::1$)|(^[fF][cCdD])\z/ ? true : false
|
||||
end
|
||||
|
||||
# Checks if the given string is a valid TCP port
|
||||
# @param [String] port string for testing
|
||||
# @return [Boolean] true if the string is a valid TCP port, otherwise false
|
||||
def self.is_valid_port?(port)
|
||||
valid = false
|
||||
valid = true if port.to_i > 0 && port.to_i < 2**16
|
||||
valid
|
||||
end
|
||||
|
||||
# Checks if string is a valid domain name
|
||||
# @param [String] domain string for testing
|
||||
# @return [Boolean] If the string is a valid domain name
|
||||
# @note Only validates the string format. It does not check for a valid TLD since ICANN's list of TLD's is not static.
|
||||
def self.is_valid_domain?(domain)
|
||||
return false unless is_non_empty_string?(domain)
|
||||
return true if domain =~ /^[0-9a-z-]+(\.[0-9a-z-]+)*(\.[a-z]{2,}).?$/i
|
||||
|
||||
false
|
||||
end
|
||||
|
||||
# Check for valid browser details characters
|
||||
# @param [String] str String for testing
|
||||
# @return [Boolean] If the string has valid browser details characters
|
||||
# @note This function passes the \302\256 character which translates to the registered symbol (r)
|
||||
def self.has_valid_browser_details_chars?(str)
|
||||
return false unless is_non_empty_string?(str)
|
||||
|
||||
!(str =~ %r{[^\w\d\s()-.,;:_/!\302\256]}).nil?
|
||||
end
|
||||
|
||||
# Check for valid base details characters
|
||||
# @param [String] str String for testing
|
||||
# @return [Boolean] If the string has only valid base characters
|
||||
# @note This is for basic filtering where possible all specific filters must be implemented
|
||||
# @note This function passes the \302\256 character which translates to the registered symbol (r)
|
||||
def self.has_valid_base_chars?(str)
|
||||
return false unless is_non_empty_string?(str)
|
||||
|
||||
(str =~ /[^\302\256[:print:]]/).nil?
|
||||
end
|
||||
|
||||
# Verify the yes and no is valid
|
||||
# @param [String] str String for testing
|
||||
# @return [Boolean] If the string is either 'yes' or 'no'
|
||||
def self.is_valid_yes_no?(str)
|
||||
return false if has_non_printable_char?(str)
|
||||
return false if str !~ /\A(Yes|No)\z/i
|
||||
|
||||
true
|
||||
end
|
||||
end
|
||||
|
||||
# Check if only the characters in 'chars' are in 'str'
|
||||
# @param [String] chars List of characters to match
|
||||
# @param [String] str String for testing
|
||||
# @return [Boolean] Whether or not the only characters in str are specified in chars
|
||||
def self.only?(chars, str)
|
||||
regex = Regexp.new('[^' + chars + ']')
|
||||
regex.match(str.encode('UTF-8', invalid: :replace, undef: :replace, replace: '')).nil?
|
||||
end
|
||||
|
||||
# Check if one or more characters in 'chars' are in 'str'
|
||||
# @param [String] chars List of characters to match
|
||||
# @param [String] str String for testing
|
||||
# @return [Boolean] Whether one of the characters exists in the string
|
||||
def self.exists?(chars, str)
|
||||
regex = Regexp.new(chars)
|
||||
not regex.match(str.encode('UTF-8', invalid: :replace, undef: :replace, replace: '')).nil?
|
||||
end
|
||||
|
||||
# Check for null char
|
||||
# @param [String] str String for testing
|
||||
# @return [Boolean] If the string has a null character
|
||||
def self.has_null? (str)
|
||||
return false unless is_non_empty_string?(str)
|
||||
exists?('\x00', str)
|
||||
end
|
||||
|
||||
# Check for non-printable char
|
||||
# @param [String] str String for testing
|
||||
# @return [Boolean] Whether or not the string has non-printable characters
|
||||
def self.has_non_printable_char?(str)
|
||||
return false unless is_non_empty_string?(str)
|
||||
not only?('[:print:]', str)
|
||||
end
|
||||
|
||||
# Check if num characters only
|
||||
# @param [String] str String for testing
|
||||
# @return [Boolean] If the string only contains numbers
|
||||
def self.nums_only?(str)
|
||||
return false unless is_non_empty_string?(str)
|
||||
only?('0-9', str)
|
||||
end
|
||||
|
||||
# Check if valid float
|
||||
# @param [String] str String for float testing
|
||||
# @return [Boolean] If the string is a valid float
|
||||
def self.is_valid_float?(str)
|
||||
return false unless is_non_empty_string?(str)
|
||||
return false unless only?('0-9\.', str)
|
||||
not (str =~ /^[\d]+\.[\d]+$/).nil?
|
||||
end
|
||||
|
||||
# Check if hex characters only
|
||||
# @param [String] str String for testing
|
||||
# @return [Boolean] If the string only contains hex characters
|
||||
def self.hexs_only?(str)
|
||||
return false unless is_non_empty_string?(str)
|
||||
only?('0123456789ABCDEFabcdef', str)
|
||||
end
|
||||
|
||||
# Check if first character is a number
|
||||
# @param [String] String for testing
|
||||
# @return [Boolean] If the first character of the string is a number
|
||||
def self.first_char_is_num?(str)
|
||||
return false unless is_non_empty_string?(str)
|
||||
not (str =~ /^\d.*/).nil?
|
||||
end
|
||||
|
||||
# Check for space characters: \t\n\r\f
|
||||
# @param [String] str String for testing
|
||||
# @return [Boolean] If the string has a whitespace character
|
||||
def self.has_whitespace_char?(str)
|
||||
return false unless is_non_empty_string?(str)
|
||||
exists?('\s', str)
|
||||
end
|
||||
|
||||
# Check for non word characters: a-zA-Z0-9
|
||||
# @param [String] str String for testing
|
||||
# @return [Boolean] If the string only has alphanums
|
||||
def self.alphanums_only?(str)
|
||||
return false unless is_non_empty_string?(str)
|
||||
only?("a-zA-Z0-9", str)
|
||||
end
|
||||
|
||||
# @overload self.is_valid_ip?(ip, version)
|
||||
# Checks if the given string is a valid IP address
|
||||
# @param [String] ip string to be tested
|
||||
# @param [Symbol] version IP version (either <code>:ipv4</code> or <code>:ipv6</code>)
|
||||
# @return [Boolean] true if the string is a valid IP address, otherwise false
|
||||
#
|
||||
# @overload self.is_valid_ip?(ip)
|
||||
# Checks if the given string is either a valid IPv4 or IPv6 address
|
||||
# @param [String] ip string to be tested
|
||||
# @return [Boolean] true if the string is a valid IPv4 or IPV6 address, otherwise false
|
||||
def self.is_valid_ip?(ip, version = :both)
|
||||
return false unless is_non_empty_string?(ip)
|
||||
valid = case version.inspect.downcase
|
||||
when /^:ipv4$/
|
||||
ip =~ /^((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}
|
||||
(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])$/x
|
||||
when /^:ipv6$/
|
||||
ip =~ /^(([0-9a-f]{1,4}:){7,7}[0-9a-f]{1,4}|
|
||||
([0-9a-f]{1,4}:){1,7}:|
|
||||
([0-9a-f]{1,4}:){1,6}:[0-9a-f]{1,4}|
|
||||
([0-9a-f]{1,4}:){1,5}(:[0-9a-f]{1,4}){1,2}|
|
||||
([0-9a-f]{1,4}:){1,4}(:[0-9a-f]{1,4}){1,3}|
|
||||
([0-9a-f]{1,4}:){1,3}(:[0-9a-f]{1,4}){1,4}|
|
||||
([0-9a-f]{1,4}:){1,2}(:[0-9a-f]{1,4}){1,5}|
|
||||
[0-9a-f]{1,4}:((:[0-9a-f]{1,4}){1,6})|
|
||||
:((:[0-9a-f]{1,4}){1,7}|:)|
|
||||
fe80:(:[0-9a-f]{0,4}){0,4}%[0-9a-z]{1,}|
|
||||
::(ffff(:0{1,4}){0,1}:){0,1}
|
||||
((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]).){3,3}
|
||||
(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|
|
||||
([0-9a-f]{1,4}:){1,4}:
|
||||
((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]).){3,3}
|
||||
(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))$/ix
|
||||
when /^:both$/
|
||||
is_valid_ip?(ip, :ipv4) || is_valid_ip?(ip, :ipv6)
|
||||
end ? true : false
|
||||
|
||||
valid
|
||||
end
|
||||
|
||||
# Checks if the given string is a valid private IP address
|
||||
# @param [String] ip string for testing
|
||||
# @return [Boolean] true if the string is a valid private IP address, otherwise false
|
||||
# @note Includes RFC1918 private IPv4, private IPv6, and localhost 127.0.0.0/8, but does not include local-link addresses.
|
||||
def self.is_valid_private_ip?(ip)
|
||||
return false unless is_valid_ip?(ip)
|
||||
return ip =~ /\A(^127\.)|(^192\.168\.)|(^10\.)|(^172\.1[6-9]\.)|(^172\.2[0-9]\.)|(^172\.3[0-1]\.)|(^::1$)|(^[fF][cCdD])\z/ ? true : false
|
||||
end
|
||||
|
||||
# Checks if the given string is a valid TCP port
|
||||
# @param [String] port string for testing
|
||||
# @return [Boolean] true if the string is a valid TCP port, otherwise false
|
||||
def self.is_valid_port?(port)
|
||||
valid = false
|
||||
valid = true if port.to_i > 0 && port.to_i < 2**16
|
||||
valid
|
||||
end
|
||||
|
||||
# Checks if string is a valid domain name
|
||||
# @param [String] domain string for testing
|
||||
# @return [Boolean] If the string is a valid domain name
|
||||
# @note Only validates the string format. It does not check for a valid TLD since ICANN's list of TLD's is not static.
|
||||
def self.is_valid_domain?(domain)
|
||||
return false unless is_non_empty_string?(domain)
|
||||
return true if domain =~ /^[0-9a-z-]+(\.[0-9a-z-]+)*(\.[a-z]{2,}).?$/i
|
||||
false
|
||||
end
|
||||
|
||||
# Check for valid browser details characters
|
||||
# @param [String] str String for testing
|
||||
# @return [Boolean] If the string has valid browser details characters
|
||||
# @note This function passes the \302\256 character which translates to the registered symbol (r)
|
||||
def self.has_valid_browser_details_chars?(str)
|
||||
return false unless is_non_empty_string?(str)
|
||||
not (str =~ /[^\w\d\s()-.,;:_\/!\302\256]/).nil?
|
||||
end
|
||||
|
||||
# Check for valid base details characters
|
||||
# @param [String] str String for testing
|
||||
# @return [Boolean] If the string has only valid base characters
|
||||
# @note This is for basic filtering where possible all specific filters must be implemented
|
||||
# @note This function passes the \302\256 character which translates to the registered symbol (r)
|
||||
def self.has_valid_base_chars?(str)
|
||||
return false unless is_non_empty_string?(str)
|
||||
(str =~ /[^\302\256[:print:]]/).nil?
|
||||
end
|
||||
|
||||
# Verify the yes and no is valid
|
||||
# @param [String] str String for testing
|
||||
# @return [Boolean] If the string is either 'yes' or 'no'
|
||||
def self.is_valid_yes_no?(str)
|
||||
return false if has_non_printable_char?(str)
|
||||
return false if str !~ /\A(Yes|No)\z/i
|
||||
true
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,151 +1,162 @@
|
||||
#
|
||||
# Copyright (c) 2006-2021 Wade Alcorn - wade@bindshell.net
|
||||
# Copyright (c) 2006-2024 Wade Alcorn - wade@bindshell.net
|
||||
# Browser Exploitation Framework (BeEF) - http://beefproject.com
|
||||
# See the file 'doc/COPYING' for copying permission
|
||||
#
|
||||
module BeEF
|
||||
module Filters
|
||||
module Filters
|
||||
# Check the browser type value - for example, 'FF'
|
||||
# @param [String] str String for testing
|
||||
# @return [Boolean] If the string has valid browser name characters
|
||||
def self.is_valid_browsername?(str)
|
||||
return false unless is_non_empty_string?(str)
|
||||
return false if str.length > 2
|
||||
return false if has_non_printable_char?(str)
|
||||
|
||||
# Check the browser type value - for example, 'FF'
|
||||
# @param [String] str String for testing
|
||||
# @return [Boolean] If the string has valid browser name characters
|
||||
def self.is_valid_browsername?(str)
|
||||
return false unless is_non_empty_string?(str)
|
||||
return false if str.length > 2
|
||||
return false if has_non_printable_char?(str)
|
||||
true
|
||||
end
|
||||
true
|
||||
end
|
||||
|
||||
# Check the Operating System name value - for example, 'Windows XP'
|
||||
# @param [String] str String for testing
|
||||
# @return [Boolean] If the string has valid Operating System name characters
|
||||
def self.is_valid_osname?(str)
|
||||
return false unless is_non_empty_string?(str)
|
||||
return false if has_non_printable_char?(str)
|
||||
return false if str.length < 2
|
||||
true
|
||||
end
|
||||
# Check the Operating System name value - for example, 'Windows XP'
|
||||
# @param [String] str String for testing
|
||||
# @return [Boolean] If the string has valid Operating System name characters
|
||||
def self.is_valid_osname?(str)
|
||||
return false unless is_non_empty_string?(str)
|
||||
return false if has_non_printable_char?(str)
|
||||
return false if str.length < 2
|
||||
|
||||
# Check the Hardware name value - for example, 'iPhone'
|
||||
# @param [String] str String for testing
|
||||
# @return [Boolean] If the string has valid Hardware name characters
|
||||
def self.is_valid_hwname?(str)
|
||||
return false unless is_non_empty_string?(str)
|
||||
return false if has_non_printable_char?(str)
|
||||
return false if str.length < 2
|
||||
true
|
||||
end
|
||||
true
|
||||
end
|
||||
|
||||
# Verify the browser version string is valid
|
||||
# @param [String] str String for testing
|
||||
# @return [Boolean] If the string has valid browser version characters
|
||||
def self.is_valid_browserversion?(str)
|
||||
return false unless is_non_empty_string?(str)
|
||||
return false if has_non_printable_char?(str)
|
||||
return true if str.eql? "UNKNOWN"
|
||||
return true if str.eql? "ALL"
|
||||
return false if not nums_only?(str) and not is_valid_float?(str)
|
||||
return false if str.length > 20
|
||||
true
|
||||
end
|
||||
# Check the Hardware name value - for example, 'iPhone'
|
||||
# @param [String] str String for testing
|
||||
# @return [Boolean] If the string has valid Hardware name characters
|
||||
def self.is_valid_hwname?(str)
|
||||
return false unless is_non_empty_string?(str)
|
||||
return false if has_non_printable_char?(str)
|
||||
return false if str.length < 2
|
||||
|
||||
# Verify the os version string is valid
|
||||
# @param [String] str String for testing
|
||||
# @return [Boolean] If the string has valid os version characters
|
||||
def self.is_valid_osversion?(str)
|
||||
return false unless is_non_empty_string?(str)
|
||||
return false if has_non_printable_char?(str)
|
||||
return true if str.eql? "UNKNOWN"
|
||||
return true if str.eql? "ALL"
|
||||
return false unless BeEF::Filters::only?("a-zA-Z0-9.<=> ", str)
|
||||
return false if str.length > 20
|
||||
true
|
||||
end
|
||||
true
|
||||
end
|
||||
|
||||
# Verify the browser/UA string is valid
|
||||
# @param [String] str String for testing
|
||||
# @return [Boolean] If the string has valid browser / ua string characters
|
||||
def self.is_valid_browserstring?(str)
|
||||
return false unless is_non_empty_string?(str)
|
||||
return false if has_non_printable_char?(str)
|
||||
return false if str.length > 300
|
||||
true
|
||||
end
|
||||
|
||||
# Verify the cookies are valid
|
||||
# @param [String] str String for testing
|
||||
# @return [Boolean] If the string has valid cookie characters
|
||||
def self.is_valid_cookies?(str)
|
||||
return false unless is_non_empty_string?(str)
|
||||
return false if has_non_printable_char?(str)
|
||||
return false if str.length > 2000
|
||||
true
|
||||
end
|
||||
# Verify the browser version string is valid
|
||||
# @param [String] str String for testing
|
||||
# @return [Boolean] If the string has valid browser version characters
|
||||
def self.is_valid_browserversion?(str)
|
||||
return false unless is_non_empty_string?(str)
|
||||
return false if has_non_printable_char?(str)
|
||||
return true if str.eql? 'UNKNOWN'
|
||||
return true if str.eql? 'ALL'
|
||||
return false if !nums_only?(str) and !is_valid_float?(str)
|
||||
return false if str.length > 20
|
||||
|
||||
# Verify the system platform is valid
|
||||
# @param [String] str String for testing
|
||||
# @return [Boolean] If the string has valid system platform characters
|
||||
def self.is_valid_system_platform?(str)
|
||||
return false unless is_non_empty_string?(str)
|
||||
return false if has_non_printable_char?(str)
|
||||
return false if str.length > 200
|
||||
true
|
||||
end
|
||||
true
|
||||
end
|
||||
|
||||
# Verify the date stamp is valid
|
||||
# @param [String] str String for testing
|
||||
# @return [Boolean] If the string has valid date stamp characters
|
||||
def self.is_valid_date_stamp?(str)
|
||||
return false unless is_non_empty_string?(str)
|
||||
return false if has_non_printable_char?(str)
|
||||
return false if str.length > 200
|
||||
true
|
||||
end
|
||||
# Verify the os version string is valid
|
||||
# @param [String] str String for testing
|
||||
# @return [Boolean] If the string has valid os version characters
|
||||
def self.is_valid_osversion?(str)
|
||||
return false unless is_non_empty_string?(str)
|
||||
return false if has_non_printable_char?(str)
|
||||
return true if str.eql? 'UNKNOWN'
|
||||
return true if str.eql? 'ALL'
|
||||
return false unless BeEF::Filters.only?('a-zA-Z0-9.<=> ', str)
|
||||
return false if str.length > 20
|
||||
|
||||
# Verify the CPU type string is valid
|
||||
# @param [String] str String for testing
|
||||
# @return [Boolean] If the string has valid CPU type characters
|
||||
def self.is_valid_cpu?(str)
|
||||
return false unless is_non_empty_string?(str)
|
||||
return false if has_non_printable_char?(str)
|
||||
return false if str.length > 200
|
||||
true
|
||||
end
|
||||
true
|
||||
end
|
||||
|
||||
# Verify the memory string is valid
|
||||
# @param [String] str String for testing
|
||||
# @return [Boolean] If the string has valid memory type characters
|
||||
def self.is_valid_memory?(str)
|
||||
return false unless is_non_empty_string?(str)
|
||||
return false if has_non_printable_char?(str)
|
||||
return false if str.length > 200
|
||||
true
|
||||
end
|
||||
# Verify the browser/UA string is valid
|
||||
# @param [String] str String for testing
|
||||
# @return [Boolean] If the string has valid browser / ua string characters
|
||||
def self.is_valid_browserstring?(str)
|
||||
return false unless is_non_empty_string?(str)
|
||||
return false if has_non_printable_char?(str)
|
||||
return false if str.length > 300
|
||||
|
||||
# Verify the GPU type string is valid
|
||||
# @param [String] str String for testing
|
||||
# @return [Boolean] If the string has valid GPU type characters
|
||||
def self.is_valid_gpu?(str)
|
||||
return false unless is_non_empty_string?(str)
|
||||
return false if has_non_printable_char?(str)
|
||||
return false if str.length > 200
|
||||
true
|
||||
end
|
||||
true
|
||||
end
|
||||
|
||||
# Verify the browser_plugins string is valid
|
||||
# @param [String] str String for testing
|
||||
# @return [Boolean] If the string has valid browser plugin characters
|
||||
# @note This string can be empty if there are no browser plugins
|
||||
# @todo Verify if the ruby version statement is still necessary
|
||||
def self.is_valid_browser_plugins?(str)
|
||||
return false unless is_non_empty_string?(str)
|
||||
return false if str.length > 1000
|
||||
if str.encoding === Encoding.find('UTF-8')
|
||||
return (str =~ /[^\w\d\s()-.,';_!\302\256]/u).nil?
|
||||
else
|
||||
return (str =~ /[^\w\d\s()-.,';_!\302\256]/n).nil?
|
||||
# Verify the cookies are valid
|
||||
# @param [String] str String for testing
|
||||
# @return [Boolean] If the string has valid cookie characters
|
||||
def self.is_valid_cookies?(str)
|
||||
return false unless is_non_empty_string?(str)
|
||||
return false if has_non_printable_char?(str)
|
||||
return false if str.length > 2000
|
||||
|
||||
true
|
||||
end
|
||||
|
||||
# Verify the system platform is valid
|
||||
# @param [String] str String for testing
|
||||
# @return [Boolean] If the string has valid system platform characters
|
||||
def self.is_valid_system_platform?(str)
|
||||
return false unless is_non_empty_string?(str)
|
||||
return false if has_non_printable_char?(str)
|
||||
return false if str.length > 200
|
||||
|
||||
true
|
||||
end
|
||||
|
||||
# Verify the date stamp is valid
|
||||
# @param [String] str String for testing
|
||||
# @return [Boolean] If the string has valid date stamp characters
|
||||
def self.is_valid_date_stamp?(str)
|
||||
return false unless is_non_empty_string?(str)
|
||||
return false if has_non_printable_char?(str)
|
||||
return false if str.length > 200
|
||||
|
||||
true
|
||||
end
|
||||
|
||||
# Verify the CPU type string is valid
|
||||
# @param [String] str String for testing
|
||||
# @return [Boolean] If the string has valid CPU type characters
|
||||
def self.is_valid_cpu?(str)
|
||||
return false unless is_non_empty_string?(str)
|
||||
return false if has_non_printable_char?(str)
|
||||
return false if str.length > 200
|
||||
|
||||
true
|
||||
end
|
||||
|
||||
# Verify the memory string is valid
|
||||
# @param [String] str String for testing
|
||||
# @return [Boolean] If the string has valid memory type characters
|
||||
def self.is_valid_memory?(str)
|
||||
return false unless is_non_empty_string?(str)
|
||||
return false if has_non_printable_char?(str)
|
||||
return false if str.length > 200
|
||||
|
||||
true
|
||||
end
|
||||
|
||||
# Verify the GPU type string is valid
|
||||
# @param [String] str String for testing
|
||||
# @return [Boolean] If the string has valid GPU type characters
|
||||
def self.is_valid_gpu?(str)
|
||||
return false unless is_non_empty_string?(str)
|
||||
return false if has_non_printable_char?(str)
|
||||
return false if str.length > 200
|
||||
|
||||
true
|
||||
end
|
||||
|
||||
# Verify the browser_plugins string is valid
|
||||
# @param [String] str String for testing
|
||||
# @return [Boolean] If the string has valid browser plugin characters
|
||||
# @note This string can be empty if there are no browser plugins
|
||||
# @todo Verify if the ruby version statement is still necessary
|
||||
def self.is_valid_browser_plugins?(str)
|
||||
return false unless is_non_empty_string?(str)
|
||||
return false if str.length > 1000
|
||||
|
||||
if str.encoding === Encoding.find('UTF-8')
|
||||
(str =~ /[^\w\d\s()-.,';_!\302\256]/u).nil?
|
||||
else
|
||||
(str =~ /[^\w\d\s()-.,';_!\302\256]/n).nil?
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,67 +1,71 @@
|
||||
#
|
||||
# Copyright (c) 2006-2021 Wade Alcorn - wade@bindshell.net
|
||||
# Copyright (c) 2006-2024 Wade Alcorn - wade@bindshell.net
|
||||
# Browser Exploitation Framework (BeEF) - http://beefproject.com
|
||||
# See the file 'doc/COPYING' for copying permission
|
||||
#
|
||||
module BeEF
|
||||
module Filters
|
||||
|
||||
# Check if the string is a valid path from a HTTP request
|
||||
# @param [String] str String for testing
|
||||
# @return [Boolean] If the string has valid path characters
|
||||
def self.is_valid_path_info?(str)
|
||||
return false if str.nil?
|
||||
return false unless str.is_a? String
|
||||
return false if has_non_printable_char?(str)
|
||||
true
|
||||
end
|
||||
module Filters
|
||||
# Check if the string is a valid path from a HTTP request
|
||||
# @param [String] str String for testing
|
||||
# @return [Boolean] If the string has valid path characters
|
||||
def self.is_valid_path_info?(str)
|
||||
return false if str.nil?
|
||||
return false unless str.is_a? String
|
||||
return false if has_non_printable_char?(str)
|
||||
|
||||
# Check if the session id valid
|
||||
# @param [String] str String for testing
|
||||
# @return [Boolean] If the string has valid hook session id characters
|
||||
def self.is_valid_hook_session_id?(str)
|
||||
return false unless is_non_empty_string?(str)
|
||||
return false unless has_valid_key_chars?(str)
|
||||
true
|
||||
end
|
||||
true
|
||||
end
|
||||
|
||||
# Check if valid command module datastore key
|
||||
# @param [String] str String for testing
|
||||
# @return [Boolean] If the string has valid command module datastore key characters
|
||||
def self.is_valid_command_module_datastore_key?(str)
|
||||
return false unless is_non_empty_string?(str)
|
||||
return false unless has_valid_key_chars?(str)
|
||||
true
|
||||
end
|
||||
# Check if the session id valid
|
||||
# @param [String] str String for testing
|
||||
# @return [Boolean] If the string has valid hook session id characters
|
||||
def self.is_valid_hook_session_id?(str)
|
||||
return false unless is_non_empty_string?(str)
|
||||
return false unless has_valid_key_chars?(str)
|
||||
|
||||
# Check if valid command module datastore value
|
||||
# @param [String] str String for testing
|
||||
# @return [Boolean] If the string has valid command module datastore param characters
|
||||
def self.is_valid_command_module_datastore_param?(str)
|
||||
return false if has_null?(str)
|
||||
return false unless has_valid_base_chars?(str)
|
||||
true
|
||||
end
|
||||
true
|
||||
end
|
||||
|
||||
# Check for word and some punc chars
|
||||
# @param [String] str String for testing
|
||||
# @return [Boolean] If the string has valid key characters
|
||||
def self.has_valid_key_chars?(str)
|
||||
return false unless is_non_empty_string?(str)
|
||||
return false unless has_valid_base_chars?(str)
|
||||
true
|
||||
end
|
||||
# Check if valid command module datastore key
|
||||
# @param [String] str String for testing
|
||||
# @return [Boolean] If the string has valid command module datastore key characters
|
||||
def self.is_valid_command_module_datastore_key?(str)
|
||||
return false unless is_non_empty_string?(str)
|
||||
return false unless has_valid_key_chars?(str)
|
||||
|
||||
# Check for word and underscore chars
|
||||
# @param [String] str String for testing
|
||||
# @return [Boolean] If the sting has valid param characters
|
||||
def self.has_valid_param_chars?(str)
|
||||
return false if str.nil?
|
||||
return false unless str.is_a? String
|
||||
return false if str.empty?
|
||||
return false unless (str =~ /[^\w_\:]/).nil?
|
||||
true
|
||||
end
|
||||
true
|
||||
end
|
||||
|
||||
end
|
||||
# Check if valid command module datastore value
|
||||
# @param [String] str String for testing
|
||||
# @return [Boolean] If the string has valid command module datastore param characters
|
||||
def self.is_valid_command_module_datastore_param?(str)
|
||||
return false if has_null?(str)
|
||||
return false unless has_valid_base_chars?(str)
|
||||
|
||||
true
|
||||
end
|
||||
|
||||
# Check for word and some punc chars
|
||||
# @param [String] str String for testing
|
||||
# @return [Boolean] If the string has valid key characters
|
||||
def self.has_valid_key_chars?(str)
|
||||
return false unless is_non_empty_string?(str)
|
||||
return false unless has_valid_base_chars?(str)
|
||||
|
||||
true
|
||||
end
|
||||
|
||||
# Check for word and underscore chars
|
||||
# @param [String] str String for testing
|
||||
# @return [Boolean] If the sting has valid param characters
|
||||
def self.has_valid_param_chars?(str)
|
||||
return false if str.nil?
|
||||
return false unless str.is_a? String
|
||||
return false if str.empty?
|
||||
return false unless (str =~ /[^\w_:]/).nil?
|
||||
|
||||
true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,61 +1,62 @@
|
||||
#
|
||||
# Copyright (c) 2006-2021 Wade Alcorn - wade@bindshell.net
|
||||
# Copyright (c) 2006-2024 Wade Alcorn - wade@bindshell.net
|
||||
# Browser Exploitation Framework (BeEF) - http://beefproject.com
|
||||
# See the file 'doc/COPYING' for copying permission
|
||||
#
|
||||
module BeEF
|
||||
module Filters
|
||||
|
||||
# Verify the hostname string is valid
|
||||
# @param [String] str String for testing
|
||||
# @return [Boolean] If the string is a valid hostname
|
||||
def self.is_valid_hostname?(str)
|
||||
return false unless is_non_empty_string?(str)
|
||||
return false if has_non_printable_char?(str)
|
||||
return false if str.length > 255
|
||||
return false if (str =~ /^[a-zA-Z0-9][a-zA-Z0-9\-\.]*[a-zA-Z0-9]$/).nil?
|
||||
true
|
||||
module BeEF
|
||||
module Filters
|
||||
# Verify the hostname string is valid
|
||||
# @param [String] str String for testing
|
||||
# @return [Boolean] If the string is a valid hostname
|
||||
def self.is_valid_hostname?(str)
|
||||
return false unless is_non_empty_string?(str)
|
||||
return false if has_non_printable_char?(str)
|
||||
return false if str.length > 255
|
||||
return false if (str =~ /^[a-zA-Z0-9][a-zA-Z0-9\-.]*[a-zA-Z0-9]$/).nil?
|
||||
|
||||
true
|
||||
end
|
||||
|
||||
def self.is_valid_verb?(verb)
|
||||
%w[HEAD GET POST OPTIONS PUT DELETE].each { |v| return true if verb.eql? v }
|
||||
false
|
||||
end
|
||||
|
||||
def self.is_valid_url?(uri)
|
||||
return true unless uri.nil?
|
||||
|
||||
# OPTIONS * is not yet supported
|
||||
# return true if uri.eql? "*"
|
||||
# TODO : CHECK THE normalize_path method and include it somewhere (maybe here)
|
||||
# return true if uri.eql? self.normalize_path(uri)
|
||||
false
|
||||
end
|
||||
|
||||
def self.is_valid_http_version?(version)
|
||||
# from browsers the http version contains a space at the end ("HTTP/1.0\r")
|
||||
version.gsub!(/\r+/, '')
|
||||
['HTTP/1.0', 'HTTP/1.1'].each { |v| return true if version.eql? v }
|
||||
false
|
||||
end
|
||||
|
||||
def self.is_valid_host_str?(host_str)
|
||||
# from browsers the host header contains a space at the end
|
||||
host_str.gsub!(/\r+/, '')
|
||||
return true if 'Host:'.eql?(host_str)
|
||||
|
||||
false
|
||||
end
|
||||
|
||||
def normalize_path(path)
|
||||
print_error "abnormal path `#{path}'" if path[0] != '/'
|
||||
ret = path.dup
|
||||
|
||||
ret.gsub!(%r{/+}o, '/') # // => /
|
||||
while ret.sub!(%r{/\.(?:/|\Z)}, '/'); end # /. => /
|
||||
while ret.sub!(%r{/(?!\.\./)[^/]+/\.\.(?:/|\Z)}, '/'); end # /foo/.. => /foo
|
||||
|
||||
print_error "abnormal path `#{path}'" if %r{/\.\.(/|\Z)} =~ ret
|
||||
ret
|
||||
end
|
||||
end
|
||||
|
||||
def self.is_valid_verb?(verb)
|
||||
["HEAD", "GET", "POST", "OPTIONS", "PUT", "DELETE"].each {|v| return true if verb.eql? v }
|
||||
false
|
||||
end
|
||||
|
||||
def self.is_valid_url?(uri)
|
||||
return true if !uri.nil?
|
||||
# OPTIONS * is not yet supported
|
||||
#return true if uri.eql? "*"
|
||||
# TODO : CHECK THE normalize_path method and include it somewhere (maybe here)
|
||||
#return true if uri.eql? self.normalize_path(uri)
|
||||
false
|
||||
end
|
||||
|
||||
def self.is_valid_http_version?(version)
|
||||
# from browsers the http version contains a space at the end ("HTTP/1.0\r")
|
||||
version.gsub!(/[\r]+/,"")
|
||||
["HTTP/1.0", "HTTP/1.1"].each {|v| return true if version.eql? v }
|
||||
false
|
||||
end
|
||||
|
||||
def self.is_valid_host_str?(host_str)
|
||||
# from browsers the host header contains a space at the end
|
||||
host_str.gsub!(/[\r]+/,"")
|
||||
return true if "Host:".eql?(host_str)
|
||||
false
|
||||
end
|
||||
|
||||
def normalize_path(path)
|
||||
print_error "abnormal path `#{path}'" if path[0] != ?/
|
||||
ret = path.dup
|
||||
|
||||
ret.gsub!(%r{/+}o, '/') # // => /
|
||||
while ret.sub!(%r'/\.(?:/|\Z)', '/'); end # /. => /
|
||||
while ret.sub!(%r'/(?!\.\./)[^/]+/\.\.(?:/|\Z)', '/'); end # /foo/.. => /foo
|
||||
|
||||
print_error "abnormal path `#{path}'" if %r{/\.\.(/|\Z)} =~ ret
|
||||
ret
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,30 +1,30 @@
|
||||
#
|
||||
# Copyright (c) 2006-2021 Wade Alcorn - wade@bindshell.net
|
||||
# Copyright (c) 2006-2024 Wade Alcorn - wade@bindshell.net
|
||||
# Browser Exploitation Framework (BeEF) - http://beefproject.com
|
||||
# See the file 'doc/COPYING' for copying permission
|
||||
#
|
||||
module BeEF
|
||||
module Filters
|
||||
|
||||
# Verify the page title string is valid
|
||||
# @param [String] str String for testing
|
||||
# @return [Boolean] If the string is a valid page title
|
||||
def self.is_valid_pagetitle?(str)
|
||||
return false unless str.is_a? String
|
||||
return false if has_non_printable_char?(str)
|
||||
return false if str.length > 500 # CxF Increased this because some page titles are MUCH longer
|
||||
true
|
||||
end
|
||||
module Filters
|
||||
# Verify the page title string is valid
|
||||
# @param [String] str String for testing
|
||||
# @return [Boolean] If the string is a valid page title
|
||||
def self.is_valid_pagetitle?(str)
|
||||
return false unless str.is_a? String
|
||||
return false if has_non_printable_char?(str)
|
||||
return false if str.length > 500 # CxF Increased this because some page titles are MUCH longer
|
||||
|
||||
# Verify the page referrer string is valid
|
||||
# @param [String] str String for testing
|
||||
# @return [Boolean] If the string is a valid referrer
|
||||
def self.is_valid_pagereferrer?(str)
|
||||
return false unless str.is_a? String
|
||||
return false if has_non_printable_char?(str)
|
||||
return false if str.length > 350
|
||||
true
|
||||
true
|
||||
end
|
||||
|
||||
# Verify the page referrer string is valid
|
||||
# @param [String] str String for testing
|
||||
# @return [Boolean] If the string is a valid referrer
|
||||
def self.is_valid_pagereferrer?(str)
|
||||
return false unless str.is_a? String
|
||||
return false if has_non_printable_char?(str)
|
||||
return false if str.length > 350
|
||||
|
||||
true
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,16 +1,15 @@
|
||||
#
|
||||
# Copyright (c) 2006-2021 Wade Alcorn - wade@bindshell.net
|
||||
# Copyright (c) 2006-2024 Wade Alcorn - wade@bindshell.net
|
||||
# Browser Exploitation Framework (BeEF) - http://beefproject.com
|
||||
# See the file 'doc/COPYING' for copying permission
|
||||
#
|
||||
module BeEF
|
||||
module HBManager
|
||||
|
||||
# Get hooked browser by session id
|
||||
# @param [String] sid hooked browser session id string
|
||||
# @return [BeEF::Core::Models::HookedBrowser] returns the associated Hooked Browser
|
||||
def self.get_by_session(sid)
|
||||
BeEF::Core::Models::HookedBrowser.where(:session => sid).first
|
||||
BeEF::Core::Models::HookedBrowser.where(session: sid).first
|
||||
end
|
||||
|
||||
# Get hooked browser by id
|
||||
@@ -19,6 +18,5 @@ module BeEF
|
||||
def self.get_by_id(id)
|
||||
BeEF::Core::Models::HookedBrowser.find(id)
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (c) 2006-2021 Wade Alcorn - wade@bindshell.net
|
||||
# Copyright (c) 2006-2024 Wade Alcorn - wade@bindshell.net
|
||||
# Browser Exploitation Framework (BeEF) - http://beefproject.com
|
||||
# See the file 'doc/COPYING' for copying permission
|
||||
#
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (c) 2006-2021 Wade Alcorn - wade@bindshell.net
|
||||
# Copyright (c) 2006-2024 Wade Alcorn - wade@bindshell.net
|
||||
# Browser Exploitation Framework (BeEF) - http://beefproject.com
|
||||
# See the file 'doc/COPYING' for copying permission
|
||||
#
|
||||
@@ -12,8 +12,8 @@ module BeEF
|
||||
attr_writer :logger
|
||||
|
||||
def logger
|
||||
@logger ||= Logger.new("#{$home_dir}/beef.log").tap do |log|
|
||||
log.progname = self.name
|
||||
@logger ||= Logger.new("#{$home_dir}/beef.log").tap do |log|
|
||||
log.progname = name
|
||||
log.level = Logger::WARN
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,12 +1,8 @@
|
||||
class CreateCommandModules < ActiveRecord::Migration[6.0]
|
||||
|
||||
def change
|
||||
|
||||
create_table :command_modules do |t|
|
||||
t.text :name
|
||||
t.text :path
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
def change
|
||||
create_table :command_modules do |t|
|
||||
t.text :name
|
||||
t.text :path
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,19 +1,15 @@
|
||||
class CreateHookedBrowsers < ActiveRecord::Migration[6.0]
|
||||
|
||||
def change
|
||||
|
||||
create_table :hooked_browsers do |t|
|
||||
t.text :session
|
||||
t.text :ip
|
||||
t.text :firstseen
|
||||
t.text :lastseen
|
||||
t.text :httpheaders
|
||||
t.text :domain
|
||||
t.integer :port
|
||||
t.integer :count
|
||||
t.boolean :is_proxy
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
def change
|
||||
create_table :hooked_browsers do |t|
|
||||
t.text :session
|
||||
t.text :ip
|
||||
t.text :firstseen
|
||||
t.text :lastseen
|
||||
t.text :httpheaders
|
||||
t.text :domain
|
||||
t.integer :port
|
||||
t.integer :count
|
||||
t.boolean :is_proxy
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,14 +1,10 @@
|
||||
class CreateLogs < ActiveRecord::Migration[6.0]
|
||||
|
||||
def change
|
||||
|
||||
create_table :logs do |t|
|
||||
t.text :logtype
|
||||
t.text :event
|
||||
t.datetime :date
|
||||
t.references :hooked_browser
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
def change
|
||||
create_table :logs do |t|
|
||||
t.text :logtype
|
||||
t.text :event
|
||||
t.datetime :date
|
||||
t.references :hooked_browser
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,16 +1,12 @@
|
||||
class CreateCommands < ActiveRecord::Migration[6.0]
|
||||
|
||||
def change
|
||||
|
||||
create_table :commands do |t|
|
||||
t.references :command_module
|
||||
t.references :hooked_browser
|
||||
t.text :data
|
||||
t.datetime :creationdate
|
||||
t.text :label
|
||||
t.boolean :instructions_sent, default: false
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
def change
|
||||
create_table :commands do |t|
|
||||
t.references :command_module
|
||||
t.references :hooked_browser
|
||||
t.text :data
|
||||
t.datetime :creationdate
|
||||
t.text :label
|
||||
t.boolean :instructions_sent, default: false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,15 +1,11 @@
|
||||
class CreateResults < ActiveRecord::Migration[6.0]
|
||||
|
||||
def change
|
||||
|
||||
create_table :results do |t|
|
||||
t.references :command
|
||||
t.references :hooked_browser
|
||||
t.datetime :date
|
||||
t.integer :status
|
||||
t.text :data
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
def change
|
||||
create_table :results do |t|
|
||||
t.references :command
|
||||
t.references :hooked_browser
|
||||
t.datetime :date
|
||||
t.integer :status
|
||||
t.text :data
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,12 +1,8 @@
|
||||
class CreateOptionCaches < ActiveRecord::Migration[6.0]
|
||||
|
||||
def change
|
||||
|
||||
create_table :option_caches do |t|
|
||||
t.text :name
|
||||
t.text :value
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
def change
|
||||
create_table :option_caches do |t|
|
||||
t.text :name
|
||||
t.text :value
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,13 +1,9 @@
|
||||
class CreateBrowserDetails < ActiveRecord::Migration[6.0]
|
||||
|
||||
def change
|
||||
|
||||
create_table :browser_details do |t|
|
||||
t.text :session_id
|
||||
t.text :detail_key
|
||||
t.text :detail_value
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
def change
|
||||
create_table :browser_details do |t|
|
||||
t.text :session_id
|
||||
t.text :detail_key
|
||||
t.text :detail_value
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,18 +1,14 @@
|
||||
class CreateExecutions < ActiveRecord::Migration[6.0]
|
||||
|
||||
def change
|
||||
|
||||
create_table :executions do |t|
|
||||
t.text :session_id
|
||||
t.integer :mod_count
|
||||
t.integer :mod_successful
|
||||
t.text :mod_body
|
||||
t.text :exec_time
|
||||
t.text :rule_token
|
||||
t.boolean :is_sent
|
||||
t.integer :rule_id
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
def change
|
||||
create_table :executions do |t|
|
||||
t.text :session_id
|
||||
t.integer :mod_count
|
||||
t.integer :mod_successful
|
||||
t.text :mod_body
|
||||
t.text :exec_time
|
||||
t.text :rule_token
|
||||
t.boolean :is_sent
|
||||
t.integer :rule_id
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,20 +1,16 @@
|
||||
class CreateRules < ActiveRecord::Migration[6.0]
|
||||
|
||||
def change
|
||||
|
||||
create_table :rules do |t|
|
||||
t.text :name
|
||||
t.text :author
|
||||
t.text :browser
|
||||
t.text :browser_version
|
||||
t.text :os
|
||||
t.text :os_version
|
||||
t.text :modules
|
||||
t.text :execution_order
|
||||
t.text :execution_delay
|
||||
t.text :chain_mode
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
def change
|
||||
create_table :rules do |t|
|
||||
t.text :name
|
||||
t.text :author
|
||||
t.text :browser
|
||||
t.text :browser_version
|
||||
t.text :os
|
||||
t.text :os_version
|
||||
t.text :modules
|
||||
t.text :execution_order
|
||||
t.text :execution_delay
|
||||
t.text :chain_mode
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,12 +1,8 @@
|
||||
class CreateInterceptor < ActiveRecord::Migration[6.0]
|
||||
|
||||
def change
|
||||
|
||||
create_table :interceptors do |t|
|
||||
t.text :ip
|
||||
t.text :post_data
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
def change
|
||||
create_table :interceptors do |t|
|
||||
t.text :ip
|
||||
t.text :post_data
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,12 +1,8 @@
|
||||
class CreateWebCloner < ActiveRecord::Migration[6.0]
|
||||
|
||||
def change
|
||||
|
||||
create_table :web_cloners do |t|
|
||||
t.text :uri
|
||||
t.text :mount
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
def change
|
||||
create_table :web_cloners do |t|
|
||||
t.text :uri
|
||||
t.text :mount
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
class CreateMassMailer < ActiveRecord::Migration[6.0]
|
||||
|
||||
def change
|
||||
|
||||
create_table :mass_mailers do |t|
|
||||
#todo fields
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
@@ -1,17 +1,13 @@
|
||||
class CreateNetworkHost < ActiveRecord::Migration[6.0]
|
||||
|
||||
def change
|
||||
|
||||
create_table :network_hosts do |t|
|
||||
t.references :hooked_browser
|
||||
t.text :ip
|
||||
t.text :hostname
|
||||
t.text :ntype
|
||||
t.text :os
|
||||
t.text :mac
|
||||
t.text :lastseen
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
def change
|
||||
create_table :network_hosts do |t|
|
||||
t.references :hooked_browser
|
||||
t.text :ip
|
||||
t.text :hostname
|
||||
t.text :ntype
|
||||
t.text :os
|
||||
t.text :mac
|
||||
t.text :lastseen
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,15 +1,11 @@
|
||||
class CreateNetworkService < ActiveRecord::Migration[6.0]
|
||||
|
||||
def change
|
||||
|
||||
create_table :network_services do |t|
|
||||
t.references :hooked_browser
|
||||
t.text :proto
|
||||
t.text :ip
|
||||
t.text :port
|
||||
t.text :ntype
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
def change
|
||||
create_table :network_services do |t|
|
||||
t.references :hooked_browser
|
||||
t.text :proto
|
||||
t.text :ip
|
||||
t.text :port
|
||||
t.text :ntype
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,44 +1,40 @@
|
||||
class CreateHttp < ActiveRecord::Migration[6.0]
|
||||
|
||||
def change
|
||||
|
||||
create_table :https do |t|
|
||||
t.text :hooked_browser_id
|
||||
# The http request to perform. In clear text.
|
||||
t.text :request
|
||||
# Boolean value as string to say whether cross-domain requests are allowed
|
||||
t.boolean :allow_cross_domain, :default => true
|
||||
# The http response body received. In clear text.
|
||||
t.text :response_data
|
||||
# The http response code. Useful to handle cases like 404, 500, 302, ...
|
||||
t.integer :response_status_code
|
||||
# The http response code. Human-readable code: success, error, ecc..
|
||||
t.text :response_status_text
|
||||
# The port status. closed, open or not http
|
||||
t.text :response_port_status
|
||||
# The XHR Http response raw headers
|
||||
t.text :response_headers
|
||||
# The http response method. GET or POST.
|
||||
t.text :method
|
||||
# The content length for the request.
|
||||
t.text :content_length, :default => 0
|
||||
# The request protocol/scheme (http/https)
|
||||
t.text :proto
|
||||
# The domain on which perform the request.
|
||||
t.text :domain
|
||||
# The port on which perform the request.
|
||||
t.text :port
|
||||
# Boolean value to say if the request was cross-domain
|
||||
t.text :has_ran, :default => "waiting"
|
||||
# The path of the request.
|
||||
# Example: /secret.html
|
||||
t.text :path
|
||||
# The date at which the http response has been saved.
|
||||
t.datetime :response_date
|
||||
# The date at which the http request has been saved.
|
||||
t.datetime :request_date
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
def change
|
||||
create_table :https do |t|
|
||||
t.text :hooked_browser_id
|
||||
# The http request to perform. In clear text.
|
||||
t.text :request
|
||||
# Boolean value as string to say whether cross-domain requests are allowed
|
||||
t.boolean :allow_cross_domain, default: true
|
||||
# The http response body received. In clear text.
|
||||
t.text :response_data
|
||||
# The http response code. Useful to handle cases like 404, 500, 302, ...
|
||||
t.integer :response_status_code
|
||||
# The http response code. Human-readable code: success, error, ecc..
|
||||
t.text :response_status_text
|
||||
# The port status. closed, open or not http
|
||||
t.text :response_port_status
|
||||
# The XHR Http response raw headers
|
||||
t.text :response_headers
|
||||
# The http response method. GET or POST.
|
||||
t.text :method
|
||||
# The content length for the request.
|
||||
t.text :content_length, default: 0
|
||||
# The request protocol/scheme (http/https)
|
||||
t.text :proto
|
||||
# The domain on which perform the request.
|
||||
t.text :domain
|
||||
# The port on which perform the request.
|
||||
t.text :port
|
||||
# Boolean value to say if the request was cross-domain
|
||||
t.text :has_ran, default: 'waiting'
|
||||
# The path of the request.
|
||||
# Example: /secret.html
|
||||
t.text :path
|
||||
# The date at which the http response has been saved.
|
||||
t.datetime :response_date
|
||||
# The date at which the http request has been saved.
|
||||
t.datetime :request_date
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,13 +1,9 @@
|
||||
class CreateRtcStatus < ActiveRecord::Migration[6.0]
|
||||
|
||||
def change
|
||||
|
||||
create_table :rtc_statuss do |t|
|
||||
t.references :hooked_browser
|
||||
t.integer :target_hooked_browser_id
|
||||
t.text :status
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
def change
|
||||
create_table :rtc_statuss do |t|
|
||||
t.references :hooked_browser
|
||||
t.integer :target_hooked_browser_id
|
||||
t.text :status
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,13 +1,9 @@
|
||||
class CreateRtcManage < ActiveRecord::Migration[6.0]
|
||||
|
||||
def change
|
||||
|
||||
create_table :rtc_manages do |t|
|
||||
t.references :hooked_browser
|
||||
t.text :message
|
||||
t.text :has_sent, default: "waiting"
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
def change
|
||||
create_table :rtc_manages do |t|
|
||||
t.references :hooked_browser
|
||||
t.text :message
|
||||
t.text :has_sent, default: 'waiting'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,14 +1,10 @@
|
||||
class CreateRtcSignal < ActiveRecord::Migration[6.0]
|
||||
|
||||
def change
|
||||
|
||||
create_table :rtc_signals do |t|
|
||||
t.references :hooked_browser
|
||||
t.integer :target_hooked_browser_id
|
||||
t.text :signal
|
||||
t.text :has_sent, default: "waiting"
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
def change
|
||||
create_table :rtc_signals do |t|
|
||||
t.references :hooked_browser
|
||||
t.integer :target_hooked_browser_id
|
||||
t.text :signal
|
||||
t.text :has_sent, default: 'waiting'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,14 +1,10 @@
|
||||
class CreateRtcModuleStatus < ActiveRecord::Migration[6.0]
|
||||
|
||||
def change
|
||||
|
||||
create_table :rtc_module_statuss do |t|
|
||||
t.references :hooked_browser
|
||||
t.references :command_module
|
||||
t.integer :target_hooked_browser_id
|
||||
t.text :status
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
def change
|
||||
create_table :rtc_module_statuss do |t|
|
||||
t.references :hooked_browser
|
||||
t.references :command_module
|
||||
t.integer :target_hooked_browser_id
|
||||
t.text :status
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,14 +1,10 @@
|
||||
class CreateXssraysDetail < ActiveRecord::Migration[6.0]
|
||||
|
||||
def change
|
||||
|
||||
create_table :xssraysdetails do |t|
|
||||
t.references :hooked_browser
|
||||
t.text :vector_name
|
||||
t.text :vector_method
|
||||
t.text :vector_poc
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
def change
|
||||
create_table :xssraysdetails do |t|
|
||||
t.references :hooked_browser
|
||||
t.text :vector_name
|
||||
t.text :vector_method
|
||||
t.text :vector_poc
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,14 +1,10 @@
|
||||
class CreateDnsRule < ActiveRecord::Migration[6.0]
|
||||
|
||||
def change
|
||||
|
||||
create_table :dns_rules do |t|
|
||||
t.text :pattern
|
||||
t.text :resource
|
||||
t.text :response
|
||||
t.text :callback
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
def change
|
||||
create_table :dns_rules do |t|
|
||||
t.text :pattern
|
||||
t.text :resource
|
||||
t.text :response
|
||||
t.text :callback
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
class CreateIpecExploit < ActiveRecord::Migration[6.0]
|
||||
|
||||
def change
|
||||
|
||||
create_table :ipec_exploits do |t|
|
||||
t.text :name
|
||||
t.text :protocol
|
||||
t.text :os
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
@@ -1,13 +0,0 @@
|
||||
class CreateIpecExploitRun < ActiveRecord::Migration[6.0]
|
||||
|
||||
def change
|
||||
|
||||
create_table :ipec_exploit_runs do |t|
|
||||
t.boolean :launched
|
||||
t.text :http_headers
|
||||
t.text :junk_size
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
@@ -1,12 +1,8 @@
|
||||
class CreateAutoloader < ActiveRecord::Migration[6.0]
|
||||
|
||||
def change
|
||||
|
||||
create_table :autoloaders do |t|
|
||||
t.references :command
|
||||
t.boolean :in_use
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
def change
|
||||
create_table :autoloaders do |t|
|
||||
t.references :command
|
||||
t.boolean :in_use
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,18 +1,14 @@
|
||||
class CreateXssraysScan < ActiveRecord::Migration[6.0]
|
||||
|
||||
def change
|
||||
|
||||
create_table :xssraysscans do |t|
|
||||
t.references :hooked_browser
|
||||
t.datetime :scan_start
|
||||
t.datetime :scan_finish
|
||||
t.text :domain
|
||||
t.text :cross_domain
|
||||
t.integer :clean_timeout
|
||||
t.boolean :is_started
|
||||
t.boolean :is_finished
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
def change
|
||||
create_table :xssraysscans do |t|
|
||||
t.references :hooked_browser
|
||||
t.datetime :scan_start
|
||||
t.datetime :scan_finish
|
||||
t.text :domain
|
||||
t.text :cross_domain
|
||||
t.integer :clean_timeout
|
||||
t.boolean :is_started
|
||||
t.boolean :is_finished
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
#
|
||||
# Copyright (c) 2006-2021 Wade Alcorn - wade@bindshell.net
|
||||
# Copyright (c) 2006-2024 Wade Alcorn - wade@bindshell.net
|
||||
# Browser Exploitation Framework (BeEF) - http://beefproject.com
|
||||
# See the file 'doc/COPYING' for copying permission
|
||||
#
|
||||
module BeEF
|
||||
module Core
|
||||
module AutorunEngine
|
||||
|
||||
class Engine
|
||||
|
||||
include Singleton
|
||||
|
||||
def initialize
|
||||
@@ -20,54 +18,264 @@ module BeEF
|
||||
|
||||
@debug_on = @config.get('beef.debug')
|
||||
|
||||
@VERSION = ['<','<=','==','>=','>','ALL']
|
||||
@VERSION_STR = ['XP','Vista']
|
||||
@VERSION = ['<', '<=', '==', '>=', '>', 'ALL']
|
||||
@VERSION_STR = %w[XP Vista 7]
|
||||
end
|
||||
|
||||
# Checks if there are any ARE rules to be triggered for the specified hooked browser.
|
||||
#
|
||||
# Returns an array with rule IDs that matched and should be triggered.
|
||||
# if rule_id is specified, checks will be executed only against the specified rule (useful
|
||||
# for dynamic triggering of new rulesets ar runtime)
|
||||
def find_matching_rules_for_zombie(browser, browser_version, os, os_version)
|
||||
rules = BeEF::Core::Models::Rule.all
|
||||
|
||||
return if rules.nil?
|
||||
return if rules.empty?
|
||||
|
||||
# TODO: handle cases where there are multiple ARE rules for the same hooked browser.
|
||||
# maybe rules need to have priority or something?
|
||||
|
||||
print_info '[ARE] Checking if any defined rules should be triggered on target.'
|
||||
|
||||
match_rules = []
|
||||
rules.each do |rule|
|
||||
next unless zombie_matches_rule?(browser, browser_version, os, os_version, rule)
|
||||
|
||||
match_rules.push(rule.id)
|
||||
print_more("Hooked browser and OS match rule: #{rule.name}.")
|
||||
end
|
||||
|
||||
print_more("Found [#{match_rules.length}/#{rules.length}] ARE rules matching the hooked browser.")
|
||||
|
||||
match_rules
|
||||
end
|
||||
|
||||
# @return [Boolean]
|
||||
# Note: browser version checks are supporting only major versions, ex: C 43, IE 11
|
||||
# Note: OS version checks are supporting major/minor versions, ex: OSX 10.10, Windows 8.1
|
||||
def zombie_matches_rule?(browser, browser_version, os, os_version, rule)
|
||||
return false if rule.nil?
|
||||
|
||||
unless zombie_browser_matches_rule?(browser, browser_version, rule)
|
||||
print_debug("Browser version check -> (hook) #{browser_version} #{rule.browser_version} (rule) : does not match")
|
||||
return false
|
||||
end
|
||||
|
||||
print_debug("Browser version check -> (hook) #{browser_version} #{rule.browser_version} (rule) : matched")
|
||||
|
||||
unless zombie_os_matches_rule?(os, os_version, rule)
|
||||
print_debug("OS version check -> (hook) #{os_version} #{rule.os_version} (rule): does not match")
|
||||
return false
|
||||
end
|
||||
|
||||
print_debug("OS version check -> (hook) #{os_version} #{rule.os_version} (rule): matched")
|
||||
|
||||
true
|
||||
rescue StandardError => e
|
||||
print_error e.message
|
||||
print_debug e.backtrace.join("\n")
|
||||
end
|
||||
|
||||
# @return [Boolean]
|
||||
# TODO: This should be updated to support matching multiple OS (like the browser check below)
|
||||
def zombie_os_matches_rule?(os, os_version, rule)
|
||||
return false if rule.nil?
|
||||
|
||||
return false unless rule.os == 'ALL' || os == rule.os
|
||||
|
||||
# check if the OS versions match
|
||||
os_ver_rule_cond = rule.os_version.split(' ').first
|
||||
|
||||
return true if os_ver_rule_cond == 'ALL'
|
||||
|
||||
return false unless @VERSION.include?(os_ver_rule_cond) || @VERSION_STR.include?(os_ver_rule_cond)
|
||||
|
||||
os_ver_rule_maj = rule.os_version.split(' ').last.split('.').first
|
||||
os_ver_rule_min = rule.os_version.split(' ').last.split('.').last
|
||||
|
||||
if os_ver_rule_maj == 'XP'
|
||||
os_ver_rule_maj = 5
|
||||
os_ver_rule_min = 0
|
||||
elsif os_ver_rule_maj == 'Vista'
|
||||
os_ver_rule_maj = 6
|
||||
os_ver_rule_min = 0
|
||||
elsif os_ver_rule_maj == '7'
|
||||
os_ver_rule_maj = 6
|
||||
os_ver_rule_min = 0
|
||||
end
|
||||
|
||||
# Most of the times Linux/*BSD OS doesn't return any version
|
||||
# (TODO: improve OS detection on these operating systems)
|
||||
if !os_version.nil? && !@VERSION_STR.include?(os_version)
|
||||
os_ver_hook_maj = os_version.split('.').first
|
||||
os_ver_hook_min = os_version.split('.').last
|
||||
|
||||
# the following assignments to 0 are need for later checks like:
|
||||
# 8.1 >= 7, because if the version doesn't have minor versions, maj/min are the same
|
||||
os_ver_hook_min = 0 if os_version.split('.').length == 1
|
||||
os_ver_rule_min = 0 if rule.os_version.split('.').length == 1
|
||||
else
|
||||
# XP is Windows 5.0 and Vista is Windows 6.0. Easier for comparison later on.
|
||||
# TODO: BUG: This will fail horribly if the target OS is Windows 7 or newer,
|
||||
# as no version normalization is performed.
|
||||
# TODO: Update this for every OS since Vista/7 ...
|
||||
if os_version == 'XP'
|
||||
os_ver_hook_maj = 5
|
||||
os_ver_hook_min = 0
|
||||
elsif os_version == 'Vista'
|
||||
os_ver_hook_maj = 6
|
||||
os_ver_hook_min = 0
|
||||
elsif os_version == '7'
|
||||
os_ver_hook_maj = 6
|
||||
os_ver_hook_min = 0
|
||||
end
|
||||
end
|
||||
|
||||
if !os_version.nil? || rule.os_version != 'ALL'
|
||||
os_major_version_match = compare_versions(os_ver_hook_maj.to_s, os_ver_rule_cond, os_ver_rule_maj.to_s)
|
||||
os_minor_version_match = compare_versions(os_ver_hook_min.to_s, os_ver_rule_cond, os_ver_rule_min.to_s)
|
||||
return false unless (os_major_version_match && os_minor_version_match)
|
||||
end
|
||||
|
||||
true
|
||||
rescue StandardError => e
|
||||
print_error e.message
|
||||
print_debug e.backtrace.join("\n")
|
||||
end
|
||||
|
||||
# @return [Boolean]
|
||||
def zombie_browser_matches_rule?(browser, browser_version, rule)
|
||||
return false if rule.nil?
|
||||
|
||||
b_ver_cond = rule.browser_version.split(' ').first
|
||||
|
||||
return false unless @VERSION.include?(b_ver_cond)
|
||||
|
||||
b_ver = rule.browser_version.split(' ').last
|
||||
|
||||
return false unless BeEF::Filters.is_valid_browserversion?(b_ver)
|
||||
|
||||
# check if rule specifies multiple browsers
|
||||
if rule.browser =~ /\A[A-Z]+\Z/
|
||||
return false unless rule.browser == 'ALL' || browser == rule.browser
|
||||
|
||||
# check if the browser version matches
|
||||
browser_version_match = compare_versions(browser_version.to_s, b_ver_cond, b_ver.to_s)
|
||||
return false unless browser_version_match
|
||||
else
|
||||
browser_match = false
|
||||
rule.browser.gsub(/[^A-Z,]/i, '').split(',').each do |b|
|
||||
if b == browser || b == 'ALL'
|
||||
browser_match = true
|
||||
break
|
||||
end
|
||||
end
|
||||
return false unless browser_match
|
||||
end
|
||||
|
||||
true
|
||||
rescue StandardError => e
|
||||
print_error e.message
|
||||
print_debug e.backtrace.join("\n")
|
||||
end
|
||||
|
||||
# Check if the hooked browser type/version and OS type/version match any Rule-sets
|
||||
# stored in the BeEF::Core::AutorunEngine::Models::Rule database table
|
||||
# stored in the BeEF::Core::Models::Rule database table
|
||||
# If one or more Rule-sets do match, trigger the module chain specified
|
||||
def run(hb_id, browser_name, browser_version, os_name, os_version)
|
||||
def find_and_run_all_matching_rules_for_zombie(hb_id)
|
||||
return if hb_id.nil?
|
||||
|
||||
hb_details = BeEF::Core::Models::BrowserDetails
|
||||
browser_name = hb_details.get(hb_id, 'browser.name')
|
||||
browser_version = hb_details.get(hb_id, 'browser.version')
|
||||
os_name = hb_details.get(hb_id, 'host.os.name')
|
||||
os_version = hb_details.get(hb_id, 'host.os.version')
|
||||
|
||||
are = BeEF::Core::AutorunEngine::Engine.instance
|
||||
match_rules = are.match(browser_name, browser_version, os_name, os_version)
|
||||
are.trigger(match_rules, hb_id) if match_rules !=nil && match_rules.length > 0
|
||||
rules = are.find_matching_rules_for_zombie(browser_name, browser_version, os_name, os_version)
|
||||
|
||||
return if rules.nil?
|
||||
return if rules.empty?
|
||||
|
||||
are.run_rules_on_zombie(rules, hb_id)
|
||||
end
|
||||
|
||||
# Run the specified rule IDs on the specified zombie ID
|
||||
# only if the rules match.
|
||||
def run_matching_rules_on_zombie(rule_ids, hb_id)
|
||||
return if rule_ids.nil?
|
||||
return if hb_id.nil?
|
||||
|
||||
rule_ids = [rule_ids.to_i] if rule_ids.is_a?(String)
|
||||
|
||||
hb_details = BeEF::Core::Models::BrowserDetails
|
||||
browser_name = hb_details.get(hb_id, 'browser.name')
|
||||
browser_version = hb_details.get(hb_id, 'browser.version')
|
||||
os_name = hb_details.get(hb_id, 'host.os.name')
|
||||
os_version = hb_details.get(hb_id, 'host.os.version')
|
||||
|
||||
are = BeEF::Core::AutorunEngine::Engine.instance
|
||||
rules = are.find_matching_rules_for_zombie(browser_name, browser_version, os_name, os_version)
|
||||
|
||||
return if rules.nil?
|
||||
return if rules.empty?
|
||||
|
||||
new_rules = []
|
||||
rules.each do |rule|
|
||||
new_rules << rule if rule_ids.include?(rule)
|
||||
end
|
||||
|
||||
return if new_rules.empty?
|
||||
|
||||
are.run_rules_on_zombie(new_rules, hb_id)
|
||||
end
|
||||
|
||||
# Run the specified rule IDs on the specified zombie ID
|
||||
# regardless of whether the rules match.
|
||||
# Prepare and return the JavaScript of the modules to be sent.
|
||||
# It also updates the rules ARE execution table with timings
|
||||
def trigger(rule_ids, hb_id)
|
||||
def run_rules_on_zombie(rule_ids, hb_id)
|
||||
return if rule_ids.nil?
|
||||
return if hb_id.nil?
|
||||
|
||||
hb = BeEF::HBManager.get_by_id(hb_id)
|
||||
hb_session = hb.session
|
||||
|
||||
rule_ids = [rule_ids] if rule_ids.is_a?(Integer)
|
||||
|
||||
rule_ids.each do |rule_id|
|
||||
rule = BeEF::Core::Models::Rule.find(rule_id)
|
||||
modules = JSON.parse(rule.modules)
|
||||
|
||||
execution_order = JSON.parse(rule.execution_order)
|
||||
execution_delay = JSON.parse(rule.execution_delay)
|
||||
chain_mode = rule.chain_mode
|
||||
chain_mode = rule.chain_mode
|
||||
|
||||
mods_bodies = Array.new
|
||||
mods_codes = Array.new
|
||||
mods_conditions = Array.new
|
||||
unless %w[sequential nested-forward].include?(chain_mode)
|
||||
print_error("[ARE] Invalid chain mode '#{chain_mode}' for rule")
|
||||
return
|
||||
end
|
||||
|
||||
mods_bodies = []
|
||||
mods_codes = []
|
||||
mods_conditions = []
|
||||
|
||||
# this ensures that if both rule A and rule B call the same module in sequential mode,
|
||||
# execution will be correct preventing wrapper functions to be called with equal names.
|
||||
rule_token = SecureRandom.hex(5)
|
||||
|
||||
modules.each do |cmd_mod|
|
||||
mod = BeEF::Core::Models::CommandModule.where(:name => cmd_mod['name']).first
|
||||
mod = BeEF::Core::Models::CommandModule.where(name: cmd_mod['name']).first
|
||||
options = []
|
||||
replace_input = false
|
||||
cmd_mod['options'].each do|k,v|
|
||||
options.push({'name' => k, 'value' => v})
|
||||
cmd_mod['options'].each do |k, v|
|
||||
options.push({ 'name' => k, 'value' => v })
|
||||
replace_input = true if v == '<<mod_input>>'
|
||||
end
|
||||
|
||||
command_body = prepare_command(mod, options, hb_id, replace_input, rule_token)
|
||||
|
||||
|
||||
mods_bodies.push(command_body)
|
||||
mods_codes.push(cmd_mod['code'])
|
||||
mods_conditions.push(cmd_mod['condition'])
|
||||
@@ -75,31 +283,32 @@ module BeEF
|
||||
|
||||
# Depending on the chosen chain mode (sequential or nested/forward), prepare the appropriate wrapper
|
||||
case chain_mode
|
||||
when 'nested-forward'
|
||||
wrapper = prepare_nested_forward_wrapper(mods_bodies, mods_codes, mods_conditions, execution_order, rule_token)
|
||||
when 'sequential'
|
||||
wrapper = prepare_sequential_wrapper(mods_bodies, execution_order, execution_delay, rule_token)
|
||||
else
|
||||
wrapper = nil
|
||||
print_error "Chain mode looks wrong!"
|
||||
# TODO catch error, which should never happen as values are checked way before ;-)
|
||||
when 'nested-forward'
|
||||
wrapper = prepare_nested_forward_wrapper(mods_bodies, mods_codes, mods_conditions, execution_order, rule_token)
|
||||
when 'sequential'
|
||||
wrapper = prepare_sequential_wrapper(mods_bodies, execution_order, execution_delay, rule_token)
|
||||
else
|
||||
# we should never get here. chain mode is validated earlier.
|
||||
print_error("[ARE] Invalid chain mode '#{chain_mode}'")
|
||||
next
|
||||
end
|
||||
|
||||
print_more "Triggering rules #{rule_ids} on HB #{hb_id}"
|
||||
|
||||
are_exec = BeEF::Core::Models::Execution.new(
|
||||
:session_id => hb_session,
|
||||
:mod_count => modules.length,
|
||||
:mod_successful => 0,
|
||||
:rule_token => rule_token,
|
||||
:mod_body => wrapper,
|
||||
:is_sent => false,
|
||||
:id => rule_id
|
||||
session_id: hb_session,
|
||||
mod_count: modules.length,
|
||||
mod_successful: 0,
|
||||
rule_token: rule_token,
|
||||
mod_body: wrapper,
|
||||
is_sent: false,
|
||||
rule_id: rule_id
|
||||
)
|
||||
are_exec.save!
|
||||
# Once Engine.check() verified that the hooked browser match a Rule, trigger the Rule ;-)
|
||||
print_more "Triggering ruleset #{rule_ids.to_s} on HB #{hb_id}"
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Wraps module bodies in their own function, using setTimeout to trigger them with an eventual delay.
|
||||
# Launch order is also taken care of.
|
||||
@@ -114,7 +323,7 @@ module BeEF
|
||||
delayed_exec = ''
|
||||
c = 0
|
||||
while c < mods.length
|
||||
delayed_exec += %Q| setTimeout(function(){#{mods[order[c]][:mod_name]}_#{rule_token}();}, #{delay[c]}); |
|
||||
delayed_exec += %| setTimeout(function(){#{mods[order[c]][:mod_name]}_#{rule_token}();}, #{delay[c]}); |
|
||||
mod_body = mods[order[c]][:mod_body].to_s.gsub("#{mods[order[c]][:mod_name]}_mod_output", "#{mods[order[c]][:mod_name]}_#{rule_token}_mod_output")
|
||||
wrapped_mod = "#{mod_body}\n"
|
||||
wrapper += wrapped_mod
|
||||
@@ -141,16 +350,17 @@ module BeEF
|
||||
# if the first once return with success. Also, the second module has the possibility of mangling first
|
||||
# module output and use it as input for some of its module inputs.
|
||||
def prepare_nested_forward_wrapper(mods, code, conditions, order, rule_token)
|
||||
wrapper, delayed_exec = '',''
|
||||
delayed_exec_footers = Array.new
|
||||
wrapper = ''
|
||||
delayed_exec = ''
|
||||
delayed_exec_footers = []
|
||||
c = 0
|
||||
|
||||
while c < mods.length
|
||||
if mods.length == 1
|
||||
i = c
|
||||
else
|
||||
i = c + 1
|
||||
end
|
||||
i = if mods.length == 1
|
||||
c
|
||||
else
|
||||
c + 1
|
||||
end
|
||||
|
||||
code_snippet = ''
|
||||
mod_input = ''
|
||||
@@ -159,11 +369,11 @@ module BeEF
|
||||
mod_input = 'mod_input'
|
||||
end
|
||||
|
||||
conditions[i] = true if conditions[i] == nil || conditions[i] == ''
|
||||
conditions[i] = true if conditions[i].nil? || conditions[i] == ''
|
||||
|
||||
if c == 0
|
||||
# this is the first wrapper to prepare
|
||||
delayed_exec += %Q|
|
||||
delayed_exec += %|
|
||||
function #{mods[order[c]][:mod_name]}_#{rule_token}_f(){
|
||||
#{mods[order[c]][:mod_name]}_#{rule_token}();
|
||||
|
||||
@@ -185,7 +395,7 @@ module BeEF
|
||||
#{mods[order[c]][:mod_name]}_#{rule_token}_mod_output = mod_result[1];
|
||||
|
|
||||
|
||||
delayed_exec_footer = %Q|
|
||||
delayed_exec_footer = %|
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -198,10 +408,10 @@ module BeEF
|
||||
delayed_exec_footers.push(delayed_exec_footer)
|
||||
|
||||
elsif c < mods.length - 1
|
||||
code_snippet = code_snippet.to_s.gsub(mods[order[c-1]][:mod_name], "#{mods[order[c-1]][:mod_name]}_#{rule_token}")
|
||||
code_snippet = code_snippet.to_s.gsub(mods[order[c - 1]][:mod_name], "#{mods[order[c - 1]][:mod_name]}_#{rule_token}")
|
||||
|
||||
# this is one of the wrappers in the middle of the chain
|
||||
delayed_exec += %Q|
|
||||
delayed_exec += %|
|
||||
function #{mods[order[c]][:mod_name]}_#{rule_token}_f(){
|
||||
if(#{mods[order[c]][:mod_name]}_#{rule_token}_can_exec){
|
||||
#{code_snippet}
|
||||
@@ -223,7 +433,7 @@ module BeEF
|
||||
#{mods[order[c]][:mod_name]}_#{rule_token}_mod_output = mod_result[1];
|
||||
|
|
||||
|
||||
delayed_exec_footer = %Q|
|
||||
delayed_exec_footer = %|
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -236,9 +446,9 @@ module BeEF
|
||||
|
||||
delayed_exec_footers.push(delayed_exec_footer)
|
||||
else
|
||||
code_snippet = code_snippet.to_s.gsub(mods[order[c-1]][:mod_name], "#{mods[order[c-1]][:mod_name]}_#{rule_token}")
|
||||
code_snippet = code_snippet.to_s.gsub(mods[order[c - 1]][:mod_name], "#{mods[order[c - 1]][:mod_name]}_#{rule_token}")
|
||||
# this is the last wrapper to prepare
|
||||
delayed_exec += %Q|
|
||||
delayed_exec += %|
|
||||
function #{mods[order[c]][:mod_name]}_#{rule_token}_f(){
|
||||
if(#{mods[order[c]][:mod_name]}_#{rule_token}_can_exec){
|
||||
#{code_snippet}
|
||||
@@ -258,7 +468,6 @@ module BeEF
|
||||
wrapper
|
||||
end
|
||||
|
||||
|
||||
# prepare the command module (compiling the Erubis templating stuff), eventually obfuscate it,
|
||||
# and store it in the database.
|
||||
# Returns the raw module body after template substitution.
|
||||
@@ -266,16 +475,16 @@ module BeEF
|
||||
config = BeEF::Core::Configuration.instance
|
||||
begin
|
||||
command = BeEF::Core::Models::Command.new(
|
||||
:data => options.to_json,
|
||||
:hooked_browser_id => hb_id,
|
||||
:command_module_id => BeEF::Core::Configuration.instance.get("beef.module.#{mod.name}.db.id"),
|
||||
:creationdate => Time.new.to_i,
|
||||
:instructions_sent => true
|
||||
data: options.to_json,
|
||||
hooked_browser_id: hb_id,
|
||||
command_module_id: BeEF::Core::Configuration.instance.get("beef.module.#{mod.name}.db.id"),
|
||||
creationdate: Time.new.to_i,
|
||||
instructions_sent: true
|
||||
)
|
||||
command.save!
|
||||
|
||||
command_module = BeEF::Core::Models::CommandModule.find(mod.id)
|
||||
if (command_module.path.match(/^Dynamic/))
|
||||
if command_module.path.match(/^Dynamic/)
|
||||
# metasploit and similar integrations
|
||||
command_module = BeEF::Modules::Commands.const_get(command_module.path.split('/').last.capitalize).new
|
||||
else
|
||||
@@ -293,18 +502,18 @@ module BeEF
|
||||
|
||||
build_missing_beefjs_components(command_module.beefjs_components) unless command_module.beefjs_components.empty?
|
||||
|
||||
if config.get("beef.extension.evasion.enable")
|
||||
if config.get('beef.extension.evasion.enable')
|
||||
evasion = BeEF::Extension::Evasion::Evasion.instance
|
||||
command_body = evasion.obfuscate(command_module.output) + "\n\n"
|
||||
else
|
||||
command_body = command_module.output + "\n\n"
|
||||
command_body = command_module.output + "\n\n"
|
||||
end
|
||||
|
||||
# @note prints the event to the console
|
||||
print_more "Preparing JS for command id [#{command.id}], module [#{mod.name}]"
|
||||
|
||||
replace_input ? mod_input = 'mod_input' : mod_input = ''
|
||||
result = %Q|
|
||||
mod_input = replace_input ? 'mod_input' : ''
|
||||
result = %|
|
||||
var #{mod.name}_#{rule_token} = function(#{mod_input}){
|
||||
#{clean_command_body(command_body, replace_input)}
|
||||
};
|
||||
@@ -312,8 +521,8 @@ module BeEF
|
||||
var #{mod.name}_#{rule_token}_mod_output = null;
|
||||
|
|
||||
|
||||
return {:mod_name => mod.name, :mod_body => result}
|
||||
rescue => e
|
||||
{ mod_name: mod.name, mod_body: result }
|
||||
rescue StandardError => e
|
||||
print_error e.message
|
||||
print_debug e.backtrace.join("\n")
|
||||
end
|
||||
@@ -324,163 +533,43 @@ module BeEF
|
||||
#
|
||||
# Also replace <<mod_input>> with mod_input variable if needed for chaining module output/input
|
||||
def clean_command_body(command_body, replace_input)
|
||||
begin
|
||||
cmd_body = command_body.lines.map(&:chomp)
|
||||
wrapper_start_index,wrapper_end_index = nil
|
||||
cmd_body = command_body.lines.map(&:chomp)
|
||||
wrapper_start_index, wrapper_end_index = nil
|
||||
|
||||
cmd_body.each_with_index do |line, index|
|
||||
if line.to_s =~ /^(beef|[a-zA-Z]+)\.execute\(function\(\)/
|
||||
wrapper_start_index = index
|
||||
break
|
||||
end
|
||||
cmd_body.each_with_index do |line, index|
|
||||
if line.to_s =~ /^(beef|[a-zA-Z]+)\.execute\(function\(\)/
|
||||
wrapper_start_index = index
|
||||
break
|
||||
end
|
||||
if wrapper_start_index.nil?
|
||||
print_error "[ARE] Could not find module start index"
|
||||
end
|
||||
|
||||
cmd_body.reverse.each_with_index do |line, index|
|
||||
if line.include?('});')
|
||||
wrapper_end_index = index
|
||||
break
|
||||
end
|
||||
end
|
||||
if wrapper_end_index.nil?
|
||||
print_error "[ARE] Could not find module end index"
|
||||
end
|
||||
|
||||
cleaned_cmd_body = cmd_body.slice(wrapper_start_index..-(wrapper_end_index+1)).join("\n")
|
||||
if cleaned_cmd_body.eql?('')
|
||||
print_error "[ARE] No command to send"
|
||||
end
|
||||
|
||||
# check if <<mod_input>> should be replaced with a variable name (depending if the variable is a string or number)
|
||||
if replace_input
|
||||
if cleaned_cmd_body.include?('"<<mod_input>>"')
|
||||
final_cmd_body = cleaned_cmd_body.gsub('"<<mod_input>>"','mod_input')
|
||||
elsif cleaned_cmd_body.include?('\'<<mod_input>>\'')
|
||||
final_cmd_body = cleaned_cmd_body.gsub('\'<<mod_input>>\'','mod_input')
|
||||
elsif cleaned_cmd_body.include?('<<mod_input>>')
|
||||
final_cmd_body = cleaned_cmd_body.gsub('\'<<mod_input>>\'','mod_input')
|
||||
else
|
||||
return cleaned_cmd_body
|
||||
end
|
||||
return final_cmd_body
|
||||
else
|
||||
return cleaned_cmd_body
|
||||
end
|
||||
rescue => e
|
||||
print_error "[ARE] There is likely a problem with the module's command.js parsing. Check Engine.clean_command_body"
|
||||
end
|
||||
end
|
||||
print_error '[ARE] Could not find module start index' if wrapper_start_index.nil?
|
||||
|
||||
cmd_body.reverse.each_with_index do |line, index|
|
||||
if line.include?('});')
|
||||
wrapper_end_index = index
|
||||
break
|
||||
end
|
||||
end
|
||||
print_error '[ARE] Could not find module end index' if wrapper_end_index.nil?
|
||||
|
||||
# Checks if there are any ARE rules to be triggered for the specified hooked browser
|
||||
#
|
||||
# Note: browser version checks are supporting only major versions, ex: C 43, IE 11
|
||||
# Note: OS version checks are supporting major/minor versions, ex: OSX 10.10, Windows 8.1
|
||||
#
|
||||
# Returns an array with rule IDs that matched and should be triggered.
|
||||
# if rule_id is specified, checks will be executed only against the specified rule (useful
|
||||
# for dynamic triggering of new rulesets ar runtime)
|
||||
def match(browser, browser_version, os, os_version, rule_id=nil)
|
||||
match_rules = []
|
||||
if rule_id != nil
|
||||
rules = [BeEF::Core::Models::Rule.find(rule_id)]
|
||||
cleaned_cmd_body = cmd_body.slice(wrapper_start_index..-(wrapper_end_index + 1)).join("\n")
|
||||
|
||||
print_error '[ARE] No command to send' if cleaned_cmd_body.eql?('')
|
||||
|
||||
# check if <<mod_input>> should be replaced with a variable name (depending if the variable is a string or number)
|
||||
return cleaned_cmd_body unless replace_input
|
||||
|
||||
if cleaned_cmd_body.include?('"<<mod_input>>"')
|
||||
cleaned_cmd_body.gsub('"<<mod_input>>"', 'mod_input')
|
||||
elsif cleaned_cmd_body.include?('\'<<mod_input>>\'')
|
||||
cleaned_cmd_body.gsub('\'<<mod_input>>\'', 'mod_input')
|
||||
elsif cleaned_cmd_body.include?('<<mod_input>>')
|
||||
cleaned_cmd_body.gsub('\'<<mod_input>>\'', 'mod_input')
|
||||
else
|
||||
rules = BeEF::Core::Models::Rule.all
|
||||
cleaned_cmd_body
|
||||
end
|
||||
return nil if rules == nil
|
||||
return nil unless rules.length > 0
|
||||
|
||||
print_info "[ARE] Checking if any defined rules should be triggered on target."
|
||||
# TODO handle cases where there are multiple ARE rules for the same hooked browser.
|
||||
# TODO the above works well, but maybe rules need to have priority or something?
|
||||
rules.each do |rule|
|
||||
begin
|
||||
browser_match, os_match = false, false
|
||||
|
||||
b_ver_cond = rule.browser_version.split(' ').first
|
||||
b_ver = rule.browser_version.split(' ').last
|
||||
|
||||
os_ver_rule_cond = rule.os_version.split(' ').first
|
||||
os_ver_rule_maj = rule.os_version.split(' ').last.split('.').first
|
||||
os_ver_rule_min = rule.os_version.split(' ').last.split('.').last
|
||||
|
||||
# Most of the times Linux/*BSD OS doesn't return any version
|
||||
# (TODO: improve OS detection on these operating systems)
|
||||
if os_version != nil && !@VERSION_STR.include?(os_version)
|
||||
os_ver_hook_maj = os_version.split('.').first
|
||||
os_ver_hook_min = os_version.split('.').last
|
||||
|
||||
# the following assignments to 0 are need for later checks like:
|
||||
# 8.1 >= 7, because if the version doesn't have minor versions, maj/min are the same
|
||||
os_ver_hook_min = 0 if os_version.split('.').length == 1
|
||||
os_ver_rule_min = 0 if rule.os_version.split('.').length == 1
|
||||
else
|
||||
# most probably Windows XP or Vista. the following is a hack as Microsoft had the brilliant idea
|
||||
# to switch from strings to numbers in OS versioning. To prevent rewriting code later on,
|
||||
# we say that XP is Windows 5.0 and Vista is Windows 6.0. Easier for comparison later on.
|
||||
os_ver_hook_maj, os_ver_hook_min = 5, 0 if os_version == 'XP'
|
||||
os_ver_hook_maj, os_ver_hook_min = 6, 0 if os_version == 'Vista'
|
||||
end
|
||||
|
||||
os_ver_rule_maj, os_ver_rule_min = 5, 0 if os_ver_rule_maj == 'XP'
|
||||
os_ver_rule_maj, os_ver_rule_min = 6, 0 if os_ver_rule_maj == 'Vista'
|
||||
|
||||
next unless @VERSION.include?(b_ver_cond)
|
||||
next unless BeEF::Filters::is_valid_browserversion?(b_ver)
|
||||
|
||||
next unless @VERSION.include?(os_ver_rule_cond) || @VERSION_STR.include?(os_ver_rule_cond)
|
||||
# os_ver without checks as it can be very different or even empty, for instance on linux/bsd)
|
||||
|
||||
# skip rule unless the browser matches
|
||||
browser_match = false
|
||||
# check if rule specifies multiple browsers
|
||||
if rule.browser !~ /\A[A-Z]+\Z/
|
||||
rule.browser.gsub(/[^A-Z,]/i, '').split(',').each do |b|
|
||||
browser_match = true if b == browser || b == 'ALL'
|
||||
end
|
||||
# else, only one browser
|
||||
else
|
||||
next unless rule.browser == 'ALL' || browser == rule.browser
|
||||
# check if the browser version matches
|
||||
browser_version_match = compare_versions(browser_version.to_s, b_ver_cond, b_ver.to_s)
|
||||
if browser_version_match
|
||||
browser_match = true
|
||||
else
|
||||
browser_match = false
|
||||
end
|
||||
print_more "Browser version check -> (hook) #{browser_version} #{rule.browser_version} (rule) : #{browser_version_match}"
|
||||
end
|
||||
next unless browser_match
|
||||
|
||||
# skip rule unless the OS matches
|
||||
next unless rule.os == 'ALL' || os == rule.os
|
||||
|
||||
# check if the OS versions match
|
||||
if os_version != nil || rule.os_version != 'ALL'
|
||||
os_major_version_match = compare_versions(os_ver_hook_maj.to_s, os_ver_rule_cond, os_ver_rule_maj.to_s)
|
||||
os_minor_version_match = compare_versions(os_ver_hook_min.to_s, os_ver_rule_cond, os_ver_rule_min.to_s)
|
||||
else
|
||||
# os_version_match = true if (browser doesn't return an OS version || rule OS version is ALL )
|
||||
os_major_version_match, os_minor_version_match = true, true
|
||||
end
|
||||
|
||||
os_match = true if os_ver_rule_cond == 'ALL' || (os_major_version_match && os_minor_version_match)
|
||||
print_more "OS version check -> (hook) #{os_version} #{rule.os_version} (rule): #{os_major_version_match && os_minor_version_match}"
|
||||
|
||||
if browser_match && os_match
|
||||
print_more "Hooked browser and OS type/version MATCH rule: #{rule.name}."
|
||||
match_rules.push(rule.id)
|
||||
end
|
||||
rescue => e
|
||||
print_error e.message
|
||||
print_debug e.backtrace.join("\n")
|
||||
end
|
||||
end
|
||||
print_more "Found [#{match_rules.length}/#{rules.length}] ARE rules matching the hooked browser type/version."
|
||||
|
||||
return match_rules
|
||||
rescue StandardError => e
|
||||
print_error "[ARE] There is likely a problem with the module's command.js parsing. Check Engine.clean_command_body. #{e.message}"
|
||||
end
|
||||
|
||||
# compare versions
|
||||
@@ -491,7 +580,8 @@ module BeEF
|
||||
return true if cond == '<' && ver_a < ver_b
|
||||
return true if cond == '>=' && ver_a >= ver_b
|
||||
return true if cond == '>' && ver_a > ver_b
|
||||
return false
|
||||
|
||||
false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,89 +1,80 @@
|
||||
#
|
||||
# Copyright (c) 2006-2021 Wade Alcorn - wade@bindshell.net
|
||||
# Copyright (c) 2006-2024 Wade Alcorn - wade@bindshell.net
|
||||
# Browser Exploitation Framework (BeEF) - http://beefproject.com
|
||||
# See the file 'doc/COPYING' for copying permission
|
||||
#
|
||||
module BeEF
|
||||
module Core
|
||||
module AutorunEngine
|
||||
|
||||
class Parser
|
||||
|
||||
include Singleton
|
||||
|
||||
def initialize
|
||||
@config = BeEF::Core::Configuration.instance
|
||||
end
|
||||
|
||||
BROWSER = ['FF','C','IE','S','O','ALL']
|
||||
OS = ['Linux','Windows','OSX','Android','iOS','BlackBerry','ALL']
|
||||
VERSION = ['<','<=','==','>=','>','ALL','Vista','XP']
|
||||
CHAIN_MODE = ['sequential','nested-forward']
|
||||
BROWSER = %w[FF C IE S O ALL]
|
||||
OS = %w[Linux Windows OSX Android iOS BlackBerry ALL]
|
||||
VERSION = ['<', '<=', '==', '>=', '>', 'ALL', 'Vista', 'XP']
|
||||
CHAIN_MODE = %w[sequential nested-forward]
|
||||
MAX_VER_LEN = 15
|
||||
# Parse a JSON ARE file and returns an Hash with the value mappings
|
||||
def parse(name,author,browser, browser_version, os, os_version, modules, exec_order, exec_delay, chain_mode)
|
||||
begin
|
||||
success = [true]
|
||||
|
||||
return [false, 'Illegal chain_mode definition'] unless CHAIN_MODE.include?(chain_mode)
|
||||
return [false, 'Illegal rule name'] unless BeEF::Filters.is_non_empty_string?(name)
|
||||
return [false, 'Illegal author name'] unless BeEF::Filters.is_non_empty_string?(author)
|
||||
# if multiple browsers were specified, check each browser
|
||||
if browser.kind_of?(Array)
|
||||
browser.each do |b|
|
||||
return [false, 'Illegal browser definition'] unless BROWSER.include?(b)
|
||||
end
|
||||
# else, if only one browser was specified, check browser and browser version
|
||||
else
|
||||
return [false, 'Illegal browser definition'] unless BROWSER.include?(browser)
|
||||
if browser_version != 'ALL'
|
||||
return [false, 'Illegal browser_version definition'] unless
|
||||
VERSION.include?(browser_version[0,2].gsub(/\s+/,'')) &&
|
||||
BeEF::Filters::is_valid_browserversion?(browser_version[2..-1].gsub(/\s+/,'')) && browser_version.length < MAX_VER_LEN
|
||||
end
|
||||
end
|
||||
def parse(name, author, browser, browser_version, os, os_version, modules, execution_order, execution_delay, chain_mode)
|
||||
raise ArgumentError, "Invalid rule name: #{name}" unless BeEF::Filters.is_non_empty_string?(name)
|
||||
raise ArgumentError, "Invalid author name: #{author}" unless BeEF::Filters.is_non_empty_string?(author)
|
||||
raise ArgumentError, "Invalid chain_mode definition: #{chain_mode}" unless CHAIN_MODE.include?(chain_mode)
|
||||
raise ArgumentError, "Invalid os definition: #{os}" unless OS.include?(os)
|
||||
|
||||
if os_version != 'ALL'
|
||||
return [false, 'Illegal os_version definition'] unless
|
||||
VERSION.include?(os_version[0,2].gsub(/\s+/,'')) &&
|
||||
BeEF::Filters::is_valid_osversion?(os_version[2..-1].gsub(/\s+/,'')) && os_version.length < MAX_VER_LEN
|
||||
end
|
||||
|
||||
return [false, 'Illegal os definition'] unless OS.include?(os)
|
||||
|
||||
# check if module names, conditions and options are ok
|
||||
modules.each do |cmd_mod|
|
||||
mod = BeEF::Core::Models::CommandModule.where(:name => cmd_mod['name']).first
|
||||
if mod != nil
|
||||
modk = BeEF::Module.get_key_by_database_id(mod.id)
|
||||
mod_options = BeEF::Module.get_options(modk)
|
||||
|
||||
opt_count = 0
|
||||
mod_options.each do |opt|
|
||||
if opt['name'] == cmd_mod['options'].keys[opt_count]
|
||||
opt_count += 1
|
||||
else
|
||||
return [false, "The specified option (#{cmd_mod['options'].keys[opt_count]
|
||||
}) for module (#{cmd_mod['name']}) does not exist"]
|
||||
end
|
||||
end
|
||||
else
|
||||
return [false, "The specified module name (#{cmd_mod['name']}) does not exist"]
|
||||
end
|
||||
end
|
||||
|
||||
exec_order.each{ |order| return [false, 'execution_order values must be Integers'] unless order.integer?}
|
||||
exec_delay.each{ |delay| return [false, 'execution_delay values must be Integers'] unless delay.integer?}
|
||||
|
||||
return [false, 'execution_order and execution_delay values must be consistent with modules numbers'] unless
|
||||
modules.size == exec_order.size && modules.size == exec_delay.size
|
||||
|
||||
success
|
||||
rescue => e
|
||||
print_error "#{e.message}"
|
||||
print_debug "#{e.backtrace.join("\n")}"
|
||||
return [false, 'Something went wrong.']
|
||||
unless modules.size == execution_delay.size
|
||||
raise ArgumentError, "Number of execution_delay values (#{execution_delay.size}) must be consistent with number of modules (#{modules.size})"
|
||||
end
|
||||
execution_delay.each { |delay| raise TypeError, "Invalid execution_delay value: #{delay}. Values must be Integers." unless delay.is_a?(Integer) }
|
||||
|
||||
unless modules.size == execution_order.size
|
||||
raise ArgumentError, "Number of execution_order values (#{execution_order.size}) must be consistent with number of modules (#{modules.size})"
|
||||
end
|
||||
execution_order.each { |order| raise TypeError, "Invalid execution_order value: #{order}. Values must be Integers." unless order.is_a?(Integer) }
|
||||
|
||||
# if multiple browsers were specified, check each browser
|
||||
if browser.is_a?(Array)
|
||||
browser.each do |b|
|
||||
raise ArgumentError, "Invalid browser definition: #{browser}" unless BROWSER.include?(b)
|
||||
end
|
||||
# else, if only one browser was specified, check browser and browser version
|
||||
else
|
||||
raise ArgumentError, "Invalid browser definition: #{browser}" unless BROWSER.include?(browser)
|
||||
|
||||
if browser_version != 'ALL' && !(VERSION.include?(browser_version[0, 2].gsub(/\s+/, '')) &&
|
||||
BeEF::Filters.is_valid_browserversion?(browser_version[2..-1].gsub(/\s+/, '')) && browser_version.length < MAX_VER_LEN)
|
||||
raise ArgumentError, "Invalid browser_version definition: #{browser_version}"
|
||||
end
|
||||
end
|
||||
|
||||
if os_version != 'ALL' && !(VERSION.include?(os_version[0, 2].gsub(/\s+/, '')) &&
|
||||
BeEF::Filters.is_valid_osversion?(os_version[2..-1].gsub(/\s+/, '')) && os_version.length < MAX_VER_LEN)
|
||||
return ArgumentError, "Invalid os_version definition: #{os_version}"
|
||||
end
|
||||
|
||||
# check if module names, conditions and options are ok
|
||||
modules.each do |cmd_mod|
|
||||
mod = BeEF::Core::Models::CommandModule.where(name: cmd_mod['name']).first
|
||||
|
||||
raise "The specified module name (#{cmd_mod['name']}) does not exist" if mod.nil?
|
||||
|
||||
modk = BeEF::Module.get_key_by_database_id(mod.id)
|
||||
mod_options = BeEF::Module.get_options(modk)
|
||||
|
||||
opt_count = 0
|
||||
mod_options.each do |opt|
|
||||
if opt['name'] != cmd_mod['options'].keys[opt_count]
|
||||
raise ArgumentError, "The specified option (#{cmd_mod['options'].keys[opt_count]}) for module (#{cmd_mod['name']}) was not specified"
|
||||
end
|
||||
|
||||
opt_count += 1
|
||||
end
|
||||
end
|
||||
|
||||
true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
#
|
||||
# Copyright (c) 2006-2021 Wade Alcorn - wade@bindshell.net
|
||||
# Copyright (c) 2006-2024 Wade Alcorn - wade@bindshell.net
|
||||
# Browser Exploitation Framework (BeEF) - http://beefproject.com
|
||||
# See the file 'doc/COPYING' for copying permission
|
||||
#
|
||||
module BeEF
|
||||
module Core
|
||||
module AutorunEngine
|
||||
|
||||
class RuleLoader
|
||||
|
||||
include Singleton
|
||||
|
||||
def initialize
|
||||
@@ -16,80 +14,111 @@ module BeEF
|
||||
@debug_on = @config.get('beef.debug')
|
||||
end
|
||||
|
||||
# this expects parsed JSON as input
|
||||
def load(data)
|
||||
# Load an ARE rule set
|
||||
# @param [Hash] ARE ruleset as JSON
|
||||
# @return [Hash] {"success": Boolean, "rule_id": Integer, "error": String}
|
||||
def load_rule_json(data)
|
||||
name = data['name'] || ''
|
||||
author = data['author'] || ''
|
||||
browser = data['browser'] || 'ALL'
|
||||
browser_version = data['browser_version'] || 'ALL'
|
||||
os = data['os'] || 'ALL'
|
||||
os_version = data['os_version'] || 'ALL'
|
||||
modules = data['modules']
|
||||
execution_order = data['execution_order']
|
||||
execution_delay = data['execution_delay']
|
||||
chain_mode = data['chain_mode'] || 'sequential'
|
||||
|
||||
begin
|
||||
BeEF::Core::AutorunEngine::Parser.instance.parse(
|
||||
name,
|
||||
author,
|
||||
browser,
|
||||
browser_version,
|
||||
os,
|
||||
os_version,
|
||||
modules,
|
||||
execution_order,
|
||||
execution_delay,
|
||||
chain_mode
|
||||
)
|
||||
rescue => e
|
||||
print_error("[ARE] Error loading ruleset (#{name}): #{e.message}")
|
||||
return { 'success' => false, 'error' => e.message }
|
||||
end
|
||||
|
||||
name = data['name']
|
||||
author = data['author']
|
||||
browser = data['browser']||'ALL'
|
||||
browser_version = data['browser_version']||'ALL'
|
||||
os = data['os']||'ALL'
|
||||
os_version = data['os_version']||'ALL'
|
||||
modules = data['modules']
|
||||
exec_order = data['execution_order']
|
||||
exec_delay = data['execution_delay']
|
||||
chain_mode = data['chain_mode']
|
||||
existing_rule = BeEF::Core::Models::Rule.where(
|
||||
name: name,
|
||||
author: author,
|
||||
browser: browser,
|
||||
browser_version: browser_version,
|
||||
os: os,
|
||||
os_version: os_version,
|
||||
modules: modules.to_json,
|
||||
execution_order: execution_order.to_s,
|
||||
execution_delay: execution_delay.to_s,
|
||||
chain_mode: chain_mode
|
||||
).first
|
||||
|
||||
parser_result = BeEF::Core::AutorunEngine::Parser.instance.parse(
|
||||
name,author,browser,browser_version,os,os_version,modules,exec_order,exec_delay,chain_mode)
|
||||
unless existing_rule.nil?
|
||||
msg = "Duplicate rule already exists in the database (ID: #{existing_rule.id})"
|
||||
print_info("[ARE] Skipping ruleset (#{name}): #{msg}")
|
||||
return { 'success' => false, 'error' => msg }
|
||||
end
|
||||
|
||||
if parser_result.length == 1 && parser_result.first
|
||||
print_info "[ARE] Ruleset (#{name}) parsed and stored successfully."
|
||||
if @debug_on
|
||||
print_more "Target Browser: #{browser} (#{browser_version})"
|
||||
print_more "Target OS: #{os} (#{os_version})"
|
||||
print_more "Modules to Trigger:"
|
||||
modules.each do |mod|
|
||||
print_more "(*) Name: #{mod['name']}"
|
||||
print_more "(*) Condition: #{mod['condition']}"
|
||||
print_more "(*) Code: #{mod['code']}"
|
||||
print_more "(*) Options:"
|
||||
mod['options'].each do |key,value|
|
||||
print_more "\t#{key}: (#{value})"
|
||||
end
|
||||
end
|
||||
print_more "Exec order: #{exec_order}"
|
||||
print_more "Exec delay: #{exec_delay}"
|
||||
are_rule = BeEF::Core::Models::Rule.new(
|
||||
name: name,
|
||||
author: author,
|
||||
browser: browser,
|
||||
browser_version: browser_version,
|
||||
os: os,
|
||||
os_version: os_version,
|
||||
modules: modules.to_json,
|
||||
execution_order: execution_order.to_s,
|
||||
execution_delay: execution_delay.to_s,
|
||||
chain_mode: chain_mode
|
||||
)
|
||||
are_rule.save
|
||||
|
||||
print_info("[ARE] Ruleset (#{name}) parsed and stored successfully.")
|
||||
|
||||
if @debug_on
|
||||
print_more "Target Browser: #{browser} (#{browser_version})"
|
||||
print_more "Target OS: #{os} (#{os_version})"
|
||||
print_more 'Modules to run:'
|
||||
modules.each do |mod|
|
||||
print_more "(*) Name: #{mod['name']}"
|
||||
print_more "(*) Condition: #{mod['condition']}"
|
||||
print_more "(*) Code: #{mod['code']}"
|
||||
print_more '(*) Options:'
|
||||
mod['options'].each do |key, value|
|
||||
print_more "\t#{key}: (#{value})"
|
||||
end
|
||||
are_rule = BeEF::Core::Models::Rule.new(
|
||||
:name => name,
|
||||
:author => author,
|
||||
:browser => browser,
|
||||
:browser_version => browser_version,
|
||||
:os => os,
|
||||
:os_version => os_version,
|
||||
:modules => modules.to_json,
|
||||
:execution_order => exec_order,
|
||||
:execution_delay => exec_delay,
|
||||
:chain_mode => chain_mode)
|
||||
are_rule.save
|
||||
return { 'success' => true, 'rule_id' => are_rule.id}
|
||||
else
|
||||
print_error "[ARE] Ruleset (#{name}): ERROR. " + parser_result.last
|
||||
return { 'success' => false, 'error' => parser_result.last }
|
||||
end
|
||||
|
||||
rescue => e
|
||||
err = 'Malformed JSON ruleset.'
|
||||
print_error "[ARE] Ruleset (#{name}): ERROR. #{e} #{e.backtrace}"
|
||||
return { 'success' => false, 'error' => err }
|
||||
print_more "Exec order: #{execution_order}"
|
||||
print_more "Exec delay: #{exec_delay}"
|
||||
end
|
||||
|
||||
{ 'success' => true, 'rule_id' => are_rule.id }
|
||||
rescue TypeError, ArgumentError => e
|
||||
print_error("[ARE] Failed to load ruleset (#{name}): #{e.message}")
|
||||
{ 'success' => false, 'error' => e.message }
|
||||
end
|
||||
|
||||
def load_file(json_rule_path)
|
||||
begin
|
||||
rule_file = File.open(json_rule_path, 'r:UTF-8', &:read)
|
||||
self.load JSON.parse(rule_file)
|
||||
rescue => e
|
||||
print_error "[ARE] Failed to load ruleset from #{json_rule_path}"
|
||||
end
|
||||
# Load an ARE ruleset from file
|
||||
# @param [String] JSON ARE ruleset file path
|
||||
def load_rule_file(json_rule_path)
|
||||
rule_file = File.open(json_rule_path, 'r:UTF-8', &:read)
|
||||
self.load_rule_json(JSON.parse(rule_file))
|
||||
rescue => e
|
||||
print_error("[ARE] Failed to load ruleset from #{json_rule_path}: #{e.message}")
|
||||
end
|
||||
|
||||
# Load all JSON ARE rule files from arerules/enabled/ directory
|
||||
def load_directory
|
||||
Dir.glob("#{$root_dir}/arerules/enabled/**/*.json") do |rule|
|
||||
print_debug "[ARE] Processing rule: #{rule}"
|
||||
self.load_file rule
|
||||
Dir.glob("#{$root_dir}/arerules/enabled/**/*.json") do |rule_file|
|
||||
print_debug("[ARE] Processing ruleset file: #{rule_file}")
|
||||
load_rule_file(rule_file)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright (c) 2006-2021 Wade Alcorn - wade@bindshell.net
|
||||
// Copyright (c) 2006-2024 Wade Alcorn - wade@bindshell.net
|
||||
// Browser Exploitation Framework (BeEF) - http://beefproject.com
|
||||
// See the file 'doc/COPYING' for copying permission
|
||||
//
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright (c) 2006-2021 Wade Alcorn - wade@bindshell.net
|
||||
// Copyright (c) 2006-2024 Wade Alcorn - wade@bindshell.net
|
||||
// Browser Exploitation Framework (BeEF) - http://beefproject.com
|
||||
// See the file 'doc/COPYING' for copying permission
|
||||
//
|
||||
@@ -39,7 +39,7 @@ if(typeof beef === 'undefined' && typeof window.beef === 'undefined') {
|
||||
*/
|
||||
debug: function(msg) {
|
||||
isDebug = '<%= @client_debug %>'
|
||||
if (typeof console == "object" && typeof console.log == "function" && isDebug.localeCompare("true")) {
|
||||
if (typeof console == "object" && typeof console.log == "function" && isDebug === 'true') {
|
||||
var currentdate = new Date();
|
||||
var pad = function(n){return ("0" + n).slice(-2);}
|
||||
var datetime = currentdate.getFullYear() + "-"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright (c) 2006-2021 Wade Alcorn - wade@bindshell.net
|
||||
// Copyright (c) 2006-2024 Wade Alcorn - wade@bindshell.net
|
||||
// Browser Exploitation Framework (BeEF) - http://beefproject.com
|
||||
// See the file 'doc/COPYING' for copying permission
|
||||
//
|
||||
@@ -4331,24 +4331,6 @@ beef.browser = {
|
||||
if (has_wmp) details['browser.capabilities.wmp'] = has_wmp;
|
||||
if (has_vlc) details['browser.capabilities.vlc'] = has_vlc;
|
||||
|
||||
var pf_integration = "<%= @phishing_frenzy_enable %>";
|
||||
if (pf_integration) {
|
||||
var pf_param = "uid";
|
||||
var pf_victim_uid = "";
|
||||
var location_search = window.location.search.substring(1);
|
||||
var params = location_search.split('&');
|
||||
for (var i = 0; i < params.length; i++) {
|
||||
var param_entry = params[i].split('=');
|
||||
if (param_entry[0] == pf_param) {
|
||||
pf_victim_uid = param_entry[1];
|
||||
details['PhishingFrenzyUID'] = pf_victim_uid;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
details['PhishingFrenzyUID'] = "N/A";
|
||||
}
|
||||
|
||||
return details;
|
||||
},
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright (c) 2006-2021 Wade Alcorn - wade@bindshell.net
|
||||
// Copyright (c) 2006-2024 Wade Alcorn - wade@bindshell.net
|
||||
// Browser Exploitation Framework (BeEF) - http://beefproject.com
|
||||
// See the file 'doc/COPYING' for copying permission
|
||||
//
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright (c) 2006-2021 Wade Alcorn - wade@bindshell.net
|
||||
// Copyright (c) 2006-2024 Wade Alcorn - wade@bindshell.net
|
||||
// Browser Exploitation Framework (BeEF) - http://beefproject.com
|
||||
// See the file 'doc/COPYING' for copying permission
|
||||
//
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright (c) 2006-2021 Wade Alcorn - wade@bindshell.net
|
||||
// Copyright (c) 2006-2024 Wade Alcorn - wade@bindshell.net
|
||||
// Browser Exploitation Framework (BeEF) - http://beefproject.com
|
||||
// See the file 'doc/COPYING' for copying permission
|
||||
//
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright (c) 2006-2021 Wade Alcorn - wade@bindshell.net
|
||||
// Copyright (c) 2006-2024 Wade Alcorn - wade@bindshell.net
|
||||
// Browser Exploitation Framework (BeEF) - http://beefproject.com
|
||||
// See the file 'doc/COPYING' for copying permission
|
||||
//
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright (c) 2006-2021 Wade Alcorn - wade@bindshell.net
|
||||
// Copyright (c) 2006-2024 Wade Alcorn - wade@bindshell.net
|
||||
// Browser Exploitation Framework (BeEF) - http://beefproject.com
|
||||
// See the file 'doc/COPYING' for copying permission
|
||||
//
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user